본문 바로가기
반응형

Git에 대해서 항상 사용했지만, git의 개념과 역할에 대해 잘 모르는 나의 모습을 발견하고 회사 선배의 추천을 받아 git 문서를 읽고 정리해보았다.

https://git-scm.com/book/ko/v2

 

Git - Book

 

git-scm.com

 

Git이란?

Git(깃)은 버전 관리 시스템을 말한다. 그렇다면 우리가 사용하는 GitHub(깃헙)은? git을 관리하는 프로젝트를 올려둘 수 있는 사이트이다. 

버전 관리란?

버전 관리는 프로젝트의 상태를 시간에 따라 기록하고 추적할 수 있게 하는 시스템을 말한다. 이를 통해 소프트웨어 개발자는 파일의 변경 내역을 관리하고, 언제든지 과거의 특정 시점으로 되돌릴 수 있다. Git은 이러한 버전 관리 시스템(VCS) 중 가장 널리 사용되는 분산 버전 관리 시스템(DVCS)이다.

 

그렇다면 상태를 기록하고 추적할 수 있게 도와주는 시스템, git에 대해 의문점이 생길 것이다. 어디에 저장하고, 어떻게 불러오는가?

이에 대한 해답으로 DVCS에 대해 알아보자. 

 

DVCS(분산 버전 관리 시스템, Distributed Version Control System)란?

 DVCS는 모든 사용자가 로컬에 프로젝트의 전체 히스토리를 복사해 보유하며, 중앙 서버 없이도 독립적으로 작업하고 이후 원격 저장소와 동기화할 수 있는 시스템을 말한다. 

 

 즉 각 사용자가 개인 컴퓨터에서 독립적으로 작업한 후, 그 작업 내용을 원격 저장소에 모아두고 공유하는 개념을 말하는 것이다. 

여기서 우리는 개인의 컴퓨터에 저장된 프로젝트를 로컬 저장소 로컬 저장소 (Local Repository)라고 정의 했으며, 중앙 서버에 저장되어있는 프로젝트를 원격 저장소(Remote Repository)라고 하기로 했다. 

 

그렇다면 우리는 어떻게 로컬&원격 저장소를 사용하게 되는지 알아보자 

 

DVCS 패턴
출처 - Git book

로컬 저장소와 원격 저장소와의 관계

로컬 저장소와 원격 저장소 사이에서는 2가지 특징을 가지고 있다. 

 

  • 독립성: 로컬 저장소는 원격 저장소와 독립적으로 동작한다. 사용자는 인터넷 연결 없이도 로컬에서 파일을 수정하고 커밋할 수 있습니다. 각 개발자는 자신만의 브랜치를 만들고, 다른 팀원의 작업에 영향을 받지 않고 독립적으로 작업을 수행할 수 있다. 
  • 동기화: 필요할 때 원격 저장소와 동기화할 수 있다. git push로 자신의 작업을 원격 저장소에 푸시하여 팀원과 공유할 수 있으며, git pull 또는 git fetch로 다른 개발자의 변경 사항을 로컬로 가져와 최신 상태로 동기화할 수 있다. 

그렇다면 로컬 저장소에서 원격 저장소에 저장하는 과정을 살펴보자.

 

1. 프로젝트 수정

- 우리는 프로젝트를 로컬 저장소(개인 컴퓨터)에서 수정하게 된다. 이때는 git에서 파일의 변경 사항을 추적하지만 변경 사항을 저장하거나 원격 저장소로 전송하지는 않는다. 

 

2. 스테이징(Staging)

- 스테이징 영역이란 커밋할 파일을 미리 준비하는 곳이다. 즉 변경된 파일을 인식하는 과정에서 커밋할 파일들을 저장하는 곳이라는 점에서 프로젝트 수정시에 git에서 파일의 변경 사항을 추적하는 것과의 차이가 있다. 아래 단계를 통해 프로젝트 수정 단계와 스테이징 상태의 차이를 쉽게 알 수 있다. 

 

  • Untracked (추적되지 않음): 아직 Git에서 관리하지 않는 파일로, 새로 생성한 파일이 여기에 해당한다. 
  • Modified (수정됨): Git에서 추적 중인 파일이 수정된 상태이다.
  • Staged (스테이징됨): git add 명령어를 통해 수정된 파일을 스테이징 영역에 추가한 상태로, 커밋할 준비가 된 상태입니다.

3. 커밋(commit)

- 커밋은 Git에서 변경 사항을 로컬 저장소에 영구적으로 저장하는 작업을 말한다. 커밋할 때, 각 커밋이 프로젝트의 *스냅샷으로 저장되기 때문에 프로젝트의 현재 상태를 기록하고, 이후 이를 추적할 수 있다. 

*스냅샷이란 프로젝트의 특정 시점에서의 파일 상태를 저장한 것을 의미하며, 이를 통해 프로젝트를 특정 시점으로 되돌릴 수 있다.


각 커밋은 SHA-1 해시라는 고유 식별자를 가지고 있으며, 이를 통해 커밋을 식별할 수 있다. SHA-1 해시는 변경된 파일의 내용, 작성자, 날짜 등을 기반으로 생성된다. 

 

하지만 커밋은 로컬 저장소에만 저장된다. 그렇기에 원격 저장소에 반영하려면, git push 명령어를 사용해 변경 사항을 원격 저장소에 전송해야 한다.

 

4. 푸시(git push)

- 푸시는 로컬 저장소에서 커밋한 내용을 원격 저장소로 업로드하는 작업이다. 아래 명령어를 통해 원하는 원격 저장소로 저장할 수 있다. 
이때 나오는 브랜치에 대해서는 밑에서 다루도록 하겠다. 

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

 

 

 

5. 동기화 과정

- 로컬에서 작업하다보보면, 다른 개발자들이 작업한 최신 내용을 원격 저장소에서 가져와 동기화하는 과정이 필요할 수 있다. 이때 git pull 또는 git fetch 명령어를 사용하여 프로젝트를 동기화를 하게 된다.

 

a) git pull: 원격 저장소의 최신 변경 사항을 가져와 병합

git pull origin <브랜치명>

- git pull은 원격 저장소에서 최신 커밋을 가져오고, 이를 로컬 브랜치와 자동으로 병합(merge)하는 작업을 수행한다. 이는 git fetch와 git merge를 한 번에 실행하는 것과 같다. 

 

git fetch: 원격 저장소의 최신 변경 사항을 가져오기만 함

- git fetch는 원격 저장소의 최신 상태를 가져오기만 한다. 이를 통해 로컬의 현재 작업에 영향을 주지 않으면서, 원격 저장소의 최신 상태를 미리 확인할 수 있다.

 

6.병합(Merge)

- 병합은 다른 브랜치나 원격 저장소의 변경 사항을 현재 브랜치에 합치는 작업을 말하며, 두 개의 커밋 이력을 하나로 합치는 역할을 한다.

아래 명령어의 경우 A-barnch의 변경사항을 현재 브랜치에 병합하게 된다. 

git merge A-branch

 

Git Branch

프로넥트를 진행하다보면, 코드를 통째로 복사하고 나서 원래 코드와는 상관없이 독립적으로 개발을 진행할 수 있는데, 이렇게 독립적으로 개발하는 것이 브랜치다. 자 브랜치에 대해 알아보자

 

브랜치(Branch)

- 브랜치는 Git에서 커밋들의 연결된 연속적인 기록을 가리키는 포인터다. 즉, 브랜치는 프로젝트의 특정 시점에서 새로운 분기를 만들어, 그 분기에서 독립적으로 작업할 수 있게 해준다.  브랜치를 통해 새로운 기능을 개발하거나 버그를 수정할 때, 메인 브랜치에서 분기된 브랜치에서 작업을 진행한 후, 작업이 완료되면 다시 병합(merge)을 통해 메인 브랜치반영할 수 있다. 

 

병합(Merge)과 충돌 관리

- 브랜치를 사용해 독립적으로 작업을 완료한 후, 이를 메인 브랜치에 반영하려면 병합(merge) 과정이 필요하다. 병합은 두 브랜치의 변경 사항을 하나로 통합하는 작업을 말한다. 

 병합 시, 같은 파일의 같은 부분이 서로 다르게 수정되면 충돌(conflict)이 발생할 수 있는데, 이때는 사용자가 충돌을 수동으로 해결해야 한다. 

 아래 코드를 보면 merge를 통해 병합 커밋 M이 생성되었고, 양쪽 브랜치의 히스토리가 모두 남아있는 것을 확인할 수 있다. 

# 병합 전
main 브랜치:      A --- B --- C
                   \
feature 브랜치:     D --- E

# 병합 후 
main 브랜치:      A --- B --- C ----------- M
                   \                     /
feature 브랜치:     D --- E --------------

 

 

리베이스(Rebase)

- 리베이스는 한 브랜치의 변경 사항을 다른 브랜치의 최상단에 재배치하는 작업으로, 이는 각 커밋을 일종의 "패치"로 처리하여 순차적으로 다시 적용하는 방식이다. rebase를 사용하면 커밋 히스토리가 마치 하나의 연속된 히스토리처럼 보이게 하므로, 더 깔끔하고 직관적인 커밋 로그를 유지할 수 있다.

 아래 코드를 보면 rebase를 통해 D', E'가 새로 적용되면서 병합 커밋이 생성되지 않고, 모든 커밋이 하나의 직선형 히스토리로 정리된 것을 확인할 수 있다.

# 리베이스 전
main 브랜치:      A --- B --- C
                   \
feature 브랜치:     D --- E

# 리베이스 후 
main 브랜치:      A --- B --- C --- D' --- E'

 

rebase 과정에서 충돌이 일어났을 때

- 병합(merge)와 유사하게 처리된다. 하지만 이때 충돌을 해결한 후에 스테이징을 진행하고, git rebase --continue를 사용하여 리베이스 작업을 이어나갈 수 있다. 

 

  • 리베이스 중 충돌 발생
  • 충돌 파일 수정: 충돌이 발생한 파일을 열고, 수동으로 수정
  • 수정된 파일 스테이징: git add <파일> 명령을 사용해 수정된 파일을 스테이징
  • 리베이스 계속 진행: git rebase --continue 명령으로 리베이스를 계속할 수 있도록 설정
  • 리베이스 중단 (선택): 리베이스를 중단하고 싶다면, git rebase --abort를 사용해 작업을 중단
  • 푸시(강제 푸시) : ㅇ리베이스는 커밋 히스토리를 수정하는 작업이기에 원격 저장소와 로컬 저장소의 히스토리가 달라 이전 커밋 내용을 덮어씌우기 위해 git push --force를 사용하여 원격 저장소에 커밋을 반영한다. 

 

태그(tag)

Git 태그(tag)는 특정 커밋을 고정하여 그 시점을 영구적으로 표시하는 포인터로, 버전 관리에 사용되며 특정 시점의 코드를 쉽게 참조하거나 배포할 수 있게 해준다. 

git tag v1.0
# 특정 커밋에 태그를 붙임
git tag v1.0 <커밋ID>  # 특정 커밋에 태그 추가
git push origin v1.0    # 태그를 원격 저장소로 푸시

 

 

반응형