Skip to main content

Easily understand Git Revisions, Branches and Tags

·12 mins
Recommended basics: Articles you should know

To get the full picture of this article, you should know about this topics:

Git - Distributed version control

Learn how to use Git for effective version control, track changes, and collaborate seamlessly. This guide covers essential Git commands and concepts - a perfect starting point.

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 new to Git/SCM, I highly recommend to read through this article first:

Git - Distributed version control

Learn how to use Git for effective version control, track changes, and collaborate seamlessly. This guide covers essential Git commands and concepts - a perfect starting point.

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.

Receive high-quality, ad-free updates on software development. Sign up for our free newsletter today!

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:

gitGraph commit id:"commit1" commit id:"commit2" commit id:"commit3" type: HIGHLIGHT

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:

gitGraph commit id:"commit1" commit id:"commit2" branch my-task checkout my-task commit id:"commit3" commit id:"commit4" type: HIGHLIGHT checkout main commit id:"commit5" type: HIGHLIGHT

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.

I cover git basics very detailed in this article:

Git - Distributed version control

Learn how to use Git for effective version control, track changes, and collaborate seamlessly. This guide covers essential Git commands and concepts - a perfect starting point.

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.

gitGraph commit id:"commit1" commit id:"commit2" commit id:"commit3" type: HIGHLIGHT

In this case you easily tell git to checkout commit1:

1
git checkout commit1
gitGraph commit id:"commit1" type: HIGHLIGHT commit id:"commit2" commit id:"commit3"

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.

Receive high-quality, ad-free updates on software development. Sign up for our free newsletter today!

How to create a git branch? #

At any point you can create a new branch in git:

1
git switch -c newbranch

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:

1
git switch anotherbranch

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.

Receive high-quality, ad-free updates on software development. Sign up for our free newsletter today!

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:

gitGraph commit id:"commit1" commit id:"commit2" type: HIGHLIGHT branch anotherbranch checkout anotherbranch commit id:"commit3" commit id:"commit4"

Let’s say you’re working on main which point’s to commit2, if you now run:

1
git merge anotherbranch

It will merge commit4 onto commit2:

gitGraph commit id:"commit1" commit id:"commit2" branch anotherbranch checkout anotherbranch commit id:"commit3" commit id:"commit4" checkout main merge anotherbranch id:"mergecommit" type: HIGHLIGHT

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.

IDEs integrate very well with git, they have a graphical representation for all shown features:

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.

gitGraph commit id:"commit1" commit id:"commit2" branch tmp-branch checkout tmp-branch commit id:"commit3" commit id:"commit4"

You can simply run:

1
git branch -d tmp-branch

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:

1
git branch -D 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.

Good to know:

Git - Distributed version control

Learn how to use Git for effective version control, track changes, and collaborate seamlessly. This guide covers essential Git commands and concepts - a perfect starting point.

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.

gitGraph commit id:"commit1" commit id:"commit2" tag: "my-first-tag" commit id:"commit3" commit id:"commit4" type: HIGHLIGHT

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:

1
git tag my-first-tag

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:

1
git tag -d my-first-tag

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:

1
git switch -c fix-bug my-first-tag

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.

gitGraph commit id:"commit1" commit id:"commit2" tag: "my-first-tag" branch "fix-bug" checkout fix-bug commit id:"fix-commit1" tag: "my-second-tag" checkout main commit id:"commit3" commit id:"commit4"

Remember: commit4 does not magically have the fix-commit1. Don’t forget to merge the new changes back to main.

Receive high-quality, ad-free updates on software development. Sign up for our free newsletter today!

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:

1
git switch -c my-important-branch 9afadbf

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:

1
git reflog --no-abbrev

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:

1
git switch -c my-important-branch 9afadbf84e1cefa3b19e19c42657705734a3ac61

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:

1
git tag my-important-tag my-important-branch

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:

1
2
3
4
5
6
7
GIT_COMMITTER_DATE="2024-01-01T09:00:00+02:00" \
GIT_AUTHOR_DATE="2024-01-01T09:00:00+02:00" \
  git tag \
    -a \
    my-important-tag \
    -m "my important tag" \
    my-important-branch

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.

Oliver Lippert
Author
Oliver Lippert
I pay attention to the details. I think deeply about the purpose of functions, the clarity of variable names, and the importance of commit messages. Long-term thinking is crucial. Writing code is straightforward, but projects become more challenging as they grow. With over 15 years of experience, I’ve gained insights that I apply in coding, code reviews and business discussions.