programing

Git 기록에서 중요한 파일 및 해당 커밋 제거

mailnote 2023. 5. 21. 11:52
반응형

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 man 페이지의 "Recovering From Upstream REBase"에 있는 지침을 따라야 합니다.

: 실행git rebase --interactive


앞으로 중요한 정보를 실수로 변경했지만 원격 저장소로 푸시하기 전에 일부 변경 사항을 알게 되면 더 쉬운 수정 사항이 있습니다.마지막으로 중요한 정보를 추가한 경우 중요한 정보를 제거한 후 다음을 실행할 수 있습니다.

git commit -a --amend

그러면 사용자가 변경한 모든 새 변경 사항으로 이전 커밋이 수정됩니다.git rm변경 내용이 이전 기록으로 거슬러 올라가지만 원격 리포지토리로 푸시되지 않은 경우 대화형 기본 재배치를 수행할 수 있습니다.

git rebase -i origin/master

그러면 원격 저장소에 대한 마지막 공통 조상 이후로 수행한 커밋이 편집기에 열립니다.중요한 정보가 있는 커밋을 나타내는 행에서 "선택"을 "편집"으로 변경하고 저장 및 종료합니다.Git는 변경 사항을 살펴보고 다음과 같은 작업을 수행할 수 있는 위치에 둡니다.

$EDITOR file-to-fix
git commit -a --amend
git rebase --continue

중요한 정보가 포함된 각 변경 사항에 대해 설명합니다.최종적으로 분기에 다시 연결되어 새로운 변경사항을 안전하게 적용할 수 있습니다.

암호를 변경하는 것은 좋은 생각이지만, 당신의 레포 기록에서 암호를 제거하는 과정에서, 저는 BFG Repo-Cleaner를 추천합니다.git-filter-branchGit 저장소에서 개인 데이터를 제거하도록 명시적으로 설계되었습니다.

성을 합니다.private.txt제거할 암호 등을 나열하는 파일(한 줄에 한 항목씩)을 선택한 다음 다음 명령을 실행합니다.

$ java -jar bfg.jar  --replace-text private.txt  my-repo.git

레포 기록에서 임계값 크기(기본적으로 1MB) 미만의 모든 파일이 검색되고 일치하는 문자열(최신 커밋에 포함되지 않음)이 "***REMOVED****" 문자열로 대체됩니다.그러면 다음을 사용할 수 있습니다.git gc데드 데이터를 정리합니다.

$ git gc --prune=now --aggressive

는 일반적으로 실행 중인 .git-filter-branch옵션은 단순화되고 다음과 같은 두 가지 일반적인 사용 사례를 중심으로 조정됩니다.

  • 미친 듯이 큰 파일 제거
  • 암호, 자격 증명 및 기타 개인 데이터 제거

전체 공개:저는 BFG Repo-Cleaner의 저자입니다.

git filter-repo이제 공식적으로 권장됩니다.git filter-branch

이것은 의 맨 페이지에 언급되어 있습니다.git filter-branchGit 2.5 인치.

git 필터 repo를 사용하여 다음과 같은 특정 파일을 제거할 수 있습니다: git/GitHub의 기록에서 폴더내용 제거

pip install git-filter-repo
git filter-repo --path path/to/remove1 --path path/to/remove2 --invert-paths

이렇게 하면 빈 커밋이 자동으로 제거됩니다.

또는 특정 문자열을 다음으로 바꿀 수 있습니다.Git 역사 전체에서 문자열을 대체하는 방법은 무엇입니까?

git filter-repo --replace-text <(echo 'my_password==>xxxxxxxx')

GitHub에 푸시한 경우 강제 푸시만으로는 충분하지 않습니다. 리포지토리를 삭제하거나 지원팀에 문의하십시오.

1초 후에 무리하게 밀어도 아래 설명과 같이 충분하지 않습니다.

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

  • 유출된 것이 비밀번호처럼 변경 가능한 자격 증명입니까?

    • 예: 즉시 암호를 수정하고 더 많은 OAuth 및 API 키를 사용하는 것을 고려하십시오!

    • 아니요(이상 사진):

      • 저장소의 모든 이슈가 핵이 되더라도 상관이 있습니까?

        • 아니요: 리포지토리 삭제

        • 예:

          • 지원팀에 문의
          • 누출이 매우 중요한 경우에는 GitHub 지원이 응답하기를 기다리는 동안 일부 저장소 다운타임을 확보하여 누출 가능성을 줄일 수 있습니다.

다음과 같은 이유로 1초 후에 강제로 누르는 것만으로는 충분하지 않습니다.

  • GitHub은 오랫동안 커밋을 매달고 있습니다.

    그러나 GitHub 직원은 당신이 그들에게 연락하면 그러한 위험한 커밋을 삭제할 수 있는 권한을 가지고 있습니다.

    저는 모든 GitHub 커밋 이메일을 그들이 저에게 그것을 받아 적으라고 요청한 레포에 업로드했을 때 이 직접적인 경험을 했습니다. 그래서 저는 그렇게 했고, 그들은 그렇게 했습니다.gc그러나 데이터가 포함된 풀 요청은 삭제해야 합니다. 이로 인해 초기 테이크다운 후 최대 1년까지 리포 데이터에 액세스할 수 있습니다.

    다음을 통해 커밋을 확인할 수 있습니다.

    해당 커밋에서 소스를 얻는 한 가지 편리한 방법은 다운로드 zip 방법을 사용하는 것입니다. zip 방법은 다음과 같이 모든 참조를 참조하십시오.https://github.com/cirosantilli/myrepo/archive/SHA.zip

  • 누락된 SHA를 가져올 수 있는 방법은 다음과 같습니다.

    • 를 사용하여 type": "PushEvent"예: 내 것: https://api.github.com/users/cirosantilli/events/public (웨이백 머신)
    • 콘텐츠를 제거하려고 시도한 풀 요청의 SHA를 살펴봄으로써 더 편리한 경우가 있습니다.
  • 정기적으로 GitHub 데이터를 풀링하여 다른 곳에 저장하는 http://ghtorrent.org/ 및 https://www.githubarchive.org/ 와 같은 스크랩퍼가 있습니다.

    저는 그들이 실제 커밋 디프를 긁어낼지 찾을 수 없었고, 데이터가 너무 많을 것이기 때문에 그럴 가능성은 낮지만, 기술적으로 가능하며, 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에서 매달리는 커밋을 제거하는 방법은 무엇입니까?

사용할 수 있습니다.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/

기록의 모든 커밋, reflog, 태그 등에서 사라집니다.

저는 가끔 같은 문제에 부딪히고, 이 자리와 다른 곳으로 돌아와야 할 때마다, 그래서 저는 그 과정을 자동화했습니다.

스택 오버플로의 기여자에 대한 크레딧으로 이를 정리할 수 있습니다.

저는 데이비드 언더힐의 이 대본을 추천합니다. 저에게는 매력적인 작품이었습니다.

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

Windows에 대한 솔루션이 있습니다.

git filter-branch --tree-filter "rm -f 'filedir/filename'" HEAD

git push --force

경로가 올바른지 확인하십시오. 그렇지 않으면 작동하지 않습니다.

도움이 되길 바랍니다.

필터 분기 사용:

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

분명히 해야 할 일:받아들여진 답이 맞습니다.일단 해보세요.그러나 일부 사용 사례에서는 불필요하게 복잡할 수 있으며, 특히 '치명적인: 잘못된 수정본 --prune-empty'와 같은 불쾌한 오류가 발생하거나 레포 기록에 관심이 없는 경우에는 더욱 그렇습니다.

대안은 다음과 같습니다.

  1. cd를 프로젝트의 기본 분기로
  2. 중요 코드/파일 제거
  3. rm -rf.git/ # 코드에서 모든 git 정보 제거
  4. github으로 이동하여 리포지토리 삭제
  5. 이 가이드에 따라 일반적으로 하는 것처럼 코드를 새 리포지토리에 푸시합니다. https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/

이렇게 하면 물론 모든 커밋 기록 분기와 github repo 및 로컬 gitrepo에서 문제가 제거됩니다.이 방법을 사용할 수 없는 경우 다른 방법을 사용해야 합니다.

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

안드로이드 프로젝트에서 저는 admob_keys.xml을 app/src/main/res/values/폴더에 별도의 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

저는 지금까지 이것을 몇 번 해야 했습니다.이 작업은 한 번에 하나의 파일에서만 작동합니다.

  1. 파일을 수정한 모든 커밋 목록을 가져옵니다.맨 아래에 있는 사람이 첫 번째 커밋을 수행합니다.

    git log --pretty=oneline --branches -- pathToFile

  2. 기록에서 파일을 제거하려면 이전 명령의 첫 번째 commit sha1 및 파일 경로를 사용하여 다음 명령에 입력합니다.

    git filter-branch --index-filter 'git rm --cached --ignore-unmatch <path-to-file>' -- <sha1-where-the-file-was-first-added>..

따라서 다음과 같습니다.

git rm --cached /config/deploy.rb
echo /config/deploy.rb >> .gitignore

을 git에 합니다..gitignore

OP가 GitHub을 사용하고 있다는 점을 고려할 때, 중요한 데이터를 Gitrepo에 커밋하면 이전 옵션 중 하나를 사용하여 기록에서 완전히 제거할 수 있습니다(아래에서 자세한 내용 참조).

  1. git filter-repo도구(GitHub에서 소스 보기).

  2. BFG Repo-Cleaner 도구(GitHub의 오픈 소스 - 뷰 소스).

앞의 옵션 중 하나를 선택한 후에 수행해야 할 추가 단계가 있습니다.아래의 추가 섹션을 확인하십시오.

가장 최근에 푸시되지 않은 커밋에 추가된 파일을 제거하는 것이 목적인 경우 아래의 대안 섹션을 참조하십시오.

향후 고려 사항에 대해 유사한 상황을 방지하려면 아래의 For the Future 섹션을 확인하십시오.


옵션 1

를 사용합니다. 앞으로 나아가기 전에 주의하십시오.

실행하는 경우git filter-repo변경 내용을 저장한 후에는 다른 stash 명령을 사용하여 변경 내용을 검색할 수 없습니다.를 실행하기 git filter-repo변경한 내용을 삭제하는 것이 좋습니다.하려면 를 합니다.git stash show -p | git apply -R자세한 내용은 Git 도구 - 저장청소를 참조하십시오.

하고 이 을 제이레기서파제에추다고니습겠가하에 하겠습니다..gitignore(재커밋을 방지하기 위해).

앞으로 나아가기 전에, 다음 사항을 확인합니다.git filter-repo설치(설치 방법은 여기를 참조) 및 자신의 레포의 로컬 복사본을 가지고 있습니다(그렇지 않은 경우 저장소 복제 방법은 여기를 참조).

  1. GitBash를 열고 리포지토리에 액세스합니다.

    cd YOUR-REPOSITORY
    
  2. (으)로 합니다..git/configjava.

  3. 달려.

    git filter-repo --invert-paths --path PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA
    

    체교다를 PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA파일 이름뿐만 아니라 제거할 파일의 경로를 지정합니다.

    • Git를 강제로 처리하지만 모든 분기 및 태그의 전체 기록은 확인하지 않습니다.

    • 지정된 파일을 제거하고 결과적으로 생성된 빈 커밋도 제거합니다.

    • 일부 : 예일구성을원격다 URL에 )을 합니다..git/config으)로 표시)

    • 기존 태그를 덮어씁니다.

  4. 중요한 데이터가 포함된 파일을 다음에 추가합니다..gitignore

    echo "YOUR-FILE-WITH-SENSITIVE-DATA" >> .gitignore
    
    git add .gitignore
    
    git commit -m "Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore"
    
  5. 리포지토리 기록에서 모든 항목이 제거되었는지, 모든 분기가 체크아웃되었는지 확인합니다.그런 다음 다음 다음 단계로 이동합니다.

  6. 로컬 변경사항을 강제로 푸시하여 GitHub.com 의 리포지토리뿐만 아니라 푸시한 모든 분기를 덮어씁니다.커밋 기록에서 중요한 데이터를 제거하려면 강제 푸시가 필요합니다.자세한 내용은 이 답변 하단의 첫 번째 메모를 참조하십시오.

    git push origin --force --all
    

옵션 2

BFG Repo-Cleaner 사용.이는 보다 빠르고 단순합니다.git filter-branch.

예를 들어 중요한 데이터가 있는 파일을 제거하고 최근 커밋을 그대로 유지하려면 다음을 실행합니다.

bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

모바꾸면려에 나열된 passwords.txt 수 곳이면 하십시오.

bfg --replace-text passwords.txt

중요한 데이터를 제거한 후에는 GitHub에 변경 사항을 강제로 적용해야 합니다.

git push --force

추가의

위의 옵션 중 하나를 사용한 후:

  1. GitHub 지원팀에 문의하십시오.

  2. (팀과 함께 작업하는 경우)이전(오염된) 리포지토리 기록에서 만든 분기를 병합하지 말고 기본 재배치하라고 말합니다.한 번의 합병 약속은 방금 숙청의 어려움에 빠졌던 오염된 역사의 일부 또는 전부를 다시 가져올 수 있습니다.

  3. 시간이 지나고 의도하지 않은 부작용이 없다고 확신한 후에는 다음 명령을 사용하여 로컬 저장소의 모든 개체를 강제로 참조 해제하고 가비지를 수집할 수 있습니다(Git 1.8.5 이상 사용).

    git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
    
    git reflog expire --expire=now --all
    
    git gc --prune=now
    

대안

파일이 가장 최근의 커밋으로 추가되었지만 GitHub.com 으로 푸시되지 않은 경우 파일을 삭제하고 커밋을 수정할 수 있습니다.

  1. GitBash를 열고 리포지토리에 액세스합니다.

    cd YOUR-REPOSITORY.l
    
  2. 파일을 제거하려면 다음을 입력합니다.git rm --cached:

    git rm --cached GIANT_FILE
    # Stage our giant file for removal, but leave it on disk
    
  3. 를 사용하여 이 변경 .--amend -CHEAD:

    git commit --amend -CHEAD
    # Amend the previous commit with your change
    # Simply making a new commit won't work, as you need
    # to remove the file from the unpushed history as well
    
  4. GitHub.com 에 자신의 약속을 푸시합니다.

    git push
    # Push our rewritten, smaller commit
    

미래를 위하여

중요한 데이터가 노출되는 것을 방지하기 위해 다음과 같은 다른 모범 사례가 있습니다.

  • 시각적 프로그램을 사용하여 변경 내용을 커밋합니다.다양한 대안(GitHub Desktop, GitKraken, Gitk 등)이 있으며 변경 사항을 추적하는 것이 더 쉬울 수 있습니다.

  • 명령 catch-all은 .git add .그리고.git commit -a대신에, 신대사를 하세요.git add filename그리고.git rm filename파일을 개별적으로 준비합니다.

  • 사용하다git add --interactive각 파일 내의 변경 사항을 개별적으로 검토하고 준비합니다.

  • 사용하다git diff --cached커밋을 위해 준비한 변경 사항을 검토합니다.이것이 바로 그 차이입니다.git commit사용하지 않는 한 생산할 것입니다.-a 깃발

  • 보안 하드웨어(HSM 상자, 하드웨어 키(예: Yubikey/Solokey)에서 비밀 키를 생성합니다.

  • x508에서 팀을 훈련시킵니다.


주의:

  • 한 번의 강제 실행 시 저장소 기록을 다시 작성하여 커밋 기록에서 중요한 데이터를 제거합니다.이 경우 다른 사용자가 작업을 기반으로 한 커밋을 덮어쓸 수 있습니다.

  • 이 답변에 대해 일부 GitHub 게시물의 사용된 콘텐츠:

언급URL : https://stackoverflow.com/questions/872565/remove-sensitive-files-and-their-commits-from-git-history

반응형