🤔 git revert란?
git revert란 일부 기존의 커밋들을 되돌리는 작업이다. git reset과는 다른 것이, git reset은 기존의 커밋을 아예 삭제해버린다. 하지만 git revert는 변경 사항을 되돌린 커밋을 하나 새로 생성한다. 예를 들어 아래와 같은 커밋 A, B, C가 있다고 가정해보자. (알파벳은 커밋을 구분하기 위해 임의로 붙인 이름이다.)
이 때 커밋 C의 변경 내역을 reset, revert를 통해 되돌린다면 어떻게 될까? 커밋 내역을 살펴보면 git reset은 커밋 C에 대한 기록이 아예 없어진다. git revert는 새로운 커밋 X가 생긴다. 커밋 X의 변경 내역을 살펴보면, 커밋 C에서 변경했던 코드들이 그 이전 상태로 돌아가있다.
git reset을 사용하는 것이 더 깔끔해보일 수도 있다. 내가 git revert를 사용할 때는 주로 다음와 같은 상황에 사용한다. '변경 내역을 롤백했다'는 사실을 커밋 내역에 기록하고 싶을 때. 이걸 기록할 필요가 있을까 싶지만 나는 개인적으로 변경사항에서 어떤 이슈가 발생했기 때문에 롤백했다는 사실을 기록하는 것을 선호한다. (가능하다면 어떤 이슈가 있었는지도) 실무에서 코드를 작성하다보면 코드를 저렇게 짜는게 깔끔해보이지만, 비즈니스적인 문제로 이렇게 짤 수 밖에 없었던 히스토리가 생긴다. 전임자나 코드를 작성한 사람을 찾아가서 물어봐도 되지만 전임자가 퇴사했다면? ... 이런 이유로 히스토리를 남기는 것을 선호하는 편이다.
또는 force push가 불가능한 경우에도 사용한다. reset 명령어는 커밋 기록을 삭제하기 때문에 일반 push가 아닌 force push를 통해 커밋 기록을 덮어씌우기 해야한다. 그래서 main branch에서는 force push를 못하도록 설정해둔 경우도 많다.
🤩 git revert의 사용법
$ git revert [--[no-]edit] [-n] [-m <parent-number>] <commit>…
- <commit>...: 되돌리기를 원하는 커밋
- -e: --edit. revert가 커밋되기 전에 메시지를 편집 (default)
- -m parent-number: --mainline parent-number. 지정된 부모를 기준으로 되돌리기
- --no-edit: 커밋 메시지 편집을 생략
- --cleanup=<mode>: 커밋 전에 지공된 커밋 메시지를 정리하는 방법 결정
- -n: --no-commit. 되돌리기만 하고 자동으로 커밋되지는 않도록 설정
다른 추가 옵션 및 더 자세한 설명 보러가기 👉 https://git-scm.com/docs/git-revert
예제 코드를 통해 git revert를 사용해보자. 아래 같은 커밋 내역이 있을 때 commit A를 제거하고 싶다면 어떻게 해야할까?
커맨드 창에 아래 명령어를 입력하면 된다.
$ git revert 2827a8aa
위 명령어를 입력한 뒤에는 커밋 메시지 편집기가 뜬다. 자동으로 커밋 메시지가 작성되어있지만, 수정이 필요하다면 수정한다.
편집기를 닫으면 커밋 내역에서 revert한 새로운 커밋이 생긴 것을 볼 수 있다.
🥸 머지 커밋을 git revert하기
소스 코드는 보통 여러 사람에 의해 관리된다. 그래서 아래 그림과 같이 브랜치를 여러개로 나눠서 작업하다가, 작업이 끝나면 메인 브랜치로 합쳐지는 일이 많다.
이때 특정 브랜치에서 작업했던 내역을 revert하고 싶으면 어떻게 할까? 아까 추가옵션 중 하나였던 -m을 이용하면 된다.
$ git revert -m [parent-number] [commit hash]
branch-A의 작업 내역을 제거하고 싶다면 아래와 같이 입력하면 된다.
$ git revert -m 1 [branch-A 머지커밋의 hash]
✚ resolve한 커밋 revert 하기
앞서 사용했던 revert 명령어에서는 -m 옵션을 '1'과 함께 사용했었다. 이 숫자는 [parent-number]인데, 단어 그대로 부모의 숫자를 의미한다. 만약 머지 과정 중에 resolve가 일어났다면 꼭 주의해야 하는 부분이다. (resolve: 동시에 같은 소스 코드를 수정하여 발생한 충돌을 해결한 것)
아래와 같은 커밋 히스토리에서 branch-A에서 작업했던 내역들을 제거해보자. resolve가 일어난 커밋 a680e107은 e61ea649와 같은 소스 코드를 수정하여 충돌이 발생했었다고 가정한다.
parent-number는 무엇을 기준으로 선정되는걸까? git log를 보면 알 수 있다. 'Merge:' 옆을 살펴보면 두 개의 커밋 해시가 나타나있다. 왼쪽 커밋인 3717cba가 parent-number = 1, 오른쪽 커밋인 798f040이 parent-number = 2이다.
1) parent-number = 1인 경우
$ git revert -m 1 e61ea649
git revert는 마법처럼 revert하려는 커밋의 작업내역만 쏙 빼주는 기능이 아니다. 내가 지정한 부모(3717cbaa), revert하려는 커밋(e61ea649), 최신 커밋(a680e107)을 비교하여 새로운 머지 커밋을 생성하는 기능이다. 세 버전의 소스 코드를 비교하다보면 충돌이 일어난다. a680e107 커밋을 생성할 때를 생각해보자. 소스 코드에서 충돌이 발생해서 해결했던건데, 또 같은 범위의 소스 코드를 수정하게려고 하니 충돌이 일어나는 것이다. 이때는 충돌난 부분을 살펴보고, 수동으로 resolve를 해주면 된다.
이 과정에 대해서 더 자세히 이해하고 싶다면 3 way merge에 대해 찾아보거나, 또는 생활코딩 - git revert를 참고하길 바란다.
2) parent-number = 2인 경우
$ git revert -m 2 e61ea649
내가 지정한 부모(765938d4), revert하려는 커밋(e61ea649), 최신 커밋(a680e107)을 비교하여 새로운 머지 커밋을 생성한다. 여기서 3717cbaa는 소스 코드 비교 대상이 아니기 때문에 revert한 뒤에는 변경 내역이 사라질 수 있다.
참고
'Develop > etc' 카테고리의 다른 글
구조적 동시성 이해하기 (feat. goto의 역사) (0) | 2024.12.23 |
---|---|
Windows에서 8080 port 사용이 불가능한 현상 (1) | 2022.09.18 |
[IntelliJ] gradle project 생성 시 불필요한 파일들이 생기는 현상 (0) | 2022.09.02 |
OAuth vs OpenID (0) | 2022.08.31 |
[OAuth] 슬랙 로그인 구현하기 (5) | 2022.07.31 |