Git을, 아니 사실상 GitHub를 클라우드의 용도로 사용했다고 하는게 맞는 표현인 것 같다. 습관적으로 작업이 끝날 시점에 git add ., git commit -m, git remote add origin, git push만 했었는데, 이 기회에 Git의 전체적인 부분부터 조금 세밀한 부분들까지 정리를 하려고 한다.
SnapShot + Delta 방식
Github로 대표되는 VCS(Version Control System)은 2가지 종류로 나눌 수 있다.
CVCS(Central) - 중앙 집중적 시스템, SVN으로 대표되는 CVCS는 단 하나의 history만 존재하고, 서버, 네트워크의 영향을 많이 받는다.
Delta방식 - 각 버전들의 ’차이점’에 대한 기록이다. 용량이 큰 파일을 다루는데 적합하지만, 계속 비교를 해야 하므로 연산 속도가 오래걸린다.

DVCS(Distributed) - 분산형 시스템, Git으로 대표되고, 대부분의 연산이 Local에서 이루어지기 때문에 네트워크의 영향을 전혀 받지 않는다.(Local Repository)
SnapShot방식 - 하나의 파일에 변동이 생겼을 때, 파일의 상태 ‘전체’를 그대로 저장하는 기록방식이다.
(사실 git에서의 저장 방식은 말하자면 SnapShot + Delta 방식이다. git은 성능을 위해 달라지지 않은 파일이 있으면 파일을 새로 저장하지 않고, 단지 이전 상태의 파일에 대한 링크만을 저장한다.)

무결성
Git에서 파일이나 Commit Version을 관리할 때는, 파일이름이나 Commit의 제목 등(String or Int)으로 관리하지 않고, 보안을 위해 체크섬(Checksum)을 사용한다. 이는 해시 함수에 데이터 전체를 입력하여 생성된 40자 길이의 16진수 값으로, 데이터의 내용 중 어느 한 곳만 변경되어도 그 전과 처음부터 끝까지 전혀 다른 해시값으로 변경된다. (git은 이 체크섬 종류 중 SHA-1이라는 보안 해시 함수를 사용한다.)
이를 통해 Git은 보안을 유지하고, Key가 있으면 Value값을 도출 가능하지만 Value만 있으면 Key를 도출할 수 없는 One-Way 무결성을 지닐 수 있게 된다.
(어? 그렇다면 우리가 GitHub, Xcode Commit에서 찾아볼 수 있는 이게 해시값인가?? 하지만 이건 7자리인데??)


맞다! 편의상 7자리만으로 표현을 한 것이고, 옆에 Copy버튼을 누르게 되면 40자 길이의 full hash value를 살펴볼 수 있다.
또한, 조금 더 깊게 알아보자면 Git 체크섬은 이러한 커밋 뿐 아니라 파일 자체에서도 살펴볼 수 있다.
Git 체크섬의 종류
방금 알아본 그 Git 체크섬이고, 명령어를 통해 터미널에서도 직접 확인을 해볼 수 있다.
git log

터미널에서 명령어를 통해 파일의 파일 체크섬을 알아볼 수 있다.
git hash-object <file>
>> 75c1140eff8d310e1622d390730c12e21ae285b6
Git의 상태와 동작방식
기본이 되는 내용은 너무 많은 블로그들에서 다루고 있는 내용이라서 그림으로 넘어가고, 내가 궁금했던, 알게된 부분들에 대해서 더 자세히 알아보려고 한다.

!! 여기서 의문점, Staging Area는 도대체 왜 존재하는 것일까?
Git을 그냥 클라우드와 비슷한 역할로 사용했던 나로서는 git add .는 commit 전에 해야하는 귀찮은 작업에 불과했다. 또한, commit할 파일들을 추적하는 곳이라고 했는데, 왜 매번 git add로 이미 맨날 올렸던 파일들을 또 올려야 하는지 이해가 되지 않았다.
이것에 대한 해답은 의외로 terminal도, git 문서도 아닌, xcode IDE에서 git을 관리하는 것을 하다가 문득 이해가 되었다.

일부분만 커밋을 하고 싶을 때
xcode자체에서 commit을 하기 전, Stage All로 모든 파일을 올릴 수도 있고, 하나씩 클릭해서 원하는 파일만 Staged 상태로 올릴 수도 있다. 항상 git add .(git add all)만 해서 add할 파일을 지정할 수 있다는 사실을 잊고 있었는데, 이렇게 원하는 파일만 add를 해서 일부분만 커밋할 일이 있을 때 Staging Area가 필요했다.
충돌을 해결할 때
비슷한 경우로, 5개의 파일을 merge를 했는데 2개의 파일에서 conflict가 났다면, 먼저 나머지 3개의 파일은 안전한 저장소에 저장해두고 싶을 것이다. 이럴 때 Staging Area에 일단 나머지 3개의 파일을 add시키고, 2개의 파일을 수정 후 commit하면 좋다.
Commit Amend 할 때
사진 오른쪽 위를 보면 Amend라는 기능이 있는 모습을 볼 수 있다. Amend는 이미 Commit된 결과를 수정(로그메시지 등)하고 새로운 Commit이 아니라 가장 최근 커밋에 덮어쓰는 것이다. 이 때, 전체 결과를 모두 Amend하기보다 조금 추가된 부분들만 로그메시지를 수정하면서 살짝 수정하고싶을 때 Staging Area를 사용하면 유용할 것이다.
(여기서 조금 주의해야할 부분! Amend를 진행해서 Commit에 변경사항이 아주 조금이라도 생겼을 경우에는 앞서 알아본 무결성에 의해서 Commit 체크섬이 완전히 달라져버린다. → 이 상황에서 이미 전에 remote Repository에 commit이 push가 된 상황이라면, 같은 이전 Commit을 가리키는 ID(체크섬)가 다른 Commit이 두 개가 생겨버린다. 하나의 branch에서 이런 일은 많은 오류를 초래할 수 있으니 주의해야한다.)
Index

git을 쓰면서 .git을 열어본 적이 없다는게 좀 실망스러워서 열어서 구조를 살펴보았다. 가장 눈에 보이는건 index였는데, Staging Area가 index 방식…? 으로 파일을 저장한다는 말을 얼핏 들은 것 같아서 관계에 대해서 궁금해졌다.
좀 찾아봤는데 원하는 대답을 얻지 못해서 GPT한테 물어봤는데, 결론은 Index == Staging Area라고 생각해도 될 것 같다.
Git내부에서, Index는 Staging Area를 구현하는 데이터 구조를 말한다.

깃이 이해하는 형태의 구조로 Index라는 파일에 모든 데이터가 저장된다. (구체적으로는 마지막 커밋이 보이는 모습으로)
이를 통해서 파일의 수정 여부를 체크하고, add가능 유무를 사용자에게 알려주는 방식으로 동작한다고 이해했다.
LifeCycle
마지막 의문점이었다.

공부하다보니, 그 전에 머리에 들어오지 않던 Git의 File Status LifeCycle과 동치인 질문이었는데, 확실히 그냥 무작정 외우는 것 보다 궁금해서 찾아보는게 더 머리에 잘 들어온다고 느꼈다.

(여기서 gitIgnore를 통해서 untracked상태로 되돌릴 수는 있는데, 이미 전에 git add를 하고 commit을 했다면 이미 API key등은 너의 remote repository commit 기록에 영원히 남아있을 수도 있다.)
Xcode IDE에서 이와 관련해서 이해할 수도 있는데, commit을 진행한 후에는 모두 Unmodified상태로 바뀌어서 어떠한 파일도 add(Staged)할 수 없다.

여기서 파일을 수정하게되면, Modified상태로 바뀌게 되고, 이 Modified상태인 파일들만 add(Staged)할 수 있다.

참조