CLI와 Git 내부의 폴더와 파일을 분석하여 Git 명령어들이 어떻게 동작하는지 살펴본다.
Git init 내부 분석
- Git Bash에서 임의의 빈 폴더에 git init을 통해. git을 만든다.(로컬저장소 생성)
ls -al. git를
통해. git 폴더 내부를 살펴보면 다양한 폴더들이 생성된 것을 확인할 수 있다.
ls -al 명령의 각 칼럼의 의미
-rw-r--r-- 1
- 파일과 권한과 상태를 의미하는 것인데, Git 내부 명령을 이해하는데 중요한 것은
- _맨 앞이 ‘-’로 시작하면 파일 ‘d’로 시작하면 폴더_라는 것
junpyohong
- 파일 소유자의 아이디
- 파일 소유자의 아이디
staff
- 파일이 속한 그룹(파일 소유자가 속한 그룹)
- 파일이 속한 그룹(파일 소유자가 속한 그룹)
73
- 파일의 크기, 바이트 표시로 표시
- 파일의 크기, 바이트 표시로 표시
Dec 27 13:36
- 파일 생성 시간
- 파일 생성 시간
description
- 파일 이름
Git add, status 내부 분석
Git status
- 워킹트리와 스테이지, HEAD 커밋 세 가지 공간의 차이를 비교해서 보여주는 역할
Git Bash로 단계별 이해
- 해당 Git 폴더에 “Git-Test”를 적은 txt 파일을 생성한 뒤
git status
- cat.txt 상태가 Untracked(추적되지 않는) file이란 것을 확인할 수 있다.
- 해당 상태는 아래 그림과 같다.
- 새로 파일을 생성할 경우 워킹트리에만 해당 파일이 존재한다.
- 스테이지는 아직 비어있고 한 번도 커밋하지 않았기 때문에 HEAD 커밋은 없다.
- 스테이지 파일 추가(add)
git add
이후 git status로 상태를 확인해 보면 cat.txt 파일이 변경되었다는 문구가 뜬다.ls -a
로 .git 폴더를 다시 살펴보면 전에는 없었던 index 폴더가 새로 생성된 것을 확인할 수 있다.
- .git/index 폴더 분석
- file 명령어를 사용해 ./git/index를 알아보면 Git stage(index = stage)라는 것을 알 수 있다.
- 스테이지 cat.txt 파일 체크섬과 워킹트리에 있던(로컬저장소)에 있는 cat.txt 체크섬과 비교한다.
- 두 체크섬 값이 일치하는 것을 확인할 수 있다.
- 두 체크섬 값이 일치하는 것을 확인할 수 있다.
- git/objects 폴더 분석
- objects 폴더에 cat.txt의 체크섬 앞자리 두 개로 이루어진 폴더가 생성됐음
- 그 폴더를 확인해 보면 앞자리 두 개를 제외한 체크섬을 이름으로 갖는 파일이 있음
- 이를 git show로 확인해 보면 Git-Test라는 문구가 정상 출력
- Git에서는 편의상 체크섬을 5개만 입력해도 된다.
- 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 내부 분석
- git commit 실행
- 로그를 확인해 보면 커밋에 대한 체크섬이 있는 것을 확인할 수 있다.
- 커밋에 대한 체크섬은 스테이지에서와 달리 무조건 다른 값을 가진다.
- 커밋에 대한 체크섬은 스테이지에서와 달리 무조건 다른 값을 가진다.
- 로그를 확인해 보면 커밋에 대한 체크섬이 있는 것을 확인할 수 있다.
- git/objects 상태 변화
- .git/objects 폴더 내부를 보면 새로운 폴더 a9와 bd가 생성된 것을 확인할 수 있다.
- 이중 우리가 위에서 만들었던 커밋은 bd 폴더이며 확인해 보면 로그와 같은 것을 확인할 수 있다.
- git show 명령어로 해당 폴더(객체)를 확인하면 커밋 객체라는 것을 재확인할 수 있다.
- 상태 확인
- 해당 상태에서 stage를 확인해 보면 스테이지가 비어있지 않고 cat.txt가 있는 것을 확인할 수 있다.
- 워킹트리가 Clean 하다 → 워킹트리, 스테이지, HEAD 커밋의 내용이 모두 똑같다.
Git tree 객체
- objects에 있던 a9 폴더 분석
- git show를 통해 체크섬을 확인하면 cat.txt와 tree라는 객체가 들어있다.
- 스테이지 및 커밋 객체 분석
- ls-tree 명령어로 트리 객체의 내용을 확인하면 아래의 스테이지의 내용과 동일한 것을 볼 수 있다.
- 커밋 로그로 해당 커밋의 체크섬을 확인하고 이를 활용하여 타입을 알아낸다. → commit 객체임을 확인
- commit 객체 내부를 보면 커밋 객체 = 트리 객체 + 커밋 메시지로 이루어진 것을 확인할 수 있다.
핵심 요약
-
- 커밋을 하면 스테이지의 객체로 트리가 만들어진다.
- 커밋에는 커밋 메시지와 트리 객체가 포함된다.
수동 커밋을 통한 Commit의 내부와 동작 방식 분석
파일 수정하고 추가 커밋
- 파일 내용 수정
-
- 기존에 있던 cat.txt 파일에 “add text”라는 글자를 추가하는 파일 수정 작업 수행
- 노란색 네모를 보면 수정 전의 체크섬 값과 수정 후의 체크섬 값이 다른 것을 확인할 수 있다.
- 워킹트리, 스테이지, HEAD 비교
- cat.txt 파일이 수정된 상태에서 현재 폴더와, 스테이지, HEAD의 체크섬 내용을 비교한다.
- 워킹 트리의 체크섬과 (스테이지, 헤드 커밋 내용)의 체크섬이 다르다.
→ 아직 변경사항을 스테이지에 추가하지 않았기 때문 - 파일 수정한 상태 그림으로 표현
- 워킹트리의 cat.txt만 다른 체크섬 값을 가짐
- 워킹트리의 cat.txt만 다른 체크섬 값을 가짐
- 워킹 트리의 체크섬과 (스테이지, 헤드 커밋 내용)의 체크섬이 다르다.
- 변경 내용 스테이지 추가
- git add로 수정한 파일을 스테이지에 올린다.
- 올린 후 상태는 아래와 같다.
직접 트리를 만들어서 커밋
- 해당 파트에서 사용하는 명령어들은 저수준(Low-Level) 명령어이기 때문에 평소에는 사용되지 않는다.
- 수동으로 트리 생성
git write-tree
로 트리 생성 후, 생성된 트리 객체의 체크섬을 확인
→ 생성된 트리 객체와 스테이지의 내용(체크섬)이 같음.
- 트리로 커밋하기
git commit-tree
명령어를 사용해 트리 객체를 이용해서 직접 커밋 생성-p HEAD
는 부모 커밋이 HEAD라는 사실을 명시
← 커밋 객체는 반드시 부모 커밋을 가져야 하기 때문에 부모를 지정해 주는 옵션 -p 사용
- 생성된 커밋을 확인해 보면 정상적으로 커밋이 등록된 것을 확인할 수 있다.
- 그런데 커밋 로그를 확인해 보면 로그에는 출력되지 않는다.
→ HEAD가 갱신되지 않았기 때문 → HEAD를 직접 갱신해줘야 함
- HEAD 직접 갱신
- .git 폴더에 HEAD 파일의 내용을 변경하여 HEAD를 직접 변경한다.
1. ./git/refs/heads/main 에 HEAD 객체에 대한 정보가 있다
2. `git update-ref` 명령어로 위에서 직접 커밋한 객체의 체크섬을 가져와 업데이트한다.
3. HEAD 파일의 변경을 확인한 후, 커밋 로그를 출력하면 정상적으로 로그가 나오는 것을 확인할 수 있다.
- 해당 단계를 그림으로 나타내기
중복 파일 관리
- git에서 파일은 blob으로 관리됨
- blob은 제목이나 생성 날짜와는 관계없이 내용이 같을 경우 같은 체크섬을 가진다.
→ 복사된 파일은 같은 체크섬을 가진다. - 커밋할 때, 이전 커밋에 있었던 체크섬 값이 다시 올라왔다면?
- 이전 blob 객체를 활용한 커밋을 실행
- 저장소에 별도의 blob 객체가 추가로 생기지 않는다.
→ 같은 파일을 복사하거나 새로운 커밋을 여러 개 만들어도, 그 안의 파일이 같은 내용이라면
하나의 blob으로 관리되므로 빠르고 효율적
브랜치 작업 내부 분석
브랜치 생성, 삭제
- 브랜치 생성하고 확인
- [test] 브랜치를 생성한다. 커밋을 지정하지 않았으므로 HEAD 커밋으로부터 브랜치가 생성
- 커밋 로그를 확인해 보면 [test] 브랜치는 12e9fd0을 참조하고 있음
- .git/refs/heads 폴더를 확인해 보면 이전과 다르게 test라는 파일이 추가됐음
- test 파일의 내용은 HEAD 커밋의 전체 체크섬 내용
- 브랜치 삭제 및 재생성
git branch -d
와rm. git/refs/head/<브랜치이름>
이 동일한 기능
→ 브랜치를 삭제 및 생성하는 것은./git/refs/heads/에 파일을 추가하고 삭제하는 것
브랜치 체크아웃
- 현재 HEAD의 부모 커밋으로부터 [test3] 브랜치 생성
- 로그를 통해 이전 부모 트리에 정상적으로 [test3] 브랜치가 생성된 것을 확인
- HEAD 파일의 내용과 [test3] 브랜치로 체크아웃 후 HEAD 파일의 내용을 비교
- /refs/heads/<브랜치이름>의 양식을 가지고 있는 것을 확인 가능
→ /refs/heads에서 참조하는 파일을 바꾸는 것이 체크아웃
- /refs/heads/<브랜치이름>의 양식을 가지고 있는 것을 확인 가능
- git status로 워킹트리를 확인해 보면 clean 한 상태
→ 워킹트리 = 스테이지 = HEAD 인 상태
- 브랜치 체크아웃 정의
→ HEAD를 이동시키고, 스테이지와 워킹트리를 HEAD가 가리키는 커밋과 동일한 내용으로 변경
수동 체크아웃
echo “ref: refs/heads/main” >. git/HEAD
→ HEAD 파일 직접 수정- 로그를 확인해 보면 HEAD가 main을 가리키는 것을 볼 수 있음
- status로 상태를 확인하면 워킹트리와 스테이지는 여전히 이전 브랜치를 가리키고 있음
→ HEAD 커밋만 main으로 직접 변경해 줬기 때문 reset --hard
→ 커밋, 스테이지, 워킹트리의 내용을 모두 같게 함- 스테이지와 워킹트리의 내용을 직접 수정할 수도 있지만 번거로움
최종 요약
git add
→ 워킹트리의 내용을 스테이지에 추가git commit
→ 스테이지의 내용으로 새로운 커밋 생성- 커밋 후
git status
하면 clean 한 상태임을 표시- clean : 워킹트리, 스테이지, HEAD의 커밋들이 모두 동일한 내용을 담고 있다는 뜻
- clean : 워킹트리, 스테이지, HEAD의 커밋들이 모두 동일한 내용을 담고 있다는 뜻
- 커밋 객체 = 트리 객체 + blob 객체들
- 커밋 객체는 부모 커밋에 대한 참조를 가지고 있다
- 브랜치를 생성하면 단순히 브랜치 파일 하나를 추가한다.
- 브랜치 체크아웃은 HEAD를 변경하고 브랜치가 참조하는 커밋의 내용으로 스테이지와 워킹트리를 변경