At the start of this workshop you forked the original upstream
repository into your own fork, in your own GitHub account. This allowed you to work in your fork without interupting any work taking place in upstream
. You pulled changes from upstream
into your fork via git pull upstream main
and you requested that upstream
pulled your changes by issueing pull requests.
You can visualise your fork and upstream
as being two parallel lines of development, e.g.
your fork o-----o--o--o--o
/ /
/ /
upstream o--o--o--o--o--o
The circles represent commits, while the lines joining your fork to upstream
represent the git pull upstream main
calls that pulled code from upstream
into your fork.
GitHub helpfully draws these diagrams for you. Go to ‘Insights’ then ‘Network’. Here you will get an interactive plot that will let you explore the individual commits, e.g.
Your fork of upstream
represents a separate branch of development of upstream
. This branch is called main
. We use main
as a convention to name the primary branch of development within a fork. So upstream main
is the primary branch of development in upstream
. And origin main
is the primary branch of development in your fork (remember that origin
is the default name given to your repository).
You can create additional branches of development within a repository. These branches behave like forks, but they are within a repository. For example, go back to the main page of your repository and click on the main
button. This should bring up a list of the branches, e.g.
Here you can create a new branch by typing in a name, and then clicking Create branch
. For example, let’s create a branch where we will do the work of installing the corner of the kitchen for Thompson the cat. Call the branch cat_corner
and click Create branch
.
This will create the branch and will automatically switch you to cat_corner
.
You can click on the branch name button and switch back and forth between the main
and cats_corner
branches.
Next, type the command git pull
. You should see that git will report that a new branch has been created, e.g.
From https://github.com/chrys-at-home/super_project
* [new branch] cat_corner -> origin/cat_corner
You can switch between different branches on the command line using the git checkout
command, followed by the name you want to switch to. To switch to the cat_corner
branch, type
git checkout cat_corner
You should see output similar to;
Branch 'cat_corner' set up to track remote branch 'cat_corner' from 'origin'.
Switched to a new branch 'cat_corner'
Typing git status
should also show that you are now on the cat_corner
branch, e.g.
On branch cat_corner
Your branch is up to date with 'origin/cat_corner'.
You can make changes and commit to your cat_corner
branch, and it will not affect or change your main
branch. For example, edit planning/stage1.MD
and add in a step to install an automatic cat feeder, e.g.
1. Paint the ceiling
1. Tile the walls
1. Install the counter tops
1. Install the electric oven
1. Install automatic cat feeder
1. Install the fridge
Commit and push this change (git commit -a
and git push
). You will see that this will push to the cat_corner
branch, e.g.
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 374 bytes | 374.00 KiB/s, done.
Total 4 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/chrys-at-home/super_project.git
f17f8fb..7a62c0d cat_corner -> cat_corner
If you look at the Insights
page on GitHub, you can see that this commit as a new line that has branched from main
, e.g.
We can also represent that using a “circle and line” diagram, e.g.
origin cat_corner o
/
/
origin main o-----o--o--o--o
/ /
/ /
upstream main o--o--o--o--o--o
Further commits to cat_corner
will add to this line, e.g.
origin cat_corner o--o--o--o
/
/
origin main o-----o--o--o--o
/ /
/ /
upstream main o--o--o--o--o--o
Make some more changes to planning/stage1.MD
and commit and push them to the cat_corner
branch.
Look at the network view on the GitHub Insights
page. Can you see your new commits?
It is very easy to switch between branches. Simply type git checkout BRANCH_NAME
to switch to the branch you want, e.g.
git checkout main
will switch back to origin main
. If you do this, take a look at planning/stage1.MD
. Notice how the changes you made in cat_corner
are not in this file.
Now switch back to cat_corner
by typing
git checkout cat_corner
Take a look at planning/stage1.MD
. See that your changes are restored.
Branches behave pretty much identically to forks. You can consider them as separate forks within a repository. This means that you can pull changes from one branch into another, and you can also issue pull requests from one branch to another.
For example, switch back to main
via git checkout main
. Now edit planning/stage1.MD
and add an extra line to the bottom, e.g. similar to the last line shown below;
1. Install the counter tops
1. Install the electric oven
1. Install the fridge
This is a new line added to demonstrate pulling - with some more changes
This is another line added to demonstrate pulling across branches
Commit this change (git commit -a
) and push to main
(git push
). The GitHub Insights
network graph will now look something like this;
Now switch back to your cat_corner
branch by typing;
git checkout cat_corner
We can pull this latest change that was made in main
into cat_corner
by typing;
git pull origin main
This will open a text editor showing you that the change can be automatically merged, and when you save this it will merge the change, e.g.
From https://github.com/chrys-at-home/super_project
* branch main -> FETCH_HEAD
Auto-merging planning/stage1.MD
Merge made by the 'recursive' strategy.
planning/stage1.MD | 2 ++
1 file changed, 2 insertions(+)
Double check planning/stage1.MD
- notice how the line added to origin main
has been merged into the file for origin cat_corner
.
Push this change to cat_corner
(git push
). The GitHub network graph should now look something like this;
If we wanted, we could follow a similar process to merge changes from cat_corner
into main
, e.g. git checkout main
, followed by git pull origin cat_corner
, then git push
. But we could also achieve the same thing using a pull request. If you navigate back to the main web page for your repository, you should see that GitHub has seen that cat_corner
has changed, and given you the option of making a pull request, e.g.
If you click on Compare and Pull Request
this will open up the pull request dialog. This will be pre-populated with a request to pull from origin cat_corner
into upstream main
(where origin
is your repository, and upstream
is the chryswoods
repository).
Change the base repository to be your repository (so this is a pull request from origin cat_corner
to origin main
). Note that the dialog will now change to only showing you the branch names, e.g.
Fill in the pull request message and click Create pull request
. This will create the pull request.
Next, you can merge the pull request by clicking Merge pull request
. Click this, and then click Confirm merge
. The pull request should be successfully merged and closed. At this point, there may no longer be any need for the cat_corner
branch (maybe we have finished all changes that are needed for this?). In this case, we can then delete the branch, by clicking on the Delete branch
button.
This will delete the branch. But note that the branch can be undeleted if needed (e.g. by pushing to it again), and also all of the changes made have now been pulled into main
.
If you look at the GitHub network graph, you should see that the cat_corner
branch is shown as merged into main
, and that it then stops, e.g.
We can also represent this is a circle and line diagram, e.g.
origin cat_corner o--o--o--o------o
/ / \
/ / \
origin main o-----o--o--o--o---------------o-----o
/ /
/ /
upstream main o--o--o--o--o--o
Deleting a branch on GitHub will not delete the branch locally. You can list your branches using the git branch
command, e.g.
git branch
for me prints
* cat_corner
main
The *
shows which branch you are currently on. Since we have deleted cat_corner
from GitHub, we should also delete it locally. To do this, we will first switch to the main
branch…
git checkout main
You should see printed a message telling you that your branch is behind that on GitHub, e.g.
Your branch is behind 'origin/main' by 4 commits, and can be fast-forwarded.
(use "git pull" to update your local branch)
This is because the pull request meant commits were pushed into main
on GitHub that are not reflected locally. To pull these changes, you need to run
git pull
This will pull all of the changes in GitHub to your local repository.
Next, to delete the cat_corner
branch you should type;
git branch -d cat_corner
The -d
means “delete the branch”. Again, this won’t actually delete any files, as they all still exist in the repository.
We have an additional usage of the git checkout
command for changing between branches, and git pull
for pulling changes from the remote repository (GitHub). We also have the new command, git branch
to get information about branches and to delete branches.
Git Cheat Sheet
(1) git init : Tell git to start version controlling the files in a directory
(initialises git in a directory)
(2) git status : Tell git to print the status of the files in the version
controlled directory.
(3) git add : Tell git to start monitoring (tracking) the versions of a new
file, e.g. `git add README.md` will tell git to track `README.md`
(4) git commit -a : Tell git to save a new snapshot version of all of the tracked
files in the directory. The `-a` means "all files". You can
commit new versions of individual files if you want, but this
is not recommended.
(5) git diff : Tell git to show the differences between the files in the working
directory and the last saved version in the git repository. This will
show the differences for all tracked files. Use
`git diff FILENAME` to limit to only the file `FILENAME`
(6a) git checkout VERSION FILENAME : Tell git to bring `VERSION` version of `FILENAME` into the
current working directory. If `VERSION` is `main` then
restore the last version of `FILENAME` that was saved
to the repository.
(6b) git checkout VERSION : Tell git to change the working directory back to a specific `VERSION`
number. If `VERSION` is `main`, then return the working directory to
the last saved version in the repository.
(6c) git checkout BRANCH : Switch to the branch called `BRANCH`, e.g. git checkout main will
switch to the `main` branch.
(7) git log : Print a log of the versions in the repository. Use `git log -n N`
to limit to the last `N` versions. You may need to use `q` to exit
from the text viewer if there are a lot of versions to print.
(8) git mv OLD NEW : Rename a file from name `OLD` to name `NEW`.
(9) git rm FILENAME : Remove the file `FILENAME` from the working directory (it still exists
in the repository). Will only work if the file is tracked by
git and doesn't have any changes. Use `-f` to force removal of files.
(10) git push : Push versions that are saved in the local repository (.git folder)
so they are backed up to a remote repository (.git folder)
(11) git clone URL : Clone (download) a local copy of the remote repository that is available
at the specified URL. You will only be allowed to push to that repository
if you have permission. If not, then fork the repository into your
own account before cloning.
(12a) git remote -v : Show information about all of the remotes that have been configured
for a local repository.
(12b) git remote add NAME URL : Add a new remote called `NAME` that refers to the remote
repository at `URL`, e.g.
`git remote add upstream https://github.com/chryswoods/super_project.git`
will add a remote called `upstream` that refers to the original
`super_project` URL.
(13a) git pull : Pull changes from the remote repository into the local repository.
This is the opposite of git push
(13b) git pull REMOTE BRANCH : Pull changes from the specified BRANCH of the specified REMOTE into
the local repository and merge them into the working tree. For example,
`git pull upstream main` would pull changes from the default branch
of `upstream` into the local repository. By default, REMOTE is `origin`
and BRANCH is `main`, so `git pull` will pull changes from the same
remote repository that `git push` pushes to.
(14) git blame FILENAME : Print a line-by-line view of who changed each line in a file at
which commit.
(15a) git branch : Print out information about all of the branches in a repository
(15b) git branch -d BRANCH : Delete the branch called `BRANCH`
Create a new branch in GitHub. Commit some changes. Issue a pull request from that branch to main
to pull those changes back into main
. Accept the pull request and then delete the branch. Check the GitHub network view to make sure that you can see all of these steps represented.
You can create a branch from any committed version in the repository. If you navigate to an old commit, and then create a branch, then the branch will be from that old version of the files. In this way you can revert back to an old version of the files and make edits from that point. Using branches to “edit the past” is one of the key use cases.
Equally another good use case is to create branches that refer to specific releases or versions of a project, e.g. every time you create a release you create a branch for that release. This way, you can use those branches to back-port in fixes from later versions of the code.