Visual Git 마스터하기: Tig를 활용한 인터랙티브 Git 강좌

모듈 1: 첫걸음 - Git과 Tig, 그리고 첫 만남

강좌 목표: Git과 Tig의 필요성을 이해하고, 직접 설치하여 첫 커밋 히스토리를 tig로 확인하는 경험을 합니다. '명령어의 결과'를 '시각적인 히스토리'로 인식하는 첫 단추를 끼웁니다.


1. Intro: 왜 Git을 써야 할까? (버전 관리의 필요성)

혹시 이런 경험 없으신가요? 최종_보고서.docx, 진짜_최종_보고서.docx, 이게진짜최종_보고서_수정1.docx...

프로젝트 파일이 복잡해질수록 우리는 파일명에 의존해 버전을 관리하곤 합니다. 하지만 이건 매우 위험하고 비효율적인 방법입니다. 만약 동료와 함께 이 파일을 수정한다면요? 누가 어떤 부분을 수정했는지, 실수로 중요한 내용을 삭제했다면 어떻게 되돌릴 수 있을까요?

Git은 바로 이 문제를 해결하는 '버전 관리 시스템(Version Control System)'입니다. Git을 사용하면 다음과 같은 강력한 능력을 얻게 됩니다.

  1. 시간 여행 (코드의 스냅샷 저장): 프로젝트의 특정 상태를 '커밋(Commit)'이라는 단위로 저장합니다. 마치 게임의 '세이브 포인트'처럼, 언제든 원하는 시점의 코드로 돌아갈 수 있습니다. 버그가 발생했을 때, 어떤 변경사항 때문에 문제가 생겼는지 쉽게 추적하고 되돌릴 수 있죠.

  2. 안전한 협업 (독립적인 작업 공간): '브랜치(Branch)'라는 기능을 통해 기존 코드를 건드리지 않고, 자신만의 독립적인 공간에서 새로운 기능을 개발하거나 버그를 수정할 수 있습니다. 작업이 완료되면 원래의 코드와 안전하게 합칠 수 있어 여러 명이 동시에 작업해도 코드가 꼬이지 않습니다.

  3. 든든한 백업 (히스토리 전체 보관): 단순 파일 백업과 다릅니다. Git은 프로젝트의 '모든 변경 이력'을 저장합니다. 내 컴퓨터의 파일이 모두 사라져도, GitHub 같은 원격 저장소에 올려두었다면 모든 히스토리와 함께 프로젝트 전체를 완벽하게 복원할 수 있습니다.

결론: Git은 더 이상 선택이 아닌, 현대 개발자에게 꼭 필요한 기본 소양입니다.


2. Intro: Tig는 무엇이고 왜 써야 할까? (Git의 시각화)

Git은 정말 강력하지만, 모든 상호작용이 터미널의 텍스트 명령어로 이루어집니다. 예를 들어, 프로젝트의 변경 이력을 보려면 git log 명령어를 사용합니다.

# git log --oneline --graph --all 의 출력 예시
* 1ab2c3d (HEAD -> feature/login) Add login button
* 4d5e6f7 Implement login logic
| * 8g9h0i1 (main) Fix typo in README
|/
* 7j8k9l0 Initial commit

이것도 유용하지만, 브랜치가 수십 개로 복잡해지면 텍스트만으로는 전체 구조를 파악하기 매우 어렵습니다.

그래서 우리는 대안을 찾습니다.

  • GUI 툴 (SourceTree, GitKraken 등): 예쁜 그래픽으로 히스토리를 보여줘서 직관적이지만, 프로그램이 무겁고, 마우스를 써야 하며, 터미널 환경을 벗어나야 하는 단점이 있습니다.
  • Tig (Text-mode Interface for Git): 바로 이 지점에서 tig가 빛을 발합니다. tig터미널 환경을 벗어나지 않으면서도 Git 히스토리를 그래픽 유저 인터페이스(GUI)처럼 시각적으로 보여주는 놀라운 도구입니다.

Tig를 써야 하는 이유:

  • 가볍고 빠릅니다: 터미널에서 즉시 실행됩니다.
  • 시각적입니다: 복잡한 브랜치 구조와 커밋 히스토리를 ASCII 아트로 그려주어 한눈에 파악할 수 있습니다.
  • 인터랙티브합니다: 단순히 보기만 하는 게 아니라, tig 화면 안에서 커밋 내용을 자세히 보고, 브랜치를 바꾸고, 심지어 커밋까지 할 수 있습니다.

결론: tig는 CLI(Command Line Interface)의 속도와 효율성 + GUI의 시각적 직관성을 모두 잡은, Git 경험을 10배 향상시키는 최고의 파트너입니다.


3. 설치 및 기본 설정

tig는 Git의 '뷰어'이므로, 당연히 Git이 먼저 설치되어 있어야 합니다.

1) Git 설치

대부분의 최신 운영체제에는 Git이 이미 설치되어 있습니다. 터미널을 열고 확인해보세요.

git --version

만약 설치되어 있지 않다면 공식 사이트를 참고하여 설치해주세요.

2) Tig 설치

각 운영체제에 맞는 패키지 매니저를 사용하면 간단히 설치할 수 있습니다.

  • macOS (Homebrew 사용):

    brew install tig
    
  • Ubuntu/Debian Linux (apt 사용):

    sudo apt-get update
    sudo apt-get install tig
    
  • Windows (scoop 또는 winget 사용): Git for Windows (Git Bash) 환경에서 사용하는 것을 권장합니다.

    # scoop 사용 시
    scoop install tig
    
    # winget 사용 시
    winget install tig
    

3) 최초 Git 설정

Git을 처음 설치했다면, 커밋에 기록될 사용자 정보(이름, 이메일)를 설정해야 합니다. 이 정보는 당신의 '디지털 서명'과 같습니다.

git config --global user.name "Your Name"
git config --global user.email "youremail@example.com"

4. 나의 첫 번째 저장소와 첫 Tig 실행 (실습)

이제 Git과 tig를 직접 경험해볼 시간입니다.

1. 실습용 폴더를 만들고 이동합니다.

mkdir my-git-project
cd my-git-project

2. 이 폴더를 Git 저장소로 초기화합니다. 이 명령을 실행하면 폴더 내에 숨김 파일인 .git 디렉토리가 생성되며, 이제 Git이 이 폴더의 모든 변경사항을 추적하기 시작합니다.

git init

3. 첫 번째 파일을 만들고, Git에게 추적하라고 알려줍니다 (add). add는 변경된 파일들을 '스테이징 영역(Staging Area)'이라는 커밋 대기실로 보내는 과정입니다.

echo "Hello, Git World!" > README.md
git add README.md

4. 첫 번째 커밋(스냅샷)을 남깁니다. commit은 스테이징 영역에 있는 파일들을 하나의 의미 있는 변경사항 묶음(스냅샷)으로 저장하고, 메시지를 남기는 행위입니다.

git commit -m "Initial commit: Add README.md"

5. 대망의 순간: tig를 실행합니다! 이제 터미널에 tig 라고만 입력하고 Enter를 누르세요.

tig

축하합니다! 다음과 비슷한 화면을 보게 될 것입니다.

[main] [HEAD] o 2023-10-27 Your Name    Initial commit: Add README.md

--
main:
  (0) Main view
  (s) Status      (l) Log           (d) Diff          (t) Tree
  (f) File log    (b) Blame         (r) Refs          (y) Stash
  (h) Help        (q) Quit

tig 화면 분석:

  • [main] [HEAD] o ...: 이것이 방금 우리가 만든 커밋입니다.
    • [main]: 현재 main 브랜치에 있다는 뜻입니다.
    • [HEAD]: 현재 작업 중인 위치(포인터)를 의미합니다.
    • o: 커밋을 나타내는 점입니다.
    • 뒤이어 날짜, 작성자(git config에서 설정한 이름), 그리고 커밋 메시지가 보입니다.

기본 조작법:

  • k 또는 위쪽 화살표: 위로 이동
  • j 또는 아래쪽 화살표: 아래로 이동
  • Enter: 선택한 커밋의 변경 내용(Diff) 보기
  • q: tig 종료하기 (또는 이전 화면으로 돌아가기)

미션:

  1. 파일을 한 번 더 수정하고, 두 번째 커밋을 만들어보세요.

    echo "Learning tig is fun!" >> README.md
    git add README.md
    git commit -m "Update README with tig info"
    
  2. 다시 tig를 실행해서 커밋이 두 줄로 쌓인 히스토리를 눈으로 직접 확인해보세요.

  3. 키보드 j, k로 커밋 사이를 오가보고, 각 커밋에서 Enter를 눌러 어떤 내용이 변경되었는지 확인해보세요.


모듈 1 요약:

당신은 이제 Git이 왜 필요한지 설명할 수 있고, tig를 이용해 내가 만든 작업의 히스토리를 '시각적으로' 확인할 수 있게 되었습니다. 텍스트로만 보던 git log와는 전혀 다른 경험이죠. 다음 모듈에서는 tig의 다양한 뷰(View)를 탐험하며 Git의 상태를 속속들이 파헤쳐 보겠습니다.


모듈 2: Tig의 눈으로 Git 바라보기 (핵심 뷰)

강좌 목표: tig의 기본 화면(Main View)을 넘어, 작업 현황(Status View), 브랜치 목록(Branch View), 코드 작성자 추적(Blame View) 등 핵심 뷰(View)를 자유자재로 넘나들며 Git의 상태를 입체적으로 파악합니다. tig 안에서 Git의 주요 명령어를 실행하는 경험을 통해 생산성을 극대화합니다.


1. Main View: 커밋 히스토리 여행하기 (심화)

모듈 1에서 우리는 tig를 실행하면 가장 먼저 보이는 Main View를 만났습니다. 이곳은 우리 프로젝트의 시간 흐름, 즉 커밋 히스토리 전체를 보여주는 지도와 같습니다. 이제 이 지도를 더 깊이 탐험해 봅시다.

핵심 인터랙션: Enter 키로 커밋 내용 확인하기

tig의 Main View에서 가장 중요한 기능 중 하나는 특정 커밋에서 정확히 무엇이 변경되었는지 즉시 확인하는 것입니다.

  1. tig를 실행하세요.
  2. 키보드의 j(아래), k(위)를 이용해 확인하고 싶은 커밋으로 이동합니다.
  3. 해당 커밋 위에서 Enter 키를 누르세요.

화면이 바뀌면서 선택한 커밋의 상세 변경 내역(Diff)이 나타납니다.

  • 초록색 + 기호: 해당 커밋에서 추가된 라인입니다.
  • 빨간색 - 기호: 해당 커밋에서 삭제된 라인입니다.

이 화면에서 다시 q 키를 누르면 이전의 Main View로 돌아옵니다. 이 j/k (이동) → Enter (상세 보기) → q (돌아가기) 흐름은 tig 사용의 가장 기본적인 리듬입니다.

실습: 모듈 1에서 만든 my-git-project 폴더로 이동하여 README.md 파일을 열고 내용을 자유롭게 추가 및 삭제한 후 새로운 커밋을 만드세요. 그 다음 tig를 실행하여 각 커밋을 오가며 Enter 키로 어떤 내용이 어떻게 변했는지 직접 확인하고 q 키로 돌아오는 연습을 반복해보세요.


2. Status View: 내 작업 현황판

지금까지 수정한 내용, 새로 추가한 파일들을 커밋하기 전에 확인하려면 git status 명령어를 사용해야 했습니다. tigStatus View는 이 과정을 tig 안에서 훨씬 직관적으로 처리하게 해줍니다.

Status View로 전환하기: s

tig의 아무 뷰에서나 s (status) 키를 눌러보세요.

# tig 화면에서 's' 키를 누른 후의 예시

[main] ?? new-file.txt
[main]  M README.md

--
status:
  (u) Update      (c) Commit        (r) Revert
  (s) Status      (l) Log           (q) Quit

화면 해석:

  • Unstaged changes: 아직 git add 하지 않은 변경사항 목록입니다. (??: 추적하지 않는 새 파일, M: 수정된 파일)
  • Staged changes: git add를 통해 커밋 대기실(스테이징 영역)에 올라간 파일 목록입니다. (지금은 비어있음)

핵심 인터랙션: u, C 로 커밋까지 한 번에!

Status View는 단순히 보여주기만 하는 것이 아니라, 직접 파일을 스테이징하고 커밋까지 할 수 있는 강력한 작업 공간입니다.

  1. u (update/unstage): 파일 스테이징/언스테이징

    • Unstaged changes 목록에 있는 파일 위에서 u 키를 누르면, 해당 파일이 Staged changes 목록으로 이동합니다. (git add <file>과 동일한 효과)
    • 반대로, Staged changes 목록의 파일 위에서 u 키를 누르면 Unstaged changes로 돌아옵니다. (git reset HEAD <file>과 동일한 효과)
  2. C (Commit): 커밋하기

    • 스테이징할 파일들을 모두 u 키로 올렸다면, 대문자 C 키를 누르세요.
    • 터미널의 기본 편집기(Vim, Nano 등)가 열리면서 커밋 메시지를 작성하는 화면이 나타납니다.
    • 메시지를 작성하고 저장 후 종료하면, 커밋이 완료됩니다!

실습 (가장 중요한 실습!):

  1. README.md 파일을 수정합니다.
  2. feature.txt 라는 새 파일을 만듭니다.
  3. tig를 실행하고 s 키를 눌러 Status View로 들어갑니다.
  4. README.mdfeature.txtUnstaged changes에 있는 것을 확인합니다.
  5. j, k로 이동하며 각 파일 위에서 u 키를 눌러 Staged changes로 옮겨보세요.
  6. C 키를 눌러 "Add new feature and update README" 라는 메시지로 커밋을 완료하세요.
  7. q 키로 Status View를 나와 Main View로 돌아가면, 방금 만든 커밋이 최상단에 추가된 것을 볼 수 있습니다. 이제 당신은 tig를 벗어나지 않고 addcommit을 모두 수행했습니다!

3. Branch View & Refs View: 가지들 한눈에 보기

프로젝트가 커지면 여러 브랜치를 동시에 관리하게 됩니다. tig는 흩어져 있는 모든 브랜치와 태그를 한 곳에서 보여줍니다.

  • b (branch): 로컬 브랜치 목록을 보여줍니다.
  • r (refs): 로컬 브랜치, 원격 브랜치, 태그 등 모든 참조(Reference)를 보여줍니다. 보통 r을 더 자주 씁니다.

Refs View로 전환하기: r

tig 화면에서 r 키를 눌러보세요.

# 'r' 키를 누른 후의 예시

[refs]
  HEAD
  refs/heads/main
  refs/heads/feature/login
  refs/remotes/origin/main
  refs/tags/v1.0

핵심 인터랙션: Enter로 특정 브랜치 히스토리 필터링하기

Refs View의 진정한 힘은 '필터링' 기능에 있습니다.

  1. r 키로 Refs View를 엽니다.
  2. 보고 싶은 브랜치(예: refs/heads/feature/login)로 이동합니다.
  3. Enter 키를 누릅니다.

화면이 Main View로 바뀌면서, 오직 feature/login 브랜치에 해당하는 커밋 히스토리만 필터링되어 보입니다. 전체 히스토리를 다시 보고 싶다면, r 키로 돌아가 HEAD에서 Enter를 누르면 됩니다.


4. Blame View: 이 코드는 누가, 언제 수정했을까?

협업 시 "이 코드는 어떤 의도로 작성되었을까?" 궁금할 때가 많습니다. Blame View는 파일의 각 라인이 마지막으로 수정된 커밋 정보(작성자, 날짜, 커밋 해시)를 보여주는 강력한 추적 도구입니다.

Blame View로 진입하기: Main View → Diff View → B

Blame View는 진입 방법이 조금 다릅니다.

  1. tig의 Main View에서 특정 커밋을 선택하고 **Enter**를 눌러 Diff View로 들어갑니다.
  2. 파일 변경 내역이 보이는 이 화면에서, 추적하고 싶은 파일 섹션에 커서가 있을 때 대문자 B 키를 누릅니다.

이제 해당 파일의 전체 내용이 나타나며, 각 줄의 왼쪽에 누가, 언제, 어떤 커밋에서 이 라인을 수정했는지에 대한 정보가 표시됩니다. 버그의 원인이 된 코드를 찾았을 때, 이 기능을 사용하면 해당 변경사항의 맥락을 파악하고 담당자에게 질문하기가 매우 용이해집니다.


모듈 2 요약:

당신은 이제 tig의 4대 핵심 뷰(Main, Status, Refs, Blame)를 모두 다룰 수 있게 되었습니다. 단순히 히스토리를 보는 것을 넘어, tig 안에서 직접 파일을 스테이징하고 커밋하며, 브랜치를 필터링하고, 코드의 역사를 추적하는 '능동적인' 사용자 되었습니다. 이제 tig를 통해 Git의 가장 중요하고 흥미로운 기능인 '브랜치'를 시각적으로 다루어 볼 준비가 되었습니다. 다음 모듈 3에서는 브랜치를 만들고 합치는 과정을 tig로 직접 눈으로 보며 마스터해 보겠습니다.


모듈 3: 브랜치 전략, Tig로 시각화하기

강좌 목표: Git의 꽃이라 불리는 '브랜치'의 개념을 완벽히 이해합니다. 브랜치를 만들고, 이동하고, 합치는(Merge, Rebase) 모든 과정을 tig의 ASCII 그래프를 통해 시각적으로 추적하며, 복잡한 히스토리를 깔끔하게 관리하는 능력을 기릅니다.


1. 브랜치, 왜 써야 할까? (독립적인 작업 공간)

팀 프로젝트를 한다고 상상해 보세요. A는 로그인 기능을 만들고, B는 메인 페이지 디자인을 개선하고 있습니다. 만약 두 사람이 main이라는 단 하나의 브랜치에서 동시에 작업한다면 어떻게 될까요?

  • 아직 미완성인 A의 로그인 코드가 B의 작업에 영향을 줄 수 있습니다.
  • 두 사람이 같은 파일을 수정하면 코드가 엉망이 될 수 있습니다. (충돌, Conflict)
  • 갑자기 긴급한 버그를 수정해야 할 때, 현재 작업 중인 내용을 모두 되돌려야 하는 재앙이 발생합니다.

**브랜치(Branch)**는 이런 문제를 해결하기 위해, 기존 코드(보통 main 브랜치)의 특정 시점에서 새로운 가지를 만들어 독립적인 작업 공간을 제공하는 기능입니다.

  • 안전성: 각자 자신의 브랜치에서 작업하므로 다른 사람의 작업에 영향을 주지 않습니다.
  • 동시성: 여러 기능을 동시에 개발할 수 있습니다.
  • 유연성: 기능 개발, 버그 수정, 테스트 등 목적에 따라 브랜치를 만들고, 작업이 끝나면 원래 브랜치와 합치거나 필요 없으면 버릴 수 있습니다.

결론: 브랜치는 안전하고 효율적인 협업을 위한 Git의 핵심 기능입니다.


2. 브랜치 생성과 전환, 그리고 시각화

이제 직접 브랜치를 만들고 tig로 어떻게 보이는지 확인해 봅시다.

1. 새 브랜치 생성 및 이동 (Checkout) 현재 우리는 main 브랜치에 있습니다. "로그인 기능 개발"을 위한 feature/login 브랜치를 만들어 보겠습니다.

# 'feature/login' 브랜치를 생성하고, 그 브랜치로 즉시 이동(-b 옵션)
git checkout -b feature/login

git branch feature/logingit checkout feature/login 두 명령을 합친 것입니다.

2. 핵심: tig --all 로 전체 히스토리 보기 그냥 tig만 실행하면 현재 브랜치(feature/login)의 히스토리만 보입니다. 모든 브랜치를 함께 보려면 --all 옵션을 사용해야 합니다.

tig --all

tig 화면을 보면, 이제 mainfeature/login이 같은 커밋을 가리키고 있습니다. (HEAD -> feature/login, main) 처럼 표시될 것입니다. HEAD는 "내가 지금 작업하는 곳"을 가리키는 포인터이며, 이제 feature/login을 따라다닙니다.

3. 새 브랜치에서 커밋하기 feature/login 브랜치에서 로그인과 관련된 작업을 하고 커밋을 만들어 봅시다.

echo "Login form added" > login.html
git add login.html
git commit -m "Feat: Add login form structure"

4. 히스토리가 갈라지는 순간 확인하기 다시 tig --all을 실행해 보세요. 마법 같은 순간이 펼쳐집니다.

# 'tig --all' 실행 예시
* 1a2b3c4 (HEAD -> feature/login) Feat: Add login form structure
|
* d4e5f6g (main) Update README with tig info
...
  • ASCII 그래프: feature/login 브랜치가 main 브랜치에서 분기되어 새로운 커밋(1a2b3c4)을 쌓아 올린 모습이 세로선 | 과 별표 * 로 명확하게 보입니다.
  • 포인터: HEADfeature/login은 새 커밋으로 이동했지만, main은 예전 커밋에 그대로 머물러 있습니다.

이것이 바로 tig의 힘입니다. 텍스트 명령어만으로는 상상해야 했던 '브랜치의 분기'를 직접 눈으로 확인하는 순간입니다.


3. Merge (병합): 가지를 하나로 합치기

feature/login 브랜치에서 기능 개발이 끝났다고 가정합시다. 이제 이 변경사항을 main 브랜치에 합쳐야 합니다. 이것을 **Merge(병합)**라고 합니다.

1. 합칠 대상 브랜치로 이동 main 브랜치에 feature/login을 합칠 것이므로, main 브랜치로 돌아가야 합니다.

git checkout main

2. Merge 명령어 실행 main 브랜치에서, 합치고 싶은 브랜치(feature/login)를 지정하여 병합합니다.

git merge feature/login

3. Merge 결과, tig로 확인하기 다시 tig --all 을 실행해 보세요.

# 'tig --all' 실행 예시
*   5h6i7j8 (HEAD -> main) Merge branch 'feature/login'
|\
| * 1a2b3c4 (feature/login) Feat: Add login form structure
|/
* d4e5f6g Update README with tig info
...
  • Merge Commit: "Merge branch 'feature/login'" 이라는 메시지를 가진 새로운 Merge Commit(5h6i7j8)이 생성되었습니다. 이 커밋은 두 개의 부모 커밋(기존 main의 마지막 커밋과 feature/login의 마지막 커밋)을 가집니다.
  • 그래프: 갈라졌던 두 브랜치가 Merge Commit을 통해 다시 하나로 합쳐지는 모습이 |\|/ 같은 그래프로 명확하게 보입니다. mainHEAD 포인터는 이제 이 Merge Commit을 가리킵니다.

4. Rebase (재배치): 히스토리 깔끔하게 만들기

Rebase는 Merge와 같이 브랜치를 합치는 또 다른 방법이지만, 동작 방식이 완전히 다릅니다. Rebase는 말 그대로 브랜치의 **베이스(Base, 기준점)를 재배치(Re-base)**하여 히스토리를 한 줄로 깨끗하게 만듭니다.

상황 설정: Merge를 되돌리고 Rebase를 해보기 위해, 방금 한 Merge를 취소해 봅시다. (tig에서 Merge Commit 바로 이전 커밋의 해시(e.g., d4e5f6g)를 확인하세요.)

# 이전 상태로 되돌리기 (주의: 이미 원격에 push한 커밋에는 사용하면 안 됩니다!)
git reset --hard d4e5f6g

1. Rebase 명령어 실행 feature/login 브랜치의 변경사항들을, main 브랜치의 최신 커밋 위로 옮겨 붙이겠습니다. 먼저 feature/login 브랜치로 이동해야 합니다.

git checkout feature/login
git rebase main

2. Rebase 결과, tig로 확인하기 tig --all 로 결과를 확인하면, Merge와는 완전히 다른 모습에 놀라게 될 것입니다.

# 'tig --all' 실행 예시 (Rebase 후)
* 1a2b3c4' (HEAD -> feature/login) Feat: Add login form structure
* d4e5f6g (main) Update README with tig info
...
  • 선형 히스토리: Merge처럼 히스토리가 갈라지고 합쳐지는 지저분한 그래프가 사라지고, 마치 처음부터 main 브랜치에서 순서대로 작업한 것처럼 히스토리가 한 줄로 깔끔하게 정리되었습니다.
  • 새로운 커밋 해시: feature/login의 커밋이었던 1a2b3c41a2b3c4' 처럼 새로운 해시값을 가진 커밋으로 재작성되었습니다. (Rebase는 기존 커밋을 복사해서 새로 만드는 과정이기 때문입니다.)

3. Fast-forward Merge 이제 main 브랜치로 돌아가서 merge를 해보세요.

git checkout main
git merge feature/login

tig --all 을 보면, 별도의 Merge Commit 없이 main 포인터가 feature/login의 위치로 '빨리 감기(Fast-forward)'처럼 쓱 이동한 것을 볼 수 있습니다. 히스토리가 매우 깨끗하게 유지됩니다.

Merge vs Rebase: 언제 무엇을 쓸까?

  • Merge: "두 브랜치를 합쳤다"는 사실 자체를 히스토리에 명확히 남기고 싶을 때 사용합니다. 팀의 공식적인 히스토리에 적합합니다.
  • Rebase: 브랜치가 너무 지저분하게 뻗어 나가는 것을 방지하고, 최종적으로 main에 합치기 전에 내 작업 히스토리를 깔끔하게 정리하고 싶을 때 사용합니다. (특히 개인 브랜치에서)

경고: 이미 팀원과 공유한(원격 저장소에 push한) 브랜치에서는 절대 rebase를 사용하면 안 됩니다. 다른 팀원의 히스토리와 충돌하여 큰 혼란을 일으킬 수 있습니다.


모듈 3 요약:

당신은 이제 Git 브랜치의 핵심인 분기(Branching), 병합(Merge), 재배치(Rebase)의 개념을 tig를 통해 눈으로 직접 확인하며 완벽히 이해했습니다. 지저분한 Merge 히스토리와 깔끔한 Rebase 히스토리의 차이를 시각적으로 비교함으로써, 언제 어떤 전략을 써야 할지 판단하는 능력을 갖추게 되었습니다. 이제 이 로컬에서의 경험을 바탕으로, 다음 모듈에서는 다른 사람과 협업하기 위한 '원격 저장소'와의 상호작용을 배워보겠습니다.


모듈 4: 협업의 시작 - 원격 저장소와 Tig

강좌 목표: 로컬 저장소의 작업을 GitHub과 같은 원격 저장소와 동기화하는 방법을 배웁니다. push, pull, fetch 명령어의 차이점을 tigorigin/main과 같은 원격 브랜치 포인터의 움직임을 통해 명확하고 직관적으로 이해합니다. 이를 통해 팀원들과 코드를 안전하게 공유하고 최신 상태를 유지하는 능력을 기릅니다.


1. 원격 저장소(Remote) 연동

지금까지 우리의 모든 작업(커밋, 브랜치)은 개인 컴퓨터, 즉 **로컬 저장소(Local Repository)**에만 저장되어 있습니다. 협업을 하려면 이 작업 내역을 모든 팀원이 접근할 수 있는 중앙 서버, 즉 **원격 저장소(Remote Repository)**에 올려야 합니다. 가장 대표적인 원격 저장소 서비스가 바로 GitHub입니다.

1. GitHub에 새 원격 저장소 생성하기

  1. GitHub에 접속하여 로그인합니다.
  2. 우측 상단의 '+' 버튼 또는 'New' 버튼을 눌러 새 저장소를 만듭니다.
  3. 저장소 이름은 로컬 프로젝트와 동일하게 my-git-project로 설정합니다.
  4. 중요: Initialize this repository with a README 옵션은 체크 해제합니다. 우리는 이미 로컬에 작업 내역이 있기 때문입니다.
  5. 'Create repository' 버튼을 클릭합니다.

2. 로컬 저장소에 원격 저장소 주소 등록하기

저장소가 생성되면, GitHub는 친절하게도 "...or push an existing repository from the command line" 이라는 안내를 보여줍니다. 이 안내문의 명령어를 사용하면 됩니다.

# 'origin'이라는 별명으로 원격 저장소 주소를 등록합니다.
git remote add origin https://github.com/YourUsername/my-git-project.git

# 등록된 원격 저장소 정보를 확인합니다.
git remote -v
  • origin: 원격 저장소 주소에 붙이는 기본 별명입니다. 다른 이름으로 지정할 수도 있지만, origin이 관례입니다.
  • 이제 Git은 origin이라는 단어가 GitHub에 있는 우리 저장소를 의미한다는 것을 압니다.

2. Push & Pull: 내 코드를 공유하고, 동료 코드를 가져오기

Push: 내 로컬 작업을 원격 저장소에 올리기 (업로드)

push는 내 컴퓨터(로컬)의 커밋들을 원격 저장소(origin)로 전송하여 팀원들과 공유하는 명령어입니다.

# 현재 로컬의 'main' 브랜치를 원격 'origin'의 'main' 브랜치로 push 합니다.
# -u 옵션은 앞으로 이 로컬 브랜치가 원격의 해당 브랜치를 추적하도록 설정하는 것입니다. (최초 한번만)
git push -u origin main
  • 핵심: tig로 Push 결과 확인하기**

push가 성공적으로 완료된 후, tig --all을 실행해 보세요.

# 'tig --all' 실행 예시 (Push 후)
* ... (HEAD -> main, origin/main) Latest commit
...
  • origin/main 포인터 등장: 이전에는 보이지 않던 origin/main 이라는 새로운 포인터가 생겼습니다! 이것은 원격 저장소 originmain 브랜치가 어디까지 알고 있는지를 나타냅니다.
  • 동일한 위치: push를 했기 때문에, 로컬 main과 원격 origin/main은 현재 동일한 최신 커밋을 가리키고 있습니다.

Pull: 원격 저장소의 최신 작업을 내 로컬로 가져오기 (다운로드 + 병합)

이제 다른 팀원이 새로운 작업을 push했다고 상상해 봅시다. 우리는 그 최신 내용을 우리 로컬 컴퓨터로 가져와야 합니다. 이 때 pull 명령어를 사용합니다.

(실습을 위해 GitHub 사이트에서 직접 README.md 파일을 수정하여 새 커밋을 만들어 봅시다.)

  1. GitHub의 my-git-project 저장소 페이지로 이동합니다.
  2. README.md 파일을 클릭하고, 연필 모양(Edit) 아이콘을 눌러 내용을 수정한 뒤, "Commit changes" 버튼을 눌러 커밋합니다.

이제 원격 저장소는 우리 로컬보다 한 발 앞서 나간 상태입니다. 이 변경사항을 가져와 봅시다.

git pull origin main
  • 핵심: tig로 Pull 결과 확인하기**

pull 명령 후 tig --all을 다시 실행하면,

# 'tig --all' 실행 예시 (Pull 후)
* ... (HEAD -> main, origin/main) Commit from GitHub
* ... Previous local commit
...
  • 포인터 동기화: pull을 통해 원격 저장소의 새 커밋이 로컬로 다운로드되고, 로컬 main 브랜치에 병합(merge)되었습니다. 그 결과, HEAD, main, origin/main 포인터가 모두 다시 최신 커밋을 함께 가리키게 됩니다.

3. Fetch vs Pull 명확히 이해하기

많은 입문자들이 fetchpull의 차이를 헷갈려 합니다. tig는 이 둘의 차이를 명확하게 보여주는 최고의 교사입니다.

결론부터 말하면: git pull = git fetch + git merge 입니다.

fetch: 일단 가져와서 보기만 할게 (다운로드)

fetch는 원격 저장소의 최신 변경 내역을 로컬로 가져오되, 내 작업 브랜치(main)와 자동으로 합치지는 않습니다. 단지 "원격 저장소는 이런 변경사항이 있구나" 하고 정보만 업데이트하는 것입니다.

pull: 가져와서 합치기까지 할게 (다운로드 + 병합)

pullfetch를 수행한 다음, 가져온 내용을 현재 내 작업 브랜치와 즉시 merge까지 해버립니다.

  • 실습: tigfetchpull의 차이 눈으로 보기**
  1. 상황 만들기: 다시 GitHub 사이트에서 README.md 파일을 한번 더 수정하고 커밋합니다. 이제 원격 저장소가 다시 앞서 나갑니다.

  2. fetch 실행: 이번에는 pull 대신 fetch를 실행합니다.

    git fetch origin
    
  3. tigfetch 결과 확인: tig --all을 실행해 보세요. 이것이 가장 중요한 순간입니다.

    # 'tig --all' 실행 예시 (Fetch 후)
    * ... (origin/main) New commit from GitHub
    |
    * ... (HEAD -> main) My previous commit
    ...
    
    • 포인터 분리!
      • origin/main 포인터는 GitHub에서 새로 만든 커밋으로 혼자 이동했습니다. 원격의 최신 정보를 반영한 것이죠.
      • 하지만 HEAD -> main 포인터는 이전 커밋에 그대로 머물러 있습니다! fetch는 내 작업을 전혀 건드리지 않았다는 명확한 증거입니다.
  4. 수동으로 Merge 하기: 이제 main 브랜치에 origin/main의 변경사항을 직접 합쳐봅시다.

    git merge origin/main
    
  5. tig로 최종 결과 확인: tig --all을 다시 실행하면, main 포인터가 origin/main의 위치로 이동하며 합쳐지고, 두 포인터가 다시 같은 커밋을 가리키는 것을 볼 수 있습니다. 이 결과는 git pull을 실행했을 때와 동일합니다.

언제 fetch를 쓸까? 동료가 어떤 작업을 했는지 내 로컬 브랜치에 영향을 주지 않고 미리 확인하고 싶을 때 매우 유용합니다. fetch로 변경사항을 가져온 뒤, tigorigin/main의 히스토리를 쭉 훑어보고, 준비가 되었을 때 merge를 실행하는 것이 훨씬 안전한 워크플로우입니다.


모듈 4 요약:

당신은 이제 로컬 작업을 원격 저장소에 공유(push)하고, 팀원의 작업을 내 로컬로 가져오는(pull) 방법을 마스터했습니다. 더 나아가, tig의 원격 브랜치 포인터(origin/main)의 움직임을 통해 fetchpull의 근본적인 차이점을 시각적으로 완벽하게 이해했습니다. 이제 당신은 Git을 이용한 기본적인 팀 협업을 수행할 준비가 되었습니다. 다음 모듈에서는 과거의 실수를 바로잡거나, 필요한 커밋만 쏙쏙 가져오는 등 Git의 강력한 시간 여행 기술들을 배워보겠습니다.


모듈 5: 시간 여행과 문제 해결 (고급 스킬)

강좌 목표: 잘못된 커밋을 안전하게 되돌리고(revert), 과거의 특정 시점으로 돌아가며(reset), 다른 브랜치의 유용한 커밋만 가져오고(cherry-pick), 지저분한 커밋 히스토리를 재구성하는(rebase -i) 등 Git의 강력한 시간 여행 기술들을 마스터합니다. 이 모든 위험할 수 있는 작업들을 tig를 통해 시각적으로 확인하며 안전하고 자신감 있게 수행하는 능력을 기릅니다.


1. revert: 안전하게 과거 되돌리기

실수로 버그가 있는 코드를 커밋하고 push까지 해버렸다면 어떻게 할까요? 히스토리를 강제로 삭제하는 reset은 팀원들에게 혼란을 줄 수 있어 위험합니다. 이럴 때 **revert**를 사용합니다. revert는 특정 커밋의 변경사항을 취소하는 새로운 커밋을 만들어 문제를 해결합니다.

1. 문제 상황 만들기 먼저, 버그를 포함한 커밋을 만들어 원격 저장소에 push까지 해봅시다.

echo "This is a critical bug!" >> bug.txt
git add bug.txt
git commit -m "Feat: Add new feature (with a bug)"
git push origin main

2. tig로 되돌릴 커밋 확인 및 해시 복사 tig를 실행하여 방금 만든 "Feat: Add new feature (with a bug)" 커밋을 찾으세요. 커밋 라인의 맨 앞에 있는 a1b2c3d 같은 7자리의 **커밋 해시(hash)**가 필요합니다. tig 화면에서 해당 커밋 위에 커서를 놓고 y 키를 누르면 해시 값이 클립보드에 복사됩니다.

3. revert 실행 복사한 해시를 사용하여 revert 명령을 실행합니다.

# a1b2c3d 부분에 방금 복사한 해시를 붙여넣으세요.
git revert a1b2c3d

이 명령을 실행하면 커밋 메시지 편집기가 열립니다. 기본 메시지("Revert '...'")를 그대로 사용하거나 수정 후 저장하고 종료합니다.

4. tig로 결과 확인 tig를 다시 실행해 보세요.

# 'tig' 실행 예시 (Revert 후)
* 4e5f6g7 (HEAD -> main) Revert "Feat: Add new feature (with a bug)"
* a1b2c3d (origin/main) Feat: Add new feature (with a bug)
...
  • 새로운 Revert 커밋: 기존의 버그 커밋(a1b2c3d)은 그대로 남아있고, 그 위에 "Revert..."라는 새로운 커밋(4e5f6g7)이 쌓였습니다.
  • 안전한 히스토리:Revert 커밋의 내용을 Enter로 확인해 보면, 버그 커밋에서 했던 변경사항을 정확히 반대로 수행(파일을 삭제하거나, 추가했던 내용을 삭제)한 것을 볼 수 있습니다. 기존 히스토리를 삭제하지 않고 새로운 커밋을 추가하여 문제를 해결했기 때문에 팀원들과 공유하기에 매우 안전합니다.

2. reset: 강력하지만 위험한 과거 바꾸기

reset은 브랜치 포인터를 특정 과거 커밋으로 강제로 이동시켜, 그 이후의 커밋들을 히스토리에서 사라지게 만드는 강력한 도구입니다. 아직 push하지 않은, 로컬에만 있는 실수를 바로잡을 때 매우 유용합니다.

--soft, --mixed(기본값), --hard 옵션의 차이

  • --soft: 커밋만 취소. 변경된 파일 내용은 스테이징 영역(git add 한 상태)에 그대로 남아있음.

  • --mixed: 커밋과 스테이징을 모두 취소. 변경된 파일 내용은 워킹 디렉토리(수정만 한 상태)에 남아있음.

  • --hard: (주의!) 커밋, 스테이징, 워킹 디렉토리의 변경 내용을 모두 삭제. 해당 시점 이후의 모든 작업이 영구적으로 사라짐.

  • 실습: reset --hard의 파괴력 tig로 확인하기**

  1. 상황 만들기: 로컬에서만 두 개의 잘못된 커밋을 만들었다고 가정합시다.

    echo "Mistake 1" > mistake.txt
    git add . && git commit -m "Oops, mistake 1"
    echo "Mistake 2" >> mistake.txt
    git add . && git commit -m "Oops, mistake 2"
    
  2. tig로 현재 상태와 돌아갈 지점 확인 tig를 켜서 방금 만든 두 개의 "Oops" 커밋과, 그 이전의 정상적인 커밋을 확인하세요. 정상 커밋의 해시를 y로 복사합니다.

  3. reset --hard 실행

    # 복사한 정상 커밋의 해시를 붙여넣으세요.
    git reset --hard <정상_커밋_해시>
    
  4. tig로 결과 확인 tig를 다시 실행하면, "Oops" 커밋 두 개가 히스토리에서 완전히 사라진 것을 볼 수 있습니다. ls 명령어로 파일 목록을 봐도 mistake.txt 파일이 사라졌습니다. reset --hard는 이렇게 과거를 없었던 일로 만들어 버립니다.

경고: reset은 히스토리를 재작성하므로, 이미 팀원과 공유한(push한) 커밋에는 절대 사용하지 마세요. 꼭 필요하다면 revert를 사용해야 합니다.


3. cherry-pick: 필요한 커밋만 쏙쏙 가져오기

feature/A 브랜치에서 작업한 5개의 커밋 중, 딱 1개의 커밋(예: 유용한 유틸리티 함수)만 지금 당장 main 브랜치에도 적용하고 싶을 때가 있습니다. 이럴 때 **cherry-pick**을 사용하면 해당 커밋 하나만 '체리처럼 쏙 따서' 내 브랜치에 복사해올 수 있습니다.

1. 상황 만들기

  • feature/new-util 이라는 브랜치를 만듭니다.

  • 해당 브랜치에서 2개의 커밋을 만듭니다. (하나는 불필요한 커밋, 다른 하나는 유용한 커밋)

    git checkout -b feature/new-util
    echo "useless" > temp.txt && git add . && git commit -m "WIP: temporary work"
    echo "export const useful = () => {}" > util.js && git add . && git commit -m "Feat: Add a very useful utility"
    

2. tig로 가져올 커밋 확인 및 해시 복사

  • main 브랜치로 돌아옵니다. (git checkout main)
  • tig --all을 실행하여 feature/new-util 브랜치를 봅니다.
  • 가져오고 싶은 "Feat: Add a very useful utility" 커밋을 찾아 해시를 y로 복사합니다.

3. cherry-pick 실행

git cherry-pick <복사한_유틸리티_커밋_해시>

4. tig로 결과 확인 tig를 실행해 보면, main 브랜치의 최상단에 "Feat: Add a very useful utility" 커밋이 그대로 복사되어 들어온 것을 볼 수 있습니다. feature/new-util 브랜치의 불필요한 커밋은 가져오지 않았습니다.


4. rebase -i: 인터랙티브 리베이스로 커밋 재구성하기

push 하기 전에, 너무 자잘하게 만든 커밋들을 하나의 의미 있는 커밋으로 합치거나(squash), 커밋 메시지를 수정하고 싶을 때 **인터랙티브 리베이스(rebase -i)**를 사용합니다. 히스토리를 예술 작품처럼 다듬는 과정입니다.

1. 상황 만들기: 로컬에서 자잘한 커밋 3개를 만들었다고 가정합니다.

echo "1" > work.txt && git add . && git commit -m "fix: typo"
echo "2" >> work.txt && git add . && git commit -m "add part of feature"
echo "3" >> work.txt && git add . && git commit -m "complete the feature and fix style"

2. tig로 재구성할 커밋 범위 확인 tig를 켜면 방금 만든 3개의 너저분한 커밋이 보입니다. 이 3개의 커밋을 정리할 것입니다. 현재 위치(HEAD)로부터 3개 이전까지를 의미하는 HEAD~3을 범위로 사용합니다.

3. rebase -i 실행

git rebase -i HEAD~3

4. 인터랙티브 화면에서 히스토리 편집 이 명령을 실행하면, 다음과 같은 편집기 화면이 나타납니다.

pick a1b2c3d fix: typo
pick b2c3d4e add part of feature
pick c3d4e5f complete the feature and fix style

# Commands:
# p, pick = use commit
# s, squash = use commit, but meld into previous commit
...
  • 맨 위 커밋(a1b2c3d)은 pick(그대로 둠)으로 놔두고,

  • 아래 두 개의 커밋 앞 단어 picks (또는 squash)로 바꿉니다.

  • picks 로 변경:

    pick a1b2c3d fix: typo
    s b2c3d4e add part of feature
    s c3d4e5f complete the feature and fix style
    
  • 편집기를 저장하고 종료하면, 3개 커밋의 메시지를 하나로 합치는 두 번째 편집기 창이 열립니다. 여기서 최종 커밋 메시지(예: "Feat: Implement the full feature")를 깔끔하게 작성하고 저장, 종료합니다.

5. tig로 결과 확인 tig를 다시 실행해 보세요. 너저분했던 3개의 커밋이 하나의 깔끔한 커밋으로 합쳐진 마법 같은 결과를 볼 수 있습니다. 이제 이 잘 정리된 커밋을 push하면 됩니다.


모듈 5 요약:

당신은 이제 Git의 가장 강력한 시간 여행 도구들을 자유자재로 다룰 수 있게 되었습니다. tig를 나침반 삼아, 안전하게 실수를 되돌리고(revert), 로컬 히스토리를 정리하며(reset, rebase -i), 필요한 작업만 쏙쏙 가져오는(cherry-pick) 방법을 체득했습니다. 이는 단순한 명령어 사용을 넘어, 복잡한 프로젝트 히스토리를 자신감 있게 관리하는 'Git 전문가'로 가는 중요한 발판입니다. 마지막 모듈에서는 이 모든 기술을 내 손에 맞게 최적화하는 방법을 배우겠습니다.


모듈 6: Tig, 나만의 무기로 만들기 (최적화 및 활용)

강좌 목표: 지금까지 배운 tig의 기능들을 조합하여 자신만의 효율적인 Git 워크플로우를 만듭니다. 자주 사용하는 단축키와 팁을 익히고, .tigrc 설정 파일을 통해 tig의 외형과 동작을 커스터마이징하여 생산성을 극대화합니다. tig를 '그냥 사용하는 도구'에서 '내 손에 꼭 맞는 무기'로 진화시킵니다.


1. 나만의 Tig 워크플로우 만들기

숙련된 개발자는 매일 반복하는 작업을 자신만의 루틴으로 만듭니다. tig를 사용하면 Git과 관련된 거의 모든 일상 업무를 터미널을 벗어나지 않고, 일관된 흐름으로 처리할 수 있습니다.

예시: "나의 하루" 워크플로우

아침에 출근해서 어제 하던 작업을 이어가는 상황을 가정해 봅시다.

  1. (S) 상태 확인: 터미널을 열고 프로젝트 폴더에서 tig를 실행합니다. 가장 먼저 s 키를 눌러 Status View로 들어갑니다.

    • 어제 작업하다가 커밋하지 않은 파일은 없는지? (Unstaged changes)
    • 실수로 추가된 불필요한 파일은 없는지?
    • Action: tig 화면에서 바로 어제의 변경 사항을 확인합니다.
  2. (F) 동료 작업 확인: **q**로 Main View로 돌아와, F 키(대문자)를 누릅니다. (git fetch와 동일)

    • tig가 원격 저장소(origin)의 최신 정보를 가져옵니다.
    • origin/main 포인터가 앞으로 이동했다면, 밤새 동료가 새로운 작업을 push했다는 의미입니다.
    • Action: j, korigin/main까지 이동하며 동료의 커밋 내용을 Enter로 훑어봅니다. 내 작업과 충돌할 부분이 있는지 미리 파악할 수 있습니다.
  3. (M) 최신 내용 병합: origin/main의 내용을 내 로컬 브랜치로 합칩니다.

    • 안전한 방법: tig 화면에서 M 키(대문자)를 누릅니다. Merge...? 프롬프트가 뜨면 origin/main을 입력하고 엔터. (git merge origin/main과 동일)
    • Rebase 선호 시: 터미널에서 git rebase origin/main을 실행하고 tig로 결과를 확인합니다.
  4. (작업 & 커밋): 이제 내 할 일을 합니다. 코드를 작성하고 수정합니다.

    • 어느 정도 작업이 완료되면, 다시 tig를 켜고 s (Status View)로 갑니다.
    • u 키로 스테이징하고, C (대문자) 키로 커밋합니다. (모듈 2에서 배운 내용) 이 과정을 반복합니다.
  5. (P) 작업 내용 공유: 퇴근 전, 오늘 작업한 내용을 push합니다.

    • tig 화면에서 P 키(대문자)를 누릅니다. Push...? 프롬프트가 뜨면 엔터를 누릅니다. (git push와 동일)

이 워크플로우의 장점: tig 라는 단일 인터페이스 안에서 상태 확인 → 동료 작업 확인 → 병합 → 내 작업 → 커밋 → 공유까지의 모든 사이클이 끊김 없이 이어집니다. 컨텍스트 전환 비용이 줄어들어 개발에 더 집중할 수 있습니다.


2. 유용한 단축키와 팁 (생산성 부스터)

tig에는 숨겨진 보석 같은 기능들이 많습니다. 이것들만 알아도 작업 속도가 몇 배는 빨라집니다.

  • / (검색): Main View에서 /를 누르고 키워드를 입력하면, 커밋 메시지, 작성자, 파일명 등에서 해당 키워드를 포함한 커밋을 찾아 하이라이트해 줍니다. n (다음), N (이전)으로 검색 결과 간 이동이 가능합니다. "특정 티켓 번호(#123)와 관련된 모든 커밋 찾기" 등에 매우 유용합니다.

  • @<file> (특정 파일 히스토리 보기): tig를 실행할 때 파일 경로를 함께 주면, 해당 파일의 변경 이력만 필터링해서 보여줍니다.

    tig -- README.md
    # 또는 tig 실행 후, :log README.md 입력
    

    README.md 파일이 언제, 누구에 의해, 어떻게 변해왔는지 한눈에 볼 수 있습니다.

  • L (상세 로그 보기): Main View에서 커밋을 선택하고 L (대문자) 키를 누르면 git show 명령어처럼 해당 커밋의 메타데이터와 전체 변경 내용을 한 번에 보여줍니다.

  • h (도움말): 어떤 뷰에서든 h 키를 누르면 해당 뷰에서 사용할 수 있는 모든 단축키 목록을 보여줍니다. tig의 모든 기능을 외울 필요가 없습니다. 궁금할 땐 h를 누르세요.


3. .tigrc 파일로 커스터마이징하기

tig의 진정한 화룡점정은 .tigrc 설정 파일을 통해 나만의 도구로 튜닝하는 것입니다. 이 파일은 보통 홈 디렉토리(~/.tigrc)에 만듭니다.

1. .tigrc 파일 생성

touch ~/.tigrc

이제 이 파일을 텍스트 편집기로 열어 원하는 설정을 추가하면 됩니다.

2. 추천 커스터마이징 설정 예시

아래 내용을 ~/.tigrc 파일에 복사/붙여넣기하고 tig를 다시 실행해 보세요.

# .tigrc 예시

# 1. Main View에 브랜치/태그 정보를 항상 표시 (가장 유용한 설정!)
set main-view = date author:20,width=20 refs commit-title:*,wrap
set line-graphics = utf-8  # ASCII 그래프를 더 예쁜 문자로 표시

# 2. 작성자 이름 대신 이메일 주소 일부를 표시 (옵션)
# set author-display = email

# 3. 자주 사용하는 명령 단축키로 바인딩하기
# Main View에서 대문자 P를 누르면 git push가 바로 실행됨
bind main P !git push
# Main View에서 대문자 F를 누르면 git fetch --prune이 바로 실행됨
# (--prune: 원격에서 삭제된 브랜치를 로컬에서도 깔끔하게 정리해주는 옵션)
bind main F !git fetch --prune

# 4. 색상 테마 변경하기 (기본, blue, black 등)
# set color-scheme = blue

설정 설명:

  • set main-view = ...: tig의 메인 화면에 표시될 정보의 종류와 너비를 지정합니다. 위 설정은 refs(브랜치/태그)를 항상 보여주게 하여 tig --all을 매번 입력할 필요가 없게 만듭니다.
  • set line-graphics = utf-8: |, * 같은 기본 ASCII 문자를 , 등 더 보기 좋은 특수문자로 바꿔줍니다.
  • bind <view> <key> <command>: 특정 뷰(main, status 등)에서 특정 키(<key>)를 눌렀을 때 실행될 외부 명령어(<command>)를 지정합니다. !git push처럼 앞에 !를 붙이면 쉘 명령을 실행할 수 있습니다. 위 예시는 P키로 푸시, F키로 페치를 바로 실행하게 해줍니다.

맺음말: 이제 Git이 두렵지 않습니다

이 강좌를 통해 여러분은 Git의 기본적인 개념부터 브랜치 전략, 협업, 그리고 과거를 제어하는 고급 기술까지 tig라는 훌륭한 나침반과 함께 항해했습니다.

  • 여러분은 이제:
    • 복잡한 Git 히스토리를 한눈에 파악하고,
    • CLI 환경에서 마우스 없이 빠르고 효율적으로 Git을 다루며,
    • Merge와 Rebase의 차이를 시각적으로 설명할 수 있고,
    • revert, cherry-pick 같은 고급 기술을 자신감 있게 사용할 수 있으며,
    • tig를 자신만의 워크플로우에 맞게 최적화할 수 있게 되었습니다.

Git은 더 이상 두려움의 대상이 아닙니다. tig와 함께라면 Git은 여러분의 가장 강력하고 신뢰할 수 있는 개발 파트너가 될 것입니다. 여기서 멈추지 말고, GitHub Flow, Git-flow와 같은 팀의 브랜치 전략론을 학습하며 더 큰 규모의 협업에 도전해 보세요.


보너스 모듈 7: 충돌(Conflict) 해결의 기술

강좌 목표: Git 협업의 필연적인 과정인 '충돌(Conflict)'을 더 이상 두려워하지 않고, 체계적으로 해결하는 능력을 기릅니다. tig를 통해 충돌 상황을 인지하고, 표준적인 도구를 이용해 해결한 뒤, 깔끔하게 정리된 히스토리를 시각적으로 확인합니다.


1. 충돌은 왜, 언제 발생하는가?

충돌은 Git의 오류가 아니라, 의사소통이 필요한 시점이라는 신호입니다. Git이 두 개의 다른 브랜치를 합치려 할 때, 같은 파일의 같은 라인을 서로 다르게 수정한 내역을 발견하면 자동으로 결정할 수 없습니다. 이때 Git은 작업을 멈추고 사용자에게 "이 부분은 어떻게 합쳐야 할지 당신이 직접 결정해 주세요"라고 요청합니다. 이것이 바로 충돌입니다.

2. Merge 충돌 시뮬레이션 및 해결

가장 흔한 Merge 충돌 상황을 직접 만들고 해결해 봅시다.

1. 충돌 상황 만들기

  • main 브랜치에서 team-rules.md 파일을 만듭니다.

    git checkout main
    echo "# 우리 팀의 규칙" > team-rules.md
    echo "- 1. 일찍 출근하기" >> team-rules.md
    git add . && git commit -m "Docs: 팀 규칙 초기 버전 작성"
    
  • 이제 feature/rule-update 브랜치를 만들어 규칙을 수정합니다.

    git checkout -b feature/rule-update
    # 1번 규칙을 수정
    sed -i '' 's/일찍 출근하기/정시 출근하기/' team-rules.md # macOS
    # sed -i 's/일찍 출근하기/정시 출근하기/' team-rules.md  # Linux
    git add . && git commit -m "Feat: 출근 규칙 현실화"
    
  • 그런데 그 사이, 다른 팀원이 main 브랜치에서 같은 라인을 다르게 수정했다고 가정합시다.

    git checkout main
    # 1번 규칙을 또 다르게 수정
    sed -i '' 's/일찍 출근하기/자율 출근하기/' team-rules.md # macOS
    # sed -i 's/일찍 출근하기/자율 출근하기/' team-rules.md  # Linux
    git add . && git commit -m "Feat: 자율 출근 제도로 변경"
    

2. 충돌 발생시키기 이제 main 브랜치에서 feature/rule-update 브랜치를 merge 해봅시다.

git merge feature/rule-update

터미널에 CONFLICT (content): Merge conflict in team-rules.md 와 같은 메시지가 뜨며 작업이 멈춥니다.

3. tig로 충돌 상태 확인하기 이때 tig를 실행하고 s 키를 눌러 Status View를 보면, 충돌의 증거를 명확히 볼 수 있습니다.

# Status View 예시
[main|MERGING] UU team-rules.md

--
status:
  Unmerged paths:
    (u)se stage 1 (base)  (2)se stage 2 (ours)  (3)se stage 3 (theirs)
  • [main|MERGING]: 브랜치 이름 옆에 MERGING 상태가 표시됩니다.
  • UU: Unmerged, both updated. 양쪽 브랜치에서 모두 수정되어 병합하지 못했다는 의미입니다.

4. 충돌 해결하기 (VS Code 활용) 충돌은 텍스트 편집기에서 직접 해결합니다. VS Code와 같은 최신 편집기는 이 과정을 매우 편리하게 도와줍니다.

  • 터미널에서 code . 를 입력해 VS Code를 엽니다.

  • team-rules.md 파일을 열면, 충돌 부분이 다음과 같이 표시됩니다.

    # 우리 팀의 규칙
    <<<<<<< HEAD
    - 1. 자율 출근하기
    =======
    - 1. 정시 출근하기
    >>>>>>> feature/rule-update
    
  • 해석:

    • <<<<<<< HEAD: HEAD(현재 브랜치, 즉 main)의 내용입니다.
    • =======: 양쪽 브랜치 내용의 구분선입니다.
    • >>>>>>> feature/rule-update: 병합하려던 브랜치(feature/rule-update)의 내용입니다.
  • VS Code는 이 구문 위에 [Accept Current Change] | [Accept Incoming Change] | [Accept Both Changes] 와 같은 편리한 버튼을 제공합니다.

  • 여기서는 팀원과 논의 후, "자율 출근"으로 결정했다고 가정하고 [Accept Current Change] 를 클릭합니다. 또는, 직접 키보드로 해당 라인들을 지우고 최종 합의된 내용(예: - 1. 논의 후 자율 출근으로 결정)으로 수정합니다.

5. 해결 완료 알리기 충돌 부분을 말끔하게 정리하고 파일을 저장했다면, Git에게 "해결 완료!"라고 알려주어야 합니다.

git add team-rules.md
git commit

git commit-m 옵션을 주지 않으면, Git이 자동으로 "Merge branch '...'" 라는 커밋 메시지가 포함된 편집기 창을 열어줍니다. 그대로 저장하고 종료하면 됩니다.

6. tig로 최종 결과 확인 다시 tig --all을 실행하면, 언제 충돌이 있었냐는 듯 깔끔한 Merge Commit이 생성되고 히스토리가 성공적으로 합쳐진 것을 시각적으로 확인할 수 있습니다.


보너스 모듈 8: 실전 브랜치 전략: Git-flow vs GitHub Flow

강좌 목표: 대표적인 두 가지 실전 브랜치 전략의 개념과 차이점을 이해합니다. tig의 그래프를 통해 각 전략이 어떤 히스토리 모양을 만드는지 시각적으로 비교하고, 내 프로젝트에 어떤 전략이 더 적합할지 판단하는 능력을 기릅니다.


1. Git-flow: 체계적인 대규모 프로젝트를 위한 전략

Git-flow는 여러 종류의 브랜치가 각자의 명확한 역할을 가지고 상호작용하는, 다소 복잡하지만 매우 체계적인 전략입니다. 버전 릴리즈가 중요한 소프트웨어(ex: 데스크톱 앱, 모바일 앱)에 적합합니다.

  • 주요 브랜치:

    • main (또는 master): 배포된 버전의 코드만 모아두는 가장 안정적인 브랜치. 직접 커밋하지 않음.
    • develop: 다음 버전에 포함될 기능들이 통합되는 개발의 중심 브랜치.
  • 보조 브랜치:

    • feature/*: 새로운 기능 개발을 위한 브랜치. develop에서 분기하여 작업 후, 다시 develop으로 병합.
    • release/*: 배포 준비를 위한 브랜치. develop에서 분기하여 버전 넘버링, 최종 버그 수정 등을 진행. 완료되면 maindevelop 양쪽에 모두 병합.
    • hotfix/*: 긴급 버그 수정을 위한 브랜치. main에서 직접 분기하여 수정 후, maindevelop 양쪽에 모두 병합.
  • tig로 본 Git-flow 히스토리:** tig --all 로 보면, 여러 줄기의 브랜치가 복잡하게 얽히고설키는 모습을 보입니다. featuredevelop으로, releasehotfixmaindevelop 양쪽으로 합쳐지는 복잡하지만 질서정연한 그래프가 그려집니다.

2. GitHub Flow: 빠르고 지속적인 배포를 위한 전략

GitHub Flow는 Git-flow의 복잡성을 대폭 줄인, 매우 단순하고 빠른 전략입니다. 웹 애플리케이션처럼 수시로 배포가 일어나는 프로젝트(CI/CD)에 매우 적합합니다.

  • 핵심 원칙: main 브랜치는 언제나 배포 가능한 상태로 유지한다.

  • 워크플로우:

    1. 새로운 작업(기능, 버그 수정 등)이 필요하면 main에서 설명적인 이름의 브랜치(feature/user-auth, fix/login-bug 등)를 만든다.
    2. 해당 브랜치에서 자유롭게 커밋하며 작업한다.
    3. 작업이 완료되면 원격 저장소에 push하고 **Pull Request(PR)**를 생성한다.
    4. PR을 통해 팀원들의 코드 리뷰를 받고, 자동화된 테스트를 통과시킨다.
    5. 리뷰와 테스트가 모두 통과되면, 해당 브랜치를 main에 병합하고 즉시 배포한다.
  • tig로 본 GitHub Flow 히스토리:** tig --all 로 보면, 마치 생선 뼈처럼 main이라는 하나의 굵은 줄기를 중심으로 짧게 뻗어 나갔다가 다시 합쳐지는 feature 브랜치들의 연속으로 보입니다. Git-flow에 비해 훨씬 단순하고 선형적인 그래프가 그려집니다.

항목Git-flowGitHub Flow
복잡도높음 (브랜치 종류가 많음)낮음 (main + feature)
주요 브랜치main, developmain
배포 주기계획된 릴리즈 (주기적)수시로, 지속적으로
적합한 프로젝트버전 관리 앱, 대규모 시스템웹 서비스, CI/CD 환경
Tig 그래프 모양복잡한 다중 줄기 그래프단순한 단일 줄기(어골형) 그래프

보너스 모듈 9: Git 내부 동작 원리 (The Internals)

강좌 목표: Git을 블랙박스가 아닌, 내부 구조가 보이는 화이트박스로 이해합니다. Git의 3대 핵심 객체(Blob, Tree, Commit)의 관계를 파악하고, .git 폴더 안의 파일들이 어떻게 히스토리를 구성하는지 직접 확인하여 Git에 대한 근본적인 이해를 높입니다.


1. .git 폴더: 모든 역사가 담긴 곳

git init을 실행하면 생기는 .git 폴더가 Git의 본체입니다. 이 안에 프로젝트의 모든 버전, 브랜치, 설정 정보가 들어있습니다.

  • HEAD: 현재 내가 작업 중인 브랜치가 무엇인지 가리키는 포인터. (cat .git/HEAD 로 열어보면 ref: refs/heads/main 과 같이 나옴)
  • refs/: 브랜치, 태그 등 모든 '참조' 정보가 담긴 폴더. refs/heads/main 파일 안에는 main 브랜치가 가리키는 최신 커밋의 해시값이 들어있습니다.
  • objects/: Git의 핵심 데이터베이스. 프로젝트의 모든 내용물(파일, 디렉토리 구조, 커밋 정보)이 객체 형태로 압축되어 저장됩니다.

2. Git의 3대 핵심 객체

Git은 모든 것을 3가지 종류의 객체로 저장합니다. 모든 객체는 내용에 따라 고유한 40자리의 SHA-1 해시값을 가집니다.

  1. Blob (Binary Large Object): 파일의 내용물 그 자체입니다. 파일 이름이나 생성 날짜 같은 메타데이터는 전혀 없고, 오직 순수한 데이터 덩어리입니다. 같은 내용의 파일은 프로젝트 내에서 단 하나의 Blob 객체만 공유합니다.

  2. Tree: 디렉토리 구조를 저장합니다. 특정 시점의 디렉토리에 어떤 파일(Blob)과 하위 디렉토리(다른 Tree)가 있었는지에 대한 목록과 각 항목의 해시값을 가지고 있습니다. 폴더의 스냅샷과 같습니다.

  3. Commit: 하나의 스냅샷을 의미하는 가장 중요한 객체입니다. Commit 객체는 다음 정보를 가리키는 포인터를 가지고 있습니다.

    • 해당 시점의 최상위 디렉토리 구조 (tree 객체의 해시)
    • 이전 커밋(들) (parent 커밋의 해시)
    • 작성자, 커밋한 사람, 날짜, 그리고 커밋 메시지

3. git cat-file로 히스토리 추적하기

git cat-file -p <hash> 명령어는 해당 해시값의 객체 내용을 예쁘게 보여주는 마법 같은 도구입니다. 이것으로 히스토리의 연결고리를 직접 따라가 봅시다.

  1. 현재 브랜치의 최신 커밋 찾기:

    cat .git/refs/heads/main
    # 4e5f6g7... 와 같은 해시값이 출력됨
    
  2. Commit 객체 내용 보기: 위에서 얻은 해시로 Commit 객체를 열어봅니다.

    git cat-file -p 4e5f6g7
    # 출력 예시:
    # tree a1b2c3d...       <-- 이 커밋의 파일/디렉토리 구조
    # parent 1a2b3c4...     <-- 이전 커밋
    # author Your Name ...
    #
    # Merge branch 'feature/rule-update'
    
  3. Tree 객체 내용 보기: 위에서 찾은 tree 해시로 Tree 객체를 열어봅니다.

    git cat-file -p a1b2c3d
    # 출력 예시:
    # 100644 blob b2c3d4e...  README.md
    # 100644 blob c3d4e5f...  team-rules.md
    
  4. Blob 객체 내용 보기: 위에서 찾은 team-rules.mdblob 해시로 Blob 객체를 열어봅니다.

    git cat-file -p c3d4e5f
    # 출력 예시:
    # # 우리 팀의 규칙
    # - 1. 논의 후 자율 출근으로 결정
    

    이 과정을 통해, 브랜치(refs/heads/main)는 커밋을, 커밋은 트리와 부모 커밋을, 트리는 블롭을 가리키는 연결 리스트 구조임을 알 수 있습니다. tig는 바로 이 연결 구조를 읽어서 우리에게 예쁜 그래프로 시각화해주는 것입니다.

최종 요약:

이 보너스 모듈들을 통해 당신은 이제 실전 협업의 난관인 충돌을 자신감 있게 해결하고, 프로젝트의 성격에 맞는 브랜치 전략을 논의할 수 있으며, Git이 내부적으로 어떻게 동작하는지에 대한 깊은 이해까지 갖추게 되었습니다. 진정한 'Git 전문가'의 반열에 오르신 것을 축하합니다