Difficult merges in git

- don't panic

Andy Balaam
artificialworlds.net/blog

Contents

Don't Panic

Commit your code

Commit your code

$ git status
On branch master
Changes not staged for commit:
	modified:   northern.txt
	modified:   southern.txt
Untracked files:
	brummie.txt
	welsh.txt

Commit your code

Make a branch

$ git checkout -b unfinished-edits
M	northern.txt
M	southern.txt
$ git status
On branch unfinished-edits
Changes not staged for commit:
	modified:   northern.txt
	modified:   southern.txt
Untracked files:
	brummie.txt
	welsh.txt

Commit your code

Commit onto it

$ git add .
$ git commit -m "Changes and new regions"
[unfinished-edits 49f9e3d] Changes and new regions
 4 files changed, 5 insertions(+), 1 deletion(-)
 create mode 100644 brummie.txt
 create mode 100644 welsh.txt

Commit your code

Switch back to master

$ git branch
  master
  release-0.1
  release-0.2
* unfinished-edits
$ git checkout master
Switched to branch 'master'
$ ls
northern.txt  pirate.txt  scottish.txt  southern.txt

Merges happen here

$ git push
To git@idviz.hursley.ibm.com:sayings
 ! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'git@idviz.hursley.ibm.com:sayings'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Merges happen here

Merges happen here

Merges happen here

Merges happen here

Merges happen here

Don't blunder - visualise

$ git pull
remote: Counting objects: 17, done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 12 (delta 3), reused 0 (delta 0)
Unpacking objects: 100% (12/12), done.
From idviz.hursley.ibm.com:sayings
   40127fe..1e923f0  master     -> origin/master
Auto-merging pirate.txt
CONFLICT (content): Merge conflict in pirate.txt
Automatic merge failed; fix conflicts and then commit the result.

Don't blunder - visualise

Don't blunder - visualise

Don't blunder - visualise

$ git merge --abort
$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 1 and 3 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
nothing to commit, working directory clean

Don't blunder - visualise

Don't blunder - visualise

Don't blunder - visualise

Merge

$ git checkout master
$ git merge origin/master
Auto-merging pirate.txt
CONFLICT (content): Merge conflict in pirate.txt
Automatic merge failed; fix conflicts and then commit the result.
$ git mergetool
Normal merge conflict for 'pirate.txt':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (kdiff3): 

Merge

$ git merge --abort
$ git log 40127fe..master
3db0259 Barrel-related pirate saying
$ git show 3db0259
...
 Me hearties
+Roll out the barrel
 Yo ho ho

Merge

$ git log 40127fe..origin/master
1e923f0 Change case of some northern sayings
761a86a Change case of some scottish sayings
725cacd Convert spaces to tabs
$ git show 725cacd pirate.txt
...
 Arr!
-Me hearties
-Yo ho ho
+Me     hearties
+Yo     ho      ho
$ git show 761a86a pirate.txt
$ git show 1e923f0 pirate.txt

Merge

$ git mergetool
...
Hit return to start merge resolution tool (kdiff3): 

Merge

$ git status
Your branch and 'origin/master' have diverged,
...
Changes to be committed:
	modified:   northern.txt
	modified:   pirate.txt
	modified:   scottish.txt
	modified:   southern.txt
Untracked files:
	pirate.txt.orig

Merge

$ git diff --cached pirate.txt
...
 Arr!
-Me hearties
+Me     hearties
 Roll out the barrel
-Yo ho ho
+Yo     ho      ho

Merge

$ cat pirate.txt
Arr!
Me	hearties
Roll out the barrel
Yo	ho	ho

Wrong!

Merge

You are editing the merge commit

Merge

$ vim pirate.txt
...
$ cat pirate.txt
Arr!
Me	hearties
Roll    out the barrel
Yo	ho	ho

Right!

Merge

$ git add pirate.txt
$ git status
Your branch and 'origin/master' have diverged,
...
Changes to be committed:
	modified:   northern.txt
	modified:   pirate.txt
	modified:   scottish.txt
	modified:   southern.txt
...

Merge

$ git commit
COMMIT_EDITMSG
Merge remote-tracking branch 'origin/master'

Conflicts:
        pirate.txt
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
#       .git/MERGE_HEAD
# and try again.

Merge

$ git push
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 668 bytes | 0 bytes/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To git@idviz.hursley.ibm.com:sayings
   1e923f0..f576904  master -> master

Rebase

Rebase

$ git checkout unfinished-edits 
Switched to branch 'unfinished-edits'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Changes and new regions
Using index info to reconstruct a base tree...
M	northern.txt
M	southern.txt
Falling back to patching base and 3-way merge...
Auto-merging southern.txt
CONFLICT (content): Merge conflict in southern.txt
Auto-merging northern.txt
CONFLICT (content): Merge conflict in northern.txt
Failed to merge in the changes.
...

Rebase

Rebase

$ git rebase --abort
$ gitk --all

Rebase

When you're ready:

$ git rebase master
...
Auto-merging southern.txt
CONFLICT (content): Merge conflict in southern.txt
Auto-merging northern.txt
CONFLICT (content): Merge conflict in northern.txt

Rebase

You are editing the new commits

Rebase

$ git log 40127fe..unfinished-edits
49f9e3d Changes and new regions
$ git show 49f9e3d northern.txt
...
 Yer not as green as yer cabbage looking
-By ek pet
+By 'ek pet

Rebase

$ git mergetool
...
Normal merge conflict for 'northern.txt':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (kdiff3): 

Rebase

Rebase

$ git status
rebase in progress; onto f576904
...
Changes to be committed:
	new file:   brummie.txt
	modified:   northern.txt
	modified:   southern.txt
	new file:   welsh.txt
...
$ git rebase --continue 
Applying: Changes and new regions

Rebase

$ git reset HEAD^
Unstaged changes after reset:
M	northern.txt
M	southern.txt
$ rm *.orig; git status
On branch unfinished-edits
Changes not staged for commit:
	modified:   northern.txt
	modified:   southern.txt
Untracked files:
	brummie.txt
	welsh.txt

Disaster recovery

Find "lost" commits

$ git reflog | grep "new regions"
82f2d6d HEAD@{2}: rebase: Changes and new regions
49f9e3d HEAD@{13}: commit: Changes and new regions

Disaster recovery

Make a lost commit into a branch

$ git checkout 49f9e3d
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
...
HEAD is now at 49f9e3d... Changes and new regions
$ git checkout -b phew
Switched to a new branch 'phew'

Disaster recovery

Remember:

More info

Donate! patreon.com/andybalaam
Play! Rabbit Escape
Videos youtube.com/user/ajbalaam
Twitter @andybalaam
Blog artificialworlds.net/blog
Projects artificialworlds.net