Skip to article frontmatterSkip to article content
Git Logo

Git Branches

Git “branches” are an important component of many Git and GitHub workflows. If you plan to use GitHub to manage your own resources, or contribute to a GitHub hosted project, it is essential to have a basic understanding of what branches are and how to use them. For example, the best practices for a simple workflow for suggesting changes to a GitHub repository are: create your own fork of the repository, make a branch from your fork where your changes are made, and then suggest these changes move to the upstream repository with a Pull Request. This section of the GitHub chapter assumes you have read the prior GitHub sections, are at least somewhat familiar with git commands and the vocabulary (“cloning,” “forking,” “merging,” “Pull Request” etc), and that you have already created your own fork of the GitHub Sandbox Repository hosted by Project Pythia.

Overview:

  1. What are Git Branches
  2. Creating a New Branch
  3. Switching Branches
  4. Setting up a Remote Branch
  5. Merging Branches
  6. Deleting Branches
  7. Updating Your Branches
  8. Complete Workflow

Prerequisites

ConceptsImportanceNotes
What is GitHub?NecessaryGitHub user account required
GitHub RepositoriesNecessary
Issues and DiscussionsRecommended
Cloning and Forking a RepositoryNecessary
Configuring your GitHub AccountRecommended
Basic Version Control with gitNecessary
  • Time to learn: 30 minutes

What are Git branches?

Git branches allow for non-linear or differing revision histories of a repository. At a point in time, you can split your repository into multiple development paths (branches) where you can make different commits in each, typically with the ultimate intention of merging these branches and development changes together at a later time.

Branching is one of git’s methods for helping with collaborative document editing, much like “change tracking” in Google Docs or Microsoft Word. It enables multiple people to edit copies of the same document content, while reducing or managing edit collisions, and with the ultimate aim of merging everyone’s changes together later. It also allows the same person to edit multiple copies of the same document, but with different intentions. Some reasons for wanting to split your repository into multiple paths (i.e. branches) is to experiment with different methods of solving a problem (before deciding which method will ultimately be merged) and to work on different problems within the same codebase (without confusing which code changes are relevant to which problem).

These branches can live on your computer (local) or on GitHub (remote). They are brought together through Git pushes, pulls, merges, and Pull Requests. Pushing is how you transfer changes from your local repository to a remote repository. Pulling is how you fetch upstream changes into your branch. Merging is how you piece the forked history back together again (i.e. join two branches). And Pull Requests are how you suggest the changes you’ve made on your branch to the upstream codebase.

One rule of thumb is for each development feature to have its own development branch until that feature is ready to be added to the upstream (remote) codebase. This allows you to compartmentalize your Pull Requests so that smaller working changes can be merged upstream independently of one another. For example, you might have a complete or near-complete feature on its own branch with an open Pull Request awaiting review. While you wait for feedback from the team before merging it, you can still work on a second feature on a second branch without affecting your first feature’s Pull Request. We encourage you to always do your work in a designated branch.

Creating a New Branch

branching The above flowchart demonstrates forking a remote repository, labeled “Upstream”, creating a local copy, labeled “Clone”, creating a new branch, “branchA”, and adding two commits, C3 and C4, to “branchA” of the local clone of the forked repository. Different commits can be added to different branches in any order without depending on or knowing about each other.

From your terminal, navigate to your local clone of your Github-Sandbox Repository fork:

cd github-sandbox

Let’s begin by checking the status of our repository:

git status
Git Status

You will see that you are already on a branch called “main”. And that this branch is up-to-date with “origin/main” and has nothing to commit.

Now check the status of your remote repository with

git remote -v
Git Remote

We are set up to pull (denoted as ‘fetch’ in the output above) and push from the same remote repository.

Next, check all of your exising Git branches with:

git branch -a
Git Branch

You will see one local branch (main) and your remote branch (remotes/origin/HEAD and remotes/origin/main, where HEAD points to main). HEAD is the pointer to the current branch reference, or in essence, a pointer to your last commit. More on this in a later section.

Now, before we make some sample changes to our codebase, let’s create a new branch where we’ll make these changes:

git branch branchA

Check that this branch was created with:

git branch
Git NewBranch

This will display the current and the new branch. You’ll notice that current or active branch, indicated by the “*” is still the main branch. Thus, any changes we make to the contents of our local repository will still be made on main. We will need to switch branches to work in the new branch, branchA.

Switching Branches

To switch branches use the command git checkout as in:

git checkout branchA

To check your current branch use git status:

git status
Git Checkout

Notice that git status doesn’t say anything about being up-to-date, as before. This is because this branch only exists locally, not in our upstream GitHub fork.

Setting up a Remote Branch

While your clone lives locally on your laptop, a remote branch exists on your GitHub server. You have to tell GitHub about your local branch before these changes are reflected remotely in your upstream fork.

pushing The above flowchart demonstrates pushing two new local commits (C3 and C4) to the corresponding remote branch. Before the push, the changes from these commits exist ONLY locally and are not represented on your upstream GitHub repository. After the push, everything is up-to-date.

Before we push this branch upstream, let’s make some sample changes (like C3 or C4) by creating a new empty file, with the ending “.py”.

touch hello.py
Git Status

You can check that this file has been created by comparing an ls before and after this command, and also with a git status that will show your new untracked file.

git add and git commit your new file and check the status again.

Git Add

Your new branch is now one commit ahead of your main branch. You can see this with a git log.

Git Log

In a real workflow, you would continue making edits and git commits on a branch until you are ready to push up to GitHub.

Try to do this with

git push
Git Push

You will get an error message, “fatal: The current branch branchA has no upstream branch.” So what is the proper method for getting our local branch changes up to GitHub?

First, we need to set an upstream branch to direct our local push to:

git push --set-upstream origin branchA

Thankfully, Git provided this command in the previous error message. If you cloned using HTTPS, you will be asked to enter your username and password, as described in GitHub’s PAT Creation page.

Set Upstream

We can see that this worked by doing a git branch -a

Notice the new branch called remotes/origin/branchA. And when you do a git status you’ll see that we are up to date with this new remote branch.

Git Commit Status

On future commits you will not have to repeat these steps, as your remote branch will already be established. Simply push with git push to have your remote branch reflect your future local changes.

Merging Branches

Merging is how you bring your split branches of a repository back together again.

If you want to merge two local branches together, the steps are as follows:

Let’s assume your two branches are named branchA and branchB, and you want your changes from branchB to now be reflected in branchA

  1. First checkout the branch you want to merge INTO:
git checkout branchA
  1. Then execute a merge:
git merge branchB

If there were competing edits in the 2 branches that Git cannot automatically resolve, a merge conflict occurs. This typically happens if edits are to the same line in different commits. Conflicts can be resolved in the command line or in your GUI of choice (such as Visual Studio Code).

A Pull Request is essentially a merge that happens on an upstream remote. We will continue this demonstration and cover the specifics of merging via a Pull Request more thoroughly in the next section.

PR The above flowchart demonstrates a simple Pull Request where the upstream main repository has accepted the changes from the feature branch of your fork. The latest commit to the Upstream Main repository is now C4. Your Feature branch can now be safely deleted.

Deleting Branches

After the feature you worked on has been completed and merged, you may want to delete your branch. deletebranch

To do this locally, you must first switch back to main or any non-target branch. Then you can enter

git branch -d <branch>

for example

git branch -d branchA

To delete the branch remotely, type

git push <remote> --delete <branch>.

as in

git push origin --delete jukent/branchA

Updating Your Branches

Previously, we showed you how to merge branches together, combining the changes from two different branches into one. Afterwards you deleted your feature branch branchA. Your local clone and fork of your main branch have now both need to pull from the upstream repository.

pull The above flowchart demonstrates pulling in the upstream changes from Upstream Main after a Pull Request has been merged, first into your fork and then into your clone. Before continuing to work, with new commits on the feature branch, it is best to pull in the upstream changes.

In this example, all of the changes to the branches were local and made by a single person, you. In a collaborative environment, other contributors may be making changes to their own feature branches (or main branch), which will ultimately be pushed up to the remote repository. Either way, your branches will become stale and need to be refreshed. The more time that passes by, the more likely this is to happen, particularly for an active GitHub repository. Here we show you how to sync your branches with the upstream branches.

Once a Pull Request has been merged, you will find that these upstream changes are not automatically included in your fork or your other branches. In order to include the changes from the upstream main branch, you will need to do a git pull.

First check if there are any upstream changes:

git status

Then, if there are no merge conflicts:

git pull

git pull is a combination of git fetch and git merge. That is it updates the remote tracking branches (git fetch) AND updates your current branch with any new commits on the remote tracking branch (git merge).

This same concept applies to work in a team setting. Multiple authors will have their own feature branches that merge into the same Upstream Main repository via Pull Requests. It is important for each author to do regular git pulls to stay up to date with each other’s contributions.

Complete Workflow

All in all your Git Branching workflow should resemble this flow: gitworkflow

  1. Fork the upstream repository
  2. Create a local clone of your upstream fork
  3. Create and switch to a new branch in local copy
  4. Make changes
  5. Add and commit changes in branch
  6. Push commits to fork (Set an upstream branch only for first push)
  7. Repeat last three steps as necessary
  8. Merge into upstream main branch via Pull Request
  9. Delete branch from clone and fork
  10. Pull upstream changes to main branch of fork and clone

Summary

  • Git Branches allow you to independently work on different features of a project via differing revision histories of a repository.
  • A useful workflow is to create a new branch locally, switch to it and set up a remote branch. During your revision, push to your upstream branch and pull from main as often as necessary. Then suggest your edits via a Pull Request and, if desired, delete your branch after the merge.

What’s Next?

Opening a Pull Request on GitHub

Resources and references