prosource

커밋하기 전에 Git에서 후행 공백을 자동으로 제거하도록 합니다.

probook 2023. 7. 2. 20:49
반응형

커밋하기 전에 Git에서 후행 공백을 자동으로 제거하도록 합니다.

팀과 함께 Git를 사용하고 있으며 디프, 로그, 병합 등에서 공백 변경 사항을 제거하고 싶습니다.이를 위한 가장 쉬운 방법은 Git가 적용되는 모든 커밋에서 후행 공백(및 기타 공백 오류)을 자동으로 제거하는 것이라고 생각합니다.

는 다음사추했습다니고에 하려고 노력했습니다.~/.gitconfig파일, 하지만 내가 커밋할 때 아무 것도 하지 않습니다.뭔가 다른 것을 위해 설계된 것일 수도 있습니다.해결책은 무엇입니까?

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

루비에 대한 구체적인 아이디어가 있을 경우를 대비해 루비를 사용하고 있습니다.커밋하기 전에 자동 코드 형식을 지정하는 것이 다음 단계가 될 것입니다. 하지만 이는 어려운 문제이며 실제로 큰 문제를 일으키지는 않습니다.

설정해당설정(설정core.whitespace그리고.apply.whitespace)는 후행 공백을 제거하기 위한 것이 아니라 다음과 같은 목적으로 사용됩니다.

  • core.whitespace를 발생시킵니다.
  • apply.whitespace그리고 그것들을 벗겨내지만, "항상 자동적으로"가 아닌 패치 중에만.

이 작업을 수행하는 것이 더 나을 것입니다(후행 공백 제거 포함).


든지 언든지 제행있하실지수선습다니택할을 실행하지 할 수 .pre-commit잠금 해제:

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

으로 a: 기적으로apre-commit스크립트(이와 같은)에는 "후행 제거" 기능이 없고 다음과 같은 "경고" 기능이 있습니다.

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

그러나 특히 다음과 같은 점을 고려할 때 더 나은 후크를 구축할 수 있습니다.

준비 영역에 일부 변경 사항만 추가된 상태에서 Git에서 커밋하면 작업 복사본으로 존재하지 않았을 수도 있고 작동하지 않을 도 있는 "원자" 개정이 여전히 발생합니다.


예를 들어, 노인다른 대답에서 공백을 감지하고 제거하는 후크제안합니다.
해당 후크가 각 파일의 파일 이름을 가져오기 때문에 특정 유형의 파일에 주의할 것을 권장합니다. 다음에서 후행 공백을 제거하지 마십시오..md(마크다운) 파일!


하케레논평에서 또 다른 접근법을 제안했습니다.

추가하행끝를두마공지크로으정후운고하다행다지공않있"를 추가하면 행 두의 공백을 수 .\ 앞에\n.

그런 다음 콘텐츠 필터 드라이버:

git config --global filter.space-removal-at-eol.clean 'sed -e "s/ \+$//"'
# register in .gitattributes 
*.md filter=space-removal-at-eol

Git을 속여 빈 공간을 수정할 수 있습니다. Git을 속여 변경 사항을 패치로 처리합니다."커밋 전 후크" 솔루션과 달리 이러한 솔루션은 Git에 공백 수정 명령을 추가합니다.

네, 이것들은 해킹입니다.


강력한 솔루션

다음 Git 별칭은 에서 가져온 것입니다.

"것은 작업을 합니다."강력"이란 이러한 별칭이 트리 또는 인덱스가 더럽든 상관없이 올바른 작업을 수행하여 오류 없이 실행된다는 것을 의미합니다.의 경우에는 작동하지 않습니다.git rebase -i이미 진행 중입니다. 만약 당신이 이 코너 케이스에 관심이 있다면 추가 확인을 위해 나를 참조하십시오.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 .
    

    +를 enter눌러 각 파일에 대한 모든 변경 사항을 선택합니다.Git가 공백 오류를 수정한다는 경고가 표시됩니다.
    (git -c color.ui=auto diff이 시점에서 사용자의 비선택적 변경사항이 정확히 공백 오류임을 나타냅니다.

  3. 작업 복사본에서 공백 오류를 제거합니다.

    git checkout .
    
  4. 변경 내용을 다시 가져옵니다(변경 내용을 커밋할 준비가 되지 않은 경우).

    git reset
    

GIT_EDITOR=:을 사용하는 :편집자로서, 그리고 명령으로서.:정체성입니다.

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

#!/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

macOS(또는 모든 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또는 이미 있는 것을 찾아서 그 안의 어딘가에 아래쪽 덩어리를 붙여넣습니다.하세요 그기리고세요하억▁and▁to리요.chmod a+x그것도.

또는 글로벌 사용의 경우(현재미래의 모든 리포지토리에 Git 사후 커밋 후크 적용을 통해) 에 넣을 수 있습니다.$GIT_PREFIX/git-core/templates/hooks( /또는 /또는 /를 실행하고 실행합니다.git init기존 저장소 내부에 있습니다.

에 의하면git help init:

중입니다.git init기존 리포지토리에서 안전합니다.이미 있는 항목을 덮어쓰지 않습니다.를 다시 하는 주요 git init새로 추가된 템플릿을 선택합니다.

Git 특성 및 Git 구성으로 설정된 필터 사용

좋아요, 이것은 이 문제를 해결하는 새로운 방법입니다.제 접근 방식은 후크를 사용하지 않고 필터와 Git 속성을 사용하는 것입니다.이렇게 하면 개발 중인 각 컴퓨터에서 파일을 커밋하기 전에 파일 끝에 추가 후행 공백과 추가 빈 줄을 제거하는 필터 세트를 설정할 수 있습니다.

그런 다음 필터를 적용해야 하는 파일 유형을 나타내는 .git 특성 파일을 설정합니다.에는 두 단계가 .clean때 그리고 인스에파때추적니다됩용가할일을덱▁which다니적▁when됩▁and▁is▁applied용때.smudge작업 디렉토리에 추가할 때 적용됩니다.

Git에게 글로벌 특성 파일을 찾으라고 말합니다.

먼저 글로벌 구성에 글로벌 특성 파일을 사용하도록 지시합니다.

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-of는 다음과 같아야 합니다.

#!/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

커밋 전 훅을 시도해 보세요.후행 공백을 자동으로 감지하여 제거할 수 있습니다.

Git Bash(윈도우즈), Mac OS X 및 Linux에서 작동할 수 있습니다!


스냅샷:

$ git commit -am "test"
auto remove trailing whitespace in foobar/main.m!
auto remove trailing whitespace in foobar/AppDelegate.m!
[master 80c11fe] test
1 file changed, 2 insertions(+), 2 deletions(-)

다음은 Ubuntu 및 Mac OS X 호환 버전입니다.

#!/bin/sh
#

# A Git hook script to find and fix trailing white space
# in your commits. Bypass it with the --no-verify option
# to git-commit
#

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]+:.*//' > /dev/null 2>&1 || sed -E 's/:[0-9]+:.*//') | uniq` ; do
  # Fix them!
  (sed -i 's/[[:space:]]*$//' "$FILE" > /dev/null 2>&1 || sed -i '' -E 's/[[:space:]]*$//' "$FILE")
  git add "$FILE"
done

# Now we can commit
exit

저는 오늘 이것에 대해 생각하고 있었습니다.이것이 제가 자바 프로젝트를 위해 하게 된 전부입니다.

egrep -rl ' $' --include *.java *  | xargs sed -i 's/\s\+$//g'

숭고한 텍스트 사용자용입니다.

설정-사용자 구성에서 다음을 올바르게 설정합니다.

"trim_trailing_white_space_on_save": true

for 루프는 에사파루용을 합니다.$IFS에서 $가 포함된 은 $IFS 변수에 있는 의 서로 됩니다.for 루우프

이 스크립트는 이 문제를 해결합니다. sed 매뉴얼에 나와 있는 다중 행 모드 수정자가 내 Ubuntu 상자에서 기본적으로 작동하지 않는 것 같아서 다른 구현을 찾아보니 반복 레이블이 있는 것을 발견했습니다. 기본적으로 내가 올바르게 이해한 경우에만 파일의 마지막 줄에서 대체가 시작됩니다.

#!/bin/sh
#

# A Git hook script to find and fix trailing white space
# in your commits. Bypass it with the --no-verify option
# to git-commit
#

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

SAVEIFS="$IFS"
# only use new-line character as separator, introduces EOL-bug?
IFS='
'
# Find files with trailing white space
for FILE in $(
    git diff-index --check --cached $against -- \
    | sed '/^[+-]/d' \
    | ( sed -r 's/:[0-9]+:.*//' || sed -E 's/:[0-9]+:.*//' ) \
    | uniq \
)
do
# replace whitespace-characters with nothing
# if first execution of sed-command fails, try second one (Mac OS X version)
    (
        sed -i ':a;N;$!ba;s/\n\+$//' "$FILE" > /dev/null 2>&1 \
        || \
        sed -i '' -E ':a;N;$!ba;s/\n\+$//' "$FILE" \
    ) \
    && \
# (re-)add files that have been altered to Git commit-tree
#   when change was a [:space:]-character @EOL|EOF git-history becomes weird...
    git add "$FILE"
done
# restore $IFS
IFS="$SAVEIFS"

# Exit script with the exit-code of git's check for white space characters
exec git diff-index --check --cached $against --

1 sed-분포 패턴:sed를 사용하여 새 줄(\n)을 대체하려면 어떻게 해야 합니까?

이렇게 하면 커밋하기 전에 공백이 자동으로 제거되지는 않지만 적용하기가 매우 쉽습니다.$PATH의 디렉토리에 있는 git-wsf(Git white space fix)라는 이름의 파일에 다음 Perl 스크립트를 넣었습니다.

git wsf | sh

그리고 Git가 diff로 보고하는 파일 행에서만 모든 공백을 제거합니다.

#! /bin/sh
git diff --check | perl -x $0
exit

#! /usr/bin/perl

use strict;

my %stuff;
while (<>) {
    if (/trailing whitespace./) {
        my ($file,$line) = split(/:/);
        push @{$stuff{$file}},$line;
    }
}

while (my ($file, $line) = each %stuff) {
    printf "ex %s <<EOT\n", $file;
    for (@$line) {
        printf '%ds/ *$//'."\n", $_;
    }
    print "wq\nEOT\n";
}

동일한 결과에 대한 Python Script.

import subprocess                                                                 
                                                                              
def get_trailing_lines():                                                         
                                                                              
    result = subprocess.run([                                                     
                            'git',                                            
                            'diff',                                           
                            '--check'                                         
                        ], capture_output=True)                               
                                                                              
    return result.stdout.decode().split('\n')                                     
                                                                              
                                                                              
def modify_line(file_path, l_num):                                                
                                                                              
    f_lines = open(file_path).readlines()                                         
    f_lines[l_num] = f_lines[l_num].rstrip()+'\n'\                                
                     if '\n' in f_lines[l_num] else f_lines[l_num].rstrip()    
                                                                              
    with open(file_path, "w") as w_fp:                                            
        w_fp.writelines(f_lines)                                                  
                                                                              
                                                                              
if __name__ == '__main__':                                                        
                                                                              
    l = get_trailing_lines()                                                      
    for m, d in zip(l[::2], l[1::2]):                                             
        f_path, l_no, *_ = m.split(":")                                           
        modify_line(f_path, int(l_no)-1)                                          

이렇게 하면 문제가 직접적으로 해결되지는 않겠지만 실제 프로젝트 공간에서 git-config를 통해 설정하면 파일 ~/.git/config가 아닌 파일 ./.git/config를 편집할 수 있습니다.모든 프로젝트 구성원 간에 설정을 일관되게 유지하는 것이 좋습니다.

git config core.whitespace "trailing-space,space-before-tab"
git config apply.whitespace "trailing-space,space-before-tab"

줄에 오는 하려면 파의줄끝있는후행공휴백다삭로으사다제용니합음을면하려일대용을에▁at▁to▁use를 사용합니다.ed:

test -s file &&
   printf '%s\n' H ',g/[[:space:]]*$/s///' 'wq' | ed -s file

Vim에서 파일을 엽니다.탭을 공백으로 바꾸려면 Vim 명령줄에 다음을 입력합니다.

:%s#\t#    #gc

뒤에 오는 다른 공백을 제거하려면

:%s#\s##gc

이것은 저에게 거의 도움이 되었습니다.편집할 파일이 많으면 지루합니다.하지만 사전 커밋 후크와 여러 텍스트 편집기로 작업하는 것보다 더 쉽다는 것을 알게 되었습니다.

언급URL : https://stackoverflow.com/questions/591923/make-git-automatically-remove-trailing-white-space-before-committing

반응형