특정 커밋 제거
친구와 함께 프로젝트를 진행하고 있었는데, 친구가 편집해서는 안 되는 파일들을 많이 편집했습니다.어떻게든 저는 그의 작품을 제 작품에 통합했습니다. 제가 그것을 끄집어냈을 때나, 제가 원하는 특정 파일을 골라내려고 했을 때 말이죠.저는 그 파일들에 대한 편집 내용이 포함된 커밋들을 어떻게 제거할 것인지를 오랫동안 찾고 놀았습니다. 되돌리기와 재배치 사이에서 뒤죽박죽인 것 같습니다. 그리고 간단한 예는 없습니다. 문서들은 제가 저보다 더 많이 알고 있다고 추측합니다.
다음은 질문의 단순화된 버전입니다.
다음 시나리오에서 커밋 2를 제거하려면 어떻게 해야 합니까?
$ mkdir git_revert_test && cd git_revert_test
$ git init
Initialized empty Git repository in /Users/josh/deleteme/git_revert_test/.git/
$ echo "line 1" > myfile
$ git add -A
$ git commit -m "commit 1"
[master (root-commit) 8230fa3] commit 1
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 myfile
$ echo "line 2" >> myfile
$ git commit -am "commit 2"
[master 342f9bb] commit 2
1 files changed, 1 insertions(+), 0 deletions(-)
$ echo "line 3" >> myfile
$ git commit -am "commit 3"
[master 1bcb872] commit 3
1 files changed, 1 insertions(+), 0 deletions(-)
예상 결과는 다음과 같습니다.
$ cat myfile
line 1
line 3
여기 제가 어떻게 되돌리려고 노력했는지에 대한 예가 있습니다.
$ git revert 342f9bb
Automatic revert failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>' or 'git rm <paths>'
and commit the result.
네 가지 방법이 있습니다.
깨끗한 방법으로 되돌리지만 되돌리려면 로그에 기록합니다.
git revert --strategy resolve <commit>
어려운 방법으로는 마지막 커밋만 제거합니다.
git reset --soft "HEAD^"
사용하지 마십시오.git reset --hard
마지막 커밋 이후 파일의 모든 변경 사항도 삭제하기 때문입니다.한다면--soft
효과가 없습니다. 오히려 시도하십시오.--mixed
또는--keep
.
기본 재배치(최근 5개 커밋의 로그를 표시하고 원하지 않는 행을 삭제하거나, 다시 정렬하거나, 여러 커밋을 한 번에 스쿼시하거나, 원하는 다른 작업을 수행합니다.): 이 도구는 매우 유용합니다.
git rebase -i HEAD~5
실수가 있을 경우:
git rebase --abort
빠른 기본 재배치: ID를 사용하여 특정 커밋만 제거:
git rebase --onto commit-id^ commit-id
대안: 다음을 시도할 수도 있습니다.
git cherry-pick commit-id
또 다른 대안:
git revert --no-commit
마지막 수단으로, 기록 편집의 완전한 자유가 필요한 경우(예: Git에서 원하는 내용을 편집할 수 없기 때문에) 이 매우 빠른 오픈 소스 응용 프로그램인 reposurge를 사용할 수 있습니다.
로컬에서 과 같이 변경해야 합니다.git push
변경 사항을 원격에 적용할 수 있습니다.또한 에서 커밋을 제거하지("때이 허용되지 않음할 수 .git push -f
변경 사항을 강제로 적용합니다.
을 하는데 밀어야 .git push --force
다른 분기를 덮어쓸 수 있기 때문입니다(현재 체크아웃이 다른 분기에 있더라도 변경한 경우).강제로 푸시할 때 항상 원격 분기를 지정하는 것을 선호합니다.git push --force origin your_branch
.
쉬운 해결책은 다음과 같습니다.
git rebase -i HEAD~x
에▁where디x
커밋 수입니다.
그게 다예요, 당신은 끝났어요.삭제한 커밋이 이미 리모컨에 있는 경우 강제로 푸시해야 합니다.--force는 유해한 것으로 간주되므로 사용합니다.git push --force-with-lease
.
Git가 되돌리기 위해 diff를 계산할 때 사용하는 알고리즘은 다음을 요구합니다.
- 되돌리는 라인은 이후의 커밋에 의해 수정되지 않습니다.
- 이후 역사에서 다른 "인접" 커밋은 없습니다.
"인접"의 정의는 컨텍스트 diff의 기본 줄 수(3)를 기반으로 합니다.따라서 'myfile'이 다음과 같이 구성된 경우:
$ cat >myfile <<EOF
line 1
junk
junk
junk
junk
line 2
junk
junk
junk
junk
line 3
EOF
$ git add myfile
$ git commit -m "initial check-in"
1 files changed, 11 insertions(+), 0 deletions(-)
create mode 100644 myfile
$ perl -p -i -e 's/line 2/this is the second line/;' myfile
$ git commit -am "changed line 2 to second line"
[master d6cbb19] changed line 2
1 files changed, 1 insertions(+), 1 deletions(-)
$ perl -p -i -e 's/line 3/this is the third line/;' myfile
$ git commit -am "changed line 3 to third line"
[master dd054fe] changed line 3
1 files changed, 1 insertions(+), 1 deletions(-)
$ git revert d6cbb19
Finished one revert.
[master 2db5c47] Revert "changed line 2"
1 files changed, 1 insertions(+), 1 deletions(-)
그러면 모든 것이 예상대로 작동합니다.
두 번째 대답은 매우 흥미로웠습니다.아직 정식으로 출시되지 않은 기능(Git v1.7.2-rc2에서 사용 가능)이 있는데, 이 기능을 Return Strategy라고 합니다.다음과 같이 git를 호출할 수 있습니다.
git revert --sysolve 확인 <commit>
그리고 당신이 의미하는 바를 더 잘 이해할 수 있을 겁니다.저는 사용 가능한 전략 목록이 무엇인지 알지 못하며, 어떤 전략의 정의도 알지 못합니다.
접근법 1
먼저 되돌려야 하는 커밋 해시(ex:1406cd61)를 가져옵니다. 단순 수정은 명령 아래에 있습니다.
$ git revert 1406cd61
1406cd61 커밋 후 1406cd61 파일과 관련된 변경 사항을 더 커밋하면 위의 단순 명령은 작동하지 않습니다.그러면 당신은 아래 단계인 체리 따기를 해야 합니다.
접근 2
아래 일련의 작업을 수행하십시오. --force를 사용하고 있으므로 이 작업을 수행하려면 gitrepo에 대한 관리자 권한이 있어야 합니다.
1단계: 제거할 커밋 전에 커밋 찾기git log
2단계: 커밋 확인git checkout <commit hash>
3단계: 현재 체크아웃 커밋을 사용하여 새 지점 만들기git checkout -b <new branch>
4단계: 이제 제거된 커밋 후 커밋을 추가해야 합니다.git cherry-pick <commit hash>
5단계: 이제 유지할 다른 모든 커밋에 대해 4단계를 반복합니다.
6단계: 모든 커밋이 새 분기에 추가되고 커밋되었습니다.모든 것이 올바른 상태이고 의도한 대로 작동하는지 확인합니다.커밋된 모든 항목을 다시 확인합니다.git status
7단계: 중단된 분기로 전환git checkout <broken branch>
8단계: 이제 제거할 커밋 전에 중단된 분기를 커밋으로 하드 재설정합니다.git reset --hard <commit hash>
9단계: 고정 분기를 이 분기에 병합합니다.git merge <branch name>
10단계: 병합된 변경사항을 원점으로 다시 푸시합니다. 경고:원격 repo를 덮어씁니다! git push --force origin <branch name>
2 및 3단계를 8단계로 바꾼 다음 7 및 9단계를 수행하지 않으면 새 분기를 만들지 않고 공정을 수행할 수 있습니다.
당신의 선택은 둘 중 하나입니다.
- 오류를 유지하고 해결책을 소개합니다.
- 오류를 제거하고 기록을 변경합니다.
(1) 다른 사용자가 잘못된 변경을 선택한 경우와 (2) 오류가 푸시되지 않은 개인 분기로 제한된 경우를 선택해야 합니다.
Git revert는 자동화된 작업 도구로, (1) 이전의 일부 커밋을 취소하는 새 커밋을 만듭니다.오류 및 제거는 프로젝트 기록에 표시되지만 저장소에서 제거하는 사용자는 업데이트할 때 문제가 발생하지 않습니다.하지 않기 'myfile'을 편집해야 하려면).git add myfile
그리고.git commit
분쟁에 대처하기 위해.그러면 당신은 당신의 역사에서 4개의 커밋과 4개의 커밋을 되돌리는 커밋 2로 끝날 것입니다.
기록이 변경되어도 아무도 신경 쓰지 않는 경우, 기록을 다시 작성하고 커밋 2(선택 2)를 제거할 수 있습니다. 쉬운 은 이위한쉬방은을 입니다.git rebase -i 8230fa3
이렇게 하면 편집기로 이동할 수 있으며 커밋을 제거하고 다른 커밋 메시지 옆에 "선택"을 유지하여 잘못된 커밋을 포함하지 않도록 선택할 수 있습니다.이 일의 결과에 대해 자세히 읽어보세요.
은 않서원커수있제다습니로 할 수 .git rebase
동료의 주제 분기에 있는 일부 커밋을 주제 분기에 포함했지만 나중에 이러한 커밋을 원하지 않는다고 가정합니다.
git checkout -b tmp-branch my-topic-branch # Use a temporary branch to be safe.
git rebase -i master # Interactively rebase against master branch.
이때 텍스트 편집기가 대화형 기본 재배치 보기를 엽니다.예를들면
- 줄을 삭제하여 원하지 않는 커밋 제거
- 저장 후 종료
기본 재배치에 실패한 경우 임시 분기를 삭제하고 다른 전략을 시도합니다.그렇지 않으면 다음 지침을 계속 수행합니다.
git checkout my-topic-branch
git reset --hard tmp-branch # Overwrite your topic branch with the temp branch.
git branch -d tmp-branch # Delete the temporary branch.
주제 분기를 원격으로 푸시하는 경우 커밋 기록이 변경되었기 때문에 강제로 푸시해야 할 수 있습니다.만약 다른 사람들이 같은 지점에서 일하고 있다면, 그들에게 알려주세요.
여기 있는 다른 답변들로부터, 저는 약간 혼란스러웠습니다.git rebase -i
커밋을 제거하는 데 사용할 수 있으므로, 여기에 제 테스트 사례를 기록해도 괜찮기를 바랍니다(OP와 매우 유사함).
여기 있습니다.bash
저장 생를 위하수에 테스트 저장소를 위해 수 /tmp
폴더:
set -x
rm -rf /tmp/myrepo*
cd /tmp
mkdir myrepo_git
cd myrepo_git
git init
git config user.name me
git config user.email me@myself.com
mkdir folder
echo aaaa >> folder/file.txt
git add folder/file.txt
git commit -m "1st git commit"
echo bbbb >> folder/file.txt
git add folder/file.txt
git commit -m "2nd git commit"
echo cccc >> folder/file.txt
git add folder/file.txt
git commit -m "3rd git commit"
echo dddd >> folder/file.txt
git add folder/file.txt
git commit -m "4th git commit"
echo eeee >> folder/file.txt
git add folder/file.txt
git commit -m "5th git commit"
시점에서, 는 시에서는우, 리점이를 가지고 .file.txt
다음과 같은 내용으로:
aaaa
bbbb
cccc
dddd
eeee
이 시점에서 HEAD는 5번째 커밋, HEAD~1은 4번째 커밋, HEAD~4는 1번째 커밋(HEAD~5는 존재하지 않음)입니다.세 번째 커밋을 제거하고 싶다고 가정해 보겠습니다. 이 명령은 다음에서 실행할 수 있습니다.myrepo_git
디렉터리:
git rebase -i HEAD~4
(결과적으로 "치명적: 단일 수정이 필요합니다. 잘못된 업스트림 HEAD~5").텍스트 편집기(@Dennis 답변의 스크린샷 참조)가 다음 내용으로 열립니다.
pick 5978582 2nd git commit
pick 448c212 3rd git commit
pick b50213c 4th git commit
pick a9c8fa1 5th git commit
# Rebase b916e7f..a9c8fa1 onto b916e7f
# ...
그래서 우리는 우리가 요청한 HEAD~4를 포함하지 않고 모든 커밋을 받습니다.라인 삭제pick 448c212 3rd git commit
하면 파을저다에서 이 을 받을 수 다음 응답을 받을 수 있습니다.git rebase
:
error: could not apply b50213c... 4th git commit
When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".
Could not apply b50213c... 4th git commit
myspo를 엽니다.folder/file.txt
텍스트 편집기에서 수정된 내용을 확인할 수 있습니다.
aaaa
bbbb
<<<<<<< HEAD
=======
cccc
dddd
>>>>>>> b50213c... 4th git commit
기적으로본,git
가 두 커밋에 했을 때 HEAD의 을 알 수 .aaaa
+bbbb
그리고 나서 그것은 약간의 추가된 부분이 있습니다.cccc
+dddd
기존 콘텐츠에 추가하는 방법을 알지 못합니다.
그래서 여기서.git
당신을 위해 결정할 수 없습니다. 결정을 내려야 하는 것은 당신입니다. 세 번째 커밋을 제거함으로써, 당신은 그것에 의해 도입된 변경 사항을 유지합니다(여기, 줄).cccc
) -- 또는 그렇지 않습니다.그렇지 않은 경우, 다음을 포함하여 추가 라인을 제거합니다.cccc
folder/file.txt
텍스트 편집기를 사용하면 다음과 같습니다.
aaaa
bbbb
dddd
.folder/file.txt
이다 명음실수있에서 과 같은 수 있습니다.myrepo_git
디렉터리:
$ nano folder/file.txt # text editor - edit, save
$ git rebase --continue
folder/file.txt: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add
아 - 그래서 우리가 갈등을 해결했다는 표시를 하기 위해, 우리는 해야 합니다. git add
그자리의 folder/file.txt
git rebase --continue
:
$ git add folder/file.txt
$ git rebase --continue
여기서 텍스트 편집기가 다시 열리고 선이 표시됩니다.4th git commit
여기서 우리는 커밋 메시지를 변경할 기회가 있습니다(이 경우 의미 있게 변경될 수 있습니다).4th (and removed 3rd) commit
를 들어하지 않고 하면 다음과 같은결과가 저장하지 않고 텍스트 편집기를 종료하면 다음과 같은 결과를 얻을 수 있습니다.
$ git rebase --continue
[detached HEAD b8275fc] 4th git commit
1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/master.
이 시점에서, 이제 당신은 이와 같은 이력을 가지고 있습니다(또한 당신은 말할 수 있습니다).gitk .
의 folder/file.txt
(분명히 원래 커밋의 변경되지 않은 타임스탬프 포함):
1st git commit | +aaaa
----------------------------------------------
2nd git commit | aaaa
| +bbbb
----------------------------------------------
4th git commit | aaaa
| bbbb
| +dddd
----------------------------------------------
5th git commit | aaaa
| bbbb
| dddd
| +eeee
그리고 만약 이전이라면, 우리는 그 선을 유지하기로 결정했습니다.cccc
한 세 ), 는 다음과 같이했을 입니다.
1st git commit | +aaaa
----------------------------------------------
2nd git commit | aaaa
| +bbbb
----------------------------------------------
4th git commit | aaaa
| bbbb
| +cccc
| +dddd
----------------------------------------------
5th git commit | aaaa
| bbbb
| cccc
| dddd
| +eeee
음, 이것은 제가 찾은 종류의 독서였습니다, 어떻게 그것을 더듬기 시작했습니다.git rebase
커밋/임의 삭제 측면에서 작동하므로 다른 사용자에게도 도움이 되기를 바랍니다.
따라서 잘못된 커밋이 어느 시점에 병합 커밋에 포함된 것처럼 들립니다.병합 커밋이 아직 풀렸습니까?만약 그렇다면, 당신은 사용하고 싶을 것입니다.git revert
당신은 이를 악물고 갈등을 헤쳐나가야 할 것입니다.그렇지 않은 경우 기본 재배치 또는 되돌리기를 수행할 수 있지만 병합 커밋 전에 다시 수행한 다음 병합을 다시 수행할 수 있습니다.
첫 번째 사건은 저희가 도와드릴 수 있는 게 별로 없어요, 정말요.복구를 시도한 후 자동 복구가 실패했음을 발견하면 충돌을 검사하고 적절하게 해결해야 합니다.충돌을 입니다. 즉, "" "" "" "" ""를 할 수 .git status
충돌 위치를 확인하려면 병합되지 않은 파일을 편집하고, 충돌된 헝크를 찾고, 해결 방법을 파악하고, 충돌된 파일을 추가하고, 마지막으로 커밋합니다.사용하는 경우git commit
-m <message>
는 ), 에서 생성한 .git revert
충돌을 해결한 방법에 대한 메모를 추가한 다음 저장하고 종료하여 커밋할 수 있습니다.
두 번째 경우, 병합 전에 문제를 해결하는 경우에는 병합 이후에 더 많은 작업을 수행했는지 여부에 따라 두 가지 하위 사례가 있습니다.그렇지 않은 경우에는 간단히git reset --hard HEAD^
병합을 중지하려면 되돌린 다음 병합을 다시 수행합니다.하지만 당신은 그랬을 거예요.따라서 다음과 같은 작업을 수행하게 됩니다.
- 병합 직전에 임시 분기를 만들고 확인합니다.
- 를 합니다 또기사리용 (되돌는또()).
git rebase -i <something before the bad commit> <temporary branch>
잘못된 커밋을 제거하기 위해) - 병합을 다시 수행합니다.
- 후속 작업의 기본을 다음과 같이 변경합니다.
git rebase --onto <temporary branch> <old merge commit> <real branch>
- 임시 분기를 제거합니다.
그래서 당신은 약간의 일을 하고 그것을 밀었습니다, 그들을 커밋 A와 B라고 부르죠.당신의 동료도 일을 좀 했습니다, C와 D를 커밋합니다.동료 작업을 병합한 다음(합병 커밋 E) 작업을 계속하고, 이 작업도 수행하고(커밋 F), 동료가 해서는 안 될 변경 사항을 발견했습니다.
커밋 기록은 다음과 같습니다.
A -- B -- C -- D -- D' -- E -- F
당신은 정말로 C, D, D'를 없애고 싶어합니다. 당신이 당신의 동료들을 당신의 동료들로 병합했다고 말하기 때문에, 이러한 커밋들은 이미 "밖에" 있기 때문에, 예를 들어 Gitrebase를 사용하여 커밋을 제거하는 것은 불가능합니다.정말이에요, 시도해 봤어요.
이제 두 가지 방법이 있습니다.
아직 동료나 다른 사람(일반적으로 "오리진" 서버)에게 E 및 F를 푸시하지 않았다면 당분간 기록에서 제거할 수 있습니다.저장할 작업입니다.이 작업은 다음을 통해 수행할 수 있습니다.
git reset D'
(D'를 에서 얻을 수 있는 실제 커밋 해시로 바꿉니다.
git log
이 시점에서 커밋 E와 F는 사라지고 변경 사항은 로컬 작업 공간에서 커밋되지 않은 변경 사항이 다시 적용됩니다.이 시점에서 저는 그것들을 지점으로 옮기거나 패치로 만들어 나중에 사용할 수 있도록 저장할 것입니다. 수 .
git revert
또는 수동으로.작업을 완료한 후 작업을 재생합니다.병합 충돌이 발생할 수 있지만, 적어도 병합 충돌은 동료의 코드 대신 작성한 코드에 포함됩니다."역 패치할 수 .
git revert
그러나 작업이 "방해"되기 때문에, 말하자면 더 많은 병합 충돌과 더 혼란스러운 충돌을 겪게 될 것입니다.결국 그렇게 된 것 같군요
gitrevert --커밋이 병합인 경우 해결되지 않음: gitrevert --commitresolve -m1 사용
패치를 사용하여 모든 변경 사항을 되돌릴 수 있는 간단한 솔루션이 있습니다.
- 현재 헤드 브랜치 확인(예: 개발)
git checkout develop
- 기록 로그에서 commit-id를 조회하고 새 분기에 대한 변경 사항만 체크아웃합니다.
git log
git checkout -b your-branch <your-commit-id>
- 분기를 찾아 이전 상태로 되돌리려는 상태를 찾습니다.
git checkout -b prev-status <previous-commit-id>
- 모든 변경 사항을 되돌릴 수 있는 패치를 만듭니다.
git diff your-branch..prev-status > reverts.patch
# the comparing order of branches is important
- 현재 헤드 분기를 체크아웃하고 되돌리기 패치를 적용
git checkout origin develop
git apply reverts.patch
git add *
git commit -m "revert all my changes"
다음은 egit로 이 작업을 수행하는 간단한 예입니다.
- 파일 3을 추가한 커밋 3을 삭제하고 싶습니다.
- 삭제할 커밋 앞에 있는 커밋을 마우스 오른쪽 단추로 클릭하고 "대화형 기본 재배치"를 선택합니다.
- 기본 보기에서 커밋 3을 선택하고 위의 건너뛰기 아이콘을 클릭합니다.이 아이콘 위로 이동하면 커밋이 삭제됨을 알려줍니다.
- 기본 재배치 시작을 클릭합니다.
- 스테이징을 시작하고 푸시를 클릭합니다.
- 팝업이 나타나면 강제로 클릭하고 앞으로 이동합니다.
- 그런 다음 커밋이 삭제되었음을 확인할 수 있습니다.
최근에 비슷한 문제가 발생하여 몇 가지 경우에 효과가 있을 수 있는 간단한 작업을 수행하게 되었습니다.
내 시나리오:
% git log --oneline
4ad59d6 commit 3
f244533 commit 2
c5b4688 commit 1
우리가 하고 싶었던 것은 "commit 2"의 변경 사항을 되돌린 commit 4를 만드는 것입니다.이것이 우리가 한 일입니다.
커밋 2의 변경 내용을 가져옵니다.
git show > ~/sshow/commit.2.git
변경 내용을 되돌립니다.
git apply -R ~/patches/commit.2.patch
새 커밋 만들기:
git commit -Am "commit 4: commit 2의 변경 사항을 되돌립니다."
추신: 이것은 우리가 쉽게 되돌리기를 적용할 수 있는 경우에 효과가 있습니다 - 만약 같은 코드 라인이 시간이 지남에 따라 수정되었다면, 이것은 효과가 없을 것입니다.
가장 간단한 방법은 로그를 찾고 커밋할 수 있는 카운트를 가지고 삭제할 커밋 메시지를 체크아웃하는 것입니다.
를 바꿉니다.x
카운트를 사용하여 모든 commit-msg를 표시하고 제거할 commit-msg를 삭제합니다.
# git rebase -i HEAD~x
나는 매우 간단한 방법을 볼 것입니다.
git reset --hard HEAD <YOUR COMMIT ID>
원격 분기를 재설정합니다.
git push origin -f
언급URL : https://stackoverflow.com/questions/2938301/remove-specific-commit
'programing' 카테고리의 다른 글
8년 된 이 VBA 64비트 컴파일러 버그를 어떻게 고칠 수 있습니까? (0) | 2023.05.25 |
---|---|
Postgres의 기존 열에 'serial' 추가 (0) | 2023.05.25 |
두 리포지토리 간의 차이 파악 (0) | 2023.05.25 |
mongodb가 아닌 mongo 셸만 설치합니다. (0) | 2023.05.25 |
VBA 언어로 "값이 비어 있지 않은 경우"를 어떻게 표현합니까? (0) | 2023.05.25 |