etc./StackOverFlow

여러 git 커밋을 되돌리는 방법은 무엇입니까?

청렴결백한 만능 재주꾼 2023. 4. 26. 12:46
반응형

질문자 :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

Jakub Narębski

유용하다고 생각한 깨끗한 방법

 git revert --no-commit HEAD~3..

이 명령은 단 하나의 커밋으로 마지막 3개의 커밋을 되돌립니다.

또한 역사를 다시 쓰지 않습니다.

.. 범위를 만드는 데 도움이 됩니다. 의미 HEAD~3.. HEAD~3..HEAD 와 동일합니다.


deepdive

이렇게 하려면 되돌리려 는 커밋 범위를 지정하여 되돌리기 명령을 사용하기만 하면 됩니다.

귀하의 예를 고려하여 다음을 수행해야 합니다('마스터' 분기에 있다고 가정).

 git revert master~3..master

또는 git revert B...D 또는 git revert DCB

이것은 B, C 및 D의 역 커밋으로 로컬에 새로운 커밋을 생성합니다(이 커밋에 의해 도입된 변경 사항을 취소함을 의미합니다):

 A <- B <- C <- D <- BCD' <- HEAD

Victor

git reset --hard a git reset --mixed d git commit

그것은 한 번에 그들 모두를 되돌리는 역할을 할 것입니다. 좋은 커밋 메시지를 주세요.


Jeff Ferland

Jakub의 답변과 유사하게 되돌릴 연속 커밋을 쉽게 선택할 수 있습니다.

 # revert all commits from B to HEAD, inclusively $ git revert --no-commit B..HEAD $ git commit -m 'message'

konyak

먼저 작업 복사본이 수정되지 않았는지 확인합니다. 그 다음에:

 git diff --binary HEAD commit_sha_you_want_to_revert_to | git apply

그런 다음 커밋하십시오. 되돌리는 이유가 무엇인지 문서화하는 것을 잊지 마십시오.


mateusz.fiolka

이 질문에 답을 할 수 없다는 것이 너무 속상합니다. 다른 모든 질문은 올바르게 되돌리고 역사를 보존하는 방법과 관련이 있습니다. 이 질문은 "나는 지점의 머리가 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를 더 잘 기록한다고 말했습니다. 이야기의 끝.


Suamere

이것은 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>

차이가 없어야 합니다.


Warren Dew

공유 리포지토리에서 커밋 그룹을 되돌리는 쉬운 방법(사람들이 사용하고 기록을 보존하려는)은 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

Ruslan Kabalin

그 중 어느 것도 나를 위해 일하지 않았으므로 되돌릴 세 개의 커밋(마지막 세 개의 커밋)이 있으므로 다음을 수행했습니다.

 git revert HEAD git revert HEAD~2 git revert HEAD~4 git rebase -i HEAD~3 # pick, squash, squash

매력처럼 일했습니다 :)


Dorian

여기에서 다른 접근 방식보다 덜 우아할 수 있지만 저는 항상 get reset --hard HEAD~N 을 사용하여 여러 커밋을 실행 취소했습니다. 여기서 N 은 되돌리려는 커밋 수입니다.

또는 정확한 커밋 수를 확신 git reset --hard HEAD^ (한 커밋으로 돌아가기)를 여러 번 실행하면 됩니다.


Ian

제 생각에는 매우 쉽고 깨끗한 방법이 될 수 있습니다.

A로 돌아가다

 git checkout -f A

마스터의 머리를 현재 상태로 가리키다

 git symbolic-ref HEAD refs/heads/master

저장

 git commit

nulll

나는 정말로 하드 리셋을 피하고 싶었습니다. 이것이 내가 생각해 낸 것입니다.

 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

Nebulastic

만약 너라면

  1. 병합 된 커밋이 있고
  2. 되돌릴 수 없으며
  3. 당신은 당신이 되돌릴 역사를 짓밟는 것을 신경 쓰지 않습니다.

그러면 당신은 할 수 있습니다

 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

ScottyBlades

긴 범위의 커밋을 되돌린 다음 다시 되돌려 팀이 대상 브랜치(직접 커밋됨)를 강제로 푸시하지 않고도 명확한 풀 요청을 제시할 수 있도록 해야 합니다.

 # 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(스쿼시되지 않음)의 결과가 분기를 "이전" 원본에 병합한다고 가정합니다. 대상 지점)


ti7

기능의 커밋을 일시적으로 되돌리려면 다음 명령을 사용할 수 있습니다.

작동 방식은 다음과 같습니다.

자식 로그 --pretty=oneline | grep 'feature_name' | 컷 -d ' ' -f1 | xargs -n1 git 되돌리기 --no-edit


Ajit Singh

출처 : http:www.stackoverflow.com/questions/1463340/how-to-revert-multiple-git-commits

반응형