Git을 처음 쓸때는 작업 이력을 저장하는 개념 정도로 commit을 이해하고 사용했었다. 그러다보니 commit 이력이 지저분해졌고, 다른 개발자들이 내 코드를 commit 단위로 리뷰하기 어려웠다. 또한 commit 단위로 수정 이력을 추적하는 것도 불가능해져 비로소 commit을 깔끔하게 관리하는데 공을 들이기 시작했다. 내가 주로 활용하는 방법은 2가지가 있다.
1. git stash
현재 작업중인 파일의 snapshot을 스테이징 영역에 잠시 보관해두는 명령이다. 개인적으로는 현재 브랜치의 작업이 완료되지 않은 상태에서 잠시 저장하고 다른 브랜치로 넘어가야 하는 상황에 주로 쓴다. 처음에는 이 명령어를 사용하면서도 혹시나 스테이징 영역이 날아가버리지는 않을지 불안하기도 했지만 다행히 아직까지 그런 경험은 없다.
간단한 예제를 보자. 다음과 같은 코드가 있으며 현재 a 브랜치에서 작업을 진행중이다.
public static void main(String[] args) {
String result = biggerIsGreater("abcd");
System.out.println(result);
}
아래와 같이 주석 한줄을 추가하여 코드를 수정했다.
public static void main(String[] args) {
String result = biggerIsGreater("abcd");
//예제는 해커랭크 문제중 일부 발췌입니다..
System.out.println(result);
}
이 상황에서 b 브랜치로 넘어가 작업을 해야하는 긴급 수정사항이 생겼다고 해보자. 그러면 현재 작업중인 이 수정 내역을 임시로 저장해야한다. git stash 명령어를 활용하면 스테이징 영역에 수정사항이 저장된다.
$ git stash
작업 폴더와 WIP on a: 6ecd196 first commit 인덱스 상태를 저장했습니다
이제 b 브랜치로 넘어가서 작업을 끝나고 다시 a 브랜치로 돌아온다. b 브랜치로 넘어가기 전에 저장했던 수정 내역을 복구하기 위해서는 git stash apply 명령어를 사용하면 된다.
$ git stash apply
현재 브랜치 a
아래와 같이 스테이징 영역에 저장되어 있던 수정 내역이 되돌아오게 된다.
public static void main(String[] args) {
String result = biggerIsGreater("abcd");
//예제는 해커랭크 문제중 일부 발췌입니다..
System.out.println(result);
}
2. git rebase
이미 수정 내역을 commit 해버렸을 때는 어떨까? 다시말해 과거의 commit을 수정하고 싶다면 말이다. 결론적으로 말해 이런 경우, rebase를 통해 과거의 commit 이력을 변경하는 방법이 있다.
예시를 보자. 다음과 같이 코드를 수정하고 commit을 한 상황이다.
public static void main(String[] args) {
String result = biggerIsGreater("abcd");
//예제는 해커랭크 문제중 일부 발췌입니다..
System.out.print(result);
}
그런데 알고보니, print가 아닌 println 메서드를 사용해서 출력을 해야했다. 보통의 경우에는 그냥 현재 상태에서 다시 수정한 뒤 commit 이력을 추가하는 것이 바람직하겠지만, 반드시 과거 commit을 수정해야만 하는 상황이라고 가정해보자.
먼저, git log
로 수정하려는 commit의 바로 이전의 commit id를 확인한다. 아래 예시에서 commit id는 ffbffae94e578748bc4a3426494c8d6e0d34f6d7
임을 확인할 수 있다.
$ git log
commit 90e1e76ef7afdb503e8163eb49c12f6510c8389d (HEAD -> a)
Author: kim-solshar
Date: Sat Mar 13 17:11:31 2021 +0900
print로 결과 출력
commit ffbffae94e578748bc4a3426494c8d6e0d34f6d7
Author: kim-solshar
Date: Sat Mar 13 16:54:55 2021 +0900
second commit
해당 commit id를 타겟으로 rebase를 진행한다. 그러면 해당 지점을 기준으로 commit 이력이 재생성되는 것이다.
$ git rebase --interactive ffbffae94e578748bc4a3426494c8d6e0d34f6d7
rebase를 실행하면 다음과 같이 뜨는데, shif + i
를 눌러 실행모드로 들어간 뒤 pick
을 edit
으로 변경해준다.
pick 90e1e76 print로 결과 출력
# Rebase ffbffae..90e1e76 onto ffbffae (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
commit 메세지도 변경해준뒤 :wq!를 입력하여 저장한다.
edit 90e1e76 println으로 결과 출력
# Rebase ffbffae..90e1e76 onto ffbffae (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
코드를 수정한뒤 다시 commit --amend로 커밋을 수정하고, rebase를 진행하라는 안내가 뜬다.
$ git rebase --interactive ffbffae94e578748bc4a3426494c8d6e0d34f6d7
90e1e76... println으로 결과 출력 위치에서 멈췄습니다
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
코드를 수정한다. 예시에서는 print를 println으로 변경해주는 간단한 수정을 했다.
public static void main(String[] args) {
String result = biggerIsGreater("abcd");
//예제는 해커랭크 문제중 일부 발췌입니다..
System.out.println(result);
}
--amend 옵션을 주어 commit을 진행한다.
$ git commit --amend
commit 메세지를 수정하여 :wq!
명령으로 저장한다.
println으로 결과 출력
# 변경 사항에 대한 커밋 메시지를 입력하십시오. '#' 문자로 시작하는
# 줄은 무시되고, 메시지를 입력하지 않으면 커밋이 중지됩니다.
#
# 시각: Sat Mar 13 17:11:31 2021 +0900
#
# 대화형 리베이스 진행 중. 갈 위치는 ffbffae
# 최근 완료한 명령 (1개 명령 완료):
# edit 90e1e76 println으로 결과 출력
# 명령이 남아있지 않음.
# 'a' 브랜치를 'ffbffae' 위로 리베이스하는 중 커밋을 편집하는 중입니다.
#
:wq!
commit이 정상적으로 수정한다.
$ git commit --amend
[HEAD 분리됨 05198e9] println으로 결과 출력
Date: Sat Mar 13 17:11:31 2021 +0900
1 file changed, 1 insertion(+)
마지막으로 아래 명령어를 입력하여 rebase를 마무리한다.
(base) 11ST1101162MN001:hackerrank a1101162$ git rebase --continue
Successfully rebased and updated refs/heads/a.
이제 git history를 확인해보면 아래와 같이 commit 이력이 수정이 된 것을 확인할 수 있다.
주의할 점은, rebase는 과거의 commit 이력을 변경해버리는 명령이기에 신중히 실행해야 한다. 또한, remote repository와 commit 이력이 틀어지기 때문에 force push를 통해 강제 동기화 등을 해주어야한다. 이 과정에서 중요한 commit 이력을 날려버리는 불상사가 발생할 수도 있으니 프로덕션 코드에서 rebase를 할때는 신중을 기하도록 하자.
참고
'IT > 개발지식' 카테고리의 다른 글
객체지향 의존 역전 원리(DIP) 제대로 알기 (0) | 2021.08.02 |
---|---|
Redis의 다양한 구성을 빠르게 따라해보자 (0) | 2021.06.14 |
JPA의 핵심 - 영속성 컨텍스트 훑어보기 (0) | 2020.09.26 |
DataJpaTest를 활용한 테스트 (0) | 2019.03.02 |
Mockito를 활용한 단위테스트 (0) | 2018.11.14 |