모든 글

Git 이력은 개인 작업일지가 아니라 팀의 자산입니다

커밋을 다듬기 전에 작업부터 나누고, 동료가 검토하기 좋은 PR과 다음 사람이 변경 이유를 추적하고 릴리스를 복구할 수 있는 이력을 남깁니다.

  • git
  • collaboration
  • software-engineering

출처 및 AI 안내: 이 글은 제미니의 개발실무 유튜브를 기반으로 작성되었습니다. gpt-5.6-sol 모델을 사용해 생성·편집했습니다.

커밋을 만드는 방식은 크게 두 가지가 있습니다. 먼저 커밋 단위를 정하고 한 단계씩 저장하는 개발자가 있습니다. 기능을 끝까지 만든 뒤 PR을 열기 전에 작업을 커밋으로 다시 정리하는 개발자도 있습니다. 저는 둘 다 씁니다. 어느 한쪽을 고집하는 것보다 중요한 능력은 다른 사람이 이해할 수 있을 만큼 작업 자체를 작게 만드는 일입니다.

태스크가 “리뷰 시스템 개발”이라면 커밋을 나누기 전부터 일이 너무 큽니다. 리뷰 등록, 조회, 수정, 삭제는 서로 다른 변경입니다. 전부 한 브랜치에서 처리하면 파일 50개를 건드리고 커밋이 열 개를 넘으며 설계, 구현, 정리가 한꺼번에 섞일 수 있습니다. 커밋 이름을 깔끔하게 붙여도 그 PR은 읽기 어렵습니다.

커밋 방식을 고민하기 전에 태스크부터 나눠야 합니다. 독립적으로 전달할 수 있는 작업이라면 브랜치와 PR도 나눕니다. 일이 작으면 커밋도 자연스럽게 정리됩니다.

한 번에 한 가지 모자를 씁니다

기능을 추가하면서 근처 코드를 함께 리팩터링하는 실수를 자주 봅니다. 리팩터링이 기능 구현에 꼭 필요할 때도 있습니다. 하지만 작업하다 지저분한 코드를 발견해서 내친김에 고치는 경우도 많습니다.

그러면 리뷰어는 서로 다른 질문을 동시에 풀어야 합니다. 동작이 바뀐 이유가 새 기능 때문일까요, 리팩터링 때문일까요? 기능을 내기 위해 그 리팩터링이 꼭 필요했을까요? 문제가 생기면 어느 부분을 되돌려야 할까요?

저는 한 번에 한 가지 모자를 쓰려고 합니다. 먼저 동작을 유지하는 리팩터링을 별도 변경으로 끝낸 뒤 기능을 추가합니다. 또는 기능을 먼저 전달하고 관련 없는 정리는 다음 작업으로 미룹니다. 기존 코드를 절대 건드리지 말자는 규칙이 아닙니다. 변경의 목적이 보이게 하자는 기준입니다.

PR이 작으면 리뷰어도 설계에 관해 이야기할 여유가 생깁니다. 주문 팀 개발자에게 거대한 리뷰 시스템 변경을 검토해 달라고 하면 정책을 몰라 포맷 정도만 볼 수 있습니다. 요구사항과 판단을 설명한 좁은 변경이라면 같은 사람도 의미 있는 질문을 할 수 있습니다.

리뷰어는 PR의 사용자입니다. 작성자만 편한 방식이 아니라 그 사용자가 읽기 좋은 방식으로 일을 정리해야 합니다.

작업 커밋과 리뷰 커밋의 독자가 다릅니다

개발 중에는 되돌아갈 지점이 필요할 때마다 커밋합니다. 이 커밋은 거칠어도 됩니다. 실험하고, 리셋하고, 방법을 비교하고, 작업을 잃지 않기 위한 기록입니다. 저는 드래프트 PR도 일찍 올리는 편이지만 이 단계의 브랜치는 여전히 작업 중인 공간입니다.

리뷰를 요청하기 전에는 커밋을 다시 정리합니다. 리셋한 뒤 목적이 분명한 커밋으로 재구성할 수도 있습니다. 제가 실무에서 두는 기준 하나는 같은 클래스가 서로 관계없는 커밋에서 반복해서 바뀌지 않게 하는 것입니다. User가 1번 커밋에서 바뀌고 3번, 7번에서 또 바뀌면 커밋 순서대로 읽는 리뷰어는 최종 변경 이유를 찾으려고 계속 앞뒤로 이동해야 합니다.

모든 상황에서 한 파일은 반드시 한 커밋에만 등장해야 한다는 법은 아닙니다. 작성자가 보낸 오후를 통째로 재현하지 않아도 순서대로 읽을 수 있는 커밋을 만들기 위한 압력에 가깝습니다.

리뷰 중에는 수정 커밋을 보통 그대로 쌓습니다. 리뷰는 대화입니다. 댓글에 따라 무엇을 바꿨는지 분리된 커밋으로 보여주면 리뷰어가 확인하기 쉽습니다.

리뷰가 끝나면 이력을 한 번 더 봅니다. 리뷰에서 나온 수정이 앞으로도 참고할 판단을 담고 있다면 보존할 가치가 있습니다. 단순 오타 수정이나 빠뜨린 한 줄을 원래 구현에 넣은 정도라면 관련 커밋에 리베이스하거나 스쿼시하는 편입니다. 이런 정리는 팀 정책에 합의한 머지 전 피처 브랜치에서 해야 합니다. 이력을 다시 쓰면 커밋 ID가 바뀌므로 협업자와 의존 브랜치에 알리고 저장소 보호 규칙도 지켜야 합니다. PR 대화가 남더라도 diff 맥락과 커밋 참조는 오래된 상태가 될 수 있습니다. 영구적인 Git 이력은 다음 개발자에게 소프트웨어가 어떤 의미 있는 상태를 거쳤는지 알려줘야지, 중간의 모든 실수를 강제로 읽게 할 필요는 없습니다.

과정마다 독자가 달라집니다.

  • 작업 중인 커밋은 나를 위한 것입니다.
  • 리뷰를 요청할 때의 커밋과 PR은 동료를 위한 것입니다.
  • 리뷰가 끝난 뒤의 이력은 회사와 다음 사람을 위한 것입니다.

그래서 처음 만든 커밋 나열이 모든 단계에 가장 좋은 형태일 가능성은 낮습니다.

큰 변경은 순서를 보여주는 브랜치로 나눕니다

한 PR에 담을 수 없는 작업도 있습니다. 그런 경우에는 거대한 브랜치 하나보다 의존 관계가 있는 여러 브랜치를 순서대로 쌓는 편을 선호합니다.

첫 PR은 최소한의 기반 구조를 넣습니다. 다음 브랜치는 첫 브랜치에서 시작해 작업 하나를 추가합니다. 그다음 브랜치는 다시 다음 작업을 추가할 수 있습니다. 순서대로 리뷰하고 머지하며, 앞 브랜치의 기준점이 바뀌면 뒤 브랜치를 리베이스합니다. 관리에는 손이 가지만 각 리뷰의 주제가 제한됩니다.

브랜치를 대상 브랜치의 최신 상태에 맞추는 것도 중요합니다. 일반적인 피처 개발에서는 develop을 피처 브랜치에 계속 머지하기보다 최신 develop 위로 리베이스하는 편을 선호합니다. 예외는 있지만 반복되는 머지 커밋은 그래프를 읽기 어렵게 하고 나중의 복구도 필요 이상으로 힘들게 합니다.

그래프 자체를 예쁘게 만들자는 얘기는 아닙니다. 그래프에는 운영상의 역할이 있습니다.

문제가 난 릴리스를 기준으로 이력을 설계합니다

장애가 나면 정리된 이력의 가치가 드러납니다. 여러 사람이 만든 변경이 한 릴리스에 들어갔다고 해봅시다. 한 변경이 장애를 일으켰지만, 같은 릴리스의 다른 변경은 캐시 키를 바꿔서 안전하게 롤백할 수 없습니다. 전체를 되돌리면 한 경로가 깨지고 그대로 두면 다른 경로가 깨집니다.

팀은 좋은 변경만 고르고 문제가 된 변경을 빼서 핫픽스 릴리스를 만들어야 합니다. 이력에 리뷰 반영이라는 커밋이 수십 개 있고 같은 파일이 계속 바뀐다면 사람들이 한 화면 뒤에 모여 이 커밋을 넣을지 뺄지 묻게 됩니다. 저는 이런 장면을 여러 번 봤습니다. 급한 상황에서 모호한 커밋 하나하나가 위험합니다.

작고 응집된 커밋과 읽을 수 있는 브랜치 이력은 의도한 변경을 되돌리거나 체리픽하기 쉽게 만듭니다. 물론 하위 호환 가능한 배포 설계를 대신하지는 않습니다. 캐시 포맷, 데이터베이스 변경, API 계약에는 여전히 롤백 계획이 필요합니다. Git 이력은 첫 계획이 실패했을 때 쓰는 두 번째 방어선입니다.

팀은 실용적인 규칙에 합의해야 합니다. PR 크기, 태스크를 나눌 시점, 리뷰 커밋 처리, 피처 브랜치 리베이스 여부, 머지 전략이 남기는 결과를 정합니다. 자동화로 너무 큰 변경에 경고할 수 있지만 파일 개수 자체가 원칙은 아닙니다. 열 파일짜리 변경도 엉킬 수 있고, 기계적인 이름 변경은 많은 파일을 건드려도 명확할 수 있습니다.

오래가는 기준은 단순합니다. 지금 리뷰할 수 있고 나중에 복구할 수 있게 일을 만드세요. Git은 회사의 자산과 엔지니어링 판단을 기록합니다. 개인 작업일지처럼 다루면 작성자는 몇 분을 아끼지만 리뷰하고, 디버깅하고, 코드를 이어받는 모든 동료가 그 비용을 냅니다.