Deprecation Notice:This article was written more than a year ago which means that its contents might no longer be up-to-date. If you notice any inaccuracies, feel free to leave a message in the comments below and we will look into updating the article soon as we can. Thank you for your support.

Table of Contents


Merge and Rebase in Git

When working with branches in Git it is common to at some point merge the changes back into the main branch. While this is a fairly trivial task, it can sometimes cause confusion if not done correctly. We will in this guide explain the dos and don’ts of merging and rebasing in Git.

Initializing the Git repository

For the sake of this article we will initialise a brand new Git repository in an empty directory with one master branch and one secondary branch. We will also create a few random text files so that we have something to work with.

Let us start by creating an example folder in our home directory.

$ cd ~
$ mkdir example 
$ cd example

Confirm that we are in the correct directory.

$ pwd
/home/geek/example

We will also add some arbitrary text files to this directory.

$ echo this is our first file > first.txt
$ echo this is our second file > second.txt

Confirm that the files have been created.

$ ls
first.txt       second.txt

We are now ready to initialise a new Git repository in the example directory.

$ git init
Initialized empty Git repository in /home/geek/example/.git/

If we now run Git’s status command we can see that two files are waiting to be added to the staging area.

$ git status
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        first.txt
        second.txt

nothing added to commit but untracked files present (use "git add" to track)

Let us add the files.

$ git add .

When we run status we can see that the files have been added but that they are not yet committed.

$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   first.txt
        new file:   second.txt

We will now commit the files and add a comment.

$ git commit -m "initial commit"
[master (root-commit) 457b6bd] initial commit
 2 files changed, 2 insertions(+)
 create mode 100644 first.txt
 create mode 100644 second.txt

Verify that there is nothing more to commit.

$ git status
On branch master
nothing to commit, working tree clean

We will now checkout (and create) a secondary branch.

$ git checkout -b secondary 
Switched to a new branch 'secondary'

Let us verify that both branches exist. The star * symbol next to the name indicates active branch and from what we can see, secondary is currently active.

$ git branch
  master
* secondary

We will now make some edits to our text files.

$ echo first edit >> first.txt
$ echo first edit in second file >> second.txt 

Let us confirm that the file contents has changed.

$ cat first.txt 
this is our first file
first edit

$ cat second.txt 
this is our second file
first edit in second file

If we now run the status command we can see that the files have been modified.

$ git status
On branch secondary
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   first.txt
        modified:   second.txt

no changes added to commit (use "git add" and/or "git commit -a")

Let us add and commit the changes.

$ git add .
$ git commit -m “my second commit”
[secondary 5065d0b] my second commit
 2 files changed, 2 insertions(+)

If we now look into the history of commits by issuing the log command when can see that the secondary branch is ahead of master by one commit.

$ git log --oneline --graph
* 5065d0b (HEAD -> secondary) my second commit
* 457b6bd (master) initial commit

We will now checkout the master branch again.

$ git checkout master
Switched to branch 'master'

We will now go ahead and make multiple changes to the files. The purpose is to in a later step show what will happen when you merge changes that have been made to the same files in both branches.

$ echo another edit to the first file >> first.txt 
$ git commit -a -m "second commit to the first file"
[master 220c118] second commit to the first file
 1 file changed, 1 insertion(+)

$ echo a further edit to the second file >> second.txt 
$ git commit -a -m "more edits to the second file"
[master 66ab089] more edits to the second file
 1 file changed, 1 insertion(+)

Let us inspect the tree of commits.

$ git log --oneline --graph
* 66ab089 (HEAD -> master) more edits to the second file
* 220c118 second commit to the first file
* 457b6bd initial commit

We can see that there are three commits made in total to the master branch.

Merging and rebasing

We have now reached the part what this article is actually about and this is to merge the secondary branch into our master branch.

Let us checkout the secondary branch again.

$ git checkout secondary
Switched to branch 'secondary'

Let us refresh what the commits made to this branch look like.

$ git log --oneline --graph
* 5065d0b (HEAD -> secondary) my second commit
* 457b6bd initial commit

We will now introduce a new command called rebase which will reapply the commits from the master branch onto the secondary branch. Let us run the command to see what happens.

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: my second commit
Using index info to reconstruct a base tree...
M       first.txt
M       second.txt
Falling back to patching base and 3-way merge...
Auto-merging second.txt
CONFLICT (content): Merge conflict in second.txt
Auto-merging first.txt
CONFLICT (content): Merge conflict in first.txt
error: Failed to merge in the changes.
Patch failed at 0001 my second commit
hint: 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".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

Whoa, what on earth just happened?! There appears to be a merge conflict of some sort and Git is telling us to fix the problem before it is able to resume with the rebasing. Let us start by investigating what the difference is between our two branches by issuing the diff command.

$ git diff master secondary
diff --git a/first.txt b/first.txt
index 51427f6..addd5da 100644
--- a/first.txt
+++ b/first.txt
@@ -1,2 +1,2 @@
 this is our first file
-another edit to the first file
+first edit
diff --git a/second.txt b/second.txt
index 6b8ae6d..a935fa7 100644
--- a/second.txt
+++ b/second.txt
@@ -1,2 +1,2 @@
 this is our second file
-a further edit to the second file
+first edit in second file

From this rather obscure output we can vaguely make out that in the first.txt and second.txt files there are lines of text that exists on the same line in both branches.

Let us open the files in our favourite text editor instead because it will be much easier to see what is going on. We will use nano to open first.txt.

$ nano first.txt 

this is our first file
<<<<<<< HEAD
another edit to the first file
=======
first edit
>>>>>>> my second commit

Now it is much easier to see what is going on. The section between the <<<<<<< HEAD and >>>>>>> markers indicates an area where Git has identified a merge conflict. It is basically asking whether we would like to keep the line “another edit to the first file” from the master branch or the line “first edit” from the secondary branch, as separated by the ======= marker.

We have decided that we want to keep everything and will as such simply remove the markers that Git has inserted into our file. The cleaned up first.txt file should now look like this.

this is our first file
another edit to the first file
first edit

Save and close first.txt file before editing second.txt.

$ nano second.txt 

this is our second file
<<<<<<< HEAD
a further edit to the second file
=======
first edit in second file
>>>>>>> my second commit

We now know what we need to do and will again save both edits, one line after the other. The cleaned up second.txt should now look this this. You can go ahead and save and close this file.

this is our second file
a further edit to the second file
first edit in second file

We have now, in theory, addressed the merge conflicts that Git complained about earlier. When we run the status command we can see that Git provides several suggestions for what to do next.

$ git status
rebase in progress; onto 66ab089
You are currently rebasing branch 'secondary' on '66ab089'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

        both modified:   first.txt
        both modified:   second.txt

no changes added to commit (use "git add" and/or "git commit -a")

We will go with the final suggestion which is to add our files to the staging area.

$ git add .

We are a now ready to resume the rebase by adding the --continue flag to the command.

$ git rebase --continue
Applying: my second commit

If we run the status command again we can see that the working tree is now clean.

$ git status
On branch secondary
nothing to commit, working tree clean

We can also verify that our secondary branch now is ahead of the master branch.

$ git log --oneline --graph
* 62c5f37 (HEAD -> secondary) my second commit
* 66ab089 (master) more edits to the second file
* 220c118 second commit to the first file
* 457b6bd initial commit

All that remains now is to go back to the master branch where we will complete our final step, and that is to merge the changes from the secondary branch on top of the master branch.

$ git checkout master
Switched to branch 'master'

We will now perform the actual merge.

$ git merge secondary
Updating 66ab089..62c5f37
Fast-forward
 first.txt  | 1 +
 second.txt | 1 +
 2 files changed, 2 insertions(+)

If we now run the log command we can see that HEAD points to both our master and secondary branches. In plain English this means that the secondary branch has been successfully merged with the master branch. Success! :)

$ git log --oneline --graph
* 62c5f37 (HEAD -> master, secondary) my second commit
* 66ab089 more edits to the second file
* 220c118 second commit to the first file
* 457b6bd initial commit

Further information

For more information on the Git command, type.

$ man git
...

$ git help
...

See Also

How to add new PDF compression filters for the Preview tool on Mac
How to add new PDF compression filters for the Preview tool on Mac

How to create PDFs with the Preview tool on Mac
How to create PDFs with the Preview tool on Mac

How to install Homebrew for Mac
How to install Homebrew for Mac

How to find out which shell I am running?
How to find out which shell I am running?

Syncing files with lftp
Syncing files with lftp

How to mirror drives with rsync
How to mirror drives with rsync

How to install a Samsung ML-191x 252x Series printer with AirPrint support on a Raspberry Pi
How to install a Samsung ML-191x 252x Series printer with AirPrint support on a Raspberry Pi

Querying the Illuminates by Default attribute in Maya
Querying the Illuminates by Default attribute in Maya

Remove nodes from a set in Maya
Remove nodes from a set in Maya




comments powered by Disqus

See also