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
This commit is contained in:
commit
c425d361f5
@ -95,12 +95,26 @@ from the format described above in the following way:
|
||||
. there are more "src" modes and "src" sha1
|
||||
. status is concatenated status characters for each parent
|
||||
. no optional "score" number
|
||||
. single path, only for "dst"
|
||||
. tab-separated pathname(s) of the file
|
||||
|
||||
Example:
|
||||
For `-c` and `--cc`, only the destination or final path is shown even
|
||||
if the file was renamed on any side of history. With
|
||||
`--combined-all-paths`, the name of the path in each parent is shown
|
||||
followed by the name of the path in the merge commit.
|
||||
|
||||
Examples for `-c` and `--cc` without `--combined-all-paths`:
|
||||
------------------------------------------------
|
||||
::100644 100644 100644 fabadb8 cc95eb0 4866510 MM desc.c
|
||||
::100755 100755 100755 52b7a2d 6d1ac04 d2ac7d7 RM bar.sh
|
||||
::100644 100644 100644 e07d6c5 9042e82 ee91881 RR phooey.c
|
||||
------------------------------------------------
|
||||
|
||||
Examples when `--combined-all-paths` added to either `-c` or `--cc`:
|
||||
|
||||
------------------------------------------------
|
||||
::100644 100644 100644 fabadb8 cc95eb0 4866510 MM describe.c
|
||||
::100644 100644 100644 fabadb8 cc95eb0 4866510 MM desc.c desc.c desc.c
|
||||
::100755 100755 100755 52b7a2d 6d1ac04 d2ac7d7 RM foo.sh bar.sh bar.sh
|
||||
::100644 100644 100644 e07d6c5 9042e82 ee91881 RR fooey.c fuey.c phooey.c
|
||||
------------------------------------------------
|
||||
|
||||
Note that 'combined diff' lists only files which were modified from
|
||||
|
@ -143,6 +143,19 @@ copying detection) are designed to work with diff of two
|
||||
Similar to two-line header for traditional 'unified' diff
|
||||
format, `/dev/null` is used to signal created or deleted
|
||||
files.
|
||||
+
|
||||
However, if the --combined-all-paths option is provided, instead of a
|
||||
two-line from-file/to-file you get a N+1 line from-file/to-file header,
|
||||
where N is the number of parents in the merge commit
|
||||
|
||||
--- a/file
|
||||
--- a/file
|
||||
--- a/file
|
||||
+++ b/file
|
||||
+
|
||||
This extended format can be useful if rename or copy detection is
|
||||
active, to allow you to see the original name of the file in different
|
||||
parents.
|
||||
|
||||
4. Chunk header format is modified to prevent people from
|
||||
accidentally feeding it to `patch -p1`. Combined diff format
|
||||
|
@ -10,8 +10,8 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git diff-tree' [--stdin] [-m] [-s] [-v] [--no-commit-id] [--pretty]
|
||||
[-t] [-r] [-c | --cc] [--root] [<common diff options>]
|
||||
<tree-ish> [<tree-ish>] [<path>...]
|
||||
[-t] [-r] [-c | --cc] [--combined-all-paths] [--root]
|
||||
[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -105,6 +105,13 @@ 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.
|
||||
|
@ -960,6 +960,13 @@ options may be given. See linkgit:git-diff-files[1] for more options.
|
||||
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
|
||||
|
@ -83,9 +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] "
|
||||
"[<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]\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;
|
||||
|
||||
|
@ -23,11 +23,20 @@ static int compare_paths(const struct combine_diff_path *one,
|
||||
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 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
|
||||
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 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
|
||||
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 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
|
||||
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 @@ static void show_combined_header(struct combine_diff_path *elem,
|
||||
if (!show_file_header)
|
||||
return;
|
||||
|
||||
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 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1332,7 +1378,9 @@ static const char *path_path(void *obj)
|
||||
|
||||
/* 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;
|
||||
@ -1357,7 +1405,8 @@ static struct combine_diff_path *find_paths_generic(const struct object_id *oid,
|
||||
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 +1516,8 @@ void diff_tree_combined(const struct object_id *oid,
|
||||
* 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;
|
||||
@ -1540,6 +1590,10 @@ void diff_tree_combined(const struct object_id *oid,
|
||||
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);
|
||||
}
|
||||
|
||||
|
1
diff.h
1
diff.h
@ -296,6 +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) \
|
||||
|
@ -2151,6 +2151,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
|
||||
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;
|
||||
@ -2647,6 +2650,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
|
||||
}
|
||||
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) {
|
||||
|
@ -172,6 +172,7 @@ struct rev_info {
|
||||
verbose_header:1,
|
||||
ignore_merges:1,
|
||||
combine_merges:1,
|
||||
combined_all_paths:1,
|
||||
dense_combined_merges:1,
|
||||
always_show_header:1;
|
||||
|
||||
|
@ -435,4 +435,92 @@ test_expect_success 'combine diff gets tree sorting right' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'setup for --combined-all-paths' '
|
||||
git branch side1c &&
|
||||
git branch side2c &&
|
||||
git checkout side1c &&
|
||||
test_seq 1 10 >filename-side1c &&
|
||||
git add filename-side1c &&
|
||||
git commit -m with &&
|
||||
git checkout side2c &&
|
||||
test_seq 1 9 >filename-side2c &&
|
||||
echo ten >>filename-side2c &&
|
||||
git add filename-side2c &&
|
||||
git commit -m iam &&
|
||||
git checkout -b mergery side1c &&
|
||||
git merge --no-commit side2c &&
|
||||
git rm filename-side1c &&
|
||||
echo eleven >>filename-side2c &&
|
||||
git mv filename-side2c filename-merged &&
|
||||
git add filename-merged &&
|
||||
git commit
|
||||
'
|
||||
|
||||
test_expect_success '--combined-all-paths and --raw' '
|
||||
cat <<-\EOF >expect &&
|
||||
::100644 100644 100644 f00c965d8307308469e537302baa73048488f162 088bd5d92c2a8e0203ca8e7e4c2a5c692f6ae3f7 333b9c62519f285e1854830ade0fe1ef1d40ee1b RR filename-side1c filename-side2c filename-merged
|
||||
EOF
|
||||
git diff-tree -c -M --raw --combined-all-paths HEAD >actual.tmp &&
|
||||
sed 1d <actual.tmp >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '--combined-all-paths and --cc' '
|
||||
cat <<-\EOF >expect &&
|
||||
--- a/filename-side1c
|
||||
--- a/filename-side2c
|
||||
+++ b/filename-merged
|
||||
EOF
|
||||
git diff-tree --cc -M --combined-all-paths HEAD >actual.tmp &&
|
||||
grep ^[-+][-+][-+] <actual.tmp >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success FUNNYNAMES 'setup for --combined-all-paths with funny names' '
|
||||
git branch side1d &&
|
||||
git branch side2d &&
|
||||
git checkout side1d &&
|
||||
test_seq 1 10 >$(printf "file\twith\ttabs") &&
|
||||
git add file* &&
|
||||
git commit -m with &&
|
||||
git checkout side2d &&
|
||||
test_seq 1 9 >$(printf "i\tam\ttabbed") &&
|
||||
echo ten >>$(printf "i\tam\ttabbed") &&
|
||||
git add *tabbed &&
|
||||
git commit -m iam &&
|
||||
git checkout -b funny-names-mergery side1d &&
|
||||
git merge --no-commit side2d &&
|
||||
git rm *tabs &&
|
||||
echo eleven >>$(printf "i\tam\ttabbed") &&
|
||||
git mv "$(printf "i\tam\ttabbed")" "$(printf "fickle\tnaming")" &&
|
||||
git add fickle* &&
|
||||
git commit
|
||||
'
|
||||
|
||||
test_expect_success FUNNYNAMES '--combined-all-paths and --raw and funny names' '
|
||||
cat <<-\EOF >expect &&
|
||||
::100644 100644 100644 f00c965d8307308469e537302baa73048488f162 088bd5d92c2a8e0203ca8e7e4c2a5c692f6ae3f7 333b9c62519f285e1854830ade0fe1ef1d40ee1b RR "file\twith\ttabs" "i\tam\ttabbed" "fickle\tnaming"
|
||||
EOF
|
||||
git diff-tree -c -M --raw --combined-all-paths HEAD >actual.tmp &&
|
||||
sed 1d <actual.tmp >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success FUNNYNAMES '--combined-all-paths and --raw -and -z and funny names' '
|
||||
printf "aaf8087c3cbd4db8e185a2d074cf27c53cfb75d7\0::100644 100644 100644 f00c965d8307308469e537302baa73048488f162 088bd5d92c2a8e0203ca8e7e4c2a5c692f6ae3f7 333b9c62519f285e1854830ade0fe1ef1d40ee1b RR\0file\twith\ttabs\0i\tam\ttabbed\0fickle\tnaming\0" >expect &&
|
||||
git diff-tree -c -M --raw --combined-all-paths -z HEAD >actual &&
|
||||
test_cmp -a expect actual
|
||||
'
|
||||
|
||||
test_expect_success FUNNYNAMES '--combined-all-paths and --cc and funny names' '
|
||||
cat <<-\EOF >expect &&
|
||||
--- "a/file\twith\ttabs"
|
||||
--- "a/i\tam\ttabbed"
|
||||
+++ "b/fickle\tnaming"
|
||||
EOF
|
||||
git diff-tree --cc -M --combined-all-paths HEAD >actual.tmp &&
|
||||
grep ^[-+][-+][-+] <actual.tmp >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user