Code

Merge branch 'py/diff-submodule'
authorJunio C Hamano <gitster@pobox.com>
Sun, 11 May 2008 01:16:25 +0000 (18:16 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 11 May 2008 01:16:25 +0000 (18:16 -0700)
* 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

1  2 
diff-lib.c
read-cache.c

diff --combined diff-lib.c
index 9139e45fb98b4cb62d4e9dd243d3dc45f631aaeb,4a3e25536c894dfb928754e6314a400d39c6f9ad..c5894c7c5aa166370f407ace804dc1a857d04fe4
@@@ -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)
                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 {
                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);
                        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 3b20a142ea93f67d8a1246ebd27797aad8035e6e,9ee125597ecaf5aa95a43148d631343a7de8b4b4..4525f8a5ac4d6c1a7ff9c0085036ae0ac1a238bf
  
  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))
                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;