Git 기초 #1 Git이란 — 스냅샷 모델과 세 영역

7 분 소요

코드를 파일 복사로 관리해 본 경험이 있다면 이런 폴더를 만든 적이 있을 것입니다. report_final.docx, report_final_real.docx, report_final_real2.docx. 어느 파일이 진짜 최신인지, 둘 사이에 무엇이 달라졌는지, 지난주 버전으로 돌아가려면 어느 파일을 열어야 하는지 아무도 답할 수 없는 상태가 됩니다. 코드에서도 똑같은 일이 벌어지고, 여기에 “여러 명이 같은 파일을 동시에 고친다"는 조건까지 더해지면 복사본 방식은 완전히 무너집니다.

버전 관리 시스템은 이 문제를 푸는 도구입니다. 파일의 변경 이력을 기록하고, 언제든 과거 시점으로 돌아가고, 여러 사람의 수정을 안전하게 합칩니다. 그리고 현재 이 분야의 표준은 압도적으로 Git입니다. Git이 어떤 문제를 푸는 도구인지 큰 그림부터 보고 싶다면 비개발자를 위한 IT 상식 #5 Git과 버전 관리를 먼저 읽어도 좋습니다. 그 글이 코드 없이 읽는 개념 소개라면, 이 시리즈는 터미널에서 직접 명령을 실행하며 익히는 실무 입문입니다.

총 6편으로 구성됩니다.

  • #1 Git이란 — 스냅샷 모델과 세 영역 ← 이번 글
  • #2 add·commit·status — 스테이징 영역의 의미
  • #3 브랜치와 머지 — fast-forward와 3-way
  • #4 원격 저장소 — clone·fetch·pull·push와 origin의 정체
  • #5 되돌리기 — restore·reset·revert 구분
  • #6 GitHub와 첫 Pull Request

이번 글은 명령을 외우기 전에 알아야 할 Git의 핵심 모델 두 가지, 스냅샷세 영역을 세우고, git init으로 첫 저장소를 만드는 데까지 진행합니다. 이 두 모델만 제대로 잡아 두면 나머지 다섯 편의 모든 명령이 “세 영역 사이에서 스냅샷을 옮기는 일"로 일관되게 읽힙니다.

버전 관리가 풀어 주는 세 가지 문제 #

복사본 방식과 비교하면 버전 관리 시스템이 해결하는 문제는 세 가지로 정리됩니다.

  • 이력 — 언제, 누가, 왜 바꿨는지가 변경 단위로 남습니다. 파일 이름에 날짜를 붙이는 대신 기록 자체를 조회합니다.
  • 복구 — 어제 오후의 상태, 배포 직전의 상태처럼 특정 시점으로 정확히 돌아갈 수 있습니다.
  • 협업 — 여러 명이 같은 프로젝트를 동시에 고치고, 서로의 변경을 나중에 합칩니다. 누가 마지막에 저장했는지에 따라 남의 작업이 사라지는 사고가 없어집니다.

이 시리즈에서 이력과 복구는 #2와 #5에서, 협업은 #4와 #6에서 각각 실제 명령으로 확인합니다.

Git은 델타가 아니라 스냅샷을 저장합니다 #

Git 이전 세대의 버전 관리 시스템은 대부분 파일별 변경분(델타)을 쌓는 방식이었습니다. 파일 A의 1번째 수정, 2번째 수정처럼 차이만 기록하고, 특정 시점의 전체 상태가 필요하면 델타를 처음부터 순서대로 적용해 재구성했습니다.

Git은 접근이 다릅니다. 커밋할 때마다 그 시점 프로젝트 전체의 스냅샷을 저장합니다. 커밋 하나는 그 시점에 모든 파일이 어떤 내용이었는지를 통째로 가리키는 기록입니다. 물론 내용이 바뀌지 않은 파일을 매번 중복 저장하지는 않습니다. 바뀌지 않은 파일은 이미 저장된 동일 내용을 그대로 가리키는 참조만 담기 때문에 저장 공간 문제는 생기지 않습니다.

커밋에는 스냅샷 외에 두 가지가 더 들어갑니다. 부모 커밋을 가리키는 포인터와 작성자, 시각, 메시지 같은 메타데이터입니다. 커밋이 자신의 부모를 가리키며 이어지므로 전체 이력은 다음과 같은 사슬이 됩니다.

커밋 — 스냅샷과 부모 포인터의 사슬
[C1] ◀── [C2] ◀── [C3]
  │        │        │
 스냅샷    스냅샷    스냅샷
(그 시점  (그 시점  (그 시점
 전체)     전체)     전체)

각 커밋은 부모를 가리킵니다. C3에서 출발해 포인터를
따라가면 프로젝트의 전체 역사가 복원됩니다.
노트
이 모델이 중요한 이유는 #3에서 분명해집니다. 브랜치는 이 사슬 위의 특정 커밋을 가리키는 포인터 하나에 불과하므로, Git에서 브랜치를 만드는 비용은 사실상 0입니다. 델타 기반 시스템에서 브랜치가 무겁고 느렸던 것과 대비되는 지점입니다.

저장소 전체가 내 컴퓨터에 있습니다 #

Git은 분산 버전 관리 시스템입니다. 저장소를 복제하면 최신 파일만 받는 것이 아니라 첫 커밋부터 지금까지의 이력 전체가 내 컴퓨터에 들어옵니다. 그래서 네트워크가 없어도 커밋, 이력 조회, 버전 비교가 전부 가능합니다. 서버에 접속해야만 커밋할 수 있었던 중앙집중식 시스템과 구분되는 특징입니다.

GitHub라는 이름이 자연스럽게 떠오를 텐데, GitHub는 Git 그 자체가 아니라 원격 사본을 올려 두는 호스팅 서비스입니다. 내 컴퓨터의 저장소와 GitHub의 저장소는 대등한 사본이고, 둘을 맞추는 명령이 #4에서 다룰 push와 pull입니다. GitHub 위에서의 협업 흐름은 #6에서 정리합니다.

설치 확인과 최초 설정 #

Git이 설치되어 있는지부터 확인합니다.

설치 확인
git --version
# git version 2.47.1

버전이 출력되지 않으면 설치가 필요합니다. macOS는 xcode-select --install 또는 Homebrew의 brew install git, Windows는 Git for Windows 설치 프로그램, Linux는 배포판 패키지 관리자(dnf install git, apt install git)를 사용합니다.

설치를 확인했으면 자신을 소개하는 설정을 한 번만 해 둡니다.

최초 설정 — 이름, 이메일, 기본 브랜치
git config --global user.name "Hong Gildong"
git config --global user.email "gildong@example.com"
git config --global init.defaultBranch main

user.nameuser.email은 앞으로 만들 모든 커밋에 작성자 정보로 기록됩니다. 나중에 GitHub 계정과 연결할 이메일을 넣어 두면 좋습니다. init.defaultBranch는 새 저장소의 기본 브랜치 이름을 main으로 지정하는 설정입니다. Git이 오랫동안 기본값으로 쓰던 master 대신 현재는 main이 사실상의 표준이고, GitHub의 기본값도 main입니다. 설정이 제대로 들어갔는지는 git config --list로 확인합니다.

git init — .git 디렉터리의 정체 #

이제 첫 저장소를 만듭니다. 빈 디렉터리 하나면 충분합니다.

첫 저장소 만들기
mkdir hello-git
cd hello-git
git init
# Initialized empty Git repository in /Users/gildong/hello-git/.git/

출력 메시지가 핵심을 그대로 말해 줍니다. git init이 한 일은 현재 디렉터리 안에 .git이라는 숨김 디렉터리를 만든 것이 전부입니다. 앞으로 만들 모든 커밋, 모든 스냅샷, 모든 설정이 이 .git 안에 저장됩니다. 반대로 말하면 .git 디렉터리를 지우는 순간 이 프로젝트의 이력은 전부 사라지고 평범한 폴더로 돌아갑니다.

프로젝트 폴더와 .git의 관계를 구분해 두면 다음 절의 세 영역이 자연스럽게 이해됩니다. 여러분이 파일을 만들고 고치는 프로젝트 폴더가 작업 공간이고, .git이 기록 보관소입니다.

.git 내부 파일을 직접 열어 고칠 일은 없습니다. 내부 구조가 궁금해 들여다보는 것은 좋은 공부지만, 수정은 반드시 git 명령을 통해서 합니다.

세 영역 — 파일 하나가 기록되기까지 #

Git을 처음 배울 때 가장 많이 막히는 지점이 여기입니다. Git에서 파일은 저장 버튼 한 번으로 기록되지 않고, 서로 다른 역할을 가진 세 영역을 거칩니다.

세 영역과 두 번의 이동
working directory        staging area          repository (.git)
─────────────────        ────────────          ─────────────────
파일을 만들고 고치는       다음 커밋에 담을        커밋(스냅샷)이
실제 작업 공간            변경의 대기 목록        영구 보관되는 곳

      │                       │
      └────── git add ───────▶│
                              └───── git commit ──────▶ 새 스냅샷 기록
  • working directory — 지금 눈에 보이는 프로젝트 폴더 그 자체입니다. 에디터로 파일을 만들고 고치는 모든 작업이 여기서 일어납니다.
  • staging area — 다음 커밋에 포함할 변경을 골라 두는 대기 목록입니다. git add가 변경을 이 영역에 올립니다.
  • repository.git 디렉터리입니다. git commit이 staging area에 올라온 내용으로 새 스냅샷을 만들어 여기에 영구 기록합니다.

파일을 고친다고 해서 바로 기록되지 않고, git add로 올린다고 해서 아직 기록된 것도 아닙니다. git commit까지 마쳐야 비로소 스냅샷 사슬에 한 칸이 추가됩니다. 그런데 왜 굳이 add라는 중간 단계를 거칠까요? 이 질문이 다음 글의 주제입니다. 미리 한 줄로 답하면, 커밋에 “무엇을 담을지"를 설계할 수 있게 하기 위해서입니다.

마무리 #

이번 글의 핵심은 두 가지 모델입니다.

  • Git은 델타가 아니라 스냅샷을 저장합니다. 커밋은 그 시점 전체의 스냅샷과 부모 포인터의 묶음이고, 이력은 커밋의 사슬입니다.
  • 파일은 working directory, staging area, repository 세 영역을 거쳐 기록됩니다. git addgit commit이 두 번의 이동을 담당합니다.

여기에 더해 git config로 최초 설정을 마쳤고, git init으로 첫 저장소를 만들었습니다. 다음 글인 “Git 기초 #2 add·commit·status — 스테이징 영역의 의미"에서는 이 hello-git 저장소에 실제 파일을 만들어 add, commit, status, diff를 손으로 굴려 보며 스테이징 영역이 왜 존재하는지를 확인하겠습니다.

X