IT story

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

hot-time 2020. 4. 30. 07:32
반응형

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


팀과 함께 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를 다시 실행하는 주된 이유는 새로 추가 된 템플릿을 선택하는 것입니다.


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

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


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

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

시도하십시오 사전을 커밋 후크 , 그것은 자동으로 후행 공백을 감지 할 수 있습니다 제거 . 감사합니다!

그것은 아래에서 작동 할 수 있습니다 GitBash(windows), Mac OS X and 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(-)

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

좋아, 이것은이 문제를 해결하기위한 새로운 방법입니다 ... 내 접근 방식은 후크를 사용하지 않고 필터와 자식 속성을 사용하는 것입니다. 이 기능을 사용하면 개발중인 각 컴퓨터에서 파일 끝에서 추가 공백과 공백을 제거하는 필터 세트를 커밋하기 전에 설정할 수 있습니다. 그런 다음 필터를 적용 할 파일 형식을 나타내는 .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 스크립팅 매직 추가

Finally, put the fixup-eol-eof script somewhere on your path, and make it executable. The script uses sed to do some on the fly editing (remove spaces and blanks at the end of lines, and extraneous blank lines at the end of the file)

fixup-eol-eof should look like this:

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

my gist of this

Tell git which file types to apply your newly created filter to

Lastly, create or open ~/.gitattributes_global in your favorite editor and add lines like:

pattern attr1 [attr2 [attr3 […]]]

So if we want to fix the whitespace issue, for all of our c source files we would add a line that looks like this:

*.c filter=fix-eol-eof

Discussion of the filter

The filter has two phases, the clean phase which is applied when things are added to the index or checked in, and the smudge phase when git puts stuff into your working directory. Here, our smudge is just running the contents through the cat command which should leave them unchanged, with the exception of possibly adding a trailing newline character if there wasn’t one at the end of the file. The clean command is the whitespace filtering which I cobbled together from notes at http://sed.sourceforge.net/sed1line.txt. It seems that it must be put into a shell script, I couldn’t figure out how to inject the sed command, including the sanitation of the extraneous extra lines at the end of the file directly into the git-config file. (You CAN get rid of trailing blanks, however, without the need of a separate sed script, just set the filter.fix-eol-eofto something like sed 's/[ \t]*$//' %f where the \t is an actual tab, by pressing tab.)

The require = true causes an error to be raised if something goes wrong, to keep you out of trouble.

Please forgive me if my language concerning git is imprecise. I think I have a fairly good grasp of the concepts but am still learning the terminology.


Here is an ubuntu+mac os x compatible version:

#!/bin/sh
#

# A git hook script to find and fix trailing whitespace
# 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

Have fun


Was thinking about this today. This is all I ended up doing for a java project:

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

the for-loop for files uses the $IFS shell variable. in the given script, filenames with a character in them that also is in the $IFS-variable will be seen as two different files in the for-loop. This script fixes it: multiline-mode modifier as given sed-manual doesn't seem to work by default on my ubuntu box, so i sought for a different implemenation and found this with an iterating label, essentially it will only start substitution on the last line of the file if i've understood it correctly.

#!/bin/sh
#

# A git hook script to find and fix trailing whitespace
# 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 seperator, introduces EOL-bug?
IFS='
'
# Find files with trailing whitespace
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( MacOSx-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 whitespace-characters
exec git diff-index --check --cached $against --

[1] sed-subsition pattern: How can I replace a newline (\n) using sed? .


For Sublime Text users.

Set following properly in you Setting-User configuration.

"trim_trailing_white_space_on_save": true


This doesn't remove whitespace automatically before a commit, but it is pretty easy to effect. I put the following perl script in a file named git-wsf (git whitespace fix) in a dir in $PATH so I can:

git wsf | sh

and it removes all whitespace only from lines of files that git reports as a 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";
}

Slightly late but since this might help someone out there, here goes.

Open the file in VIM. To replace tabs with whitespaces, type the following in vim command line

:%s#\t#    #gc

To get rid of other trailing whitespaces

:%s#\s##gc

This pretty much did it for me. It's tedious if you have a lot of files to edit. But I found it easier than pre-commit hooks and working with multiple editors.


To delete trailing whitespace at end of line in a file portably, use ed:

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

This probably won't directly solve your problem, but you might want to set those via git-config in your actual project space, which edits ./.git/config as opposed to ~/.gitconfig. Nice to keep the settings consistent among all project members.

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

참고URL : https://stackoverflow.com/questions/591923/make-git-automatically-remove-trailing-whitespace-before-committing

반응형