revision: optionally record matches with pathspec elements

Unlike "git add" and other end-user facing commands, where it is diagnosed as an error to give a pathspec with an element that does not match any path, the diff machinery does not care if some elements of the pathspec do not match. Given that the diff machinery is heavily used in pathspec-limited "git log" machinery, and it is common for a path to come and go while traversing the project history, this is usually a good thing. However, in some cases we would want to know if all the pathspec elements matched. For example, "git add -u <pathspec>" internally uses the machinery used by "git diff-files" to decide contents from what paths to add to the index, and as an end-user facing command, "git add -u" would want to report an unmatched pathspec element. Add a new .ps_matched member next to the .prune_data member in "struct rev_info" so that we can optionally keep track of the use of .prune_data pathspec elements that can be inspected by the caller. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Apr 3, 2024 at 23:44 UTC 86829f3f3ea62853a4a632637ade6de94a1f4c7c
7 files changed +23 -10
builtin/add.c
+2 -2
@@ -553,8 +553,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
553 exit_status |= renormalize_tracked_files(&pathspec, flags);
554 else
555 exit_status |= add_files_to_cache(the_repository, prefix,
556 - &pathspec, include_sparse,
557 - flags);
556 + &pathspec, NULL,
557 + include_sparse, flags);
558
559 if (add_new_files)
560 exit_status |= add_files(&dir, flags);
builtin/checkout.c
+2 -1
@@ -878,7 +878,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
878 * entries in the index.
879 */
880
881 - add_files_to_cache(the_repository, NULL, NULL, 0, 0);
881 + add_files_to_cache(the_repository, NULL, NULL, NULL, 0,
882 + 0);
883 init_merge_options(&o, the_repository);
884 o.verbosity = 0;
885 work = write_in_core_index_as_tree(the_repository);
builtin/commit.c
+1 -1
@@ -444,7 +444,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
444 repo_hold_locked_index(the_repository, &index_lock,
445 LOCK_DIE_ON_ERROR);
446 add_files_to_cache(the_repository, also ? prefix : NULL,
447 - &pathspec, 0, 0);
447 + &pathspec, NULL, 0, 0);
448 refresh_cache_or_die(refresh_flags);
449 cache_tree_update(&the_index, WRITE_TREE_SILENT);
450 if (write_locked_index(&the_index, &index_lock, 0))
diff-lib.c
+10 -1
@@ -127,7 +127,16 @@ void run_diff_files(struct rev_info *revs, unsigned int option)
127 if (diff_can_quit_early(&revs->diffopt))
128 break;
129
130 - if (!ce_path_match(istate, ce, &revs->prune_data, NULL))
130 + /*
131 + * NEEDSWORK:
132 + * Here we filter with pathspec but the result is further
133 + * filtered out when --relative is in effect. To end-users,
134 + * a pathspec element that matched only to paths outside the
135 + * current directory is like not matching anything at all;
136 + * the handling of ps_matched[] here may become problematic
137 + * if/when we add the "--error-unmatch" option to "git diff".
138 + */
139 + if (!ce_path_match(istate, ce, &revs->prune_data, revs->ps_matched))
140 continue;
141
142 if (revs->diffopt.prefix &&
read-cache-ll.h
+2 -2
@@ -480,8 +480,8 @@ extern int verify_ce_order;
480 int cmp_cache_name_compare(const void *a_, const void *b_);
481
482 int add_files_to_cache(struct repository *repo, const char *prefix,
483 - const struct pathspec *pathspec, int include_sparse,
484 - int flags);
483 + const struct pathspec *pathspec, char *ps_matched,
484 + int include_sparse, int flags);
485
486 void overlay_tree_on_index(struct index_state *istate,
487 const char *tree_name, const char *prefix);
read-cache.c
+5 -3
@@ -3958,8 +3958,8 @@ static void update_callback(struct diff_queue_struct *q,
3958 }
3959
3960 int add_files_to_cache(struct repository *repo, const char *prefix,
3961 - const struct pathspec *pathspec, int include_sparse,
3962 - int flags)
3961 + const struct pathspec *pathspec, char *ps_matched,
3962 + int include_sparse, int flags)
3963 {
3964 struct update_callback_data data;
3965 struct rev_info rev;
@@ -3971,8 +3971,10 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
3971
3972 repo_init_revisions(repo, &rev, prefix);
3973 setup_revisions(0, NULL, &rev, NULL);
3974 - if (pathspec)
3974 + if (pathspec) {
3975 copy_pathspec(&rev.prune_data, pathspec);
3976 + rev.ps_matched = ps_matched;
3977 + }
3978 rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
3979 rev.diffopt.format_callback = update_callback;
3980 rev.diffopt.format_callback_data = &data;
revision.h
+1
@@ -142,6 +142,7 @@ struct rev_info {
142 /* Basic information */
143 const char *prefix;
144 const char *def;
145 + char *ps_matched; /* optionally record matches of prune_data */
146 struct pathspec prune_data;
147
148 /*