이 영역을 누르면 첫 페이지로 이동
Coding Groot 블로그의 첫 페이지로 이동

Coding Groot

페이지 맨 위로 올라가기

Coding Groot

코딩 블로그

Git Internals 정리 :: Git은 어떻게 동작할까?

  • 2020.03.16 09:22
  • Git/Git Note
글 작성자: Coding Groot

Git의 내부 동작 방식

Git은 복잡하고 처음에는 매뉴얼만으로 이해하긴 어려웠다...
그리고 가끔씩 무슨 소리인지 모르겠는 경고문을 보여주곤 한다...
나도 처음에 막 건들다가 아래와 같은 경고문을 보게 되면 정말 당황한 적이 있다.
Detached Head?? Linked List의 헤드인가...? 왜 Head가 분리됐지...?

무슨 소리냐 ㅋㅋㅋ ㅠㅠ

Git의 문서를 보면 아직 이해가 안 되거나 아주 중요한 내용인지 모르고 그냥 읽고 넘어가버릴 때가 많다... 매뉴얼은 이해하기 어렵고 Git의 주의점까지 다 외워야 할까? ㅠㅠ

나는 Pro Git의 마지막 장인 Git Internals(Git 내부 동작)를 읽으며 모든 막막함이 자연스럽게 해결되었다.

[참고] Pro Git이란?

Git의 교과서이다. 

정리가 상세하게 되어있어서 웬만한 건 여기서 힌트를 얻을 수 있었다.
나는 제일 마지막 장(Git Internals)을 읽고 Git을 사용하는 데에 큰 도움을 얻었다.
번역도 괜찮고 https://github.com/progit/progit2에서 무료로 보거나 다운로드할 수 있다.
+) "Git Internals", "Git 내부 동작 방식"은 의외로 어렵지 않았습니다! 처음에 제목만 보고 겁먹었는데 오히려 어떻게 만들었는지 따라가다 보면 재미있었고 유익했습니다.

Git의 내부 동작 방식을 이해하면 이 명령어가 대충 어떻게 작동할지 예상이 간다. 오히려 Git의 내부 동작 방식을 이해하면 문서가 훨씬 더 읽기 쉬워진다! 해서는 안될 실수도 알 수 있다.

그러니 Git이 어렵다면 또는 Git 문서가 난해하게 느껴진다면 Git Internals를 한번 공부해 보자. 이 글은 내가 공부하면서 기억하고 싶었던 내용을 정리하는 글이다.


현재 추적 중인 파일들이 저장된 자료구조 - index

  • .git/index에 위치한다.
  • index는 현재 브랜치가 추적 중인 모든 파일을 기록/관리한다.
    흔히 git add [파일명] 또는 Stage Area에 올리는 것을 index에 기록한다고 표현한다.
  • index는 그냥 출력해서 읽은 순 없기 때문에 명령어로 읽어야 한다.

그냥 파일을 읽어보면 이렇게 깨져서 나온다.
이렇게 Git 명령어로 읽어야 한다

  • index 파일 출력: git ls-files --stage 또는 git ls-files -s
  • git add [파일명]하면 index 파일의 내용이 바뀐다.
  • 다음 commit이 준비되는 장소이다.
  • 내용
    • 파일명, object SHA-1, mode bit, stage number

man git-ls-files -s


Git이 파일 관리하기 위해 만드는 파일 - Object(tree, blob, commit, tag)

  • .git/objects 폴더에 저장되어 있다. 이 것을 loose하게 저장된 파일이라고 말한다.

오브젝트 파일들이 위치하는 곳!

  • Git의 모든 파일은 오브젝트로 관리한다. 내 파일의 텍스트 내용도 commit내용도 다 오브젝트로 만들어서 관리가 된다.
    • Git은 commit마다 새로운 오브젝트를 만들어 낸다.
    • 내가 아주 작은 부분만 저장해도 바뀐 부분만 저장하는 게 아니라 전체의 텍스트 내용을 저장하는 오브젝트를 만든다.
    • 이것을 특정 시점의 사진을 찍는 것과 비슷하다고 해서 Snapshot 저장 방식이라고 부른다. 
Git이 매번 파일의 Snapshot을 찍어서 저장하면 공간 낭비가 심합니다.
내가 소스코드에 스페이스바 하나만 쳐도 그 파일 전체를 저장하는 오브젝트를 파일을 만들어서 그래요. ㅠㅜ
만약에 매번 Snapshot만 찍는다면 1년만 지나도 어마 어마한 공간 낭비됩니다.

이것을 해결하기 위해 Git은 주기적으로 오브젝트 파일들을 하나로 압축(Pack up)합니다.

Object의 압축 - Packfiles

  • 오브젝트 파일들이 너무 많아지면 Git 압축해 .git/pack 폴더 아래에 오브젝트들을 압축한 바이너리 파일(*.pack)과 그 파일에 무엇이 압축되었는지 기록한 index 파일이 만들어진다. 이 것을 압축해서 저장한 packfile이라고 한다. 
  • 원래는 특정 시점(Ex. Push할 때)에 Git이 판단해서 packfile로 오브젝트 파일들을 압축하지만 우리가 명령어(git gc)를 쳐서 수동으로 압축할 수도 있다.

`git gc` 실행 후

Object

  • 오브젝트를 담고 있는 폴더명+오브젝트의 파일명=SHA-1값이다.

한번 실제로 확인해 보자.

Test.txt파일을 만들어서 "Hello World"를 저장하고 commit했다.

텍스트 파일 생성 후 커밋!

.git/objects 폴더 안에는 어떤 변화가 생겼을까?

3개의 오브젝트 파일이 새로 생겼다!

Git은 모두 오브젝트로 파일들을 관리한다 했다!
위에서 하나는 Hello World라는 텍스트 내용을 저장하는 오브젝트, 또 다른 하나는 commit 내용을 저장하는 오브젝트이다.

commit을 오브젝트로 만든다고 하면 git은 commit의 SHA-1값의 앞부분 두 글자를 폴더명, 나머지를 파일명으로 하고 그 파일 안에 commit내용을 저장합니다! 이 사실을 확인해 보는 예제를 진행하는 중입니다.

git log를 통해 방금 만든 commit의 SHA-1 값을 확인해 보자.

commit의 SHA-1값을 확인!

94ae61a1cc407d40c07660277efa4d8df53dd577이다.
이것을 통해 우리는 내부적으로 .git/objects/94 라는 폴더가 생기고 94라는 폴더 아래에 ae61a1cc407d40c07660277efa4d8df53dd577라는 commit 오브젝트 파일이 생성됐다는 사실을 알 수 있다.

어떤 정보가 있을지 commit 오브젝트 파일을 출력해서 확인해 보자. 그런데 오브젝트 파일들 역시 loose하게 git이 압축을 해놓는다. 그래서 그냥 바로 열어서 보지는 못한다. 오브젝트 파일을 우리 문자로 출력해 주는 git cat-file 명령어를 사용해야 한다.

zlib압축 데이터 파일이라 그냥 읽지는 못한다.

git cat-file -t [SHA-1값]로 오브젝트 파일의 타입을 확인해 보자.

오브젝트 파일의 type을 출력하는데 쓰는 명령어입니다. 

git cat-file -t [오브젝트 SHA-1값]

commit의 SHA-1값으로 생성된 오브젝트 파일의 타입은 커밋이다.

git cat-file -p [SHA-1값]으로 오브젝트 파일 안에 어떤 내용이 있는지 확인해 보자.

오브젝트 파일의 내용을 pretty하게 출력하는데 쓰는 명령어입니다. (p가 pretty의 약자...)

git cat-file -p [오브젝트 SHA-1값]

방금 만든 commit 오브젝트 파일의 내용

살펴보니 
tree라는 다른 오브젝트를 가리키는 SHA-1값
parent라는 다른 오브젝트를 가리키는 SHA-1값
author와 누가 커밋했는지 그리고 커밋 메시지가 뭔지 나온다.

내 commit의 내용을 잘 담고 있는 것을 확인할 수 있었다.

하지만 내 파일명과 안의 내용(snapshot)은 어디에 있는 걸까?

Test.txt에 "Hello World"을 저장해서 commit했다. git은 commit할 때의 파일 내용을 또 다른 blob이라는 타입의 오브젝트에 저장한다. 

우리가 commit할 때를 생각해 보면 우리는 한 가지 파일만 수정하는지 않는다. 그래서 한 commit에는 여러 가지 파일들의 변경 사항이 저장된다. 그리고 파일의 각각의 결로도 다르다. Git을 그 내용을 commit에 다 때려 박기보다는 변경된 파일의 내용을 저장하고 있는 blob 오브젝트(snapshot)을 모아놓기 위한 tree 오브젝트를 만들어서 사용한다. 그래서 현재 commit에는 저장된 파일에 대한 직접적인 정보가 없고 tree 오브젝트에 대한 링크만 있다.

그러므로 내 commit 오브젝트가 가리키는 tree 오브젝트를 열어보면 commit할 때의 내 파일의 내용이 저장된 blob 오브젝트를 찾을 수 있다.

tree 오브젝트의 내용을 열어보자.

우리가 새로 저장한 파일의 내용을 저장하고 있는 blob 오브젝트의 SHA-1값을 찾음!

그럼 마지막으로 저 blob 오브젝트를 열어보자!

"Hello World"가 저장되어 있다!

Test.txt파일 안의 내용인 "Hello World"가 저장되어 있다!

여기서 알 수 있는 중요한 사실이 있다. blob 오브젝트는 파일의 내용만 저장하지 파일명까진 저장하지 않는다는 것이다!! 파일명은 무조건 tree나 index같은 다른 오브젝트에 의해서 링크되어야 한다.

Object의 종류와 그 역할 정리
  • blob: 텍스트 내용 저장, 파일명에 대한 정보는 저장하지 않음
  • tree: 파일명 + 해당하는 blob 오브젝트의 SHA-1 값, 다른 디렉토리 가리키는 tree 오브젝트 SHA-1 값 저장
  • commit: tree SHA-1 값, parent 오브젝트 SHA-1 값, author, committer, commit 메시지 저장
  • tag: tag

git cat-file


추가로 보면 좋은 글

  • https://blog.meain.io/2023/what-is-in-dot-git/

썸네일 출처

  • Icons made by Flat Icons from www.flaticon.com
반응형
저작자표시 비영리 동일조건 (새창열림)

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • Fork한 저장소에 upstream의 최신 commit 가져오기 :: GitHub Compare / Bitbucket / add remote

    Fork한 저장소에 upstream의 최신 commit 가져오기 :: GitHub Compare / Bitbucket / add remote

    2020.04.09
  • Git의 파일 상태 구분법

    Git의 파일 상태 구분법

    2020.04.09
  • .gitignore가 동작 안할 때 상황별로 해결하기

    .gitignore가 동작 안할 때 상황별로 해결하기

    2020.02.29
  • GitHub README.md 이미지가 갱신/업데이트 안 되는 경우 해결법

    GitHub README.md 이미지가 갱신/업데이트 안 되는 경우 해결법

    2020.02.20
다른 글 더 둘러보기

정보

Coding Groot 블로그의 첫 페이지로 이동

Coding Groot

  • Coding Groot의 첫 페이지로 이동

검색

메뉴

  • 홈
  • 태그
  • 방명록
  • 소개
  • 블로그 저작권

카테고리

  • 분류 전체보기 (182)
    • Git (23)
      • Git Tutorial (9)
      • Git Note (7)
      • Git Lecture (7)
    • Programming Language (1)
      • C (2)
      • C Sharp (5)
      • Java (4)
      • JavaScript (7)
      • Julia (5)
      • Python (4)
    • Programming (8)
      • Algorithm (2)
      • Compiler (5)
      • Data Structure (0)
      • Web (12)
      • NestJS (2)
    • DevOps, Infra (36)
      • Apple (6)
      • Cloud (15)
      • Database (1)
      • Network (4)
      • Linux (8)
    • Game Programming (11)
      • Unity Tutorial (5)
      • Unity Note (6)
    • Hardware Design (1)
      • Digital Circuit (1)
    • Note (49)
      • Coffee (2)
      • Retrospect (15)
      • Reading List (14)
    • Mathematics (1)

최근 글

인기 글

댓글

공지사항

아카이브

태그

  • 회고
  • Github
  • aws
  • 서평
  • javascript
  • git
  • tutorial
  • 한빛미디어
  • 전체 보기…

정보

Coding Groot의 Coding Groot

Coding Groot

Coding Groot

블로그 구독하기

  • 구독하기
  • RSS 피드

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기

나의 외부 링크

  • GitHub
  • SlideShare
  • 유니티 2020 수업
  • TIL Blog
  • 모도코

방문자

  • 전체 방문자
  • 오늘
  • 어제
Powered by Tistory / Kakao. Copyright © Coding Groot.

티스토리툴바