Git rebase와 강제 푸시

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

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

리베이스 중 발생하는 일들

리베이스하는 경우:

  1. 여러분이 브랜치를 처음 생성한 후에 대상 브랜치에 제출된 모든 커밋이 Git에 의해 가져와집니다.
  2. Git은 여러분의 브랜치에 있는 모든 커밋을 가져온 브랜치의 모든 커밋 위에 쌓습니다:

    Git rebase illustration

대부분의 리베이스는 main에 대해 수행되지만, release-15-3와 같은 다른 브랜치에도 리베이스할 수 있습니다. 또한 origin 대신에 upstream과 같은 다른 원격 저장소를 지정할 수도 있습니다.

경고: git rebase는 커밋 이력을 다시 작성합니다. 이 작업은 공유 브랜치에서 수행시 해로운 결과를 초래할 수 있습니다. 이는 복잡하고 해결하기 어려운 병합 충돌을 유발할 수 있습니다. 여러분의 브랜치를 기본 브랜치에 대해 리베이스하는 대신에 이를 대신해서 가져오는 것(git pull origin master)을 고려해보세요. 가져오기는 비슷한 효과를 가지고 있지만 다른 사람들의 작업을 손상시키는 위험이 덜합니다.

Git을 사용한 리베이스

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

커밋에 대해 더 고급스러운 옵션이 필요한 경우 대화형 리베이스를 수행하세요.

전제 조건:

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

Git을 사용하여 브랜치를 대상 브랜치에 대해 리베이스하려면 다음을 수행하세요:

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

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

    git checkout my-branch
    
  4. 선택 사항. 브랜치의 백업을 만듭니다:

    git branch my-branch-backup
    

    이 지점 이후에 my-branch에 추가된 변경 내용은 백업 브랜치에서 복원할 경우 손실됩니다.

  5. main 브랜치 대상 리베이스:

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

    2. 파일을 추가합니다:

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

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

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

UI에서 리베이스하기

GitLab UI에서 병합 요청을 리베이스할 수 있습니다.

전제 조건:

  • 병합 충돌이 존재하지 않아야 합니다.
  • 소스 프로젝트에 대해 적어도 개발자 역할을 가져야 합니다. 이 역할을 가지면 소스 프로젝트의 소스 브랜치에 푸시할 수 있는 권한이 주어집니다.
  • 만약 병합 요청이 forked된 상태라면, fork가 상위 프로젝트의 구성원으로부터 커밋을 허용해야 합니다.

UI에서 리베이스하려면:

  1. 병합 요청으로 이동합니다.
  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에서 병합 요청에 들어가서 리베이스할 커밋의 수를 확인합니다.

  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)
    #
    # 명령어:
    # p, pick <commit> = 커밋 사용
    # r, reword <commit> = 커밋 사용, 그러나 커밋 메시지 편집
    # e, edit <commit> = 커밋 사용, 그러나 수정할 준비를 멈춤
    # s, squash <commit> = 커밋 사용, 그러나 이전 커밋과 합침
    # f, fixup [-C | -c] <commit> = "squash"와 유사하지만 이전 커밋만 유지
    
  7. i를 눌러 Vim의 편집 모드로 전환합니다.
  8. 키보드 화살표를 사용하여 목록에서 두 번째 커밋으로 이동합니다.
  9. picksquash 또는 fixup(또는 s 또는 f)로 변경합니다.
  10. 나머지 커밋도 같은 작업을 수행합니다. 첫 번째 커밋은 pick으로 남깁니다.
  11. 편집 모드를 종료하고 저장 후 나갑니다:

    • ESC를 누릅니다.
    • :wq를 입력합니다.
  12. 합치기를 수행할 때 Git은 커밋 메시지를 표시하여 편집할 수 있도록 합니다:

    • #으로 시작하는 모든 줄은 무시되고 커밋 메시지에 포함되지 않습니다. 그 외의 내용만 포함됩니다.
    • 그대로 둘 경우 :wq를 입력합니다. 커밋 메시지를 편집하려면 편집 모드로 전환하여 커밋 메시지를 편집한 후 저장합니다.
  13. 대상 브랜치에 커밋합니다.

    • 리베이스하기 전에 커밋을 대상 브랜치에 푸시하지 않았다면 강제 푸시 없이 변경 내용을 푸시합니다:

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

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

Force pushing

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

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

만약 강제 푸시하려는 브랜치가 보호된 상태라면, 브랜치를 보호 해제하거나 강제 푸시를 허용해야 합니다. 그 후에 강제 푸시하고 다시 보호할 수 있습니다.

백업된 브랜치 복원

브랜치가 백업되었고, 리베이스 또는 강제 푸시를 시도할 수 있습니다. 만약 문제가 발생하면, 백업에서 브랜치를 복원할 수 있습니다:

  1. 올바른 브랜치인지 확인하세요:

    git checkout my-branch
    
  2. 백업으로 브랜치 다시 설정하기:

    git reset --hard my-branch-backup
    

리베이스 후 승인

브랜치를 리베이스했다면 커밋이 추가되었습니다. 만약 프로젝트가 커밋을 추가하는 사용자의 승인을 방지하도록 구성되어 있다면, 리베이스한 머지 요청을 승인할 수 없습니다.

관련 주제

문제 해결

/rebase 퀵 액션 후 Unmergeable state

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

이 머지 요청은 현재 병합할 수 없는 상태이며, 리베이스할 수 없습니다.

이 오류는 다음 중 하나의 조건이 충족될 때 발생합니다:

  • 소스 브랜치와 대상 브랜치 사이에 충돌이 있음.
  • 소스 브랜치에 커밋이 없음.
  • 소스 또는 대상 브랜치가 존재하지 않음.
  • 오류가 발생하여 차이가 생성되지 않음.

unmergeable state 오류를 해결하려면:

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

/rebase/merge 빠른 액션이 무시됨

/rebase를 사용하면, 경주 상태가 발생하지 않도록 소스 브랜치가 리베이스되거나 삭제되기 전에 /merge가 무시됩니다.