2023. 4. 23. 18:19ㆍGit
작업 트리를 수정하는 방법들을 설명한다.
이번 포스팅에서는 Git의 살짝 고급(?) 기술을 소개한다.
혼자서 개발하다보면 작업 트리를 수정할 일이 많지 않지만 협업을 하게 된다면 얘기가 달라진다.
작업 트리가 깔끔해야 하는 상사를 만날 수도 있고, Commit convention을 굉장히 중요시하는 팀에서 일할 수도 있기 때문이다.
(보통 Commit convention이 안 중요하다는 말은 아니다)
시작해보자
Git에서 작업한 내용 되돌리기
작업한 내용을 되돌리는 방법은 크게 두 가지가 있다.
1. git reset
2. git revert
먼저 git reset은 현재 Branch가 가리키는 Commit을 바꾼다.
마치 처음부터 commit을 하지 않은 것처럼 이전 Commit으로 Branch를 옮기는 것이다.
이는 실제 작업 트리에서 해당 Commit이 아예 삭제된다는 뜻이다.
git reset HEAD~2
위 명령어를 실행하면 다음과 같다.
실제 작업 트리에서 Commit이 아예 삭제된다는 점은 굉장히 위험할 수 있다.
여러 개발자와 협업하는 상황에서 reset으로 Remote Branch의 Commit을 함부로 날린다면
해당 Commit에서 작업하고 있던 다른 개발자들이 혼돈의 도가니에 빠질 수 있기 때문이다.
이런 혼란을 막기 위해서 git revert 명령어를 사용하면 된다.
git revert 명령어는 작업한 내용을 되돌리고, 되돌린 내용을 협업하는 개발자들과 공유 할 수 있다.
git revert HEAD
위 명령어를 실행하면 아래 이미지와 같다.
revert는 reset과 달리 대상 Commit을 작업 트리에서 삭제하지 않는다.
반대로 되돌리려고 한 Commit의 아래에 새로운 Commit이 생성된다.
Image 2를 보면 생성된 M3` Commit의 변경내역이 정확히 M3 Commit 내용의 반대의 내용으로
코드는 M2 Commit과 같은 상태라고 할 수 있다.
Cherry-pick
다른 Branch의 Commit을 선택하여 현재 작업 Branch(HEAD)에 복사해오는 명령어다.
git cherry-pick <Commit 1> <Commit 2> <...>
위처럼 parameter로 복사해오고 싶은 Commit들을 넘기면 해당 Commit들을 현재 작업 Branch로 복사해온다.
-----------------------현재 main branch--------------------------
git cherry-pick F2 F3
위 명령어를 실행시키면 아래 이미지(Image 4)처럼 동작한다.
Git interactive rebase
작업 트리 수정의 끝판왕이 바로 interactive rebase다.
이전 포스팅(Part 1)에서는 git merge 와 git rebase를 비교하면서 Commit을
병합하는 방법의 하나로 소개했다.
하지만 -i 옵션을 붙였을 때는 다양하게 Commit history를 수정할 수 있다.
git rebase -i HEAD~4
rebase는 위 명령어처럼 사용할 수 있다.
명령어를 실행하면 아래 이미지와 같은 내용을 볼 수 있다.
현재 가리키고 있는 HEAD 위에서부터 네 개의 Commit이 보이고,
앞에 pick이라는 단어를 볼 수 있다. 뿐만 아니라, 그 밑에 Commands 아래로 사용할 수 있는 여러 명령어를 보여준다.
이러한 명령어를 이용하여 HEAD~4 의 Commit을 수정, 삭제, 병합, 순서이동 등 대상 Commit에 대해 Interactive하게 수정할 수 있다.
여러 명령어가 있지만 그나마 사용하기 쉬운 명령어들만 설명한다.
그럼, 각 명령어가 어떻게 동작하는지 알아보자.
pick은 Commit을 그대로 사용하거나 다른 Commit과 순서를 바꿀 수 있다.
위 이미지(Image 5)에서 볼수 있듯이 rebase -i 명령어를 실행하면 기본값으로 각 Commmit은 pick으로 세팅되어있다.
편집 없이 종료한다면 작업 트리에 아무런 변화가 없고, 커밋의 순서를 바꾸거나 해당 라인을 지우고 종료하면 작업 트리에 변화를 줄 수 있다.
시도해보자
git rebase -i HEAD~4
fa523e7(second commit) 41916d9(third commit)의 순서를 바꾸고 vim을 저장하고 종료해보자
rebase가 끝난 후 작업 트리를 보면 second commit과 third commit의 순서가 바뀌었다. 뿐만 아니라 second commit과 third commit의 Commit id도 바뀐 것을 볼 수 있다.
Git이 rebase 할때 새로운 Commit을 생성한다는 것을 알수있다.
reword는 Commit의 commit message를 수정할 수 있다.
메세지를 변경하고 싶은 Commit에 reword 명령어를 입력하고 종료하면
아래 이미지처럼 메세지를 변경할 수 있는 vim을 볼 수 있다.
edit은 Commit message 뿐만 아니라 작업 내용도 수정할 수 있다.
위 이미지(Image12)와 같이 edit으로 세팅한 후 vim을 종료하면 reword 때와는 다르게 vim이 종료되고 아무것도 실행되지 않는다. 이때 git status 명령어를 실행해보면 아래 이미지(Image13)의 내용을 볼수 있다.
내용을 보면 현재 interactive rebase가 진행중이며
“git commit — amend”나 “git rebase — continue” 명령어를 사용할 수 있는것처럼 보인다.
“git commit — amend” 명령어를 실행하면 위에서 설명했던 reword 명령어를 실행했던거처럼 Commit message를 수정 할 수 있다.
“git rebase — continue” 명령어를 실행하면 진행 중인 rebase를 종료할 수 있는데, 그 전에 Commit을 추가 할 수 있다. 추가된 Commit은 second commit과 firth commit 사이에 위치한다.
squash, fixup은 Commit을 이전 Commit과 합친다.
두 명령어 모두 이전 Commit과 대상 Commit을 병합하는데 차이점이 있다면
squash는 Commit message까지 합쳐진다. 반면에 fixup은 이전 Commit의 메세지만 남겨진다.
먼저 squash를 시도해보자
squash로 수정한 후 vim을 저장 후 종료하면 아래와같은 vim을 볼 수 있다.
target으로 잡았던 Commit의 message는 ignored되고, 이전 Commit에 합쳐진다는 내용이다.
vim을 저장하고 종료해보자.
squash했던 Commit은 이전 Commit인 “second commit by rebase edit!!!!!”과 병합되고 Commit message도 합쳐진다.
(병합된 message가 줄바꿈이 되어있어 아래 작업 트리에서는 보이지 않는다)
이번엔 fixup을 시도해보자.
이번에도 대상이 된 Commit의 이전 Commit에 병합되겠지만 squash와 다르게 commit message는 사라진다.
drop은 Commit을 삭제한다.
drop 명령어로 세팅하고 vim을 저장 후 종료하면 해당 Commit은 작업 트리에서 삭제되어버린다.
주의사항
Git 공식 문서에는 다음과 같이 쓰여있다.
“이미 공개 저장소에 Push 한 커밋을 Rebase 하지 마라”
pick 명령어를 설명할 때에도 한번 언급했던거처럼 rebase는 기존 Commit과 내용은 같지만 새로 만들어진 Commit이다.
팀원들이 작업하고 있던 브랜치를 rebase 하면 새로운 Commit으로 대체될 것이고, 팀원들의 커밋 히스토리가 엉망이 될수 있다.
따라서 rebase는 로컬 저장소의 Commit을 대상으로만 사용하는것이 좋겠다.
Part 3에서는 작업 트리를 수정하는 방법을 소개했다.
Git의 기본 명령어(Part 1)부터 작업 트리를 수정할 수 있다면 실제 프로젝트를 진행할 때 Git때문에 골치아플일은 없을것이라고 생각한다.
** 사실과 다른 게 있다면 언제든지 조언 부탁드립니다.
'Git' 카테고리의 다른 글
[Git] 깃 실속있게 정복하기 Part 2 (0) | 2023.04.23 |
---|---|
[Git] 깃 실속있게 정복하기 Part 1 (0) | 2023.04.23 |