リモートでブランチ履歴が変更されると、通常は次のようになります。
o git@git.server.com:XXXXX/Project.git
+ efe2e8b...cda0ee7 HEAD -> Ant_Config_processing (forced update)
スクリプトを使用してこの(強制更新)ステータスを取得する方法はありますか?
アイデアは、それを検出し、ユーザーにアクションを促すエイリアスを作成することです。
リモートでブランチ履歴が変更されると、通常は次のようになります。
o git@git.server.com:XXXXX/Project.git
+ efe2e8b...cda0ee7 HEAD -> Ant_Config_processing (forced update)
スクリプトを使用してこの(強制更新)ステータスを取得する方法はありますか?
アイデアは、それを検出し、ユーザーにアクションを促すエイリアスを作成することです。
私も同様の問題を抱えており、それを理解しました。
リモート(ベア)リポジトリのフックスクリプト内で強制更新を検出したいので、私の答えは元の質問には適さないかもしれませんが、将来の訪問者のために役立つことを願っています。
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 N
commitOは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)
プッシュすると、標準入力で呼び出される受信前スクリプトをフックします。stdinパラメータの形式は、githooks(5)で説明されています。
通常、stdinから2つのコミットオブジェクトsha1(oldrevとnewrev)を抽出します。oldrevは古いツリーのHEADであり、newrevは新しいツリーのHEADです。
この状況では、git-rev-list
出力によって強制プッシュを検出できます。
git rev-list oldrev ^newrev
oldrevからは到達可能であるが、newrevからは到達できないコミットを示しています。これは、コミットが古いツリーにのみ存在したことを示しています。このコマンドでコミットが表示された場合、古いツリーが新しいツリーに置き換えられたため、強制更新が発生しました。これが私たちが欲しいものです!
このコマンドがコミットを表示しない場合、新しいツリーは通常更新されているため、強制更新は発生しませんでした。単に。
これを行う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
コマンドを使用するgit-merge-base
と、2つのコミットに最も近い共通の祖先が検索されます。
早送り更新の場合、の共通の祖先oldrev
とnewrev
を指す必要があり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