Git receive/update hooks and new branches

11,660

Solution 1

The term "right answer" is a bit ambiguous in this case. I actually think that "all revs reachable from newrev but nowhere else" is completely correct. This is true even if there was a merge - in that case, you should see the commits unique to the new ref, and the merge commit, but not the commits that were merged.

So, I would say, check if the "oldrev" is all zeroes, and if it is, act accordingly:

if [ "$oldrev" -eq 0 ]; then
    # list everything reachable from newrev but not any heads
    git rev-list $(git for-each-ref --format='%(refname)' refs/heads/* | sed 's/^/\^/') "$newrev"
else
    git rev-list "$oldrev..$newrev"
fi

Solution 2

When $oldrev is all zeros, a different git rev-list command does all you need:

git rev-list $newrev --not --branches=*

will give you a list of revisions reachable from $newrev but not from any branches.

Note that this definitely does not do the same thing as git rev-list $oldrev..$newrev when oldrev is not all zeros, so you'll want to check which case you're in and pick the appropriate command to run.

Solution 3

I just figured it out myself.

git log newref --not otherheads

is the key to get all logs of a branch that are not on any other branch. Below is my python script to check for the correct maximum line length of the commit messages.

import sys
import commands

ref = sys.argv[1]
old = sys.argv[2]
new = sys.argv[3]

x = 0

# only a tag is pushed to server, nothing to check
if ref.find('refs/tags/') >= 0:
  if len(ref.strip('refs/tags/')) > 25:
    print 'tag name is longer than 25 characters'
    exit(1)
  else:
    exit(0)
# either a new branch is pushed or an empty repo is being pushed
if old == '0000000000000000000000000000000000000000':
  heads = commands.getoutput("git for-each-ref --format='%(refname)' 'refs/heads/*'")
  heads = heads.replace(ref+'\n','').replace('\n',' ')
  hashes = commands.getoutput('git log '+new+' --pretty=%H --not '+heads).split('\n')
else:
  hashes = commands.getoutput('git log '+old+'..'+new+' --pretty=%H').split('\n')

for hash in hashes:
  subject = commands.getoutput('git show '+hash+' --format=%s --summary').split('\n')
  body = commands.getoutput('git show '+hash+' --format=%b --summary').split('\n')

  if len(subject[0]) > 75:
    print
    print 'commit: '+hash
    print 'bad commit message(s): header line is too long or second line is not blank (max 75 chars)'
    print 'bad line: "%s"' % subject[0]
    print 'length of header line: %d' % len(subject[0])
    print 'try again with correct message format'
    print
    x = 1

  for line in body: 
    if len(line) > 75:
      print
      print 'commit: '+hash
      print 'bad commit message(s): description lines are too long (max 75 chars)'
      print 'bad line: "%s"' % line
      print 'length of  line: %d' % len(line)
      print 'try again with correct message format'
      print
      x = 1

if x == 0:
  exit(0)
else:
  exit(1)

Solution 4

I solved this for my update hook using the following:

if [ "$oldrev" -eq 0 ]; then
git log "$(git show-branch --merge-base)".."$newrev"; else
foo;
fi
Share:
11,660
marc.guenther
Author by

marc.guenther

Updated on June 03, 2022

Comments

  • marc.guenther
    marc.guenther about 2 years

    I have a problem with the 'update' hook. In the case of a new branch, it gets a 0000000000000000000000000000000000000000 as the 'oldrev'. And I don't know how to handle that case.

    We have the requirement, that every commit message references a valid Jira issue. So I have installed an "update" hook on our central repository. That hook gets an "oldrev" and a "newrev". I then pass those to "git rev-list" like this:

    git rev-list $oldrev..$newrev

    This gives me the list of all revs, which I can then iterate through, and do whatever I need to do.

    The problem is, when the user pushes a new branch, the hook gets 0000000000000000000000000000000000000000 as the oldrev. And "git rev-list" simply complains with:

    fatal: Invalid revision range 0000000000000000000000000000000000000000..21bac83b2

    So how do I get the list of all the revs that are on that new branch? I have searched the net for quite some time now, and found nothing. The example hooks I found either

    • don't handle the problem, and fail with the above error message
    • incorrectly try to fix the problem by setting the oldrev to "", which returns the wrong results from rev-list
    • simply give up when they encounter that oldrev

    None of these sound particularly exciting.

    So does someone have any idea how to get the right answer in that case? I was thinking about querying git for "give me all revs that are reachable from newrev, but not from any of the other branches (=all branches except the new one)". But even that would give the wrong answer if there had been a merge from the new branch to any of the old ones.