I want to enforce (i.e. throw an error and fail) that whenever I do a git merge I don't have any unstaged changes, much in the same why a git rebase will not work if unstaged changes exist. Is there a way to do this?
+2
A:
It ain't pretty, but it works. I'd be interested in seeing a better solution.
Git already rejects the merge if the file to be merged is dirty:
$ git init
Initialized empty Git repository in /tmp/mmm/.git/
$ echo this is file1 > file1
$ git add file1
$ git ci -m'first commit' file1
[master (root-commit) efd89a6] first commit
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 file1
$ git co -b branch1
Switched to a new branch 'branch1'
$ echo change file1 >> file1
$ git ci -m'change on a branch' file1
[branch1 031e317] change on a branch
1 files changed, 1 insertions(+), 0 deletions(-)
$ git co master
Switched to branch 'master'
$ echo change on master >> file1
$ git merge branch1
Updating efd89a6..031e317
error: Your local changes to 'file1' would be overwritten by merge. Aborting.
Please, commit your changes or stash them before you can merge.
Continuing the example:
$ git ci -m'commit change on master' file1
[master 8a2d52c] commit change on master
1 files changed, 1 insertions(+), 0 deletions(-)
$ git merge branch1
Auto-merging file1
CONFLICT (content): Merge conflict in file1
Automatic merge failed; fix conflicts and then commit the result.
$ vi file1
$ git add file1
$ git ci
[master ee16606] Merge branch 'branch1'
$ git log --oneline
ee16606 Merge branch 'branch1'
8a2d52c commit change on master
031e317 change on a branch
efd89a6 first commit
$ echo this is file2 > file2
$ git add file2
$ git co -b branch2
A file2
Switched to a new branch 'branch2'
$ echo change on branch2 >> file2
$ git ci -m'commit on branch2' file2
[branch2 06ff9c3] commit on branch2
1 files changed, 2 insertions(+), 0 deletions(-)
create mode 100644 file2
$ git co master
Switched to branch 'master'
$ echo this change logically conflicts with the change to file2 on branch2 >> file1
It is the next command that you want to force a failure -- you want to avoid this merge when your tree is dirty. You can do this in the prepare-commit-msg hook, but only if you do --no-ff merges, and don't let the merge automatically commit. Here's an outline of the hook:
#!/bin/sh
case "$2,$3" in
merge,)
echo "Check here if the working tree is dirty. If it is, fail."
exit 1
;;
*) ;;
esac
You have to use --no-ff and --no-commit, on every branch that you'd be merging into and want to protect from merges like this:
git config branch.master.mergeoptions "--no-commit --no-ff"
And here's what the session would look like:
$ git merge branch2
Automatic merge went well; stopped before committing as requested
$ git ci
IN THE PREP HOOK: .git/COMMIT_EDITMSG, merge,
Check here if the working tree is dirty. If it is, fail.
$ git status
# On branch master
# Changes to be committed:
#
# modified: file2
#
# Changed but not updated:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: file1
#
bstpierre@bstpierre 1119 /tmp/mmm master
$ git ci
IN THE PREP HOOK: .git/COMMIT_EDITMSG, merge,
Check here if the working tree is dirty. If it is, fail.
bstpierre@bstpierre 1120 /tmp/mmm master
$ echo $?
1
And undoing back to the pre-merge state:
$ git reset --merge
$ git status
# On branch master
# Changed but not updated:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: file1
#
no changes added to commit (use "git add" and/or "git commit -a")
bstpierre
2010-09-23 13:38:55