Re: [PATCH v3 09/10] builtin/diff-tree: learn --merge-base
- From
Junio C Hamano <gitster@pobox.com>
- Date
- Sep 21, 2020, 21:09 UTC
- Message-ID
- <xmqqwo0met17.fsf@gitster.c.googlers.com>
- In-Reply-To
- <20200921172740.GA946178@generichostname>
Denton Liu <liu.denton@gmail.com> writes:
Show 14 quoted lines
> @@ -165,7 +175,12 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
> case 2:
> tree1 = opt->pending.objects[0].item;
> tree2 = opt->pending.objects[1].item;
> - if (tree2->flags & UNINTERESTING) {
> + if (merge_base) {
> + struct object_id oid;
> +
> + diff_get_merge_base(opt, &oid);
> + tree1 = lookup_object(the_repository, &oid);
> + } else if (tree2->flags & UNINTERESTING) {
> SWAP(tree2, tree1);
> }
> diff_tree_oid(&tree1->oid, &tree2->oid, "", &opt->diffopt);OK. Handling this in that "case 2" does make sense.
However.
The above code as-is will allow something like
git diff --merge-base A..B
and it will be taken the same as
git diff --merge-base A B
But let's step back and think why we bother with SWAP() in the normal case. This is due to the possibility that A..B, which currently is left in the pending.objects[] array as ^A B, might someday be stored as B ^A. If we leave that code to protect us from the possibility, shouldn't we be protecting us from the same "someday" for the new code, too?
That is "git diff --merge-base A..B", when the control reaches this part of the code, may have tree1=B tree2=^A
Which suggests that a consistently written code would look like so:
tree1 = opt->pending.objects[0].item; tree2 = opt->pending.objects[1].item;
if (tree2->flags & UNINTERESTING)
/*
* A..B currently becomes ^A B but it is perfectly
* ok for revision parser to leave us B ^A; detect
* and swap them in the original order.
*/
SWAP(tree2, tree1); if (merge_base) {
struct object_id oid;diff_get_merge_base(opt, &oid); tree1 = lookup_object(the_repository, &oid); } diff_tree_oid(&tree1->oid, &tree2->oid, "", &opt->diffopt); log_tree_diff_flush(opt);
Another possibility is to error out when "--merge-base A..B" is given, which might be simpler. Then the code would look more like
tree1 = ... tree2 = ...
if (merge_base) {
if ((tree1->flags | tree2->flags) & UNINTERESTING)
die(_("use of --merge-base with A..B forbidden"));
... get merge base and assign it to tree1 ...
} else if (tree2->flags & UNINTERESTING) {
SWAP();
}While we are at it, what happens when "--merge-base A...B" is given?
In the original code without "--merge-base", "git diff-tree A...B" places the merge base between A and B in pending.objects[0] and B in pending.objects[1], I think. "git diff-tree --merge-base A...B" would further compute the merge base between these two objects, but luckily $(git merge-base $(merge-base A B) B) is the same as $(git merge-base A B), so you won't get an incorrect answer from such a request. Is this something we want to diagnose as an error? I am inclined to say we should allow it (and if it hurts the user can stop doing so) as there is no harm done.
Thanks.