브랜치란?
브랜치(Branch)는 원래 나뭇가지라는 의미이다.
버전 관리 시스템에서는 나무가 가지에서 새 줄기를 뻗듯이 여러 갈래로 퍼지는 데이터 흐름을 가리키는 말로 사용된다.
브랜치가 필요한 이유
예시)
사용 설명서를 만든다고 상상해보자. 이때, 사용 설명서의 버전 관리는 깃으로 한다.
제품 출시 전에는 아래 그림처럼 개발 순서에 따라 사용 설명서를 작성하면 된다.
그러나 문제는 고객사마다 추가로 요구하는 내용이 다른 것이다. 이를 반영하면 고객사에 따라 제품이 달라질 것이고 이에 맞춰 사용 설명서도 달라져야 한다.
만일 처음에 작성했던 저장소(아래 그림의 master) 전체를 여러 개 복사해서 각 고객사(아래 그림의 apple, google, ms)의 이름을 붙인 다음 저장소마다 버전 관리를 따로 하는 방법이 있다.
그러나 위 방법은 효율적이지 않다. 고객사마다 디렉터리를 복사하면 자료가 중복되기 때문이다. 그리고 고객사마다 디렉터리 이름을 다르게 사용해야 하기 때문에 버전 관리 시스템의 장점 중 하나인 파일 이름을 더럽히지 않는 것이 적용되지 않는다.
만일 google의 'GH' 내용이 apple 에서도 필요하다면 어떻게 해야 할까? 'GH' 버전에서 필요한 부분의 코드만 복사하여 붙여 넣으면 'GE'와 'GF' 버전을 만들 때 수정한 내용이 'AE'에 반영되어 있지 않기 때문에 오류가 발생할 수 있다. 그렇다고 'GG' 버전 코드 전체를 그대로 덮어 버리면 'AE' 버전을 만들면서 수정한 내용이 바뀌거나 사라질 수 있다.
즉, 브랜치를 사용해야 한다.
브랜치 기능 살펴보기
깃으로 버전 관리를 시작하면 기본적으로 master라는 브랜치가 만들어진다. 사용자가 커밋할 때마다 master 브랜치는 최신 커밋을 가리킨다. 즉, 브랜치는 커밋을 가리키는 포인터라고 생각하면 된다.
새 브랜치를 만들면 기존에 저장한 파일을 master 브랜치에 그대로 유지하면서 기존 파일 내용을 수정하거나 새로운 기능을 구현할 파일을 만들 수 있다. master 브랜치에서 뻗어 나오는 새 브랜치를 만드는 것을 분기(branch)라고 한다.
새 브랜치에서 원하는 작업을 다 끝냈다면 새 브랜치에 있던 파일을 원래 master 브랜치에 합칠 수 있다. 분기했던 브랜치를 master 브랜치에 합치는 것을 병합(merge)라고 한다.
브랜치 만들기
실습 상황 설정하기
1. manual이라는 새 디렉터리를 만들고 해당 디렉터리로 이동한다.
$ mkdir manual
$ cd manual
2. manual 디렉터리를 저장소로 만들고 ls -al 명령을 사용하여 .git 디렉터리 만들어졌는지 확인한다.
$ git init
$ ls -al
3. manual 디렉터리에 work.txt 파일을 만든다.
$ vim work.txt
4. 'content 1'이라는 내용을 입력한 다음 저장한다.
5. 방금 만든 work.txt 파일을 스테이지에 올리고 커밋한다. 커밋 메시지는 'work 1'이라고 한다.
$ git add work.txt
$ git commit -m "work 1"
6. 커밋이 완료되면 커밋 내역을 확인해본다.
$ git log
7. work.txt 파일을 두 번 더 커밋한다. 먼저 work.txt 파일에 'content 2'를 추가한 후 'work 2'라는 메시지와 함께 커밋한다.
$ vim work.txt
$ git commit -am "work 2"
8. 그리고 work.txt 파일에 'content 3'를 추가한 후 'work 3'라는 메시지와 함께 커밋한다.
$ vim work.txt
$ git commit -am "work 3"
9. 커밋이 끝나면 'git log'를 입력해서 커밋 내역을 확인한다. 커밋 메시지가 'work 1', 'work 2', 'work 3'인 커밋들이 보일 것이다. master 브랜치가 가장 최신 커밋인 'work 3'을 가리키고 있고, HEAD가 master 브랜치를 가리키고 있다. HEAD는 여러 브랜치 중에서 현재 작업 중인 브랜치를 가리킨다.
새 브랜치 만들기
1. 깃에서 브랜치를 만들거나 확인하는 명령은 git branch이다.
$ git branch
2. master는 특별한 브랜치이다. 저장소를 만들 때 기본적으로 master 브랜치가 만들어진다. 그동안 master 브랜치에서 작업하고 있었던 것이다.
3. 새로운 브랜치를 만들려면 git branch 명령 다음에 만들려는 브랜치 이름을 적는다.
$ git branch apple
4. apple 브랜치가 제대로 만들어졌는지 확인한다.
$ git branch
5. master 브랜치 위에 apple 브랜치가 추가된 것을 확인할 수 있다. master 앞에 * 표시는 아직 우리가 master 브랜치에서 작업하고 있다는 뜻이다.
6. 브랜치가 추가된 후에는 커밋 로그 화면도 다르게 나타난다. git log 명령을 통해 확인하면 (HEAD -> master, apple)로 바뀌어져 있다. master, apple 2개의 브랜치가 있고 HEAD -> master이므로 현재 작업 중인 브랜치는 master 브랜치라는 의미이다.
7. google 브랜치와 ms 브랜치를 만들어본다. 그 후, git branch 명령으로 저장소 안에 있는 모든 브랜치를 확인한다.
$ git branch google
$ git branch ms
$ git branch
브랜치 사이 이동하기 - git checkout
브랜치를 여러 개 만들었으면 각 브랜치를 오가면서 작업할 수 있어야 한다.
1. git log로 확인하면 master 브랜치를 비롯하여 ms, google, apple 브랜치가 'work 3' 커밋 상태에서 만들어진 것을 확인할 수 있다. master 브랜치 뿐만 아니라 ms와 google, apple 브랜치에도 최신 커밋이 'work 3'라는 뜻이다.
2. 현재 master 브랜치에 있다는 것을 기억하자. 커밋을 하나 더 만든다. work.txt 파일 안에 'master content 4'라는 내용을 추가한 후 'master work 4'라는 메시지와 함께 커밋한다.
$ vim work.txt
$ git commit -am "master content 4"
3. matser 브랜치에 새로운 커밋이 추가되었다. git log --oneline 을 사용하여 확인한다. --oneline 옵션은 한 줄에 한 커밋씩 나타내 주기 때문에 커밋을 간략하게 확인할 때 편리하다.
$ git log --oneline
4. 최신 커밋인 'master work 4'는 master 브랜치에만 적용되어 있다. ms와 google, apple 브랜치는 아직 'work 3' 커밋 상태이다.
5. 다른 브랜치로 이동하려면 'git checkout' 명령 다음에 브랜치 이름을 사용한다. apple 브랜치로 이동하는 것을 'apple 브랜치로 체크아웃한다'라고 말한다.
$ git checkout apple
6. $ 위에 나타난 파일 경로 끝에 (apple)이라고 표시된다. 현재 브랜치가 apple이라는 뜻이다.
7. git log 명령을 사용해 현재 브랜치의 커밋 로그를 확인한다.
$ git log --oneline
8. master 브랜치에서 apple 브랜치를 분기하기 전까지 master 브랜치에 있던 커밋들은 그대로 apple 브랜치에 복사된 것을 확인할 수 있다. 최신 커밋 해시에서 HEAD가 apple을 가리키고 있다.
9. work.txt 파일에 무엇이 있는지 cat 명령을 통해 확인한다. 최신 커밋이 work3 이기 때문에 content 1 부터 content 3까지 세 개의 행만 존재한다. apple 브랜치가 master 브랜치에서 분기된 이후에 master 브랜치에 추가된 커밋은 apple 브랜치에 영향을 미치지 않았단 것을 알 수 있다.
$ cat work.txt
브랜치 정보 확인하기
여러 브랜치에서 각각 커밋이 이루어질 때 커밋끼리 어떤 관계를 하고 있는지 확인하는 방법과 브랜치 사이의 차이점을 확인하는 방법을 알아보자.
새 브랜치에서 커밋하기
apple 브랜치에 새로운 커밋을 만든다. 현재는 apple 브랜치로 체크아웃한 상태이다.
1. apple 브랜치에는 work.txt 파일이 있다. 이 파일을 열고 'apple content 4'를 추가하고 저장한다.
$ vim work.txt
2. apple.txt라는 새로운 파일도 만든다. 'apple content 4'라는 텍스트를 입력하고 저장한다.
$ vim apple.txt
3. 수정된 2개의 파일을 각각 스테이지에 올릴 수도 있지만 git add 뒤에 마침표(.)를 추가하면 현재 저장소에서 수정된 파일을 한꺼번에 스테이지에 올릴 수 있다.
$ git add .
$ git commit -m "apple content 4"
4. 커밋이 어떻게 저장되어 있는지 git log 명령으로 확인한다.
$ git log --oneline
5. (HEAD -> apple)이라고 되어 있으니 현재 apple 브랜치에 체크아웃한 상태이고, apple 브랜치의 최신 커밋은 'apple content 4'이다.
6. git log 명령에 --branches 옵션을 사용하면 각 브랜치의 커밋을 함께 볼 수 있다.
$ git log --oneline --branches
7. 커밋 해시마다 오른쪽에 (HEAD -> apple), (master), (ms, google)이다. master 브랜치의 최신 커밋은 'master content 4'이고 ms 브랜치와 google 브랜치의 최신 커밋은 'work 3'이다.
8. 브랜치와 커밋의 관계를 그래프 형태로 보고자 하면 git log 명령에 --graph 옵션을 함께 사용한다.
$ git log --oneline --branches --graph
9. 커밋 내역 왼쪽에 수직선(|)은 커밋과 커밋의 관계를 보여주는 것이다. apple 브랜치의 최신 커밋은 'apple content 4'인데 점선을 따라 'apple content 4' 커밋의 부모를 찾아가 보면 'work 3' 커밋을 만나게 된다. 즉, apple 브랜치에서는 'work 3' 커밋 다음에 'apple content 4' 커밋이 만들어졌다는 의미이다.
10. master 브랜치의 최신 커밋은 'master content 4'이다. 그리고 수직선을 따라가 부모 커밋을 찾아보면 'work 3' 커밋이다. apple 브랜치의 커밋과 master 브랜치의 커밋이 같은 부모 커밋을 가지고 있다. 즉, master 브랜치나 apple 브랜치는 'work 3' 커밋까지는 같고 그 이후부터 브랜치마다 다른 커밋을 만들었다는 사실을 알 수 있다.
브랜드 사이의 차이점 알아보기
브랜치마다 커밋이 점점 쌓여갈수록 브랜치 사이에 어떤 차이가 있는지 일일이 확인하기 어려워진다. 브랜치 이름 사이에 마침표 두 개(..)를 넣는 명령으로 차이점을 쉽게 확인할 수 있다. 브랜치 이름과 마침표 사이는 공백없이 입력하며, 마침표 왼쪽에 있는 브랜치를 기준으로 오른쪽 브랜치와 비교한다.
$ git log master..apple
이렇게 하면 master 브랜치에는 없고 apple 브랜치에만 있는 커밋, 즉, 'apple content 4' 커밋을 보여준다.
$ git log apple..master
apple 브랜치에는 없고 master 브랜치에만 있는 'master content 4' 커밋을 보여준다.
브랜치 병합하기
브랜치 작업을 마무리하고 기존 브랜치와 합치는 것을 브랜치 병합(merge)라고 한다.
서로 다른 파일 병합하기
새로운 저장소를 만들어서 필요한 브랜치와 커밋만 사용하여 연습해보자.
1. 홈 디렉터리에서 manual-2라는 깃 저장소를 만든다. git init 다음에 디렉터리 이름을 입력하면 새로운 디렉터리를 만들고 저장소를 초기화하는 과정을 한꺼번에 처리할 수 있다. manual-2 디렉터리로 이동한 후 ls -al 명령을 사용하면 .git/ 디렉터리가 만들어진 것을 확인할 수 있다.
$ cd ~
$ git init manual-2
$ cd manual-2
$ ls -al
2. 빔에서 work.txt 파일을 만들고 '1'을 입력한 후 저장한다. 그 후 'work 1'이라는 커밋 메시지와 함께 커밋한다.
$ vim work.txt
$ git add work.txt
$ git commit -m "work 1"
3. 'o2'라는 브랜치를 만든다.
$ git branch o2
4. 현재 master 브랜치에 master.txt 라는 파일을 하나 더 만든다. 빔에서 'master 2'라는 내용일 입력하고 저장한다. 그리고 'master work 2' 라는 메시지와 함께 커밋한다.
$ vim master.txt
$ git add master.txt
$ git commit -m "master work 2"
5. o2 브랜치로 체크아웃한다.
$ git checkout o2
6. o2 브랜치에서 o2.txt 라는 파일을 만들고 'o2 2'라는 내용을 저장한다. 'o2 work 2'라는 메시지와 함께 커밋한다.
$ vim o2.txt
$ git add o2.txt
$ git commit -m "o2 work 2"
7. git log 명령을 사용해서 현재 커밋의 상태를 확인한다. 커밋 'work 1'은 master 브랜치와 o2 브랜치가 똑같이 가지고 있다. master 브랜치에는 'master work 2' 커밋이 생겼고 o2 브랜치에는 'o2 work 2' 커밋이 생겼다.
$ git log --oneline --branches --graph
8. o2 브랜치에서 작업이 다 끝났다고 가정하고 o2 브랜치의 내용을 master 브랜치로 병합한다. 브랜치를 병합하려면 먼저 master 브랜치로 체크아웃 해야 한다. (나는 master가 아니라 main으로 작성)
$ git checkout master
9. 브랜치를 병합하려면 git merge 명령 뒤에 가져올 브랜치 이름을 적는다.
$ git merge o2
10. 자동으로 빔이 실행되면서 'Merge branch o2'라는 커밋 메시지가 나타난다. 브랜치를 병합하면서 만들어지는 커밋 메시지이다. 커밋 메시지를 수정할 수도 있고, 자동 메시지를 그대로 사용해도 된다.
11. ls -al 명령을 사용하여 확인하면 o2 브랜치에 있던 o2.txt 파일이 master 브랜치에 합쳐졌음을 알 수 있다.
12. git log --oneline --branches --graph 명령으로 브랜치와 커밋들이 어떻게 병합되었는지 확인할 수 있다. 'o2 work 2' 커밋이 master 브랜치에 병합되면서 'Merge branch o2'라는 커밋이 새로 생긴다.
빨리 감기 병합
master 브랜치에서 브랜치를 분기한 후에 master 브랜치에 아무 변화가 없다면 분기한 브랜치를 병합하는 것은 간단하다. 분기한 브랜치에서 만든 최신 커밋을 master 브랜치가 가리키게만 하면 되기 때문이다. 화면에 커밋 해시가 업데이트되었다는 내용과 함께 fast-forward라는 메시지가 나타난다. 이런 병합을 빨리 감기 병합(fast-forward merge)라고 한다. git merge 명령의 결과가 단순히 포인터를 움직인 것이기 때문에 따로 커밋 메시지 창은 열리지 않는다.
브랜치를 병합할 때 편집기 창이 열리지 않게 하려면
브랜치를 병합할 때 자동으로 편집기가 실행되면서 커밋 메시지를 추가 작성할 수 있다. 만약 편집기 창을 열지 않고 깃에서 지정하는 커밋 메시지를 그대로 사용하겠다면 --no-edit 옵션을 추가한다.
$ git merge o2 --no-edit
브랜치를 병합할 때 편집기 창이 나타나지 않도록 설정한 경우, 커밋 메시지를 추가하거나 수정하고 싶다면 병합 명령에 --edit 옵션을 사용한다.
$ git merge o2 --edit
같은 문서의 다른 위치를 수정했을 때 병합하기
master 브랜치와 o2 브랜치에는 똑같이 work.txt 파일이 있다. 양쪽 브랜치에서 work.txt 문서를 수정하되 서로 다른 위치를 수정한 후 브랜치를 병합하면 어떻게 될까?
1. 홈 디렉터리로 이동한 후 manual-3이라는 깃 저장소를 만들고 manual-3 디렉터리로 이동한다.
$ cd ~
$ git init manual-3
$ cd manual-3
2. 빔에서 work.txt 파일을 만든다. 나중에 work.txt 문서를 수정하고 병합할 것이기 때문에 내용 사이에 두 줄의 공백을 두었다.
3. work.txt를 스테이지에 올리고 커밋한다. 커밋 메시지는 'work 1'이라고 한다.
$ git add work.txt
$ git commit -m "work 1"
4. 'work 1'이라는 커밋을 만들었으므로 o2라는 새로운 브랜치를 만든다. 그러면 master 브랜치와 o2 브랜치에 모두 'work 1' 커밋이 있다.
$ git branch o2
5. 먼저 master 브랜치의 work.txt를 수정한다.
$ vim work.txt
6. work.txt 문서에는 '#title'과 'content'가 2개씩 있다. 그 중 첫 번째 'content' 다음 줄에 'master content 2'라고 입력한 후 저장한다.
7. 수정한 work.txt를 커밋하고 커밋 메시지는 'master work 2'라고 한다.
$ git commit -am "master work 2"
8. o2 브랜치의 work.txt 파일을 수정한다. 먼저 o2 브랜치로 체크아웃하고 work.txt 파일을 불러온다.
$ git checkout o2
$ vim work.txt
9. 두 번째 'content' 다음 줄에 'o2 content 2'라고 입력하고 저장한다.
10. 수정한 work.txt 파일을 커밋하고 커밋 메시지는 'o2 work 2'라고 한다.
$ git commit -am "o2 work 2"
11. master 브랜치와 o2 브랜치 양쪽에서 work.txt 파일을 수정했지만 문서 안의 수정 위치는 다르다. o2 브랜치를 master 브랜치에 합치기 위해 master 브랜치로 체크아웃한다. (나는 master가 아닌 main)
$ git checkout master
12. git merge 명령을 사용해 o2 브랜치를 master 브랜치로 끌어온다.
$ git merge o2
13. 자동으로 빔이 실행되면서 커밋 메시지가 나타난다. 메시지를 수정할 수도 있고 그대로 사용할 수도 있다.
14. 터미널 창에는 'Auto-merging work.txt'로 시작하는 병합 완료 메시지가 나타난다. cat 명령을 사용하여 work.txt 파일을 확인한다.
$ cat work.txt
15. master 브랜치의 수정 내용과 o2 브랜치의 수정 내용이 자연스럽게 하나의 파일에 합쳐진 것을 볼 수 있다.
같은 문서의 같은 위치를 수정했을 때 병합하기
깃에서는 줄 단위로 변경 여부를 확인한다. 깃 브랜치에 같은 파일 이름을 가지고 있으면서 같은 줄을 수정했을 때 브랜치를 병합하면 브랜치 충돌(conflict)이 발생한다.
1. 홈 디렉터리로 이동한 후 manual-4라는 깃 저장소를 만들고, manual-4 디렉터리로 이동한다.
$ cd ~
$ git init manual-4
$ cd manual-4
2. 빔에서 work.txt 파일을 만든다.
3. 방금 만든 work.txt를 스테이지에 올리고 커밋한다. 커밋 메시지는 'work 1'이라고 한다.
$ git add work.txt
$ git commit -m "work 1"
4. o2 브랜치를 만든다. o2 브랜치는 만들어 지면서 master 브랜치의 최신 커밋을 가져온다. 즉, 브랜치 양쪽에 work.txt가 있다.
$ git branch o2
5. 현재 브랜치는 master이고 이 브랜치에서 work.txt를 수정한다.
$ vim work.txt
6. 빈 공간에 'master content 2'를 입력하고 저장한다.
7. 수정한 work.txt를 커밋하고 커밋 메시지는 'master work 2'라고 한다.
$ git commit -am "master work 2"
8. o2 브랜치의 work.txt 파일도 수정한다. 먼저 o2 브랜치로 체크아웃하고 work.txt 파일을 연다.
$ git checkout o2
$ vim work.txt
9. master 브랜치에서 추가 내용을 입력했던 위치와 같은 곳에 'o2 content 2'라고 입력하고 저장한다.
10. 수정한 work.txt 파일을 커밋하고 커밋 메시지는 'o2 work 2'라고 한다.
$ git commit -am "o2 work 2"
11. master 브랜치와 o2 브랜치 양쪽에서 work.txt 파일을 수정했지만 문서 안의 수정 위치가 같다. 먼저 master 브랜치로 체크아웃한다. (master가 아니라 main으로 함)
$ git checkout master
12. git merge 명령을 사용해 o2 브랜치를 master 브랜치로 끌어온다.
$ git merge o2
13. git merge 명령을 실행했을 때 자동으로 빔이 열리지 않고 메시지가 나타난다. 이때, 충돌(conflict)이 발생했다는 의미이다.
14. 충돌이 생긴 문서는 자동으로 병합될 수 없으므로 직접 충돌 부분을 해결한 후 커밋해야 한다. 빔에서 work.txt를 연다.
$ vim work.txt
15. 이는 master 브랜치에 있던 내용과 o2 브랜치에 있던 내용이 한꺼번에 나타났다. '<<<<<<< HEAD'와 가운데 가로줄 사이의 내용은 현재 브랜치인 master 브랜치에서 수정한 내용이다. 가로줄과 '>>>>>>> o2' 사이의 내용은 o2 브랜치에서 수정한 내용이다. 직접 내용을 수정해야 한다.
16. 내용을 원하는 대로 수정하면 문서는 수정되어 있다. 문서를 저장하고 편집기를 저장한다.
17. 수정한 work.txt를 스테이지에 올리고 커밋한다. 커밋 메시지는 'merge o2 branch'라고 한다. 이처럼 work.txt의 충돌을 해결하고 커밋한다.
$ git commit -am "merge o2 branch"
18. git log 명령에 --oneline과 --branches, --graph 옵션을 사용하면 지금까지 만든 브랜치와 커밋의 관계를 한눈에 확인할 수 있다.
$ git log --oneline --branches --graph
병합 및 충돌 해결 프로그램
프로젝트의 규모가 클수록 브랜치가 많으므로 브랜치에서 병합해야 할 파일도 많아진다. 그만큼 충돌이 많이 생긴다. 그래서 깃의 브랜치 병합을 자동으로 처리해 주고 충돌을 해결해 주는 프로그램이 많다. 병합 알고리즘에는 2 way merge와 3 way merge가 있는데 3 way merge가 훨씬 효율적이므로 이를 선택하는 것이 좋다.
프로그램 이름 | 설명 |
P4Merge | 무료이고 직관적이며 사용이 편리하고 병합 기능이 뛰어난다. 단축키가 지원되지 않는 단점이 있다. |
Meld | 무료이며 오픈 소스이다. 파일을 비교하는 것뿐만 아니라 직접 편집할 수 있다. |
Kdiff3 | 무료이고 사용이 편리하고 병합 기능이 뛰어나지만 한글이 깨져 보일 수 있다. |
Araxis Merge | 유료지만 용량이 큰 파일에서도 잘 동작한다. |
병합이 끝난 브랜치 삭제하기
브랜치를 병합한 후 더 이상 사용하지 않는 브랜치는 깃에서 삭제할 수 있다. 브랜치를 삭제하더라도 이 브랜치가 완전히 지워지는 것이 아니라 다시 같은 이름의 브랜치를 만들면 예전 내용을 다시 볼 수 있다.
1. git branch 명령을 사용하면 현재 저장소에 어떤 브랜치가 있는지 확인할 수 있다.
$ git branch
2. 저장소의 기본 브랜치는 master이므로 브랜치를 삭제하려면 master 브랜치에서 해야 한다.
$ git checkout master
3. 브랜치를 삭제할 때는 git branch 명령에 -d 옵션을 사용한다.
$ git branch -d o2
master 브랜치에 병합하지 않은 브랜치를 삭제하려면 오류 메시지가 나타납니다. 이럴 때 옵션 -d 대신 -D를 사용해서 강제로 브랜치를 삭제할 수 있다.
4. 'Deleted branch o2' 처럼 메시지가 나타나면 성공적으로 브랜치가 삭제된 것이다. 다만, 브랜치를 삭제한다는 것은 완전히 저장소에서 없애는 것이 아니라 깃의 흐름 속에서 감추는 것이라고 생각하면 된다.
브랜치 관리하기
브랜치에서 checkout과 reset의 작동 원리
1. 홈 디렉터리로 이동한 후 test라는 깃 저장소를 만들고, test 디렉터리로 이동한다.
$ cd ~
$ git init test
$ cd test
2. 빔에서 c1.txt 파일을 만들고 숫자 '1'을 입력하고 저장한다. c1.txt를 스테이지에 올리고 커밋한다. 커밋 메시지는 'c1'이라고 한다.
$ vim c1.txt
$ git add c1.txt
$ git commit -m "c1"
3. git log 명령을 실행한다. 커밋 로그 첫 번째 줄에 (HEAD -> master) 표시가 있다. 여기서 HEAD는 현재 작업 트리가 어떤 버전을 기반으로 작업 중인지를 가리키는 포인터이다. HEAD는 기본적으로 master 브랜치를 가리킨다. 브랜치는 기본적으로 브랜치에 담긴 커밋 중에서 가장 최근 커밋을 가리킨다.
$ git log --oneline
4. sub라는 브랜치를 만든다. sub 브랜치 또한 c1 커밋을 가리킨다.
$ git branch sub
5. 다시 한 번 빔에서 c2.txt 파일을 만들고 숫자 '2'를 입력한 후 저장한다. c2.txt를 스테이지에 올리고 'c2'라는 메시지와 함께 커밋한다. 이제 master는 c2 커밋을 가리키게 된다. HEAD는 그대로 master 브랜치를 가리키고 있다.
$ vim c2.txt
$ git add c2.txt
$ git commit -m "c2"
6. sub 브랜치에 커밋을 만들어준다. master 브랜치에서 sub 브랜치로 이동하려면 git checkout 명령을 사용한다. git checkout 명령은 HEAD가 가리키는 것을 제어할 수 있다.
$ git checkout sub
7. sub 브랜치에서 빔을 사용해 s1.txt 문서를 만들고 내용은 's1'이라고 입력하고 저장한다. s1.txt 문서를 스테이지에 올리고 's1'이라는 메시지와 함께 커밋한다.
$ vim s1.txt
$ git add s1.txt
$ git commit -m "s1"
8. reset 명령으로 master 브랜치에 있던 여러 커밋 중 하나를 골라서 되돌아갔다. 브랜치가 여러 개일때는 현재 브랜치가 아닌 다른 브랜치에 있는 커밋을 골라서 최신 커밋으로 지정할 수 있다. 먼저 git log 명령을 사용해서 c2 커밋 해시를 확인한다.
$ git log --oneline --branches
9. git reset 명령 다음에 c2 커밋의 커밋 해시를 입력한다.
$ git reset b696843
10. git log 명령을 사용하여 확인해보자.
$ git log --oneline --branches --graph
11. sub 브랜치의 최신 커밋이 master 브랜치의 최신 커밋인 c2로 바뀐다. HEAD는 그대로 sub 브랜치를 가리키고 있다. 이렇게 git reset 명령을 사용하면 현재 브랜치가 가리키는 커밋을 여러 브랜치 사이를 넘나들면서 제어할 수 있다. sub 브랜치는 c2 커밋을 가리키고 있기 때문에 원래 가리키고 있던 s1 커밋은 연결이 끊기면서 삭제된다.
git checkout 명령을 사용하면 HEAD를 제어해서 브랜치를 이동할 수 있다. git reset 명령을 사용하면 HEAD가 가리키고 있는 브랜치의 최신 커밋을 원하는 커밋으로 지정할 수 있다. 이때 어떤 브랜치에 있는 커밋이든 지정할 수 있으며, 명령을 수행한 뒤 브랜치와 연결이 끊긴 커밋은 삭제된다.
수정 중인 파일 감추기 및 되돌리기 - git stash
브랜치에서 파일을 수정하고 커밋하지 않은 상태에서 급하게 다른 파일을 커밋해야 할 경우가 있다. 아직 커밋하지 않은 파일들을 그냥 두어도 상관없지만 계속 커밋하라는 메시지가 나타나기 때문에 번거롭다. 그리고 실수로 다른 파일과 함께 커밋이 될 수도 있다. 즉, 아직 커밋하지 않고 작업 중인 파일들을 잠시 감춰둘 수 있다. 그리고 당장 필요한 작업들을 끝낸 후 다시 감춰둔 파일들을 꺼내오면 된다.
1. 홈 디렉터리로 이동한 후 st라는 저장소를 만들고 st 디렉터리로 이동한다.
$ cd ~
$ git init st
$ cd st
2. git stash 명령을 사용하려면 파일이 tracked 상태여야 한다. 즉, 한 번은 커밋한 상태여야 한다. 빔을 사용하여 f1.txt 파일을 작성한다. 스테이지에 올리고 'f1' 메시지와 함께 커밋한다.
$ vim f1.txt
$ git add f1.txt
$ git commit -m "f1"
3. f2.txt 파일도 만들고 내용을 입력한 후 저장한다. f2.txt 파일도 스테이지에 올린 후 'f2'라는 메시지와 함께 커밋한다.
$ vim f2.txt
$ git add f2.txt
$ git commit -m "f2"
4. 빔에서 f1.txt 파일을 연 후 내용을 수정하고 저장한다. f2.txt 파일도 수정하고 저장한다.
$ vim f1.txt
$ vim f2.txt
5. git status 명령을 실행하면 현재 브랜치에서 f1.txt와 f2.txt가 수정되었다고 나타난다.
$ git status
6. f1.txt 파일과 f2.txt 파일을 커밋하기 전에 다른 파일을 수정해야 한다고 가정해보자. 커밋하지 않은 수정 내용을 어딘가에 보관하려면 git stash 명령을 사용한다. git stash save 또는 간단히 git stash라고만 해도 된다.
$ git stash
7. git status 명령을 실행하면 조금 전에 나타났던 modified 메시지가 사라진다.
8. 같은 방법으로 여러 파일을 수정한 후 따로 보관할 수 있으며, 이렇게 감춘 파일들은 stash 목록에서 확인할 수 있다. 가장 먼저 감춘 것은 stash@{0}이 들어있고 다른 파일이 추가되면 기존 파일은 stash@{1}로 옮겨진다. 가장 최근에 감춘 것을 위에 쌓기 때문에 stash 스택이라고도 표현한다.
$ git stash list
9. 급한 작업을 모두 마쳤다면 감춰둔 파일을 꺼내와 계속 수정하거나 커밋할 수 있다. git stash 명령 뒤에 pop을 추가하면 stash 목록에서 가장 최근 항목을 되돌린다.
$ git stash pop
stash 목록에 저장된 수정 내용을 나중에 또 사용할지도 모른다면 git stash apply 명령을 사용한다. stash 목록에서 가장 최근 항목을 되돌리지만 저장했던 내용은 그대로 남겨둔다.
git stash drop 명령은 stash 목록에서 가장 최근 항목을 삭제한다.
'Study > git' 카테고리의 다른 글
[깃&깃허브 입문] 깃허브로 백업하기 (0) | 2025.06.09 |
---|---|
[깃&깃허브 입문] 깃으로 버전 관리하기 (0) | 2025.03.24 |
[깃&깃허브 입문] 깃 시작하기 (0) | 2025.03.20 |