4

「gitpush」中に追加されたすべてのリビジョンを抽出し、それぞれに対して何らかの処理(通知メールの送信など)を行うgitpost-receiveフックがあります。これは、マージする場合を除いてうまく機能します。例えば:

  1. branch1でいくつかのコミットを行い、次にbranch1をプッシュします。受信後フックはコミットを正しく処理します。
  2. branch1をbranch2にマージしてから、branch2をプッシュします。受信後フックは、マージされたすべてのコミットを2回処理します。

どうすればこれを回避できますか?以下は、処理する必要のあるコミットを抽出する受信後フックの始まりです(最後に、$ COMMITSは処理するコミットのリストを保持します)。

#!/bin/sh

REPO_PATH=`pwd`
COMMITS=''

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# for each ref that was updated during the push
while read OLD_REV NEW_REV REF_NAME; do
  OLD_REV="`git rev-parse $OLD_REV`"
  NEW_REV="`git rev-parse $NEW_REV`"
  if expr "$OLD_REV" : '0*$' >/dev/null; then
    # if the branch was created, add all revisions in the new branch; skip tags
    if ! expr "$REF_NAME" : 'refs/tags/' >/dev/null; then
      REF_REV="`git rev-parse $REF_NAME`"
      REF_NAME="`git name-rev --name-only $REF_REV`"
      COMMITS="$COMMITS `git rev-list $REF_NAME | git name-rev --stdin | grep -G \($REF_NAME.*\) | awk '{ print $1 }' | tr '\n' ' '`"
    fi

  elif expr "$NEW_REV" : '0*$' >/dev/null; then
    # don't think branch deletes ever hit a post-receive hook, so we should never get here
    printf ''
  else
    # add any commits in this push
    COMMITS="$COMMITS `git rev-parse --not --all | grep -v $(git rev-parse $REF_NAME) | git rev-list --reverse --stdin $(git merge-base $OLD_REV $NEW_REV)..$NEW_REV | tr '\n' ' '`"
  fi
done
4

4 に答える 4

7

見てください$(prefix)/share/git-core/contrib/hooks/post-receive-email、それはあなたが望むことを(私が思うに)まさに行います。基本的にはgit for-each-ref、すべてのブランチの名前を検索し、更新されているブランチ以外のブランチから到達可能なすべてのコミットを除外するために使用します。

if [ "$change_type" = create ]
then
    # Show all revisions exclusive to this (new) branch.
    revspec=$newrev
else
    # Branch update; show revisions not part of $oldrev.
    revspec=$oldrev..$newrev
fi

other_branches=$(git for-each-ref --format='%(refname)' refs/heads/ |
     grep -F -v $refname)
git rev-parse --not $other_branches | git rev-list --pretty --stdin $revspec

(ここでは簡略化しており、カットアンドペーストのジョブで何も損傷しないことを願っています。ここでの入力は次のとおり$change_typeです。isがすべてゼロの場合、それ以外の場合はcreate;最近の行の古いrevSHA1です-stdinから読み取ります;は新しいrevSHA1であり、フルネームです。例:。)$oldrevupdate$oldrev$newrev$refnamerefs/heads/topic

于 2012-05-03T05:30:19.963 に答える
1

以前に処理されたコミットのハッシュをテキストファイルに保持することです。フックが実行されるたびに、そのファイルを調べて、特定のコミットがすでに処理されているかどうかを確認します。そのコミットをまだ処理していない場合は、それを処理してから、そのコミットをファイルに記録します。

これはあまりスケーラブルではありません。リポジトリにコミットが追加されるとテキストファイルが大きくなり、特定のコミットをチェックする時間も長くなるためです。

于 2012-05-02T19:47:15.643 に答える
0

これを行うには、マージコミット(2つ以上の親を持つコミット)が発生したときに、受信後のフックの処理を停止します。これには、他の「実際の」コミットがスローされないようにするために、マージをプッシュするときに少しの規律が必要です。規律は、マージする前に常にプッシュしてから、マージを個別にプッシュすることです。

于 2012-05-02T20:53:45.223 に答える
0

私はこれを受信後のフックに完全に実装しました。新しいコミットが単一のブランチにプッシュされたか、複数のブランチに同時にプッシュされたかに関係なく、最後のフェッチ以降の新しいコミットのみを複製せずにtracに通知します。このメソッドは、TRAC_HEADどのコミットがすでに処理されているかを追跡するために、gitディレクトリに呼び出されたファイルを保持します。

フックを有効にする前に、ディレクトリcat refs/heads/* > TRAC HEADで実行することをお勧めします。.git

#!/bin/sh
#
# Reads and notifies trac of only new commits that have not yet been dealt with.
#
# The "post-receive" script is run after receive-pack has accepted a pack
# and the repository has been updated.  It is passed arguments in through
# stdin in the form
#  <oldrev> <newrev> <refname>
# For example:
#  aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
#

TRAC_PATH="/path/to/trac/env"

# Read the standard input
while read oldrev newrev refname ; do

        echo "Processing branch: $refname"

        # Read the last revisions for each branch from TRAC_HEAD
        exclusions=$(cat TRAC_HEAD | uniq |  sed -e 's/^/^/' -e 's/ / ^/g' | xargs echo)

        echo "Exclusion list: $exclusions"

        git rev-list --reverse $newrev $exclusions | while read rev ; do
                trac-admin $TRAC_PATH changeset added '(default)' $rev
                echo "Processed: $rev"
        done

        # Add to the exclusions file the latest revision from this branch
        echo $newrev >> TRAC_HEAD

done

# Update the TRAC_HEAD file
cat refs/heads/* > TRAC_HEAD
于 2013-04-27T00:06:57.920 に答える