Remote Branches with GitHub#
Learning objectives#
Create remote branches using GitHub
Track remote branches locally
Merge remote branches using a pull request
Delete branches in your local and remote repositories
Local and remote branches#
Branches can reside in our local repository and/or remote repository, in the
same way that commits can. An upstream branch is one which resides in the
remote repository and is tracked locally, meaning the local branch is linked to
the remote branch. Our local repository stores references to any remote branches,
prepending their names with remotes/origin/
(or simply origin/
). It should
be noted that these remote branches are not updated automatically - we need to
use git fetch
to update them.
Viewing branches#
We can list all the branches that our local repository is aware of (both
local branches and remote branches) by using git branch --all
(or
just git branch -a
):
$ git branch -a
branches-material
* main
remotes/origin/HEAD -> origin/main
remotes/origin/main
There are three branches worth noting here, namely main
(our local version of
main
), remotes/origin/main
(our remote version of main
) and branches-material
(our newly created local branch). We can safely ignore
remotes/origin/HEAD -> origin/main
for the time being.
As we have only created branches-material
locally, it does not have a remote
counterpart, unlike main
. Using GitHub, we can verify there is no remote branch
called branches-material
. The necessary steps are as follows:
Step 1 Navigate to your repository on GitHub.
Step 2 Click on branch(es), above the list of files on the left-hand side, as indicated in the following screenshot:
Step 3 Click on All branches, located to the left of the green New branch button on the right-hand side of the screen — this will display a list of all the branches in your remote repository.
branches-material
will be missing from this list.
Working with remote branches#
So far, we’ve seen how to create a local branch, commit to it and merge it into
another branch (e.g. into main
). This branch didn’t have an upstream branch
in the remote repository. We’re now going to look at the case where we
use GitHub to create a branch in the remote repository, which we then
bring into our local repository to work with. This approach takes advantage of
useful functionality provided by GitHub, promoting collaborative working. We
will look at an alternative workflow that doesn’t rely on the features GitHub
provides in a later episode.
Now, let’s add some material to the cheatsheet relating to working with remote branches, using GitHub to drive this development. The basic flow for doing this will be the following:
Create a remote branch on GitHub that will receive our additions to the cheatsheet.
Work on the cheatsheet locally, then push the changes up to the remote branch.
Use GitHub to merge the work into the
main
branch in the remote repository, using a pull request.
In order to do this, we need to do the following:
Create a remote branch on GitHub.
Update our local repository from the remote repository, so that we have a reference to the newly created remote branch.
Create a local branch that is set up to track the remote one.
Add new commits to the local branch corresponding to our work on the cheatsheet.
Push these commits to the upstream remote branch.
Merge the remote branch into the remote
main
branch, using a pull request on GitHub.Update our local repository to reflect this change to the remote repository.
Create a remote branch on GitHub#
In GitHub, the following steps allow you to create a new remote branch:
Step 1 Navigate to your repository on GitHub.
Step 2 Click on the dropdown, located to the left of branches, on the left-hand side of the screen.
Step 3 Select the branch you would like to create a branch from. (For this course, this will typically be
main
. If it ismain
, this step becomes redundant.)Step 4 Click on the dropdown again and type in the name of your new branch where it says Find or create a branch….
Step 5 Click on Create branch: new-branch from ‘base-branch’, where new-branch is the name of your new branch and base-branch is the name of the branch you are branching off of (e.g.
main
).
In our example git-good-practice
repository, let’s suppose we’ve just created a
new remote branch called remote-branches-material
, which is based on top of
main
. Our local repository doesn’t have any knowledge of this new branch, as
can be seen by listing the branches:
$ git branch -a
branches-material
* main
remotes/origin/HEAD -> origin/main
remotes/origin/main
Fetch the remote branch#
In order to update our local repository so that it has knowledge of the new remote branch, we use the following command from within our local repository:
git fetch
(Like with git push
and git pull
, we can instead run git fetch origin
to
be explicit about the reference to the remote repository.)
We won’t go into too much detail about exactly what git fetch origin
is doing. For
our purposes, we use it to inspect the remote repository for information about
any new branches, or commits that have been made in remote branches, that our
local repository doesn’t yet know about.
In our example, after running git fetch
in our git-good-practice
repository, we see that information about the new remote remote-branches-material
has been retrieved:
$ git fetch
Username for 'https://github.com': jbloggs9999
Password for 'https://jbloggs9999@github.com':
From https://github.com/jbloggs9999/git-good-practice
* [new branch] remote-branches-material -> origin/remote-branches-material
$ git branch -a
branches-material
* main
remotes/origin/HEAD -> origin/main
remotes/origin/main
remotes/origin/remote-branches-material
However, this has only created a reference to the remote branch, indicated
by remotes/origin/remote-branches-material
in the above output. We still need
to create a local branch that will track the remote branch.
Create a new tracking local branch#
In order to create a local version of the
origin/remote-branches-material
branch where we can add commits, we can
perform the following checkout:
$ git checkout remote-branches-material
Switched to a new branch 'remote-branches-material'
branch 'remote-branches-material' set up to track 'origin/remote-branches-material'.
You may be surprised by this: after all, we’ve asked Git to checkout a branch
that doesn’t actually exist! Fortunately, Git is smart enough to realise that
what we want to do is set up a new local branch that tracks the origin/remote-branches-material
remote branch. So it automatically creates a new local branch — called remote-branches-material
— that
will track origin/remote-branches-material
, and checks out this new local branch for us. We
can verify this by listing all the branches again:
$ git branch -a
branches-material
main
* remote-branches-material
remotes/origin/HEAD -> origin/main
remotes/origin/main
remotes/origin/remote-branches-material
Add content to the local branch and push#
We are now set to add our new material to Git-cheatsheet.md
about remote
branches. We modify the start of the subsection Branches so that it now reads as
follows:
## Branches
`git branch <new-branch-name>` — Create a new branch called `<new-branch-name>`
based at the current commit (i.e. at `HEAD`).
`git checkout <branch>` — Check out the branch `<branch>`, so that new commits
are added to `<branch>`.
- Can also be used to create and checkout a new local branch `<branch>` that
tracks an existing remote branch `origin/<branch>`.
`git merge <branch-to-merge-in>` — Combine the commit history of `<branch-to-merge-in>`
with that of the branch currently checked out.
Having included this addition, we commit to our local remote-branches-material
branch.
Markdown syntax#
Unordered lists are denoted by using a hyphen (-
) or an asterisk (*
), followed by a space, with the text in the list item following. Example:
- Foo
- Bar
- Baz
renders as:
Foo
Bar
Baz
We’re now in the position where our local branch
remote-branches-material
is ahead of the remote branch
origin/remote-branches-material
that it tracks, as can be seen from
the log on remote-branches-material
:
$ git log --oneline -3
5125372 (HEAD -> remote-branches-material) Add note about creating local tracking branches
3b918f2 (origin/remote-branches-material, origin/main, origin/HEAD, main, branches-material) Add entry about merging branches
51da8da Add entry about checking out a branch
In order to update an upstream remote branch with new commits in the local
tracking branch, we can use git push
(or git push origin
), like we did when working with
the main
branch in the episode Pushing to and Pulling From the Remote Repository.
Note however that this will push the commits on the currently checked out branch to its upstream
remote branch. So, in general, if you have a local branch <foo>
that tracks a
remote branch origin/<foo>
, then in order to push <foo>
to origin/<foo>
we
need to first checkout <foo>
.
Alternative: specify the branch explicitly#
Alternatively, if you have a local branch <foo>
that tracks a remote branch origin/<foo>
, then you can run git push origin <foo>
from any local branch to push commits from <foo>
to origin/<foo>
.
In our example, we’re already on the branch remote-branches-material
that we want to push,
so we can just go ahead and do git push
:
$ git push
Username for 'https://github.com': jbloggs9999
Password for 'https://jbloggs9999@github.com':
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 438 bytes | 219.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/jbloggs9999/git-good-practice.git
3b918f2..5125372 remote-branches-material -> remote-branches-material
The last line of the git push
message shows that we’ve successfully updated the remote
branch with the new commit.
Merge remote branch into remote main
#
Once we have pushed our changes to the remote branch, we can merge said remote
branch into remote main
by means of a pull request on GitHub. We can create and
complete a pull request (PR) as follows:
Step 1 Navigate to your repository on GitHub.
Step 2 Click on the Pull requests tab (third tab from the left).
Step 3 Click on the green New pull request button on the right-hand side of the screen.
Step 4 Ensure
main
has been chosen as base and choose your remote branch, which in this case isremote-branches-material
, as compare.Step 5 Click on the green Create pull request button.
Step 6 GitHub will generate a title based on the name of the branch you are comparing, but this can be changed. You are also welcome to add a description where it says Leave a comment.
Step 7 Click on the green Create pull request button.
Step 8 Click on the green Merge pull request button, located near the bottom of the page.
Pull changes into our local repository#
We have just merged our branch into main
in the remote repository. To see
the changes made to main
in our local repository, we need to pull them from
the remote repository.
To update main
, we first check it out:
$ git checkout main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
There’s an important point to make about the output here. It is stated that
Your branch is up to date with 'origin/main'.
. This doesn’t mean there aren’t changes on the remote to
pull in. Instead, it means that Git is not aware of any extra commits in
origin/main
compared to main
since last fetch
ing from the remote repository.
So, let us fetch updates from the remote repository:
$ git fetch
Username for 'https://github.com': jbloggs9999
Password for 'https://jbloggs9999@github.com':
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (1/1), 667 bytes | 83.00 KiB/s, done.
From https://github.com/jbloggs/git-good-practice
3b918f2..86ebbee main -> origin/main
We can see that our local repository is now aware of the change to the remote
origin/main
branch by checking the status again:
$ git status
On branch main
Your branch is behind 'origin/main' by 2 commits, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working tree clean
In the Pushing to and Pulling From the Remote Repository
episode, we mentioned that git pull
can be used to retrieve updates from the
remote repository. To be more precise, git pull
is used to bring in commits
in a remote branch into a corresponding local branch. In general, if you have
a remote branch that has commits not yet in a local tracking
branch <branch>
, then run the following command with <branch>
checked out
to update <branch>
with these new commits:
git pull
(or, to be explicit about the remote repository, git pull origin
).
pull
automatically fetch
es#
git pull
actually performs a two step process on a branch <branch>
. First, it runs a git fetch
to retrieve all new commits, branches, etc. from the remote repository. Then, it merges the changes that have been fetched into the origin/<branch>
into <branch>
. As a result, we did not in fact need to use the git fetch
command before using git pull
above.
We pull the changes to origin/main
into our local main
branch:
$ git pull
Username for 'https://github.com': jbloggs9999
Password for 'https://jbloggs9999@github.com':
Updating 3b918f2..86ebbee
Fast-forward
Git-cheatsheet.md | 3 +++
1 file changed, 3 insertions(+)
We can now see from the log that our changes are fully reflected in main
:
$ git log --oneline -5
86ebbee (HEAD -> main, origin/main, origin/HEAD) Merge pull request #1 from jbloggs9999/remote-branches-material
5125372 (origin/remote-branches-material, remote-branches-material) Add note about creating local tracking branches
3b918f2 (branches-material) Add entry about merging branches
51da8da Add entry about checking out a branch
8124186 Add entry about creating branches
Cleaning up#
All the work we’ve done in our branches has been incorporated into main
(both
locally and in the remote repository). So, to clean up the state of the repository,
we’re going to delete the branches branches-material
and remote-branches-material
,
including the remote version of remote-branches-material
, since these
no longer serve any purpose.
Good practice: deleting old branches#
It is good practice to delete branches that are no longer required. This makes navigating a repository easier and makes it clear what work is still ongoing compared to work that has been finished.
Deleting branches from a local repository#
The general commands for deleting branches are as follows:
For deleting local branches:
git branch -d <local-branches>
For deleting remote branches:
git branch -d -r <remote-branches>
In both cases, note that you can specify more than one branch by separating the branch names by a space.
There are a couple of important things to note about deleting branches:
You can’t delete a branch you currently have checked out. So make sure you checkout a different branch before deletion e.g. do deletions from
main
.Deleting branches removes the commits contained in those branches which don’t feature in other branches. So, before deleting a branch, be sure that the changes you want to keep have been merged into another branch e.g.
main
.
We delete our local branches:
$ git branch -d branches-material remote-branches-material
Deleted branch branches-material (was 3b918f2).
Deleted branch remote-branches-material (was 5125372).
Then we delete our remote branch reference origin/remote-branches-material
:
$ git branch -r -d origin/remote-branches-material
Deleted remote-tracking branch origin/remote-branches-material (was 5125372).
Force deletion#
Git may stop you from deleting a branch, because it can’t verify that all the commits in the branch have been merged into a corresponding remote branch or another local branch. This is a protection mechanism to stop you from potentially losing changes. If you encounter this but are sure you want to proceed with the deletion, you can force the deletion by using -D
instead of -d
in the commands above.
Our local repository is now looking cleaner with regards to the branches we have:
$ git branch -a
* main
remotes/origin/HEAD -> origin/main
remotes/origin/main
Note also that the references to the non-main
branches have disappeared from
the log (note that the commits have not disappeared, however, because these
are part of main
):
$ git log --oneline -5
86ebbee (HEAD -> main, origin/main, origin/HEAD) Merge pull request #1 from jbloggs9999/remote-branches-material
5125372 Add note about creating local tracking branches
3b918f2 Add entry about merging branches
51da8da Add entry about checking out a branch
8124186 Add entry about creating branches
Deleting branches from the remote repository via GitHub#
Finally, we need to delete the remote branch remote-branches-material
from the
remote repository in GitHub. The necessary steps are as follows:
Step 1 Navigate to your respository on GitHub.
Step 2 Click on branches, above the list of files on the left-hand side.
Step 3 Click on All branches, located to the left of the green New branch button on the right-hand side of the screen.
Step 4 Identify the branch to be deleted and click on the appropriate bin icon on the right-hand side of the screen. If you hover over the icon, it will show a message stating Delete chosen-branch, where chosen-branch is the name of the branch to be deleted.