안녕하세요. 데이블 Service Front-end Team(SF Team)에 한재원이라고 합니다.

“여러분은 혹시 Git 때문에 고통받고 계시지 않으신가요?”

저는 올해 2월에 데이블에 합류하게 되었는데요. 거기에 수식어 하나를 덧붙이자면, 2월에 ‘개발자 첫 커리어’를 데이블로 시작했습니다. 즉 아직은 귀여운(?) 병아리 개발자인 셈입니다.

갑자기 웬 고해성사냐, 라고 생각하실 수도 있겠지만 잠깐 기다려보세요. 할 말이 있습니다. 그것은 바로 저 역시 초반부터 Git으로 고통받았기 때문입니다.

개발자로서 실무에서 협업하는 상황을 처음 겪다 보니 초반에는 걱정 없이 잘 될 줄만 알았던 Git이 꼬이기 시작했습니다. 특히 엄청 다양한 Git 사례(문제)들이 발생했기 때문에 막상 검색할 때도 어떻게 할지 몰랐습니다. 단순히 rebase 방법, revert 방법 이런 것들은 검색을 통해 찾을 수 있겠지만 현재 우리 프로젝트에 놓인 꼬여있는 브랜치(Branch)와 커밋(Commit)을 예쁘게 풀어줄 최적의 방법을 찾기란 어려웠죠.


아, 이래선 안 되겠구나

병아리 개발자라며 미숙한 티를 내면서 자기 위로를 해봐도 소용없습니다. 회사에 합류한 이상 저는 더 이상 투정 부리는 아마추어가 되면 안 됐기 때문이죠. 그리하여 본격적으로 Git에 관해서 공부할 필요성을 느꼈습니다. 또한 공부한 내용을 동료들에게 공유하는 시간을 가지면 Git에 대해 익숙하지 않은 동료분들께도 도움이 되겠다고 생각했죠.

그래서 <Git피하지말고 Git깔나게: 데이봇을 만들어가며 배우는 Git 기초 세션>이라는 세션을 발표하게 되었습니다. 해당 세션은 저희 팀 내부에서 진행했지만 Git에 익숙하지 않은 많은 개발자분에도 도움이 될 거라 생각했습니다. 팀 내부에 공유했던 영상은 본문에 임베딩을 포함하여 글 마지막에도 발표 자료와 함께 링크를 공유하도록 하겠습니다. 또한 영상 속에는 실습을 해보면서 Git을 익히는 사례도 포함되어 있으니 참고해주세요.

이 글은 해당 세션의 발표 내용을 글로 요약하여 쓴 것입니다.




“원리만 이해한다면 자유자재로 Git을 다룰 수 있다.”

저희 SF Team 리드이자 CPO인 군우님께서 하신 말입니다. 사실 이 말이 처음에는 잘 와닿지 않았습니다. 그 당시만 해도 그냥 Git을 다루는 게 어려웠기 때문이죠.

하지만 Git을 개인적으로 학습하면서 정리하다 보니 ‘아, 정말 Git의 흐름을 잘 알고 있다면 전혀 어려울 일이 아닐 수도 있겠다’는 생각이 들었습니다. 반대로 말하면 대부분의 Git을 어려워하는 사람들은 Git의 흐름과 원리를 제대로 이해하지 못하고 있을 확률이 높다고 생각했습니다.

저의 경험을 비추어 보았을 때 Git을 어려워하는 이유는 이런 것 같습니다. Git을 처음에 마주칠 때는 보통 개발에 발을 딛은 지 얼마 되지 않은 상태에다가, 방대한 Git 용어들과 익숙하지 않은 시커먼 화면(terminal)에서 무언가를 쳐야 한다는 공포감 때문에 ‘Git은 너무 어려워!’하고 머릿속에 여전히 남아 있는 게 아닐까요.

다시 돌아와서 어쨌든 Git은 원리만 이해한다면 아주 심플하게 활용할 수 있다고 생각합니다. 지금부터는 Git에 기초적이지만 기반이 되는 개념들을 통해 Git과 친숙해져 보는 시간을 가져 보도록 하겠습니다. 또한, 제가 실무에서 경험했던 Git과 관련된 사례를 영상에서 소개하고 해결하는 방법이 포함되어 있으니 참고해주세요.


Git은 한마디로 관찰자다

흔히 Git을 쉽게 비유하여 설명할 때 카메라로 사진을 찍는다(캡처한다), 문서를 작성하고 저장할 때 ‘작업물_최종.ppt’, ‘작업물_진짜최종.ppt’ 같은 것을 예시로 듭니다.

저는 Git을 이렇게 비유하고 싶습니다.

“Git은 관찰자다!”

우리는 무언가를 작업할 때 모든 걸 기억하지 못합니다. 인간이 가진 한계가 있기 때문이죠. 그렇기 때문에 이 작업을 기억할 수 있도록 Git이라는 (모든 걸 내다볼 수 있는 전지전능한) 관찰자에게 도움을 요청한다고 생각해보자고요. 즉 Git(관찰자)은 나를 도와주는 협업의 관계인 셈이죠.

Git이라는 관찰자에게 ‘내가 작업하고 있는 이 디렉터리의 변화를 모두 관찰해줘!’라고 도움을 요청하면 Git은 ‘알겠다!’고 하며 등장합니다.


git init

위에서 말한 도움을 요청하는 메시지가 바로 git init입니다. 관찰을 원하는 디렉터리 안에서 git init을 외치는 순간 Git이라는 관찰자를 고용한 셈인 거죠. (디렉터리 안에서라는 말은 터미널상 Git에게 도움을 요청하려는 프로젝트 디렉터리에 위치해 있는 것을 말합니다)


잠깐! 깨알 상식(1)

프로젝트 1개당 1명의 관찰자만 고용할 수 있습니다. TO가 1명이라는 겁니다. 그러니까 내가 작업할 디렉터리에 git init을 했다면, 그 안에 또 다른 디렉터리 안에서 같은 명령어를 실행하면 안 된다는 말입니다. 어차피 전지전능한 관찰자 1명이 디렉터리 안에 모든 것을 주시하기 때문입니다.


Git은 크게 3가지 영역으로 되어 있다

Git은 크게 3가지 영역이 존재합니다.

git의 3가지 영역

첨부 이미지와 같이 실제 작업하는 공간인 Working Directory와 대기하는 공간인 Staging Area, 마지막으로 최종 도착지점인 Repository가 있습니다. 그리고 그사이엔 git add, git commit이 있죠.


git의 3가지 영역 관찰자 시점

이걸 위에서 설명한 관찰자의 시점으로 말하면 이렇습니다. Working Directory에서 열심히 코드를 짜다가 어느 시점에서 저장(기억)하고 싶은 욕구가 생길 때 관찰자에게 저장을 요청합니다. 저장을 요청하는 메시지가 git add입니다.

그러면 Staging Area에 들어가는데 여기는 바로 관찰자의 주머니라고 생각하시면 편합니다. 주머니이기 때문에 언제든 넣고 뺄 수 있습니다. 즉 완전히 저장한 것은 아니고 임시로 주머니에 넣은 거라 할 수 있습니다. 또한 그 주머니는 종잡을 수 없이 너무나 커서 내가 넣고 싶은 것들을 아주 많이 넣을 수 있습니다.

자, 이제 이것을 완전히 기억하고 싶어졌습니다(완전히 저장하고 싶은 거죠). 최종적으로 주머니에 넣은 작업 상황들을 하나의 꾸러미로 포장을 해야 합니다. 이것이 바로 우리에게 친숙한 단어, git commit입니다. git commit을 하게 되면 Repository(.git)에 쏙 하고 들어가서 관찰자의 꾸러미 리스트에 영원히 남게 됩니다.

하나의 커밋(Commit)을 하기 위해서 이런 플로우를 거치게 되는 것입니다.


커밋(Commit)은 뭐지?

Commit은 개발자라면 아주 많이 들어봤을 단어죠. 위에 비유를 계속 이어가자면 commit이란 Git Repository에 잘 포장된 꾸러미입니다. Git의 용어로 말하면 Git Repository에 체크포인트(Check Point) 중 하나입니다.

커밋(commit)

이 꾸러미는 여러 개 만들 수 있지만 위 이미지처럼 굴비 엮이듯 연결되어 있습니다.


잠깐! 깨알 상식(2)

Commit은 원자적(Atomic Commits)으로 유지해야 합니다. 각 Commit은 한 가지에 집중할 수 있도록 최대한 원자성을 유지하는 것이 중요합니다.

하나의 파일을 Commit하라는 말이 아닙니다. 우리가 작업하고 있는 하나의 기능 또는 하나의 작업을 의미합니다.


Branch(브랜치)?

Git은 협업 도구입니다. 이 말인즉슨 여러 동료 개발자와 함께 하나의 프로젝트를 동시적으로 진행하는데 아주 좋다는 것입니다. 여기서 Branch가 그 역할을 톡톡히 하죠. 즉 여러 작업을 동시에 진행할 수 있도록 하는 것이 Git의 핵심 기능입니다.

하나의 홈페이지를 만든다고 가정했을 때, 누구는 navbar, 누구는 articles, 누구는 footer를 만든다고 합시다. 여기서 그 역할마다 Branch를 생성하여 동시에 기능 작업을 수행할 수 있습니다.

브랜치(branch)

위 이미지는 하나의 Branch(노란색)에서 각각 파랑, 보라의 Branch가 생성되어 동시적인 작업을 하는 것의 예시를 보여준 것입니다.

아까 관찰자를 고용하는 방법 기억하시나요? git init. 이 관찰을 시작함을 알리는 그 순간 master(또는 main)이라고 하는 Branch가 자동으로 생성됩니다. 그리고 HEAD는 master를 가리킵니다.


HEAD는 또 뭐죠..?

HEAD는 현재 포인터이자, Branch를 가리키고 있는 것입니다.

git의 HEAD 1

그림으로 설명하면 이렇습니다. 첫 commit을 하게 되면, master 브랜치에 commit(43acff..)이 생기고 HEAD는 master 브랜치를 바라보게 됩니다.

git의 HEAD 2

두 번째 commit(3fdc42..)을 하면 위와 같은 그림이 됩니다.

git의 HEAD 3

여기서 새로운 Branch(bugfix)를 만들면 위 그림처럼 됩니다(git checkout -b bugfix 또는 git switch -c bugfix를 했을 때).

HEAD가 bugfix라는 Branch를 가리키고 있다면, 여기서 commit을 하게 될 경우 bugfix라는 Branch에서 가지가 뻗어 나와 새로운 commit이 생성됩니다. master 브랜치는 변화 없이 그대로입니다.

HEAD는 책의 북마크라고 생각하면 쉽습니다. 책에 표시한 북마크처럼 왔다 갔다 할 수 있습니다. 위 과정은 뒤에 소개할 영상으로 만나볼 수 있는데요. 영상을 한번 보고 오셔도 좋습니다.


그래서 정리하자면 이렇습니다

현재 HEAD가 가리키는 곳, 그리고 Commit과 Branch의 흐름 등의 개념과 원리를 완벽히 이해한다면 어떤 문제가 발생했을 때 어떻게 해결해야 할 지 파악할 수 있습니다.

Git과 관련된 여러 기술적인 명령어, 용어들은 후순위일 뿐입니다.


추가로 아래 발표 자료와 영상을 첨부합니다. 영상에서 데이봇을 직접 만들어가며 따라 할 수 있는 사례 몇 가지가 포함되어 있는데요. 글로 사례들을 하나하나 소개하려고 하니 너무 장황해질 것 같아서 영상으로 대신하는 점 양해 바랍니다.

아래 제목들은 영상에 소개되는 사례입니다.

  1. amend로 실수 수정하기(+ 수정할 때 vim 외에 다른 editor로 바꾸기)
  2. 다른 branch의 특정 파일(폴더) 가져오기
  3. 다른 branch의 특정 commit 가져오기(충돌이 일어날 수 있음)
  4. 병합한 것을 깔끔하게 rebase로 정리하기
  5. 여러 commit 히스토리를 rebase로 정리하기(rebase를 쓰면 안 되는 시나리오)
  6. 중첩된 commit 떼어내기
  7. 아, 그때 그 commit의 그 파일로 돌아가고 싶다
  8. 잘못된 branch에 commit을 해버렸다
  9. revert로 돌아가 보기(reset과 revert의 차이점)

이상 데이블 SF팀의 한재원이었습니다.

감사합니다.