Merge branch 'jc/maint-add-sync-stat'

* 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

Conflicts:

	builtin-add.c
This commit is contained in:
Junio C Hamano 2007-11-14 14:15:40 -08:00
commit c78a24986d
10 changed files with 92 additions and 38 deletions

View File

@ -120,7 +120,7 @@ void add_files_to_cache(int verbose, const char *prefix, const char **files)
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = update_callback; rev.diffopt.format_callback = update_callback;
rev.diffopt.format_callback_data = &verbose; rev.diffopt.format_callback_data = &verbose;
run_diff_files(&rev, 0); run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
} }
static void refresh(int verbose, const char **pathspec) static void refresh(int verbose, const char **pathspec)

View File

@ -1993,7 +1993,7 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
return -1; return -1;
return 0; 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) static int check_patch(struct patch *patch, struct patch *prev_patch)

14
cache.h
View File

@ -175,8 +175,8 @@ extern struct index_state the_index;
#define remove_file_from_cache(path) remove_file_from_index(&the_index, (path)) #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 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 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_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
#define ce_modified(ce, st, really) ie_modified(&the_index, (ce), (st), (really)) #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
#endif #endif
enum object_type { enum object_type {
@ -268,8 +268,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 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 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 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 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 index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object); extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);

View File

@ -18,7 +18,7 @@ int main(int ac, char **av)
if (ce_match_stat(ce, &st, 0)) if (ce_match_stat(ce, &st, 0))
dirty++; dirty++;
else if (ce_match_stat(ce, &st, 2)) else if (ce_match_stat(ce, &st, CE_MATCH_RACY_IS_DIRTY))
racy++; racy++;
else else
clean++; clean++;

View File

@ -173,9 +173,10 @@ static int is_in_index(const char *path)
} }
static int handle_diff_files_args(struct rev_info *revs, 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 */ /* revs->max_count == -2 means --no-index */
while (1 < argc && argv[1][0] == '-') { 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; revs->diffopt.no_index = 1;
} }
else if (!strcmp(argv[1], "-q")) else if (!strcmp(argv[1], "-q"))
*silent = 1; *options |= DIFF_SILENT_ON_REMOVED;
else else
return error("invalid option: %s", argv[1]); return error("invalid option: %s", argv[1]);
argv++; argc--; 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 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; return -1;
if (revs->diffopt.no_index) { 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"); perror("read_cache");
return -1; 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 entries, i;
int diff_unmerged_stage = revs->max_count; 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) if (diff_unmerged_stage < 0)
diff_unmerged_stage = 2; 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); ce->sha1, ce->name, NULL);
continue; continue;
} }
changed = ce_match_stat(ce, &st, 0); changed = ce_match_stat(ce, &st, ce_option);
if (!changed && !revs->diffopt.find_copies_harder) if (!changed && !revs->diffopt.find_copies_harder)
continue; continue;
oldmode = ntohl(ce->ce_mode); oldmode = ntohl(ce->ce_mode);

6
diff.h
View File

@ -224,7 +224,11 @@ extern void diff_flush(struct diff_options*);
extern const char *diff_unique_abbrev(const unsigned char *, int); 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, extern int setup_diff_no_index(struct rev_info *revs,
int argc, const char ** argv, int nongit, const char *prefix); 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); extern int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv);

View File

@ -203,7 +203,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
strcpy(path + len, ce->name); strcpy(path + len, ce->name);
if (!lstat(path, &st)) { 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) if (!changed)
return 0; return 0;
if (!state->force) { if (!state->force) {

View 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, 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; unsigned int changed;
int ignore_valid = options & 01; int ignore_valid = options & CE_MATCH_IGNORE_VALID;
int assume_racy_is_modified = options & 02; int assume_racy_is_modified = options & CE_MATCH_RACY_IS_DIRTY;
/* /*
* If it's marked as always valid in the index, it's * 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, 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; int changed, changed_fs;
changed = ie_match_stat(istate, ce, st, really);
changed = ie_match_stat(istate, ce, st, options);
if (!changed) if (!changed)
return 0; return 0;
/* /*
@ -387,6 +389,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
int size, namelen, pos; int size, namelen, pos;
struct stat st; struct stat st;
struct cache_entry *ce; struct cache_entry *ce;
unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
if (lstat(path, &st)) if (lstat(path, &st))
die("%s: unable to stat (%s)", path, strerror(errno)); die("%s: unable to stat (%s)", path, strerror(errno));
@ -421,7 +424,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
pos = index_name_pos(istate, ce->name, namelen); pos = index_name_pos(istate, ce->name, namelen);
if (0 <= pos && if (0 <= pos &&
!ce_stage(istate->cache[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 */ /* Nothing changed, really */
free(ce); free(ce);
return 0; return 0;
@ -783,11 +786,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. * to link up the stat cache details with the proper files.
*/ */
static struct cache_entry *refresh_cache_ent(struct index_state *istate, 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 stat st;
struct cache_entry *updated; struct cache_entry *updated;
int changed, size; int changed, size;
int ignore_valid = options & CE_MATCH_IGNORE_VALID;
if (lstat(ce->name, &st) < 0) { if (lstat(ce->name, &st) < 0) {
if (err) if (err)
@ -795,16 +800,23 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
return NULL; return NULL;
} }
changed = ie_match_stat(istate, ce, &st, really); changed = ie_match_stat(istate, ce, &st, options);
if (!changed) { 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))) !(ce->ce_flags & htons(CE_VALID)))
; /* mark this one VALID again */ ; /* mark this one VALID again */
else else
return ce; return ce;
} }
if (ie_modified(istate, ce, &st, really)) { if (ie_modified(istate, ce, &st, options)) {
if (err) if (err)
*err = EINVAL; *err = EINVAL;
return NULL; return NULL;
@ -815,13 +827,14 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
memcpy(updated, ce, size); memcpy(updated, ce, size);
fill_stat_cache_info(updated, &st); 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 * If ignore_valid is not set, we should leave CE_VALID bit
* --no-assume-unchanged (i.e. things to be edited) will * alone. Otherwise, paths marked with --no-assume-unchanged
* reacquire CE_VALID bit automatically, which is not * (i.e. things to be edited) will reacquire CE_VALID bit
* really what we want. * 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); updated->ce_flags &= ~htons(CE_VALID);
return updated; return updated;
@ -835,6 +848,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
int allow_unmerged = (flags & REFRESH_UNMERGED) != 0; int allow_unmerged = (flags & REFRESH_UNMERGED) != 0;
int quiet = (flags & REFRESH_QUIET) != 0; int quiet = (flags & REFRESH_QUIET) != 0;
int not_new = (flags & REFRESH_IGNORE_MISSING) != 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++) { for (i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce, *new; struct cache_entry *ce, *new;
@ -856,7 +870,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)) if (pathspec && !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen))
continue; continue;
new = refresh_cache_ent(istate, ce, really, &cache_errno); new = refresh_cache_ent(istate, ce, options, &cache_errno);
if (new == ce) if (new == ce)
continue; continue;
if (!new) { if (!new) {

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/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: 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) dir/other (untracked)
and issues a git add -u with path limiting on "dir" to add 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 . ./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 test_done

View File

@ -404,7 +404,7 @@ static void verify_uptodate(struct cache_entry *ce,
return; return;
if (!lstat(ce->name, &st)) { 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) if (!changed)
return; return;
/* /*
@ -925,7 +925,7 @@ int oneway_merge(struct cache_entry **src,
if (o->reset) { if (o->reset) {
struct stat st; struct stat st;
if (lstat(old->name, &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); old->ce_flags |= htons(CE_UPDATE);
} }
return keep_entry(old, o); return keep_entry(old, o);