From: Junio C Hamano Date: Sun, 11 May 2008 01:16:25 +0000 (-0700) Subject: Merge branch 'py/diff-submodule' X-Git-Tag: v1.5.6-rc0~68^2~2 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/2855e70ad11abf7e7f30f975b063bd60d5abdf4f?ds=inline;hp=-c Merge branch 'py/diff-submodule' * py/diff-submodule: is_racy_timestamp(): do not check timestamp for gitlinks diff-lib.c: rename check_work_tree_entity() diff: a submodule not checked out is not modified Add t7506 to test submodule related functions for git-status t4027: test diff for submodule with empty directory --- 2855e70ad11abf7e7f30f975b063bd60d5abdf4f diff --combined diff-lib.c index 9139e45fb9,4a3e25536c..c5894c7c5a --- a/diff-lib.c +++ b/diff-lib.c @@@ -337,11 -337,17 +337,17 @@@ int run_diff_files_cmd(struct rev_info } return run_diff_files(revs, options); } + /* - * See if work tree has an entity that can be staged. Return 0 if so, - * return 1 if not and return -1 if error. + * Has the work tree entity been removed? + * + * Return 1 if it was removed from the work tree, 0 if an entity to be + * compared with the cache entry ce still exists (the latter includes + * the case where a directory that is not a submodule repository + * exists for ce that is a submodule -- it is a submodule that is not + * checked out). Return negative for an error. */ - static int check_work_tree_entity(const struct cache_entry *ce, struct stat *st, char *symcache) + static int check_removed(const struct cache_entry *ce, struct stat *st, char *symcache) { if (lstat(ce->name, st) < 0) { if (errno != ENOENT && errno != ENOTDIR) @@@ -352,7 -358,20 +358,20 @@@ return 1; if (S_ISDIR(st->st_mode)) { unsigned char sub[20]; - if (resolve_gitlink_ref(ce->name, "HEAD", sub)) + + /* + * If ce is already a gitlink, we can have a plain + * directory (i.e. the submodule is not checked out), + * or a checked out submodule. Either case this is not + * a case where something was removed from the work tree, + * so we will return 0. + * + * Otherwise, if the directory is not a submodule + * repository, that means ce which was a blob turned into + * a directory --- the blob was removed! + */ + if (!S_ISGITLINK(ce->ce_mode) && + resolve_gitlink_ref(ce->name, "HEAD", sub)) return 1; } return 0; @@@ -402,7 -421,7 +421,7 @@@ int run_diff_files(struct rev_info *rev memset(&(dpath->parent[0]), 0, sizeof(struct combine_diff_parent)*5); - changed = check_work_tree_entity(ce, &st, symcache); + changed = check_removed(ce, &st, symcache); if (!changed) dpath->mode = ce_mode_from_stat(ce, st.st_mode); else { @@@ -466,7 -485,7 +485,7 @@@ if (ce_uptodate(ce)) continue; - changed = check_work_tree_entity(ce, &st, symcache); + changed = check_removed(ce, &st, symcache); if (changed) { if (changed < 0) { perror(ce->name); @@@ -479,11 -498,8 +498,11 @@@ continue; } changed = ce_match_stat(ce, &st, ce_option); - if (!changed && !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER)) - continue; + if (!changed) { + ce_mark_uptodate(ce); + if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER)) + continue; + } oldmode = ce->ce_mode; newmode = ce_mode_from_stat(ce, st.st_mode); diff_change(&revs->diffopt, oldmode, newmode, @@@ -527,7 -543,7 +546,7 @@@ static int get_stat_data(struct cache_e if (!cached) { int changed; struct stat st; - changed = check_work_tree_entity(ce, &st, cbdata->symcache); + changed = check_removed(ce, &st, cbdata->symcache); if (changed < 0) return -1; else if (changed) { diff --combined read-cache.c index 3b20a142ea,9ee125597e..4525f8a5ac --- a/read-cache.c +++ b/read-cache.c @@@ -23,21 -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 @@@ -198,7 -257,8 +198,8 @@@ static int ce_match_stat_basic(struct c static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce) { - return (istate->timestamp && + return (!S_ISGITLINK(ce->ce_mode) && + istate->timestamp && ((unsigned int)istate->timestamp) <= ce->ce_mtime); } @@@ -379,7 -439,7 +380,7 @@@ int remove_index_entry_at(struct index_ { 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) @@@ -429,43 -489,11 +430,43 @@@ static int index_name_pos_also_unmerged 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)) @@@ -498,19 -526,18 +499,19 @@@ 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) @@@ -1344,7 -1371,7 +1345,7 @@@ int write_index(const struct index_stat struct cache_entry *ce = cache[i]; if (ce->ce_flags & CE_REMOVE) continue; - if (is_racy_timestamp(istate, ce)) + if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce)) ce_smudge_racily_clean_entry(ce); if (ce_write_entry(&c, newfd, ce) < 0) return -1;