現在のブランチでコミットするものがないかどうかを確認するにはどうすればよいですか?


172

目標は、シェルコマンドで評価できる明確なステータスを取得することです。

試しましたgit statusが、コミットする項目がある場合でも、常に0を返します。

git status
echo $?  #this is always 0

私はアイデアを持っていますが、それはむしろ悪いアイデアだと思います。

if [ git status | grep -i -c "[a-z]"> 2 ];
then
 code for change...
else
  code for nothing change...
fi

その他の方法で?


次のソルブで更新します。MarkLongairの投稿を参照してください

これを試しましたが、問題が発生します。

if [ -z $(git status --porcelain) ];
then
    echo "IT IS CLEAN"
else
    echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    echo git status
fi

次のエラーが表示されます [: ??: binary operator expected

今、私は男を見て、git diffを試します。

===================私の希望のコード、そしてより良い答えの希望======================

#if [ `git status | grep -i -c "$"` -lt 3 ];
# change to below code,although the above code is simple, but I think it is not strict logical
if [ `git diff --cached --exit-code HEAD^ > /dev/null && (git ls-files --other --exclude-standard --directory | grep -c -v '/$')` ];
then
        echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    exit 1

else
    exit 0
fi

4
更新セクションでは、あなたが実際に何をやっていないようだeckesに示唆して彼の答え、彼が言うように、あなたの周りに二重引用符を配置する必要があります- $(git status --porcelain)。また、メッセージに感嘆符を付ける場合は、二重引用符ではなく一重引用符を使用する必要があります。つまり、echo 'PLEASE COMMIT YOUR CHANGE FIRST!!!'代わりに使用する必要があります
Mark Longair

4
Markが言うように、私が言ったように、を二重引用符で囲む必要があり$(git status --porcelain)ます!
eckes

1
この質問は、回答の一部が含まれていない場合、はるかに役立つでしょう。
12

@ 9nix00は言われたことを行い、上記のシェルスクリプトのバグを編集および修正します。BUG:if [-z $(some command)] FIX:if [-z "$(some command)"]
MarcH

回答:


232

の出力git status --porcelainが空かどうかをテストする代わりに、気になる各条件を個別にテストすることもできます。たとえば、の出力に追跡されていないファイルが含まれているかどうかは気にならない場合がありますgit status

たとえば、ローカルのステージングされていない変更があるかどうかを確認するには、次の戻りコードを確認します。

git diff --exit-code

ステージングされているがコミットされていない変更があるかどうかを確認するには、以下の戻りコードを使用できます。

git diff --cached --exit-code

最後に、作業ツリーに無視されない追跡されていないファイルがあるかどうかを知りたい場合は、次のコマンドの出力が空かどうかをテストできます。

git ls-files --other --exclude-standard --directory

更新: 以下のコマンドを変更して、出力からディレクトリを除外できるかどうかを尋ねます。空のディレクトリ--no-empty-directoryを除外するには、を追加しますが、その出力のすべてのディレクトリを除外するには、次のように出力をフィルタリングする必要があると思います。

git ls-files --other --exclude-standard --directory | egrep -v '/$'

手段にのみ出力パターンに一致しない行、およびパターンは任意の行とその両端に一致します。-vegrep/


私はこれらのヒントを学んで、問題があります。つまり、git ls-files --other --exclude-standard --directoryを使用して、リストインクルードディレクトリを取得します。これらのディレクトリを除外する方法はありますか?
9nix00

はい、これは私が欲しいです。そして、新しいスクリプトコード用に投稿を更新します。私はあなたの提案がより厳密な論理的であると思いますが、より多くのコードが笑っています...
9nix00 2011年

3
@albfan:git-diffのmanページにあります:「diff(1)と同様のコードでプログラムを終了させます。つまり、相違点がある場合は1で終了し、相違点がない場合は0で終了します。」
Mark Longair、2014年

指摘しておきますが、少なくとも2007年から存在しています13da0fc0、シェルスクリプトに非常に便利で、古いバージョンのgitと完全に互換性があります
albfan

10
--quiet(これはを意味します--exit-code)また、終了コードのみを必要とする人のために、出力を抑制します。
phs

113

の戻り値は、コミットされる変更があるかどうかではなくgit status、の終了コードを通知するだけですgit status

よりコンピューターで読み取り可能なバージョンのgit status出力が必要な場合は、

git status --porcelain

詳細については、の説明を参照してくださいgit status

使用例(スクリプトgit status --porcelainは、出力があるかどうかをテストするだけであり、解析は必要ありません):

if [ -n "$(git status --porcelain)" ]; then
  echo "there are changes";
else
  echo "no changes";
fi

テストする文字列、つまりの出力を引用する必要があることに注意してくださいgit status --porcelain。テストコンストラクトの詳細については、「高度なBashスクリプトガイド(セクション文字列の比較」を参照してください。


こんにちは、あなたは良い提案をしました、私はそれを試しましたが、スクリプトでは、それはいくつかの問題を引き起こします、私がこれを使用した場合、それを改善しました[-z $(git status --porcelain)]; エラーが発生します。[:??:バイナリ演算子が必要です。マニュアルを見つけて、[-z $(git status --short)]の場合はこれを使用します。これは機能します、ありがとう!
9nix00

申し訳ありませんが、まだ問題があります。コミットがクリーンなとき。磁器を使用し、両方ともOKです。しかし、コミットがクリーンでない場合。エラーになります。[:??:二項演算子が必要です。おそらく、base64を使用してエンコードする必要があると思います。私が試してみましょう!base64コマンドツールのダウンロード.... lol
9nix00

コミットがクリーンでない場合に問題が発生します。
9nix00

1
素晴らしいソリューション。堅牢性を高める|| echo noために、コマンド置換に追加して、git status根本的に失敗した場合にワークスペースが誤ってクリーンと報告されないようにすることができます。また、コードは(賞賛すべき)POSIX準拠ですが、bashガイドにリンクしているため[[ ... ]]、POSIX互換ではなくbashを使用する[ ... ]場合は、コマンド置換を二重引用符で囲む必要はありません(ただし、害は)しません:[[ -z $(git status --porcelain) ]]
mklement0 2014年

@eckes数日前に新しいレポを開始し、コミットを追加しました。コミット前フックをいくつか記述して、何をコミットするか、そしてあなたの言うことが私のケースでは機能しなかったことを確認しました。
alinsoar 2018年

33

あなたが私のような人なら、あなたは以下があるかどうか知りたいです:

1)既存のファイルへの変更2)新しく追加されたファイル3)削除されたファイル

特に4)追跡されていないファイルについて知りたくありません。

これはそれを行うはずです:

git status --untracked-files=no --porcelain

以下は、リポジトリがクリーンな場合にスクリプトを終了するためのbashコードです。追跡されていないファイルオプションの短いバージョンを使用します。

[[ -z $(git status -uno --porcelain) ]] && echo "this branch is clean, no need to push..." && kill -SIGINT $$;

4
+1 —untracked-files=no; テストはに簡略化できると思います[[ -z $(git status --untracked-files=no --porcelain) ]]git status基本的なエラーが発生しない限り、stderrに書き込んではいけません。その出力を確認たい場合は、(そのイベントでより堅牢な動作が必要な場合は|| echo no、コマンド置換に追加して、クリーン性のテストが失敗するようにします)。文字列比較/ -z演算子は複数行の文字列を処理できます-の必要はありませんtail
mklement0 2014年

2
mklement0 @おかげで、少しでも短く:[[ -z $(git status -u no --porcelain) ]]
moodboom

1
訂正:私の短いバージョンは、実際には「no」という名前のファイルのステータスをチェックするだけです!Bzzt。する必要があります: [[ -z $(git status -uno --porcelain) ]]
moodboom

2
フォローアップに感謝します。それは微妙なバグです-教訓は、オプションの引数を持つ短い オプションは、間に空白を入れずに直接引数を追加する必要があるということです。修正された短いバージョンを直接回答に組み込むのはどうですか?
mklement0

9

git status --porcelain簡単なgrepテストと組み合わせることが可能です。

if git status --porcelain | grep .; then
    echo Repo is dirty
else
    echo Repo is clean
fi

私は時々これを単純なワンライナーとして使用します:

# pull from origin if our repo is clean
git status --porcelain | grep . || git pull origin master

-qsサイレントにするには、grepコマンドに追加します。


2
上品さのために+1。わずかな注意:git status致命的に失敗するはずです(たとえば、レポジトリの破損)。テストでは、クリーンなワークスペースが誤って報告されます。1つのオプションはを使用することgit status --porcelain 2>&1ですが、でgrepを使用した場合、エラーメッセージが「食われる」ことになります-q。(それに対処する優雅さを失うことになります。(git status --porcelain || echo err) | grep -q .
mklement0

または、次のように書くこともできますtest -z "$(git status --porcelain)" || git pull origin master
。– VasiliNovikov

5

gitソースコードから、以下を含むshスクリプトがあります。

require_clean_work_tree () {
    git rev-parse --verify HEAD >/dev/null || exit 1
    git update-index -q --ignore-submodules --refresh
    err=0

    if ! git diff-files --quiet --ignore-submodules
    then
        echo >&2 "Cannot $1: You have unstaged changes."
        err=1
    fi

    if ! git diff-index --cached --quiet --ignore-submodules HEAD --
    then
        if [ $err = 0 ]
        then
            echo >&2 "Cannot $1: Your index contains uncommitted changes."
        else
            echo >&2 "Additionally, your index contains uncommitted changes."
        fi
        err=1
    fi

    if [ $err = 1 ]
    then
        test -n "$2" && echo >&2 "$2"
        exit 1
    fi
}

このsnipletショーは、どのようにその可能性を使用するgit diff-filesと、git diff-index以前から知られているファイルが変更されたかどうかを確認します。ただし、新しい不明なファイルが作業ツリーに追加されたかどうかを確認することはできません。


これは、新しいファイルを除いて正常に動作します。これを追加できます。もし!git ls-files --other --exclude-standard --directory | grep -c -v '/ $' then exit 0 else echo "新しいファイルをコミットしてください。追加したくない場合は、git-ignoreファイルに追加してください。" 1 fiを終了
9nix00

ただ、if [ -n "$(git ls-files --others --exclude-standard)" ]追加の配管やgrepingせずに追跡されていないファイルを検出するのに十分でなければなりません。
Arrowmaster

5

これについてテストを行います:

git diff --quiet --cached

またはこれは明示的です:

git diff --quiet --exit-code --cached

どこ:

--exit-code

diff(1)と同様のコードでプログラムを終了させます。つまり、差があった場合は1で終了し、0は差がないことを意味します。

- 静か

プログラムのすべての出力を無効にします。暗黙の--exit-code


3

私は議論に少し遅れていますが、git status --porcelain何も返さない場合は終了コード0が必要であり、それ以外の場合は!= 0でなければ、次のように試してください。

exit $( git status --porcelain | wc -l )

これにより、行数が終了コードになり、255行を超えると問題が発生する可能性があります。そう

exit $( git status --porcelain | head -255 | wc -l )

それを説明します;)


1
255行を超える出力がある場合、これは基本的に未定義になります。
3

よくわかりました、ありがとう!
Skeeve

2

私はこれをスクリプトで使用しています:

  • すべてがきれいな場合は0
  • 1差分または追跡されていないファイルがある場合

    [-z "$(git status --porcelain)"]


使用するif ! git diff --quiet; thenと、よりクリーンでパフォーマンスが向上します(私はそう思います)。つまり、標準出力ではなく、終了コードを使用します。
Alexander Mills

1
@AlexanderMillsのgit diff --quiet動作はgit status --porcelain、キャッシュされた変更の場合とは異なります。
Martin von Wittich

0

きれいではありませんが、動作します:

git status | grep -qF 'working directory clean' || echo "DIRTY"

メッセージがロケールに依存するかどうかわからないので、おそらくLANG=C前に置く。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.