힘내 : 저장소에서 파일을 삭제하지 않고 색인에서 파일을 제거하는 방법


163

사용할 때

git rm --cached myfile

로컬 파일 시스템에서 삭제되지 않습니다. 이것이 목표입니다. 그러나 이미 파일의 버전을 지정하고 커밋 한 경우 명령을 사용하기 전에 파일을 중앙 리포지토리로 푸시하고 다른 리포지토리로 가져 오면 해당 시스템에서 파일이 삭제됩니다.

파일 시스템에서 파일을 삭제하지 않고 버전 관리에서 파일을 제거하는 방법이 있습니까?

편집 : 명확히, 나는 희망한다.


아마도 사용 사례를 확장 할 수 있습니다. 인덱스는 다음 커밋을위한 준비 영역이므로 현재 분기에서 파일을 제거하지 않으려면 왜 인덱스에서 파일을 제거 하시겠습니까?
CB Bailey

1
죄송 해요. 나는 myfile이 어떤 이유로 든 오래 전에 커밋되고 배포되었다고 말하려고했습니다. 이제 목표는 사람들의 시스템에서 삭제하지 않고 버전 관리에서 제거하는 것입니다. 이것이 나온 이유는 실수로 구성 파일의 버전을 지정했기 때문입니다. 구성 파일이 필요하므로 외부 시스템에서 구성 파일을 제거하고 싶지 않습니다.
Fletcher Moore

질문을 더 명확하게 편집했습니다.
Fletcher Moore

3
git rm --cached는 다른 작업 디렉토리에서 파일을 제거하지 않습니다. 해당 디렉토리에서 작업하는 사람이 풀을 실행하는 경우에만 파일이 제거됩니다. 이 파일은 쉽게 복구 할 수 있습니다 "자식 체크 아웃 HEAD @ {1} foo는"(풀 후 즉시 실행합니다.)
윌리엄 Pursell을

답변:


119

Git 커밋이 "이 파일 추적을 중지하지만 삭제하지 마십시오"와 같은 의도를 기록 할 수 있다고 생각하지 않습니다.

이러한 의도를 실현하려면 파일을 삭제하는 커밋을 병합하거나 리베이스하는 저장소에서 Git 외부의 개입이 필요합니다.


사본 저장, 삭제 적용, 복원

아마도 가장 쉬운 방법은 다운 스트림 사용자에게 파일 사본을 저장하고 삭제 한 다음 파일을 복원하도록 지시하는 것입니다. 리베이스를 통해 파일을 가져오고 파일을 수정하는 경우 충돌이 발생합니다. 이러한 충돌을 해결하려면 git rm foo.conf && git rebase --continue(충돌 된 커밋이 제거 된 파일 이외의 변경 사항이있는 git rebase --skip경우 ) 또는 (충돌하는 커밋이 제거 된 파일로만 변경된 경우)를 사용하십시오.

삭제 된 커밋을 가져온 후 파일을 추적되지 않은 상태로 복원

이미 삭제 커밋을 가져온 경우 git show 를 사용하여 파일의 이전 버전을 복구 할 수 있습니다 .

git show @{1}:foo.conf >foo.conf

또는 git checkout (William Pursell의 의견에 따라; 색인에서 다시 제거해야합니다!) :

git checkout @{1} -- foo.conf && git rm --cached foo.conf

삭제를 가져온 후 다른 조치를 취한 경우 (또는 분리 된 HEAD로 리베이스를 사용하는 경우) 이외의 것이 필요할 수 있습니다 @{1}. 그들은 git log -g삭제하기 직전에 커밋을 찾는 데 사용할 수 있습니다 .


한 의견에서“추적을 해제하지만 유지”하려는 파일은 소프트웨어를 실행하는 데 필요한 일종의 구성 파일이라고합니다 (직접 저장소 외부에서).

파일을 '기본'으로 유지하고 수동 / 자동으로 활성화

이 저장소에있는 구성 파일의 내용을 유지하기 위해 계속 완전히 받아 들일 수없는 경우 (예를 들어)에서 추적 파일의 이름을 변경 할 수 있습니다 foo.conffoo.conf.default다음 사용자에 지시하려면 cp foo.conf.default foo.conf이름 바꾸기 커밋 적용한 후. 또는 사용자가 이미 리포지토리의 기존 부분 (예 : 스크립트 또는 리포지토리의 내용으로 구성된 다른 프로그램 (예 : Makefile유사))을 사용하여 소프트웨어를 시작 / 배포하는 경우 기본 메커니즘을 시작 / 배포 프로세스 :

test -f foo.conf || test -f foo.conf.default &&
    cp foo.conf.default foo.conf

이러한 기본 메커니즘을 사용하면 사용자는 추가 작업을 수행하지 않고도 이름 foo.conf을 바꾸는 커밋을 가져올 수 foo.conf.default있습니다. 또한 나중에 추가 설치 / 저장소를 만드는 경우 구성 파일을 수동으로 복사하지 않아도됩니다.

기록을 다시 쓰려면 수동 개입이 필요합니다…

저장소에서 컨텐츠를 유지 보수 할 수없는 경우 다음과 같이 히스토리에서 컨텐츠를 완전히 제거 할 수 git filter-branch --index-filter …있습니다. 이것은 기록을 다시 작성하는데, 각 브랜치 / 리포지토리에 대해 수동 개입이 필요합니다 ( git rebase 맨 페이지 의“업스트림 리베이스 에서 복구”섹션 참조 ). 구성 파일에 필요한 특수 처리는 다시 쓰기에서 복구하는 동안 수행해야하는 또 다른 단계 일뿐입니다.

  1. 구성 파일의 사본을 저장하십시오.
  2. 다시 쓰기에서 복구하십시오.
  3. 구성 파일을 복원하십시오.

재발을 방지하기 위해 무시

어떤 방법을 사용하든, .gitignore아무도 실수로 git add foo.conf다시 할 수 없도록 저장소 의 파일에 구성 파일 이름을 포함 시키려고 할 수 있습니다 (가능하지만 -f/ 가 필요함 --force). 구성 파일이 둘 이상인 경우 구성 파일을 모두 단일 디렉토리로 '이동'하고 전체를 무시하는 것을 고려할 수 있습니다 ( '이동'함으로써 프로그램이 구성 파일을 찾을 위치를 변경하고 사용자를 가져 오는 것을 의미합니다 (또는 파일을 새 위치로 복사 / 이동하기위한 실행 / 배포 메커니즘) : 파일을 무시할 디렉토리에 mv 파일을 넣고 싶지는 않을 것입니다).


5
엄청나게 철저한 대응. 감사합니다!
Fletcher Moore

아래의 Tom Power의 답변은 첫 번째 문장과 모순되는 것으로 보입니다.
Mike S

1
@ Mikes : 그 효과 --{,no-}assume-unchanged는 순전히 로컬입니다 : 상태는 커밋에 직접 기록되지 않습니다. 리포지토리가 파일에 대한 새로운 변경 사항을 커밋하지 못하게 할 수 있지만 버전 관리에서 제거하지는 않습니다. 귀하의 모든 관련 관련, 비 노출 된 저장소에 대해 설정할 수있는 경우에, 당신의 상황에 도움이 될 수 있습니다,하지만 당신은 수있는 것이 아닙니다 직접 (기타 관련, 비 베어 저장소에 특히 사람이를 + 풀 / REBASE를 밀어 귀하는 질문에 대한 최초의 질문자의 명확한 설명에 따라 통제 할 수 없습니다.
Chris Johnsen

1
I do not think a Git commit can record an intention like “stop tracking this file, but do not delete it”.-이제 가능합니다git rm --cached foo.conf
Nick Volynkin

1
@ NickVolynkin : 질문이 이미 어커의 목적에 부적합하다는 것을 나타내지 않습니다. 결과 커밋이 다른 저장소로 풀 될 때 파일을 (자동으로) 유지합니까?
Chris Johnsen 2016 년

86

이번 주에 실수로 커밋했을 때 똑같은 문제가 있었지만 공유 저장소에서 빌드 파일을 제거하려고 시도했습니다.

http://gitready.com/intermediate/2009/02/18/temporarily-ignoring-files.html

나를 위해 잘 작동했지만 지금까지 언급하지 않았습니다.

git update-index --assume-unchanged <file>

버전 관리에서 관심있는 파일을 제거하려면 다른 모든 명령을 정상적으로 사용하십시오.

git update-index --no-assume-unchanged <file>

다시 넣고 싶었다면.

편집 : Chris Johnsen 및 KPM의 의견을 참조하십시오.이 기능은 로컬에서만 작동하며 다른 사용자가하지 않은 경우 파일을 버전 제어 상태로 유지합니다. 허용 된 답변은이를 처리하기위한보다 완전하고 올바른 방법을 제공합니다. 이 방법을 사용하는 경우 링크의 참고 사항도 있습니다.

분명히 이것과 관련하여 몇 가지주의 사항이 있습니다. 파일을 직접 추가하면 인덱스에 추가됩니다. 이 플래그를 사용하여 커밋을 병합하면 병합이 정상적으로 실패하여 수동으로 처리 할 수 ​​있습니다.


7
이것은 언급 된 특정 문제에 대한 답이 아닙니다. 자체 로컬 저장소에서만 작동하므로 각 사용자가 직접 수행해야합니다. 고통입니다.
KPM

28

색인에서 파일을 제거하려면 다음을 사용하십시오.

git reset myfile

이것은 로컬 사본이나 다른 사람에게 영향을 미치지 않아야합니다.


1
reset파일이 현재 HEAD 커밋에없는 경우에만 색인에서 파일을 제거하고, 그렇지 않으면 색인 버전을 현재 HEAD 버전으로 되돌립니다.
CB Bailey

1
아마도 나는 그 질문을 오해했지만, 커밋에 영향을 미치지 않고 인덱스에서 파일을 제거하는 것과 관련이있는 것 같습니다.
Armand

Charles가 말했듯이 reset은 "파일 제거"가 아닙니다. 자세한 내용을 보려면 git help reset을 입력하십시오.
Simon B.

4
"저장소에서 파일을 삭제하지 않고 색인에서 파일을 제거하는 방법"이라는 제목의 질문에 대한 답변입니다. OP는 실제로 "로컬 사본을 삭제하지 않고 파일을 어떻게 추적 해제합니까?"
hewsonism

@hewsonism OP는 "모든 파일 시스템"(편집 전이라도)이라고 말했습니다.
jbobbins


15

수행 한 후 git rm --cached명령을 추가하려고 myfile받는 .gitignore파일 (존재하지 않는 경우 새로 생성). 이것은 git에게 무시하도록 지시해야한다 myfile.

.gitignore당신이 그것을 커밋하고 원격 저장소에 밀어해야하므로 파일은 버전이있다.


1

내 해결책은 다른 작업 사본을 가져온 다음 수행하는 것입니다.

git log --pretty="format:" --name-only -n1 | xargs git checkout HEAD^1

최신 주석의 모든 파일 경로를 가져 와서 HEAD의 부모에서 확인하십시오. 작업이 완료되었습니다.


0

위의 솔루션은 대부분의 경우 잘 작동합니다. 그러나 해당 파일의 모든 추적 (예 : 비밀번호와 같은 민감한 데이터)도 제거해야하는 경우 파일을 계속 검색 할 수 있으므로 전체 커밋 히스토리에서 해당 파일을 제거해야합니다.

존재하지 않는 것처럼 전체 커밋 기록에서 파일의 모든 흔적을 제거하면서 파일을 시스템에 그대로 유지하는 솔루션이 있습니다.

https://help.github.com/articles/remove-sensitive-data/

로컬 git 저장소에 있고 드라이 런을 수행하지 않아도되는 경우 실제로 3 단계로 건너 뛸 수 있습니다. 필자의 경우 이미 .gitignore 파일을 만들고 작업하려는 리포지토리에 있었기 때문에 3 단계와 6 단계 만 필요했습니다.

변경 사항을 보려면 리포지토리의 GitHub 루트로 이동하여 페이지를 새로 고쳐야 할 수도 있습니다. 그런 다음 링크를 탐색하여 파일이 있던 이전 커밋으로 이동하여 파일이 제거되었는지 확인하십시오. 나를 위해 단순히 이전 커밋 페이지를 새로 고치면 변경 사항이 표시되지 않았습니다.

처음에는 위협적으로 보였지만 실제로는 쉽고 매력처럼 작동했습니다! :-)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.