ローカルGitリポジトリに変更がある場合、Bashスクリプトをチェックインするにはどうすればよいですか?


176

変更をチェックすると、正しく機能しないスクリプトがいくつかあります。

私はこのようにしてみました:

VN=$(git describe --abbrev=7 HEAD 2>/dev/null)

git update-index -q --refresh
CHANGED=$(git diff-index --name-only HEAD --)
if [ ! -z $CHANGED ];
    then VN="$VN-mod"
fi

前回のコミット以降に変更があったかどうか、ある種のブールチェックはありますか?または、ローカルリポジトリに新しい変更があるかどうかを実際にテストするにはどうすればよいですか?

私は、バージョン作成スクリプト(ここのどこかで見つけたもの)のためにこれをすべて行っています。


3
何が問題になっていgit statusますか?
karlphillip

4
@karlphillip:本当に必要のない多くの処理を行います。
Cascabel、2011

1
@karlphillipこれは「磁器」コマンドです。つまり、出力は人間によって読み取られるように設計されており、バージョン間またはローカライズにより変更される可能性があるため、スクリプトでの使用には適していません
Andrew Spencer

回答:


201

あなたがやっていることはほとんど機能します:$CHANGED空の場合は引用し、空かどうかを-zテストする必要があります。つまり、変更はありません。あなたが意味したのは:

if [ -n "$CHANGED" ]; then
    VN="$VN-mod"
fi

Git'sからの引用GIT-VERSION-GEN

git update-index -q --refresh
test -z "$(git diff-index --name-only HEAD --)" ||
VN="$VN-dirty"

あなたはそれをコピーしていたようですが、引用の詳細を忘れていました。

もちろん、これを行うこともできます。

if git diff-index --quiet HEAD --; then
    # No changes
else
    # Changes
fi

または、「何かが変わった」場合のみを気にする場合:

if ! git diff-index --quiet HEAD --; then
    VN="$VN-mod"
fi

を使用--quietすると、Gitが単一のdiffに遭遇するとすぐに処理を停止できるという利点があるため、ワークツリー全体をチェックする必要がない場合があります。


2
こんにちは、これは質問に対する最良の回答の1つでした。あなたは私に必要なすべての情報と、他の人にも必要な情報をすべて提供してくれました:)。最後の「何かが変わった」だけが必要です:)そして、あなたは正しかった、私はそれをコピーしました。
kmindi

9
驚くべきbash完了スクリプトgit diff --no-ext-diff --quiet --exit-code、ダーティな状態を判別するために使用しているようです。
mjs 2012年

3
@mjs:これは確かにこのようなものを探すのに最適な場所です!この--no-ext-diffオプションは安全性に優れています(誰かが外部diffドライバーを構成している場合)。ただし、--exit-codeこれはによって暗示されるため、必要ありません--quiet
Cascabel 2012年

4
追跡されていないファイルを報告しないため、これは私には機能しません
Cookie

1
git diff-indexファイルの変更時刻のみが変更されても(内容は変更されない)、変更が報告されます。あなたtouchがファイルなら、それは実行git statusがリセットするという修正を報告します。git status以下のように使用することをお勧めします。
サンポ

303

使用git status

cd /git/directory
if [[ `git status --porcelain` ]]; then
  # Changes
else
  # No changes
fi

15
最良の答えは、「シェルおよびgitアーキテクト」からの答えが残念なことです。
jwg 2014

4
バージョン管理されていないファイルを考慮し、磁器を使用するため、これは素晴らしいです。異なるgitバージョンとの互換性が高くなるはずです。
Jayd、2015年

25
追跡されていないファイルを無視するには:if [[ git status --porcelain --untracked-files=no]]; その後
storm_m2138 2017

4
ローカルの変更をチェックする場合-> if [[ $(git status --porcelain | wc -l) -gt 0 ]]; then echo CHANGED else echo NOT CHANGED locally fi
カルロスサルトス

3
このコードの内容:実行git status --porcelain出力が空でないかどうかを確認します。その場合、変更が存在することを意味します。
bhathiya-perera

18

ジェフロミの答えはいいですが、参考のために掲載します。

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
}

参考までに、この権利を読んだ場合、$1は実行するタスクの名前を表す文字列で$2あり、オプションで失敗時のカスタムエラーメッセージを含む文字列です。たとえば、次のように呼び出しますrequire_clean_work_tree deploy "Skipping deploy, clean up your work tree or run dev-push"
Umbrella

6

同様の問題がありましたが、追加されたファイルも確認する必要がありました。だから私は次のことをしました:

cd /local/repo
RUN=0
git diff --no-ext-diff --quiet --exit-code || RUN=1
if [ $RUN = 0 ]; then
    RUN=`git ls-files --exclude-standard --others| wc -l`
fi

if [ $RUN = 0 ]; then
    exit 0
fi

5

git status あなたの友だちです

が機能するようにGitディレクトリに移動git statusします。

cd c:/path/to/.git

変数を設定して作業ツリーを設定し、「この操作は作業ツリーで実行する必要があります」エラーが発生しないようにします。

WORKTREE=c:/path/to/worktree

git status出力をBash変数にキャプチャする

--porcelain標準形式であり、解析可能であることを保証するものを使用します。

CHANGED=$(git --work-tree=${WORKTREE} status --porcelain)

-n(null以外)の場合、変更があります。

if [ -n "${CHANGED}" ]; then
  echo 'changed';

else
  echo 'not changed';
fi

1
これには、追跡されていないファイルを検出するという利点もあります。
Luiz C.

2

これも機能します:

if [ $(git status --porcelain | wc -l) -eq "0" ]; then
  echo "  🟢 Git repo is clean."
else
  echo "  🔴 Git repo dirty. Quit."
  exit 1
fi

1

これはうまくいきます。影響を受けるファイルも一覧表示されます。

if git diff-index --name-status --exit-code HEAD;
then
    echo Git working copy is clean...;
else
    echo ;
    echo ERROR: Git working copy is dirty!;
    echo Commit your changes and try again.;
fi;

1
差分を見たくない場合git diff --no-ext-diff --quiet --exit-codeは、作業も行います。
Alex

1

以下は、差分があるかどうかを確認し、それをユーザーに出力し、展開前に変更をコミットするかどうかをユーザーに確認するBashスクリプト関数の便利なセットです。これは、HerokuおよびPythonアプリケーション用に構築されていますが、他のアプリケーションに変更を加える必要はほとんどありません。

commit(){
    echo "Please enter a commit message..."
    read msg
    git add . --all
    git commit -am $msg
}

check_commit(){
    echo ========== CHECKING FOR CHANGES ========
    changes=$(git diff)
    if [ -n "$changes" ]; then
        echo ""
        echo "*** CHANGES FOUND ***"
        echo "$changes"
        echo ""
        echo "You have uncomitted changes."
        echo "Would you like to commit them (y/n)?"
        read n
        case $n in
            "y") commit;;
            "n") echo "Changes will not be included...";;
            *) echo "invalid option";;
        esac
    else
        echo "... No changes found"
    fi
}

deploy(){
    check_commit
    echo ========== DEPLOYING TO HEROKU ========
    git push heroku master
    heroku run python manage.py syncdb
}

Gistsからコピーできます:https ://gist.github.com/sshadmand/f33afe7c9071bb725105


1

OPの質問は9年以上経過しています。その時何がman git-status言ったのかはわかりませんが、今ここでそれが言っていることです:

--porcelain[=<version>]  
Give the output in an easy-to-parse format for scripts. This is similar to the 
short output, but will remain stable across Git versions and regardless of user 
configuration. See below for details.  

The version parameter is used to specify the format version. This is optional and 
defaults to the original version v1 format.  

これは、この--porcelain議論がリポジトリの変更状況をテストするのに適していることを示唆しています。

OPの質問、「前回のコミット以降に変更があったかどうか、またはローカルリポジトリに新しい変更があるかどうかを実際にテストするにはどうすればよいのか、何らかのブールチェックはありますか?」

私はそれ自体bashはブールデータ型を持っているとは思わないが、これは十分に近いかもしれない:

[ -z "`git status --porcelain`" ] && echo "NULL-NO DIFFS" || echo "DIFFS EXIST"

これはif-then-else、スクリプトのフォームとして再キャストすることも、git repoフォルダー内で CLIをそのまま実行することもできます。それ以外の場合は、目的の-Cリポジトリへのパス仕様を指定してオプションを使用します。

git -C ~/path/to/MyGitRepo status --porcelain 

補遺:

  1. -u, --untracked-file無視したいファイルのステータスを報告しないようにオプションを使用することを勧める人もいます。これには不幸な副作用が伴うことに注意してください。新しく追加されたファイルにもステータスが付けられません。このオプションは状況によっては便利ですが、使用する前に慎重に検討してください。

0

ここに私がそれをする方法があります...

CHANGES=`git status | grep "working directory clean"`
if [ ! CHANGES -eq "" ] then
    # do stuff here
else
    echo "You have uncommitted changes..."
fi

3
私はgitステータスを使用するのが好きですが、バージョン間で互換性のない方法で変更されないことが保証されているため、スクリプトで--porcelainを使用して結果を変更なしの空の文字列と比較することをお勧めします。
Paul Chernoch

0
nano checker_git.sh

これを貼り付け

#!/bin/bash

echo "First arg: $1"

cd $1

bob="Already up-to-date."
echo $bob

echo $(git pull) > s.txt
cat s.txt
if [ "$(cat s.txt)" == "$bob" ]
then
echo "up"
else
echo "not up"

fi
rm -rf st.txt

走る sh checker_git.sh gitpath


0

@RyanMoonの回答への@ storm_m2138コメントに基づいて(リンク)私はで以下を使用していますPowershell

function hasChanges($dir="."){ $null -ne (iex "git -C $dir status --porcelain --untracked-files=no") }

gci -Directory | ?{ hasChanges $_ } | %{ Write-Host "$_ has changes" }
gci -Directory | ?{ hasChanges $_ } | %{ iex "git -C $_ add -u"; iex "git -C $_ commit -m"Somemthing" }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.