One of the driving factors behind Git’s original design was to support the messy, non-linear approach to development that stems from working on large-scale, fast-moving projects. The need to split off development from the main development line, make changes independently and in isolation of other changes on the main development line, easily merge those changes back in, and do all this in a lightweight manner, was what drove the creators of Git to build a very lightweight, elegant model to support this kind of workflow.
In this chapter, you’ll explore the first half of this paradigm: branching. You’ve touched on branching quite briefly in Chapter 1, “A Crash Course in Git,” but you probably didn’t quite understand what you, or Git, were doing in that moment.
Although you can hobble through your development career never really understanding how branching in Git actually works, branching is incredibly important to the development workflows of many development teams, both large and small, so knowing what’s going on under the hood, and having a solid mental model of your repository’s branching structure will help you immensely as your projects grow in size and complexity.
What is a commit?
That question was asked and answered in a shallow manner a few chapters ago, but it’s a good time to revisit that question and explore commits in more detail.
Recall that a commit represents the state of your project tree — your directory — at a particular point in time:
├── LICENSE ├── README.md ├── articles │ ├── clickbait_ideas.md │ ├── ios_article_ideas.md │ └── live_streaming_ideas.md ├── books │ └── book_ideas.md └── videos ├── content_ideas.md └── platform_ideas.md
You probably think about your files primarily in terms of their content, their position inside the directory hierarchy, and their names. So when you think of a commit, you’re likely to think about the state of the files, their content and names at a particular point in time. And that’s correct, to a point: Git also adds some more information to that “state of your files” concept in the form of metadata.
Git metadata includes such things like “when was this committed?” and “who committed this?”, but most importantly, it includes the concept of “where did this commit originate from?” — and that piece of information is known as the commit’s parent. A commit can have one or two parents, depending on how it was branched and merged back in, but you’ll get to that point later.
Git takes all that metadata, including a reference to this commit’s parent, and wraps that up with the state of your files as the commit. Git then hashes that collection of things using SHA1 to create an ID, or key, that is unique to that commit inside your repository. This makes it extremely easy to refer to a commit by its hash value, or as you saw in the previous chapter, its short hash.
What is a branch?
The concept of a branch is massively simple in Git: It’s simply a reference, or a label, to a commit in your repository. That’s it. Really. And because you can refer to a commit in Git simply through its hash, you can see how creating branches is a terribly cheap operation. There’s no copying, no extra cloning, just Git saying “OK, your new branch is a label to commit
477e542”. Boom, done.
Creating a branch
You created a branch before in the crash-course chapter, but now you’re going to create a branch and watch exactly what Git is doing.
git branch testBranch
How Git tracks branches
To see that Git actually did something, execute the following command to see what Git’s done in the background:
git log -1
commit 477e542bfa35942ddf069d85fbe3fb0923cfab47 (HEAD -> master, testBranch) Author: Chris Belanger <email@example.com> Date: Wed Jan 23 16:49:56 2019 -0400 Adding .gitignore files and HTML
Checking your current branch
Git can easily tell you which branch you’re on, if you ever need to know. Execute the following command to verify you’re working on testbranch:
* master testBranch
Switching to another branch
To switch to testBranch, execute the
checkout command like so:
git checkout testBranch
Switched to branch 'testBranch'
git checkout master
git branch -d testBranch
Viewing local and remote branches
To see all of the branches that Git knows about on this repository, either local or remote, execute the following command:
git branch --all
* master remotes/origin/HEAD -> origin/master remotes/origin/clickbait remotes/origin/master
git checkout --track origin/clickbait
Branch 'clickbait' set up to track remote branch 'clickbait' from 'origin'. Switched to a new branch 'clickbait'
OK, what is this
origin thing that you keep seeing?
git remote -v
origin https://www.github.com/belangerc/ideas (fetch) origin https://www.github.com/belangerc/ideas (push)
git branch --all -v
* clickbait e69a76a Adding suggestions from Mic master 477e542 [ahead 8] Adding .gitignore files and HTML remotes/origin/HEAD -> origin/master remotes/origin/clickbait e69a76a Adding suggestions from Mic remotes/origin/master c470849 Going to try this livestreaming thing
Viewing branches graphically
To see a visual representation of the current state of your local branches, execute the following command:
git log --oneline --graph
* e69a76a (HEAD -> clickbait, origin/clickbait) Adding suggestions from Mic
A shortcut for branch creation
I confess, I took you the long way ’round with that command
git checkout --track origin/clickbait, but seeing the long form of that command hopefully helped you understand what Git actually does when it checks out and tracks a branch from the remote.
Challenge: Delete a branch with commits
You don’t want to muck up your existing branches for this challenge, so you’ll need to create a temporary local branch, switch to it, make a commit, and then delete that branch.
- A commit in Git includes information about the state of the files in your repository, along with metadata such as the commit time, the commit creator, and the commit’s parent or parents.
- The hash of your commit becomes the unique ID, or key, to identify that particular commit in your repository.
- A branch in Git is simply a reference to a particular commit by way of its hash.
masteris simply a convenience convention, but has come to be accepted as the original branch of a repository.
mainis also another common convenience branch name in lieu of
git branch <branchname>to create a branch.
git branchto see all local branches.
git checkout <branchname>to switch to a local branch, or to checkout and track a remote branch.
git branch -d <branchname>to delete a local branch.
git branch --allto see all local and remote branches.
master, is simply a convenience convention that is an alias for the URL of the remote repository.
git checkout -b <branchname>to create and switch to a local branch in one fell swoop.
Where to go from here?
Get used to branching in Git, because you’ll be doing it often. Lightweight branches are pretty much the reason that Git has drawn so many followers, as it matches the workflow of concurrent development teams.