interactive rebase 사용해 이전 커밋 조작하기
앞선글에서 git rebase를 이용해 rebase 대상 브랜치의 commit history를 새로 만드는 것을 살펴보았다. commit history를 새로 만들 수 있다는 것은 현재 시점 이전에 생긴 커밋들을 조작할 수 있다는 것이다. git rebase는 interaction 모드인 -i 옵션을 이용해 커밋 히스토리를 합칠 수 있는 기능을 제공한다. git을 사용하다 보면 이전 커밋들을 합치고 싶은 경우가 생기는데, 그 때 이 기능을 사용하면 된다.
git rebase -i 를 사용해 커밋 메세지를 수정하기 위해서는 다음 명령어를 사용하면 된다. HEAD~n 은 HEAD 커밋으로부터 n 번째 까지의 커밋을 수정한다는 뜻이다.
git rebase -i HEAD~n
예를 들어 git rebase -i HEAD~2 와 같이 사용하면 HEAD로부터 2번째까지의 커밋을 수정할 수 있다.
$ git rebase -i HEAD~2
pick 949d10a cc
pick 0b9b467 main cc
여기에는 다음과 같은 여러 옵션이 있다. 이번 글에서는 가장 자주 사용하는 reward와 fixup, drop만 사용할 것이다.
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified); use -c <commit> to reword the commit message
#
# These lines can be re-ordered; they are executed from top to bottom.
reward 키워드 사용해 커밋 메세지 수정하기
위의 파일의 pick을 다음과 같이 reward로 수정한 후에 저장하면
reward 949d10a second commit
pick 0b9b467 main cc
git 에 변경사항이 생겨 add가 필요해진다. 이에 대해 add하고 해당 커밋을 하면 해당 커밋의 메세지가 수정된다.
➜ demo-page git:(949d10a) ✗ git status
대화형 리베이스 진행 중. 갈 위치는 ead0a3e
최근 완료한 명령 (2개 명령 완료):
pick 949d10a second commit
pick 0b9b467 main cc
명령이 남아있지 않음.
현재 'main' 브랜치를 'ead0a3e' 위로 리베이스하는 중입니다.
(충돌을 바로잡고 "git rebase --continue"를 사용하십시오)
(이 패치를 건너뛰려면 "git rebase --skip"을 사용하십시오)
(원본 브랜치를 가져오려면 "git rebase --abort"를 사용하십시오)
병합하지 않은 경로:
(use "git restore --staged <file>..." to unstage)
(해결했다고 표시하려면 "git add <파일>..."을 사용하십시오)
양쪽에서 추가: cc
커밋할 변경 사항을 추가하지 않았습니다 ("git add" 및/또는 "git commit -a"를
사용하십시오)
➜ demo-page git:(949d10a) ✗ git add cc
➜ demo-page git:(949d10a) ✗ git commit -m "rebase -i commit"
로그를 확인해보면 다음과 같이 나온다.
$ git log --oneline
9a60ea6 (HEAD) rebase -i commit
949d10a cc
fixup 키워드 사용해 커밋 합치기
fixup 키워드를 사용하면 이후 커밋에 이전 커밋을 합칠 수 있다. 예를 들어 아래와 같이 fixup을 사용하면 이전 커밋인 9a60ea6 이 사라지고 cc 메세지에 해당하는 커밋에 합쳐진다.
$ git rebase -i HEAD~2
pick 949d10a cc
fixup 9a60ea6 rebase -i commit
히스토리가 새로 만들어지므로 cc의 커밋 해시값은 바뀐다. 위의 커밋 해시값은 949d10a였는데 바뀐 해시값은 c5739b4인 것을 확인할 수 있다.
git log --oneline
c5739b4 (HEAD -> main) cc
*다음처럼 fixup 키워드는 한 번에 여러 커밋에도 사용할 수 있다. 그러면 커밋들이 모두 하나의 커밋으로 합쳐진다.
$ git rebase -i HEAD~3
pick 949d7ba delete commit
fixup 9aabea6 delete one more xml
fixup ea60ea6 delete xml
drop 키워드 사용해 커밋 지우기
drop 키워드를 사용하면 특정 커밋을 지울 수 있다. 예를 들어 아래와 같이 drop을 사용하면 first commit이 사라진다.
$ git rebase -i HEAD~2
drop 9a60ea6 first commit
pick 949d10a head commit
interaction rebase 사용 시 주의할 점
interaction rebase 또한 rebase이므로 커밋 히스토리를 처음부터 끝까지 다시 쓰는 것이다. 이로 인해 중간 시점의 커밋이 바뀔 경우 그 이후 커밋들에 대한 해시값이 바뀌게 된다. 따라서 협업하는 브랜치에 대한 rebase 사용은 신중에 또 신중을 기해야 한다. 다른 사람들의 커밋 해시값과 내 커밋 해시값이 다르면 메세지가 같더라도 깃 시스템 상에서는 다른 커밋으로 인식하기 때문이다.