Git 대화형 리베이스 가이드, 실제 예제와 함께

Git을 이용한 버전 관리는 현대 개발자들의 도구 벨트에서 기본이 되었습니다. commit, push, pull과 같은 명령어들은 이제 우리 손가락의 근육 기억에 깃든 상태입니다. 그러나 상대적으로 많은 개발자들이 Git의 “고급” 기능들을 알지 못하고 있으며, 이들이 얼마나 매우 가치 있는지 모르고 있습니다! 이 글에서는 Git의 가장 강력한 도구 중 하나인 “Interactive Rebase”를 탐색해보겠습니다.

모든 개발자의 도구 모음에 Interactive Rebase가 포함되어야 하는 이유

간단하게 말하면, 과장하지 않고, Interactive Rebase는 프로젝트에서 깔끔하고 잘 구조화된 커밋 기록을 만들어내어 여러분이 더 나은 개발자가 되도록 도와줍니다.

잘 구조화된 커밋 기록이 왜 중요할까요? 반대로 생각해보세요: 동료들이 최근 변경 사항에서 실제로 무엇을 했는지 알 수 없는 읽기 어려운 커밋 기록. 이런 프로젝트에서는 점점 더 많은 “어두운 구석”이 드러나며, 스스로 작업한 작은 부분만을 이해할 수 있습니다.

이것을 깔끔하고 잘 구조화된 커밋 기록과 대조해보세요: 이는 프로젝트의 코드베이스를 더 읽기 쉽게 만들고 이해하기 쉽게 만듭니다. 이는 건강하고 장기적으로 지속되는 프로젝트를 위한 필수적인 요소입니다!

Interactive Rebase가 여러분에게 무엇을 해줄 수 있는가

Interactive Rebase는 여러분의 커밋 기록을 최적화하고 정리해줍니다. 다양한 사용 사례를 다루며, 다음과 같은 작업을 수행할 수 있습니다:

  • 이전 커밋 메시지 편집
  • 커밋 삭제
  • 여러 커밋 합치기(squash/combine)
  • 커밋 순서 변경
  • 구 커밋 수정
  • 구 커밋 분할/수정을 위해 다시 열기

대화형 리베이스를 사용해야 할 때와 사용하지 말아야 할 때

다른 몇몇 Git 도구들과 마찬가지로, 대화형 리베이스는 “역사를 재구성”한다. 이는 대화형 리베이스를 사용하여 일련의 커밋을 조작할 때, 이 부분의 커밋 역사가 재작성된다는 것을 의미합니다: 커밋의 SHA-1 해시가 변경되었습니다. 완전히 새로운 커밋 객체라고 할 수 있습니다.

이 사실은 간단하지만 중요한 규칙을 생각해내는데 쓰입니다: 이미 동료들과 원격 저장소에 공유한 커밋에 대해 대화형 리베이스(또는 역사를 재구성하는 다른 도구들)를 사용하지 마십시오. 대신, 자신의 기능 브랜치에서 병합하기 전에 자신의 로컬 커밋을 청소하는 데 사용하십시오.

대화형 리베이스 작업의 기본 메커니즘

대화형 리베이스를 사용할 수 있는 많은 다양한 방법이 있지만, 기본 워크플로우는 항상 동일합니다. 이 기본 메커니즘을 확실히 이해하면 대화형 리베이스의 “복잡한 신비” 분위기가 사라지고 도구 벨트에서 귀중한 접근 가능한 항목이 됩니다.

1 단계: 세션을 어디서 시작해야 하나요?

가장 먼저 대답해야 할 질문은 “내 커밋 역사의 어느 부분을 조작하고 싶은가?”입니다. 이것은 대화형 리베이스 세션을 어디서 시작해야 하는지를 알려줍니다. 실제로 곧 수행할 때와 같이 구 커밋 메시지를 편집하고 싶다고 가정해 보겠습니다.

시작 상황은 아래 그림과 같으며, 이전 커밋 메시지를 편집하기 위해 대화형 리베이스를 사용하고 있습니다.

코드>C2의 커밋 메시지를 변경하려면 해당 커밋의 부모 커밋(또는 그 이전 커밋, 필요한 경우)에서 대화형 리베이스 세션을 시작해야 합니다. 이 예시에서는 <코드>C1를 대화형 리베이스 세션의 시작점으로 사용합니다.

2단계: 실제 세션 시작!

실제 세션을 시작하는 것은 매우 간단합니다:

$ git rebase -i HEAD~3

대화형으로 진행하기를 원한다는 것을 나타내는 <코드>-i 플래그와 함께 <코드>git rebase 명령어를 사용하고, 기준 커밋(1단계에서 선택한 것)을 제공합니다. 이 예시에서는 <코드>HEAD~3를 사용하여 “HEAD 커밋에서 3개 이전”의 커밋을 지정했습니다. 또는 특정 SHA-1 해시를 제공할 수도 있습니다.

3단계: Git에게 어떤 작업을 하고 싶은지 알리기

대화형 리베이스 세션을 시작한 후에는 Git이 일련의 커밋을 나열하는 에디터 창이 표시됩니다. 이는 최신 커밋부터 시작하여 1단계에서 선택한 기준 커밋을 포함하지 않습니다.

이 단계에서 두 가지 중요한 사항을 염두에 두어야 합니다:

  1. 커밋이 역순으로 나열됩니다! 가장 최근의 커밋은 맨 위에 나타날 것으로 예상되지만, 실제로는 목록의 맨 아래에 나타납니다. 걱정하지 마세요: 깃 저장소는 완벽합니다! 🥳 대화형 리베이스 작업을 진행 중이라는 것을 기억하세요. 이 작업에서는 최종적으로 가장 오래된 커밋부터 최신 커밋까지 커밋을 재적용해야 합니다.
  2. 이 편집기 창에서 실제 변경 사항을 만들지 마세요! 어쩌면 이 편집기 창에서 커밋 메시지를 변경하고 싶어서 참을 수 없을지도 모르지만 (결국 그게 우리가 원하는 것이니까…), 참을성을 가지셔야 합니다. 여기서 우리는 Git에게 무엇을 하고 싶은지만 알려줄 것입니다 — 실제 변경은 하지 않을 것입니다. 이 점을 실제로 곧 보여드리겠습니다!

이론적인 개요를 제외하고, 함께 실제 사례로 뛰어들어 봅시다!

오래된 커밋 메시지 편집

대화형 리베이스의 매우 인기 있는 사용 사례 중 하나는 사후에 오래된 커밋 메시지를 편집할 수 있다는 것입니다. git commit --amend도 커밋 메시지를 변경할 수 있다는 것을 아실 수 있습니다 — 하지만 이것은 가장 최근의 커밋에 한정됩니다. 그보다 오래된 어떤 커밋이라도 대화형 리베이스를 사용해야 합니다!

구체적인 시나리오를 살펴보겠습니다. 아래는 수정해야 할 좋지 않은 커밋 메시지의 이미지입니다.

참고: 더 나은 개요와 명확한 시각화를 위해, 일부 스크린샷에서 Tower Git 데스크톱 클라이언트를 사용하고 있습니다. 이 튜토리얼을 따르기 위해 Tower가 필요하지 않습니다.

예시로, 현재 제목이 “인덱스에서 마크업 구조 최적화…”인 커밋의 메시지를 수정하고 싶다고 가정해 보겠습니다.

첫 번째 단계는 이 대화형 rebase 세션을 시작하기 위한 기준 커밋을 결정하는 것입니다. 우리는 “나쁜 사과” 커밋의 부모로 돌아가야 하므로 세션을 HEAD~3(HEAD 커밋에서 세 커밋 뒤, 이는 “헤드라인 변경…”이라는 제목의 커밋임)에서 시작합니다:

$ git rebase -i HEAD~3

이 명령을 실행하자마자 가장 좋아하는 에디터가 열리고 선택한 커밋 목록(기준 커밋을 제공하여)을 표시합니다.

다시 한 번 상기시키지만, 여기서 커밋 메시지를 변경하고 싶을지라도 그렇게 하지 않습니다. 우리는 단지 “작업 키워드”로 각 줄을 표시합니다. 이 경우, 커밋을 reword하고 싶습니다(즉, 커밋 메시지를 변경하고 싶지만 커밋의 나머지 부분은 그대로 두고 싶음).

매우 실용적으로, 사용 가능한 모든 작업 키워드는 이 창 맨 아래에 문서화되어 있으므로 암기할 필요가 없습니다!

기본 pick 키워드(즉, “커밋을 그대로 사용”)를 선호하는 작업 키워드로 교체한 후 창을 저장하고 닫을 수 있습니다.

그렇게 한 후, 현재 커밋 메시지가 포함된 새 에디터 창이 열립니다. 마지막으로, 처음 목적한 대로 이 오래된 커밋의 메시지를 편집할 수 있습니다!

변경 사항을 마친 후 에디터 창을 저장하고 닫으면 대화형 rebase 세션이 완료되고 커밋 메시지가 업데이트됩니다! 🎉

원치 않는 커밋 삭제

Interactive rebase를 통해 필요하지 않거나 원하지 않는 이전 커밋을 삭제할 수도 있습니다. 예를 들어, 최근 커밋에 개인 비밀번호를 실수로 포함시켜버린 경우를 상상해보세요: 이러한 민감한 정보는 대부분의 경우 코드베이스에 포함되어서는 안 됩니다.

또한, 정보를 삭제한 후 다시 커밋하는 것만으로는 문제를 해결하지 못합니다: 이렇게 되면 비밀번호가 여전히 저장소에 이전 커밋 형태로 저장되어 있는 것입니다. 실제로 원하는 것은 이 데이터를 저장소에서 깔끔하게 완전히 삭제하는 것입니다!

먼저 인터랙티브 리베이스 세션의 기준 커밋을 결정합니다. 나쁜 커밋의 부모 이상에서 시작해야 하므로 “Optimize markup structure…” 커밋을 기준으로 삼겠습니다:

$ git rebase -i 6bcf266b

이번에는 git rebase -i 명령어에 구체적인 SHA-1 해시를 사용했음에 주목하세요. 물론 커밋 해시 대신 HEAD~2를 사용하여 해당 커밋을 참조할 수도 있습니다.

이 명령어를 실행한 후 다시 한 번 커밋 목록이 표시됩니다.

이번에는 drop 액션 키워드를 사용하여 원치 않는 커밋을 제거합니다. 또는 이 특별한 경우에는 편집기에서 전체 줄을 삭제할 수도 있습니다. 줄(커밋을 나타냄)이 저장 및 창 닫기 시 더 이상 존재하지 않으면 Git은 해당 커밋을 삭제합니다.

어떻게 하든, 편집기 창을 저장하고 닫은 후 해당 커밋은 저장소 기록에서 삭제됩니다!

여러 커밋을 하나로 결합

상호작용 형 리베이스의 또 다른 사용 사례는 여러 개별 커밋을 결합하여 하나로 만들고 싶을 때입니다. 어떻게 이것이 작동하는지 자세히 살펴보기 전에, 언제 또는 이것이 가치 있을지에 대해 잠시 이야기해 보겠습니다.

일반적으로 커밋을 “더 크게” 만드는 것(여러 개를 하나로 결합)은 대부분의 경우 좋은 전략이 아닙니다. 기본 규칙은 커밋을 가능한 한 작게 유지하는 것이며, “작은” 것은 “읽고 이해하기 쉬운” 것을 의미합니다. 그러나 여전히 이것이 합리적인 상황도 있습니다. 두 가지 예를 들어 보겠습니다.

  • 이전 커밋에서 문제를 발견했다고 가정해 보십시오. 그런 다음 문제를 해결하기 위해 새로운 커밋을 생성할 수 있습니다. 이러한 상황에서 이러한 커밋을 하나로 결합할 수 있다면 매우 합리적입니다: 결국 최신 커밋은 처음부터 존재하지 않아야 할 문제를 해결하기 위한 “반창고”에 불과했습니다. 이러한 커밋을 결합함으로써, 처음부터 문제가 없었던 것처럼 보입니다!
  • 또 다른 예는 작업을 약간 지나치게 세분화했다는 것을 알게 되었을 때입니다. 작은 커밋을 만드는 것은 모두 좋지만, 많은 불필요하게 작은 커밋들로 커밋 기록을 가득 채우면 목표를 지나치게 벗어납니다.

두 예시 모두 동일한 이유에 기반합니다: 처음부터 하나로 되어야 했던 두 개(또는 그 이상)의 커밋을 결합함으로써, 더 깔끔하고 읽기 쉬운 커밋 기록을 생성하게 됩니다!

함께 실제 예를 살펴보고, 아래에 나와 있는 상황을 시작 상황으로 삼아 봅시다.

문맥적으로 보면, 이 두 커밋을 하나로 합치는 것이 더 합리적일 수 있습니다. 대화형 리베이스의 squash 도구를 사용하면 이 두 커밋을 실제로 결합할 수 있습니다:

$ git rebase -i HEAD~3

이제까지 다음에 무슨 일이 일어나는지 이미 익숙해졌을 것입니다: 커밋 목록을 보여주는 에디터 창이 열립니다.

I already mentioned that we’re going to use the squash action keyword in this case. There’s an important thing to know about how squash works: the line you mark up with the keyword will be combined with the line directly above! This explains why I marked line 2 with the squash keyword in our example.

이 창을 저장하고 닫으면 새로운 창이 열립니다. 여러 커밋을 결합함으로써 당연히 새로운 커밋을 만들고 있기 때문입니다. 그리고 이 커밋도 다른 어떤 커밋과 마찬가지로 커밋 메시지가 필요합니다!

위의 스크린샷에서 보이는 것은 Git이 우리를 위해 준비한 것입니다: 각각의 원래 커밋 메시지를 결합하고 몇 가지 주석을 추가했습니다. 이전 메시지를 삭제하고 새로 시작하거나, 기존 메시지를 유지하고 추가 정보를 입력할 수 있습니다.

이 에디터 창을 저장하고 닫은 후, 이제 두 개의 별도 커밋이 하나로 합쳐진 것을 자랑스럽게 말할 수 있습니다!

대화형 리베이스의 힘을 활용하세요

I hope you agree that Git’s interactive rebase tools can be very valuable! As developers, it’s important for us to strive for a clean and clear commit history. It’s a crucial ingredient in keeping a codebase healthy and easy to understand (both for your teammates, and yourself, after some time has passed).

더 알아보고 싶다면, “Git 구급 상자“를 매우 추천합니다. 이는 (무료로 제공되는) 짧은 동영상 모음으로, Git에서 정리하고 실수를 취소하는 방법을 보여줍니다.

즐거운 시간 되세요!

Git 대화형 리베이스 FAQ

Git Rebase와 Git Merge의 차이점은 무엇인가요?

Git Rebase와 Git Merge는 한 브랜치에서 다른 브랜치로 변경 사항을 통합하는 두 가지 다른 방법입니다. Git Merge는 두 개의 다른 브랜치의 코드를 결합하는 간단한 방법입니다. 이는 커밋의 시간 순서를 보존하면서 역사에 새 커밋을 생성합니다. 반면에 Git Rebase는 일련의 커밋을 새로운 기준 커밋으로 이동하거나 결합하는 방법입니다. 이는 “다른 모든 사람이 한 일에 기반하여 변경 사항을 원한다”고 말하는 것과 같습니다. 즉, 다른 브랜치 위에 현재 브랜치의 변경 사항을 배치할 수 있게 해줍니다.

Git Rebase를 어떻게 취소할 수 있나요?

Git Rebase를 취소하려면 git reflog 명령을 사용하여 되돌아가고 싶은 커밋을 찾은 다음 git reset --hard HEAD@{number} 명령을 사용할 수 있습니다. git reflog 명령은 HEAD에 대해 만들어진 모든 변경 사항의 목록을 보여주고, git reset 명령은 현재 HEAD를 지정된 상태로 설정할 수 있게 해줍니다.

Git Interactive Rebase의 목적은 무엇인가요?

Git Interactive Rebase를 사용하면 편집, 삭제, 압축 등 커밋을 여러 가지 방식으로 변경할 수 있습니다. 커밋 메시지를 변경할 수 있을 뿐만 아니라 실수를 했다면 실제 코드를 변경할 수도 있습니다. 이는 프로젝트의 커밋 역사에 대한 완전한 제어권을 부여하는 강력한 도구입니다.

Git Interactive Rebase를 사용하여 커밋을 압축하려면 어떻게 해야 하나요?

스쿼시 작업은 여러 커밋을 하나로 결합하는 행위입니다. Git에서는 git rebase -i 명령어를 사용하여 원하는 커밋 해시 뒤에 커밋을 스쿼시할 수 있습니다. 열리는 텍스트 에디터에서 picksquashs로 바꿔 각 커밋 옆에 원하는 커밋을 스쿼시하도록 표시할 수 있습니다.

Git Interactive Rebase를 사용할 때의 위험요소는 무엇인가요?

Git Interactive Rebase는 강력한 도구이지만, 제대로 사용하지 않으면 위험할 수 있습니다. 이 도구는 커밋 기록을 재작성하므로 다른 사람들과 공유하는 공개 브랜치에서 작업 중일 때 문제가 될 수 있습니다. 아직 푸시되지 않은 로컬 브랜치에서 사용하는 것이 좋습니다.

Git Rebase 중에 충돌을 어떻게 해결할 수 있나요?

Rebase 중에 충돌이 발생할 수 있습니다. Git은 이를 해결하기 전까지 일시 중지하고 계속할 수 있습니다. 충돌을 해결하려면 git add로 해결된 파일을 추가하여 파일을 수정하여 충돌하는 변경 사항을 수정한 다음, 모든 충돌을 해결한 후 git rebase --continue로 리베이스를 계속할 수 있습니다.

Git Interactive Rebase를 사용하여 커밋을 분할할 수 있나요?

예, Git Interactive Rebase를 사용하여 커밋을 더 작은 단위로 분할할 수 있습니다. 이는 단일 커밋에서 여러 변경 사항을 수행했지만 나중에 이들이 별도의 커밋이어야 함을 결정한 경우에 유용할 수 있습니다.

Git Interactive Rebase를 사용하여 커밋 메시지를 편집하려면 어떻게 해야 하나요?

대화형 리베이스 중에 커밋 메시지를 편집할 수 있습니다. 커밋 목록에서 편집하려는 커밋 옆에 pickreword 또는 r로 바꿉니다. 계속하면 Git은 reword로 표시된 각 커밋에 대해 텍스트 편집기를 열어 커밋 메시지를 변경할 수 있게 해줍니다.

Git Rebase와 Git Pull의 차이점은 무엇인가요?

Git Pull은 원격 저장소의 변경 사항을 가져와서 현재 브랜치에 병합하는 명령어입니다. 반면에 Git Rebase는 일련의 커밋을 새로운 기준 커밋으로 이동하거나 결합하는 명령어입니다. 두 명령어 모두 변경 사항을 통합하는 데 사용되지만, 그렇게 하는 방식이 다릅니다.

Git Interactive Rebase를 사용하여 커밋의 순서를 변경할 수 있나요?

예, Git Interactive Rebase를 사용하여 커밋의 순서를 변경할 수 있습니다. 커밋 목록에서 라인의 순서를 변경하면 커밋의 순서가 변경됩니다. 커밋 기록을 더 논리적이고 명확하게 만들고 싶을 때 유용합니다.

Source:
https://www.sitepoint.com/git-interactive-rebase-guide/