2012-09-07 2 views
13

インターネットは、この質問に対する間違った回答と理想的でない回答を絶対に散らばっています。これはあなたがしたいと思う共通のものだと思うので、残念です。プレコミットフックでコミットしようとしているものをテストする

問題:pre-commitフックが実行されると、リポジトリがきれいでない可能性があります。あなたがテストを素朴に実行すると、あなたがコミットしているものに反することはありませんが、作業中のツリーには何らかの傷があります。

明らかにするべきことは、終了時にpre-commitgit popの先頭のgit stash --keep-index --include-untrackedです。そうすれば、私たちが望む(純粋な)インデックスに対してテストします。

残念ながらgit add --patchを使用すると(特にハンクを編集する場合)、[email protected]{0}の内容がコミット後の作業ツリーと一致しない可能性があるため、マージ競合マーカーが生成されます。

もう1つの一般的な解決方法は、リポジトリを複製して新しい一時的なテストでテストを実行することです。一つは、まだコミットしていないということです。私たちがコミットしようとしている状態で、リポジトリのコピーを簡単に手に入れることはできません(私はそうする方法があると確信しています、私は興味がないから:)。第二に、私のテストは現在の作業ディレクトリの場所に敏感かもしれません。たとえば、ローカル環境設定のためです。

So:git stash --keep-index --include-untrackedの前に、マージ競合マーカーを導入せずに、コミット後のHEADを変更せずにワークツリーを復元するにはどうすればよいですか?

+0

プリコミットスクリプトは、入力として、コミットされたデータを受信します。なぜあなたは何か他のものを見る必要がありますか?おそらくあなたがやろうとしていることは、プレコミットフック以外の何かの中で最もうまくいくでしょう。あなたは完全なリポジトリにアクセスする必要がありますか? –

+0

@WilliamPursell: "コミットされているデータ"とはどういう意味ですか?プリコミットスクリプトは、作業ツリー(つまり、ソースリポジトリのベース)で実行されます。問題は、リポジトリにいくつか変更を加えていくつかのファイルを追加するだけで(例えば、いくつかのファイルを追加するが他のものは追加しない場合)、コミットが起こる前にテストしないことです。作業ディレクトリにあるものは何でもテストします。 – pwaller

+0

あなたがコミットしているパッチはstdin上でpre-commitフックに利用できます。コミットされているパッチではない場合、何をテストしていますか?プリコミットフックの目的は、パッチを検証することです。 –

答えて

2

リポジトリ全体のクローニングが高すぎる場合は、おそらく作業ディレクトリのコピーが必要です。紛争に対処しようとするよりも簡単にコピーを作成することができます。例えば:それは$ TMPDにコミットした後になるように、あなたがそこにあなたのテストを実行できるように

#!/bin/sh -e 

trap 'rm -rf $TMPD' 0 
mkdir ${TMPD=$PWD/.tmpdir} 
git ls-tree -r HEAD | while read mod type sha name; do 
    if test "$type" = blob; then 
     mkdir -p $TMPD/$(dirname "$name") 
     git show $sha > $TMPD/"$name"; 
     chmod $mod $TMPD/"$name" 
    fi 
done 
cd $TMPD 
git diff --cached HEAD | patch 
# Run tests here 

これは、ツリーの状態をダンプします。ここで行うよりも安全な方法でテンポラリディレクトリを取得する必要がありますが、最終差分が機能するように(またはスクリプトとCDを簡単にするため)、作業ディレクトリの子でなければなりません。

-1

私が最終的に私が探していた解決策が見つかりました。コミットする前のインデックスの状態だけがチェックされ、コミット前と同じようにインデックスと作業ツリーが残されます。

問題が発生した場合や、より良い方法が見つかった場合は、コメントまたは自分の回答として返信してください。

gitリポジトリまたは動作中のツリーを実行中に隠したり、他の方法で変更しようとする人はいないことを前提としています。これは無保証で、間違っていて風にあなたのコードを投げるかもしれません。注意して使用してください。

# pre-commit.sh 
REPO_PATH=$PWD 
git stash save -q --keep-index --include-untracked # ([email protected]{1}) 
git stash save -q         # ([email protected]{0}) 

# Our state at this point: 
# * clean worktree 
# * [email protected]{0} contains what is to be committed 
# * [email protected]{1} contains everything, including dirt 

# Now reintroduce the changes to be committed so that they can be tested 
git stash apply [email protected]{0} -q 

git_unstash() { 
    G="git --work-tree \"$REPO_PATH\" --git-dir \"$REPO_PATH/.git\"" 
    eval "$G" reset -q --hard    # Clean worktree again 
    eval "$G" stash pop -q [email protected]{1}  # Put worktree to original dirty state 
    eval "$G" reset -q [email protected]{0} .  # Restore index, ready for commit 
    eval "$G" stash drop -q [email protected]{0}  # Clean up final remaining stash 
} 
trap git_unstash EXIT 

... tests against what is being committed go here ... 
+0

次の記事のコメントで述べたように、コミットを修正している場合や、作業ツリーが汚い場合は正しく動作しません。 http:// codeinthehole。/ – pwaller

2

あなたは(すなわち、現在のチェックアウトの完全なコピーを作成します。)一時ディレクトリを使用するように余裕があれば、あなたはそのような一時ディレクトリを使用することができます。

tmpdir=$(mktemp -d) # Or put it wherever you like 
git archive HEAD | tar -xf - -C "$tmpdir" 
git diff --staged | patch -p1 -d "$tmpdir" 
cd "$tmpdir" 
... 

これは、基本的にはウィリアムPursellのですコードをシンプルにするgit archiveを利用しており、より高速になることが期待されます。最初cd'ingによってあるいは

cd somewhere 
git -C path/to/repo archive HEAD | tar -xf - 
git -C path/to/repo diff --staged | patch -p1 
... 

git -Cは、Gitの1.8.5を必要とします。

+0

私はあなたに投票しましたが、テスト中に "$ PWDに滞在"を満足していません。これは一部のシステムでは必要ですが、 goライブラリーなど。 – pwaller

+0

pwallerの懸念の他に、 'git commit -a'を実行しているとこの解決法はうまくいかないと私は思っています。なぜならあなたのスクリプトは私たちがステージングされたファイルだけをコミットしていると仮定しているからです。 – TanguyP

1

git write-treeは、pre-commitフックで有効です。これは、インデックスのレポにツリーを書き込みます(このツリーは、コミットが完了した場合に再利用されます)。

ツリーがレポに書き込まれたら、git archive | tar -xを使用して、ツリーを一時ディレクトリ。

例えば:

#!/bin/bash 

TMPDIR=$(mktemp -d) 
TREE=$(git write-tree) 
git archive $TREE | tar -x -C $TMPDIR 

# Run tests in $TMPDIR 

RESULT=$? 
rm -rf "$TMPDIR" 
exit $RESULT 
関連する問題