Branching
Last updated on 2026-03-02 | Edit this page
Overview
Questions
- What are branches?
- Why use branches?
- How can I switch between branches and commits?
- Comparing commits on a branch
Objectives
- What branches are and why they are used
- Switching branches and commits
- Comparing branches/commits
- Stashing commits
Branches
Branches are key to working with version control as they allow the
development of new features or fixing of bugs without touching the
current working version of code. New features and bug fixes are then
merged into the main branch to update the code base, but
what is a branch?
The word suggests an analogy with trees where branches are parts of a tree that extend from the “main” trunk or recursively from parent “branches”. An intuitive model of this is shown in the figure below.
%%{init: {'theme': 'base', 'gitGraph': {'rotateCommitLabel': true}
}
}%%
gitGraph
accTitle: Simple Git Branches
accDescr {Basic GitHub Branches with the main branch showing five commits and a branch forking off at the
third commit with two commits of its own.}
commit id: "0-472f101"
commit id: "1-51816d6"
commit id: "2-6769ff2 (base)"
branch "branch"
commit id: "3-8c52dce"
checkout main
commit id: "4-8ec389a"
checkout "branch"
commit id: "5-2315fa0 (HEAD)"
checkout main
commit id: "6-93e787c (HEAD)"
The branch has two commits on it and stems from the
parent main at a point referred to as base. A
branch is not just the two commits that appear to exist on it
(i.e. 3-8c52dce and 5-2315fa0) rather it is
the full commit history of that lineage including the commits in the
“parent”. That means the branch consists of the commits
0-472f101, 1-98f9a30 and
2-6769ff2 as well as 3-8c52dce and
5-2315fa0.
In a repository that is version controlled you will typically be
checked out on the HEAD of a named branch. The
HEAD means the most recent commit in the history of that
branch which on the branch is commit 5-2315fa0
whilst on main the HEAD is
6-93e787c.
You can change branches by using
git switch <branchname>.
Challenge 1: What is the first and last commit
on branch divide?
Using the python-maths repository you have cloned edit
the .git/config as shown below and fetch the
divide, multiply and
ns-rse/branches.
BASH
[remote "upstream"]
url = git@github.com:ns-rse/python-maths.git
fetch = +refs/heads/*:refs/remotes/upstream/*
Fetch the branches from upstream with the following
BASH
git fetch upstream {divide,multiply,ns-rse/merge-conflict}
git checkout --track upstream/divide
Now look up the first and last commit of the divide
branch.
What are the commit hashes, commit messages, date and committers’ names?
BASH
git switch divide
git lol
* 6353fb4 2024-03-26 (HEAD -> divide, upstream/divide, origin/divide) bug: Fix tpyo in divide function [Neil Shephard]
* 7485e56 2024-03-26 chore: Fix merge conflict [Neil Shephard]
* adfef4d 2024-03-25 feat: Divide branch [Neil Shephard]
* 400896a 2024-03-25 Divide branch [Neil Shephard]
* c1f64b0 2024-02-02 Setting up the repository for git-collaboration [Neil Shephard]
* fa76751 2023-10-19 Merge pull request #6 from RSE-Sheffield/ns-rse/5-setup-clean-up [GitHub]
|\
| * c8f0697 2022-10-04 5 | Removing comment from setup.cfg [Neil Shephard]
* | aff8153 2023-01-20 Merge pull request #7 from RSE-Sheffield/subtract-mistake [GitHub]
|\ \
| |/
|/|
| * a45a8dd 2023-01-20 introduce mistake in subtract issue [Robert (Bob) Turner]
| * 604a397 2022-12-21 introduce delibarate mistake [Robert (Bob) Turner]
|/
* f06c0ab 2022-06-07 Merge pull request #4 from RSE-Sheffield/simplify_deliberate_errors [GitHub]
|\
| * f55c0d2 2022-05-06 remove missing colon and no newline deliberate errors [David Wilby]
|/
* 5c9ae75 2021-05-18 correct python testing instruction [Anna Krystalli]
* 86d7633 2021-05-18 add correct details to each issue [Anna Krystalli]
* a58d6e7 2021-05-17 add all github issue templates [Anna Krystalli]
* 9429ab4 2021-05-14 complete subtract issue template [Anna Krystalli]
* bb560b0 2021-05-14 simplify function [Anna Krystalli]
* 325d038 2021-05-14 Merge pull request #1 from RSE-Sheffield/tests_changes [GitHub]
|\
| * 608ad59 2021-05-14 Restructure so tests pass [Will Furnass]
|/
* 8584b0f 2021-05-14 correct pull request branch spec [Anna Krystalli]
* cdc9ea3 2021-05-14 correct push branch specification [Anna Krystalli]
* c01ff62 2021-05-14 add instructions to README [Anna Krystalli]
* 585287a 2021-05-14 add test and CI [Anna Krystalli]
* 3f4d54b 2021-05-14 rename python_package folder [Anna Krystalli]
* 4b1707b 2021-05-14 use requirements.txt instead of env.yml [davidwilby]
* 2556966 2021-05-14 remove build specs from conda env [davidwilby]
* b50e658 2021-05-14 move env.yml to right place.. [davidwilby]
* 0d2f520 2021-05-14 Merge branch 'main' of github.com:RSE-Sheffield/python-calculator into main [davidwilby]
|\
| * b1179a7 2021-05-14 add package name folder [Anna Krystalli]
* | c883789 2021-05-14 add conda environment yaml [davidwilby]
|/
* fdb8716 2021-05-14 draft commit [Anna Krystalli]
* 328e61b 2021-05-13 Add subtraction issue template [GitHub]
* 31a4a93 2021-05-13 Initial commit [GitHub]
From the git log graph we see the first and last commits
were:
| Commit | Hash | Message | Date | Committer |
|---|---|---|---|---|
| First | 31a4a93 | Initial commit | 2021-05-13 | Anna Krystalli |
| Last | 6353fb4 | bug: Fix tpyo in divide function | 2024-03-26 | Neil Shephard |
Challenge 2: What commit did the
multiply branch diverge from main ?
Again using the python-maths repository switch to the
multiply branch.
Use git log --graph --pretty to find the commit at which
multiply diverged from main. How many commits
have been made on the main branch?
Hint You will need to find
ns-rse/multiply in the commit messages and follow the line
backwards.
BASH
git switch main
git lol
...
* ba7a5da 2024-04-24 bug: ISSUE_TEMPLATES > ISSUE_TEMPLATES [Neil Shephard]
* ae5402f 2024-04-23 Merge pull request #3 from ns-rse/multiply [GitHub]
|\
| * b702501 2024-03-26 (upstream/multiply, origin/multiply, multiply) bug: multiply instead of add arguments [Neil Shephard]
| * 11e36a3 2024-03-26 feat: Adding multiply function and tests [Neil Shephard]
* | 12a159c 2024-04-23 Merge pull request #2 from ns-rse/divide [GitHub]
|\ \
| * | 6353fb4 2024-03-26 (upstream/divide, origin/divide, divide) bug: Fix tpyo in divide function [Neil Shephard]
| * | 7485e56 2024-03-26 chore: Fix merge conflict [Neil Shephard]
| * | adfef4d 2024-03-25 feat: Divide branch [Neil Shephard]
| * | 400896a 2024-03-25 Divide branch [Neil Shephard]
| |/
* | f8dcc8d 2024-03-15 Merge pull request #1 from ns-rse/ns-rse/initial-setup [GitHub]
|\ \
| * | a4b1bb4 2024-03-15 Min Python version >= 3.10 to align with workflow [Neil Shephard]
| * | 4f5daa2 2024-03-15 Quoting Python versions and adding os matrix to workflow [Neil Shephard]
| * | 74e909b 2024-03-08 Issue template for amend and fixup of square_root function [Neil Shephard]
| * | bffc993 2024-03-07 Issue template for amend/fixup on zero-division branch [Neil Shephard]
| * | 44c70e6 2024-02-02 Tidying .pre-commit-config.yaml| [Neil Shephard]
| |/
| * c1f64b0 2024-02-02 Setting up the repository for git-collaboration [Neil Shephard]
|/
* fa76751 2023-10-19 Merge pull request #6 from RSE-Sheffield/ns-rse/5-setup-clean-up [GitHub]
|\
...
This is a little more challenging to interpret but reading the output
carefully we have an indicator of where the multiply branch
was merged and We can trace that line back to the furthest left branch
(which is main and origin/main).
We can see that the multiply branch diverged from the
fa76751 commit on main and that two commits
have been made on the multiply branch.
switch v’s
checkout
git switch was introduced in Git
v2.23.0 along with git restore to provide two separate
commands for the functionality that was originally available in
git checkout. git checkout still exists and
allows you to which could “switch” branches, including creating branches
using the --branch/-b flag, and change
(“restore”) individual files with
git checkout [treeish] -- <filename> (more on this
later).
Splitting this functionality means that git switch is
solely for switching branches (including creating them with
the -c flag) whilst git restore is solely
concerned with restoreing files but it is destructive,
i.e. you can lose work, and we will cover its use later the
git revert command as an alternative.
git checkout has not been deprecated though and is still
available and many people still use it as old habits die hard.
Working with Branches
The git switch command is the common method for working
with branches. It allows you to create and switch between branches along
with a few other tasks.
To list the branches that are available you can just type
git branch or optionally include the --list
option. In the python-maths repository you have cloned you
should see a number of branches listed. The branch you are currently
checked out on is listed first with an asterisk (*) at the
start and they are by default listed alphabetically (you may remember
during the introduction there was a suggestion to change the
configuration to use -commitdate which lists them in
reverse chronological order of the most recent branch first).
Creating Branches
You can create a new branch using
git switch -c <new_branch>. By default it will use
the branch you currently have checked out as a basis for the new branch.
If you wish to use a different branch as a basis you can do so by
including its name before the name of the new branch.
To create a new branch called ns-rse/test you can use
the following.
Git will use the current HEAD of the main
branch as a basis for creating the ns-rse/test branch.
Starting off up-to-date
Most of the time when creating branches you should do so from the
main branch. It is therefore important to make sure your
local copy of the main branch is up-to-date. Before
creating a branch you should switch to the main branch and
ensure it is up-to-date.
This means you can omit the explicit statement of which branch you
wish to use as the basis for the new branch, typically
main, when creating it as you will be already be checked
out on that branch when git pull.
Naming Branches
Branch names can not include spaces, you should use underscores or
dashes instead. You can include some special characters too but I would
avoid using # as this is the character used by most shells
to indicate a comment and you would therefore have to always
double quote the branch name at the command line.
A useful convention when creating branches is to include some meta
data about who owns the branch and what it is for and to construct the
branch name from your GitHub/GitLab username followed by a
/. Because you will typically be working on a particular
issue then including the issue number followed by a short few words
which describe the work or issue can make it easy for others (including
your future self) to find out more information about the branch and why
the work has been undertaken. For example GitHub user
ns-rse working on issue 1 to fix typehints might create a
branch called ns-rse/1-fix-typehints from main.
This structure is informative as it provides other people you collaborate with or who look at the repository an indication of who created the branch, what issue they are working on and a very short indication of what it is concerned about. With this information it is very easy to look up the relevant Issue and find more details.
Challenge 3: Assign Issues, Create Branches and Complete the Tasks
In the python-maths repository you have cloned and setup
on GitHub there are issue templates.
In your pairs assign the
01 Add zero division exception and test to one person and
the 02 Add a square root function and test to the other
person.
Work through the tasks adding the necessary code, saving, staging and
committing your changes then pushing to origin (GitHub).
The issues contain all the code you need and it can be copy and
pasted into files.
NB Please note the comment about holding back on merging the Square Root work, there will be conflicts that need resolving.
Assign the person who worked on the Square root function to review the Zero Division exception and if everything looks good merge the pull request.
BASH
git switch main
git pull
git switch -c ns-rse/4-square-root
# MAKE EDITS AS DESCRIBED IN THE GITHUB ISSUE
git add -u
git commit -m "Adds square root function"
git push
You should not have created a pull request, if you have you may find that there are conflicts which need resolving. This is by design and we will resolve them later.
Deleting branches
Branches are typically short lived as they are created to address
small focused pieces of work such as fixing a bug or implementing a new
feature before being merged into the main branch. Over time
you will accrue a number of redundant, out-dated branches and it is
therefore good practice to delete unwanted branches after they have been
merged.
You can not delete a branch you currently have checked out so you
must first checkout an alternative branch. Typically this would be the
main branch after your Pull Request has been merged and the
changes you were working on have been incorporated. You should
git pull the main branch after merging changes
so your local copy is aware of any recent merges from branches you are
about to delete.
Challenge 4: Delete a branch
Create a throw away branch from main and then delete it
(hint see git branch --help). You can create a branch with
your username and throwaway
(e.g. ns-rse/throwaway) with the following.
Pretending the branch you just created has been merged into the
main branch via a Pull Request delete the now redundant
branch (in this example ns-rse/throwaway).
Force branch deletion
You were able to delete the branch you created because you hadn’t
made any changes to it. If you have made changes on a branch and they
have not been merged into main then Git will warn you of
this and refuse to delete the branch. This can be over-ridden with the
--force flag or the shorthand -D which is the
same as --delete --force.
BASH
git switch -c ns-rse/throwaway
touch test_file
git add test_file
git commit -m "Adding test_file"
git switch -
git branch -d ns-rse/throwaway
error: the branch 'ns-rse/throwaway' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D ns-rse/throwaway'
hint: Disable this message with "git config advice.forceDeleteBranch false"
git -D ns-rse/throwaway
Be very careful when forcing deletion of branches, if you
have not pushed your changes to the remote origin then you
_will_lose them.
Challenge 5 : Automatically delete branches on GitHub
In your pairs navigate to the Settings page on the repository owners account and enable the Automatically delete head branches option. Hint - Search GitHub documentation for how to automatically delete branches.
This option is on the Settings > General page under the Pull Requests section where you can select “Automatically delete head branches”.
Time Travelling - Losing your HEAD
A branch is a history of commits and you can use git log
to see the commit history (and customise the output to make it easier to
read as we have already done), but what if you wanted to look at the
state of the branch at a previous point in time? Well because Git has
kept track of everything you can do that and the command to do so is
git checkout which takes a “reference” as an argument. So
far you have been using branch names as references but commit hashes are
also references and so can be used to checkout the state of the
repository in the past.
%%{init: {'theme': 'base', 'gitGraph': {'rotateCommitLabel': true}
}
}%%
gitGraph
accTitle: Simple Git Branches
accDescr {A linear Git History on the main branch showing the position of HEAD.}
commit id: "0-472f101"
commit id: "1-51816d6"
commit id: "2-6769ff2"
commit id: "3-8c52dce"
commit id: "4-8ec389a"
commit id: "5-2315fa0"
commit id: "6-93e787c"
commit id: "7-bc43901"
commit id: "8-a80cef8" tag: "HEAD"
Here we have a simple linear history and the HEAD of
branch is on commit 8-a80cef8 If you want to checkout
commit 4-8ec389a then you would
git checkout 4-8ec389a and you will see the following
useful and informative warning message.
BASH
git checkout 4-8ec389a
Note: switching to 4-8ec389a'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 4-8ec389a complete subtract issue template
Have you lost your head because it is now detached? No,
HEAD is just a special reference that points to a specific
commit (tags are the same) and it is a short hand way of referring to a
commit, what has happened is that Git has moved the commit
HEAD points to from 8-a40cef8 to
4-8ec389a. If you make changes to this branch they will be
lost when you switch back to the 8-a40cef8 commit and you
are told you can do this with git switch -. If you want to
make changes and save them from commit 4-8ec389a you are
advised to create a new branch to do so.
Work in Progress
If you try to git checkout whilst you have unstaged
changes you are likely to hit an error about changes being
overwritten.
BASH
error: Your local changes to the following files would be overwritten by checkout:
README.md
Please commit your changes or stash them before you switch branches.
Aborting
This is to be expected, here the README.md file has
changed but those changes have not been staged and committed and if we
checkout another commit or branch the state of the
README.md will be reverted. Without committing or stashing
the changes as advised Git would not be able to revert back to the
changes you have made.
We’re going to cover switching branches whilst working later on.
Challenge 6: Checkout old commits
- Look at the history of the
python-mathsrepository and find out who the author of commit585287awas (there are several ways of doing this). - Checkout this commit and look at the contents of the file
tests/test_add.py(you can usecat tests/test_add.py). - Switch back to
HEAD, has anything changed in thetests/test_add.pyfile?
You could query the logs for the specific commit and it will show you the history from there.
BASH
git log 585287a
commit 585287aec5d94b10d03ae8fd35ad0423b2c1b0db (HEAD)
Author: Anna Krystalli <annakrystalli@googlemail.com>
Date: 2021-05-14 12:38:09 +0300
add test and CI
Alternatively you can checkout the specific hash and use
git log to look at who made the commit.
BASH
git checkout 585287a
git log
commit 585287aec5d94b10d03ae8fd35ad0423b2c1b0db (HEAD)
Author: Anna Krystalli <annakrystalli@googlemail.com>
Date: 2021-05-14 12:38:09 +0300
add test and CI
We can see it was made by
Anna Krystalli <annakrystalli@googlemail.com> on
2021-05-14 12:38:09 +0300.
BASH
cat tests/test_add.py
import src.python_calculator.add as add
def test_add():
assert add.add(1, 3) == 4
git switch -
cat tests/test_add.py
cat: tests/test_add.py: No such file or directory
The file tests/test_add.py has an import statement and
defines the test_add() function which checks if the
add.add() function returns the value of 4 when given the
numbers 1 and 3.
The tests/test_add.py file no longer exists on the
HEAD of the main branch!
Checkout Anything
You are not restricted to switch to commits on the same branch you are currently on. You can checkout any commit in the history as long as you know the commit hash.
Comparing References
This is quite a convoluted way of comparing branches though and in this instance the difference is quite simple the file no longer exists, but imagine you wanted to compare a file between branches or commits without having to switch branches and try and hold in your head what the file looked like on one branch whilst you look at the other. That would probably be very challenging.
Fortunately Git can help you here with git diff. This
takes one or two arguments, which are commits or references that you
want to compare. If only one argument is given it compares the currently
checked out commit to the supplied commit/reference.
Thus to compare the HEAD of the divide
branch you would
BASH
git switch ns-rse/1-zero-divide-exception
git diff 585287a
# Equivalent to...
git diff HEAD 585287a
If you want to limit this to a specific file use the
-- <file1> <file2> option.
Ooops! I Did It Again
Nothing to do with Britney Spears but you are at some stage likely to
commit changes to the wrong branch. This can easily happen when starting
to work on an issue without first creating a new branch to contain the
work and you commit the changes to either the main branch,
which is often protected so you won’t be able to push your changes, or
the last branch you were working on.
git reset
One way to solve this with Git is to git reset the
branch to which you have just mistakenly made the commit. This removes
reference to the changes from the Git history but leaves the changes to
the files in place and they appear as unstaged files. It is
ideal if you have only one commit you wish to
reset.
Relative Refs
Normally you are working on the HEAD of a branch which
is the most recent commit that has been made along with any staged, but
uncommitted changes. Git has a simple way of referring to previous
commits relative to HEAD using the ~ (tilde)
character and counting backwards.
%%{init: {'theme': 'base', 'gitGraph': {'rotateCommitLabel': true}
}
}%%
gitGraph
accTitle: Simple Git Branches
accDescr {Relative references on the main branch with 9 commits showing the commit hash and the reference relative to the HEAD.}
commit id: "0-472f101" tag: "~8"
commit id: "1-51816d6" tag: "~7"
commit id: "2-6769ff2" tag: "~6"
commit id: "3-8c52dce" tag: "~5"
commit id: "4-8ec389a" tag: "~4"
commit id: "5-2315fa0" tag: "~3"
commit id: "6-93e787c" tag: "~2"
commit id: "7-bc43901" tag: "~1"
commit id: "8-a80cef8" tag: "HEAD"
If you want to undo the last commit then you can do this
using git reset HEAD~1.
reset options
There are three options to git reset that influence how
the changes in commits are handled, these are --soft,
--mixed (the default) and --hard.
For a detailed exposition of git reset see the excellent
Atlassian
| Git reset article.
Challenge 7: Commits on the wrong branch
- Switch to the
mainbranch of thepytest-mathsrepository. - Create a new file using
echo -e "# This is TODO list" > TODO.md - Stage and commit the file to the
mainbranch of your repository. NB to do this you may have to disable thepre-commitchecks with the-nflag, i.e.git commit -n.
Ooops you’ve just committed to the main branch which is
protected so you can’t push your changes. Now move the commit to a new
branch so you can push them.
- Reset the change.
- Create a new branch called
<github_user>/todo. - Stage and commit the file to
<github_user>/todo.
You can git reset --mixed to HEAD~1,
i.e. the previous commit, which removes the CONTRIBUTING.md
file from the commit history, leaving it unstaged, then create a new
branch and add it to that.
Alternatively you can checkout the previous commit before
you added the file by mistake, create the
<github_user>/contributing branch, and
git cherrypick the commit from main which
contains the CONTRIBUTING.md file and then remove
the commit from main.
BASH
git switch main
echo -e "# This is a TODO list" > TODO.md
git add TODO.md
git commit -n -m "docs: Adding a todo file"
git log # Note the commit of the mistaken hash
git checkout HEAD~1 # Checkout the previous commit on the main branch
git switch -c ns-rse/todo
git cherrypick <hash>
git switch main
git reset --hard HEAD~1
git revert
git reset is destructive, you can lose work using it and
it is advisable not to use it when you have more than one
commit you wish to undo as you lose the intermediary work between
commits as you are restored to the commit you are resetting to.
Fortunately Git has the revert option which is a
non-destructive approach to undoing changes in your Git history. Instead
it takes a specified commit and inverts the changes, i.e. goes back to
the previous state and rather than discarding the changes it makes a new
“revert” commit to record the inversion. This new “revert” commit
becomes the HEAD of the branch. git revert
has to have a reference in order to work, whether that is
absolute (i.e. a hash) or relative.
reset v’s revert
The differences between reset and revert is
that one (reset) is destructive and loses changes the other
(revert) undoes the changes and makes a new commit
recording these changes.
Be very careful when using reset, if you have
not pushed your changes to the remote origin then you will
lose them.
Switching Branches during Work in Progress
Sometimes you will be doing some work and a colleague will ask you to review a pull request or help them with a problem they have on their branch. When performing pull request reviews it can be quite common to run tests to check everything passes if you don’t have Continuous Integration doing this automatically for you (we will come to that in another episode).
But there is a challenge, in order to switch branches you have to stage and commit all changes to tracked files.
BASH
git switch -c branch2
echo -e "\nAny questions please feel free to get in touch\n" >> CONTRIBUTING.md
git add CONTRIBUTING.md
git commit -m "Adding CONTRIBUTING.md"
echo -e "\nPlease don't break my repository though!" >> CONTRIBUTING.md
git switch main
error: Your local changes to the following files would be overwritten by checkout:
CONTRIBUTING.md
Please commit your changes or stash them before you switch branches.
Aborting
Whilst you could git commit --ammend, use
--fixup or rebase -i to commit your changes
there is another option.
git stash
git stash allows you to save your current changes in a
temporary location and then reverts to the last commit
(HEAD). This allows you to move about
(git switch) to other branches and undertake work. There
are lots of options to git stash but the basics are pretty
straight-forward. You start by git stash push (the
push is actually optional) and you can include a
--message that explains what the stash contains, you are
told if this has worked and on what branch the stash was made and can
then switch branches, pull down changes, create a new branch and do
something different.
2. Switch to main and create branch3
Undertake the work that is required on branch3,
e.g. making changes to the README.md.
3. Return to branch2
When you have finished this other work can return to
branch2 and pop the stash back. To see what
stashes there are you can use git stash list
4. pop the last stash
When you are ready to restore the work you can do so using
git stash pop which by default will restore the
last stash.
BASH
git stash pop
On branch branch2
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (13c8c6fb23f9fcdd884b4528356db37527c9b3e4)
The changes to CONTRIBUTING.md and the corresponding
entry are removed from the stash list.
Multiple Stashes
Over time you may collect multiple stashes.
1. Make two stashes
We stash CONTRIBUTING.md, the last message is reused by
default, then we add ANOTHER.md and stash it with a
different message.
2. Pop the CONTRIBUTING.md stash
There are now two stashes each with different names.
You may not want to restore the work stashed with the commit message
WIP ANOTHER.md file but rather restore the earlier
WIP CONTRIBUTING.md file work first. You can do this by
referring to the number associated with the stash that is within the
curly braces. For the WIP CONTRIBUTING.md file stash this
is 1.
BASH
git stash list
git stash pop 1
On branch branch2
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{1} (dd538beb8f14590f720e9b9f677ba7381240bd92)
Only the CONTRIBUTING.md file has been restored and not
the ANOTHER.md and there is only one stash left.
BASH
git stash list
stash@{0}: On example-stashes: WIP ANOTHER.md file
ls -lha CONTRIBUTING.md ANOTHER.md
ANOTHER.md: No such file or directory (os error 2).
.rw-r--r-- neil neil 0 B Thu Feb 13 13:36:29 2025 CONTRIBUTING.md
Challenge 7: Stashing
Working in your pairs on the python-maths
repository…
- Create a
<github-username>/todobranch. - Create a
TODO.mdwithecho -e "# This is a ToDo List\n\n1. Task1\n2. Task2." > TODO.md - Do not add and commit, instead
git stash -m "WIP : adding TODO.md"your changes - Switch to the
mainbranch and create a<github-username>/citationbranch. - Add a basic
CITATION.cffwithecho -e "cff-version: 1.2.0\ntitle: Python Maths Package\ntype: software" > CITATION.cff - Add and commit this file.
- Unstash the
TODO.mdfile on thecitationbranch. - Stage and commit the changes. Do NOT create a pull request or merge these changes.
- Delete the branches locally (try and avoid any messages telling you
there are unmerged changes, see
git branch --helpon how to force deletion of unmerged branches).
Lets create the <github-username>/todo branch
BASH
git switch main
git pull
git switch -c <github-username>/todo
echo -e "# This is a ToDo List\n\n1. Task1\n2.Task2." > TODO.md
If we want to switch branches without making a commit but save our
work in progress we stash the work and switch to main and
before creating a new branch
(<github-username>/citation) for adding a
CITATION.cff file.
BASH
git stash -m "WIP : adding TODO.md"
git switch main
git switch -c <github-username>/citation
echo -e "cff-version: 1.2.0\ntitle: Python Maths Package\ntype: software" > CITATION.cff
git add CITATION.cff
git commit -m "doc: Adding a CITATION.cff"
We now unstash the WIP : adding TODO.md stash to this
branch and commit the changes, amending the commit and push to
GitHub.
You can now make a pull request to merge these changes, assign it and
have it reviewed and merged. Once merged we can switch to
main, pull the merged branch and force delete the two
branches we created locally.
Popping around and applying
You can git stash apply to pop a stash but
leave it in the stash list. This might be useful if you want to apply
the stashed changes to several branches you are working on.
There are a lot of useful things git stash can be used
for. Refer to the help pages (git stash --help) for more
information as well as the Further Resources.
References - a revelation
Whilst we have focused on consolidating our understanding of branches in this introductory episode there have been hints as to the true nature of branches in Git, have you worked out what this is yet?
Internally Git does not have branches at all! Branches are merely a reference to a series of commits and each commit in a “branch” references the commit prior to it. In fact everything in Git that allows us to look at the different states of the repository and move between them is a reference, whether that is a named branch, or a tag which is a relative reference. They all point to a commit.
This was a revelation that came to me as I wrote the material for this Episode and thought it worth sharing.
- Branches and how they relate to each other are fundamental to collaborating using Git.
- The history of a branch is a series of commits and extends all the way back to the very first commit and not the point at which it forked from its parents.
- Branches can be easily created, merged and deleted.
- Commits all have references and Git can move you between these
references using
git commitor compare them usinggit diff.