Skip to contentSkip to conversation

git-jump: pick a mode automatically when invoked without arguments

PATCH Superseded Greg Hurrell via GitGitGadget 5 participants 15 messages May 8 – May 26

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 git-jump: pick a mode automatically when invoked without arguments

From: Greg Hurrell <[email protected]>

When git jump is invoked with no positional arguments (and no arguments after --stdout) it currently prints usage and exits with status 1.

But there are two situations where we can usefully infer the most valuable and likely mode that a user would want to use, and select it automatically when they run git jump without arguments:

1. When there are unmerged paths in the index, the user likely wants git jump merge.

2. When the working tree has unstaged changes, the user likely wants git jump diff.

Detect these two cases and dispatch to the corresponding mode automatically, falling back to the existing usage-and-exit behavior when neither holds.

---
git-jump: pick a mode automatically when invoked without arguments

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2108%2Fwincent%2Fauto-jump-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2108/wincent/auto-jump-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/2108

 contrib/git-jump/README   |  4 ++++
 contrib/git-jump/git-jump | 16 +++++++++++++---
 2 files changed, 17 insertions(+), 3 deletions(-)
contrib/git-jump/README +4 -0
index 3211841305..420b20b6a2 100644
@@ -55,6 +55,10 @@ To use it, just drop git-jump in your PATH, and then invoke it like
 this:
 
 --------------------------------------------------
+# pick a mode automatically: "merge" if there are unmerged paths,
+# "diff" if the worktree has unstaged changes, otherwise show usage
+git jump
+
 # jump to changes not yet staged for commit
 git jump diff
 
contrib/git-jump/git-jump +13 -3
index 8d1d5d79a6..ac0ad2f037 100755
@@ -2,7 +2,7 @@
 
 usage() {
 	cat <<\EOF
-usage: git jump [--stdout] <mode> [<args>]
+usage: git jump [--stdout] [<mode>] [<args>]
 
 Jump to interesting elements in an editor.
 The <mode> parameter is one of:
@@ -99,8 +99,18 @@ while test $# -gt 0; do
 	shift
 done
 if test $# -lt 1; then
-	usage >&2
-	exit 1
+	if test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" != "true"; then
+		usage >&2
+		exit 1
+	fi
+	if test -n "$(git ls-files -u)"; then
+		set -- merge
+	elif ! git diff --quiet; then
+		set -- diff
+	else
+		usage >&2
+		exit 1
+	fi
 fi
 mode=$1; shift
 type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }

base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0

Signature · 1 line
gitgitgadget
#1 lore raw
Quoted 13 lines · Greg Hurrell via GitGitGadget

From: Greg Hurrell <[email protected]>

When git jump is invoked with no positional arguments (and no arguments after --stdout) it currently prints usage and exits with status 1.

But there are two situations where we can usefully infer the most valuable and likely mode that a user would want to use, and select it automatically when they run git jump without arguments:

1. When there are unmerged paths in the index, the user likely wants git jump merge.

Quoted 6 lines

2. When the working tree has unstaged changes, the user likely wants git jump diff.

Detect these two cases and dispatch to the corresponding mode automatically, falling back to the existing usage-and-exit behavior when neither holds.

OK, I guess this saves a little bit of typing. I never really thought about it because I long ago aliased the various invocations in my shell ("git jump diff" in particular is so useful that it is just "d" in my shell).

I'd be a little worried that it is more confusing to somebody approaching the command for the first time and just runs "git jump" to not see usage or other guidance. But that might be overly paranoid.

Would having "git jump auto" work for you? I.e., are you primarily trying to avoid the mental effort of selecting the command, or the finger effort of typing it?

Quoted 5 lines

if test $# -lt 1; then

contrib/git-jump/git-jump +2 -2
-	usage >&2
-	exit 1
+	if test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" != "true"; then
+		usage >&2

contrib/git-jump/git-jump while test $# -gt 0; do · line 113

Quoted 10 lines
contrib/git-jump/git-jump +10 -0
+		exit 1
+	fi
+	if test -n "$(git ls-files -u)"; then
+		set -- merge
+	elif ! git diff --quiet; then
+		set -- diff
+	else
+		usage >&2
+		exit 1
+	fi

The implementation looks reasonable. In theory we could save a diff invocation by trying diff mode and reporting whether it found anything. But the --quiet invocation is not too expensive, and avoiding it is probably not worth the gymnastics required.

-Peff

#2 lore raw
Quoted 5 lines · Jeff King

On Fri, May 08, 2026 at 09:07:34AM +0000, Greg Hurrell via GitGitGadget wrote:

I'd be a little worried that it is more confusing to somebody approaching the command for the first time and just runs "git jump" to not see usage or other guidance. But that might be overly paranoid.

Hopefully, they at least read the README before installing it from contrib/ (although Homebrew recently starting installing it for folks automatically, so may not remain true for much longer on macOS...)

Quoted 3 lines

Would having "git jump auto" work for you? I.e., are you primarily trying to avoid the mental effort of selecting the command, or the finger effort of typing it?

It's mostly the finger effort of typing it because I generally know exactly which mode I want; eg.

- I'm in the middle of a rebase, and hit a conflict; 100% of the time, I want to explore the conflicts, so I want git jump to do git jump merge.

- I have unstaged changes, and I want to make some tweaks before committing; so I want git jump to do git jump diff.

- Otherwise, I'm wanting to search for something (ie. git jump grep), so by definition I'm going to be doing some extra typing anyway (ie. git jump grep <pattern>).

This is muscle memory for me at this point, because I've had a git jump alias for this in my dotfiles[^1] for a couple of years. Homebrew installing git-jump by default a few months ago[^2] broke this, because aliases can't shadow builtin commands.

[^1]: https://github.com/wincent/wincent/commit/99183f86fe35
[^2]: https://github.com/Homebrew/homebrew-core/commit/e9fc066240f2

Best wishes,
Greg

#3 lore raw
Quoted 10 lines · Greg Hurrell
Quoted 5 lines · Jeff King

On Fri, May 08, 2026 at 09:07:34AM +0000, Greg Hurrell via GitGitGadget wrote:

I'd be a little worried that it is more confusing to somebody approaching the command for the first time and just runs "git jump" to not see usage or other guidance. But that might be overly paranoid.

Hopefully, they at least read the README before installing it from contrib/ (although Homebrew recently starting installing it for folks automatically, so may not remain true for much longer on macOS...)

Yeah, I'd hope so. And even if it might be more discoverable, I'm not sure that is more important than being convenient for experienced users.

I guess a config option would be possible, but probably not worth it for something as trivial as git-jump.

Quoted 2 lines

It's mostly the finger effort of typing it because I generally know exactly which mode I want; eg.

OK, that makes sense.

Quoted 4 lines

This is muscle memory for me at this point, because I've had a git jump alias for this in my dotfiles[^1] for a couple of years. Homebrew installing git-jump by default a few months ago[^2] broke this, because aliases can't shadow builtin commands.

Ah, yeah, that is frustrating. We try to avoid aliases overrides to prevent confusion, but for an add-on tool like git-jump I think it is overly cautious. It might be reasonable to limit that protection only to commands in Git's exec-path, but I haven't thought hard about it. And I think it should be considered separately from this patch anyway.

So yeah, your patch looks good to me. Thanks.

-Peff

#4 lore raw
Quoted 3 lines · Greg Hurrell

Hopefully, they at least read the README before installing it from contrib/ (although Homebrew recently starting installing it for folks automatically, so may not remain true for much longer on macOS...)

Oh! I didn't know that but looking closer on my homebrew installed Git, looks like you're right.

I would've assumed that if users had jumped through the hoops of installing git-jump from contrib/ it stands to reason they would have some sense of what it does. But if this is landing as a part of regular brew install git, I'd wager there's a few unsuspecting people running git-jump that don't know what it does.

Quoted 1 line

Would having "git jump auto" work for you?

Imo, this sounds ideal -- there's something odd about git jump picking the subcommand heuristically. At least when I invoke git-jump I always do so with a specific intent of _where_ I want to jump. Then again, I never do a jump merge or a jump ws.

Quoted 2 lines

Homebrew installing git-jump by default a few months ago[^2] broke this, because aliases can't shadow builtin commands.

But it looks like this doesn't work in this case. Even if you have git-jump installed stand-alone (mine is in ~/bin/git-jump, in PATH, before /opt/homebrew/bin.)

FWIW I alias jump to j, jump diff to jd and jump grep to jg. E.g.

git jd # git jump diff

contrib/git-jump/git-jump line 5

Quoted 2 lines · Greg Hurrell via GitGitGadget
contrib/git-jump/git-jump +1 -1
-usage: git jump [--stdout] <mode> [<args>]
+usage: git jump [--stdout] [<mode>] [<args>]

The usage message makes <mode> optional but doesn't explain what happens when you omit it. Seems worth documenting the auto-detect behavior there too.

Quoted 9 lines

But there are two situations where we can usefully infer the most valuable and likely mode that a user would want to use, and select it automatically when they run git jump without arguments:

1. When there are unmerged paths in the index, the user likely wants git jump merge.

2. When the working tree has unstaged changes, the user likely wants git jump diff.

I can think of a third situation -- when there are staged changes flagged by git diff --cached --check.

If we're going to teach git-jump how to be more clever about where to jump, does it also make sense to bake git jump ws into this?

Also, if this is going to grow into a proper auto-detect heuristic, it might be cleaner as a first-class mode rather than logic spliced into the argument parser. Something like:

    mode_auto() {
        if test -n "$(git ls-files -u)"; then
            mode_merge "$@"
        elif ! git diff --quiet; then
            mode_diff "$@"
        elif ! git diff --cached --check >/dev/null 2>&1; then
            mode_ws --cached "$@"
        else
            return 0
        fi
    }

That way git jump auto works explicitly, bare git jump defaults to it (just set -- auto when $# -lt 1), and the usage text can document the heuristic. It also keeps the detection and dispatch in one place in case someone wants to tweak the priority later.

All in all, I think an auto jumping mode could be genuinely useful.

#5 lore raw
Quoted 27 lines · Erik Cervin Edin

contrib/git-jump/git-jump line 5

Quoted 2 lines · Greg Hurrell via GitGitGadget
contrib/git-jump/git-jump +1 -1
-usage: git jump [--stdout] <mode> [<args>]
+usage: git jump [--stdout] [<mode>] [<args>]

The usage message makes <mode> optional but doesn't explain what happens when you omit it. Seems worth documenting the auto-detect behavior there too.

If we're going to teach git-jump how to be more clever about where to jump, does it also make sense to bake git jump ws into this?

Also, if this is going to grow into a proper auto-detect heuristic, it might be cleaner as a first-class mode rather than logic spliced into the argument parser. Something like:

    mode_auto() {
        if test -n "$(git ls-files -u)"; then
            mode_merge "$@"
        elif ! git diff --quiet; then
            mode_diff "$@"
        elif ! git diff --cached --check >/dev/null 2>&1; then
            mode_ws --cached "$@"
        else
            return 0
        fi
    }
Quoted 4 lines

That way git jump auto works explicitly, bare git jump defaults to it (just set -- auto when $# -lt 1), and the usage text can document the heuristic. It also keeps the detection and dispatch in one place in case someone wants to tweak the priority later.

All of those suggestions sound reasonable to me. Jeff, do you agree? If so, I can update the patch.

Best wishes,
Greg

#6 lore raw
Quoted 28 lines · Greg Hurrell
Quoted 27 lines · Erik Cervin Edin

contrib/git-jump/git-jump line 5

Quoted 2 lines · Greg Hurrell via GitGitGadget
contrib/git-jump/git-jump +1 -1
-usage: git jump [--stdout] <mode> [<args>]
+usage: git jump [--stdout] [<mode>] [<args>]

The usage message makes <mode> optional but doesn't explain what happens when you omit it. Seems worth documenting the auto-detect behavior there too.

If we're going to teach git-jump how to be more clever about where to jump, does it also make sense to bake git jump ws into this?

Also, if this is going to grow into a proper auto-detect heuristic, it might be cleaner as a first-class mode rather than logic spliced into the argument parser. Something like:

    mode_auto() {
        if test -n "$(git ls-files -u)"; then
            mode_merge "$@"
        elif ! git diff --quiet; then
            mode_diff "$@"
        elif ! git diff --cached --check >/dev/null 2>&1; then
            mode_ws --cached "$@"
        else
            return 0
        fi
    }
Quoted 7 lines
Quoted 4 lines

That way git jump auto works explicitly, bare git jump defaults to it (just set -- auto when $# -lt 1), and the usage text can document the heuristic. It also keeps the detection and dispatch in one place in case someone wants to tweak the priority later.

All of those suggestions sound reasonable to me. Jeff, do you agree? If so, I can update the patch.

Yeah, I agree that having an explicit "auto" mode (and then just defaulting to it) makes perfect sense.

I don't really have an opinion on adding "ws" in here. Despite being the person who added the whitespace mode in the first place, I can't remember ever using it in the last 10 years. ;) But the cost is fairly low to support it, so we might as well.

-Peff

#7 lore raw

PATCH v2 1/1 git-jump: pick a mode automatically when invoked without arguments

In reply to Greg Hurrell via GitGitGadget

From: Greg Hurrell <[email protected]>

When git jump is invoked with no positional arguments (and no arguments after --stdout) it currently prints usage and exits with status 1.

But there are several situations where we can usefully infer the most valuable and likely mode that a user would want to use, and select it automatically:

1. When there are unmerged paths in the index, the user likely wants git jump merge.

2. When the working tree has unstaged changes, the user likely wants git jump diff.

3. In the presence of conflict markers or whitespace errors (as reported by git diff --check), the user likely wants git jump ws.

In this commit we teach git jump a new "auto" mode which detects these cases and dispatches to the corresponding mode automatically. The user can either explicitly spell out git jump auto, or just leave it at git jump (because "auto" is the default).

If none of the interesting cases listed above applies, then auto mode falls back to the existing usage-and-exit behavior.

---
git-jump: pick a mode automatically when invoked without arguments

Changes since v0:

* Added explicit "auto" keyword/mode.
* Updated additional detail to usage info and README.
* (Bonus) Added ws usage example to README.

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2108%2Fwincent%2Fauto-jump-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2108/wincent/auto-jump-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/2108

Range-diff vs v1:

1: 87fa66d233 ! 1: 5fbc8480ef git-jump: pick a mode automatically when invoked without arguments
@@ Commit message
arguments after --stdout) it currently prints usage and exits with status 1.

- But there are two situations where we can usefully infer the most
+ But there are several situations where we can usefully infer the most
valuable and likely mode that a user would want to use, and select it
- automatically when they run git jump without arguments:
+ automatically:

1. When there are unmerged paths in the index, the user likely wants git jump merge.
@@ Commit message
2. When the working tree has unstaged changes, the user likely wants git jump diff.

- Detect these two cases and dispatch to the corresponding mode
- automatically, falling back to the existing usage-and-exit behavior
- when neither holds.
+ 3. In the presence of conflict markers or whitespace errors (as reported
+ by git diff --check), the user likely wants git jump ws.
+
+ In this commit we teach git jump a new "auto" mode which detects these
+ cases and dispatches to the corresponding mode automatically. The user
+ can either explicitly spell out git jump auto, or just leave it at
+ git jump (because "auto" is the default).
+
+ If none of the interesting cases listed above applies, then auto mode
+ falls back to the existing usage-and-exit behavior.

## contrib/git-jump/README ##
-@@ contrib/git-jump/README: To use it, just drop git-jump in your PATH, and then invoke it like
- this:
+@@ contrib/git-jump/README: git jump grep foo_bar
+ # arbitrary grep options
+ git jump grep -i foo_bar

- --------------------------------------------------
++# jump to places with conflict markers or whitespace errors ++# (as reported by # git diff --check)
++git jump ws
++
+ # use the silver searcher for git jump grep
+ git config jump.grepCmd "ag --column"
++
+# pick a mode automatically: "merge" if there are unmerged paths,
-+# "diff" if the worktree has unstaged changes, otherwise show usage -+git jump
++# "diff" if the worktree has unstaged changes, "ws" if there are ++# whitespace problems; otherwise show usage
++git jump auto
+
- # jump to changes not yet staged for commit
- git jump diff
++# with no explicit mode, same as "auto"
++git jump
+ --------------------------------------------------

+ You can use the optional argument '--stdout' to print the listing to

## contrib/git-jump/git-jump ##
@@
@@ contrib/git-jump/git-jump
+usage: git jump [--stdout] [<mode>] [<args>]

Jump to interesting elements in an editor.
- The <mode> parameter is one of:
-@@ contrib/git-jump/git-jump: while test $# -gt 0; do
- shift
- done
- if test $# -lt 1; then
-- usage >&2
-- exit 1
+-The <mode> parameter is one of:
++The <mode> parameter is one of the following,
++defaulting to "auto" if omitted:
+
+ diff: elements are diff hunks. Arguments are given to diff.
+
+@@ contrib/git-jump/git-jump: grep: elements are grep hits. Arguments are given to git grep or, if +
+ ws: elements are whitespace errors. Arguments are given to diff --check.
+
++auto: select one of the other modes based on worktree state;
++ "merge" if there are unmerged paths, "diff" if there are
++ unstaged changes, "ws" if there are whitespace errors.
++
+ If the optional argument --stdout is given, print the quickfix
+ lines to standard output instead of feeding it to the editor.
+ EOF
+@@ contrib/git-jump/git-jump: mode_ws() {
+ git diff --check "$@"
+ }
+
++mode_auto() {
+ if test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" != "true"; then
+ usage >&2
+ exit 1
+ fi
-+ if test -n "$(git ls-files -u)"; then
-+ set -- merge
-+ elif ! git diff --quiet; then
-+ set -- diff
++ if test -n "$(git ls-files -u "$@")"; then
++ mode_merge "$@"
++ elif ! git diff --quiet "$@"; then
++ mode_diff "$@"
++ elif ! git diff --check >/dev/null 2>&1; then
++ mode_ws "$@"
+ else
+ usage >&2
+ exit 1
+ fi
++}
++
+ use_stdout=
+ while test $# -gt 0; do
+ case "$1" in
+@@ contrib/git-jump/git-jump: while test $# -gt 0; do
+ shift
+ done
+ if test $# -lt 1; then
+- usage >&2
+- exit 1
++ set -- auto
fi
mode=$1; shift
type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }

 contrib/git-jump/README   | 12 ++++++++++++
 contrib/git-jump/git-jump | 29 +++++++++++++++++++++++++----
 2 files changed, 37 insertions(+), 4 deletions(-)
contrib/git-jump/README +12 -0
index 3211841305..ac35792e55 100644
@@ -75,8 +75,20 @@ git jump grep foo_bar
 # arbitrary grep options
 git jump grep -i foo_bar
 
+# jump to places with conflict markers or whitespace errors
+# (as reported by # `git diff --check`)
+git jump ws
+
 # use the silver searcher for git jump grep
 git config jump.grepCmd "ag --column"
+
+# pick a mode automatically: "merge" if there are unmerged paths,
+# "diff" if the worktree has unstaged changes, "ws" if there are
+# whitespace problems; otherwise show usage
+git jump auto
+
+# with no explicit mode, same as "auto"
+git jump
 --------------------------------------------------
 
 You can use the optional argument '--stdout' to print the listing to
contrib/git-jump/git-jump +25 -4
index 8d1d5d79a6..43d3b42a41 100755
@@ -2,10 +2,11 @@
 
 usage() {
 	cat <<\EOF
-usage: git jump [--stdout] <mode> [<args>]
+usage: git jump [--stdout] [<mode>] [<args>]
 
 Jump to interesting elements in an editor.
-The <mode> parameter is one of:
+The <mode> parameter is one of the following,
+defaulting to "auto" if omitted:
 
 diff: elements are diff hunks. Arguments are given to diff.
 
@@ -16,6 +17,10 @@ grep: elements are grep hits. Arguments are given to git grep or, if
 
 ws: elements are whitespace errors. Arguments are given to diff --check.
 
+auto: select one of the other modes based on worktree state;
+      "merge" if there are unmerged paths, "diff" if there are
+      unstaged changes, "ws" if there are whitespace errors.
+
 If the optional argument `--stdout` is given, print the quickfix
 lines to standard output instead of feeding it to the editor.
 EOF
@@ -82,6 +87,23 @@ mode_ws() {
 	git diff --check "$@"
 }
 
+mode_auto() {
+	if test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" != "true"; then
+		usage >&2
+		exit 1
+	fi
+	if test -n "$(git ls-files -u "$@")"; then
+		mode_merge "$@"
+	elif ! git diff --quiet "$@"; then
+		mode_diff "$@"
+	elif ! git diff --check >/dev/null 2>&1; then
+		mode_ws "$@"
+	else
+		usage >&2
+		exit 1
+	fi
+}
+
 use_stdout=
 while test $# -gt 0; do
 	case "$1" in
@@ -99,8 +121,7 @@ while test $# -gt 0; do
 	shift
 done
 if test $# -lt 1; then
-	usage >&2
-	exit 1
+	set -- auto
 fi
 mode=$1; shift
 type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }

base-commit: 1c00d2d8392f603a6263f11f1a50fde96ae5475e

Signature · 1 line
gitgitgadget
#8 lore raw
Quoted 2 lines · Greg Hurrell via GitGitGadget

If none of the interesting cases listed above applies, then auto mode falls back to the existing usage-and-exit behavior.

If more than one interesting cases apply, what happens, and what should happen?

contrib/git-jump/README git jump grep foo_bar · line 79

Quoted 10 lines
contrib/git-jump/README +2 -0
index 3211841305..ac35792e55 100644
@@ -75,8 +75,20 @@ git jump grep foo_bar
 # arbitrary grep options
 git jump grep -i foo_bar
 
+# jump to places with conflict markers or whitespace errors
+# (as reported by # `git diff --check`)

Is "#" after "reported by" intended?

contrib/git-jump/git-jump line 5

Quoted 10 lines
contrib/git-jump/git-jump +1 -1
index 8d1d5d79a6..43d3b42a41 100755
@@ -2,10 +2,11 @@
 
 usage() {
 	cat <<\EOF
-usage: git jump [--stdout] <mode> [<args>]
+usage: git jump [--stdout] [<mode>] [<args>]

So "git jump --stdout foo.c" should mean "git jump --stdout auto foo.c", OK.

Quoted 12 lines
contrib/git-jump/git-jump +4 -0
@@ -16,6 +17,10 @@ grep: elements are grep hits. Arguments are given to git grep or, if
 
 ws: elements are whitespace errors. Arguments are given to diff --check.
 
+auto: select one of the other modes based on worktree state;
+      "merge" if there are unmerged paths, "diff" if there are
+      unstaged changes, "ws" if there are whitespace errors.
+
 If the optional argument `--stdout` is given, print the quickfix
 lines to standard output instead of feeding it to the editor.
 EOF

contrib/git-jump/git-jump mode_ws() { · line 94

Quoted 8 lines
contrib/git-jump/git-jump +5 -0
@@ -82,6 +87,23 @@ mode_ws() {
 	git diff --check "$@"
 }
 
+mode_auto() {
+	if test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" != "true"; then
+		usage >&2
+		exit 1
+	fi

That looks like a basic safety measure, which is good.

contrib/git-jump/git-jump mode_ws() { · line 99

Quoted 5 lines
contrib/git-jump/git-jump +5 -0
+	if test -n "$(git ls-files -u "$@")"; then
+		mode_merge "$@"
+	elif ! git diff --quiet "$@"; then
+		mode_diff "$@"
+	elif ! git diff --check >/dev/null 2>&1; then

Shouldn't this "diff --check" be restricted by "$@" if given?

Quoted 6 lines
contrib/git-jump/git-jump +6 -0
+		mode_ws "$@"
+	else
+		usage >&2
+		exit 1
+	fi
+}
#9 lore raw
Quoted 16 lines · Junio C Hamano

contrib/git-jump/git-jump mode_ws() { · line 94

Quoted 5 lines
contrib/git-jump/git-jump +5 -0
+mode_auto() {
+	if test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" != "true"; then
+		usage >&2
+		exit 1
+	fi

That looks like a basic safety measure, which is good.

contrib/git-jump/git-jump mode_ws() { · line 99

Quoted 5 lines
contrib/git-jump/git-jump +5 -0
+	if test -n "$(git ls-files -u "$@")"; then
+		mode_merge "$@"
+	elif ! git diff --quiet "$@"; then
+		mode_diff "$@"
+	elif ! git diff --check >/dev/null 2>&1; then

Shouldn't this "diff --check" be restricted by "$@" if given?

Quoted 1 line

contrib/git-jump/git-jump mode_ws() { · line 100

Quoted 1 line
contrib/git-jump/git-jump +1 -0
+		mode_ws "$@"

If there are any unstaged changes (possibly with whitespace errors), 'git diff --quiet' would exit with non-zero, so "elif ! git diff --quiet" would be taken and we do mode_diff. The user cannot rely on "auto" to trigger mode_ws to check whitespace errors in the working tree files because of this. If there is no unstaged changes, 'git diff --quiet' woudl exit with zero, so the control comes to "git diff --check", but then there is nothing mode_ws to work on in that case, right? So it is not clear to me in what situation this auto selection of mode_ws would help us.

Quoted 5 lines
Quoted 5 lines
contrib/git-jump/git-jump +5 -0
+	else
+		usage >&2
+		exit 1
+	fi
+}
#10 lore raw

PATCH v3 1/1 git-jump: pick a mode automatically when invoked without arguments

In reply to Greg Hurrell via GitGitGadget

From: Greg Hurrell <[email protected]>

When git jump is invoked with no positional arguments (and no arguments after --stdout) it currently prints usage and exits with status 1.

But there are two situations where we can usefully infer the most valuable and likely mode that a user would want to use, and select it automatically:

1. When there are unmerged paths in the index, the user likely wants git jump merge.

2. When the working tree has unstaged changes, the user likely wants git jump diff.

In this commit we teach git jump a new "auto" mode which detects these cases and dispatches to the corresponding mode automatically. The user can either explicitly spell out git jump auto, or just leave it at git jump (because "auto" is the default).

If none of the interesting cases listed above applies, then auto mode falls back to the existing usage-and-exit behavior.

---
git-jump: pick a mode automatically when invoked without arguments

Changes since v2; all of these in response to feedback from Junio:

* Removed stray # from README.
* Don't both teaching "auto" to select "ws" mode, because it is always subsumed by "diff".
* Update usage string to make clear that git jump --stdout foo is not a synonym for git jump --stdout auto foo, because distinguishing between foo as <mode> and foo as <arg> is fraught with ambiguity.

In answer to Junio's question:

> If more than one interesting cases apply, what happens, and what > should happen?

it's an ordered choice (merge > diff).

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2108%2Fwincent%2Fauto-jump-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2108/wincent/auto-jump-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/2108

Range-diff vs v2:

1: 5fbc8480ef ! 1: af758dcfd2 git-jump: pick a mode automatically when invoked without arguments
@@ Commit message
arguments after --stdout) it currently prints usage and exits with status 1.

- But there are several situations where we can usefully infer the most
+ But there are two situations where we can usefully infer the most
valuable and likely mode that a user would want to use, and select it automatically:

@@ Commit message
2. When the working tree has unstaged changes, the user likely wants git jump diff.

- 3. In the presence of conflict markers or whitespace errors (as reported
- by git diff --check), the user likely wants git jump ws.
-
In this commit we teach git jump a new "auto" mode which detects these cases and dispatches to the corresponding mode automatically. The user can either explicitly spell out git jump auto, or just leave it at
@@ contrib/git-jump/README: git jump grep foo_bar
git jump grep -i foo_bar

+# jump to places with conflict markers or whitespace errors
-+# (as reported by # git diff --check)
++# (as reported by git diff --check)
+git jump ws
+
# use the silver searcher for git jump grep
@@ contrib/git-jump/README: git jump grep foo_bar
+# whitespace problems; otherwise show usage
+git jump auto
+
-+# with no explicit mode, same as "auto"
++# with no explicit mode and no args, same as "auto"
+git jump
--------------------------------------------------

@@ contrib/git-jump/README: git jump grep foo_bar

## contrib/git-jump/git-jump ##
@@
-
usage() {
cat <<\EOF
--usage: git jump [--stdout] <mode> [<args>] -+usage: git jump [--stdout] [<mode>] [<args>]
+ usage: git jump [--stdout] <mode> [<args>]
++ or: git jump [--stdout]

Jump to interesting elements in an editor.
-The <mode> parameter is one of:
-+The <mode> parameter is one of the following, -+defaulting to "auto" if omitted:
++The <mode> parameter is one of the following. ++With no <mode> and no <args>, it defaults to "auto".

diff: elements are diff hunks. Arguments are given to diff.

@@ contrib/git-jump/git-jump: mode_ws() {
+ mode_merge "$@"
+ elif ! git diff --quiet "$@"; then
+ mode_diff "$@"
-+ elif ! git diff --check >/dev/null 2>&1; then
-+ mode_ws "$@"
+ else
+ usage >&2
+ exit 1

 contrib/git-jump/README   | 12 ++++++++++++
 contrib/git-jump/git-jump | 26 +++++++++++++++++++++++---
 2 files changed, 35 insertions(+), 3 deletions(-)
contrib/git-jump/README +12 -0
index 3211841305..aabec4a756 100644
@@ -75,8 +75,20 @@ git jump grep foo_bar
 # arbitrary grep options
 git jump grep -i foo_bar
 
+# jump to places with conflict markers or whitespace errors
+# (as reported by `git diff --check`)
+git jump ws
+
 # use the silver searcher for git jump grep
 git config jump.grepCmd "ag --column"
+
+# pick a mode automatically: "merge" if there are unmerged paths,
+# "diff" if the worktree has unstaged changes, "ws" if there are
+# whitespace problems; otherwise show usage
+git jump auto
+
+# with no explicit mode and no args, same as "auto"
+git jump
 --------------------------------------------------
 
 You can use the optional argument '--stdout' to print the listing to
contrib/git-jump/git-jump +23 -3
index 8d1d5d79a6..79286d8112 100755
@@ -3,9 +3,11 @@
 usage() {
 	cat <<\EOF
 usage: git jump [--stdout] <mode> [<args>]
+   or: git jump [--stdout]
 
 Jump to interesting elements in an editor.
-The <mode> parameter is one of:
+The <mode> parameter is one of the following.
+With no <mode> and no <args>, it defaults to "auto".
 
 diff: elements are diff hunks. Arguments are given to diff.
 
@@ -16,6 +18,10 @@ grep: elements are grep hits. Arguments are given to git grep or, if
 
 ws: elements are whitespace errors. Arguments are given to diff --check.
 
+auto: select one of the other modes based on worktree state;
+      "merge" if there are unmerged paths, "diff" if there are
+      unstaged changes, "ws" if there are whitespace errors.
+
 If the optional argument `--stdout` is given, print the quickfix
 lines to standard output instead of feeding it to the editor.
 EOF
@@ -82,6 +88,21 @@ mode_ws() {
 	git diff --check "$@"
 }
 
+mode_auto() {
+	if test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" != "true"; then
+		usage >&2
+		exit 1
+	fi
+	if test -n "$(git ls-files -u "$@")"; then
+		mode_merge "$@"
+	elif ! git diff --quiet "$@"; then
+		mode_diff "$@"
+	else
+		usage >&2
+		exit 1
+	fi
+}
+
 use_stdout=
 while test $# -gt 0; do
 	case "$1" in
@@ -99,8 +120,7 @@ while test $# -gt 0; do
 	shift
 done
 if test $# -lt 1; then
-	usage >&2
-	exit 1
+	set -- auto
 fi
 mode=$1; shift
 type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }

base-commit: aec3f587505a472db67e9462d0702e7d463a449d

Signature · 1 line
gitgitgadget
#11 lore raw
Quoted 7 lines · Greg Hurrell via GitGitGadget

* Removed stray # from README.
* Don't both teaching "auto" to select "ws" mode, because it is always subsumed by "diff".
* Update usage string to make clear that git jump --stdout foo is not a synonym for git jump --stdout auto foo, because distinguishing between foo as <mode> and foo as <arg> is fraught with ambiguity.

Quoted 6 lines

In answer to Junio's question:

> If more than one interesting cases apply, what happens, and what > should happen?

it's an ordered choice (merge > diff).

After 'diff --quiet "$@"' says "nothing interesting between the index and the working tree", I actually think it may be worth using either 'git diff --check HEAD "$@"' or 'git diff --cached --check "$@"' to see if ws fix is needed.

But I am not a target audience of this feature, so I'll let others figure out what to do here.

#12 lore raw
In reply to Greg Hurrell via GitGitGadget
Quoted 9 lines · Greg Hurrell via GitGitGadget

Changes since v2; all of these in response to feedback from Junio:

* Removed stray # from README.
* Don't both teaching "auto" to select "ws" mode, because it is always subsumed by "diff".
* Update usage string to make clear that git jump --stdout foo is not a synonym for git jump --stdout auto foo, because distinguishing between foo as <mode> and foo as <arg> is fraught with ambiguity.

Quoted 6 lines

In answer to Junio's question:

> If more than one interesting cases apply, what happens, and what > should happen?

it's an ordered choice (merge > diff).

Dropping the "ws" mode from auto makes sense to me. It could be slotted in between "merge" and "diff" (a whitespace problem always implies a diff, but a diff does not always imply a whitespace problem). But would that actually be useful?

My impression of the "auto" feature is: I am too lazy to type, so just take me to the interesting bits. And interesting in my experience with git-jump is either "I am merging, take me to the conflict" or "I am writing new code, take me to what I already did". Limiting the second case just to whitespace violations (assuming there is at least one) would probably be more confusing than helpful.

You could perhaps argue for one more layer of "interesting", which is:
if there are no unstaged changes, take me to the staged ones. Looking at staged changes can be misleading if the working tree file has moved on (since by definition we are dumping the editor into the working tree file, not the staged contents). But if we know the diff between index and working tree is empty, then that is not an issue.

I do sometimes use "git jump diff --cached" explicitly for that purpose.

If sounds like Greg has been living with "auto" and finding it useful for a while. So I'm mostly inclined to take the patch as-is, and people can experiment with it and suggest changes after using it in practice.

But here's my one final thought. The hierarchy of "merge > diff > diff --cached", etc, makes me wonder if we could simply concatenate the outputs. I.e., show all of the merge conflicts and all of the diffs, whitespace changes, and so on. But I guess you run into two issues:

1. There will be duplicates. Every merge conflict is also a diff. And every whitespace violation is also a diff. So at the very least you need to de-dup these (which might not be entirely trivial, as they may overlap rather than starting at the same line).

2. When resolving a merge, I'm not sure if the diffs are actually interesting. Usually I git-jump around until there are no more conflicts, and then I see if it builds. But I almost never want to jump to the other changes introduced by the side-branch. There are too many of them, and they are probably uninteresting. So adding both "merge" and "diff" elements to the quicklist would be annoying.

-Peff

#13 lore raw
Quoted 11 lines · Jeff King

My impression of the "auto" feature is: I am too lazy to type, so just take me to the interesting bits. And interesting in my experience with git-jump is either "I am merging, take me to the conflict" or "I am writing new code, take me to what I already did". Limiting the second case just to whitespace violations (assuming there is at least one) would probably be more confusing than helpful.

If sounds like Greg has been living with "auto" and finding it useful for a while. So I'm mostly inclined to take the patch as-is, and people can experiment with it and suggest changes after using it in practice.

Yes, the "take me to the interesting bits" is very much the mental model I've been operating with, using the simplest definition of "interesting" ("merge conflicts", followed by "changes in the worktree"). I think that starting simple, but leaving the door open to possibly introducing more subtleties in the future makes the most sense.

- Greg

#14 lore raw
In reply to Jeff King
Quoted 9 lines · Jeff King
Quoted 2 lines · Greg Hurrell via GitGitGadget

* Don't both teaching "auto" to select "ws" mode, because it is always subsumed by "diff".

Dropping the "ws" mode from auto makes sense to me. It could be slotted in between "merge" and "diff" (a whitespace problem always implies a diff, but a diff does not always imply a whitespace problem). But would that actually be useful?

When I originally proposed the idea of a third branch, there was a subtle difference -- it was a git diff --cached --check.

Quoted 5 lines · Erik Cervin Edin

If we're going to teach git-jump how to be more clever about where to jump, does it also make sense to bake git jump ws into this?

        elif ! git diff --cached --check >/dev/null 2>&1; then
            mode_ws --cached "$@"

Ever so often I come across file with a diff --check offending white-space (often a missing newline at the end of some file) and because I have a commit hook set up, I have to go looking for where that error is. In this particular case it's always a staged change, and then a *staged* white space problem doesn't imply a diff.

This happens rarely enough that I haven't internalized that I can use "git jump diff --check --cached" and it takes me a while to navigate to the offending files.

But the main suggestion was really considering the possibility to expand this beyond these two auto jumps in the future -- I'm not sure an auto jump that goes looking for staged white spaces issues would be useful to anyone in practise and at this stage I thinks it's best to drop it.