Git Step-6 : Rebase 심화
Rebase 심화
Git Step-3 Branch에서도 Rebase에 대한 설명을 했지만, 복잡한 부분이 있어 조금만 더 알아보도록 하겠습니다.
rebase는 특정 branch가 파생된 base 커밋 지점을 다른 커밋으로 옮기는 명령어입니다.
-
Case1: 기본적인 rebase
A---B---C topic / D---E---F---G master $git rebase master topic A'--B'--C' topic / D---E---F---G master
여기서 rebase 명령은 topic branch의
base 커밋이 E
였는데 master branch가 가리키고 있던G 커밋으로 이동
시킨겁니다. 그러면서 A–B–C가 A’–B’–C’로 바뀐것은 rebase 과정에서 기존 커밋(A, B, C)을 지우고 새로운 커밋(A’, B’, C’)으로 만들어서 이동 시키기 때문에 커밋들의 hash값이 변경되었기 때문입니다. 그래서remote에 push로 공유되지 않은 커밋들만 rebase
를 해야 동료들과의 좋은 관계를 유지할 수 있습니다. -
Case1 테스트
* 744b19d (HEAD -> feature-tmp) tmp2 * 7521b6b tmp | * 2647c71 (develop) modify2 a.txt in develop | * ce2ef9b modify a.txt in develop |/ * 96c1620 Merge branch 'release' into develop $git rebase ce2ef9b feature-tmp * 2662976 (HEAD -> feature-tmp) tmp2 * 4a16942 tmp | * 2647c71 (develop) modify2 a.txt in develop |/ * ce2ef9b modify a.txt in develop * 96c1620 Merge branch 'release' into develop
-
Case2: 동일파일 커밋 생략
만약 topic branch의 A커밋과 master branch의 A’ 커밋의 파일 내용이 같다면 hash값이 다르더라도 topic branch의 A 커밋은 생략됩니다.
A---B---C topic / D---E---A'---F master $git rebase master topic B'---C' topic / D---E---A'---F master
-
Case2 테스트
* be4ecdf (HEAD -> feature-tmp) Add function save in feature-tmp * 94a6d2f Add function new in feature-tmp | * 8b5df2c (develop) Add function delete in develop | * 15a171b Add function new in develop |/ * 96c1620 Merge branch 'release' into develop #94a6d2f 커밋과 15a171b 커밋의 파일 내용을 동일하게 한 다음 #feature-tmp branch를 develop branch로 rebase 해보겠습니다. $git rebase develop feature-tmp First, rewinding head to replay your work on top of it... Applying: Add function save in feature-tmp #rebase 후에 15a171b 커밋은 존재하지만 94a6d2f 커밋에 대한 커밋 메시지는 찾아볼 수 없습니다. #실제 커밋도 96c1620 커밋 이후로 4개에서 3개로 줄었습니다. * 802293c (HEAD -> feature-tmp) Add function save in feature-tmp * 8b5df2c (develop) Add function delete in develop * 15a171b Add function new in develop * 96c1620 Merge branch 'release' into develop
-
Case3: upstream branch가 아닌 branch에 rebase 하기
branch를 rebase할 대상은 upstream branch을 지정해야 됩니다. 만약 upstream branch보다 더 상위 branch에 rebase를 할려면 –onto 옵션을 사용해야 합니다.
o---o---o---o---o master \ o---o---o---o---o next \ o---o---o topic $git rebase --onto master next topic o---o---o---o---o master | \ | o'--o'--o' topic \ o---o---o---o---o next
-
Case3 테스트
–onto 옵션 안쓰고 rebase하면 어떻게 될까요?
* e85c3ac (HEAD -> feature-sub) commit-3 sub
* 54bb2c2 commit-2 sub
* bcf6ab8 commit-1 sub
* b703c62 (feature-tmp) commit-3 tmp
* 1ac353d commit-2 tmp
* 05247d2 commit-1 tmp
| * 27fc591 (develop) commit-3 develop
| * 6a6df56 commit-2 develop
| * 336501f commit-1 develop
|/
* 96c1620 Merge branch 'release' into develop
$git rebase develop feature-sub
First, rewinding head to replay your work on top of it...
Applying: commit-1 tmp
Applying: commit-2 tmp
Applying: commit-3 tmp
Applying: commit-1 sub
Applying: commit-2 sub
Applying: commit-3 sub
#엉망이 됩니다. feature-sub와 feature-tmp branch 내용과 함께 develop branch로 rebase 되고,
#기존 feature-tmp branch는 base 커밋으로 부터 분기된 모습입니다.
* aed1de0 (HEAD -> feature-sub) commit-3 sub
* 22c95a7 commit-2 sub
* 223399e commit-1 sub
* 50cb78e commit-3 tmp
* 2ae2d72 commit-2 tmp
* 9c91a5f commit-1 tmp
* 27fc591 (develop) commit-3 develop
* 6a6df56 commit-2 develop
* 336501f commit-1 develop
| * b703c62 (feature-tmp) commit-3 tmp
| * 1ac353d commit-2 tmp
| * 05247d2 commit-1 tmp
|/
* 96c1620 Merge branch 'release' into develop
--onto 옵션 쓰고 정상적으로 rebase
- 39c4e08 (HEAD -> feature-sub) commit-3 sub
- b4e9927 commit-2 sub
- 25076ff commit-1 sub
- b703c62 (feature-tmp) commit-3 tmp
- 1ac353d commit-2 tmp
- 05247d2 commit-1 tmp | * 27fc591 (develop) commit-3 develop | * 6a6df56 commit-2 develop | * 336501f commit-1 develop |/
- 96c1620 Merge branch ‘release’ into develop
$git rebase –onto develop feature-tmp feature-sub First, rewinding head to replay your work on top of it… Applying: commit-1 sub Applying: commit-2 sub Applying: commit-3 sub
#정상적으로 develop branch 부터 feature-sub branch의 커밋 히스토리가 이어짐.
- ecbbe9c (HEAD -> feature-sub) commit-3 sub
- 65ecc14 commit-2 sub
- 378ab22 commit-1 sub
- 27fc591 (develop) commit-3 develop
- 6a6df56 commit-2 develop
- 336501f commit-1 develop | * b703c62 (feature-tmp) commit-3 tmp | * 1ac353d commit-2 tmp | * 05247d2 commit-1 tmp |/
-
96c1620 Merge branch ‘release’ into develop ```
- Case4: 동일 branch 내에서 특정 커밋 구간을 삭제 하는 방법.
E---F---G---H---I---J topicA
$git rebase --onto topicA~5 topicA~3 topicA
#F~G 구간 커밋을 삭제함.
E---H'---I'---J' topicA
풀이)
(1) topicA~5 = E
(2) topicA~3 = G (E---F---G)
(3) topicA = J (E---F---G---H---I---J)
(1) + ( (3)-(2) ) = result
(3)-(2) = (H'---I'---J') //이 과정에서 커밋객체가 새로 만들어짐.
E + (H'---I'---J') = E---H'---I'---J'
(topicA~5, topicA~3 이 무슨말인지 모르신다면 Git Step-7 : 커밋 참조 객체의 특정 노드 접근 )
-
Case4 테스트(동일 파일로 커밋을 만들어서 테스트 하면 Conflict가 발생할 수 있습니다.)
* abee4f4 (HEAD -> feature-sub) sub-6 * d04af09 sub-5 * 947e42b sub-4 * 255bfc5 sub-3 * 877da95 sub-2 * 6a1a693 sub-1 * 27fc591 (develop) commit-3 develop * 6a6df56 commit-2 develop * 336501f commit-1 develop | * b703c62 (feature-tmp) commit-3 tmp | * 1ac353d commit-2 tmp | * 05247d2 commit-1 tmp |/ * 96c1620 Merge branch 'release' into develop $git rebase --onto feature-sub~5 feature-sub~3 feature-sub First, rewinding head to replay your work on top of it... Applying: sub-4 Applying: sub-5 Applying: sub-6 # sub-2와 sub-3의 커밋이 삭제되었습니다. * e1bdcbd (HEAD -> feature-sub) sub-6 * 03257cc sub-5 * f06624a sub-4 * 6a1a693 sub-1 * 27fc591 (develop) commit-3 develop * 6a6df56 commit-2 develop * 336501f commit-1 develop | * b703c62 (feature-tmp) commit-3 tmp | * 1ac353d commit-2 tmp | * 05247d2 commit-1 tmp |/ * 96c1620 Merge branch 'release' into develop
-
Rebase Conflict 해결
Rebase 과정은 rebase 대상의 커밋들 각각 처리하게 됩니다. 만약 rebase 중 Conflict가 발생하면 해결한 뒤 git add하고 git rebase –continue로 rebase를 계속 진행합니다.
$git log --oneline --graph --all * 1525536 (HEAD -> feature-rebase) rebase-3 commit * 06b68a1 rebase-2 commit * 45253e4 rebase-1 commit | * d0de388 (develop) develop-1 commit |/ * 96c1620 Merge branch 'release' into develop
feature-rebase를 develop로 rebase할 예정이며, 96c1620 커밋 이후 모든 커밋은 동일한 지점을 수정하여 커밋하였기 때문에 Conflict가 발생할 것입니다.
$git rebase develop First, rewinding head to replay your work on top of it... Applying: rebase-1 commit Using index info to reconstruct a base tree... M a.txt Falling back to patching base and 3-way merge... Auto-merging a.txt CONFLICT (content): Merge conflict in a.txt error: Failed to merge in the changes. Patch failed at 0001 rebase-1 commit hint: Use 'git am --show-current-patch' to see the failed patch 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".
이렇게 Conflict가 발생하고 연결된 editor가 있다면 editor로 conflict를 해결 하라고 나옵니다.
그리고 위에서 hint부분들을 보시면 conflict를 해결한 다음 git add하고 git rebase –continue를 실행하라고 나옵니다. 그리고 –skip옵션과 –abort옵션도 사용 가능합니다.
$git add . $git rebase --continue Applying: rebase-1 commit Applying: rebase-2 commit Applying: rebase-3 commit $git log --oneline --graph --all * 25fe954 (HEAD -> feature-rebase) rebase-3 commit * 6924ca6 rebase-2 commit * 2f12e18 rebase-1 commit * 3debbc6 (develop) develop-1 commit * 96c1620 Merge branch 'release' into develop
위에서는 develop의 3debbc6 커밋과 2f12e18 커밋의 conflict만 발생하였습니다.
그런데 만약 conflict를 해결할 때 rebase 중인 첫번째 커밋의 내용을 수정하면 두번째 rebase 대상 커밋과 다시 충돌이 발생합니다.
* 2c2fbd7 (HEAD -> feature-rebase) rebase-3 commit * e97e383 rebase-2 commit * 843fb9e rebase-1 commit | * d0de388 (develop) develop-1 commit |/ * 96c1620 Merge branch 'release' into develop
아래 그림에서 843fb9e의 커밋 내용을 수정하고 continue를 해보겠습니다.
conflict에서 수정한 라인과 다음 rebase 대상의 커밋의 수정 포인트가 동일라인이면 다시 conflict가 발생합니다.
만약 rebase하시다가 rebase를 취소하고 싶으시면 git rebase –continue 대신에 git rebase –abort 명령을 쓰시면 rebase 시작 전으로 돌아갑니다.
```
댓글남기기