Skip to content

Commit b988427

Browse files
committed
Merge branch 'rs/diff-caret-bang-with-parents'
"git diff rev^!" did not show combined diff to go to the rev from its parents. * rs/diff-caret-bang-with-parents: diff: support ^! for merges revisions.txt: unspecify order of resolved parts of ^! revision: use strtol_i() for exclude_parent
2 parents 1fc3c0a + a79c6b6 commit b988427

File tree

5 files changed

+35
-13
lines changed

5 files changed

+35
-13
lines changed

Documentation/git-diff.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ If --merge-base is given, use the merge base of the two commits for the
7979

8080
This form is to view the results of a merge commit. The first
8181
listed <commit> must be the merge itself; the remaining two or
82-
more commits should be its parents. A convenient way to produce
83-
the desired set of revisions is to use the `^@` suffix.
84-
For instance, if `master` names a merge commit, `git diff master
85-
master^@` gives the same combined diff as `git show master`.
82+
more commits should be its parents. Convenient ways to produce
83+
the desired set of revisions are to use the suffixes `^@` and
84+
`^!`. If A is a merge commit, then `git diff A A^@`,
85+
`git diff A^!` and `git show A` all give the same combined diff.
8686

8787
'git diff' [<options>] <commit>..<commit> [--] [<path>...]::
8888

Documentation/revisions.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ Revision Range Summary
363363

364364
'<rev>{caret}!', e.g. 'HEAD{caret}!'::
365365
A suffix '{caret}' followed by an exclamation mark is the same
366-
as giving commit '<rev>' and then all its parents prefixed with
366+
as giving commit '<rev>' and all its parents prefixed with
367367
'{caret}' to exclude them (and their ancestors).
368368

369369
'<rev>{caret}-<n>', e.g. 'HEAD{caret}-, HEAD{caret}-2'::

builtin/diff.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,19 +209,26 @@ static int builtin_diff_tree(struct rev_info *revs,
209209
static int builtin_diff_combined(struct rev_info *revs,
210210
int argc, const char **argv,
211211
struct object_array_entry *ent,
212-
int ents)
212+
int ents, int first_non_parent)
213213
{
214214
struct oid_array parents = OID_ARRAY_INIT;
215215
int i;
216216

217217
if (argc > 1)
218218
usage(builtin_diff_usage);
219219

220+
if (first_non_parent < 0)
221+
die(_("no merge given, only parents."));
222+
if (first_non_parent >= ents)
223+
BUG("first_non_parent out of range: %d", first_non_parent);
224+
220225
diff_merges_set_dense_combined_if_unset(revs);
221226

222-
for (i = 1; i < ents; i++)
223-
oid_array_append(&parents, &ent[i].item->oid);
224-
diff_tree_combined(&ent[0].item->oid, &parents, revs);
227+
for (i = 0; i < ents; i++) {
228+
if (i != first_non_parent)
229+
oid_array_append(&parents, &ent[i].item->oid);
230+
}
231+
diff_tree_combined(&ent[first_non_parent].item->oid, &parents, revs);
225232
oid_array_clear(&parents);
226233
return 0;
227234
}
@@ -385,6 +392,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
385392
int i;
386393
struct rev_info rev;
387394
struct object_array ent = OBJECT_ARRAY_INIT;
395+
int first_non_parent = -1;
388396
int blobs = 0, paths = 0;
389397
struct object_array_entry *blob[2];
390398
int nongit = 0, no_index = 0;
@@ -543,6 +551,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
543551
continue;
544552
obj->flags |= flags;
545553
add_object_array(obj, name, &ent);
554+
if (first_non_parent < 0 &&
555+
(i >= rev.cmdline.nr || /* HEAD by hand. */
556+
rev.cmdline.rev[i].whence != REV_CMD_PARENTS_ONLY))
557+
first_non_parent = ent.nr - 1;
546558
} else if (obj->type == OBJ_BLOB) {
547559
if (2 <= blobs)
548560
die(_("more than two blobs given: '%s'"), name);
@@ -590,7 +602,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
590602
&ent.objects[0], &ent.objects[1]);
591603
} else
592604
result = builtin_diff_combined(&rev, argc, argv,
593-
ent.objects, ent.nr);
605+
ent.objects, ent.nr,
606+
first_non_parent);
594607
result = diff_result_code(&rev.diffopt, result);
595608
if (1 < rev.diffopt.skip_stat_unmatch)
596609
refresh_index_quietly();

revision.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2113,9 +2113,8 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
21132113
int exclude_parent = 1;
21142114

21152115
if (mark[2]) {
2116-
char *end;
2117-
exclude_parent = strtoul(mark + 2, &end, 10);
2118-
if (*end != '\0' || !exclude_parent)
2116+
if (strtol_i(mark + 2, 10, &exclude_parent) ||
2117+
exclude_parent < 1)
21192118
return -1;
21202119
}
21212120

t/t4038-diff-combined.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,21 @@ test_expect_success 'check combined output (1)' '
8080
verify_helper sidewithone
8181
'
8282

83+
test_expect_success 'check combined output (1) with git diff <rev>^!' '
84+
git diff sidewithone^! -- >sidewithone &&
85+
verify_helper sidewithone
86+
'
87+
8388
test_expect_success 'check combined output (2)' '
8489
git show sidesansone -- >sidesansone &&
8590
verify_helper sidesansone
8691
'
8792

93+
test_expect_success 'check combined output (2) with git diff <rev>^!' '
94+
git diff sidesansone^! -- >sidesansone &&
95+
verify_helper sidesansone
96+
'
97+
8898
test_expect_success 'diagnose truncated file' '
8999
>file &&
90100
git add file &&

0 commit comments

Comments
 (0)