Merge branch 'jc/maint-add-sync-stat' into maint
authorJunio C Hamano <gitster@pobox.com>
Sun, 25 Nov 2007 02:03:04 +0000 (18:03 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 25 Nov 2007 02:03:04 +0000 (18:03 -0800)
* jc/maint-add-sync-stat:
t2200: test more cases of "add -u"
git-add: make the entry stat-clean after re-adding the same contents
ce_match_stat, run_diff_files: use symbolic constants for readability

builtin-add.c
builtin-apply.c
cache.h
check-racy.c
diff-lib.c
diff.h
entry.c
read-cache.c
t/t2200-add-update.sh
unpack-trees.c
index 850e1c23e545e8f84e5a72ea7a7bdd1a99746938..4fc9d6f7ccdd7b989d75ae6e24df997c4deb3505 100644 (file)
@@ -117,7 +117,7 @@ static void update(int verbose, const char *prefix, const char **files)
        rev.diffopt.format_callback_data = &verbose;
        if (read_cache() < 0)
                die("index file corrupt");
-       run_diff_files(&rev, 0);
+       run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
 }
 
 static void refresh(int verbose, const char **pathspec)
index 5cc90e68f880180b072db946080c4168b98603cf..0fff02e0d826115d4b05d8ba6415a0107d3cf22f 100644 (file)
@@ -2099,7 +2099,7 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
                        return -1;
                return 0;
        }
-       return ce_match_stat(ce, st, 1);
+       return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);
 }
 
 static int check_patch(struct patch *patch, struct patch *prev_patch)
diff --git a/cache.h b/cache.h
index 60af6d35794beb67dd7165668677cfbca9334f30..c9954d78084588a1541cb45861eb9dbce9a6b7a6 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -174,8 +174,8 @@ extern struct index_state the_index;
 #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
 #define add_file_to_cache(path, verbose) add_file_to_index(&the_index, (path), (verbose))
 #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
-#define ce_match_stat(ce, st, really) ie_match_stat(&the_index, (ce), (st), (really))
-#define ce_modified(ce, st, really) ie_modified(&the_index, (ce), (st), (really))
+#define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
+#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
 #endif
 
 enum object_type {
@@ -266,8 +266,14 @@ extern int remove_file_from_index(struct index_state *, const char *path);
 extern int add_file_to_index(struct index_state *, const char *path, int verbose);
 extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
 extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
-extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat *, int);
-extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int);
+
+/* do stat comparison even if CE_VALID is true */
+#define CE_MATCH_IGNORE_VALID          01
+/* do not check the contents but report dirty on racily-clean entries */
+#define CE_MATCH_RACY_IS_DIRTY 02
+extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat *, unsigned int);
+extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, unsigned int);
+
 extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
 extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
 extern int read_fd(int fd, char **return_buf, unsigned long *return_size);
index d6a08b4a55273af1a5f2933f3b5c6cb818ba74c6..00d92a16631a80ff8ec4e995dafcd3e55434fad5 100644 (file)
@@ -18,7 +18,7 @@ int main(int ac, char **av)
 
                if (ce_match_stat(ce, &st, 0))
                        dirty++;
-               else if (ce_match_stat(ce, &st, 2))
+               else if (ce_match_stat(ce, &st, CE_MATCH_RACY_IS_DIRTY))
                        racy++;
                else
                        clean++;
index da5571302df6ed418874fd4d7423853a7de5b52c..ec1b5e3d446c4e5a56fb5f3e4420499c4e8918eb 100644 (file)
@@ -173,9 +173,10 @@ static int is_in_index(const char *path)
 }
 
 static int handle_diff_files_args(struct rev_info *revs,
-               int argc, const char **argv, int *silent)
+                                 int argc, const char **argv,
+                                 unsigned int *options)
 {
-       *silent = 0;
+       *options = 0;
 
        /* revs->max_count == -2 means --no-index */
        while (1 < argc && argv[1][0] == '-') {
@@ -192,7 +193,7 @@ static int handle_diff_files_args(struct rev_info *revs,
                        revs->diffopt.no_index = 1;
                }
                else if (!strcmp(argv[1], "-q"))
-                       *silent = 1;
+                       *options |= DIFF_SILENT_ON_REMOVED;
                else
                        return error("invalid option: %s", argv[1]);
                argv++; argc--;
@@ -305,9 +306,9 @@ int setup_diff_no_index(struct rev_info *revs,
 
 int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
 {
-       int silent_on_removed;
+       unsigned int options;
 
-       if (handle_diff_files_args(revs, argc, argv, &silent_on_removed))
+       if (handle_diff_files_args(revs, argc, argv, &options))
                return -1;
 
        if (revs->diffopt.no_index) {
@@ -329,13 +330,16 @@ int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
                perror("read_cache");
                return -1;
        }
-       return run_diff_files(revs, silent_on_removed);
+       return run_diff_files(revs, options);
 }
 
-int run_diff_files(struct rev_info *revs, int silent_on_removed)
+int run_diff_files(struct rev_info *revs, unsigned int option)
 {
        int entries, i;
        int diff_unmerged_stage = revs->max_count;
+       int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
+       unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
+                             ? CE_MATCH_RACY_IS_DIRTY : 0);
 
        if (diff_unmerged_stage < 0)
                diff_unmerged_stage = 2;
@@ -441,7 +445,7 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                                       ce->sha1, ce->name, NULL);
                        continue;
                }
-               changed = ce_match_stat(ce, &st, 0);
+               changed = ce_match_stat(ce, &st, ce_option);
                if (!changed && !revs->diffopt.find_copies_harder)
                        continue;
                oldmode = ntohl(ce->ce_mode);
diff --git a/diff.h b/diff.h
index 4546aad219742e4ad878937dbd05436c93d298b9..efaa8f711a35c1339aba2bcaffeab6bf95343983 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -224,7 +224,11 @@ extern void diff_flush(struct diff_options*);
 
 extern const char *diff_unique_abbrev(const unsigned char *, int);
 
-extern int run_diff_files(struct rev_info *revs, int silent_on_removed);
+/* do not report anything on removed paths */
+#define DIFF_SILENT_ON_REMOVED 01
+/* report racily-clean paths as modified */
+#define DIFF_RACY_IS_MODIFIED 02
+extern int run_diff_files(struct rev_info *revs, unsigned int option);
 extern int setup_diff_no_index(struct rev_info *revs,
                int argc, const char ** argv, int nongit, const char *prefix);
 extern int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv);
diff --git a/entry.c b/entry.c
index fc3a506ecef4ed654f26c11996df109dd135a4ed..ef88f62ce82e7188a8d1863227a87033543958fb 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -200,7 +200,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
        strcpy(path + len, ce->name);
 
        if (!lstat(path, &st)) {
-               unsigned changed = ce_match_stat(ce, &st, 1);
+               unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
                if (!changed)
                        return 0;
                if (!state->force) {
index 928e8fa1aee22a0a79c57ca675576d4998503ea9..c3dbf894261ddae12a48542ba8869cbd8f2ebd50 100644 (file)
@@ -194,11 +194,12 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
 }
 
 int ie_match_stat(struct index_state *istate,
-                 struct cache_entry *ce, struct stat *st, int options)
+                 struct cache_entry *ce, struct stat *st,
+                 unsigned int options)
 {
        unsigned int changed;
-       int ignore_valid = options & 01;
-       int assume_racy_is_modified = options & 02;
+       int ignore_valid = options & CE_MATCH_IGNORE_VALID;
+       int assume_racy_is_modified = options & CE_MATCH_RACY_IS_DIRTY;
 
        /*
         * If it's marked as always valid in the index, it's
@@ -238,10 +239,11 @@ int ie_match_stat(struct index_state *istate,
 }
 
 int ie_modified(struct index_state *istate,
-               struct cache_entry *ce, struct stat *st, int really)
+               struct cache_entry *ce, struct stat *st, unsigned int options)
 {
        int changed, changed_fs;
-       changed = ie_match_stat(istate, ce, st, really);
+
+       changed = ie_match_stat(istate, ce, st, options);
        if (!changed)
                return 0;
        /*
@@ -386,6 +388,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
        int size, namelen, pos;
        struct stat st;
        struct cache_entry *ce;
+       unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
 
        if (lstat(path, &st))
                die("%s: unable to stat (%s)", path, strerror(errno));
@@ -420,7 +423,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
        pos = index_name_pos(istate, ce->name, namelen);
        if (0 <= pos &&
            !ce_stage(istate->cache[pos]) &&
-           !ie_modified(istate, istate->cache[pos], &st, 1)) {
+           !ie_match_stat(istate, istate->cache[pos], &st, ce_option)) {
                /* Nothing changed, really */
                free(ce);
                return 0;
@@ -782,11 +785,13 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
  * to link up the stat cache details with the proper files.
  */
 static struct cache_entry *refresh_cache_ent(struct index_state *istate,
-                                            struct cache_entry *ce, int really, int *err)
+                                            struct cache_entry *ce,
+                                            unsigned int options, int *err)
 {
        struct stat st;
        struct cache_entry *updated;
        int changed, size;
+       int ignore_valid = options & CE_MATCH_IGNORE_VALID;
 
        if (lstat(ce->name, &st) < 0) {
                if (err)
@@ -794,16 +799,23 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
                return NULL;
        }
 
-       changed = ie_match_stat(istate, ce, &st, really);
+       changed = ie_match_stat(istate, ce, &st, options);
        if (!changed) {
-               if (really && assume_unchanged &&
+               /*
+                * The path is unchanged.  If we were told to ignore
+                * valid bit, then we did the actual stat check and
+                * found that the entry is unmodified.  If the entry
+                * is not marked VALID, this is the place to mark it
+                * valid again, under "assume unchanged" mode.
+                */
+               if (ignore_valid && assume_unchanged &&
                    !(ce->ce_flags & htons(CE_VALID)))
                        ; /* mark this one VALID again */
                else
                        return ce;
        }
 
-       if (ie_modified(istate, ce, &st, really)) {
+       if (ie_modified(istate, ce, &st, options)) {
                if (err)
                        *err = EINVAL;
                return NULL;
@@ -814,13 +826,14 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
        memcpy(updated, ce, size);
        fill_stat_cache_info(updated, &st);
 
-       /* In this case, if really is not set, we should leave
-        * CE_VALID bit alone.  Otherwise, paths marked with
-        * --no-assume-unchanged (i.e. things to be edited) will
-        * reacquire CE_VALID bit automatically, which is not
-        * really what we want.
+       /*
+        * If ignore_valid is not set, we should leave CE_VALID bit
+        * alone.  Otherwise, paths marked with --no-assume-unchanged
+        * (i.e. things to be edited) will reacquire CE_VALID bit
+        * automatically, which is not really what we want.
         */
-       if (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID)))
+       if (!ignore_valid && assume_unchanged &&
+           !(ce->ce_flags & htons(CE_VALID)))
                updated->ce_flags &= ~htons(CE_VALID);
 
        return updated;
@@ -834,6 +847,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
        int allow_unmerged = (flags & REFRESH_UNMERGED) != 0;
        int quiet = (flags & REFRESH_QUIET) != 0;
        int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
+       unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
 
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce, *new;
@@ -855,7 +869,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
                if (pathspec && !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen))
                        continue;
 
-               new = refresh_cache_ent(istate, ce, really, &cache_errno);
+               new = refresh_cache_ent(istate, ce, options, &cache_errno);
                if (new == ce)
                        continue;
                if (!new) {
index eb1ced3c371ecaeab9d0dc14be888bf7df110483..24f892f79386478fd5f1162654cb9b72d940bbe4 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git add -u with path limiting
+test_description='git add -u
 
 This test creates a working tree state with three files:
 
@@ -9,7 +9,10 @@ This test creates a working tree state with three files:
   dir/other (untracked)
 
 and issues a git add -u with path limiting on "dir" to add
-only the updates to dir/sub.'
+only the updates to dir/sub.
+
+Also tested are "git add -u" without limiting, and "git add -u"
+without contents changes.'
 
 . ./test-lib.sh
 
@@ -85,4 +88,27 @@ test_expect_success 'replace a file with a symlink' '
 
 '
 
+test_expect_success 'add everything changed' '
+
+       git add -u &&
+       test -z "$(git diff-files)"
+
+'
+
+test_expect_success 'touch and then add -u' '
+
+       touch check &&
+       git add -u &&
+       test -z "$(git diff-files)"
+
+'
+
+test_expect_success 'touch and then add explicitly' '
+
+       touch check &&
+       git add check &&
+       test -z "$(git diff-files)"
+
+'
+
 test_done
index ccfeb6e245f32d88170ae51f0367ee15aa950a37..9411c67a067e109621d310edfa4a66df99b7eb89 100644 (file)
@@ -406,7 +406,7 @@ static void verify_uptodate(struct cache_entry *ce,
                return;
 
        if (!lstat(ce->name, &st)) {
-               unsigned changed = ce_match_stat(ce, &st, 1);
+               unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
                if (!changed)
                        return;
                /*
@@ -927,7 +927,7 @@ int oneway_merge(struct cache_entry **src,
                if (o->reset) {
                        struct stat st;
                        if (lstat(old->name, &st) ||
-                           ce_match_stat(old, &st, 1))
+                           ce_match_stat(old, &st, CE_MATCH_IGNORE_VALID))
                                old->ce_flags |= htons(CE_UPDATE);
                }
                return keep_entry(old, o);