공백이 아닌 변경 사항 만 추가


343

파일을 저장할 때 후행 공백을 자동으로 잘라내는 텍스트 편집기가 있으며 후행 공백에 심각한 문제가있는 오픈 소스 프로젝트에 기여하고 있습니다.

패치를 제출할 때마다 먼저 관련 공백 만 선택하여 관련 정보 만 선택해야합니다. 그것뿐만 아니라, 내가 달릴 때 git rebase나는 보통 몇 가지 문제 때문에 부딪칩니다.

따라서 나는 공백이 아닌 변경 사항 만 유사한 방식으로 색인에 추가 할 수 있기를 원 git add -p하지만 모든 변경 사항을 직접 선택할 필요는 없습니다.

누구든지 이것을하는 방법을 알고 있습니까?

편집 : 나는 프로젝트가 작동하는 방식을 바꿀 수 없으며 , 메일 링리스트에서 토론 한 후에 이것을 무시하기로 결정했습니다.

답변:


395

@Frew 솔루션은 내가 필요한 것이 아니기 때문에 정확히 같은 문제에 대해 만든 별칭입니다.

alias.addnw=!sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero -'

또는 간단하게 실행할 수 있습니다.

git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero -

최신 정보

이 의견 에 따라 옵션 -U0--unidiff-zero대안 컨텍스트 일치 문제를 추가 했습니다 .

기본적으로 add공백을 변경하지 않고 적용 할 패치를 적용합니다 . 당신은이 후 것을 볼 git addnw your/file아직 unstaged 변화가있을 것입니다, 그것은 왼쪽 공백을합니다.

--no-color는 필요하지 않지만 항상 색상이 설정되어 있으므로 사용해야합니다. 어쨌든 미안보다 안전합니다.


7
이것은 나를 위해 잘 작동했지만 git apply --ignore-whitespace다른 방법으로 패치를 적용해야했습니다.
jupp0r

106
git add 옵션이 실제로 있어야합니다 git add -w.
Jarl

7
이것은 나에게 문제를 patch does not apply주고 error while searching for... 어떤 아이디어?
DTI-Matt

18
나를 위해 일하지 않았다. 있어 patch does not apply오류가 발생했습니다.
Jerry Saravia

13
@bronson이 지적한 것처럼 컨텍스트의 공백으로 인해 '패치 실패'가 발생하면이 개정 된 명령이 작동합니다 (컨텍스트가없는 패치를 생성합니다) git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero. 인덱스가 가능한 한 최신 상태이기 때문에 위험하지 않으므로 패치의 신뢰할 수있는 기반입니다.
void.pointer

36

이것은 나를 위해 작동합니다 :

숨기고 싶다면이 방법이 효과적입니다.

git stash && git stash apply && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

나는하지 숨겨 놨다 좋아한다, 그러나 나는 자식 + Cygwin에서 내가 그렇게 물건을 내가 다음을 설정 적어도 reflog에 갔다 있는지 확인, 변경 내용이 손실 곳에서 버그로 실행 :

git add . && git commit -am 'tmp' && git reset HEAD^ && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

기본적으로 공간 변경을 포함하지 않는 diff를 만들고 모든 변경 사항을 되 돌린 다음 diff를 적용합니다.


1
+1. git stash적어도 테스트 될 때까지 변경 사항을 백업하기 위해 체크 아웃 대신 수행 할 수 있습니다 .
Paŭlo Ebermann 2016 년

1
당신은 많은 숨김으로 끝나고 기본적 으로이 모든 것을 실제로 할 필요는 없습니다. 작동하지만 조금 지저분하다고 생각합니다
Colin Hebert

3
콜린에 동의합니다. 스크립트가 작동하면 숨김을 만들 필요가 없습니다. stash를 실행 한 다음 stash pop을 실행하는 것이 좋을지 모릅니다. 필요한 경우 팝된 숨김을 복구 할 수 있지만 그렇지 않으면 많은 숨김으로 끝나지 않습니다. 이것은 또한 여분의 파일을 남겨 둡니다
Casebash

바이너리 파일을 건너 뛰는 것은 어떻습니까? 위의 스 니펫을 적용하려고 할 때 전체 색인 줄없이 패치를 적용 할 수 없다는 오류가 발생합니다! 나를이기는 것은 처음부터 이러한 파일 / 바이너리를 만지지 않았다는 것입니다!
tver3305

1
첫 번째 명령 "git rm foo.patch"의 끝은 "rm foo.patch"여야한다고 생각합니다. 그렇지 않으면 매우 도움이됩니다.
잭 케이시

33

실제 변경 사항 만 포함 된 패치 파일 (공백 변경 만있는 행 제외)을 만든 다음 작업 영역을 정리하고 해당 패치 파일을 적용하십시오.

git diff> 백업
git diff -w> 변경
git reset --hard
patch <변경

나머지 차이, 다음 검토 addcommit정상 등을.

Mercurial과 동등한 기능은 다음과 같습니다.

hg diff> 백업
hg diff -w> 변경
hg 되돌리기-모든
hg 가져 오기-커밋 변경 없음


"보호 된"질문은 무엇입니까? 그리고 나도 대답. 나는 그것이 질문이 얇은 공기에서 빠져 나온 것처럼 보이기 때문에 이것이 나에게도 대답 할 자격이 없다고 생각한다.
jww

4
@jww 원래 포스터의 핵심은 "공백 제어 만 소스 제어에 적용하지 않는 방법"입니다. OP는 Git을 사용하고 있지만 이것은 내가 사용한 모든 소스 제어 시스템에도 적용됩니다. 이 답변은 누군가가 Mercurial을 사용하는 경우 올바른 절차를 보여줍니다. Sublesion 등을 사용하는 사람들을 위해 다른 누군가가 솔루션을 제공 할 수도 있다고 상상할 수 있습니다.
Steve

1
@ jww와 @ pagid : Mercurial 솔루션과 동일한 접근 방식을 사용하여 Git을 구체적으로 다루기 위해 답변을 편집했습니다. 내 생각에 StackOverflow는 단순한 Q + A 포럼 이상이되며 지식 저장소 역할도합니다. 원래 포스터 이외의 사람들은 주어진 답변으로부터 도움을받을 수 있으며 상황은 다양합니다. 그렇기 때문에 하나의 특정 상황만을 목표로하는 것이 아니라 일반적인 원칙을 전달하는 답변이 유효하다고 생각합니다.
Steve Pitchers

@Steve- "Git을 구체적으로 설명하기 위해 답변을 편집했습니다 ..." -왜 수은과 관련하여 새로운 질문을 한 다음 새로운 질문에 자신의 답변을 추가하지 않습니까?
jww

8
이것은 실제로 내가 본 접근 중 가장 깨끗하고 이해 가능하며 깨지지 않는 방법입니다.
Kzqai 2016 년

12

댓글의 사용자에 따라 패치 컨텍스트의 공백으로 인해 최상위 투표 답변이 모든 경우에 작동하지 않습니다.

다음과 같이 명령을 수정했습니다.

$ git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero

컨텍스트가없는 패치를 생성합니다. 패치의 수명이 짧기 때문에 문제가되지 않습니다.

해당 별칭, 다시 다른 사용자가 제공 한 내용의 개정판 :

addw = !sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero' -

들여 쓰기 변경 사항 만 무시하려면 --ignore-space-change대신 사용해야 했습니다 -w. git diff -U0 --ignore-space-change --no-color | git apply --cached --unidiff-zero
Andy

이 사랑스럽고 맥락없는 트릭을 사용하지 말라고 경고하는 단어는 무시하려는 '공백'변경 사항 중 일부가 빈 줄 제거 / 추가 인 경우 다른 오프셋 --ignore-blank-lines잘못된 오프셋 으로 패치되는 것을 알 수 있습니다.
elbeardmorez

12

에 다음을 추가하십시오 .gitconfig.

anw = !git diff -U0 -w --no-color -- \"$@\" | git apply --cached --ignore-whitespace --unidiff-zero "#"

영감 을 주신 @Colin Herbert의 답변 에 감사드립니다 .

구문 설명

마지막은 #이 내부 주석으로 처리하지 그래서 인용해야 .gitconfig하지만, 대신 통해 전달되는 쉘 내부에 주석으로 처리됩니다 - 그것은 말 사이에 삽입 git apply하고 사용자가 제공 한 인수가 git상기 자동 장소 명령 행의 끝. 이러한 주장은 여기서 원하지 않습니다 – 우리는 git apply그것들을 사용하고 싶지 않기 때문에 앞의 주석 문자입니다. 이 명령을 실행하여이 명령을 실행할 수 있습니다 GIT_TRACE=1 git anw.

--신호는 인수의 종료 및 명명 된 파일이있는 경우에 허용 -w거나 스위치처럼 보이는 무언가를 git diff.

$@사용자가 제공 한 인용 인수를 유지하려면 이스케이프 된 큰 따옴표 가 필요합니다. 경우 "문자가 탈출하지 않습니다, 그것은에 의해 소비 될 것이다 .gitconfig파서와 쉘에 도달하지.

참고 : .gitconfig별칭 구문 분석 아무것도 특별 같은 작은 따옴표를 인식하지 못합니다 - 유일한 특수 문자는 ", \, \n, 및 ;(A 외부 "-quoted 문자열). 이것이 "작은 따옴표로 묶인 문자열 안에있는 것처럼 보이더라도 항상 탈출 해야하는 이유입니다 (git은 완전히 무의식적입니다).

예를 들어 이것은 중요합니다. bash작업 트리의 루트에서 명령 을 실행하기에 편리한 별칭이있는 경우 잘못된 공식은 다음과 같습니다.

sh = !bash -c '"$@"' -

올바른 것은 다음과 같습니다.

sh = !bash -c '\"$@\"' -

우수한. 이를 통해 한 번에 하나의 파일을 추가 할 수있었습니다. 인수에 루트 디렉토리를 추가하는 것 외에, 'git add -A'와 같은 작업을 수행하는 방법이 있습니까?
Chucky

7

다음은 어떻습니까 :

git add `git diff -w --ignore-submodules |grep "^[+][+][+]" |cut -c7-`

역 따옴표 안의 명령은 공백이 아닌 파일 이름을 가져옵니다.


2
또는 git add `git diff -w |grep '^+++' |cut -c7-`서브 모듈을 사용하지 않는 경우
karmakaze

-1

후행 공백이 의도적인지 먼저 고려해야합니다. Linux 커널, Mozilla, Drupal 및 Kerberos를 포함한 많은 프로젝트 (스타일에 대한 Wikipedia 페이지에서 일부를 언급)는 후행 공백을 금지합니다. 리눅스 커널 문서에서 :

적절한 편집기를 사용하고 줄 끝에 공백을 두지 마십시오.

귀하의 경우 문제는 다른 방법입니다. 이전 커밋 (및 현재 커밋) 은이 지침을 따르지 않았습니다.

나는 아무도 후행 공백을 원하지 않으며, 문제를 해결하는 것이 환영받을만한 변화라고 생각합니다. 다른 사용자도 같은 문제가 발생할 수 있습니다. 후행 공백을 추가하는 기고자들이 그렇게하고 있다는 것을 인식하지 못할 수도 있습니다.

문제를 무시하기 위해 git을 재구성하거나 편집기에서 다른 바람직한 기능을 비활성화하는 대신 문제를 설명하는 프로젝트 메일 링리스트에 게시하는 것으로 시작하겠습니다. 많은 편집기 (및 git 자체)는 후행 공백을 처리하도록 구성 할 수 있습니다.


16
의도적이지는 않지만 프로젝트에 참여한 100 명 이상의 사람들이 생각하는 방식을 바꿀 수는 없습니다. 그들은 신경 쓰지 않으며 후행 공백 만 처리하는 1000 개 이상의 변경 사항이있는 패치를 허용하지 않습니다. 그들은 문제에 대해 알고 무시하기로 결정했습니다. 이 토론은 이미 목록에서 이루어졌으며 닫혔습니다. 이 경우, 그들에게 적응해야 할 사람은 나입니다.
Edu Felipe

19
그런 다음이 프로젝트 코드에서 작업 할 때 후행 공백을 자르지 않도록 편집기를 구성하십시오.
jamessan

-2

후행 공백을 제거 하는 자식 사전 커밋 후크를 찾았습니다 . 그러나 다른 사람들이 이것을 사용할 수 없다면 유효한 해결책이 아닐 수도 있습니다.

  #!/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"
  done
  exit

4
이 질문은 후행 공백을 유지하는 방법을 묻습니다.
Douglas Douglas

@Douglas : 아마도이 답변을 사용하여 임시 브랜치에서 커밋을 만들고, 실제 패치를 커밋하고 어떻게 든 브랜치로만 diff를 선택할 수 있습니다.
Tobias Kienzler
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.