A branch is a pointer to a commit (under the hood, it is a small file containing the 40 character hash checksum of the commit it points to)
This is what On branch main
means in the output of git status
This is also what (HEAD -> main)
means when you run git log
If your changes break code, you still have a fully functional branch to go back to if needed
You can create a branch for each alternative approach. This allows you to jump back and forth between various alternatives
You can work on different aspects of the project on different branches. This prevents having messy incomplete work all over the place on the same branch
Mostly, branches are great for collaboration: each person can work on their own branch and merge it back to the main branch when they are done with one section of a project
When you run git init
to initialize a repository, a branch gets created and it is called main
(you could rename it to something else if you wanted—that initial branch, despite its name, has nothing special)
You can create additional branches with:
git branch <branch-name>
git branch test
Notice that HEAD
still points to main
You switch to a branch with:
git switch <branch-name>
git switch test
When you create a branch, most of the time you want to switch to it. There is a handy way to create a branch and switch to it immediately:
git switch -c <branch-name>
You can delete a branch with:
git branch -d <branch-name>
git branch
git branch -v # show sha1 and commit message for each head
git branch -vv # also show upstream branch
git branch -r
git branch -a
Here is a classic workflow with branches
You just switched to the branch test
:
Now you make a series of commits on that branch:
Now you make a series of commits on that branch:
You want to merge them back into the main branch
First, you switch to main
(to merge, you need to be on the branch you want to merge into):
git switch main
Then you merge test
into main
:
git merge test
This merge is called a fast-forward merge: the branch main
could be fast-forwarded to the branch test
Now, you can delete the branch test
which has become useless:
git branch -d test
Let’s consider another common workflow with a branch test2
starting from the same situation (you just created and switched to test2
):
You create a number of commits on test2
:
You create a number of commits on test2
:
Then you switch to main
:
and you create commits on main
:
and you create commits on main
:
To merge test2
into main
, you need to be on main
, but that’s already the case.
So you can run:
git merge test2
and you get:
Note that in order to make the merge in this scenario, Git had to create a new commit, called a merge commit and that this commit has 2 parents
Finally, you can now delete the test2
branch with git branch -d test2
:
If the same section of a file is changed on different branches, Git cannot know which version you would like to keep. The merge gets interrupted until you resolve the conflict
You can use a merge tool (run git mergetool --tool-help
to get help setting this up)
Many GUI applications for Git as well as powerful text editors such as Emacs and Vim offer merge tools
You can also resolve the conflict manually in any text editor:
When a merge gets interrupted due to a conflict, Git tells you which file contains a conflict. Open this file and look for a section that looks like this:
<<<<<<< HEAD
Version of this section of the file on the current branch
=======
Alternative version of the same section of the file
>>>>>>> alternative version
The <<<<<<< HEAD
, =======
, and >>>>>>>
are markers added by Git to identify the alternative versions at the location of the conflict
You have to decide which version you want to keep (or write yet another version), remove the 3 lines with the markers, and remove the line(s) with the version(s) you do not want to keep