2

I have some tests in my pre-commit hook which require the hash of the previous commit to work. By previous commit I mean the one that will become the parent of the commit that's being created right now.

Normally, I can just use git rev-parse HEAD. However, during an --amend commit, the HEAD points to the commit which will be deleted and replaced, so what I really need is HEAD^.

I also a little concerned about rebasing. I have no idea what weird things can happen then.

How can I reliably get the parent commit's hash (as described) in the pre-commit hook?

Piotr Siupa
  • 3,929
  • 2
  • 29
  • 65

1 Answers1

3

Closest I can get is detect it after the fact, in a post-rewrite hook.

In the code, pre-commit is called before Git has even determined the parents. This looks arbitrary to me, the prepare_to_commit call could be moved one paragraph down and the parents passed as hook args without breaking backward compatibility except for some why-would-you-do-that cases, but that's not how it works now.

Real enforcement needs to be done in the publishing repo's pre-receive anyway, if detecting the fault in a post-rewrite and complaining about it to the user there, maybe reset --soft'ing back to the original to undo the change, isn't going to do it for you, maybe writing up a description of what you're really doing here and either a patch or a help-me missive would get it changed.

jthill
  • 55,082
  • 5
  • 77
  • 137
  • 1
    OK, so Git doesn't know the parent commit. It must know whether it is an amend commit, though. Maybe that information can be extracted and then it's just a matter of using `HEAD` or `HEAD^`? Although, checking if commit is `--amend` doesn't seem to be that easy either. Best solution I've found parses command line found using `ps` which looks really fragile to me: https://stackoverflow.com/questions/19387073/how-to-detect-commit-amend-by-pre-commit-hook – Piotr Siupa Jul 23 '22 at 17:44
  • It's not that it doesn't know it, it's that it hasn't worked it out yet at the time it calls the pre-commit hook. – jthill Jul 23 '22 at 17:47
  • I cannot say any of those solutions is without problems. `pre-receive` won't work since my server won't even be able to compile the program. `post-rewrite` could maybe work but it would be really annoying since you write (sometimes very long) commit message before it could trigger. And even if this would get changed in Git itself, I cannot assume everyone will have the latest version. (You have to wait a few years for an official update on some systems.) – Piotr Siupa Jul 23 '22 at 17:54
  • The post-rewrite issue seems pretty easily solvable, if having to prepare a commit message a second time becomes annoying enough you could have your post-rewrite save it before rejecting the commit and your prepare-commit-message recover it. – jthill Jul 23 '22 at 18:05
  • Maybe this is the solution. To just move most of the tests to `post-commit`/`post-merge`. The plus would be that you would no longer have to wait for tests to write the commit message but on the other hand `--no-verify` would no longer work. – Piotr Siupa Jul 23 '22 at 18:15
  • 1
    mmm. That's fixable too, have the precommit do something the post-commit&c. check and undo, then they can tell if precommit ran. – jthill Jul 23 '22 at 18:22
  • For anyone reading this and wondering if testing in the `post-commit` and undoing a commit is a good idea, it is not. I managed to make it work so I know wham I'm saying. I'm going to undo what I did and stick to the normal techniques of doing tests in the `pre-commit` and trying to detect if this is an `--amend` commit. Even if in some case it won't work, at least it wont backfire, removing one commit too many. (And it will eventually unless your code is 100% error-free.) – Piotr Siupa Aug 20 '22 at 20:36