Volume XXII, number 279Tuesday, October 6, 2026Latest message 32 minutes ago

The Git List

News and archive of git@vger.kernel.org, since April 2005

v2, 4 partscompletion: add support for 'git history'

17 messages between Aug 6, 2026 and Aug 13, 2026, from Vincent Mailhol, Patrick Steinhardt, D. Ben Knoble, Ben Knoble.

Plain Markdown or JSON for tools and agents. Diffs are folded; open one to read it.

Vincent MailholAug 6, 2026, 20:27 UTC on lore

This series adds Bash completion for the subcommands of "git history" and their options.

Patch #1 adds the basic subcommand and options completion. Patch #2 and #3 take care of the value of the --empty and --update-refs options. Finally, Patch #4 adds completion for pathspecs accepted by "split".

For each of the completions, add a set of relevant test cases.
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
Changes in v2:
  - Complete exactly one required revision and leave subsequent
    arguments to subcommand-specific completion.
  - Do not complete options after "--".
  - Complete values for "--empty" and "--update-refs".
  - Complete pathspecs for "git history split".
  - Expand the test coverage for options, revisions, and pathspecs.
Link to v1: https://lore.kernel.org/r/20260804-history_autocompletion-v1-1-6f7459ffb677@kernel.org
---
Vincent Mailhol (4):
      completion: add 'git history' subcommands
      completion: complete 'git history --empty' values
      completion: complete 'git history --update-refs' values
      completion: complete 'git history split' pathspecs
 contrib/completion/git-completion.bash | 68 ++++++++++++++++++++++++++++++++++
 t/t9902-completion.sh                  | 49 ++++++++++++++++++++++++
 2 files changed, 117 insertions(+)
Range-diff versus v1:
1:  d0574dca8c ! 1:  6625c7ac29 completion: add 'git history' subcommands
    @@ Metadata
      ## Commit message ##
         completion: add 'git history' subcommands
     
    -    Use the parse-options completion helpers for the "git history"
    -    subcommands and their options. Complete positional arguments as
    -    revisions, and add coverage for each kind of completion.
    +    Use the parse-options completion helpers for the
    +
    +      git history
    +
    +    subcommands and their options. All current history subcommands take a
    +    revision as their first positional argument, so complete that argument
    +    as a revision.
    +
    +    Once the revision is present, leave any further positional arguments to
    +    subcommand-specific completion. This allows a subcommand to complete
    +    another kind of argument, such as the pathspec accepted by
    +
    +      git history split
    +
    +    or another revision if a future subcommand accepts one.
     
         Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
    +    ---
    +    Changes in v2:
    +
    +      - Test options before and after revisions.
    +      - Do not complete options after "--".
    +      - Stop revision completion after the first required
     
      ## contrib/completion/git-completion.bash ##
     @@ contrib/completion/git-completion.bash: _git_help ()
      	fi
      }
      
    ++__git_history_has_revision ()
    ++{
    ++	local i
    ++
    ++	for ((i = __git_cmd_idx + 2; i < cword; i++)); do
    ++		case "${words[i]}" in
    ++		--empty|--update-refs)
    ++			((i++))
    ++			;;
    ++		-*)
    ++			;;
    ++		*)
    ++			return 0
    ++			;;
    ++		esac
    ++	done
    ++	return 1
    ++}
    ++
     +_git_history ()
     +{
     +	local subcommands subcommand
    @@ contrib/completion/git-completion.bash: _git_help ()
     +		return
     +	fi
     +
    -+	case "$cur" in
    -+	--*)
    -+		__gitcomp_builtin "history_$subcommand"
    -+		;;
    -+	*)
    ++	if ! __git_has_doubledash; then
    ++		case "$cur" in
    ++		--*)
    ++			__gitcomp_builtin "history_$subcommand"
    ++			return
    ++			;;
    ++		esac
    ++	fi
    ++
    ++	if ! __git_history_has_revision; then
     +		__git_complete_refs
    -+		;;
    -+	esac
    ++		return
    ++	fi
     +}
     +
      _git_init ()
    @@ t/t9902-completion.sh: test_expect_success 'git clone --config= - value' '
     +'
     +
     +test_expect_success 'git history subcommand options' '
    -+	test_completion "git history fixup --upd" "--update-refs="
    ++	test_completion "git history split main --" <<-\EOF &&
    ++	--update-refs=Z
    ++	--dry-run Z
    ++	--no-dry-run Z
    ++	EOF
    ++	test_completion "git history fixup --upd" "--update-refs=" &&
    ++	test_completion "git history fixup --ree" "--reedit-message " &&
    ++	test_completion "git history split --upd" "--update-refs=" &&
    ++	test_completion "git history split main --dry" "--dry-run " &&
    ++	test_completion "git history reword main -- --d" ""
     +'
     +
     +test_expect_success 'git history revisions' '
    -+	test_completion "git history split ma" "main "
    ++	test_completion "git history split ma" "main " &&
    ++	test_completion "git history split --update-refs head ma" "main " &&
    ++	test_completion "git history fixup --empty drop ma" "main " &&
    ++	test_completion "git history reword main m" ""
     +'
     +
      test_expect_success 'git reflog show' '
-:  ---------- > 2:  f618f35153 completion: complete 'git history --empty' values
-:  ---------- > 3:  abae09f208 completion: complete 'git history --update-refs' values
-:  ---------- > 4:  7bfb6664dc completion: complete 'git history split' pathspecs

--- base-commit: c56d675cccfbcf71406c4a6806c7745e4a756294 change-id: 20260804-history_autocompletion-84620c2f8500

Vincent MailholAug 6, 2026, 20:27 UTC in reply to Vincent Mailhol on lore

[PATCH v2 1/4] completion: add 'git history' subcommands

Use the parse-options completion helpers for the
  git history

subcommands and their options. All current history subcommands take a revision as their first positional argument, so complete that argument as a revision.

Once the revision is present, leave any further positional arguments to subcommand-specific completion. This allows a subcommand to complete another kind of argument, such as the pathspec accepted by

  git history split
or another revision if a future subcommand accepts one.
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
Changes in v2:
  - Test options before and after revisions.
  - Do not complete options after "--".
  - Stop revision completion after the first required
---
 contrib/completion/git-completion.bash | 48 ++++++++++++++++++++++++++++++++++
 t/t9902-completion.sh                  | 29 ++++++++++++++++++++
 2 files changed, 77 insertions(+)
Show changes to 2 files +77 −0

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index e875787710..7372e2919b 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -2137,6 +2137,54 @@ _git_help ()
 	fi
 }
 
+__git_history_has_revision ()
+{
+	local i
+
+	for ((i = __git_cmd_idx + 2; i < cword; i++)); do
+		case "${words[i]}" in
+		--empty|--update-refs)
+			((i++))
+			;;
+		-*)
+			;;
+		*)
+			return 0
+			;;
+		esac
+	done
+	return 1
+}
+
+_git_history ()
+{
+	local subcommands subcommand
+
+	__git_resolve_builtins "history"
+
+	subcommands="$___git_resolved_builtins"
+	subcommand="$(__git_find_subcommand "$subcommands")"
+
+	if [ -z "$subcommand" ]; then
+		__gitcomp "$subcommands"
+		return
+	fi
+
+	if ! __git_has_doubledash; then
+		case "$cur" in
+		--*)
+			__gitcomp_builtin "history_$subcommand"
+			return
+			;;
+		esac
+	fi
+
+	if ! __git_history_has_revision; then
+		__git_complete_refs
+		return
+	fi
+}
+
 _git_init ()
 {
 	case "$cur" in
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 9ae3c48ebd..5ccb38c751 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -3107,6 +3107,35 @@ test_expect_success 'git clone --config= - value' '
 	EOF
 '
 
+test_expect_success 'git history subcommands' '
+	test_completion "git history " <<-\EOF
+	drop Z
+	fixup Z
+	reword Z
+	split Z
+	EOF
+'
+
+test_expect_success 'git history subcommand options' '
+	test_completion "git history split main --" <<-\EOF &&
+	--update-refs=Z
+	--dry-run Z
+	--no-dry-run Z
+	EOF
+	test_completion "git history fixup --upd" "--update-refs=" &&
+	test_completion "git history fixup --ree" "--reedit-message " &&
+	test_completion "git history split --upd" "--update-refs=" &&
+	test_completion "git history split main --dry" "--dry-run " &&
+	test_completion "git history reword main -- --d" ""
+'
+
+test_expect_success 'git history revisions' '
+	test_completion "git history split ma" "main " &&
+	test_completion "git history split --update-refs head ma" "main " &&
+	test_completion "git history fixup --empty drop ma" "main " &&
+	test_completion "git history reword main m" ""
+'
+
 test_expect_success 'git reflog show' '
 	test_when_finished "git checkout - && git branch -d shown" &&
 	git checkout -b shown &&
-- 
2.54.0
Vincent MailholAug 6, 2026, 20:27 UTC in reply to Vincent Mailhol on lore

[PATCH v2 2/4] completion: complete 'git history --empty' values

The "--empty" option accepts "drop", "keep", or "abort" for the "drop" and "fixup" subcommands. Complete these values.

Although the synopsis only documents the:
  --empty=<value>
form, parse-options also accepts the value as a separate argument:
  --empty <value>
Support both forms to follow the parser.
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
Changes in v2:
  - New patch.
---
 contrib/completion/git-completion.bash | 13 +++++++++++--
 t/t9902-completion.sh                  |  5 ++++-
 2 files changed, 15 insertions(+), 3 deletions(-)
Show changes to 2 files +15 −3

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 7372e2919b..fe5223b8ec 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -2171,8 +2171,17 @@ _git_history ()
 	fi
 
 	if ! __git_has_doubledash; then
-		case "$cur" in
-		--*)
+		case "$prev,$cur" in
+		--empty,*|*,--empty=*)
+			case "$subcommand" in
+			drop|fixup)
+				__gitcomp "drop keep abort" "" \
+					"${cur##--empty=}"
+				return
+				;;
+			esac
+			;;
+		*,--*)
 			__gitcomp_builtin "history_$subcommand"
 			return
 			;;
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 5ccb38c751..52a036a1ad 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -3126,7 +3126,10 @@ test_expect_success 'git history subcommand options' '
 	test_completion "git history fixup --ree" "--reedit-message " &&
 	test_completion "git history split --upd" "--update-refs=" &&
 	test_completion "git history split main --dry" "--dry-run " &&
-	test_completion "git history reword main -- --d" ""
+	test_completion "git history reword main -- --d" "" &&
+	test_completion "git history fixup --empty=ke" "keep " &&
+	test_completion "git history drop --empty ab" "abort " &&
+	test_completion "git history reword --empty=ke" ""
 '
 
 test_expect_success 'git history revisions' '
-- 
2.54.0
Vincent MailholAug 6, 2026, 20:27 UTC in reply to Vincent Mailhol on lore

[PATCH v2 3/4] completion: complete 'git history --update-refs' values

The "--update-refs" option accepts either "branches" or "head". Complete these values.

Although the synopsis only documents the:
  --update-refs=<value>
form, parse-options also accepts the value as a separate argument:
  --update-refs <value>
Support both forms to follow the parser.
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
Changes in v2:
  - New patch.
---
 contrib/completion/git-completion.bash | 5 +++++
 t/t9902-completion.sh                  | 6 +++++-
 2 files changed, 10 insertions(+), 1 deletion(-)
Show changes to 2 files +10 −1

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index fe5223b8ec..6f1ba96763 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -2181,6 +2181,11 @@ _git_history ()
 				;;
 			esac
 			;;
+		--update-refs,*|*,--update-refs=*)
+			__gitcomp "branches head" "" \
+				"${cur##--update-refs=}"
+			return
+			;;
 		*,--*)
 			__gitcomp_builtin "history_$subcommand"
 			return
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 52a036a1ad..ea86ecc08f 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -3129,7 +3129,11 @@ test_expect_success 'git history subcommand options' '
 	test_completion "git history reword main -- --d" "" &&
 	test_completion "git history fixup --empty=ke" "keep " &&
 	test_completion "git history drop --empty ab" "abort " &&
-	test_completion "git history reword --empty=ke" ""
+	test_completion "git history reword --empty=ke" "" &&
+	test_completion "git history fixup --update-refs=he" "head " &&
+	test_completion "git history split --update-refs he" "head " &&
+	test_completion "git history reword main -- --update-refs=he" "" &&
+	test_completion "git history reword main -- --update-refs he" ""
 '
 
 test_expect_success 'git history revisions' '
-- 
2.54.0
Vincent MailholAug 6, 2026, 20:27 UTC in reply to Vincent Mailhol on lore

[PATCH v2 4/4] completion: complete 'git history split' pathspecs

Arguments following the required revision of "git history split" are pathspecs. Complete them from tracked paths, including after an explicit "--".

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
Changes in v2:
  - New patch.
---
 contrib/completion/git-completion.bash |  6 ++++++
 t/t9902-completion.sh                  | 13 +++++++++++++
 2 files changed, 19 insertions(+)
Show changes to 2 files +19 −0

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 6f1ba96763..d313780d8b 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -2197,6 +2197,12 @@ _git_history ()
 		__git_complete_refs
 		return
 	fi
+
+	case "$subcommand" in
+	split)
+		__git_complete_index_file "--cached"
+		;;
+	esac
 }
 
 _git_init ()
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index ea86ecc08f..391cc849a8 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -3143,6 +3143,19 @@ test_expect_success 'git history revisions' '
 	test_completion "git history reword main m" ""
 '
 
+test_expect_success 'git history split pathspecs' '
+	test_completion "git history split main -- --update-refs=h" "" &&
+	test_completion "git history split main -- --update-refs h" "" &&
+	test_completion "git history split --dry-run main file" <<-\EOF &&
+	file1Z
+	file2Z
+	EOF
+	test_completion "git history split main -- file" <<-\EOF
+	file1Z
+	file2Z
+	EOF
+'
+
 test_expect_success 'git reflog show' '
 	test_when_finished "git checkout - && git branch -d shown" &&
 	git checkout -b shown &&
-- 
2.54.0
Patrick SteinhardtAug 7, 2026, 06:30 UTC in reply to Vincent Mailhol on lore

Re: [PATCH v2 1/4] completion: add 'git history' subcommands

On Thu, Aug 06, 2026 at 10:27:36PM +0200, Vincent Mailhol wrote:
Show 17 quoted lines
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index e875787710..7372e2919b 100644
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -2137,6 +2137,54 @@ _git_help ()
>  	fi
>  }
>  
> +__git_history_has_revision ()
> +{
> +	local i
> +
> +	for ((i = __git_cmd_idx + 2; i < cword; i++)); do
> +		case "${words[i]}" in
> +		--empty|--update-refs)
> +			((i++))
> +			;;

This will unfortunately be quite a pain to maintain going forward, as we now have to be aware of updating this site every single time we add a new option that accepts a parameter.

I don't really have a good idea for how to fix that reliably though, I have to admit. Maybe we should just mostly ignore this edge case and always complete references, unless we have seen a `--`? That can be checked rather easily via `__git_hash_doubledash`.

That'd still be a huge win compared to the status quo, and if we really care about making this work properly we can still iterate.

Patrick
Vincent MailholAug 7, 2026, 06:44 UTC in reply to Patrick Steinhardt on lore

Re: [PATCH v2 1/4] completion: add 'git history' subcommands

On 07/08/2026 at 08:30, Patrick Steinhardt wrote:
Show 22 quoted lines
> On Thu, Aug 06, 2026 at 10:27:36PM +0200, Vincent Mailhol wrote:
>> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
>> index e875787710..7372e2919b 100644
>> --- a/contrib/completion/git-completion.bash
>> +++ b/contrib/completion/git-completion.bash
>> @@ -2137,6 +2137,54 @@ _git_help ()
>>  	fi
>>  }
>>  
>> +__git_history_has_revision ()
>> +{
>> +	local i
>> +
>> +	for ((i = __git_cmd_idx + 2; i < cword; i++)); do
>> +		case "${words[i]}" in
>> +		--empty|--update-refs)
>> +			((i++))
>> +			;;
> 
> This will unfortunately be quite a pain to maintain going forward, as we
> now have to be aware of updating this site every single time we add a
> new option that accepts a parameter.
Do you foreseen such new parameters?
> I don't really have a good idea for how to fix that reliably though, I
> have to admit. Maybe we should just mostly ignore this edge case and
> always complete references, unless we have seen a `--`? That can be
> checked rather easily via `__git_hash_doubledash`.

My toughs are that if such a special case ever surface, we can just dispatch it earlier before we check for the __git_history_has_revision, like this:

---8<---
Show changes to contrib/completion/git-completion.bash +9 −0
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index d313780d8b..786fcb5e16 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -2193,6 +2193,15 @@ _git_history ()
 		esac
 	fi
 
+	# Subcommands which takes something else than a revision
+	case "$subcommand" in
+	foo)
+		# 'git history foo' take a file first
+		__git_complete_index_file "--cached"
+		return
+		;;
+	esac
+
 	if ! __git_history_has_revision; then
 		__git_complete_refs
 		return
---8<---

This seems reasonable to me. Once we know what this mysterious new
command would be, maybe we can find a smarter and more tailored
solution, but at the moment, I would not call this a blocker.

> That'd still be a huge win compared to the status quo, and if we really
> care about making this work properly we can still iterate.

Thanks!


Yours sincerely,
Vincent Mailhol
Patrick SteinhardtAug 7, 2026, 07:08 UTC in reply to Vincent Mailhol on lore

Re: [PATCH v2 1/4] completion: add 'git history' subcommands

On Fri, Aug 07, 2026 at 08:44:41AM +0200, Vincent Mailhol wrote:
Show 25 quoted lines
> On 07/08/2026 at 08:30, Patrick Steinhardt wrote:
> > On Thu, Aug 06, 2026 at 10:27:36PM +0200, Vincent Mailhol wrote:
> >> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> >> index e875787710..7372e2919b 100644
> >> --- a/contrib/completion/git-completion.bash
> >> +++ b/contrib/completion/git-completion.bash
> >> @@ -2137,6 +2137,54 @@ _git_help ()
> >>  	fi
> >>  }
> >>  
> >> +__git_history_has_revision ()
> >> +{
> >> +	local i
> >> +
> >> +	for ((i = __git_cmd_idx + 2; i < cword; i++)); do
> >> +		case "${words[i]}" in
> >> +		--empty|--update-refs)
> >> +			((i++))
> >> +			;;
> > 
> > This will unfortunately be quite a pain to maintain going forward, as we
> > now have to be aware of updating this site every single time we add a
> > new option that accepts a parameter.
> 
> Do you foreseen such new parameters?

Yes, I'm very sure we'll gain more parameters for those commands. Commit signing, sign-offs, handling of notes are all things that are currently being discussed, and they likely will require new options.

Show 35 quoted lines
> > I don't really have a good idea for how to fix that reliably though, I
> > have to admit. Maybe we should just mostly ignore this edge case and
> > always complete references, unless we have seen a `--`? That can be
> > checked rather easily via `__git_hash_doubledash`.
> 
> My toughs are that if such a special case ever surface, we can just
> dispatch it earlier before we check for the
> __git_history_has_revision, like this:
> 
> ---8<---
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index d313780d8b..786fcb5e16 100644
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -2193,6 +2193,15 @@ _git_history ()
>  		esac
>  	fi
>  
> +	# Subcommands which takes something else than a revision
> +	case "$subcommand" in
> +	foo)
> +		# 'git history foo' take a file first
> +		__git_complete_index_file "--cached"
> +		return
> +		;;
> +	esac
> +
>  	if ! __git_history_has_revision; then
>  		__git_complete_refs
>  		return
> ---8<---
> 
> This seems reasonable to me. Once we know what this mysterious new
> command would be, maybe we can find a smarter and more tailored
> solution, but at the moment, I would not call this a blocker.

I'm not really concerned about new subcommands for now, true. But hardcoding the parameters as we do above feels error prone to me and will very likely diverge as the command evolves.

Patrick
Vincent MailholAug 7, 2026, 08:09 UTC in reply to Patrick Steinhardt on lore

Re: [PATCH v2 1/4] completion: add 'git history' subcommands

On 07/08/2026 at 09:08, Patrick Steinhardt wrote:
Show 30 quoted lines
> On Fri, Aug 07, 2026 at 08:44:41AM +0200, Vincent Mailhol wrote:
>> On 07/08/2026 at 08:30, Patrick Steinhardt wrote:
>>> On Thu, Aug 06, 2026 at 10:27:36PM +0200, Vincent Mailhol wrote:
>>>> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
>>>> index e875787710..7372e2919b 100644
>>>> --- a/contrib/completion/git-completion.bash
>>>> +++ b/contrib/completion/git-completion.bash
>>>> @@ -2137,6 +2137,54 @@ _git_help ()
>>>>  	fi
>>>>  }
>>>>  
>>>> +__git_history_has_revision ()
>>>> +{
>>>> +	local i
>>>> +
>>>> +	for ((i = __git_cmd_idx + 2; i < cword; i++)); do
>>>> +		case "${words[i]}" in
>>>> +		--empty|--update-refs)
>>>> +			((i++))
>>>> +			;;
>>>
>>> This will unfortunately be quite a pain to maintain going forward, as we
>>> now have to be aware of updating this site every single time we add a
>>> new option that accepts a parameter.
>>
>> Do you foreseen such new parameters?
> 
> Yes, I'm very sure we'll gain more parameters for those commands. Commit
> signing, sign-offs, handling of notes are all things that are currently
> being discussed, and they likely will require new options.

Got it! I kind of mixed subcommands and parameters in my head. My previous answer was totally off topic, sorry.

For the new parameters, indeed. The issue is that these options accept two syntax:

  --empty=<value>
or
  --empty <value>
The first one falls under the '-*)' switch case anyway, so if you do a
  git history fix --new-option=foo <TAB>
the __git_history_has_revision will handle it properly. If you do:
  git history fix --new-option=<TAB>

you just get no completion until the code is modified to teach what are the correct value for --new-option. This is acceptable in term of maintainability.

If you do:
  git history fix --new-option <TAB>

then __git_history_has_revision will assume that --new-option is a toggle parameter which takes no value and will incorrectly complete it with a reference.

Finally, if you do a:
  git history fix --new-option value <TAB>

then the value is interpreted as a reference and the <TAB> gives no completion.

For a
  git history fix --gpg-sign

this is mostly OK. Assuming the new --gpg-sign works identically as the git rebase option, the --gpg-sign value is optional and default the the committer identity. So in most of the cases, the user will not give a value and will correctly get the reference completion when doing:

  git history fix --gpg-sign <TAB>

So the only case where we are screwed is if the option takes an argument *and* the user specify it as --new-option (without the final '='). In that case, the damage is still not huge. I expect most of the users to pass option with the final '='.

Show 39 quoted lines
>>> I don't really have a good idea for how to fix that reliably though, I
>>> have to admit. Maybe we should just mostly ignore this edge case and
>>> always complete references, unless we have seen a `--`? That can be
>>> checked rather easily via `__git_hash_doubledash`.
>>
>> My toughs are that if such a special case ever surface, we can just
>> dispatch it earlier before we check for the
>> __git_history_has_revision, like this:
>>
>> ---8<---
>> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
>> index d313780d8b..786fcb5e16 100644
>> --- a/contrib/completion/git-completion.bash
>> +++ b/contrib/completion/git-completion.bash
>> @@ -2193,6 +2193,15 @@ _git_history ()
>>  		esac
>>  	fi
>>  
>> +	# Subcommands which takes something else than a revision
>> +	case "$subcommand" in
>> +	foo)
>> +		# 'git history foo' take a file first
>> +		__git_complete_index_file "--cached"
>> +		return
>> +		;;
>> +	esac
>> +
>>  	if ! __git_history_has_revision; then
>>  		__git_complete_refs
>>  		return
>> ---8<---
>>
>> This seems reasonable to me. Once we know what this mysterious new
>> command would be, maybe we can find a smarter and more tailored
>> solution, but at the moment, I would not call this a blocker.
> 
> I'm not really concerned about new subcommands for now, true. But
> hardcoding the parameters as we do above feels error prone to me and
> will very likely diverge as the command evolves.
I think that there are two options:
  1. What I did, which work great today and will start to diverge the
     day we add more arguments which takes a value as you highlighted.
  2. Ignore the '--argument <value>' syntax and only complete the
     '--argument=<value>'.
Point 2. will consistently give incorrect results when doing:
  git history fix --new-option value <TAB>

but is easier to maintain. And the '--argument <value>' syntax isn't covered in the manpages anyway, so this option is just a "we implement the manpages and that's it!" approach.

My preference goes slightly to 1., but I am OK to send a v3 with option 2.

Yours sincerely, Vincent Mailhol

D. Ben KnobleAug 10, 2026, 12:43 UTC in reply to Vincent Mailhol on lore

Re: [PATCH v2 1/4] completion: add 'git history' subcommands

On Fri, Aug 7, 2026 at 4:13 AM Vincent Mailhol <mailhol@kernel.org> wrote:
Show 26 quoted lines
>
> On 07/08/2026 at 09:08, Patrick Steinhardt wrote:
> > On Fri, Aug 07, 2026 at 08:44:41AM +0200, Vincent Mailhol wrote:
> >> On 07/08/2026 at 08:30, Patrick Steinhardt wrote:
> >>> On Thu, Aug 06, 2026 at 10:27:36PM +0200, Vincent Mailhol wrote:
> >>>> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> >>>> index e875787710..7372e2919b 100644
> >>>> --- a/contrib/completion/git-completion.bash
> >>>> +++ b/contrib/completion/git-completion.bash
> >>>> @@ -2137,6 +2137,54 @@ _git_help ()
> >>>>    fi
> >>>>  }
> >>>>
> >>>> +__git_history_has_revision ()
> >>>> +{
> >>>> +  local i
> >>>> +
> >>>> +  for ((i = __git_cmd_idx + 2; i < cword; i++)); do
> >>>> +          case "${words[i]}" in
> >>>> +          --empty|--update-refs)
> >>>> +                  ((i++))
> >>>> +                  ;;
> >>>
> >>> This will unfortunately be quite a pain to maintain going forward, as we
> >>> now have to be aware of updating this site every single time we add a
> >>> new option that accepts a parameter.
[snip]
> > Yes, I'm very sure we'll gain more parameters for those commands. Commit
> > signing, sign-offs, handling of notes are all things that are currently
> > being discussed, and they likely will require new options.
[snip]
Show 52 quoted lines
>
> For the new parameters, indeed. The issue is that these options accept
> two syntax:
>
>   --empty=<value>
>
> or
>
>   --empty <value>
>
> The first one falls under the '-*)' switch case anyway, so if you do a
>
>   git history fix --new-option=foo <TAB>
>
> the __git_history_has_revision will handle it properly. If you do:
>
>   git history fix --new-option=<TAB>
>
> you just get no completion until the code is modified to teach what are
> the correct value for --new-option. This is acceptable in term of
> maintainability.
>
> If you do:
>
>   git history fix --new-option <TAB>
>
> then __git_history_has_revision will assume that --new-option is a
> toggle parameter which takes no value and will incorrectly complete it
> with a reference.
>
> Finally, if you do a:
>
>   git history fix --new-option value <TAB>
>
> then the value is interpreted as a reference and the <TAB> gives no
> completion.
>
> For a
>
>   git history fix --gpg-sign
>
> this is mostly OK. Assuming the new --gpg-sign works identically as the
> git rebase option, the --gpg-sign value is optional and default the the
> committer identity. So in most of the cases, the user will not give a
> value and will correctly get the reference completion when doing:
>
>   git history fix --gpg-sign <TAB>
>
> So the only case where we are screwed is if the option takes an argument
> *and* the user specify it as --new-option (without the final '='). In
> that case, the damage is still not huge. I expect most of the users to
> pass option with the final '='.
[later]
Show 22 quoted lines
> > I'm not really concerned about new subcommands for now, true. But
> > hardcoding the parameters as we do above feels error prone to me and
> > will very likely diverge as the command evolves.
>
> I think that there are two options:
>
>   1. What I did, which work great today and will start to diverge the
>      day we add more arguments which takes a value as you highlighted.
>
>   2. Ignore the '--argument <value>' syntax and only complete the
>      '--argument=<value>'.
>
> Point 2. will consistently give incorrect results when doing:
>
>   git history fix --new-option value <TAB>
>
> but is easier to maintain. And the '--argument <value>' syntax isn't
> covered in the manpages anyway, so this option is just a "we implement
> the manpages and that's it!" approach.
>
> My preference goes slightly to 1., but I am OK to send a v3 with
> option 2.
- The manuals (gitcli, especially) recommend the stuck form (-oArg,
--long-opt=Arg)
- Completion code that I'm aware of completes the string "--long-opt="

So I suspect most folks using completion will end up with the stuck form. If we want to support the unstuck form, I'm ok with that (Vincent's (1)). It seems simpler for now to go with (2), which aligns with the rest of the codebase, and wait to see if anyone complains though.

Switching topics:
Show 8 quoted lines
> >>> I don't really have a good idea for how to fix that reliably though, I
> >>> have to admit. Maybe we should just mostly ignore this edge case and
> >>> always complete references, unless we have seen a `--`? That can be
> >>> checked rather easily via `__git_hash_doubledash`.
> >>
> >> My toughs are that if such a special case ever surface, we can just
> >> dispatch it earlier before we check for the
> >> __git_history_has_revision, like this:
[snip]
> >>
> >> This seems reasonable to me. Once we know what this mysterious new
> >> command would be, maybe we can find a smarter and more tailored
> >> solution, but at the moment, I would not call this a blocker.

This is similar to what we do stash and a few other subcommand-commands, where we need to dispatch a bit differently. I think trying to assume all git-history commands will have the same shape is both pleasant (consistent interface!) and unlikely to hold up (something will diverge somewhere).

-- 
D. Ben Knoble
D. Ben KnobleAug 10, 2026, 12:48 UTC in reply to Vincent Mailhol on lore

Re: [PATCH v2 2/4] completion: complete 'git history --empty' values

On Thu, Aug 6, 2026 at 4:36 PM Vincent Mailhol <mailhol@kernel.org> wrote:
Show 13 quoted lines
>
> The "--empty" option accepts "drop", "keep", or "abort" for the "drop"
> and "fixup" subcommands. Complete these values.
>
> Although the synopsis only documents the:
>
>   --empty=<value>
>
> form, parse-options also accepts the value as a separate argument:
>
>   --empty <value>
>
> Support both forms to follow the parser.

Comments on 1/4 apply here, too. I don't mind supporting both, but I wonder if we should be consistent with gitcli(1) and just go with the stuck form.

I can only find one hit for the pattern "--[[:alnum:]-]+[^=],?\*" (use "git grep -E") in the completion code, and it's "--no-*)", so I'm not sure if other commands support completing the unstuck form? For example, "git commit --cleanup <tab>" doesn't complete the mode argument, but "git commit --cleanup=<tab>" does.

Show 56 quoted lines
>
> Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
> ---
> Changes in v2:
>
>   - New patch.
> ---
>  contrib/completion/git-completion.bash | 13 +++++++++++--
>  t/t9902-completion.sh                  |  5 ++++-
>  2 files changed, 15 insertions(+), 3 deletions(-)
>
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index 7372e2919b..fe5223b8ec 100644
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -2171,8 +2171,17 @@ _git_history ()
>         fi
>
>         if ! __git_has_doubledash; then
> -               case "$cur" in
> -               --*)
> +               case "$prev,$cur" in
> +               --empty,*|*,--empty=*)
> +                       case "$subcommand" in
> +                       drop|fixup)
> +                               __gitcomp "drop keep abort" "" \
> +                                       "${cur##--empty=}"
> +                               return
> +                               ;;
> +                       esac
> +                       ;;
> +               *,--*)
>                         __gitcomp_builtin "history_$subcommand"
>                         return
>                         ;;
> diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
> index 5ccb38c751..52a036a1ad 100755
> --- a/t/t9902-completion.sh
> +++ b/t/t9902-completion.sh
> @@ -3126,7 +3126,10 @@ test_expect_success 'git history subcommand options' '
>         test_completion "git history fixup --ree" "--reedit-message " &&
>         test_completion "git history split --upd" "--update-refs=" &&
>         test_completion "git history split main --dry" "--dry-run " &&
> -       test_completion "git history reword main -- --d" ""
> +       test_completion "git history reword main -- --d" "" &&
> +       test_completion "git history fixup --empty=ke" "keep " &&
> +       test_completion "git history drop --empty ab" "abort " &&
> +       test_completion "git history reword --empty=ke" ""
>  '
>
>  test_expect_success 'git history revisions' '
>
> --
> 2.54.0
>
>
-- 
D. Ben Knoble
D. Ben KnobleAug 10, 2026, 12:50 UTC in reply to Vincent Mailhol on lore

Re: [PATCH v2 2/4] completion: complete 'git history --empty' values

One other thing, sorry
On Thu, Aug 6, 2026 at 4:36 PM Vincent Mailhol <mailhol@kernel.org> wrote:
Show 38 quoted lines
>
> The "--empty" option accepts "drop", "keep", or "abort" for the "drop"
> and "fixup" subcommands. Complete these values.
>
> Although the synopsis only documents the:
>
>   --empty=<value>
>
> form, parse-options also accepts the value as a separate argument:
>
>   --empty <value>
>
> Support both forms to follow the parser.
>
> Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
> ---
> Changes in v2:
>
>   - New patch.
> ---
>  contrib/completion/git-completion.bash | 13 +++++++++++--
>  t/t9902-completion.sh                  |  5 ++++-
>  2 files changed, 15 insertions(+), 3 deletions(-)
>
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index 7372e2919b..fe5223b8ec 100644
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -2171,8 +2171,17 @@ _git_history ()
>         fi
>
>         if ! __git_has_doubledash; then
> -               case "$cur" in
> -               --*)
> +               case "$prev,$cur" in
> +               --empty,*|*,--empty=*)
> +                       case "$subcommand" in
> +                       drop|fixup)

This feels a bit "inside out" to me, especially when reading the other completions. I think the usual pattern is to check the subcommand first and dispatch if necessary. Thoughts?

Show 10 quoted lines
> +                               __gitcomp "drop keep abort" "" \
> +                                       "${cur##--empty=}"
> +                               return
> +                               ;;
> +                       esac
> +                       ;;
> +               *,--*)
>                         __gitcomp_builtin "history_$subcommand"
>                         return
>                         ;;
[snip]
-- 
D. Ben Knoble
D. Ben KnobleAug 10, 2026, 12:52 UTC in reply to Vincent Mailhol on lore

Re: [PATCH v2 3/4] completion: complete 'git history --update-refs' values

On Thu, Aug 6, 2026 at 4:37 PM Vincent Mailhol <mailhol@kernel.org> wrote:
Show 37 quoted lines
>
> The "--update-refs" option accepts either "branches" or "head".
> Complete these values.
>
> Although the synopsis only documents the:
>
>   --update-refs=<value>
>
> form, parse-options also accepts the value as a separate argument:
>
>   --update-refs <value>
>
> Support both forms to follow the parser.
>
> Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
> ---
> Changes in v2:
>
>   - New patch.
> ---
>  contrib/completion/git-completion.bash | 5 +++++
>  t/t9902-completion.sh                  | 6 +++++-
>  2 files changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index fe5223b8ec..6f1ba96763 100644
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -2181,6 +2181,11 @@ _git_history ()
>                                 ;;
>                         esac
>                         ;;
> +               --update-refs,*|*,--update-refs=*)
> +                       __gitcomp "branches head" "" \
> +                               "${cur##--update-refs=}"
> +                       return
> +                       ;;

Contrary to my comments on 2/4, this seems like a reasonable place for --update-refs, since that applies to all current git-history commands. If that ever changes, well… we'll deal with it then I suppose.

>                 *,--*)
>                         __gitcomp_builtin "history_$subcommand"
>                         return
[snip]
-- 
D. Ben Knoble
D. Ben KnobleAug 10, 2026, 12:58 UTC in reply to Vincent Mailhol on lore

Re: [PATCH v2 4/4] completion: complete 'git history split' pathspecs

On Thu, Aug 6, 2026 at 4:37 PM Vincent Mailhol <mailhol@kernel.org> wrote:
Show 29 quoted lines
>
> Arguments following the required revision of "git history split" are
> pathspecs. Complete them from tracked paths, including after an explicit
> "--".
>
> Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
> ---
> Changes in v2:
>
>   - New patch.
> ---
>  contrib/completion/git-completion.bash |  6 ++++++
>  t/t9902-completion.sh                  | 13 +++++++++++++
>  2 files changed, 19 insertions(+)
>
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index 6f1ba96763..d313780d8b 100644
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -2197,6 +2197,12 @@ _git_history ()
>                 __git_complete_refs
>                 return
>         fi
> +
> +       case "$subcommand" in
> +       split)
> +               __git_complete_index_file "--cached"
> +               ;;
> +       esac
In context, this seems late to me relative to other completion functions:
- complete subcommands
- special case a few options
- handle revisions
- split
vs., say, _git_notes, _git_reflog, etc. where the pattern is
    case "$subcommand,$cur" in
to dispatch on combinations. We could use "split,*)" to dispatch there.

OTOH! The split completion wants to benefit from the other things done (like revision completion), and only then (before or after --) delegate to pathspecs. So, I dunno: I think this location achieves that goal, but it diverges somewhat from the way other completions are written.

[snip]
-- 
D. Ben Knoble
Vincent MailholAug 13, 2026, 08:20 UTC in reply to D. Ben Knoble on lore

Re: [PATCH v2 2/4] completion: complete 'git history --empty' values

On Mon. 10 Aug. 2026 at 14:50, D. Ben Knoble <ben.knoble@gmail.com> wrote:
Show 45 quoted lines
> One other thing, sorry
>
> On Thu, Aug 6, 2026 at 4:36 PM Vincent Mailhol <mailhol@kernel.org> wrote:
> >
> > The "--empty" option accepts "drop", "keep", or "abort" for the "drop"
> > and "fixup" subcommands. Complete these values.
> >
> > Although the synopsis only documents the:
> >
> >   --empty=<value>
> >
> > form, parse-options also accepts the value as a separate argument:
> >
> >   --empty <value>
> >
> > Support both forms to follow the parser.
> >
> > Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
> > ---
> > Changes in v2:
> >
> >   - New patch.
> > ---
> >  contrib/completion/git-completion.bash | 13 +++++++++++--
> >  t/t9902-completion.sh                  |  5 ++++-
> >  2 files changed, 15 insertions(+), 3 deletions(-)
> >
> > diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> > index 7372e2919b..fe5223b8ec 100644
> > --- a/contrib/completion/git-completion.bash
> > +++ b/contrib/completion/git-completion.bash
> > @@ -2171,8 +2171,17 @@ _git_history ()
> >         fi
> >
> >         if ! __git_has_doubledash; then
> > -               case "$cur" in
> > -               --*)
> > +               case "$prev,$cur" in
> > +               --empty,*|*,--empty=*)
> > +                       case "$subcommand" in
> > +                       drop|fixup)
>
> This feels a bit "inside out" to me, especially when reading the other
> completions. I think the usual pattern is to check the subcommand
> first and dispatch if necessary. Thoughts?
The motivation is to have a single:
  case "$cur" in
statement.

After dropping support for the separated option-value form, this is what the code looks like if we check the subcommand first and the option second:

        if ! __git_has_doubledash; then
                case "$subcommand" in
                drop|fixup)
                        case "$cur" in
                        --empty=*)
                                __gitcomp "drop keep abort" "" \
                                        "${cur##--empty=}"
                                return
                                ;;
                        esac
                        ;;
                esac
                case "$cur" in
                --update-refs=*)
                        __gitcomp "branches head" "" \
                                "${cur##--update-refs=}"
                        return
                        ;;
                --*)
                        __gitcomp_builtin "history_$subcommand"
                        return
                        ;;
                esac
        fi

See the repeated 'case "$cur" in'. Note that it is not possible to have a wild card *) in the first switch case unless the --update-refs=*) dispatch gets duplicated. In the end, by using this approach, one part of the code will need to get duplicated.

On the contrary, by dispatching the option first and the subcommand second like this:

        if ! __git_has_doubledash; then
                case "$cur" in
                --empty=*)
                        case "$subcommand" in
                        drop|fixup)
                                __gitcomp "drop keep abort" "" \
                                        "${cur##--empty=}"
                                ;;
                        esac
                        return
                        ;;
                --update-refs=*)
                        __gitcomp "branches head" "" \
                                "${cur##--update-refs=}"
                        return
                        ;;
                --*)
                        __gitcomp_builtin "history_$subcommand"
                        return
                        ;;
                esac
        fi
we do not see the conflict and do not need to repeat any of the switch cases.
Show 11 quoted lines
> > +                               __gitcomp "drop keep abort" "" \
> > +                                       "${cur##--empty=}"
> > +                               return
> > +                               ;;
> > +                       esac
> > +                       ;;
> > +               *,--*)
> >                         __gitcomp_builtin "history_$subcommand"
> >                         return
> >                         ;;
> [snip]

Yours sincerely, Vincent Mailhol

Ben KnobleAug 13, 2026, 11:12 UTC in reply to Vincent Mailhol on lore

Re: [PATCH v2 2/4] completion: complete 'git history --empty' values

Show 31 quoted lines
> Le 13 août 2026 à 04:20, Vincent Mailhol <mailhol@kernel.org> a écrit :
> 
> On Mon. 10 Aug. 2026 at 14:50, D. Ben Knoble <ben.knoble@gmail.com> wrote:
>> One other thing, sorry
>> 
>>> On Thu, Aug 6, 2026 at 4:36 PM Vincent Mailhol <mailhol@kernel.org> wrote:
>>> 
>>> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
>>> index 7372e2919b..fe5223b8ec 100644
>>> --- a/contrib/completion/git-completion.bash
>>> +++ b/contrib/completion/git-completion.bash
>>> @@ -2171,8 +2171,17 @@ _git_history ()
>>>        fi
>>> 
>>>        if ! __git_has_doubledash; then
>>> -               case "$cur" in
>>> -               --*)
>>> +               case "$prev,$cur" in
>>> +               --empty,*|*,--empty=*)
>>> +                       case "$subcommand" in
>>> +                       drop|fixup)
>> 
>> This feels a bit "inside out" to me, especially when reading the other
>> completions. I think the usual pattern is to check the subcommand
>> first and dispatch if necessary. Thoughts?
> 
> The motivation is to have a single:
> 
>  case "$cur" in
> 
> statement.
I now suspect this is why some use the « case "$subcommand,$cur" » variant ? Apologies for not thinking of that previously. 
Vincent MailholAug 13, 2026, 13:45 UTC in reply to Ben Knoble on lore

Re: [PATCH v2 2/4] completion: complete 'git history --empty' values

On Thu. 13 Aug. 2026 at 13:12, Ben Knoble <ben.knoble@gmail.com> wrote:
Show 33 quoted lines
> > Le 13 août 2026 à 04:20, Vincent Mailhol <mailhol@kernel.org> a écrit :
> >
> > On Mon. 10 Aug. 2026 at 14:50, D. Ben Knoble <ben.knoble@gmail.com> wrote:
> >> One other thing, sorry
> >>
> >>> On Thu, Aug 6, 2026 at 4:36 PM Vincent Mailhol <mailhol@kernel.org> wrote:
> >>>
> >>> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> >>> index 7372e2919b..fe5223b8ec 100644
> >>> --- a/contrib/completion/git-completion.bash
> >>> +++ b/contrib/completion/git-completion.bash
> >>> @@ -2171,8 +2171,17 @@ _git_history ()
> >>>        fi
> >>>
> >>>        if ! __git_has_doubledash; then
> >>> -               case "$cur" in
> >>> -               --*)
> >>> +               case "$prev,$cur" in
> >>> +               --empty,*|*,--empty=*)
> >>> +                       case "$subcommand" in
> >>> +                       drop|fixup)
> >>
> >> This feels a bit "inside out" to me, especially when reading the other
> >> completions. I think the usual pattern is to check the subcommand
> >> first and dispatch if necessary. Thoughts?
> >
> > The motivation is to have a single:
> >
> >  case "$cur" in
> >
> > statement.
>
> I now suspect this is why some use the « case "$subcommand,$cur" » variant ?
IMHO,
  case "$subcommand,$cur"

is not very elegant. Sometimes, it is a good trade-off, but here, it does not seem to be the best solution. Of course, maybe some future changes in git history would make this a preferable option, but I do not have a crystal ball to predict the future.

> Apologies for not thinking of that previously.
No problem :)

Yours sincerely, Vincent Mailhol

Back to recent threads

[PATCH v2 0/4] completion: add support for 'git history' | The Git List