Github 여러 Commit의 Author(커밋 작성자) 변경하기 / Commit Message 변경하기(rebase, reset, reflog, filter-branch )
github에는 커밋을 하게 되면 아래와 같이 잔디가 심어지는데,
며칠 전 내 github에 들어가보니 이 때까지 커밋했던게 제대로 반영이 되어 있지 않았다.
무슨 일인가 확인해보니 내 계정이 아니고 다른 계정을 만들어놨던게 Author로 등록이 되어서 하나도 반영이 되지 않았던 것이다. 그래서 구글링을 해서 복구하긴 했지만 나랑 완벽하게 똑같은 사례가 없어서 이것 저것 찾아보느라 힘들었기 때문에 기록 겸 다음에 같은 실수가 일어났을 때 찾아보려고 포스팅을 한다.
Git commit Author 변경
아래의 Error(잘못된 커밋)의 예와 같이 의도치 않은 작성자가 입력되어 변경하고 싶다.
이미 Git 원격저장소로 push까지 한 상태이기 때문에 reset 이나 rebase 를 통하여 변경할 수 있다.
만약 push를 하지 않고 로컬 저장소에만 있는 상태라면 git commit --amend 명령어를 사용하면 직전 커밋을 수정할 수도 있다.
또한, push를 했더라도 직전 커밋만 수정하면 된다면 git reset HEAD^1 으로 HEAD를 돌린 이후에 git push origin + branch 이름으로 강제 push를 해주면 된다.
나같은 경우 예시에서는 마지막 한 개의 커밋만 저렇게 되었지만 실제로는 이 때까지 한 전체 commit의 Author를 변경해야 했기 때문에 rebase 를 사용해야 했다.
rebase 명령어를 사용해야 되는 경우는,
- Git 원격 저장소에 이미 반영된 경우
- 바로 직전이 아닌 중간에 위치해있는 commit을 수정해야 되는 경우
commit hash 값 찾기
먼저 커밋을 변경하려면 변경할 커밋의 hash값 또는 변경할 커밋의 hash값을 알아야한다.
hash 값은 github에 들어가서 커밋 히스토리에서 hash 값을 찾아봐도 되고,
더 편한 방법은 터미널에서 git log 명령어를 사용하면 된다.
또는 짧게 hash 값만 확인하고 싶다면, git log --oneline 명령어를 사용하면 된다.
rebase 이용하기
이젠 hash 값을 알아냈으니 본격적으로 rebase 명령어를 사용해보자.
1) git rebase 명령어 입력
현재 변경하고 싶은 commit 의 hash 값이 e81c643이다.
# git rebase -i {변경할 커밋의 해시값}^
# git rebase -i {변경할 커밋의 이전 커밋의 해시값}
git rebase -i e81c643^
여기서 -i 는 (--interactive), 대화형 모드로 rebase를 실행하는 것이다.
또 나처럼 처음부터 모든 commit을 변경해야 된다면 git rebase -i --root 명령어를 사용하면 된다.
2) 변경 대상의 커밋 설정 변경하기
위의 rebase 명령어를 실행하면 따로 설정을 하지 않았다면 vi 에디터가 열린다.
초기 상태는 pick {hash 값} {커밋 메시지} 로 적혀있을텐데 변경할 커밋을 찾은 뒤, pick 을 edit 또는 e 로 변경해준다.
edit e81c643 Error (잘못된 커밋), Author 변경하기 예시
# Rebase b5f5663..e81c643 onto b5f5663 (1 command)
#
# 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.
#
# 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
수정 한 뒤에 esc를 누르고, :wq 명령어를 통해서 저장하고 나가면 된다.
$ git rebase -i e81c643^
Stopped at e81c643... Error (잘못된 커밋), Author 변경하기 예시
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
저장하고 나오면 위와 같이 rebase 진행모드를 시작한다.
3) 작성자(author) 수정하기
$ git commit --amend --author="작성자명 <email주소>"
# 또는 git commit --amend까지 입력하면 vi 에디터에서 직접 수정할 수 있다.
$ git commit --amend
Error (잘못된 커밋), Author 변경하기 예시
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Author: Choi HyungWook <qpflapffhs76@naver.com>
# Date: Thu Aug 12 13:51:19 2021 +0900
#
# interactive rebase in progress; onto b5f5663
# Last command done (1 command done):
# edit e81c643 Error (잘못된 커밋), Author 변경하기 예시
# No commands remaining.
# You are currently editing a commit while rebasing branch 'main' on 'b5f5663'.
#
# Changes to be committed:
# new file: src/error.js
또한, 여기서 commit message도 수정하고 쉽다면 --amend 뒤에 -m "수정할 message" 를 입력해주면 된다.
최종적으로 명령어를 입력하면 수정사항이 반영된다.
$ git commit --amend --author="CTD <qpflapffhs76@gmail.com>"
[detached HEAD 1cd1106] error (잘못된 커밋), Author 변경하기 예시
1 file changed, 1 insertion(+)
4) 다음 커밋으로 계속 진행하기
이제 수정을 마쳤으니 rebase 작업을 종료하면 된다.
$ git rebase --continue
여기서, edit으로 변경했던 커밋이 1개가 아니라면 다음 커밋으로 넘어가게 되고 3번의 과정을 다시 반복해주면 된다.
$ git rebase --continue
Successfully rebased and updated refs/heads/master.
5) push한 후 확인하기
이제 로컬 저장소에는 커밋이 반영되었고 원격 저장소로 push만 하면 된다.
다만, rebase 작업 이후에는 --force 옵션을 사용하여 강제로 진행해야 한다.
$ git push -f origin +브랜치이름
push가 성공적으로 끝났다면 github 홈페이지에 들어가서 확인해보자.
정상적으로 변경되었음을 알 수 있다.
https://docs.github.com/en/get-started/using-git/using-git-rebase-on-the-command-line
github 공식 문서에도 잘 정리되어 있으니 참고해도 좋을듯 하다.
git filter-branch
근데 여기서, commit이 1분 전이라고 되어있는데 COMMITTER_DATE값이 수정시간으로 변경되었기 때문이다.
이를 해결해주려면 git filter-branch를 사용하여 AUTHOR_DATE로 덮어 씌워야 한다.
git filter-branch --env-filter \
'if [ "$GIT_AUTHOR_DATE" != "$GIT_COMMITTER_DATE" ]
then
export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
fi'
만약 하나의 커밋만 수정하고 싶다면, 아래 명령어를 입력하면 된다.
git filter-branch --env-filter \
'if [ $GIT_COMMIT = 커밋해시값 ]
then
export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
fi'
또는 커밋의 날짜를 직접 변경하고 싶다면, 아래 명령어를 입력한다.
git filter-branch --env-filter \
'if [ $GIT_COMMIT = 커밋해시값 ]
then
export GIT_AUTHOR_DATE=2020-12-01T18:30:00+0900
export GIT_COMMITTER_DATE=2020-12-01T18:30:00+0900
fi'
이후 원격저장소에 push 해주면 된다.
여기서 git filter-branch로 날짜를 변경할 수 있다면 author도 변경할 수 있는게 아닌가? 해서 찾아봤는데 이 방법도 있다.
다만, 꽤나 위험한 방법이고 기존 커밋의 hash가 모두 바뀌므로 개인 프로젝트가 아닌 협업하는 프로젝트에서는 협의 없이 절대로 해서는 안 되는 방법이라고 한다.
#!/bin/sh
git filter-branch --env-filter '
OLD_EMAIL="your-old-email@example.com"
CORRECT_NAME="Your Correct Name"
CORRECT_EMAIL="your-correct-email@example.com"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
해당 블로그를 참고했다.
https://docs.github.com/en/get-started/using-git
github 공식문서에서도 filter-branch 예제가 잘 나와있다.