git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* git diff ^! syntax stopped working for stashes in Git 2.28
@ 2022-09-12  9:57 Tim Jaacks
  2022-09-12 11:16 ` René Scharfe
  0 siblings, 1 reply; 6+ messages in thread
From: Tim Jaacks @ 2022-09-12  9:57 UTC (permalink / raw)
  To: git@vger.kernel.org

Hello,

I noticed that the following syntax to show the changes of a stash stopped working in Git 2.28:

  git diff stash@{0}^!

It still works on commits and HEAD, though:

  git diff f27984d^!
  git diff HEAD^!

And diffing against the stash's parent works as well:

  git diff stash@{0}^1 stash@{0}

I assume this is a bug. Can anybody confirm this? I verified the behavior change trying different Git versions via docker:

  docker run -it --rm --user $(id -u):$(id -g) -v $HOME:$HOME:rw -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro -v $PWD:$PWD:rw -w $PWD bitnami/git:2.27.0 diff stash@{0}^!

With v2.27.0 the above syntax works, with v2.28.0 and later it doesn't.

Kind regards,
Tim

-- 
Tim Jaacks
SOFTWARE DEVELOPER
SECO Northern Europe GmbH

Schlachthofstrasse 20
21079 Hamburg
Germany
T: +49 40 791899-183
E: tim.jaacks@seco.com

Register: Amtsgericht Hamburg, HRB 148893
Represented by: Dirk Finstel, Marc-Michael Braun, Massimo Mauri


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: git diff ^! syntax stopped working for stashes in Git 2.28
  2022-09-12  9:57 git diff ^! syntax stopped working for stashes in Git 2.28 Tim Jaacks
@ 2022-09-12 11:16 ` René Scharfe
  2022-09-12 19:09   ` Chris Torek
  0 siblings, 1 reply; 6+ messages in thread
From: René Scharfe @ 2022-09-12 11:16 UTC (permalink / raw)
  To: Tim Jaacks, git@vger.kernel.org; +Cc: Chris Torek

Am 12.09.22 um 11:57 schrieb Tim Jaacks:
> Hello,
>
> I noticed that the following syntax to show the changes of a stash stopped working in Git 2.28:
>
>   git diff stash@{0}^!
>
> It still works on commits and HEAD, though:
>
>   git diff f27984d^!
>   git diff HEAD^!
>
> And diffing against the stash's parent works as well:
>
>   git diff stash@{0}^1 stash@{0}
>
> I assume this is a bug. Can anybody confirm this? I verified the behavior change trying different Git versions via docker:
>
>   docker run -it --rm --user $(id -u):$(id -g) -v $HOME:$HOME:rw -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro -v $PWD:$PWD:rw -w $PWD bitnami/git:2.27.0 diff stash@{0}^!
>
> With v2.27.0 the above syntax works, with v2.28.0 and later it doesn't.

Bisects to 8bfcb3a690 (git diff: improve range handling, 2020-06-12).

Reverting it partially like in the patch below restores the behavior of
"git diff stash@{0}^!".  Tests still pass.

A stash revision is a merge.  With "stash@{0}^!" it ends up in
ent.objects[2] and its parents (marked UNINTERESTING) in ent.objects[0]
and ent.objects[1].

I don't know if the current behavior is expected or if the patch is the
right fix, but in any case it would need a good explanation that I
cannot come up with on the spot.

Copying Chris, author of the mentioned patch.  Old discussion thread:
https://lore.kernel.org/git/pull.804.git.git.1591661021.gitgitgadget@gmail.com/

René


diff --git a/builtin/diff.c b/builtin/diff.c
index 54bb3de964..c34adf2695 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -588,6 +588,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
 				sdiff.left, sdiff.right, sdiff.base);
 		result = builtin_diff_tree(&rev, argc, argv,
 					   &ent.objects[0], &ent.objects[1]);
+	} else if (ent.objects[0].item->flags & UNINTERESTING) {
+		result = builtin_diff_tree(&rev, argc, argv,
+					   &ent.objects[0],
+					   &ent.objects[ent.nr-1]);
 	} else
 		result = builtin_diff_combined(&rev, argc, argv,
 					       ent.objects, ent.nr);


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: git diff ^! syntax stopped working for stashes in Git 2.28
  2022-09-12 11:16 ` René Scharfe
@ 2022-09-12 19:09   ` Chris Torek
  2022-09-14 15:57     ` René Scharfe
  0 siblings, 1 reply; 6+ messages in thread
From: Chris Torek @ 2022-09-12 19:09 UTC (permalink / raw)
  To: René Scharfe; +Cc: Tim Jaacks, git@vger.kernel.org

On Mon, Sep 12, 2022 at 4:16 AM René Scharfe <l.s.r@web.de> wrote:
> Am 12.09.22 um 11:57 schrieb Tim Jaacks:
>> I noticed that the following syntax to show the changes of a stash stopped working in Git 2.28:
>>
>>   git diff stash@{0}^!

> Bisects to 8bfcb3a690 (git diff: improve range handling, 2020-06-12).

It's not really clear to me what `git diff stash^!` (and similar) *should* do.
That it worked before was at least in part an accident of implementation.

> A stash revision is a merge.  With "stash@{0}^!" it ends up in
> ent.objects[2] and its parents (marked UNINTERESTING) in ent.objects[0]
> and ent.objects[1].

Right: the ^! suffix produces a negated list of the children as additional
revs (with the stash itself as the lone positive rev).  Note that a stash
made with `-u` will list *three* such revs rather than just two, since such
a stash is a three-parent merge.

You're advised (in the git stash documentation) to use `git stash show`,
not `git diff`, to get a diff from the stash's parent commit to the stash's
working-tree commit.

It's certainly possible to detect a single positive rev and two or three
negative ones as special cases here, but it's not clear that this is a
good idea.  Note that in commit bafa2d741e I made one
of the tests stop using `git diff HEAD^!` on the grounds that it's not
defined behavior.

Chris

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: git diff ^! syntax stopped working for stashes in Git 2.28
  2022-09-12 19:09   ` Chris Torek
@ 2022-09-14 15:57     ` René Scharfe
  2022-09-28  9:02       ` AW: " Tim Jaacks
  0 siblings, 1 reply; 6+ messages in thread
From: René Scharfe @ 2022-09-14 15:57 UTC (permalink / raw)
  To: Chris Torek; +Cc: Tim Jaacks, git@vger.kernel.org

Am 12.09.22 um 21:09 schrieb Chris Torek:
> On Mon, Sep 12, 2022 at 4:16 AM René Scharfe <l.s.r@web.de> wrote:
>> Am 12.09.22 um 11:57 schrieb Tim Jaacks:
>>> I noticed that the following syntax to show the changes of a stash stopped working in Git 2.28:
>>>
>>>   git diff stash@{0}^!
>
>> Bisects to 8bfcb3a690 (git diff: improve range handling, 2020-06-12).
>
> It's not really clear to me what `git diff stash^!` (and similar) *should* do.
> That it worked before was at least in part an accident of implementation.

I get the same impression.

git show stash@{0}` and `git show stash@{0}^!` both show a combined
diff, which makes sense to me.  `git diff stash@{0}^!` also results in a
call of diff_tree_combined(), but with trees  in a different order.
`git diff stash@{0} stash@{0}^1 stash@{0}^2` gives me the same combined
diff, but `git diff stash@{0}^!` gives nothing because it acts like
`git diff stash@{0}^1 stash@{0}^2 stash@{0}` instead, and both parents
have the same tree.

That's because revision.c::handle_revision_arg_1() adds the parents
before the child when handling "^!" and
builtin/diff::builtin_diff_combined() expects the child first.
Rotating the array there lets `git diff stash@{0}^!` show a combined
diff, but breaks t4013.173, t4013.174 and t4057.

Letting revision.c::handle_revision_arg_1() add the child first makes
`git diff stash@{0}^!` consistent with `git show stash@{0}^!`.  Tests
still pass.  gitrevisions(7) says <rev>^! is the "same as giving commit
<rev> and then all its parents prefixed with ^ to exclude them", so
this seems to be an actual fix.

My demo patch below feels iffy, though.  Hopefully this behavior can
be implemented in a nicer way.

>> A stash revision is a merge.  With "stash@{0}^!" it ends up in
>> ent.objects[2] and its parents (marked UNINTERESTING) in ent.objects[0]
>> and ent.objects[1].
>
> Right: the ^! suffix produces a negated list of the children as additional
> revs (with the stash itself as the lone positive rev).  Note that a stash
> made with `-u` will list *three* such revs rather than just two, since such
> a stash is a three-parent merge.
>
> You're advised (in the git stash documentation) to use `git stash show`,
> not `git diff`, to get a diff from the stash's parent commit to the stash's
> working-tree commit.

So, Tim, does `git stash show -p stash@{0}` work for you?

> It's certainly possible to detect a single positive rev and two or three
> negative ones as special cases here, but it's not clear that this is a
> good idea.  Note that in commit bafa2d741e I made one
> of the tests stop using `git diff HEAD^!` on the grounds that it's not
> defined behavior.

Letting `git diff X^!` mean the same as `git diff X ^X^` for a non-merge
makes sense to me given the definition from gitrevisions(7) cited above.
That in turn is the same as `git diff X^..X` and `git diff X^ X`.

René


---
 revision.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/revision.c b/revision.c
index c516415c48..ad4ead2c0a 100644
--- a/revision.c
+++ b/revision.c
@@ -1819,7 +1819,7 @@ static void add_alternate_refs_to_pending(struct rev_info *revs,
 }

 static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
-			    int exclude_parent)
+			    int exclude_parent, int dry_run)
 {
 	struct object_id oid;
 	struct object *it;
@@ -1850,6 +1850,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
 	if (exclude_parent &&
 	    exclude_parent > commit_list_count(commit->parents))
 		return 0;
+	if (dry_run)
+		return 1;
 	for (parents = commit->parents, parent_number = 1;
 	     parents;
 	     parents = parents->next, parent_number++) {
@@ -2083,6 +2085,7 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
 	const char *arg = arg_;
 	int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
 	unsigned get_sha1_flags = GET_OID_RECORD_PATH;
+	int add_parents = 0;

 	flags = flags & UNINTERESTING ? flags | BOTTOM : flags & ~BOTTOM;

@@ -2100,14 +2103,16 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
 	mark = strstr(arg, "^@");
 	if (mark && !mark[2]) {
 		*mark = 0;
-		if (add_parents_only(revs, arg, flags, 0))
+		if (add_parents_only(revs, arg, flags, 0, 0))
 			return 0;
 		*mark = '^';
 	}
 	mark = strstr(arg, "^!");
 	if (mark && !mark[2]) {
 		*mark = 0;
-		if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), 0))
+		if (add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), 0, 1))
+			add_parents = 1;
+		else
 			*mark = '^';
 	}
 	mark = strstr(arg, "^-");
@@ -2122,7 +2127,7 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
 		}

 		*mark = 0;
-		if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), exclude_parent))
+		if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), exclude_parent, 0))
 			*mark = '^';
 	}

@@ -2145,6 +2150,8 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
 	add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
 	add_pending_object_with_path(revs, object, arg, oc.mode, oc.path);
 	free(oc.path);
+	if (add_parents)
+		add_parents_only(revs, arg_, flags ^ (UNINTERESTING | BOTTOM), 0, 0);
 	return 0;
 }

--
2.37.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* AW: git diff ^! syntax stopped working for stashes in Git 2.28
  2022-09-14 15:57     ` René Scharfe
@ 2022-09-28  9:02       ` Tim Jaacks
  2022-09-28 17:39         ` René Scharfe
  0 siblings, 1 reply; 6+ messages in thread
From: Tim Jaacks @ 2022-09-28  9:02 UTC (permalink / raw)
  To: René Scharfe, Chris Torek; +Cc: git@vger.kernel.org

Hey Chris, hey René,

thanks a lot for your replys.

> So, Tim, does `git stash show -p stash@{0}` work for you?

Yes, that works indeed. However, in my certain use-case I would prefer using `git diff`.
 
> Letting `git diff X^!` mean the same as `git diff X ^X^` for a non-merge
> makes sense to me given the definition from gitrevisions(7) cited above.
> That in turn is the same as `git diff X^..X` and `git diff X^ X`.

Yes, that is exactly how it worked before. And all the other syntaxes still work correctly.

René, I saw you submitted some patches already, but these weren't approved obviously. So how does this continue now?

Kind regards,
Tim

-- 
Tim Jaacks
SOFTWARE DEVELOPER
SECO Northern Europe GmbH

Schlachthofstrasse 20
21079 Hamburg
Germany
T: +49  40 791899-183
E: tim.jaacks@seco.com

Registergericht:  Amtsgericht Hamburg, HRB 148893
Geschäftsführer: Stefan Heczko, Marc-Michael Braun, Massimo Mauri     


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: git diff ^! syntax stopped working for stashes in Git 2.28
  2022-09-28  9:02       ` AW: " Tim Jaacks
@ 2022-09-28 17:39         ` René Scharfe
  0 siblings, 0 replies; 6+ messages in thread
From: René Scharfe @ 2022-09-28 17:39 UTC (permalink / raw)
  To: Tim Jaacks, Chris Torek; +Cc: git@vger.kernel.org

Am 28.09.22 um 11:02 schrieb Tim Jaacks:
>
>> Letting `git diff X^!` mean the same as `git diff X ^X^` for a
>> non-merge makes sense to me given the definition from
>> gitrevisions(7) cited above. That in turn is the same as `git diff
>> X^..X` and `git diff X^ X`.
>
> Yes, that is exactly how it worked before. And all the other syntaxes
> still work correctly.

`git diff X^!` still works for a non-merge commit as well.  Only
merge commits were affected by the change made in v2.28.  And stashes
are stored as merge commits internally, causing them to be affected.

> René, I saw you submitted some patches already, but these weren't
> approved obviously. So how does this continue now?

It's RC time (release candidate) and only fixes for regressions added
after v2.37 are accepted currently.  I'll resend my patches once v2.38
is out, if necessary.

René

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-09-28 17:39 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-12  9:57 git diff ^! syntax stopped working for stashes in Git 2.28 Tim Jaacks
2022-09-12 11:16 ` René Scharfe
2022-09-12 19:09   ` Chris Torek
2022-09-14 15:57     ` René Scharfe
2022-09-28  9:02       ` AW: " Tim Jaacks
2022-09-28 17:39         ` René Scharfe

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).