📌 연습 중인 git branching 사이트
Learn Git Branching
An interactive Git visualization tool to educate and challenge!
종합선물세트
Level 1. 딱 한 개의 커밋만 가져오기
개발 중에 종종 이런 상황이 생긴다.
눈에 잘 띄지 않는 버그를 찾아서 해결하려고 어떤 부분의 문제인지를 찾기 위해 디버그용 코드와 화면에 정보를 프린트하는 코드를 몇 줄 넣는다.
디버깅용 코드나 프린트 명령은 그 브랜치에 들어있다. 마침내 버그를 찾아서 고쳤고, 원래 작업하는 브랜치에 합치면 된다!
이제 bugFix 브랜치의 내용을 main에 합쳐 넣으려 하지만, 단순히 main 브랜치를 최신 커밋으로 이동시킨다면(fast-forward) 그 불필요한 디버그용 코드들도 함께 들어가 버린다는 문제가 생긴다.
이 문제를 해결하는 여러가지 방법이 있지만, 가장 간단한 2가지 방법은 아래와 같다.
(1) git rebase -i
- 어떤 commit을 취하거나 버릴지를 선택할 수 있다.
- commit의 순서를 바꿀 수도 있다.
- 어떤 작업의 일부만 골라내기에 유용하다.
(2) git cherry-pick
- 개별 commit을 골라서 HEAD 위에 떨어뜨릴 수 있다.
🗒️문제🗒️
이번 레벨을 통과하기 위해 어떤 방법을 쓰시든 자유입니다만, main브랜치가 bugFix 브랜치의 커밋을 일부 가져오게 해주세요.
이번 문제는 오른쪽의 목표와 꼭 같은 형태가 될 필요 없이, bugFix 브랜치의 C4 commit을 main 브랜치로 이동만 시키면 되는 문제였다. 다양한 방법이 있겠지만 나는 아래의 과정대로 진행해서 통과했다.
1) git checkout main
: main 브랜치로 이동
2) git cherry-pick C4
: C4 commit을 main 브랜치로 복사해서 C4' commit 생성
Level 2. 커밋들 갖고 놀기
🗒️문제🗒️
이번에도 꽤 자주 발생하는 상황이다.
newImage와 caption 브랜치에 각각의 변경내역이 있고 서로 약간 관련이 있어서, 저장소에 차례로 쌓여있는 상황이다.
때로는 이전 commit의 내용을 살짝 바꿔야하는 골치아픈 상황에 빠지게 된다.
이번에는 디자인 쪽에서 우리의 작업이력(history)에서는 이미 한참 전의 commit 내용에 있는 newImage의 크기를 살짝 바꿔 달라는 요청이 들어왔다.
이 문제를 풀기 위한 많은 방법이 있겠지만 (체리픽도 가능) 우선은 다음과 같은 방법으로 해결해보자.
1) git rebase -i 명령으로 우리가 바꿀 commit을 가장 최근 순서로 바꾸기
2) git commit --amend 명령으로 커밋 내용을 정정한다.
3) 다시 git rebase -i 명령으로 이전의 commit 순서대로 되돌려 놓는다.
4) 마지막으로, main을 지금 트리가 변경된 부분으로 이동한다.
최종적으로 목표 결과를 봤을 때, 우리가 commit을 2번 옮겼기 때문에, 두 커밋 모두 따옴표 표시가 붙어있다. 정정한(ammend) commit은 따옴표가 추가로 하나 더 붙어있다.
문제에서 풀이 과정이 다 나와 있어서 그대로 git 명령어로만 바꿔서 구현했다.
1) git rebase -i HEAD~2
: 현재 위치인 HEAD에서부터 2번 뒤에 있는 commit인 C1 리베이스의 목적지로 설정하고, 그 사이에 있는 commit들을 보여주는 interactive rebase 대화창을 띄운다. + 여기서 C2, C3 commit의 순서를 바꿔준다.
2) git commit --amend
: 현재 위치인 C2' commit 내용을 정정한다. => C2'' commit 생성
3) git rebase -i HEAD~2
: 이전의 commit 순서로 돌려놓는다.
4) git branch -f main caption
: main 브랜치를 지금 변경된 부분인 caption 브랜치로 이동시킨다.
Level 3. 커밋들 갖고 놀기 #2
Level 2에서 봤듯이 rebase -i
명령으로 commit의 순서를 바꿀 수 있다. 정정할 commit이 바로 직전(top)에 있으면 간단히 --amend
로 수정할 수 있고, 그리고 나서 다시 원하는 순서로 되돌려 놓으면 된다.
이 방법의 한가지 문제는 순서를 꽤 많이 바꿔야한다는 점인데, 그러다가 리베이스 중에 충돌이 날 수 있다.
이번에는 다른 방법인 git cherry-pick
으로 해결해 보자!
전에도 공부했듯이 git cherry-pick
은 HEAD에다 어떤 커밋읻느 떨어뜨려 놓을 수 있다. (단, 그 commit이 현재 가리키고 있는 commit이 아니어야 함)
🗒️문제🗒️
그럼 이번 레벨에서는 아까와 마찬가지로 C2 커밋의 내용을 정정하되, rebase -i를 쓰지 말고 해보세요. ^.~
1) git checkout main
: main 브랜치로 이동
2) git cherry-pick C2
: C2 commit을 main 브랜치로 복사해서 C2' commit 생성
3) git commit --amend
: 현재 위치인 C2' commit 내용을 정정한다. => C2'' commit 생성
4) git cherry-pick C3
: C3 commit을 main 브랜치로 복사해서 C3' commit 생성
Level 4. Git 태그
이전 강의에서 배웠듯이, 브랜치는 이동하기 쉽다.
작업의 완료, 진행에 따라 이리저리 이동하면서 서로 다른 commit을 참조하게 된다.
브랜치는 쉽게 변하며 임시적인 것으로 항상 바뀌고 있다.
이런 상황에서, 프로젝트의 history(작업 이력)에서 중요한 지점들에 "영구적으로" 표시를 할 방법이 없을까 궁금할 것이다.
주요 릴리즈나 큰 브랜치 병합(merge)이 있을 때가 그런 상황일 것이다.
이런 상황에 commit들을 표시할 브랜치보다 영구적인 방법이 바로 Git 태그이다.
Git 태그는 특정 commit들을 브랜치로 참조하듯이 영구적인 milestone(이정표)으로 표시한다.
중요한 점은, git 태그는 commit들이 추가적으로 생성되어도 절대! 움직이지 않는다는 것이다.
태그를 '체크아웃' 한 후에 그 태그에서 어떤 작업을 완료할 수 없다.
태그는 commit 트리에서 특정 지점을 표시하기 위한 닻같은 역할을 한다.
예를 들어, C1에 v1이라는 태그를 만들어 보자.
git tag v1 C1
: 태그 이름을 v1이라고 짓고, commit C1을 지정해서 참조
만약 지정해주지 않으면 git은 HEAD가 있는 지점에 태그를 붙인다.
🗒️문제🗒️
이번 레벨에서는 goal에 나타난것과 같이 태그를 만들고 v1을 체크아웃하면 됩니다. 분리된 HEAD 상태로 변하는것을 확인 해 보십시오 -- 이것은 v1 태그에 직접 커밋을 할 수 없기 때문입니다.
다음 레벨에서는 태그의 더 흥미로운 활용 방법을 확인해 볼 것입니다.
1) git tag v0 C1
: 태그 이름을 v0라고 짓고, commit C1을 지정해서 참조
2) git checkout HEAD^
: HEAD의 부모인 C2 commit으로 이동
3) git tag v1
: commit을 별도로 지정하지 않았기 때문에 현재 HEAD가 있는 위치인 C2 commit 에 v1 태그 붙이기
Level 5. Git describe (묘사)
커밋 트리에서 태그가 훌륭한 '닻' 역할을 하기 때문에, git에는 가장 가까운 닻(=태그)에 비해 상대적으로 어디에 위치해 있는지 describe(묘사) 해주는 명령어가 있다. 이 명령어가 git describe이다!
git describe
는 커밋 히스토리에서 앞 뒤로 여러 커밋을 이동하고 나서 커밋 트리에서 방향감각을 다시 찾는데 도움을 준다.
🌟git describe <ref>
이런 형태로 쓰이는데, <ref>
에는 commit을 의미하는 어떤 것이든 쓸 수 있다!
만약 ref
를 특정 지어주지 않으면, git은 그냥 지금 체크아웃된 곳(=HEAD)을 사용한다.
명령어의 출력은 다음과 같은 형태로 나타난다.
🌟<tag>_<numCommits>_g<hash>
tag
: 가장 가까운 부모 태그를 나타낸다.numCommits
: 그 태그가 몇 commit 멀🌞리 있는지를 나타낸다.<hash>
: 묘사하고 있는 commit의 해시를 나타낸다.
예를 들어..
이 상황에서 아래의 2가지 입력에 대해서는 각각 오른쪽과 같은 출력이 나온다.
git describe main
=> v1_2_gC2
git describe side
=> v2_1_gC4
🗒️문제🗒️
이정도면 git describe를 충분히 활용할 수 있습니다! 이 레벨의 몇 지점을 describe 명령어를 통해 확인해보면서 느낌을 익혀 봅시다.준비가 되면 커밋을 한번해서 레벨을 종료하세요. 자유롭게 연습해보세요 :P
🌞 ref에 브랜치명을 사용한 경우
git describe main
=>v0_2_gC2
git describe side
=>v1_1_gC4
git describe bugFix
=>v1_2_gC6
🌞 ref에 commit 해시를 사용한 경우
git describe C2
=>v0_2_gC2
git describe C4
=>v1_1_gC4
git describe C6
=>v1_2_gC6
git describe C1
=>v0_1_gC1
🌞 ref에 아무것도 특정하지 않은 경우 (HEAD 위치 기준)
git describe
=>v1_2_gC6
🌞 ref에 태그가 붙어 있는 commit의 해시를 사용한 경우
git describe C0
=>v0
git describe C3
=>v1