diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-03-22 14:22:44 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2008-04-09 01:22:25 -0700 |
commit | 1102952b45dde09d73445aa2284bcb592362fa23 (patch) | |
tree | 313f32f319e2d7fda886e7fcf9179e558eaba1ab /read-cache.c | |
parent | 6835550def046bfd52f3e65f248024956a6df62c (diff) | |
download | git-1102952b45dde09d73445aa2284bcb592362fa23.tar.gz |
Make git-add behave more sensibly in a case-insensitive environment
This expands on the previous patch, and allows "git add" to sanely handle
a filename that has changed case, keeping the case in the index constant,
and avoiding aliases.
In particular, if you have an index entry called "File", but the
checked-out tree is case-corrupted and has an entry called "file"
instead, doing a
git add .
(or naming "file" explicitly) will automatically notice that we have an
alias, and will replace the name "file" with the existing index
capitalization (ie "File").
However, if we actually have *both* a file called "File" and one called
"file", and they don't have the same lstat() information (ie we're on a
case-sensitive filesystem but have the "core.ignorecase" flag set), we
will error out if we try to add them both.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'read-cache.c')
-rw-r--r-- | read-cache.c | 37 |
1 files changed, 36 insertions, 1 deletions
diff --git a/read-cache.c b/read-cache.c index 8c57adfa16..6b7d16c554 100644 --- a/read-cache.c +++ b/read-cache.c @@ -429,6 +429,38 @@ static int index_name_pos_also_unmerged(struct index_state *istate, return pos; } +static int different_name(struct cache_entry *ce, struct cache_entry *alias) +{ + int len = ce_namelen(ce); + return ce_namelen(alias) != len || memcmp(ce->name, alias->name, len); +} + +/* + * If we add a filename that aliases in the cache, we will use the + * name that we already have - but we don't want to update the same + * alias twice, because that implies that there were actually two + * different files with aliasing names! + * + * So we use the CE_ADDED flag to verify that the alias was an old + * one before we accept it as + */ +static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_entry *alias) +{ + int len; + struct cache_entry *new; + + if (alias->ce_flags & CE_ADDED) + die("Will not add file alias '%s' ('%s' already exists in index)", ce->name, alias->name); + + /* Ok, create the new entry using the name of the existing alias */ + len = ce_namelen(alias); + new = xcalloc(1, cache_entry_size(len)); + memcpy(new->name, alias->name, len); + copy_cache_entry(new, ce); + free(ce); + return new; +} + int add_file_to_index(struct index_state *istate, const char *path, int verbose) { int size, namelen; @@ -471,11 +503,14 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose) /* Nothing changed, really */ free(ce); ce_mark_uptodate(alias); + alias->ce_flags |= CE_ADDED; return 0; } - if (index_path(ce->sha1, path, &st, 1)) die("unable to index file %s", path); + if (ignore_case && alias && different_name(ce, alias)) + ce = create_alias_ce(ce, alias); + ce->ce_flags |= CE_ADDED; if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE)) die("unable to add %s to index",path); if (verbose) |