19

commit --amend を実行すると、コミットが既にリモート リポジトリにプッシュされている場合、コミットは安全ではありません。

安全でない commit --amend を pre-commit フックとアボートで検出したい。

ただし、pre-commit フックには引数がありません。--amend を検出する方法がわかりません。

私は何をすべきか ?

4

5 に答える 5

7

TL;DR バージョン: 以下のスクリプト (真ん中のようなもの) があり、特定のワークフローを強制します。git commit --amend特定の sを正確に防止するわけではなく(さらに、スクリプトをスキップするためにいつでも使用できます)、必要な場合とそうでない場合がある--no-verify他の s を防止 (または少なくとも警告)します。git commit

警告ではなくエラーアウトにするには、 に変更WARNINGしてERRORに変更sleep 5exit 1ます。

編集: この git フックでは、これが「修正」コミットであることを伝えることができないため、エラーを出すことはお勧めできません。したがって、--no-verify単に新しいものを追加する場合、これは失敗します (追加する必要があります)。アップストリームがあり、アップストリームの先頭にあるブランチにコミットします。


リポジトリ内のコミットを実際に変更するわけではなく、新しい別のコミットを追加し、そこにブランチ ヒントを再ポイントするだけなので、必ずしも安全ではないというわけではありません。たとえば、ブランチが次のようになっているとします。git commit --amend

A - B - C - D      <-- master, origin/master
          \
            E - F  <-- HEAD=branch, origin/branch

次に、成功git commit --amendした場合は次のようになります。

A - B - C - D      <-- master, origin/master
          \
            E - F  <-- origin/branch
              \
                G  <-- HEAD=branch

まだ commitがFあり、 commitGは の「修正」バージョンですF。ただし、それGは「早送り」ではないのは事実であり、この場合Fはおそらくすべきではありませんgit push -f origin branch

すでにそのような状況にある場合、つまり、成功した後git commit --amend(以下のスクリプトを使用せずに、または使用して)、同様のケースが発生します。

A - B - C - D       <-- master, origin/master
          \
            E - F   <-- origin/branch
              \
                G   <-- HEAD=branch

あなたが今git commit(たとえなくても--amend)、あなたは新しいコミットを追加します、例えば、にG接続しHます; ただし、プッシュしようとすることHは早送りではありません。

を具体的にテストすることはできません--amendが、「上流」があるかどうか、存在する場合は現在HEADがその上流の祖先であるかどうかを確認できます。これを行う少し安っぽい pre-commit フックを次に示します (エラー終了ではなく警告とスリープを使用)。

#!/bin/sh

# If initial commit, don't object
git rev-parse -q --verify HEAD >/dev/null || exit 0

# Are we on a branch?  If not, don't object
branch=$(git symbolic-ref -q --short HEAD) || exit 0

# Does the branch have an upstream?  If not, don't object
upstream=$(git rev-parse -q --verify @{upstream}) || exit 0

# If HEAD is contained within upstream, object.
if git merge-base --is-ancestor HEAD $upstream; then
    echo "WARNING: if amending, note that commit is present in upstream"
    sleep 5:
fi
exit 0

ここでの基本的な問題は、 を使用しなくても、この状況が常に発生することgit commit --amendです。上記と同じ設定で開始するとしますが、コミットFはまだ存在しません:

A - B - C - D      <-- master, origin/master
          \
            E      <-- HEAD=branch, origin/branch

ここで、レポのコピーで、に取り組むことにしましたbranch。バグを修正してgit commit:

A - B - C - D      <-- master, origin/master
          \
            E      <-- origin/branch
              \
                F  <-- HEAD=branch

あなたは今、先を行ってoriginおりgit push origin branch、正しいことをするでしょう。しかし、あなたが 1 つのバグを修正している間に、Joe は自分のリポジトリのコピーで別のバグを修正し、自分のバージョンをにプッシュしてorigin/branch、あなたをpush一歩先に進めました。したがって、実行git fetchして更新すると、次のようになります。

A - B - C - D      <-- master, origin/master
          \
            E - J  <-- origin/branch
              \
                F  <-- HEAD=branch

Jジョーのコミットはどこにありますか)。git commitこれは完全に正常な状態であり、別の修正 (たとえば、3 番目のバグ) を追加してから、Joe の修正も含めるようにマージまたはリベースできるとよいでしょう。サンプルの pre-commit フックは反対します。

常に最初にリベースまたはマージしてから 3 番目の修正を追加すると、スクリプトは反対しません。F上記の-and-J状況に陥ってgit merge(またはgit pullマージを行う ) を使用するとどうなるかを見てみましょう。

A - B - C - D             <-- master, origin/master
          \
            E - J         <-- origin/branch
              \   \
                F - M     <-- HEAD=branch

これで commit M、マージが「先行」していJます。したがって、スクリプト@{upstream}は commitを検出し、 commit( ) が の祖先であるJかどうかをチェックします。そうではなく、追加の新しいコミットが許可されているため、「3番目のバグを修正」コミットすると次のようになります。HEADMJN

A - B - C - D             <-- master, origin/master
          \
            E - J         <-- origin/branch
              \   \
                F - M - N <-- HEAD=branch

別の方法として、3 番目のバグを修正する前に次のことを行うことgit rebaseができます。J

A - B - C - D          <-- master, origin/master
          \
            E - J      <-- origin/branch
              \  \
              (F) F'   <-- HEAD=branch

(F'これはチェリーピックされたコミットFです。括弧を付けFて、まだリポジトリにある間は、それを指すブランチ ラベルがなくなっているため、ほとんど見えないことを示しています。) これで、プレコミット フック スクリプトは動作しません。 t オブジェクト、再び。

于 2013-10-15T19:13:57.030 に答える
0

これが該当するかどうかを確認する別の方法は--amend、標準シェルで次のとおりです。

git_command=$(ps -ocommand= -p $PPID)
if [ -z "${git_command##git\ commit*--amend*}" ]; then
    echo "The original command was a: git commit --amend"
    exit 0
fi
于 2019-06-24T13:50:00.273 に答える