Gitリポジトリにコミットされていない変更があるかどうかを確認するにはどうすればよいですか:
スクリプトから?
git-status
は、gitバージョン1.6.4.2では常にゼロを返すようです。
素晴らしいタイミング!数日前にまさにこれについてのブログ記事を書きました。そのとき、プロンプトにgitステータス情報を追加する方法を見つけました。
ここに私がやることがあります:
ダーティステータスの場合:
# Returns "*" if the current git branch is dirty.
function evil_git_dirty {
[[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]] && echo "*"
}
追跡されていないファイルの場合(--porcelain
フラグがgit status
に通知されます。これにより、解析可能な出力が得られます):
# Returns the number of untracked files
function evil_git_num_untracked_files {
expr `git status --porcelain 2>/dev/null| grep "^??" | wc -l`
}
git diff --shortstat
の方が便利ですが、git status --porcelain
を使用してダーティファイルを取得することもできます。
# Get number of files added to the index (but uncommitted)
expr $(git status --porcelain 2>/dev/null| grep "^M" | wc -l)
# Get number of files that are uncommitted and not added
expr $(git status --porcelain 2>/dev/null| grep "^ M" | wc -l)
# Get number of total uncommited files
expr $(git status --porcelain 2>/dev/null| egrep "^(M| M)" | wc -l)
注:2>/dev/null
はエラーメッセージを除外するため、これらのコマンドをgit以外のディレクトリで使用できます。 (ファイル数については、単に0
を返します。)
編集:
投稿は次のとおりです。
Gitを確実に「スクリプト化」するための鍵は、「配管」コマンドを使用することです。
開発者は、配管コマンドを変更するときに注意して、非常に安定したインターフェイスを提供するようにします(つまり、リポジトリ状態、stdin、コマンドラインオプション、引数などの特定の組み合わせは、コマンド/オプションが存在します)。配管コマンドの新しい出力バリエーションは、新しいオプションを介して導入できますが、古いバージョンに対して既に作成されたプログラムには問題を導入できません(新しいオプションは存在しなかったため、使用しませんでした(少なくとも、使用されていません)スクリプトの作成時)。
残念ながら、「毎日」のGitコマンドは「磁器」コマンドなので、ほとんどのGitユーザーは配管コマンドに慣れていない可能性があります。磁器と配管コマンドの区別は、メインで行われます git manpage ( 高レベルコマンド(磁器) と 低レベルコマンド(配管) ) 。
コミットされていない変更を見つけるには、おそらく git diff-index
(他のツリー(たとえばHEAD
)とインデックス(およびおそらく追跡された作業ツリーのビット)を比較します)、おそらく git diff-files
(インデックスに対して作業ツリーを比較します)、そしておそらく git ls-files
(ファイルをリストします。例えば、追跡されていない無視されないファイルをリストします).
(以下のコマンドでは、HEAD
の代わりにHEAD --
が使用されることに注意してください。そうでない場合は、コマンド fails がHEAD
という名前のファイルがある場合)
リポジトリが変更をステージングした(まだコミットされていない)かどうかを確認するには、次を使用します。
git diff-index --quiet --cached HEAD --
0
で終了する場合、違いはありませんでした(1
は違いがあることを意味します)。作業ツリーにステージングできる変更があるかどうかを確認するには:
git diff-files --quiet
git diff-index
の場合と同じです(0
==違いなし; 1
==違い)。インデックスと作業ツリー内の追跡対象ファイルの組み合わせにHEAD
に関して変更があるかどうかを確認するには:
git diff-index --quiet HEAD --
HEAD
にある内容に戻る」)、引き続き「違いなし」を報告することです。これと同じ状況で、2つの別々のコマンドは両方とも「差異が存在する」というレポートを返します。追跡されていないファイルについても言及しました。 「追跡されず無視されない」ことを意味する場合もあれば、単なる「追跡されない」ことを意味する場合もあります(無視されたファイルを含む)。いずれにせよ、git ls-files
は仕事のためのツールです:
「未追跡」の場合(存在する場合、無視されたファイルが含まれます):
git ls-files --others
「追跡されず無視されない」場合:
git ls-files --exclude-standard --others
私の最初の考えは、これらのコマンドに出力があるかどうかを確認することです。
test -z "$(git ls-files --others)"
0
で終了する場合、追跡されていないファイルはありません。 1
で終了する場合、追跡されていないファイルがあります。これにより、git ls-files
からの異常終了が「追跡されていないファイルなし」レポートに変換される可能性がわずかにあります(両方とも上記のコマンドのゼロ以外の終了になります)。もう少し堅牢なバージョンは次のようになります。
u="$(git ls-files --others)" && test -z "$u"
git ls-files
からの予期しないエラーが伝播する可能性があります。この場合、ゼロ以外の出口は「追跡されていないファイルがある」ことを意味するか、エラーが発生したことを意味します。代わりに「エラー」結果を「追跡されていないファイルなし」の結果と組み合わせたい場合は、test -n "$u"
を使用します(0
の終了は「追跡されていないファイル」を意味し、ゼロ以外はエラーまたは「追跡されていないファイルなし」を意味します)。別のアイデアは、追跡されていないファイルがないときに--error-unmatch
を使用してゼロ以外の終了を引き起こすことです。また、「追跡されていないファイルがない」(exit 1
)と「エラーが発生しました」(ゼロ以外の終了、ただし128
)を混同するリスクもあります。しかし、0
対1
対0以外の終了コードのチェックは、おそらくかなり堅牢です。
git ls-files --others --error-unmatch . >/dev/null 2>&1; ec=$?
if test "$ec" = 0; then
echo some untracked files
Elif test "$ec" = 1; then
echo no untracked files
else
echo error from ls-files
fi
上記のgit ls-files
の例はいずれも、追跡されていない無視されていないファイルのみを検討する場合に--exclude-standard
を使用できます。
git 1.7.0以降を使用している場合...
このページのすべての回答といくつかの実験を読んだ後、正確さと簡潔さの正しい組み合わせを見つける方法は次のとおりだと思います。
test -n "$(git status --porcelain)"
Gitは、追跡、無視、追跡されないが無視されないなどの間で多くのニュアンスを可能にしますが、典型的なユースケースは、チェックアウトがクリーンでない場合にすべてを停止するビルドスクリプトを自動化することです。
その場合、プログラマが何をするかをシミュレートすることは理にかなっています:git status
と入力して出力を確認します。ただし、表示される特定の単語に依存したくないため、1.7.0で導入された--porcelain
モードを使用します。有効にすると、クリーンなディレクトリは出力されません。
次に、test -n
を使用して、出力があったかどうかを確認します。
このコマンドは、作業ディレクトリがクリーンな場合は1を返し、コミットする変更がある場合は0を返します。反対の場合は、-n
を-z
に変更できます。これは、これをスクリプト内のコマンドにチェーンするのに便利です。例えば:
test -z "$(git status --porcelain)" || red-alert "UNCLEAN UNCLEAN"
これは、「変更する必要がないか、アラームをオフにする」という事実を効果的に示しています。書くスクリプトによっては、このワンライナーはifステートメントよりも望ましい場合があります。
VonC の答えからの実装:
if [[ -n $(git status --porcelain) ]]; then echo "repo is dirty"; fi
これらの答えのいくつかを見てみました...(そして* nixとwindowsでさまざまな問題がありましたが、これは私が持っていた要件でした)...以下がうまくいくことがわかりました...
git diff --no-ext-diff --quiet --exit-code
* nixの終了コードを確認するには
echo $?
#returns 1 if the repo has changes (0 if clean)
Window $の終了コードを確認するには
echo %errorlevel%
#returns 1 if the repos has changes (0 if clean)
ソース: https://github.com/sindresorhus/pure/issues/115 共有してくれた投稿の@paulirishに感謝
次のようなスクリプトで 'git status
をカプセル化しない理由:
そうすれば、スクリプトでその「拡張」ステータスを使用できます。
xfe が excellent answer で言及しているように、git status --porcelain
はスクリプトベースのソリューションに役立つ
--porcelain
安定した、解析しやすいスクリプト形式で出力を提供します。
現在、これは--short output
と同じですが、将来変更されないことが保証されており、スクリプトに対して安全です。
xfe の提案に従うように更新された1つのDIYの可能性
#!/bin/sh
exit $(git status --porcelain | wc -l)
Chris Johnsen で述べたように、これはGit 1.7.0以降でのみ機能します。
実行の最後に変更された追跡ファイルまたは無視されない追跡されていないファイルがある場合、ビルドを失敗させる簡単な方法が非常に頻繁に必要でした。
これは、ビルドが残り物を生成するケースを回避するために非常に重要です。
これまでのところ、私が使用することになった最高のコマンドは次のようになります。
test -z "$(git status --porcelain | tee /dev/fd/2)" || \
{{ echo "ERROR: git unclean at the end, failing build." && return 1 }}
それは少し複雑に見えるかもしれませんし、誰かがこれが望ましい動作を維持する短絡バリアントを見つけたら感謝します:
@ eduard-wirchの回答は非常に完全でしたが、両方を同時にチェックしたかったので、ここに私の最終的なバリエーションがあります。
set -eu
u="$(git ls-files --others)"
if ! git diff-index --name-only --quiet HEAD -- || [ -z "${u:-}" ]; then
dirty="-dirty"
fi
Set -eまたは同等の機能を使用して実行しない場合、代わりにu="$(git ls-files --others)" || exit 1
を実行できます(または、これが使用された関数で機能する場合に戻ります)
したがって、untracked_filesは、コマンドが正常に成功した場合にのみ設定されます。
その後、両方のプロパティを確認し、変数(または何でも)を設定できます。
あなたもできる
git describe --dirty
。汚れた作業ツリーを検出した場合、Wordの末尾に「-dirty」が追加されます。 git-describe(1)
によると:
--dirty[=<mark>]
Describe the working tree. It means describe HEAD and appends <mark> (-dirty by default) if
the working tree is dirty.
。警告:追跡されていないファイルは「ダーティ」とは見なされません。これは、マンページに記載されているように、作業ツリーのみを考慮しているためです。
これは、any追跡されていないファイルがリポジトリに存在するかどうかを調べるための、よりシェルに優しいバリエーションです。
# Works in bash and zsh
if [[ "$(git status --porcelain 2>/dev/null)" = *\?\?* ]]; then
echo untracked files
fi
これは2番目のプロセスgrep
を分岐せず、gitリポジトリにいるかどうかを確認する必要もありません。シェルプロンプトなどに便利です。
このスレッドからの回答のより良い組み合わせがあるかもしれません..しかし、これは私のために動作します...あなたの.gitconfig
の[alias]
セクションのために...
# git untracked && echo "There are untracked files!"
untracked = ! git status --porcelain 2>/dev/null | grep -q "^??"
# git unclean && echo "There are uncommited changes!"
unclean = ! ! git diff --quiet --ignore-submodules HEAD > /dev/null 2>&1
# git dirty && echo "There are uncommitted changes OR untracked files!"
dirty = ! git untracked || git unclean
dirty state =未追跡ファイルを含むすべての変更を検出するために使用する最も単純な自動テスト:
git add --all
git diff-index --exit-code HEAD
注意:
add --all
diff-index
がなければ、追跡されていないファイルに気付きません。git reset
を実行して、すべてのステージングを解除します。