зеркало из https://github.com/microsoft/git.git
revision: do not peel tags used in range notation
A range notation "A..B" means exactly the same thing as what "^A B"
means, i.e. the set of commits that are reachable from B but not
from A. But the internal representation after the revision parser
parsed these two notations are subtly different.
- "rev-list ^A B" leaves A and B in the revs->pending.objects[]
array, with the former marked as UNINTERESTING and the revision
traversal machinery propagates the mark to underlying commit
objects A^0 and B^0.
- "rev-list A..B" peels tags and leaves A^0 (marked as
UNINTERESTING) and B^0 in revs->pending.objects[] array before
the traversal machinery kicks in.
This difference usually does not matter, but starts to matter when
the --objects option is used. For example, we see this:
$ git rev-list --objects v1.8.4^1..v1.8.4 | grep $(git rev-parse v1.8.4)
$ git rev-list --objects v1.8.4 ^v1.8.4^1 | grep $(git rev-parse v1.8.4)
04f013dc38
v1.8.4
With the former invocation, the revision traversal machinery never
hears about the tag v1.8.4 (it only sees the result of peeling it,
i.e. the commit v1.8.4^0), and the tag itself does not appear in the
output. The latter does send the tag object itself to the output.
Make the range notation keep the unpeeled objects and feed them to
the traversal machinery to fix this inconsistency.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
15999998fb
Коммит
895c5ba3c1
59
revision.c
59
revision.c
|
@ -1157,41 +1157,56 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
|
|||
}
|
||||
if (!get_sha1_committish(this, from_sha1) &&
|
||||
!get_sha1_committish(next, sha1)) {
|
||||
struct commit *a, *b;
|
||||
struct commit_list *exclude;
|
||||
|
||||
a = lookup_commit_reference(from_sha1);
|
||||
b = lookup_commit_reference(sha1);
|
||||
if (!a || !b) {
|
||||
if (revs->ignore_missing)
|
||||
return 0;
|
||||
die(symmetric ?
|
||||
"Invalid symmetric difference expression %s...%s" :
|
||||
"Invalid revision range %s..%s",
|
||||
arg, next);
|
||||
}
|
||||
struct object *a_obj, *b_obj;
|
||||
|
||||
if (!cant_be_filename) {
|
||||
*dotdot = '.';
|
||||
verify_non_filename(revs->prefix, arg);
|
||||
}
|
||||
|
||||
if (symmetric) {
|
||||
a_obj = parse_object(from_sha1);
|
||||
b_obj = parse_object(sha1);
|
||||
if (!a_obj || !b_obj) {
|
||||
missing:
|
||||
if (revs->ignore_missing)
|
||||
return 0;
|
||||
die(symmetric
|
||||
? "Invalid symmetric difference expression %s"
|
||||
: "Invalid revision range %s", arg);
|
||||
}
|
||||
|
||||
if (!symmetric) {
|
||||
/* just A..B */
|
||||
a_flags = flags_exclude;
|
||||
} else {
|
||||
/* A...B -- find merge bases between the two */
|
||||
struct commit *a, *b;
|
||||
struct commit_list *exclude;
|
||||
|
||||
a = (a_obj->type == OBJ_COMMIT
|
||||
? (struct commit *)a_obj
|
||||
: lookup_commit_reference(a_obj->sha1));
|
||||
b = (b_obj->type == OBJ_COMMIT
|
||||
? (struct commit *)b_obj
|
||||
: lookup_commit_reference(b_obj->sha1));
|
||||
if (!a || !b)
|
||||
goto missing;
|
||||
exclude = get_merge_bases(a, b, 1);
|
||||
add_pending_commit_list(revs, exclude,
|
||||
flags_exclude);
|
||||
free_commit_list(exclude);
|
||||
|
||||
a_flags = flags | SYMMETRIC_LEFT;
|
||||
} else
|
||||
a_flags = flags_exclude;
|
||||
a->object.flags |= a_flags;
|
||||
b->object.flags |= flags;
|
||||
add_rev_cmdline(revs, &a->object, this,
|
||||
}
|
||||
|
||||
a_obj->flags |= a_flags;
|
||||
b_obj->flags |= flags;
|
||||
add_rev_cmdline(revs, a_obj, this,
|
||||
REV_CMD_LEFT, a_flags);
|
||||
add_rev_cmdline(revs, &b->object, next,
|
||||
add_rev_cmdline(revs, b_obj, next,
|
||||
REV_CMD_RIGHT, flags);
|
||||
add_pending_object(revs, &a->object, this);
|
||||
add_pending_object(revs, &b->object, next);
|
||||
add_pending_object(revs, a_obj, this);
|
||||
add_pending_object(revs, b_obj, next);
|
||||
return 0;
|
||||
}
|
||||
*dotdot = '.';
|
||||
|
|
|
@ -48,4 +48,12 @@ test_expect_success 'rev-list --objects with pathspecs and copied files' '
|
|||
! grep one output
|
||||
'
|
||||
|
||||
test_expect_success 'rev-list A..B and rev-list ^A B are the same' '
|
||||
git commit --allow-empty -m another &&
|
||||
git tag -a -m "annotated" v1.0 &&
|
||||
git rev-list --objects ^v1.0^ v1.0 >expect &&
|
||||
git rev-list --objects v1.0^..v1.0 >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
Загрузка…
Ссылка в новой задаче