[Git & Git Hub] Branch

정진우·2024년 4월 23일
0

Git & Git Hub

목록 보기
2/11
post-thumbnail

Branch

Branch는 버전 관리 시스템에서 코드베이스의 여러 버전을 동시에 개발하고 관리할 수 있도록 하는 기능입니다. 쉽게 말하면, 나뭇가지처럼 코드베이스가 여러 방향으로 분기되어 발전하는 것을 가능하게 합니다.

  • 코드 개발 라인을 여러 개의 분기로 나누어 관리하는 기능입니다.
  • 각각의 독립된 Branch에서 마음대로 소스코드를 변경하여 작업 한 후 원래 버전과 비교하여 또 하나의 새로운 버전을 만들어 낼 수 있습니다.
  • 주로 여러명이 동시에 작업할 때, 다른 사람에게 영향을 주거나 받지 않기 위해, 팀 프로젝트에서 많이 활용되고 있습니다.
  • 개발자들은 각자 맡은 역할의 기능을 구현하면서 "작업단위"로 업무가 진행됩니다. 이때 서로에게 영향을 주지 않고 내용을 모두 기록하기 위해 만들어진 기능입니다.

작업 트리(Work Tree) = 작업 공간(working space)

  • 개인 컴퓨터 환경에서 소스 코드를 편집하는 일반적인 프로젝트 폴더입니다.
  • 브랜치 또는 커밋 단위로 헤드를 움직일 시에 작업 트리도 같이 변화합니다.

HEAD⁉️

HEAD는 현재 작업중인 브랜치를 가리키는 화살표라고 생각하면 됩니다. master는 기본 개발 라인의 이름입니다. 따라서 HEAD -> master"현재 작업 중인 브랜치는 기본 개발 라인(master)입니다" 라는 뜻 입니다.

branch 명령어

# branch 생성
git branch [새로운 브랜치 이름] # 지정된 이름의 새로운 브랜치를 생성합니다.

# branch 관리
git branch # 로컬 브랜치 목록을 확인합니다.
git branch -r # 원격 저장소의 브랜치 목록을 확인합니다. 
git branch -a # 로컬 및 원격 저장소의 모든 브랜치 목록을 확인합니다.
git branch -v # 로컬 브랜치와 연결된 원격 브랜치 정보를 확인합니다.

# branch 이름 변경
git branch -m [브랜치 이름] # 브랜치의 이름을 변경, 이름을 변경하려면 해당 브랜치에서 이름을 변경해야 합니다.

# branch 삭제
git branch -d [브랜치 이름] # 로컬에서 지정된 브랜치를 삭제합니다.
git branch -D [브랜치 이름] # 로컬에서 지정된 브랜치를 강제 삭제합니다.

branch 변경

⭐️ Branching Exercise ⭐️
1. git checkout

  • 브랜치 변경 : git checkout은 작업 브랜치를 변경하는데 사용됩니다. 예를 들어, git checkout my-branch명령어는 현재 작업 중인 브랜치에서 my-branch브랜치로 변경합니다.
  • 파일 복원 : git checkout은 특정 파일 또는 디렉토리의 변경 사항을 최근 커밋 상태로 되돌리는데도 사용됩니다. 예를 들어, git checkout -- myfile.txt명령어는 myfile.txt파일의 모든 변경 사항을 취소하고 최근 커밋의 상태로 되돌립니다.
  • 커밋 체크아웃 : 특정 커밋으로 체크아웃하려면 git checkout 명령어와 함께 커밋 해시를 사용합니다. 이렇게 하면 해당 커밋의 상태로 작업 트리가 변경됩니다. 즉, git checkout a1b2c3d4와 같이 명령어를 입력하면 a1b2c3d4라는 해시를 가진 커밋으로 작업 트리가 이동하게 됩니다. 이를 통해 특정 커밋의 상태를 확인하거나 이동할 수 있습니다.
# branch 변경
git checkout [브랜치 이름] # 지정된 브랜치로 이동합니다.
git checkout -b [새로운 브랜치 이름] # 새로운 브랜치를 생성하고 해당 브랜치로 이동합니다.
git checkout -t [원격 브랜치 이름] # 원격 브랜치를 추적하는 로컬 브랜치를 생성 해당 브랜치로 이동

# 특정 커밋으로 이동
git checkout [커밋 해시] # 지정된 커밋으로 이동합니다.
git checkout HEAD~1 # 현재 브랜치의 이전 커밋으로 이동합니다.

# 파일 복원
git checkout [파일 이름] # 지정된 파일을 최신 버전으로 복원합니다.
  1. git switch
  • 브랜치를 변경하는 명확한 명령어입니다. 또한 새로운 브랜치를 생성하고 그 브랜치로 바로 이동할 수 있습니다. 이는 git checkout -b [새로운 브랜치 이름] 명령어와 동일 합니다.
  • git checkout의 명령어 중 브랜치 변경 기능이 git switch로 분리되어 사용되기 시작했습니다.
  • git switch를 사용할 때 스테이징되지 않은 변경 사항이 있을 경우, 새로운 브랜치에 포함되지 않기 때문에 변경 사항을 만들 때마다 브랜치 이동 전에 항상 git add로 등록하고 git commit할 것을 권장합니다.
  • git switch 명령어를 사용할 때 스테이징되지 않은 변경 사항은 새로운 브랜치에 포함되지 않고 사라집니다. 따라서, 변경 사항을 만들 때마다 브랜치 이동 전에 git add로 변경 사항을 스테이징하고 git commit으로 커밋하는 것이 좋습니다.
# branch 변경
git switch [브랜치 이름] 
# 지정된 브랜치로 이동합니다.
# 로컬에 해당 브랜치가 없는 경우 자동으로 해당 원격 브랜치를 추적하는 로컬 브랜치가 만들어집니다.

git switch -c [새로운 브랜치 이름] # 새로운 브랜치를 생성하고 해당 브랜치로 이동합니다.

# 특정 커밋 이동 
git switch [커밋 해시] # 특정 커밋으로 이동할 수 있습니다.

branch 병합

⭐️ Git Merging Exercise ⭐️
git merge는 브랜치와 브랜치를 병합할 수 있는 명령입니다. 브랜치를 병합한다는 것은 다른 브랜치의 변경 사항을 현재 브랜치에 적용하는 것을 의미합니다.

# 브랜치 병합
git merge [병합할 브랜치명]
# merge를 진행할 때 아무 옵션을 주지 않는 경우
# 현 브랜치와 병합할 브랜치가 Fast-forward 관계이면 Fast-forward 병합을 진행하며, 그렇지 않은 경우는 Merge 커밋을 생성하여 3 way-merge를 진행

git merge --no-ff [병합할 브랜치명]
# 현재 브랜치와 병합 대상의 관계가 Fast-forward관계 여부와 상관없이 merge 커밋을 생성하여 병합

git merge --ff-only [병합할 브랜치명]
# 현재 브랜치와 병합 대상의 관계가 Fast-forward인 경우에만 병합을 진행, merge 커밋 생성되지 않는다.

git merge --squash [병합할 브랜치명]

Remote Tracking Branches

  • 리모트 트래킹 브랜치는 리모트 브랜치를 추적하는 레퍼런스이며 브랜치다. 리모트 트래킹 브랜치는 로컬에 있지만 임의로 움직일 수 없다. 리모트 서버에 연결할 때마다 리모트의 브랜치 업데이트 내용에 따라서 자동으로 갱신될 뿐이다. 리모트 트래킹 브랜치는 일종의 북마크라고 할 수 있다. 리모트 저장소에 마지막으로 연결했던 순간에 브랜치가 무슨 커밋을 가리키고 있었는지를 나타낸다.
  • 리모트 트래킹 브랜치의 이름은 <remote>/<branch> 형식으로 되어 있다. 예를 들어 리모트 저장소 origin 의 master 브랜치를 보고 싶다면 origin/master 라는 이름으로 브랜치를 확인하면 된다. 다른 팀원과 함께 어떤 이슈를 구현할 때 그 팀원이 iss53 브랜치를 서버로 Push 했고 당신도 로컬에 iss53 브랜치가 있다고 가정하자. 이때 서버의 iss53 브랜치가 가리키는 커밋은 로컬에서 origin/iss53 이 가리키는 커밋이다.
git checkout origin/main
# 원격 추적 브랜치의 커밋으로 이동합니다.

Git Branch 종류 (5가지)

Gitflow Workflow 에서는 항상 유지되는 메인 브랜치(master, develop), 일정 기간 동안만 유지되는 보조 브랜치들(feature, release, hotfix) 을 포함하여 총 5가지의 브랜치를 사용합니다.

  • master : 제품으로 출시될 수 있는 브랜치
  • develop : 다음 출시 버전을 개발하는 브랜치
  • feature : 기능을 개발하는 브랜치
  • release : 이번 출시 버전을 준비하는 브랜치
  • hotfix : 출시 버전에서 발생한 버그를 수정 하는 브랜치


master branch - 제품으로 출시될 수 있는 브랜치

  • 배포(release) 이력을 관리하기 위해 사용. 즉, 배포 가능한 상태만을 관리한다.

develop branch - 다음 출시 버전을 개발하는 브랜치

  • 기능 개발을 위한 브랜치들을 병합하기 위해 사용, 모든 기능이 추가되고 버그가 수정되어 배포 가능한 안정적인 상태라면 develop branchmaster branch에 병합(merge)합니다.
  • 평소에는 develop branch를 기반으로 개발을 진행합니다.

feature branch - 기능을 개발하는 브랜치

  • feature branch는 새로운 기능 개발 및 버그 수정이 필요할 때마다 develop branch로 부터 분기합니다.
  • feature branch에서의 작업은 기본적으로 공유할 필요가 없기 때문에, 자신의 로컬 저장소에서 관리한다. 개발이 완료되면 develop branch로 병합(merge)하여 다른 사람과 공유 합니다.

release branch - 이번 출시 버전을 준비하는 브랜치

  • 배포를 위한 전용 브랜치를 사용함으로써 한 팀이 해당 배포를 준비하는 동안 다른팀은 다음 배포를 위한 기능개발을 계속 할 수 있다. 딱딱 끊어지는 개발 단계를 정의하기에 좋습니다.
  • develop branch에서 배포 가능한 수준의 기능이 모이거나 정해진 배포 일정이 되면 release branch를 생성합니다.

hotfix branch - 출시 버전에서 발생한 버그를 수정 하는 브랜치

  • 배포한 버전에 긴급하게 수정을 해야 할 필요가 있을 경우, master branch에서 분기하는 브랜치입니다.
  • develop branch에서 문제를 수정하여 배포 가능한 버전을 만드는데는 시간이 많이 걸리며 안정성을 보장하기 어렵습니다. 따라서, 바로 배포 가능한 master branch에서 직접 브랜치를 생성하고, 필요한 부분만을 수정한 후 다시 master branch에 병합(merge)하여 배포합니다.

merge의 종류

  • Fast-forward
  • 3-way merge
  • Squash merge
  • Rebase merge

Fast-forward

Fast-Forward merge는 Git에서 사용하는 병합 방식 중 하나입니다. 이 방식은 현재 브랜치에 변경 사항이 없고, 병합하려는 브랜치가 현재 브랜치로부터 직접 분기된 경우에 사용할 수 있습니다. 이런 경우, Git은 병합 과정을 "Fast Forward" 하여 이전 브랜치의 모든 커밋을 그대로 가져오고, 브랜치 포인터를 최신 커밋으로 이동시킵니다. 즉, 별도의 병합 커밋을 생성하지 않고, 새 브랜치의 커밋을 현재 브랜치로 "빠르게 앞당기는" 방식입니다.

예시

  1. my-branch 브랜치는 master 브랜치에서 분기되었습니다.
  2. my-branch 브랜치에서 변경 사항을 추가하고 커밋했습니다.
  3. master 브랜치에서 git merge my-branch 명령어를 사용하여 my-branch 브랜치의 변경 사항을 병합했습니다.
  4. 병합 과정에서 별도의 병합 커밋이 생성되지 않았고, my-branch 브랜치의 커밋이 master 브랜치에 "빠르게 앞당겨졌습니다."

3-way merge

3-way merge는 Git에서 사용하는 병합 방식 중 하나로, 두 브랜치가 최근에 분기된 지점(공통 조상 커밋)을 기준으로 두 브랜치의 변경 사항을 비교하여 병합결과를 생성합니다.

예시 - 1

예를 들어, feature 브랜치와 master 브랜치가 있다고 가정해봅시다. 각 브랜치의 마지막 커밋은 f2m2이고, 공통 조상 커밋(base)을 b라고 합시다. 3-way merge 과정은 다음과 같습니다.
1. 3-way-merge에서는 공통 조상 커밋(base)을 기준으로 각 브랜치의 마지막 커밋(f2, m2)의 차이점을 비교합니다.
2. 각 파일의 변경 사항을 분석하여 충돌 여부를 확인합니다.
3. 충돌이 없는 경우 Git은 자동으로 새로운 커밋을 생성합니다.
4. 충돌이 발생하면 개발자가 직접 해결해야 합니다.

예시 - 2 (충돌발생)

 1. 내 브랜치 커밋 
 2. 남의 브랜치 커밋 
 3. Base는 공통 조상 커밋을 의미하며, 두 브랜치가 공유하는 가장 최근의 커밋

Base가 공통 조상 커밋으로서 기준이 되며, 이를 통해 동일한 내용을 공유하게 됩니다.

MyBaseOther
AAA
BBB
CCC
DDD

다음 표는 My 브랜치와 Other 브랜치의 변경 사항을 보여줍니다. Base는 두 브랜치의 공통 조상 커밋입니다.

MyBaseOther
AAA
HBB
CCT
HDT

Base 커밋을 기준으로 My 브랜치와 Other 브랜치의 변경 사항을 비교합니다.

MyBaseOther3 way merge
AAAA
HBBH
CCTT
HDTConflict
  1. BaseMyOther가 모두 동일한 경우 Base의 내용이 병합 결과에 반영됩니다.
  2. BaseOther가 동일하고 My가 다른경우 My의 내용이 병합 결과에 반영됩니다.
  3. BaseMy가 동일하고 Other가 다른경우 Other의 내용이 병합 결과에 반영됩니다.
  4. BaseMyOther 모두 다른 경우 충돌(Conflict)이 발생합니다. 두 브랜치 모두 Base와 다르게 변경되었기 때문입니다. 어떤 변경이 최신 업데이트인지 시스템이 판단할 수 없으므로, 사용자는 이 충돌을 수동으로 해결해야 합니다.
  5. 충돌 해결

병합 결과가 반영되어 작성된 내용과 아래의 충돌이 발생한 내용이 있습니다. 사용자는 이를 수동으로 해결해야 하는 상황입니다.

  • HEAD의 내용 (현재 master 브랜치의 내용)을 사용합니다.
  • feature 브랜치의 내용을 사용합니다.
  • HEADfeature의 내용을 모두 사용합니다.
  • 충돌 표시자 (<<<, >>>, ===)를 제거하고 완전히 다른 내용을 입력합니다.
    원하는 내용을 작성하고 저장한 후, 변경 사항을 commit하면 merge가 성공적으로 이루어집니다.

Squash merge

Squash는 여러개의 커밋을 하나의 커밋으로 합치는 것을 의미합니다. Squash merge는 병합할 브랜치의 모든 커밋을 하나의 커밋으로 Squash한 새로운 커밋을 Base 브랜치에 추가하는 방식으로 병합하는 것을 의미합니다.

  • commit F, G, H를 결합하여 새로운 commit, I를 생성하고 main에 추가합니다. I의 커밋의 부모는 E커밋 입니다. 이는 Feature 브랜치의 commit history를 정리하기 위해 사용됩니다.

Squash를 하게 되면 모든 커밋 이력이 하나의 커밋으로 합쳐지고 사라진다는 점을 주의해야 한다.

git switch main
git merge --squash my-branch
git commit -m "Squash and Merge"

Rebase merge

  • 브랜치의 공통 조상이 되는 Base를 다른 브랜치의 커밋 지점으로 바꾸는 것입니다. Base를 재정의하여 커밋 히스토리를 조작합니다.
  • 커밋 히스토리를 더 깔끔하게 만들어 줍니다. rebase를 사용하면 원하는 브랜치에 직접적으로 변경 사항을 적용할 수 있어서 커밋 히스토리가 선형적으로 유지됩니다.
  • 불필요한 merge 커밋을 줄여줍니다. rebase는 현재 브랜치를 선택한 브랜치의 최신 커밋 위로 옮기므로, 현재 브랜치와 선택한 브랜치를 병합할 때 추가적인 merge 커밋이 생성되지 않습니다.

Rebase의 주의사항

  • rebase는 과거의 커밋을 변경하므로, 이미 원격 저장소에 Push된 커밋은 Rebase를 하지 않는 것이 일반적입니다.
  • 충돌이 발생하면 해결이 복잡할 수 있습니다. rebase는 각 변경 사항을 순서대로 적용하기 때문에, 같은 충돌을 여러 번 해결해야 할 수도 있습니다.

Rebase 예시

  • feature 브랜치와 master 브랜치가 있습니다.
  • 각 브랜치의 마지막 커밋은 f2와 m2입니다.
  • 현재 공통 조상 커밋(base)은 b입니다.
# feature 브랜치로 변경 HEAD 포인터는 feature를 가리킨다.
git switch feature

# feature 브랜치의 이력을 master 브랜치의 최신 커밋 위에 재배치
git rebase master 

# master 브랜치로 변경 HEAD 포인터는 master를 가리킨다.
git switch master

# master 브랜치에 feature 브랜치의 변경 사항을 병합
git merge feature

git checkout feature # feature 브랜치로 변경 HEAD 포인터는 feature를 가리킨다.
git rebase master # feature 브랜치의 이력을 master 브랜치의 최신 커밋 위에 재배치
git checkout master # master 브랜치로 변경 HEAD 포인터는 master를 가리킨다.
git merge feature # master 브랜치에 feature 브랜치의 변경 사항을 병합
  • rebase를 실행하면 기존 브랜치의 커밋(f1f2)들이 새로운 베이스 커밋 위에 다시 적용됩니다. 이 과정에서 기존의 커밋 객체들은 그래프 구조에서 더 이상 어떠한 브랜치나 태그에도 참조되지 않는 dangling 상태가 됩니다. 이러한 dangling 커밋들은 Git 내부에서는 여전히 존재하지만, 접근하기 위해서는 직접적인 참조가 필요하며 더 이상 필요하지 않은 경우에는 정리해주는 것이 좋습니다.

참고

profile
내가 바뀌지 않으면 아무것도 바뀌지 않는다 🔥🔥🔥

0개의 댓글