If you don’t know what a merge or fast-forward is, check out this tutorial first.
When you develop a feature in a side branch, you need to get your changes merged into the main branch. The problem is merge commits will complicate your main branch commit history:
It creates an extra merge commit in the commit history.
The merge commit does some background merge magic in your files, meaning you will find them in a different state than you left before the merge.
The commit history will have a mixed order of commits from the original branch and the merged branch. Commits may not be in a coherent, sequential order.
If you do merge commits on a regular basis your commit history will be hard to follow.
1. The feature developer rebases their changes on top of the master branch
2. The main branch maintainer pulls the changes in the side branch as a fast-forward.
Let’s assume you have a series of commits on a feature branch:
A rebase re-applies all commits in a feature branch on top of the HEAD commit of the branch you want to merge into (such as master). After a rebase, the feature branch can be trivially applied with a fast-forward.
Your project maintainer will be happy, because after pulling your changes her git logs will show a natural succession of commits with your changes and no merge.
You simply type:
git checkout feature/new-feature-branch
git rebase <branch-to-be-merged-into>
As mentioned above, this rewinds the feature branch HEAD back to the common ancestor, and re-apply all changes on top of the top commit of master.
Here is the end result:
The project maintainer can now merge the feature branch to master trivially with a fast-forward and no merge:
A merge conflict occurs when commits in two git branches modify the same contents in the same file, and there is no clear evidence which change is the right one to pick.
Let us look at the scenario where re-winding and re-applying all commits in a feature branch causes a conflict with the main branch.
git checkout -b feature-branch
[Modify line 3 in file & save]
git add file
git commit
git checkout master
[Modify line 3 in file & save]
git add file
git commit
Merge options now:
Now, if the maintainer does:
git pull . feature-branch
he has to resolve the conflict. This is a no go option. No maintainer wants to resolve conflict of others.
1. If the feature developer does:
git pull . master
on the side branch, he will get a conflict, and will create a merge commit.
The maintainer pulls it:
git pull . feature-branch
The maintainer now can merge the change, but he will have to merge a “merge commit”. A less than ideal situation.
This is the best option. Maintainer simply does a fast-forward to get the feature and sees a natural progression of commits in the main branch.
Feature developer does:
git checkout -b backup
(This is to save the current branch, as rebase modifies the branch we are on permanently)
git checkout feature-branch
git rebase master
Result:
Bahadirs-iMac:new-repo bahadir$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Commit #1 in feature branch
Using index info to reconstruct a base tree...
M a.c
.git/rebase-apply/patch:12: new blank line at EOF.
+
warning: 1 line adds whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging a.c
CONFLICT (content): Merge conflict in a.c
error: Failed to merge in the changes.
Patch failed at 0001 Commit #1 in feature branch
Use 'git am --show-current-patch' to see the failed patch
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
The 2 versions of the file’s portion with conflict is nicely presented to you by Git:
<<<<<<< HEAD
Hello New World! Master branch!
Line 4
Line 5
=======
Hello world in feature branch
Line 4
Line 5
>>>>>>> Commit #1 in feature branch
First version is between the portion <<<< HEAD and =====
The second version is between the portion ===== and >>>>> Commit name
A simple resolution is to delete those markers, and pick only one of the versions.
Hello world in feature branch
Line 4
Line 5
In this scenario, we deleted markers, and picked the 2nd version, done by the feature branch.
In a frequent scenario, you may need to mix and decide on a change that includes parts of both versions:
Hello New World! Master branch! Hello world in feature branch
Line 4
Line 5
Don’t forget to delete markers: <<<<<<<, =====, >>>>>>>> Save and type:
git add <conflicted-file>
git rebase --continue
You repeat the above conflict resolution step multiple times, until all conflicts are resolved.
If you find that there are too many and you want to attempt it in the future, you can type:
git rebase --abort
To try this again later in the future.