itsource

잘못된 병합을 수정하고 수정된 병합에 좋은 커밋을 재생하려면 어떻게 해야 합니까?

mycopycode 2023. 5. 27. 11:07
반응형

잘못된 병합을 수정하고 수정된 병합에 좋은 커밋을 재생하려면 어떻게 해야 합니까?

않는파일을 .filename.orig병합을 해결하는 동안) 지금까지 눈치채지 못한 채 몇 번 전에 저장소로 전송되었습니다.저장소 기록에서 파일을 완전히 삭제하고 싶습니다.

변경 내역을 다음과 같이 다시 작성할 수 있습니까?filename.orig애초에 저장소에 추가된 적이 없습니까?

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

비록 ~일지라도filter-branch당신이 원하는 것을 할 것입니다, 그것은 꽤 복잡한 명령이고 저는 아마 이것을 하기로 선택할 것입니다.git rebase아마 개인적인 취향일 겁니다. filter-branch더명령어 할 수 에, 조더복잡 단명로수수있반면는행할으령일한금,▁can,▁the반▁command면▁a있.rebase솔루션은 한 번에 한 단계씩 동일한 논리적 작업을 수행하는 것입니다.

다음 조리법을 시도해 보십시오.

# create and check out a temporary branch at the location of the bad merge
git checkout -b tmpfix <sha1-of-merge>

# remove the incorrectly added file
git rm somefile.orig

# commit the amended merge
git commit --amend

# go back to the master branch
git checkout master

# replant the master branch onto the corrected merge
git rebase tmpfix

# delete the temporary branch
git branch -d tmpfix

( 임시 분기가 것은 ' HEAD로 이 할 수 , ''로 된 commit id를 해야 합니다.git commit --amend에공기위단계한에 git rebase임시 분기 이름을 사용하는 대신 명령을 사용합니다.)

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

원본 포스터에는 다음과 같은 내용이 있습니다.

제가 실수로 원치 않는 파일을 범했습니다...몇 번 전에 내 저장소에...저장소 기록에서 파일을 완전히 삭제하고 싶습니다.

변경 내역을 다음과 같이 다시 작성할 수 있습니까?filename.orig애초에 저장소에 추가된 적이 없습니까?

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

  1. 커밋을 수정합니다.
  2. 하드 재설정(기본값 추가).
  3. 비대화형 기본 재배치입니다.
  4. 대화형 기본 재배치.
  5. 분기를 필터링하고 있습니다.

원래 포스터의 경우, 커밋을 수정하는 것 자체가 실제로 선택사항은 아닙니다. 왜냐하면 그는 이후에 몇 번의 추가 커밋을 했기 때문입니다. 하지만 완성도를 위해, 이전 커밋을 수정하고 싶은 다른 사람들을 위해 어떻게 해야 하는지도 설명하겠습니다.

이러한 모든 솔루션에는 다른 방식으로 기록/커밋을 변경/재작성하는 작업이 포함되므로 커밋의 이전 복사본을 가진 사용자는 자신의 기록을 새 기록과 다시 동기화하기 위해 추가 작업을 수행해야 합니다.


솔루션 1: 커밋 수정

이전 커밋에서 실수로 변경한 경우(예: 파일 추가) 변경 내역이 더 이상 존재하지 않도록 하려면 이전 커밋을 수정하여 파일을 제거하면 됩니다.

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

솔루션 2: 하드 재설정(기본값 추가)

솔루션 #1과 마찬가지로 이전 커밋을 제거하려는 경우 상위 항목으로 하드 재설정할 수도 있습니다.

git reset --hard HEAD^

이 명령을 실행하면 분기가 이전st 1개의 상위 커밋으로 하드 재설정됩니다.

그러나 원래 포스터와 마찬가지로 변경을 취소하려는 커밋 후에 여러 번 커밋한 경우에도 하드 재설정을 사용하여 수정할 수 있지만 기본 재배치를 사용해야 합니다.다음은 과거의 커밋을 수정하는 데 사용할 수 있는 단계입니다.

# Create a new branch at the commit you want to amend
git checkout -b temp <commit>

# Amend the commit
git rm <file>
git commit --amend --no-edit

# Rebase your previous branch onto this new commit, starting from the old-commit
git rebase --rebase-merges --onto temp <old-commit> master

# Verify your changes
git diff master@{1}

해결책 3: 비상호작용 베이스

이는 기록에서 커밋을 완전히 제거하려는 경우에 사용할 수 있습니다.

# Create a new branch at the parent-commit of the commit that you want to remove
git branch temp <parent-commit>

# Rebase onto the parent-commit, starting from the commit-to-remove
git rebase --rebase-merges --onto temp <commit-to-remove> master

# Or use `-r` instead of the longer `--rebase-merges`
git rebase -r --onto temp <commit-to-remove> master

# Verify your changes
git diff master@{1}

솔루션 4: 대화형 기본 재배치

이 솔루션을 사용하면 솔루션 #2 및 #3과 동일한 작업을 수행할 수 있습니다. 즉, 직전의 커밋보다 과거의 커밋을 수정하거나 제거할 수 있으므로 사용할 솔루션을 선택하는 것이 어느 정도 결정적입니다.인터렉티브 리베이스는 성능상의 이유로 수백 개의 커밋을 리베이스하기에 적합하지 않으므로 이러한 상황에서는 비인터랙티브 리베이스 또는 필터 분기 솔루션(아래 참조)을 사용합니다.

대화형 기본 재배치를 시작하려면 다음을 사용합니다.

git rebase --interactive <commit-to-amend-or-remove>~

# Or `-i` instead of the longer `--interactive`
git rebase -i <commit-to-amend-or-remove>~

이렇게 하면 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)

수정하거나 제거할 커밋이 이 목록의 맨 위에 표시됩니다.제거하려면 목록에서 해당 줄을 삭제하기만 하면 됩니다.그렇지 않으면 다음과 같이 "선택"을 "편집"으로 바꿉니다st.

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

음다, 입력을 입력합니다.git rebase --continue커밋을 완전히 제거하도록 선택한 경우에는 확인 이외의 모든 작업을 수행해야 합니다(이 솔루션의 마지막 단계 참조).그러나 커밋을 수정하려는 경우 git가 커밋을 다시 적용한 다음 기본 재배치를 일시 중지합니다.

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

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

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

바로 그겁니다.마지막 단계로 커밋을 수정하든 완전히 제거하든 상관없이 기본 재배치 전에 분기 상태로 변경하여 분기에 다른 예기치 않은 변경 사항이 없는지 확인하는 것이 좋습니다.

git diff master@{1}

솔루션 5: 분기 필터링

마지막으로, 이 솔루션은 파일이 존재하는 모든 흔적을 기록에서 완전히 지우려는 경우에 가장 적합하며, 다른 솔루션은 이 작업을 수행할 수 없습니다.

git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>'

그러제거다니됩면다가 제거됩니다.<file>루트 커밋에서 시작하여 모든 커밋에서 시작합니다. 범위를 대 커 다 범 시 작 하 려 는 경 우 성HEAD~5..HEAD 그러당면은신그추주전수있다니습달할로장으가것을▁to▁argument▁as▁thatal에 추가 인수로 전달할 수 있습니다.filter-branch 답변에서 지적한 바와 같이:

git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>' HEAD~5..HEAD

시 에 그후, 에다.filter-branch완료되었습니다. 필터링 작업 전에 분기를 이전 상태로 변경하여 다른 예기치 않은 변경 사항이 없는지 확인하는 것이 좋습니다.

git diff master@{1}

필터-분기 대안: BFG 리포 클리너

BFG Repo Cleaner 도구가 다음보다 더 빨리 실행된다고 들었습니다.git filter-branch그래서 당신은 그것도 옵션으로 확인하는 것이 좋을 것입니다.실행 가능한 대안으로 필터 분기 설명서에 공식적으로 언급되기도 합니다.

git-filter-branch를 사용하면 Git 내역에 대해 셸 스크립트로 복잡한 다시 쓰기를 수행할 수 있지만 대용량 파일이나 암호와 같은 원하지 않는 데이터를 제거하는 경우에는 이러한 유연성이 필요하지 않을 수 있습니다.이러한 작업의 경우 Git-filter-branch의 JVM 기반 대안인 BFG Repo-Cleaner를 고려할 수 있습니다. 일반적으로 이러한 사용 사례의 경우 최소 10-50배 더 빠르며 상당히 다른 특성을 가지고 있습니다.

  • 파일의 특정 버전은 한 만 치료됩니다.Git-filter-branch와 달리 BFG는 기록 내에서 파일이 커밋된 위치 또는 시간에 따라 파일을 다르게 처리할 수 있는 기회를 제공하지 않습니다.이러한 제약 조건은 BFG의 핵심 성능 이점을 제공하며, 잘못된 데이터를 정리하는 작업에 적합합니다. 잘못된 데이터가 어디에 있는지 상관하지 않고 제거하기만 하면 됩니다.

  • 기본적으로 BFG는 멀티 코어 시스템을 최대한 활용하여 병렬로 커밋 파일 트리를 정리합니다. git-filter-branch는 각 커밋에 대해 실행되는 스크립트에서 자체 병렬을 포함하는 필터를 작성할 수 있지만 커밋을 순차적으로(즉, 단일 스레드 방식으로) 정리합니다.

  • 명령 옵션은 git-filter 브랜치보다 훨씬 제한적이며 원하지 않는 데이터를 제거하는 작업에만 사용됩니다.--strip-blobs-bigger-than 1M.

추가 리소스

  1. Pro Git § 6.4 Git 도구 - 기록 다시 쓰기.
  2. git-filter-branch(1) Manual 페이지.
  3. git-commit(1) 수동 페이지.
  4. git-reset(1) 수동 페이지.
  5. git-rebase(1) Manual 페이지.
  6. BFG Repo Cleaner(작성자 본인의 답변 참조).

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

가지고 계신다면,

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

에서 변경할 때마다 수행됩니다.merge-pointHEADfilename.orig를 삭제하고 변경 내용을 다시 씁니다.용사를 합니다.--ignore-unmatch어떤 이유로 filename.orig가 변경 사항에서 누락된 경우에도 명령이 실패하지 않음을 의미합니다.git-filter-branch man 페이지의 예제 섹션에서 권장되는 방법입니다.

Windows 사용자를 위한 참고 사항:파일 경로는 슬래시를 사용해야 합니다.

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

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

편집

네온의 편집은 안타깝게도 리뷰 도중에 거절되었습니다.
아래 네온 게시물을 참조하십시오. 유용한 정보가 포함되어 있을 수 있습니다!


들어 모든 를 제거하려면: 모제거*.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

마스터 브랜치가 하나밖에 없어서 왜 그런지 모르겠어요.어쨌든, 저는 마침내 비어 있는 새로운 baregit 저장소에 밀어넣음으로써 git repository를 완전히 정리했습니다.

$ 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 Repo-Cleaner를 사용하는 것이 좋습니다.git-filter-branchGit 기록에서 파일을 제거하기 위해 특별히 설계되었습니다.실제로 모든 참조(모든 태그, 분기 등)를 기본적으로 처리하지만 10배~50배 더 빠릅니다.

다음 단계를 주의 깊게 따라야 합니다. http://rtyley.github.com/bfg-repo-cleaner/ #backup - 하지만 핵심 비트는 바로 이것입니다. BFG jar(Java 6 이상 버전 포함)를 다운로드하고 다음 명령을 실행합니다.

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

이 "" "" "" "" "" "" " "" "입니다.filename.orig(최근 커밋에 포함되지 않음)이 제거됩니다.이것은 사용하는 것보다 훨씬 쉽습니다.git-filter-branch같은 일을 하는 것!

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

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의 솔루션에 추가하기 위해, 저는 Gitrebase -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(댓글로), 이는 아누프존이 게시한 게시물입니다.저는 그 자체의 공간을 답으로 삼을 가치가 있다고 생각합니다.

(배시 스크립트로 변환했습니다)

#!/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여전히 태그, 리필로그 항목, 원격 등에서 참조할 수 있기 때문에, 당신의 레포에서.

이러한 참조도 모두 제거한 다음 가비지 수집기에 전화하는 것이 좋습니다.당신은 할 수 .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 reset HEAD file/path

언급URL : https://stackoverflow.com/questions/307828/how-do-you-fix-a-bad-merge-and-replay-your-good-commits-onto-a-fixed-merge

반응형