1. 브랜치란?
브랜치란 하나의 코드 관리 흐름으로, 나뭇가지를 뜻한다. Git은 루트 커밋을 시작으로 여러번의 수정을 거치고 가지가 갈라지는 나무 모양을 하고 있다. 여기서 가지 하나하나를 브랜치라고 한다.
예를 들면 하나의 프로그램이라도 유료 버전, 무료 버전이 있을 수 있다. 이럴 때 다른 두 개의 프로젝트를 만들기 보다, 하나의 프로젝트 내에서 두 개의 브랜치를 만드는 것이 더 효율적이다.
현재까지 나는 하나의 브랜치 위에서 작업해왔다. git bash에서 git status를 입력하면 on branch main 이라고 출력되는 것을 볼 수 있다. 여기서 main 은 레포지토리를 만들고 커밋을 하면 자동으로 생기는 기본 브랜치이다.
지금까지 만든 프로젝트를 무료 버전으로 하고, 유료 버전의 브랜치를 하나 추가하도록 하겠다.
브랜치를 만들때는 git branch [브랜치의 이름] 을 입력하면 된다.
그러면 지금까지 작업한 내용들도 모두 premium 브랜치에 속하게 된다. 이제 만든 브랜치로 이동해보겠다.
브랜치를 이동할 때는 git checkout [가고싶은 브랜치이름] 을 입력한다.
그리고 현재 상태를 보면, premium 브랜치에 있다고 잘 출력된다. 이제부터 작업을 하면 premium 브랜치에만 반영되고, master 브랜치에는 반영되지 않는다.
유료 버전을 생성했으므로, license 파일에 Free 를 지우고 Premium 이라고 수정해주고 커밋까지 완료한다.
자 그러면 브랜치에 따라 license 파일의 내용이 달라졌다. 확인해보면 main 브랜치에는 Free, premium 브랜치에는 premium 이라고 출력될 것이다.
2. 브랜치 다뤄보기
현재 프로젝트에 생성된 모든 브랜치를 조회할때는 git branch 커맨드를 사용하면 된다.
여기서 현재 내가 위치한 main 브랜치 옆에는 ☆ 표시가 뜬다.
브랜치를 삭제할 때는 -d 옵션을 주면 된다. git branch -d [삭제할 브랜치 이름]
best 브랜치를 생성한 후, 삭제해 보겠다.
보통 브랜치를 생성하면 바로 해당 브랜치로 이동하는 경우가 많다. 이럴 경우 git checkout -b [생성할 브랜치 이름] 커맨드를 입력하면 브랜치 생성과 이동이 동시에 가능하다.
3. 브랜치 merge하기
무료 버전에 divide 함수를 추가해주겠다.
그런 후 main 브랜치에서 커밋해주었다.
그런데 방금 추가한 divide 함수를 유료 버전에도 추가하려면?? premium 브랜치에 가서 add하고 커밋하는 방법도 있지만, branch merge 를 이용 하면 다른 브랜치에서 했던 커밋들을 그대로 가져올 수 있다.
premium 브랜치에서 git merge main 커맨드를 입력하면 아래와 같이 뜬다.
커밋 메세지를 남길 때 출력된 화면과 같다. merge를 하면 merge 커밋이라는 새로운 커밋이 생겨서 커밋 메세지를 남기는 창이 뜨는 것이다.
:wq 를 입력해서 vim을 나간다.
그런 후 premium브랜치에서 calculator.py 파일을 출력해보면?
main브랜치를 merge 했으므로, main브랜치에서만 추가했던 devide함수가 premium브랜치에도 잘 출력된다.
4. merge할 때 conflict가 날 수도 있다
calculator.py 파일에서 divide 함수를 사진과 같이 수정하고, premium 브랜치에 커밋해주었다.
그런 다음 calculator.py 파일에서 아래와 같이 수정하고 이번엔 main 브랜치에 커밋했다.
자 정리해보면 똑같은 divide 함수를 premium 브랜치와 main 브랜치에서 서로 다른 이름으로 바꿔주었다.
여기서 premium 브랜치에 main 브랜치를 merge하면 어떻게 될까?
뭔가 CONFLICT ~~ 라고 뜬다. 뒷 문장을 해석해보면 calculator.py 파일에서 머지하는 과정에 충돌이 발생했다고 나타난다.
calculator.py 파일에는 사진과 같이 뜨고 있다. 이 부분이 conlfict가 발생한 부분이다.
사진에서 가운데 "======" 선을 기준으로 위에 HEAD 라고 되어있는 부분이 premium 브랜치에서 수정한 부분이고, 아래가 main 브랜치에서 수정한 부분이다. 이런 상황에서 git은 divide_premium과 divide_free 중에 어느 것을 반영해야할지 결정하지 못한다. 이런걸 conflict 라고 한다.
이제 해결 방법을 알아보겠다. 지금은 premium 브랜치에 main 브랜치를 merge하는 상황이다. 먼저 premium 브랜치에서 divide 함수의 이름을 결정해줘야 한다. divide_premium을 해도 되고, 아예 새로운 이름으로 정해도 된다. 나는 새로운 이름으로 정해 보겠다.
그런 후 premium 브랜치에 커밋해주었다.
merge를 하다보면 conflict가 발생하는 경우가 많다. 해결방법을 정리해보면!!
- 컨플릭트가 발생한 파일을 연다
- 머지의 결과가 되었으면 하는 모습대로 코드를 수정
- 커밋
끝!
merge.. 헷갈리는 부분이 많다. merge하면 어떤 부분들이 병합되는지? 기준을 잘 모르겠다.
license 파일의 내용이 각각 free, premium으로 다른데 왜 conflict가 일어나지 않을까 찾아보니..
서로 같은 파일에서 다른부분 수정할 땐 git이 알아서 서로 다른부분 수정한 것을 포함해서 merge하고
서로 같은 파일에서 같은부분 수정한 것을 merge할 때 conflict 충돌이 일어난다고 한다.
[출처] [14일]Git branch란? (branch, merge)|작성자 나는
블로그 참조
그러니까 정리해보면.. premium브랜치에 main브랜치를 merge한 상황이니까, main브랜치의 내용이 모두 premium브랜치에 반영되는데 같은 파일에서 같은 위치에 있는 부분 수정한 것을 merge할 때(ex. divide 함수) conflict가 발생했고,
license 파일의 경우는 같은 부분을 수정한것이라고 보지 않은 것 같다.. ?
그런데 merge하면 두 브랜치의 내용이 병합되는 줄 알았는데 ??
premium 브랜치에는 mulitply 함수를 그대로 두고, main 브랜치에서 multiply 함수를 fly라는 쌩판 다른 함수로 바꾸었다. 그런 후 premium 브랜치에서 main 브랜치를 머지해보니 fly함수도 premium브랜치에 추가될 줄 알았는데.. 안되네. 뭔가 내가 이해를 잘못하고 있는 건가 뭐야 이거 해볼수록 더 헷갈리잖아^^ 일단 merge는 전체 수강 완료 후 다시 알아보도록 하자^_^
-> 뒷부분 강의에 해설이 나오더라.. 커밋 히스토리 상에서 분리된 선에 각각 존재할 때 머지를 하면 3-way merge 방식으로 3가지 커밋을 고려해서 merge하기 때문에 저런 결과가 나왔다. License 파일에서 공통 부모 커밋의 내용이 free였고, base에서 변화가 발생한 premium이 머지 결과가 되어서 conflict가 발생하지 않았던 것!-!
5. conlfict가 났을 때 merge 자체를 취소해도 된다
앞서 설명한 방법처럼 conflict를 해결하지 않고, merge 자체를 취소하는 방법도 있다.
merge 이전의 상태로 돌아가려면 git merge --abort 커맨드를 입력하면 된다.
6. Remote Repository의 브랜치
이전에 Local Repository의 내용을 Remote Repository로 보내는 작업을 할 때
- GitHub에서 Math_Box라는 리모트 레포지토리(remote repository)를 만들고
- 로컬 레포지토리(local repository)의 내용을 그 리모트 레포지토리에 보내기위해 커맨드 2개를 실행했다.
git remote add origin https://github.com/../Math_Box.git
git push -u origin master
이번에 해당 커맨드의 의미를 알아보도록 하겠다.
git remote add origin https://github.com/../Math_Box.git
우선 이 커맨드에서 remote는 리모트 레포지토리에 관한 작업을 할 때 쓰는 커맨드이다. 그리고 그 뒤의 add는 새로운 리모트 레포지토리를 등록하겠다는 뜻이다.
그 다음에 origin https://github.com/../Math_Box.git 표현은 https://github.com/../Math_Box.git 리모트 레포지토리를 origin이라는 이름으로 등록하겠다는 뜻이다. 그러니까 이 커맨드를 실행하고 나면 https://github.com/../Math_Box.git 를 origin으로 간단하게 나타낼 수 있게 되는 것이다.
origin이 아닌 원하는 다른 단어를 입력해도 큰 상관은 없지만 Git에서는 리모트 레포지토리를 최초로 추가할 때 origin이라는 이름으로 가리키는 것이 관례화되어 있다.
git push -u origin master
이 커맨드의 뜻은 현재 로컬 레포지토리에 있는 master 브랜치의 내용(=master 브랜치와 관계된 모든 커밋들)을 origin이라는 리모트 레포지토리로 보낸다는 뜻이다. (master는 main으로 생각하기)
이때 같은 이름의 브랜치로 전송하게 되는데 만약 origin이라는 리모트 레포지토리에 master 브랜치가 없으면 master 브랜치를 새로 생성하고 푸시한다.
그런데 여기서 옵션 -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을 해줘야 한다.
리모트 레포지토리에 있는 master 브랜치는 GitHub 페이지에서 볼 수 있지만, 내 컴퓨터에서도 확인할 수 있는 방법이 있다.
위 그림에서
- master가 로컬 레포지토리의 master 브랜치를 나타내고
- origin/master가 리모트 레포지토리의 master 브랜치를 나타낸다.
이때까지 로컬 레포지토리의 master 브랜치에서 여러 커밋을 했지만 그러고나서 git push를 해준 적은 없었다. 그래서 위 그림처럼 origin/master가 master보다 이전의 커밋을 가리키고 있는 것이다.
-> 혹시나 로컬과 리모트의 저장소가 일치하지 않을 때는 git push를 했을 때 오류가 날 수 있다. 이런 경우 git push -f origin 을 사용하면 강제적으로 진행한다. 바람직한 해결 방법은 아니다. git pull 해서 merge한 후 push 하는 게 가장 안전한 방법!
7. master(=main) 브랜치와 premium 브랜치 둘다 push 하기
main 브랜치에서 git push하면 로컬 main 브랜치의 내용이 리모트 main 브랜치로 올라갈 것이다.
그리고 나서 커밋 히스토리를 보면 두 브랜치(main, origin/main)가 같은 최신 커밋에 놓여있다.
이제 premium 브랜치도 리모트 브랜치로 올려보겠다. premium 브랜치로 이동해 git push를 입력해주면..
띠용 오류가 뜬다. 내용을 보면 premium 브랜치가 upstream 브랜치를 가지고 있지 않다고 뜬다. 아래줄엔 git push --set-upstream origin premium 을 실행하라고 뜬다.
이전 챕터에서 설명했듯, 로컬 레포지토리의 내용을 리모트 레포지토리에 처음 보낼땐 tracking 정보 설정을 위해 --set-upstream 옵션을 줘야한다. 오류창에 뜬 대로 커맨드를 입력해보겠다.
그런다음 깃허브에 잘 올라갔는지 확인해보겠다.
git bash에서 커밋 히스토리를 보면 최신 커밋에 리모트 레포지토리의 premium 브랜치(origin/premium)도 잘 보인다.
'1. 프로그래밍 > 1-1. Git' 카테고리의 다른 글
6. Git 협업하기 (0) | 2021.09.05 |
---|---|
5. 브랜치 사용하기 (2) - [ git reset / checkout / merge ] (0) | 2021.09.05 |
4. 커밋 다루기 - [ commit history / 커밋 메세지 / HEAD / git reset ] (0) | 2021.08.31 |
3. GitHub 시작하기 - [ Git hub / Remote Repository / 사용자 초대 / Readme.md ] (0) | 2021.08.24 |
2. Git 써보기 - [ repository / commit / add ] (0) | 2021.08.19 |