27 03 2020
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- https://raw.githubusercontent.com/nemisj/git-learn/master/branch-without-branch.sh | bash
or using wget if you don’t have curl
wget -qO- https://raw.githubusercontent.com/nemisj/git-learn/master/branch-without-branch.sh | bash
and one for PowerShell users on Windows:
Invoke-WebRequest https://raw.githubusercontent.com/nemisj/git-learn/master/branch-without-branch.ps1 -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.
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}}
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
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
.
Now we have a log of a second branch, we can create a full picture of the git history we have so far:
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
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.
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
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.
Imagine these ping-pong balls are connected using strings, cables or anything you come up with.
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.
GIT: Learn by doing. Intro GIT: Learn by doing