[Git] 7.4. CLI로 rebase 해보기
카테고리: Git
Rebase 사용하기
3-way 병합을 하면 병합 커밋이 생성되기 때문에 트리가 다소 지저분해진다는 단점이 있다. rebase는 소스트리 한글판에서 ‘재배치’라고 표기된다. 즉 내 브랜치의 커밋들을 재배치하는 것.
Rebase의 원리
1. HEAD와 대상 브랜치의 공통 조상을 찾는다.
2. 공통 조상 이후에 생성한 커밋들을 대상 브랜치 뒤로 재배치한다.
Rebase 실습
앞 절에서 만들었던 병합 커밋을 되돌리고 rebase를 한다. [feature1] 브랜치를 한 단계 되돌릴 때는 git reset –hard 명령을 사용한다.
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ git checkout feature1 # feature1으로 전환.
Already on 'feature1'
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ git reset --hard HEAD~ # 현재 브랜치에서 한 단계 되돌린다
HEAD is now at c201e9e 새로운 기능 1 추가
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ git log --oneline --graph --all -n3 # 로그 확인
- bc26b63 (origin/master, master, hotfix) hotfix 실습
| \* c201e9e (HEAD -> feature1) 새로운 기능 1 추가
|/
- 9e5110b (tag: v0.1) mybranch1 두 번째 커밋
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1)
$ git rebase master # HEAD 브랜치의 커밋들을 master로 재배치
error: could not apply c201e9e... 새로운 기능 1 추가
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply c201e9e... 새로운 기능 1 추가
Auto-merging file1.txt
CONFLICT (content): Merge conflict in file1.txt
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (feature1|REBASE 1/1)
$ git push
fatal: You are not currently on a branch.
To push the history leading to the current (detached HEAD)
state now, use
git push origin HEAD:<name-of-remote-branch>
위 코드의 실행결과는 다음과 같다.
$ git reset --hard HEAD~
명령으로 커밋을 한 단계 이전으로 되돌렸다. 되돌린 커밋은 병합하는 커밋이었으므로 병합 커밋이 사라진다. $ git rebase --abort
명령으로 rebase를 시도하였으나, merge에서와 마찬가지로 충돌로 인해 rebase는 실패한다. 실패 메시지에는 수동으로 충돌을 해결한 후에 스테이지에 추가할 것을 알려준다. 그 후 git rebase –continue 명령을 수행하라는 것을 알려준다. (몇 가지 rebase 옵션들을 더 알려주지만 충돌을 해결하고 다시 continue 해보겠다.)
충돌 해결 및 rebase 이어서 하기
오류 발생으로 이전 git bash 입력창을 날려버렸기 때문에 입력 명령을 나열하며 설명한다.
-
$ git status
명령을 입력해 충돌 대상을 확인한다. Unmerged paths : both modified: file1.txt 가 있었다. -
VSC에서 file1.txt를 직접 Open하여 수동으로 충돌을 해결한다.
-
$ git add file1.txt
를 이용해 변경사항을 스테이징하고 상태를 확인한ㄴ다.$ git status
를 이용해 file1.txt가 modified 된 것을 확인한다. -
$ git rebase --continue
명령을 입력하자 아래와 같은 실행 결과가 나왔다.
뭔가 무시무시한 경고창이 떴다. 일단 (E)dit anyway의 E를 입력하자 commit message을 편집하는 창이 나왔다. 나는 그 창에서 커밋 메시지를 입력하고 저장하는 방법을 찾을 수 없었기 때문에 끄고 다시 git bash를 실행했다.
$ git status
명령을 이용해 지금 무슨 상황인지를 확인하는 것이다. ‘interactive rebase in progress’ 라는 빨간 글씨가 나왔다. 유추하건데, rebase가 진행되고 있다는 뜻인가?
다시 오류가 뜰 지 모르지만, 용기를 무릅쓰고 $ git rebase --continue
명령을 입력하였다. Successfully rebased… 라는 메시지가 나왔다. rebase가 성공한 모양이다.
이를 정확히 확인하고자 $ git log --oneline --graph --all -n2
명령을 사용하였고, 가지 치는 브랜치 없이 이쁘게 커밋이 정리된 것을 확인할 수 있었다. 이제 필요 없어진 [feature1] 브랜치는 $ git merge feature1
명령을 이용해 병합시켜 버렸다.
유용한 Rebase의 사용법 : 뻗어나온 가지 없애기
뻗어나온 가지 커밋을 없애고 정리하는 방법을 고민해보자.
보통 커밋 만들기
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ echo "master1" >> master1.txt # master1.txt 파일 생성 후 "master1" 텍스트 입력
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git add master1.txt # 스테이지에 추가
warning: LF will be replaced by CRLF in master1.txt.
The file will have its original line endings in your working directory
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git commit -m "master 커밋 1" # 커밋
[master 8768eab] master 커밋 1
1 file changed, 1 insertion(+)
create mode 100644 master1.txt
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git push origin master # 푸시
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 580 bytes | 580.00 KiB/s, done.
Total 6 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/Orchemi/hello-git-cli.git
bc26b63..8768eab master -> master
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git log --oneline -n1 # 로그 확인
8768eab (HEAD -> master, origin/master) master 커밋 1
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ ls # 작업 디렉토리 상태 확인
file1.txt master1.txt
위 코드의 실행결과는 다음과 같다.
가지 커밋 만들기
$ git reset --hard HEAD~ # 한 단계 이전으로 HEAD 되돌리기
HEAD is now at 9c9f39f 새로운 기능 1 추가
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ echo "master2" >> master2.txt # master2.txt 만들고 "master2" 텍스트 입력
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git add . # 스테이지에 추가
warning: LF will be replaced by CRLF in master2.txt.
The file will have its original line endings in your working directory
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git commit -m "master2 커밋" # 커밋
[master 993bace] master2 커밋
1 file changed, 1 insertion(+)
create mode 100644 master2.txt
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git log --oneline --graph --all -n3 # 로그 확인
- 993bace (HEAD -> master) master2 커밋
| \* 8768eab (origin/master) master 커밋 1
|/
- 9c9f39f (feature1) 새로운 기능 1 추가
위 코드를 실행한 결과이다.
예상대로 같은 커밋인 ‘새로운 기능 1 추가’ 커밋에서부터 2개의 서로 다른 커밋을 만들었기 때문에 가지가 생성되었다. 이 상황에서 git pull을 하게 되면 git pull = git fetch + git merge 이기 때문에 가지를 병합하기 위한 병합 커밋이 생기고, 이에 따라 커밋 히스토리가 지저분해진다.
git pull 수행결과
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git pull # git pull 수행, merge message 창은 그냥 닫는다.
.
.
.
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git status # git 상태 확인
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git log --oneline --graph --all -n4 # 로그 확인
- 0497765 (HEAD -> master) Merge branch 'master' of https://github.com/Orchemi/hello-git-cli
|\
| \* 8768eab (origin/master) master 커밋 1
- | 993bace master2 커밋
|/
- 9c9f39f (feature1) 새로운 기능 1 추가
위의 코드를 실행하면 다음과 같다.
이렇게 불필요한 가지 커밋과 병합 커밋이 발생하였다. 이를 rebase를 이용해 정리해보자.
rebase로 가지 없애기
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git reset --hard HEAD~ # 병합 커밋 되돌리기
HEAD is now at 993bace master2 커밋
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git rebase origin/master # rebase 수행으로 현재 커밋 재배치
Successfully rebased and updated refs/heads/master.
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git log --oneline --all --graph -n3 # 로그 확인
- 3fc1633 (HEAD -> master) master2 커밋
- 8768eab (origin/master) master 커밋 1
- 9c9f39f (feature1) 새로운 기능 1 추가
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 323 bytes | 323.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/Orchemi/hello-git-cli.git
8768eab..3fc1633 master -> master
위 코드의 실행결과는 다음과 같다.
rebase를 실행한 결과, 지저분한 가지 커밋들이 사라지고 일련의 커밋 히스토리를 확인할 수 있다.
임시 브랜치 사용하기
많은 입문자들은 충돌 해결, merge, rebase 등을 할 때 소스가 깨지거나 작업한 내용이 사라지는 두려움, Git의 커밋 히스토리가 꼬일 것 같은 두려움을 가진다. 이럴 때 사용하는 것이 바로 임시 브랜치이다.
원래 작업하려고 햇던 브랜치의 커밋으로 임시 브랜치를 만들고 나면 해당 브랜치에서는 아무 작업이나 막 해도 전혀 상관 없다. 임시 브랜치가 필요 없어지는 시점에 CLI에서 $ git branch -D <브랜치 이름>
명령으로 브랜치를 삭제할 수 있다.
임시 브랜치 생성 사용 및 삭제
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git branch test feature1 # [feature1] 브랜치로부터 [test] 임시 브랜치 생성
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git checkout test # [test] 브랜치 체크아웃
Switched to branch 'test'
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (test)
$ echo "아무말 대잔치" > test.txt
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (test)
$ cat test.txt # test.txt 파일 내용 확인
아무말 대잔치
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (test)
$ git add .
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (test)
$ git commit -m "임시 커밋"
[test d753e8f] 임시 커밋
1 file changed, 1 insertion(+)
create mode 100644 test.txt
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (test)
$ git log --oneline --graph --all -n4 # 로그 확인
- d753e8f (HEAD -> test) 임시 커밋
| _ 3fc1633 (origin/master, master) master2 커밋
| _ 8768eab master 커밋 1
|/
- 9c9f39f (feature1) 새로운 기능 1 추가
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (test)
$ git checkout master # 임시 브랜치 삭제
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git branch -D test
Deleted branch test (was d753e8f).
tmdgn@ASUSSH MINGW64 ~/Documents/hello-git-cli (master)
$ git log --oneline --graph --all -n3 # 로그 확인
- 3fc1633 (HEAD -> master, origin/master) master2 커밋
- 8768eab master 커밋 1
- 9c9f39f (feature1) 새로운 기능 1 추가
위 코드의 실행 결과는 다음과 같다.
Reference
- 팀 개발을 위한 Git GitHub 시작하기, 한빛미디어, 정호영,진유림
댓글남기기