16

pre-commitフックが実行されると、リポジトリがクリーンでない可能性があります。したがって、単純にテストを実行すると、コミットしているものに反するのではなく、作業ツリーにあるものに反することになります。

やるべきことは明らかgit stash --keep-index --include-untrackedで、 の最初とpre-commit最後git popにあります。そうすれば、(純粋な) インデックスに対してテストを行うことができます。これが私たちが望んでいることです。

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

もう 1 つの一般的な解決策は、リポジトリを複製し、新しい一時リポジトリでテストを実行することです。それには2つの問題があります:

  1. まだコミットしていないため、コミットしようとしている状態のリポジトリのコピーを簡単に取得することはできません。と
  2. たとえば、ローカル環境の構成が原因で、テストが現在の作業ディレクトリの場所に敏感になる場合があります。

git stash --keep-index --include-untrackedマージ競合マーカーを導入せず、 post-commit を変更せずに、作業ツリーを の前の状態に復元するにはどうすればよいHEADですか?

4

5 に答える 5

4

git write-treepre-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
于 2016-04-02T14:12:57.373 に答える
2

リポジトリ全体のクローンを作成するのに費用がかかりすぎる場合は、作業ディレクトリのコピーが必要になる可能性があります。コピーを作成することは、競合に対処しようとするよりも簡単です。例えば:

#!/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

これにより、$ TMPDでコミットした後のツリーの状態がダンプされるため、そこでテストを実行できます。ここで行うよりも安全な方法で一時ディレクトリを取得する必要がありますが、最終的な差分が機能するためには(または、スクリプトとCDを以前に簡略化するために)、作業ディレクトリの子である必要があります。

于 2012-09-08T23:28:43.417 に答える
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"
...

これは基本的に William Pursell のソリューションですが、git archiveこれを利用してコードを単純化し、より高速になると期待しています。

または、最初に cd を実行します。

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

git -CGit 1.8.5 が必要です。

于 2014-05-29T12:11:32.407 に答える
-1

I have finally found the solution I was looking for. Only the state of the index before commit is checked, and it leaves the index and working tree in exactly as it was before the commit.

If you see any problems or a better way, please do reply, either as a comment or your own answer.

This assumes that nothing else will try to stash or otherwise modify the git repository or working tree whilst it is running. This comes with no warranty, might be wrong and throw your code into the wind. USE WITH CAUTION.

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

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

# Now reintroduce the changes to be committed so that they can be tested
git stash apply stash@{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 stash@{1}      # Put worktree to original dirty state
    eval "$G" reset -q stash@{0} .        # Restore index, ready for commit
    eval "$G" stash drop -q stash@{0}     # Clean up final remaining stash
}
trap git_unstash EXIT

... tests against what is being committed go here ...
于 2012-09-14T15:32:25.000 に答える