16

リモートでブランチ履歴が変更されると、通常は次のようになります。

o git@git.server.com:XXXXX/Project.git
 + efe2e8b...cda0ee7 HEAD -> Ant_Config_processing (forced update)

スクリプトを使用してこの(強制更新)ステータスを取得する方法はありますか?

アイデアは、それを検出し、ユーザーにアクションを促すエイリアスを作成することです。

4

3 に答える 3

27

私も同様の問題を抱えており、それを理解しました。

リモート(ベア)リポジトリのフックスクリプト内で強制更新を検出したいので、私の答えは元の質問には適さないかもしれませんが、将来の訪問者のために役立つことを願っています。


Gitフックスクリプトから強制更新を検出する方法

https://github.com/kyanny/git-hooks-detect-force-update

これは、強制更新を検出する方法を学習するためのサンプルgitpre-receiveフックスクリプトです。

結論

$ git rev-list oldrev ^newrev

テストする方法

$ rake -T
rake forced_push  # git hooks test detect forced update
rake normal_push  # git hooks test

ステップバイステップの紹介

まず、 git-rev-list(1)の構文について説明します。

この場合、このまっすぐな履歴を持つGit作業リポジトリ内を想定しています。

1 --- 2 --- O --- X --- 3 --- 4 --- N

の一般的な使用法git-rev-listは以下のとおりです。

$ git rev-list N

このコマンドは、コミットNから到達可能なすべてのコミットを表示します(注:git-rev-listコミットを時系列の逆順で表示します)

git-rev-list複数の引数を受け入れます。

$ git rev-list N O

git rev-list NcommitOはcommitNの祖先であるため、このコマンドはと同じ出力を表示します。

次に、git-rev-list出力からコミットを除外できます。

$ git rev-list N ^O

^ Oは、Oから到達可能なコミットを除外することを意味するため、このコマンドはN、4、3、Xを表示します(注:Oは除外されます)


について学んだのでgit-rev-list、強制更新が発生した場合について説明します。

この場合、この複雑な履歴を持つGit作業リポジトリ内を想定しています。

* --- B --- * --- O ($oldrev)
       \
        * --- X --- * --- N ($newrev)
  1. 古いツリーでは、4つのコミット(*、B、*、O)があり、それらをリモートにプッシュしました。
  2. コミットBから新しいブランチをチェックアウトします。これは新しいツリーです。
  3. 新しいツリーでは、4つのコミット(*、X、*、N)があり、-forceオプションを使用してそれらをリモートにプッシュしました。

プッシュすると、標準入力で呼び出される受信前スクリプトをフックします。stdinパラメータの形式は、githooks(5)で説明されています。

通常、stdinから2つのコミットオブジェクトsha1(oldrevとnewrev)を抽出します。oldrevは古いツリーのHEADであり、newrevは新しいツリーのHEADです

この状況では、git-rev-list出力によって強制プッシュを検出できます。

git rev-list oldrev ^newrevoldrevからは到達可能であるが、newrevからは到達できないコミットを示しています。これは、コミットが古いツリーにのみ存在したことを示しています。このコマンドでコミットが表示された場合、古いツリーが新しいツリーに置き換えられたため、強制更新が発生しました。これが私たちが欲しいものです!

このコマンドがコミットを表示しない場合、新しいツリーは通常更新されているため、強制更新は発生しませんでした。単に。

関連項目

于 2012-09-04T07:36:01.447 に答える
7

これを行う1つの方法は、を使用することです。これgit reflogは、ブランチへの変更の記録を保持します。

reflogを使用すると、プル/フェッチの前にブランチが指している場所を取得し(スクリプト化されている場合は、自動的にマージされないため、フェッチを使用します)、新しいリモートの「ヒント」からそのコミットに到達できるかどうかを確認できます。ブランチ。

bashを使用して、これを試すことができます。

$ git rev-list remotename/branchname | grep $(git rev-parse remotename/branchname@{1})
$ echo $?
1

ハッシュ(または終了ステータス0)を返す場合は、ブランチ履歴でブランチの前のヒントが見つかったことを意味するため、早送りマージでした。何も返さない(または終了ステータス1)場合は、強制的に更新されています。

出力をチェックしてgit reflog remotename/branchname、branchnameが強制的に更新されたかどうかを確認できます。

$ git reflog remotename/branchname
dc2afab refs/remotes/remotename/branchname@{0}: fetch rewrite: forced-update
4603c2c refs/remotes/remotename/branchname@{1}: fetch rewrite: forced-update
于 2012-04-25T17:49:46.640 に答える
3

コマンドを使用するgit-merge-baseと、2つのコミットに最も近い共通の祖先が検索されます。

早送り更新の場合、の共通の祖先oldrevnewrevを指す必要がありoldrevます。非早送りをブロックするために事前受信フックに配置されるサンプルコード:

mergebase=`git merge-base $oldrev $newrev`
if [ "$oldrev" != "$mergebase" ]; then
  echo "Non fast-forward update not allowed for $refname, from ${oldrev:0:16} to ${newrev:0:16} merge base ${mergebase:0:16}"
  exit 1
fi
于 2013-01-19T22:32:05.883 に答える