Git 이란?

ohyujeong·2025년 1월 20일
0

git

목록 보기
3/3

Git

Git은 컴퓨터 파일의 변경사항을 추적하고 협업을 하기 위한 분산 버전 관리 시스템이다.

여기서 버전 관리 시스템이란 저장소의 파일 변화를 시간에 따라 기록하고, 후에 특정 시점의 버전을 다시 꺼내올 수 있는 시스템이다.

다음과 같은 작업을 수행할 수 있다.

  • 파일을 수정 전 상태로 돌린다.
  • 실수로 제거한 파일을 복구한다.
  • 프로젝트 자체를 이전 상태로 돌린다.
  • 시간에 따라 수정 내용을 비교한다.
  • 어떤 작업자가 문제를 일으켰는 지 확인한다.

이에 따라 Git은 주로 여러 명의 개발자가 하나의 소프트웨어 개발 프로젝트에 참여할 때 소스코드를 관리하고 협업하기 위해 사용된다.

Git 과 Github

Git은 코드의 버전을 관리하는 시스템이고,

GithubGit 저장소를 관리하는 클라우드 기반 호스팅 서비스이다.

다시 말해, Git으로 관리되는 파일을 클라우드에 저장하고 관리할 수 있게 도와주는 서비스이다.

Github는 Git의 기본적인 버전 관리 기능에 더해 이슈(Issue) 트래킹, 풀 리퀘스트(Pull Request) 등 협업과 프로젝트 관리를 위한 여러 추가적인 기능들을 제공한다.

Github와 같은 서비스로는 GitLab, Bitbucket, Launchpad 가 있다.

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

Git은 버전 관리 시스템중에서도 분산 버전 관리 시스템이다.

"분산"이라는 단어가 버전 관리 시스템에 붙은 이유는 어떻게 데이터를 저장하고 관리하는지와 관련이 있다.

위 그림은 중앙 집중식 버전 관리 시스템(CVCS, Centered Version Control System)과 분산 버전 관리 시스템 (DVCS, Distributed Version Control System)에서 파일을 수정할 때의 작동방식이다.

중앙 집중식 버전 관리 시스템은 한 개의 중앙 서버에 모든 파일과 변경 이력을 저장한다.

따라서 저장소의 파일을 수정하려고 할 때는 중앙 서버에 연결된 상태에서 해당 파일의 최신 버전을 가져오고 파일을 수정한 후에 다시 중앙 서버에 수정 내용을 커밋(commit)하여 중앙 저장소에 반영한다.

분산 버전 관리 시스템은 여기서 좀 더 나아가서 중앙 서버를 둠과 동시에 각 작업자의 로컬 컴퓨터에도 그 중앙 서버의 저장소를 그대로 복제한 로컬 저장소를 둔다. 작업자는 이 로컬 저장소에서 파일을 수정할 수 있다.

이에 따라 다음과 같은 이점이 있다.

  • 로컬 저장소가 있기 때문에 파일 수정 시 중앙 서버에 접근하지 않아도 되어 네트워크 상태에 상관없이 작업할 수 있다.
  • 다른 개발자의 작업에 영향을 받지 않고 로컬 저장소에서 독립적으로 작업할 수 있다.
  • 각 개발자들이 저장소의 복제본을 가지고 있어 중앙 저장소에 문제가 있을 시 복구에 용이하다.

CVCS보다는 직관적으로 이해하기 힘들지만 유연하고 빠른 버전관리를 할 수 있어 소스코드 버전 관리 시스템의 표준으로 자리잡았다.

Git 구성요소

구성요소는 다음과 같다.

  • Repository (저장소)
  • Commit (커밋)
  • Branch (브랜치)
  • Tag (태그)

하나씩 자세하게 알아보자.

Repository (저장소)

프로젝트의 파일과 각 파일의 변경 이력을 저장하는 공간이다. 주로 “repo”라고 줄여서 표현된다.

다음과 같이 두 종류로 나뉜다.

  • Remote Repository (원격 저장소): 프로젝트의 코드와 변경 이력을 공유하는 중심 지점으로 작동하는 저장소이다.
  • Local Repository (로컬 저장소): 각 작업자의 컴퓨터에 있는 저장소이다. 여러 개의 로컬 저장소를 가질 수 있다. 로컬 저장소는 다음과 같이 두가지 형태를 갖는다.
    • 원격 저장소와 연결된 로컬 저장소 : 원격 저장소를 복제했을 경우 해당 원격 저장소와 로컬 저장소가 연결되어 연결된 원격 저장소에서 로컬 저장소로 변경사항을 가져오고 업로드할 수 있다. 또한 로컬 저장소는 여러 개의 원격 저장소를 가질 수 있다.
    • 원격 저장소와 연결되지 않은 로컬 저장소 : 로컬 저장소는 원격 저장소 없이도 완전히 기능할 수 있지만, 협업이나 코드 공유, 백업과 같은 목적으로 원격 저장소와 연결하는 것이 일반적이다.

관련 용어

clone : 원격 저장소를 작업자의 로컬 컴퓨터로 복제하는 작업이다. 이렇게 되면 작업자의 컴퓨터에 클론한 원격 저장소가 등록된 로컬 저장소가 생성된다.

origin : 원격 저장소를 로컬에 clone 하면 생성되는 로컬 저장소에 연결된 원격 저장소의 기본 이름이다.

fetch **** : 원격 저장소에서 최신 변경 사항을 로컬 저장소로 가져오는 작업이다.

pull ** : 원격 저장소에서 최신 변경 사항을 로컬 저장소로 가져오는 fetch ** 작업을 함과 동시에 로컬 저장소의 브랜치와 병합하는 작업이다. 즉, fetch **** + merge 이다.

push ****: 로컬 저장소의 변경 사항을 원격 저장소에 업로드하는 작업이다.

Commit (커밋)

커밋은 Git 저장소의 기록 단위로, 파일이나 폴더의 변경 사항을 저장하는 행위를 말한다.

각 커밋은 저장소의 변경된 내용을 스냅샷(Snapshot)으로 캡처하고, 이러한 스냅샷들이 모여 저장소의 변경 이력을 구성한다. 여기서 스냅샷은 다음 그림과 같이 차이점만을 기록하는 델타(Delta)방식과는 달리 기존 내용에 수정된 내용을 포함한 전체를 기록하는 것이다.

각 커밋은 고유한 ID를 가지며, 누가 언제 어떤 변경을 했는지의 정보를 가지고 있다.

이 커밋 ID는 커밋 객체에 포함된 다양한 데이터들(커밋 시 생성되는 Git 객체, 타임스탬프, 커밋메세지 등등)을 기반으로 SHA-1 해시 알고리즘을 사용하여 생성되어, 커밋의 내용이 조금이라도 달라지면 완전히 다른 값으로 변경되므로 다른 커밋들과 구분될 수 있다.

커밋 시 생성되는 Git 객체

코드를 수정하고 커밋을 하게 되면, Git은 커밋 객체, 트리 객체, 블롭 객체를 생성한다.

예를 들어 초기 커밋(Initial commit)이 되어있고 README.md 파일이 있는 디렉토리에 같은 내용을 가진 hello.txt , world.txt 파일 2개를 생성하고 커밋한다면 다음과 같이 Git 객체가 3개 생성된다. (new! 표시된 객체)

  • commit(커밋) 객체 : 커밋 시 생성되는 커밋 객체는 해당 커밋의 메타데이터인 작성자(author), 기여자(commiter), 커밋 메세지와 이전 커밋객체, 트리객체의 참조 정보를 가지고 있다.
    • hello.txt , world.txt 파일 생성 내용이 반영된 커밋 98ca9 가 생성되었다.
    • 생성된 커밋 객체는 최초 커밋객체이자 이전 커밋 객체인 34ac2 와 트리객체 92ec2 를 참조한다.
    • 최초 커밋 객체인 34ac2 는 이전 커밋 객체가 없다.
  • tree(트리) 객체 : 새로운 파일이 추가되거나 기존 파일이 변경되면 새로운 트리 객체가 생성된다. 커밋을 한 시점의 디렉토리 구조와 그 안에 포함된 파일(블롭 객체)의 참조 정보를 가지고 있다.
    • hello.txt , world.txt 파일이 새로 생성되어 새로운 트리객체 92ec2 가 생성되었다.

    • 변경사항이 없는 README.md 는 이전 블롭객체를 그대로 참조하고,

      hello.txt , world.txt 는 각기 다른 이름으로 두 개의 항목을 가지지만 내용이 같으므로 같은 블롭 객체 5b1d3 을 참조한다.

  • blob(블롭) 객체 : Git에서 파일은 블롭이라는 객체로 저장된다. 블롭 객체의 ID는 해당 블롭의 내용에 대한 체크섬이다. 파일의 내용만을 가지고 있고 파일 이름이나 디렉토리 구조는 가지고 있지 않다. 이렇게 파일의 내용만을 기반으로 하기 때문에 동일한 내용을 가진 파일은 하나의 블롭으로 관리한다.
    • 새롭게 생성된 hello.txt , world.txt 파일은 같은 내용을 가지고 있기 때문에 하나의 블롭객체 cba0a가 생성되었다.
    • 기존 파일인 README.md 는 변경되지 않았으므로 이전 커밋 34ac2 에서 생성/사용된 블롭객체 5b1d3 을 재사용한다.

이러한 커밋 저장 방식으로 Git은 각 커밋을 독립적인 스냅샷으로 처리하고,

데이터 무결성을 유지하면서도 저장되는 데이터의 크기를 최소화한다.

Branch (브랜치)

Git 저장소를 새로 생성하면 하나의 main 이라는 이름의 브랜치가 기본적으로 생성된다.

(기존 master 였던 기본 브랜치명은 노예제도를 연상시킨다는 이유로 main 으로 변경되었다. )

이 브랜치를 기본 작업 라인으로 삼고, 작업을 다른 방향으로 분기시키려고 할 때 새로운 브랜치를 생성하여 사용한다.

예를 들어, 기존 코드에서 기능을 추가해야 할 부분이 생기면 작업하던 브랜치에서 feature 브랜치를 생성하여 해당 브랜치에서 수정작업을 한다. 이렇게 분기되는 과정이 나무의 가지처럼 갈라진다고 하여 브랜치라고 한다.

위 그림과 같이 기본 브랜치는 main이며, 안정성을 위해 브랜치를 분리하거나 (dev), 새로운 기능 개발( feature )이나 버그 수정을 위해 별도의 브랜치를 생성할 수 있다. 작업자들은 이렇게 생성한 브랜치에서 기능 추가, 버그 수정, 테스트 등을 독립적으로 진행하여 커밋 한 후 main 브랜치로 다시 병합한다. 이렇게 브랜치를 생성하고 병합하는 워크플로를 통해서 유연하게 코드를 관리하면서 협업할 수 있다.

관련 용어

merge (병합): 두 브랜치를 하나의 브랜치로 결합하는 작업이다. 각 브랜치의 변경사항들이 합쳐진다.

위의 그림에서 feature 브랜치는 dev 브랜치로부터 분기되었고 수정을 거쳐 다시 dev 브랜치와 병합되었다.

checkout , switch : 현재 작업하고 있는 브랜치를 다른 브랜치로 전환하는 작업이다. 전환하고자 하는 브랜치의 작업 상태를 현재 작업하고 있는 작업 디렉토리에 적용한다.

예를 들어 dev브랜치에서 작업 중이고 feature 브랜치로 전환하고자 한다면 feature 브랜치로 checkout ****한다고 표현한다. 그리고 내가 작업 중이었던 작업 디렉토리는 feature 브랜치의 작업 상태가 반영된다.

stash : 현재 작업 중인 디렉토리의 수정된 파일과 스테이징된 변경 사항들, 즉 아직 커밋이 되지 않은 변경사항들을 임시로 보관하고, 작업 디렉토리를 마지막 커밋 상태로 되돌린다. 현재 작업을 커밋하고 싶지 않지만, 현재 상태를 잠시 보관해야 할 때 사용한다. 예를 들어 현재 작업중인 브랜치에서 다른 브랜치로 checkout 해야할 때 현재 작업중인 내용을 커밋해야 checkout 이 가능하므로, 작업중인 내용들을 stash 하고 브랜치를 전환한다.

Tag (태그)

태그는 작업 지점 중 특정 지점을 표시하는 데 사용된다.

이는 특정 커밋에 태그를 생성함으로써 이루어진다. 이렇게 생성된 태그의 태그명을 사용하여 특정 커밋으로 체크아웃할 수도 있다. (해당 커밋 시점의 파일과 코드 상태로 돌아감)

태그에는 다음과 같이 두 가지 유형이 있다.

  • 경량 태그(Lightweight Tag) : 경량 태그는 단순히 특정 커밋을 참조한다. 커밋 체크섬만 저장하고 메타데이터나 태그 메시지는 저장하지 않는다.
  • 주석 태그(Annotated Tag): 이 태그는 태그를 만든 사람의 이름, 이메일, 태깅 날짜와 같은 메타데이터태그 메시지를 저장한다.

태그명 작성 - 유의적 버전 (Semantic Versioning) 방식 사용

태그명은 여러 내용이 올 수 있겠지만 일반적으로 배포 버전을 나타낸다.

버전을 나타낼 때 일반적으로 유의적 버전 방식을 사용한다. 이 방식은 버전 번호를 x.y.z-i+m 형식으로 표현한다.

각 자리가 의미하는 바를 자세히 알아보자.

x : Major(메이저) 버전으로, 구 버전을 지원하지 않는 수준의 API 변경이 있을 경우 올린다.

y : Minor(마이너) 버전으로, API의 기능이 추가되었지만 기존 버전을 여전히 지원하는 수준으로만 변경이 있을 경우 올린다.

z : Patch(패치) 버전으로, 기존 기능의 버그를 고쳤을 경우 올린다.

i : Pre-release identifier(프리 릴리즈 식별자)로, 정식 릴리스 전의 초기 버전을 나타내는 데 사용된다.

alpha , beta , rc (Release Candidate)와 같은 버전을 나타낼 때 사용된다.

다음과 같이 작성할 수 있다.

1.0.0-alpha, 1.0.0-beta.1 , 1.0.0-rc.3

프리릴리스 버전은 정식 릴리스보다 낮은 우선 순위를 가진다.

m: Build metadata(빌드 메타데이터)로, 버전에 대한 빌드 번호나 날짜와 같은 추가적인 정보를 제공한다.

버전 간의 우선순위를 판단하고자 할 때 무시된다. (메타데이터만 다른 두 버전의 우선순위는 같다.)

  • 기호로 시작하며, 이어서 추가 데이터가 온다. 다음과 같이 작성할 수 있다.

1.0.0-alpha+001, 1.0.0+20130313144700

유의적 버전 방식은 다음과 같은 규칙이 있다.

  • x.y.z 의 각각 자리수는 자연수로 표기되어야하고, 한번 올리면 감소해서는 안된다.
  • 프로젝트가 초기 개발 단계일 때는 0.1.0 버전명부터 시작하면 된다.
  • 프로젝트가 공개될 준비가 되면 1.0.0 으로 설정한다.

이 외에도 더 많은 규칙이 있다. https://semver.org/lang/ko/ 에서 자세한 내용을 확인할 수 있다.

이러한 유의적 버전을 사용하여 다음과 같이 태그명을 작성할 수 있다.

태그에 작성할 내용이 버전임을 명시하기 위해 버전 앞에 **v 접두어를 사용**한다.

저장소에서의 커밋 단계와 파일 상태

변경사항을 커밋할 때, 다음과 같은 3가지 단계를 거치게 된다. (각 단계마다 불려지는 명칭이 여러 개 있다.)

Git Directory / Repository (깃 디렉토리 /레포지토리)

  • 깃 디렉토리는 Git의 핵심으로 프로젝트의 메타데이터와 Git 객체(커밋, 트리, 블롭) 데이터베이스를 저장하는 곳이다.
  • Git 프로젝트의 루트 경로에 있는 .git 폴더이다.

➡️ 사용자가 특정 브랜치나 커밋을 체크아웃하면 Git은 해당 커밋에 해당하는 파일 상태를 깃 디렉토리의 데이터베이스에서 가져와 워킹 트리에 적용한다.

Working Directory / Working Tree (워킹 디렉토리 / 워킹 트리)

  • 워킹 트리는 사용자가 실제로 작업하는 파일들이 있는 디렉토리이다.
  • 프로젝트의 특정 버전이 체크아웃 되어있다.

➡️ 워킹 트리에서 파일들을 수정하고 그 중 커밋할 파일스테이징 영역에 올린다.

Staging Area / Index (스테이징 영역 / 인덱스)

  • 변경사항을 커밋하기 위해 준비하는 임시 공간이다.

➡️ 스테이징 영역에 있는 파일들을 커밋해서 깃 디렉토리에 스냅샷으로 저장한다.

스테이징 영역을 사용하는 이유

워킹 트리에서 파일들을 자유롭게 수정하고, 커밋 시에는 원하는 파일들만 스테이징 영역에 올려 커밋할 파일과 그렇지 않은 파일을 분리할 수 있다. 명확한 커밋을 위해서는 변경 사항을 커밋에 맞게 모아놓아야 하는데, 이 역할을 스테이징 영역이 해준다.

이러한 커밋 과정이 파일 관점에서는 다음과 같이 4가지 상태로 나뉜다.

Untracked (관리대상이 아님)

  • 워킹 트리의 모든 파일은 크게 Tracked(관리대상임)와 Untracked(관리대상이 아님)로 나뉜다.
  • 이 상태의 파일은 Git에 의해 관리되고 있지 않다.
  • 워킹 트리에는 존재하지만 이전에 커밋된 적이 없고, 현재 커밋 대상에도 포함되지 않은(스테이징 영역에 올라가지 않은) 상태다.

➡️ 파일을 스테이징 영역에 추가하는 명령어를 사용하여 Staged 상태로 변환시킬 수 있다.

Unmodified (수정되지 않음)

  • 이 상태의 파일은 버전 관리 시스템의 관리 대상으로 Tracked 상태이다.
  • 마지막 커밋 이후 변경되지 않은 상태이다.
  • 처음 저장소를 Clone 하면 모든 파일은 Tracked이면서 Unmodified 상태이다.

➡️ 파일 내용을 수정하면 Modified 상태로 변경된다.

Modified (수정됨)

  • 이 상태의 파일은 버전 관리 시스템의 관리 대상으로 Tracked 상태이다.
  • 마지막 커밋 이후 수정된 상태이다.

➡️ 수정한 파일을 스테이징 영역에 올리면 Staged 상태로 변경된다.

Staged (스테이징됨)

  • 이 상태의 파일은 버전 관리 시스템의 관리 대상으로 Tracked 상태이다.
  • 커밋에 포함될 준비가 된 상태이다.

➡️ 해당 영역에 있는 파일들을 커밋한다. 커밋에 포함된 파일들은 모두 Tracked 상태가 된다.

파일은 커밋되었기 때문에 최신 커밋에서 변경되지 않은 상태이므로 Unmodified 상태가 된다.


참고

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

https://blog.dnd.ac/types-of-git-branch/

https://www.nagarelab.com/en/3073

https://nozeroslope.tistory.com/186

https://www.oreilly.com/library/view/version-control-with/9781449345037/ch04.html

https://johngrib.github.io/wiki/semantic-versioning/

https://semver.org/lang/ko/

https://commonflow.org/

https://iseunghan.tistory.com/322

https://blog.npcode.com/2012/10/23/git%EC%9D%98-staging-area%EB%8A%94-%EC%96%B4%EB%96%A4-%EC%A0%90%EC%9D%B4-%EC%9C%A0%EC%9A%A9%ED%95%9C%EA%B0%80/

profile
거친 돌이 다듬어져 조각이 되듯

0개의 댓글