summaryrefslogtreecommitdiff
path: root/read-cache.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-03-22 21:22:44 (GMT)
committerJunio C Hamano <gitster@pobox.com>2008-04-09 08:22:25 (GMT)
commit1102952b45dde09d73445aa2284bcb592362fa23 (patch)
tree313f32f319e2d7fda886e7fcf9179e558eaba1ab /read-cache.c
parent6835550def046bfd52f3e65f248024956a6df62c (diff)
downloadgit-1102952b45dde09d73445aa2284bcb592362fa23.zip
git-1102952b45dde09d73445aa2284bcb592362fa23.tar.gz
git-1102952b45dde09d73445aa2284bcb592362fa23.tar.bz2
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.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/read-cache.c b/read-cache.c
index 8c57adf..6b7d16c 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)