Git 브랜치(Branch)다루기2 - 삭제, Merge 방식
브랜치 삭제 : $ git branch -d <BranchName>
- 해당 브랜치를 삭제한다.
특정 브랜치 생성해 작업 후 이를 다른 브랜치로 병합(=합치기=merge)해야할 때 '브랜치 병합'이 필요하다.
브랜치 병합(=merge=합치기=머지) :
① $ git checkout <병합 작업할 브랜치명> 명령 후,
② $ git merge <병합 대상인 브랜치명> 명령 실행한다!
- ① 다른 브랜치(B) 내용을 병합할 브랜치(A)로 이동 후 (checkout),
② 다른 브랜치(B)를 병합할 브랜치(A)에 합친다. (merge)
$ git checkout A $ git merge B |
- ※ ① 주의) "아직 커밋하지 않은 파일이 Checkout 할 브랜치와 충돌 나면 브랜치를 변경할 수 없다."
이렇게 말해도 이해 잘 안 간다.
일단 예제를 보는 게 더 이해가 쉽다!
Example) 브랜치 merge, 제거 예제
상황은 아래와 같다.
- 'main' 브랜치만 존재하는 원격 저장소 프로젝트 - 프로젝트에 다음 달까지 QnA 기능이 개발되어야 한다 -> 'addQnA'라는 브랜치를 생성해 작업할 예정 - (QnA 기능 개발 도중) 긴급 이슈 발생해 수정이 필요 -> 'hotfix'브랜치 생성해 이슈 수정 작업할 예정 |
ⓐ 'main'브랜치만 존재하는 원격 저장소 프로젝트의 형상
- 초록색 사각형 : 원격 저장소 프로젝트 커밋사항
원격 저장소 프로젝트에는 커밋사항은 자신의 이전 커밋사항을 가리키며 연결되어 있다.
- 'main' 브랜치(remote)는 마지막 커밋사항인 'commit 1002'를 가리킨다.
ㄴ> 브랜치 : 마지막 커밋을 가리키는 포인터 같은 것
ⓑ 내달까지 QnA 기능이 추가 개발되어야 해서
원격 프로젝트의 최신 형상(commit 1002)을 로컬로 checkout으로 가져오고
이를 바라보는 'addQnA'라는 브랜치를 생성한다.
$ git checkout -b addQnA
Switched to a new branch "addQnA"
ㄴ> 브랜치를 생성 및 이동(Checkout)까지 한 번에 하려면 $ git checkout 명령에 -b 라는 옵션을 추가
ㄴ> 위 명령어 수행 후 로컬 저장소 형상은 아래와 같다.
- 'main' 브랜치(local)는 Git이 자동으로 생성한 브랜치로 원격 마지막 커밋사항인 'commit 1002'를 가리킨다.
- 'addQnA' 브랜치는 지금 막 생성되어 원격 마지막 커밋사항인 'commit 1002'를 가리킨다.
- 'HEAD' 브랜치는 로컬에서 지금 작업 중인 "브랜치(branch)"를 가리키는 포인터이다.
$git checkout -b 명령으로 생성된 브랜치 이동하였으므로 작업 중인 'addQnA' 브랜치를 가리킨다.
ⓒ 일부 QnA 기능 개발해서 로컬에 커밋(commit 1003)한 경우
- 'addQnA' 브랜치와 'HEAD' 브랜치는 로컬에 새로운 커밋사항을 따라 이동한다.
ⓓ 이때 긴급 수정 이슈 발생했다!!
-> 원격의 최신 형상(commit 1002)에서 이슈 수정을 위한 'hotfix' 브랜치를 로컬에 생성하고,
'hotfix' 브랜치에서 이슈 수정 작업을 하려고 한다
ⓔ 하지만 현재 내 로컬에는 개발중인 'addQnA' 브랜치 작업 사항들이 존재하므로
이 상태로 작업하면, 'addQnA' 브랜치의 작업사항에 'hotfix' 브랜치의 버그 해결작업들이 섞일 위험이 있다;;
▼
∴ 이를 방지하기 위해 'addQnA' 브랜치의 작업사항을 어딘가에 저장해두고,
'addQnA' 브랜치 작업하기 전인 'main'브랜치 형상으로 내 로컬이 변해야 한다.
※ 주의) 내 로컬 브랜치 변경 시, 커밋하지 않은 파일이 Checkout 할 브랜치와 충돌 날 수 있다 ※
( Stash이나 커밋 Amend 등으로 충돌해결가능하나 아직 모르므로.......;;;;;;
일단 지금은 작업하던 것을 모두 커밋하고 main 브랜치로 옮기자!! )
ⓔ -1) 'main'브랜치 로 내 로컬을 변경
$ git checkout main
Switched to branch 'main'
- ※ 주의) 브랜치를 이동에는 "아직 커밋하지 않은 파일이 Checkout 할 브랜치와 충돌 나면 브랜치를 변경할 수 없음"을 주의하여
로컬의 워킹 디렉토리를 정리하는 것이 좋다.
- 'main' 브랜치(local)는 'addQnA' 브랜치의 작업사항이 없는 이전 형상으므로 새로운 문제에 집중할 수 있는 환경이 만들어진다.
ⓕ 이슈 수정을 위한 'hotfix'브랜치 생성 및 이동(checkout)한다.
$ git checkout -b hotfix
Switched to a new branch 'hotfix'
-이제 'hotfix' 브랜치는 로컬에 새로운 커밋사항을 따라 이동한다.
ⓕ 긴급 수정 이슈 수정하여 로컬에서 커밋(commit 1004)했다.
$ git commit -a -m 'fixed the broken email address'
- 로컬의 작업 브랜치인 'hotfix' 브랜치가 로컬의 새로운 커밋사항(commit1004)를 따라 이동한다.
- 'HEAD' 브랜치는 지금 작업 중인 브랜치인 'hotfix' 브랜치를 가리킨다.
ⓖ 긴급 이슈 수정 작업 완료 후 'hotfix' 브랜치를 main 브랜치에 합쳐야 한다.
- 운영 환경에 적용하려면 문제를 제대로 고쳤는지 테스트하고 최종적으로 운영환경에 배포하기 위해서
hotfix 브랜치를 master 브랜치에 합쳐야 한다.
- $ git merge 명령으로 브랜치를 합칠(=merge=병합) 수 있다.
$ git checkout main
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)
- 명령어 실행 결과 메시지에서 'fast-forward' 확인!!!
- 'hotfix' 브랜치가 가리키는 (commit 1004) 커밋이 (commit 1002) 커밋에서 갈라진 브랜치이기 때문에 merge하면
'main' 브랜치 포인터는 그저 최신 커밋으로 이동한다. 이러한 Merge 방식을 'Fast forward' 라고 부른다.
['Fast forward' 방식]
: A 브랜치에서 다른 브랜치 B 를 Merge 할 때 B 브랜치가 A 브랜치 이후의 커밋을 가리키고 있으면(A의 커밋이 B의 조상), B 브랜치와 동일한 커밋을 가리키도록 A브랜치가 가리키는 곳만 이동하는 Merge 방식. - Merge 방식 중 하나 |
+) 그림 22. Merge 후 hotfix 같은 것을 가리키는 master 브랜치
ⓗ 이제 더 이상 필요없는 'hotfix' 브랜치는 삭제한다.
$ git branch -d hotfix
Deleted branch hotfix (3a0874c)
ⓘ 다시 작업하던 'addQnA' 브랜치로 되돌아가서 개발하고 커밋을 해보자.
ⓘ-1) 'addQnA' 브랜치로 이동(checkout)
$ git checkout addQnA
Switched to branch "addQnA"
ⓘ-2)'addQnA' 브랜치에서 새 작업사항 커밋 (commit1005)
$ git commit -a -m 'finished the new footer [addQnA]'
[addQnA ad82d7a] finished the new footer [addQnA]
1 file changed, 1 insertion(+)
위에서 이슈 수정 작업('hotfix' 브랜치)이 addQnA 브랜치에 영향을 끼치지 않는다
이후, #1 or #2 방식으로 Merge 진행 가능하다.
#1) main 브랜치를 addQnA 브랜치에 병합(Merge)
- $ git merge main 명령으로 main 브랜치를 addQnA 브랜치에 Merge 하면
addQnA 브랜치에 hotfix 이슈 수정 사항이 적용된다.
#2) addQnA 브랜치 개발 완료 후 main 브랜치에 병합(Merge)
- addQnA 브랜치가 main 브랜치에 Merge 할 수 있는 수준이 될 때까지 기다렸다가
Merge 하면 hotfix 와 addQnA 브랜치가 합쳐진다.
- 그림 24. 커밋 3개를 Merge
$ git checkout main
Switched to branch 'main'
$ git merge addQnA
Merge made by the 'recursive' strategy.
index.html | 1 +
1 file changed, 1 insertion(+)
ㄴ> "현재 브랜치가 가리키는 커밋이 Merge 할 브랜치의 조상이 아니므로" Git은 'Fast-forward’로 Merge 하지 않는다.
cf) hotfix 를 Merge 했을 때 메시지
ㄴ> 이 경우에는 Git은 각 브랜치가 가리키는 커밋 두 개와 공통 조상 하나를 사용하여 '3-way Merge'를 한다.
['3-way Merge' 방식]
: A 브랜치에서 다른 브랜치 B 를 Merge 할 때 B 브랜치가 A 브랜치 이후의 커밋이 아니면 (A의 커밋이 B의 조상이 아님!) (단순히 브랜치 포인터를 최신 커밋으로 옮기는 게 아니라) 3-way Merge 결과를 별도의 커밋으로 만들고 나서 A 브랜치가 그 별도의 커밋을 가리키도록 이동시키는 Merge 방식. - 이런 별도의 커밋을 [Merge 커밋]이라고 한다. -Merge 방식 중 하나 - (그림 24. 커밋 3개를 Merge -> 그림 25. Merge 커밋) |
[Merge 커밋]
: (사용자 요청에 의한 커밋이 아닌) merge작업 중 브랜치 포인터가 이동('Fast-forward' Merge)할 수 없는 경우, Git이 두 브랜치를 merge하고 이를 커밋한 것을 말한다. - 이전 커밋(='parent'=부모 커밋)이 여러개이다. |
ⓚ addQnA 브랜치를 master에 Merge 후 addQnA 브랜치를 삭제하고 이슈의 상태를 처리 완료로 표시
$ git branch -d addQnA
END!
스터디 도움 참조 블로그 (References)
- 3.2 Git 브랜치 https://git-scm.com/book/ko/v2/Git-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EB%B8%8C%EB%9E%9C%EC%B9%98%EC%99%80-Merge-%EC%9D%98-%EA%B8%B0%EC%B4%88 - 브랜치 명령어 https://backlog.com/git-tutorial/kr/reference/branch.html - git--distributed-even-if-your-workflow-isnt (Pro Git Book) https://git-scm.com/book/en/v2 |