티스토리 뷰
git revert에 대해
commit
을 잘못한 경우
git commit을 잘못남겼을 때, 보통 어떻게 하는가?
- 나는 보통
git reset
또는git rebase
를 통해 commit을 제거(drop)했고, - 이를
force push
(--force
)함으로써 branch를 관리했다.
하지만 이 방식은 협업 시, 문제를 초래할 수 있다. (로컬에서만 사용하는 것은 문제 없음)
force push
된 branch에서 작업하던 다른 사람들은pull
시에 충돌(Conflict)이 발생할 수 있고, 이를 해결해야 한다. 이를 방지하기 위해서는 작업하던 사람들이 사용하던 branch 내역을 지우거나 백업해두고pull
해야만 한다.- 혹은 pull 받을 때 충돌없이 알아서 rebase 될 수 있는데, 이게 협업한 사람이 제거해서는 안 될 commit을 제거한 경우라면 해당 commit 기록을 다시 복원할 방법이 없다. 로컬에서 해당 커밋을 갖고 있는 누군가를 찾아다녀야 한다 😂
- 협업 하던 사람이 1명이여도 위 과정은 진짜 불편하다(이걸 협업이라고 할 수 있을까? 정도). 근데 보통 팀은 1명이 아니다. 10명, 20명, … 100명 이상이 될 수도 있다. 근데 위 과정처럼
force push
했다고 하자. 100명이 이를 로컬에서 다 관리/처리해야만 하는 것이다.
왜 이러한 문제가 발생할까?
git reset
,git rebase
는 commit 기록을 아예 제거해버린다는 것에 있다.- 즉, 과거에 대한 기록을 제거하는 것이다.
난 이게 git의 목적에 맞는 것인지는 모르겠다 (사용해야만 하는 경우가 있긴 하지만).
기록, 버전관리를 위해 만들어진 툴에서 기록을 제거한다니… 마치 사관이 역사 기록을 하던 가운데 중간 중간 제거하는 느낌이라서 조금 어색하다. 뭔가 하지 말아야 하는 행동을 하는 느낌…?
- 뭔가 실수한 내역을 지우고, 깔끔한 branch 관리를 위해 필요하다고 하자.
- 그런 실수한 내역 또한 기록이지 않을까?
- ex) 과거에 이러한 실수가 있었군.
- → 이러한 실수를 반복하면 안되겠구나.
- → 이러한 실수는 왜 했을까? 하지 않으려면 어떻게 해야할까?
- ex) 과거에 이러한 실수가 있었군.
근데 위는 그냥 생각일 뿐이고, git이 아닌 협업툴(github, gitlab 등)에서는 사용해야만 하는 경우가 있다.
1. 보안적으로 위험한 commit이 push 된 경우
Public repository에 Secret key가 노출된 커밋이 올라간다면 위험한 일이 벌어질 수 있다.
이런 경우는 이후 설명할 revert가 아닌 reset/rebase로 commit 자체를 제거해주어야 한다. 사실 Public 뿐만 아니라 Private repository 또한 그렇다. Private repository라고 Secret key를 노출된 채로 올리는 것은 보안적으로 위험한 행위이다.
추가로 Pull request에 secret key가 commit으로 노출되면 force push로도 이력이 완벽히 제거되지 않는다 (어느 commit hash에서 force push 됬는지 이전 커밋의 기록이 남음).
이런 경우 Pull request 기록 자체를 제거해야하는데, 혼자 할 수 있는 방법은 없고 github 측에 메일을 보내 요청해야 한다. 이런 경우, secret key를 무효화/변경하는 방법이 훨씬 안전하다.
ex) 당근마켓 블로그 예제가 있길래 예제 추가 (링크). force push 해도 기록이 남아있다.
2. 협업 convention 인 경우
오픈소스에서는 수 많은 사람들이 함께 개발하기에 Branch/Commit을 깔끔하게 유지하는 것이 관리하는데 큰 도움이 될 수 있다 (Squash merge처럼).
이런건 보통 Repository 내 Contriubuting.md
파일을 참조하면 알 수 있다.
예를 들어, Kubernetes docs website repository에서는 Squash commit을 통해 PR - commit을 깔끔히 관리한다. (즉, 이런 곳에서는 PR에 대해 Maintainer가 revert 하지말고 reset/rebase를 통해 커밋기록을 지워달라 요청할 수 있다)
오픈소스 뿐 아니라 회사/프로젝트 개발 팀 convention이 있는 경우도 있다.
3. 혼자 개발하는 경우
혼자 feature를 개발하는데 Branch/Commit을 깔끔하게 유지하고 싶은 경우에는 사용에 아무런 문제가 없다.
다시 돌아와서 그럼, 앞선 reset/rebase의 협업 시 문제 부분을 어떻게 해결할 수 있을까?
git revert
그럼, 이러한 문제는 어떻게 해결할 수 있을까?
git revert
를 사용하면 된다.
git revert
는 commit 기록을 제거하는 기록을 남기는 작업이다.
git reset
,git rebase
와 비교하면- reset, rebase는
기록을 제거하는 것
- revert는
기록을 제거하는 과정을 기록하는 것
- reset, rebase는
- 즉, 기존 commit 기록을 제거하지 않고 새로운 commit으로 기존 commit을 제거하는 과정을 기록하니 여러 사용자들과 협업할 때 충돌(Conflict)이 발생하지 않는다.
- 기존 commit 기록은 그대로 유지되고, 단순히 새로운 commit 기록이 생긴 것이므로 충돌이 발생하지 않는다.
Example
예시를 보자.
일단 test1~5 까지의 5개 파일을 추가했고, 각 파일을 추가할 때마다 commit한 상황이다.
$ git log
* 62bf919 - (HEAD -> main) test5 (8 seconds ago)<kimbb>
* e0b14d1 - test4 (19 seconds ago)<kimbb>
* 160448d - test3 (42 seconds ago)<kimbb>
* a1beb63 - test2 (49 seconds ago)<kimbb>
* 94c6296 - test1 (57 seconds ago)<kimbb>
$ ls
-rw-r--r-- 1 user staff 0 3 14 20:18 test1
-rw-r--r-- 1 user staff 0 3 14 20:18 test2
-rw-r--r-- 1 user staff 0 3 14 20:18 test3
-rw-r--r-- 1 user staff 0 3 14 20:18 test4
-rw-r--r-- 1 user staff 0 3 14 20:18 test5
여기서 test3을 추가했던 commit을 revert 해보자.
$ git revert 160448d
[main bddc0e4] Revert "test3"
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 test3
$ git log
* bddc0e4 - (HEAD -> main) Revert "test3" (34 seconds ago)<kimbb>
* 62bf919 - test5 (48 seconds ago)<kimbb>
* e0b14d1 - test4 (59 seconds ago)<kimbb>
* 160448d - test3 (82 seconds ago)<kimbb>
* a1beb63 - test2 (89 seconds ago)<kimbb>
* 94c6296 - test1 (57 seconds ago)<kimbb>
$ ls
-rw-r--r-- 1 user staff 0 3 14 20:18 test1
-rw-r--r-- 1 user staff 0 3 14 20:18 test2
-rw-r--r-- 1 user staff 0 3 14 20:18 test4
-rw-r--r-- 1 user staff 0 3 14 20:18 test5
위에서 볼 수 있듯 git revert 하는 법은 매우 쉽다. 되돌리고(취소하고) 싶은 commit의 hash 값을 git revert
명령어로 넘겨주기만 하면 된다.
revert commit이 새로 추가되었고, test3 파일이 제거된 것을 볼 수 있다.
- commit 메시지는 revert 시에 commit 하면서 변경할 수 있다.
- default로는 위의 revert commit 메시지처럼
Revert "{message of revert commit}"
이다.
reset, rebase를 사용했다면 새로운 Commit이 생겨나지 않고, test3 commit만 제거할 수 있을 것이다. 하지만 github 같은 git platform을 이용해 협업하는 과정이라면 글 초반에 언급한 문제들이 발생할 수 있다.
만약 revert 작업을 바로 commit 하길 원하지 않는다면 --no-commit
(-n
) 옵션을 사용하자.
$ git revert --no-commit a1beb63
$ git status
On branch main
Revert "Revert "test3""
You are currently reverting commit a1beb63.
(all conflicts fixed: run "git revert --continue")
(use "git revert --skip" to skip this patch)
(use "git revert --abort" to cancel the revert operation)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: test2
$ git log
* bddc0e4 - (HEAD -> main) Revert "test3" (34 seconds ago)<kimbb>
* 62bf919 - test5 (48 seconds ago)<kimbb>
* e0b14d1 - test4 (59 seconds ago)<kimbb>
* 160448d - test3 (82 seconds ago)<kimbb>
* a1beb63 - test2 (89 seconds ago)<kimbb>
* 94c6296 - test1 (57 seconds ago)<kimbb>
$ git commit -m 'Revert "test2"'
$ git log
* 8567c55 - (HEAD -> main) Revert "test2" (22 seconds ago)<kimbb>
* bddc0e4 - Revert "test3" (61 seconds ago)<kimbb>
* 62bf919 - test5 (48 seconds ago)<kimbb>
* e0b14d1 - test4 (59 seconds ago)<kimbb>
* 160448d - test3 (82 seconds ago)<kimbb>
* a1beb63 - test2 (89 seconds ago)<kimbb>
* 94c6296 - test1 (57 seconds ago)<kimbb>
여러 개의 연속적인 commit을 revert하고 싶다면 commit hash 사이에 ..
을 이용해 연결해주면 된다.
$ git revert 62bf919..8567c55
[main 80b32a8] Revert "Revert "test2""
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test2
[main 90b97dc] Revert "Revert "test3""
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test3
$ git log
* 90b97dc - (HEAD -> main) Revert "Revert "test3"" (4 seconds ago)<kimbb>
* 80b32a8 - Revert "Revert "test2"" (5 seconds ago)<kimbb>
* 8567c55 - Revert "test2" (42 seconds ago)<kimbb>
* bddc0e4 - Revert "test3" (61 seconds ago)<kimbb>
* 62bf919 - test5 (48 seconds ago)<kimbb>
* e0b14d1 - test4 (59 seconds ago)<kimbb>
* 160448d - test3 (82 seconds ago)<kimbb>
* a1beb63 - test2 (89 seconds ago)<kimbb>
* 94c6296 - test1 (57 seconds ago)<kimbb>
{a}..{b}
을 진행한다고 하면,
- a commit은 포함되지 않고 그 이후 commit부터 b commit까지 revert 된다.
- 연속적인 commit을 revert 시에 시간 역순으로 revert commit이 남게 된다.
- {a+1} ~ {b}라면
revert b
, … ,revert a+1
순으로 revert commit이 남는다.
- {a+1} ~ {b}라면
연속적인 n개의 commit을 revert하면 n개의 revert commit이 남는다.
revert commit이 너무 많이 남는 것이 싫다면, --no-commit
(-n
) 옵션을 사용해 하나의 revert commit으로 모을 수 있다.
$ git revert -n 8567c55..90b97dc
$ git status
On branch main
You are currently reverting commit 80b32a8.
(all conflicts fixed: run "git revert --continue")
(use "git revert --skip" to skip this patch)
(use "git revert --abort" to cancel the revert operation)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: test2
deleted: test3
$ git commit -m "Revert some commits"
$ git log
* ab6f190 - (HEAD -> main) Revert "Revert some commits" (10 seconds ago)<kimbb>
* 90b97dc - Revert "Revert "test3"" (42 seconds ago)<kimbb>
* 80b32a8 - Revert "Revert "test2"" (42 seconds ago)<kimbb>
* 8567c55 - Revert "test2" (42 seconds ago)<kimbb>
* bddc0e4 - Revert "test3" (61 seconds ago)<kimbb>
* 62bf919 - test5 (48 seconds ago)<kimbb>
* e0b14d1 - test4 (59 seconds ago)<kimbb>
* 160448d - test3 (82 seconds ago)<kimbb>
* a1beb63 - test2 (89 seconds ago)<kimbb>
* 94c6296 - test1 (57 seconds ago)<kimbb>
$ ls
-rw-r--r-- 1 user staff 0 3 14 20:18 test1
-rw-r--r-- 1 user staff 0 3 14 20:18 test4
-rw-r--r-- 1 user staff 0 3 14 20:18 test5
Github에서는 Pull Request(PR)의 Revert를 쉽게 할 수 있도록 지원한다.
PR이 머지된 이후 아래 같은 로그가 남는데, 버튼 중 Revert
를 누르면 해당 PR 작업의 Revert commit PR을 바로 생성할 수 있다.
이에 대해 당근마켓 팀 블로그에서 내부동작을 자세히 다뤘다. 아래 글도 참고해보면 좋을 것 같다.
'Development' 카테고리의 다른 글
우리 PostgreSQL은 언제부터 이뻤나? (0) | 2023.08.11 |
---|---|
[실용주의 프로그래머] 동시성이란 (1) | 2023.04.23 |
Javascript에서의 물음표(?) 사용 (0) | 2023.02.23 |
인증(AuthN)과 인가(AuthZ)에 대한 이야기 (0) | 2022.06.12 |
Pagination(Paging), offset을 사용하지 맙시다 (2) | 2022.06.12 |
- Total
- Today
- Yesterday
- 클린 아키텍처
- 일상
- MySQL
- 비동기
- Spring boot
- Intellij
- python
- OpenTelemetry
- container
- Istio
- 하루
- jasync
- tag
- Clean Architecture
- docker
- boj
- 로그
- c++
- 알고리즘
- gradle
- Algorithm
- Spring
- HTTP
- Log
- 쿠버네티스
- Kubernetes
- k8s
- WebFlux
- java
- 백준
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |