Git 기초개념

깃이 동작하는 기초 원리를 이해하면, 깃을 보다 효과적으로 사용할 수 있습니다.

차이가 아니라 스냅샷

서브버전과 깃의 가장 큰 차이점은 데이터를 다루는 방법입니다.

서브버전과 같은 VCS에서는 파일의 변화를 시간순으로 관리합니다. 여기서 파일 버전 사이의 차이점델타(delta, Δ) 라고 합니다. 서브버전은 각 버전 사이에 파일에 어떤 델타가 발생하는지 기록합니다.

각 파일에 대한 변화를 저장하는 시스템

이에 비해 깃은 델타를 기록하지 않습니다. 대신 파일의 현재 상태 그대로를 기록합니다.1 이를 스냅샷(snapshot) 이라고 합니다. 파일이 변경되지 않았다면, 깃은 파일을 새로 저장하지 않습니다. 대신 그 이전 상태의 파일에 대한 링크만 저장합니다. 깃은 파일을 스냅샷의 연속으로 기록합니다.

시간순으로 프로젝트의 스냅샷을 저장

스냅샷을 다루기 때문에 깃은 버전 사이의 전환이 매우 빠릅니다. 서브버전에서 버전을 전환하려면 두 버전 사이에 있는 모든 델타를 적용해야 하지만, 깃에서는 단순히 해당 버전의 파일 스냅샷으로 파일을 교체해주면 됩니다. 버전 사이의 신속한 전환이 가능하기 때문에 이후 설명할 브랜치를 더 적극적으로 활용할 수 있습니다.

거의 모든 명령을 로컬에서 실행

프로젝트의 모든 히스토리가 로컬 디스크에 있기 때문에 모든 깃 명령은 순식간에 실행됩니다.

예를 들어 어떤 파일의 현재 버전과 한 달 전의 버전을 비교하고 싶을 때도, 깃은 로컬에 저장되어 있는 히스토리에서 파일을 찾습니다. 파일을 비교하기 위해 리모트에 있는 히스토리를 찾을 필요가 없다는 말이죠.

즉 오프라인 상태이거나, VPN에 연결하지 못하는 상황에서도 작업을 할 수 있습니다. 비행기나 기차처럼 네트워크에 연결하기 힘든 상황에서도 커밋을 할 수 있습니다. 서브버전같은 시스템에서는 오프라인에서 파일을 편집할 순 있어도 커밋은 하지 못합니다. 사소해 보이지만 실제 이런 상황에서 작업을 하게 되면 느껴지는 차이가 매우 큽니다.

Git의 무결성

깃은 데이터를 저장하기 전에 항상 체크섬2을 구하고 그 체크섬으로 데이터를 관리합니다. 깃은 SHA-1 해시를 사용해 체크섬을 생성하며, 만들어진 체크섬은 40자 길이의 16진수 문자열입니다. SHA-1 체크섬은 아래 처럼 생겼습니다.

24b9da6552252987aa493b52f8696cd6d3b00373

깃에서 모든 파일과 디렉토리를 구분할 때 체크섬을 사용해 구분합니다. 때문에 파일의 이름이 바뀌더라도 파일 내용이 바뀌지 않는다면 체크섬도 바뀌지 않기 때문에 추가로 깃 데이터베이스에 저장되지 않습니다. 이처럼 깃은 파일을 매우 효율적으로 저장합니다.

Git은 데이터를 추가할 뿐

깃으로 무얼 하든 깃 데이터베이스에 데이터가 추가됩니다. 다른 버전 관리 시스템처럼 깃도 커밋하지 않으면 변경사항을 잃어버릴 수 있습니다. 하지만 일단 커밋하고 나면, 변경사항은 깃 데이터베이스에 저장되어 삭제되지 않습니다.

깃을 사용하면 프로젝트가 망가질 것을 걱정할 필요 없이 여러 수정사항들을 실험해볼 수 있습니다. 모든 변경사항들이 깃 데이터베이스에 저장되어 있기 때문에 되돌리기가 매우 쉽기 때문입니다.

세 가지 상태

깃은 파일을 Committed, Modified, Staged 이렇게 세 가지 상태로 관리합니다.

  • Committed: 데이터가 로컬 데이터베이스에 안전하게 저장한 상태
  • Modified: 수정한 파일을 아직 로컬 데이터베이스에 커밋하지 않은 상태
  • Staged: 현재 수정한 파일을 곧 커밋할 것이라고 표시한 상태

이 세 가지 상태는 깃 프로젝트의 세 가지 단계와 관련되어 있습니다.

워킹 디렉토리, 스테이징 에어리어, 저장소

먼저 .git 디렉토리는 프로젝트의 메타데이터와 객체 데이터베이스가 위치한 곳입니다. 이 .git 디렉토리가 깃의 핵심입니다. 다른 컴퓨터에 있는 저장소를 클론하는 것은 바로 이 .git 디렉토리를 복사하는 것입니다.

워킹 디렉토리는 프로젝트의 특정 버전을 체크아웃한 것이다. .git 디렉토리의 데이터베이스에서 해당 버전에 맞는 파일을 가져와 워킹 디렉토리를 만듭니다.

스테이징 에어리어.git 디렉토리 안에 있습니다. 여기에는 곧 커밋할 파일에 대한 정보가 저장됩니다. 인덱스라고도 부릅니다.

깃이 하는 일은 다음과 같습니다.

  1. 워킹 디렉토리에서 파일을 수정한다. (checkout & modify)
  2. 스테이징 에어리어에 파일을 스테이지해서 커밋할 스냅샷을 만든다. 모든 파일을 추가할 수도 있고 일부만 선택하여 추가할 수도 있다. (stage)
  3. 스테이징 에어리어에 있는 파일을 커밋해서 .git 디렉토리에 영구적인 스냅샷으로 저장한다. (commit)

.git 디렉토리에 있는 파일들은 Committed 상태입니다. 파일을 수정하고 스테이징 에어리어에 추가했다면 Staged 상태입니다. 그리고 체크아웃 하고 나서 수정했지만, 아직 스테이징 에어리어에 추가하지 않았으면 Modified입니다.

지금 당장은 이 개념들을 모두 이해하기는 어려울 수 있습니다. 하지만 어느정도 깃에 익숙해지고 나서 다시 읽어보면, 깃의 원리에 대해 더 명확히 이해할 수 있을 것입니다.


  1. 정확히 표현하자면, 파일의 바이너리(0과 1로 된 값의 연속)를 저장. ↩︎

  2. 데이터의 무결성을 확인할 수 있는 데이터. 데이터의 바이너리를 해시해서 나온 체크섬을 함께 전송하면, 수신측에서 직접 해시한 체크섬과 비교하여 검증한다. ↩︎