Git Merge. You are in the middle of a merge. Cannot Amend.

Let’s say I made changes to branch “abc”, committed and pushed them.  This fired a build and a code-review after which the code is ready to be merged. But before these changes are merged, another party merged changes from a branch “xyz” into “abc”.

How do I replay my changes on top of changes from “xyz” in “abc” ? Here are the steps, in the root of the directory tree where the changes are located.

$ git pull origin abc // tldr don't do this. try git pull --rebase
Auto-merging file1
CONFLICT (content): Merge conflict in file1
Automatic merge failed; fix conflicts and then commit the result.

At this point, I resolve the commits and attempt a git commit –amend. But this gives an error.  The problem is the pull step itself, which does a fetch+merge and where the merge fails. (check git –help pull).

$ git commit --amend
fatal: You are in the middle of a merge -- cannot amend.
$ git rebase 
First, rewinding head to replay your work on top of it...
Applying: change name
Using index info to reconstruct a base tree...
M file1
Falling back to patching base and 3-way merge...
Auto-merging file1
CONFLICT (content):

To recover from this do, squash the unnecessary merge and do a rebase.

$ git reset --merge 
$ git rebase
First, rewinding head to replay your work on top of it..

This shows a list of conflicting files. Find the conflicting files and edit them to resolve conflicts.

$ git rebase --continue
file: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add

$ git add file1 file2
$ git rebase --continue
Applying: change name
$ git commit --amend
$ git push origin HEAD:refs/for/abc

Here’s the git rebase doc for reference. The rebase command is composed of multiple cherry-pick commands. Cherry-pick is a change-parent operation and changes commit-id = hash(parent-commit-id + changes). Here it re-chains my commit on top of a different commit than the one I started with. The commit –amend would not have changed the commit-id, and so it would not change the parent, so it fails.

Some idempotent (safe) and useful git commands.

$ git reflog [--date=iso]  # show history of local commits to index
$ git show  # or git show commit-hash
$ git diff [ --word-diff | --color-diff ]
$ git status # shows files staged for commit (added via git add to the index). different from git diff
$ git branch [-a]
$ git tag -l
$ git describe # most recent tag reachable from current commit
$ git config --list
$ git remote -v
$ git fetch --dry-run 
$ git log --decorate --graph --abbrev-commit --date=relative --author=username
$ git log --decorate --pretty="format:%C(yellow)%h%C(green)%d%Creset %s -> %C(green)%an%C(blue), %C(red)%ar%Creset"
$ git log -g --abrev-commit --pretty=online 'HEAD@{now}'
$ git grep login -- "*yml"
$ tig    # use d, t, g to change views; use / to search
$ git fsck [--unreachable]

Difference between ‘origin’ and ‘upstream’ terms is explained here. An interactive git cheat sheet is here.

Update sequence: working_directory -> index -> commit -> remote

origin = main remote repository

master = default (master/main) branch on the remote repository

HEAD = current revision

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s