문제

실수로 원치 않는 파일을 커밋했습니다 (filename.orig 내 저장소로의 병합을 해결하는 동안 몇 번의 커밋 전에, 지금까지 눈치 채지 못했습니다. 저장소 기록에서 파일을 완전히 삭제하고 싶습니다.

변경 기록을 다시 작성할 수 있습니까? filename.orig 처음에 저장소에 추가되지 않았습니까?

도움이 되었습니까?

해결책

귀하의 상황이 질문에 설명 된 상황이 아닌 경우이 레시피를 사용하지 마십시오. 이 레시피는 잘못된 병합을 고정하고 좋은 커밋을 고정 합병으로 재생하기위한 것입니다.

하지만 filter-branch 당신이 원하는 것을 할 것입니다. 그것은 꽤 복잡한 명령이며 아마도 이것을하기로 선택할 것입니다. git rebase. 아마도 개인적인 취향 일 것입니다. filter-branch 단일, 약간 더 복잡한 명령으로 할 수 있지만 rebase 솔루션은 한 번에 한 단계 씩 동등한 논리 작업을 수행하는 것입니다.

다음 레시피를 시도하십시오.

(실제로 임시 지점이 필요하지 않으며 '분리 된 머리'로이 작업을 수행 할 수 있지만 git commit --amend 공급하기위한 단계 git rebase 임시 지점 이름을 사용하기보다는 명령.)

다른 팁

소개 : 5 가지 솔루션을 사용할 수 있습니다

원래 포스터는 다음과 같습니다.

실수로 원치 않는 파일을 커밋했습니다 ... 몇 명의 커밋 전에 저장소에 ... 저장소 기록에서 파일을 완전히 삭제하고 싶습니다.

변경 기록을 다시 작성할 수 있습니까? filename.orig 처음에 저장소에 추가되지 않았습니까?

git에서 파일의 기록을 완전히 제거하는 방법에는 여러 가지가 있습니다.

  1. 수정은 커밋됩니다.
  2. 하드 리셋 (아마도 리베이스와 함께).
  3. 비 중과 리바이스.
  4. 대화식 레바 제.
  5. 필터링 분기.

원래 포스터의 경우, 커밋을 수정하는 것은 실제로 선택이 아닙니다. 나중에 몇 차례 추가 커밋을했기 때문에 완전성을 위해서는 Justs가 원하는 다른 사람을 위해 어떻게 해야하는지 설명 할 것입니다. 그들의 이전 커밋을 수정합니다.

이러한 모든 솔루션에는 관련이 있습니다 변경/재 작성 역사/커밋은 다른 방식으로 커밋되므로, 구식 사본을 가진 사람은 누구나 새로운 역사와 역사를 다시 동기화하기 위해 추가 작업을 수행해야합니다.


솔루션 1 : 수정이 커밋됩니다

실수로 이전 커밋에서 파일 추가 (예 : 파일 추가)를 변경하고 그 변경의 이력이 더 이상 존재하기를 원하지 않으면 이전 커밋을 그로부터 제거하기 위해 간단히 수정할 수 있습니다.

git rm <file>
git commit --amend --no-edit

솔루션 2 : 하드 리셋 (아마도 리베이스와 함께)

솔루션 #1과 마찬가지로 이전 커밋을 제거하려면 부모에게 하드 리셋을 단순히 수행 할 수있는 옵션도 있습니다.

git reset --hard HEAD^

그 명령 부모 커밋.

하지만, 원래 포스터와 마찬가지로, 변경 사항을 취소하려는 커밋 후 몇 차례 커밋을 한 경우에도 하드 리셋을 사용하여 수정할 수 있지만 그렇게하면 Rebase를 사용하는 것도 포함됩니다. 역사상 더 큰 커밋을 수정하는 데 사용할 수있는 단계는 다음과 같습니다.


솔루션 3 : 비 응체 리베이스

역사에서 전적으로 커밋을 제거하고 싶다면 다음과 같습니다.


해결책 4 : 대화식 레바 제

이 솔루션을 사용하면 솔루션 #2 및 #3과 동일한 것을 달성 할 수 있습니다. 즉, 즉시 이전 커밋보다 역사상 커밋을 수정하거나 제거합니다. 대화 형 레아 베스는 성능의 이유로 수백 가지의 커밋을 재건하는 데 적합하지 않으므로 이러한 종류의 상황에서 비 중환자 레바 제 또는 필터 브랜치 솔루션 (아래 참조)을 사용합니다.

대화식 레바이스를 시작하려면 다음을 사용하십시오.

이로 인해 GIT가 커밋 역사를 수정하거나 제거하려는 커밋의 부모에게 다시 전달할 수 있습니다. 그런 다음 편집기 GIT가 사용되는 편집기 GIT (기본적으로 VIM)에서 리바운드 커밋 목록을 역 순서로 표시합니다.

pick 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
pick 7668f34 Modify Bash config to use Homebrew recommended PATH
pick 475593a Add global .gitignore file for OS X
pick 1b7f496 Add alias for Dr Java to Bash config (OS X)

수정하거나 제거하려는 커밋은이 목록의 맨 위에 있습니다. 제거하려면 목록에서 라인을 삭제하십시오. 그렇지 않으면 "선택"을 1의 "편집"으로 바꾸십시오. 그런 선과 같은 라인 :

edit 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`

다음으로 입력하십시오 git rebase --continue. 커밋을 완전히 제거하기로 선택한 경우, 그 모든 것이 수행 해야하는 모든 것을 선택한 경우 (확인을 제외 하고이 솔루션의 최종 단계를 참조하십시오). 반면에 커밋을 수정하려면 git이 커밋을 다시 신청 한 다음 Rebase를 일시 중지합니다.

Stopped at 00ddaacab0a85d9989217dd9fe9e1b317ed069ac... Add symlinks
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

이 시점에서 파일을 제거하고 커밋을 수정 한 다음 Rebase를 계속할 수 있습니다.

git rm <file>
git commit --amend --no-edit
git rebase --continue

그게 다야. 마지막 단계로서, 커밋을 수정했거나 완전히 제거하든 완전히 제거하든, Rebase 이전에 상태와 다른 지점을 차단하여 다른 예상치 못한 변경 사항이 없음을 확인하는 것은 항상 좋은 생각입니다.

git diff master@{1}

해결책 5 : 필터링 분기

마지막으로,이 솔루션은 역사에서 파일의 존재의 모든 흔적을 완전히 닦으려면 가장 좋습니다.

그것은 제거 할 것입니다 <file> 루트 커밋에서 시작하여 모든 커밋에서. 대신 커밋 범위를 다시 작성하려면 HEAD~5..HEAD, 당신은 그것을 추가 논쟁으로 전달할 수 있습니다. filter-branch, 지적한대로이 답변:

다시, 후 filter-branch 완료되며, 일반적으로 필터링 작업 전에 지점을 이전 상태로 전환함으로써 다른 예상치 못한 변경 사항이 없음을 확인하는 것이 좋습니다.

git diff master@{1}

필터 브랜치 대안 : BFG 리포 클리너

나는 그 말을 들었다 BFG 리포 클리너 도구는보다 빠르게 실행됩니다 git filter-branch, 따라서 옵션으로 확인하고 싶을 수도 있습니다. 공식적으로 언급되어 있습니다 필터 브랜치 문서 실행 가능한 대안으로 :

Git-Filter-Branch는 GIT 기록을 복잡한 쉘 스크립트 재 작성을 만들 수 있지만 간단한 경우이 유연성이 필요하지 않을 것입니다. 원치 않는 데이터 제거 큰 파일이나 비밀번호처럼. 해당 작업의 경우 고려할 수 있습니다 BFG 리포 클리너, git-filter-branch에 대한 JVM 기반 대안, 일반적으로 이러한 유스 케이스의 경우 적어도 10-50 배 더 빠르고 매우 다른 특성을 갖습니다.

  • 특정 버전의 파일은 정확히 정리됩니다 한 번. BFG는 Git-Filter-Branch와는 달리 파일이 귀하의 역사 내에서 어디에서 저지른시기에 따라 다르게 처리 할 수있는 기회를 제공하지 않습니다. 이 제약 조건은 BFG의 핵심 성능 이점을 제공하며 나쁜 데이터를 정리하는 작업에 적합합니다. 어디 나쁜 데이터는 단지 원한다는 것입니다 다 쓴.

  • 기본적으로 BFG는 멀티 코어 머신을 최대한 활용하여 클렌징 파일 트리를 병렬로 커밋합니다. git-filter-branch는 순차적으로 커밋됩니다 (즉, 단일 스레드 방식으로) ~이다각 커밋에 대해 실행 된 스크립트에서 자신의 평행주의를 포함하는 필터를 작성할 수 있습니다.

  • 그만큼 명령 옵션 Git-Filter 지점보다 훨씬 제한적이며 원치 않는 데이터를 제거하는 작업에 전념합니다. --strip-blobs-bigger-than 1M.

추가 리소스

  1. Pro Git § 6.4 git 도구 - 재 작성 기록.
  2. git-filter-branch (1) 매뉴얼 페이지.
  3. git-commit (1) 수동 페이지.
  4. git-reset (1) 수동 페이지.
  5. git-rebase (1) 수동 페이지.
  6. BFG 리포 클리너 (또한보십시오 이 대답은 창조주 자신의 대답입니다).

당신이 그 이후로 아무것도 헌신하지 않았다면, 그냥 git rm 파일과 git commit --amend.

당신이 가지고 있다면

git filter-branch \
--index-filter 'git rm --cached --ignore-unmatch path/to/file/filename.orig' merge-point..HEAD

각 변경 사항을 통해 진행됩니다 merge-point 에게 HEAD, filename.orig를 삭제하고 변경을 다시 작성하십시오. 사용 --ignore-unmatch 어떤 이유로 Filename.orig가 변경에서 누락 된 경우 명령이 실패하지 않음을 의미합니다. 그것이 예제 섹션에서 권장되는 방법입니다. git-filter-branch man 페이지.

Windows 사용자의 참고 : 파일 경로 ~ 해야 하다 앞쪽 슬래시를 사용하십시오

이것이 가장 좋은 방법입니다.
http://github.com/guides/completely-remove-a-file-from-all-revisions

먼저 파일의 사본을 백업하십시오.

편집하다

편집 네온 불행히도 검토 중에 거부당했습니다.
아래 Neons 게시물을 참조하십시오. 유용한 정보가 포함되어있을 수 있습니다!


예를 들어 모든 것을 제거합니다 *.gz 실수로 git 저장소에 커밋 된 파일 :

$ du -sh .git ==> e.g. 100M
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch *.gz' HEAD
$ git push origin master --force
$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --prune=now
$ git gc --aggressive --prune=now

여전히 나를 위해 효과가 없었습니까? (저는 현재 GIT 버전 1.7.6.1에 있습니다)

$ du -sh .git ==> e.g. 100M

왜 마스터 지점 만 있었기 때문에 왜 그런지 잘 모르겠습니다. 어쨌든, 나는 마침내 새로운 비어 있고 베어 git 리포지토리를 밀어서 내 git repo를 진정으로 청소했습니다.

$ git init --bare /path/to/newcleanrepo.git
$ git push /path/to/newcleanrepo.git master
$ du -sh /path/to/newcleanrepo.git ==> e.g. 5M 

(예!)

그런 다음 새 디렉토리로 복제하고 .git 폴더를이 디렉토리로 옮겼습니다. 예를 들어

$ mv .git ../large_dot_git
$ git clone /path/to/newcleanrepo.git ../tmpdir
$ mv ../tmpdir/.git .
$ du -sh .git ==> e.g. 5M 

(예! 드디어 청소!)

모든 것이 잘 있는지 확인한 후 ../large_dot_git 그리고 ../tmpdir 디렉토리 (아마도 몇 주 또는 한 달 안에, 만일만큼 ...)

GIT 이력을 다시 작성하려면 영향을받는 모든 커밋 ID를 변경해야하므로 프로젝트 작업을 수행하는 모든 사람은 리포의 이전 사본을 삭제하고 역사를 청소 한 후 신선한 클론을 수행해야합니다. 불편 함이 많을수록 더 많은 이유가 필요합니다. 불필요한 파일은 실제로 문제를 일으키는 것이 아니라 프로젝트를 진행하고 있으며, 원한다면 GIT 역사를 정리할 수도 있습니다!

가능한 한 쉽게 만들려면 BFG 리포 클리너, 더 간단하고 빠른 대안 git-filter-branch GIT 기록에서 파일을 제거하도록 특별히 설계되었습니다. 여기서 인생을 더 쉽게 만드는 한 가지 방법은 실제로 처리한다는 것입니다. 모두 기본적으로 참조 (모든 태그, 분기 등). 10-50x 더 빠르게.

여기서 단계를주의 깊게 따라야합니다. http://rtyley.github.com/bfg-repo-cleaner/#usage -하지만 핵심 비트는 바로 다음입니다. 다운로드 BFG JAR (Java 6 이상이 필요) 및이 명령을 실행합니다.

$ java -jar bfg.jar --delete-files filename.orig my-repo.git

전체 저장소 기록이 스캔되며 이름이 지정된 파일 filename.orig (그것은 당신의 안에 있지 않습니다 최신 저지르다) 제거됩니다. 이것은 사용하는 것보다 훨씬 쉽습니다 git-filter-branch 똑같은 일을하기 위해!

전체 공개 : 저는 BFG 리포 클리너의 저자입니다.

You should probably clone your repository first.

Remove your file from all branches history:
git filter-branch --tree-filter 'rm -f filename.orig' -- --all

Remove your file just from the current branch:
git filter-branch --tree-filter 'rm -f filename.orig' -- --HEAD    

Lastly you should run to remove empty commits:
git filter-branch -f --prune-empty -- --all

Charles Bailey의 솔루션에 추가하기 위해 Git Rebase -I를 사용하여 이전 커밋에서 원치 않는 파일을 제거했으며 매력처럼 작동했습니다. 단계들:

# Pick your commit with 'e'
$ git rebase -i

# Perform as many removes as necessary
$ git rm project/code/file.txt

# amend the commit
$ git commit --amend

# continue with rebase
$ git rebase --continue

내가 찾은 가장 간단한 방법은 제안했습니다 leontalbot (의견으로), 그것은 a Anoopjohn에 의해 게시 된 게시물. 답으로 자체 공간의 가치가 있다고 생각합니다.

(나는 그것을 bash 스크립트로 변환했다)

#!/bin/bash
if [[ $1 == "" ]]; then
    echo "Usage: $0 FILE_OR_DIR [remote]";
    echo "FILE_OR_DIR: the file or directory you want to remove from history"
    echo "if 'remote' argument is set, it will also push to remote repository."
    exit;
fi
FOLDERNAME_OR_FILENAME=$1;

#The important part starts here: ------------------------

git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch $FOLDERNAME_OR_FILENAME" -- --all
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

if [[ $2 == "remote" ]]; then
    git push --all --force
fi
echo "Done."

모든 크레딧이 있습니다 Annopjohn, 그리고 leontalbot 그것을 지적하기 위해.

노트

스크립트에 유효성 검사가 포함되어 있지 않으므로 실수를하지 않고 문제가 발생할 경우 백업이 있는지 확인하십시오. 그것은 나를 위해 일했지만 당신의 상황에서는 효과가 없을 수도 있습니다. 주의해서 사용하십시오 (무슨 일이 일어나고 있는지 알고 싶다면 링크를 따르십시오).

분명히, git filter-branch 갈 길입니다.

안타깝게도 이것은 완전히 제거하기에 충분하지 않습니다 filename.orig REPO에서 태그, 리플 로그 항목, 리모컨 등으로 여전히 참조 할 수 있으므로.

이 모든 참조를 제거한 다음 쓰레기 수집기를 호출하는 것이 좋습니다. 당신은 사용할 수 있습니다 git forget-blob 스크립트 이것 한 단계 로이 모든 것을 할 웹 사이트.

git forget-blob filename.orig

정리하고 싶은 최신 커밋 인 경우 GIT 버전 2.14.3 (Apple Git-98)으로 시도했습니다.

touch empty
git init
git add empty
git commit -m init

# 92K   .git
du -hs .git

dd if=/dev/random of=./random bs=1m count=5
git add random
git commit -m mistake

# 5.1M  .git
du -hs .git

git reset --hard HEAD^
git reflog expire --expire=now --all
git gc --prune=now

# 92K   .git
du -hs .git

이것이 무엇입니다 git filter-branch 설계되었습니다.

당신은 또한 사용할 수 있습니다 :

git reset HEAD file/path

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top