Git 프로젝트를 GitHub에 배치하고 싶지만 중요한 데이터가 포함 된 특정 파일 (사용자 이름 및 비밀번호, capistrano의 경우 /config/deploy.rb)이 포함되어 있습니다.
이 파일 이름을 .gitignore에 추가 할 수 있지만 Git 내에서 기록을 제거하지는 않습니다.
또한 /.git 디렉토리를 삭제하여 다시 시작하고 싶지 않습니다.
Git 히스토리에서 특정 파일의 모든 흔적 을 제거하는 방법이 있습니까?
Git 프로젝트를 GitHub에 배치하고 싶지만 중요한 데이터가 포함 된 특정 파일 (사용자 이름 및 비밀번호, capistrano의 경우 /config/deploy.rb)이 포함되어 있습니다.
이 파일 이름을 .gitignore에 추가 할 수 있지만 Git 내에서 기록을 제거하지는 않습니다.
또한 /.git 디렉토리를 삭제하여 다시 시작하고 싶지 않습니다.
Git 히스토리에서 특정 파일의 모든 흔적 을 제거하는 방법이 있습니까?
답변:
모든 실질적인 목적을 위해 가장 먼저 염려해야 할 것은 암호 변경입니다! git 저장소가 완전히 로컬인지 아니면 다른 곳에 원격 저장소가 있는지는 확실하지 않습니다. 원격이고 다른 사람으로부터 보호되지 않으면 문제가있는 것입니다. 이 문제를 해결하기 전에 해당 리포지토리를 복제 한 사용자는 로컬 컴퓨터에 암호 복사본을 갖게되며 기록에서 나온 "고정"버전으로 강제로 업데이트 할 수있는 방법이 없습니다. 당신이 할 수있는 유일한 안전한 방법은 당신이 사용한 다른 곳으로 암호를 바꾸는 것입니다.
그 방법으로 문제를 해결하는 방법은 다음과 같습니다. GitHub는 그 질문에 정확히 FAQ로 답했습니다 .
Windows 사용자를위한 참고 사항 :이 명령에서 작은 따옴표 대신 큰 따옴표 ( ")를 사용하십시오.
git filter-branch --index-filter \
'git update-index --remove PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA' <introduction-revision-sha1>..HEAD
git push --force --verbose --dry-run
git push --force
2019 업데이트 :
이것은 FAQ의 현재 코드입니다.
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" \
--prune-empty --tag-name-filter cat -- --all
git push --force --verbose --dry-run
git push --force
이 코드를 GitHub와 같은 원격 저장소로 푸시하고 다른 사람들이 해당 원격 저장소를 복제 한 후에는 이제 히스토리를 다시 작성하는 상황에 처해 있습니다. 이후에 다른 사람이 최신 변경 사항을 풀다운하면 변경 사항을 빨리 적용 할 수 없으므로 적용 할 수 없다는 메시지가 표시됩니다.
이 문제를 해결하려면 기존 리포지토리를 삭제하고 다시 복제하거나 git-rebase 맨 페이지의 "UPSTREAM REBASE에서 복구"아래의 지침을 따라야합니다 .
팁 : 실행git rebase --interactive
나중에 민감한 정보로 실수로 일부 변경 사항을 커밋했지만 원격 리포지토리로 푸시하기 전에 차리면 더 쉽게 해결할 수 있습니다. 마지막 커밋이 민감한 정보를 추가하는 것이면 민감한 정보를 제거하고 다음을 실행하면됩니다.
git commit -a --amend
이렇게하면 이전에 커밋을 수정하여 전체 파일 제거를 포함하여 새로운 변경 사항을 적용합니다. git rm
. 변경 사항이 히스토리로 다시 되돌아가도 여전히 원격 저장소로 푸시되지 않은 경우 대화식 리베이스를 수행 할 수 있습니다.
git rebase -i origin/master
그러면 원격 저장소를 사용하여 마지막 공통 조상 이후로 커밋 한 편집기가 열립니다. 민감한 정보가있는 커밋을 나타내는 행에서 "pick"을 "edit"로 변경하고 저장하고 종료하십시오. 힘내 변경 사항을 안내하고 당신이 할 수있는 자리에 당신을 떠날 것입니다 :
$EDITOR file-to-fix
git commit -a --amend
git rebase --continue
민감한 정보로 변경 될 때마다. 결국 지점에 다시 도착하게되며 새로운 변경 사항을 안전하게 적용 할 수 있습니다.
filter-branch
코드와 링크 된 github 페이지 의 코드 에는 실질적인 차이가있는 것 같습니다 . 예를 들어 그들의 세 번째 줄 --prune-empty --tag-name-filter cat -- --all
. 솔루션이 변경되었거나 누락 된 것이 있습니까?
<introduction-revision-sha1>..HEAD
작동하지 않습니다. 이후 두 번째 커밋에서 파일을 제거합니다. (커밋 범위에 초기 커밋을 포함시키는 방법은 무엇입니까?) 저장 방법은 다음과 같습니다. help.github.com/articles/… git filter-branch --force --index-filter \ 'git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA' \ --prune-empty --tag-name-filter cat -- --all
비밀번호를 변경하는 것은 좋은 생각이지만, 리포지토리에서 비밀번호를 제거하는 과정에서는 Git 리포지토리에서 개인 데이터를 제거하기 위해 보다 빠르고 간단한 대안 인 BFG Repo-Cleaner 를 사용하는 것이 좋습니다 git-filter-branch
.
private.txt
제거 할 비밀번호 등을 나열 하는 파일을 작성하고 (한 줄에 한 항목 씩) 다음 명령을 실행하십시오.
$ java -jar bfg.jar --replace-text private.txt my-repo.git
리포지토리의 임계 값 크기 (기본적으로 1MB) 미만의 모든 파일이 검사되고 일치하는 문자열 ( 최근 커밋에 없는 문자열)이 "*** REMOVED ***"문자열로 바뀝니다. 그런 다음 git gc
죽은 데이터를 정리 하는 데 사용할 수 있습니다 .
$ git gc --prune=now --aggressive
BFG는 일반적으로 달리는 것보다 10-50 배 빠르며이 git-filter-branch
두 가지 일반적인 사용 사례에 따라 옵션이 단순화되고 조정됩니다.
전체 공개 : 저는 BFG Repo-Cleaner의 저자입니다.
git commit
. 그렇지 않으면 개발자 도구 상자에서 새 도구에 대해 +1 :)
These are your protected commits, and so their contents will NOT be altered
나머지 커밋 내역을 탐색하고 수정하는 동안 마지막 커밋에 대해 명시 적으로보고합니다 . 그러나 롤백해야 할 경우, 롤백 ***REMOVED***
한 커밋에서 검색 만하면됩니다.
GitHub로 푸시 한 경우 강제 푸시로 충분하지 않은 경우 리포지토리를 삭제하거나 지원 센터에 문의하십시오.
나중에 1 초간 강제로 밀어도 아래 설명 된 것처럼 충분하지 않습니다.
유일하게 유효한 조치는 다음과 같습니다.
비밀번호와 같이 변경 가능한 자격 증명이 유출 된 것은 무엇입니까?
아니오 (알몸 사진) :
리포지토리의 모든 문제가 해결되는지 걱정하십니까?
예:
다음과 같은 이유로 1 초 후에 강제로 충분하지 않습니다.
GitHub는 오랫동안 커밋 된 커밋을 유지합니다.
그러나 GitHub 직원은 이러한 매달린 커밋을 삭제할 수 있습니다.
모든 GitHub 커밋 이메일을 리포지토리에 업로드 했을 때이 기능을 직접 경험해 보았습니다 gc
. 그러나 데이터 가 포함 된 풀 요청은 삭제해야합니다. 해야합니다. 이로 인해 리포지토리 데이터는 최초 게시 중단 후 최대 1 년 동안 액세스 할 수 있습니다.
매달려 커밋은 다음 중 하나를 통해 볼 수 있습니다.
커밋에서 소스를 얻는 편리한 방법 중 하나는 다음과 같은 참조를 허용 할 수있는 download zip 메소드를 사용하는 것입니다. https://github.com/cirosantilli/myrepo/archive/SHA.zip
누락 된 SHA를 다음 중 하나를 사용하여 가져올 수 있습니다.
type": "PushEvent"
. 예 : 광산 : https://api.github.com/users/cirosantilli/events/public ( Wayback machine )http://ghtorrent.org/ 및 https://www.githubarchive.org/ 와 같은 스크레이퍼가 있습니다. GitHub 데이터를 정기적으로 풀링하여 다른 곳에 저장하는 스크랩 퍼가 있습니다.
그들이 실제 커밋 차이를 긁어 내는지 알 수 없었습니다. 데이터가 너무 많기 때문에 가능하지는 않지만 기술적으로 가능하며 NSA와 친구는 사람들이나 관심있는 커밋과 연결된 내용 만 보관하는 필터를 가지고있을 것입니다.
그러나 강제 푸시 대신 저장소를 삭제하면 커밋이 API에서도 즉시 사라지고 404를 제공합니다 (예 : https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824 이 작품을 동일한 이름으로 다른 저장소를 다시 작성하더라도
이것을 테스트하기 위해 https://github.com/cirosantilli/test-dangling 리포지토리를 만들고 다음 을 수행했습니다.
git init
git remote add origin git@github.com:cirosantilli/test-dangling.git
touch a
git add .
git commit -m 0
git push
touch b
git add .
git commit -m 1
git push
touch c
git rm b
git add .
git commit --amend --no-edit
git push -f
GitHub에서 매달려 커밋을 제거하는 방법 도 참조하십시오 .
데이비드 언더 힐 (David Underhill) 의이 스크립트 를 추천 합니다 .
natacado의 필터 브랜치와 함께 다음 명령을 추가하여 뒤에 남는 혼란을 정리합니다.
rm -rf .git/refs/original/
git reflog expire --all
git gc --aggressive --prune
전체 스크립트 (David Underhill의 모든 크레딧)
#!/bin/bash
set -o errexit
# Author: David Underhill
# Script to permanently delete files/folders from your git repository. To use
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2
if [ $# -eq 0 ]; then
exit 0
fi
# make sure we're at the root of git repo
if [ ! -d .git ]; then
echo "Error: must run this script from the root of a git repository"
exit 1
fi
# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter \
"git rm -rf --cached --ignore-unmatch $files" HEAD
# remove the temporary history git-filter-branch
# otherwise leaves behind for a long time
rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --prune
다음으로 변경하면 마지막 두 명령이 더 잘 작동 할 수 있습니다.
git reflog expire --expire=now --all && \
git gc --aggressive --prune=now
git gc --aggressive --prune=now
명확하게 : 허용되는 답변이 맞습니다. 먼저 해보십시오. 그러나 일부 사용 사례의 경우 특히 '치명적 : 잘못된 개정-자두 비우기'와 같은 눈에 띄지 않는 오류가 발생하거나 실제로 리포지토리의 역사에 관심이없는 경우 불필요하게 복잡 할 수 있습니다.
대안은 다음과 같습니다.
이것은 물론 모든 커밋 히스토리 브랜치와 github repo 및 로컬 git repo 모두에서 문제를 제거합니다. 이것이 용납 할 수없는 경우 다른 방법을 사용해야합니다.
이것을 핵 옵션이라고 부릅니다.
당신이 사용할 수있는 git forget-blob
.
사용법은 매우 간단 git forget-blob file-to-forget
합니다. 여기에서 더 많은 정보를 얻을 수 있습니다
그것은 당신의 역사, 참조, 태그 등의 모든 커밋에서 사라질 것입니다.
나는 때때로 같은 문제에 부딪 쳤고,이 포스트와 다른 사람들에게 돌아올 때마다 프로세스를 자동화 한 이유입니다.
Stack Overflow의 기여자에게이 크레딧을 제공 할 수있는 크레딧
사용 필터 지점 :
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch *file_path_relative_to_git_repo*' --prune-empty --tag-name-filter cat -- --all
git push origin *branch_name* -f
나는 이것을 현재까지 몇 번해야했다. 한 번에 하나의 파일에서만 작동합니다.
파일을 수정 한 모든 커밋 목록을 가져옵니다. 맨 아래에있는 것이 첫 번째 커밋입니다.
git log --pretty=oneline --branches -- pathToFile
히스토리에서 파일을 제거하려면 첫 번째 커밋 sha1과 이전 명령의 파일 경로를 사용하여 다음 명령으로 채우십시오.
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <path-to-file>' -- <sha1-where-the-file-was-first-added>..
내 안드로이드 프로젝트 에서 app / src / main / res / values / 폴더에 xml 파일로 admob_keys.xml 이있었습니다 . 이 민감한 파일을 제거하기 위해 아래 스크립트를 사용하여 완벽하게 작동했습니다.
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch app/src/main/res/values/admob_keys.xml' \
--prune-empty --tag-name-filter cat -- --all