I could use some guidance from the git experts out there regarding making push operations to non-bare repositories safe. Basically I have a plan about how to do this, and co
I suggest using the post-update hook indicated by the Git FAQ entry ”Why won't I see changes in the remote repo after "git push"?”.
It will stash away staged and unstaged changes (to tracked files) before doing the hard reset. It is safer than a plain hard reset, but as the FAQ entry says, it still does not cover all the situations that might come up (e.g. an index with a pre-existing conflict can not be stashed; it does not auto-merge changes to unmodified files like git checkout does, etc.).
However, …
if at all possible, …
you should probably just avoid pushing to any checked out branch in the first place.
Pushing to a non-bare repository is okay as long as you are not pushing to the checked out branch (after all, the involved configuration variable is receive.denyCurrentBranch, not “receive.denyNonBare”).
The last paragraph of the above-linked FAQ entry links to (as, in a comment below, Mark Longair mentions) another entry that outlines an approach for pushing to a non-bare repository. The motivation for the entry is an asymmetric network connection between two non-bare repositories, but the technique can be applied to any situation where you need/want to push to a non-bare repository.
This latter FAQ entry gives an example of pushing to a remote-tracking branch (under refs/remotes/). Only the refs under refs/heads/ can be checked out without detaching HEAD (without the use of git symoblic-ref), so pushing to anything outside refs/heads/ should be safe for avoiding “pushing to the checked out branch”.
Since you are working in a centralized environment, you might be able to make a policy for the destination of such pushes. For example:
When you need to push commits to someone else’s non-bare repository, push them to
refs/remotes/from/. To avoid conflicts with normal remote-tracking branches, no one should ever define a remote named/ from. Branches pushed like this will show up ingit branch -a(or-r) and, accordingly, can be referenced without therefs/remotes/prefix. However, thefrompseudo-remote will not show up ingit remotebecause there is noremote.from.urlconfiguration variable.Example:
alice$ remote add betty bettys-machine:path/to/some/non-bare/repository alice$ git push betty master:refs/remotes/from/alice/bug/123/master betty$ git log --reverse -p origin/master..from/alice/bug/123/master