This recreates the example described in the Github help page about Resolving a Merge Conflict on the Command Line. You will create a git branch to represent each step in this process:
You will then merge those changes to the real master branch.
We use these branches to explore some of the most useful features of git.
In a git repository, create a file called planets.md with one line of text that reads
the number of planets are
Just create the file; don’t add or commit it in Git quite yet.
Create a new git branch called planets-before-merge-conflict
by running
$ git branch planets-before-merge-conflict
Now check out that branch by running
$ git checkout planets-before-merge-conflict
Note: You can create a branch and check it out with a single command. To create a branch called planets-before-merge-conflict
and check it out, you could have used git checkout -b planets-before-merge-conflict
instead of the two commands above.
Add planets.md to git and commit it to the current branch by running
$ git add .
$ git commit -m"planets.md before merge conflict"
Now look at the difference between the master
branch and the planets-before-merge-conflict
branch by running
$ git diff master planets-before-merge-conflict
diff --git a/planets.md b/planets.md
new file mode 100644
index 0000000..463f8d5
--- /dev/null
+++ b/planets.md
@@ -0,0 +1 @@
+the number of planets are
Create two new branches called branch-a
and branch-b
by running
$ git branch branch-a
$ git branch branch-b
Compare branch-a and branch-b by running
$ git diff branch-a branch-b
Note: This didn’t return anything because the two branches are identical. Git diff lists all the differences between the two branches. There are no differences between the two branches, so it doesn’t return anything.
To confirm that the two branches are identical, look at the git log for each branch
$ git log branch-a
$ git log branch-b
The commit messages and the commit hashes should be identical.
Check out branch-a
by running
$ git checkout branch-a
Run git branch
to confirm that you’re on the right branch
* branch-a
branch-b
master
planets-before-merge-conflict
Open planets.md and add “nine” on line 2, so the text looks like:
the number of planets are
nine
Add this change to git and commit it to the current branch (branch-a)
$ git add .
$ git commit -m"sets the correct number of planets"
Check out branch-b
by running
$ git checkout branch-b
Open planets.md and add “eight” on line 2, so the text looks like:
the number of planets are
eight
Add this change to git and commit it to the current branch (branch-b)
$ git add .
$ git commit -m"pluto is not a planet."
Compare branch-a
and branch-b
by running
$ git diff branch-a branch-b
diff --git a/planets.md b/planets.md
index 641c3e9..60b4993 100644
--- a/planets.md
+++ b/planets.md
@@ -1,2 +1,2 @@
the number of planets are
-nine
+eight
Output the commit history for each branch by running
$ git log branch-a
$ git log branch-b
When you compare these two commits, you should see that both of them have the original commit with the message “planets.md before merge conflict” and that commit hash is the same in both branches but each branch has a different commit after this one. On branch-a there is a commit with the message “sets the correct number of planets” while on branch-b there is a commit with the message “pluto is not a planet.” the commit messages are different AND the commit hashes are different.
In normal use, you would merge these changes into the master branch, but for the purposes of this exercise we will create a fake “master” branch. This will let us compare all of the stages of the process before we finish.
To create the fake “master” branch, checkout the planets-before-merge-conflict
branch which contains the original version of planets.md by running
$ git checkout planets-before-merge-conflict
Now create a new “branch-master” branch where we will combine everyone’s work
$ git checkout -b branch-master
With the branch-master
branch checked out, merge the work from branch-a
to branch-master
by running
$ git merge branch-a
Updating 8b8c8ee..57c1710
Fast-forward
planets.md | 1 +
1 file changed, 1 insertion(+)
Now branch-master
contains the work from branch-a
Inspect the git log – at this point branch-master is identical to branch-a.
$ git log branch-a
$ git log branch-master
The final commit hashes for both histories should be identical. This means that both histories are identical.
You can also confirm that their contents are identical by running
$ git diff branch-a branch-master
If it returns nothing, that means they are identical (there are no differences to display)
Now we need to resolve the conflict between our two branches. While on branch-master
, run
$ git merge branch-b
Git will warn you about the conflict:
Auto-merging planets.md
CONFLICT (content): Merge conflict in planets.md
Automatic merge failed; fix conflicts and then commit the result.
To get more information about which files are in conflict, run
$ git status
On branch branch-master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: planets.md
no changes added to commit (use "git add" and/or "git commit -a")
Open planets.md in a text editor. You will see that git has marked the merge conflicts in the file:
the number of planets are
<<<<<<< HEAD
nine
=======
eight
>>>>>>> branch-b
The conflict is marked with “conflict markers”. It begins with <<<<<<< HEAD
and ends with >>>>>>> branch-b
. The changes that came from HEAD (the current branch) are before the =======
and the changes that came from branch-b are after the =======
.
Visual merge tools like Meld make it easier to read merge conflicts and resolve them.
This is a good opportunity to try out one of those tools.
As the github help page says, to resolve the conflict simply open the file in a text editor, delete the conflict markers, and type out the value you want to put in that line:
the number of planets are
nine, or eight, depending on who you ask.
Save the edited file and add it to git by running
$ git add .
Confirm that everything is staged properly for the commit by running git status
. It should say
On branch branch-master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: planets.md
Commit the merged file by running
$ git commit -m"making peace between branch-a and branch-b"
Run git log
to see that branch-master now reflects the full history of changes, including the conflicting changes on branch-a and branch-b and the most recent commit, which merges those branches. It should include commits with all of these messages (in reverse-order because git displays the most recent commits first):
Now you have at least 5 branches in your git repository, including the original master
branch from before you started this lesson.
$ git branch
branch-a
branch-b
* branch-master
master
planets-before-merge-conflict
Compare the contents of these branches using git diff
and git log
. For example:
$ git diff planets-before-merge-conflict master
$ git diff branch-master planets-before-merge-conflict
$ git diff master branch-master
Push all of your branches to github
git push --all
Counting objects: 16, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (16/16), 1.28 KiB | 0 bytes/s, done.
Total 16 (delta 4), reused 0 (delta 0)
remote: Resolving deltas: 100% (4/4), done.
To git@github.com:codeforphilly/decentralized-data-examples.git
* [new branch] branch-a -> branch-a
* [new branch] branch-b -> branch-b
* [new branch] branch-master -> branch-master
* [new branch] planets-before-merge-conflict -> planets-before-merge-conflict
Checkout the master
branch and merge the work from branch-master
$ git checkout master
$ git merge branch-master
Updating 0de7844..72f3743
Fast-forward
planets.md | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 planets.md
Now that you’ve merged your work into the main master
branch, you can delete all of the other branches without losing any history because the master
branch actually contains all of the work from all of the branches, including the entire history of changes. To confirm this, compare the commit hashes that you see when you run git log master
against the commit hashes in each of the other branches. You will see that the git history in branch-master contains all of the commits from the other branches, with exactly the same commit messages and hashes.
You can also restore a specific state from your history by checking out that commit. To do this, you need the commit hash from running git log
. Run git log
and pick the commit hash for any of the old commits. For example, the hash for the commit with the log message “pluto is not a planet.”. For this example, we will pretend the hash for that commit is ca41886daca7f55aa7d88a5ae7b226dd3e670739. The first 8 characters will be enough to uniquely identify the hash, so we’ll use ca41886d
in the example.
You can make the working copy of your git repository match the state in that commit by running
$ git checkout ca41886d
This will warn you that “You are in ‘detached HEAD’ state.”. This means your working copy is showing a state of the repository that is not the HEAD of any of your branches. This is great for poking around in your git history, but you will eventually want to either check out one of your branches or you will want to create a new branch with this commit as its head.
With your working copy in this ‘detached HEAD’ state, you will see the files exactly as they were when the commit was written to git. In this example, planets.md will say there are eight planets. Open it up and check!
Note that the git history for this ‘detached HEAD’ state is the git history that you would have seen when this commit was written to git. Try running git log
and see what it shows as the history.
When you’re done exploring this feature, go back to the master
branch by running
$ git checkout master
This will revert your working copy to the contents of the master branch. It will be like you never checked out the old commit.
Now, if you want, clean up your repository by deleting the redundant branches. If you want to get a copy of
$ git branch -d planets-before-merge-conflict
$ git branch -d branch-a
$ git branch -d branch-b
$ git branch -d branch-master
You’ve deleted the local branches, but we pushed copies of those branches to github when you ran git push --all
. Deleting remote branches involves one of the strangest git commands. Git doesn’t have a “delete remote branch” argument. Instead you have to “push” the instructions to delete the branch by putting a colon before the branch name. For example:
$ git push :branch-a
This is really weird, but it’s just how git works. When you push a branch to a remote git repo, you can give it any name you want. For example, if you want to push branch-b to the remote repository called origin, you use the command:
$ git push origin branch-b
If you want to call the remote branch thestuff
instead of branch-b
, you would use the command
$ git push origin branch-b:thestuff
And so, this is the weird part, in order to delete a remote branch called branch-b
you need to use the command
$ git push origin :branch-b
This is basically telling git “push the lack of a branch to the remote location called branch-b
”. Yeah. Weird.
If you want to review an example of this repository with all of the branches you created in this lesson, Look at the branches in https://github.com/CodeForPhilly/decentralized-data-examples.