로컬 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

1
@karlphillip "porcelain"명령입니다. 즉, 출력은 사람이 읽도록 설계되어 있으며 (버전 간 또는 지역화로 인해) 변경 될 수 있기 때문에 스크립트에 사용하기에 적합하지 않습니다.
Andrew Spencer

답변:


201

당신이하고있는 일은 거의 효과가 있습니다. $CHANGED비어 있으면 인용 하고 비우기를 -z테스트해야합니다. 이는 변경이 없음을 의미합니다. 당신이 의미 한 것은 :

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

Git의 인용문 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

사용하면 --quietGit이 단일 diff를 발견하자마자 처리를 중단 할 수 있다는 이점이 있으므로 전체 작업 트리를 확인하지 않아도됩니다.


2
안녕하세요, 그것은 질문에 대한 최고의 답변 중 하나였습니다. 당신은 나에게 필요한 모든 정보와 다른 사람들에게도 필요한 정보를 줬습니다. :). 나는 "뭔가 바뀌었다"라는 마지막 것을 필요로 할 것이다. :) 당신이 옳았다. 나는 그것을 복사했다.
kmindi

9
놀라운 bash 완성 스크립트git diff --no-ext-diff --quiet --exit-code 는 더티 상태를 결정하는 데 사용 되는 것 같습니다 .
mjs

3
@ mjs : 실제로 이와 같은 것을 찾을 수있는 좋은 장소입니다! --no-ext-diff(가) 비록 옵션은 (경우에 누군가가 외부 DIFF 드라이버를 구성한) 안전을 위해 좋은 --exit-code이 암시 이후, 필요는 없습니다 --quiet.
Cascabel

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 architects'의 답변이 더 높은 투표를받은 것입니다.
jwg

4
버전이없는 파일을 고려하고 도자기를 사용하기 때문에 다른 git 버전과 더 호환되어야합니다.
Jayd

25
추적되지 않은 파일을 무시하려면 : if [[ git status --porcelain --untracked-files=no]]; then
storm_m2138

4
로컬 변경 사항 확인-> if [[ $(git status --porcelain | wc -l) -gt 0 ]]; then echo CHANGED else echo NOT CHANGED locally fi
Carlos Saltos

3
이 코드는 무엇을 : 실행 git status --porcelain출력이 비어 있지 않은 경우를 참조하십시오. 그렇다면 변경 사항이 있음을 의미합니다.
bhathiya-perera

18

Jefromi의 답변은 좋지만 참고 용으로 게시하고 있습니다.

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"
우산

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 status작동 하려면 Git 디렉토리로 변경하십시오 .

cd c:/path/to/.git

'작업 트리에서 실행해야합니다'오류가 표시되지 않도록 변수를 설정하여 작업 트리를 설정하십시오.

WORKTREE=c:/path/to/worktree

캡처 git statusBash 변수에서 출력

--porcelain표준 형식이며 구문 분석이 가능한 것을 사용하십시오 .

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

-n (널이 아님)이면 변경 사항이 있습니다.

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
diff를보고 싶지 않으면 git diff --no-ext-diff --quiet --exit-code작동합니다.
Alex

1

다음은 diff가 있는지 확인하고이를 사용자에게 인쇄 한 후 배포 전에 변경 사항을 커밋할지 묻는 메시지를 표시하는 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
}

https://gist.github.com/sshadmand/f33afe7c9071bb725105 에서 Gists에서 복사 할 수 있습니다.


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 status를 사용하는 것이 좋지만 스크립트에서 --porcelain을 사용하고 변경 사항이없는 빈 문자열과 결과를 비교하는 것이 좋습니다. 버전간에 호환되지 않는 방식으로 변경되지 않도록 보장하기 때문입니다.
Paul Chernoch 2016 년

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

@ storm_m2138 @RyanMoon의 답변 ( 링크 )에 대한 의견을 바탕으로에 다음을 사용하고 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.