프로그래밍/깃&깃허브

[깃&깃허브] 03. 깃과 브랜치 (p.84~130)

aSpring 2021. 3. 13. 21:59
728x90
728x90

2021/01/16 - [분류 전체보기] - Do it! 공부단

2021/02/19 - [프로그래밍/깃&깃허브] - [깃&깃허브] 01. 깃 시작하기 (~p.37)

2021/02/20 - [프로그래밍/깃&깃허브] - [깃&깃허브] 02. 깃으로 버전 관리하기 (p.38~83)


03 깃과 브런치

웹 사이트 개발, 완성 -> 고객이 새로운 기능 추가 요구
-> 기존 파일에 새로운 기능을 위한 소스 추가 -> 새로운 버전 만듦

But, 이것이 오류없이 완벽하게 동작한다는 보장이 없다

제대로 동작하는 소스는 그대로 둔 채 새 소스를 추가한 버전을 따로 만들어 관리 -> 완벽하게 완성 후 원래 소스에 더할 수 있다면!!! --> 이럴 때 사용하는 것이 깃의 '브랜치(Branch)'라는 기능

03-1 브랜치란?

브랜치(Branch) : 나무가 가지에서 새 줄기를 뻗듯이 여러 갈래로 퍼지는 데이터 흐름

- 모든 버전 관리 시스템에 있는 개념

 

브랜치가 필요한 이유

ex) 어떤 제품의 사용설명서를 만든다

 

브랜치 기능 살펴보기

- 분기(branch)한다

- 병합(merge)한다

 

master라는 브랜치 생성되고, 사용자가 커밋할 때마다 최신 커밋을 가리킨다

-> 즉, 브랜치는 커밋을 가리키는 포인터와 비슷

-> 새 브랜치를 만들면 기존에 저장한 파일을 master 브랜치에 그대로 유지하면서 기존 파일 내용 수정 혹은 새로운 기능을 구현할 파일을 만들 수 있음 => master 브랜치에서 뻗어 나오는 새 브랜치를 만드는 것 == '분기(branch) 한다'

& 새 브랜치에서 원하는 작업이 다 끝나면 원래의 master 브랜치에 합칠 수 있음 == '병합(merge) 한다'

 

03-2 브랜치 만들기

실습 상황 설정하기

디렉터리를 만들고, 사용 설명서를 그 안에 만든다고 생각하면서 텍스트 파일 하나 만들기

1. 터미널 창에서 홈 디렉터리에 manual 디렉터리 만들고, 이동

2. manual 디렉터리를 저장소로 만들고, .git 디렉터리가 만들어졌는지 확인하기

3. manual 디렉터리 안에 work.txt 파일 만들기

4. content 1 이라고 입력하고 저장

5. work.txt 파일을 스테이지에 올리고 커밋하기, 이 때 커밋 메시지는 work 1

6. 커밋 내역 확인

7. work.txt 파일을 두 번 더 커밋하기

HEAD : 여러 브랜치 중 현재 작업 중인 브랜치를 가리킴

 

------------- 초기 사용 설명서 만드는 작업 끝 ---------------

 

이제부터는 여러 고객사에게 서로 다른 내용의 사용 설명서를 제공해야 함

 

새 브랜치 만들기

ex) 고객사 : apple, google, ms

 

1. git branch : 깃에서 브랜치를 만들거나 확인

- master : 저장소를 만들 때 기본적으로 만들어지는 브랜치, 이때까지 내가 작업하고 있었던 브랜치

2. 고객사인 apple의 브랜치 만들기 : git branch apple

- apple이라는 브랜치가 만들어졌고, * 표시 : 우리는 아직까지 master 브랜치에서 작업 중이라는 뜻

- 디렉터리 경로 맨 끝 (master) 이 표시도 현재 브랜치가 master라는 뜻

 

3. 커밋 확인해보기 : git log

- 이전에는 HEAD -> master만 나왔는데,

HEAD -> master, apple : 저장소에 master, apple 2개의 브랜치가 있고, HEAD -> master이므로 현재 작업 중인 브랜치는 master 브랜치라는 의미

※ HEAD : 작업 중인 브랜치를 가리키는 포인터라고 생각하자

 

4. google 브랜치, ms 브랜치도 만들고 저장소 안에 있는 모든 브랜치 확인하기

 

브랜치 사이 이동하기 - git checkout

1. git log 확인해보기

- ms, google, apple 모두 'work 3' 커밋 상태에서 만들어진 것을 확인할 수 있음

--> 즉, master, ms, google, apple 브랜치 모두 최신 커밋이 'work 3'

 

2. 현재 위치한 브랜치(즉, master)에서 work.txt 파일을 수정('master content 4' 추가), 'master work 4' 메시지와 함께 커밋

 

3. git log --oneline : 한 줄에 한 커밋씩 나타내주어 커밋을 간략히 확인 가능

- ms, google, apple 브랜치의 최신 버전은 'work 3'이고, HEAD 즉 현재 작업 중인 master라는 브랜치의 최신 커밋은 master work 4라는 것을 확인 가능

 

4. 다른 브랜치로 이동 : git checkout 가고자하는 브랜치 이름 -> apple 브랜치로 이동 : apple 브랜치로 체크아웃한다

- (apple) : 현재 브랜치가 apple이라는 뜻

 

5. 그렇다면, apple 브랜치에서 git log를 확인해보자 : 현재 브랜치의 커밋 로그 확인

- HEAD -> apple : 현재 브랜치는 apple

- master 브랜치에서 분기하기 전까지 master 브랜치에 있던 커밋(work 1, 2)들은 그대로 apple, ms, google 브랜치에 복사되었음

 

6. apple 브랜치의 최신 커밋은 work 3(master 브랜치는 master work 4), work.txt 내용 확인해보기

- master 브랜치에서 입력했던 'master content 4'가 없음

--> 분기 이후에 master 브랜치에 추가된 커밋은 apple 브랜치에 영향을 미치지 않았다

 

03-3 브랜치 정보 확인하기

여러 브랜치에서 각각 커밋이 이루어질 때, 커밋끼리 어떤 관계를 하고 있는지 확인하는 방법
브랜치 사이의 차이점을 확인하는 방법

새 브랜치에서 커밋하기

<apple 브랜치에서 새로운 커밋 만들기>

- apple 브랜치로 체크아웃한 상태에서 진행

 

1. vim에서 work.txt 파일을 열고 'apple content 4' 추가, 저장

2. 실제 업무에서는 apple 고객사만을 위한 내용이 담긴 파일도 필요함 -> apple.txt 파일 만들고, apple content 4 입력, 저장

3. 수정된 2개의 파일을 각각 스테이지에 올릴 수도 있지만 'git add .'을 입력하면 현재 저장소에서 수정된 파일을 한꺼번에 스테이지에 올릴 수 있고, 스테이징 후 'apple content 4'라는 메시지와 함께 커밋하기

4. 커밋이 어떻게 저장되었는지 확인 : git log

- 최신 커밋은 해시가 f540e98인 커밋이라고 해야 정확한 표현이지만, 편읳상 커밋 메시지를 사용해서 'apple content 4'라고 부르자

 

5. git log --oneline --branches : 각 브랜치의 커밋을 함께 볼 수 있음

- 괄호 속의 내용을 보고, 어떤 브랜치에서 만든 커밋인지 구별 가능

- master 브랜치의 최신 커밋은 master work 4

- ms, google은 work 3

- apple은 apple content 4

 

6. 브랜치와 커밋의 관계를 그래프 형태로 보기 쉽게 표시 : --graph 옵션

git log --oneline --branches --graph

- 점선을 따라가 보면 apple content 4의 부모, master work 4의 부모도 work 3

- 즉, apple 브랜치에서는 work 3 커밋 다음에 apple content 4 커밋이 만들어졌다는 뜻

- 그리고, master 브랜치와 apple 브랜치는 work 3 커밋까지는 같고 그 이후부터 브랜치마다 다른 커밋을 만들었다는 것을 알 수 있음

 

브랜치 사이의 차이점 알아보기

git log master..apple

--> ..을 기준으로 앞에 적힌 브랜치를 기준으로 오른쪽에 적힌 브랜치와 비교

첫 번째 -> master 브랜치에는 없는 apple 브랜치의 커밋을 보여줌

두 번째 -> apple 브랜치에는 없는 master 브랜치의 커밋을 보여줌

 

03-4 브랜치 병합하기

각 상황마다 브랜치 병합(merge) 방법 알아보기
병합하면서 브랜치 사이에 발생할 수 있는 충돌 해결하는 방법 살펴보기

 

서로 다른 파일 병합하기
1. 홈 디렉터리로 이동 -> manual-2 깃 저장소 만들기

-- git init 디렉터리이름 : 새로운 디렉터리 만들고 + 저장소 초기화 한꺼번에 처리

 

2. 빔에서 work.txt 파일을 만들고 1 입력 후 저장, 커밋 메시지는 work 1

vim work.txt
git add work.txt
git commit -m "work 1"

HEAD가 master 브랜치를 가리키고, master가 work 1 커밋을 가리킴

 

3. o2라는 브랜치 만들기

 

4. 현재 master 브랜치에 master.txt 파일 만들고, master 2 입력 후 저장, master work 2 메시지와 함께 커밋

- HEAD는 master 브랜치를, master 브랜치는 master work 2 커밋을 가리킴

 

5. o2 브랜치로 체크아웃하기(현재는 master 브랜치)

6. o2 브랜치에서 o2.txt 파일 만들고 'o2 work 2' 입력, 저장, o2 work 2 메시지와 함께 커밋

 

7. 현재 커밋 상태 확인 : git log --oneline --branches --graph

 

8. o2 브랜치에서 작업이 다 끝났다고 가정 -> o2 브랜치의 내용을 master 브랜치로 병합하기

--> 브랜치를 병합하려면 먼저 master 브랜치로 체크아웃해야 함

 

9. 브랜치 병합 : git merge 가져올 브랜치 이름  -> git merge o2

-- 자동으로 빔이 실행되면서 'Merge branch o2' 라는 커밋 메시지가 나타나는데, 이는 브랜치를 병합하면서 만들어지는 커밋 메시지 -> 수정할 수도 있고, 그대로 사용해도 됨

※ 사용자 시스템 환경에 따라 편집 창이 뜨지 않거나, 병합 후 나타나는 메시지가 다를 수 있음

But, 오류 메시지가 나타나지 않으면 병합은 제대로 된 것

 

10. 제대로 합쳐졌는지 확인 : ls -al

 

11. 브랜치와 커밋들이 어떻게 병합되었는지 확인 : git log --oneline --branches --graph

 

[한 걸음 더!] 빨리 감기 병합

master 브랜치에서 브랜치를 분기한 후, master 브랜치에 아무 변화가 없다면(새로운 커밋을 만들지 않았다면) 분기한 브랜치를 병합하는 것은 간단
분기한 브랜치에서 만든 최신 커밋을 master 브랜치가 가리키게만 하면 됨
-> 이 경우 화면에서 커밋 해시가 업데이트되었다는 내용과 함께 fast-forward라는 메시지가 나타남
: 빨리 감기 병합(fast-forward merge)

git merge 명령의 결과가 단순히 포인터를 움직인 것이기 때문에 따로 커밋 메시지 창은 열리지 않음

 

[한 걸음 더!] 브랜치를 병합할 때 편집기 창이 열리지 않게 하려면

$ git merge o2 --no-edit

 

내가 이렇게 설정해뒀는데 이번 커밋에서는 메시지를 추가/수정하고 싶다면 병합 명령에 --edit 옵션 사용

$ git merge o2 --edit

 

같은 문서의 다른 위치를 수정했을 때 병합하기

master 브랜치, o2 브랜치 모두에는 똑같이 work.txt 파일이 존재
- work.txt 파일을 수정하는데 master 브랜치와 o2 브랜치에서 각각 다른 내용으로 수정했다고 할 때, 병합을 하면..?

1. 홈 디렉터리로 이동 후 manual-3이라는 저장소를 만들고, manual-3 디렉터리로 이동

2. work.txt 파일을 만들고 다음과 같이 입력 후 저장(내용 사이에 두 줄의 공백 두기)

# title
content


# title
content

3. work.txt 파일 스테이징, 커밋 -> 메시지는 work 1

4. o2 브랜치 만들기 --> 그럼 master 브랜치와 o2 브랜치에 모두 work 1 커밋 존재

5. 먼저 master 브랜치에서 work.txt 수정, 커밋(메시지 master work 2)

# title
content
master content 2

# title
content

 

6. o2 브랜치에서도 work.txt 수정, 커밋(메시지 o2 work 2)

# title
content


# title
o2 content 2

 

7. work.txt 파일의 work 1 버전(master, o2)과 master work 2(master), o2 work 2(o2) 모두 각각 다름

- master 브랜치와 o2 브랜치 양쪽에서 work.txt 파일을 수정했지만 문서 안의 수정 위치는 다르다. 이럴 경우에는 어떻게 병합을 해야할까

work 1                              master content 2                           o2 content 2

 

8. o2 브랜치를 master 브랜치에 합치기 위해 master 브랜치로 체크아웃

 

9. o2 브랜치를 master 브랜치로 끌어오기 : git merge o2

 

10. 병합 완료 메시지 : Auto-merging work.txt

- o2 브랜치의 work.txt가 master 브랜치의 work.txt와 어떻게 병합되었을지 cat 명령으로 work.txt 파일 내용 확인

- 브랜치를 자동으로 ! 자연스럽게 합쳐 주었음

 

같은 문서의 같은 위치를 수정했을 때 병합하기

깃에서는 줄 단위로 변경 여부 확인
- 각 브랜치에 같은 파일 이름을 가지고 있으면서 같을 줄을 수정했을 때 브랜치 병합 시 브랜치 충돌(conflic) 발생

master 브랜치, o2 브랜치에서 같은 파일의 같은 위치를 수정한 후 병합해 보면서
어떤 경우에 브랜치 충돌이 생기는지, 어떻게 해결하는지 알아보기

1. 홈 디렉터리로 이동, manual-4 저장소 생성 후 이동

2. work.txt 파일 만들고 빈 줄 하나만 두기

# title
content

# title
content

3. 스테이징 & 커밋 - 메시지 work 1

4. o2 브랜치 만들기 - master, o2 브랜치 모두에 work.txt 존재(내용 동일)

 

5. master 브랜치에서 work.txt 수정 후 커밋 - 메시지 master work 2

# title
content
master content 2
# title
content

 

6. o2 브랜치에서 work.txt 수정 후 커밋 - 메시지 o2 work 2

# title
content
o2 content 2
# title
content

 

7. master 브랜치, o2 브랜치 양쪽에서 각각 work.txt를 수정했는데, 아까와는 다르게 수정 위치가 동일

- 이런 경우는 어떻게 병합이 될지 확인 해보자

 

8. o2 브랜치를 master 브랜치로 끌어오기

 

9. 이전에 git merge 명령 실행 때와는 달리 자동으로 vim이 열리지 않고 메시지가 나타남

- work.txt를 자동 병합 하는 동안 충동(conflic)이 발생했다는 뜻

※ 여러 개의 파일을 병합했다면 충돌이 발생한 파일 외에 다른 파일들은 자동으로 master 브랜치에 병합됨

- 충돌이 생긴 문서는 자동 병합될 수 없음 -> 사용자가 직접 충돌 부분 해결 후 커밋해야 함

- 충돌이 생긴 work.txt는 어떻게 되었을지 빔에서 열어보기

 

10. work.txt의 내용이 다음과 같이 되어있다.

- master 브랜치에 있던 내용과 o2 브랜치에 있던 내용이 한꺼번에 나타남

- <<<<<< HEAD와 ====== 사이 내용은 현재 브랜치에서 수정한 내용

- ======와 >>>>>> o2 사이 내용은 o2 브랜치에서 수정한 내용

--> 양쪽 브랜치의 내용을 참고하면서 직접 내용을 수정한 후 ====, <<< HEAD, >>> o2 삭제 -> 저장, 종료

 

11. 수정한 work.txt를 스테이징 + 커밋(메시지 merge o2 branch)

--> o2 브랜치에서 병합한 work.txt의 충동을 해결하고 커밋 완료

 

12. 지금까지 마든 브랜치와 커밋의 관계 한눈에 확인하기 : git log --oneline --branches --graph

 

[한 걸음 더!] 병합 및 충돌 해결 프로그램

<병합 알고리즘>

- 2 way merge

- 3 way merge : 훨씬 효율적이므로 이를 지원하는 프로그램을 선택하는 것이 좋은

 

<자주 사용하는 병합 자동화 프로그램>

프로그램 이름 설명
P4Merge 장점 : 무료, 직관적, 사용 편리, 뛰어난 병합 기능
단점 : 단축키 미지원 
Meld 무료, 오픈소스
파일 비교, 직접 편집 가능
Kdiff3 무료, 사용 편리, 뛰어난 병합 기능
But, 한글 깨짐 있을 수 있음
Araxis Merge 유료지만 용량이 큰 파일에서도 잘 작동

 

병합이 끝난 브랜치 삭제하기

- 병합 후 더이상 사용하지 않는 브랜치 삭제 가능

- 단, 삭제했더라도 다음에 다시 같은 이름의 브랜치를 만들면 예전 내용을 다 볼 수 있음(완전히 지워지는 것이 아님)

 

1. 현재 저장소에 있는 브랜치 확인 : git branch

2. o2 브랜치 삭제

- 기본 브랜치 master에서 -d 옵션을 사용해 삭제

※ master 브랜치에 병합하지 않은 브랜치를 삭제하려면 오류 메시지 나타남 : -d대신 -D로 강제로 브랜치 삭제 가능

3. 'Deleted branch 02'처럼 메시지가 나타나면 성공적으로 브랜치가 삭제된 것

- 브랜치를 삭제한다는 것(완전히 저장소에서 없애는 것이 아니라 깃의 흐름 속에서 감추는 것)

- git branch 명령을 사용해  o2가 사라진 것을 확인 가능

 

 

03-5 브랜치 관리하기

브랜치에서 checkout과 reset의 작동 원리

1. 홈 디렉터리로 이동 > 깃 저장소 'test'를 만들고, 이동

2. c1.txt 파일을 만들고 1 입력, 저장 > 스테이징 & 커밋(c1)

3. git log

(HEAD -> master) : HEAD는 현재 작업 트리(워킹 디렉터리)가 어떤 버전을 기반으로 작업 중인지 가리키는 포인터, HEAD는 기본적으로 master 브랜치를 가리킴 -> master 브랜치는 기본적으로 브랜치에 담긴 커밋 중 가장 최근의 커밋을 가리킴

여기에서는 HEAD는 master 브랜치를 가리키고 master 브랜치는 c1 커밋을 가리킴

4. sub 브랜치 만들기

sub 브랜치 또한 c1 커밋을 가리킴

5. c2.txt 만들고 2 입력, 저장 > 스테이징 & 커밋(c2)

HEAD는 여전히 master 브랜치를 가리키고 master 브랜치는 이제 c2 커밋을 가리킨다

6. sub 브랜치로 이동

7. s1.txt 문서를 만들고 s1 입력, 저장 > 스테이징 & 커밋(s1)

HEAD는 sub 브랜치를 가리키고 sub 브랜치는 s1 커밋을 가리킴

8. sub 브랜치에 있는 상태에서 master 브랜치에 있는 c2 커밋을 sub 브랜치의 최신 커밋으로 지정

- git reset 커밋 해시

브랜치가 여러 개일 때, 현재 브랜치가 아닌 다른 브랜치에 있는 커밋을 골라서 최신 커밋으로 지정 가능

9. git log 명령을 사용해 확인해보기

HEAD는 여전히 sub 브랜치를 가리키고 sub 브랜치는 c2 커밋을 가리킨다, 기존에 sub 브랜치가 가리키고 있던 c1은 연결이 끊기면서 삭제 됨

-- git reset 명령을 사용하면 현재 브랜치가 가리키는 커밋을 여러 브랜치 사이를 넘나들면서 제어할 수 있음

정리
git checkout : HEAD를 제어해 브랜치 이동
git reset : HEAD가 가리키고 있는 브랜치의 최신 커밋을 원하는 커밋으로 지정 가능
-> 어떤 브랜치에 있는 커밋이든 지정 가능하고 명령 수행 후 브랜치와 연결이 끊긴 커밋은 삭제됨

 

수정 중인 파일 감추기 및 되돌리기 - git stash

브랜치에서 파일을 수정하고 커밋하지 않은 상태에서 급하게 다른 파일을 커밋해야 할 경우,
아직 커밋하지 않은 파일들을 그냥 두어도 상관없지만 계속 커밋하라는 메시지가 나타나서 번거롭고 실수로 다른 파일과 함께 커밋 될 수도 있음
-> 아직 커밋하지 않고 작업 중인 파일들을 잠시 감춰둘 수 있고, 당장 필요한 작업들을 끝낸 후 감춰둔 파일들을 다시 꺼내올 수 있음

1. 홈 디렉터리로 이동 > st 저장소 만들고 이동

2. git stash 명령을 사용하려면 파일이 tracked 상태여아 함(즉, 한 번은 커밋한 상태여야 함)

- f1.txt 파일 작성(아무 내용이나) > 스테이징 & 커밋(f1)

- f2.txt 파일 작성 > 스테이징 & 커밋(f2)

3. f1.txt, f2.txt 파일을 각각 아무렇게나 수정 후 저장

4. 상태 확인 -> f1.txt와 f2.txt가 수정되었다고 나타남

5. 수정한 f1.txt, f2.txt 파일을 커밋하기 전에 다른 파일을 수정해야 하는 상황일 때, 커밋하지 않은 수정 내용을 어딘가에 보관하려면 git stash 명령 사용 : git stash save 또는 git stash

6. 다시 한 번 상태 확인하기 : modified 메시지가 사라져 있음(f1.txt, f2.txt 파일이 사라진 것은 아님)

7. 같은 방법으로 여러 파일을 수정한 후 따로 보관 가능하며, 이렇게 감춘 파일들은 stash 목록에서 확인 가능

: git stash list

- 가장 먼저 감춘 것은 stash@{0}에 들어있는데 다른 파일이 추가되면 기존 파일은 stash@{1}로 옮겨지고 새로 추가된 파일은 stash@{0}에 담김 --> 가장 최근에 보관한 것이 stash@{0}에 담김

-> 먼저 감춘 것을 아래에, 가장 최근에 감춘 것을 위에 쌓는다 : stash 스택(stack)

- stack : 선입후출(First In, Last Out) 방식의 저장 공간

8. 급한 작업을 모두 마치면 감춰둔 파일을 꺼내와서 계속 수정하거나 커밋 가능 : git stash pop

- stash 목록에서 가장 최근 항목을 되돌림 -> f1.txt와 f2.txt가 modified 상태로 되돌아감

- 그리고 다시 한 번 stash list를 확인해보면 아무 것도 없는 것을 확인할 수 있음

 

[한 걸음 더!] stash apply와 stash drop

git stash apply

- stash 목록에 저장된 수정 내용을 나중에 또 사용할지도 모른다면 : git stash apply 명령 사용

- stash 목록에서 가장 최근 항목을 되돌리지만 저장했던 내용은 그대로 남겨둠

git stash drop

- stash 목록에서 가장 최근 항목 삭제

 

03장에서 꼭 기억해야 할 명령

git branch fixed 새로운 브랜치 fixed를 만든다
git checkout fixed fixed 브랜치로 체크아웃한다
git log --oneline 커밋 로그에서 한 줄에 한 커밋씩 표시한다
git add . 수정한 전체 파일을 스테이지에 올린다
git log --branches --graph 커밋 로그에 각 브랜치의 커밋을 그래프로 표시한다
git merge fixed fixed 브랜치를 master 브랜치에 병합한다
cat edit.txt 터미널 창에서 edit.txt 내용을 확인한다
git init doit doit 디렉터리를 만드는 동시에 지역 저장소로 만든다
git reset c1의 커밋해시 현재 커밋을 다른 브랜치에 있는 c1 커밋으로 되돌린다
git branch -d fixed 병합이 끝난 fixed 브랜치를 삭제한다
git stash
git stash save
작업 트리의 수정 내용을 따로 보관해서 감춘다
git stash pop 따로 보관했던 수정 내용을 꺼내온다

 

728x90
728x90