다시 시작하는 Git/GitHub - 커밋 변경편

Hyuno Choi·2021년 5월 1일
0
post-thumbnail

2021년 5월 1일

Git을 사용하면서 가장 많이 하는 것이 커밋을 만드는 일이고, 그렇기 때문에 그 내용이나 단위에서 실수를 범할 때가 많습니다. 그럴 때마다 열심히 구글링을 하며 커밋을 되돌릴 방법을 찾는데요, 이번에는 지난 포스팅 마지막 부분에 적었던 커밋을 수정하는 방법을 확장하여 커밋 변경 방법에 대해 확실히 정리해보려고 합니다.

commit --amend

이번에도 Git을 시각적으로 보여주는 연습 툴을 통해 설명하겠습니다.

커밋 두 개가 있습니다. 이제 지금 하던 작업도 저장하고 세 번째 커밋으로 추가하려고 합니다. 그런데 다시 생각해보니, 두 번째 커밋을 조금 성급하게 만들었던 것 같습니다. "두 번째 커밋과 지금 작업하고 있는 내용을 합쳐서 하나의 커밋으로 만들었다면 더 좋았을텐데" 하고 후회합니다.

이럴 때 사용할 수 있는 커밋 옵션이 바로 --amend입니다. 이 옵션을 사용하게 되면 현재 추가한 라인을 이전 커밋에서 추가되었던 라인과 합쳐 하나의 커밋으로 만들어줍니다.

$ git commit --amend를 실행한 모습입니다. 이전 커밋과 현재 작업 내용이 합쳐저 하나의 커밋으로 만들어진 것을 볼 수 있습니다.

실습도 같이 해보겠습니다. test라는 디렉토리를 만들고 그 안에 script.txt라는 파일을 생성해줍니다.

  1. 저는 first commit 커밋에서 첫 줄에 hello를 추가하고,
  2. Add second line 커밋에서 두 번째 줄에 hello world를 추가했습니다.
  3. $ git log 명령어로 커밋 이력을 보면 다음과 같은 이력이 보입니다.
$ git log
commit afdfbc21734f83befb42af3805bf9749d6c47929 (HEAD -> master)
Author: soonitoon <soonitoon@gmail.com>
Date:   Sat May 1 19:39:37 2021 +0900

    Add second line

commit e60ca783fc8a11fe4104ab8e4aa5d3a9a61204a7
Author: soonitoon <soonitoon@gmail.com>
Date:   Sat May 1 19:39:02 2021 +0900

    first commit
  1. 여기서 저는 세 번째 줄에 hello world!!를 추가합니다.

그런데 여기서 지금 만든 변경 사항을 세 번째 커밋으로 만드는 것이 아니라, 두 번째 커밋과 합치고 싶다고 가정합니다.

  1. 다음 두 명령어를 입력해 커밋을 진행합니다.
$ git add script.txt
$ git commit --amend

명령어를 입력하면 이렇게 커밋을 입력할 수 있는 Vim 편집기가 뜨게 됩니다. 두 번째 커밋과 현재의 변경사항이 합쳐진 새 커밋의 메시지를 작성할 수 있습니다.

Add second line

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Sat May 1 19:39:37 2021 +0900
#
# On branch master
# Changes to be committed:
#       modified:   script.txt
#

여기서는 커밋 메시지를 변경하지 않겠습니다.

  1. :wq를 순서대로 눌러 커밋을 완료합니다.

이제 모든 과정이 끝났습니다. $ git log 명령어를 통해 커밋 이력을 보면 커밋이 두 개밖에 없는 것을 볼 수 있습니다.

cherry-pick🍒

여러 브랜치에서 작업을 하다보면 특정 커밋만 하나 떼와서 다른 브랜치에 붙이고 싶을 때가 있습니다. 저는 브랜치 전환을 깜빡하고 커밋을 날려버릴 때가 종종 있는데요, 이런 상황에서 cherry-pick이 유용하게 쓰일 수 있습니다.

이제 cherry-pick이 필요한 상황을 가정해보도록 하겠습니다.

저는 master 브랜치에 checkout 해놓은 사실을 잊어버리고 issue 브랜치에 만들어야 할 커밋을 master 브랜치에 만들고 말았습니다. 현재 녹색으로 표시된 커밋을 그 커밋이라고 하겠습니다.

$ git checkout issue

명령어를 통해 커밋을 가져와 붙이고 싶은 브랜치로 이동합니다.

$ git cherry-pick 해당 커밋 아이디

다음과 같은 과정을 거치면 해당 커밋이 원하는 브랜치로 '복사'됩니다.

이후 reset이나 revert 등을 통해 master 브랜치에 남아있는 커밋을 제거하면 될 것입니다.

rebase -i

이 명령어는 $ git rebase -i HEAD~~와 같이 쓸 수 있고, 기능이 상당히 다양합니다.

# 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 <commit> = like "squash", but discard this commit's log message
# 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.

실제로 명령어를 실행해보면 이렇게 rebase -i의 기능을 상세히 설명해줍니다.

명령에 뒤에 붙은 HEAD~~는 수정할 커밋의 범위를 지정하는 데 사용됩니다. HEAD 뒤에 붙는 물결이 두 개 붙었으니 가장 최근에 만들어진 커밋과 그 다음 커밋까지가 범위에 들어가게 됩니다. 이번 포스팅에서는 커밋들을 하나로 합치는 방법과 커밋을 수정하는 방법에 대해 작성하겠습니다.

rebase -i를 활용한 커밋 합치기🍋🍹

우선 s, squash에 해당하는 커밋 통합부터 살펴보겠습니다. 커밋 이력을 쭉 보다보면 어떤 커밋들은 하나의 커밋일 때 조금 더 논리적으로 보일 때가 있습니다. 이런 경우에 squash를 활용해 커밋을 합칠 수 있습니다.

실습을 위해 예를 들어보겠습니다. 로그에 보이는대로 저는 커밋을 세 개 만들었고, add third lineadd second line 커밋과 통합하고 싶다고 가정합니다.

commit 6faff8a8a7ddefb4b893fac5df2f8663a49e06a5 (HEAD -> master)
Author: Hyuno Choi <hyunochoi@Hyunoui-MacBookPro.local>
Date:   Thu Jun 24 16:21:58 2021 +0900

    add third line

commit a73f93c0737a090919849dbe45345c0b14f465e7
Author: Hyuno Choi <hyunochoi@Hyunoui-MacBookPro.local>
Date:   Thu Jun 24 16:21:10 2021 +0900

    add second line

commit fbd7830e6f86ba988e48383a37b3aff36f638b8a
Author: Hyuno Choi <hyunochoi@Hyunoui-MacBookPro.local>
Date:   Thu Jun 24 16:19:23 2021 +0900

    first commit
$ git rebase -i HEAD~~

명령어를 입력해 rebase 모드로 진입합니다. 범위는 세 번째와 두 번째 커밋으로 합니다.

pick a73f93c add second line
pick 6faff8a add third line

# Rebase fbd7830..6faff8a onto fbd7830 (2 commands)
#
# 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 <commit> = like "squash", but discard this commit's log message
# 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.

명령어를 입력하면 해당 Vim 화면이 보이게 됩니다. 여기서 squash를 하는 방법은 간단합니다. 맨 위에 pick이라는 글자와 함께 범위에 해당하는 커밋이 보입니다. 여기서 통합하여 없애려는 커밋 앞의 pick을 지우고 그 자리에 squash를 입력하고 저장해주면 됩니다.

pick a73f93c add second line
squash 6faff8a add third line

이렇게 pick을 squash로 변경하고 esc키로 명령 모드 진입 후, :wq를 입력해 저장 후 종료합니다.

# This is a combination of 2 commits.
# This is the 1st commit message:

add second line

# This is the commit message #2:

add third line

그러면 이렇게 커밋 메시지를 새로 작성할 수 있는 편집기 창이 뜨게 됩니다. 적절한 메시지 작성 후 역시 명령 모드에서 wq를 입력하여 커밋을 마칩니다.

이제 $ git log 명령어로 로그를 확인하면 커밋이 통합된 것을 볼 수 있습니다. 저는 커밋 메시지를 수정하지 않고 커밋을 날렸습니다.

commit 18abb2c246bf9a1e656db31990b407730c706c21 (HEAD -> master)
Author: Hyuno Choi <hyunochoi@Hyunoui-MacBookPro.local>
Date:   Thu Jun 24 16:21:10 2021 +0900

    add second line

    add third line

commit fbd7830e6f86ba988e48383a37b3aff36f638b8a
Author: Hyuno Choi <hyunochoi@Hyunoui-MacBookPro.local>
Date:   Thu Jun 24 16:19:23 2021 +0900

    first commit

rebase -i를 활용한 커밋 수정하기

이번에도 방법은 같습니다. rebase -i 모드에서 squash 대신 edit을 사용하여 커밋을 수정해보겠습니다. 예시 역시 같습니다. 세 개의 커밋을 만들어 둔 상태라고 가정합니다.

commit 7351f5246b94d1b5a08002c41c5a4cb617266d94 (HEAD -> master)
Author: Hyuno Choi <hyunochoi@Hyunoui-MacBookPro.local>
Date:   Thu Jun 24 17:04:06 2021 +0900

    third commit

commit 98a20b6880f86e924408ee1c45ce7cc47a287539
Author: Hyuno Choi <hyunochoi@Hyunoui-MacBookPro.local>
Date:   Thu Jun 24 17:03:38 2021 +0900

    second commit

commit 3f737229534fb5d6db811314061c9bfc5622db0b
Author: Hyuno Choi <hyunochoi@Hyunoui-MacBookPro.local>
Date:   Thu Jun 24 17:03:09 2021 +0900

    first commit

저는 여기서 second commit을 수정해보겠습니다.

$ git rebase -i HEAD~~

명령어를 통해서 두 번째 커밋까지를 범위에 포함시켜 rebase 모드에 진입합니다.

edit 98a20b6 second commit
pick 7351f52 third commit

그리고 수정하려는 커밋 앞의 pick을 edit으로 바꿔주고 저장 후 종료합니다.

편집기를 종료하면 다음과 같은 메시지를 볼 수 있습니다. 지금 상태는 우리가 수정하겠다고 표시한 커밋에 체크아웃된 상태입니다.

Stopped at 98a20b6...  second commit
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를 통해 리베이스를 마칩니다.

second commit

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Thu Jun 24 17:03:38 2021 +0900
#
# interactive rebase in progress; onto 3f73722
# Last command done (1 command done):
#    edit 98a20b6 second commit
# Next command to do (1 remaining command):
#    pick 7351f52 third commit
# You are currently editing a commit while rebasing branch 'master' on '3f73722'.
#
# Changes to be committed:
#       modified:   sample.txt
#

해당 커밋에서 파일 수정을 마친 후 $ git commit --amend를 입력하면 커밋 메시지를 작성할 수 있는 편집기가 실행됩니다. 적절한 메시지를 입력하고 저장 후 종료합니다.

이후 $ git rebase --continue 명령어를 입력하면 Successfully rebased and updated refs/heads/master.라는 메시지와 함께 커밋 수정이 완료됩니다.

물론 해당 커밋에서 수정한 부분이 이후의 커밋과 충돌을 일으킨다면 충돌을 해결한 후에 리베이스를 마쳐야 합니다. 리베이스에서의 충돌 해결에 대한 내용은 이전 포스트를 참고해주세요.

마지막으로...

이렇게 이미 만들어진 커밋을 수정하는 방법에 대해 글을 작성해보았는데요, 이번 포스팅 내용만으로도 커밋 수정이 필요할 때 적절히 대처할 수 있을 것입니다.

마지막으로 반드시 알아두어야 할 것이 하나 있습니다.

커밋을 수정하면 해당 커밋의 아이디도 함께 바뀌게 됩니다.

이는 수정한 커밋이 이전 커밋과 다른 커밋이라는 의미로 해석해도 됩니다. 커밋을 수정하고 생긴 변경 사항을 원격 저장소에 푸쉬할 때는 원격 저장소의 기존 커밋 이력과 충돌이 발생할 수도 있다는 사실을 기억해야 합니다.

커밋 변경편을 마지막으로 Git/GitHub 포스팅이 마무리 되었습니다!🎉 후기를 마지막으로 포스팅을 마치도록 하겠습니다.

profile
프론트엔드 웹 개발자를 목표로 하고 있습니다.

0개의 댓글