Showing posts with label GIT Detached HEAD. Show all posts
Showing posts with label GIT Detached HEAD. Show all posts

Thursday, 8 August 2019

GIT: WHAT IS DETACHED HEAD STATE?

INTRODUCTION

In our previous article on working with the git version control system, we explained how to use the git checkout command to retrieve previously committed versions of files from the git repository. In this article, we will talk about a situation that arises if you don’t mention a file name while running the git checkout command and simply type ‘git checkout HEAD~n’ where n is the commit to which to want to move the head to.
How does a repository go into a detached HEAD state?
Using the git checkout command we generally check out a branch of the repository to work with the content within that branch. We’ll talk about branches in detail in a separate article.  For the time being, we’ll define branches as movable pointers to commits in the version history of our git repository. When we initialize a git repository we work with a default branch named master. We may create further branches and subsequently work with those branches. Let’s take a look at the state of the files inside the repository we’ve been using four commits before the current committed state.
[sahil@linuxnix my_first_repo]$ git diff HEAD~4
diff --git a/README.md b/README.md
deleted file mode 100644
index ba76a74..0000000
--- a/README.md
+++ /dev/null
@@ -1 +0,0 @@
-This is a readme file for my first git repository
diff --git a/test.txt b/test.txt
index c66d471..e945f40 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,4 @@
This is a test file!
+Added another line to test file
+Adding a third line to test file
+Adding a fourth line to test file
As you may observe from the above output, the at four commits before the current commit the file test.txt had three fewer lines and we had a file named README.md which we deleted and is no longer available in the repository and hence the /dev/null state for the file.
[sahil@linuxnix my_first_repo]$ pwd
/home/sahil/git/my_first_repo
[sahil@linuxnix my_first_repo]$ ls
README1.md test.txt
Now, let us use git checkout to revert to four commits before the current committed state of the repository.
[sahil@linuxnix my_first_repo]$ git checkout HEAD~4
Note: checking out 'HEAD~4'.

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 a291f69... Added file test.txt and updated .md files
if we execute the ls command in the repository we will observe that the file we deleted README.md is now back.
[sahil@linuxnix my_first_repo]$ ls
README1.md README.md test.txt
So, now the repository is in a detached HEAD state. But what does it mean?
Detached HEAD is the state wherein a particular commit gets checked out instead of a file or a branch. While in this state we are not on a branch right now. We’re browsing a snapshot of our Git files from a specific commit in the commit history.  The problem with a detached HEAD state is that changes made to files in this state do not belong to any branch i.e., not even the master branch. Due to this changes made to files can easily get lost since they are not being recorded in the context of a revision or branch.
Fixing detached HEAD state:
Getting out of a detached HEAD state is fairly straightforward. Simply execute the following command.
[sahil@linuxnix my_first_repo]$ git checkout master
Previous HEAD position was a291f69... Added file test.txt and updated .md files
Switched to branch 'master'
[sahil@linuxnix my_first_repo]$
This brings us back to the master branch thereby getting rid of the detached HEAD state.

Friday, 28 December 2018

GIT: What's a "detached HEAD" in Git?

It might very well be that you'll never come across this "mysterious" state in your Git career. However, if you do one day, you'd probably like to know what a "detached HEAD" is - and how you might have arrived at that state.

Understanding how "checkout" works

With the "git checkout" command, you determine which revision of your project you want to work on. Git then places all of that revision's files in your working copy folder.
Normally, you use a branch name to communicate with "git checkout":
$ git checkout development
However, you can also provide the SHA1 hash of a specific commit instead:
$ git checkout 56a4e5c08
Note: checking out '56a4e5c08'.

You are in 'detached HEAD' state...
This exact state - when a specific commit is checked out instead of a branch - is what's called a "detached HEAD".

The problem with a detached HEAD

The HEAD pointer in Git determines your current working revision (and thereby the files that are placed in your project's working directory). Normally, when checking out a proper branch name, Git automatically moves the HEAD pointer along when you create a new commit. You are automatically on the newest commit of the chosen branch.
When you instead choose to check out a commit hash, Git won't do this for you. The consequence is that when you make changes and commit them, these changes do NOT belong to any branch.
This means they can easily get lost once you check out a different revision or branch: not being recorded in the context of a branch, you lack the possibility to access that state easily (unless you have a brilliant memory and can remember the commit hash of that new commit...).

When a detached HEAD shows up

There are a handful of situations where detached HEAD states are common:
  • Submodules are indeed checked out at specific commits instead of branches.
  • Rebase works by creating a temporary detached HEAD state while it runs.

Where a detached HEAD should not show up

Additionally, another situation might spring to mind: what about going back in time to try out an older version of your project? For example in the context of a bug, you want to see how things worked in an older revision.
This is a perfectly valid and common use case. However, you don't have to maneuver yourself into a detached HEAD state to deal with it. Instead, remember how simple and cheap the whole concept of branching is in Git: you can simply create a (temporary) branch and delete it once you're done.
$ git checkout -b test-branch 56a4e5c08

...do your thing...

$ git checkout master
$ git branch -d test-branch

Thursday, 27 December 2018

GIT: What is detached head?

http://git-scm.com/docs/git-checkout#_detached_head

So, if a head is synonymous with a branch, what does that make a detached head? Well, it’s simply a commit hash which isn’t pointed to by a tag or a branch. So, whenever you have checked out a non-referenced head, you end up with a detached head.

GIT: Recovering lost commits

32.1. Detached HEAD

If you checkout a commit or a tag, you are in the so-called detached HEAD mode. If you commit changes in this mode, you have no branch which points to this commit. After you checkout a branch you cannot see the commit you did in detached head mode in the git log command.
To find such commits you can use the git reflog command.

32.2. git reflog

Reflog is a mechanism to record the movements of the HEAD and the branches references.
The reflog command gives a history of the complete changes of the HEAD reference.
git reflog
# <output>
# ... snip ...
1f1a73a HEAD@{2}: commit: More chaanges - typo in the commit message
45ca204 HEAD@{3}: commit: These are new changes
cf616d4 HEAD@{4}: commit (initial): Initial commit
The git reflog command also list commits which you have removed.
There are multiple reflogs: one per branch and one for HEAD. For branches use the git reflog [branch] command and for HEAD use the git reflog or the git reflog HEAD command.

32.3. Example

The following example shows how you can use git reflog to reset the current local branch to a commit which isn’t reachable from the current branch anymore.
# assume the  ID for the second commit is
# 45ca2045be3aeda054c5418ec3c4ce63b5f269f7

# resets the head for your tree to the second commit
git reset --hard 45ca2045be3aeda054c5418ec3c4ce63b5f269f7

# see the log
git log

# output shows the history until the 45ca2045be commit

# see all the history including the deletion
git reflog

# <output>
cf616d4 HEAD@{1}: reset: moving to 45ca2045be3aeda054c5418ec3c4ce63b5f269f7
# ... snip ...
1f1a73a HEAD@{2}: commit: More chaanges - typo in the commit message
45ca204 HEAD@{3}: commit: These are new changes
cf616d4 HEAD@{4}: commit (initial): Initial commit

git reset --hard 1f1a73a