포스트

Git : 기초부터 심화까지

Git : 기초부터 심화까지

Git은 단순히 작업 기록을 남기는 도구가 아니라, 프로젝트의 전체 스냅샷을 유기적인 그래프 구조로 관리하는 시스템입니다. 명령어가 방대해 보이지만 저장, 이동, 합치기, 되돌리기, 공유라는 5가지 핵심 메커니즘을 중심으로 각 명령어의 세부 동작과 파생 옵션들을 심층 분석합니다.


1. 커밋과 히스토리: 데이터의 최소 단위 (Storage)

커밋 (Commit)

커밋은 프로젝트의 특정 시점을 기록한 스냅샷입니다. Git은 가벼운 상태를 유지하기 위해 전체 파일을 매번 복사하지 않고, 변경 내역인 델타(Delta)를 저장합니다. 각 커밋은 고유한 해시값(SHA-1)을 가지며, 이전 커밋(부모)을 가리키는 포인터를 포함하여 거대한 히스토리 트리를 형성합니다.

  • git commit: 현재의 변경 사항을 새 커밋으로 기록합니다.
  • git commit -am "메시지": 이미 추적 중인 파일들에 대해 addcommit을 동시에 수행합니다.
  • git commit --amend: 마지막 커밋을 수정합니다. 메시지를 오타 냈거나 빠뜨린 파일을 포함하고 싶을 때 사용하며, 내부적으로는 기존 커밋을 버리고 새로운 커밋을 생성합니다.

브랜치 (Branch)

브랜치는 “하나의 커밋과 그 부모 커밋들을 포함하는 작업 내역”입니다. 하지만 기술적으로 브랜치는 특정 커밋을 가리키는 가벼운 포인터일 뿐입니다.

  • git branch [이름]: 새로운 브랜치 포인터를 생성합니다.
  • git checkout [이름] / git switch [이름]: 해당 브랜치로 HEAD를 이동시킵니다.
  • git checkout -b [이름]: 브랜치 생성과 이동을 한 번에 수행합니다.

2. 위치 제어: 포인터의 이동 (Navigation)

HEAD와 상대 참조

HEAD는 현재 작업 중인 위치를 가리키는 특수한 포인터입니다. 보통은 브랜치 이름을 가리키지만, 특정 커밋을 직접 가리키게 되면 ‘분리된 HEAD(Detached HEAD)’ 상태가 됩니다.

  • 캐럿 (^): 한 단계 부모 커밋으로 이동합니다. main^2는 머지 커밋의 두 번째 부모를 의미합니다.
  • **틸드 (~)**: 수직으로 여러 단계를 올라갑니다. `HEAD~3`은 현재 위치 기준 3단계 이전 조상을 가리킵니다.

브랜치 강제 재지정 (-f 옵션)

브랜치 포인터를 현재 위치가 아닌 특정 커밋으로 강제로 옮기고 싶을 때 사용합니다.

  • git branch -f main HEAD~3: main 브랜치를 현재 기준 3단계 뒤로 강제 이동시킵니다.

3. 병합과 재배치: 흐름의 통합 (Merging & Rebasing)

Git Merge

두 개의 서로 다른 작업 흐름을 하나로 합칩니다.

  • 작동 방식: 두 브랜치의 공통 조상(Base)을 찾아 그 이후의 변경분들을 합쳐 두 개의 부모를 가진 새로운 머지 커밋을 만듭니다.
  • 특징: 병합의 역사가 그대로 남으므로 팀 단위의 큰 흐름을 파악하기에 좋습니다.

Git Rebase

커밋들을 모아서 복사한 뒤, 다른 곳에 떨궈 놓는 방식입니다.

  • 작동 방식: 현재 브랜치의 커밋들을 대상 브랜치 위로 재배치합니다. 타겟 지점과 공통 지점 사이의 내 커밋들을 복사해 타겟 끝에 붙입니다.
  • 장점: 히스토리가 일직선으로 정리되어 가독성이 극대화됩니다.
  • 주의: 이미 원격에 Push되어 공유된 커밋은 절대 Rebase하지 마세요. 히스토리가 꼬이게 됩니다.

4. 변경 되돌리기: 취소와 복구 (Undo)

Git Reset

브랜치 포인터를 예전의 커밋으로 이동시키는 방식입니다.

  • –soft: 커밋만 취소하고 스테이징 상태는 유지합니다.
  • –mixed (기본): 커밋과 스테이징을 취소하지만 작업 디렉토리 파일은 남깁니다.
  • –hard: 커밋, 스테이징, 실제 파일 변경 사항까지 모두 삭제합니다. 매우 위험하므로 주의해서 사용해야 합니다.
  • 한계: 히스토리를 직접 수정하므로 로컬에서만 사용해야 하며, 공유 브랜치에는 사용하지 않습니다.

Git Revert

현재 커밋의 변경을 취소하는 새로운 커밋을 만듭니다.

  • 특징: 기존 히스토리를 파괴하지 않으므로 원격 저장소에 공유된 작업을 되돌릴 때 가장 안전합니다.

5. 고급 커밋 조작: 정교한 관리 (Advanced)

Git Cherry-pick

다른 브랜치에 있는 특정 커밋들만 골라서 현재 위치(HEAD) 아래에 복사본을 만듭니다.

  • git cherry-pick C2 C4: C2와 C4 커밋의 변경 사항만 현재 브랜치로 가져옵니다.

Interactive Rebase (-i)

원하는 커밋이 정확히 무엇인지 모를 때 대화형 UI를 통해 히스토리를 편집합니다.

  • pick: 커밋 유지
  • reword: 커밋 메시지 수정
  • squash: 이전 커밋과 합치기
  • drop: 커밋 삭제

Git Stash

커밋하지 않은 변경 사항을 임시 저장소에 저장합니다. 브랜치를 급하게 바꿔야 하거나 작업 중간에 다른 작업을 처리해야 할 때 유용합니다.

  • git stash pop: 저장된 작업을 다시 불러와 현재 작업 트리에 적용합니다.

6. 이정표와 식별: Tag & Describe

Git Tag

중요한 지점(릴리즈 버전 등)에 영구적인 이름을 붙입니다. 태그는 브랜치와 달리 커밋이 추가되어도 절대 움직이지 않는 ‘닻’ 역할을 합니다.

  • git tag v1.0 main: main 위치에 v1.0 태그 생성.

Git Describe

가장 가까운 태그에 비해 상대적으로 어디에 위치해 있는지 묘사해 줍니다.

  • 출력: <tag>-<numCommits>-g<hash>
  • 태그명, 태그로부터의 거리(커밋 수), 현재 커밋의 해시값을 통해 위치를 식별합니다.

7. 원격 저장소 협업: 공유 (Remote)

원격 저장소는 GitHub 같은 서버에 있는 공용 저장소입니다.

  • git clone: 원격 저장소의 모든 데이터를 로컬로 복제해 옵니다.
  • git fetch: 원격의 새 커밋들을 다운로드하지만 로컬 브랜치를 바꾸지는 않습니다.
  • git pull: 원격 변경을 가져와 현재 브랜치에 합칩니다 (fetch + merge).
  • git pull –rebase: 원격 변경 위에 내 작업을 다시 쌓아 히스토리를 깨끗하게 유지합니다.
  • git push: 내 로컬 커밋을 원격에 업로드합니다.
  • origin/main: 원격 브랜치의 로컬 복사본입니다. 원격이 갱신되어도 fetch를 해야만 최신 상태가 반영됩니다.

원격 브랜치 추적 설정

  • git checkout -b side origin/main: 원격을 기준으로 새 브랜치 생성 및 추적.
  • git branch -u origin/main side: 기존 브랜치가 원격을 추적하도록 설정.
  • git push -u origin main: 첫 push 시 추적 관계를 자동 설정합니다.

📊 미션 수행 결과 (Learn Git Branching 클리어)

“별이 없는 기본기를 다지기 위한 연습” 미션을 위해 로컬 및 원격 저장소의 모든 단계를 시나리오별로 실습했습니다.

로컬 저장소 조작 실습 완료

로컬 레벨 완료

원격 저장소 협업 실습 완료

원격 레벨 완료

💡 최종 결론

Git은 명령어를 개별적으로 외우기보다 저장-이동-합치기-되돌리기-공유라는 큰 흐름 속에서 데이터의 구조가 어떻게 변하는지 파악하는 것이 중요합니다. 이번 미션을 통해 어떤 복잡한 협업 상황에서도 당황하지 않고 프로젝트의 형상을 관리할 수 있는 단단한 기초를 마련했습니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.