백엔드 JW님과 JY님이랑 단기 속성 Git 스터디를 하게 되었다. 내가 git 명령어를 복붙할 줄 안다고 해서 다룰줄 안다고 할 수 있을까! 스터디라고 해서 명령어만 배울줄 알았는데 어림없는 생각이었다. 멘토링이라고 해도될 만큼의 퀄리티.. 외쳐 갓Jw.. 스터디때 배운 내용 + 추가적으로 더 공부해볼 내용 정리겸 해보겠다.
Git
Git은 Content-addressable 파일시스템이다. 이게 무슨 말이냐 하면 Git의 핵심은 단순한 Key-Value(역주 - 예, 파일 이름과 파일 데이터) 데이터 저장소라는 것이다. 어떤 형식의 데이터라도 집어넣을 수 있고 해당 Key로 언제든지 데이터를 다시 가져올 수 있다.
.git
directory
Git 저장소의 핵심! Git의 동작과 버전 관리 기능을 가능하게 하는데 필수적인 요소들을 포함한다. 이 폴더엔 Git의 내부 동작을 제어하는 파일과 폴더가 있다.
tree
구조
.git
폴더 내부에 있는 파일과 폴더들은 Git 저장소의 트리 구조를 형성하고 있다.
config
git config
의 명령을 사용해서 구성 정보를 읽고 변경할 수 있다.
- Git 저장소의 구성 정보를 담고 있음.
- 주요 설정 항목, 사용자 정보, 원격 저장소 정보 등이 저장
refs
🌟
별 표시는 깃 공식 홈페이지에서 핵심이라고 말한 요소
- Git의 Reference를 저장한다.
- 참조는 브랜치, 태그, 원격 추적 브랜치 등의 이름과 커밋 해시 값을 매핑하는 역할
refs/heads
폴더에는 로컬 브랜치가, refs/tags
폴더에는 태그가 저장됩니다.
objects
🌟
- Git에서 관리되는 모든 객체(Object)를 저장한다.
- 객체는 커밋(Commit), 트리(Tree), 블롭(Blob), 태그(tag)의 데이터를 포함한다.
- 커밋 Commit
스냅샷 역할
커밋 객체는 특정 시점에서의 프로젝트의 상태를 나타냄.
각 커밋 객체는 커밋 메시지, 저자 정보, 부모 커밋 정보 등을 포함.
해당 커밋이 참조하는 트리 객체의 해시 값도 포함.
커밋 객체는 Git 저장소의 히스토리를 구성하고, 프로젝트의 변경 사항을 추적한다.
- 트리 Tree
디렉토리의 구조와 파일들의 정보를 나타냄.
각 트리 객체는 파일이나 다른 하위 트리를 가리키는 엔트리들의 목록을 포함.
트리 객체는 계층적인 구조를 가지며, 파일 시스템의 디렉토리 구조를 반영함.
- 블롭 Blob
블롭 객체는 파일의 내용을 나타낸다.
각 블롭 객체는 파일 데이터를 직접 저장하며, 파일의 SHA-1 해시 값으로 식별됨.
Git은 파일의 내용이 변경되면 새로운 블롭 객체를 생성하여 저장
- 태그 Tag
커밋이나 다른 태그를 가리키는 참조.
각 태그 객체는 태그의 이름, 태그를 생성한 사람의 정보, 태그가 가리키는 커밋의 해시 값 등을 포함
태그 객체는 주로 프로젝트의 특정 버전을 나타내는 데 사용
- 각 객체는 Git에서 파일의 스냅샷, 디렉토리의 트리 구조, 커밋 정보 등을 나타내는 역할을 한다.
- Git 내부에서 사용하는 40자 길이의
SHA-1
해시 값으로 이름이 저장된 파일들이 저장된다.
- Git은 데이터를 저장할 때 데이터와 헤더로 생성한 SHA-1 체크섬으로 파일 이름을 짓는다. 해시의 처음 두 글자를 따서 디렉토리 이름에 사용하고 나머지 38글자를 파일 이름에 사용한다.
- 객체 파일은 내부적으로 압축되어 저장되어있음.
index
파일 🌟
- Staging Area에 있는 파일들의 목록을 담고 있음.
HEAD
🌟
- 현재 작업 중인 branch를 가리킴(포인터)
- HEAD가 가리키는 커밋은 기준점으로 사용
- 보통 branch를 가리키지만 직접 커밋 해시값이나 태그를 가리킬 수도 있음.
- HEAD 파일을 통해 Git은 작업 중인 브랜치를 파악하고 새로운 커밋을 작성할 때 해당 브랜치에 연결한다.
- HEAD의 위치를 유지하고 변경하는 것은 프로젝트의 버전 관리와 작업 흐름을 올바르게 유지하는 데 매우 중요
hooks
- Git 동작의 특정 시점에서 실행되는 스크립트를 담고 있다.
- 예를 들어,
pre-commit
, 커밋이 수행되기 전에 실행되는 스크립트를 포함
- 커밋 전에 자동으로 특정 작업을 수행할 수 있다.
diff
와 status
뭐가 다를까
둘다 Git에서 변경 사항을 확인하는 데에 사용되는 두 가지 명령이다. 하지만? 다른 목적과 동작을 갖고 있다!
git diff
- 현재 Working directory와 Staging area, 혹은 Commit 사이의 차이점을 보여준다.
- 변경된 파일의 내용 차이를 비교한다.
- 변경된 내용을 확인하고 수정한 파일을 Staging area에 추가하거나 Commit할 준비를 할 수 있다.
git status
- 현재 Working directory의 상태를 보여준다.
- Staging area와 Commit의 차이를 알려준다.
- 작업 디렉토리의 수정된 파일, 스테이징 영역에 있는 파일, 커밋되지 않은 변경 사항 등을 보여줌.
- 현재 작업 중인 브랜치의 상태를 파악하고 변경된 파일을 스테이징하거나 커밋할 필요성을 확인할 수 있습니다.
추적하는 값이 다르다! status는 파일의 상태가 변경되었는지 여부 체크하는 것, diff는 파일 내부 콘텐츠의 변경 여부를 체크한다.
switch
와 checkout
차이점
Git 2.23에서 checkout을 대신할 switch
, restore
가 도입되었다.
git --help에도 checkout 명령어가 안 나온다..!
왜 checkout이 대체 되었을까?
기능이 많기 때문이다. 기능이 많으면 원하는 의도대로 시행이 안될 수 있다. 변수를 막자!
(브랜치 전환 이외에도, 커밋, 태그 등의 참조를 체크아웃하거나, 작업 디렉토리의 파일을 변경할 수 있음.)
- checkout: Switch branches or restore working tree files
- switch: Switch branches
- restore: Restore working tree files
checkout의 기능을 switch랑 restore가 나눠서 담당했다고 보면 된다.
git switch
브랜치를 변경하는 부분만 담당한다.
$ git switch develop
$ git switch -c new-branch
$ git switch -c new-branch2 515c633a
git restore
워킹 트리의 파일을 복원해 주는 역할을 한다.
$ git restore README.md
$ git restore --staged README.md
SHA-1? checksum?
- Git은 데이터를 저장하기 전에 항상 체크섬을 구하고 그 기준으로 데이터를 관리한다. 그 체크섬을 구하는데 SHA-1 해시를 사용하고, 그러면 체크섬은 160 bit가 되고, 이를 16진수로 표현하면 40자가 됨.
- 저장소에 보관하는 파일도 이 체크섬을 키로 해서 보관하고, 전체 트리(디렉터리)도 이 체크섬으로 보관하며, 커밋에 대한 데이터도 이 체크섬 기준으로 보관.
- Git은 어떤 데이터든지 데이터를 저장하기 전에 항상 체크섬을 구하고, 체크섬을 기준으로 모든 데이터를 관리한다. 이 40자는 거의 유일한 값이 나오기 때문에 고유키로 쓸 수 있다.
- 체크섬은 파일의 이름이나 작성시간이 아닌 오직 '내용content'을 기준으로 만들어진다. 그래서 만약 어떤 저장소의 A.txt, B.txt, C.txt가 모두 같은 내용 'a'를 담고 있다면, 혹은 어떤 파일의 내용이 기존의 내용에서 변한 게 없다면, Git은 여러 번 저장할 필요 없이 처음 만들었던 하나의 체크섬을 활용한다.
- Git은 파일의 변경사항만 저장하는 것이 아니라 내용 전체를 저장하는 방식으로 동작함. 이런 방식 덕분에 우리는 10번째 전에 했던 커밋이라도, 하나하나 거슬러 올라갈 필요 없이 한 번에 이동해서 찾아볼 수 있다.
SHA-1이 어떤 함수인지.. 등에 대해선 생략하겠다.
참조 ✅