diff options
author | Junio C Hamano <gitster@pobox.com> | 2008-05-10 18:14:28 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2008-05-10 18:14:28 -0700 |
commit | 380a7426794dcad369dd48519cd01d6e0246cde5 (patch) | |
tree | a6671d54dfa9c41094f541ef5377ae53d04e842c /read-cache.c | |
parent | 1f8115b113def8ee03701aa87b26c5e8b7c94434 (diff) | |
parent | 1102952b45dde09d73445aa2284bcb592362fa23 (diff) | |
download | git-380a7426794dcad369dd48519cd01d6e0246cde5.tar.gz git-380a7426794dcad369dd48519cd01d6e0246cde5.tar.xz |
Merge branch 'lt/case-insensitive'
* lt/case-insensitive:
Make git-add behave more sensibly in a case-insensitive environment
When adding files to the index, add support for case-independent matches
Make unpack-tree update removed files before any updated files
Make branch merging aware of underlying case-insensitive filsystems
Add 'core.ignorecase' option
Make hash_name_lookup able to do case-independent lookups
Make "index_name_exists()" return the cache_entry it found
Move name hashing functions into a file of its own
Make unpack_trees_options bit flags actual bitfields
Diffstat (limited to 'read-cache.c')
-rw-r--r-- | read-cache.c | 114 |
1 files changed, 44 insertions, 70 deletions
diff --git a/read-cache.c b/read-cache.c index c3692f41a..3b20a142e 100644 --- a/read-cache.c +++ b/read-cache.c @@ -23,80 +23,21 @@ struct index_state the_index; -static unsigned int hash_name(const char *name, int namelen) -{ - unsigned int hash = 0x123; - - do { - unsigned char c = *name++; - hash = hash*101 + c; - } while (--namelen); - return hash; -} - -static void hash_index_entry(struct index_state *istate, struct cache_entry *ce) -{ - void **pos; - unsigned int hash; - - if (ce->ce_flags & CE_HASHED) - return; - ce->ce_flags |= CE_HASHED; - ce->next = NULL; - hash = hash_name(ce->name, ce_namelen(ce)); - pos = insert_hash(hash, ce, &istate->name_hash); - if (pos) { - ce->next = *pos; - *pos = ce; - } -} - -static void lazy_init_name_hash(struct index_state *istate) -{ - int nr; - - if (istate->name_hash_initialized) - return; - for (nr = 0; nr < istate->cache_nr; nr++) - hash_index_entry(istate, istate->cache[nr]); - istate->name_hash_initialized = 1; -} - static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce) { - ce->ce_flags &= ~CE_UNHASHED; istate->cache[nr] = ce; - if (istate->name_hash_initialized) - hash_index_entry(istate, ce); + add_name_hash(istate, ce); } static void replace_index_entry(struct index_state *istate, int nr, struct cache_entry *ce) { struct cache_entry *old = istate->cache[nr]; - remove_index_entry(old); + remove_name_hash(old); set_index_entry(istate, nr, ce); istate->cache_changed = 1; } -int index_name_exists(struct index_state *istate, const char *name, int namelen) -{ - unsigned int hash = hash_name(name, namelen); - struct cache_entry *ce; - - lazy_init_name_hash(istate); - ce = lookup_hash(hash, &istate->name_hash); - - while (ce) { - if (!(ce->ce_flags & CE_UNHASHED)) { - if (!cache_name_compare(name, namelen, ce->name, ce->ce_flags)) - return 1; - } - ce = ce->next; - } - return 0; -} - /* * This only updates the "non-critical" parts of the directory * cache, ie the parts that aren't tracked by GIT, and only used @@ -438,7 +379,7 @@ int remove_index_entry_at(struct index_state *istate, int pos) { struct cache_entry *ce = istate->cache[pos]; - remove_index_entry(ce); + remove_name_hash(ce); istate->cache_changed = 1; istate->cache_nr--; if (pos >= istate->cache_nr) @@ -488,11 +429,43 @@ 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, pos; + int size, namelen; struct stat st; - struct cache_entry *ce; + struct cache_entry *ce, *alias; unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY; if (lstat(path, &st)) @@ -525,18 +498,19 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose) ce->ce_mode = ce_mode_from_stat(ent, st.st_mode); } - pos = index_name_pos(istate, ce->name, namelen); - if (0 <= pos && - !ce_stage(istate->cache[pos]) && - !ie_match_stat(istate, istate->cache[pos], &st, ce_option)) { + alias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case); + if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, &st, ce_option)) { /* Nothing changed, really */ free(ce); - ce_mark_uptodate(istate->cache[pos]); + 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) |