Git rebase 및 강제 푸시

Git에서 재베이스는 다른 브랜치의 내용으로 여러분의 브랜치를 업데이트합니다. 재베이스는 여러분의 브랜치의 변경 사항이 대상 브랜치의 변경 사항과 충돌하지 않음을 확인합니다.

Merge 충돌이 발생하면 이를 해결하기 위해 재베이스할 수 있습니다.

재베이스 중 발생하는 일

재베이스할 때:

  1. Git은 여러분이 초기에 브랜치를 생성한 후 대상 브랜치에 제출된 모든 커밋을 가져옵니다.
  2. Git은 여러분이 가진 커밋을 해당 브랜치에서 가져온 모든 커밋 위에 쌓습니다:

    Git rebase illustration

대부분의 재베이스는 main 대상으로 수행하지만, 다른 브랜치(ex. release-15-3)로도 재베이스할 수 있습니다. 또한 origin 대신 upstream과 같은 다른 원격 리포지터리를 지정할 수도 있습니다.

caution
git rebase는 커밋 히스토리를 재작성합니다. 이는 공유 브랜치에서 이 작업을 하는 것이 해로울 수 있습니다. 이로 인해 복잡하고 해결하기 어려운 Merge 충돌이 발생할 수 있습니다. 기본 브랜치에 대해 여러분의 브랜치를 재베이스 하는 대신, 이를 대신하여 풀링하는 것을 고려해보세요 (git pull origin master). 풀링은 다른 사람의 작업을 침해할 위험이 적은 유사한 효과를 가지고 있습니다.

Git을 사용한 재베이스

Git을 사용하여 재베이스할 때 각 커밋이 여러분의 브랜치에 적용됩니다. Merge 충돌이 발생하면 해결 방법을 선택하라는 메시지가 표시됩니다.

커밋에 대해 더 고급 옵션을 원한다면 대화식 재베이스를 수행하세요.

필수 조건:

  • 브랜치에 강제 푸시할 수 있는 권한이 있어야 합니다.

Git을 사용하여 브랜치를 대상 브랜치에 재베이스하려면:

  1. 터미널을 열고 프로젝트로 이동합니다.
  2. 대상 브랜치의 최신 내용을 가져왔는지 확인합니다. 이 예시에서 대상 브랜치는 main입니다:

    git fetch origin main
    
  3. 브랜치를 확인합니다:

    git checkout my-branch
    
  4. 옵션. 브랜치의 백업을 만듭니다:

    git branch my-branch-backup
    

    이 시점 이후에 my-branch에 추가된 변경 사항은 백업 브랜치를 복원하면 손실됩니다.

  5. 메인 브랜치를 대상으로 재베이스합니다:

    git rebase origin/main
    
  6. Merge 충돌이 존재하면:
    1. 에디터에서 충돌을 해결합니다.

    2. 파일을 추가합니다:

      git add .
      
    3. 재베이스를 계속합니다:

      git rebase --continue
      
  7. 다른 사람의 커밋을 보호하면서 대상 브랜치로 변경 사항을 강제로 푸시합니다:

    git push origin my-branch --force-with-lease
    

UI에서 재베이스

GitLab UI에서 Merge Request을 재베이스할 수 있습니다.

필수 조건:

  • Merge 충돌이 없어야 합니다.
  • 소스 프로젝트에 대해 적어도 개발자 역할을 가져야 합니다. 이 권한은 소스 프로젝트의 소스 브랜치로 푸시할 수 있는 권한을 부여합니다.
  • Merge Request이 fork인 경우, fork는 upstream 프로젝트의 구성원으로부터 커밋을 허용해야 합니다.

UI에서 재베이스하려면:

  1. Merge Request으로 이동합니다.
  2. 댓글에 /rebase를 입력합니다.
  3. 댓글을 선택합니다.

GitLab은 브랜치를 기본 브랜치로 재베이스하도록 계획하며 가능한 한 빨리 실행합니다.

Git을 사용하여 대화식으로 재베이스

각 커밋을 어떻게 처리할지 지정하려면 대화식 재베이스를 사용합니다. 이 명령은 명령줄에서 실행해야 합니다.

필수 조건:

  • 이 지침을 따르려면 Vim이 여러분의 텍스트 편집기여야 합니다.

대화식 재베이스를 위해:

  1. 터미널을 열고 프로젝트로 이동합니다.
  2. 대상 브랜치의 최신 내용을 가져왔는지 확인합니다. 이 예시에서 대상 브랜치는 main입니다:

    git fetch origin main
    
  3. 브랜치를 확인합니다:

    git checkout my-branch
    
  4. 옵션. 브랜치의 백업을 만듭니다:

    git branch my-branch-backup
    

    이 시점 이후에 my-branch에 추가된 변경 사항은 백업 브랜치를 복원하면 손실됩니다.

  5. GitLab UI에서 Merge Request에서 다시 확인하여 몇 개의 커밋을 재베이스할지 확인합니다.
  6. 이러한 커밋을 엽니다. 예를 들어, 브랜치에서 마지막 다섯 개의 커밋 (HEAD~5)을 편집하려면 다음과 같이 입력합니다:

    git rebase -i HEAD~5
    

    Git은 마지막 다섯 개의 커밋을 가장 오래된 커밋부터 터미널 텍스트 편집기에서 엽니다. 각 커밋은 적용할 작업, SHA, 커밋 제목이 표시됩니다:

    pick 111111111111 Second round of structural revisions
    pick 222222222222 Update inbound link to this changed page
    pick 333333333333 Shifts from H4 to H3
    pick 444444444444 Adds revisions from editorial
    pick 555555555555 Revisions continue to build the concept part out
       
    # Rebase 111111111111..222222222222 onto zzzzzzzzzzzz (5 commands)
    #
    # Commands:
    # p, pick <commit> = use commit
    # r, reword <commit> = use commit, but edit the commit message
    # e, edit <commit> = use commit, but stop for amending
    # s, squash <commit> = use commit, but meld into previous commit
    # f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
    
  7. i를 눌러 Vim의 편집 모드로 전환합니다.
  8. 키보드 화살표를 사용하여 디렉터리에서 두 번째 커밋으로 이동합니다.
  9. picksquash 또는 fixup(s 또는 f)로 변경합니다.
  10. 나머지 커밋에 대해 동일한 작업을 수행합니다. 첫 번째 커밋은 pick으로 남겨 둡니다.
  11. 편집 모드를 종료하고 저장한 후 빠져나갑니다:
    • ESC를 누릅니다.
    • :wq를 입력합니다.
  12. Squash하는 경우, Git은 커밋 메시지를 출력하여 편집할 수 있는 기회를 제공합니다:
    • #로 시작하는 모든 줄은 무시되고 커밋 메시지에 포함되지 않습니다. 나머지는 모두 포함됩니다.
    • 그대로 둘 경우 :wq를 입력합니다. 커밋 메시지를 편집하려면 편집 모드로 전환하고 커밋 메시지를 편집한 후 저장합니다.
  13. 대상 브랜치에 커밋합니다.
    • 만약 커밋을 재베이스하기 전에 대상 브랜치에 커밋을 푸시하지 않았다면 강제 푸시 없이 변경 사항을 푸시합니다:

      git push origin my-branch
      
    • 이미 이러한 커밋을 푸시했다면 강제 푸시를 사용합니다:

      git push origin my-branch --force-with-lease
      

강제 푸시

Git에서 복잡한 작업은 원격 브랜치를 강제로 업데이트해야 합니다. 커밋을 통합(Merge), 브랜치를 재설정하거나 리베이스하는 등의 작업은 브랜치의 히스토리를 변경합니다. Git은 이러한 보다 파괴적인 변경이 실수로 발생하는 것을 방지하기 위해 강제로 업데이트해야 합니다.

공유 브랜치에서는 강제 푸시를 권장하지 않습니다. 다른 사람의 변경 내용을 사전에 파괴할 수 있기 때문입니다.

강제로 푸시하려는 브랜치가 보호됨 경우, 다음 중 하나를 수행하지 않는 한 강제로 푸시할 수 없습니다:

그런 다음 강제로 푸시하고 다시 보호할 수 있습니다.

백업된 브랜치 복원

브랜치가 백업되고 있으며 리베이스나 강제 푸시를 시도할 수 있습니다. 어떤 문제가 발생하더라도 백업에서 브랜치를 복원할 수 있습니다:

  1. 올바른 브랜치에 있는지 확인합니다:

    git checkout my-branch
    
  2. 백업된 브랜치에 대해 브랜치를 재설정합니다:

    git reset --hard my-branch-backup
    

리베이스 후 승인

브랜치를 리베이스하면 커밋이 추가됩니다. 프로젝트가 구성되어 있다면 커밋을 추가하는 사용자의 승인을 방지하도록 되어 있으면 리베이스한 Merge Request에 대해 승인할 수 없습니다.

관련 주제

문제 해결

/rebase 퀵 액션 후 Unmergeable state

/rebase 명령은 백그라운드 작업을 예약합니다. 해당 작업은 소스 브랜치의 변경 내용을 대상 브랜치의 최신 커밋에 리베이스하려고 시도합니다. /rebase 빠른 액션을 사용한 후에 이러한 오류가 발생하면 리베이스를 예약할 수 없습니다:

This merge request is currently in an unmergeable state, and cannot be rebased.

이 오류는 다음 조건 중 하나라도 해당되는 경우에 발생합니다:

  • 소스 및 대상 브랜치 간에 충돌이 있습니다.
  • 소스 브랜치에 커밋이 없습니다.
  • 소스 또는 대상 브랜치 중 하나가 존재하지 않습니다.
  • 차이가 생성되지 않는 오류가 발생했습니다.

unmergeable state 오류를 해결하려면:

  1. 모든 Merge 충돌을 해결합니다.
  2. 소스 브랜치가 존재하고 커밋이 있는지 확인합니다.
  3. 대상 브랜치가 존재하는지 확인합니다.
  4. 차이가 생성되었는지 확인합니다.

/rebase 후에 /merge 퀵 액션이 무시됨

/rebase가 사용된 경우, 레이스 조건을 피하기 위해 /merge는 무시됩니다. 이렇게 하면 소스 브랜치가 리베이스되거나 삭제되기 전에 머지되지 않도록 합니다.