My workflow usually involves uploading commits for review e.g. commit chain A(HEAD) -> B -> C
- and if I get a review on commit B
- I run git rebase -i
, select B
for editing, and then run git commit --amend
followed by git rebase --continue
to patch the commit with fixes in-place in the chain.
This is the common flow, but sometimes - when I edit B
I get a merge conflict in A
.
The way an interactive rebase workflow is supposed to work is that I resolve the conflicts, stage them with git add
- and then run git rebase --continue
without amending the commit.
However, the merge-conflict-free git commit --amend
flow is so common that I often find myself making the absentminded mistake of running git commit --amend; git rebase --continue
instead of git rebase --continue
- which wreaks havoc on my chain, squashing two commits together and I then need to delve into git reflog
to unsquash them.
This is almost never the desired behavior, and is usually a mistake - it's rare that someone would want to amend a new commit with resolved merge conflicts into the previous commit.
Is there a way to configure git to disallow amending a commit when in the middle of a merge conflict?
CodePudding user response:
During rebase, there is a .git/rebase-merge
directory. --amend
can be captured in the hook prepare-commit-msg.
or commit, followed by a commit object name (if a -c, -C or --amend option was given).
So one of the ideas is to fail prepare-commit-msg
and abort the commit if .git/rebase-merge
exists and --amend
is used. In order to bypass the test, we can define a config value, foo.bar
.
A demo in Bash,
#!/bin/bash
msg_file=$1
msg_source=$2
msg_object=$3
foo_bar=$(git config --get foo.bar)
if [[ "${foo_bar}" != "false" ]];then
gitdir=$(git rev-parse --absolute-git-dir)
rebase_dir=${gitdir}/rebase-merge
if [[ -d "${rebase_dir}" ]] && [[ "$msg_source" = commit ]];then
echo "Forbid 'git commit --amend' during rebase"
echo "Maybe you want 'git rebase --continue'?"
echo "If you do want to amend during rebase, use 'git -c foo.bar=false commit --amend'"
exit 1
fi
fi
The side effect is that git commit -C $commit
or git commit -c $commit
during rebase are also failed. But we can bypass it with -c foo.bar=false
.