threads / patch / 61708

patch, 3 partsAdd a Hook To git commit --message Bash Completion

Subject: [PATCH 0/3] Add a Hook To git commit --message Bash Completion

## tl;dr

6 messages between Jun 30, 2024 and Jun 30, 2024. Diffs are folded; open one to read it.

replies: 5people: 2as markdown or json

Mikko Johannes Koivunalho· Jun 30, 2024, 21:33 UTC · lore

I want to create part or all of the `git commit -m *` command's message with a script. I work for one Jira ticket at a time and I need to create many commits which all start with "TKT-123: " (any Jira ticket number/identifier). To make the commits faster, I run `git commit --message="TKT-123: add new file"` on the command line.

I want the Bash completion mechanism to propose the message for me. I would fetch the newest ticket number and place it on the command line when I type `git commit --message=<TAB>`.

Example: # Doing commit: git commit --message=<TAB> # you would get (also without the closing double quote): git commit --message="ABC-1234

Mikko Johannes Koivunalho (3):
  completion: Add hook in Bash completion for commit message
  completion: Add hook in Bash completion for commit message; docs
  completion: Add hook in Bash completion for commit message; tests
 Documentation/config/completion.txt    | 11 +++++
 contrib/completion/git-completion.bash | 40 +++++++++++++++
 t/t9902-completion.sh                  | 68 ++++++++++++++++++++++++++
 3 files changed, 119 insertions(+)
base-commit: 790a17fb19d6eadd16c52e5d284a5c6921744766
-- 
2.30.2
Mikko Johannes Koivunalho· Jun 30, 2024, 21:33 UTC · re: Mikko Johannes Koivunalho · lore

[PATCH 2/3] completion: Add hook in Bash completion for commit message; docs

Signed-off-by: Mikko Johannes Koivunalho <mikko.koivunalho@iki.fi>
---
 Documentation/config/completion.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)
Show changes to Documentation/config/completion.txt +11 −0
diff --git a/Documentation/config/completion.txt b/Documentation/config/completion.txt
index 4d99bf33c9..5032eab5da 100644
--- a/Documentation/config/completion.txt
+++ b/Documentation/config/completion.txt
@@ -5,3 +5,14 @@ completion.commands::
 	can add more commands, separated by space, in this
 	variable. Prefixing the command with '-' will remove it from
 	the existing list.
+
+completion.commitMessageCallback::
+    This is only used by git-completion.bash for declaring an executable
+    or a shell function which will be used when user types
+    `git commit --message=` and then presses completion key (TAB).
+    The callback must return one string for commit message.
+    This can be used when all commit messages must have, for example,
+    same prefix, e.g. a work order number.
+    Instead of this configuration variable, environment variable
+    GIT_COMPLETION_COMMIT_MESSAGE_CALLBACK can be used.
+    Environment variable overrides the configuration variable.
-- 
2.30.2
Mikko Johannes Koivunalho· Jun 30, 2024, 21:33 UTC · re: Mikko Johannes Koivunalho · lore

[PATCH 3/3] completion: Add hook in Bash completion for commit message; tests

Signed-off-by: Mikko Johannes Koivunalho <mikko.koivunalho@iki.fi>
---
 t/t9902-completion.sh | 68 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)
Show changes to t/t9902-completion.sh +68 −0
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 932d5ad759..4ea80fddd2 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -146,6 +146,74 @@ else
 	ROOT="$(pwd)"
 fi
 
+test_expect_success 'setup for commit message completion' "
+    commit-msg-callback-function () { echo HelloFromCallbackFunction; } &&
+    printf '#!/usr/bin/env sh\necho HelloFromCallbackExe\n' >.git/hooks/commit-callback &&
+    chmod +x .git/hooks/commit-callback
+"
+
+test_expect_success 'git commit --message= (empty)' "
+    test_completion 'git commit --message=' ' '
+"
+
+test_expect_success 'setup for commit message completion (run a shell function)' '
+    git config --local completion.commitMessageCallback commit-msg-callback-function
+'
+
+test_expect_success 'git commit --message=HelloFromCallbackFunction' '
+    test_completion "git commit --message=" "HelloFromCallbackFunction"
+'
+
+test_expect_success 'setup for commit message completion (run an executable file)' "
+    git config --local completion.commitMessageCallback \"${PWD}/.git/hooks/commit-callback\"
+"
+
+test_expect_success 'git commit --message=HelloFromCallbackExe' '
+    test_completion "git commit --message=" "HelloFromCallbackExe"
+'
+
+test_expect_success 'setup for commit message completion (do completion in a subdir)' '
+    mkdir -p commit_message_completion_subdir &&
+    cd commit_message_completion_subdir
+'
+
+test_expect_success 'git commit --message=HelloFromCallbackExe' '
+    test_completion "git commit --message=" "HelloFromCallbackExe"
+'
+
+test_expect_success 'teardown from commit message completion (do completion in a subdir)' '
+    cd .. &&
+    rm -r commit_message_completion_subdir
+'
+
+test_expect_success 'setup for commit message completion (run an executable file with ENV var set)' "
+    GIT_COMPLETION_COMMIT_MESSAGE_CALLBACK=commit-msg-callback-function &&
+    export GIT_COMPLETION_COMMIT_MESSAGE_CALLBACK
+"
+
+test_expect_success 'git commit --message=HelloFromCallbackFunction (ENV var overrides config)' '
+    test_completion "git commit --message=" "HelloFromCallbackFunction"
+'
+
+test_expect_success 'setup for commit message completion (completion begins with quote char)' '
+    commit-msg-callback-function-with-quote () { echo \"HelloFromCallbackFunctionWithQuote; } &&
+    GIT_COMPLETION_COMMIT_MESSAGE_CALLBACK=commit-msg-callback-function-with-quote &&
+    export GIT_COMPLETION_COMMIT_MESSAGE_CALLBACK
+'
+
+test_expect_success 'git commit --message=HelloFromCallbackFunction (completion begins with quote char)' '
+    test_completion "git commit --message=" "\"HelloFromCallbackFunctionWithQuote"
+'
+
+test_expect_success 'teardown after commit message completion' '
+    unset -v GIT_COMPLETION_COMMIT_MESSAGE_CALLBACK &&
+    git config --local --unset completion.commitMessageCallback &&
+    unset -f commit-msg-callback-function &&
+    unset -f commit-msg-callback-function-with-quote &&
+    rm .git/hooks/commit-callback
+
+'
+
 test_expect_success 'setup for __git_find_repo_path/__gitdir tests' '
 	mkdir -p subdir/subsubdir &&
 	mkdir -p non-repo &&
-- 
2.30.2
Mikko Johannes Koivunalho· Jun 30, 2024, 21:33 UTC · re: Mikko Johannes Koivunalho · lore

[PATCH 1/3] completion: Add hook in Bash completion for commit message

Signed-off-by: Mikko Johannes Koivunalho <mikko.koivunalho@iki.fi>
---
 contrib/completion/git-completion.bash | 40 ++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
Show changes to contrib/completion/git-completion.bash +40 −0
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 60a22d619a..5350531c8f 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -81,6 +81,34 @@
 #     case insensitively, even on systems with case sensitive file systems
 #     (e.g., completing tag name "FOO" on "git checkout f<TAB>").
 
+#   GIT_COMPLETION_COMMIT_MESSAGE_CALLBACK
+#
+#     Name of an executable or a script which returns a commit message.
+#     Use this, for example, to always start a commit message with a predefined
+#     prefix. Example:
+#     # Extract Jira ticket number from branch name:
+#     extract_ticket () {
+#       if [[ "$(git rev-parse --symbolic-full-name HEAD)" =~ ([[:alpha:]]{3,}-[[:digit:]]{1,}) ]]
+#       then
+#         echo "\"${BASH_REMATCH[1]^^} "
+#       fi
+#     }
+#     GIT_COMPLETION_COMMIT_MESSAGE_CALLBACK=extract_ticket
+#     # Doing commit:
+#     git commit --message=<TAB>
+#     # you would get (without the closing double quote):
+#     git commit --message="ABC-1234
+#
+# You can set the following Git configuration variables to influence the behavior of
+# the completion routines:
+#
+#   completion.commitMessageCallback
+#
+#     Name of an executable, script or shell functions which returns a commit message.
+#     See above environment variable GIT_COMPLETION_COMMIT_MESSAGE_CALLBACK.
+#     The config variable gets overriden by the environment variable if latter is present.
+#
+
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
 *)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
@@ -1824,6 +1852,18 @@ _git_commit ()
 			" "" "${cur##--cleanup=}"
 		return
 		;;
+	--message=*)
+		if test -n "${GIT_COMPLETION_COMMIT_MESSAGE_CALLBACK-}"
+		then
+			__gitcomp_direct_append "$(${GIT_COMPLETION_COMMIT_MESSAGE_CALLBACK})"
+		elif test -n "$(__git config completion.commitMessageCallback)"
+		then
+			__gitcomp_direct_append "$("$(__git config completion.commitMessageCallback)")"
+		else
+			__gitcomp_direct_append " "
+		fi
+		return
+		;;
 	--reuse-message=*|--reedit-message=*|\
 	--fixup=*|--squash=*)
 		__git_complete_refs --cur="${cur#*=}"
-- 
2.30.2
brian m. carlson· Jun 30, 2024, 21:44 UTC · re: Mikko Johannes Koivunalho · lore

Re: [PATCH 0/3] Add a Hook To git commit --message Bash Completion

On 2024-06-30 at 21:33:33, Mikko Johannes Koivunalho wrote:
Show 16 quoted lines
> I want to create part or all of the `git commit -m *` command's
> message with a script. I work for one Jira ticket at a time and I
> need to create many commits which all start with "TKT-123: "
> (any Jira ticket number/identifier). To make the commits faster,
> I run `git commit --message="TKT-123: add new file"` on the command
> line.
> 
> I want the Bash completion mechanism to propose the message for
> me. I would fetch the newest ticket number and place it on the command
> line when I type `git commit --message=<TAB>`.
> 
> Example:
> # Doing commit:
> git commit --message=<TAB>
> # you would get (also without the closing double quote):
> git commit --message="ABC-1234

This is easy to do with a prepare-commit-msg or commit-msg hook, and those are the intended tools for this purpose. I've used these hooks to generate a message for a ticket based on the branch name at a past company (so a branch called tkt-123 would result in the TKT-123: entry in the appropriate place in the commit message).

While you certainly can commit on the command line, it's not encouraged because you're supposed to write a commit message that explains the commit in detail. Only very rarely is a single line commit message useful, and even in the case you've cited, I'd want to know why you added a new file. What does the file do? What problem is it supposed to solve? Why are we adding a new file when we could add the changes to an existing file? Why is this change valuable at all?

That being said, all of this is possible with a prepare-commit-msg hook, and that's a better and more generic way than using the bash completion, which is specific to bash.

-- 
brian m. carlson (they/them or he/him)
Toronto, Ontario, CA
Mikko Johannes Koivunalho· Jun 30, 2024, 22:12 UTC · re: brian m. carlson · lore

Re: [PATCH 0/3] Add a Hook To git commit --message Bash Completion

On 30/06/2024 23:44, brian m. carlson wrote:
Show 34 quoted lines
> On 2024-06-30 at 21:33:33, Mikko Johannes Koivunalho wrote:
>> I want to create part or all of the `git commit -m *` command's
>> message with a script. I work for one Jira ticket at a time and I
>> need to create many commits which all start with "TKT-123: "
>> (any Jira ticket number/identifier). To make the commits faster,
>> I run `git commit --message="TKT-123: add new file"` on the command
>> line.
>>
>> I want the Bash completion mechanism to propose the message for
>> me. I would fetch the newest ticket number and place it on the command
>> line when I type `git commit --message=<TAB>`.
>>
>> Example:
>> # Doing commit:
>> git commit --message=<TAB>
>> # you would get (also without the closing double quote):
>> git commit --message="ABC-1234
> This is easy to do with a prepare-commit-msg or commit-msg hook, and
> those are the intended tools for this purpose.  I've used these hooks to
> generate a message for a ticket based on the branch name at a past
> company (so a branch called tkt-123 would result in the TKT-123: entry
> in the appropriate place in the commit message).
>
> While you certainly can commit on the command line, it's not encouraged
> because you're supposed to write a commit message that explains the
> commit in detail.  Only very rarely is a single line commit message
> useful, and even in the case you've cited, I'd want to know why you
> added a new file.  What does the file do?  What problem is it supposed
> to solve?  Why are we adding a new file when we could add the changes to
> an existing file?  Why is this change valuable at all?
>
> That being said, all of this is possible with a prepare-commit-msg hook,
> and that's a better and more generic way than using the bash completion,
> which is specific to bash.

I have used the prepare-commit-msg hook for this same purpose, and also commit-msg hook to check that the commit message does contain a valid ticket identificator string. When doing small changes it is just faster and more convenient for me to use command line completion to help. The projects where I work often don't require longer commit messages and explanations so formulating the commit message in editor is not necessary. When longer and more meticulous commit messages are required I do them in the editor.

-- Mikko Koivunalho

← back to recent threads