Seren dev's blog
article thumbnail
이 글은 인프런의 "알잘딱깔센 GitHub" 강의를 듣고 정리한 내용입니다.

 

인프런 강의 링크

 

[무료] 30분 요약 강좌 시즌4 : 알잘딱깔센 GitHub - 인프런 | 강의

알아서! 잘! 딱! 깔끔하고! 센스있게! 정리하는 GitHub 핵심 개념 책의 무료강의입니다. 해당 책과 Notion 링크도 무료로 다운로드 받을 수 있습니다. 비영리 프로젝트로 교재활용도 허락없이 가능합

www.inflearn.com

노션 링크

 


Branch 사용하기

개발 작업을 할 때, 개발자들은 작업 레파지토리에서 소스 코드를 공유한다. 연관성이 없는 기능을 개발한다고 할 때 어떤 개발자는 A 기능을 작업하고 또 다른 개발자는 B 기능을 맡아 작업한다고 가정해보자.

만약 A 작업이 다 끝난 뒤에 B 작업을 수행한다면 연관성이 없는 기능 단위의 작업을 비효율적으로 하고 있는 것이다. 별도로 작업하여 합치는 방안이 가장 좋을 것이다. 별도로 작업하여 별도의 공간을 마련하는 것이 브랜치, 합치는 것이 머지다.

어떻게 나누어야 할지 결정하는 것을 브랜치 전략이라고 한다.

 

브랜치는 독립적인 작업을 할 수 있는 공간이다. A 기능을 A 브랜치에서 작업하고, B 기능을 B 브랜치에서 작업하면, 서로 다른 독립적인 공간에서 작업하는 것이기 때문에 서로에게 영향을 주지 않고 작업할 수 있다. 메인 작업 공간의 코드를 복사한 개별적인 작업 공간을 만들고 거기서 각각의 기능 개발을 진행한다. 그리고 작업이 완료되었을 때, 코드를 합치면 된다.

개리는 기본 브랜치에서 작업한다. 개리1 ~ 개리3까지 작업을하고 빙키가 프로젝트에 참여하여 개리3을 pull 받고, 서로 다른 기능을 구현하기 때문에 브랜치를 분리한다. 빙키는 이제 분리된 작업공간(기능 브랜치)에서 자신의 커밋을 남기며 작업을 독립적으로 진행한다.

 

만약 서로 같은 부분을 다르게 수정하여 합치면? 충돌이 발생한다. 충돌이 날 때 해결 방법은 현재 챕터의 5. conflict에서 설명한다.

 

git에서의 기본 브랜치는 master 브랜치(이하 main으로 표기) 이다. 기본 브랜치는 git 저장소를 초기화할 때 자동으로 만들어진다. 이때, 'HEAD'라는 특수한 포인터가 있다. 이 포인터는 지금 작업 중인 브랜치를 가리킨다.

GitHub의 기본 브랜치 명이 Git과 다른 이유
master가 노예제를 연상하게 한다는 이유로 많은 프로그래밍 언어, 서비스에서 master 대신 main을 사용하고 있다.
git config --global init.defaultBranch main
명령을 통해 git에서도 GitHub처럼 기본 브랜치를 main으로 사용할 수 있다.

 

하나의 기능 개발이 완료되면 특정 브랜치의 내용들을 main 브랜치에 합친다. 또 새로운 작업을 하려고 하면 main 브랜치에서 다시 새로운 feature 브랜치를 생성하고 작업한다.

브랜치 사용 방법 및 실습

  • 현재 브랜치 목록과 현재 브랜치 확인
$ git branch

 

브랜치 실습을 위해 로컬 폴더 garry, bingky를 새로 생성하고 깃헙에서 새로운 레포지토리를 생성한다. 이 때 README 파일을 생성한다.

garry 폴더에 git bash 실행 후

git clone https://github.com/Soomin-Lim/branchtest.git .

README 파일 수정 후 아래 과정을 3번 반복한다.

  • branch 만들기
$ git branch Gary

개리4가 아니라 개리3

 

기본 브랜치(main, master)

앞에서 언급했듯, git에서의 기본 브랜치는 master이고 GitHub에서의 기본 브랜치는 main이다.

git init 명령을 통해 초기화하고 레포지토리에 연결하는 과정(해당 챕터에서 진행하는 과정)을 진행하게 되면 기본 브랜치는 master가 된다. 앞에 언급된 명령어 git config --global init.defaultBranch main 로 설치 시 또는 설치 후 설정을 통해 기본 브랜치 이름을 바꿀 수도 있습니다. 깃허브에서 제공하는 초기화 설정을 사용하거나 가이드라인을 따라 진행한다면 기본 브랜치가 main이 된다.

README.md file 초기세팅
git-hub 레포지토리 연결 가이드라인

Branch 이동/변경, 파일 복원하기

checkout

checkout은 브랜치 변경 또는 작업 트리 파일 복원을 할 수 있습니다. 하지만 기존의 checkout이 가진 기능이 너무 많았습니다. 때문에 Git 2.23에서 checkout을 대신해 switchrestore가 도입되었습니다.

 

checkout을 통해 브랜치를 이동하여 사용할 수 있습니다. 즉, 사용할 브랜치를 지정하는 것이다.

$ git checkout Gary

개리4가 아니라 개리3

새로운 내용을 추가하고 커밋해보자.

$ echo 'hello branch' >> branch.txt
$ git status
$ git add branch.txt
$ git commit -m "개리4"

 

git checkout main을 입력하여 main 브랜치로 이동하면 GitBranch.txt 파일이 없는 것을 확인할 수 있다.

 

 

다른 누군가가 원격 저장소에서 코드를 받아온다.

$ git clone https://github.com/Soomin-Lim/branchtest.git .

Binky 브랜치 생성 -> Binky 브랜치로 이동 -> 파일 생성 -> add -> commit -> push

이 때 push에서 에러가 발생한다.

에러가 난 이유?
로컬 저장소의 브랜치 정보는 원격 저장소에 자동으로 등록되지 않으므로 로컬 저장소에 있는 브랜치가 원격 저장소에 있는 브랜치를 추적할 수 있도록 하지 않았기 때문이다. 이 때 로컬 브랜치가 추적해야 할 브랜치를 upstream 브랜치라고 한다.

해결 방법
아래의 방법을 통해 로컬 브랜치가 원격 브랜치를 추적할 수 있도록 한다.
1) git push --set -upstream <원격 저장소> <브랜치명>
git push --set -upstream origin Binky
2) git push -u <원격 저장소> <브랜치명>
git push -u origin Binky

 

Gary 브랜치에서 커밋한 것도 git push를 해주면 깃헙에서 Binky와 Gary 브랜치를 확인할 수 있다.

(원래는 bingky 로컬 폴더에서 git clone을 하기 전에 Gary 브랜치를 push 해주어야 한다.)

💡 git push vs git push <원격저장소명> <브랜치명>

git push <원격저장소명> <브랜치명> 는 어느 원격 저장소의 어느 브랜치에 push할 지 전달한다.

git push 를 할 때에는 이미 연결된 곳에 push할 수 있지만, 원격 저장소에 해당 브랜치가 없는 경우에는 git push -u origin <브랜치명> 을 실행해야 이후에 간단히 push할 수 있다. -u 옵션이 --set -upstream 이다.

여기서 origin은 키워드가 아니다. one, two등 이름으로 할 수 있다. 이는 여러 원격 저장소를 연결할 수 있기 때문이다. main이 어느 원격 저장소(GitHub인지 GitLab인지 또는 그 외인지)의 main인지 알 수 없기 때문에 설정해주어야 한다.

 

switch

브랜치를 변경한다. checkout과 같다.

$ git switch Gary

브랜치를 새로 만들어서 변경할 수도 있다.

$ git switch -c Gary

 

restore

restore는 파일의 수정 내용을 최신 커밋 상태로 복원add 를 통해 스테이지에 올린 파일을 빼낼 때 사용한다.

 

우선 파일을 생성한 후 커밋을 합니다. (Binky 브랜치에서 실습)

$ echo 'hello' >> restoreTest.txt
$ git add .
$ git commit -m 'restore test'

이후 해당 파일을 수정한 후에 저장을 한다.

  1. 아래의 명령어 입력
$ vi restoreTest.txt
  1. 아래 순서에 따라 순차적으로 편집
i -> 수정 후 -> Esc -> :wq

modified 파일이 있다고 나온 것을 볼 수 있습니다.

 

이때, 파일의 수정 내용을 최근 커밋 상태로 복원하는 방법은 2가지가 있다.

1) restore을 이용하여 변경 사항을 되돌리기

$ git restore restoreTest.txt

 

2) checkout을 이용하여 파일 변경 내역을 되돌리기

git checkout -- filename해당 파일 내용이 최신 커밋 전으로 돌아가도록 한다. 이때, checkout으로 지워진 내용은 커밋을 하지 않았기 때문에 다시 복구할 수 없다.

$ git checkout -- restoreTest.txt

modified 파일이 없는 것을 확인할 수 있다.

 

 

스테이지에 올린 파일을 빼는 방법은 두 가지가 있다.

$ git add .
$ git status

1) restore 명령어를 이용하여 빼기

$ git restore --staged restoreTest.txt

2) reset 명령어를 이용하여 빼기

$ git reset HEAD restoreTest.txt

 

Branch 삭제/복구하기

branch 삭제

특정 브랜치를 삭제하는 명령어다.

$ git branch -d <브랜치명>

branch 복구

1단계. git reflog로 복구 시점 확인

먼저, 삭제한 브랜치를 어떤 시점으로 복구할 것인지 알아야 한다. 삭제한 브랜치가 남겼었던 커밋 중 어떤 상태로 돌아갈 지를 찾아서 커밋 해시값을 가져와야 한다. 이를 위해서 모든 참조 목록을 확인 할 수 있는 git reflog 명령어를 입력한다.

$ git reflog

reflog는 모든 참조 내역들을 뜻한다. main 브랜치에서 어떤 브랜치로 참조를 했는지, 어떤 커밋을 날렸는지 등 모든 내역들을 git reflog를 통해 확인할 수 있다.

git log커밋 로그를 확인하는 명령어

 

Gary 브랜치를 git branch -D Gary 명령어로 삭제 한 뒤, 복구 시켜보자.

2단계. git checkout으로 브랜치 복구

브랜치를 복구하는 명령어는 다음과 같다.

$ git checkout -b <삭제한 브랜치명> <커밋 해시값>

git reflog로 삭제한 브랜치의 마지막 커밋 해시값을 확인한 뒤, 이를 이용해서 브랜치를 복구시킬 수 있다.

 


merge(합병)하기

개리4가 아니라 개리3, 개리5가 아니라 개리4, 빙키1이 아니라 빙키4

일단 먼저 Binky에서 push하지 않은 것이 있기 때문에 Binky 브랜치에서 먼저 git push를 한다.

 

그 다음 두 branch로 나누어 작업했던 것을 병합하기 위해 로컬 저장소의 main 브랜치에서 merge한 다음 깃헙 레포지토리에 push한다.

$ git checkout main
$ git log
$ git merge binky
$ git push origin main

원격 저장소에 반영이 된 모습이다.

 

이번에는 gary의 브랜치를 merge해 보자. 만약, 두 브랜치가 같은 곳을 수정했다면 충돌이 일어나지만 지금은 다른 곳을 수정했다는 가정하에 진행한다.

$ git merge Gary
$ git push origin master

원격 저장소에 반영이 된 모습이다.

merge해도 원격 저장소에 Gary 브랜치와 Binky 브랜치는 존재한다.


conflict

conflict 실습을 위해 conflicttest 레포지토리를 하나 생성한다.

그 다음 garry 로컬 폴더의 내용을 모두 삭제한다.

 

a 브랜치를 생성 후 a 브랜치로 이동하고, README 파일의 내용을 #conflict-a로 변경한 다음 add -> commit -> push 한다.

실행 결과는 다음과 같다.

그리고 bingky 로컬 폴더의 내용을 모두 삭제한 다음 git clone을 한다.

이 때 bingky 로컬 폴더의 README 파일 내용은 #conflicttest 이다.

 

b 브랜치를 생성 후 b 브랜치로 이동하고, README 파일의 내용을 #conflict-b로 변경한 다음 add -> commit -> push 한다.

Github 레포지토리

 

b 브랜치부터 먼저 merge하자.

그 다음 a 브랜치를 merge하면 에러가 발생한다.

merge할 때 두 브랜치가 같은 곳을 수정했다면 충돌이 일어나기 때문에 이때 충돌난 시점을 찾아 수동으로 고쳐주어야 한다.

bingky 로컬 폴더에서 README 파일을 열면 다음과 같이 충돌된 부분이 나타난다.

visual studio code에서는 충돌에 대해 좀 더 자동화된 도구를 제공한다.
아래와 같이 충돌이 났을 때 현재 코드를 유지할지, 머지된 코드를 반영할지 클릭으로 처리할 수 있다.

# conflict-a

두 가지 변경 내역을 비교한 다음 위와 같이 원하는 코드를 남기면 된다.

그 다음 commit하거나 merge하면 에러가 발생하기 때문에 add를 한 다음 commit -> push 해야 한다.

conflict 실습 전체 코드

문제

main branch : 
    -readme 파일 'hello world'
a branch : 
    - readme 파일 'hello a' 수정
    - a폴더 > a.txt(hello1) 생성
b branch :
    - readme 파일 'hello b' 수정
    - b폴더 > b.txt(hello2) 생성

2개를 merge, 충돌 해결

명령어

########## master branch ########## 
git init
echo 'hello world' >> README.md
git add .
git commit -m '1'
git branch a
git branch b

########## a branch ########## 

git checkout a
# 메모장으로 hello a로 수정 후 저장
mkdir a
cd a
touch a.txt
cd ..
git add .
git commit -m '2'

########## b branch ########## 

git checkout b
# 메모장으로 hello b로 수정 후 저장
mkdir b
cd b
touch b.txt
cd ..
git add .
git commit -m '3'

########## master branch ########## 

git checkout master
git merge a
git merge b # 충돌 발생, VSC에서 해결해보세요.

 

728x90
profile

Seren dev's blog

@Seren dev

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!