Notes of Maks Nemisj

Experiments with JavaScript

GIT: Learn by doing. Chapter 1

This is the second article of the series about Git. If you haven’t read the introduction, I strongly advise you to do this since this chapter will operate on the knowledge you’ve received in the intro. This time you will have to do exercises in the terminal of your choice. Most of the practices will have a bootstrap script, which will help you to set up the initial folder structure with dummy repositories and commits.

Branches without branch names

The previous chapter was an extended reading, I know, but it was needed to decouple your mind from the idea that “branch” in Git is the holy grail. Contrariwise, the branch is the last thing you should be thinking when working with Git. Putting ‘git commit’ in the first place makes working with Git a different adventure. To make this a second nature, we are going to practice in the form of small tasks, as I already mentioned before.

Task 1: Prepare the environment

To start a task, create a folder anywhere, cd into it from the console and execute a script which is below ( REMINDER: before executing any unknown script, read the content of it, to make sure it doesn’t install any malware on your system 😉 )

curl -o- | bash

or using wget if you don’t have curl

wget -qO- | bash

and one for PowerShell users on Windows:

Invoke-WebRequest -UseBasicParsing | Invoke-Expression

This script will create branch-without-branch folder as a Git repository with two branches in it. Those branches will not have any names, and if you use any Git client, you won’t see these branches yet.

If you run the bootstrap script for a second time, you will notice that hashes are different now. As I’ve already explained, hashes are unique and change every time you do things to Git. This means the hashes I have in the pictures will be different than yours.

Let’s have a look at the history of a newly created repository.

Git log of "branch-without-branch" folder
Git log of “branch-without-branch” folder

What you can notice is that there are no signs of branches in this log at all. Still, the branches are there, and this is what you’re going to find out.

One thing to note is that currently, the last commit I’m at is ee23fc10.

If a commit doesn’t have any branch name on it, it is called dangling and is not visible in git logs nor git clients. It is still available, and you can return to it by doing git checkout {{hash-of-the-commit}}

Dangling commit
Dangling commit

Task 2: Find a dangling commit

To find out which dangling commits are there you can use the git fsck command. Execute in terminal:

git fsck --lost-found

--lost-found will print all the dangling commits, except the one on which you’re currently. My dangling commit is: 906194feded708a451b92bb8b317f71e9d81d43e

Dangling commit with fsck command
Dangling commit with fsck command

The dangling commit, which shows our terminal is the second unnamed branch. This branch is not visible in the git client yet. To find out branch history and the point where it is branched from we have to checkout this commit and see the logs.

Task 3: Checkout the dangling commit

By using the git checkout command, we are going to examine this second branch (execute in a terminal and put your hash instead of mine):

git checkout 906194feded708a451b92bb8b317f71e9d81d43e

If you look now into the Git history, you can see that it’s different. It does not end anymore with Added 1.2.2 commit message but instead with Added 1.1.2.

Git log of "branch-without-branch" folder after checkout
Git log of “branch-without-branch” folder after checkout

Now we have a log of a second branch, we can create a full picture of the git history we have so far:

Both branches in the histogram
Both branches in the histogram

Task 4: Find another dangling commit

Rerun git fsck to see that you have different dangling commit, which points now to the previous branch. Mine is ee23fc1047bcce7944a7e146157d8fb93fa5554c. This is exactly the commit where I was before checkout of the first dangling commit. Execute in terminal:

git fsck --lost-found
Log of the first dangling commit
Log of first the dangling commit

Task 5: Keep committing

Now, while you’re on an unnamed branch, create a change and commit it. I will create a new file and will commit it with a message “keep committing”. This is what I have done to commit file, you can use your editor to commit changes:

touch second-file
git add second-file
git commit -m "Keep committing"

My history after I’ve made the commit:

As you can see, you can continue working on the same branch and make new commits

Task 7: Creating a new branch

But what about making a new branch? Well, that’s easy too. Remember I told you about the time machine previously? You checkout point where you want to start branching with git checkout, and you make new commits on top of that. Doing this will create a new branch line.

To start this exercise, take the first commit in your repo. For me, this is 8d348af0. Make checkout and create a new commit. Do it in your editor or use following commands for bash:

git checkout 8d348af0
touch this-is-new-branch-file
git add this-is-new-branch-file
git commit -m "This is a new branch"

History shows that we have two commits in there – the initial commit and the new one.

New branch log
New branch log

By running git fsck we can see that now we have two dangling commits, cause we have two other branches which are not visible to us. Test it in your terminal:

git fsck --lost-found
Two dangling commits, two branches

This means that in total we have 3 branches in the current git repository. The new histogram will look now like this:

Final thoughts

As you can see, branching without branch names is not a problem in Git, maybe a more cumbersome, but still possible. This is exactly what I want to make clear. Here is an analogy that might help you.

Task 6: Bucket with ping-pong balls

Imagine a bucket full of ping-pong balls enumerated in random order.

Bucket with enumerated ping-pong balls

Imagine these ping-pong balls are connected using strings, cables or anything you come up with.

Connected ping-pong balls

This bucket is a Git repository, and these ping-pong balls are commits. Numbers on these balls are commit hashes. The only difference between this analogy and Git is that while connections of ping-pong balls do not have explicit direction, the relation between Git commits has a defined direction.

One of the commits is always a parent, and the other one is a child. The parent is regularly below the child in the history you usually see in the Git log of your Git client.

Take this git history from above – commit 8d348af0 is the parent of child commit 4acd0469, and in its turn, the commit 4acd0469 is the parent of children a080d192 and 3229b166.

If a commit has two children instead of one, these are, literally, two branches. They might not have a name, they are not visible in the UI, but they are real branches. The commit without any children and a branch name on it called a dangling commit.

, ,

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.