Git으로 더티 인덱스 또는 추적되지 않은 파일 확인


243

내 git 저장소에 커밋되지 않은 변경 사항이 있는지 어떻게 확인할 수 있습니까?

  1. 인덱스에 추가되었지만 커밋되지 않은 변경 사항
  2. 추적되지 않은 파일

스크립트에서?

git-status git 버전 1.6.4.2에서는 항상 0을 반환하는 것으로 보입니다.


3
준비되지 않은 수정 된 파일이 있으면 git status는 1을 반환합니다. 그러나 일반적으로 git 도구는 특히 반환 상태에 철저하지는 않습니다. EG git diff는 차이가 있는지 여부에 관계없이 0을 반환합니다.
intuited

11
@intuited : 당신이 필요로하는 경우 diff차이가 아니라 명령의 성공적인 실행의 유무를 표시하기 위해 당신은 사용할 필요 --exit-code--quiet. git 명령은 일반적으로 0 또는 0이 아닌 종료 코드를 반환하여 명령의 성공을 나타냅니다.
CB Bailey

1
@Charles Bailey : 이봐, 나는 그 옵션을 놓쳤다. 감사! 나는 그것을하기 위해 실제로 그것을 필요로하지 않았거나 아마도 맨 페이지를 닦았을 것입니다. 다행입니다. :)
attuited

1
로버트-이것은 커뮤니티에 매우 혼란스러운 주제입니다 ( '포셀린'이 다른 상황에서 다르게 사용되는 것을 돕지 않습니다). 선택한 답변은 더 강력한 투표의 2.5 배 배 높은 답변을 무시하고 git 디자인을 따릅니다. @ChrisJ의 답변을 보셨습니까?
mike

1
@Robert-허용되는 답변을 변경하는 것이 좋습니다. 선택한 것은보다 취약한 자식 'porcelain'명령에 의존합니다. 실제 정답은 2 배 의 upvotes 와 함께 올바른 git 'plumbing'명령에 의존합니다. 그 정답은 원래 Chris Johnsen이했습니다. 오늘 이이 페이지를 누군가에게 추천 해야하는 세 번째 시간이므로 이것을 가져옵니다.하지만 대답을 가리킬 수는 없습니다. 왜 받아 들여진 대답이 차선책 / 경계선이 잘못되었는지 설명했습니다. 감사합니다!
mike

답변:


173

좋은 타이밍! 나는 며칠 전에 정확하게 git status 정보를 프롬프트에 추가하는 방법을 알았을 때 블로그 게시물을 작성했습니다.

내가하는 일은 다음과 같습니다.

  1. 더티 상태의 경우 :

    # Returns "*" if the current git branch is dirty.
    function evil_git_dirty {
      [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]] && echo "*"
    }
  2. 추적되지 않은 파일의 경우 ( 파싱 ​​가능한 출력을 제공 하는 --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 상태 정보 추가

향상된 Git 지원 쉘 프롬프트


8
git bash 완성에는 프롬프트로 수행하는 작업을 거의 수행하기위한 쉘 기능이 제공된다는 점에 주목할 가치가 있습니다 __git_ps1. 그것은 당신이 rebase, am-apply, merge 또는 bisect의 과정에서 특별한 치료를 포함한 지사 이름을 보여줍니다. 또한 환경 변수 GIT_PS1_SHOWDIRTYSTATE를 설정하여 비 단계적 변경에 대한 별표와 단계적 변경에 대한 별표를 얻을 수 있습니다. (추적되지 않은 파일을 표시하고 git-describe출력 할 수도 있습니다)
Cascabel

8
경고 : git diff --shortstat변경 사항이 이미 색인에있는 경우 거짓 부정을 제공합니다.
Marko Topolnik

4
git status --porcelain때문에 바람직하고, git diff --shortstat새로 생성 된 빈 파일을 잡을 수 없습니다. 당신은 어떤 깨끗한 작업 트리에서 그것을 시도 할 수 있습니다 :touch foo && git diff --shortstat
Campadrenalin

7
아니오-도자기 란 결과물이 사람을 위한 것이며 쉽게 깨짐 을 의미합니다 !! 안정적이고 스크립트 친화적 인 옵션을 올바르게 사용하는 @ChrisJohnsen의 답변을 참조하십시오.
mike

7
도자기 옵션에 대한 git-status 매뉴얼 페이지의 @mike : "스크립트를 위해 구문 분석하기 쉬운 형식으로 출력을 제공합니다. 이는 짧은 출력과 비슷하지만 사용자 구성에 관계없이 Git 버전에서 안정적으로 유지됩니다. "
itsadok

399

Git을“스크립트”로 확실하게 만드는 열쇠는 '배관'명령을 사용하는 것입니다.

개발자는 배관 명령을 변경할 때 매우 안정적인 인터페이스를 제공하도록주의를 기울입니다 (예 : 지정된 저장소 상태, stdin, 명령 행 옵션, 인수 등의 조합이 명령 / 명령이있는 모든 버전의 Git에서 동일한 출력을 생성 함) 옵션이 존재합니다). 배관 명령의 새로운 출력 변형은 새로운 옵션을 통해 도입 될 수 있지만 이전 버전에 대해 이미 작성된 프로그램에는 아무런 문제가 발생할 수 없습니다 (새로운 옵션은 존재하지 않았기 때문에 (또는 적어도 사용되지 않음) 스크립트가 작성된 시점).

불행히도 '매일'Git 명령은 'porcelain'명령이므로 대부분의 Git 사용자는 배관 명령에 익숙하지 않을 수 있습니다. 자기 명령과 배관 명령의 구분은 기본 git 맨 페이지 에서 이루어집니다 (하위 레벨 명령 (도자기)하위 레벨 명령 (배관) 이라는 하위 섹션 참조 ) .


커밋되지 않은 변경 사항을 찾으려면 git diff-index다른 트리 (예 :)와 비교하여 인덱스 (및 작업 트리의 추적 비트 비교 HEAD), git diff-files(인덱스와 작업 트리 비교) 및 git ls-files(파일 목록; 추적되지 않은 목록 나열) , 무시되지 않은 파일).

(아래 명령에서 이라는 파일 있으면 명령 이 실패 하기 때문에 HEAD --대신 사용됩니다 .)HEADHEAD

리포지토리가 단계적 변경 (아직 커밋되지 않은)을 확인하려면 다음을 사용하십시오.

git diff-index --quiet --cached HEAD --
  • 종료되면 0차이가 없었습니다 (차이가 1있음을 의미).

작업 트리에 스테이징 가능한 변경 사항이 있는지 확인하려면 다음을 수행하십시오.

git diff-files --quiet
  • 종료 코드는 git diff-index( 0== 차이점 없음; 1== 차이점)과 동일합니다.

작업 트리에서 색인과 추적 된 파일의 조합이 다음과 관련하여 변경되었는지 확인하려면 다음을 수행하십시오 HEAD.

git diff-index --quiet HEAD --
  • 이것은 이전 두 가지의 조합과 같습니다. 주요한 차이점 중 하나는 작업 트리에서 "실행 취소"한 단계적 변경 사항이있는 경우 여전히 "차이 없음"을보고한다는 것입니다 (에있는 내용으로 돌아 가기 HEAD). 이와 같은 상황에서 두 개의 개별 명령은 모두 "차이가 존재"한다는 보고서를 반환합니다.

추적되지 않은 파일도 언급했습니다. "추적되지 않은 및 무시 됨"을 의미하거나 일반 "추적되지 않은"(무시 된 파일 포함)을 의미 할 수 있습니다. 어느 쪽이든 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가 전파 될 수 있습니다. 이 경우, 0이 아닌 종료는 "추적되지 않은 파일이 있음"을 의미하거나 오류가 발생했음을 의미 할 수 있습니다. 대신 "오류"결과와 "추적되지 않은 파일 없음"결과를 함께 사용하려면 test -n "$u"종료를 0"추적되지 않은 일부 파일", 0이 아닌 경우 오류 또는 "추적되지 않은 파일 없음"을 사용하십시오.

또 다른 아이디어는 --error-unmatch추적되지 않은 파일이 없을 때 0이 아닌 종료를 발생시키는 데 사용 하는 것입니다. 또한 1"오류가 발생했습니다"(0이 아닌 경우도 있지만)로 " 추적되지 않은 파일 없음"(종료 ) 을 병합 할 위험이 있습니다 128. 그러나 0이 아닌 종료 코드 01vs. 종료 코드를 확인하는 것은 상당히 강력합니다.

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.


5
로컬 추적되지 않은 파일 을 git ls-files --others제공 하는 반면 , 허용되는 답변 중 하나는 git 저장소 아래에있는 모든 추적되지 않은 파일을 제공합니다. 나는 원래 포스터 중 어느 것이 원하는지는 아니지만 두 가지의 차이점은 흥미 롭습니다. git status --porcelain
Eric O Lebigot

1
@phunehehe :로 pathspec을 제공해야합니다 --error-unmatch. 시도하십시오 (예 : git ls-files --other --error-unmatch --exclude-standard .말미에 cwd를 참조하십시오; 작업 트리의 최상위 디렉토리에서 실행하십시오).
Chris Johnsen

8
@phs : 당신은 수행해야 할 수 있습니다 git update-index -q --refresh(가) 이전 diff-index통계 (2) 정보가 일치하지에 의해 발생하는 몇 가지 "잘못된 반응"을 피하기 위해.
Chris Johnsen

1
나는 git update-index필요 에 물렸다 ! 파일을 수정하지 않고 파일을 만지고있는 경우 중요합니다.
Nakedible

2
@RobertSiemer "local"이란 현재 디렉토리 아래의 파일을 의미하며 , 이는 기본 git 저장소 아래에 있을 수 있습니다 . 이 --porcelain솔루션은 하위 디렉토리 중 하나에 있더라도 전체 git 저장소 (git 무시 파일 제외) 에서 발견 된 모든 추적되지 않은 파일을 나열합니다 .
Eric O Lebigot

139

git 1.7.0 이상이라고 가정하면 ...

이 페이지의 모든 답변과 몇 가지 실험을 읽은 후 정확성과 간결함의 올바른 조합을 달성하는 방법은 다음과 같습니다.

test -n "$(git status --porcelain)"

git은 추적, 무시, 추적되지 않지만 무시되지 않은 것들 사이에 많은 뉘앙스를 허용하지만, 일반적인 사용 사례는 빌드 스크립트를 자동화하는 것이며, 체크 아웃이 깨끗하지 않으면 모든 것을 중지하려는 경우입니다.

이 경우 프로그래머가하는 일을 시뮬레이션하는 것이 합리적입니다 : git status출력을보고 입력 하십시오. 그러나 특정 단어가 표시되는 것을 원하지 않기 때문에 --porcelain1.7.0에 도입 된 모드를 사용합니다 . 사용 가능한 경우, 클린 디렉토리는 출력되지 않습니다.

그런 다음 test -n출력이 있는지 여부를 확인 하는 데 사용 합니다.

이 명령은 작업 디렉토리가 깨끗하면 1을 반환하고 커밋해야 할 변경 사항이 있으면 0을 반환합니다. 당신은을 변경할 수 있습니다 -nA와 -z는 반대합니다. 스크립트의 명령에이를 연결하는 데 유용합니다. 예를 들면 다음과 같습니다.

test -z "$(git status --porcelain)" || red-alert "UNCLEAN UNCLEAN"

이것은 "변경하거나 알람을 설정하지 않습니다"라고 효과적으로 말합니다. 이 one-liner는 작성하는 스크립트에 따라 if 문보다 선호 될 수 있습니다.


1
나에게 다른 모든 명령은 Linux와 Windows 간의 동일한 응답에서 다른 결과를 제공했습니다. 이 명령은 둘 다 동일한 출력을 주었다.
Adarsha

6
질문에 대답하고 답답하지 않고 분명한 답변을 제공하지 않습니다.
NateS

수동 배포 스크립트의 경우 배포와 함께 test -n "$(git diff origin/$branch)"로컬 커밋이 허용되지 않도록하기 위해
이것을와 결합하십시오

14

VonC 의 답변 에서 구현 :

if [[ -n $(git status --porcelain) ]]; then echo "repo is dirty"; fi

8

이 답변 중 몇 가지를 살펴 보았습니다 ... (그리고 * 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에게 감사드립니다.


4

다음 git status과 같은 스크립트로 ' 를 캡슐화하지 마십시오 .

  • 해당 명령의 출력을 분석합니다
  • 필요한 것을 기반으로 적절한 오류 코드를 반환합니다

이렇게하면 스크립트에서 해당 '향상된'상태를 사용할 수 있습니다.


으로 0xFE로는 그의에서 언급 우수한 대답 , git status --porcelain모든 스크립트 기반 솔루션에서 쓸모있다

--porcelain

스크립트를 위해 안정적이고 분석하기 쉬운 형식으로 출력을 제공하십시오.
현재 이것은와 동일 --short output하지만 향후 변경되지 않으므로 스크립트에 안전합니다.


아마 게으 르기 때문일 것입니다. 꽤 많이 사용되는 유스 케이스 인 것처럼 내장 된 것이 있다고 생각했습니다.
Robert Munteanu

나는 그것에 매우 만족하지 않지만 귀하의 제안에 따라 솔루션을 게시했습니다.
Robert Munteanu

4

하나의 DIY 가능성, 0xfe 의 제안 을 따르도록 업데이트 됨

#!/bin/sh
exit $(git status --porcelain | wc -l) 

Chris Johnsen 이 언급했듯이 이것은 Git 1.7.0 이상에서만 작동합니다.


6
이 문제는 향후 버전에서 문자열 'working directory clean'을 안정적으로 기대할 수 없다는 것입니다. --porcelain 플래그는 구문 분석을위한 것이기 때문에 더 나은 해결책은 다음과 같습니다. exit $ (git status --porcelain | wc -l)
0xfe

@ 0xfe- --porcelain깃발이 언제 추가 되었는지 아십니까 ? 1.6.4.2에서는 작동하지 않습니다.
Robert Munteanu

@Robert : git status --short다음 시도하십시오 .
VonC

3
git status --porcelain그리고 git status --short모두 1.7.0에서 소개되었다. 나중에 형식을 다양 --porcelain하게 할 수 있도록 특별히 도입되었습니다 git status --short. 따라서 git status --short동일한 문제가 발생합니다 git status( '배관 식'명령이 아니기 때문에 언제든지 출력이 변경 될 수 있음).
Chris Johnsen

@Chris, 배경 정보에 감사드립니다. Git 1.7.0 현재 이것을 수행하는 가장 좋은 방법을 반영하도록 답변을 업데이트했습니다.
Robert Munteanu

2

실행이 끝날 때 수정 된 추적 파일이나 추적되지 않은 추적되지 않은 파일이있는 경우 빌드를 실패하는 간단한 방법이 종종 필요했습니다.

빌드에서 남은 음식을 만드는 경우를 피하는 데 매우 중요합니다.

지금까지 내가 사용한 최고의 명령은 다음과 같습니다.

 test -z "$(git status --porcelain | tee /dev/fd/2)" || \
     {{ echo "ERROR: git unclean at the end, failing build." && return 1 }}

약간 복잡해 보일 수 있으며 원하는 동작을 유지하는 짧은 변형을 발견하면 감사하겠습니다.

  • 짝수가 정상이면 출력 및 성공 종료 코드가 없습니다.
  • 실패하면 종료 코드 1
  • 실패 이유를 설명하는 stderr의 오류 메시지
  • 실패의 원인이되는 파일 목록을 다시 표시하십시오.

2

@ 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는 명령이 제대로 성공한 경우에만 설정됩니다.

그런 다음 두 속성을 모두 확인하고 변수 (또는 무엇이든)를 설정할 수 있습니다.


1

이 있는지 찾기위한 더 쉘 친화적 인 변형 어떤 비 추적 파일이 저장소에 존재한다 :

# Works in bash and zsh
if [[ "$(git status --porcelain 2>/dev/null)" = *\?\?* ]]; then
  echo untracked files
fi

이것은 두 번째 프로세스를 수행 grep하지 않으며 git 저장소에 있는지 여부를 확인할 필요가 없습니다. 쉘 프롬프트 등에 편리합니다.


1

당신은 또한 할 수 있습니다

git describe --dirty

. 더러운 작업 트리를 감지하면 끝에 "-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.

. 주의 사항 : 맨 페이지 상태에 따라 작업 트리에만 관심이 있으므로 추적되지 않은 파일은 "더러운"것으로 간주되지 않습니다.


0

이이 스레드에서 답변의 더 나은 조합 ..하지만 저이 작품 ... 수 .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

0

더티 상태 를 감지하기 위해 사용하는 가장 간단한 자동 테스트 = 추적되지 않은 파일을 포함한 모든 변경 사항 :

git add --all
git diff-index --exit-code HEAD

노트:

  • 없이 add --all diff-index 추적되지 않은 파일을 알 수 없습니다.
  • 일반적으로 git reset오류 코드를 테스트 한 후 모든 단계를 다시 실행 취소합니다.

문제는 구체적으로 "스크립트에서"입니다. 더티 상태를 테스트하기 위해 인덱스를 변경하는 것은 좋지 않습니다.
ScottJ

@ScottJ, 문제를 해결할 때 반드시 모든 사람이 색인을 수정할 수 있는지 여부를 엄격히 준수해야하는 것은 아닙니다. 버전 번호가있는 자동 패치 소스에 관한 자동화 된 작업의 경우를 고려하고 태그를 만드십시오-색인에 있는지 여부에 관계없이 다른 로컬 수정이 방해받지 않아야합니다. 지금까지는 추적되지 않은 파일을 포함한 모든 변경 사항에 대한 신뢰할 수있는 테스트였습니다 .
uvsmtid

-3

여기에 가장 깨끗하고 깨끗한 방법이 있습니다. 선택한 답변이 어떤 이유로 든 작동하지 않았으므로 커밋되지 않은 새 파일 인 단계적 변경 사항을 선택하지 못했습니다.

function git_dirty {
    text=$(git status)
    changed_text="Changes to be committed"
    untracked_files="Untracked files"

    dirty=false

    if [[ ${text} = *"$changed_text"* ]];then
        dirty=true
    fi

    if [[ ${text} = *"$untracked_files"* ]];then
        dirty=true
    fi

    echo $dirty
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.