Easily understand Git Revisions, Branches and Tags
Table of Contents
Recommended basics: Articles you should know
To get the full picture of this article, you should know about this topics:
You may also want to use the content map to find interesting articles that play into this one.
In this article I’ll showcase the meaning of a git revision, a git branch and a git tag. You’ll understand their purpose and also see several use-cases how to work with them. I hope you found this article for learning purposes.
If you’re in a critical situation right now, all the best fixing it. I highly recommend to stay calm. This article will likely give you good input for your next decisions.
What is a git branch? #
As discussed in the article about git, it is basically a chain of single commits / revisions. Each of them have a technical unique identifier which is good for computers, but not so much for us humans.
A branch is simply a “pointer” to a specific commit / revision in git. Nothing more. This sounds silly, but source control management (SCM) is there to keep track of many parallel changes for single-person projects or projects where hundreds of people change code on a daily basis.
Single-branch example #
Let’s start straight-forward. A repository with just you working on one branch:
In this graph main
is pointing / linking to commit3
. You can “proof” that by literally looking into the branch file,
which git will save in .git/refs/heads/*
:
> cat .git/refs/heads/main
commit3
(Modified example to improve readability)
Multi-branch example #
Now let’s go a little bit more complex. A repository with just you working on two branches:
In this scenario you started working on main
, then decided to switch to a new branch my-task
, modify some code
there and then switched back to main
and continued your work over there. Now main
points to commit5
and
my-task
points to commit4
.
What is a git commit / revision? #
The whole idea of Git (and other SCMs) is to “chain” changes. Every part of this chain is a commit
or revision
. You
can see this illustrated in the graphs above (e.g. commit1
). The two words have the same meaning.
How to checkout a specific git revision? #
At some points you see yourself in a situation where you need to “travel back in time” and see your codebase in a particular state of the past. This is no problem using git. Let’s say you have three commits and temporarily need to go back to the first commit to check something.
In this case you easily tell git to checkout commit1
:
|
|
By checking out this previous commit, as you can see in this graph, the newer commits neither are removed nor does
the main
branch changes it’s pointer value. In this case main
still is pointing to commit3
.
This is why git will inform you at this point, that you’re working on a “detached head”. It basically informs you that no branch points to the current commit. This is totally fine for research, but if you want to change code, you probably create a new branch first.
How to create a git branch? #
At any point you can create a new branch in git:
|
|
You should replace newbranch
with some wording that’s meaningful to you and your upcoming work. This is simply to
remember what this branch is used for.
This command will now create the new branch for you and directly switch to it. If an branch with this name exists already, the command will fail.
How to switch between git branches? #
May you guess it already, switching between existing branches in git is nearly similar, just remove -c
:
|
|
This command will now switch to anotherbranch
. If no branch with this name exists, the command will fail.
What is “main”? #
By now you should have understood that working in git mostly means working in some branch. This opens the question “what’s the first branch in a new repository?” and “what is the default branch?”.
By default nowadays most projects go with main
as the default branch. A decade (or two) ago, it used to be master
,
may you find projects still using this identifier.
This means main
is just a default identifier used by git. If you create a new repository with git init
, you’ll
directly be working on main
branch. You’re totally free to change that. You can work in repositories that do not have
a branch called main
. It is just a name, nothing more.
How can I “combine” two branches? #
After creating a branch, working on the topic, you probably wonder how to bring together your new branch with another,
since the idea of branches is to be temporary, beside the default (main
) branch. In git this is called
“merging”.
Merging can happen with multiple “strategies”, I’ll not cover this topic in detail in this article. I plan a standalone article on this in the future.
Merging is usually easy, if there’s no conflicts. You always merge into the current branch you’re working on right now.
You always specify which other branch you want to merge. In this example, the merge will create one new commit
that
represents the merge:
Let’s say you’re working on main
which point’s to commit2
, if you now run:
|
|
It will merge commit4
onto commit2
:
In this case mergecommit
holds the information that it merges commit4
onto commit2
. The merge does not delete
anotherbranch
, which now still points to commit4
. The merge does automatically commit and let main
now point to
mergecommit
. You do not need to worry if anything goes wrong, no information ever will be lost, all commits still
exist. This way you can revert anything you do at any time.
I’ll not cover dealing with merge conflicts in this article. I plan a standalone article on this in the future.
How to delete branches in git? #
At this point it get’s interesting. If you work just locally, it’s totally easy. If you have co-workers, some additional communication is needed.
First things first: git will ensure the branch you’re about to delete is merged somewhere. This way it protects you from “loosing” anything (technically you wouldn’t loose anything). Let’s say you created a temporary branch, tested something that didn’t work and now you want to get rid of it.
You can simply run:
|
|
As long as you go by -d
(lowercase d
), git will fail since commit4
would end up without any branch or tag
pointing to it. In our scenario right now this is expected, so replace -d
by -D
(uppercase D
) and git will
delete the tmp-branch:
|
|
Read very carefully: “git will delete the branch”. Now, remember “A branch is simply a “pointer” to a specific commit / revision. Nothing more.”. It is important to understand:
By deleting a branch, you delete the pointer, not the commit.
Deleting a branch in git does not result in loss of any work. If you’ve just deleted a branch and now find yourself in a pressure situation to “recover” it, just read Can I restore an accidentally deleted branch? (yes you can).
How to delete a git branch in a team environment #
As discussed in the git basics article, one of gits benefits is decentralisation. This is now important, since we talk about deleting information. Deleting in your computer is no problem, but that doesn’t delete the information for all your team members.
If you find yourself in a situation to delete a branch within the whole team, the only way is to communicate with all parties and ask them to remove on their computer. Everything else will end up with the risk that someone, willingly or not, pushes back the branch to the repository.
What is a git tag? #
I mentioned already, that branches are meant to be temporary. But what if you have some state of your codebase, that you want to reference to permanently? A release for example? In this case you should use a git tag.
A tag is simply a “pointer” to a specific commit / revision in git. Nothing more.
In this example my-first-tag
points to commit2
.
What makes tags different from branches? #
While branches are pointers to commits and this pointer is meant to change with every new commit, a git tag is meant to stay at it’s reference forever. A git tag, in my definition, must not change, it’s permanent. It is something that I reference now or in 5 years, it’ll always give me the same result. I know that some people disagree with me on that.
How to create git tags? #
Creating tags in git is pretty easy. Checkout the branch or commit you want to tag and run:
|
|
That’s it. Git now created a tag with the name my-first-tag
pointing to the current commit.
How to delete tags in git? #
It is possible to delete git tags. It is very similar to deleting branches except that there’s no warning about “detached” commits:
|
|
Similar as for branches, this will just delete the tag on your computer, not for anybody else.
How to create a git branch from a tag? #
As said, tags are meant to not change. But what if you tagged something with a huge bug, that needs to be fixed? You simply combine the learnings of this article: tags must not change, but branches are there to change. So you simply create a new branch from that tag. The easiest way is letting git do all the work:
|
|
Now you’re working on branch fix-bug
that is exactly the codebase you had when creating the tag my-first-tag
. You
simply fix your bug, commit everything and create a new tag once everything is correct.
Remember: commit4
does not magically have the fix-commit1
. Don’t forget to merge the new changes back to main
.
Can I restore an accidentally deleted branch? #
We talked about deleting branches already. Let’s say it was late and you wanted to delete branch
but typed brunch
.
Git was warning you but as always you thought “Let me do my business you dump computer”, right? Now, brunch
was pointing to some serious work that you really need back.
First things first: Calm down. Nothing is deleted. You’r now just missing the “pointer” (see What is a git branch?).
If you still have your terminal open, you should have the commit sha already:
> git branch -D my-important-branch
Branch b2 deleted (was 9afadbf).
In this case you’re looking for 9afadbf
. Simply recreate the brnach from that ref:
|
|
In case you deleted the branch and shutdown your system, you need to be a detective now and lookup the last known
reference. Git keeps track of everything you do (just regarding your repository, for sure) and you can review
that so called reflog
:
|
|
You search for all the lines that do name your branch (my-important-branch
), for example:
9afadbf84e1cefa3b19e19c42657705734a3ac61 (HEAD -> my-important-branch) HEAD@{0}: commit: a very important commit
Now you have the commit ref, that you can use to recreate the branch:
|
|
Can I restore an accidentally deleted tag? #
For a long time I thought restoring tags an branches simply work the same way. And basically it is. You can create tags at any time using either a branch name, a tag name or a commit ref:
|
|
Technically now you have the tag my-important-tag
pointing to the current commit of branch my-important-branch
which
is 9afadbf84e1cefa3b19e19c42657705734a3ac61
as of this article. In many cases “that’s it” and your done.
That was until I realised that the tag would have the date/time of the tag creation, which is not necessarily the date/time of the commit.
Define date of the restored tag #
If you have a (not so) little monk in you, like I, you probably find yourself in a situation where you wan’t to overwrite some information while creating a git tag. Gladly, this is totally possible, using “annotated” tags.
Instead of git tag my-important-tag
you add -a
to it: git tag -a my-important-tag
, now you also need to set a
“message” for the tag (like for commits) and using GIT_COMMITTER_DATE
and GIT_AUTHOR_DATE
environment variables,
you can overwrite the date information as well:
|
|
I used a multiline command for better readability.
Now you’d see a tag my-important-tag
that was created at JAN 1st of 2024 pointing to the current commit of branch
my-important-branch
which is 9afadbf84e1cefa3b19e19c42657705734a3ac61
as of this article.
Why restoring tags technically is different from branches #
The key difference is that branches just are names, tags hold additional information like date/time but also the author of the tag.
Conclusion - git branches / tags are very handy #
As you can see, git is not safely handle your code changes, but also how you interact with it. You need to use it, to improve your understanding of the several aspects.
Now it’s time to get your hands dirty.