views:

35

answers:

3

Hi there,

I am moving my team over from an old CVS repository to using git. I was hoping to add in a precommit hook to ensure before a commit is done locally (and pushed) each person has an up to date repo.

For instance, in CVS everyone would do a 'cvs up' before making changes, and then committing. I want to force it so people can't commit changes unless they have done a git pull origin master first (we won't be using extra branches)

Is there an easy way to do this? cheers for any help :)

+4  A: 

Check and see if the SHAs from git ls-remote origin HEAD (remote tip) and git rev-parse HEAD (local tip) are equal?

Note that in doing this, you're throwing away a LOT of Git's flexibility - think about whether that's really what you want to do. Part of the strength of git pull is that even if you've commit things that diverged from the master copy, when you pull from the master copy your changes can be merged in (and in most cases, the process is entirely automatic).

If your goal is to have a linear commit history (which has its own trade-offs), I'd suggest taking a look at the rebase command instead of forcing your developers to never commit behind origin/master.

Edit

Actually, if you're doing just git pull (instead of rebasing), you won't be able to compare the heads, because pull would be doing merge commits. Instead, you'd need to compare git ls-remote origin HEAD to git merge-base origin/HEAD HEAD.

Some other comments

  • Why are you using Git, but then not using extra branches at all? That's kind of like buying a car, but never using the engine (and instead just pushing it everywhere). Branches are cheap in Git, fast to set up, and nearly effortless to merge. You are doing yourself a disservice if you don't make use of them.

  • Why do you care about everyone being up-to-date before making changes? This isn't CVS, conflict resolution isn't terrible - Git will auto-resolve 95% of conflicts for you without you having to do a thing, so whether you git pull before or after you make your changes doesn't really matter - you just need to pull before you push and you'll be fine.

  • Related to the previous point: since non-fast-forward pushes are rejected by default, you don't really need a hook. Just tell your developers "if your push is rejected as being non-fast-forward, do a git pull, then try pushing again" and everything will work.

Amber
"since non-fast-forward pushes are rejected by default, you don't really need a hook." my point exactly ;) +1. And you can even give this advice automatically through [`git config`](http://www.kernel.org/pub/software/scm/git/docs/git-config.html): see `advice.pushNonFastForward`. Or enforce it on the remote side with `receive.denyNonFastForwards` (will block it even with forced push).
VonC
(`advice.pushNonFastForward` is enabled by default.)
Amber
@Amber: true, so that means the "`git pull` first" advice will be addressed by default.
VonC
+2  A: 

This destroys the 'distributed' nature of git. It makes every commit somewhat global. The cvs "commit" is analogous to the git "push" which is what communicates with the remote end.

If you truly want to take advantage of the distributed model, you should encourage and make your team understand the point of local commits rather than make the system hit the central repo on every commit (which is sawn off centralised).

Noufal Ibrahim
+2  A: 

If you are tracking the remote branch:

git fetch
git log HEAD..origin
# or:
git diff ...origin

As other answers alluded to, forcing that kind of check is not always a good solution for any remote repo, but can be interesting as a warning.

Don't forget that a git push will be by default rejected if it is not a fastforward change.
So the git pull will be the way to avoid that message anyway.

VonC