How to prevent commit in detached HEAD
Asked Answered
F

3

5

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.

Fretted answered 17/5, 2016 at 6:51 Comment(0)
R
7

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. Credits go to svachalek

Why should git prevent commiting in detached HEAD? Detached HEAD means only 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 many developers in your team enter this state? Maybe they apply some weird worklow?

Romeoromeon answered 17/5, 2016 at 7:19 Comment(2)
While this will prevent commits to detached head, it will also interfere with (interactive) rebase operations. Internally, rebase uses detached heads to replay the commits.Kirsten
Allowing rebases would require detecting them in the hook. However, I can hardly imagine a developer who does interactive rebase and is afraid of commits in detached HEAD at the same time.Romeoromeon
M
2

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.

Mutineer answered 17/5, 2016 at 9:51 Comment(0)
P
1

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.

Press answered 17/5, 2016 at 7:52 Comment(3)
+1 for the idea of branch creation in the post-checkout hook. However, it would have to create branches with random names which in turn would create a big mess over time.Romeoromeon
@Romeoromeon Yes, random branch name is indeed a problem. We could use some logic to find a proper name but by contrast it's still a bit troublesome. So just ignore it or find the root cause and prevent it in advance. As I know, repo sync with no repo start can also lead to detached HEAD state if Repo is in use.Press
Creating the branch in the post-commit hook would avoid creating branches when the user doesn't actually want to commit anything. See gist.github.com/ben-cohen/316f89c763e9d8a027335261a44c4954Sevastopol

© 2022 - 2024 — McMap. All rights reserved.