Hou bio photo

Hou

웹/자바 개발자

얼마전 사내 깃 교육을 들었다. 유익했지만 대부분 알고있고 정작 내가 궁금한 내용들은 시간이 없어서 듣지 못해서 pro git을 보면서 포스팅 하려한다.

최근 커밋 수정하기

프로젝트하면서 깃과 관련한 가장 필요한 욕구가 아니였나 싶다. 이상한 파일을 잘못 커밋했을 때 혹은 맥에서는 뒤에 한글자가 빠져서 커밋되는 경우가 많았는데 이 때 정말 필요했었다. 이러한 경우 –amend 옵션을 쓰면 된다.
잘못된 commit을 한 후 수정해보자. git 명령어를 기준으로 설명하자면

git commit -m "first commit" // 잘못된 커밋이다. 
git add forgotten_file // 이전 커밋에서 놓친 파일이나 변경내용을 staging상태에 더 해준다.
git commit --amend // amend 명령어를 입력하면 이전 commit에 관한 창이 뜬다. 거기서 commit msg를 수정해주면 이전 커밋을 변경할 수 있다.

만약 remote 브런치에도 이미 푸쉬한 상태라면 어떨까? 소스트리를 쓰는 경우 한번에 푸쉬까지 해버리는 경우가 많아서 자주 일어나는 일이다. amend 후에 리모트 브런치에 푸쉬를 해보면 이전 staging과 달라서 non-fast forward 에러가 난다. 이럴 땐 –force 옵션을 주어서 푸쉬를 하면 수정가능하다.

amend 명령어는 바로 이전 커밋에 한해서만 수정이 가능하다. 그 전 커밋에 대하여 완벽하게 수정하는 방법은 사실 없다.

rebase를 이용한 수정

위에서 완벽한 방법은 없다고는 했지만 어느정도 우회하는 방법은 있다. 이미 여러개의 커밋을 한 뒤라면 interactive rebase를 이용해 이전 커밋들에 대하여 수정이 가능하다. 시나리오를 보자면 commit1, 2, 3이라는 이름으로 순서대로 3개의 커밋을 한 상태이다. 이 중 commit1과 2를 수정할 예정이다. git reabse -i 를 이용해서 해드의 부모를 수정하고자하는 가장 빠른 커밋의 부모를 넘겨준다. 마지막 3개 커밋을 수정할 것이기 때문에 ~3으로 넘겨준다.

git rebase -i HEAD~3

그럼 아래와 같은 편집기가 열린다. 가장 먼저 한 커밋부터 순서대로 표시되어 있다.(로그의 역순) 이 상태에서 편집기를 종료하면 아무런 변화도 일어나지 않는다. 수정을 하려면 수정하고자하 하는 커밋의 앞 단어를 바꿔 주어야 한다. 현재는 pick이라고 되어있는데 이 단어를 edit로 고치게 되면 이 커밋을 수정하겠다라는 뜻이 된다.

pick 606f7b7 commit1
pick 4fe5602 commit2
pick 31fc57e commit3

# Rebase 717c2ea..31fc57e onto 717c2ea (       3 TODO item(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

두개의 커밋을 수정한다고 해놓고 편집기를 종료해보자.

edit 606f7b7 commit1
edit 4fe5602 commit2
pick 31fc57e commit3

그러면 아래와 같은 메시지가 뜬다.

topped at 606f7b796717f324f1bc74debe2a2e1030431a8d... new `1
You can amend the commit now, with

    git commit --amend

Once you are satisfied with your changes, run

    git rebase --continue

메시지에 있는대로 git commit –amend와 git rebase –continue를 진행하면 된다. 여기서 주의할것은 리베이스는 edit으로 변경한 커밋순서대로 이루어진다는 점이다. 그래서 먼저 commit1에 관한 리베이스가 진행되고 continue를 하면 다음 commit2에 관한 rebase가 진행된다. git commit –amend는 처음에 살펴본대로 커밋을 수정 할 수 있다. 즉 amend 명령어를 호출하기 전까지 commit을 변경 할 수 있다. 파일을 추가하거나 변경한 후 git add 로 stage 상태에 추가, git commit –amend로 메시지를 변경한 후 git rebase –continue를 진행하여 commit2에 관한 수정으로 넘어간다. 같은 과정으로 commit2에 관한 rebase를 완료하면 아래 메시지를 볼 수 있다.

Successfully rebased and updated refs/heads/.

커밋 수정 뿐만 아니라 이전 커밋들을 합칠 수도 또는 나눌 수도 있다. interactive rebase에서 커밋의 순서를 변경하면 커밋순서가 변경되고 edit대신 squash를 입력해주면 이전 커밋과 머지 할 수 있도록 편집기를 띄워준다.

pick 606f7b7 commit1
squash 4fe5602 commit2
squash 31fc57e commit3

sourceTree에서는 변경하고자 하는 커밋의 바로 전 커밋에서 마우스 오른 쪽을 클린한 후 rebase children … interactive를 클릭 해보면 위에서 설명한것과 같은 비슷한 ui를 볼 수 있다.



마치면서 주의할 점은 rebase가 현재 HEAD로 부터의 커밋들이 아닌 이미 머지했거나 한참뒤의 커밋을 수정하려고 하면 브런치가 꼬여버리게 된다. 그래서 아직 머지 하지 않은 최근 커밋을 수정 할 때 사용해야 할 것이다.

  • 참고 : pro git

comments powered by Disqus