Time travel

Marie-Hélène Burle

training@westgrid.ca

Time travel

Time travel

Looking at the past without travelling

git log

 →  Overview of project history

git show

 → Information about Git objects such as commits

Travelling through history

 →  Move the HEAD pointer

Working directory & index get updated to match the snapshot pointed at

 →  Your project is back at the state in which it was when you made that commit

Before:

Travelling through history

 →  Move the HEAD pointer

Working directory & index get updated to match the snapshot pointed at

 →  Your project is back at the state in which it was when you made that commit

After:

Moving HEAD

Identify the commit we want to move to

With git log

With the ~ notation:

HEAD~ or HEAD~1 is the main parent of the commit HEAD is pointing to

HEAD~2 is the main parent before that

HEAD~3 refers to the 3rd commit before the current commit

etc.

Moving HEAD

You move HEAD with git checkout:

git checkout <commit-hash>

This is great to look around, then go back to the “present” with:

git checkout main

Moving HEAD

Starting point:

Now, we move HEAD to the commit 31fukv1:

git checkout 31fukv1

Detached HEAD

HEAD is not pointing at a branch anymore: it is pointing directly at a commit  →  detached HEAD state

Your files are back at their state when you created commit 31fukv1

Detached HEAD

You can look at your project at that point in its history, then go back to the “present” with:

git checkout main

And that’s that.

Creating commits from a detached HEAD

Now, when you are at commit 31fukv1, maybe you want to try something

But when you come back to “the present”, those experiments will get lost

So what if you want to keep those changes?

Here is what happens if you make a commit:

Creating commits from a detached HEAD

You can make more commits:

The thing is that you are still in this detached HEAD state. HEAD is not pointing to a branch as it normally is.

Is this a problem?

Bad workflow

It becomes a problem if you checkout main from there:

If you don’t care about those commits, all is good.

But if you want to keep them, this is a bad situation because those commits are now left behind: they are not in the history of any branch or tag.

Bad workflow

This is bad for three reasons:

  • Those commits will not show when you run git log, so it is easy to forget about them

  • It is not easy to go back to them because there aren’t any tag or branch that you can switch to

  • The garbage collection (which runs every 30 days by default) will delete commits which are not on any branch or tag. So you will ultimately loose them

Good workflow

Here is a proper workflow if you have created commits from a detached HEAD state

Good workflow

First, create a new branch:

Good workflow

Only then can you safely checkout main:

The commits 23f481q and rthy7wg are now on a branch. They are part of the project history, they will not get deleted. All is good.

Recovering commits left behind

What if you left commits behind (not on a branch)?

You can retrieve their hash by running:

git reflog

This tracks the position of HEAD over time

You can then checkout the commit you care about (so you are going back to a detached HEAD state):

git checkout <hash-abandonned-commit>

This puts you back into a situation where you can rescue the commit(s) by creating a branch

Do this as soon as possible

Questions?