만약 여러개의 연속된 커밋들을 되돌리면서 그 중에 몇개의 커밋은 유지하고 싶은 경우, 아래와 같은 작업을 수행한다:
git rebase -i <rebase를 시작할 기준 커밋 SHA>
-i 옵션은 rebase 를 "대화형 (interactive) 모드" 로 동작하게 해 준다. rebase 수행에 따른 실제 커밋을 replay 적용하기 직전에, 앞으로 replay 될 각각의 커밋들에 대해 수행할 작업을 신택할 수 있도록 잠시 rebase 작업을 멈추게 된다.
rebase -i 수행시 아래와 같이 적용될 커밋들과 각 수행할 작업 목록을 편집할 수 있도록 사용자의 기본 편집기에 표시하여 줄 것이다:
커밋을 제거하고 싶다면, 간단히 해당 라인을 편집기에서 삭제하기만 하면 된다. 위 그림에 표시된 예제에서, 잘못된 커밋들을 프로젝트에서 제거하고자 한다면 1 번 라인과 3-4 번 라인을 삭제하면 된다. 만약 두개의 커밋을 하나로 합치고자 한다면, squash 나 fixup
명령을 아래와 같이 기입하여 준다.
git revert 를 이용하면 기존 커밋들을 되돌릴 수 있으며, 이는 특히 원격 저장소에 해당 커밋들이 이미 push 된 경우 더욱 유용하다.
이 작업은 기존 커밋의 효과를 되돌리는 새로운 커밋을 생성하게 되며, 이를 통해 history 를 덮어쓰지 않고도 안전하게 원격 저장소에 되돌린 결과물을 push 할 수 있게 된다.
git push --force 을 통해 history 를 덮어쓰는 행위는 해당 저장소를 사용하는 다른 사용자들로부터 항의를 받을 수 있는 위험한 행위이므로 절대 이러한 작업을 수행해서는 안된다.
만약, 방금 push 한 커밋에 버그가 있는 것을 발견하여 해당 커밋을 바로 되돌리고 싶다면, 아래와 같이 수행하도록 한다:
git revert HEAD~1
git push
이 작업 이후, 로컬에서 위 revert 커밋을 다시 revert 한 다음, 문제점을 수정한 후에 정상 동작하는 코드를 push 하도록 한다:
git revert HEAD~1
수정 .. 수정 .. 수정 ..
git add -A .
git commit -m "Update error code"
git push
만약 revert 하고자 하는 커밋이 history 상에서 이후에 추가된 다른 커밋들에 뒤덮여 있다면 (HEAD~1 로 지정할 수 없다면), 커밋 해시값을 지정해서 revert 를 수행할 수도 있다. Git 은 해당 커밋을 되돌리는 counter-commit 을 생성해 줄 것이고, 이를 원격 저장소에 안전하게 push 할 수 있다.
만약 merge 작업을 수행하긴 하였지만 원격 저장소에 아직 push 를 하지 않은 상태라면 아래에 소개된 일반적인 커밋 되돌리기와 유사한 과정을 통해 merge 작업을 되돌릴 수 있다.
reset 을 이용한 방법은 merge 커밋 자체와 해당 커밋 이후 브랜치에 추가된 모든 커밋들을 되돌리기에 가장 간단한 방법이다.
그러나, 이렇게 reset 을 하려면 되돌아갈 대상 커밋의 SHA 해시값을 알아야 하는데, git log 의 결과는 merge 한 두 브랜치 모두의 커밋 목록을 보여주기에 되돌아가고자 하는 정확한 커밋을 알아내기가 어려울 수 있다. 만약 잘못된 커밋을 지정하여 reset 을 수행한다면 (예: 되돌아가고자 하는 브랜치가 아닌 merge 의 대상이 되었던 브랜치의 커밋을 지정한다던가) 이전에 커밋하였던 작업 내역이 유실될 수 있다.
git reset --hard <작업 중이던 브랜치의 마지막 커밋>
혹은, 만약 되돌리고자 하는 merge 커밋 자체가 가장 최근에 추가된 커밋이라면:
git reset HEAD~
revert 를 이용하는 방법은 이미 커밋된 어떠한 작업도 무효화하지 않는다는 점에서 더욱 안전한 방법이나, 이후에 해당 브랜치와의 merge 를 다시 수행하고 싶다면 revert 한 커밋을 다시 revert 해야 한다는 점에서 추가적인 작업이 더 필요한 방법이기도 하다 (아래 섹션을 참고하라).
원격 저장소에 push 완료된 merge 작업 되돌리기
아래와 같이 'add-gremlins' 라는 새로운 feature 를 추가하는 상황을 고려해보자
이 시점에서는 시스템에 문제를 일으켰던 feature 가 원격 저장소에서 제외되어 다른 개발자들의 시스템이 다시 정상 동작하기 시작할 것이다.
이제 add-gremlins feature 의 문제를 해결한 후 다시 merge 를 수행하기 위해서는, 위 revert 작업을 되돌릴 필요가 있다.
git checkout feature/add-gremlins
...
# 문제 해결을 위한 커밋을 이 시점에 추가한다.
git checkout master
...
git revert e443799
...
git merge feature/add-gremlins
...
# 문제 수정으로 인해 새로이 발생한 merge conflict 을 해결한다
...
git commit # merge 작업을 커밋한다
...
git push
이 과정을 마치면 해당 feature 가 성공적으로 다시 추가되었을 것이다. 그러나, 이러한 버그들이 주로
merge conflict 으로 인해 발생하는 경우가 많다는 점을 고려하면, 아래와 같이 feature 브랜치에서 master 를 merge 한 후 문제를 해결하는 작업 순서를 따르는 것이 더 유용할 때가 있다.
git checkout feature/add-gremlins
...
# master 브랜치를 merge 한 후 바로 이전 revert 작업을 revert 한다.# 이 작업을 통해 이전에 master 에 문제가 생겼던 상태와 동일한 상태를 만들수 있다.
git merge master
...
git revert e443799
...
# 이제 발생한 문제를 해결한다 (여러 커밋이 이 시점에서 추가될 수 있다)
git checkout master
...
# revert 작업을 revert 하는 것은 위에서 수행 하였기에 이 시점에서는 필요하지 않다
git merge feature/add-gremlins
...
# 문제 수정으로 인해 새로이 발생한 merge conflict 을 해결한다
git commit #commit the merge
...
git push