호우동의 개발일지

Today :

article thumbnail

CLI와 Git 내부의 폴더와 파일을 분석하여 Git 명령어들이 어떻게 동작하는지 살펴본다.


Git init 내부 분석

내부 분석

  1. Git Bash에서 임의의 빈 폴더에 git init을 통해. git을 만든다.(로컬저장소 생성)
  2. ls -al. git를 통해. git 폴더 내부를 살펴보면 다양한 폴더들이 생성된 것을 확인할 수 있다.

ls -al 명령의 각 칼럼의 의미

ls -al

  • -rw-r--r-- 1
    • 파일과 권한과 상태를 의미하는 것인데, Git 내부 명령을 이해하는데 중요한 것은
    • _맨 앞이 ‘-’로 시작하면 파일 ‘d’로 시작하면 폴더_라는 것

  • junpyohong
    • 파일 소유자의 아이디

  • staff
    • 파일이 속한 그룹(파일 소유자가 속한 그룹)

  • 73
    • 파일의 크기, 바이트 표시로 표시

  • Dec 27 13:36
    • 파일 생성 시간

  • description
    • 파일 이름

 


Git add, status 내부 분석


Git status

  • 워킹트리와 스테이지, HEAD 커밋 세 가지 공간의 차이를 비교해서 보여주는 역할

Git Bash로 단계별 이해

  1. 해당 Git 폴더에 “Git-Test”를 적은 txt 파일을 생성한 뒤 git status
    cat.txt
  2. cat.txt 상태가 Untracked(추적되지 않는) file이란 것을 확인할 수 있다.
  3. 해당 상태는 아래 그림과 같다.
    UnTracked
    • 새로 파일을 생성할 경우 워킹트리에만 해당 파일이 존재한다.
    • 스테이지는 아직 비어있고 한 번도 커밋하지 않았기 때문에 HEAD 커밋은 없다.

  1. 스테이지 파일 추가(add)
    스테이지 파일 추가
  • git add 이후 git status로 상태를 확인해 보면 cat.txt 파일이 변경되었다는 문구가 뜬다.
  • ls -a 로 .git 폴더를 다시 살펴보면 전에는 없었던 index 폴더가 새로 생성된 것을 확인할 수 있다.

  1. .git/index 폴더 분석
    v폴더 분석
  • file 명령어를 사용해 ./git/index를 알아보면 Git stage(index = stage)라는 것을 알 수 있다.
  • 스테이지 cat.txt 파일 체크섬과 워킹트리에 있던(로컬저장소)에 있는 cat.txt 체크섬과 비교한다.
    • 두 체크섬 값이 일치하는 것을 확인할 수 있다.
      체크섬 일치 확인
  1. git/objects 폴더 분석
    폴더 분석
    • objects 폴더에 cat.txt의 체크섬 앞자리 두 개로 이루어진 폴더가 생성됐음
    • 그 폴더를 확인해 보면 앞자리 두 개를 제외한 체크섬을 이름으로 갖는 파일이 있음
    • 이를 git show로 확인해 보면 Git-Test라는 문구가 정상 출력
      • Git에서는 편의상 체크섬을 5개만 입력해도 된다.
        명령어 수행 후의 상태

체크섬을 이용한 객체의 종류와 내용 확인

  • git cat-file -t <체크섬> : 해당 체크섬을 가진 객체의 타입을 알려주는 명령
  • git cat-file <객체타입> <체크섬> : 객체의 타입을 알고 있을 때 해당 파일의 내용을 표시
    객체의 종류 확인
    • 스테이지에 올라가 있는 28946(cat.txt) 객체는 blob(binary large object) 타입임을 확인
    • blob 객체타입을 명령어로 주고 확인해 보면 “Git-Test”가 나옴

  • 스테이지에 올리는 과정에서의 체크섬은 파일의 내용이 같다면 체크섬이 같다.

git add, status 핵심 요약

  • git status
    → 워킹트리와 스테이지, HEAD 커밋 세 가지 공간의 차이를 비교해서 보여주는 역할

  • git add
    → 워킹트리에 존재하는 파일을 stage에 추가하는 명령

  • stage에 올라갈 때 해당 파일의 체크섬 값과 동일한 이름을 가지는 blob 객체가 생성되고
    이 객체는 .git/objects 파일에 저장. 그리고 스테이지의 내용은 .git/index에 기록됨

 


git commit 내부 분석

  1. git commit 실행
    git commit 실행
    • 로그를 확인해 보면 커밋에 대한 체크섬이 있는 것을 확인할 수 있다.
      • 커밋에 대한 체크섬은 스테이지에서와 달리 무조건 다른 값을 가진다.

  2. git/objects 상태 변화
    git 상태 변화
    • .git/objects 폴더 내부를 보면 새로운 폴더 a9와 bd가 생성된 것을 확인할 수 있다.
    • 이중 우리가 위에서 만들었던 커밋은 bd 폴더이며 확인해 보면 로그와 같은 것을 확인할 수 있다.
    • git show 명령어로 해당 폴더(객체)를 확인하면 커밋 객체라는 것을 재확인할 수 있다.

  1. 상태 확인
    상태 확인
    • 해당 상태에서 stage를 확인해 보면 스테이지가 비어있지 않고 cat.txt가 있는 것을 확인할 수 있다.
    • 워킹트리가 Clean 하다 → 워킹트리, 스테이지, HEAD 커밋의 내용이 모두 똑같다.

워킹트리 clean


Git tree 객체

  1. objects에 있던 a9 폴더 분석
    • git show를 통해 체크섬을 확인하면 cat.txt와 tree라는 객체가 들어있다.

a9

  1. 스테이지 및 커밋 객체 분석

커밋 객체 분석

  • ls-tree 명령어로 트리 객체의 내용을 확인하면 아래의 스테이지의 내용과 동일한 것을 볼 수 있다.
  • 커밋 로그로 해당 커밋의 체크섬을 확인하고 이를 활용하여 타입을 알아낸다. → commit 객체임을 확인
  • commit 객체 내부를 보면 커밋 객체 = 트리 객체 + 커밋 메시지로 이루어진 것을 확인할 수 있다.

commit 내부


핵심 요약

    1. 커밋을 하면 스테이지의 객체로 트리가 만들어진다.
    2. 커밋에는 커밋 메시지와 트리 객체가 포함된다.

 


수동 커밋을 통한 Commit의 내부와 동작 방식 분석


파일 수정하고 추가 커밋

  1. 파일 내용 수정

파일 내용 수정

    1. 기존에 있던 cat.txt 파일에 “add text”라는 글자를 추가하는 파일 수정 작업 수행
    2. 노란색 네모를 보면 수정 전의 체크섬 값과 수정 후의 체크섬 값이 다른 것을 확인할 수 있다.

  1. 워킹트리, 스테이지, HEAD 비교
  • cat.txt 파일이 수정된 상태에서 현재 폴더와, 스테이지, HEAD의 체크섬 내용을 비교한다.
    비교
    • 워킹 트리의 체크섬과 (스테이지, 헤드 커밋 내용)의 체크섬이 다르다.
      → 아직 변경사항을 스테이지에 추가하지 않았기 때문

    • 파일 수정한 상태 그림으로 표현
      파일 수정한 상태 그림 표현
      • 워킹트리의 cat.txt만 다른 체크섬 값을 가짐

  1. 변경 내용 스테이지 추가

변경

  • git add로 수정한 파일을 스테이지에 올린다.
  • 올린 후 상태는 아래와 같다.

변경 내용 스테이지 추가


직접 트리를 만들어서 커밋

  • 해당 파트에서 사용하는 명령어들은 저수준(Low-Level) 명령어이기 때문에 평소에는 사용되지 않는다.
  1. 수동으로 트리 생성
    직접 트리를 만들어서 커밋
    • git write-tree 로 트리 생성 후, 생성된 트리 객체의 체크섬을 확인
      → 생성된 트리 객체와 스테이지의 내용(체크섬)이 같음.

  1. 트리로 커밋하기
    1. git commit-tree 명령어를 사용해 트리 객체를 이용해서 직접 커밋 생성
      • -p HEAD는 부모 커밋이 HEAD라는 사실을 명시
        ← 커밋 객체는 반드시 부모 커밋을 가져야 하기 때문에 부모를 지정해 주는 옵션 -p 사용

    2. 생성된 커밋을 확인해 보면 정상적으로 커밋이 등록된 것을 확인할 수 있다.
    3. 그런데 커밋 로그를 확인해 보면 로그에는 출력되지 않는다.
      HEAD가 갱신되지 않았기 때문 → HEAD를 직접 갱신해줘야 함

커밋 로그 확인

  1. HEAD 직접 갱신
  • .git 폴더에 HEAD 파일의 내용을 변경하여 HEAD를 직접 변경한다.

헤더

1.  ./git/refs/heads/main 에 HEAD 객체에 대한 정보가 있다
2.  `git update-ref` 명령어로 위에서 직접 커밋한 객체의 체크섬을 가져와 업데이트한다.
3.  HEAD 파일의 변경을 확인한 후, 커밋 로그를 출력하면 정상적으로 로그가 나오는 것을 확인할 수 있다.
  • 해당 단계를 그림으로 나타내기
    단계 그림

중복 파일 관리

  • git에서 파일은 blob으로 관리됨
  • blob은 제목이나 생성 날짜와는 관계없이 내용이 같을 경우 같은 체크섬을 가진다.
    → 복사된 파일은 같은 체크섬을 가진다.

  • 커밋할 때, 이전 커밋에 있었던 체크섬 값이 다시 올라왔다면?
    • 이전 blob 객체를 활용한 커밋을 실행
    • 저장소에 별도의 blob 객체가 추가로 생기지 않는다.
      → 같은 파일을 복사하거나 새로운 커밋을 여러 개 만들어도, 그 안의 파일이 같은 내용이라면
      하나의 blob으로 관리되므로 빠르고 효율적

 


브랜치 작업 내부 분석


브랜치 생성, 삭제

  1. 브랜치 생성하고 확인
    브랜치 생성
    1. [test] 브랜치를 생성한다. 커밋을 지정하지 않았으므로 HEAD 커밋으로부터 브랜치가 생성
    2. 커밋 로그를 확인해 보면 [test] 브랜치는 12e9fd0을 참조하고 있음
    3. .git/refs/heads 폴더를 확인해 보면 이전과 다르게 test라는 파일이 추가됐음
    4. test 파일의 내용은 HEAD 커밋의 전체 체크섬 내용

  1. 브랜치 삭제 및 재생성
    브랜치 삭제
    • git branch -drm. git/refs/head/<브랜치이름> 이 동일한 기능
      브랜치를 삭제 및 생성하는 것은./git/refs/heads/에 파일을 추가하고 삭제하는 것

브랜치 체크아웃

브랜치 체크아웃

  1. 현재 HEAD의 부모 커밋으로부터 [test3] 브랜치 생성
  2. 로그를 통해 이전 부모 트리에 정상적으로 [test3] 브랜치가 생성된 것을 확인
  3. HEAD 파일의 내용과 [test3] 브랜치로 체크아웃 후 HEAD 파일의 내용을 비교
    • /refs/heads/<브랜치이름>의 양식을 가지고 있는 것을 확인 가능
      → /refs/heads에서 참조하는 파일을 바꾸는 것이 체크아웃

  4. git status로 워킹트리를 확인해 보면 clean 한 상태
    → 워킹트리 = 스테이지 = HEAD 인 상태

  • 브랜치 체크아웃 정의
    → HEAD를 이동시키고, 스테이지와 워킹트리를 HEAD가 가리키는 커밋과 동일한 내용으로 변경

수동 체크아웃

수동체크아웃

  1. echo “ref: refs/heads/main” >. git/HEAD → HEAD 파일 직접 수정
  2. 로그를 확인해 보면 HEAD가 main을 가리키는 것을 볼 수 있음
  3. status로 상태를 확인하면 워킹트리와 스테이지는 여전히 이전 브랜치를 가리키고 있음
    → HEAD 커밋만 main으로 직접 변경해 줬기 때문

  4. reset --hard → 커밋, 스테이지, 워킹트리의 내용을 모두 같게 함
    • 스테이지와 워킹트리의 내용을 직접 수정할 수도 있지만 번거로움

 


최종 요약

  • git add → 워킹트리의 내용을 스테이지에 추가
  • git commit → 스테이지의 내용으로 새로운 커밋 생성
  • 커밋 후 git status 하면 clean 한 상태임을 표시
    • clean : 워킹트리, 스테이지, HEAD의 커밋들이 모두 동일한 내용을 담고 있다는 뜻

  • 커밋 객체 = 트리 객체 + blob 객체들
  • 커밋 객체는 부모 커밋에 대한 참조를 가지고 있다
  • 브랜치를 생성하면 단순히 브랜치 파일 하나를 추가한다.
  • 브랜치 체크아웃은 HEAD를 변경하고 브랜치가 참조하는 커밋의 내용으로 스테이지와 워킹트리를 변경