Why does git allow you to commit to a detached head? Is there any pre commit hook that can disable it? What is the purpose? Many new developers do this and I'd like to find a way to disable it.Answer1:
This can be only prevented by a local git
pre-commit hook, so developers would need to create it. Add the
your-local-project/.git/hooks/pre-commit file with the following contents:
#!/bin/sh if ! git symbolic-ref HEAD &> /dev/null; then echo "You are in a detached head state! Commit has been blocked. (Use --no-verify to bypass this check.)" exit 1 fi
Make sure it's executable. <a href="https://gist.github.com/svachalek/5437407" rel="nofollow">Credits go to svachalek</a>
Why should git prevent commiting in detached HEAD? Detached HEAD means <em>only</em> that there is no pointer to the repository state you are working on. It assumes that you know what you are doing.
I would rather investigate why <em>many developers</em> in your team enter this state? Maybe they apply some weird worklow?Answer2:
git checkout $commit-sha1 can lead to a detached HEAD. So does
git checkout FETCH_HEAD. A detached HEAD could be considered as a branch without a name. If it does not confuse you, you could just ignore it. As @fracz said, you could prevent it by
pre-commit. You could also make it a branch with a name with
git checkout -b some_name. A
post-checkout hook may help you to detect the detached HEAD state and make it a branch.
Git uses this internally for many operations. The detached HEAD mode simply gets you on the (one, single, special) anonymous branch, and the anonymous branch can be given a name later.
This is, for instance, how
git rebase manages to copy the commits from their original chain to a new chain. First it checks out the
--onto target commit (
--onto defaults to the
<upstream>) using this detached HEAD mode. Then, for each commit that is to be copied, it copies that commit (with
git cherry-pick or something equivalent: the details vary depending on interactive vs non-interactive rebase, and if interactive, many more details). Last, it moves the existing branch label so that it points to the final copied commit.