あなたのように、私は走ります
git stash --keep-index --include-untracked
その後、テストなどを実行できます。
次の部分は注意が必要です。これらは私が試したいくつかのことです:
git stash pop
競合で失敗する可能性がありますが、これは許容できません。
git stash pop --index
競合で失敗する可能性がありますが、これは許容できません。
git checkout stash -- .
追跡されたすべての変更を適用し(良好)、ステージングも行い(許容できない)、追跡されていないファイルをスタッシュから復元しません(許容できない)。隠し場所は残ります(罰金-私はできますgit stash drop
)。
git merge --squash --strategy-option=theirs stash
競合で失敗する可能性がありますが、これは許容できません。競合しない場合でも、追跡されていないファイルをスタッシュから復元しません(許容できません)。
git stash && git stash pop stash@{1} && git stash pop
(チェンジセットを逆の順序で適用しようとすると)競合が発生して失敗する可能性があり、これは許容できません。
しかし、私は私たちが望むことを行うコマンドのセットを見つけました:
# Stash what we actually want to commit
git stash
# Unstash the original dirty tree including any untracked files
git stash pop stash@{1}
# Replace the current index with that from the stash which contains only what we want to commit
git read-tree stash
# Drop the temporary stash of what we want to commit (we have it all in working tree now)
git stash drop
出力を減らし、1行にまとめるには:
git stash --quiet && git stash pop --quiet stash@{1} && git read-tree stash && git stash drop --quiet
私の知る限り、これで復元されないのは、インデックスに追加されてから作業ツリーから削除されたファイル(最終的には追加されて存在する)と、インデックスで名前が変更されたファイルとその後、作業ツリーから削除されます(同じ結果)。このため、最初の隠し場所の前のような行でこれら2つのケースに一致するファイルを探し、git status -z | egrep -z '^[AR]D' | cut -z -c 4- | tr '\0' '\n'
復元後にループして削除する必要があります。
git stash --keep-index --include-untracked
明らかに、作業ツリーに追跡されていないファイルまたはステージングされていない変更がある場合にのみ、イニシャルを実行する必要があります。git status --porcelain | egrep --silent '^(\?\?|.[DM])'
これを確認するには、スクリプトでテストを使用できます。
これは既存の回答よりも優れていると思います-中間変数(ツリーが汚れているかどうか、およびスタッシュの復元後に削除する必要があるファイルのレコードを除く)を必要とせず、コマンドが少なく、安全のためにガベージコレクションをオフにする必要はありません。中間の隠し場所がありますが、私はこれがまさに彼らが求めている種類のものであると主張します。
これが私の現在のpre-commitフックで、上記のすべてを実行します。
#!/bin/sh
# Do we need to tidy up the working tree before tests?
# A --quiet option here doesn't actually suppress the output, hence redirection.
git commit --dry-run >/dev/null
ret=$?
if [ $ret -ne 0 ]; then
# Nothing to commit, perhaps. Bail with success.
exit 0
elif git status --porcelain | egrep --silent '^(\?\?|.[DM])'; then
# There are unstaged changes or untracked files
dirty=true
# Remember files which were added or renamed and then deleted, since the
# stash and read-tree won't restore these
#
# We're using -z here to get around the difficulty of parsing
# - renames (-> appears in the string)
# - files with spaces or doublequotes (which are doublequoted, but not when
# untracked for unknown reasons)
# We're not trying to store the string with NULs in it in a variable,
# because you can't do that in a shell script.
todelete="$(git status -z | egrep -z '^[AR]D' | cut -z -c 4- | tr '\0' '\n')"
else
dirty=false
fi
if $dirty; then
# Tidy up the working tree
git stash --quiet --keep-index --include-untracked
ret=$?
# Abort if this failed
if [ $ret -ne 0 ]; then
exit $ret
fi
fi
# Run tests, remember outcome
make precommit
ret=$?
if $dirty; then
# Restore the working tree and index
git stash --quiet && git stash pop --quiet stash@{1} && git read-tree stash && git stash drop --quiet
restore_ret=$?
# Delete any files which had unstaged deletions
if [ -n "$todelete" ]; then
echo "$todelete" | while read file; do
rm "$file"
done
# Abort if this failed
if [ $restore_ret -ne 0 ]; then
exit $restore_ret
fi
fi
fi
# Exit with the exit status of the tests
exit $ret
どんな改善も歓迎します。