Its been six months since I’ve been part of switching the last project still running on SVN to git. Most of the developers in the project had not yet have the luck of working with git. After introducing the team to git and answering questions over the course of the following months i’m trying to give an overview of the two most common unknown concepts in git I’ve encountered.
Following I’ll use the term “label” for concepts such as branch and tag.
The git history is a graph that contains nodes (commits) that are linked.
After checking the log of a repository you might see the following:
You can see two labels
master both pointing to the commit with the shortened hash
HEAD points to the current commit we have checked out. As a result
git checkout HEAD will never change anything as we are always already on the commit where
HEAD points to. The other label
master points to the last commit created in our master-branch.
git checkout -b new-branch it looks like this:
Now we have one more label that points to the only existing commit.
That’s all it took to create a branch. No copies necessary as in SVN.
After creating a new commit on our
new-branch the log looks like:
HEAD and the
new-branch label has moved forward.
Now we want to merge the new feature back into our master branch. We create an explicit merge commit via
git merge --no-ff new-branch
HEAD and the
master label has moved forward.
new-branch is still available as a reference to the tip of the feature branch.
Now we tag our release via
git tag v2.7
As we continue to create commits
HEAD and the branch label will move on. The tag will stay.
The difference between a tag and a branch is that a tag can’t be moved (without deleting and recreating it)
This knowledge should help dealing with questions like
If i create a tag on the commit of the tip of a branch and then delete this branch, can i go back to it?
Yes. As the branch label has just pointed to a commit so does the tag.
It states that I’m in ‘detached HEAD’ state. What does this mean?
You are on a commit that has only one label point to it (
HEAD) when you create commits now and then say check out
master again the connection to your previous commits is lost because no label points to them.
The whole references and labels concept is very nicely explained in Git For Ages 4 And Up. Don’t be quenched by the title :)
There is a fear that if should you ever type in something like
git reset HEAD~1 --hard, which deletes the commit
HEAD currently points to, is lost irretrievably. This is not true thanks to the concept of
git reflog which I’m going to showcase here:
Lets say you have created a new feature branch
awesome_feature and created the first commit in it.
Now we delete this commit via
git reset HEAD~1 --hard and realize we want to have the commit back.
After you type
git reflog you will see:
We can now go back to the state before the deletion via
git reset --hard 6a81aa2 and were back to:
Still, the full reflog will not be there forever. Git will clean it periodically.