From: Junio C Hamano Date: Thu, 7 Mar 2019 00:59:54 +0000 (+0900) Subject: Merge branch 'en/combined-all-paths' X-Git-Tag: v2.22.0-rc0~174 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/c425d361f5bf46d99cd96d7eac3488ebb2e92b60?hp=-c Merge branch 'en/combined-all-paths' Output from "diff --cc" did not show the original paths when the merge involved renames. A new option adds the paths in the original trees to the output. * en/combined-all-paths: log,diff-tree: add --combined-all-paths option --- c425d361f5bf46d99cd96d7eac3488ebb2e92b60 diff --combined Documentation/git-diff-tree.txt index 43daa7c046,28b93ecd54..24f32e8c54 --- a/Documentation/git-diff-tree.txt +++ b/Documentation/git-diff-tree.txt @@@ -10,8 -10,8 +10,8 @@@ SYNOPSI -------- [verse] 'git diff-tree' [--stdin] [-m] [-s] [-v] [--no-commit-id] [--pretty] - [-t] [-r] [-c | --cc] [--root] [] - [] [...] + [-t] [-r] [-c | --cc] [--combined-all-paths] [--root] + [] [] [...] DESCRIPTION ----------- @@@ -31,7 -31,10 +31,7 @@@ include::diff-options.txt[ ...:: If provided, the results are limited to a subset of files - matching one of these prefix strings. - i.e., file matches `/^||.../` - Note that this parameter does not provide any wildcard or regexp - features. + matching one of the provided pathspecs. -r:: recurse into sub-trees @@@ -105,12 -108,65 +105,19 @@@ include::pretty-options.txt[ itself and the commit log message is not shown, just like in any other "empty diff" case. + --combined-all-paths:: + This flag causes combined diffs (used for merge commits) to + list the name of the file from all parents. It thus only has + effect when -c or --cc are specified, and is likely only + useful if filename changes are detected (i.e. when either + rename or copy detection have been requested). + --always:: Show the commit itself and the commit log message even if the diff itself is empty. include::pretty-formats.txt[] - - -LIMITING OUTPUT ---------------- -If you're only interested in differences in a subset of files, for -example some architecture-specific files, you might do: - - git diff-tree -r arch/ia64 include/asm-ia64 - -and it will only show you what changed in those two directories. - -Or if you are searching for what changed in just `kernel/sched.c`, just do - - git diff-tree -r kernel/sched.c - -and it will ignore all differences to other files. - -The pattern is always the prefix, and is matched exactly. There are no -wildcards. Even stricter, it has to match a complete path component. -I.e. "foo" does not pick up `foobar.h`. "foo" does match `foo/bar.h` -so it can be used to name subdirectories. - -An example of normal usage is: - - torvalds@ppc970:~/git> git diff-tree --abbrev 5319e4 - :100664 100664 ac348b... a01513... git-fsck-objects.c - -which tells you that the last commit changed just one file (it's from -this one: - ------------------------------------------------------------------------------ -commit 3c6f7ca19ad4043e9e72fa94106f352897e651a8 -tree 5319e4d609cdd282069cc4dce33c1db559539b03 -parent b4e628ea30d5ab3606119d2ea5caeab141d38df7 -author Linus Torvalds Sat Apr 9 12:02:30 2005 -committer Linus Torvalds Sat Apr 9 12:02:30 2005 - -Make "git-fsck-objects" print out all the root commits it finds. - -Once I do the reference tracking, I'll also make it print out all the -HEAD commits it finds, which is even more interesting. ------------------------------------------------------------------------------ - -in case you care). - - include::diff-format.txt[] GIT diff --combined Documentation/rev-list-options.txt index cad711ce0a,642ce943c1..ca959a7286 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@@ -270,13 -270,13 +270,13 @@@ depending on a few rules + -- 1. If the starting point is specified as `ref@{Nth}`, show the index -format. + format. + 2. If the starting point was specified as `ref@{now}`, show the -timestamp format. + timestamp format. + 3. If neither was used, but `--date` was given on the command line, show -the timestamp in the format requested by `--date`. + the timestamp in the format requested by `--date`. + 4. Otherwise, show the index format. -- @@@ -730,13 -730,8 +730,13 @@@ specification contained in + The form '--filter=tree:' omits all blobs and trees whose depth from the root tree is >= (minimum depth if an object is located -at multiple depths in the commits traversed). Currently, only =0 -is supported, which omits all blobs and trees. +at multiple depths in the commits traversed). =0 will not include +any trees or blobs unless included explicitly in the command-line (or +standard input when --stdin is used). =1 will include only the +tree and blobs which are referenced directly by a commit reachable from + or an explicitly-given object. =2 is like =1 +while also including trees and blobs one more level removed from an +explicitly-given commit or tree. --no-filter:: Turn off any previous `--filter=` argument. @@@ -836,13 -831,6 +836,13 @@@ Note that the `-local` option does not value (which is always measured in UTC), but does switch the accompanying timezone value. + +`--date=human` shows the timezone if the timezone does not match the +current time-zone, and doesn't print the whole date if that matches +(ie skip printing year for dates that are "this year", but also skip +the whole date itself if it's in the last few days and we can just say +what weekday it was). For older dates the hour and minute is also +omitted. ++ `--date=unix` shows the date as a Unix epoch timestamp (seconds since 1970). As with `--raw`, this is always in UTC and therefore `-local` has no effect. @@@ -960,6 -948,13 +960,13 @@@ options may be given. See linkgit:git-d the parents have only two variants and the merge result picks one of them without modification. + --combined-all-paths:: + This flag causes combined diffs (used for merge commits) to + list the name of the file from all parents. It thus only has + effect when -c or --cc are specified, and is likely only + useful if filename changes are detected (i.e. when either + rename or copy detection have been requested). + -m:: This flag makes the merge commits show the full diff like regular commits; for each merge parent, a separate log entry diff --combined builtin/diff-tree.c index a90681bcba,ebe48f60c1..cb9ea79367 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@@ -1,4 -1,3 +1,4 @@@ +#define USE_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" #include "config.h" #include "diff.h" @@@ -83,9 -82,13 +83,13 @@@ static int diff_tree_stdin(char *line } static const char diff_tree_usage[] = - "git diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] " + "git diff-tree [--stdin] [-m] [-c | --cc] [-s] [-v] [--pretty] [-t] [-r] [--root] " "[] [] [...]\n" " -r diff recursively\n" + " -c show combined diff for merge commits\n" + " --cc show combined diff for merge commits removing uninteresting hunks\n" + " --combined-all-paths\n" + " show name of file in all parents for combined diffs\n" " --root include the initial commit as diff against /dev/null\n" COMMON_DIFF_OPTIONS_HELP; @@@ -166,7 -169,7 +170,7 @@@ int cmd_diff_tree(int argc, const char if (opt->diffopt.detect_rename) { if (!the_index.cache) - read_index(&the_index); + repo_read_index(the_repository); opt->diffopt.setup |= DIFF_SETUP_USE_SIZE_CACHE; } while (fgets(line, sizeof(line), stdin)) { diff --combined combine-diff.c index 23d8fabe75,54cb892ae5..3e49f3bda8 --- a/combine-diff.c +++ b/combine-diff.c @@@ -23,11 -23,20 +23,20 @@@ static int compare_paths(const struct c two->path, strlen(two->path), two->mode); } - static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent) + static int filename_changed(char status) + { + return status == 'R' || status == 'C'; + } + + static struct combine_diff_path *intersect_paths( + struct combine_diff_path *curr, + int n, + int num_parent, + int combined_all_paths) { struct diff_queue_struct *q = &diff_queued_diff; struct combine_diff_path *p, **tail = &curr; - int i, cmp; + int i, j, cmp; if (!n) { for (i = 0; i < q->nr; i++) { @@@ -50,6 -59,13 +59,13 @@@ oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid); p->parent[n].mode = q->queue[i]->one->mode; p->parent[n].status = q->queue[i]->status; + + if (combined_all_paths && + filename_changed(p->parent[n].status)) { + strbuf_init(&p->parent[n].path, 0); + strbuf_addstr(&p->parent[n].path, + q->queue[i]->one->path); + } *tail = p; tail = &p->next; } @@@ -68,6 -84,10 +84,10 @@@ if (cmp < 0) { /* p->path not in q->queue[]; drop it */ *tail = p->next; + for (j = 0; j < num_parent; j++) + if (combined_all_paths && + filename_changed(p->parent[j].status)) + strbuf_release(&p->parent[j].path); free(p); continue; } @@@ -81,6 -101,10 +101,10 @@@ oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid); p->parent[n].mode = q->queue[i]->one->mode; p->parent[n].status = q->queue[i]->status; + if (combined_all_paths && + filename_changed(p->parent[n].status)) + strbuf_addstr(&p->parent[n].path, + q->queue[i]->one->path); tail = &p->next; i++; @@@ -960,12 -984,25 +984,25 @@@ static void show_combined_header(struc if (!show_file_header) return; - if (added) - dump_quoted_path("--- ", "", "/dev/null", - line_prefix, c_meta, c_reset); - else - dump_quoted_path("--- ", a_prefix, elem->path, - line_prefix, c_meta, c_reset); + if (rev->combined_all_paths) { + for (i = 0; i < num_parent; i++) { + char *path = filename_changed(elem->parent[i].status) + ? elem->parent[i].path.buf : elem->path; + if (elem->parent[i].status == DIFF_STATUS_ADDED) + dump_quoted_path("--- ", "", "/dev/null", + line_prefix, c_meta, c_reset); + else + dump_quoted_path("--- ", a_prefix, path, + line_prefix, c_meta, c_reset); + } + } else { + if (added) + dump_quoted_path("--- ", "", "/dev/null", + line_prefix, c_meta, c_reset); + else + dump_quoted_path("--- ", a_prefix, elem->path, + line_prefix, c_meta, c_reset); + } if (deleted) dump_quoted_path("+++ ", "", "/dev/null", line_prefix, c_meta, c_reset); @@@ -1227,6 -1264,15 +1264,15 @@@ static void show_raw_diff(struct combin putchar(inter_name_termination); } + for (i = 0; i < num_parent; i++) + if (rev->combined_all_paths) { + if (filename_changed(p->parent[i].status)) + write_name_quoted(p->parent[i].path.buf, stdout, + inter_name_termination); + else + write_name_quoted(p->path, stdout, + inter_name_termination); + } write_name_quoted(p->path, stdout, line_termination); } @@@ -1321,18 -1367,12 +1367,20 @@@ static const char *path_path(void *obj return path->path; } +/* + * Diff stat formats which we always compute solely against the first parent. + */ +#define STAT_FORMAT_MASK (DIFF_FORMAT_NUMSTAT \ + | DIFF_FORMAT_SHORTSTAT \ + | DIFF_FORMAT_SUMMARY \ + | DIFF_FORMAT_DIRSTAT \ + | DIFF_FORMAT_DIFFSTAT) /* find set of paths that every parent touches */ static struct combine_diff_path *find_paths_generic(const struct object_id *oid, - const struct oid_array *parents, struct diff_options *opt) + const struct oid_array *parents, + struct diff_options *opt, + int combined_all_paths) { struct combine_diff_path *paths = NULL; int i, num_parent = parents->nr; @@@ -1350,14 -1390,16 +1398,15 @@@ * show stat against the first parent even when doing * combined diff. */ - int stat_opt = (output_format & - (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT)); + int stat_opt = output_format & STAT_FORMAT_MASK; if (i == 0 && stat_opt) opt->output_format = stat_opt; else opt->output_format = DIFF_FORMAT_NO_OUTPUT; diff_tree_oid(&parents->oid[i], oid, "", opt); diffcore_std(opt); - paths = intersect_paths(paths, i, num_parent); + paths = intersect_paths(paths, i, num_parent, + combined_all_paths); /* if showing diff, show it in requested order */ if (opt->output_format != DIFF_FORMAT_NO_OUTPUT && @@@ -1467,7 -1509,8 +1516,8 @@@ void diff_tree_combined(const struct ob * diff(sha1,parent_i) for all i to do the job, specifically * for parent0. */ - paths = find_paths_generic(oid, parents, &diffopts); + paths = find_paths_generic(oid, parents, &diffopts, + rev->combined_all_paths); } else { int stat_opt; @@@ -1477,7 -1520,8 +1527,7 @@@ * show stat against the first parent even * when doing combined diff. */ - stat_opt = (opt->output_format & - (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT)); + stat_opt = opt->output_format & STAT_FORMAT_MASK; if (stat_opt) { diffopts.output_format = stat_opt; @@@ -1521,7 -1565,8 +1571,7 @@@ show_raw_diff(p, num_parent, rev); needsep = 1; } - else if (opt->output_format & - (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT)) + else if (opt->output_format & STAT_FORMAT_MASK) needsep = 1; else if (opt->output_format & DIFF_FORMAT_CALLBACK) handle_combined_callback(opt, paths, num_parent, num_paths); @@@ -1540,6 -1585,10 +1590,10 @@@ while (paths) { struct combine_diff_path *tmp = paths; paths = paths->next; + for (i = 0; i < num_parent; i++) + if (rev->combined_all_paths && + filename_changed(tmp->parent[i].status)) + strbuf_release(&tmp->parent[i].path); free(tmp); } diff --combined diff.h index d9ad73f0e1,90ea0256a5..3199ba31f8 --- a/diff.h +++ b/diff.h @@@ -9,17 -9,16 +9,17 @@@ #include "object.h" #include "oidset.h" -struct rev_info; +struct combine_diff_path; +struct commit; +struct diff_filespec; struct diff_options; struct diff_queue_struct; -struct strbuf; -struct diff_filespec; -struct userdiff_driver; struct oid_array; -struct commit; -struct combine_diff_path; +struct option; struct repository; +struct rev_info; +struct strbuf; +struct userdiff_driver; typedef int (*pathchange_fn_t)(struct diff_options *options, struct combine_diff_path *path); @@@ -65,39 -64,39 +65,39 @@@ typedef struct strbuf *(*diff_prefix_fn #define DIFF_FLAGS_INIT { 0 } struct diff_flags { - unsigned recursive:1; - unsigned tree_in_recursive:1; - unsigned binary:1; - unsigned text:1; - unsigned full_index:1; - unsigned silent_on_remove:1; - unsigned find_copies_harder:1; - unsigned follow_renames:1; - unsigned rename_empty:1; - unsigned has_changes:1; - unsigned quick:1; - unsigned no_index:1; - unsigned allow_external:1; - unsigned exit_with_status:1; - unsigned reverse_diff:1; - unsigned check_failed:1; - unsigned relative_name:1; - unsigned ignore_submodules:1; - unsigned dirstat_cumulative:1; - unsigned dirstat_by_file:1; - unsigned allow_textconv:1; - unsigned textconv_set_via_cmdline:1; - unsigned diff_from_contents:1; - unsigned dirty_submodules:1; - unsigned ignore_untracked_in_submodules:1; - unsigned ignore_dirty_submodules:1; - unsigned override_submodule_config:1; - unsigned dirstat_by_line:1; - unsigned funccontext:1; - unsigned default_follow_renames:1; - unsigned stat_with_summary:1; - unsigned suppress_diff_headers:1; - unsigned dual_color_diffed_diffs:1; + unsigned recursive; + unsigned tree_in_recursive; + unsigned binary; + unsigned text; + unsigned full_index; + unsigned silent_on_remove; + unsigned find_copies_harder; + unsigned follow_renames; + unsigned rename_empty; + unsigned has_changes; + unsigned quick; + unsigned no_index; + unsigned allow_external; + unsigned exit_with_status; + unsigned reverse_diff; + unsigned check_failed; + unsigned relative_name; + unsigned ignore_submodules; + unsigned dirstat_cumulative; + unsigned dirstat_by_file; + unsigned allow_textconv; + unsigned textconv_set_via_cmdline; + unsigned diff_from_contents; + unsigned dirty_submodules; + unsigned ignore_untracked_in_submodules; + unsigned ignore_dirty_submodules; + unsigned override_submodule_config; + unsigned dirstat_by_line; + unsigned funccontext; + unsigned default_follow_renames; + unsigned stat_with_summary; + unsigned suppress_diff_headers; + unsigned dual_color_diffed_diffs; }; static inline void diff_flags_or(struct diff_flags *a, @@@ -230,7 -229,6 +230,7 @@@ struct diff_options unsigned color_moved_ws_handling; struct repository *repo; + struct option *parseopts; }; void diff_emit_submodule_del(struct diff_options *o, const char *line); @@@ -296,6 -294,7 +296,7 @@@ struct combine_diff_path char status; unsigned int mode; struct object_id oid; + struct strbuf path; } parent[FLEX_ARRAY]; }; #define combine_diff_path_size(n, l) \ diff --combined revision.c index 162d511d46,384fa69aed..eb8e51bc63 --- a/revision.c +++ b/revision.c @@@ -27,7 -27,6 +27,7 @@@ #include "commit-reach.h" #include "commit-graph.h" #include "prio-queue.h" +#include "hashmap.h" volatile show_early_output_fn_t show_early_output; @@@ -100,148 -99,6 +100,148 @@@ void mark_tree_uninteresting(struct rep mark_tree_contents_uninteresting(r, tree); } +struct path_and_oids_entry { + struct hashmap_entry ent; + char *path; + struct oidset trees; +}; + +static int path_and_oids_cmp(const void *hashmap_cmp_fn_data, + const struct path_and_oids_entry *e1, + const struct path_and_oids_entry *e2, + const void *keydata) +{ + return strcmp(e1->path, e2->path); +} + +static void paths_and_oids_init(struct hashmap *map) +{ + hashmap_init(map, (hashmap_cmp_fn) path_and_oids_cmp, NULL, 0); +} + +static void paths_and_oids_clear(struct hashmap *map) +{ + struct hashmap_iter iter; + struct path_and_oids_entry *entry; + hashmap_iter_init(map, &iter); + + while ((entry = (struct path_and_oids_entry *)hashmap_iter_next(&iter))) { + oidset_clear(&entry->trees); + free(entry->path); + } + + hashmap_free(map, 1); +} + +static void paths_and_oids_insert(struct hashmap *map, + const char *path, + const struct object_id *oid) +{ + int hash = strhash(path); + struct path_and_oids_entry key; + struct path_and_oids_entry *entry; + + hashmap_entry_init(&key, hash); + + /* use a shallow copy for the lookup */ + key.path = (char *)path; + oidset_init(&key.trees, 0); + + if (!(entry = (struct path_and_oids_entry *)hashmap_get(map, &key, NULL))) { + entry = xcalloc(1, sizeof(struct path_and_oids_entry)); + hashmap_entry_init(entry, hash); + entry->path = xstrdup(key.path); + oidset_init(&entry->trees, 16); + hashmap_put(map, entry); + } + + oidset_insert(&entry->trees, oid); +} + +static void add_children_by_path(struct repository *r, + struct tree *tree, + struct hashmap *map) +{ + struct tree_desc desc; + struct name_entry entry; + + if (!tree) + return; + + if (parse_tree_gently(tree, 1) < 0) + return; + + init_tree_desc(&desc, tree->buffer, tree->size); + while (tree_entry(&desc, &entry)) { + switch (object_type(entry.mode)) { + case OBJ_TREE: + paths_and_oids_insert(map, entry.path, &entry.oid); + + if (tree->object.flags & UNINTERESTING) { + struct tree *child = lookup_tree(r, &entry.oid); + if (child) + child->object.flags |= UNINTERESTING; + } + break; + case OBJ_BLOB: + if (tree->object.flags & UNINTERESTING) { + struct blob *child = lookup_blob(r, &entry.oid); + if (child) + child->object.flags |= UNINTERESTING; + } + break; + default: + /* Subproject commit - not in this repository */ + break; + } + } + + free_tree_buffer(tree); +} + +void mark_trees_uninteresting_sparse(struct repository *r, + struct oidset *trees) +{ + unsigned has_interesting = 0, has_uninteresting = 0; + struct hashmap map; + struct hashmap_iter map_iter; + struct path_and_oids_entry *entry; + struct object_id *oid; + struct oidset_iter iter; + + oidset_iter_init(trees, &iter); + while ((!has_interesting || !has_uninteresting) && + (oid = oidset_iter_next(&iter))) { + struct tree *tree = lookup_tree(r, oid); + + if (!tree) + continue; + + if (tree->object.flags & UNINTERESTING) + has_uninteresting = 1; + else + has_interesting = 1; + } + + /* Do not walk unless we have both types of trees. */ + if (!has_uninteresting || !has_interesting) + return; + + paths_and_oids_init(&map); + + oidset_iter_init(trees, &iter); + while ((oid = oidset_iter_next(&iter))) { + struct tree *tree = lookup_tree(r, oid); + add_children_by_path(r, tree, &map); + } + + hashmap_iter_init(&map, &map_iter); + while ((entry = hashmap_iter_next(&map_iter))) + mark_trees_uninteresting_sparse(r, &entry->trees); + + paths_and_oids_clear(&map); +} + struct commit_stack { struct commit **items; size_t nr, alloc; @@@ -356,20 -213,7 +356,20 @@@ static struct object *get_reference(str { struct object *object; - object = parse_object(revs->repo, oid); + /* + * If the repository has commit graphs, repo_parse_commit() avoids + * reading the object buffer, so use it whenever possible. + */ + if (oid_object_info(revs->repo, oid, NULL) == OBJ_COMMIT) { + struct commit *c = lookup_commit(revs->repo, oid); + if (!repo_parse_commit(revs->repo, c)) + object = (struct object *) c; + else + object = NULL; + } else { + object = parse_object(revs->repo, oid); + } + if (!object) { if (revs->ignore_missing) return object; @@@ -1540,7 -1384,7 +1540,7 @@@ void add_index_objects_to_pending(struc { struct worktree **worktrees, **p; - read_index(revs->repo->index); + repo_read_index(revs->repo); do_add_index_objects_to_pending(revs, revs->repo->index, flags); if (revs->single_worktree) @@@ -1687,7 -1531,7 +1687,7 @@@ static void prepare_show_merge(struct r head->object.flags |= SYMMETRIC_LEFT; if (!istate->cache_nr) - read_index(istate); + repo_read_index(revs->repo); for (i = 0; i < istate->cache_nr; i++) { const struct cache_entry *ce = istate->cache[i]; if (!ce_stage(ce)) @@@ -1746,8 -1590,8 +1746,8 @@@ static int handle_dotdot_1(const char * if (!*b_name) b_name = "HEAD"; - if (get_oid_with_context(a_name, oc_flags, &a_oid, a_oc) || - get_oid_with_context(b_name, oc_flags, &b_oid, b_oc)) + if (get_oid_with_context(revs->repo, a_name, oc_flags, &a_oid, a_oc) || + get_oid_with_context(revs->repo, b_name, oc_flags, &b_oid, b_oc)) return -1; if (!cant_be_filename) { @@@ -1881,7 -1725,7 +1881,7 @@@ int handle_revision_arg(const char *arg if (revarg_opt & REVARG_COMMITTISH) get_sha1_flags |= GET_OID_COMMITTISH; - if (get_oid_with_context(arg, get_sha1_flags, &oid, &oc)) + if (get_oid_with_context(revs->repo, arg, get_sha1_flags, &oid, &oc)) return revs->ignore_missing ? 0 : -1; if (!cant_be_filename) verify_non_filename(revs->prefix, arg); @@@ -2151,6 -1995,9 +2151,9 @@@ static int handle_revision_opt(struct r revs->diff = 1; revs->dense_combined_merges = 0; revs->combine_merges = 1; + } else if (!strcmp(arg, "--combined-all-paths")) { + revs->diff = 1; + revs->combined_all_paths = 1; } else if (!strcmp(arg, "--cc")) { revs->diff = 1; revs->dense_combined_merges = 1; @@@ -2614,7 -2461,7 +2617,7 @@@ int setup_revisions(int argc, const cha struct object_id oid; struct object *object; struct object_context oc; - if (get_oid_with_context(revs->def, 0, &oid, &oc)) + if (get_oid_with_context(revs->repo, revs->def, 0, &oid, &oc)) diagnose_missing_default(revs->def); object = get_reference(revs, revs->def, &oid, 0); add_pending_object_with_mode(revs, object, revs->def, oc.mode); @@@ -2647,6 -2494,9 +2650,9 @@@ } if (revs->combine_merges) revs->ignore_merges = 0; + if (revs->combined_all_paths && !revs->combine_merges) + die("--combined-all-paths makes no sense without -c or --cc"); + revs->diffopt.abbrev = revs->abbrev; if (revs->line_level_traverse) { diff --combined revision.h index d32d62abc6,253c12c29a..4134dc6029 --- a/revision.h +++ b/revision.h @@@ -67,7 -67,6 +67,7 @@@ struct rev_cmdline_info #define REVISION_WALK_NO_WALK_SORTED 1 #define REVISION_WALK_NO_WALK_UNSORTED 2 +struct oidset; struct topo_walk_info; struct rev_info { @@@ -172,6 -171,7 +172,7 @@@ verbose_header:1, ignore_merges:1, combine_merges:1, + combined_all_paths:1, dense_combined_merges:1, always_show_header:1; @@@ -328,7 -328,6 +329,7 @@@ void put_revision_mark(const struct rev void mark_parents_uninteresting(struct commit *commit); void mark_tree_uninteresting(struct repository *r, struct tree *tree); +void mark_trees_uninteresting_sparse(struct repository *r, struct oidset *trees); void show_object_with_name(FILE *, struct object *, const char *);