0

Suppose I have had to use git filter-branch to remove a file from revision history. I want to ensure that all my collaborators update all their local copies before they push again. The obvious way to do this seems to be to use a pre-receive hook on the master repo to ensure that the original revision ID of the revision that introduced the problem file never reappears.

How do I write that hook?

zwol
  • 135,547
  • 38
  • 252
  • 361
  • why don't you just mail them explaining the situation and asking them to clone the repository again? you will be rewriting part of the history and they won't be able to fast-forward push or pull without a lot of errors. add the file to `.gitignore` to avoid future inclusions of that file. – KurzedMetal Jul 10 '12 at 18:22
  • Of course I will mail them explaining the situation, but this is the sort of thing where one wishes to apply both belt and suspenders. – zwol Jul 10 '12 at 21:18

1 Answers1

1

I strongly support paranoia. That written, I hope your contributors would notice the "your branch has diverged" warnings or the fact their merge commits suddenly pull in hundreds of new SHA1 hashes.

Something like the following should get you most of the way there. I unfortunately cannot test it right now, but git-receive-pack and githooks's man pages were helpful, as was this example:

#!/bin/sh
while read oldrev newrev refname
do
    git rev-list ^$oldrev $newrev | grep "<problem-hash>"
    if test $? = 0; then
        echo "Problematic hash found. Please contact the maintainer."
        exit 1
    fi
done

Searching for the file itself using pre-receive:

#!/bin/sh
while read oldrev newrev refname
do
    git diff $oldrev $newrev --name-only | grep "<full_file_path>"
    if test $? = 0; then
        echo "Problematic hash found. Please contact the maintainer."
        exit 1
    fi
done
Christopher
  • 42,720
  • 11
  • 81
  • 99
  • I think this will only catch the case where one of the new refs (i.e. branch heads) points *directly* to the problem revision, not where one of the new refs has the problem revision as a parent. – zwol Jul 11 '12 at 07:23
  • 1
    @Zack that's what i tried to say with my previous comment, no one can `git push` without `--force`ing any commit that has as base the changed ("problematic") commits, because you **will rewrite them** with `filter-branch`. I guess as paranoid as you are, you are not letting your devs do non fast-forwards pushes, aren't you?. AFAIK, `.gitinore`ing that "problematic" file is all that you need. – KurzedMetal Jul 11 '12 at 11:32
  • @Zack: Updated the script to accommodate your concerns, although I generally agree with KurzedMetal's comments that prohibiting non-ff updates and adding the file to `.gitignore` is likely sufficient. You could also use the update hook to look for the file itself, I suppose. – Christopher Jul 11 '12 at 12:15
  • ...and added an attempt at finding the file using pre-receive, not update. It might be slightly more useful, but I'm also assuming you're adding the file to `.gitignore`. – Christopher Jul 11 '12 at 12:24
  • It's entirely possible that disallowing "fast forwards", whatever those are, is sufficient, but I don't care to assume. I have been bitten several too many times by Git's habit of taking standard terms and making them mean something subtly different from what they mean in *every other version control system ever* (yes, including the other DVCSes). – zwol Jul 11 '12 at 14:17
  • @Zack: if you're running your own git server you can [set configuration options](http://stackoverflow.com/a/1754553/877115) that prevent `git push --force` from working. This would prohibit a contributor from forcibly overwriting your newly filtered branch. It's usually a good policy regardless, and hopefully the (newly edited) hooks will help you get your other policies in force. – Christopher Jul 11 '12 at 14:24