[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

민감한 정보로 변경 될 때마다. 결국 지점에 다시 도착하게되며 새로운 변경 사항을 안전하게 적용 할 수 있습니다.


답변

비밀번호를 변경하는 것은 좋은 생각이지만, 리포지토리에서 비밀번호를 제거하는 과정에서는 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의 저자입니다.


답변

GitHub로 푸시 한 경우 강제 푸시로 충분하지 않은 경우 리포지토리를 삭제하거나 지원 센터에 문의하십시오.

나중에 1 초간 강제로 밀어도 아래 설명 된 것처럼 충분하지 않습니다.

유일하게 유효한 조치는 다음과 같습니다.

  • 비밀번호와 같이 변경 가능한 자격 증명이 유출 된 것은 무엇입니까?

    • 예 : 비밀번호를 즉시 수정하고 더 많은 OAuth 및 API 키 사용을 고려하십시오!
    • 아니오 (알몸 사진) :

      • 리포지토리의 모든 문제가 해결되는지 걱정하십니까?

        • 아니오 : 저장소를 삭제하십시오.
        • 예:

          • 연락처 지원
          • 누출이 당신에게 매우 중요한 경우, 누출 가능성을 줄이기 위해 저장소 가동 중지 시간을 기꺼이 할 수있는 시점 까지 GitHub 지원이 귀하에게 응답하기를 기다리는 동안 비공개로 만드십시오.

다음과 같은 이유로 1 초 후에 강제로 충분하지 않습니다.

그러나 강제 푸시 대신 저장소를 삭제하면 커밋이 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


답변

명확하게 : 허용되는 답변이 맞습니다. 먼저 해보십시오. 그러나 일부 사용 사례의 경우 특히 ‘치명적 : 잘못된 개정-자두 비우기’와 같은 눈에 띄지 않는 오류가 발생하거나 실제로 리포지토리의 역사에 관심이없는 경우 불필요하게 복잡 할 수 있습니다.

대안은 다음과 같습니다.

  1. 프로젝트의 기본 분기에 cd
  2. 민감한 코드 / 파일 제거
  3. rm -rf .git / # 코드에서 모든 자식 정보를 제거하십시오
  4. github로 이동하여 저장소를 삭제하십시오.
  5. 이 안내서에 따라 평소와 같이 코드를 새 저장소로 푸시하십시오-https:
    //help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/

이것은 물론 모든 커밋 히스토리 브랜치와 github repo 및 로컬 git repo 모두에서 문제를 제거합니다. 이것이 용납 할 수없는 경우 다른 방법을 사용해야합니다.

이것을 핵 옵션이라고 부릅니다.


답변

당신이 사용할 수있는 git forget-blob .

사용법은 매우 간단 git forget-blob file-to-forget합니다. 여기에서 더 많은 정보를 얻을 수 있습니다

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

그것은 당신의 역사, 참조, 태그 등의 모든 커밋에서 사라질 것입니다.

나는 때때로 같은 문제에 부딪 쳤고,이 포스트와 다른 사람들에게 돌아올 때마다 프로세스를 자동화 한 이유입니다.

Stack Overflow의 기여자에게이 크레딧을 제공 할 수있는 크레딧


답변

창문에 내 해결책이 있습니다.

git filter-branch –tree-filter “rm -f ‘filedir / filename'”HEAD

git push –force

그렇지 않으면 경로가 올바른지 확인하십시오.

나는 그것이 도움이되기를 바랍니다