VCS, GIT 내부 동작 원리, SHA1알고리즘, Fork, Clone

현지·2025년 9월 24일

VCS

VCS는 Version Control System의 약자로 버전관리 시스템을 이르는 말이다. 이름 그대로 파일의 변화를 버전에 따라 기록하고 관리하기 때문에, 파일을 이전 상태로 쉽게 복구할 수 있다.

git 동작 원리

버전 관리 시스템의 한 종류인 git을 사용하기 위해선 처음에 git init이란 명령어를 실행해야한다. 새 디렉터리나 기존 디렉터리에서 git init을 실행하면 Git은 .git디렉터리를 생성하는데, 이 디렉터리에 Git이 저장하고 조작하는 파일들, 트리 구조, 커밋 등 모든 것이 저장된다.

git 공식 문서를 보면 config, description, hooks/등 여러 파일과 디렉토리가 생성되지만 그 중 가장 중요한 것은 역시 objects 디렉토리이다.(이 단계에서 index파일은 아직 생성되지 않는다.) objects디렉토리는 데이터베이스의 모든 콘텐츠와 버전 정보들을 객체 형태로 저장하는데 이 객체들의 종류는 다음과 같다.

  • blob
  • tree
  • commit

그럼 이제 git add 명령어와 git commit 명령어를 입력하면 각 객체들이 object파일에 어떻게 저장되는지 흐름을 따라가며 알아보자.

  1. git add
  • 파일1이라는 제목의 파일을 작성한다.
  • git add 파일1이라는 명령어를 실행할시, 파일1의 내용은 SHA1 해시알고리즘을 통해 일정한 길이의 문자열로 변환된다.
  • 해시된 값의 앞에서 2글자는 object밑의 디렉토리명이 되고, 나머지 해시값은 해당 디렉토리 밑에 파일명이 된다. 이 파일이 blob객체다! 그리고 그 blob객체 파일의 내용에 파일1의 원본 내용이 들어있게 된다.
  • 그러면 blob객체에는 실질적으로 파일의 내용만 담기게 되는데 파일제목같은건 어디에 저장될까? 바로 index파일에 저장된다.
  • index파일은 첫 add 실행시 생성되고, 여기에 Git의 스테이징 영역 정보를 저장한다. (스테이징 영역은 커밋 될 준비가 된 파일들이 위치한 영역을 뜻한다.)
  • index파일에는 해당 파일의 파일이름, 해시값등이 담기게 된다. 나중에 이 정보들을 보고 커밋을 할 수 있다.
  • 간단하게 말하면 파일의 내용은 objects디렉토리 밑에, 파일의 이름은 index파일에 저장되게 된다.
  1. git commit
  • 스테이징 영역에 담긴 파일을 커밋하면, 하위트리와 blob으로 구성된 tree 정보, 커밋한 사용자 정보, 커밋 메시지 등을 담은 commit객체가 만들어진다.
  • tree는 index정보를 바탕으로 만들어진다.
  • 여기서 만약에 파일을 다시 수정하고 add 한 후에(여기서 index파일의 해시값도 당연히 업데이트 된다.) 또 commit을 하면 새로운 tree가 생성되는데, 만약 커밋한 파일들 중 내용이 변경되지 않은 파일이 있다면 그 파일은 이전 커밋에서의 해시값과 동일한 값을 가진다. 재활용하는 것이다. 그리고 새로 생성된 commit오브젝트는 첫 commit오브젝트를 parent로 가진다.

https://git-scm.com/book/en/v2/Git-Internals-Git-Objects
공식문서에 git의 동작흐름이 이해하기 쉽게 그림과 예시와 함께 자세하게 잘 나와있다.

SHA1? zlib?

blob객체를 생성할때 SHA1알고리즘을 사용한다고 하는데 이게 뭘까?
SHA-1 해시 값은 40자리 고정 문자열로, 내용이 같으면 무조건 같은 해시 값이 나온다. 이걸 통해서 git은 해시 값을 통해 파일이 변경되었는지, 그대로인지 판단해서 변경된 파일(해시값이 바뀐 파일)만 새로 저장한다.

sha256은 SHA-1보다 더 강력한 해시 알고리즘이다. SHA-1은 160비트 40자리 해시값이고, SHA-256은 256비트 64자리 해시값이다. 이 덕분에 sha256는 SHA-1보다 보안에 훨씬 더 강력하다. 또한 같은 해시값이 만들어질 가능성 또한 매우 적다.

zlib는 또 무엇인가. 간단히 말하자면 압축 알고리즘이다. Git은 저장 효율을 높이기 위해, 저장하는 객체를 zlib 압축해서 .git/objects/에 저장한다.

node.js에는 SHA와 zlib 두 개의 알고리즘 모듈이 모두 내장되어 있다!

파일 상태 용어

<Tracking 단계>
git init 직후에는 모든 파일이 Untracked (추적 안됨) 상태, git add <파일>을 하면 → Tracked (추적됨) 상태로 전환됨

Git이 "이 파일은 나중에 커밋할지 말지 확인해야겠군!" 하고 계속 지켜보는 게 Tracking

<Modified 단계>
추적 중인(Tracked) 파일을 수정해서 저장소와 내용이 다른 상태

<Staged 단계>
커밋할 준비가 완료된 상태. Git이 “얘는 커밋할 거야” 하고 인덱스(index)에 올려둔 파일

Fork vs Clone

이건 예전부터 계속 헷갈렸던 개념이었는데 둘 다 대충 남의 코드를 복사해온다는 느낌으로 알고 있어서 차이점을 그리 자세하게 알진 못했다.

좀 더 정확하게 비교를 하자면 Fork는 남의 원격 저장소 -> 내 원격 저장소로 옮기는 작업이다. 이건 당연히 Git의 기능이 아니라 GitHub같은 원격 저장소 서비스에서만 존재하는 기능이다. 보통 외부 프로젝트에 PR을 보내고 싶을때 Upstream저장소(원본 저장소)에 push할 권한을 가지고 있지 않기 때문에 본인의 원격 저장소로 작업물을 복사해오는 걸 뜻한다. 이렇게 되면 원본과 내 저장소 사이에 연결이 생겨 PR요청을 보내는 것이 가능해진다.

Clone은 원격 저장소 -> 로컬 저장소로 복사하는 Git의 명령어이다. 복사할 저장소는 내꺼든 남의거든 상관없이 복사해 올 수 있지만 외부 프로젝트에 연결은 안 되어 있기 때문에 나중에 내 원격저장소에 코드를 올려도 PR이 불가능하다.

보통 오픈 소스 프로젝트에 기여할때는 해당 저장소의 push 권한이 없기 때문에 Fork -> Clone의 순서를 따른다.

권한이 부여된 경우 굳이 번거롭게 외부 저장소를 만들 필요 없이 해당 원본 프로젝트 내에서 직접적으로 브랜치를 통해 작업하기 때문에 Clone만으로 프로젝트에 참여하는 경우가 많다고 한다.

결론적으로 둘 다 저장소를 복사하는건 맞는데 그 용도나 복사되는 장소, 목적등이 다르다.

profile
헤맨만큼 내 땅이다

0개의 댓글