After the success that my first post achieved, I decided to write this post to help my readers understand even more the concepts behind git. If you didn’t read my first post you can click in the next link:

In the previous article I showed how git how git works under the hood. In this post I will interactively travel in a git graph, just to show you how sometimes we put restrictions to ourselves without realising the simplicity and freedom that git provide us.

Let’s get our hand dirty

Initialising our git project:

> mkdir git-time-travel

> cd git-time-travel

> git init

Initialized empty Git repository in /Users/bullian/git-time-travel/.git/

Creating 1 file:

> echo "line 1" > file.txt

Checking the status of our project:

> git status On branch master No commits yet Untracked files:

(use "git add <file>..." to include in what will be committed) file.txt nothing added to commit but untracked files present (use "git add" to track)

We can see that we are on the branch master, no commits done until now and our file is untracked by git at this moment, the same is to say that git doesn’t have any version of this file yet in his repository.

To commit a file we have to explicitly add it to the staging area. Some users that had changed from svn to git may think that this step is unnecessary, but the reality is that it puts you on a position where you control everything that is versioned in your project.

We are going to add and commit the file we just created, then we are going to commit 4 more versions adding 1 more line to the file for each commit.

> git add file.txt

> git commit -m "Add first line" > echo "line 2" >> file.txt

> add file.txt

> git commit -m "Add second line" > echo "line 3" >> file.txt

> add file.txt

> git commit -m "Add third line" > echo "line 4" >> file.txt

> add file.txt

> git commit -m "Add fourth line" > echo "line 5" >> file.txt

> add file.txt

> git commit -m "Add fifth line"

We end up with a graph like this:

Reading a commit with git checkout

In the last article I highlighted the fact that the git repository is a database. Like every database you can perform a read operation without side effects. Say I want to see how the file was in the third commit (fd3f55a):

> git checkout fd3f55a Note: checking out 'fd3f55a'. 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 performing another checkout. If you want to create a new branch to retain commits you create, you may

do so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name> HEAD is now at fd3f55a Add third line

Like the feedback indicates, every change you make here will not impact any branch. Let’s look at the content of the file:

> cat file.txt line 1

line 2

line 3

And finally let’s look how the git graph is right now:

The only thing that changed here was the HEAD reference, that now is pointing to the third commit. If you execute git log, you will only see the first 3 commits, if you want to see all the commit execute git log — all.

Just for fun, let’s perform an hard reset, and then checkout master to see if it changes anything:

> git reset --hard HEAD~1

> git checkout master

> git log --pretty --graph * 2047343 - (HEAD -> master) Add fifth line (18 minutes ago) <bullian>

* 0eb8dca - Add fourth line (18 minutes ago) <bullian>

* fd3f55a - Add third line (19 minutes ago) <bullian>

* f7a6649 - Add second line (20 minutes ago) <bullian>

* 25b346f - Add first line (20 minutes ago) <bullian>

Not even an hard reset over a detached HEAD impacts a branch.

Once you achieve a state you can recover it

Let’s use now the git reset hard on a branch and pretend that after the git reset we realised that we made a big poo.

Do you have something to worry about?

Absolutely nothing.

Let’s see:

> git checkout master

> git reset --hard HEAD~3 #reset master to 3 commits before

The graph now will look like this:

Oh my god what a big pile of 💩, it was a mistake I just wanted to visit this node. Nothing to worry about we just need to make a git reset back to the right commit. But you don’t have always access to this git graph and your project may be so big that you cannot realise what was the previous commit your branch was pointing to.

What can we do?

Use reflog is the answer. It lists each command you made and references the commit the branch was referencing after the execution. In our situation we want the command before the reset so:

> git reflog f7a6649 (HEAD -> master) HEAD@{0}: reset: moving to HEAD~3

2047343 HEAD@{1}: checkout: moving from f7a66499ba191d86a6c5e5e1a8542ff9e221e02b to master > git reset --hard HEAD@{1} > git log --pretty --graph * 2047343 (HEAD -> master) Add fifth line

* 0eb8dca Add fourth line

* fd3f55a Add third line

* f7a6649 Add second line

* 25b346f Add first line

(END)

We have our branch back.

I hope you enjoyed

Kind regards

Henrique Mota