독학/git, github

[Git/GitHub] 팀 개발을 위한 Git, GitHub 시작하기 DAY6

최연재 2023. 2. 17. 06:23

day5 실습에 이어서 챕터 7인 <브랜치 생성 및 조작하기>를 학습했다.

 

교재 실습하기

📌 CLI로 브랜치 생성하기

  • git log --oneline : 커밋 로그를 확인한다.
  • [origin]으로 시작하는 브랜치는 원격 브랜치이므로, 현재 로컬에는 master 브랜치만 있다. HEAD는 master 브랜치를 가리키고 있다.
  • git branch : 현재 브랜치를 확인한다.
  • git branch mybranch1 : mybranch1 브랜치를 생성한다.
  • *master 문구는 HEAD→ master와 같은 뜻이다.

 

📌 CLI로 checkout 하기

  • git checkout mybranch1 : 브랜치 체크아웃
  • git branch : 현재 브랜치를 확인한다. 현재 브랜치는 mybranch1이다. (프롬프트도 mybranch1로 변경되었다.)
  • git log --oneline --all : HEAD의 변경을 확인한다.
  • cat file1.txt : 파일의 내용을 확인한다.
  • echo "third - my branch" >> file1.txt : 파일에 내용을 추가한다.

  • git status : 스테이지 상태를 확인한다.
  • git add file1.txt : 스테이지에 변경사항을 추가한다.

  • git commit : 커밋
  • git log --oneline --all : 브랜치가 변경된 것을 확인할 수 있다. 

커밋 메시지는 다음과 같다.

 

📌 CLI를 이용한 빨기 감기 병합

  • echo "fourth - my branch" >> file1.txt : 파일에 내용을 추가한다.
  • git status : 스테이지 상태 확인

커밋 메시지는 다음과 같다.

  • git commit : 신규 커밋을 추가한다.
  • git checkout master : 마스터 브랜치 체크아웃

  • git merge mybranch1 : fast-forward 병합한다.
  • 작업의 흐름이 하나였기 때문에 fast-forward 병합으로 완료됐다.

 

📌 reset --hard로 브랜치 되돌리기

 

  • git reset --hard HEAD~2 : HEAD를 2단계 이전으로 되돌렸다.

 

📌 빨리 감기 병합 상황에서 rebase 하기

  • git checkout mybranch1 : 브랜치를 변경한다.
  • git rebase master : 리베이스를 시도한다.
  • git log --oneline --all : 로크를 확인한다 -> 변한 것이 없다.
  • mybranch1 브랜치는 이미 master 브랜치 위에 있기 때문에 재배치할 커밋이 없다. 따라서 rebase master를 수행해도 아무 일도 일어나지 않는다.

  • git checkout master : master 브랜치 체크아웃
  • git rebase mybranch1 : 리베이스를 시도한다. -> 성공했다.
  • git log --oneline --all  : 변경 사항을 확인하면 빨리 감기 병합이 됐다.

  • git push : master 브랜치를 원격에 push한다.
  • git branch -d : 필요없어진 브랜치를 삭제한다.

 

📌배포 버전에 태깅하기

  • git tag -a -m "첫 번째 태그 생성" v0.1 : 주석 있는 태그를 생성한다.
  • git push origin v0.1 : 태그를 푸시한다.

 

📌CLI로 3-way 병합하기

❗새로운 브랜치 및 커밋 생성

  • git checkout master : master로 체크아웃한다.
  • git checkout -b feature1 : feature1 브랜치를 생성하고, 체크아웃한다.
  • echo "기능 1 추가" >> file1.txt : 파일 내용을 수정한다.
  • git add file1.txt : 스테이징

커밋 메시지는 다음과 같다.

❗hotfix 브랜치 생성, 커밋

커밋 메시지는 다음과 같다.

  • git merge hotfix : 빨리 감기 병합한다.
  • hotfix의 커밋은 버그 수정이었기 때문에 이 내용을 현재 개발 중인 feature1 브랜치에 반영해야 한다.

현재 히스토리

  • 히스토리를 보면 master와 feature1 브랜치는 서로 다른 분기로 진행되고 있다.
  • 빨리 감기 병합이 불가능하므로 3-way 병합을 해야 한다.

  • git merge master : master 브랜치와 병합을 시도한다. -> 실패

  • git status : 실패의 원인을 확인한다.

  • 충돌이 일어난 파일을 vscode로 연다.
  • 여기에서는 두 변경 사항 모두 수락을 누른다

다음과 같이 정리됐다.

  • cat file1.txt : 최종으로 변경된 내용을 확인한다.
  • git add file1.txt : 스테이징
  • git stauts : 모든 충돌이 해결되었음을 알 수 있다!

  • git commit : 머지 커밋을 생성한다.
  • git log --oneline --all --graph -n4 : 로그를 확인한다.

커밋 메시지는 다음과 같다.
현재 히스토리

  • git add 및 git status를 수행하면 충돌한 파일의 수정을 완료한 후에 git commit 명령을 수행하면 된다.
  • git commit 명령으로 충돌이 발생한 3-way 병합을 끝낸다.

 

📌CLI로 rebase 해보기

앞에서 만들었던 병합 커밋을 되돌리고 rebase 시도

  • git reset --hard HEAD~ : 현재 브랜치를 한 단계 전으로 되돌린다.
  • git rebase master : HEAD 브랜치의 커밋을 master로 재배치한다. -> 실패

  • git status : 충돌 대상을 확인한다.
  • vscode로 문제가 된 파일을 열어 수정한다.

  • git rebase --continue : 리베이스를 계속 진행한다.
  • git log --oneline --graph --all -n2 : 로그를 확인한다. merge와 다르게 병합 커밋도 없고, 히스토리도 깔끔하다. (HEAD가 가리키는 커밋 체크섬 값이 변경되었다.)

  • master 브랜치에서 feature1 브랜치로 병합한다.
  • 빨리 감기 병합이 수행된다.

히스토리는 다음과 같다.

 

📌 rebase로 뻗어나온 가지 없애기

  • 보통 두 대의 PC에서 한 브랜치에 작업을 하는 경우에 생기는 히스토리다.
  • 한 PC에서 커밋을 생성하고 push했는데, 다른 PC에서는 pull을 하지 않고 커밋을 하게되면 이전 커밋을 부모로 하는 커밋이 생긴다.
  • 위 상황에서 pull을 하면 자동으로 3-way 병합을 해야 한다. -> 불필요한 병합 커밋이 생긴다.
  • reset --hard로 병합 커밋을 되돌리고 rebase를 하면 된다!

보통 커밋 만들기
로그와 작업 디렉토리 상태 확인

  • 보통 커밋을 만든 뒤 reset --hard HEAD~ 명령어로 한 단계 이전 커밋으로 간다.
  • 로그를 확인하면 자기가 생겼다.

  • git pull 명령을 수행하면 자동으로 병합 커밋이 생긴다.

rebase로 가지 없애기

  • git reset --hard HEAD~ : 병합 커밋을 되돌린다.
  • git rebase origin/master : 로컬 master 브랜치의 가지 커밋이 origin/master 브랜치로 재배치된다.
  • 이후 로그를 확인하고 origind에 푸시한다.

히스토리는 다음과 같다!

 

📌임시 브랜치 사용하기

  • feature1 브랜치에서임시 브랜치를 생성한다.
  • test 브랜치로 체크아웃하고 새로운 커밋을 생성한다.

  • 임시 브랜치가 필요 없어지면 git branch -D 브랜치이름으로 삭제한다.

 

 

배운 내용 정리

⭐ 브랜치를 사용하는 이유

- 새로운 기능 추가

  • 가장 대표적으로 브랜치를 사용하는 경우이다.
  • [master] 브랜치에는 정상적으로 동작하는 안정적인 버전의 프로젝트가 저장되어 있기 때문에 새로운 기능을 추가할 때 [master] 브랜치의 최신 커밋으로부터 브랜치를 생성해서 개발한다.
  • 개발, 코드 리뷰, 테스트까지 모두 완료해서 이상이 없으면 [master] 브랜치로 병합한다.

- 버그 수정

  • 버그가 발생하면 [master] 브랜치로부터 새로운 브랜치를 생성해서 작업한다. 
  • 버그 수정이 끝나면 [master] 브랜치로 병합한다. 
  • 새로 개발한 내용을 다시 [master] 브랜치로 병합할 때 버그 수정으로 인해 충돌이 생길 수 있기에 주의해야 한다.

- 병합과 리베이스 테스트

  • 임시 브랜치를 만들어서 병합과 리베이스 테스트를 해 본다.
  • 잘못되었을 경우에는 브랜치를 삭제한다.

- 이전 코드 개선

  • 기능 구현이 완료되었는데 코드를 개선하고 싶을 경우 브랜치를 사용한다.
  • 브랜치를 만들어서 이전 코드를 삭제하고 새 코드를 작성한다.
  • 다른 브랜치의 이전 커밋에는 기존의 코드가 남아있기 때문에 문제가 발생하지 않는다.

- 특정 커밋으로 돌아가고 싶을 때

  • 이미 저장되어 있는 특정 커밋으로 돌아가고 싶을 경우 hard reset이나 revert를 사용한다.
  • hard reset의 경우 커밋이 사라질 수 있고,revert는 사용이 까다롭기 때문에 브랜치를 사용해도 된다.
  • 브랜치를 새로 만들어서 작업하고, 이후 리베이스나 병합을 사용하는 것이 좋다. 

 

⭐ HEAD

- HEAD는 현재 작업 중인 브랜치를 가리킨다.

- 브랜치는 커밋을 가리키므로 HEAD도 커밋을 가리킨다.

- HEAD는 현재 작업 중인 브랜치의 최신 커밋을 가리킨다.

 

⭐ 새로운 커밋 생성

- 생성된 새로운 커밋의 부모는 언제나 이전 커밋이다.

- 커밋이 생성되면 새로운 커밋으로 갱신된다.

- 가리키는 브랜치와 함께 새로운 커밋을 가리킨다.

 

⭐ switch, restore

- 체크아웃은 브랜치 전환, 작업 디렉토리의 파일 내용 복구 기능을 한다.

- git switch, git restore 명령으로 나뉘었다. 

 

⭐ reset

- 현재 브랜치를 특정 커밋으로 되돌릴 때 사용한다.

- git reset --hard 명령을 실행하면 현재 브랜치를 지정한 커밋으로 옮긴 후 해당 커밋의 내용을 작업 폴더에 반영한다.

- git reset --hard 명령을 사용하려면 커밋 체크섬을 알아야 한다.

- git log를 통해 커밋 체크섬을 알 수 있지만, HEAD~ 또는 HEAD^로 시작하는 약칭을 사용해도 된다.

 

⭐rebase

- 현재 브랜치에만 있는 새로운 커밋을 대상 브랜치 위로 재배치시킨다.

- 현재 브랜치에 재배치할 커밋이 없을 경우 아무 일도 일어나지 않는다.

- 빨리 감기 병합이 가능한 상황에서 rebase하면 빨리 감기 병합을 한다.

- 3-way 병합을 하면 병합 커밋이 생성되므로 트리가 지저분해진다.

- 브랜치의 커밋을 재배치하는 rebase를 사용하면 트리가 깔끔하다.

- HEAD와 대상 브랜치의 공통 조상을 찾고, 공통조상 이후에 생성된 커밋들을 대상 브랜치 뒤로 재배치한다.

- 재배치된 커밋들은 기존의 커밋과 다른 커밋이다. (커밋 체크섬이 다르다.)

- rebase는 재배치 대상 커밋이 여러 개일 경우 여러 번 충돌이 발생할 수 있고, 커밋을 단계별로 수정하기 때문에 git rebase --continue 명령으로 중단된 rebase를 재개하게 한다.

- 여러 커밋에 충돌이 발생했다면, 충돌을 해결할 때마다 git rebase --continue 명령을 매번 입력해야 한다.- 원격저장소에 푸시한 브랜치는 rebase하지 않는 것이 좋다. (협업 과정에서 동일한 커밋의 사본이 여러 개 생성되고 충돌이 발생하는 등의 문제가 발생할 수 있음.)

 

⭐ 3-way 병합 vs rebase

  3-way 병합 rebase
특징 머지 커밋 생성 현재 커밋들을 수정하면서 대상 브랜치 위로 재배치
장점 한 번만 충돌 발생 깔끔한 히스토리
단점 트리가 약간 지저분해진다. 여러 번 충돌이 발생할 수 있다.

 

 

배운 명령어 정리

⭐브랜치 관련 명령어

- git branch -v

  • 로컬 저장소의 브랜치 목록을 보는 명령으로 -v 옵션을 사용하면 마지막 커밋도 함께 표시된다.
  • 표시된 브랜치 중에서 이름 왼쪽에 *가 붙어 있으면 HEAD 브랜치이다.

- git branch -f 브랜치이름 커밋체크섬

  • 새로운 브랜치를 생성한다.
  • 커밋체크섬 값을 주지 않으면 HEAD로부터 브랜치를 생성한다.
  • 이미 있는 브랜치를 다른 커밋으로 옮기고 싶을 때는 -f 옵션을 줘야 한다.

- git branch -r-v 

  • 원격저장소에 있는 브랜치를 보고 싶을 때 사용한다.
  • -v 옵션을 사용해서 커밋 요약도 볼 수 있다.

- git checkout 브랜치이름

  • 특정 브랜치로 체크아웃할 때 사용한다.
  • 브랜치 이름 대신 체크섬을 쓸 수는 있지만 권장하지 않는다.

⚠️ git checkout 커밋체크섬

  • HEAD와 브랜치가 분리되는 Detached HEAD 상황이 된다.
  • 여전히 커밋을 생성할 수 있지만 다른 브랜치로 체크아웃하는 순간 Detached HEAD의 커밋은 다 사라져서 보이지 않는다. 
  • 커밋은 로컬저장소에 남아있기 때문에 git reflog 명령으로 복구할 수는 있지만 권장하지 않는다.

- git checkout -b 브랜치이름 커밋체크섬

  • 특정 커밋에서 브랜치를 새로 생성하고 동시에 체크아웃까지 한다.
  • 두 명령을 하나로 합친 명령이기 때문에 간결해서 자주 사용한다.

- git merge 대상브랜치

  • 현재 브랜치와 대상 브랜치를 병합할 때 사용한다.
  • 병합 커밋(merge commit)이 새로 생기는 경우가 많다.

- git rebase 대상브랜치

  • 내 브랜치의 커밋들을 대상 브랜치에 재배치시킨다.
  • 히스토리가 깔끔해져서 자주 사용하지만 조심해야 한다.

- git branch -d

   브랜치이름

  • 특정 브랜치를 삭제할 때 사용한다.
  • HEAD 브랜치나 병합이 되지 않은 브랜치는 삭제할 수 있다.

- git branch -D

   브랜치이름

  • 브랜치를 강제로 삭제하는 명령이다.
  • -d로 삭제할 수 없는 브랜치를 지우고 싶을 때 사용하며, 조심해야 한다.

⭐ hard reset

git reset --hard 이동할 커밋 체크섬

: 현재 브랜치를 지정한 커밋으로 옮긴다. 작업 폴더의 내용도 변경된다. 

 

⭐ 커밋 체크섬 대신 사용 가능한 약칭

HEAD~숫자 :  HEAD~n은 n번째 위쪽 조상이라는 뜻으로 HEAD~는 부모 커밋을 말한다.

HAED^숫자 : 병합 커밋처럼 부모가 둘 이상인 커밋에서만 의미가 있다. HEAD^는 부모 커밋이고,  HAED^2는 두 번째 부모 커밋이다.

 

⭐ git rebase 대상 브랜치 : 현재 브랜치에만 있는 새로운 커밋을 대상 브랜치 위로 재배치시킨다.

 

⭐ 태그

- git tag -a -m 간단한 메시지 태그 이름 브랜치 또는 체크섬 

  • -a로 주석 있는(annotated) 태그를 생성한다.
  • 메시지와 태그 이름은 필수이며 브랜치 이름을 생략하면 HEAD에 태그를 생성한다.

- git push 원격저장소 별명 태그 이름 : 원격저장소에 태그를 업로드한다.

 

⭐switch

- git switch 브랜치이름 : git checkout 브랜치이름 과 동일한 명령으로 현재 브랜치를 변경한다.

- git switch -c 브랜치이름 :  git checkout -b 브랜치이름 과 동일한 명령으로 새로운 브랜치를 만들고 해당 브랜치로 변경한다.

 

⭐rebase

- git rebase 대상브랜치 : HEAD와 대상브랜치의 공통조상을 찾은 뒤 공통조상 이후에 생성된 커밋들을 대상브랜치 뒤로 재배치한다.

- git rebase --continue : 충돌로 인해 중단된 rebase를 재개한다.