[git] 커밋하기 전에 자식이 후행 공백을 자동으로 제거하도록하십시오.

팀과 함께 git을 사용하고 있으며 diff, log, merge 등에서 공백 변경 사항을 제거하고 싶습니다.이 작업을 수행하는 가장 쉬운 방법은 git이 후행 공백 (및 기타 공백 오류)을 자동으로 제거하는 것이라고 가정합니다 ) 적용되는 모든 커밋에서.

~/.gitconfig파일로 다음을 추가하려고했지만 커밋 할 때 아무것도하지 않습니다. 어쩌면 다른 무언가를 위해 설계되었을 수도 있습니다. 해결책은 무엇입니까?

[core]
    whitespace = trailing-space,space-before-tab
[apply]
    whitespace = fix

누구든지 루비 관련 아이디어가있는 경우를 대비하여 루비를 사용하고 있습니다. 커밋하기 전에 자동 코드 형식화는 다음 단계이지만, 어려운 문제이며 실제로 큰 문제를 일으키지 않습니다.



답변

이러한 설정 ( core.whitespaceapply.whitespace)은 후행 공백을 제거하지 않고 다음을 수행합니다.

  • core.whitespace: 감지하여 오류 발생
  • apply.whitespace: 항상 “자동으로”가 아닌 패치 중에 만 제거하십시오.

나는 그것을 위해 git hook pre-commit더 나은 일을 할 것이라고 믿는다 (후행 공백 제거 포함)


주어진 시간에 pre-commit후크를 실행하지 않도록 선택할 수 있습니다 .

  • 일시적으로 : git commit --no-verify .
  • 영구적으로 : cd .git/hooks/ ; chmod -x pre-commit

경고 : 기본, a로 pre-commit(같은 스크립트 이 하나 ), 한 없는 기능 “을 후행 제거” “하지만,”경고 “기능과 같은 :

if (/\s$/) {
    bad_line("trailing whitespace", $_);
}

그러나 특히 다음을 고려할 때 더 나은 pre-commit후크를 만들 수 있습니다.

준비 영역에 약간의 변경 사항 만 추가하여 Git에서 커밋하면 여전히 작업 복사본으로 존재하지 않았거나 작동하지 않을 수 있는 “원자”개정이 생성 됩니다.


예를 들어, 노인다른 대답 에서 공백을 감지하고 제거 하는 pre-commit후크 를 제안합니다 .
그 후크는 각 파일의 파일 이름을 얻으므로 특정 유형의 파일에주의를 기울이는 것이 좋습니다. .md(마크 다운) 파일 에서 후행 공백을 제거하고 싶지 않습니다 !


답변

변경 사항을 패치로 처리하도록 Git을 속여서 Git이 공백을 수정하도록 속일 수 있습니다. “사전 커밋 후크”솔루션과 달리이 솔루션은 Git에 공백 수정 명령을 추가합니다.

예, 이것은 해킹입니다.


강력한 솔루션

다음 Git 별칭은 my~/.gitconfig 에서 가져옵니다
.

“견고한”이란 트리 나 인덱스가 더티인지에 관계없이 이러한 별칭이 오류없이 실행되고 올바른 작업을 수행함을 의미합니다. 그러나 대화식 git rebase -i이 이미 진행중인 경우 작동하지 않습니다 . 마지막에 설명 된 트릭이 작동하는 이 코너 케이스에 관심이 있다면 추가 확인을 위해 ~/.gitconfig 참조하십시오 git add -e.

Git 별칭을 만들지 않고 쉘에서 직접 실행하려면 큰 따옴표 사이에 모든 것을 복사하여 붙여 넣으십시오 (쉘이 Bash와 같다고 가정).

색인을 수정하지만 트리는 수정하지 마십시오

다음 fixwsGit 별칭은 인덱스의 모든 공백 오류를 수정하지만 트리를 건드리지 않습니다.

# Logic:
#
# The 'git stash save' fails if the tree is clean (instead of
# creating an empty stash :P). So, we only 'stash' and 'pop' if
# the tree is dirty.
#
# The 'git rebase --whitespace=fix HEAD~' throws away the commit
# if it's empty, and adding '--keep-empty' prevents the whitespace
# from being fixed. So, we first check that the index is dirty.
#
# Also:
# - '(! git diff-index --quiet --cached HEAD)' is true (zero) if
#   the index is dirty
# - '(! git diff-files --quiet .)' is true if the tree is dirty
#
# The 'rebase --whitespace=fix' trick is from here:
# https://stackoverflow.com/a/19156679/470844
fixws = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git stash save FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git stash pop && \
    git reset --soft HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

아이디어는 색인에 공백 오류가있는 경우 git fixws전에 실행하는 것입니다 git commit.

인덱스와 트리를 수정

다음 fixws-global-tree-and-indexGit 별명은 색인 및 트리의 모든 공백 오류를 수정합니다 (있는 경우).

# The different cases are:
# - dirty tree and dirty index
# - dirty tree and clean index
# - clean tree and dirty index
#
# We have to consider separate cases because the 'git rebase
# --whitespace=fix' is not compatible with empty commits (adding
# '--keep-empty' makes Git not fix the whitespace :P).
fixws-global-tree-and-index = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~2 && \
    git reset HEAD~ && \
    git reset --soft HEAD~ ; \
  elif (! git diff-files --quiet .) ; then \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git reset HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

버전이 지정되지 않은 파일에서 공백을 수정하려면

git add --intent-to-add <unversioned files> && git fixws-global-tree-and-index

단순하지만 강력한 솔루션

이러한 버전은 복사 및 붙여 넣기가 더 쉬워 지지만 해당 조건이 충족되지 않으면 올바른 작업을 수행하지 않습니다.

현재 디렉토리를 기반으로하는 하위 트리 수정 (비어 있지 않은 경우 인덱스 재설정)

git add -e아이디 편집기로 패치를 “편집”하는 데 사용 ::

(export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .) && git checkout . && git reset

색인 수정 및 보존 (트리가 더럽거나 색인이 비어있는 경우 실패)

git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset --soft HEAD~

나무와 색인을 수정하십시오 (그러나 비어 있지 않으면 색인을 재설정하십시오)

git add -u :/ && git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset HEAD~

export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .트릭의 설명

이 답변 에서 git rebase --whitespace=fix트릭 에 대해 배우기 전에 더 복잡한 트릭을 사용했습니다 .git add

우리가 수동으로 한 경우 :

  1. 설정 apply.whitespacefix(당신은 한 번만 수행하면) :

    git config apply.whitespace fix
    

    이것은 Git에게 패치 에서 공백을 수정하도록 지시 합니다.

  2. Git이 변경 사항을 패치 로 취급하도록 설득 하십시오 .

    git add -up .
    

    각 파일에 대한 모든 변경 사항을 선택하려면 a+ enter를 누르십시오 . Git의 공백 오류 수정에 대한 경고가 표시됩니다.
    ( git -c color.ui=auto diff이 시점에서 색인이 생성되지 않은 변경 사항은 정확히 공백 오류임을 나타냅니다).

  3. 작업 사본에서 공백 오류를 제거하십시오.

    git checkout .
    
  4. 변경 사항을 다시 가져 오십시오 (커밋 할 준비가되지 않은 경우).

    git reset
    

편집기 및 명령
GIT_EDITOR=:으로 사용 하는 수단 은 ID입니다.::


답변

후행 공백을 제거 하는 자식 사전 커밋 후크를 찾았습니다 .

#!/bin/sh

if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
   against=HEAD
else
   # Initial commit: diff against an empty tree object
   against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -r 's/:[0-9]+:.*//' | uniq` ; do
   # Fix them!
   sed -i 's/[[:space:]]*$//' "$FILE"
   git add "$FILE"
done
exit


답변

Mac OS (또는 BSD)에서 sed 명령 매개 변수는 약간 달라야합니다. 이 시도:

#!/bin/sh

if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
   against=HEAD
else
   # Initial commit: diff against an empty tree object
   against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -E 's/:[0-9]+:.*//' | uniq` ; do
    # Fix them!
    sed -i '' -E 's/[[:space:]]*$//' "$FILE"
    git add "$FILE"
done

이 파일을 다른 이름으로 저장 .git/hooks/pre-commit하거나 이미 존재하는 파일을 찾아서 그 안에 어딘가에 하단 청크를 붙여 넣습니다. 그리고 chmod a+x그것도 기억하십시오 .

또는 글로벌 사용 (경유 – 전역 설정 힘내 후크를 저지 당신이 그것을 넣을 수 있습니다) $GIT_PREFIX/git-core/templates/hooks(GIT_PREFIX에 / usr 또는 경우 / usr / local이나 / usr / 주 또는 / 옵션 / 지역 / 공유) 실행 git init기존의 repos 내부.

에 따르면 git help init:

기존 저장소에서 git init를 실행하는 것이 안전합니다. 이미 존재하는 것을 덮어 쓰지 않습니다. git init를 다시 실행하는 주된 이유는 새로 추가 된 템플릿을 선택하는 것입니다.


답변

차라리이 작업을 좋아하는 편집자에게 맡기고 싶습니다.

저장할 때 후행 공백을 제거하도록 명령을 설정하십시오.


답변

자식 속성 사용 및 자식 설정으로 필터 설정

좋아, 이것은이 문제를 해결하기위한 새로운 방법입니다 … 내 접근 방식은 후크를 사용하지 않고 필터와 자식 속성을 사용하는 것입니다. 이 기능을 사용하면 개발중인 각 컴퓨터에서 파일 끝에 커밋하기 전에 추가 공백과 줄을 제거하는 필터 세트가 설정됩니다. 그런 다음 필터를 적용 할 파일 형식을 나타내는 .gitattributes 파일을 설정하십시오. 필터에는 clean파일을 색인에 추가 할 때 적용되는 단계 와 smudge작업 디렉토리에 추가 할 때 적용되는 두 단계 가 있습니다.

자식에게 전역 속성 파일을 찾도록 지시하십시오.

먼저 전역 속성 파일을 사용하도록 전역 구성에 지시하십시오.

git config --global core.attributesfile ~/.gitattributes_global

글로벌 필터 만들기

이제 필터를 작성하십시오.

git config --global filter.fix-eol-eof.clean fixup-eol-eof %f
git config --global filter.fix-eol-eof.smudge cat
git config --global filter.fix-eol-eof.required true

sed 스크립팅 매직 추가

마지막으로, fixup-eol-eof스크립트를 경로 어딘가에 놓고 실행 가능하게 만드십시오. 스크립트는 sed를 사용하여 일부 편집 작업을 수행합니다 (파일 끝에서 공백과 공백을 제거하고 파일 끝에서 불필요한 공백을 제거합니다)

fixup-eol-eof는 다음과 같아야합니다.

#!/bin/bash
sed -e 's/[  ]*$//' -e :a -e '/^\n*$/{$d;N;ba' -e '}' $1

이것의 내 요지

git에게 새로 만든 필터를 적용 할 파일 형식을 알려주세요

마지막으로 좋아하는 편집기에서 ~ / .gitattributes_global을 만들거나 열고 다음과 같은 줄을 추가하십시오.

pattern attr1 [attr2 [attr3 […]]]

따라서 공백 문제를 해결하려면 모든 c 소스 파일에 대해 다음과 같은 줄을 추가하십시오.

*.c filter=fix-eol-eof

필터에 대한 토론

필터에는 두 가지 단계가 있습니다. 색인에 항목을 추가하거나 체크인 할 때 적용되는 정리 단계와 git이 작업 디렉토리에 항목을 넣을 때의 얼룩 단계입니다. 여기서 우리의 얼룩은 cat파일 끝에 후행 줄 바꿈 문자가 없으면 가능한 줄 바꿈 문자를 추가하는 것을 제외하고 는 명령을 통해 내용을 실행 합니다. clean 명령은 공백 필터링으로 http://sed.sourceforge.net/sed1line.txt의 노트와 함께 사용되었습니다 . 쉘 스크립트에 넣어야하는 것 같습니다. 파일 끝의 불필요한 여분의 줄을 git-config 파일에 직접 추가하는 등 sed 명령을 삽입하는 방법을 알 수 없었습니다. (당신 수 있습니다별도의 SED 스크립트의 필요없이, 그러나 후행 공백을 제거, 바로 설정 filter.fix-eol-eof같은 것으로 sed 's/[ \t]*$//' %f(가) 어디에 \t탭을 눌러, 실제 탭입니다.)

require = true는 문제가 발생하면 문제가 발생하지 않도록 오류를 발생시킵니다.

자식에 관한 언어가 정확하지 않은 경우 용서해주십시오. 나는 개념을 상당히 잘 알고 있다고 생각하지만 여전히 용어를 배우고 있습니다.


답변

대상 파일에 후행 공백이 너무 많으면 이전 제안에서 읽을 수없는 커밋을 만드는 경향이 있기 때문에 변경 / 추가 한 행에서 후행 공백 만 제거하는이 사전 커밋 후크를 작성했습니다.

#!/bin/sh

if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
   against=HEAD
else
   # Initial commit: diff against an empty tree object
   against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

IFS='
'

files=$(git diff-index --check --cached $against -- | sed '/^[+-]/d' | perl -pe 's/:[0-9]+:.*//' | uniq)
for file in $files ; do
    diff=$(git diff --cached $file)
    if test "$(git config diff.noprefix)" = "true"; then
        prefix=0
    else
        prefix=1
    fi
    echo "$diff" | patch -R -p$prefix
    diff=$(echo "$diff" | perl -pe 's/[ \t]+$// if m{^\+}')
    out=$(echo "$diff" | patch -p$prefix -f -s -t -o -)
    if [ $? -eq 0 ]; then
        echo "$diff" | patch -p$prefix -f -t -s
    fi
    git add $file
done