Skip to content

gitk: add user-defined custom commands - #2371

Open
twied wants to merge 1 commit into
git:masterfrom
twied:custom_commands
Open

gitk: add user-defined custom commands#2371
twied wants to merge 1 commit into
git:masterfrom
twied:custom_commands

Conversation

@twied

@twied twied commented Aug 4, 2026

Copy link
Copy Markdown

cc: Johannes Sixt j6t@kdbg.org

@gitgitgadget-git

Copy link
Copy Markdown

Welcome to GitGitGadget

Hi @twied, and welcome to GitGitGadget, the GitHub App to send patch series to the Git mailing list from GitHub Pull Requests.

Please make sure that either:

  • Your Pull Request has a good description, if it consists of multiple commits, as it will be used as cover letter.
  • Your Pull Request description is empty, if it consists of a single commit, as the commit message should be descriptive enough by itself.

You can CC potential reviewers by adding a footer to the PR description with the following syntax:

CC: Revi Ewer <revi.ewer@example.com>, Ill Takalook <ill.takalook@example.net>

NOTE: DO NOT copy/paste your CC list from a previous GGG PR's description,
because it will result in a malformed CC list on the mailing list. See
example.

Also, it is a good idea to review the commit messages one last time, as the Git project expects them in a quite specific form:

  • the lines should not exceed 76 columns,
  • the first line should be like a header and typically start with a prefix like "tests:" or "revisions:" to state which subsystem the change is about, and
  • the commit messages' body should be describing the "why?" of the change.
  • Finally, the commit messages should end in a Signed-off-by: line matching the commits' author.

It is in general a good idea to await the automated test ("Checks") in this Pull Request before contributing the patches, e.g. to avoid trivial issues such as unportable code.

Contributing the patches

Before you can contribute the patches, your GitHub username needs to be added to the list of permitted users. Any already-permitted user can do that, by adding a comment to your PR of the form /allow. A good way to find other contributors is to locate recent pull requests where someone has been /allowed:

Both the person who commented /allow and the PR author are able to /allow you.

An alternative is the channel #git-devel on the Libera Chat IRC network:

<newcontributor> I've just created my first PR, could someone please /allow me? https://github.com/gitgitgadget/git/pull/12345
<veteran> newcontributor: it is done
<newcontributor> thanks!

Once on the list of permitted usernames, you can contribute the patches to the Git mailing list by adding a PR comment /submit.

If you want to see what email(s) would be sent for a /submit request, add a PR comment /preview to have the email(s) sent to you. You must have a public GitHub email address for this. Note that any reviewers CC'd via the list in the PR description will not actually be sent emails.

After you submit, GitGitGadget will respond with another comment that contains the link to the cover letter mail in the Git mailing list archive. Please make sure to monitor the discussion in that thread and to address comments and suggestions (while the comments and suggestions will be mirrored into the PR by GitGitGadget, you will still want to reply via mail).

If you do not want to subscribe to the Git mailing list just to be able to respond to a mail, you can download the mbox from the Git mailing list archive (click the (raw) link), then import it into your mail program. If you use GMail, you can do this via:

curl -g --user "<EMailAddress>:<Password>" \
    --url "imaps://imap.gmail.com/INBOX" -T /path/to/raw.txt

To iterate on your change, i.e. send a revised patch or patch series, you will first want to (force-)push to the same branch. You probably also want to modify your Pull Request description (or title). It is a good idea to summarize the revision by adding something like this to the cover letter (read: by editing the first comment on the PR, i.e. the PR description):

Changes since v1:
- Fixed a typo in the commit message (found by ...)
- Added a code comment to ... as suggested by ...
...

To send a new iteration, just add another PR comment with the contents: /submit.

Need help?

New contributors who want advice are encouraged to join git-mentoring@googlegroups.com, where volunteers who regularly contribute to Git are willing to answer newbie questions, give advice, or otherwise provide mentoring to interested contributors. You must join in order to post or view messages, but anyone can join.

You may also be able to find help in real time in the developer IRC channel, #git-devel on Libera Chat. Remember that IRC does not support offline messaging, so if you send someone a private message and log out, they cannot respond to you. The scrollback of #git-devel is archived, though.

@gitgitgadget-git

Copy link
Copy Markdown

There is an issue in commit 8c9001c:
gitk: add user-defined custom commands

  • Lines in the body of the commit messages should be wrapped between 60 and 76 characters.
    Indented lines, and lines without whitespace, are exempt

Allow users to define up to three custom commands each for the commit
list and the diff display area.  Commands are configured in a new
"Commands" tab in the preferences dialog, with a name and a command
template per slot.  Non-empty slots appear in the right-click context
menu of the respective area.

Command templates support placeholder substitution (commit id, commit
title, author name, author date, etc.) and are executed via "sh -c"
to allow for background execution by appending "&", and pipeing.  If
a command terminates with exit code 42, its output is displayed;
otherwise only non-zero exit codes are reported.

Signed-off-by: Tim Wiederhake <twied@gmx.net>
Assisted-by: Claude Opus 4.6
@twied
twied force-pushed the custom_commands branch from 8c9001c to 8fdce43 Compare August 4, 2026 21:17
@dscho

dscho commented Aug 4, 2026

Copy link
Copy Markdown
Member

/allow

@gitgitgadget-git

Copy link
Copy Markdown

User twied is now allowed to use GitGitGadget.

WARNING: twied has no public email address set on GitHub; GitGitGadget needs an email address to Cc: you on your contribution, so that you receive any feedback on the Git mailing list. Go to https://github.com/settings/profile to make your preferred email public to let GitGitGadget know which email address to use.

@twied

twied commented Aug 4, 2026

Copy link
Copy Markdown
Author

/submit

@gitgitgadget-git

Copy link
Copy Markdown

Submitted as pull.2371.git.git.1785879839766.gitgitgadget@gmail.com

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-git-2371/twied/custom_commands-v1

To fetch this version to local tag pr-git-2371/twied/custom_commands-v1:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-git-2371/twied/custom_commands-v1

@gitgitgadget-git

Copy link
Copy Markdown

Johannes Sixt wrote on the Git mailing list (how to reply to this email):

Am 04.08.26 um 23:43 schrieb Tim Wiederhake via GitGitGadget:
> Allow users to define up to three custom commands each for the commit
> list and the diff display area.  Commands are configured in a new
> "Commands" tab in the preferences dialog, with a name and a command
> template per slot.  Non-empty slots appear in the right-click context
> menu of the respective area.
> 
> Command templates support placeholder substitution (commit id, commit
> title, author name, author date, etc.) and are executed via "sh -c"
> to allow for background execution by appending "&", and pipeing.  If
> a command terminates with exit code 42, its output is displayed;
> otherwise only non-zero exit codes are reported.

Thanks, but this commit message is a bit lacking: it does not explain
why it is a good idea to have this feature, what purpose it servers. For
this reason, it is not possible to tell whether the design is sound and
whether the implementation follows the design.

> Signed-off-by: Tim Wiederhake <twied@gmx.net>
> Assisted-by: Claude Opus 4.6
Thank you for being explicit about AI assistance. Note that this code is
going to be downstreamed to the Git project. Therefore, their AI
rules[*] must be obeyed.

Equally important is that I want to be sure that you have checked and
carefully reviewed and understood everything the AI produced. I am not
going to look at the code until there is sufficient insurance that you
did. (Blatantly put, I don't want to review code produced by someone
else with AI.)

[*] https://git-scm.com/docs/SubmittingPatches#ai

-- Hannes

@gitgitgadget-git

Copy link
Copy Markdown

User Johannes Sixt <j6t@kdbg.org> has been added to the cc: list.

@gitgitgadget-git

Copy link
Copy Markdown

Tim Wiederhake wrote on the Git mailing list (how to reply to this email):

On Wed, 2026-08-05 at 08:59 +0200, Johannes Sixt wrote:
> Am 04.08.26 um 23:43 schrieb Tim Wiederhake via GitGitGadget:
> > Allow users to define up to three custom commands each for the
> > commit
> > list and the diff display area.  Commands are configured in a new
> > "Commands" tab in the preferences dialog, with a name and a command
> > template per slot.  Non-empty slots appear in the right-click
> > context
> > menu of the respective area.
> > 
> > Command templates support placeholder substitution (commit id,
> > commit
> > title, author name, author date, etc.) and are executed via "sh -c"
> > to allow for background execution by appending "&", and pipeing. 
> > If
> > a command terminates with exit code 42, its output is displayed;
> > otherwise only non-zero exit codes are reported.
> 
> Thanks, but this commit message is a bit lacking: it does not explain
> why it is a good idea to have this feature, what purpose it servers.
> For
> this reason, it is not possible to tell whether the design is sound
> and
> whether the implementation follows the design.
> 
> > Signed-off-by: Tim Wiederhake <twied@gmx.net>
> > Assisted-by: Claude Opus 4.6
> Thank you for being explicit about AI assistance. Note that this code
> is
> going to be downstreamed to the Git project. Therefore, their AI
> rules[*] must be obeyed.
> 
> Equally important is that I want to be sure that you have checked and
> carefully reviewed and understood everything the AI produced. I am
> not
> going to look at the code until there is sufficient insurance that
> you
> did. (Blatantly put, I don't want to review code produced by someone
> else with AI.)
> 
> [*] https://git-scm.com/docs/SubmittingPatches#ai
> 
> -- Hannes

Hi Hannes,

thanks for the feedback!

I agree that the commit message is a bit light on the "why" side of
things. Personally, I wrote this patch because i wanted gitk to have
the ability to let me select a line in any commit, rebase to that
commit, start an editor with that file and line selected, and after
quitting the editor amend the commit and continue the rebase. An "edit
this line at that point in history" function of sorts, because I tend
to spot typos only twenty commits later.

If I had proposed a patch to this effect, I am sure it would have been
nack'd as too niche, wrong tool, or any other reason. But having the
possibility to define custom commands allows users to adapt gitk to
their workflow instead of the other way round. I am very open to
suggestions on how to put this in the commit message without resorting
to (contrieved) examples.

Regarding the use about AI: I used Claude to produce the initial
implementation. I do not write Tcl, and frankly, this patch has not
changed that. I have reworked the code - using Claude - until it was
effectively the Tcl version of code I would have written myself in
Python or C or any other language that I actually understand. Does that
pass the bar?

Regards,
Tim

@gitgitgadget-git

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email):

"Tim Wiederhake via GitGitGadget" <gitgitgadget@gmail.com> writes:

> +    set len [string length $cmd_template]
> +    for {set i 0} {$i < $len} {incr i} {
> +        if {[string index $cmd_template $i] eq "%" && $i + 1 < $len} {
> +            set next [string index $cmd_template [expr {$i + 1}]]
> +            if {!$blame_computed && ($next eq "b" || $next eq "l")} {
> +                set blame [get_blame_origin]
> +                set blame_id [lindex $blame 0]
> +                set blame_line [lindex $blame 1]
> +                set blame_computed 1
> +            }
> +            switch -- $next {
> +                "%" { append cmd "%" }
> +                "i" { append cmd $id }
> +                "t" { append cmd [lindex $commitinfo($id) 0] }
> +                "a" { append cmd [lindex $commitinfo($id) 1] }
> +                "d" { append cmd [lindex $commitinfo($id) 2] }
> +                "c" { append cmd [lindex $commitinfo($id) 3] }
> +                "D" { append cmd [lindex $commitinfo($id) 4] }
> +                "m" { append cmd [lindex $commitinfo($id) 5] }
> +                "M" { if {[info exists markedid]} { append cmd $markedid } }
> +                "b" { append cmd $blame_id }
> +                "f" { append cmd [get_diff_file] }
> +                "l" { append cmd $blame_line }
> +                default { append cmd "%" $next }
> +            }
> +            incr i
> +        } else {
> +            append cmd [string index $cmd_template $i]
> +        }
> +    }
> +
> +    if {[catch {exec sh -c $cmd 2>@1} output]} {

What do various members of $commitinfo field have?  I presume that
title and message are pretty much free text under control of anybody
who can write to the repository and entice you to run this command,
so running with "sh -c $cmd" would require $cmd to be quoting the
payload properly, or you'd be opening yourself to be an arbitrary
command execution, no?  With template "echo '%t'" you thought you
are just printing the title but if the title has "title?'; echo no'" in
it, wouldn't cmd end up being 

	echo 'title?'; echo no''

and a more creative type can use something other than "echo no", to
have a process run under your name and do more interesting things,
right?

Note that I no longer speak Tcl (even though I admit I used to), so
if there is some "magic" that makes use of $cmd in {exec sh -c $cmd}
safe, the above may be missing the mark by a mile.

@gitgitgadget-git

Copy link
Copy Markdown

Johannes Sixt wrote on the Git mailing list (how to reply to this email):

Am 07.08.26 um 23:39 schrieb Tim Wiederhake:
> If I had proposed a patch to this effect, I am sure it would have been
> nack'd as too niche, wrong tool, or any other reason. But having the
> possibility to define custom commands allows users to adapt gitk to
> their workflow instead of the other way round. I am very open to
> suggestions on how to put this in the commit message without resorting
> to (contrieved) examples.

The reason why you were unable to sell the change better is that your
change is a large set of features in a single commit. If you started
small, it would be much easier to get off the ground.

For example, start with "I notice in the diff that a change is not quite
right. Let me start an editor with the file loaded." That is a feature I
can understand is useful.

Next, let the editor start with the cursor at a particular line! That's
quite useful, too, but need not be part of the first step.

Then proceed to a use-case that needs to call `git rebase`.

But when it comes to author, committer, dates, or blame information as
potential substitutions, you will have a much harder time to argue that
they are useful. Move these features in their own patch. If you do have
a use-case, mention it.

The gist of it is: make this a patch series that starts small and works
its way forward with additional features in new commits. Don't add
features just "because we can".

> Regarding the use about AI: I used Claude to produce the initial
> implementation. I do not write Tcl, and frankly, this patch has not
> changed that. I have reworked the code - using Claude - until it was
> effectively the Tcl version of code I would have written myself in
> Python or C or any other language that I actually understand. Does that
> pass the bar?

I am not 100% sure. I take it that you understand what the added Tcl
code does (that should not bee too difficult even if this is your first
time doing Tcl). However, the Git project's guideline says:

> It’s not yet clear that this can be legally satisfied when 
> submitting significant amount of content that has been generated by
> AI tools.
So,... Any advice from the Git community would be appreciated.

-- Hannes

@gitgitgadget-git

Copy link
Copy Markdown

Johannes Sixt wrote on the Git mailing list (how to reply to this email):

Am 08.08.26 um 00:16 schrieb Junio C Hamano:
> With template "echo '%t'" you thought you
> are just printing the title but if the title has "title?'; echo no'" in
> it, wouldn't cmd end up being 
> 
> 	echo 'title?'; echo no''
> 
> and a more creative type can use something other than "echo no", to
> have a process run under your name and do more interesting things,
> right?

A very important observation!

-- Hannes

@gitgitgadget-git

Copy link
Copy Markdown

Tim Wiederhake wrote on the Git mailing list (how to reply to this email):

On Fri, 2026-08-07 at 15:16 -0700, Junio C Hamano wrote:
> "Tim Wiederhake via GitGitGadget" <gitgitgadget@gmail.com> writes:
> 
> > +    set len [string length $cmd_template]
> > +    for {set i 0} {$i < $len} {incr i} {
> > +        if {[string index $cmd_template $i] eq "%" && $i + 1 <
> > $len} {
> > +            set next [string index $cmd_template [expr {$i + 1}]]
> > +            if {!$blame_computed && ($next eq "b" || $next eq
> > "l")} {
> > +                set blame [get_blame_origin]
> > +                set blame_id [lindex $blame 0]
> > +                set blame_line [lindex $blame 1]
> > +                set blame_computed 1
> > +            }
> > +            switch -- $next {
> > +                "%" { append cmd "%" }
> > +                "i" { append cmd $id }
> > +                "t" { append cmd [lindex $commitinfo($id) 0] }
> > +                "a" { append cmd [lindex $commitinfo($id) 1] }
> > +                "d" { append cmd [lindex $commitinfo($id) 2] }
> > +                "c" { append cmd [lindex $commitinfo($id) 3] }
> > +                "D" { append cmd [lindex $commitinfo($id) 4] }
> > +                "m" { append cmd [lindex $commitinfo($id) 5] }
> > +                "M" { if {[info exists markedid]} { append cmd
> > $markedid } }
> > +                "b" { append cmd $blame_id }
> > +                "f" { append cmd [get_diff_file] }
> > +                "l" { append cmd $blame_line }
> > +                default { append cmd "%" $next }
> > +            }
> > +            incr i
> > +        } else {
> > +            append cmd [string index $cmd_template $i]
> > +        }
> > +    }
> > +
> > +    if {[catch {exec sh -c $cmd 2>@1} output]} {
> 
> What do various members of $commitinfo field have?  I presume that
> title and message are pretty much free text under control of anybody
> who can write to the repository and entice you to run this command,
> so running with "sh -c $cmd" would require $cmd to be quoting the
> payload properly, or you'd be opening yourself to be an arbitrary
> command execution, no?  With template "echo '%t'" you thought you
> are just printing the title but if the title has "title?'; echo no'"
> in
> it, wouldn't cmd end up being 
> 
> 	echo 'title?'; echo no''
> 
> and a more creative type can use something other than "echo no", to
> have a process run under your name and do more interesting things,
> right?
> 
> Note that I no longer speak Tcl (even though I admit I used to), so
> if there is some "magic" that makes use of $cmd in {exec sh -c $cmd}
> safe, the above may be missing the mark by a mile.

You are right, the code is vulnerable to shell injection. The first
version was calling the command directly, so no escaping was necessary.

I added the "sh -c" to facilitate process forking ("&") and simple exit
code manipulation ("command && exit 42"). But by now I honestly am not
sure anymore on what the best solution is: calling the command directly
and have the user write a wrapper script if necessary; or add code to
properly escape all data read from commits and retain the convenience.

Opinions?

Tim

@gitgitgadget-git

Copy link
Copy Markdown

Tim Wiederhake wrote on the Git mailing list (how to reply to this email):

On Sun, 2026-08-09 at 10:33 +0200, Johannes Sixt wrote:
> Am 07.08.26 um 23:39 schrieb Tim Wiederhake:
> > If I had proposed a patch to this effect, I am sure it would have
> > been
> > nack'd as too niche, wrong tool, or any other reason. But having
> > the
> > possibility to define custom commands allows users to adapt gitk to
> > their workflow instead of the other way round. I am very open to
> > suggestions on how to put this in the commit message without
> > resorting
> > to (contrieved) examples.
> 
> The reason why you were unable to sell the change better is that your
> change is a large set of features in a single commit. If you started
> small, it would be much easier to get off the ground.
> 
> For example, start with "I notice in the diff that a change is not
> quite
> right. Let me start an editor with the file loaded." That is a
> feature I
> can understand is useful.
> 
> Next, let the editor start with the cursor at a particular line!
> That's
> quite useful, too, but need not be part of the first step.
> 
> Then proceed to a use-case that needs to call `git rebase`.
> 
> But when it comes to author, committer, dates, or blame information
> as
> potential substitutions, you will have a much harder time to argue
> that
> they are useful. Move these features in their own patch. If you do
> have
> a use-case, mention it.
> 
> The gist of it is: make this a patch series that starts small and
> works
> its way forward with additional features in new commits. Don't add
> features just "because we can".
> 
> > Regarding the use about AI: I used Claude to produce the initial
> > implementation. I do not write Tcl, and frankly, this patch has not
> > changed that. I have reworked the code - using Claude - until it
> > was
> > effectively the Tcl version of code I would have written myself in
> > Python or C or any other language that I actually understand. Does
> > that
> > pass the bar?
> 
> I am not 100% sure. I take it that you understand what the added Tcl
> code does (that should not bee too difficult even if this is your
> first
> time doing Tcl). However, the Git project's guideline says:
> 
> > It’s not yet clear that this can be legally satisfied when 
> > submitting significant amount of content that has been generated by
> > AI tools.
> So,... Any advice from the Git community would be appreciated.
> 
> -- Hannes

Thanks for the continued feedback.

I think there may be a misunderstanding about what this patch does. I
am not proposing "add an edit-file button to gitk." I am proposing "let
users add their own commands to the context menus." The rebase+edit
workflow was an example of what becomes possible. It is not the feature
itself.

The incremental approach you suggest (first add an editor launch, then
line numbers, then rebase support) would make sense if I were proposing
a specific built-in workflow. But I am proposing a generic mechanism.
Shipping it with only %f but not %i or %t would produce a half-useful
extension system that nobody can actually use, existing only to satisfy
the review process. The individual substitutions are not independent
features; they are parameters of a single feature.

I did give a rationale: enabling users to adapt gitk to their workflow
instead of the other way around. And I did give a concrete example.
"Don't add features just because we can" does not apply here. The
feature has a stated purpose and a demonstrated use case. If the
rationale is unconvincing, I am happy to hear what would be convincing,
but I would rather not have to justify each placeholder individually.

That said, if splitting the patch into smaller pieces makes review
easier, I can do that -- as long as we agree that the goal is the
complete mechanism, not a series of standalone features that each need
to justify their own existence.

Regarding the use of AI: I designed the feature. The UI layout, the
"data model", the substitution mechanism, the execution semantics...
and described it in English in form of a prompt. An AI translated that
description to Tcl. I then reworked the output through multiple
iterations until the code matched what I would have written myself in a
language I'm proficient in. I believe this is a valid use of AI. The
algorithm and design are mine; the language-specific syntax is not, and
I don't think it needs to be. AI guidelines exist to guard against
unreviewed, ununderstood code being dumped into the project (and I very
much agree with that). But that is not what happened here.

Regards,
Tim

@gitgitgadget-git

Copy link
Copy Markdown

Johannes Sixt wrote on the Git mailing list (how to reply to this email):

Am 10.08.26 um 21:38 schrieb Tim Wiederhake:
> I think there may be a misunderstanding about what this patch does. I
> am not proposing "add an edit-file button to gitk." I am proposing "let
> users add their own commands to the context menus." The rebase+edit
> workflow was an example of what becomes possible. It is not the feature
> itself.

I totally understand that you are proposing a way to supply generic
commands, and I do not ask for something else, but I was a bit too terse
in what I said. I meant to say that you can use "invoke an editor" as
the justification for the generic command that is called from the diff
panel. And "git rebase" can be a justification for a generic command
called from the commit list. (These two kinds of commands should really
be added in separate steps, BTW.)

> Shipping it with only %f but not %i or %t would produce a half-useful
> extension system that nobody can actually use, existing only to satisfy
> the review process.

You already get something very useful with only the %f (filename)
substitution, because it can invoke an editor with a suitable file.

Do not underestimate the review process. Presenting the features in
digestible pieces is absolutely beneficial. The substitutions lend
themselves to be their own commits each (or in small groups per commit).

-- Hannes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants