Creating And Playing With Branches
Commands discussed in this section:
- git branch
- git checkout
The Branching Experience
Okay, this is where it gets really fun: With both ease and lightening-fast speed, you can create your own branches and jump between branches as if git was built from the ground-up for a great branching experience (yes, it was).
Starting a repository: master branch
When you first create a git repository (with a command such as git init), one branch is created. It’s your main (and only) branch. The branch, by default, is named master.
When you make that first addition to the repository, the first addition is usually made to that one branch:
The master branch.
$ git init Initialized empty Git repository ... $ echo This is the README file. > README $ git add README $ git commit -m'Initial commit' [master (root-commit) 35ede5c] Initial commit 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 README
Use the git branch command to list the branches in the repository:
$ git branch * master
The above tells us:
- There is one branch, called master.
- The current (and so far, the only) branch is master: The asterisk is placed to the left of the current branch in the repository. Being told which is the current branch is more interesting when there are multiple branches.
The commits in the repository now look like this:
- master is the name of the one branch that exists in the repository now.
- HEAD is used by git to refer to the current commit you’re working on. In this case, HEAD is referring to the master branch.
After we create another branch, you can choose to have HEAD be set to refer to the master branch or new branch. For now, you’ll note that HEAD and master both end up referring to the same commit. However, there’s not much of a choice of where they could refer yet since there is only one commit and only one branch.
More commitments, and branches make life more interesting.
We mentioned earlier that HEAD is actually a file whose contents determines where the HEAD variable refers:
$ cat .git/HEAD ref: refs/heads/master $ cat .git/refs/heads/master 35ede5c916f88d8ba5a9dd6afd69fcaf773f70ed
In this repository, the contents of the HEAD file refers to a second file named refs/heads/master. The file refs/heads/master contains the hash of the most recent commit on the master branch.
The result is HEAD points to the master branch commit from the .git/refs/heads/master file.
Let’s add another commit before we start the fun of branching:
$ echo One more line. >> README $ git commit -a -m "Added a second line." [master b26009d] Added a second line. 1 files changed, 1 insertions(+), 0 deletions(-)
Our repository with commits C1 and C2 now looks like the following diagram, with master and HEAD referring to the most recent commit, commit C2:
Now the fun starts with creating a new branch.
Creating A New Branch
Let’s create a new branch named test and then list the branches in the repository. Creating a branch is done via git branch branch-name:
$ git branch test $ git branch * master test
Sure enough, it shows there are now two branches.
You may may be a little surprised that the current branch (with the asterisk next to it) is still master. Creating a branch does not switch to the new branch, unless you use the -b option.
Switching Between Branches
You can switch to a new branch with the git checkout command:
$ git checkout test Switched to branch 'test' $ git branch master * test
Okay, we’re on our fancy, new test branch, so let’s add a commit to our new branch that includes a new file named plan:
$ echo My system test > plan $ git add plan $ git commit -m"Add plan file" [test f1302c8] Add plan file 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 plan $ ls plan README
Our repository now looks like this, with T1 representing the first commit on the new test branch:
Note that HEAD has been pointing to the test branch ever since we did the git checkout test command.
If we want to get back to the master branch we can type:
$ git checkout master
Which results in the HEAD moving:
When the git checkout master command is done, the new plan file that was part of the test branch is removed from the working directory and index:
$ ls README $ git ls-files README
Let’s do another commit. The commit parent for this new commit will be C2 rather than T1 since we are “on” the master branch. We will create a new file named Makefile and add it to the repository on the master branch:
$ echo '# Beginnings of a Makefile' > Makefile $ git add Makefile $ git commit -m'Added a Makefile' [master 2702f9b] Added a Makefile 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 Makefile
Switching Branches Changes The Working Directory
Now that we have 2 branches, master and test, we can switch beween them using git checkout. First, let’s make sure we know what branch we’re on:
$ git branch * master test $ ls Makefile README
We’re on the master branch. The master branch has the files Makefile and README.
Then switch to the test branch:
$ git checkout test Switched to branch 'test' $ git branch master * test $ ls plan README
The test branch has the files plan and README.
When you switch to a different branch, your working directory reflects the branch.
Only the master branch has the file Makefile while only the test branch has the file plan, as shown above.
To delete the branch named test:
$ git branch -d test error: Cannot delete the branch 'test' which you are currently on.
Git gives you enough rope to hang yourself, but you’re not allowed to saw off the branch you’re on.
This time let’s try deleting the test branch after we climb to a different branch:
$ git checkout master Switched to branch 'master' $ git branch -d test Deleted branch test (was 05affb3).
Switching branches without committing in the current branch
Recommendation: Switch to the branch you want to be on before you start modifying files in your working
What happens if you make changes to the current branch, and then switch branches without committing the changes to the current branch? If you plan to do this, read the switching branches without committing section.
Temporarily putting the current branch on hold
There are many situations where you might be on one branch, start making changes for that branch and then want to start working on a different branch. For example, you may be working on a new feature, but then become aware of a bug that needs to be fixed on another branch.
In this case, you would want to:
- Temporarily save changes to the working directory
- Switch branches, make changes to this branch and commit those changes
- Return to where you left off in the previous branch, with the state of its working directory
One way to handle this situation is by using the git stash command that is discussed here.