2

Right now I again committed to a git submodule without checking out master (or any other branch) before:

╭─some@machine  ~/some/poject/submodules/coollib  ‹cbc6ecc*› 
╰─$ git commit -am"some message"
[detached HEAD 0538b11] some message
 2 files changed, 13 insertions(+), 2 deletions(-)

Maybe my way of working with git is just amateurish but I think I now have to either undo that commit and checkout e.g. master and re-commit or create a branch and merge back to the branch I wanted to commit to.

To me commiting to an unnamed snapshot looks like a low-level procedure which should at least be warned about (if not forbidden)

Why is it allowed to commit to a detached HEAD? When can this be useful?

And can git's behavior be changed via global options?

frans
  • 8,868
  • 11
  • 58
  • 132
  • side remark: there are numerous questions here on git's detached HEAD mode and how to get out of the mess again. But nowhere it is discussed *why* such a mode exists after all. – EagleRainbow May 21 '16 at 08:25
  • 1
    concerning how to prevent conmiting on detached HEAD, please refer to http://stackoverflow.com/questions/37269048/how-to-prevent-commit-in-detached-head (in that - and only that - sense, the question is a duplicate) – EagleRainbow May 21 '16 at 08:25
  • The answers to this question suggest that there's really no reason why to allow this :). At least you can avoid committing to detached HEAD (using a pre-commit-hook). – frans May 21 '16 at 08:32
  • yeah, but this still leaves the question why git still allows it and/or why this `pre-commit` hook isn't engaged by default... – EagleRainbow May 21 '16 at 08:34
  • Git warns me every time I go from a branch into a detached HEAD state with a text `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 ` I wonder why you are always not warned. – ElpieKay May 21 '16 at 08:56
  • This is correct - but in case you have submodules configured you can do `git submodule update` which results in detached HEAD. The question is still: what is it good for to allow committing to a detached HEAD via the CLI? – frans May 21 '16 at 09:29

1 Answers1

3

One could equally ask "why not"; but in fact, a number of Git internal operations make use of this. The most obvious is git rebase, which gets on a detached HEAD and begins copying commits (using git cherry-pick when doing an interactive rebase, and the equivalent when doing a non-interactive rebase). For the most part, these use other commands, but in fact interactive rebase occasionally runs git commit directly, especially in the --amend form.

One could then point out that these commands could use a plumbing command, rather than git commit itself. (And in fact, some do: for instance, git stash uses git commit-tree.)

One could also rewrite Git. :-) At some point it's just too much effort.

If you want to make sure you, personally, are not on a detached head before committing, make yourself a small script that does this, e.g.:

$ git ci
not committing: in detached-HEAD state

or write a pre-commit hook that checks for detached HEAD and requires that you use --no-verify to bypass it to make a commit in that state. (The latter will interfere with reword in an interactive rebase.)

(To check whether HEAD is a symbolic reference, use git symbolic-ref HEAD, which prints the name of the branch to which HEAD points, or fails. Add -q to get just an exit status, which you can use to make a nicer error message. Write the branch name to a shell variable, or to /dev/null to dispose of it, as desired.)

torek
  • 448,244
  • 59
  • 642
  • 775
  • Does your statement imply that engaging such a `pre-commit` hook breaks rebasing? That would be - mmmh... let's call it - "quite unfortunate" – EagleRainbow May 21 '16 at 08:43
  • Based on reading the code, without actually trying it, yes. (The form of breakage is that interactive rebase will force you to do the commit yourself, with the `--no-verify` flag.) Try it out, it might make an interesting experiment. Some details may be Git-version-dependent. – torek May 21 '16 at 08:53
  • That's some nice considerations but I guess it would be easy to just let the git user interface produce warnings while the API still works as expected. Perhaps I have to reword my question to "why does the git user interface allow..." – frans May 21 '16 at 09:27
  • Incidentally, I think all of this makes more sense when you consider how Git grew from a collection of tiny C programs and some shell wrappers (to maintain branch names, for instance) over time. If one were doing a from-scratch rewrite, there are things that probably should be done differently. In any case there are things Git does that I would not: I can attempt to explain them, but I don't necessarily think they are *good ideas*, just historical artifacts (in this case anyway). – torek May 21 '16 at 10:26