Git의 가장 큰 장점은 코드 변경 이력을 커밋 단위로 추적할 수 있다는 점입니다. 문제가 생기면 언제 어떤 변경이 들어갔는지 확인하고 되돌릴 수 있습니다.
또 Git은 분산 버전 관리 시스템이라 대부분의 작업을 로컬에서 빠르게 할 수 있고, branch를 만들어 기능 개발이나 실험을 격리할 수 있습니다. Pull request, code review, merge를 통해 협업 흐름도 만들기 쉽습니다.
꼬리질문
조금 더 깊게 물어본다면
답변 뒤에 이어질 수 있는 질문들을 하나씩 열어볼 수 있어요.
Commit은 무엇인가요?
특정 시점의 변경 사항을 저장소에 기록한 단위입니다. 변경 내용뿐 아니라 작성자, 시간, 메시지, 부모 commit의 SHA-1 해시가 함께 남습니다. commit 자체도 SHA-1 해시로 식별되어 내용이 바뀌면 hash가 달라집니다.
Staging area(index)란?
working directory와 commit 사이의 중간 영역입니다. git add로 staging area에 올린 변경만 git commit에 포함됩니다. 변경 중인 파일 중 일부만 선택해 commit할 수 있는 유연성을 줍니다.
HEAD란?
현재 작업 위치를 가리키는 포인터입니다. 보통 현재 branch의 최신 commit을 가리킵니다. branch가 아닌 특정 commit을 직접 가리키는 상태를 detached HEAD라고 하며, 이 상태에서 commit을 만들면 어떤 branch에도 속하지 않아 나중에 찾기 어려워집니다.
Branch를 쓰는 이유는?
main 흐름을 깨뜨리지 않고 기능 개발, 버그 수정, 실험을 독립적으로 진행하기 위해서입니다. branch는 특정 commit을 가리키는 포인터일 뿐이라 생성 비용이 매우 낮습니다. 작업이 검증되면 merge나 rebase로 합칠 수 있습니다.
Git이 분산 버전 관리라는 말은?
각 개발자가 전체 repository history를 로컬에 가지고 있어 네트워크 없이도 commit, branch, diff, log 같은 작업을 할 수 있다는 뜻입니다. SVN 같은 중앙 집중식 VCS는 대부분의 작업에 서버 연결이 필요합니다.
Merge와 rebase의 차이는?
Merge는 두 branch의 이력을 합치는 merge commit을 만듭니다. 이력이 그대로 보존되지만 합류 지점이 명시적으로 남습니다.
Rebase는 내 commit들을 새로운 base 위에 다시 적용해 이력을 선형으로 만듭니다. 이력이 깔끔해지지만 기존 commit의 SHA-1이 바뀌어 공유 branch에서 쓰면 다른 사람의 이력과 충돌할 수 있습니다.
git reset vs git revert 차이는?
git reset은 HEAD를 이전 commit으로 이동해 이력 자체를 되돌립니다. --soft는 변경 사항을 staging area에 남기고, --hard는 변경 사항을 완전히 버립니다.
git revert는 이전 변경을 취소하는 새 commit을 만들어 이력을 보존합니다.
공유 branch에서는 이력을 바꾸지 않는 revert를 써야 하고, 아직 push하지 않은 로컬 작업 정리에는 reset을 씁니다.
cherry-pick은 언제 쓰나요?
특정 branch의 특정 commit만 골라서 다른 branch에 적용할 때 씁니다. 예를 들어 hotfix commit을 release branch에 빠르게 반영해야 할 때 유용합니다.
squash commit이란?
여러 commit을 하나로 합치는 방식입니다. git rebase -i나 merge 시 --squash 옵션으로 작업 중 쌓인 WIP commit들을 PR 병합 시점에 하나의 깔끔한 commit으로 만들 수 있습니다.
Git flow vs trunk-based development?
Git flow는 main, develop, feature, release, hotfix 등 여러 long-lived branch를 두는 전략이고, trunk-based development는 모든 개발자가 짧은 주기로 main에 직접 통합하는 전략입니다. 배포 주기가 빠른 팀일수록 trunk-based를 선호하는 경향이 있습니다.
force push는 언제 위험한가요?
git push --force는 원격 branch의 이력을 덮어쓰기 때문에, 다른 사람이 해당 branch를 기반으로 작업 중이라면 그 이력이 사라질 수 있습니다. 공유 branch에서는 --force-with-lease를 쓰거나 아예 피하는 편이 안전합니다. --force-with-lease는 원격에 내가 모르는 새 commit이 있으면 push를 거부합니다.
PR에서 커밋이 지저분해졌을 때
feature 브랜치에서 개발하다 리뷰 반영, 오타 수정 커밋이 10개 넘게 쌓였습니다. 그대로 merge하면 main 이력이 지저분해집니다.
PR merge 시 squash and merge를 선택합니다. feature 브랜치의 모든 커밋이 하나로 합쳐져 main에 들어갑니다. 작업 과정의 커밋은 사라지고 의미 있는 단위 하나만 main 이력에 남습니다.
main이 내 feature보다 앞서 나갔을 때
feature 브랜치에서 이틀째 개발 중인데 팀원이 main에 여러 커밋을 쌓았습니다. PR 올리기 전에 main 변경사항을 반영하고 싶습니다.
git rebase main을 씁니다. feature 커밋들이 최신 main 위에 다시 적용되어 이력이 선형으로 유지됩니다. git merge main을 쓰면 merge commit이 생겨 이력이 복잡해집니다. 단, 이미 push한 브랜치라면 rebase 후 --force-with-lease가 필요합니다.
프로덕션에 버그가 생겼을 때
main이 현재 배포 상태인데 버그 신고가 왔습니다. develop에는 아직 출시 전 기능이 있어 그대로 배포할 수 없습니다.
main에서 hotfix 브랜치를 분기해 버그를 수정하고 main에 merge합니다. 같은 버그가 develop에도 있다면 hotfix commit을 develop에 cherry-pick으로 적용합니다.
개발 중 급한 다른 일이 생겼을 때
feature 브랜치에서 반쯤 구현한 상태인데 갑자기 긴급 버그 수정 요청이 왔습니다. 아직 commit하기엔 기능이 미완성입니다.
git stash로 현재 변경사항을 임시 보관하고 다른 브랜치로 전환합니다. stash는 스택 구조로 여러 개를 쌓을 수 있으며, 긴급 작업 완료 후 git stash pop으로 복원합니다.
잘못된 커밋을 push했을 때
main에 실수로 디버그 코드가 포함된 커밋을 push했습니다. 다른 팀원이 이미 pull했을 수 있습니다.
git revert <hash>를 씁니다. 해당 커밋의 변경을 취소하는 새 커밋이 생겨 이력이 보존됩니다. git reset --hard + force push는 팀원의 이력을 망가뜨릴 수 있어 공유 브랜치에서는 쓰면 안 됩니다.
부가 설명
Git은 파일의 변경 내역(delta)을 저장하는 게 아니라 특정 시점의 전체 스냅샷을 저장합니다. 각 commit은 그 시점 파일 트리 전체의 SHA-1 해시를 가리키고, 내용이 같은 파일은 같은 객체를 재사용해 공간을 절약합니다. 이 구조 덕분에 commit 간 이동이나 branch 전환이 빠르고, 어느 commit에서든 전체 상태를 즉시 복원할 수 있습니다.
분산 구조에서 각 개발자는 전체 history를 로컬에 가지고 있어, 네트워크 없이 대부분의 작업이 가능하고 원격 서버가 다운돼도 작업을 이어갈 수 있습니다.
좋은 커밋 메시지와 작은 단위의 커밋은 나중에 디버깅, 리뷰, 롤백할 때 큰 도움이 됩니다.
한 줄 정리
Git은 스냅샷 기반으로 변경 이력을 안전하게 남기고, branch 기반 협업과 빠른 로컬 작업을 지원하는 분산 버전 관리 시스템입니다.