다음과 같은 git 저장소가 있습니다.
A <- B <- C <- D <- HEAD
분기의 머리가 A를 가리키도록 하고 싶습니다. 즉, B, C, D 및 HEAD가 사라지고 머리가 A와 동의어가 되기를 원합니다.
리베이스를 시도하거나(중간에 변경 사항을 푸시했기 때문에 적용되지 않음) 되돌릴 수 있는 것처럼 들립니다. 그러나 여러 커밋을 되돌리려면 어떻게 해야 합니까? 한 번에 하나씩 되돌리나요? 순서가 중요한가요?
질문자 :Bill
다음과 같은 git 저장소가 있습니다.
A <- B <- C <- D <- HEAD
분기의 머리가 A를 가리키도록 하고 싶습니다. 즉, B, C, D 및 HEAD가 사라지고 머리가 A와 동의어가 되기를 원합니다.
리베이스를 시도하거나(중간에 변경 사항을 푸시했기 때문에 적용되지 않음) 되돌릴 수 있는 것처럼 들립니다. 그러나 여러 커밋을 되돌리려면 어떻게 해야 합니까? 한 번에 하나씩 되돌리나요? 순서가 중요한가요?
내가 댓글에 쓴 것을 확장
일반적인 규칙은 누군가가 자신의 작업을 기반으로 했을 수 있기 때문에 게시한 기록을 다시 작성(변경)해서는 안 된다는 것입니다. 기록을 다시 작성(변경)하면 변경 사항을 병합하고 업데이트하는 데 문제가 발생합니다.
따라서 해결책은 제거하려는 변경 사항 을 되돌리는 새 커밋을 만드는 것입니다. git revert 명령을 사용하여 이 작업을 수행할 수 있습니다.
다음과 같은 상황이 있습니다.
A <-- B <-- C <-- D <-- 마스터 <-- HEAD
(여기서 화살표는 포인터의 방향을 나타냅니다: 커밋의 경우 "부모" 참조, 분기 헤드(분기 참조)의 경우 최상위 커밋, HEAD 참조의 경우 분기 이름).
생성해야 하는 것은 다음과 같습니다.
A <-- B <-- C <-- D <-- [(BCD) -1 ] <-- 마스터 <-- HEAD
여기서 [(BCD)^-1]
은 커밋 B, C, D의 변경 사항을 되돌리는 커밋을 의미합니다. 수학에서는 (BCD) -1 = D -1 C -1 B -1 이라고 말 하므로 필요한 상황을 얻을 수 있습니다. 다음 명령을 사용하여:
$ git revert --no-commit D $ git revert --no-commit C $ git revert --no-commit B $ git commit -m "the commit message for all of them"
병합 커밋을 제외한 모든 작업에 적용됩니다.
대체 솔루션은 커밋 A의 내용 을 체크아웃 하고 이 상태를 커밋하는 것입니다. 병합 커밋에서도 작동합니다. 그러나 추가된 파일은 삭제되지 않습니다. 로컬 변경 사항이 있는 경우 먼저 git stash
$ git checkout -f A -- . # checkout that revision over the top of local files $ git commit -a
그러면 다음과 같은 상황이 발생합니다.
A <-- B <-- C <-- D <-- A' <-- 마스터 <-- HEAD
커밋 A'는 커밋 A와 내용은 같지만 커밋이 다릅니다(커밋 메시지, 부모, 커밋 날짜).
Charles Bailey가 수정한 Jeff Ferland의 대체 솔루션은 동일한 아이디어를 기반으로 하지만 git reset 을 사용합니다. 여기에서 약간 수정되었습니다. 이 방법은 모든 작업에 적용됩니다.
$ git reset --hard A $ git reset --soft D # (or ORIG_HEAD or @{1} [previous location of HEAD]), all of which are D $ git commit
유용하다고 생각한 깨끗한 방법
git revert --no-commit HEAD~3..
이 명령은 단 하나의 커밋으로 마지막 3개의 커밋을 되돌립니다.
또한 역사를 다시 쓰지 않습니다.
..
범위를 만드는 데 도움이 됩니다. 의미 HEAD~3..
HEAD~3..HEAD
와 동일합니다.
이렇게 하려면 되돌리려 는 커밋 범위를 지정하여 되돌리기 명령을 사용하기만 하면 됩니다.
귀하의 예를 고려하여 다음을 수행해야 합니다('마스터' 분기에 있다고 가정).
git revert master~3..master
또는 git revert B...D
또는 git revert DCB
이것은 B, C 및 D의 역 커밋으로 로컬에 새로운 커밋을 생성합니다(이 커밋에 의해 도입된 변경 사항을 취소함을 의미합니다):
A <- B <- C <- D <- BCD' <- HEAD
git reset --hard a git reset --mixed d git commit
그것은 한 번에 그들 모두를 되돌리는 역할을 할 것입니다. 좋은 커밋 메시지를 주세요.
Jakub의 답변과 유사하게 되돌릴 연속 커밋을 쉽게 선택할 수 있습니다.
# revert all commits from B to HEAD, inclusively $ git revert --no-commit B..HEAD $ git commit -m 'message'
먼저 작업 복사본이 수정되지 않았는지 확인합니다. 그 다음에:
git diff --binary HEAD commit_sha_you_want_to_revert_to | git apply
그런 다음 커밋하십시오. 되돌리는 이유가 무엇인지 문서화하는 것을 잊지 마십시오.
이 질문에 답을 할 수 없다는 것이 너무 속상합니다. 다른 모든 질문은 올바르게 되돌리고 역사를 보존하는 방법과 관련이 있습니다. 이 질문은 "나는 지점의 머리가 A를 가리키기를 원한다. 즉, 나는 B, C, D, 그리고 HEAD가 사라지 기를 원하고 나는 머리가 A와 동의어가 되기를 원한다"라고 말한다.
git checkout <branch_name> git reset --hard <commit Hash for A> git push -f
Jakub의 게시물을 읽고 많은 것을 배웠지만, 회사의 어떤 사람(Pull-Request 없이 "테스트" 분기에 대한 액세스 권한이 있음)이 5개의 커밋을 수정하고 수정하려고 시도하는 5개의 잘못된 커밋을 푸시했습니다. 그뿐만 아니라 하나 또는 두 개의 Pull Request가 수락되었는데 지금은 좋지 않습니다. 잊어 버리십시오. 마지막 좋은 커밋 (abc1234)을 발견하고 기본 스크립트를 실행했습니다.
git checkout testing git reset --hard abc1234 git push -f
나는 이 리포지토리에서 일하는 다른 5명에게 지난 몇 시간 동안의 변경 사항을 기록하고 최신 테스트에서 Wipe/Re-Branch를 더 잘 기록한다고 말했습니다. 이야기의 끝.
이것은 Jakub의 답변에 제공된 솔루션 중 하나의 확장입니다.
롤백해야 하는 커밋이 병합 커밋 중 몇 개와 함께 다소 복잡하고 기록을 다시 작성하는 것을 피해야 하는 상황에 직면했습니다. 결국 추가되는 되돌리기 변경 사항 간에 충돌이 발생했기 때문에 git revert
명령을 사용할 수 없었습니다. 나는 다음 단계를 사용하여 끝났습니다.
먼저 HEAD를 분기 끝에 남겨두고 대상 커밋의 내용을 확인하십시오.
$ git checkout -f <target-commit> -- .
(-- <target-commit>
이 파일이 아닌 커밋으로 해석되도록 합니다. .는 현재 디렉토리를 나타냅니다.)
그런 다음 롤백 중인 커밋에 추가되어 삭제해야 하는 파일을 확인합니다.
$ git diff --name-status --cached <target-commit>
추가된 파일은 줄 시작 부분에 "A"가 표시되어야 하며 다른 차이점은 없어야 합니다. 이제 제거해야 하는 파일이 있으면 제거를 위해 다음 파일을 준비합니다.
$ git rm <filespec>[ <filespec> ...]
마지막으로 되돌리기를 커밋합니다.
$ git commit -m 'revert to <target-commit>'
원하는 경우 원하는 상태로 돌아가야 합니다.
$git diff <target-commit> <current-commit>
차이가 없어야 합니다.
공유 리포지토리에서 커밋 그룹을 되돌리는 쉬운 방법(사람들이 사용하고 기록을 보존하려는)은 rev-list
와 함께 git git revert
를 사용하는 것입니다. 후자는 커밋 목록을 제공하고 전자는 되돌리기를 수행합니다.
두 가지 방법이 있습니다. 단일 커밋으로 여러 커밋을 되돌리려면 다음을 사용하십시오.
for i in `git rev-list <first-commit-sha>^..<last-commit-sha>`; do git revert --no-commit $i; done
이렇게 하면 필요한 커밋 그룹을 되돌릴 수 있지만 모든 변경 사항은 작업 트리에 남겨두고 나중에 평소와 같이 모두 커밋해야 합니다.
또 다른 옵션은 되돌린 변경마다 단일 커밋을 갖는 것입니다.
for i in `git rev-list <first-commit-sha>^..<last-commit-sha>`; do git revert --no-edit -s $i; done
예를 들어 다음과 같은 커밋 트리가 있는 경우
o---o---o---o---o---o---> fff eee ddd ccc bbb aaa
변경 사항을 eee 에서 bbb 로 되돌리려면 다음을 실행하십시오.
for i in `git rev-list eee^..bbb`; do git revert --no-edit -s $i; done
그 중 어느 것도 나를 위해 일하지 않았으므로 되돌릴 세 개의 커밋(마지막 세 개의 커밋)이 있으므로 다음을 수행했습니다.
git revert HEAD git revert HEAD~2 git revert HEAD~4 git rebase -i HEAD~3 # pick, squash, squash
매력처럼 일했습니다 :)
여기에서 다른 접근 방식보다 덜 우아할 수 있지만 저는 항상 get reset --hard HEAD~N
을 사용하여 여러 커밋을 실행 취소했습니다. 여기서 N
은 되돌리려는 커밋 수입니다.
또는 정확한 커밋 수를 확신 git reset --hard HEAD^
(한 커밋으로 돌아가기)를 여러 번 실행하면 됩니다.
제 생각에는 매우 쉽고 깨끗한 방법이 될 수 있습니다.
git checkout -f A
git symbolic-ref HEAD refs/heads/master
git commit
나는 정말로 하드 리셋을 피하고 싶었습니다. 이것이 내가 생각해 낸 것입니다.
A -> B -> C -> D -> HEAD
A로 돌아가려면(4단계 뒤로):
git pull # Get latest changes git reset --soft HEAD~4 # Set back 4 steps git stash # Stash the reset git pull # Go back to head git stash pop # Pop the reset git commit -m "Revert" # Commit the changes
만약 너라면
그러면 당신은 할 수 있습니다
git reset --soft HEAD~(number of commits you'd like to revert) git commit -m "The stuff you didn't like." git log # copy the hash of your last commit git revert <hash of your last (squashed) commit>
그런 다음 변경 사항을 푸시하려는 경우 기록을 수정했기 때문에 -f
git push <your fork> <your branch> -f
긴 범위의 커밋을 되돌린 다음 다시 되돌려 팀이 대상 브랜치(직접 커밋됨)를 강제로 푸시하지 않고도 명확한 풀 요청을 제시할 수 있도록 해야 합니다.
# checkout the branch that should be targeted git checkout $branch_target # revert the commits in $branch_target to some $count where # $count is the number of commits to revert # cut is used to slice just the commit hash field from each line of output # xargs runs the command once for each line of input, reversing the commits! git log --oneline -n $count | cut -d' ' -f1 | xargs git revert # check out the branch which should be the source of the pull request git checkout -b $branch_for_pull # revert the revert commits # $count is that same number of commits being reverted (again) git log --oneline -n $count | cut -d' ' -f1 | xargs git revert # push branches up and go off to create PR in whatever web UI git push --set-upstream origin $branch_for_pull # it's new! git checkout $branch_target git push # if this branch wasn't pushed, just fix the issue locally instead..
HEAD
모든 커밋을 git log -n $count
역순으로 되돌리기 때문에 커밋 횟수에 관계없이 잘 작동합니다.
이 상태의 $branch_target
에서 보기
% git log --oneline origin/$branch_target ffff006 (origin/$branch_target, $branch_target) Revert "first commit" ffff005 Revert "second commit" ffff004 Revert "third commit" ffff003 third commit ffff002 second commit ffff001 first commit
이 상태에서 $branch_for_pull
% git log --oneline origin/$branch_for_pull ffff009 (origin/$branch_for_pull, $branch_for_pull) Revert "Revert "third commit"" ffff008 Revert "Revert "second commit"" ffff007 Revert "Revert "first commit"" ffff006 (origin/$branch_target, $branch_target) Revert "first commit" ffff005 Revert "second commit" ffff004 Revert "third commit" ffff003 third commit ffff002 second commit ffff001 first commit
의도가 변경 세트로 N 개의 분기를 생성하는 것이지만 모두 동일한 분기에 커밋된 경우에도 여전히 모든 분기를 기본 커밋으로 되돌린 다음 변경 세트가 논리적으로 정렬되어야 하므로 필요한 되돌리기만 되돌릴 수 있습니다. 5배 빠름)
HEAD~7..HEAD~5
와 같은 구문을 사용하면 되돌리기-되돌리기 분기를 정확하게 분할하기 위한 범위를 설명하는 데 도움이 될 수 있습니다.
여기에서는 마지막 7개 커밋( git log -n 7
)을 되돌릴 때 의미가 있지만 한 분기에서 5개를 복원하고( git log -n 5
git log HEAD~12..HEAD~10
에서 최상위 2개를 복원합니다. git log HEAD~12..HEAD~10
(12는 7 커밋 + 5 커밋, 새 PR 분기가 "이전" 분기를 기반으로 하거나 FF(스쿼시되지 않음)의 결과가 분기를 "이전" 원본에 병합한다고 가정합니다. 대상 지점)
기능의 커밋을 일시적으로 되돌리려면 다음 명령을 사용할 수 있습니다.
자식 로그 --pretty=oneline | grep 'feature_name' | 컷 -d ' ' -f1 | xargs -n1 git 되돌리기 --no-edit
출처 : http:www.stackoverflow.com/questions/1463340/how-to-revert-multiple-git-commits
분기가 이미 마스터에 병합되었는지 어떻게 알 수 있습니까? (0) | 2023.04.26 |
---|---|
git 브랜치 이름 지정에 일반적으로 사용되는 몇 가지 예는 무엇입니까? [닫은] (0) | 2023.04.26 |
여러 열에서 그룹화 사용 (0) | 2023.04.26 |
'==' 또는 'is'를 사용하여 문자열을 비교하면 때때로 다른 결과가 생성되는 이유는 무엇입니까? (0) | 2023.04.26 |
배치 파일에 인수를 전달하려면 어떻게 해야 합니까? (0) | 2023.04.25 |