In Git, branches are simply a group of commits (or even just a single commit).
Branches allow a project to be modified in sensible and controllable ways; let’s think about the website example we made in the previous section: lab-01-website.
If we look at what we have so far as a series of commits, we have this (Figure 2.12):
We made our first commit [37bb05a] at a point in time, and sometime later we made our second commit [88934e8]. These two commits already exist on a branch, the master branch. Now so far we haven’t mentioned branches, but that doesn’t mean we haven’t been using one.
When we created (initialised) the repository in section 2.2.1. Git automatically created a branch for us (Git always has to have at least one branch). By default this branch is called the master branch; it is this branch that we have been working on all this time.
There is nothing special about the master branch, it is just the first branch created in the repository and by default Git always calls it “master”. It is perfectly possible to rename it or even delete it. But don’t.
Virtually every project ever created with Git or GitHub will have a master branch. Not because it is special or particularly important, but because everybody just keeps it. In this sense it has had importance thrust upon it; the master branch has become the default branch for deployable code. This is just a convention you understand, there is absolutely nothing special about the master branch itself, but it is a convention I use and I explain it in the best practice section (§ 2.4.2 and appendix b).
In Figure 2.12 I’ve added a symbol; this is, in Git parlance, the head. The head (by default) points to the latest (most recent) commit on the currently active branch. In this case it is on the master branch (the only one we have) and points to commit [88934e8] which is the most recent commit.
So what do we do with branches?
Well let’s suppose that our index.html page is finished and we’re completely happy with it and its finished code is sitting at commit [88934e8].
Now let’s suppose that we want to add another page called 01-intro.html. In my best practice model for branching (§ 2.4.2), the tested deployable code is always on the master branch. Any development work needs to be done on a new branch. In this case we will call it the dev-01-intro branch (I start development branches with dev for clarity; in later sections I abbreviate this to d-).
In Git we create a new branch with the branch command. All this does is create a new branch, nothing else has happened. We haven’t moved to the new branch, we are still on the master branch and nothing has happened to any of the files in our working directory. Everything is just as it was.
To change to the new branch we use the Git checkout command. This now switches us to the new branch. It looks like this, Figure 2.13:
Ok, so these all look like maps of the London underground.
Still nothing has really happened; we’ve activated the new branch so the head has moved to dev-01-intro. The latest commit is still [88934e8] and the head still points to this commit.
All this sort of makes sense; we’ve created a new branch, but we haven’t changed any files or committed anything new to the repository. So let’s make a change and see what happens.
We are now on the new dev-01-branch. Let’s create a new 01-intro.html file in the root folder (same place as index.html) and add the following code to it:
<html lang="en"> <!-- Declare language --> <head> <!-- Start of head section --> <meta charset="utf-8"> <!-- Use Unicode character set --> <link rel="stylesheet" type="text/css" href="11-resources/01-css/style.css"> <title>PracticalSeries: Git Lab</title> </head> <body> <h1>A Practical Series Website</h1> <h3>Introduction</h3> <p>This page is an introduction to the website.</p> </body> </html>
|Code 2.4 dev-01-intro branch — create new file|
Add and commit the changes with the commit message New page 01-intro.html added. In my case it is commit number .
Now we have Figure 2.14:
The head has now moved to the new commit we just made—this is sensible, the head always points to the latest commit on the active branch.
I know what you’re thinking, you’re thinking what happens if I switch back to master?
Well let’s have a look.
Pay attention now, this bit’s important.
Our current branch dev-01-intro has an extra file in it, 01-intro.html.
The head is now pointing to the last commit made on the master branch [88934e8] and there is no longer a file called 01-intro.html in our working directory.
This is because the master branch doesn’t know anything about the dev-01-intro branch or any commits that may have been made on it.
This is a comparison of what the two branches have in their working directories (Table 2.1):
|master branch||dev-01-intro branch|
|Table 2.1 File and commit status on two different branches|
So if we are on the dev-01-intro branch we have an extra file and if we switch back to master we lose it again.
What’s the moral of all this? Well:
SWITCHING BRANCHES CHANGES THE FILES
This is important, you’ll remember it when you’re on the wrong branch and you are wondering where all your files have gone. Believe me you will be on the wrong branch more often than you think.
Let’s say we’re back on the dev-01-branch and we’ve made some changes to 01-intro.html, but we aren’t ready to commit them to the local repository—i.e. we are in the process of modifying them and we’re not ready to commit them yet.
Now let’s say we want to go have a quick look on another branch. Well there is a problem, if we try to change branches with modifications that are in the working directory or staged area, when we change branches, those modifications would be overwritten by whatever files are at the head of the branch we are changing to. We would lose the changes we had made in the previous branch and that would be bad.
Git won’t let this happen:
YOU CANNOT CHANGE BRANCHES IF YOU HAVE UNCOMMITTED CHANGES IN YOUR WORKING COPY
There is a way around this, it’s called stashing files and it’s essentially a temporary way of storing files that are a work in progress (WIP in Git terminology) without committing them—it essentially pushes the files onto a storage stack (remember the Z80 push/pop assembler commands?—no?—never mind). Neither Brackets nor GitHub support the stash and suffice it to say, I’m not a great fan of the stash either—hence I don’t cover it in these pages.
We will always commit our changes before switching branches†1.
|†1||I’m going to say something here that some people won’t agree with: “I don’t like stashing data”, I prefer to commit changes even if they’re not finished—this is complete heresy to some people who think you only commit completed work—I’m not sure the GitHub people think this, GitHub doesn’t have a stash facility and they recommend “commit early and commit often”.|
|I don’t stash unfinished work, I commit it. I commit it as an incremental build.
That’s what engineers do.