git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / Atom feed
* [PATCH] git-difftool-helper.sh: learn a new way skip to save point
@ 2021-02-07 15:19 阿德烈 via GitGitGadget
  2021-02-07 18:29 ` Junio C Hamano
                   ` (2 more replies)
  0 siblings, 3 replies; 37+ messages in thread
From: 阿德烈 via GitGitGadget @ 2021-02-07 15:19 UTC (permalink / raw)
  To: git; +Cc: 阿德烈, ZheNing Hu

From: ZheNing Hu <adlternative@gmail.com>

`git difftool` only allow us to select file to view In turn.
If there is a commit with many files and we exit in search,
We will have to traverse list again to get the file diff which
we want to see.Therefore,here is a new method:every time before
we view the file diff,the current coordinates will be stored in
`GIT_DIR/difftool_skip_to`,this file will be deleted after
successful traversing.But if an unexpected exit occurred midway,
git will view the coordinates in the save point,ask user if they
want continue from the last saved point.This will improve the
user experience.

Signed-off-by: ZheNing Hu <adlternative@gmail.com>
---
    git-difftool-helper.sh: learn a new way skip to save point
    
    this patch's origin discuss is here:
    https://lore.kernel.org/git/gOXOaoqn-E9A2ob7ykWEcDc7ZxmSwAjcP5CCFKfr5ejCOWZQ1lfAUZcbgYT9AyQCcDgJvCrnrtziXiels-Hxol3xlkGTVHk24SvAdaSUtKQ=@rtzoeller.com/
    
    git user may should travel the diff list to choice file diff to view, if
    they exit in midway,they must travel it again. I’m on the basis of the
    "difftool_skip_to" suggested by Junio,Provides a possibility for this
    user-friendly solution.
    
    Thanks!

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-870%2Fadlternative%2Fdifftool_save_point-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-870/adlternative/difftool_save_point-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/870

 git-difftool--helper.sh | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
index 46af3e60b718..56ec1d38a7a1 100755
--- a/git-difftool--helper.sh
+++ b/git-difftool--helper.sh
@@ -6,6 +6,7 @@
 # Copyright (c) 2009, 2010 David Aguilar
 
 TOOL_MODE=diff
+GIT_DIFFTOOL_SKIP_TO_FILE="$GIT_DIR/difftool-skip-to"
 . git-mergetool--lib
 
 # difftool.prompt controls the default prompt/no-prompt behavior
@@ -40,6 +41,31 @@ launch_merge_tool () {
 	# the user with the real $MERGED name before launching $merge_tool.
 	if should_prompt
 	then
+		if test -f "$GIT_DIFFTOOL_SKIP_TO_FILE"
+		then
+			SAVE_POINT_NUM=$(cat "$GIT_DIFFTOOL_SKIP_TO_FILE")
+			if test $SAVE_POINT_NUM -le $GIT_DIFF_PATH_TOTAL &&
+				test $SAVE_POINT_NUM -gt $GIT_DIFF_PATH_COUNTER
+			then
+				# choice skip or not skip when check first file.
+				if test $GIT_DIFF_PATH_COUNTER -eq "1"
+				then
+					printf "do you want to skip to last time difftool save point($SAVE_POINT_NUM) [Y/n]?"
+					read skip_ans || return
+					if test "$skip_ans" = y
+					then
+						return
+					fi
+				else
+					return
+				fi
+			fi
+		fi
+		# write the current coordinates to .git/difftool-skip-to
+		if test !$SAVE_POINT_NUM || $SAVE_POINT_NUM -ne $GIT_DIFF_PATH_COUNTER
+		then
+			echo $GIT_DIFF_PATH_COUNTER > $GIT_DIFFTOOL_SKIP_TO_FILE
+		fi
 		printf "\nViewing (%s/%s): '%s'\n" "$GIT_DIFF_PATH_COUNTER" \
 			"$GIT_DIFF_PATH_TOTAL" "$MERGED"
 		if use_ext_cmd
@@ -102,4 +128,10 @@ else
 	done
 fi
 
+if test -f $GIT_DIFFTOOL_SKIP_TO_FILE &&
+	test $GIT_DIFF_PATH_COUNTER -eq $GIT_DIFF_PATH_TOTAL
+then
+	rm $GIT_DIFFTOOL_SKIP_TO_FILE
+
+fi
 exit 0

base-commit: e6362826a0409539642a5738db61827e5978e2e4
-- 
gitgitgadget

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

* Re: [PATCH] git-difftool-helper.sh: learn a new way skip to save point
  2021-02-07 15:19 [PATCH] git-difftool-helper.sh: learn a new way skip to save point 阿德烈 via GitGitGadget
@ 2021-02-07 18:29 ` Junio C Hamano
  2021-02-07 19:04 ` Junio C Hamano
  2021-02-08 17:02 ` [PATCH v2] git-difftool-helper.sh: learn a new way go back to last " ZheNing Hu via GitGitGadget
  2 siblings, 0 replies; 37+ messages in thread
From: Junio C Hamano @ 2021-02-07 18:29 UTC (permalink / raw)
  To: 阿德烈 via GitGitGadget; +Cc: git, 阿德烈

"阿德烈 via GitGitGadget"  <gitgitgadget@gmail.com> writes:

> From: ZheNing Hu <adlternative@gmail.com>

I am a bit confused.  Are 胡哲宁 and 阿德烈 and ZeNing Hu all the
same person (I am asking that an earlier question came under the
name first listed in this sentence, and the patch uses the latter
two names, where I guess )?

>
> `git difftool` only allow us to select file to view In turn.
> If there is a commit with many files and we exit in search,
> We will have to traverse list again to get the file diff which
> we want to see.Therefore,here is a new method:every time before
> we view the file diff,the current coordinates will be stored in
> `GIT_DIR/difftool_skip_to`,this file will be deleted after
> successful traversing.But if an unexpected exit occurred midway,
> git will view the coordinates in the save point,ask user if they
> want continue from the last saved point.This will improve the
> user experience.
>
> Signed-off-by: ZheNing Hu <adlternative@gmail.com>
> ---
>     git-difftool-helper.sh: learn a new way skip to save point
>     
>     this patch's origin discuss is here:
>     https://lore.kernel.org/git/gOXOaoqn-E9A2ob7ykWEcDc7ZxmSwAjcP5CCFKfr5ejCOWZQ1lfAUZcbgYT9AyQCcDgJvCrnrtziXiels-Hxol3xlkGTVHk24SvAdaSUtKQ=@rtzoeller.com/
>     
>     git user may should travel the diff list to choice file diff to view, if
>     they exit in midway,they must travel it again. I’m on the basis of the
>     "difftool_skip_to" suggested by Junio,Provides a possibility for this
>     user-friendly solution.
>     
>     Thanks!
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-870%2Fadlternative%2Fdifftool_save_point-v1
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-870/adlternative/difftool_save_point-v1
> Pull-Request: https://github.com/gitgitgadget/git/pull/870
>
>  git-difftool--helper.sh | 32 ++++++++++++++++++++++++++++++++
>  1 file changed, 32 insertions(+)
>
> diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
> index 46af3e60b718..56ec1d38a7a1 100755
> --- a/git-difftool--helper.sh
> +++ b/git-difftool--helper.sh
> @@ -6,6 +6,7 @@
>  # Copyright (c) 2009, 2010 David Aguilar
>  
>  TOOL_MODE=diff
> +GIT_DIFFTOOL_SKIP_TO_FILE="$GIT_DIR/difftool-skip-to"
>  . git-mergetool--lib
>  
>  # difftool.prompt controls the default prompt/no-prompt behavior
> @@ -40,6 +41,31 @@ launch_merge_tool () {
>  	# the user with the real $MERGED name before launching $merge_tool.
>  	if should_prompt
>  	then
> +		if test -f "$GIT_DIFFTOOL_SKIP_TO_FILE"
> +		then
> +			SAVE_POINT_NUM=$(cat "$GIT_DIFFTOOL_SKIP_TO_FILE")
> +			if test $SAVE_POINT_NUM -le $GIT_DIFF_PATH_TOTAL &&
> +				test $SAVE_POINT_NUM -gt $GIT_DIFF_PATH_COUNTER
> +			then
> +				# choice skip or not skip when check first file.
> +				if test $GIT_DIFF_PATH_COUNTER -eq "1"
> +				then
> +					printf "do you want to skip to last time difftool save point($SAVE_POINT_NUM) [Y/n]?"
> +					read skip_ans || return
> +					if test "$skip_ans" = y
> +					then
> +						return
> +					fi
> +				else
> +					return
> +				fi
> +			fi
> +		fi
> +		# write the current coordinates to .git/difftool-skip-to
> +		if test !$SAVE_POINT_NUM || $SAVE_POINT_NUM -ne $GIT_DIFF_PATH_COUNTER
> +		then
> +			echo $GIT_DIFF_PATH_COUNTER > $GIT_DIFFTOOL_SKIP_TO_FILE
> +		fi
>  		printf "\nViewing (%s/%s): '%s'\n" "$GIT_DIFF_PATH_COUNTER" \
>  			"$GIT_DIFF_PATH_TOTAL" "$MERGED"
>  		if use_ext_cmd
> @@ -102,4 +128,10 @@ else
>  	done
>  fi
>  
> +if test -f $GIT_DIFFTOOL_SKIP_TO_FILE &&
> +	test $GIT_DIFF_PATH_COUNTER -eq $GIT_DIFF_PATH_TOTAL
> +then
> +	rm $GIT_DIFFTOOL_SKIP_TO_FILE
> +
> +fi
>  exit 0
>
> base-commit: e6362826a0409539642a5738db61827e5978e2e4

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

* Re: [PATCH] git-difftool-helper.sh: learn a new way skip to save point
  2021-02-07 15:19 [PATCH] git-difftool-helper.sh: learn a new way skip to save point 阿德烈 via GitGitGadget
  2021-02-07 18:29 ` Junio C Hamano
@ 2021-02-07 19:04 ` Junio C Hamano
  2021-02-08  8:06   ` 胡哲宁
  2021-02-08 17:02 ` [PATCH v2] git-difftool-helper.sh: learn a new way go back to last " ZheNing Hu via GitGitGadget
  2 siblings, 1 reply; 37+ messages in thread
From: Junio C Hamano @ 2021-02-07 19:04 UTC (permalink / raw)
  To: 阿德烈 via GitGitGadget; +Cc: git, 阿德烈

Sorry, but a not-yet-written reply went out by accident; please
discard it.

> `git difftool` only allow us to select file to view In turn.

Funny capitalization "In"?

> If there is a commit with many files and we exit in search,
> We will have to traverse list again to get the file diff which
> we want to see.Therefore,here is a new method:every time before

It makes it hard to lack SP after punctuation like '.', ',', and
':'.

> we view the file diff,the current coordinates will be stored in
> `GIT_DIR/difftool_skip_to`,this file will be deleted after
> successful traversing.But if an unexpected exit occurred midway,
> git will view the coordinates in the save point,ask user if they
> want continue from the last saved point.This will improve the
> user experience.

I think the idea sounds good.  Admittedly I do not use difftool
myself, so I do not even know if and how the current end user
experience is so bad to require a patch like this (e.g. I do not
know how "unexpected exit" is "unexpected"---isn't it the end user
initiated action to "quit", or does the tool crash or something?).

So I won't be the best qualified person to judge if the solution
presented is the best one for the problem.  

    $ git shortlog --no-merges git-diff-helper.sh

might be a good way to find whom to ask for review and help.

Having said that, I do have one opinion on the "skip-to" filename.
I do not think it is wise to call it after the purpose you want to
use it for (i.e. "I want to use it to skip to the recorded
position").  Instead, if the file records "the last visited
position", it is better to name it after that
(e.g. "difftool-last-position".  If it records "the next file to be
visited", then "difftool-next-file" may be a good name).

The reason is because your first design may be to visit the file the
user was visiting before the "crash" happened, but you may later
want to revise the design to allow the user to say "start at one
file before the file I was visiting" etc.  The location recorded in
the file may still be used to decide where the code skips to when
restarting, but no longer exactly where the code "skips to".  If you
name it after what it is, not what it is (currently) used for, the
design would become clearer.


> diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
> index 46af3e60b718..56ec1d38a7a1 100755
> --- a/git-difftool--helper.sh
> +++ b/git-difftool--helper.sh
> @@ -6,6 +6,7 @@
>  # Copyright (c) 2009, 2010 David Aguilar
>  
>  TOOL_MODE=diff
> +GIT_DIFFTOOL_SKIP_TO_FILE="$GIT_DIR/difftool-skip-to"
>  . git-mergetool--lib
>  
>  # difftool.prompt controls the default prompt/no-prompt behavior
> @@ -40,6 +41,31 @@ launch_merge_tool () {
>  	# the user with the real $MERGED name before launching $merge_tool.
>  	if should_prompt
>  	then
> +		if test -f "$GIT_DIFFTOOL_SKIP_TO_FILE"
> +		then
> +			SAVE_POINT_NUM=$(cat "$GIT_DIFFTOOL_SKIP_TO_FILE")

You can avoid the TOCTTOU race by

		if SAVE_POINT=$(cat 2>/dev/null "$GIT_DIFFTOOL_SKIP_TO_FILE")
		then

but that wouldn't probably matter in this application.

> +			if test $SAVE_POINT_NUM -le $GIT_DIFF_PATH_TOTAL &&
> +				test $SAVE_POINT_NUM -gt $GIT_DIFF_PATH_COUNTER

Think what happens if the file is corrupt and SAVE_POINT_NUM has (1)
an empty string, (2) garbage that has $IFS whitespace, (3) non
number, in it.  At least, quoting the variable inside double-quotes,
i.e. "$SAVE_POINT_NUM", would help an error condition reported
correctly at the runtime.

> +			then
> +				# choice skip or not skip when check first file.

A bit funny language.  Isn't the code clear enough without this comment?

> +				if test $GIT_DIFF_PATH_COUNTER -eq "1"

No need to quote the constant "1"; quoting the variable side may be
a good practice, even though I think in this codepath we know
GIT_DIFF_PATH_COUNTER is a well-formatted number.

> +				then
> +					printf "do you want to skip to last time difftool save point($SAVE_POINT_NUM) [Y/n]?"

"Skip" is probably an implementation detail that the user does not
have to know.  "Do you want to start from the last file you were
viewing?", perhaps?

> +					read skip_ans || return
> +					if test "$skip_ans" = y
> +					then
> +						return
> +					fi
> +				else
> +					return
> +				fi
> +			fi
> +		fi
> +		# write the current coordinates to .git/difftool-skip-to
> +		if test !$SAVE_POINT_NUM || $SAVE_POINT_NUM -ne $GIT_DIFF_PATH_COUNTER

Have this code been tested?  I think "test" is missing after the
"||", and I am not quite sure what you are trying to check with
"test !$SAVE_POINT_NUM", either.  The "test" utility, when given a
non-operator string (like "!23" this one is checking when the last
visited path was the 23rd one), returns true if the string is not an
empty string, and by definition a string made by appending anything
after "!" would not be empty, so the entire "|| $SAVE_POINT_NUM ..."
have been skipped in your test, I think.

Is writing the current position to the file unconditionally good
enough?  After all, we are about to go interactive with the user, so
the body of this "if" statement won't be performance critical in any
sense, no?  Or is there something more subtle going on and
correctness of the code depends on this condition?  I cannot quite
tell.

> +		then
> +			echo $GIT_DIFF_PATH_COUNTER > $GIT_DIFFTOOL_SKIP_TO_FILE

		echo "$GIT_DIFF_PATH_COUNTER" >"$GIT_DIFFTOOL_SKIP_TO_FILE"

cf. Documentation/CodingGuidelines

 - Redirection operators should be written with space before, but no
   space after them.  In other words, write 'echo test >"$file"'
   instead of 'echo test> $file' or 'echo test > $file'.  Note that
   even though it is not required by POSIX to double-quote the
   redirection target in a variable (as shown above), our code does so
   because some versions of bash issue a warning without the quotes.

	(incorrect)
	cat hello > world < universe
	echo hello >$world

	(correct)
	cat hello >world <universe
	echo hello >"$world"




> +		fi
>  		printf "\nViewing (%s/%s): '%s'\n" "$GIT_DIFF_PATH_COUNTER" \
>  			"$GIT_DIFF_PATH_TOTAL" "$MERGED"
>  		if use_ext_cmd
> @@ -102,4 +128,10 @@ else
>  	done
>  fi
>  
> +if test -f $GIT_DIFFTOOL_SKIP_TO_FILE &&
> +	test $GIT_DIFF_PATH_COUNTER -eq $GIT_DIFF_PATH_TOTAL
> +then
> +	rm $GIT_DIFFTOOL_SKIP_TO_FILE
> +
> +fi
>  exit 0

Wouldn't it be simpler to clear when we have reached at the end, i.e.

	if test "$GIT_DIFF_PATH_COUNTER" -eq "$GIT_DIFF_PATH_TOTAL"
	then
		rm -f "$GIT_DIFFTOOL_SKIP_TO_FILE"
	fi

Thanks.

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

* Re: [PATCH] git-difftool-helper.sh: learn a new way skip to save point
  2021-02-07 19:04 ` Junio C Hamano
@ 2021-02-08  8:06   ` 胡哲宁
  0 siblings, 0 replies; 37+ messages in thread
From: 胡哲宁 @ 2021-02-08  8:06 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: 阿德烈 via GitGitGadget, Git List

Junio C Hamano <gitster@pobox.com> 于2021年2月8日周一 上午3:04写道:
>
> Sorry, but a not-yet-written reply went out by accident; please
> discard it.
>

Never mind. I have synchronized different signatures of git, gmail,
github.

> > `git difftool` only allow us to select file to view In turn.
>
> Funny capitalization "In"?
>
> > If there is a commit with many files and we exit in search,
> > We will have to traverse list again to get the file diff which
> > we want to see.Therefore,here is a new method:every time before
>
> It makes it hard to lack SP after punctuation like '.', ',', and
> ':'.
>
> > we view the file diff,the current coordinates will be stored in
> > `GIT_DIR/difftool_skip_to`,this file will be deleted after
> > successful traversing.But if an unexpected exit occurred midway,
> > git will view the coordinates in the save point,ask user if they
> > want continue from the last saved point.This will improve the
> > user experience.
>
> I think the idea sounds good.  Admittedly I do not use difftool
> myself, so I do not even know if and how the current end user
> experience is so bad to require a patch like this (e.g. I do not
> know how "unexpected exit" is "unexpected"---isn't it the end user
> initiated action to "quit", or does the tool crash or something?).
>

Generally speaking, It is the user of git manually use [Ctrl+c].
However, if the program itself fails and causes the exit, I think
this "save point" can also be well recorded, because it will be
stored before view the diff.

> So I won't be the best qualified person to judge if the solution
> presented is the best one for the problem.
>
>     $ git shortlog --no-merges git-diff-helper.sh
>
> might be a good way to find whom to ask for review and help.
>

Thanks for reminding, I will -cc these authors.

> Having said that, I do have one opinion on the "skip-to" filename.
> I do not think it is wise to call it after the purpose you want to
> use it for (i.e. "I want to use it to skip to the recorded
> position").  Instead, if the file records "the last visited
> position", it is better to name it after that
> (e.g. "difftool-last-position".  If it records "the next file to be
> visited", then "difftool-next-file" may be a good name).
>

Indeed, "last-position" can better express this patch function.
I will modify it according to your suggestions.

> The reason is because your first design may be to visit the file the
> user was visiting before the "crash" happened, but you may later
> want to revise the design to allow the user to say "start at one
> file before the file I was visiting" etc.  The location recorded in
> the file may still be used to decide where the code skips to when
> restarting, but no longer exactly where the code "skips to".  If you
> name it after what it is, not what it is (currently) used for, the
> design would become clearer.
>

You are right,But I think based on this patch, the function of "skip to"
may can be added later.

>
> > diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
> > index 46af3e60b718..56ec1d38a7a1 100755
> > --- a/git-difftool--helper.sh
> > +++ b/git-difftool--helper.sh
> > @@ -6,6 +6,7 @@
> >  # Copyright (c) 2009, 2010 David Aguilar
> >
> >  TOOL_MODE=diff
> > +GIT_DIFFTOOL_SKIP_TO_FILE="$GIT_DIR/difftool-skip-to"
> >  . git-mergetool--lib
> >
> >  # difftool.prompt controls the default prompt/no-prompt behavior
> > @@ -40,6 +41,31 @@ launch_merge_tool () {
> >       # the user with the real $MERGED name before launching $merge_tool.
> >       if should_prompt
> >       then
> > +             if test -f "$GIT_DIFFTOOL_SKIP_TO_FILE"
> > +             then
> > +                     SAVE_POINT_NUM=$(cat "$GIT_DIFFTOOL_SKIP_TO_FILE")
>
> You can avoid the TOCTTOU race by
>
>                 if SAVE_POINT=$(cat 2>/dev/null "$GIT_DIFFTOOL_SKIP_TO_FILE")
>                 then
>
> but that wouldn't probably matter in this application.
>
> > +                     if test $SAVE_POINT_NUM -le $GIT_DIFF_PATH_TOTAL &&
> > +                             test $SAVE_POINT_NUM -gt $GIT_DIFF_PATH_COUNTER
>
> Think what happens if the file is corrupt and SAVE_POINT_NUM has (1)
> an empty string, (2) garbage that has $IFS whitespace, (3) non
> number, in it.  At least, quoting the variable inside double-quotes,
> i.e. "$SAVE_POINT_NUM", would help an error condition reported
> correctly at the runtime.

Understand now.A variable with '""'can show correct error usage when
these error conditions occur.

>
> > +                     then
> > +                             # choice skip or not skip when check first file.
>
> A bit funny language.  Isn't the code clear enough without this comment?
>
> > +                             if test $GIT_DIFF_PATH_COUNTER -eq "1"
>
> No need to quote the constant "1"; quoting the variable side may be
> a good practice, even though I think in this codepath we know
> GIT_DIFF_PATH_COUNTER is a well-formatted number.

Truly. I will use "DIFFTOOL_FIRST_NUM" instread of "1".

>
> > +                             then
> > +                                     printf "do you want to skip to last time difftool save point($SAVE_POINT_NUM) [Y/n]?"
>
> "Skip" is probably an implementation detail that the user does not
> have to know.  "Do you want to start from the last file you were
> viewing?", perhaps?

Yeah. Because users may choice another totally different diff,
I will use "Do you want to start from the possible last file you
were viewing?".

>
> > +                                     read skip_ans || return
> > +                                     if test "$skip_ans" = y
> > +                                     then
> > +                                             return
> > +                                     fi
> > +                             else
> > +                                     return
> > +                             fi
> > +                     fi
> > +             fi
> > +             # write the current coordinates to .git/difftool-skip-to
> > +             if test !$SAVE_POINT_NUM || $SAVE_POINT_NUM -ne $GIT_DIFF_PATH_COUNTER
>
> Have this code been tested?  I think "test" is missing after the
> "||", and I am not quite sure what you are trying to check with
> "test !$SAVE_POINT_NUM", either.  The "test" utility, when given a
> non-operator string (like "!23" this one is checking when the last
> visited path was the 23rd one), returns true if the string is not an
> empty string, and by definition a string made by appending anything
> after "!" would not be empty, so the entire "|| $SAVE_POINT_NUM ..."
> have been skipped in your test, I think.
>

Is indeed a mistake of mine, `test -z "$SAVE_POINT_NUM"` will be fine.
Shell script syntax I will pay more attention.

> Is writing the current position to the file unconditionally good
> enough?  After all, we are about to go interactive with the user, so
> the body of this "if" statement won't be performance critical in any
> sense, no?  Or is there something more subtle going on and
> correctness of the code depends on this condition?  I cannot quite
> tell.
>
> > +             then
> > +                     echo $GIT_DIFF_PATH_COUNTER > $GIT_DIFFTOOL_SKIP_TO_FILE
>
>                 echo "$GIT_DIFF_PATH_COUNTER" >"$GIT_DIFFTOOL_SKIP_TO_FILE"
>
> cf. Documentation/CodingGuidelines
>
>  - Redirection operators should be written with space before, but no
>    space after them.  In other words, write 'echo test >"$file"'
>    instead of 'echo test> $file' or 'echo test > $file'.  Note that
>    even though it is not required by POSIX to double-quote the
>    redirection target in a variable (as shown above), our code does so
>    because some versions of bash issue a warning without the quotes.
>
>         (incorrect)
>         cat hello > world < universe
>         echo hello >$world
>
>         (correct)
>         cat hello >world <universe
>         echo hello >"$world"
>
>
>
>

OK, I will read Documentation/CodingGuidelines more times.

> > +             fi
> >               printf "\nViewing (%s/%s): '%s'\n" "$GIT_DIFF_PATH_COUNTER" \
> >                       "$GIT_DIFF_PATH_TOTAL" "$MERGED"
> >               if use_ext_cmd
> > @@ -102,4 +128,10 @@ else
> >       done
> >  fi
> >
> > +if test -f $GIT_DIFFTOOL_SKIP_TO_FILE &&
> > +     test $GIT_DIFF_PATH_COUNTER -eq $GIT_DIFF_PATH_TOTAL
> > +then
> > +     rm $GIT_DIFFTOOL_SKIP_TO_FILE
> > +
> > +fi
> >  exit 0
>
> Wouldn't it be simpler to clear when we have reached at the end, i.e.
>
>         if test "$GIT_DIFF_PATH_COUNTER" -eq "$GIT_DIFF_PATH_TOTAL"
>         then
>                 rm -f "$GIT_DIFFTOOL_SKIP_TO_FILE"
>         fi
>
> Thanks.

Thanks for the advice and correct, Junio.

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

* [PATCH v2] git-difftool-helper.sh: learn a new way go back to last save point
  2021-02-07 15:19 [PATCH] git-difftool-helper.sh: learn a new way skip to save point 阿德烈 via GitGitGadget
  2021-02-07 18:29 ` Junio C Hamano
  2021-02-07 19:04 ` Junio C Hamano
@ 2021-02-08 17:02 ` ZheNing Hu via GitGitGadget
  2021-02-08 20:13   ` Junio C Hamano
                     ` (2 more replies)
  2 siblings, 3 replies; 37+ messages in thread
From: ZheNing Hu via GitGitGadget @ 2021-02-08 17:02 UTC (permalink / raw)
  To: git
  Cc: Denton Liu, David Aguilar, John Keeping, Junio C Hamano,
	ZheNing Hu, ZheNing Hu

From: ZheNing Hu <adlternative@gmail.com>

`git difftool` only allow us to select file to view in turn.
If there is a commit with many files and we exit in the search,
We will have to traverse list again to get the file diff which
we want to see. Therefore, here is a new method: every time before
we view the file diff, the current coordinates will be stored in
`GIT_DIR/difftool-last-position`, this file will be deleted after
successful traversing. But if an unexpected exit occurred midway or
users similar to using "ctrl+c" kill the process,and the user wants
to redo the same `git difftoool`, git will view the coordinates in
the save point, ask user if they want continue from the last position.
This will improve the user experience.

Signed-off-by: ZheNing Hu <adlternative@gmail.com>
---
    git-difftool-helper.sh: learn a new way skip to save point
    
    git user may should travel the diff list to choice file diff to view, if
    they exit in midway,they must travel it again. By saving current
    coordinates in GIT_DIR/difftool-last-position method, provides a
    possibility for this user-friendly solution.
    
    this patch's origin discuss is here:
    https://lore.kernel.org/git/gOXOaoqn-E9A2ob7ykWEcDc7ZxmSwAjcP5CCFKfr5ejCOWZQ1lfAUZcbgYT9AyQCcDgJvCrnrtziXiels-Hxol3xlkGTVHk24SvAdaSUtKQ=@rtzoeller.com/
    
    Thanks!

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-870%2Fadlternative%2Fdifftool_save_point-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-870/adlternative/difftool_save_point-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/870

Range-diff vs v1:

 1:  e77c3e33ba85 ! 1:  2468eaff322b git-difftool-helper.sh: learn a new way skip to save point
     @@ Metadata
      Author: ZheNing Hu <adlternative@gmail.com>
      
       ## Commit message ##
     -    git-difftool-helper.sh: learn a new way skip to save point
     +    git-difftool-helper.sh: learn a new way go back to last save point
      
     -    `git difftool` only allow us to select file to view In turn.
     -    If there is a commit with many files and we exit in search,
     +    `git difftool` only allow us to select file to view in turn.
     +    If there is a commit with many files and we exit in the search,
          We will have to traverse list again to get the file diff which
     -    we want to see.Therefore,here is a new method:every time before
     -    we view the file diff,the current coordinates will be stored in
     -    `GIT_DIR/difftool_skip_to`,this file will be deleted after
     -    successful traversing.But if an unexpected exit occurred midway,
     -    git will view the coordinates in the save point,ask user if they
     -    want continue from the last saved point.This will improve the
     -    user experience.
     +    we want to see. Therefore, here is a new method: every time before
     +    we view the file diff, the current coordinates will be stored in
     +    `GIT_DIR/difftool-last-position`, this file will be deleted after
     +    successful traversing. But if an unexpected exit occurred midway or
     +    users similar to using "ctrl+c" kill the process,and the user wants
     +    to redo the same `git difftoool`, git will view the coordinates in
     +    the save point, ask user if they want continue from the last position.
     +    This will improve the user experience.
      
          Signed-off-by: ZheNing Hu <adlternative@gmail.com>
      
     @@ git-difftool--helper.sh
       # Copyright (c) 2009, 2010 David Aguilar
       
       TOOL_MODE=diff
     -+GIT_DIFFTOOL_SKIP_TO_FILE="$GIT_DIR/difftool-skip-to"
     ++GIT_DIFFTOOL_LAST_POSITION="$GIT_DIR/difftool-last-position"
     ++DIFFTOOL_FIRST_NUM="1"
       . git-mergetool--lib
       
       # difftool.prompt controls the default prompt/no-prompt behavior
     @@ git-difftool--helper.sh: launch_merge_tool () {
       	# the user with the real $MERGED name before launching $merge_tool.
       	if should_prompt
       	then
     -+		if test -f "$GIT_DIFFTOOL_SKIP_TO_FILE"
     ++		if test -f "$GIT_DIFFTOOL_LAST_POSITION"
      +		then
     -+			SAVE_POINT_NUM=$(cat "$GIT_DIFFTOOL_SKIP_TO_FILE")
     -+			if test $SAVE_POINT_NUM -le $GIT_DIFF_PATH_TOTAL &&
     -+				test $SAVE_POINT_NUM -gt $GIT_DIFF_PATH_COUNTER
     ++			if SAVE_POINT_NUM=$(cat 2>/dev/null "$GIT_DIFFTOOL_LAST_POSITION") &&
     ++				test "$SAVE_POINT_NUM" -le "$GIT_DIFF_PATH_TOTAL" &&
     ++					test "$SAVE_POINT_NUM" -gt "$GIT_DIFF_PATH_COUNTER"
      +			then
     -+				# choice skip or not skip when check first file.
     -+				if test $GIT_DIFF_PATH_COUNTER -eq "1"
     ++				if test "$GIT_DIFF_PATH_COUNTER" -eq "$DIFFTOOL_FIRST_NUM"
      +				then
     -+					printf "do you want to skip to last time difftool save point($SAVE_POINT_NUM) [Y/n]?"
     ++					printf "Do you want to start from the possible last file you were viewing? [Y/n]?"
      +					read skip_ans || return
      +					if test "$skip_ans" = y
      +					then
     @@ git-difftool--helper.sh: launch_merge_tool () {
      +				fi
      +			fi
      +		fi
     -+		# write the current coordinates to .git/difftool-skip-to
     -+		if test !$SAVE_POINT_NUM || $SAVE_POINT_NUM -ne $GIT_DIFF_PATH_COUNTER
     ++		if test -z "$SAVE_POINT_NUM" ||
     ++			test "$SAVE_POINT_NUM" -ne "$GIT_DIFF_PATH_COUNTER"
      +		then
     -+			echo $GIT_DIFF_PATH_COUNTER > $GIT_DIFFTOOL_SKIP_TO_FILE
     ++			echo "$GIT_DIFF_PATH_COUNTER" >"$GIT_DIFFTOOL_LAST_POSITION"
      +		fi
       		printf "\nViewing (%s/%s): '%s'\n" "$GIT_DIFF_PATH_COUNTER" \
       			"$GIT_DIFF_PATH_TOTAL" "$MERGED"
     @@ git-difftool--helper.sh: else
       	done
       fi
       
     -+if test -f $GIT_DIFFTOOL_SKIP_TO_FILE &&
     -+	test $GIT_DIFF_PATH_COUNTER -eq $GIT_DIFF_PATH_TOTAL
     ++if test "$GIT_DIFF_PATH_COUNTER" -eq "$GIT_DIFF_PATH_TOTAL"
      +then
     -+	rm $GIT_DIFFTOOL_SKIP_TO_FILE
     ++	rm -f "$GIT_DIFFTOOL_LAST_POSITION"
      +
      +fi
       exit 0


 git-difftool--helper.sh | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
index 46af3e60b718..a01aa7c9d551 100755
--- a/git-difftool--helper.sh
+++ b/git-difftool--helper.sh
@@ -6,6 +6,8 @@
 # Copyright (c) 2009, 2010 David Aguilar
 
 TOOL_MODE=diff
+GIT_DIFFTOOL_LAST_POSITION="$GIT_DIR/difftool-last-position"
+DIFFTOOL_FIRST_NUM="1"
 . git-mergetool--lib
 
 # difftool.prompt controls the default prompt/no-prompt behavior
@@ -40,6 +42,30 @@ launch_merge_tool () {
 	# the user with the real $MERGED name before launching $merge_tool.
 	if should_prompt
 	then
+		if test -f "$GIT_DIFFTOOL_LAST_POSITION"
+		then
+			if SAVE_POINT_NUM=$(cat 2>/dev/null "$GIT_DIFFTOOL_LAST_POSITION") &&
+				test "$SAVE_POINT_NUM" -le "$GIT_DIFF_PATH_TOTAL" &&
+					test "$SAVE_POINT_NUM" -gt "$GIT_DIFF_PATH_COUNTER"
+			then
+				if test "$GIT_DIFF_PATH_COUNTER" -eq "$DIFFTOOL_FIRST_NUM"
+				then
+					printf "Do you want to start from the possible last file you were viewing? [Y/n]?"
+					read skip_ans || return
+					if test "$skip_ans" = y
+					then
+						return
+					fi
+				else
+					return
+				fi
+			fi
+		fi
+		if test -z "$SAVE_POINT_NUM" ||
+			test "$SAVE_POINT_NUM" -ne "$GIT_DIFF_PATH_COUNTER"
+		then
+			echo "$GIT_DIFF_PATH_COUNTER" >"$GIT_DIFFTOOL_LAST_POSITION"
+		fi
 		printf "\nViewing (%s/%s): '%s'\n" "$GIT_DIFF_PATH_COUNTER" \
 			"$GIT_DIFF_PATH_TOTAL" "$MERGED"
 		if use_ext_cmd
@@ -102,4 +128,9 @@ else
 	done
 fi
 
+if test "$GIT_DIFF_PATH_COUNTER" -eq "$GIT_DIFF_PATH_TOTAL"
+then
+	rm -f "$GIT_DIFFTOOL_LAST_POSITION"
+
+fi
 exit 0

base-commit: e6362826a0409539642a5738db61827e5978e2e4
-- 
gitgitgadget

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

* Re: [PATCH v2] git-difftool-helper.sh: learn a new way go back to last save point
  2021-02-08 17:02 ` [PATCH v2] git-difftool-helper.sh: learn a new way go back to last " ZheNing Hu via GitGitGadget
@ 2021-02-08 20:13   ` Junio C Hamano
  2021-02-08 22:15   ` David Aguilar
  2021-02-09 15:30   ` [PATCH v3] difftool.c: learn a new way start from specified file ZheNing Hu via GitGitGadget
  2 siblings, 0 replies; 37+ messages in thread
From: Junio C Hamano @ 2021-02-08 20:13 UTC (permalink / raw)
  To: ZheNing Hu via GitGitGadget
  Cc: git, Denton Liu, David Aguilar, John Keeping, ZheNing Hu

"ZheNing Hu via GitGitGadget" <gitgitgadget@gmail.com> writes:

> diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
> index 46af3e60b718..a01aa7c9d551 100755
> --- a/git-difftool--helper.sh
> +++ b/git-difftool--helper.sh
> @@ -6,6 +6,8 @@
>  # Copyright (c) 2009, 2010 David Aguilar
>  
>  TOOL_MODE=diff
> +GIT_DIFFTOOL_LAST_POSITION="$GIT_DIR/difftool-last-position"
> +DIFFTOOL_FIRST_NUM="1"

Do we need this constant?  I do not think it makes the resulting
code easier to follow.

>  . git-mergetool--lib
>  
>  # difftool.prompt controls the default prompt/no-prompt behavior
> @@ -40,6 +42,30 @@ launch_merge_tool () {
>  	# the user with the real $MERGED name before launching $merge_tool.
>  	if should_prompt
>  	then
> +		if test -f "$GIT_DIFFTOOL_LAST_POSITION"
> +		then
> +			if SAVE_POINT_NUM=$(cat 2>/dev/null "$GIT_DIFFTOOL_LAST_POSITION") &&
> +				test "$SAVE_POINT_NUM" -le "$GIT_DIFF_PATH_TOTAL" &&
> +					test "$SAVE_POINT_NUM" -gt "$GIT_DIFF_PATH_COUNTER"
> +			then

No need to push the subsequent lines that far to the right,
especially when your variable names are already overly long.  It
just makes things harder to read.

			if test -r "$GIT_DIFFTOOL_LAST_POSITION" &&
			   SAVE_POINT_NUM=$(cat "$GIT_DIFFTOOL_LAST_POSITION") &&
			   test "$SAVE_POINT_NUM" -le "$GIT_DIFF_PATH_TOTAL" &&
			   test "$SAVE_POINT_NUM" -gt "$GIT_DIFF_PATH_COUNTER"
			then

> +				if test "$GIT_DIFF_PATH_COUNTER" -eq "$DIFFTOOL_FIRST_NUM"
> +				then
> +					printf "Do you want to start from the possible last file you were viewing? [Y/n]?"

Where does that "possible" come from?  If the reason is "We might
have miscomputed or misrecorded an incorrect last position", we
probably should work harder to make sure we don't ;-)

At this point in the code, do we have the _name_ of the file we are
going to skip to readily available, or do we actually need to seek
to that position before we can find it out?

	You were looking at 'hello-world.txt' the last time.
	Do you want to restart from there [Y/n]?

would be far easier to answer for an end-user than an unspecified
"possible last file".

> +		fi
> +		if test -z "$SAVE_POINT_NUM" ||
> +			test "$SAVE_POINT_NUM" -ne "$GIT_DIFF_PATH_COUNTER"

Ditto about indentation.

Is this behaviour something we can write a test for in
t/t7800-difftool.sh, by the way?

Other than these, i.e. (cosmetic) indentation and overly long lines
(ui) giving filename is easier to work with for the users and (dev)
lack of tests, looking quite good.

Thanks.

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

* Re: [PATCH v2] git-difftool-helper.sh: learn a new way go back to last save point
  2021-02-08 17:02 ` [PATCH v2] git-difftool-helper.sh: learn a new way go back to last " ZheNing Hu via GitGitGadget
  2021-02-08 20:13   ` Junio C Hamano
@ 2021-02-08 22:15   ` David Aguilar
  2021-02-08 23:34     ` Junio C Hamano
  2021-02-09  6:04     ` 胡哲宁
  2021-02-09 15:30   ` [PATCH v3] difftool.c: learn a new way start from specified file ZheNing Hu via GitGitGadget
  2 siblings, 2 replies; 37+ messages in thread
From: David Aguilar @ 2021-02-08 22:15 UTC (permalink / raw)
  To: ZheNing Hu via GitGitGadget
  Cc: Git Mailing List, Denton Liu, John Keeping, Junio C Hamano,
	ZheNing Hu, Ryan Zoeller

(cc'd Ryan since the thread involving him was mentioned in the commit message)

On Mon, Feb 8, 2021 at 9:02 AM ZheNing Hu via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> From: ZheNing Hu <adlternative@gmail.com>
>
> `git difftool` only allow us to select file to view in turn.
> If there is a commit with many files and we exit in the search,
> We will have to traverse list again to get the file diff which
> we want to see. Therefore, here is a new method: every time before
> we view the file diff, the current coordinates will be stored in
> `GIT_DIR/difftool-last-position`, this file will be deleted after
> successful traversing. But if an unexpected exit occurred midway or
> users similar to using "ctrl+c" kill the process,and the user wants
> to redo the same `git difftoool`, git will view the coordinates in
> the save point, ask user if they want continue from the last position.
> This will improve the user experience.
>
> Signed-off-by: ZheNing Hu <adlternative@gmail.com>
> ---
>     git-difftool-helper.sh: learn a new way skip to save point
>
>     git user may should travel the diff list to choice file diff to view, if
>     they exit in midway,they must travel it again. By saving current
>     coordinates in GIT_DIR/difftool-last-position method, provides a
>     possibility for this user-friendly solution.
>
>     this patch's origin discuss is here:
>     https://lore.kernel.org/git/gOXOaoqn-E9A2ob7ykWEcDc7ZxmSwAjcP5CCFKfr5ejCOWZQ1lfAUZcbgYT9AyQCcDgJvCrnrtziXiels-Hxol3xlkGTVHk24SvAdaSUtKQ=@rtzoeller.com/
>
>     Thanks!
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-870%2Fadlternative%2Fdifftool_save_point-v2
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-870/adlternative/difftool_save_point-v2
> Pull-Request: https://github.com/gitgitgadget/git/pull/870
>
> Range-diff vs v1:
>
>  1:  e77c3e33ba85 ! 1:  2468eaff322b git-difftool-helper.sh: learn a new way skip to save point
>      @@ Metadata
>       Author: ZheNing Hu <adlternative@gmail.com>
>
>        ## Commit message ##
>      -    git-difftool-helper.sh: learn a new way skip to save point
>      +    git-difftool-helper.sh: learn a new way go back to last save point
>
>      -    `git difftool` only allow us to select file to view In turn.
>      -    If there is a commit with many files and we exit in search,
>      +    `git difftool` only allow us to select file to view in turn.
>      +    If there is a commit with many files and we exit in the search,
>           We will have to traverse list again to get the file diff which
>      -    we want to see.Therefore,here is a new method:every time before
>      -    we view the file diff,the current coordinates will be stored in
>      -    `GIT_DIR/difftool_skip_to`,this file will be deleted after
>      -    successful traversing.But if an unexpected exit occurred midway,
>      -    git will view the coordinates in the save point,ask user if they
>      -    want continue from the last saved point.This will improve the
>      -    user experience.
>      +    we want to see. Therefore, here is a new method: every time before
>      +    we view the file diff, the current coordinates will be stored in
>      +    `GIT_DIR/difftool-last-position`, this file will be deleted after
>      +    successful traversing. But if an unexpected exit occurred midway or
>      +    users similar to using "ctrl+c" kill the process,and the user wants
>      +    to redo the same `git difftoool`, git will view the coordinates in
>      +    the save point, ask user if they want continue from the last position.
>      +    This will improve the user experience.
>
>           Signed-off-by: ZheNing Hu <adlternative@gmail.com>
>
>      @@ git-difftool--helper.sh
>        # Copyright (c) 2009, 2010 David Aguilar
>
>        TOOL_MODE=diff
>      -+GIT_DIFFTOOL_SKIP_TO_FILE="$GIT_DIR/difftool-skip-to"
>      ++GIT_DIFFTOOL_LAST_POSITION="$GIT_DIR/difftool-last-position"
>      ++DIFFTOOL_FIRST_NUM="1"
>        . git-mergetool--lib
>
>        # difftool.prompt controls the default prompt/no-prompt behavior
>      @@ git-difftool--helper.sh: launch_merge_tool () {
>         # the user with the real $MERGED name before launching $merge_tool.
>         if should_prompt
>         then
>      -+         if test -f "$GIT_DIFFTOOL_SKIP_TO_FILE"
>      ++         if test -f "$GIT_DIFFTOOL_LAST_POSITION"
>       +         then
>      -+                 SAVE_POINT_NUM=$(cat "$GIT_DIFFTOOL_SKIP_TO_FILE")
>      -+                 if test $SAVE_POINT_NUM -le $GIT_DIFF_PATH_TOTAL &&
>      -+                         test $SAVE_POINT_NUM -gt $GIT_DIFF_PATH_COUNTER
>      ++                 if SAVE_POINT_NUM=$(cat 2>/dev/null "$GIT_DIFFTOOL_LAST_POSITION") &&
>      ++                         test "$SAVE_POINT_NUM" -le "$GIT_DIFF_PATH_TOTAL" &&
>      ++                                 test "$SAVE_POINT_NUM" -gt "$GIT_DIFF_PATH_COUNTER"
>       +                 then
>      -+                         # choice skip or not skip when check first file.
>      -+                         if test $GIT_DIFF_PATH_COUNTER -eq "1"
>      ++                         if test "$GIT_DIFF_PATH_COUNTER" -eq "$DIFFTOOL_FIRST_NUM"
>       +                         then
>      -+                                 printf "do you want to skip to last time difftool save point($SAVE_POINT_NUM) [Y/n]?"
>      ++                                 printf "Do you want to start from the possible last file you were viewing? [Y/n]?"
>       +                                 read skip_ans || return
>       +                                 if test "$skip_ans" = y
>       +                                 then
>      @@ git-difftool--helper.sh: launch_merge_tool () {
>       +                         fi
>       +                 fi
>       +         fi


Similar to Junio's question about, "where does this possible come
from?", I wasn't able to make out the behavior in the following
situation.

What about when the user switches branches or specifies a pathspec on
the command-line or some other avenue that ends up with the number of
files to diff being very different than the last difftool invocation?

Will difftool, for example, skip over a smaller set of files on
invocation 2 if invocation 1 involved many files and we exited out
with a counter number that is very high?

One thing that's not too good about having state files in .git/ is
that they're global data and we also have to think about, "what if the
user has multiple difftools running?" and those kind of complexities.

I don't want this to seem like I'm trying to be dismissive of this
feature which does seem like a useful thing in general, so I'll try to
come up with an alternative interface that is slightly more general
but a admittedly a little bit more cumbersome because it's not as
automatic.

What if instead of global state, maybe the user could specify a path
that difftool could skip forward to?   For example, we could teach
difftool to resume by telling it where we last left off:

   git difftool --resume-from=foo/bar099.txt

Then we don't need the global counter state file?


Finally, I'm going to plug what I believe to be the right tool for the
job here.  Have you tried git cola?[1]  Difftool is tightly
integrated, and the UI is such that you can trivially choose any of
the modified/staged files and difftool them by using the Ctrl-d
hotkey.

https://github.com/git-cola/git-cola/

Cola is purpose-built for driving difftool, and for interactive
staging, so not mentioning it in the context of wanting a better UI
for difftool would be a disservice to difftool users.
-- 
David

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

* Re: [PATCH v2] git-difftool-helper.sh: learn a new way go back to last save point
  2021-02-08 22:15   ` David Aguilar
@ 2021-02-08 23:34     ` Junio C Hamano
  2021-02-09  6:19       ` 胡哲宁
  2021-02-09  6:04     ` 胡哲宁
  1 sibling, 1 reply; 37+ messages in thread
From: Junio C Hamano @ 2021-02-08 23:34 UTC (permalink / raw)
  To: David Aguilar
  Cc: ZheNing Hu via GitGitGadget, Git Mailing List, Denton Liu,
	John Keeping, ZheNing Hu, Ryan Zoeller

David Aguilar <davvid@gmail.com> writes:

> What if instead of global state, maybe the user could specify a path
> that difftool could skip forward to?   For example, we could teach
> difftool to resume by telling it where we last left off:
>
>    git difftool --resume-from=foo/bar099.txt
>
> Then we don't need the global counter state file?

Does it have to be the second and subsequent invocation to pass the
new "resume-from" option?  As we do not have "global" state, I would
presume that we do not even know if it is the first invocation, so
perhaps a better name would be "--start-from=$pathname"?

> Finally, I'm going to plug what I believe to be the right tool for the
> job here.  Have you tried git cola?[1]  Difftool is tightly
> integrated, and the UI is such that you can trivially choose any of
> the modified/staged files and difftool them by using the Ctrl-d
> hotkey.
>
> https://github.com/git-cola/git-cola/
>
> Cola is purpose-built for driving difftool, and for interactive
> staging, so not mentioning it in the context of wanting a better UI
> for difftool would be a disservice to difftool users.

;-)

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

* Re: [PATCH v2] git-difftool-helper.sh: learn a new way go back to last save point
  2021-02-08 22:15   ` David Aguilar
  2021-02-08 23:34     ` Junio C Hamano
@ 2021-02-09  6:04     ` 胡哲宁
  1 sibling, 0 replies; 37+ messages in thread
From: 胡哲宁 @ 2021-02-09  6:04 UTC (permalink / raw)
  To: David Aguilar
  Cc: ZheNing Hu via GitGitGadget, Git Mailing List, Denton Liu,
	John Keeping, Junio C Hamano, Ryan Zoeller

David Aguilar <davvid@gmail.com> 于2021年2月9日周二 上午6:16写道:
>
> (cc'd Ryan since the thread involving him was mentioned in the commit message)
>
> On Mon, Feb 8, 2021 at 9:02 AM ZheNing Hu via GitGitGadget
> <gitgitgadget@gmail.com> wrote:
> >
> > From: ZheNing Hu <adlternative@gmail.com>
> >
> > `git difftool` only allow us to select file to view in turn.
> > If there is a commit with many files and we exit in the search,
> > We will have to traverse list again to get the file diff which
> > we want to see. Therefore, here is a new method: every time before
> > we view the file diff, the current coordinates will be stored in
> > `GIT_DIR/difftool-last-position`, this file will be deleted after
> > successful traversing. But if an unexpected exit occurred midway or
> > users similar to using "ctrl+c" kill the process,and the user wants
> > to redo the same `git difftoool`, git will view the coordinates in
> > the save point, ask user if they want continue from the last position.
> > This will improve the user experience.
> >
> > Signed-off-by: ZheNing Hu <adlternative@gmail.com>
> > ---
> >     git-difftool-helper.sh: learn a new way skip to save point
> >
> >     git user may should travel the diff list to choice file diff to view, if
> >     they exit in midway,they must travel it again. By saving current
> >     coordinates in GIT_DIR/difftool-last-position method, provides a
> >     possibility for this user-friendly solution.
> >
> >     this patch's origin discuss is here:
> >     https://lore.kernel.org/git/gOXOaoqn-E9A2ob7ykWEcDc7ZxmSwAjcP5CCFKfr5ejCOWZQ1lfAUZcbgYT9AyQCcDgJvCrnrtziXiels-Hxol3xlkGTVHk24SvAdaSUtKQ=@rtzoeller.com/
> >
> >     Thanks!
> >
> > Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-870%2Fadlternative%2Fdifftool_save_point-v2
> > Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-870/adlternative/difftool_save_point-v2
> > Pull-Request: https://github.com/gitgitgadget/git/pull/870
> >
> > Range-diff vs v1:
> >
> >  1:  e77c3e33ba85 ! 1:  2468eaff322b git-difftool-helper.sh: learn a new way skip to save point
> >      @@ Metadata
> >       Author: ZheNing Hu <adlternative@gmail.com>
> >
> >        ## Commit message ##
> >      -    git-difftool-helper.sh: learn a new way skip to save point
> >      +    git-difftool-helper.sh: learn a new way go back to last save point
> >
> >      -    `git difftool` only allow us to select file to view In turn.
> >      -    If there is a commit with many files and we exit in search,
> >      +    `git difftool` only allow us to select file to view in turn.
> >      +    If there is a commit with many files and we exit in the search,
> >           We will have to traverse list again to get the file diff which
> >      -    we want to see.Therefore,here is a new method:every time before
> >      -    we view the file diff,the current coordinates will be stored in
> >      -    `GIT_DIR/difftool_skip_to`,this file will be deleted after
> >      -    successful traversing.But if an unexpected exit occurred midway,
> >      -    git will view the coordinates in the save point,ask user if they
> >      -    want continue from the last saved point.This will improve the
> >      -    user experience.
> >      +    we want to see. Therefore, here is a new method: every time before
> >      +    we view the file diff, the current coordinates will be stored in
> >      +    `GIT_DIR/difftool-last-position`, this file will be deleted after
> >      +    successful traversing. But if an unexpected exit occurred midway or
> >      +    users similar to using "ctrl+c" kill the process,and the user wants
> >      +    to redo the same `git difftoool`, git will view the coordinates in
> >      +    the save point, ask user if they want continue from the last position.
> >      +    This will improve the user experience.
> >
> >           Signed-off-by: ZheNing Hu <adlternative@gmail.com>
> >
> >      @@ git-difftool--helper.sh
> >        # Copyright (c) 2009, 2010 David Aguilar
> >
> >        TOOL_MODE=diff
> >      -+GIT_DIFFTOOL_SKIP_TO_FILE="$GIT_DIR/difftool-skip-to"
> >      ++GIT_DIFFTOOL_LAST_POSITION="$GIT_DIR/difftool-last-position"
> >      ++DIFFTOOL_FIRST_NUM="1"
> >        . git-mergetool--lib
> >
> >        # difftool.prompt controls the default prompt/no-prompt behavior
> >      @@ git-difftool--helper.sh: launch_merge_tool () {
> >         # the user with the real $MERGED name before launching $merge_tool.
> >         if should_prompt
> >         then
> >      -+         if test -f "$GIT_DIFFTOOL_SKIP_TO_FILE"
> >      ++         if test -f "$GIT_DIFFTOOL_LAST_POSITION"
> >       +         then
> >      -+                 SAVE_POINT_NUM=$(cat "$GIT_DIFFTOOL_SKIP_TO_FILE")
> >      -+                 if test $SAVE_POINT_NUM -le $GIT_DIFF_PATH_TOTAL &&
> >      -+                         test $SAVE_POINT_NUM -gt $GIT_DIFF_PATH_COUNTER
> >      ++                 if SAVE_POINT_NUM=$(cat 2>/dev/null "$GIT_DIFFTOOL_LAST_POSITION") &&
> >      ++                         test "$SAVE_POINT_NUM" -le "$GIT_DIFF_PATH_TOTAL" &&
> >      ++                                 test "$SAVE_POINT_NUM" -gt "$GIT_DIFF_PATH_COUNTER"
> >       +                 then
> >      -+                         # choice skip or not skip when check first file.
> >      -+                         if test $GIT_DIFF_PATH_COUNTER -eq "1"
> >      ++                         if test "$GIT_DIFF_PATH_COUNTER" -eq "$DIFFTOOL_FIRST_NUM"
> >       +                         then
> >      -+                                 printf "do you want to skip to last time difftool save point($SAVE_POINT_NUM) [Y/n]?"
> >      ++                                 printf "Do you want to start from the possible last file you were viewing? [Y/n]?"
> >       +                                 read skip_ans || return
> >       +                                 if test "$skip_ans" = y
> >       +                                 then
> >      @@ git-difftool--helper.sh: launch_merge_tool () {
> >       +                         fi
> >       +                 fi
> >       +         fi
>
>
> Similar to Junio's question about, "where does this possible come
> from?", I wasn't able to make out the behavior in the following
> situation.
>
> What about when the user switches branches or specifies a pathspec on
> the command-line or some other avenue that ends up with the number of
> files to diff being very different than the last difftool invocation?
>
> Will difftool, for example, skip over a smaller set of files on
> invocation 2 if invocation 1 involved many files and we exited out
> with a counter number that is very high?
>
This is what I worry about.
> One thing that's not too good about having state files in .git/ is
> that they're global data and we also have to think about, "what if the
> user has multiple difftools running?" and those kind of complexities.
>
I admit that I did not consider the situation where multiple `git difftool`
processes are going on at the same time.
> I don't want this to seem like I'm trying to be dismissive of this
> feature which does seem like a useful thing in general, so I'll try to
> come up with an alternative interface that is slightly more general
> but a admittedly a little bit more cumbersome because it's not as
> automatic.
>
> What if instead of global state, maybe the user could specify a path
> that difftool could skip forward to?   For example, we could teach
> difftool to resume by telling it where we last left off:
>
>    git difftool --resume-from=foo/bar099.txt
>
> Then we don't need the global counter state file?
>
Wonderful idea.But as Junio said, there may be no global state support,
`start-from` will be more applicable.
>
> Finally, I'm going to plug what I believe to be the right tool for the
> job here.  Have you tried git cola?[1]  Difftool is tightly
> integrated, and the UI is such that you can trivially choose any of
> the modified/staged files and difftool them by using the Ctrl-d
> hotkey.
>
> https://github.com/git-cola/git-cola/
>
> Cola is purpose-built for driving difftool, and for interactive
> staging, so not mentioning it in the context of wanting a better UI
> for difftool would be a disservice to difftool users.
I saw the difftool UI of git-cola, and it is great to view the differences
by selecting files.I have been using vscode's git plugin before, and it
works well tool.
> --
> David
Thanks for help!
--
ZheNing Hu

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

* Re: [PATCH v2] git-difftool-helper.sh: learn a new way go back to last save point
  2021-02-08 23:34     ` Junio C Hamano
@ 2021-02-09  6:19       ` 胡哲宁
  0 siblings, 0 replies; 37+ messages in thread
From: 胡哲宁 @ 2021-02-09  6:19 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: David Aguilar, ZheNing Hu via GitGitGadget, Git Mailing List,
	Denton Liu, John Keeping, Ryan Zoeller

Junio C Hamano <gitster@pobox.com> 于2021年2月9日周二 上午7:34写道:
>
> David Aguilar <davvid@gmail.com> writes:
>
> > What if instead of global state, maybe the user could specify a path
> > that difftool could skip forward to?   For example, we could teach
> > difftool to resume by telling it where we last left off:
> >
> >    git difftool --resume-from=foo/bar099.txt
> >
> > Then we don't need the global counter state file?
>
> Does it have to be the second and subsequent invocation to pass the
> new "resume-from" option?  As we do not have "global" state, I would
> presume that we do not even know if it is the first invocation, so
> perhaps a better name would be "--start-from=$pathname"?
>
Thank you for your thinking, I agree with your point of view.
As you said before: an accurate file name may be more suitable
for users than `possible last file`.
However, without the support of the global `difftool-save-point`,
it may not be possible to know the last exit point of the user.
Even if the global state is allowed, it may need to do more work
to avoid the competition for the global state under multiple
processes.
So "--start-from=$pathname" is more suitable to provide users
with a way to quickly index to specified files.
Then I shift the front and start thinking about how to realize it! :)
> > Finally, I'm going to plug what I believe to be the right tool for the
> > job here.  Have you tried git cola?[1]  Difftool is tightly
> > integrated, and the UI is such that you can trivially choose any of
> > the modified/staged files and difftool them by using the Ctrl-d
> > hotkey.
> >
> > https://github.com/git-cola/git-cola/
> >
> > Cola is purpose-built for driving difftool, and for interactive
> > staging, so not mentioning it in the context of wanting a better UI
> > for difftool would be a disservice to difftool users.
>
> ;-)
Thanks again!

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

* [PATCH v3] difftool.c: learn a new way start from specified file
  2021-02-08 17:02 ` [PATCH v2] git-difftool-helper.sh: learn a new way go back to last " ZheNing Hu via GitGitGadget
  2021-02-08 20:13   ` Junio C Hamano
  2021-02-08 22:15   ` David Aguilar
@ 2021-02-09 15:30   ` ZheNing Hu via GitGitGadget
  2021-02-09 18:17     ` Junio C Hamano
  2021-02-14 13:09     ` [PATCH v4] difftool.c: learn a new way start at " ZheNing Hu via GitGitGadget
  2 siblings, 2 replies; 37+ messages in thread
From: ZheNing Hu via GitGitGadget @ 2021-02-09 15:30 UTC (permalink / raw)
  To: git
  Cc: Denton Liu, David Aguilar, John Keeping, Junio C Hamano,
	Ryan Zoeller, ZheNing Hu, ZheNing Hu

From: ZheNing Hu <adlternative@gmail.com>

`git difftool` only allow us to select file to view in turn.
If there is a commit with many files and we exit in the search,
We will have to traverse list again to get the file diff which
we want to see. Therefore, here is a new method: user can use
`git difftool --start-from=<filename>` to start viewing from
the specified file. This will improve the user experience.
At the same time, turn bit field constants into bit shift format
in `diff.h`.

Signed-off-by: ZheNing Hu <adlternative@gmail.com>
---
    difftool.c: learn a new way start at specified file
    
    git user may should travel the diff list to choice file diff to view, if
    they exit in midway,they must travel it again. By starting from the
    specified file method, provides a possibility for this user-friendly
    solution.
    
    this patch's origin discuss is here:
    https://lore.kernel.org/git/gOXOaoqn-E9A2ob7ykWEcDc7ZxmSwAjcP5CCFKfr5ejCOWZQ1lfAUZcbgYT9AyQCcDgJvCrnrtziXiels-Hxol3xlkGTVHk24SvAdaSUtKQ=@rtzoeller.com/
    
    Maybe this patch is more like skip to in Junio's original thread than
    the previous versions.
    
    Thanks!

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-870%2Fadlternative%2Fdifftool_save_point-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-870/adlternative/difftool_save_point-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/870

Range-diff vs v2:

 1:  2468eaff322b < -:  ------------ git-difftool-helper.sh: learn a new way go back to last save point
 -:  ------------ > 1:  29fc6b4bc08f difftool.c: learn a new way start from specified file


 Documentation/git-difftool.txt |  3 +++
 builtin/difftool.c             |  7 ++++++-
 diff.c                         |  9 +++++++++
 diff.h                         | 20 ++++++++++----------
 t/t7800-difftool.sh            | 12 ++++++++++++
 5 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index 484c485fd06c..552be097dfea 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -34,6 +34,9 @@ OPTIONS
 	This is the default behaviour; the option is provided to
 	override any configuration settings.
 
+--start-from::
+	Start viewing diff from the specified file.
+
 -t <tool>::
 --tool=<tool>::
 	Use the diff tool specified by <tool>.  Valid values include
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 6e18e623fddf..67d2befa1210 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -690,7 +690,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 {
 	int use_gui_tool = 0, dir_diff = 0, prompt = -1, symlinks = 0,
 	    tool_help = 0, no_index = 0;
-	static char *difftool_cmd = NULL, *extcmd = NULL;
+	static char *difftool_cmd = NULL, *extcmd = NULL, *start_file = NULL;
 	struct option builtin_difftool_options[] = {
 		OPT_BOOL('g', "gui", &use_gui_tool,
 			 N_("use `diff.guitool` instead of `diff.tool`")),
@@ -714,6 +714,8 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 		OPT_STRING('x', "extcmd", &extcmd, N_("command"),
 			   N_("specify a custom command for viewing diffs")),
 		OPT_ARGUMENT("no-index", &no_index, N_("passed to `diff`")),
+		OPT_STRING(0, "start-from", &start_file, N_("start-from"),
+			   N_("start viewing diff from the specified file")),
 		OPT_END()
 	};
 
@@ -724,6 +726,9 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 			     builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN |
 			     PARSE_OPT_KEEP_DASHDASH);
 
+	if (start_file)
+		setenv("START_FILE", start_file, 1);
+
 	if (tool_help)
 		return print_tool_help();
 
diff --git a/diff.c b/diff.c
index 69e3bc00ed8f..cdad26f99063 100644
--- a/diff.c
+++ b/diff.c
@@ -4249,6 +4249,7 @@ static void run_external_diff(const char *pgm,
 			      const char *xfrm_msg,
 			      struct diff_options *o)
 {
+	const char *start_file = NULL;
 	struct strvec argv = STRVEC_INIT;
 	struct strvec env = STRVEC_INIT;
 	struct diff_queue_struct *q = &diff_queued_diff;
@@ -4272,9 +4273,17 @@ static void run_external_diff(const char *pgm,
 
 	diff_free_filespec_data(one);
 	diff_free_filespec_data(two);
+
+	start_file = xstrdup_or_null(getenv("START_FILE"));
+	if (start_file) {
+		if (strcmp(start_file, name))
+			goto finish;
+		unsetenv("START_FILE");
+	}
 	if (run_command_v_opt_cd_env(argv.v, RUN_USING_SHELL, NULL, env.v))
 		die(_("external diff died, stopping at %s"), name);
 
+finish:
 	remove_tempfile();
 	strvec_clear(&argv);
 	strvec_clear(&env);
diff --git a/diff.h b/diff.h
index 2ff2b1c7f2ca..f67c43f5af95 100644
--- a/diff.h
+++ b/diff.h
@@ -86,18 +86,18 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
 
 typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data);
 
-#define DIFF_FORMAT_RAW		0x0001
-#define DIFF_FORMAT_DIFFSTAT	0x0002
-#define DIFF_FORMAT_NUMSTAT	0x0004
-#define DIFF_FORMAT_SUMMARY	0x0008
-#define DIFF_FORMAT_PATCH	0x0010
-#define DIFF_FORMAT_SHORTSTAT	0x0020
-#define DIFF_FORMAT_DIRSTAT	0x0040
+#define DIFF_FORMAT_RAW		(1U<<0)
+#define DIFF_FORMAT_DIFFSTAT	(1U<<1)
+#define DIFF_FORMAT_NUMSTAT	(1U<<2)
+#define DIFF_FORMAT_SUMMARY	(1U<<3)
+#define DIFF_FORMAT_PATCH	(1U<<4)
+#define DIFF_FORMAT_SHORTSTAT	(1U<<5)
+#define DIFF_FORMAT_DIRSTAT	(1U<<6)
 
 /* These override all above */
-#define DIFF_FORMAT_NAME	0x0100
-#define DIFF_FORMAT_NAME_STATUS	0x0200
-#define DIFF_FORMAT_CHECKDIFF	0x0400
+#define DIFF_FORMAT_NAME	(1U<<8)
+#define DIFF_FORMAT_NAME_STATUS	(1U<<9)
+#define DIFF_FORMAT_CHECKDIFF	(1U<<10)
 
 /* Same as output_format = 0 but we know that -s flag was given
  * and we should not give default value to output_format.
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 9662abc1e784..74baac96a23f 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -762,4 +762,16 @@ test_expect_success 'difftool --gui, --tool and --extcmd are mutually exclusive'
 	test_must_fail git difftool --gui --tool=test-tool --extcmd=cat
 '
 
+test_expect_success 'difftool --start-from' '
+	difftool_test_setup &&
+	test_when_finished git reset --hard &&
+	echo 1 >1 &&
+	echo 2 >2 &&
+	echo 3 >3 &&
+	git add 1 2 3 &&
+	git commit -a -m "123" &&
+	git difftool --start-from="2" HEAD^ 2>&1 >output &&
+	test_line_count = 4 output
+'
+
 test_done

base-commit: e6362826a0409539642a5738db61827e5978e2e4
-- 
gitgitgadget

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

* Re: [PATCH v3] difftool.c: learn a new way start from specified file
  2021-02-09 15:30   ` [PATCH v3] difftool.c: learn a new way start from specified file ZheNing Hu via GitGitGadget
@ 2021-02-09 18:17     ` Junio C Hamano
  2021-02-10 17:00       ` 胡哲宁
  2021-02-14 13:09     ` [PATCH v4] difftool.c: learn a new way start at " ZheNing Hu via GitGitGadget
  1 sibling, 1 reply; 37+ messages in thread
From: Junio C Hamano @ 2021-02-09 18:17 UTC (permalink / raw)
  To: ZheNing Hu via GitGitGadget
  Cc: git, Denton Liu, David Aguilar, John Keeping, Ryan Zoeller, ZheNing Hu

"ZheNing Hu via GitGitGadget" <gitgitgadget@gmail.com> writes:

> diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
> index 484c485fd06c..552be097dfea 100644
> --- a/Documentation/git-difftool.txt
> +++ b/Documentation/git-difftool.txt
> @@ -34,6 +34,9 @@ OPTIONS
>  	This is the default behaviour; the option is provided to
>  	override any configuration settings.
>  
> +--start-from::
> +	Start viewing diff from the specified file.
> +

There is nothing that specifies a file in the above ;-)

	--start-from=<file>::
		Start viewing ...

This is even more important as SYNOPSIS section of this manual page
does not duplicate the list of options and their arguments.

>  -t <tool>::
>  --tool=<tool>::
>  	Use the diff tool specified by <tool>.  Valid values include

There are many things I dislike about this patch, but do not take it
as a personal attack.  I'll try to suggest an alternative at the end,
but read along.

> diff --git a/builtin/difftool.c b/builtin/difftool.c
> index 6e18e623fddf..67d2befa1210 100644
> --- a/builtin/difftool.c
> +++ b/builtin/difftool.c
> @@ -690,7 +690,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
>  {
>  	int use_gui_tool = 0, dir_diff = 0, prompt = -1, symlinks = 0,
>  	    tool_help = 0, no_index = 0;
> -	static char *difftool_cmd = NULL, *extcmd = NULL;
> +	static char *difftool_cmd = NULL, *extcmd = NULL, *start_file = NULL;
>  	struct option builtin_difftool_options[] = {
>  		OPT_BOOL('g', "gui", &use_gui_tool,
>  			 N_("use `diff.guitool` instead of `diff.tool`")),
> @@ -714,6 +714,8 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
>  		OPT_STRING('x', "extcmd", &extcmd, N_("command"),
>  			   N_("specify a custom command for viewing diffs")),
>  		OPT_ARGUMENT("no-index", &no_index, N_("passed to `diff`")),
> +		OPT_STRING(0, "start-from", &start_file, N_("start-from"),
> +			   N_("start viewing diff from the specified file")),
>  		OPT_END()
>  	};

This may be a good UI to "difftool".

> @@ -724,6 +726,9 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
>  			     builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN |
>  			     PARSE_OPT_KEEP_DASHDASH);
>  
> +	if (start_file)
> +		setenv("START_FILE", start_file, 1);

Unacceptable.  Nothing gives Git the right to squat on such a
generic name, and there is no hint that it is used to specify the
starting point of what operation.  In addition, I do not see a good
reason why we need to use an environment variable in the first
place.  We run "diff" as an external process, with GIT_EXTERNAL_DIFF
environment pointing back at us, no?  This information should be
passed from its command line.

> diff --git a/diff.c b/diff.c
> index 69e3bc00ed8f..cdad26f99063 100644
> --- a/diff.c
> +++ b/diff.c
> @@ -4249,6 +4249,7 @@ static void run_external_diff(const char *pgm,
>  			      const char *xfrm_msg,
>  			      struct diff_options *o)
>  {
> +	const char *start_file = NULL;
>  	struct strvec argv = STRVEC_INIT;
>  	struct strvec env = STRVEC_INIT;
>  	struct diff_queue_struct *q = &diff_queued_diff;
> @@ -4272,9 +4273,17 @@ static void run_external_diff(const char *pgm,
>  
>  	diff_free_filespec_data(one);
>  	diff_free_filespec_data(two);
> +
> +	start_file = xstrdup_or_null(getenv("START_FILE"));
> +	if (start_file) {
> +		if (strcmp(start_file, name))
> +			goto finish;
> +		unsetenv("START_FILE");
> +	}

Again, an unacceptable "hack".  "start the diff output showing from
this path" would plausibly a good feature even outside the scope of
"difftool", and the feature should not be limited to the external
diff interface.  More on this later.

>  	if (run_command_v_opt_cd_env(argv.v, RUN_USING_SHELL, NULL, env.v))
>  		die(_("external diff died, stopping at %s"), name);
>  
> +finish:
>  	remove_tempfile();
>  	strvec_clear(&argv);
>  	strvec_clear(&env);
> diff --git a/diff.h b/diff.h
> index 2ff2b1c7f2ca..f67c43f5af95 100644
> --- a/diff.h
> +++ b/diff.h
> @@ -86,18 +86,18 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
>  
>  typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data);
>  
> -#define DIFF_FORMAT_RAW		0x0001
> -#define DIFF_FORMAT_DIFFSTAT	0x0002
> -#define DIFF_FORMAT_NUMSTAT	0x0004
> -#define DIFF_FORMAT_SUMMARY	0x0008
> -#define DIFF_FORMAT_PATCH	0x0010
> -#define DIFF_FORMAT_SHORTSTAT	0x0020
> -#define DIFF_FORMAT_DIRSTAT	0x0040
> +#define DIFF_FORMAT_RAW		(1U<<0)
> +#define DIFF_FORMAT_DIFFSTAT	(1U<<1)
> +#define DIFF_FORMAT_NUMSTAT	(1U<<2)
> +#define DIFF_FORMAT_SUMMARY	(1U<<3)
> +#define DIFF_FORMAT_PATCH	(1U<<4)
> +#define DIFF_FORMAT_SHORTSTAT	(1U<<5)
> +#define DIFF_FORMAT_DIRSTAT	(1U<<6)
>  
>  /* These override all above */
> -#define DIFF_FORMAT_NAME	0x0100
> -#define DIFF_FORMAT_NAME_STATUS	0x0200
> -#define DIFF_FORMAT_CHECKDIFF	0x0400
> +#define DIFF_FORMAT_NAME	(1U<<8)
> +#define DIFF_FORMAT_NAME_STATUS	(1U<<9)
> +#define DIFF_FORMAT_CHECKDIFF	(1U<<10)

Do we need these changes for the new feature to work?

I also find this "skip and discard ones earlier than the given path"
makes the utility of the feature artificially narrower than needed,
when I imagine how else this feature, or a variant of it, would be
useful in other situations.  For example, consider that there are 5
paths, and you've seen 3 of them so far before you went off, so you
are restarting from 4th file.  But wouldn't it be more useful, after
showing the 4th and 5th file, if the tool wraps around to show 1st,
2nd, and 3rd file if the user kept going?

I suspect that this feature fits the overall system much better if
it is implemented as a new step in the diffcore transformation.  The
way our diff subsystem works is roughly:

 * The front-end "diff", "diff-files", "diff-index" and "diff-trees"
   are given two "tree like things" to compare, and feeds bunch of
   <old, new> tuples to the diff internal machinery.  Each of these
   tuples are called "filepairs", and a "pair" has two "filespecs",
   one describing the contents, the mode, and the path in the "old"
   side of the "tree like things", the other describing the
   contents, the mode, and the path in the "new" side of the "tree
   like things".

 * The series of filepairs are given to the "diffcore" machinery,
   where they may be broken (i.e. a filepair that says that the old
   contents of "hello.txt" was X, and the new contents of
   "hello.txt" is Y, may become two filepairs, one that says that
   the "hello.txt" file with contents X used to be in the old tree
   but there is nothing corresponding to it in the new tree, and the
   other says that a new "hello.txt" with contents Y appeared
   without corresponding thing in the old tree), matched (i.e. there
   may originally be two filepairs, one that says path A.txt appears
   on the old side but disappeared on the new side, and the other
   that says path sub/A.txt did not exist on the old side but
   appears on the new side---these two filepairs may be merged to
   express "A.txt on the old side got renamed to sub/A.txt on the
   new side"), etc.

 * The set of filepairs processed in the "diffcore" machinery is
   given to the backend and each filepair will be shown in the
   output, as a series of patches, a diffstat, etc.

There is a step in the "diffcore" machinery called "diffcore-order".
The front-ends all feed the filepairs alphabetically to the
"diffcore" machinery, but "diffcore-order" can reorder them, so that
the original order that the "git diff HEAD --" frontend found the
changes may be to "hello.c" and then "hello.h" (because .c sorts
before .h), but the users can specify with the "-O<orderfile>"
option that they want to view the header files before the source
files.  When the set of filepairs exits the diffcore machinery, the
original "hello.c" then "hello.h" order may get modified to show
"hello.h" then "hello.c".  It probably is the simplest to model this
new feature after how "diffcore-order" does it.

So, perhaps we can introduce a new "diffcore-rotate" step, where the
filepairs before the specified location are rotated out to the end
of the filepairs?

The following is just a quick draft that is only lightly tested by
running itself with the "--rotate-to=diffcore-rotate.c" option, but
it should be sufficient to get you started.  You should add a way to
diagnose that the name given to the "--start-file" option actually
exists in the diff on the "difftool" side, because a path that does
not exist in the patch with the following code is simply ignored
(and that is very much deliberate, because we do not want it to die
while running "git log -p --rotate-to=X" where some changes may or
may not touch X).


$ ./git diff --stat -p --rotate-to=diffcore-rotate.c HEAD

 diffcore-rotate.c | 35 +++++++++++++++++++++++++++++++++++
 diffcore.h        |  1 +
 Makefile          |  1 +
 diff.c            |  4 ++++
 diff.h            |  1 +
 5 files changed, 42 insertions(+)

diff --git c/diffcore-rotate.c w/diffcore-rotate.c
new file mode 100644
index 0000000000..0d17901616
--- /dev/null
+++ w/diffcore-rotate.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021, Google LLC.
+ * Based on diffcore-order.c, which is Copyright (C) 2005, Junio C Hamano
+ */
+#include "cache.h"
+#include "diff.h"
+#include "diffcore.h"
+
+void diffcore_rotate(const char *rotate_to_filename)
+{
+	struct diff_queue_struct *q = &diff_queued_diff;
+	struct diff_queue_struct outq;
+	int rotate_to, i;
+
+	if (!q->nr)
+		return;
+
+	for (i = 0; i < q->nr; i++)
+		if (!strcmp(rotate_to_filename, q->queue[i]->two->path))
+			break;
+	/* we did not find the specified path */
+	if (q->nr <= i)
+		return;
+
+	DIFF_QUEUE_CLEAR(&outq);
+	rotate_to = i;
+
+	for (i = rotate_to; i < q->nr; i++)
+		diff_q(&outq, q->queue[i]);
+	for (i = 0; i < rotate_to; i++)
+		diff_q(&outq, q->queue[i]);
+
+	free(q->queue);
+	*q = outq;
+}
diff --git c/diffcore.h w/diffcore.h
index d2a63c5c71..bd5959375b 100644
--- c/diffcore.h
+++ w/diffcore.h
@@ -164,6 +164,7 @@ void diffcore_rename(struct diff_options *);
 void diffcore_merge_broken(void);
 void diffcore_pickaxe(struct diff_options *);
 void diffcore_order(const char *orderfile);
+void diffcore_rotate(const char *rotate_to_filename);
 
 /* low-level interface to diffcore_order */
 struct obj_order {
diff --git c/Makefile w/Makefile
index b797033c58..031b0b88e6 100644
--- c/Makefile
+++ w/Makefile
@@ -869,6 +869,7 @@ LIB_OBJS += diffcore-delta.o
 LIB_OBJS += diffcore-order.o
 LIB_OBJS += diffcore-pickaxe.o
 LIB_OBJS += diffcore-rename.o
+LIB_OBJS += diffcore-rotate.o
 LIB_OBJS += dir-iterator.o
 LIB_OBJS += dir.o
 LIB_OBJS += editor.o
diff --git c/diff.c w/diff.c
index 69e3bc00ed..90a8d5abd0 100644
--- c/diff.c
+++ w/diff.c
@@ -5599,6 +5599,8 @@ static void prep_parse_options(struct diff_options *options)
 			  DIFF_PICKAXE_REGEX, PARSE_OPT_NONEG),
 		OPT_FILENAME('O', NULL, &options->orderfile,
 			     N_("control the order in which files appear in the output")),
+		OPT_STRING(0, "rotate-to", &options->rotate_to, N_("<path>"),
+			   N_("show the change in the specified path first")),
 		OPT_CALLBACK_F(0, "find-object", options, N_("<object-id>"),
 			       N_("look for differences that change the number of occurrences of the specified object"),
 			       PARSE_OPT_NONEG, diff_opt_find_object),
@@ -6669,6 +6671,8 @@ void diffcore_std(struct diff_options *options)
 		diffcore_pickaxe(options);
 	if (options->orderfile)
 		diffcore_order(options->orderfile);
+	if (options->rotate_to)
+		diffcore_rotate(options->rotate_to);
 	if (!options->found_follow)
 		/* See try_to_follow_renames() in tree-diff.c */
 		diff_resolve_rename_copy();
diff --git c/diff.h w/diff.h
index 2ff2b1c7f2..0801469e63 100644
--- c/diff.h
+++ w/diff.h
@@ -226,6 +226,7 @@ enum diff_submodule_format {
  */
 struct diff_options {
 	const char *orderfile;
+	const char *rotate_to;
 
 	/**
 	 * A constant string (can and typically does contain newlines to look for

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

* Re: [PATCH v3] difftool.c: learn a new way start from specified file
  2021-02-09 18:17     ` Junio C Hamano
@ 2021-02-10 17:00       ` 胡哲宁
  2021-02-10 18:16         ` Junio C Hamano
  0 siblings, 1 reply; 37+ messages in thread
From: 胡哲宁 @ 2021-02-10 17:00 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: ZheNing Hu via GitGitGadget, Git List, Denton Liu, David Aguilar,
	John Keeping, Ryan Zoeller

Junio C Hamano <gitster@pobox.com> 于2021年2月10日周三 上午2:17写道:
>
> "ZheNing Hu via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
> > index 484c485fd06c..552be097dfea 100644
> > --- a/Documentation/git-difftool.txt
> > +++ b/Documentation/git-difftool.txt
> > @@ -34,6 +34,9 @@ OPTIONS
> >       This is the default behaviour; the option is provided to
> >       override any configuration settings.
> >
> > +--start-from::
> > +     Start viewing diff from the specified file.
> > +
>
> There is nothing that specifies a file in the above ;-)
>
>         --start-from=<file>::
>                 Start viewing ...
>
> This is even more important as SYNOPSIS section of this manual page
> does not duplicate the list of options and their arguments.
>
I admit my mistake,thanks for reminding.
> >  -t <tool>::
> >  --tool=<tool>::
> >       Use the diff tool specified by <tool>.  Valid values include
>
> There are many things I dislike about this patch, but do not take it
> as a personal attack.  I'll try to suggest an alternative at the end,
> but read along.
>
Of course I humbly accepted your criticism,I am only a sophomore in
university after all,It is extremely important to listen to your suggestions.
> > diff --git a/builtin/difftool.c b/builtin/difftool.c
> > index 6e18e623fddf..67d2befa1210 100644
> > --- a/builtin/difftool.c
> > +++ b/builtin/difftool.c
> > @@ -690,7 +690,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
> >  {
> >       int use_gui_tool = 0, dir_diff = 0, prompt = -1, symlinks = 0,
> >           tool_help = 0, no_index = 0;
> > -     static char *difftool_cmd = NULL, *extcmd = NULL;
> > +     static char *difftool_cmd = NULL, *extcmd = NULL, *start_file = NULL;
> >       struct option builtin_difftool_options[] = {
> >               OPT_BOOL('g', "gui", &use_gui_tool,
> >                        N_("use `diff.guitool` instead of `diff.tool`")),
> > @@ -714,6 +714,8 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
> >               OPT_STRING('x', "extcmd", &extcmd, N_("command"),
> >                          N_("specify a custom command for viewing diffs")),
> >               OPT_ARGUMENT("no-index", &no_index, N_("passed to `diff`")),
> > +             OPT_STRING(0, "start-from", &start_file, N_("start-from"),
> > +                        N_("start viewing diff from the specified file")),
> >               OPT_END()
> >       };
>
> This may be a good UI to "difftool".
>
> > @@ -724,6 +726,9 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
> >                            builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN |
> >                            PARSE_OPT_KEEP_DASHDASH);
> >
> > +     if (start_file)
> > +             setenv("START_FILE", start_file, 1);
>
> Unacceptable.  Nothing gives Git the right to squat on such a
> generic name, and there is no hint that it is used to specify the
> starting point of what operation.  In addition, I do not see a good
> reason why we need to use an environment variable in the first
> place.  We run "diff" as an external process, with GIT_EXTERNAL_DIFF
> environment pointing back at us, no?  This information should be
> passed from its command line.
Sure,I using environment variables originally hoped can be used in
git--difftool-helper.sh, later I found it was not easy to deal with, so I am
attempt to use environment variables to transmit information in
`run_external_diff`,now it seems that this method is not very good ...
>
> > diff --git a/diff.c b/diff.c
> > index 69e3bc00ed8f..cdad26f99063 100644
> > --- a/diff.c
> > +++ b/diff.c
> > @@ -4249,6 +4249,7 @@ static void run_external_diff(const char *pgm,
> >                             const char *xfrm_msg,
> >                             struct diff_options *o)
> >  {
> > +     const char *start_file = NULL;
> >       struct strvec argv = STRVEC_INIT;
> >       struct strvec env = STRVEC_INIT;
> >       struct diff_queue_struct *q = &diff_queued_diff;
> > @@ -4272,9 +4273,17 @@ static void run_external_diff(const char *pgm,
> >
> >       diff_free_filespec_data(one);
> >       diff_free_filespec_data(two);
> > +
> > +     start_file = xstrdup_or_null(getenv("START_FILE"));
> > +     if (start_file) {
> > +             if (strcmp(start_file, name))
> > +                     goto finish;
> > +             unsetenv("START_FILE");
> > +     }
>
> Again, an unacceptable "hack".  "start the diff output showing from
> this path" would plausibly a good feature even outside the scope of
> "difftool", and the feature should not be limited to the external
> diff interface.  More on this later.
What you said `from its command line` is using `git difftool
--rotate-to=<file>`,
Maybe I didn’t know whether to deal with the subcommands of `diff`, now I admit
that passing from parameters is better than passing environment variables.
>
> >       if (run_command_v_opt_cd_env(argv.v, RUN_USING_SHELL, NULL, env.v))
> >               die(_("external diff died, stopping at %s"), name);
> >
> > +finish:
> >       remove_tempfile();
> >       strvec_clear(&argv);
> >       strvec_clear(&env);
> > diff --git a/diff.h b/diff.h
> > index 2ff2b1c7f2ca..f67c43f5af95 100644
> > --- a/diff.h
> > +++ b/diff.h
> > @@ -86,18 +86,18 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
> >
> >  typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data);
> >
> > -#define DIFF_FORMAT_RAW              0x0001
> > -#define DIFF_FORMAT_DIFFSTAT 0x0002
> > -#define DIFF_FORMAT_NUMSTAT  0x0004
> > -#define DIFF_FORMAT_SUMMARY  0x0008
> > -#define DIFF_FORMAT_PATCH    0x0010
> > -#define DIFF_FORMAT_SHORTSTAT        0x0020
> > -#define DIFF_FORMAT_DIRSTAT  0x0040
> > +#define DIFF_FORMAT_RAW              (1U<<0)
> > +#define DIFF_FORMAT_DIFFSTAT (1U<<1)
> > +#define DIFF_FORMAT_NUMSTAT  (1U<<2)
> > +#define DIFF_FORMAT_SUMMARY  (1U<<3)
> > +#define DIFF_FORMAT_PATCH    (1U<<4)
> > +#define DIFF_FORMAT_SHORTSTAT        (1U<<5)
> > +#define DIFF_FORMAT_DIRSTAT  (1U<<6)
> >
> >  /* These override all above */
> > -#define DIFF_FORMAT_NAME     0x0100
> > -#define DIFF_FORMAT_NAME_STATUS      0x0200
> > -#define DIFF_FORMAT_CHECKDIFF        0x0400
> > +#define DIFF_FORMAT_NAME     (1U<<8)
> > +#define DIFF_FORMAT_NAME_STATUS      (1U<<9)
> > +#define DIFF_FORMAT_CHECKDIFF        (1U<<10)
>
> Do we need these changes for the new feature to work?
It has no effect on this new feature. I should put this modification
in an additional commit, right?
>
> I also find this "skip and discard ones earlier than the given path"
> makes the utility of the feature artificially narrower than needed,
> when I imagine how else this feature, or a variant of it, would be
> useful in other situations.  For example, consider that there are 5
> paths, and you've seen 3 of them so far before you went off, so you
> are restarting from 4th file.  But wouldn't it be more useful, after
> showing the 4th and 5th file, if the tool wraps around to show 1st,
> 2nd, and 3rd file if the user kept going?
>
Well, it would be better if you can see 1st, 2nd, 3rd again.
> I suspect that this feature fits the overall system much better if
> it is implemented as a new step in the diffcore transformation.  The
> way our diff subsystem works is roughly:
>
>  * The front-end "diff", "diff-files", "diff-index" and "diff-trees"
>    are given two "tree like things" to compare, and feeds bunch of
>    <old, new> tuples to the diff internal machinery.  Each of these
>    tuples are called "filepairs", and a "pair" has two "filespecs",
>    one describing the contents, the mode, and the path in the "old"
>    side of the "tree like things", the other describing the
>    contents, the mode, and the path in the "new" side of the "tree
>    like things".
>
>  * The series of filepairs are given to the "diffcore" machinery,
>    where they may be broken (i.e. a filepair that says that the old
>    contents of "hello.txt" was X, and the new contents of
>    "hello.txt" is Y, may become two filepairs, one that says that
>    the "hello.txt" file with contents X used to be in the old tree
>    but there is nothing corresponding to it in the new tree, and the
>    other says that a new "hello.txt" with contents Y appeared
>    without corresponding thing in the old tree), matched (i.e. there
>    may originally be two filepairs, one that says path A.txt appears
>    on the old side but disappeared on the new side, and the other
>    that says path sub/A.txt did not exist on the old side but
>    appears on the new side---these two filepairs may be merged to
>    express "A.txt on the old side got renamed to sub/A.txt on the
>    new side"), etc.
>
Thank you for these interpretations on "git diff" for me, it will help me
understand its principle.
>  * The set of filepairs processed in the "diffcore" machinery is
>    given to the backend and each filepair will be shown in the
>    output, as a series of patches, a diffstat, etc.
>
> There is a step in the "diffcore" machinery called "diffcore-order".
> The front-ends all feed the filepairs alphabetically to the
> "diffcore" machinery, but "diffcore-order" can reorder them, so that
> the original order that the "git diff HEAD --" frontend found the
> changes may be to "hello.c" and then "hello.h" (because .c sorts
> before .h), but the users can specify with the "-O<orderfile>"
> option that they want to view the header files before the source
> files.  When the set of filepairs exits the diffcore machinery, the
> original "hello.c" then "hello.h" order may get modified to show
> "hello.h" then "hello.c".  It probably is the simplest to model this
> new feature after how "diffcore-order" does it.
>
Very magical "diffcore-order", when I was looking for a solution yesterday,
I noticed that these functions similar to "diffcore_apply_filter" in
"diffcore_std",
> So, perhaps we can introduce a new "diffcore-rotate" step, where the
> filepairs before the specified location are rotated out to the end
> of the filepairs?
>
Awesome idea. In this way, `difftool --rotate-to=<file>` can call
`diff --rotate-to=<file>` , user can choose the starting file, and they can
also see previous files.
> The following is just a quick draft that is only lightly tested by
> running itself with the "--rotate-to=diffcore-rotate.c" option, but
> it should be sufficient to get you started.  You should add a way to
> diagnose that the name given to the "--start-file" option actually
> exists in the diff on the "difftool" side, because a path that does
> not exist in the patch with the following code is simply ignored
> (and that is very much deliberate, because we do not want it to die
> while running "git log -p --rotate-to=X" where some changes may or
> may not touch X).
Yes, I want to know why being so cautious in git log?If the file name is
wrong, why can't I make it exit? :)
>
>
> $ ./git diff --stat -p --rotate-to=diffcore-rotate.c HEAD
>
>  diffcore-rotate.c | 35 +++++++++++++++++++++++++++++++++++
>  diffcore.h        |  1 +
>  Makefile          |  1 +
>  diff.c            |  4 ++++
>  diff.h            |  1 +
>  5 files changed, 42 insertions(+)
>
> diff --git c/diffcore-rotate.c w/diffcore-rotate.c
> new file mode 100644
> index 0000000000..0d17901616
> --- /dev/null
> +++ w/diffcore-rotate.c
> @@ -0,0 +1,35 @@
> +/*
> + * Copyright (C) 2021, Google LLC.
> + * Based on diffcore-order.c, which is Copyright (C) 2005, Junio C Hamano
> + */
> +#include "cache.h"
> +#include "diff.h"
> +#include "diffcore.h"
> +
> +void diffcore_rotate(const char *rotate_to_filename)
> +{
> +       struct diff_queue_struct *q = &diff_queued_diff;
> +       struct diff_queue_struct outq;
> +       int rotate_to, i;
> +
> +       if (!q->nr)
> +               return;
> +
> +       for (i = 0; i < q->nr; i++)
> +               if (!strcmp(rotate_to_filename, q->queue[i]->two->path))
> +                       break;
> +       /* we did not find the specified path */
> +       if (q->nr <= i)
> +               return;
> +
> +       DIFF_QUEUE_CLEAR(&outq);
> +       rotate_to = i;
> +
> +       for (i = rotate_to; i < q->nr; i++)
> +               diff_q(&outq, q->queue[i]);
> +       for (i = 0; i < rotate_to; i++)
> +               diff_q(&outq, q->queue[i]);
> +
> +       free(q->queue);
> +       *q = outq;
> +}
> diff --git c/diffcore.h w/diffcore.h
> index d2a63c5c71..bd5959375b 100644
> --- c/diffcore.h
> +++ w/diffcore.h
> @@ -164,6 +164,7 @@ void diffcore_rename(struct diff_options *);
>  void diffcore_merge_broken(void);
>  void diffcore_pickaxe(struct diff_options *);
>  void diffcore_order(const char *orderfile);
> +void diffcore_rotate(const char *rotate_to_filename);
>
>  /* low-level interface to diffcore_order */
>  struct obj_order {
> diff --git c/Makefile w/Makefile
> index b797033c58..031b0b88e6 100644
> --- c/Makefile
> +++ w/Makefile
> @@ -869,6 +869,7 @@ LIB_OBJS += diffcore-delta.o
>  LIB_OBJS += diffcore-order.o
>  LIB_OBJS += diffcore-pickaxe.o
>  LIB_OBJS += diffcore-rename.o
> +LIB_OBJS += diffcore-rotate.o
>  LIB_OBJS += dir-iterator.o
>  LIB_OBJS += dir.o
>  LIB_OBJS += editor.o
> diff --git c/diff.c w/diff.c
> index 69e3bc00ed..90a8d5abd0 100644
> --- c/diff.c
> +++ w/diff.c
> @@ -5599,6 +5599,8 @@ static void prep_parse_options(struct diff_options *options)
>                           DIFF_PICKAXE_REGEX, PARSE_OPT_NONEG),
>                 OPT_FILENAME('O', NULL, &options->orderfile,
>                              N_("control the order in which files appear in the output")),
> +               OPT_STRING(0, "rotate-to", &options->rotate_to, N_("<path>"),
> +                          N_("show the change in the specified path first")),
>                 OPT_CALLBACK_F(0, "find-object", options, N_("<object-id>"),
>                                N_("look for differences that change the number of occurrences of the specified object"),
>                                PARSE_OPT_NONEG, diff_opt_find_object),
> @@ -6669,6 +6671,8 @@ void diffcore_std(struct diff_options *options)
>                 diffcore_pickaxe(options);
>         if (options->orderfile)
>                 diffcore_order(options->orderfile);
> +       if (options->rotate_to)
> +               diffcore_rotate(options->rotate_to);
>         if (!options->found_follow)
>                 /* See try_to_follow_renames() in tree-diff.c */
>                 diff_resolve_rename_copy();
> diff --git c/diff.h w/diff.h
> index 2ff2b1c7f2..0801469e63 100644
> --- c/diff.h
> +++ w/diff.h
> @@ -226,6 +226,7 @@ enum diff_submodule_format {
>   */
>  struct diff_options {
>         const char *orderfile;
> +       const char *rotate_to;
>
>         /**
>          * A constant string (can and typically does contain newlines to look for

Thanks for the patch!
After that, there was too little work I could do,do i just need to add
the following
 code in `diff_flush_patch_all_file_pairs`?
if (o->rotate_to && q->nr && strcmp(q->queue[0]->one->path, o->rotate_to) &&
strcmp(q->queue[0]->one->path, o->rotate_to)) {
    error(_("could not find start file name '%s'"), o->rotate_to);
        return;
}
In addition, Do I need to do the documentation and tests related to
your `diff --rotate-to`?
If so, I will finish it, otherwise, I will only do corresponding tests
for `git difftool --rotate-to`.

Thank you Junio, you are like a tireless teacher,

Happy Chinese New Year!

--
ZheNing Hu

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

* Re: [PATCH v3] difftool.c: learn a new way start from specified file
  2021-02-10 17:00       ` 胡哲宁
@ 2021-02-10 18:16         ` Junio C Hamano
  2021-02-10 20:05           ` Junio C Hamano
  2021-02-14  7:53           ` ZheNing Hu
  0 siblings, 2 replies; 37+ messages in thread
From: Junio C Hamano @ 2021-02-10 18:16 UTC (permalink / raw)
  To: 胡哲宁
  Cc: ZheNing Hu via GitGitGadget, Git List, Denton Liu, David Aguilar,
	John Keeping, Ryan Zoeller

胡哲宁 <adlternative@gmail.com> writes:

> It has no effect on this new feature. I should put this modification
> in an additional commit, right?

Or you can just drop it.  It certainly is a distracting change to be
part of this topic.

> Yes, I want to know why being so cautious in git log?If the file name is
> wrong, why can't I make it exit? :)

Imagine a history where file1 and file2 are in the initial commit.
The second commit adds file3 and modifies file2, and then the third
commit modifies file1.  What would happen when you did this?

  $ git log -p --rotate-to=file2

For the commit at HEAD, the set of paths shown would be file1 and
nothing else (because it is the only path that gets modified).  You
cannot start showing from "file2".  Dying (and not showing HEAD~1
and HEAD~2) is the last thing you want to do in this situation.  We
do not even want to give a warning or an error, as it is totally
expected that some commits do not touch a given path---it would be
very unusual if a path is touched by every commit ;-).

For "difftool --start-at=file2", the equation is different.  It does
not traverse history where each commit may or may not modify file2,
and when the user says s/he wants to resume from file2, file2 must
be in the set of paths that have changes, or something is wrong (i.e.
the user meant file3 but mistyped it as file2).

> Awesome idea. In this way, `difftool --rotate-to=<file>` can call
> `diff --rotate-to=<file>` , user can choose the starting file, and they can
> also see previous files.

So "difftool --start-at=<file>" can of use "diff --rotate-to=<file>"
to implement the feature (after all, that is why I wrote it), but
the error condition between the two are quite different.  And ...

> After that, there was too little work I could do,do i just need to add
> the following
>  code in `diff_flush_patch_all_file_pairs`?


> if (o->rotate_to && q->nr && strcmp(q->queue[0]->one->path, o->rotate_to) &&
> strcmp(q->queue[0]->one->path, o->rotate_to)) {
>     error(_("could not find start file name '%s'"), o->rotate_to);
>         return;
> }

... that is why an unconditional change like this in diff.c is not
acceptable, as it would break other codepaths like "git log -p".  If
we were to add an error there, it has to be very limited to exclude
at least "log -p"---there may be other features that share the code
that should not trigger an error for similar reasons.

If diffcore-rotate chooses "missing rotate-to file makes it a no-op"
as its semantics, and if "difftool --start-at" does not want to see
a misspelt filename making it a no-op, then the latter needs to
ensure that the name it got from the user is indeed in the set of
paths that have changes before running "diff --rotate-to" to
implement its "difftool --start-at" feature.

The "missing rotate-to file in the diff_queue MUST NOT cause
diffcore-rotate to error out" rule is probably unnegitiable, but
there are other ways to make it easier to use, though.

For example, we could change the rotate-to logic to mean "start at
the given path, or if such a path does not exist in the diff_queue,
then the first path that sorts after the given path is where we
start".  That way, if the diff_queue has paths A B C D E and
rotate-to gives C, then we rotate the output to C D E A B.  And if
the diff_queue has A B D E and rotate-to gives C, then the output
would become D E A B (instead of becoming a no-op).  Then, a mistyped
filename may not do what the user wanted to do (after all, that is
the definition of MIStyping), but it would do something noticeable
by the user, which may be useful enough and at least would let the
user notice the mistake.

> In addition, Do I need to do the documentation and tests related to
> your `diff --rotate-to`?

Once we know how we want "diff --rotate-to" to behave exactly, I can
help that part further, if you want.  And then you can build on top.

But we need to design exactly what the desired semantics would be
before any of that.

Thanks.


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

* Re: [PATCH v3] difftool.c: learn a new way start from specified file
  2021-02-10 18:16         ` Junio C Hamano
@ 2021-02-10 20:05           ` Junio C Hamano
  2021-02-14  7:53           ` ZheNing Hu
  1 sibling, 0 replies; 37+ messages in thread
From: Junio C Hamano @ 2021-02-10 20:05 UTC (permalink / raw)
  To: 胡哲宁
  Cc: ZheNing Hu via GitGitGadget, Git List, Denton Liu, David Aguilar,
	John Keeping, Ryan Zoeller

Junio C Hamano <gitster@pobox.com> writes:

> So "difftool --start-at=<file>" can of use "diff --rotate-to=<file>"

sorry; s/can of/can of course/.

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

* Re: [PATCH v3] difftool.c: learn a new way start from specified file
  2021-02-10 18:16         ` Junio C Hamano
  2021-02-10 20:05           ` Junio C Hamano
@ 2021-02-14  7:53           ` ZheNing Hu
  1 sibling, 0 replies; 37+ messages in thread
From: ZheNing Hu @ 2021-02-14  7:53 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: ZheNing Hu via GitGitGadget, Git List, Denton Liu, David Aguilar,
	John Keeping, Ryan Zoeller

Junio C Hamano <gitster@pobox.com> 于2021年2月11日周四 上午2:17写道:
>
> 胡哲宁 <adlternative@gmail.com> writes:
>
> > It has no effect on this new feature. I should put this modification
> > in an additional commit, right?
>
> Or you can just drop it.  It certainly is a distracting change to be
> part of this topic.
>
OK.
> > Yes, I want to know why being so cautious in git log?If the file name is
> > wrong, why can't I make it exit? :)
>
> Imagine a history where file1 and file2 are in the initial commit.
> The second commit adds file3 and modifies file2, and then the third
> commit modifies file1.  What would happen when you did this?
>
>   $ git log -p --rotate-to=file2
>
> For the commit at HEAD, the set of paths shown would be file1 and
> nothing else (because it is the only path that gets modified).  You
> cannot start showing from "file2".  Dying (and not showing HEAD~1
> and HEAD~2) is the last thing you want to do in this situation.  We
> do not even want to give a warning or an error, as it is totally
> expected that some commits do not touch a given path---it would be
> very unusual if a path is touched by every commit ;-).
>
Now I understand that in `log -p`, some commit do not have the file, and some
commit have the file. The best way to display the commit without the file
is to keep it as it is, and rotate the commit with the file. And in `difftool`
need to ensure the exist the specified file or give the more matching file
as the beginning(As you mentioned later).
> For "difftool --start-at=file2", the equation is different.  It does
> not traverse history where each commit may or may not modify file2,
> and when the user says s/he wants to resume from file2, file2 must
> be in the set of paths that have changes, or something is wrong (i.e.
> the user meant file3 but mistyped it as file2).
>
> > Awesome idea. In this way, `difftool --rotate-to=<file>` can call
> > `diff --rotate-to=<file>` , user can choose the starting file, and they can
> > also see previous files.
>
> So "difftool --start-at=<file>" can of use "diff --rotate-to=<file>"
> to implement the feature (after all, that is why I wrote it), but
> the error condition between the two are quite different.  And ...

> > After that, there was too little work I could do,do i just need to add
> > the following
> >  code in `diff_flush_patch_all_file_pairs`?
>
>
> > if (o->rotate_to && q->nr && strcmp(q->queue[0]->one->path, o->rotate_to) &&
> > strcmp(q->queue[0]->one->path, o->rotate_to)) {
> >     error(_("could not find start file name '%s'"), o->rotate_to);
> >         return;
> > }
>
> ... that is why an unconditional change like this in diff.c is not
> acceptable, as it would break other codepaths like "git log -p".  If
> we were to add an error there, it has to be very limited to exclude
> at least "log -p"---there may be other features that share the code
> that should not trigger an error for similar reasons.
>
> If diffcore-rotate chooses "missing rotate-to file makes it a no-op"
> as its semantics, and if "difftool --start-at" does not want to see
> a misspelt filename making it a no-op, then the latter needs to
> ensure that the name it got from the user is indeed in the set of
> paths that have changes before running "diff --rotate-to" to
> implement its "difftool --start-at" feature.
>
> The "missing rotate-to file in the diff_queue MUST NOT cause
> diffcore-rotate to error out" rule is probably unnegitiable, but
> there are other ways to make it easier to use, though.
>
> For example, we could change the rotate-to logic to mean "start at
> the given path, or if such a path does not exist in the diff_queue,
> then the first path that sorts after the given path is where we
> start".  That way, if the diff_queue has paths A B C D E and
> rotate-to gives C, then we rotate the output to C D E A B.  And if
> the diff_queue has A B D E and rotate-to gives C, then the output
> would become D E A B (instead of becoming a no-op).  Then, a mistyped
> filename may not do what the user wanted to do (after all, that is
> the definition of MIStyping), but it would do something noticeable
> by the user, which may be useful enough and at least would let the
> user notice the mistake.
>
In doing this, I think the processing methods of difftool and other diffs
are unified.I think this kind of processing is actually very easy,
just need to change
> if (!strcmp(rotate_to_filename, q->queue[i]->two->path))
to
> if (strcmp(rotate_to_filename, q->queue[i]->two->path) <= 0)
Of course, it might be better if there is an algorithm that can achieve
the highest degree of file name matching.

Now that `difftool --start-at` and `diff --rotate-to` are unified effects,
is "start-at" just an alias for "rotate-to"?
Or do I need to write like this?
> OPT_STRING(0, "start-with", &options->rotate-to, N_("<path>"),
>   N_("pass from difftool to diff, has the same effort as `rotate-to`")),

> > In addition, Do I need to do the documentation and tests related to
> > your `diff --rotate-to`?
>
> Once we know how we want "diff --rotate-to" to behave exactly, I can
> help that part further, if you want.  And then you can build on top.
>
> But we need to design exactly what the desired semantics would be
> before any of that.
>
> Thanks.
>
Thanks.

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

* [PATCH v4] difftool.c: learn a new way start at specified file
  2021-02-09 15:30   ` [PATCH v3] difftool.c: learn a new way start from specified file ZheNing Hu via GitGitGadget
  2021-02-09 18:17     ` Junio C Hamano
@ 2021-02-14 13:09     ` ZheNing Hu via GitGitGadget
  2021-02-16  1:46       ` Junio C Hamano
  2021-02-16 12:56       ` [PATCH v5 0/2] " ZheNing Hu via GitGitGadget
  1 sibling, 2 replies; 37+ messages in thread
From: ZheNing Hu via GitGitGadget @ 2021-02-14 13:09 UTC (permalink / raw)
  To: git
  Cc: Denton Liu, David Aguilar, John Keeping, Junio C Hamano,
	Ryan Zoeller, ZheNing Hu, ZheNing Hu

From: ZheNing Hu <adlternative@gmail.com>

`git difftool` only allow us to select file to view in turn.
If there is a commit with many files and we exit in the search,
We will have to traverse list again to get the file diff which
we want to see. Therefore, here is a new method: user can use
`git difftool --start-from=<filename>` to start viewing from
the specified file, This will improve the user experience.

`difftool --start-from=<file>` will pass the file name to
`diffcore-rotate`, it will traverse all files in diff_queue,
if it finds a matching file, it will rearrange the order of
diff_filepair of diff_queue, Rotate the file specified by the
user to the first one. If the file name specified by the user
does not match any item in the diff queue, Git will also rotate
the queue, it will find the the first file name larger than the
specified file name as the first element of the new diff_queue.
This will help users find their mistakes.

Signed-off-by: ZheNing Hu <adlternative@gmail.com>
---
    difftool.c: learn a new way start at specified file
    
    git user may should travel the diff list to choice file diff to view, if
    they exit in midway,they must travel it again. By starting from the
    specified file method, provides a possibility for this user-friendly
    solution.
    
    this patch's origin discuss is here:
    https://lore.kernel.org/git/gOXOaoqn-E9A2ob7ykWEcDc7ZxmSwAjcP5CCFKfr5ejCOWZQ1lfAUZcbgYT9AyQCcDgJvCrnrtziXiels-Hxol3xlkGTVHk24SvAdaSUtKQ=@rtzoeller.com/
    
    Maybe this patch is more like skip to in Junio's original thread than
    the previous versions.
    
    Thanks!

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-870%2Fadlternative%2Fdifftool_save_point-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-870/adlternative/difftool_save_point-v4
Pull-Request: https://github.com/gitgitgadget/git/pull/870

Range-diff vs v3:

 1:  29fc6b4bc08f ! 1:  3accfb942301 difftool.c: learn a new way start from specified file
     @@ Metadata
      Author: ZheNing Hu <adlternative@gmail.com>
      
       ## Commit message ##
     -    difftool.c: learn a new way start from specified file
     +    difftool.c: learn a new way start at specified file
      
          `git difftool` only allow us to select file to view in turn.
          If there is a commit with many files and we exit in the search,
          We will have to traverse list again to get the file diff which
          we want to see. Therefore, here is a new method: user can use
          `git difftool --start-from=<filename>` to start viewing from
     -    the specified file. This will improve the user experience.
     -    At the same time, turn bit field constants into bit shift format
     -    in `diff.h`.
     +    the specified file, This will improve the user experience.
     +
     +    `difftool --start-from=<file>` will pass the file name to
     +    `diffcore-rotate`, it will traverse all files in diff_queue,
     +    if it finds a matching file, it will rearrange the order of
     +    diff_filepair of diff_queue, Rotate the file specified by the
     +    user to the first one. If the file name specified by the user
     +    does not match any item in the diff queue, Git will also rotate
     +    the queue, it will find the the first file name larger than the
     +    specified file name as the first element of the new diff_queue.
     +    This will help users find their mistakes.
      
          Signed-off-by: ZheNing Hu <adlternative@gmail.com>
      
     @@ Documentation/git-difftool.txt: OPTIONS
       	This is the default behaviour; the option is provided to
       	override any configuration settings.
       
     -+--start-from::
     ++--start-from=<file>::
      +	Start viewing diff from the specified file.
      +
       -t <tool>::
       --tool=<tool>::
       	Use the diff tool specified by <tool>.  Valid values include
      
     - ## builtin/difftool.c ##
     -@@ builtin/difftool.c: int cmd_difftool(int argc, const char **argv, const char *prefix)
     - {
     - 	int use_gui_tool = 0, dir_diff = 0, prompt = -1, symlinks = 0,
     - 	    tool_help = 0, no_index = 0;
     --	static char *difftool_cmd = NULL, *extcmd = NULL;
     -+	static char *difftool_cmd = NULL, *extcmd = NULL, *start_file = NULL;
     - 	struct option builtin_difftool_options[] = {
     - 		OPT_BOOL('g', "gui", &use_gui_tool,
     - 			 N_("use `diff.guitool` instead of `diff.tool`")),
     -@@ builtin/difftool.c: int cmd_difftool(int argc, const char **argv, const char *prefix)
     - 		OPT_STRING('x', "extcmd", &extcmd, N_("command"),
     - 			   N_("specify a custom command for viewing diffs")),
     - 		OPT_ARGUMENT("no-index", &no_index, N_("passed to `diff`")),
     -+		OPT_STRING(0, "start-from", &start_file, N_("start-from"),
     -+			   N_("start viewing diff from the specified file")),
     - 		OPT_END()
     - 	};
     - 
     -@@ builtin/difftool.c: int cmd_difftool(int argc, const char **argv, const char *prefix)
     - 			     builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN |
     - 			     PARSE_OPT_KEEP_DASHDASH);
     - 
     -+	if (start_file)
     -+		setenv("START_FILE", start_file, 1);
     -+
     - 	if (tool_help)
     - 		return print_tool_help();
     - 
     + ## Makefile ##
     +@@ Makefile: LIB_OBJS += diffcore-delta.o
     + LIB_OBJS += diffcore-order.o
     + LIB_OBJS += diffcore-pickaxe.o
     + LIB_OBJS += diffcore-rename.o
     ++LIB_OBJS += diffcore-rotate.o
     + LIB_OBJS += dir-iterator.o
     + LIB_OBJS += dir.o
     + LIB_OBJS += editor.o
      
       ## diff.c ##
     -@@ diff.c: static void run_external_diff(const char *pgm,
     - 			      const char *xfrm_msg,
     - 			      struct diff_options *o)
     - {
     -+	const char *start_file = NULL;
     - 	struct strvec argv = STRVEC_INIT;
     - 	struct strvec env = STRVEC_INIT;
     - 	struct diff_queue_struct *q = &diff_queued_diff;
     -@@ diff.c: static void run_external_diff(const char *pgm,
     - 
     - 	diff_free_filespec_data(one);
     - 	diff_free_filespec_data(two);
     -+
     -+	start_file = xstrdup_or_null(getenv("START_FILE"));
     -+	if (start_file) {
     -+		if (strcmp(start_file, name))
     -+			goto finish;
     -+		unsetenv("START_FILE");
     -+	}
     - 	if (run_command_v_opt_cd_env(argv.v, RUN_USING_SHELL, NULL, env.v))
     - 		die(_("external diff died, stopping at %s"), name);
     - 
     -+finish:
     - 	remove_tempfile();
     - 	strvec_clear(&argv);
     - 	strvec_clear(&env);
     +@@ diff.c: static void prep_parse_options(struct diff_options *options)
     + 			  DIFF_PICKAXE_REGEX, PARSE_OPT_NONEG),
     + 		OPT_FILENAME('O', NULL, &options->orderfile,
     + 			     N_("control the order in which files appear in the output")),
     ++		OPT_STRING(0, "rotate-to", &options->rotate_to, N_("<path>"),
     ++			   N_("show the change in the specified path first")),
     ++		OPT_STRING(0, "start-from", &options->rotate_to, N_("<path>"),
     ++			   N_("pass from difftool to diff, has the same effort as `rotate-to`")),
     + 		OPT_CALLBACK_F(0, "find-object", options, N_("<object-id>"),
     + 			       N_("look for differences that change the number of occurrences of the specified object"),
     + 			       PARSE_OPT_NONEG, diff_opt_find_object),
     +@@ diff.c: void diffcore_std(struct diff_options *options)
     + 		diffcore_pickaxe(options);
     + 	if (options->orderfile)
     + 		diffcore_order(options->orderfile);
     ++	if (options->rotate_to)
     ++		diffcore_rotate(options->rotate_to);
     + 	if (!options->found_follow)
     + 		/* See try_to_follow_renames() in tree-diff.c */
     + 		diff_resolve_rename_copy();
      
       ## diff.h ##
     -@@ diff.h: typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
     - 
     - typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data);
     - 
     --#define DIFF_FORMAT_RAW		0x0001
     --#define DIFF_FORMAT_DIFFSTAT	0x0002
     --#define DIFF_FORMAT_NUMSTAT	0x0004
     --#define DIFF_FORMAT_SUMMARY	0x0008
     --#define DIFF_FORMAT_PATCH	0x0010
     --#define DIFF_FORMAT_SHORTSTAT	0x0020
     --#define DIFF_FORMAT_DIRSTAT	0x0040
     -+#define DIFF_FORMAT_RAW		(1U<<0)
     -+#define DIFF_FORMAT_DIFFSTAT	(1U<<1)
     -+#define DIFF_FORMAT_NUMSTAT	(1U<<2)
     -+#define DIFF_FORMAT_SUMMARY	(1U<<3)
     -+#define DIFF_FORMAT_PATCH	(1U<<4)
     -+#define DIFF_FORMAT_SHORTSTAT	(1U<<5)
     -+#define DIFF_FORMAT_DIRSTAT	(1U<<6)
     +@@ diff.h: enum diff_submodule_format {
     +  */
     + struct diff_options {
     + 	const char *orderfile;
     ++	const char *rotate_to;
       
     - /* These override all above */
     --#define DIFF_FORMAT_NAME	0x0100
     --#define DIFF_FORMAT_NAME_STATUS	0x0200
     --#define DIFF_FORMAT_CHECKDIFF	0x0400
     -+#define DIFF_FORMAT_NAME	(1U<<8)
     -+#define DIFF_FORMAT_NAME_STATUS	(1U<<9)
     -+#define DIFF_FORMAT_CHECKDIFF	(1U<<10)
     + 	/**
     + 	 * A constant string (can and typically does contain newlines to look for
     +
     + ## diffcore-rotate.c (new) ##
     +@@
     ++/*
     ++ * Copyright (C) 2021, Google LLC.
     ++ * Based on diffcore-order.c, which is Copyright (C) 2005, Junio C Hamano
     ++ */
     ++#include "cache.h"
     ++#include "diff.h"
     ++#include "diffcore.h"
     ++
     ++void diffcore_rotate(const char *rotate_to_filename)
     ++{
     ++	struct diff_queue_struct *q = &diff_queued_diff;
     ++	struct diff_queue_struct outq;
     ++	int rotate_to, i;
     ++
     ++	if (!q->nr)
     ++		return;
     ++
     ++	for (i = 0; i < q->nr; i++)
     ++		if (strcmp(rotate_to_filename, q->queue[i]->two->path) <= 0)
     ++			break;
     ++	/* we did not find the specified path */
     ++	if (q->nr <= i)
     ++		return;
     ++
     ++	DIFF_QUEUE_CLEAR(&outq);
     ++	rotate_to = i;
     ++
     ++	for (i = rotate_to; i < q->nr; i++)
     ++		diff_q(&outq, q->queue[i]);
     ++	for (i = 0; i < rotate_to; i++)
     ++		diff_q(&outq, q->queue[i]);
     ++
     ++	free(q->queue);
     ++	*q = outq;
     ++}
     +
     + ## diffcore.h ##
     +@@ diffcore.h: void diffcore_rename(struct diff_options *);
     + void diffcore_merge_broken(void);
     + void diffcore_pickaxe(struct diff_options *);
     + void diffcore_order(const char *orderfile);
     ++void diffcore_rotate(const char *rotate_to_filename);
       
     - /* Same as output_format = 0 but we know that -s flag was given
     -  * and we should not give default value to output_format.
     + /* low-level interface to diffcore_order */
     + struct obj_order {
      
       ## t/t7800-difftool.sh ##
      @@ t/t7800-difftool.sh: test_expect_success 'difftool --gui, --tool and --extcmd are mutually exclusive'
     @@ t/t7800-difftool.sh: test_expect_success 'difftool --gui, --tool and --extcmd ar
      +	test_when_finished git reset --hard &&
      +	echo 1 >1 &&
      +	echo 2 >2 &&
     -+	echo 3 >3 &&
     -+	git add 1 2 3 &&
     -+	git commit -a -m "123" &&
     -+	git difftool --start-from="2" HEAD^ 2>&1 >output &&
     -+	test_line_count = 4 output
     ++	echo 4 >4 &&
     ++	git add 1 2 4 &&
     ++	git commit -a -m "124" &&
     ++	git difftool --no-prompt --extcmd=cat --start-from="2" HEAD^  >output &&
     ++	cat >expect <<-\EOF &&
     ++	2
     ++	4
     ++	1
     ++	EOF
     ++	test_cmp output expect &&
     ++	git difftool --no-prompt --extcmd=cat --start-from="3" HEAD^  >output &&
     ++	cat >expect <<-\EOF &&
     ++	4
     ++	1
     ++	2
     ++	EOF
     ++	test_cmp output expect
      +'
     -+
       test_done


 Documentation/git-difftool.txt |  3 +++
 Makefile                       |  1 +
 diff.c                         |  6 ++++++
 diff.h                         |  1 +
 diffcore-rotate.c              | 35 ++++++++++++++++++++++++++++++++++
 diffcore.h                     |  1 +
 t/t7800-difftool.sh            | 23 ++++++++++++++++++++++
 7 files changed, 70 insertions(+)
 create mode 100644 diffcore-rotate.c

diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index 484c485fd06c..b2bb4e00f683 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -34,6 +34,9 @@ OPTIONS
 	This is the default behaviour; the option is provided to
 	override any configuration settings.
 
+--start-from=<file>::
+	Start viewing diff from the specified file.
+
 -t <tool>::
 --tool=<tool>::
 	Use the diff tool specified by <tool>.  Valid values include
diff --git a/Makefile b/Makefile
index 4edfda3e009d..6b1f6b72629a 100644
--- a/Makefile
+++ b/Makefile
@@ -882,6 +882,7 @@ LIB_OBJS += diffcore-delta.o
 LIB_OBJS += diffcore-order.o
 LIB_OBJS += diffcore-pickaxe.o
 LIB_OBJS += diffcore-rename.o
+LIB_OBJS += diffcore-rotate.o
 LIB_OBJS += dir-iterator.o
 LIB_OBJS += dir.o
 LIB_OBJS += editor.o
diff --git a/diff.c b/diff.c
index 69e3bc00ed8f..c41bdcabb791 100644
--- a/diff.c
+++ b/diff.c
@@ -5599,6 +5599,10 @@ static void prep_parse_options(struct diff_options *options)
 			  DIFF_PICKAXE_REGEX, PARSE_OPT_NONEG),
 		OPT_FILENAME('O', NULL, &options->orderfile,
 			     N_("control the order in which files appear in the output")),
+		OPT_STRING(0, "rotate-to", &options->rotate_to, N_("<path>"),
+			   N_("show the change in the specified path first")),
+		OPT_STRING(0, "start-from", &options->rotate_to, N_("<path>"),
+			   N_("pass from difftool to diff, has the same effort as `rotate-to`")),
 		OPT_CALLBACK_F(0, "find-object", options, N_("<object-id>"),
 			       N_("look for differences that change the number of occurrences of the specified object"),
 			       PARSE_OPT_NONEG, diff_opt_find_object),
@@ -6669,6 +6673,8 @@ void diffcore_std(struct diff_options *options)
 		diffcore_pickaxe(options);
 	if (options->orderfile)
 		diffcore_order(options->orderfile);
+	if (options->rotate_to)
+		diffcore_rotate(options->rotate_to);
 	if (!options->found_follow)
 		/* See try_to_follow_renames() in tree-diff.c */
 		diff_resolve_rename_copy();
diff --git a/diff.h b/diff.h
index 2ff2b1c7f2ca..0801469e6390 100644
--- a/diff.h
+++ b/diff.h
@@ -226,6 +226,7 @@ enum diff_submodule_format {
  */
 struct diff_options {
 	const char *orderfile;
+	const char *rotate_to;
 
 	/**
 	 * A constant string (can and typically does contain newlines to look for
diff --git a/diffcore-rotate.c b/diffcore-rotate.c
new file mode 100644
index 000000000000..1bcfd935cf50
--- /dev/null
+++ b/diffcore-rotate.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021, Google LLC.
+ * Based on diffcore-order.c, which is Copyright (C) 2005, Junio C Hamano
+ */
+#include "cache.h"
+#include "diff.h"
+#include "diffcore.h"
+
+void diffcore_rotate(const char *rotate_to_filename)
+{
+	struct diff_queue_struct *q = &diff_queued_diff;
+	struct diff_queue_struct outq;
+	int rotate_to, i;
+
+	if (!q->nr)
+		return;
+
+	for (i = 0; i < q->nr; i++)
+		if (strcmp(rotate_to_filename, q->queue[i]->two->path) <= 0)
+			break;
+	/* we did not find the specified path */
+	if (q->nr <= i)
+		return;
+
+	DIFF_QUEUE_CLEAR(&outq);
+	rotate_to = i;
+
+	for (i = rotate_to; i < q->nr; i++)
+		diff_q(&outq, q->queue[i]);
+	for (i = 0; i < rotate_to; i++)
+		diff_q(&outq, q->queue[i]);
+
+	free(q->queue);
+	*q = outq;
+}
diff --git a/diffcore.h b/diffcore.h
index d2a63c5c71f4..bd5959375bf4 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -164,6 +164,7 @@ void diffcore_rename(struct diff_options *);
 void diffcore_merge_broken(void);
 void diffcore_pickaxe(struct diff_options *);
 void diffcore_order(const char *orderfile);
+void diffcore_rotate(const char *rotate_to_filename);
 
 /* low-level interface to diffcore_order */
 struct obj_order {
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 9662abc1e784..949d07d70fe1 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -762,4 +762,27 @@ test_expect_success 'difftool --gui, --tool and --extcmd are mutually exclusive'
 	test_must_fail git difftool --gui --tool=test-tool --extcmd=cat
 '
 
+test_expect_success 'difftool --start-from' '
+	difftool_test_setup &&
+	test_when_finished git reset --hard &&
+	echo 1 >1 &&
+	echo 2 >2 &&
+	echo 4 >4 &&
+	git add 1 2 4 &&
+	git commit -a -m "124" &&
+	git difftool --no-prompt --extcmd=cat --start-from="2" HEAD^  >output &&
+	cat >expect <<-\EOF &&
+	2
+	4
+	1
+	EOF
+	test_cmp output expect &&
+	git difftool --no-prompt --extcmd=cat --start-from="3" HEAD^  >output &&
+	cat >expect <<-\EOF &&
+	4
+	1
+	2
+	EOF
+	test_cmp output expect
+'
 test_done

base-commit: e6362826a0409539642a5738db61827e5978e2e4
-- 
gitgitgadget

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

* Re: [PATCH v4] difftool.c: learn a new way start at specified file
  2021-02-14 13:09     ` [PATCH v4] difftool.c: learn a new way start at " ZheNing Hu via GitGitGadget
@ 2021-02-16  1:46       ` Junio C Hamano
  2021-02-16 12:56       ` [PATCH v5 0/2] " ZheNing Hu via GitGitGadget
  1 sibling, 0 replies; 37+ messages in thread
From: Junio C Hamano @ 2021-02-16  1:46 UTC (permalink / raw)
  To: ZheNing Hu via GitGitGadget
  Cc: git, Denton Liu, David Aguilar, John Keeping, Ryan Zoeller, ZheNing Hu

"ZheNing Hu via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: ZheNing Hu <adlternative@gmail.com>
>
> `git difftool` only allow us to select file to view in turn.
> If there is a commit with many files and we exit in the search,
> We will have to traverse list again to get the file diff which
> we want to see. Therefore, here is a new method: user can use
> `git difftool --start-from=<filename>` to start viewing from
> the specified file, This will improve the user experience.

It appears that you seem to have based this patch on my "if we were
to make 'git diff' help you by adding to diffcore pipeline, it would
look like this" illustration patch.

But I later sent a real version of "diff --rotate-to/--start-at"
patch (and Cc'ed you, IIRC).

  https://lore.kernel.org/git/xmqqo8gqwasu.fsf@gitster.c.googlers.com/

Please build on top of that patch instead.  E.g.

    $ git fetch
    $ git checkout -b zh/difftool-start-at fb4bfd0f8b

then work on that topic branch, perhaps.  You do not have to (and
you do not want to) include my changes to your patches.

Thanks.

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

* [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-14 13:09     ` [PATCH v4] difftool.c: learn a new way start at " ZheNing Hu via GitGitGadget
  2021-02-16  1:46       ` Junio C Hamano
@ 2021-02-16 12:56       ` ZheNing Hu via GitGitGadget
  2021-02-16 12:56         ` [PATCH v5 1/2] diff: --{rotate,skip}-to=<path> Junio C Hamano via GitGitGadget
                           ` (3 more replies)
  1 sibling, 4 replies; 37+ messages in thread
From: ZheNing Hu via GitGitGadget @ 2021-02-16 12:56 UTC (permalink / raw)
  To: git
  Cc: Denton Liu, David Aguilar, John Keeping, Junio C Hamano,
	Ryan Zoeller, ZheNing Hu

git user may should travel the diff list to choice file diff to view, if
they exit in midway,they must travel it again. By starting from the
specified file method, provides a possibility for this user-friendly
solution.

this patch's origin discuss is here:
https://lore.kernel.org/git/gOXOaoqn-E9A2ob7ykWEcDc7ZxmSwAjcP5CCFKfr5ejCOWZQ1lfAUZcbgYT9AyQCcDgJvCrnrtziXiels-Hxol3xlkGTVHk24SvAdaSUtKQ=@rtzoeller.com/

Thanks!

Junio C Hamano (1):
  diff: --{rotate,skip}-to=<path>

ZheNing Hu (1):
  difftool.c: learn a new way start at specified file

 Documentation/diff-options.txt |  8 ++++
 Documentation/git-difftool.txt | 10 +++++
 Documentation/gitdiffcore.txt  | 21 ++++++++++
 Makefile                       |  1 +
 builtin/diff-files.c           |  1 +
 builtin/diff-index.c           |  2 +
 builtin/diff-tree.c            |  3 ++
 builtin/diff.c                 |  1 +
 diff.c                         | 21 ++++++++++
 diff.h                         | 21 ++++++++++
 diffcore-rotate.c              | 46 ++++++++++++++++++++++
 diffcore.h                     |  1 +
 t/t4056-diff-order.sh          | 72 +++++++++++++++++++++++++++++++++-
 t/t7800-difftool.sh            | 30 ++++++++++++++
 14 files changed, 237 insertions(+), 1 deletion(-)
 create mode 100644 diffcore-rotate.c


base-commit: c6102b758572c7515f606b2423dfe38934fe6764
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-870%2Fadlternative%2Fdifftool_save_point-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-870/adlternative/difftool_save_point-v5
Pull-Request: https://github.com/gitgitgadget/git/pull/870

Range-diff vs v4:

 1:  3accfb942301 ! 1:  fb4bfd0f8b16 difftool.c: learn a new way start at specified file
     @@
       ## Metadata ##
     -Author: ZheNing Hu <adlternative@gmail.com>
     +Author: Junio C Hamano <gitster@pobox.com>
      
       ## Commit message ##
     -    difftool.c: learn a new way start at specified file
     -
     -    `git difftool` only allow us to select file to view in turn.
     -    If there is a commit with many files and we exit in the search,
     -    We will have to traverse list again to get the file diff which
     -    we want to see. Therefore, here is a new method: user can use
     -    `git difftool --start-from=<filename>` to start viewing from
     -    the specified file, This will improve the user experience.
     -
     -    `difftool --start-from=<file>` will pass the file name to
     -    `diffcore-rotate`, it will traverse all files in diff_queue,
     -    if it finds a matching file, it will rearrange the order of
     -    diff_filepair of diff_queue, Rotate the file specified by the
     -    user to the first one. If the file name specified by the user
     -    does not match any item in the diff queue, Git will also rotate
     -    the queue, it will find the the first file name larger than the
     -    specified file name as the first element of the new diff_queue.
     -    This will help users find their mistakes.
     -
     -    Signed-off-by: ZheNing Hu <adlternative@gmail.com>
     -
     - ## Documentation/git-difftool.txt ##
     -@@ Documentation/git-difftool.txt: OPTIONS
     - 	This is the default behaviour; the option is provided to
     - 	override any configuration settings.
     - 
     -+--start-from=<file>::
     -+	Start viewing diff from the specified file.
     -+
     - -t <tool>::
     - --tool=<tool>::
     - 	Use the diff tool specified by <tool>.  Valid values include
     +    diff: --{rotate,skip}-to=<path>
     +
     +    In the implementation of "git difftool", there is a case where the
     +    user wants to start viewing the diffs at a specific path and
     +    continue on to the rest, optionally wrapping around to the
     +    beginning.  Since it is somewhat cumbersome to implement such a
     +    feature as a post-processing step of "git diff" output, let's
     +    support it internally with two new options.
     +
     +     - "git diff --rotate-to=C", when the resulting patch would show
     +       paths A B C D E without the option, would "rotate" the paths to
     +       shows patch to C D E A B instead.  It is an error when there is
     +       no patch for C is shown.
     +
     +     - "git diff --skip-to=C" would instead "skip" the paths before C,
     +       and shows patch to C D E.  Again, it is an error when there is no
     +       patch for C is shown.
     +
     +     - "git log [-p]" also accepts these two options, but it is not an
     +       error if there is no change to the specified path.  Instead, the
     +       set of output paths are rotated or skipped to the specified path
     +       or the first path that sorts after the specified path.
     +
     +    Signed-off-by: Junio C Hamano <gitster@pobox.com>
     +
     + ## Documentation/diff-options.txt ##
     +@@ Documentation/diff-options.txt: matches a pattern if removing any number of the final pathname
     + components matches the pattern.  For example, the pattern "`foo*bar`"
     + matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`".
     + 
     ++--skip-to=<file>::
     ++--rotate-to=<file::
     ++	Discard the files before the named <file> from the output
     ++	(i.e. 'skip to'), or move them to the end of the output
     ++	(i.e. 'rotate to').  These were invented primarily for use
     ++	of the `git difftool` command, and may not be very useful
     ++	otherwise.
     ++
     + ifndef::git-format-patch[]
     + -R::
     + 	Swap two inputs; that is, show differences from index or
     +
     + ## Documentation/gitdiffcore.txt ##
     +@@ Documentation/gitdiffcore.txt: into another list.  There are currently 5 such transformations:
     + - diffcore-merge-broken
     + - diffcore-pickaxe
     + - diffcore-order
     ++- diffcore-rotate
     + 
     + These are applied in sequence.  The set of filepairs 'git diff-{asterisk}'
     + commands find are used as the input to diffcore-break, and
     +@@ Documentation/gitdiffcore.txt: Documentation
     + t
     + ------------------------------------------------
     + 
     ++diffcore-rotate: For Changing At Which Path Output Starts
     ++---------------------------------------------------------
     ++
     ++This transformation takes one pathname, and rotates the set of
     ++filepairs so that the filepair for the given pathname comes first,
     ++optionally discarding the paths that come before it.  This is used
     ++to implement the `--skip-to` and the `--rotate-to` options.  It is
     ++an error when the specified pathname is not in the set of filepairs,
     ++but it is not useful to error out when used with "git log" family of
     ++commands, because it is unreasonable to expect that a given path
     ++would be modified by each and every commit shown by the "git log"
     ++command.  For this reason, when used with "git log", the filepair
     ++that sorts the same as, or the first one that sorts after, the given
     ++pathname is where the output starts.
     ++
     ++Use of this transformation combined with diffcore-order will produce
     ++unexpected results, as the input to this transformation is likely
     ++not sorted when diffcore-order is in effect.
     ++
     ++
     + SEE ALSO
     + --------
     + linkgit:git-diff[1],
      
       ## Makefile ##
      @@ Makefile: LIB_OBJS += diffcore-delta.o
     @@ Makefile: LIB_OBJS += diffcore-delta.o
       LIB_OBJS += dir.o
       LIB_OBJS += editor.o
      
     + ## builtin/diff-files.c ##
     +@@ builtin/diff-files.c: int cmd_diff_files(int argc, const char **argv, const char *prefix)
     + 	}
     + 	if (!rev.diffopt.output_format)
     + 		rev.diffopt.output_format = DIFF_FORMAT_RAW;
     ++	rev.diffopt.rotate_to_strict = 1;
     + 
     + 	/*
     + 	 * Make sure there are NO revision (i.e. pending object) parameter,
     +
     + ## builtin/diff-index.c ##
     +@@ builtin/diff-index.c: int cmd_diff_index(int argc, const char **argv, const char *prefix)
     + 	if (!rev.diffopt.output_format)
     + 		rev.diffopt.output_format = DIFF_FORMAT_RAW;
     + 
     ++	rev.diffopt.rotate_to_strict = 1;
     ++
     + 	/*
     + 	 * Make sure there is one revision (i.e. pending object),
     + 	 * and there is no revision filtering parameters.
     +
     + ## builtin/diff-tree.c ##
     +@@ builtin/diff-tree.c: int cmd_diff_tree(int argc, const char **argv, const char *prefix)
     + 	if (merge_base && opt->pending.nr != 2)
     + 		die(_("--merge-base only works with two commits"));
     + 
     ++	opt->diffopt.rotate_to_strict = 1;
     ++
     + 	/*
     + 	 * NOTE!  We expect "a..b" to expand to "^a b" but it is
     + 	 * perfectly valid for revision range parser to yield "b ^a",
     +@@ builtin/diff-tree.c: int cmd_diff_tree(int argc, const char **argv, const char *prefix)
     + 		int saved_nrl = 0;
     + 		int saved_dcctc = 0;
     + 
     ++		opt->diffopt.rotate_to_strict = 0;
     + 		if (opt->diffopt.detect_rename) {
     + 			if (!the_index.cache)
     + 				repo_read_index(the_repository);
     +
     + ## builtin/diff.c ##
     +@@ builtin/diff.c: int cmd_diff(int argc, const char **argv, const char *prefix)
     + 	}
     + 
     + 	rev.diffopt.flags.recursive = 1;
     ++	rev.diffopt.rotate_to_strict = 1;
     + 
     + 	setup_diff_pager(&rev.diffopt);
     + 
     +
       ## diff.c ##
     +@@ diff.c: static int diff_opt_word_diff_regex(const struct option *opt,
     + 	return 0;
     + }
     + 
     ++static int diff_opt_rotate_to(const struct option *opt, const char *arg, int unset)
     ++{
     ++	struct diff_options *options = opt->value;
     ++
     ++	BUG_ON_OPT_NEG(unset);
     ++	if (!strcmp(opt->long_name, "skip-to"))
     ++		options->skip_instead_of_rotate = 1;
     ++	else
     ++		options->skip_instead_of_rotate = 0;
     ++	options->rotate_to = arg;
     ++	return 0;
     ++}
     ++
     + static void prep_parse_options(struct diff_options *options)
     + {
     + 	struct option parseopts[] = {
      @@ diff.c: static void prep_parse_options(struct diff_options *options)
       			  DIFF_PICKAXE_REGEX, PARSE_OPT_NONEG),
       		OPT_FILENAME('O', NULL, &options->orderfile,
       			     N_("control the order in which files appear in the output")),
     -+		OPT_STRING(0, "rotate-to", &options->rotate_to, N_("<path>"),
     -+			   N_("show the change in the specified path first")),
     -+		OPT_STRING(0, "start-from", &options->rotate_to, N_("<path>"),
     -+			   N_("pass from difftool to diff, has the same effort as `rotate-to`")),
     ++		OPT_CALLBACK_F(0, "rotate-to", options, N_("<path>"),
     ++			       N_("show the change in the specified path first"),
     ++			       PARSE_OPT_NONEG, diff_opt_rotate_to),
     ++		OPT_CALLBACK_F(0, "skip-to", options, N_("<path>"),
     ++			       N_("skip the output to the specified path"),
     ++			       PARSE_OPT_NONEG, diff_opt_rotate_to),
       		OPT_CALLBACK_F(0, "find-object", options, N_("<object-id>"),
       			       N_("look for differences that change the number of occurrences of the specified object"),
       			       PARSE_OPT_NONEG, diff_opt_find_object),
     @@ diff.c: void diffcore_std(struct diff_options *options)
       	if (options->orderfile)
       		diffcore_order(options->orderfile);
      +	if (options->rotate_to)
     -+		diffcore_rotate(options->rotate_to);
     ++		diffcore_rotate(options);
       	if (!options->found_follow)
       		/* See try_to_follow_renames() in tree-diff.c */
       		diff_resolve_rename_copy();
      
       ## diff.h ##
      @@ diff.h: enum diff_submodule_format {
     -  */
       struct diff_options {
       	const char *orderfile;
     -+	const char *rotate_to;
       
     ++	/*
     ++	 * "--rotate-to=<file>" would start showing at <file> and when
     ++	 * the output reaches the end, wrap around by default.
     ++	 * Setting skip_instead_of_rotate to true stops the output at the
     ++	 * end, effectively discarding the earlier part of the output
     ++	 * before <file>'s diff (this is used to implement the
     ++	 * "--skip-to=<file>" option).
     ++	 *
     ++	 * When rotate_to_strict is set, it is an error if there is no
     ++	 * <file> in the diff.  Otherwise, the output starts at the
     ++	 * path that is the same as, or first path that sorts after,
     ++	 * <file>.  Because it is unreasonable to require the exact
     ++	 * match for "git log -p --rotate-to=<file>" (i.e. not all
     ++	 * commit would touch that single <file>), "git log" sets it
     ++	 * to false.  "git diff" sets it to true to detect an error
     ++	 * in the command line option.
     ++	 */
     ++	const char *rotate_to;
     ++	int skip_instead_of_rotate;
     ++	int rotate_to_strict;
     ++
       	/**
       	 * A constant string (can and typically does contain newlines to look for
     + 	 * a block of text, not just a single line) to filter out the filepairs
      
       ## diffcore-rotate.c (new) ##
      @@
     @@ diffcore-rotate.c (new)
      +#include "diff.h"
      +#include "diffcore.h"
      +
     -+void diffcore_rotate(const char *rotate_to_filename)
     ++void diffcore_rotate(struct diff_options *opt)
      +{
      +	struct diff_queue_struct *q = &diff_queued_diff;
      +	struct diff_queue_struct outq;
     @@ diffcore-rotate.c (new)
      +	if (!q->nr)
      +		return;
      +
     -+	for (i = 0; i < q->nr; i++)
     -+		if (strcmp(rotate_to_filename, q->queue[i]->two->path) <= 0)
     -+			break;
     -+	/* we did not find the specified path */
     -+	if (q->nr <= i)
     ++	for (i = 0; i < q->nr; i++) {
     ++		int cmp = strcmp(opt->rotate_to, q->queue[i]->two->path);
     ++		if (!cmp)
     ++			break; /* exact match */
     ++		if (!opt->rotate_to_strict && cmp < 0)
     ++			break; /* q->queue[i] is now past the target pathname */
     ++	}
     ++
     ++	if (q->nr <= i) {
     ++		/* we did not find the specified path */
     ++		if (opt->rotate_to_strict)
     ++			die(_("No such path '%s' in the diff"), opt->rotate_to);
      +		return;
     ++	}
      +
      +	DIFF_QUEUE_CLEAR(&outq);
      +	rotate_to = i;
      +
      +	for (i = rotate_to; i < q->nr; i++)
      +		diff_q(&outq, q->queue[i]);
     -+	for (i = 0; i < rotate_to; i++)
     -+		diff_q(&outq, q->queue[i]);
     -+
     ++	for (i = 0; i < rotate_to; i++) {
     ++		if (opt->skip_instead_of_rotate)
     ++			diff_free_filepair(q->queue[i]);
     ++		else
     ++			diff_q(&outq, q->queue[i]);
     ++	}
      +	free(q->queue);
      +	*q = outq;
      +}
     @@ diffcore.h: void diffcore_rename(struct diff_options *);
       void diffcore_merge_broken(void);
       void diffcore_pickaxe(struct diff_options *);
       void diffcore_order(const char *orderfile);
     -+void diffcore_rotate(const char *rotate_to_filename);
     ++void diffcore_rotate(struct diff_options *);
       
       /* low-level interface to diffcore_order */
       struct obj_order {
      
     - ## t/t7800-difftool.sh ##
     -@@ t/t7800-difftool.sh: test_expect_success 'difftool --gui, --tool and --extcmd are mutually exclusive'
     - 	test_must_fail git difftool --gui --tool=test-tool --extcmd=cat
     - '
     - 
     -+test_expect_success 'difftool --start-from' '
     -+	difftool_test_setup &&
     -+	test_when_finished git reset --hard &&
     -+	echo 1 >1 &&
     -+	echo 2 >2 &&
     -+	echo 4 >4 &&
     -+	git add 1 2 4 &&
     -+	git commit -a -m "124" &&
     -+	git difftool --no-prompt --extcmd=cat --start-from="2" HEAD^  >output &&
     + ## t/t4056-diff-order.sh ##
     +@@
     + #!/bin/sh
     + 
     +-test_description='diff order'
     ++test_description='diff order & rotate'
     + 
     + GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
     + export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
     +@@ t/t4056-diff-order.sh: do
     + 	'
     + done
     + 
     ++### rotate and skip
     ++
     ++test_expect_success 'rotate and skip setup' '
     ++	>sample1.t &&
     ++	>sample2.t &&
     ++	>sample3.t &&
     ++	>sample4.t &&
     ++	git add sample[1234].t &&
     ++	git commit -m "added" sample[1234].t &&
     ++	echo modified >>sample1.t &&
     ++	echo modified >>sample2.t &&
     ++	echo modified >>sample4.t &&
     ++	git commit -m "updated" sample[1234].t
     ++'
     ++
     ++test_expect_success 'diff --rotate-to' '
     ++	git diff --rotate-to=sample2.t --name-only HEAD^ >actual &&
     ++	test_write_lines sample2.t sample4.t sample1.t >expect &&
     ++	test_cmp expect actual
     ++'
     ++
     ++test_expect_success 'diff --skip-to' '
     ++	git diff --skip-to=sample2.t --name-only HEAD^ >actual &&
     ++	test_write_lines sample2.t sample4.t >expect &&
     ++	test_cmp expect actual
     ++'
     ++
     ++test_expect_success 'diff --rotate/skip-to error condition' '
     ++	test_must_fail git diff --rotate-to=sample3.t HEAD^ &&
     ++	test_must_fail git diff --skip-to=sample3.t HEAD^
     ++'
     ++
     ++test_expect_success 'log --rotate-to' '
     ++	git log --rotate-to=sample3.t --raw HEAD~2.. >raw &&
     ++	# just distill the commit header and paths
     ++	sed -n -e "s/^commit.*/commit/p" \
     ++	       -e "/^:/s/^.*	//p" raw >actual &&
     ++
      +	cat >expect <<-\EOF &&
     -+	2
     -+	4
     -+	1
     ++	commit
     ++	sample4.t
     ++	sample1.t
     ++	sample2.t
     ++	commit
     ++	sample3.t
     ++	sample4.t
     ++	sample1.t
     ++	sample2.t
      +	EOF
     -+	test_cmp output expect &&
     -+	git difftool --no-prompt --extcmd=cat --start-from="3" HEAD^  >output &&
     ++
     ++	test_cmp expect actual
     ++'
     ++
     ++test_expect_success 'log --skip-to' '
     ++	git log --skip-to=sample3.t --raw HEAD~2.. >raw &&
     ++	# just distill the commit header and paths
     ++	sed -n -e "s/^commit.*/commit/p" \
     ++	       -e "/^:/s/^.*	//p" raw >actual &&
     ++
      +	cat >expect <<-\EOF &&
     -+	4
     -+	1
     -+	2
     ++	commit
     ++	sample4.t
     ++	commit
     ++	sample3.t
     ++	sample4.t
      +	EOF
     -+	test_cmp output expect
     ++
     ++	test_cmp expect actual
      +'
     ++
       test_done
 -:  ------------ > 2:  98e2707ee2fa difftool.c: learn a new way start at specified file

-- 
gitgitgadget

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

* [PATCH v5 1/2] diff: --{rotate,skip}-to=<path>
  2021-02-16 12:56       ` [PATCH v5 0/2] " ZheNing Hu via GitGitGadget
@ 2021-02-16 12:56         ` Junio C Hamano via GitGitGadget
  2021-02-16 12:56         ` [PATCH v5 2/2] difftool.c: learn a new way start at specified file ZheNing Hu via GitGitGadget
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 37+ messages in thread
From: Junio C Hamano via GitGitGadget @ 2021-02-16 12:56 UTC (permalink / raw)
  To: git
  Cc: Denton Liu, David Aguilar, John Keeping, Junio C Hamano,
	Ryan Zoeller, ZheNing Hu, Junio C Hamano

From: Junio C Hamano <gitster@pobox.com>

In the implementation of "git difftool", there is a case where the
user wants to start viewing the diffs at a specific path and
continue on to the rest, optionally wrapping around to the
beginning.  Since it is somewhat cumbersome to implement such a
feature as a post-processing step of "git diff" output, let's
support it internally with two new options.

 - "git diff --rotate-to=C", when the resulting patch would show
   paths A B C D E without the option, would "rotate" the paths to
   shows patch to C D E A B instead.  It is an error when there is
   no patch for C is shown.

 - "git diff --skip-to=C" would instead "skip" the paths before C,
   and shows patch to C D E.  Again, it is an error when there is no
   patch for C is shown.

 - "git log [-p]" also accepts these two options, but it is not an
   error if there is no change to the specified path.  Instead, the
   set of output paths are rotated or skipped to the specified path
   or the first path that sorts after the specified path.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/diff-options.txt |  8 ++++
 Documentation/gitdiffcore.txt  | 21 ++++++++++
 Makefile                       |  1 +
 builtin/diff-files.c           |  1 +
 builtin/diff-index.c           |  2 +
 builtin/diff-tree.c            |  3 ++
 builtin/diff.c                 |  1 +
 diff.c                         | 21 ++++++++++
 diff.h                         | 21 ++++++++++
 diffcore-rotate.c              | 46 ++++++++++++++++++++++
 diffcore.h                     |  1 +
 t/t4056-diff-order.sh          | 72 +++++++++++++++++++++++++++++++++-
 12 files changed, 197 insertions(+), 1 deletion(-)
 create mode 100644 diffcore-rotate.c

diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index e5733ccb2d1a..7c5b3cf42bcc 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -700,6 +700,14 @@ matches a pattern if removing any number of the final pathname
 components matches the pattern.  For example, the pattern "`foo*bar`"
 matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`".
 
+--skip-to=<file>::
+--rotate-to=<file::
+	Discard the files before the named <file> from the output
+	(i.e. 'skip to'), or move them to the end of the output
+	(i.e. 'rotate to').  These were invented primarily for use
+	of the `git difftool` command, and may not be very useful
+	otherwise.
+
 ifndef::git-format-patch[]
 -R::
 	Swap two inputs; that is, show differences from index or
diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt
index c970d9fe438a..2bd1220477e5 100644
--- a/Documentation/gitdiffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -74,6 +74,7 @@ into another list.  There are currently 5 such transformations:
 - diffcore-merge-broken
 - diffcore-pickaxe
 - diffcore-order
+- diffcore-rotate
 
 These are applied in sequence.  The set of filepairs 'git diff-{asterisk}'
 commands find are used as the input to diffcore-break, and
@@ -276,6 +277,26 @@ Documentation
 t
 ------------------------------------------------
 
+diffcore-rotate: For Changing At Which Path Output Starts
+---------------------------------------------------------
+
+This transformation takes one pathname, and rotates the set of
+filepairs so that the filepair for the given pathname comes first,
+optionally discarding the paths that come before it.  This is used
+to implement the `--skip-to` and the `--rotate-to` options.  It is
+an error when the specified pathname is not in the set of filepairs,
+but it is not useful to error out when used with "git log" family of
+commands, because it is unreasonable to expect that a given path
+would be modified by each and every commit shown by the "git log"
+command.  For this reason, when used with "git log", the filepair
+that sorts the same as, or the first one that sorts after, the given
+pathname is where the output starts.
+
+Use of this transformation combined with diffcore-order will produce
+unexpected results, as the input to this transformation is likely
+not sorted when diffcore-order is in effect.
+
+
 SEE ALSO
 --------
 linkgit:git-diff[1],
diff --git a/Makefile b/Makefile
index 5a239cac20e3..9b1bde2e0e64 100644
--- a/Makefile
+++ b/Makefile
@@ -863,6 +863,7 @@ LIB_OBJS += diffcore-delta.o
 LIB_OBJS += diffcore-order.o
 LIB_OBJS += diffcore-pickaxe.o
 LIB_OBJS += diffcore-rename.o
+LIB_OBJS += diffcore-rotate.o
 LIB_OBJS += dir-iterator.o
 LIB_OBJS += dir.o
 LIB_OBJS += editor.o
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 4742a4559b21..e037efb07eff 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -54,6 +54,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
 	}
 	if (!rev.diffopt.output_format)
 		rev.diffopt.output_format = DIFF_FORMAT_RAW;
+	rev.diffopt.rotate_to_strict = 1;
 
 	/*
 	 * Make sure there are NO revision (i.e. pending object) parameter,
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 7f5281c46168..06635e8fb26f 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -41,6 +41,8 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
 	if (!rev.diffopt.output_format)
 		rev.diffopt.output_format = DIFF_FORMAT_RAW;
 
+	rev.diffopt.rotate_to_strict = 1;
+
 	/*
 	 * Make sure there is one revision (i.e. pending object),
 	 * and there is no revision filtering parameters.
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 9fc95e959f0e..b6a9a9328e88 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -156,6 +156,8 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 	if (merge_base && opt->pending.nr != 2)
 		die(_("--merge-base only works with two commits"));
 
+	opt->diffopt.rotate_to_strict = 1;
+
 	/*
 	 * NOTE!  We expect "a..b" to expand to "^a b" but it is
 	 * perfectly valid for revision range parser to yield "b ^a",
@@ -192,6 +194,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 		int saved_nrl = 0;
 		int saved_dcctc = 0;
 
+		opt->diffopt.rotate_to_strict = 0;
 		if (opt->diffopt.detect_rename) {
 			if (!the_index.cache)
 				repo_read_index(the_repository);
diff --git a/builtin/diff.c b/builtin/diff.c
index 5cfe1717e8de..f1b88c7389eb 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -491,6 +491,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
 	}
 
 	rev.diffopt.flags.recursive = 1;
+	rev.diffopt.rotate_to_strict = 1;
 
 	setup_diff_pager(&rev.diffopt);
 
diff --git a/diff.c b/diff.c
index 69e3bc00ed8f..71e473854842 100644
--- a/diff.c
+++ b/diff.c
@@ -5348,6 +5348,19 @@ static int diff_opt_word_diff_regex(const struct option *opt,
 	return 0;
 }
 
+static int diff_opt_rotate_to(const struct option *opt, const char *arg, int unset)
+{
+	struct diff_options *options = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+	if (!strcmp(opt->long_name, "skip-to"))
+		options->skip_instead_of_rotate = 1;
+	else
+		options->skip_instead_of_rotate = 0;
+	options->rotate_to = arg;
+	return 0;
+}
+
 static void prep_parse_options(struct diff_options *options)
 {
 	struct option parseopts[] = {
@@ -5599,6 +5612,12 @@ static void prep_parse_options(struct diff_options *options)
 			  DIFF_PICKAXE_REGEX, PARSE_OPT_NONEG),
 		OPT_FILENAME('O', NULL, &options->orderfile,
 			     N_("control the order in which files appear in the output")),
+		OPT_CALLBACK_F(0, "rotate-to", options, N_("<path>"),
+			       N_("show the change in the specified path first"),
+			       PARSE_OPT_NONEG, diff_opt_rotate_to),
+		OPT_CALLBACK_F(0, "skip-to", options, N_("<path>"),
+			       N_("skip the output to the specified path"),
+			       PARSE_OPT_NONEG, diff_opt_rotate_to),
 		OPT_CALLBACK_F(0, "find-object", options, N_("<object-id>"),
 			       N_("look for differences that change the number of occurrences of the specified object"),
 			       PARSE_OPT_NONEG, diff_opt_find_object),
@@ -6669,6 +6688,8 @@ void diffcore_std(struct diff_options *options)
 		diffcore_pickaxe(options);
 	if (options->orderfile)
 		diffcore_order(options->orderfile);
+	if (options->rotate_to)
+		diffcore_rotate(options);
 	if (!options->found_follow)
 		/* See try_to_follow_renames() in tree-diff.c */
 		diff_resolve_rename_copy();
diff --git a/diff.h b/diff.h
index 2ff2b1c7f2ca..45300e3597f2 100644
--- a/diff.h
+++ b/diff.h
@@ -227,6 +227,27 @@ enum diff_submodule_format {
 struct diff_options {
 	const char *orderfile;
 
+	/*
+	 * "--rotate-to=<file>" would start showing at <file> and when
+	 * the output reaches the end, wrap around by default.
+	 * Setting skip_instead_of_rotate to true stops the output at the
+	 * end, effectively discarding the earlier part of the output
+	 * before <file>'s diff (this is used to implement the
+	 * "--skip-to=<file>" option).
+	 *
+	 * When rotate_to_strict is set, it is an error if there is no
+	 * <file> in the diff.  Otherwise, the output starts at the
+	 * path that is the same as, or first path that sorts after,
+	 * <file>.  Because it is unreasonable to require the exact
+	 * match for "git log -p --rotate-to=<file>" (i.e. not all
+	 * commit would touch that single <file>), "git log" sets it
+	 * to false.  "git diff" sets it to true to detect an error
+	 * in the command line option.
+	 */
+	const char *rotate_to;
+	int skip_instead_of_rotate;
+	int rotate_to_strict;
+
 	/**
 	 * A constant string (can and typically does contain newlines to look for
 	 * a block of text, not just a single line) to filter out the filepairs
diff --git a/diffcore-rotate.c b/diffcore-rotate.c
new file mode 100644
index 000000000000..445f060ab001
--- /dev/null
+++ b/diffcore-rotate.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021, Google LLC.
+ * Based on diffcore-order.c, which is Copyright (C) 2005, Junio C Hamano
+ */
+#include "cache.h"
+#include "diff.h"
+#include "diffcore.h"
+
+void diffcore_rotate(struct diff_options *opt)
+{
+	struct diff_queue_struct *q = &diff_queued_diff;
+	struct diff_queue_struct outq;
+	int rotate_to, i;
+
+	if (!q->nr)
+		return;
+
+	for (i = 0; i < q->nr; i++) {
+		int cmp = strcmp(opt->rotate_to, q->queue[i]->two->path);
+		if (!cmp)
+			break; /* exact match */
+		if (!opt->rotate_to_strict && cmp < 0)
+			break; /* q->queue[i] is now past the target pathname */
+	}
+
+	if (q->nr <= i) {
+		/* we did not find the specified path */
+		if (opt->rotate_to_strict)
+			die(_("No such path '%s' in the diff"), opt->rotate_to);
+		return;
+	}
+
+	DIFF_QUEUE_CLEAR(&outq);
+	rotate_to = i;
+
+	for (i = rotate_to; i < q->nr; i++)
+		diff_q(&outq, q->queue[i]);
+	for (i = 0; i < rotate_to; i++) {
+		if (opt->skip_instead_of_rotate)
+			diff_free_filepair(q->queue[i]);
+		else
+			diff_q(&outq, q->queue[i]);
+	}
+	free(q->queue);
+	*q = outq;
+}
diff --git a/diffcore.h b/diffcore.h
index d2a63c5c71f4..c1592bcd0135 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -164,6 +164,7 @@ void diffcore_rename(struct diff_options *);
 void diffcore_merge_broken(void);
 void diffcore_pickaxe(struct diff_options *);
 void diffcore_order(const char *orderfile);
+void diffcore_rotate(struct diff_options *);
 
 /* low-level interface to diffcore_order */
 struct obj_order {
diff --git a/t/t4056-diff-order.sh b/t/t4056-diff-order.sh
index 63ea7144bb49..aec1d9d1b42f 100755
--- a/t/t4056-diff-order.sh
+++ b/t/t4056-diff-order.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='diff order'
+test_description='diff order & rotate'
 
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
@@ -127,4 +127,74 @@ do
 	'
 done
 
+### rotate and skip
+
+test_expect_success 'rotate and skip setup' '
+	>sample1.t &&
+	>sample2.t &&
+	>sample3.t &&
+	>sample4.t &&
+	git add sample[1234].t &&
+	git commit -m "added" sample[1234].t &&
+	echo modified >>sample1.t &&
+	echo modified >>sample2.t &&
+	echo modified >>sample4.t &&
+	git commit -m "updated" sample[1234].t
+'
+
+test_expect_success 'diff --rotate-to' '
+	git diff --rotate-to=sample2.t --name-only HEAD^ >actual &&
+	test_write_lines sample2.t sample4.t sample1.t >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'diff --skip-to' '
+	git diff --skip-to=sample2.t --name-only HEAD^ >actual &&
+	test_write_lines sample2.t sample4.t >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'diff --rotate/skip-to error condition' '
+	test_must_fail git diff --rotate-to=sample3.t HEAD^ &&
+	test_must_fail git diff --skip-to=sample3.t HEAD^
+'
+
+test_expect_success 'log --rotate-to' '
+	git log --rotate-to=sample3.t --raw HEAD~2.. >raw &&
+	# just distill the commit header and paths
+	sed -n -e "s/^commit.*/commit/p" \
+	       -e "/^:/s/^.*	//p" raw >actual &&
+
+	cat >expect <<-\EOF &&
+	commit
+	sample4.t
+	sample1.t
+	sample2.t
+	commit
+	sample3.t
+	sample4.t
+	sample1.t
+	sample2.t
+	EOF
+
+	test_cmp expect actual
+'
+
+test_expect_success 'log --skip-to' '
+	git log --skip-to=sample3.t --raw HEAD~2.. >raw &&
+	# just distill the commit header and paths
+	sed -n -e "s/^commit.*/commit/p" \
+	       -e "/^:/s/^.*	//p" raw >actual &&
+
+	cat >expect <<-\EOF &&
+	commit
+	sample4.t
+	commit
+	sample3.t
+	sample4.t
+	EOF
+
+	test_cmp expect actual
+'
+
 test_done
-- 
gitgitgadget


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

* [PATCH v5 2/2] difftool.c: learn a new way start at specified file
  2021-02-16 12:56       ` [PATCH v5 0/2] " ZheNing Hu via GitGitGadget
  2021-02-16 12:56         ` [PATCH v5 1/2] diff: --{rotate,skip}-to=<path> Junio C Hamano via GitGitGadget
@ 2021-02-16 12:56         ` ZheNing Hu via GitGitGadget
  2021-02-17 10:31           ` Junio C Hamano
  2021-02-16 18:45         ` [PATCH v5 0/2] " Junio C Hamano
  2021-02-19 12:53         ` [PATCH v6] " ZheNing Hu via GitGitGadget
  3 siblings, 1 reply; 37+ messages in thread
From: ZheNing Hu via GitGitGadget @ 2021-02-16 12:56 UTC (permalink / raw)
  To: git
  Cc: Denton Liu, David Aguilar, John Keeping, Junio C Hamano,
	Ryan Zoeller, ZheNing Hu, ZheNing Hu

From: ZheNing Hu <adlternative@gmail.com>

`git difftool` only allow us to select file to view in turn.
If there is a commit with many files and we exit in the search,
We will have to traverse list again to get the file diff which
we want to see. Therefore, here is a new method: user can use
`git difftool --rotate-to=<filename>` or `git difftool --skip-to=<filename>`
to start viewing from the specified file, This will improve the
user experience.

`git difftool --rotate-to=<file>` or `git difftool --skip-to=<filename>`
will pass the path to `diffcore-rotate`, and diff-core will
adjust the order of files, make the specified file sorted to
the first.`git difftool --rotate-to=<file>` will move files before
the  specified path to the last output, and
`git difftool --skip-to=<filename>`  will ignore these files output.
It is an error when there is no patch for specified file is shown.

Signed-off-by: ZheNing Hu <adlternative@gmail.com>
---
 Documentation/diff-options.txt |  2 +-
 Documentation/git-difftool.txt | 10 ++++++++++
 t/t7800-difftool.sh            | 30 ++++++++++++++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 7c5b3cf42bcc..aa2b5c11f20b 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -701,7 +701,7 @@ components matches the pattern.  For example, the pattern "`foo*bar`"
 matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`".
 
 --skip-to=<file>::
---rotate-to=<file::
+--rotate-to=<file>::
 	Discard the files before the named <file> from the output
 	(i.e. 'skip to'), or move them to the end of the output
 	(i.e. 'rotate to').  These were invented primarily for use
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index 484c485fd06c..c64dff69c976 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -34,6 +34,16 @@ OPTIONS
 	This is the default behaviour; the option is provided to
 	override any configuration settings.
 
+--rotate-to=<file>::
+	Internally call `git diff --rotate-to=<file>`,
+	show the change in the specified path first.
+	Files before the specified path will be moved to the last output.
+
+--skip-to=<file>::
+	Internally call `git diff --skip-to=<file>`,
+	skip the output to the specified path.
+	Files before the specified path will not output.
+
 -t <tool>::
 --tool=<tool>::
 	Use the diff tool specified by <tool>.  Valid values include
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 9192c141ffc6..112b798b1c23 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -762,4 +762,34 @@ test_expect_success 'difftool --gui, --tool and --extcmd are mutually exclusive'
 	test_must_fail git difftool --gui --tool=test-tool --extcmd=cat
 '
 
+test_expect_success 'difftool --rotate-to' '
+	difftool_test_setup &&
+	test_when_finished git reset --hard &&
+	echo 1 >1 &&
+	echo 2 >2 &&
+	echo 4 >4 &&
+	git add 1 2 4 &&
+	git commit -a -m "124" &&
+	git difftool --no-prompt --extcmd=cat --rotate-to="2" HEAD^ >output&&
+	cat >expect <<-\EOF &&
+	2
+	4
+	1
+	EOF
+	test_cmp output expect &&
+	test_must_fail git difftool --no-prompt --extcmd=cat --rotate-to="3" HEAD^
+'
+
+test_expect_success 'difftool --skip-to' '
+	difftool_test_setup &&
+	test_when_finished git reset --hard &&
+	git difftool --no-prompt --extcmd=cat --skip-to="2" HEAD^ >output &&
+	cat >expect <<-\EOF &&
+	2
+	4
+	EOF
+	test_cmp output expect &&
+	test_must_fail git difftool --no-prompt --extcmd=cat --skip-to="3" HEAD^
+'
+
 test_done
-- 
gitgitgadget

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

* Re: [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-16 12:56       ` [PATCH v5 0/2] " ZheNing Hu via GitGitGadget
  2021-02-16 12:56         ` [PATCH v5 1/2] diff: --{rotate,skip}-to=<path> Junio C Hamano via GitGitGadget
  2021-02-16 12:56         ` [PATCH v5 2/2] difftool.c: learn a new way start at specified file ZheNing Hu via GitGitGadget
@ 2021-02-16 18:45         ` Junio C Hamano
  2021-02-17  4:12           ` ZheNing Hu
  2021-02-19 12:53         ` [PATCH v6] " ZheNing Hu via GitGitGadget
  3 siblings, 1 reply; 37+ messages in thread
From: Junio C Hamano @ 2021-02-16 18:45 UTC (permalink / raw)
  To: ZheNing Hu via GitGitGadget
  Cc: git, Denton Liu, David Aguilar, John Keeping, Ryan Zoeller, ZheNing Hu

"ZheNing Hu via GitGitGadget" <gitgitgadget@gmail.com> writes:

> Junio C Hamano (1):
>   diff: --{rotate,skip}-to=<path>

That's not part of your series (didn't I ask you not to include it)?

> ZheNing Hu (1):
>   difftool.c: learn a new way start at specified file

Will see what I find, but I may not be able to get to it today.

Thanks.

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

* Re: [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-16 18:45         ` [PATCH v5 0/2] " Junio C Hamano
@ 2021-02-17  4:12           ` ZheNing Hu
  2021-02-17 11:14             ` Denton Liu
  0 siblings, 1 reply; 37+ messages in thread
From: ZheNing Hu @ 2021-02-17  4:12 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: ZheNing Hu via GitGitGadget, Git List, Denton Liu, David Aguilar,
	John Keeping, Ryan Zoeller

Oh, I am sorry.
Then I only need to squash the two commit, right?

Junio C Hamano <gitster@pobox.com> 于2021年2月17日周三 上午2:45写道:
>
> "ZheNing Hu via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > Junio C Hamano (1):
> >   diff: --{rotate,skip}-to=<path>
>
> That's not part of your series (didn't I ask you not to include it)?
>
> > ZheNing Hu (1):
> >   difftool.c: learn a new way start at specified file
>
> Will see what I find, but I may not be able to get to it today.
>
> Thanks.

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

* Re: [PATCH v5 2/2] difftool.c: learn a new way start at specified file
  2021-02-16 12:56         ` [PATCH v5 2/2] difftool.c: learn a new way start at specified file ZheNing Hu via GitGitGadget
@ 2021-02-17 10:31           ` Junio C Hamano
  2021-02-17 16:18             ` ZheNing Hu
  0 siblings, 1 reply; 37+ messages in thread
From: Junio C Hamano @ 2021-02-17 10:31 UTC (permalink / raw)
  To: ZheNing Hu via GitGitGadget
  Cc: git, Denton Liu, David Aguilar, John Keeping, Ryan Zoeller, ZheNing Hu

"ZheNing Hu via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: ZheNing Hu <adlternative@gmail.com>
>
> `git difftool` only allow us to select file to view in turn.
> If there is a commit with many files and we exit in the search,

I am not sure what "in the search" refers to.  "in the middle" I
would understand, though.

> We will have to traverse list again to get the file diff which

Let's downcase this "We".

> we want to see. Therefore, here is a new method: user can use
> `git difftool --rotate-to=<filename>` or `git difftool --skip-to=<filename>`
> to start viewing from the specified file, This will improve the
> user experience.

Do we need both?  I'd rather not to give end-user-facing commands
too many knobs that would do similar things.  Too many choices to
choose from without clear answer to "which one should I prefer to
use?" is a bad combination for end-users.

> diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
> index 7c5b3cf42bcc..aa2b5c11f20b 100644
> --- a/Documentation/diff-options.txt
> +++ b/Documentation/diff-options.txt
> @@ -701,7 +701,7 @@ components matches the pattern.  For example, the pattern "`foo*bar`"
>  matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`".
>  
>  --skip-to=<file>::
> ---rotate-to=<file::
> +--rotate-to=<file>::
>  	Discard the files before the named <file> from the output
>  	(i.e. 'skip to'), or move them to the end of the output
>  	(i.e. 'rotate to').  These were invented primarily for use

Thanks for correcting, but this change should not be a part of this
patch.  Instead, you help the other's topic by giving a review (and
you could just have said "there there is closing '>' missing").

> diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
> index 484c485fd06c..c64dff69c976 100644
> --- a/Documentation/git-difftool.txt
> +++ b/Documentation/git-difftool.txt
> @@ -34,6 +34,16 @@ OPTIONS
>  	This is the default behaviour; the option is provided to
>  	override any configuration settings.
>  
> +--rotate-to=<file>::
> +	Internally call `git diff --rotate-to=<file>`,
> +	show the change in the specified path first.
> +	Files before the specified path will be moved to the last output.
> +
> +--skip-to=<file>::
> +	Internally call `git diff --skip-to=<file>`,
> +	skip the output to the specified path.
> +	Files before the specified path will not output.
> +

This, unlike the "diffcore" stuff, is end-user facing, and it is
better not to force the readers even know what --skip-to option
to the diff does (after all, difftool users are using 'git difftool'
and they are not necessarily 'git diff' users).

    --skip-to=<file>::
            Start showing the diff for the given path, skipping all
            the paths before it.

or something, perhaps.

> +test_expect_success 'difftool --skip-to' '
> +	difftool_test_setup &&
> +	test_when_finished git reset --hard &&
> +	git difftool --no-prompt --extcmd=cat --skip-to="2" HEAD^ >output &&
> +	cat >expect <<-\EOF &&
> +	2
> +	4
> +	EOF
> +	test_cmp output expect &&
> +	test_must_fail git difftool --no-prompt --extcmd=cat --skip-to="3" HEAD^
> +'

This probably should be split into two independent tests.  One to
check that the non-failing case works as expected, the other to
check that a bogus command line option errors out as expected.

Thanks.

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

* Re: [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-17  4:12           ` ZheNing Hu
@ 2021-02-17 11:14             ` Denton Liu
  2021-02-17 11:40               ` ZheNing Hu
  0 siblings, 1 reply; 37+ messages in thread
From: Denton Liu @ 2021-02-17 11:14 UTC (permalink / raw)
  To: ZheNing Hu
  Cc: Junio C Hamano, ZheNing Hu via GitGitGadget, Git List,
	David Aguilar, John Keeping, Ryan Zoeller, Johannes Schindelin

Hi ZheNing,

On Wed, Feb 17, 2021 at 12:12:10PM +0800, ZheNing Hu wrote:
> Oh, I am sorry.
> Then I only need to squash the two commit, right?

I've never used GGG before but I suspect that in your GitHub PR, you
need to set the PR base to 'master' instead of 'jc/diffcore-rotate'.

CCing the creator of GGG, please correct me if I'm wrong.

-Denton

> Junio C Hamano <gitster@pobox.com> 于2021年2月17日周三 上午2:45写道:
> >
> > "ZheNing Hu via GitGitGadget" <gitgitgadget@gmail.com> writes:
> >
> > > Junio C Hamano (1):
> > >   diff: --{rotate,skip}-to=<path>
> >
> > That's not part of your series (didn't I ask you not to include it)?
> >
> > > ZheNing Hu (1):
> > >   difftool.c: learn a new way start at specified file
> >
> > Will see what I find, but I may not be able to get to it today.
> >
> > Thanks.

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

* Re: [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-17 11:14             ` Denton Liu
@ 2021-02-17 11:40               ` ZheNing Hu
  2021-02-17 18:56                 ` Junio C Hamano
  0 siblings, 1 reply; 37+ messages in thread
From: ZheNing Hu @ 2021-02-17 11:40 UTC (permalink / raw)
  To: Denton Liu
  Cc: Junio C Hamano, ZheNing Hu via GitGitGadget, Git List,
	David Aguilar, John Keeping, Ryan Zoeller, Johannes Schindelin

Hi Denton Liu,
You mean I should cherry-pick Junio's patch to my topic branch, right?

Denton Liu <liu.denton@gmail.com> 于2021年2月17日周三 下午7:14写道:
>
> Hi ZheNing,
>
> On Wed, Feb 17, 2021 at 12:12:10PM +0800, ZheNing Hu wrote:
> > Oh, I am sorry.
> > Then I only need to squash the two commit, right?
>
> I've never used GGG before but I suspect that in your GitHub PR, you
> need to set the PR base to 'master' instead of 'jc/diffcore-rotate'.
>
> CCing the creator of GGG, please correct me if I'm wrong.
>
> -Denton
>
> > Junio C Hamano <gitster@pobox.com> 于2021年2月17日周三 上午2:45写道:
> > >
> > > "ZheNing Hu via GitGitGadget" <gitgitgadget@gmail.com> writes:
> > >
> > > > Junio C Hamano (1):
> > > >   diff: --{rotate,skip}-to=<path>
> > >
> > > That's not part of your series (didn't I ask you not to include it)?
> > >
> > > > ZheNing Hu (1):
> > > >   difftool.c: learn a new way start at specified file
> > >
> > > Will see what I find, but I may not be able to get to it today.
> > >
> > > Thanks.

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

* Re: [PATCH v5 2/2] difftool.c: learn a new way start at specified file
  2021-02-17 10:31           ` Junio C Hamano
@ 2021-02-17 16:18             ` ZheNing Hu
  0 siblings, 0 replies; 37+ messages in thread
From: ZheNing Hu @ 2021-02-17 16:18 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: ZheNing Hu via GitGitGadget, Git List, Denton Liu, David Aguilar,
	John Keeping, Ryan Zoeller

Junio C Hamano <gitster@pobox.com> 于2021年2月17日周三 下午6:31写道:
>
> "ZheNing Hu via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > From: ZheNing Hu <adlternative@gmail.com>
> >
> > `git difftool` only allow us to select file to view in turn.
> > If there is a commit with many files and we exit in the search,
>
> I am not sure what "in the search" refers to.  "in the middle" I
> would understand, though.
>
> > We will have to traverse list again to get the file diff which
>
> Let's downcase this "We".
>
> > we want to see. Therefore, here is a new method: user can use
> > `git difftool --rotate-to=<filename>` or `git difftool --skip-to=<filename>`
> > to start viewing from the specified file, This will improve the
> > user experience.
>
> Do we need both?  I'd rather not to give end-user-facing commands
> too many knobs that would do similar things.  Too many choices to
> choose from without clear answer to "which one should I prefer to
> use?" is a bad combination for end-users.
>
So users will not need to use `git difftool --skip-to`? Then I am confused
about the meaning of `git difftool --skip-to`.
> > diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
> > index 7c5b3cf42bcc..aa2b5c11f20b 100644
> > --- a/Documentation/diff-options.txt
> > +++ b/Documentation/diff-options.txt
> > @@ -701,7 +701,7 @@ components matches the pattern.  For example, the pattern "`foo*bar`"
> >  matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`".
> >
> >  --skip-to=<file>::
> > ---rotate-to=<file::
> > +--rotate-to=<file>::
> >       Discard the files before the named <file> from the output
> >       (i.e. 'skip to'), or move them to the end of the output
> >       (i.e. 'rotate to').  These were invented primarily for use
>
> Thanks for correcting, but this change should not be a part of this
> patch.  Instead, you help the other's topic by giving a review (and
> you could just have said "there there is closing '>' missing").
>
Okay, I will pay attention later.
> > diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
> > index 484c485fd06c..c64dff69c976 100644
> > --- a/Documentation/git-difftool.txt
> > +++ b/Documentation/git-difftool.txt
> > @@ -34,6 +34,16 @@ OPTIONS
> >       This is the default behaviour; the option is provided to
> >       override any configuration settings.
> >
> > +--rotate-to=<file>::
> > +     Internally call `git diff --rotate-to=<file>`,
> > +     show the change in the specified path first.
> > +     Files before the specified path will be moved to the last output.
> > +
> > +--skip-to=<file>::
> > +     Internally call `git diff --skip-to=<file>`,
> > +     skip the output to the specified path.
> > +     Files before the specified path will not output.
> > +
>
> This, unlike the "diffcore" stuff, is end-user facing, and it is
> better not to force the readers even know what --skip-to option
> to the diff does (after all, difftool users are using 'git difftool'
> and they are not necessarily 'git diff' users).
>
>     --skip-to=<file>::
>             Start showing the diff for the given path, skipping all
>             the paths before it.
>
> or something, perhaps.
>
> > +test_expect_success 'difftool --skip-to' '
> > +     difftool_test_setup &&
> > +     test_when_finished git reset --hard &&
> > +     git difftool --no-prompt --extcmd=cat --skip-to="2" HEAD^ >output &&
> > +     cat >expect <<-\EOF &&
> > +     2
> > +     4
> > +     EOF
> > +     test_cmp output expect &&
> > +     test_must_fail git difftool --no-prompt --extcmd=cat --skip-to="3" HEAD^
> > +'
>
> This probably should be split into two independent tests.  One to
> check that the non-failing case works as expected, the other to
> check that a bogus command line option errors out as expected.
>
I will finish it.
> Thanks.

Besides, I have some curiosity about one place in the code in your
patch:
> int cmd_diff_tree(...)
> ...
> if (read_stdin) {
> ...
> opt->diffopt.rotate_to_strict = 0;
> ...
}
This is the only place where rotate_to_strict is set to zero,
So the "git log -p" you mentioned earlier is here Called this code
to avoid exiting  the program because of the wrong path, right?

Thanks.

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

* Re: [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-17 11:40               ` ZheNing Hu
@ 2021-02-17 18:56                 ` Junio C Hamano
  2021-02-18  5:20                   ` ZheNing Hu
                                     ` (2 more replies)
  0 siblings, 3 replies; 37+ messages in thread
From: Junio C Hamano @ 2021-02-17 18:56 UTC (permalink / raw)
  To: ZheNing Hu
  Cc: Denton Liu, ZheNing Hu via GitGitGadget, Git List, David Aguilar,
	John Keeping, Ryan Zoeller, Johannes Schindelin

ZheNing Hu <adlternative@gmail.com> writes:

> Denton Liu <liu.denton@gmail.com> 于2021年2月17日周三 下午7:14写道:
>>
>> Hi ZheNing,
>>
>> On Wed, Feb 17, 2021 at 12:12:10PM +0800, ZheNing Hu wrote:
>> > Oh, I am sorry.
>> > Then I only need to squash the two commit, right?
>>
>> I've never used GGG before but I suspect that in your GitHub PR, you
>> need to set the PR base to 'master' instead of 'jc/diffcore-rotate'.
>>
>> CCing the creator of GGG, please correct me if I'm wrong.
>>
>> -Denton

> Hi Denton Liu,
> You mean I should cherry-pick Junio's patch to my topic branch, right?

Thanks, Denton, for helping.

ZheNing, the end result we want to see on the list is just a single
patch, your 2/2 alone, that says "this patch depends on the
diffcore-rotate topic" _under_ its "---" three-dash lines (where
"meta" comments on the patch to explain how it fits the rest of the
world, etc.).  As a single patch "topic", there won't be even 1/1
marking, i.e. something like:

    Subject: [PATCH v6] difftool.c: learn a new way start at specified file
    From: ZheNing Hu <adlternative@gmail.com>

    `git difftool` only allow us to ...
    ...
    Teach the command an option '--skip-to=<path>' to allow the
    user to say that diffs for earlier paths are not interesting
    (because they were already seen in an earlier session) and
    start this session with the named path.

    Signed-off-by: ZheNing Hu <adlternative@gmail.com>
    ---

     * An earlier round tried to implement the skipping all in the
       GIT_EXTERNAL_DIFF, but this round takes advantage of the new
       "diff --skip-to=<path>" feature implemented by gitster
       (therefore, the patch depends on that topic).

     Documentation/git-difftool.txt | 10 ++++++++++
     t/t7800-difftool.sh            | 30 ++++++++++++++++++++++++++++++
     2 files changed, 40 insertions(+)

    ... patch here ...


I do not know how to achieve that end result with GGG and I do not
know if GGG allows its users to do so easily, though.

Thanks.

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

* Re: [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-17 18:56                 ` Junio C Hamano
@ 2021-02-18  5:20                   ` ZheNing Hu
  2021-02-18 15:04                   ` ZheNing Hu
  2021-02-25 11:08                   ` Johannes Schindelin
  2 siblings, 0 replies; 37+ messages in thread
From: ZheNing Hu @ 2021-02-18  5:20 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Denton Liu, ZheNing Hu via GitGitGadget, Git List, David Aguilar,
	John Keeping, Ryan Zoeller, Johannes Schindelin

Junio, thank you for your patient explanation.
Junio C Hamano <gitster@pobox.com> 于2021年2月18日周四 上午2:56写道:
>
> ZheNing Hu <adlternative@gmail.com> writes:
>
> > Denton Liu <liu.denton@gmail.com> 于2021年2月17日周三 下午7:14写道:
> >>
> >> Hi ZheNing,
> >>
> >> On Wed, Feb 17, 2021 at 12:12:10PM +0800, ZheNing Hu wrote:
> >> > Oh, I am sorry.
> >> > Then I only need to squash the two commit, right?
> >>
> >> I've never used GGG before but I suspect that in your GitHub PR, you
> >> need to set the PR base to 'master' instead of 'jc/diffcore-rotate'.
> >>
> >> CCing the creator of GGG, please correct me if I'm wrong.
> >>
> >> -Denton
>
> > Hi Denton Liu,
> > You mean I should cherry-pick Junio's patch to my topic branch, right?
>
> Thanks, Denton, for helping.
>
> ZheNing, the end result we want to see on the list is just a single
> patch, your 2/2 alone, that says "this patch depends on the
> diffcore-rotate topic" _under_ its "---" three-dash lines (where
> "meta" comments on the patch to explain how it fits the rest of the
> world, etc.).  As a single patch "topic", there won't be even 1/1
> marking, i.e. something like:
>
>     Subject: [PATCH v6] difftool.c: learn a new way start at specified file
>     From: ZheNing Hu <adlternative@gmail.com>
>
>     `git difftool` only allow us to ...
>     ...
>     Teach the command an option '--skip-to=<path>' to allow the
>     user to say that diffs for earlier paths are not interesting
>     (because they were already seen in an earlier session) and
>     start this session with the named path.
>
I noticed that "skip-to" is more suitable for users, right?
(I always thought "rotate-to" would be better)
>     Signed-off-by: ZheNing Hu <adlternative@gmail.com>
>     ---
>
>      * An earlier round tried to implement the skipping all in the
>        GIT_EXTERNAL_DIFF, but this round takes advantage of the new
>        "diff --skip-to=<path>" feature implemented by gitster
>        (therefore, the patch depends on that topic).
>
>      Documentation/git-difftool.txt | 10 ++++++++++
>      t/t7800-difftool.sh            | 30 ++++++++++++++++++++++++++++++
>      2 files changed, 40 insertions(+)
>
>     ... patch here ...
>
>
> I do not know how to achieve that end result with GGG and I do not
> know if GGG allows its users to do so easily, though.
I understand what you mean. I think I want GGG to work normally.
 I will try to resubmit your last patch and my new patch cherry-pick to the
 new topic branch. If there are still problems with this, please point out.
>
> Thanks.

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

* Re: [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-17 18:56                 ` Junio C Hamano
  2021-02-18  5:20                   ` ZheNing Hu
@ 2021-02-18 15:04                   ` ZheNing Hu
  2021-02-18 19:11                     ` Junio C Hamano
  2021-02-25 11:08                   ` Johannes Schindelin
  2 siblings, 1 reply; 37+ messages in thread
From: ZheNing Hu @ 2021-02-18 15:04 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Denton Liu, ZheNing Hu via GitGitGadget, Git List, David Aguilar,
	John Keeping, Ryan Zoeller, Johannes Schindelin

Junio C Hamano <gitster@pobox.com> 于2021年2月18日周四 上午2:56写道:
>
> ZheNing Hu <adlternative@gmail.com> writes:
>
> > Denton Liu <liu.denton@gmail.com> 于2021年2月17日周三 下午7:14写道:
> >>
> >> Hi ZheNing,
> >>
> >> On Wed, Feb 17, 2021 at 12:12:10PM +0800, ZheNing Hu wrote:
> >> > Oh, I am sorry.
> >> > Then I only need to squash the two commit, right?
> >>
> >> I've never used GGG before but I suspect that in your GitHub PR, you
> >> need to set the PR base to 'master' instead of 'jc/diffcore-rotate'.
> >>
> >> CCing the creator of GGG, please correct me if I'm wrong.
> >>
> >> -Denton
>
> > Hi Denton Liu,
> > You mean I should cherry-pick Junio's patch to my topic branch, right?
>
> Thanks, Denton, for helping.
>
> ZheNing, the end result we want to see on the list is just a single
> patch, your 2/2 alone, that says "this patch depends on the
> diffcore-rotate topic" _under_ its "---" three-dash lines (where
> "meta" comments on the patch to explain how it fits the rest of the
> world, etc.).  As a single patch "topic", there won't be even 1/1
> marking, i.e. something like:
>
>     Subject: [PATCH v6] difftool.c: learn a new way start at specified file
>     From: ZheNing Hu <adlternative@gmail.com>
>
>     `git difftool` only allow us to ...
>     ...
>     Teach the command an option '--skip-to=<path>' to allow the
>     user to say that diffs for earlier paths are not interesting
>     (because they were already seen in an earlier session) and
>     start this session with the named path.
>
>     Signed-off-by: ZheNing Hu <adlternative@gmail.com>
>     ---
>
>      * An earlier round tried to implement the skipping all in the
>        GIT_EXTERNAL_DIFF, but this round takes advantage of the new
>        "diff --skip-to=<path>" feature implemented by gitster
>        (therefore, the patch depends on that topic).
>
>      Documentation/git-difftool.txt | 10 ++++++++++
>      t/t7800-difftool.sh            | 30 ++++++++++++++++++++++++++++++
>      2 files changed, 40 insertions(+)
>
>     ... patch here ...
>
>
> I do not know how to achieve that end result with GGG and I do not
> know if GGG allows its users to do so easily, though.
>
Hi, Junio,
I think my patch is stuck in GGG, and the current version is after I
cherry-pick your patch and my patch on the master. Because I don’t
know how to based on your patch but not submit your patch. Is there
any good way?
Thanks.
> Thanks.

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

* Re: [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-18 15:04                   ` ZheNing Hu
@ 2021-02-18 19:11                     ` Junio C Hamano
  2021-02-19 10:59                       ` ZheNing Hu
  0 siblings, 1 reply; 37+ messages in thread
From: Junio C Hamano @ 2021-02-18 19:11 UTC (permalink / raw)
  To: ZheNing Hu
  Cc: Denton Liu, ZheNing Hu via GitGitGadget, Git List, David Aguilar,
	John Keeping, Ryan Zoeller, Johannes Schindelin

ZheNing Hu <adlternative@gmail.com> writes:

> I think my patch is stuck in GGG, and the current version is after I
> cherry-pick your patch and my patch on the master. Because I don’t
> know how to based on your patch but not submit your patch. Is there
> any good way?

I am not capable of doing helpdesk for GGG but I think you can send
two of them anyway with the title of the first one munged for
reading humans to tell them not to use or even look at it ;-)

GGG may send both of them out, but the ultimate objective here in
the exercise is to avoid the unwanted first one to waste people's
time, so until such a feature is implemented in GGG (or there may
already be one, but we do not know it), that would serve as a
workaround.

Thanks.

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

* Re: [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-18 19:11                     ` Junio C Hamano
@ 2021-02-19 10:59                       ` ZheNing Hu
  0 siblings, 0 replies; 37+ messages in thread
From: ZheNing Hu @ 2021-02-19 10:59 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Denton Liu, ZheNing Hu via GitGitGadget, Git List, David Aguilar,
	John Keeping, Ryan Zoeller, Johannes Schindelin

Ok,hope these problems won't make you unpleasant.
 I will try to solve these small problems.

Junio C Hamano <gitster@pobox.com> 于2021年2月19日周五 上午3:11写道:
>
> ZheNing Hu <adlternative@gmail.com> writes:
>
> > I think my patch is stuck in GGG, and the current version is after I
> > cherry-pick your patch and my patch on the master. Because I don’t
> > know how to based on your patch but not submit your patch. Is there
> > any good way?
>
> I am not capable of doing helpdesk for GGG but I think you can send
> two of them anyway with the title of the first one munged for
> reading humans to tell them not to use or even look at it ;-)
>
> GGG may send both of them out, but the ultimate objective here in
> the exercise is to avoid the unwanted first one to waste people's
> time, so until such a feature is implemented in GGG (or there may
> already be one, but we do not know it), that would serve as a
> workaround.
>
> Thanks.

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

* [PATCH v6] difftool.c: learn a new way start at specified file
  2021-02-16 12:56       ` [PATCH v5 0/2] " ZheNing Hu via GitGitGadget
                           ` (2 preceding siblings ...)
  2021-02-16 18:45         ` [PATCH v5 0/2] " Junio C Hamano
@ 2021-02-19 12:53         ` ZheNing Hu via GitGitGadget
  2021-02-22 15:11           ` ZheNing Hu
  2021-02-22 21:40           ` Junio C Hamano
  3 siblings, 2 replies; 37+ messages in thread
From: ZheNing Hu via GitGitGadget @ 2021-02-19 12:53 UTC (permalink / raw)
  To: git
  Cc: Denton Liu, David Aguilar, John Keeping, Junio C Hamano,
	Ryan Zoeller, ZheNing Hu, ZheNing Hu

From: ZheNing Hu <adlternative@gmail.com>

`git difftool` only allow us to select file to view in turn.
If there is a commit with many files and we exit in the middle,
we will have to traverse list again to get the file diff which
we want to see. Therefore,teach the command an option
`--skip-to=<path>` to allow the user to say that diffs for earlier
paths are not interesting (because they were already seen in an
earlier session) and start this session with the named path.

Signed-off-by: ZheNing Hu <adlternative@gmail.com>
---
    difftool.c: learn a new way start at specified file
    
     * The patch of the previous version implemented the jump through
       environment variables. The current version is based on the "diff
       --skip-to=" feature implemented by gitster, which implements a
       possible solution for the jump of difftool.

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-870%2Fadlternative%2Fdifftool_save_point-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-870/adlternative/difftool_save_point-v6
Pull-Request: https://github.com/gitgitgadget/git/pull/870

Range-diff vs v5:

 1:  fb4bfd0f8b16 < -:  ------------ diff: --{rotate,skip}-to=<path>
 2:  98e2707ee2fa ! 1:  4377a917ca9e difftool.c: learn a new way start at specified file
     @@ Commit message
          difftool.c: learn a new way start at specified file
      
          `git difftool` only allow us to select file to view in turn.
     -    If there is a commit with many files and we exit in the search,
     -    We will have to traverse list again to get the file diff which
     -    we want to see. Therefore, here is a new method: user can use
     -    `git difftool --rotate-to=<filename>` or `git difftool --skip-to=<filename>`
     -    to start viewing from the specified file, This will improve the
     -    user experience.
     -
     -    `git difftool --rotate-to=<file>` or `git difftool --skip-to=<filename>`
     -    will pass the path to `diffcore-rotate`, and diff-core will
     -    adjust the order of files, make the specified file sorted to
     -    the first.`git difftool --rotate-to=<file>` will move files before
     -    the  specified path to the last output, and
     -    `git difftool --skip-to=<filename>`  will ignore these files output.
     -    It is an error when there is no patch for specified file is shown.
     +    If there is a commit with many files and we exit in the middle,
     +    we will have to traverse list again to get the file diff which
     +    we want to see. Therefore,teach the command an option
     +    `--skip-to=<path>` to allow the user to say that diffs for earlier
     +    paths are not interesting (because they were already seen in an
     +    earlier session) and start this session with the named path.
      
          Signed-off-by: ZheNing Hu <adlternative@gmail.com>
      
     - ## Documentation/diff-options.txt ##
     -@@ Documentation/diff-options.txt: components matches the pattern.  For example, the pattern "`foo*bar`"
     - matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`".
     - 
     - --skip-to=<file>::
     ----rotate-to=<file::
     -+--rotate-to=<file>::
     - 	Discard the files before the named <file> from the output
     - 	(i.e. 'skip to'), or move them to the end of the output
     - 	(i.e. 'rotate to').  These were invented primarily for use
     -
       ## Documentation/git-difftool.txt ##
      @@ Documentation/git-difftool.txt: OPTIONS
       	This is the default behaviour; the option is provided to
       	override any configuration settings.
       
      +--rotate-to=<file>::
     -+	Internally call `git diff --rotate-to=<file>`,
     -+	show the change in the specified path first.
     -+	Files before the specified path will be moved to the last output.
     ++	Start showing the diff for the given path,
     ++	the paths before it will move to end and output.
      +
      +--skip-to=<file>::
     -+	Internally call `git diff --skip-to=<file>`,
     -+	skip the output to the specified path.
     -+	Files before the specified path will not output.
     ++	Start showing the diff for the given path, skipping all
     ++	the paths before it.
      +
       -t <tool>::
       --tool=<tool>::
     @@ t/t7800-difftool.sh: test_expect_success 'difftool --gui, --tool and --extcmd ar
      +	4
      +	1
      +	EOF
     -+	test_cmp output expect &&
     -+	test_must_fail git difftool --no-prompt --extcmd=cat --rotate-to="3" HEAD^
     ++	test_cmp output expect
      +'
      +
      +test_expect_success 'difftool --skip-to' '
     @@ t/t7800-difftool.sh: test_expect_success 'difftool --gui, --tool and --extcmd ar
      +	2
      +	4
      +	EOF
     -+	test_cmp output expect &&
     -+	test_must_fail git difftool --no-prompt --extcmd=cat --skip-to="3" HEAD^
     ++	test_cmp output expect
      +'
      +
     ++test_expect_success 'difftool --rotate/skip-to error condition' '
     ++	test_must_fail git difftool --no-prompt --extcmd=cat --rotate-to="3" HEAD^ &&
     ++	test_must_fail git difftool --no-prompt --extcmd=cat --skip-to="3" HEAD^
     ++'
       test_done


 Documentation/git-difftool.txt |  8 ++++++++
 t/t7800-difftool.sh            | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index 484c485fd06c..143b0c49d739 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -34,6 +34,14 @@ OPTIONS
 	This is the default behaviour; the option is provided to
 	override any configuration settings.
 
+--rotate-to=<file>::
+	Start showing the diff for the given path,
+	the paths before it will move to end and output.
+
+--skip-to=<file>::
+	Start showing the diff for the given path, skipping all
+	the paths before it.
+
 -t <tool>::
 --tool=<tool>::
 	Use the diff tool specified by <tool>.  Valid values include
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 9192c141ffc6..3e041e83aede 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -762,4 +762,36 @@ test_expect_success 'difftool --gui, --tool and --extcmd are mutually exclusive'
 	test_must_fail git difftool --gui --tool=test-tool --extcmd=cat
 '
 
+test_expect_success 'difftool --rotate-to' '
+	difftool_test_setup &&
+	test_when_finished git reset --hard &&
+	echo 1 >1 &&
+	echo 2 >2 &&
+	echo 4 >4 &&
+	git add 1 2 4 &&
+	git commit -a -m "124" &&
+	git difftool --no-prompt --extcmd=cat --rotate-to="2" HEAD^ >output&&
+	cat >expect <<-\EOF &&
+	2
+	4
+	1
+	EOF
+	test_cmp output expect
+'
+
+test_expect_success 'difftool --skip-to' '
+	difftool_test_setup &&
+	test_when_finished git reset --hard &&
+	git difftool --no-prompt --extcmd=cat --skip-to="2" HEAD^ >output &&
+	cat >expect <<-\EOF &&
+	2
+	4
+	EOF
+	test_cmp output expect
+'
+
+test_expect_success 'difftool --rotate/skip-to error condition' '
+	test_must_fail git difftool --no-prompt --extcmd=cat --rotate-to="3" HEAD^ &&
+	test_must_fail git difftool --no-prompt --extcmd=cat --skip-to="3" HEAD^
+'
 test_done

base-commit: 1eb4136ac2a24764257567b930535fcece01719f
-- 
gitgitgadget

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

* Re: [PATCH v6] difftool.c: learn a new way start at specified file
  2021-02-19 12:53         ` [PATCH v6] " ZheNing Hu via GitGitGadget
@ 2021-02-22 15:11           ` ZheNing Hu
  2021-02-22 21:40           ` Junio C Hamano
  1 sibling, 0 replies; 37+ messages in thread
From: ZheNing Hu @ 2021-02-22 15:11 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git List, Denton Liu, David Aguilar, John Keeping, Ryan Zoeller,
	ZheNing Hu via GitGitGadget

Hi,Junio,

ZheNing Hu via GitGitGadget <gitgitgadget@gmail.com> 于2021年2月19日周五 下午8:53写道:
>
> From: ZheNing Hu <adlternative@gmail.com>
>
> `git difftool` only allow us to select file to view in turn.
> If there is a commit with many files and we exit in the middle,
> we will have to traverse list again to get the file diff which
> we want to see. Therefore,teach the command an option
> `--skip-to=<path>` to allow the user to say that diffs for earlier
> paths are not interesting (because they were already seen in an
> earlier session) and start this session with the named path.
>
> Signed-off-by: ZheNing Hu <adlternative@gmail.com>
> ---
>     difftool.c: learn a new way start at specified file
>
>      * The patch of the previous version implemented the jump through
>        environment variables. The current version is based on the "diff
>        --skip-to=" feature implemented by gitster, which implements a
>        possible solution for the jump of difftool.
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-870%2Fadlternative%2Fdifftool_save_point-v6
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-870/adlternative/difftool_save_point-v6
> Pull-Request: https://github.com/gitgitgadget/git/pull/870
>
> Range-diff vs v5:
>
>  1:  fb4bfd0f8b16 < -:  ------------ diff: --{rotate,skip}-to=<path>
>  2:  98e2707ee2fa ! 1:  4377a917ca9e difftool.c: learn a new way start at specified file
>      @@ Commit message
>           difftool.c: learn a new way start at specified file
>
>           `git difftool` only allow us to select file to view in turn.
>      -    If there is a commit with many files and we exit in the search,
>      -    We will have to traverse list again to get the file diff which
>      -    we want to see. Therefore, here is a new method: user can use
>      -    `git difftool --rotate-to=<filename>` or `git difftool --skip-to=<filename>`
>      -    to start viewing from the specified file, This will improve the
>      -    user experience.
>      -
>      -    `git difftool --rotate-to=<file>` or `git difftool --skip-to=<filename>`
>      -    will pass the path to `diffcore-rotate`, and diff-core will
>      -    adjust the order of files, make the specified file sorted to
>      -    the first.`git difftool --rotate-to=<file>` will move files before
>      -    the  specified path to the last output, and
>      -    `git difftool --skip-to=<filename>`  will ignore these files output.
>      -    It is an error when there is no patch for specified file is shown.
>      +    If there is a commit with many files and we exit in the middle,
>      +    we will have to traverse list again to get the file diff which
>      +    we want to see. Therefore,teach the command an option
>      +    `--skip-to=<path>` to allow the user to say that diffs for earlier
>      +    paths are not interesting (because they were already seen in an
>      +    earlier session) and start this session with the named path.
>
>           Signed-off-by: ZheNing Hu <adlternative@gmail.com>
>
>      - ## Documentation/diff-options.txt ##
>      -@@ Documentation/diff-options.txt: components matches the pattern.  For example, the pattern "`foo*bar`"
>      - matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`".
>      -
>      - --skip-to=<file>::
>      ----rotate-to=<file::
>      -+--rotate-to=<file>::
>      -  Discard the files before the named <file> from the output
>      -  (i.e. 'skip to'), or move them to the end of the output
>      -  (i.e. 'rotate to').  These were invented primarily for use
>      -
>        ## Documentation/git-difftool.txt ##
>       @@ Documentation/git-difftool.txt: OPTIONS
>         This is the default behaviour; the option is provided to
>         override any configuration settings.
>
>       +--rotate-to=<file>::
>      -+ Internally call `git diff --rotate-to=<file>`,
>      -+ show the change in the specified path first.
>      -+ Files before the specified path will be moved to the last output.
>      ++ Start showing the diff for the given path,
>      ++ the paths before it will move to end and output.
>       +
>       +--skip-to=<file>::
>      -+ Internally call `git diff --skip-to=<file>`,
>      -+ skip the output to the specified path.
>      -+ Files before the specified path will not output.
>      ++ Start showing the diff for the given path, skipping all
>      ++ the paths before it.
>       +
>        -t <tool>::
>        --tool=<tool>::
>      @@ t/t7800-difftool.sh: test_expect_success 'difftool --gui, --tool and --extcmd ar
>       + 4
>       + 1
>       + EOF
>      -+ test_cmp output expect &&
>      -+ test_must_fail git difftool --no-prompt --extcmd=cat --rotate-to="3" HEAD^
>      ++ test_cmp output expect
>       +'
>       +
>       +test_expect_success 'difftool --skip-to' '
>      @@ t/t7800-difftool.sh: test_expect_success 'difftool --gui, --tool and --extcmd ar
>       + 2
>       + 4
>       + EOF
>      -+ test_cmp output expect &&
>      -+ test_must_fail git difftool --no-prompt --extcmd=cat --skip-to="3" HEAD^
>      ++ test_cmp output expect
>       +'
>       +
>      ++test_expect_success 'difftool --rotate/skip-to error condition' '
>      ++ test_must_fail git difftool --no-prompt --extcmd=cat --rotate-to="3" HEAD^ &&
>      ++ test_must_fail git difftool --no-prompt --extcmd=cat --skip-to="3" HEAD^
>      ++'
>        test_done
>
>
>  Documentation/git-difftool.txt |  8 ++++++++
>  t/t7800-difftool.sh            | 32 ++++++++++++++++++++++++++++++++
>  2 files changed, 40 insertions(+)
>
> diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
> index 484c485fd06c..143b0c49d739 100644
> --- a/Documentation/git-difftool.txt
> +++ b/Documentation/git-difftool.txt
> @@ -34,6 +34,14 @@ OPTIONS
>         This is the default behaviour; the option is provided to
>         override any configuration settings.
>
> +--rotate-to=<file>::
> +       Start showing the diff for the given path,
> +       the paths before it will move to end and output.
> +
> +--skip-to=<file>::
> +       Start showing the diff for the given path, skipping all
> +       the paths before it.
> +
>  -t <tool>::
>  --tool=<tool>::
>         Use the diff tool specified by <tool>.  Valid values include
> diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
> index 9192c141ffc6..3e041e83aede 100755
> --- a/t/t7800-difftool.sh
> +++ b/t/t7800-difftool.sh
> @@ -762,4 +762,36 @@ test_expect_success 'difftool --gui, --tool and --extcmd are mutually exclusive'
>         test_must_fail git difftool --gui --tool=test-tool --extcmd=cat
>  '
>
> +test_expect_success 'difftool --rotate-to' '
> +       difftool_test_setup &&
> +       test_when_finished git reset --hard &&
> +       echo 1 >1 &&
> +       echo 2 >2 &&
> +       echo 4 >4 &&
> +       git add 1 2 4 &&
> +       git commit -a -m "124" &&
> +       git difftool --no-prompt --extcmd=cat --rotate-to="2" HEAD^ >output&&
> +       cat >expect <<-\EOF &&
> +       2
> +       4
> +       1
> +       EOF
> +       test_cmp output expect
> +'
> +
> +test_expect_success 'difftool --skip-to' '
> +       difftool_test_setup &&
> +       test_when_finished git reset --hard &&
> +       git difftool --no-prompt --extcmd=cat --skip-to="2" HEAD^ >output &&
> +       cat >expect <<-\EOF &&
> +       2
> +       4
> +       EOF
> +       test_cmp output expect
> +'
> +
> +test_expect_success 'difftool --rotate/skip-to error condition' '
> +       test_must_fail git difftool --no-prompt --extcmd=cat --rotate-to="3" HEAD^ &&
> +       test_must_fail git difftool --no-prompt --extcmd=cat --skip-to="3" HEAD^
> +'
>  test_done
>
> base-commit: 1eb4136ac2a24764257567b930535fcece01719f
> --
> gitgitgadget

A few days ago I successfully sent this patch with the help
of Denton Liu, I don't know if you see it?
Any reply is appreciated.

--
ZheNing Hu

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

* Re: [PATCH v6] difftool.c: learn a new way start at specified file
  2021-02-19 12:53         ` [PATCH v6] " ZheNing Hu via GitGitGadget
  2021-02-22 15:11           ` ZheNing Hu
@ 2021-02-22 21:40           ` Junio C Hamano
  1 sibling, 0 replies; 37+ messages in thread
From: Junio C Hamano @ 2021-02-22 21:40 UTC (permalink / raw)
  To: ZheNing Hu via GitGitGadget
  Cc: git, Denton Liu, David Aguilar, John Keeping, Ryan Zoeller, ZheNing Hu

"ZheNing Hu via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: ZheNing Hu <adlternative@gmail.com>
>
> `git difftool` only allow us to select file to view in turn.
> If there is a commit with many files and we exit in the middle,
> we will have to traverse list again to get the file diff which
> we want to see. Therefore,teach the command an option
> `--skip-to=<path>` to allow the user to say that diffs for earlier
> paths are not interesting (because they were already seen in an
> earlier session) and start this session with the named path.
>
> Signed-off-by: ZheNing Hu <adlternative@gmail.com>
> ---
>     difftool.c: learn a new way start at specified file
>     
>      * The patch of the previous version implemented the jump through
>        environment variables. The current version is based on the "diff
>        --skip-to=" feature implemented by gitster, which implements a
>        possible solution for the jump of difftool.

So there was absolutely no need to change anything in difftool,
because it just passes down anything that it does not understand
down to the underlying "git diff"?

Very interesting.

Thanks, will queue.  Let's see if we get comments from others.

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

* Re: [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-17 18:56                 ` Junio C Hamano
  2021-02-18  5:20                   ` ZheNing Hu
  2021-02-18 15:04                   ` ZheNing Hu
@ 2021-02-25 11:08                   ` Johannes Schindelin
  2021-02-25 19:01                     ` Junio C Hamano
  2 siblings, 1 reply; 37+ messages in thread
From: Johannes Schindelin @ 2021-02-25 11:08 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: ZheNing Hu, Denton Liu, ZheNing Hu via GitGitGadget, Git List,
	David Aguilar, John Keeping, Ryan Zoeller

[-- Attachment #1: Type: text/plain, Size: 2525 bytes --]

Hi Junio, ZheNing & Denton,

On Wed, 17 Feb 2021, Junio C Hamano wrote:

> ZheNing Hu <adlternative@gmail.com> writes:
>
> > Denton Liu <liu.denton@gmail.com> 于2021年2月17日周三 下午7:14写道:
> >>
> >> On Wed, Feb 17, 2021 at 12:12:10PM +0800, ZheNing Hu wrote:
> >> > Oh, I am sorry.
> >> > Then I only need to squash the two commit, right?
> >>
> >> I've never used GGG before but I suspect that in your GitHub PR, you
> >> need to set the PR base to 'master' instead of 'jc/diffcore-rotate'.

Yes, that is my understanding of what needed to be done.

> > You mean I should cherry-pick Junio's patch to my topic branch, right?

That, too.

> ZheNing, the end result we want to see on the list is just a single
> patch, your 2/2 alone, that says "this patch depends on the
> diffcore-rotate topic" _under_ its "---" three-dash lines (where
> "meta" comments on the patch to explain how it fits the rest of the
> world, etc.).  As a single patch "topic", there won't be even 1/1
> marking, i.e. something like:
>
>     Subject: [PATCH v6] difftool.c: learn a new way start at specified file
>     From: ZheNing Hu <adlternative@gmail.com>
>
>     `git difftool` only allow us to ...
>     ...
>     Teach the command an option '--skip-to=<path>' to allow the
>     user to say that diffs for earlier paths are not interesting
>     (because they were already seen in an earlier session) and
>     start this session with the named path.
>
>     Signed-off-by: ZheNing Hu <adlternative@gmail.com>
>     ---
>
>      * An earlier round tried to implement the skipping all in the
>        GIT_EXTERNAL_DIFF, but this round takes advantage of the new
>        "diff --skip-to=<path>" feature implemented by gitster
>        (therefore, the patch depends on that topic).
>
>      Documentation/git-difftool.txt | 10 ++++++++++
>      t/t7800-difftool.sh            | 30 ++++++++++++++++++++++++++++++
>      2 files changed, 40 insertions(+)
>
>     ... patch here ...
>
>
> I do not know how to achieve that end result with GGG and I do not
> know if GGG allows its users to do so easily, though.

For single-patch contributions, the PR description is not turned into a
separate cover letter (per your request, Junio), but it is put between the
commit message and the diff as you illustrated.

So yes, the comment can go into the PR description (AKA the first comment
on the PR) and the next `/submit` will include it in the single mail.

Ciao,
Dscho

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

* Re: [PATCH v5 0/2] difftool.c: learn a new way start at specified file
  2021-02-25 11:08                   ` Johannes Schindelin
@ 2021-02-25 19:01                     ` Junio C Hamano
  0 siblings, 0 replies; 37+ messages in thread
From: Junio C Hamano @ 2021-02-25 19:01 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: ZheNing Hu, Denton Liu, ZheNing Hu via GitGitGadget, Git List,
	David Aguilar, John Keeping, Ryan Zoeller

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> Hi Junio, ZheNing & Denton,
>
> On Wed, 17 Feb 2021, Junio C Hamano wrote:
>
>> ZheNing Hu <adlternative@gmail.com> writes:
>>
>> > Denton Liu <liu.denton@gmail.com> 于2021年2月17日周三 下午7:14写道:
>> >>
>> >> On Wed, Feb 17, 2021 at 12:12:10PM +0800, ZheNing Hu wrote:
>> >> > Oh, I am sorry.
>> >> > Then I only need to squash the two commit, right?
>> >>
>> >> I've never used GGG before but I suspect that in your GitHub PR, you
>> >> need to set the PR base to 'master' instead of 'jc/diffcore-rotate'.
>
> Yes, that is my understanding of what needed to be done.

Thanks.

>> > You mean I should cherry-pick Junio's patch to my topic branch, right?
>
> That, too.

Not quite.  The 'jc/diffcore-rotate' topic would be the 'upstream'
branch of their topic, so patches in jc/diffcore-rotate won't need
to and should not be cherry-picked, I think.

>> ZheNing, the end result we want to see on the list is just a single
>> patch, your 2/2 alone, that says "this patch depends on the
>> diffcore-rotate topic" _under_ its "---" three-dash lines (where
>> "meta" comments on the patch to explain how it fits the rest of the
>> world, etc.).  As a single patch "topic", there won't be even 1/1
>> marking, i.e. something like:
>> ...
>> I do not know how to achieve that end result with GGG and I do not
>> know if GGG allows its users to do so easily, though.
>
> For single-patch contributions, the PR description is not turned into a
> separate cover letter (per your request, Junio), but it is put between the
> commit message and the diff as you illustrated.
>
> So yes, the comment can go into the PR description (AKA the first comment
> on the PR) and the next `/submit` will include it in the single mail.

Good.  FWIW, the part I said "I do not now how" was not about making
the single-patch topic look the way we want, but about making the
work a single-patch topic to begin with (which was answered by the
above "set the PR base" suggestion).

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

end of thread, other threads:[~2021-02-25 19:04 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-07 15:19 [PATCH] git-difftool-helper.sh: learn a new way skip to save point 阿德烈 via GitGitGadget
2021-02-07 18:29 ` Junio C Hamano
2021-02-07 19:04 ` Junio C Hamano
2021-02-08  8:06   ` 胡哲宁
2021-02-08 17:02 ` [PATCH v2] git-difftool-helper.sh: learn a new way go back to last " ZheNing Hu via GitGitGadget
2021-02-08 20:13   ` Junio C Hamano
2021-02-08 22:15   ` David Aguilar
2021-02-08 23:34     ` Junio C Hamano
2021-02-09  6:19       ` 胡哲宁
2021-02-09  6:04     ` 胡哲宁
2021-02-09 15:30   ` [PATCH v3] difftool.c: learn a new way start from specified file ZheNing Hu via GitGitGadget
2021-02-09 18:17     ` Junio C Hamano
2021-02-10 17:00       ` 胡哲宁
2021-02-10 18:16         ` Junio C Hamano
2021-02-10 20:05           ` Junio C Hamano
2021-02-14  7:53           ` ZheNing Hu
2021-02-14 13:09     ` [PATCH v4] difftool.c: learn a new way start at " ZheNing Hu via GitGitGadget
2021-02-16  1:46       ` Junio C Hamano
2021-02-16 12:56       ` [PATCH v5 0/2] " ZheNing Hu via GitGitGadget
2021-02-16 12:56         ` [PATCH v5 1/2] diff: --{rotate,skip}-to=<path> Junio C Hamano via GitGitGadget
2021-02-16 12:56         ` [PATCH v5 2/2] difftool.c: learn a new way start at specified file ZheNing Hu via GitGitGadget
2021-02-17 10:31           ` Junio C Hamano
2021-02-17 16:18             ` ZheNing Hu
2021-02-16 18:45         ` [PATCH v5 0/2] " Junio C Hamano
2021-02-17  4:12           ` ZheNing Hu
2021-02-17 11:14             ` Denton Liu
2021-02-17 11:40               ` ZheNing Hu
2021-02-17 18:56                 ` Junio C Hamano
2021-02-18  5:20                   ` ZheNing Hu
2021-02-18 15:04                   ` ZheNing Hu
2021-02-18 19:11                     ` Junio C Hamano
2021-02-19 10:59                       ` ZheNing Hu
2021-02-25 11:08                   ` Johannes Schindelin
2021-02-25 19:01                     ` Junio C Hamano
2021-02-19 12:53         ` [PATCH v6] " ZheNing Hu via GitGitGadget
2021-02-22 15:11           ` ZheNing Hu
2021-02-22 21:40           ` Junio C Hamano

git@vger.kernel.org list mirror (unofficial, one of many)

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V1 git git/ https://public-inbox.org/git \
		git@vger.kernel.org
	public-inbox-index git

Example config snippet for mirrors.
Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.io/gmane.comp.version-control.git
 note: .onion URLs require Tor: https://www.torproject.org/

code repositories for the project(s) associated with this inbox:

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

AGPL code for this site: git clone https://public-inbox.org/public-inbox.git