Background: OS: Windows Git version: 2.11.0
According to our policy, we are: 1. Adding several field to the commit messages of unpushed commits before push 2. Verifying on remote that pushed commit's message contains the required fields
We are editing the commit message via "git --filter-branch --msg-filter" which triggered during the pre-push hook.
When trying to push via SSH, git pushes the commit SHA before it was re-written. for example:
This behavior occurs only when working over SSH. For users working over HTTPS everything works fine.
Any assistance will be appreciated.
Thanks!
As a sort of general rule, hooks are not allowed to modify commits themselves. There are specific cases that are explicitly allowed, and some that work by chance, but once a commit actually exists it cannot be changed. A git filter-branch
or git commit --amend
does not actually change any commit; instead, it adds a new commit that resembles the original, but has whatever change you had it make. This new commit has a new, different hash ID.
What's surprising is not that this failed with ssh but that this succeeded with https. That's just luck, and one could argue that it is bad luck that it worked. A pre-push hook is only intended to say "yes, this push is allowed" or "no, this push is forbidden". It is not supposed to change a name-to-commit-ID mapping. Clearly what's actually happening is that the http based push winds up repeating the name to ID mapping and getting the new ID, while the ssh based push sticks with the ID it got initially.
Now, you can actually make all this work:
git push
running during the outer git push
—the recursion will terminate since the new commit just made would be allowed, so that this branch of the logic will not run during the inner push). Then print an error message, noting that (and why) the original push was rejected and whether an "inner" push was done and if so whether it succeeded, or if not, what its ID is and how the user can use it. Finally, reject the push.There are several reasons to avoid this recursive method: (a) it violates the expectations of any experienced Git user, who would not expect his own commit to be replaced and pushed; and (b) if it goes wrong—if the recursion does not terminate immediately, for instance—it may go very wrong. Part (b) can be mitigated by cleverness in the pre-push hook (e.g., export an environment variable to the inner push noting that recursion is occurring, and if about to recurse, fail noisily if this variable is set). Part (a) is perhaps excusable given that the pre-push hook is, after all, something the user must set up himself in the first place.
Even if you handle these objections, there's one more reason to avoid it: it makes the outer (non-recursive) push fail. The user will see that the push failed, even if the inner push succeeded. This is going to be at least a little bit confusing.