programing

여러 Git 커밋을 되돌리려면 어떻게 해야 합니까?

bestprogram 2023. 5. 27. 12:04

여러 Git 커밋을 되돌리려면 어떻게 해야 합니까?

다음과 같은 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 = DCB를-1-1-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' <-- 마스터 <-- 헤드

커밋 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..
git commit -m "your message regarding reverting the multiple commits"

이 명령은 하나의 커밋만으로 마지막 3개의 커밋을 반환합니다.

또한 역사를 다시 쓰지 않기 때문에 강제로 밀어붙일 필요도 없습니다.

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

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

예를 들어, 지점 '마스터'에 있다고 가정하면 다음과 같이 해야 합니다.

git revert master~3..master

또는git revert B...D또는git revert D C B

이렇게 하면 B, C 및 D의 역 커밋으로 로컬에 새 커밋이 만들어집니다(이러한 커밋에 의해 도입된 변경 사항이 취소됨).

A <- B <- C <- D <- BCD' <- HEAD
git reset --hard a
git reset --mixed d
git commit

그것은 그들 모두에게 한 번에 되돌리는 역할을 할 것입니다.적절한 커밋 메시지를 제공합니다.

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

# Revert all commits from and including B to HEAD, inclusively
git revert --no-commit B^..HEAD
git commit -m 'message'

저는 이 질문에 그냥 대답할 수 없다는 것이 너무 답답합니다.다른 모든 질문은 올바르게 되돌리고 역사를 보존하는 방법에 관한 것입니다.이 질문은 "나는 지점장이 A, 즉 A를 가리키기를 원합니다. 저는 B, C, D, HEAD가 사라지고 헤드가 A와 동의어가 되기를 원합니다."

git checkout <branch_name>
git reset --hard <commit Hash for A>
git push -f

저는 제이콥의 게시물을 읽고 많은 것을 배웠지만, 회사의 어떤 사람(풀 요청 없이 "테스트" 지점에 푸시할 수 있는 액세스 권한이 있음)은 5번의 잘못된 커밋을 추진하여 5번의 커밋 전에 저지른 실수를 수정하고 수정하려고 했습니다.뿐만 아니라 한두 번의 당기기 요청이 받아들여졌는데, 지금은 좋지 않았습니다.그러니 잊어버리세요. 저는 마지막으로 좋은 커밋(abc1234)을 찾아 기본 스크립트를 실행했습니다.

git checkout testing
git reset --hard abc1234
git push -f

저는 이 저장소에서 일하는 다른 5명에게 지난 몇 시간 동안의 변경 사항을 기록하고 최신 테스트에서 삭제/재설치하는 것이 좋다고 말했습니다.이야기의 끝.

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

그러면:

git diff --binary HEAD commit_sha_you_want_to_revert_to | git apply

그런 다음 그냥 커밋합니다.반환 이유가 무엇인지 기록하는 것을 잊지 마십시오.

사용하기 용사Restore

은 또한 있다니습수도를 할 수 .restore명령:

A <- B <- C <- D <- HEAD

당신이 원한다고 치자.HEAD과 꼭 A최신 버전을 선택했는지 확인합니다.master그런 다음 새 가지를 자릅니다.

git switch -c feature/flux-capacitor  # synonymous with checkout -b
git restore --source A .
git add .
git commit
git push

restore은 모든것을 합니다(명령모은것변다니합경을든(다▁command니명합▁every).. 것과 .--source 은 그것을 으로 밀어넣습니다.그런 다음 해당 지점에 커밋하고 원점으로 밀어넣습니다.그런 다음 PR을 열 수 있습니다.

이렇게 하면 다른 사용자가 작업을 기반으로 했을 수 있는 기록을 변경하지 않을 수 있습니다.그것은 또한 미래의 사람들에게 유용한 역사를 남깁니다.

문서: git 복원

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

차이가 없어야 합니다.

그룹(을 보존하려는 경우)을 쉬운 은 사가용사기보고록공는존려저은방커법쉬그운되는돌리룹을용자밋의장소하유을하▁the▁to방▁of은▁on사법▁use용쉬를 사용하는 것입니다.git revert 깃과함께와 .rev-list후자는 커밋 목록을 제공하고 전자는 자체적으로 되돌립니다.

두 가지 방법이 있습니다.단일 커밋에서 여러 커밋을 되돌리려면 다음을 사용합니다.

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

매력적으로 작동했습니다 :)

제 생각에 매우 쉽고 깨끗한 방법은 다음과 같습니다.

A로 돌아가다

git checkout -f A

마스터의 머리를 현재 상태로 가리킵니다.

git symbolic-ref HEAD refs/heads/master

절약하다

git commit

아마 여기 있는 다른 접근법들보다 덜 우아하겠지만, 전 항상 사용해왔습니다.get reset --hard HEAD~N다중 커밋을 실행 취소하려면, 위치N되돌리려는 커밋 수입니다.

또는 정확한 커밋 수가 확실하지 않은 경우 그냥 실행git reset --hard HEAD^원하는 상태에 도달할 때까지 (커밋 하나를 되돌립니다).

팀이 목표 지점(직접 커밋된 지점)을 강제로 밀어넣지 않고도 명확한 풀 요청을 제시할 수 있도록 긴 범위의 커밋을 되돌린 다음 다시 커밋해야 했습니다.

# 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개의커밋(commits, 7개의 커밋)을 때 .git log -n 7분기 합니다().git log -n 5와 2 에 다른 것에서 2) 및 2 로 2 으 다 항 개 서 에 상 2 위 2 음git log HEAD~12..HEAD~10는 7 + 커밋으로, FF를 "라고 가정할 때) (12 밋 7 커 + 5 이로밋으, PR 가압치전 "이은되않" 지쇄분기때결 "전를상"할과브병가랜브정한치를합대랜치로를는나거로하반기으새랜커브▁(이(이12(압▁the▁commits▁is▁assuming▁5병▁7결▁the▁is▁of▁commits,가때브)

하드 리셋은 피하고 싶었습니다. 제가 생각해낸 것이 바로 이런 것입니다.

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

네가 만약

  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

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

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

git log --pretty=oneline | grep 'feature_name' | cut -d ' ' -f1 | xargs -n1 git revert --no-edit

언급URL : https://stackoverflow.com/questions/1463340/how-can-i-revert-multiple-git-commits