Git VSC
학습 자료 : https://git-scm.com/book/ko/v2/Git의-내부-Git-개체
우리가 개발을 하는 과정에서 반드시 사용하게 되는 것이 바로
Git
입니다. 그렇다면 우리는 어째서 다른 사람들이 시키지도 않았는데 Git을 사용하는 것일까요? 이에 대해서 이야기 위해서는 우선 Git이 Version Control System
라는 것을 먼저 이해야 합니다.VSC
버전 관리 시스템이 등장하게 된 배경은 무엇일까요? 우리는 컴퓨터로 작업을 하면서 여러 작업 파일들을 생성해봤을 것입니다. 이러한 작업 파일을 작성하고 수정하고 업데이트 하는 과정을 거친다고 생각을 해보겠습니다. 이 과정에서 수정하기 전의 상태를 기억해놓고 싶으면 어떻게 해야 할까요? 만약 현재 파일이 making_something 이라는 파일이라면 making_something2 로 파일을 복사하여 수정하기 이전의 상태를 저장할 수 있습니다. 하지만 이러한 방법의 단점은 명확합니다. 이러한 요구 사항이 늘어날 수록 계속해서 파일을 생성해야 하기 때문에 용량을 많이 차지하게 되고 가면 갈 수록 어떤 파일을 작업 해놨는지 추적하기가 어려워질 것입니다.
앞서 설명했던 단점들을 해결하기 위해 등장한 것이
Version Control System
입니다. 그렇다면 버전 관리
가 무엇인지 부터 알아보겠습니다. 버전 관리에 있어서 필요한 것은 추가하고 싶은 현재의 파일 상태를 버전으로 추가할 수 있어야 한다는 것이고 만약 그 이전의 상태로 되돌리고 싶을 경우 버전을 사용하여 이전의 상태로 복구 시킬 수 있는 기능을 필요로 합니다. 또한 파일들의 수정 내용을 비교해볼 수 있고 만들어진 날짜와 같은 정보 또한 얻을 수 있습니다.이러한 말만 들어도 정말 많은 기능을 수행하고 있지 않나요? 이러한 버전 관리에서도 종류가 나뉘는데 크게
로컬 버전 관리
, 중앙 집중식 버전 관리
, 분산 버전 관리 시스템
로 구분할 수 있습니다.로컬 버전 관리는 아주 간단한 데이터베이스를 사용해서 파일의 변경 정보를 관리합니다. 이러한 데이터베이스를 이용하는 방식이
Git Object
를 활용하여 로컬에서 버전 관리를 수행합니다.Git Object
Git은 어떻게 보면 굉장히 복잡하지만 어떻게 보면 굉장히 단순한 구조를 이용하여 버전을 관리합니다. Git의 핵심은 단순한 Key-Value 데이터 저장소를 사용하여 데이터를 Key로 언제든지 다시 가져올 수 있다는 것이 특징입니다.
commit b1d013c5dd8ba7d2244df30e02feffdafc5c85be (HEAD -> sunub, origin/sunub, origin/HEAD)
Author: sunub <bsc5672@gmail.com>
Date: Fri Jul 19 13:29:45 2024 +0900
fix : 바뀐 블로그 url 사이트맵으로 다이렉션 되도록 Link 수정
commit 9f97a4c2aa4f3bd702f86ef8f8c9b7e38cc03131
Author: sunub <bsc5672@gmail.com>
Date: Fri Jul 19 12:46:47 2024 +0900
fix : 블로그 사이트 오류 수정 중
이러한 데이터가 어떻게 저장이 되어 있는지 실제로 명령어를 이용하여 검색해보겠습니다. 우선 프롬프트에
git log
를 입력하여 보시길 바랍니다. git log 입력 시 위와 같이 commit에 대한 정보가 포함된 메시지와 저자, 언제 저장되어 있는 지에 대한 정보와 commit의 Hash Key
가 출력이 됩니다. 이 Hash Key가 Git을 이용하여 버전을 관리하는 핵심 요소입니다.Git에서 Hash를 Key 값으로 사용하는 이유는 무엇일까요? 우선
고유성을 보장
한다는 특징이 있습니다. Hash 함수로 생성되는 값들은 각각의 Hash 알고리즘에 의해서 생성이 됩니다. 예를 들어 유명한 해쉬 함수는 sha-1, sha-256과 같은 해쉬 함수 알고리즘이 있습니다. 이러한 함수들은 주어지는 문자들을 Binary 데이터로 변환하고 해당 Binary 데이터들을 특정한 값이나 규칙들을 추가하여 기존의 언어와는 전혀 다른 값을 생성합니다. 이러한 특징으로 인해서 Hash 값은 고유성을 보장
하고 충돌 가능성을 최소화 할 수 있다
는 특징이 있기 때문에 버전 관리시 파일들에 대한 Key 값으로 사용하기 적합합니다. 파일 데이터들에 대한 정보가 겹칠 경우 기존의 파일과 작성할 파일에 오류가 생길 수 있기 때문에 Hash를 Key 값으로 이러한 위험을 최소화 했습니다.위의 그림을 예시로 실제 Git Object에 대해서 자세하게 설명해보겠습니다. 가장 상위에는 Commit Object가 존재하고 해당 Commit Object의 하위 구조에는 여러개의 Tree Object 가 있습니다. Tree Object는 Tree Object 들끼리 연결이 가능하며 Tree Object의 하위 구조에는 Blob Object가 연결되어 있다는 특징을 확인하실 수 있습니다. 각각이 Object 라고 표현한 것에는 이유가 있습니다. 왜냐하면 각각의 Object들이 자신들의 속성을 갖고 있기 때문입니다. 각각의 Object들이 어떤 속성을 가질 수 있는지에 대해서 설명하겠습니다.
Commit Object
❯ git cat-file -p b1d013c5dd8ba7d2244df30e02feffdafc5c85be
tree 5373cc75a5c5d869f4b68757ddac774e131b2add
parent 9f97a4c2aa4f3bd702f86ef8f8c9b7e38cc03131
author sunub <bsc5672@gmail.com> 1721363385 +0900
committer sunub <bsc5672@gmail.com> 1721363385 +0900
fix : 바뀐 블로그 url 사이트맵으로 다이렉션 되도록 Link 수정
Commit Object는 Commit 을 작성한
Author
에 대한 정보를 포함합니다. 또한 해당 Commit 이 언제 생성되었는지에 대한 생성 일자
에 대한 정보가 포함됩니다. 또한 현재 작성된 이전 커밋에 대한 해시 데이터인 parent
에 대한 정보가 포함이 됩니다. 또한 현재 커밋의 정보를 포함하는 Commit Message와 실제로 커밋한 사람에 대한 정보인 Committer에 대한 정보가 포함이 됩니다.Tree Object
❯ git cat-file -p 5373cc75a5c5d869f4b68757ddac774e131b2add
040000 tree 186b6b9bd4982b71651db7299f113015188fb222 .vscode
100755 blob 94d12ee96fd06a712216b306ab542580b563cb0c .gitignore
100644 blob c512bbfc93c9bc876b0f29a9b091b79427699cb4 .prettierrc
앞서
git log
를 이용하여 확인할 수 있는 commit 의 키 값을 git ls-tree 해쉬값
명령어를 사용할 경우 특정 Tree Object가 어떤 데이터 구조로 구성되어 있는지 확인할 수 있습니다. 정보는 앞에서 부터 파일모드, Object 타입, Hash Key, 파일 이름
에 해당합니다. 그리고 위의 로그에서 추가로 확인할 수 있는 특징이 있는데 폴더의 경우 tree Object 타입으로 저장이 되고 파일의 경우 blob Object 타입으로 저장이 된다는 특징을 확인하실 수 있습니다.Blob Object
Blob Object가 갖고 있는 속성 값들은 다른 Object 들에 비해서 단순한 구조를 갖고 있습니다. Blob Object를 구분할 수 있는 Hash Key와
실제 데이터
에 대한 내용이 포함되어 있는데 이 실제 데이터는 압축된 데이터로 저장되어 있는 것을 확인할 수 있습니다.Git Object를 어떻게 활용하는가?
이제 각각의 Git Object가 어떤 특징을 갖고 있고 어떤 속성을 갖고 있는지에 대해서는 자세하게 설명이 되었을 것이라고 생각합니다. 그렇다면 위의 Object를 어떤 식으로 사용하여 작업을 수행하는지에 대해서 자세하게 다루어 보겠습니다.
Git Working Flow
우리는 Git을 정말 많이 사용했습니다. 특히 우리가 가장 많이 사용하는 기능은
add
commit
push
pool
와 같은 작업들을 굉장히 많이 사용합니다. 이러한 기능들의 뒤에는 어떤 것들이 숨어 있는지에 대해서 자세하게 다루어 보겠습니다.Git Status
그림의 각 줄은 Git이 Local에서 변화하는 파일들을 다루기 위해 변화하는 상태들입니다. 이 상태들이 각각 어떤 특징을 지니는지에 대해서 자세하게 다루어 보겠습니다.
- Untracked
Working DIrectory에 있는 파일이지만 Git으로 버전 관리하지 않는 파일들이 속하는 상태가 Untracked 상태입니다. 그렇다면 추적되지 않는 파일들은 어떤 파일들을 이야기 하는 것일까요? 이러한 파일들은 Blob Object가 생성되어 git area에 저장되지 않은 파일, git add 를 이용하지 않은 파일들을 Untracked 파일이라고 말합니다. Git에 의해서 파일의 상태가 추적되고 변화를 감지 하기 위해서는
git add
명령어를 이용하여 Blob Object
가 생성이 됩니다. 그리고 생성된 파일은 .git/objects
폴더에 저장이되고 해당 파일에 대한 Key
값은 StagingArea에 기록됩니다.- Modified
git add 를 이용하여 이미 Staging Area에 추가된 파일을 추가로 수정하거나 삭제할 경우 해당 파일의 상태는
Modified
, 수정 상태로 변경 됩니다. 이러한 상태의 기준은 git add를 다시 사용하였을 경우 확인할 수 있습니다. 예를 들어 이미 Modified 상태인 파일을 다시 git add 하였을 경우 해당 Staging Area에 Key 값이 저장되지 않습니다. 이렇듯 이미 추가한 파일에 대한 상태 변경을 추적하기 위하여 Modified를 활용하는 것입니다.- Unmodified
git commit
명령어를 사용할 경우 기존의 Staging Area에 저장되어 있던 Blob Object Key 값을 이용하여 해당 Blob Object의 데이터의 정보를 활용하여 해당 디렉토리 구조와 파일 정보를 포함한 새로운 Tree Object
를 생성합니다.그리고 생성된
Tree Object
에 대한 참조, 부모 커밋에 대한 참조, 작성자 정보, 커미터 정보, 커밋 메시지를 포함하는 Commit Object
또한 생성이 됩니다. 이 Commit Object는 다른 Object와 마찬가지로 .git/objects
폴더내에 저장이 되어 관리가 됩니다.이런 작업을 끝맞힌 파일의 경우 더 이상 추적하거나 추가해야할 사항들이 남아 있지 않기 때문에 Unmodified 상태로 전환되어 모든 변경 사항이 commit 되었음을 나타냅니다.
git object 내부에 tree와 commit 의 관계에 대해 설명해주세요. 그리고 미션에서 구현한 mit와의 차이점도 설명해주세요.
실제 Git Object 내부에서 Commit과 Tree Object의 관계는 하나의 Root Tree 로 인해서 연결되어 있는 관계입니다. 실제로 두 Object는 서로 다른 목적으로 사용이 되기 때문에 상속의 관계와 같이 연결되어 있는 구조라고 할 수 없습니다. 그리고 연결되어 있는 관계 또한 양방향으로 연결된 관계가 아닌 일방적으로 연결되어 있는 관계입니다. Commit Object의 경우 Tree 중 특정 Root Tree를 연결할 수 있지만 Tree의 경우 특정 Commit Object에게 연결을 시도할 수 없습니다. 그리고 이번 미션에서 사용한 mit의 경우 또한 이러한 관계는 동일하게 Tree Object가 Commit Object에 대한 정보를 알 수 없고 Commit Object만 Tree Object에 대한 정보를 얻을 수 있습니다. 하지만 실제 Git에서와의 차이는 실제 Git은 한가지의 루트 Tree의 해쉬 키에 대한 정보를 포함할 수 있다는 것입니다. 하지만 미션의 mit의 경우 현재 트리와 이전 트리에 대한 정보를 포함할 수 있다는 것에 있어서 실제 Git과의 차이가 존재합니다.
이번 짝 프로그래밍 과정에서 스스로 반성해야 할 부분은 네비게이터 역할을 수행할 경우 어느정도의 추상된 정보를 던져서 드라이버가 스스로 작성할 수 있게끔 해야 한다는 것을 느꼈습니다. 이번 미션의 경우 저는 너무 하나 하나 세세하게 설명하여서 뭘 작성해야 하는지 까지 모두 설명하다 보니 너무 오랜 시간이 걸리고 비효율적이라는 것을 느꼈습니다. 그리고 반대의 경우도 저희가 계속 그렇게 진행을 하다 보니 너무 오랜시간이 걸리기도 하고 비효율적이라는 생각이 들었습니다. 저희는 이러한 단점을 깨닫기까지 어느 정도의 시간 후에 깨달을 수 있었고 서로 협의 하에 너무 구체적인 지시사항 말고 추상적인 지시사항을 요구할 것을 의논하여 문제를 해결했습니다. 그리고 또 다른 문제점은 내비게이터와 드라이버 모두 미션에 대한 요구사항에 대한 지식이 부족하다 보니 같이 길을 잃는 경우가 빈번하였다는 것입니다. 두 사람 모두 막혀 버리니 단순히 시간이 흐를 뿐 서로 역할을 제대로 수행하지 못하는 문제가 있었습니다. 그래서 저희는 막히는 부분이 있을 경우에는 서로 내비게이터와 드라이버의 역할을 멈추고 해당 문제에 대한 충분한 논의와 다시 학습하는 시간을 가진 후 다시 역할로 돌아와 미션을 계속 수행하는 것으로 문제를 해결하고자 했습니다.