Git作業ディレクトリがスクリプトからクリーンであるかどうかを判断する


83

rsyncGit作業ディレクトリを宛先として実行するスクリプトがあります。作業ディレクトリがクリーン(コミットする変更なし)かどうかによって、スクリプトに異なる動作をさせたい。たとえば、の出力がgit status以下の場合、スクリプトを終了します。

git status
Already up-to-date.
# On branch master
nothing to commit (working directory clean)
Everything up-to-date

ディレクトリがクリーンでない場合は、さらにいくつかのコマンドを実行したいと思います。

上記のような出力をシェルスクリプトで確認するにはどうすればよいですか?


ここで最後のコマンドのステータスを確認すると役立ちますか?($?)
UVV 14

詳細を教えてください。スクリプトの主なアイデアは何ですか?
タチョミ14

@tachomi私は編集コンテキストを追加
brentwpeterson

あなたはそれはきれいではありませんと仮定して行うことができますgit reset --hard origin/branchそれはあなたが何かをコンパイルした後、クリーンアップしようとしている場合はあなたのために...のように起こっているものである場合など、
SnakeDoc

1
@SnakeDoc可能ですが、逆のケースがより一般的であると想定しています。つまり、ローカルの変更をマングルすることを避けるために作業ディレクトリが汚れている場合は終了します。両方のケースを考慮すると、将来の読者にとって質問がより便利になります。
トーマスナイマン14

回答:


134

git status出力は機械可読ではなく人間可読であることを目的としているため、の出力の解析は悪い考えです。Gitの将来のバージョンまたは異なる構成の環境で出力が同じままであるという保証はありません。

UVVのコメントは正しい軌道に乗っていますが、残念ながら、git statusコミットされていない変更があった場合の戻りコードは変わりません。ただし、スクリプトの解析しやすい形式で--porcelain出力をgit status --porcelainフォーマットするオプションを提供し、Gitバージョン間およびユーザー構成に関係なく安定したままになります。

の空の出力をgit status --porcelain、コミットする変更がないことを示すインジケータとして使用できます。

if [ -z "$(git status --porcelain)" ]; then 
  # Working directory clean
else 
  # Uncommitted changes
fi

作業ディレクトリ内の追跡されていないファイルを気にしない場合は、--untracked-files=noオプションを使用してそれらを無視できます。

if [ -z "$(git status --untracked-files=no --porcelain)" ]; then 
  # Working directory clean excluding untracked files
else 
  # Uncommitted changes in tracked files
fi

条件に対して、これはより堅牢にするために、実際に原因git statusを出力せずに失敗してstdout、我々はにチェックを絞り込むことができます。

if output=$(git status --porcelain) && [ -z "$output" ]; then
  # Working directory clean
else 
  # Uncommitted changes
fi

またgit status、作業ディレクトリが汚れている場合は意味のある終了コードを提供しませんが、diffユーティリティと同様に動作するオプションをgit diff提供し--exit-codeます。つまり、違いがあり、何も見つからなかったときにステータスで終了します。10

これを使用して、次の方法でステージングされていない変更を確認できます。

git diff --exit-code

ステージングされたが、コミットされていない変更:

git diff --cached --exit-code

けれどもgit diffへの適切な引数を経由してサブモジュールに人跡未踏のファイルに報告することができ--ignore-submodules、残念ながら実際の作業ディレクトリに人跡未踏のファイルを報告していする方法がないと思われます。作業ディレクトリ内の追跡されていないファイルが関連している場合git status --porcelainは、おそらく最善の方法です。


4
git status --porcelainコミットおよび追跡されていないファイルのステージングされていない変更がある場合でも、ughhh はコード0で終了します。
アレクサンダーミルズ

何ができるかを事前に判断することに興味がありましたgit stash(有用な戻りコードは出力されません)。--ignore-submodulesそうでなければgit statusgit stash無視するサブモジュールの変更を示すように追加する必要がありました。
デビン・レーン

1
@AlexanderMills:同じことを観察しました。しかし、その後、何if [ -zをしているかを確認しました。-z手段その次の文字列が空の場合、もし評価さへtrue。つまり、これgit status --porcelainにより文字列が生成されない場合、リポジトリはクリーンです。そうでない場合は、変更/追加/削除されたファイルがリストされ、空の文字列ではなくなります。ifその後に評価false
アデナック

19

つかいます:

git diff-index --quiet HEAD

戻りコードは、作業ディレクトリの状態を反映しています(0 =クリーン、1 =ダーティ)。追跡されていないファイルは無視されます。


6
現在のディレクトリに追跡されていないファイルがある場合、0を返します。
アダムパーキン

2
ファイルが上書き/触れたが、インデックスと他の点では同じですされていた場合は、最初に実行する必要がありますgit update-index --refresh前にgit diff-index HEAD。詳細:stackoverflow.com/q/34807971/1407170
sffc

@AdamParkinすべてのファイルを追加してgit add .から発行します。通常はスクリプトでそれを使用する方法です
ceztko

これは素晴らしい。ゼロ以外の戻り/終了コードも「エラー」として解釈されます。set-eを使用してスクリプトを実行している場合、「ダーティ」の場合はスクリプトが終了します。これはset +e、への呼び出しの前に実行し、評価した後に再度git追加することで回避できます。set -e$?
オリオンelenzil

1

アンドレの優れた答えマイナーな拡張。

これは、結果を評価する1つの方法であり、以前にset -eを発行したスクリプトを使用している場合の落とし穴も回避します。

追跡されていないファイルは無視されます。

set +e
git diff-index --quiet HEAD

if [ $? == 1 ] ; then
  set -e
  GIT_MODS="dirty"
else
  set -e
  GIT_MODS="clean"
fi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.