Git 에서 여러개의 최근 commit들을 하나로 합치고 싶을 때가 있다. (지저분하다든가 부끄럽다든가...)
이 작업은 일반적으로 Squash 라고 불린다.
Squash
먼저 이 squash 를 어떻게 하는지 알아보자.
테스트를 위해 git local repository 를 만들고 아래와 같이 3개의 commit 을 하였다.
$ git log
commit e5af3cb2f5d1c2361a76ed903792fb1e186b8058
Author: mayTree <nallwhy@gmail.com>
Date: Tue Jun 21 15:36:09 2016 +0900
Bye
commit 9e675948b6580864e8ab2e8b63789ef6af6bf5dd
Author: mayTree <nallwhy@gmail.com>
Date: Tue Jun 21 15:35:19 2016 +0900
Add title to a.md
commit be86009abcc7701dc30d8972b6d65bb088dec556
Author: mayTree <nallwhy@gmail.com>
Date: Tue Jun 21 15:29:01 2016 +0900
init여기서 최근 2개의 commit 을 squash 하려면 interactive rebase 를 실행한다.
$ git rebase -i HEAD~2 // HEAD~2는 HEAD로부터 2개의 commit 을 의미한다 pick 9e67594 Add title to a.md pick e5af3cb Bye // 이 라인의 pick 을 squash 로 변경 # Rebase be86009..e5af3cb onto be86009 (2 command(s)) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # d, drop = remove commit # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out
아래 주석은 rebase 사용에 대한 내용이고, 위의 두 줄을 보면 시간 순서대로 commit 이 나열되어있다.
앞의 9e67594 commit 이 주가 되고 뒤에 있는 e5af3cd commit 을 합쳐버릴 것이기 때문에 e5af3cd 앞에 있는 pick 을 squash 로 변경하고 :x (vi 에서 저장하고 나가기) 로 종료한다.
그러면 아래와 같은 내용이 출력된다.
# This is a combination of 2 commits. # The first commit's message is: Add title to a.md # This is the 2nd commit message: Bye # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # Date: Tue Jun 21 15:35:19 2016 +0900 # # interactive rebase in progress; onto be86009 # Last commands done (2 commands done): # pick 9e67594 Add title to a.md # squash e5af3cb Bye # No commands remaining. # You are currently editing a commit while rebasing branch 'master' on 'be86009'. # # Changes to be committed: # modified: a.md #
여기서 두 commit 을 합쳐서 생긴 새 commit 의 message 를 작성할 수 있다.
저 부분에서 주석 빼고는 다 message 에 들어가기 때문에 지금은
Add title to a.md Bye
라고 작성이 될 것이고, 바꾸고 싶으면 원하는 대로 편집하면 된다.
앞에서처럼 작성하고 나가면 아래와 같은 결과가 출력되며 commit 이 합쳐진 것을 확인할 수 있다.
[detached HEAD 66ba47b] New commit! // 새로 작성한 commit message Date: Tue Jun 21 15:35:19 2016 +0900 1 file changed, 2 insertions(+) Successfully rebased and updated refs/heads/master.
Remote repository 에 squash 한 commit push 하기
아무도 squash 한 commit 들을 pull 하지 않았다는 가정 하에 이 작업이 수행되어야 한다. 누군가 이미 해당 commit 들을 pull 했는데 그것을 rebase 를 통해 수정하고 commit 하면 큰일 날 수 있다.
이미 remote repository 에 squash 하지 않은 commit들을 push 했을 경우, squash 한 commit 을 push 하면 거부 당한다.
위에 얘기한 대로 다른 사람이 이미 변경 전 commit 들을 pull 한 경우 꼬여버릴 수 있기 때문.
대표적으로 이러한 squash 작업이 필요한 경우가 Open Source repository 를 fork 해서 수정한 후에 pull request 를 날렸는데 수정요청이 들어올 때이다.
Pull request 가 여러개의 commit 으로 이루어지게 되면 중간에 완성되지 않은 commit 이 존재하는 것이기 때문에 관리상에 어려움이 생길 수 있다. 이를 방지하기 위해 squash 를 통해 제대로 동작하는 하나의 commit 으로 만들어 주는 것이 좋다.
Fork 해온 repository 는 어짜피 나만 수정하는 것이기 때문에 아무도 pull 을 해갔을리 없으니 꼬일 걱정 없이 강제로 push 할 수 있다.
주저리주저리 이야기 했지만 방법은 간단하다.
$ git push origin <branch-name> --force
쓰여진 그대로 강제로 push 해버리면 된다.
끝.
참조
https://git-scm.com/book/ko/v1/Git-도구-히스토리-단장하기
JinKyou Son님의 창작활동을 응원하고 싶으세요?
