git rebase

이 문서에서는 git rebase 명령을 자세히 살펴봅니다. 리포지토리 설정기록 다시 쓰기 페이지에서도 rebase 명령을 살펴보았습니다. 이 페이지에서는 git rebase 구성 및 실행에 대해 더 자세히 살펴보겠습니다. 여기서는 일반적인 rebase 사용 사례와 위험에 대해 다룹니다.

rebase는 한 브랜치에서 다른 브랜치로 변경 사항을 통합하는 데 특화된 두 가지 Git 유틸리티 중 하나입니다. 또 다른 변경 통합 유틸리티는 git merge입니다. 병합은 항상 앞으로 이동하는 변경 기록입니다. 또는 rebase에는 강력한 기록 다시 쓰기 기능이 있습니다. 병합 및 rebase 비교에 대한 자세한 내용은 병합 및 rebase 비교 가이드를 참조하세요. rebase 자체에는 "수동" 모드와 "대화형" 모드의 두 가지 주요 모드가 있습니다. 아래에서 다양한 rebase 모드에 대해 자세히 설명하겠습니다.

Git rebase란 무엇입니까?

rebase는 커밋 시퀀스를 새 기준 커밋으로 이동하거나 결합하는 프로세스입니다. rebase는 가장 유용하며 기능 브랜치 워크플로의 컨텍스트에서 쉽게 시각화됩니다. 전체 프로세스는 다음과 같이 시각화할 수 있습니다.

Git 자습서: Git rebase

콘텐츠 관점에서 보면 rebase는 브랜치의 기준을 한 커밋에서 다른 커밋으로 변경하여 마치 다른 커밋에서 브랜치를 만든 것처럼 보이게 합니다. Git은 내부적으로 새 커밋을 만들고 지정된 기준에 적용하여 이것을 구현합니다. 브랜치가 동일하게 보이지만 완전히 새로운 커밋으로 구성되어 있음을 이해하는 것이 매우 중요합니다.

사용

rebase를 사용하는 주된 이유는 선형 프로젝트 기록을 유지하기 위한 것입니다. 예를 들어, 기능 브랜치에 대한 작업을 시작한 이후 메인 브랜치가 진행되는 경우를 고려하세요. 기능 브랜치의 메인 브랜치에 대한 최신 업데이트를 가져오지만 브랜치의 기록을 깨끗하게 유지하여 마치 최신 메인 브랜치에서 작업한 것처럼 보이게 하려고 합니다. 이렇게 하면 나중에 기능 브랜치를 메인 브랜치로 깨끗하게 병합하는 이점이 있습니다. "깨끗한 기록"을 유지하려는 이유는 무엇입니까? Git 작업을 수행하여 회귀 도입을 조사할 때 깨끗한 기록을 보유할 때의 이점이 명백해집니다. 현실에 더 가까운 시나리오는 다음과 같습니다.

  1. 메인 브랜치에서 버그가 식별됩니다. 성공적으로 작동하던 기능이 이제 손상되었습니다.
  2. 개발자는 git log를 사용하여 메인 브랜치의 기록을 조사합니다. 개발자는 "깨끗한 기록" 덕분에 프로젝트의 기록을 빠르게 추론할 수 있습니다.
  3. 개발자는 git log를 사용하여 버그가 도입된 시기를 식별할 수 없으므로 git bisect를 실행합니다.
  4. Git 기록이 깨끗하기 때문에 git bisect에는 회귀를 찾을 때 비교할 수 있도록 세분화된 커밋 집합이 있습니다. 개발자는 버그를 도입한 커밋을 빠르게 찾아 조치를 취할 수 있습니다.

개별 사용 페이지에서 git loggit bisect에 대해 자세히 알아보세요.

기능을 메인 브랜치에 통합하는 두 가지 옵션은 직접 병합 또는 rebase하고 병합이 있습니다. 전자 옵션은 결과적으로 3방향 병합과 병합 커밋이 되며, 후자는 빨리 감기 병합과 완벽한 선형 기록이 됩니다. 다음 다이어그램은 메인 브랜치를 rebase하여 빨리 감기 병합을 용이하게 하는 방법을 보여줍니다.

Git rebase: 마스터로 브랜치

rebase는 업스트림 변경 사항을 로컬 리포지토리에 통합하는 일반적인 방법입니다. Git 병합으로 업스트림 변경 사항을 가져오는 경우 프로젝트가 어떻게 진행되었는지 확인하고 싶을 때마다 불필요한 병합 커밋이 발생합니다. 반면에 rebase는 “모두가 이미 수행한 작업을 내 변경 사항의 기준으로 삼고 싶다”는 것과 비슷합니다.

공개 기록 rebase하지 않기

이전 기록 다시 쓰기에서 설명한 것처럼, 커밋이 공개 리포지토리로 푸시된 후에는 절대 rebase를 수행해서는 안 됩니다. rebase는 이전 커밋을 새 커밋으로 대체하고 프로젝트 기록의 일부가 갑자기 사라진 것처럼 보이게 합니다.

Git rebase 표준 및 Git rebase 대화형 비교

Git rebase 대화형은 Git rebase가 -- i 인수를 수락하는 경우입니다. i는 "대화형(interactive)"의 약자입니다. 인수가 없으면 명령이 표준 모드로 실행됩니다. 두 가지 경우 모두 별도의 기능 브랜치를 만들었다고 가정하겠습니다.

# Create a feature branch based off of main 
git checkout -b feature_branch main
# Edit files 
git commit -a -m "Adds new feature" 

표준 모드의 Git rebase는 현재 작업 중인 브랜치의 커밋을 자동으로 가져와서 전달된 브랜치의 헤드에 적용합니다.

git rebase <base>

이렇게 하면 현재 브랜치가 에 자동으로 rebase되며, 모든 종류의 커밋 참조(예: ID, 브랜치 이름, 태그 또는 HEAD에 대한 상대 참조)가 될 수 있습니다.

-i 플래그를 사용하여 git rebase를 실행하면 대화형 rebase 세션이 시작됩니다. 모든 커밋을 새 기준으로 맹목적으로 이동하는 대신 대화형 rebase를 사용하면 프로세스의 커밋을 개별적으로 변경할 수 있습니다. 이렇게 하면 일련의 기존 커밋을 제거, 분할 및 변경하여 기록을 정리할 수 있습니다. 강력한 Git commit --amend 명령과 같습니다.

git rebase --interactive <base>

현재 브랜치를 로 rebase하지만 대화형 rebase 세션을 사용합니다. 이렇게 하면 rebase할 각 커밋에 대한 명령(아래 설명)을 입력할 수 있도록 편집기가 열립니다. 이 명령은 개별 커밋이 새 기준으로 전송되는 방식을 결정합니다. 커밋 목록을 다시 정렬하여 커밋 자체의 순서를 변경할 수도 있습니다. rebase에서 각 커밋에 대한 명령을 지정하면 Git은 rebase 명령을 적용하는 커밋을 재생하기 시작합니다. rebase 편집 명령은 다음과 같습니다.




pick 2231360 some old commit
pick ee2adc2 Adds new feature


# Rebase 2cf755d..ee2adc2 onto 2cf755d (9 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit

추가 rebase 명령

기록 다시 쓰기 페이지에서 자세히 설명했듯이 rebase를 사용하여 이전 및 다중 커밋, 커밋된 파일 및 여러 메시지를 변경할 수 있습니다. 이 기능이 가장 일반적인 적용 분야이지만 git rebase에는 더 복잡한 적용 분야에서 유용할 수 있는 추가 명령 옵션도 있습니다.

  • git rebase -- d 명령은 재생 중에 최종 결합한 커밋 블록에서 커밋을 삭제한다는 의미입니다.
  • git rebase -- p는 커밋을 그대로 둡니다. 커밋의 메시지나 콘텐츠를 수정하지 않으며 브랜치 기록에서 여전히 개별 커밋이 됩니다.
  • git rebase -- x는 재생하는 동안 표시된 각 커밋에서 명령줄 셸 스크립트를 실행합니다. 유용한 예제는 특정 커밋에서 코드베이스의 테스트 도구 모음을 실행하는 것입니다. 이렇게 하면 rebase를 수행하는 동안 회귀를 식별하는 데 도움이 될 수 있습니다.

정리

대화형 rebase 기능을 사용하면 프로젝트의 기록을 완벽하게 제어할 수 있습니다. 이것을 통해 개발자는 코드 작성에 집중하면서 "복잡한" 기록을 커밋한 다음 다시 돌아가서 정리할 수 있으므로 개발자에게 많은 자유를 제공합니다.

대부분의 개발자는 기능 브랜치를 메인 코드 베이스에 병합하기 전에 대화형 rebase를 사용하여 다듬기를 좋아합니다. 이렇게 하면 “공식적인” 프로젝트 기록에 커밋하기 전에 중요하지 않은 커밋을 스쿼시하고, 사용하지 않는 커밋을 삭제하며, 다른 모든 항목이 순서에 맞는지 확인할 수 있습니다. 다른 사용자가 보기에는 전체 기능이 잘 계획된 단일 커밋으로 개발된 것처럼 보일 것입니다.

대화형 rebase의 진정한 위력은 결과 메인 브랜치의 기록에서 확인할 수 있습니다. 다른 사용자에게는 처음부터 완벽한 커밋으로 새 기능을 구현한 훌륭한 개발자로 보일 것입니다. 대화형 rebase를 통해 프로젝트 기록을 깨끗하고 의미 있게 유지할 수 있습니다.

구성 옵션

git config를 사용하여 설정할 수 있는 몇 가지 rebase 속성이 있습니다. 이 옵션은 git rebase 출력의 디자인을 변경합니다.

  • rebase.stat: 기본값이 false로 설정된 부울입니다. 이 옵션은 마지막 rebase 이후 변경된 내용을 보여주는 시각적 diffstat 콘텐츠의 표시를 토글합니다.
  • rebase.autoSquash: --autosquash 동작을 토글하는 부울 값입니다.
  • rebase.missingCommitsCheck: 누락된 커밋을 둘러싼 rebase 동작을 변경하는 여러 값으로 설정할 수 있습니다.
warn 대화형 모드에서 경고 출력을 인쇄하여 제거된 커밋에 대해 경고

error

rebase를 중지하고 제거된 커밋 경고 메시지 인쇄

ignore

기본값 설정으로 누락된 커밋 경고 무시
  • rebase.instructionFormat: 대화형 rebase 표시의 형식을 지정하는 데 사용되는 git log 형식 문자열

고급 rebase 적용 분야

명령줄 인수 --ontogit rebase에 전달할 수 있습니다. git rebase --onto 모드일 때 명령은 다음과 같이 확장됩니다.

 git rebase --onto <newbase> <oldbase>

--onto 명령을 사용하면 특정 ref를 rebase의 팁으로 전달하는 보다 강력한 형식 또는 rebase를 사용할 수 있습니다.
다음과 같은 브랜치가 있는 리포지토리 예제를 가정해 보겠습니다.


   o---o---o---o---o  main
        \
         o---o---o---o---o  featureA
              \
               o---o---o  featureB

featureB는 featureA를 기본으로 하지만 featureB는 featureA의 변경 사항에 의존하지 않으며 메인에서 분기할 수 있음을 알 수 있습니다.

 git rebase --onto main featureA featureB

featureA는 < oldbase >입니다. main< newbase >가 되고, featureB는 < newbase >HEAD가 가리킬 참조입니다. 결과는 다음과 같습니다.

 
                      o---o---o  featureB
                     /
    o---o---o---o---o  main
     \
      o---o---o---o---o  featureA
                           

rebase의 위험 이해

Git rebase로 작업할 때 고려해야 할 주의 사항은 rebase 워크플로 중에 병합 충돌이 더 자주 발생할 수 있다는 것입니다. 수명이 긴 브랜치가 메인에서 벗어나는 경우 발생합니다. 결국 메인을 기준으로 rebase하고 싶을 것이고, 이때 브랜치 변경 사항이 충돌할 수 있는 새 커밋이 메인에 많을 수 있습니다. 이 문제는 브랜치를 메인을 기준으로 자주 rebase하고 커밋을 더 자주 수행하여 쉽게 해결할 수 있습니다. --continue--abort 명령줄 인수를 git rebase에 전달하여 충돌을 처리할 때 rebase를 진행하거나 다시 설정할 수 있습니다.

더 심각한 rebase 관련 주의 사항은 대화형 기록 다시 쓰기로 인해 손실되는 커밋입니다. 대화형 모드에서 rebase를 실행하고 squash 또는 drop과 같은 하위 명령을 실행하면 브랜치의 바로 옆 로그에서 커밋이 제거됩니다. 언뜻 보기에는 커밋이 영구적으로 사라진 것처럼 보일 수 있습니다. git reflog를 사용하면 이 커밋을 복원하고 전체 rebase를 실행 취소할 수 있습니다. git reflog를 사용하여 손실된 커밋을 찾는 방법에 대한 자세한 내용은 Git reflog 설명서 페이지를 참조하세요.

Git rebase 자체는 심각하게 위험하지 않습니다. 실제 위험 사례는 기록을 다시 작성하는 대화형 rebase 실행하고 다른 사용자가 공유하는 원격 브랜치로 결과를 강제 푸시할 때 발생합니다. 다른 원격 사용자가 풀을 할 때 다른 작업을 덮어쓸 수 있으므로 피해야 하는 패턴입니다.

업스트림 rebase에서 복구

다른 사용자가 rebase하여 자신이 커밋하려는 브랜치로 강제 푸시한 경우 git pull은 자신이 이전 브랜치를 기반으로 한 커밋을 강제 푸시된 팁으로 덮어씁니다. 다행히 git reflog를 사용하면 원격 브랜치의 참조 로그를 얻을 수 있습니다. 원격 브랜치의 참조 로그에서 rebase되기 전에 ref를 찾을 수 있습니다. 그런 다음 위의 고급 rebase 애플리케이션 섹션에서 설명한 대로 --onto 옵션을 사용하여 원격 참조에 대해 브랜치를 rebase할 수 있습니다.

요약

이 문서에서는 git rebase 사용법을 다뤘습니다. 기본 및 고급 사용 사례와 고급 예제에 대해 논의했습니다. 몇 가지 주요 논의 사항은 다음과 같습니다.

  • Git rebase 표준 모드 및 대화형 모드 비교
  • Git rebase 구성 옵션
  • Git rebase --onto
  • Git rebase 손실된 커밋

git rebase 사용법을 git reflog, git fetch, git push와 같은 다른 도구와 함께 살펴봤습니다. 자세한 내용은 해당 페이지를 참조하세요.

Git을 배울 준비가 되었습니까?

이 대화형 자습서를 사용해 보세요.

지금 시작하기