깃 브랜치 기초(생성, 삭제, 체크아웃, merge), 심화 링크
위의 현재 내가 위치한 브랜치는 main
(참고로 예전에는 master 브랜치가 default였는데 지금은 main이 default 브랜치 이름이다.)
그리고 git history를 보면 지금 헤드가 어디를 향하는지도 알 수 있다.
지금까지 하나의 브랜치에서 작업했기때문에 아래 그림처럼 일률적인 작업을 볼 수 있다.
지금까지 해온 작업을 무료버전이라고 하고 유료버전의 작업을 위해서 기능을 추가하고 싶다?
그러면 이제 브랜치를 하나 더 만들어서 작업환경에 가지를 쳐주면 된다.
브랜치를 만드려면 $git branch 깃브랜치이름 을 적어주고
만든 브랜치에서 작업을 하려면 $git checkout 깃브랜치이름 을 적어주면 된다.
$git status를 하면 원하는 브랜치로 잘 갈아탄것을 확인할 수 있다.
이제 모든 작업은 위에서 설정해둔 premium 브랜치에서 이루어지게 된다.
만약에
브랜치를 만들고 체크아웃을 하는 한번에 하고 싶으면
$git branch -b 깃브랜치이름 을 적어주면 된다.
삭제하고 싶으면 다른 브랜치로 이동한 후에
$git branch -d 삭제할깃브랜치이름 을 적어주면 된다.
잘삭제 된것을 확인할 수 있다.
그런데 브랜치 삭제는 협업할 때 조심해서 써야 된다...^^
각 브랜치에서
파일 내용을 변경하고 커밋하면
서로의 브랜치는 서로 영향을 미치지 않는다.
다시 브랜치를 옮겨서 확인해보면 확실하게 알 수 있다.
위 작업은 이제 아래 브랜치 환경으로 요약할 수 있다.
다른 브랜치의 변경사항을 지금 브랜치로 가져오고 싶다면 merge 하면 된다.
지금 main 브랜치에서 변경사항을 커밋하고
premium 브랜치로 옮겨가면 main 브랜치의 변경사항은 적용되어있지 않지만
$git merge 가져올변경사항의브랜치 를 적어주면
지금 브랜치에도 변경사항이 잘 적용된 것을 확인할 수 있다.
(참고로 머지도 하나의 커밋사항이라는거!)
다른 브랜치를 merge할 때는
현재 내가 위치한 브랜치와 머지를 당하는 브랜치를 잘 구분하는게 진짜 중요하다.
퀴즈!
현재 base라는 브랜치에 있는 상태에서 extra라는 브랜치를 합병(merge)하려고 할 때 커맨드?
- git merge ( )
extra
++ Remote Repository에 있는 브랜치
Remote Repositoy에 있는 브랜치
이제 두 번째 커맨드를 설명해드릴게요.
git push -u origin master
이 커맨드의 뜻은
- 현재 로컬 레포지토리에 있는 master 브랜치의 내용(=master 브랜치와 관계된 모든 커밋들)을
- origin이라는 리모트 레포지토리로 보낸다는 뜻입니다.
이때 같은 이름의 브랜치로 전송하게 되는데 만약 origin이라는 리모트 레포지토리에 master 브랜치가 없으면 master 브랜치를 새로 생성하고 푸시합니다.
그런데 여기서 옵션 -u는 무슨 뜻일까요? -u는 --set-upstream이라는 옵션의 약자입니다.
이렇게 --set-upstream(-u) 옵션을 주면
- 로컬 레포지토리에 있는 master 브랜치가
- origin에 있는 master 브랜치를 tracking(추적)하는 걸로 설정됩니다.
tracking이라는 건 로컬 레포지토리의 한 브랜치가 리모트 레포지토리의 한 브랜치와 연결되어 그것을 계속 바라보는 상태가 되는 것이라고 생각하시면 됩니다. 이렇게 맺어진 연결 상태를 tracking connection이라고 합니다.
만약
- 로컬 레포지토리에 A라는 브랜치가 있고,
- 리모트 레포지토리에 B라는 브랜치가 있을 때
- 이런 tracking connection이 서로 맺어진 경우,
- B 브랜치를 A 브랜치의 upstream branch라고 합니다.
- 지금은 구별하기 위해서 A와 B라고 표현했지만 보통은 같은 이름인 경우가 대부분입니다.
이렇게 tracking connection이 한번 설정되고 나면,
사용자가 현재 master 브랜치에 위치해있을 때,
git push
라고만 써도 자동으로 리모트 레포지토리의 master 브랜치를 대상으로 git push가 동작하고,
git pull
라고만 써도 리모트 레포지토리의 master 브랜치를 대상으로 git pull이 동작합니다.
사실 --set-upstream(-u) 옵션을 주지 않아도 그 후에 git push와 git pull을 할 수 있기는 합니다. 하지만 맨 처음에 이 옵션을 주지 않으면 tracking connection이 없기 때문에 나중에 git push를 하고 싶을 때
git push origin master:master
이런 식으로 적어줘야 합니다. 여기서
- origin은 리모트 레포지토리를 나타내고,
- master:master에서 더 먼저 나오는 master는 로컬 레포지토리의 master 브랜치(~에서)/더 뒤에 나오는 master는 리모트 레포지토리의 master 브랜치(~으로)를 나타냅니다.
그러니까 tracking connection이 없으면 매번 이런 식으로 git push를 해줘야 합니다. git pull도 마찬가지로 이런 식의 복잡한 표현이 필요하게 됩니다.
그러니까 그냥 처음부터 tracking connection을 설정하고 그 이후부터는 git push, git pull이라고만 써서 편하게 푸시와 풀을 하는 게 좋겠죠? 이게 바로 제가 맨 처음에 로컬 레포지토리의 내용을 리모트 레포지토리로 보낼 때 -u라는 옵션을 썼던 이유입니다.
3. origin/master의 의미
자, 이제
- 로컬 레포지토리의 master 브랜치
- 리모트 레포지토리의 master 브랜치
이렇게 같은 이름이지만, 서로 다른 2개의 브랜치가 있다는 걸 알겠죠?
그럼 리모트 레포지토리에 있는 master 브랜치는 어떻게 볼 수 있을까요? GitHub 페이지에서 보면 될 겁니다.
하지만 제 컴퓨터에서도 확인할 수 있는 방법이 있습니다. 잠깐 커밋 히스토리를 살펴보면

위 그림에서
- master가 로컬 레포지토리의 master 브랜치를 나타내고
- origin/master가 리모트 레포지토리의 master 브랜치를 나타냅니다.
이때까지 로컬 레포지토리의 master 브랜치에서 여러 커밋을 했지만 그러고나서 git push를 해준 적은 없었습니다. 그래서 위 그림처럼 origin/master가 master보다 이전의 커밋을 가리키고 있는 겁니다.
다음 영상에서는 master, premium 브랜치 둘 다에서 리모트 레포지토리로 git push 하겠습니다. 그러고 나면 이제 origin/master도 master와 같은 커밋을 가리키게 될 것입니다.
++
만약 특정한 파일만 merge하고 싶을때!
https://junhobaik.github.io/git-specific-files-merge/
git 특정한 파일 병합(merge) 하기
git에서 특정한 파일만 merge 하고 싶을 때가 있다. 브랜치를 브랜치에 merge 하려하는데 특정 파일()만 병합하고 싶을 상황일 때 쓸 수 있는 방법이다. 방법 1 merge 키워드를 사용하지 않지만 아래 방
junhobaik.github.io
++
각각의 브랜치에서 수정한 사항을 머지할 때 충돌 문제!
https://project-angieangel.tistory.com/97
깃 브랜치 merge CONFLICT!
깃 브랜치 기초 merge에서 주의해야 할 사항 CONFLICT! https://project-angieangel.tistory.com/96 깃 브랜치 기초(생성, 삭제, 체크아웃, merge) 위의 현재 내가 위치한 브랜치는 main (참고로 예전에는 master..
project-angieangel.tistory.com
++새로운 커밋을 만들지 않는 merge
머지를 하면 새로운 커밋이 생긴다고 했습니다.
그리고 머지를 통해서 생겨난 커밋을 머지 커밋(merge commit)이라고 부른다고 했는데요.

이 그림을 보면 지금 master 브랜치에서 premium 브랜치를 머지해서 검은색의 머지 커밋이 생긴 것을 알 수 있습니다.
하지만 머지를 한다고 항상 이렇게 새로운 커밋이 생기는 건 아닙니다.
아래 그림를 보세요.

지금 저는 master 브랜치에 있죠? HEAD가 master 브랜치를 가리키고 있으니까요. 이 상태에서
git merge premium
을 실행하면 어떻게 될까요?
그럼 이렇게 됩니다.

premium 브랜치가 가리키던 커밋을, master 커밋도 똑같이 가리키게 되는데요. 지금 총 커밋 수는 그대로죠?
이렇게 새로운 커밋이 생기는 게 아니라 단지 브랜치가 이동하게 되는 머지를 Fast-forward 머지라고 합니다. Fast-forward는 어떤 영상이나 소리를 빨리감기(앞으로 감기)한다는 뜻인데요. 지금 master 브랜치가 더 최신 커밋으로 이동하는 모습이 꼭 빨리감기같죠?
어떤 경우에 이렇게 되는 걸까요?
커밋 히스토리에서 같은 선(line) 상에 있는 브랜치를 머지할 때 Fast-forward 머지가 이루어집니다. 방금 전에는 master 브랜치와 premium 브랜치가 둘다 같은 선 상에 있었죠? 바로 이런 경우입니다.
하지만 노트 초반부에서 봤던

이 그림처럼 두 브랜치가, 커밋 히스토리 상에서 분리된 2개의 선에 각각 존재할 때 머지를 하면 머지 커밋이 새롭게 생기는 거구요. .
그리고 이런 머지는 3-way merge라고 합니다. 이름이 3-way인 이유는 지금 1, 2, 3 표시한 3가지 커밋을 고려해서 머지를 하기 때문입니다. 지금 각각
- (1)번 : 두 갈래로 갈라지기 전 공통 조상이 되는커밋
- (2)번 : 한 브랜치가 가리키는 커밋
- (3)번 : 다른 브랜치가 가리키는 커밋
인데요. 3-way merge는 자신만의 방식을 갖고 이 3가지 커밋을 기준으로 머지 커밋을 자동으로 만들어냅니다.
그 방식에 대해서 간단하게 알려드릴게요. 아래 표에는 master 브랜치와 premium 브랜치를 머지했을 때 다양한 상황별로 그 결과가 정리되어 있는데요.
경우basemasterpremium머지 결과case1 | A | A | B | -> | B |
case2 | 1 | 2 | 1 | -> | 2 |
case3 | "hello" | (공백) | "hello" | -> | (공백) |
case4 | "bye" | "fighting" | "please" | -> | Conflict 발생! |
각 컬럼(column, 열)에 대해서 설명할게요. 지금 모든 커밋에 sample.txt 파일이 있다고 가정할게요.
- base : 두 브랜치의 공통 부모 커밋의 sample.txt 파일의 내용 중 일부 = 위 그림 (1)번
- master : 마스터 브랜치의 최신 커밋의 sample.txt 파일의 내용 중 일부 = 위 그림 (2)번
- premium : 프리미엄 브랜치의 sample.txt 파일의 내용 중 일부 = 위 그림 (3)번
- 머지 결과 : master 브랜치에서 premium 브랜치를 머지했을 때의 최종 결과
자, 각각의 경우에 왜 표와 같은 머지 결과가 생기는 건지 설명해드릴게요.
case1
지금 base가 A이고, master는 A, premium은 B죠? 그럼 base를 기준으로 볼 때, master에서는 변화가 없었지만, premium에서는 A가 B로 변경된 상태입니다. 3-way merge는 base에서 변화가 발생한 것을 우선 채택합니다. 그래서 머지 결과는 'B'가 됩니다.
case2
지금 base가 1이고, master는 2, premium은 1이죠? 이 경우에도 base에서 변화가 발생한 2가 머지 결과가 됩니다.
case3
지금 base가 "hello"이고, master는 "hello"를 삭제한 공백 상태, premium은 "hello"입니다. "hello"를 삭제해서 공백 상태가 된 것이 변화가 더 발생한 것이기 때문에 머지 결과는 공백이 됩니다.
case4
지금 base가 "bye", master가 "fighting", premium이 "please" 인데요. 지금은 이전 경우들과 좀 다르네요. 둘 다 base 때와는 다른 변화가 일어났는데요. 이렇게 두 브랜치에서 다 변화가 있을 때 Git은 어떤 변화를 선택해야할까요? 정답은 바로 'Git도 모른다!' 입니다. 사실, 바로 이런 경우에 여러분이 배운 Conflict가 발생합니다. 이전에 Conflict가 발생했을 때 그것을 해결하고 머지를 마무리했던 거 기억나시죠? 바로 이런 경우였던 겁니다.
3-way merge가 어떤 방식으로 이루어지는지 아시겠죠?
- base때의 내용과 비교했을 때 달라진 부분이 있는 것이 우선시되고,
- 두 브랜치에서 둘다 변화가 일어났을 때는 Conflict를 발생시켜서 사용자가 스스로 선택하게끔 한다는 걸 기억하시면 됩니다.
자, 이때까지 머지에 대해서 좀 깊게 배워봤습니다. 방금 배운 내용을 다 기억하지 못하더라도
머지의 종류에는 크게
- Fast-forward 머지
- 3-way 머지
이렇게 두 가지 종류가 있다는 사실만큼은 꼭 기억하세요.
++
Merge가 Already 라고 뜨는 문제!
Git merge reports "Already up-to-date" though there is a difference
I have a git repository with 2 branches: master and test. There are differences between master and test branches. Both branches have all changes committed. If I do: git checkout master git diff...
stackoverflow.com