mirror of
https://github.com/git/git
synced 2024-08-24 18:26:02 +00:00
Merge branch 'jc/maint-add-sync-stat' into maint
* 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
This commit is contained in:
commit
bc2b8eafaf
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
14
cache.h
14
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);
|
||||
|
|
|
@ -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++;
|
||||
|
|
20
diff-lib.c
20
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);
|
||||
|
|
6
diff.h
6
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);
|
||||
|
|
2
entry.c
2
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) {
|
||||
|
|
48
read-cache.c
48
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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue