diff options
-rw-r--r-- | builtin-add.c | 2 | ||||
-rw-r--r-- | builtin-apply.c | 2 | ||||
-rw-r--r-- | cache.h | 14 | ||||
-rw-r--r-- | check-racy.c | 2 | ||||
-rw-r--r-- | diff-lib.c | 20 | ||||
-rw-r--r-- | diff.h | 6 | ||||
-rw-r--r-- | entry.c | 2 | ||||
-rw-r--r-- | read-cache.c | 48 | ||||
-rwxr-xr-x | t/t2200-add-update.sh | 30 | ||||
-rw-r--r-- | unpack-trees.c | 4 |
10 files changed, 92 insertions, 38 deletions
diff --git a/builtin-add.c b/builtin-add.c index 850e1c23e5..4fc9d6f7cc 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -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) diff --git a/builtin-apply.c b/builtin-apply.c index 5cc90e68f8..0fff02e0d8 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -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) @@ -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); diff --git a/check-racy.c b/check-racy.c index d6a08b4a55..00d92a1663 100644 --- a/check-racy.c +++ b/check-racy.c @@ -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++; diff --git a/diff-lib.c b/diff-lib.c index da5571302d..ec1b5e3d44 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -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); @@ -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); @@ -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) { diff --git a/read-cache.c b/read-cache.c index 928e8fa1ae..c3dbf89426 100644 --- a/read-cache.c +++ b/read-cache.c @@ -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) { diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index eb1ced3c37..24f892f793 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -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 diff --git a/unpack-trees.c b/unpack-trees.c index ccfeb6e245..9411c67a06 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -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); |