Git은 왜 그렇게 복잡한가?


Git은 애초에 당신이 쉽다고 느끼게 만들려고 한 적이 없다.

Git이 그냥 add, commit, push의 3단계라고 생각하는가? 그건 당신이 줄곧 “싱글 플레이어 모드”로 놀고 있었다는 뜻이다. 기껏해야 LAN 협동 플레이 정도다. 그건 Git을 사용하는 게 아니다 — Git을 수동 동기화 버전의 바이두 클라우드(Baidu Netdisk)처럼 사용하는 것이다.

Git의 복잡성은 그것이 해결하려는 궁극적인 문제에서 비롯된다: 서로를 신뢰하지 않고, 생활 패턴이 반대이며, 언제든 코드를 던져두고 사라질 수 있는 프로그래머들이 어떻게 같은 프로젝트에서 협업하면서도 카오스에 빠지지 않을 수 있을까?

봐라, clone과 push는 누구나 할 수 있다. 하지만 팀에서 일하기 시작하는 순간 — pull을 하면 모든 게 충돌 투성이이고, 화면은 <<<<< HEAD와 >>>>>> 어떤-무작위-해시로 뒤덮인다 — 바로 그때 악몽이 시작된다.

나도 직접 겪었다. 우리 팀에 새로 온 백엔드 개발자는 실력은 좋았지만 Git을 다루지 못했다. 어느 날 긴급한 hotfix를 병합해야 했는데, 몇 시간째 진전이 없어 도움을 청해왔다. 그의 브랜치 그래프를 봤는데 — 맙소사, 크툴루 신화의 촉수에 버금가는 뒤엉킴이었다: 포크, 병합, 또 포크, 또 병합, 그 사이사이에 의미 없는 merge branch 'master' into master 커밋이 여럿 끼어 있었다. 뭘 했는지 물었다. 그가 말하길: “pull이 안 돼서 fetch를 했어요, 그리고 rebase를 했는데, rebase가 안 돼서 merge를 했고, merge에도 충돌이 남아 있어서 reset을 했어요…”

내 혈압이 하늘을 찔렀다. 그는 Git을 소원을 비는 우물처럼 대하고 있었다 — 듣기 좋은 명령어 아무거나 던져넣고 억지로 하면 기적이 일어나길 바라는 식이었다. 스포일러: 기적은 일어나지 않았고, 거의 사고를 낼 뻔했다.

이것은 빙산의 일각에 불과하다. 더 깊이 들어가면 원자적 히스토리 조작의 “금술”이 나온다: rebase -i, cherry-pick, filter-branch. 이것들은 무엇을 위한 것인가? 쉽게 말해, 코드 세계의 “타임머신”이다 — 과거로 돌아가 역사를 바꿀 수 있게 해준다. 하지만 영화에서 알다시피, 열 명의 타임트래블러 중 아홉은 우주를 망가뜨린다. git reflog는 후회약(후회의 약)이지만, 대부분의 경우 언제 “독”에 걸렸는지조차 모른다.

Git의 설계 철학은 중앙 권위를 전혀 신뢰하지 않는 것이다. 모든 개발자의 컴퓨터를 완전한 “평행 우주”(repository)로 간주한다. 당신이 하는 모든 commit은 그 우주에 새로운 역사적 스냅샷을 만든다. 브랜치는 원하는 만큼 수많은 평행 우주를 만들어낼 수 있게 해준다. merge와 rebase는 서로 다른 두 “타임라인”을 통합하려는 시도다 — 그게 얼마나 복잡한 일인지 생각해봐라. 물리학자들도 아직 이해하지 못했다!

스테이징 영역(staging area)은 커밋할 내용을 정밀하게 제어할 수 있도록 존재한다. 브랜치는 작업을 분리하여 서로 간섭하지 않게 한다. merge는 협업의 불가피한 산물인 분기(divergence)를 처리한다. 이 모든 것은 하나의 거대한 “분산” 목표를 위해 작동한다. Git은 무한한 자유를 준다 — 그리고 일을 망칠 무한한 가능성도 함께 준다.

그렇다면 질문은: Git은 희망이 없는가? 보통 사람들은 절대 배울 수 없는가?

그렇지 않다. 문제는 Git이 아니라 우리가 배우는 방식에 있다. 시중의 대부분 튜토리얼은 사전식 명령어 목록이거나 파편화된 시나리오 설명이다. 공식 문서는 수천 페이지짜리 《新华字典(Xinhua Dictionary)》와 같다 — 한 단어를 찾기에는 좋지만, 사전으로 소설 쓰는 법을 배울 수 있을까? 온라인 가이드는 여기저기 흩어져 있어 마치 흩어진 레고 블록 더미와 같다. 하지만 아무도 밀레니엄 팔콘(Millennium Falcon)을 조립하는 설계도를 주지 않는다.

그래서 나는 모든 것을 다루려고 하지 않고 실전 고빈도 시나리오에 집중하는 튜토리얼을 강력히 추천한다. 바이트댄스(Bytedance) 팀에서 예전에 낸 《Git 제로부터 실전 핸드북》이 꽤 괜찮다고 생각한다.

예를 들어 git pull과 git pull --rebase의 차이점과 적용 상황을 알려준다. 죽어라 암기시키는 게 아니다. 실제 충돌 사례를 단계별로 친절히 설명하며, 남의 코드를 그냥 삭제하는 게 아니라 우아하게 해결하는 방법을 보여준다. 기능 브랜치가 메인 브랜치보다 너무 뒤쳐졌을 때 동기화에 merge와 rebase 중 무엇을 써야 하는지, 그리고 각 선택의 장단점을 설명해준다.

결국 Git의 설계 철학은 “무한한 자유를 주고, 동시에 목을 매달 줄도 준다”는 것이다. 좋은 안내서는 그 줄로 그물을 엮거나 암벽을 타는 법을 가르쳐주는 것이지, 실수로 자신의 목에 올가미를 걸지 않게 해주는 것이다. 우리의 목표는 모든 명령어를 외울 수 있는 Git 고고학자가 되는 것이 아니다. 팀 내에서 여유롭게 움직이며, 팀원에게 민폐를 끼치지 않고, 결정적인 순간에 세상을 구할 수 있는 Git 장인이 되는 것이다.