Table of Contents
How to 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 create PDFs with the Preview tool on Mac
How to install Homebrew for Mac
How to find out which shell I am running?
How to sync files with lftp
How to mirror drives with rsync
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
Remove nodes from a set in Maya
comments powered by Disqus
See also
- 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 install Homebrew for Mac
- How to find out which shell I am running?
- How to sync files with lftp
- How to mirror drives with rsync
- 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
- Remove nodes from a set in Maya