source

커밋되지 않은 변경사항이 있는지 프로그래밍 방식으로 확인하려면 어떻게 합니까?

manysource 2023. 5. 25. 22:09

커밋되지 않은 변경사항이 있는지 프로그래밍 방식으로 확인하려면 어떻게 합니까?

Makefile에서 작업 트리 또는 인덱스에 커밋되지 않은 변경사항이 있는 경우 특정 작업을 수행하려고 합니다.그것을 하는 가장 깨끗하고 효율적인 방법은 무엇입니까?한 경우에는 0, 다른 경우에는 0이 아닌 반환 값으로 종료되는 명령이 제 목적에 적합합니다.

달릴 수 있습니다git status그리고 파이프를 통해 출력을 전달합니다.grep하지만 더 좋은 방법이 있을 거라고 생각해요

업데이트: 다니엘 스투츠바흐 OP논평에서 이 간단한 명령이 그에게 효과가 있었다고 지적합니다.

git update-index --refresh 
git diff-index --quiet HEAD --

더 은 테스트를 해보는 것입니다.git status --porcelain=v1 2>/dev/null | wc -l옵션을 사용합니다.
미리디움을 보세요.

(Noragon댓글에서 인덱스와 내용이 동일하지만 터치된 파일이 있으면 실행해야 한다고 언급했습니다.git update-index --refresh 앞에git diff-index 않으면, 렇지않면으그.diff-index트리가 더럽다고 잘못 보고함)

그런 다음 bash 스크립트에서 "명령이 성공했는지 확인하는 방법"을 볼 수 있습니다.

git diff-index --quiet HEAD -- || echo "untracked"; // do something about it

참고: Anthony Sottile이 언급와 같이.

git diff-index HEAD ...새로 초기화된 리포지토리와 같이 커밋이 없는 분기에서 실패합니다.
방법 중 하나는 한가해방법입니다.git diff-index $(git write-tree) ...

그리고 댓글에서 지적하는 것은git diff-files 파일에서는 디프로 감지되지 않습니다.
더 안전한 방법은 실행하는 것 같습니다.git add한 후 " 먼파일사사서용다니합에"를 사용합니다.git diff-index에 추가된 항목이 합니다.git commit.

git add ${file_args} && \
git diff-index --cached --quiet HEAD || git commit -m '${commit_msg}'

6502개의 보고서가 댓글에 있습니다.

내가 마주친 한 가지 문제는git diff-index파일의 타임스탬프를 제외하고 실제로는 아무 것도 없을 때 차이가 있다는 것을 알 수 있습니다.
중입니다.git diff되면 ( ▁once▁(,)면충히surpr해분▁()git diff합니다. 즉, 여기서는 샌드박스의 내용을 변경합니다. 여기서 의미합니다..git/index)

이러한 타임스탬프 문제는 GIT가 도커에서 실행되는 경우에도 발생할 수 있습니다.


원답:

"프로그래밍 방식"은 절대 도자기 명령의존하지 않는다는 것을 의미합니다.
항상 배관 명령에 의존해야 합니다.

다른 방법은 "Git를 사용하여 더티 인덱스 또는 추적되지 않은 파일 확인"을 참조하십시오(예:git status --porcelain)

현재 작성된 새로운 require_clean_work_tree"기능"에서 영감을 얻을 수 있습니다. ;) (2010년 10월 초)

require_clean_work_tree () {
    # Update the index
    git update-index -q --ignore-submodules --refresh
    err=0

    # Disallow unstaged changes in the working tree
    if ! git diff-files --quiet --ignore-submodules --
    then
        echo >&2 "cannot $1: you have unstaged changes."
        git diff-files --name-status -r --ignore-submodules -- >&2
        err=1
    fi

    # Disallow uncommitted changes in the index
    if ! git diff-index --cached --quiet HEAD --ignore-submodules --
    then
        echo >&2 "cannot $1: your index contains uncommitted changes."
        git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2
        err=1
    fi

    if [ $err = 1 ]
    then
        echo >&2 "Please commit or stash them."
        exit 1
    fi
}

다른 솔루션은 매우 철저하지만, 정말 빠르고 더러운 것을 원한다면 다음과 같은 것을 시도해 보십시오.

[[ -z $(git status -s) ]]

상태 요약에 출력이 있는지 확인할 뿐입니다.

git diff --exit-code사항이 이 아닌 값을 합니다. 이 경우 0이 아닌 값이 반환됩니다.git diff --quiet출력이 없어도 동일합니다., 를 사용하세요.

git diff --quiet && git diff --cached --quiet

또는

git diff --quiet HEAD

둘 중 하나가 스테이징된 커밋되지 않은 변경사항이 있는지 여부를 알려줍니다.

@Nepthar의 답변에 대한 확장:

if [[ -z $(git status -s) ]]
then
  echo "tree is clean"
else
  echo "tree is dirty, please commit changes before running this"
  exit
fi

일부 답변은 문제를 너무 복잡하게 만들거나 원하는 결과를 얻지 못하고 있습니다.예: 승인된 답변에 추적되지 않은 파일이 누락됩니다.

사용할 수 있습니다.git status --porcelain=v1출력을 프로그래밍 방식으로 구문 분석합니다.커밋되지 않은 변경 사항이 있으면 출력이 비어 있고, 그렇지 않으면 비어 있지 않습니다.

POSIX 호환 최소 작업 예제:

[ -z "$(git status --porcelain=v1 2>/dev/null)" ] && echo "No uncommitted changes."

git 저장소 외부에서 실행되는 경우에도 여전히 다음과 같이 표시됩니다.No uncommitted changes.

세부 사항

  • »--porcelain기계로 제어할 수 있는 출력을 제공합니다.
  • 사양 옵션 양사양입니다.--porcelain=v1에서는 기계로 출력의 .git갱신하다.내 글을 쓸 때, 당신은 https://git-scm.com/docs/git-status 에서 다음과 같은 다른 버전 옵션에 대한 정보를 확인할 수 있습니다.--porcelain=v2다음 버전을 사용하여 고급 스크립팅을 수행할 수 있습니다.v1.
  • 2>/dev/null그래서 있습니까?git status(즉, git 저장소 외부에서 실행되는 경우) 자동으로 오류가 발생합니다.
  • 글을 쓰는 는 이글쓰시서에, 명은령입니다.git status ... 코드 종료코반환니다합를드▁exit다를 반환합니다.128Git 저장소 내부에 없는 경우."커밋되지 않은 변경사항" 또는 "커밋되지 않은 변경사항 없음" 이외의 세 번째 옵션을 원하는 경우 이 종료 코드를 명시적으로 확인할 수 있습니다.

추가: 더티 파일 수

대답에 영감을 받았습니다.grepgit status --porcelain=v1 파일의 .각 행의 처음 두 문자는 특정 파일의 상태를 나타냅니다.그랩핑 후 출력을 파이프로 연결하여 해당 상태를 가진 수를 카운트합니다.wc -l선의 수를 계산합니다.

이러한 방식으로 일부 고급 동작을 코드화하거나 "커밋되지 않은 변경"으로 간주되는 것을 선택하여 선택할 수 있습니다.

예: 이 스크립트는 git 저장소 내에서 실행될 경우 일부 정보를 인쇄합니다.

#!/bin/sh
GS=$(git status --porcelain=v1 2>/dev/null) # Exit code 128 if not in git directory. Unfortunately this exit code is a bit generic but it should work for most purposes.
if [ $? -ne 128 ]; then
  function _count_git_pattern() {
    echo "$(grep "^$1" <<< $GS | wc -l)" 
  }                                           
  echo "There are $(_count_git_pattern "??") untracked files."                                 
  echo "There are $(_count_git_pattern " M") unstaged, modified files."
  echo "There are $(_count_git_pattern "M ")   staged, modified files."        
fi

몇 가지 유용한 깃 별칭을 만들어 준비되지 않은 파일과 준비된 파일을 나열했습니다.

git config --global alias.unstaged 'diff --name-only'
git config --global alias.staged 'diff --name-only --cached'

그러면 다음과 같은 작업을 쉽게 수행할 수 있습니다.

[[ -n "$(git unstaged)" ]] && echo unstaged files || echo NO unstaged files
[[ -n "$(git staged)" ]] && echo staged files || echo NO staged files

사용자의 어딘가에 스크립트를 만들어 보다 읽기 쉽게 만들 수 있습니다.PATH라고 하는git-has:

#!/bin/bash
[[ $(git "$@" | wc -c) -ne 0 ]]

이제 위의 예를 다음과 같이 단순화할 수 있습니다.

git has unstaged && echo unstaged files || echo NO unstaged files
git has staged && echo staged files || echo NO staged files

완전성을 위해 추적되지 않은 파일과 무시된 파일에 대한 유사한 별칭이 다음과 같습니다.

git config --global alias.untracked 'ls-files --exclude-standard --others'
git config --global alias.ignored 'ls-files --exclude-standard --others --ignored'

작업 트리는 다음과 같은 경우 "깨끗"합니다.

git ls-files \
  --deleted \
  --modified \
  --others \
  --exclude-standard \
  -- :/

아무것도 반환하지 않습니다.

설명.

  • --deleted 합니다.
  • --modified 합니다.
  • --others 합니다.
  • --exclude-standard.gitignore,.git/info/exclude...규칙.
  • -- :/ everything, 되지 않는 한 모든 항목에 대한 pathspec입니다.

작업 트리가 깨끗하면 해당 출력이 비어 있습니다.

Python 및 GitPython 패키지의 경우:

import git
git.Repo(path).is_dirty(untracked_files=True)

온다아를 반환합니다.True리포지토리가 깨끗하지 않은 경우

다른 답변에서 지적한 바와 같이, 이러한 명령만 실행해도 충분합니다.

git diff-index --quiet HEAD --

두 개의 이 "" " " " " " " 인 합니다.HEAD.

예:

#!/bin/bash
set -e
echo -n "Checking if there are uncommited changes... "
trap 'echo -e "\033[0;31mFAILED\033[0m"' ERR
git diff-index --quiet HEAD --
trap - ERR
echo -e "\033[0;32mAll set!\033[0m"

# continue as planned...

주의: 이 명령은 추적되지 않은 파일을 무시합니다.

Linux Ubuntu의 bash 터미널에서 테스트되었습니다.

의 출력을 방식으로 하는 셸 git status

...그리고 다음과 같은 경우:

  1. 오류가 있었습니다.
  2. 작업 트리가 깨끗함을 나타냅니다(커밋되지 않은 변경 사항 없음).
  3. 작업 트리가 더럽다는 것을 나타냅니다(커밋되지 않은 변경 사항이 있습니다).

여기 좋은 대답이 있습니다: 유닉스 & Llinux: Git 작업 디렉터리가 스크립트에서 깨끗한지 확인하십시오.제 대답은 그것을 바탕으로 합니다.

우리는 사용할 것입니다.--porcelain할 수 있습니다.git status스크립트에 의해 구문 분석될 예정이기 때문입니다.

man git status으)로 표시됨:

--porcelain[=<version>]

스크립트를 구문 분석하기 쉬운 형식으로 출력을 제공합니다.이는 짧은 출력과 비슷하지만 Git 버전 전체에서 사용자 구성에 관계없이 안정적으로 유지됩니다.자세한 내용은 아래를 참조하십시오.

version매개 변수는 형식 버전을 지정하는 데 사용됩니다.이 옵션은 선택 사항이며 기본적으로 원래 버전 v1 형식입니다.

다음을 수행합니다.

옵션 1

if output="$(git status --porcelain)" && [ -z "$output" ]; then
    echo "'git status --porcelain' had no errors AND the working directory" \
         "is clean."
else 
    echo "Working directory has UNCOMMITTED CHANGES."
fi

번째 파트, 번부분은째첫.if output=$(git status --porcelain)실패하고 다음 단계로 점프합니다.else다음과 같은 경우에는git status --porcelain명령에 오류가 있습니다.두 번째 파트는.&& [ -z "$output" ]테스트를 통해 확인할 수 있습니다.output빈 .zero-length) 파일 이름입니다.만약 그렇다면, 그 다음은git status깨끗하며 변경 사항이 없습니다.

옵션 2

그러나 일반적으로 제가 선호하는 사용법은 테스트를 부정하는 것입니다.-n0 아 닌신) 대신 (이 아님)-z 됩니다 (0) 다음같수니다행합이과▁(다니수합.

if output="$(git status --porcelain)" && [ -n "$output" ]; then
    echo "'git status --porcelain' had no errors AND the working directory" \
         "is dirty (has UNCOMMITTED changes)."
    # Commit the changes here
    git add -A
    git commit -m "AUTOMATICALLY COMMITTING UNCOMMITTED CHANGES"
fi

옵션 3

위의 첫 번째 코드 블록을 더 구체적으로 작성하는 방법은 다음과 같습니다.

if ! git_status_output="$(git status --porcelain)"; then
    # `git status` had an error
    error_code="$?"
    echo "'git status' had an error: $error_code" 
    # exit 1  # (optional)
elif [ -z "$git_status_output" ]; then
    # Working directory is clean
    echo "Working directory is clean."
else
    # Working directory has uncommitted changes.
    echo "Working directory has UNCOMMITTED CHANGES."
    # exit 2  # (optional)
fi

저는 위의 모든 코드를 다양한 상태에서 전체 블록을 복사하여 제 터미널에 붙여넣어 테스트했고, 다음 세 가지 조건에서 모두 정상적으로 작동합니다.

  1. 당신의.git status가 틀렸습니다.
  2. git statusclean ( 않은변경사항 없음)은 다음과 같습니다.
  3. git status더럽습니다(커밋되지 않은 변경 사항이 있습니다).

강제로 사용'git status' had an error 단순히 를 잘못 쓴다면, 히철자를잘못입력니다합순단력출▁output,▁simply.--porcelain 입이는옵션하력다▁by옵▁it로 철자하여 --porcelainn또는 무엇인가, 그리고 당신은 맨 끝에 다음과 같은 출력을 볼 수 있습니다.

'git status' had an error: 0

여기에 가장 좋고 깨끗한 방법이 있습니다.

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
}

언급URL : https://stackoverflow.com/questions/3878624/how-do-i-programmatically-determine-if-there-are-uncommitted-changes