수색…


통사론

  • git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
  • git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
  • git rebase --continue | --skip | --abort | --edit-todo

매개 변수

매개 변수 세부
--잇다 병합 충돌을 해결 한 후 rebase 프로세스를 다시 시작하십시오.
- 항아리 리베이스 작업을 중단하고 HEAD를 원래 분기로 재설정하십시오. rebase 작업이 시작될 때 분기가 제공되면 HEAD는 분기로 재설정됩니다. 그렇지 않으면 헤드가 리베이스 작업이 시작된 시점으로 재설정됩니다.
--keep-empty 그 결과로 부모로부터 아무 것도 변하지 않는 커밋을 유지하십시오.
--버킷 현재 패치를 건너 뛰고 리베이스 프로세스를 다시 시작하십시오.
-m, --merge 병합 전략을 사용하여 리베이스하십시오. 재귀 (기본값) 병합 전략을 사용하면 리베이스가 업스트림 측에서 이름 변경을 인식 할 수 있습니다. 리베이스 병합은 업스트림 브랜치 맨 위에있는 작업 분기의 각 커밋을 재생하여 작동합니다. 이 때문에 병합 충돌이 일어 났을 때, 우리 측으로보고 된 측은 업스트림으로 시작하여 지금까지 리베이스 된 시리즈이며, 그것들은 작동중인 지점입니다. 즉, 측면이 서로 바뀝니다.
--stat 마지막 리베이스 이후에 업스트림이 변경된 것을 diffstat로 표시합니다. diffstat도 구성 옵션 rebase.stat에 의해 제어됩니다.
-x, --exec command 대화식 rebase 수행, 각 커밋과 실행 command 사이에서 멈춤

비고

리베이스는 저장소 히스토리를 효과적으로 재 작성한다는 점에 유의하십시오.

원격 저장소에있는 재사용 커밋은 다른 개발자가 사용하는 저장소 노드를 해당 개발의 기본 노드로 다시 쓸 수 있습니다. 자신이 무엇을하고 있는지 정확히 알지 못하면 변경 사항을 적용하기 전에 리베이스해야합니다.

로컬 브랜치 리베이스

리베이스 는 일련의 커밋을 다른 커밋의 맨 위에 다시 적용합니다.

분기를 rebase 하려면, 분기를 체크 아웃 한 다음 다른 분기의 맨 위에 rebase 하십시오.

git checkout topic
git rebase master  # rebase current branch onto master branch

이로 인해 :

      A---B---C topic
     /
D---E---F---G master

변화하다:

              A'--B'--C' topic
             /
D---E---F---G master

이러한 작업은 분기를 체크 아웃하고 즉시 리베이스하는 단일 명령으로 결합 될 수 있습니다.

git rebase master topic   # rebase topic branch onto master branch

중요 : 리베이스 후에 적용된 커밋은 다른 해시를 갖습니다. 이미 원격 호스트로 푸시 한 커밋을 리베이스하지 않아야한다. 결과는 무능력 수 있습니다 git push 수있는 유일한 옵션 떠나, 원격 호스트로 지역으로 업데이트 분기를 git push --force .

Rebase : 우리와 우리, 지역 및 원격

rebase는 "ours"와 "theirs"의 의미를 전환합니다.

git checkout topic
git rebase   master    # rebase topic branch on top of master branch

HEAD가 지적하는 것이 무엇이든간에 "우리"

리베이스가하는 첫 번째 작업은 HEADmaster 재설정하는 것입니다. 체리 피킹이 이전 브랜치 topic 에서 새로운 topic 으로 커밋되기 전에 (이전 topic 브랜치의 모든 커밋은 다시 쓰여지고 다른 해시로 식별됩니다).

병합 도구에서 사용되는 용어 ( 로컬 참조 또는 원격 참조 와 혼동해서는 안 됨)

=> local is master ("ours"),
=> remote is topic ("theirs")

즉 병합 /은 diff 도구로 상류 지점 선물을 의미 local ( master : 당신이 리베이스하는의 상단에있는 지점), 등의 작업 지점 remote ( topic : 분기가으로 업데이트되는)

+-----------------------------------------+
| LOCAL:master |    BASE   | REMOTE:topic |
+-----------------------------------------+
|             MERGED                      |
+-----------------------------------------+

그림의 역전

병합시 :

c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
    \
     \
      \--y--y--y <- other branch to merge

우리는 현재의 브랜치 topic 변경하지 않기 때문에, 우리가하고있는 것은 여전히 ​​우리가 작업하고있는 것입니다 (그리고 우리는 다른 브랜치에서 합병합니다)

c--c--x--x--x---------o(*)  MERGE, still on branch topic
    \       ^        /
     \     ours     /
      \            /
       --y--y--y--/  
               ^
              theirs

리베이스에서 :

그러나 rebase에서 rebase가하는 첫 번째 작업은 상류 지점을 검사하여 현재 커밋을 재생하는 것입니다.

c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
    \
     \
      \--y--y--y <- upstream branch

git rebase upstream 은 먼저 HEAD 를 업스트림 브랜치로 설정합니다. 따라서 이전의 "현재"작업 브랜치와 비교하여 'ours'와 'theirs'를 전환합니다.

c--c--x--x--x <- former "current" branch, new "theirs"
    \
     \
      \--y--y--y(*) <- set HEAD to this commit, to replay x's on it
               ^       this will be the new "ours"
               |
            upstream      

리베이스는 새로운 '우리' topic 토대에서 '그들의'커밋을 재생할 것입니다 :

c--c..x..x..x <- old "theirs" commits, now "ghosts", available through "reflogs"
    \
     \
      \--y--y--y--x'--x'--x'(*) <- topic  once all x's are replayed,
               ^                      point branch topic to this commit
               |
        upstream branch

대화 형베이스

이 예제는 대화 형 모드에서 git rebase 를 사용하는 방법을 설명하기위한 것입니다. git rebase 가 무엇인지, 무엇이 무엇인지에 대한 기본적인 이해가 있어야합니다.

대화식 rebase는 다음 명령을 사용하여 시작됩니다.

git rebase -i

-i 옵션은 대화식 모드를 나타냅니다. 대화식 rebase를 사용하여 사용자는 커밋 메시지를 변경하고 재정렬, 분할 및 / 또는 스쿼시 (하나에 결합) 커밋을 커밋 할 수 있습니다.

마지막 세 가지 커밋을 다시 정렬하려고한다고 가정 해보십시오. 이렇게하려면 다음을 실행할 수 있습니다.

git rebase -i HEAD~3

위의 명령을 실행하면 텍스트 편집기에서 파일이 열리고 커밋이 리베이스되는 방식을 선택할 수 있습니다. 이 예제의 목적을 위해 커밋 순서를 변경하고 파일을 저장 한 다음 편집기를 닫습니다. 이렇게하면 신청 한 순서대로 rebase가 시작됩니다. git log 를 확인하면 커밋이 지정한 새 순서로 표시됩니다.

재 작성 커밋 메시지

자, 커밋 메시지 중 하나가 모호하고 더 이해하기 쉽도록 결정했습니다. 같은 명령을 사용하여 마지막 세 커밋을 살펴 보겠습니다.

git rebase -i HEAD~3

대신 커밋으로 업데이트됩니다 순서를 재 배열, 우리가 변경됩니다이 시간 pick , 기본은합니다 reword 메시지를 변경하려는 경우 커밋에.

편집기를 닫으면 rebase가 시작되고 다시 말하기를 원하는 특정 커밋 메시지에서 멈 춥니 다. 이렇게하면 커밋 메시지를 원하는대로 변경할 수 있습니다. 메시지를 변경 한 후에는 편집기를 닫아 계속 진행하십시오.

커밋의 내용 변경하기

커밋 메시지를 변경하는 것 외에도 커밋에 의해 수행 된 변경 사항을 적용 할 수 있습니다. 그렇게하기 위해서 단지 하나의 커밋에 대해 edit 하기 위해 pick 을 변경하십시오. Git은 해당 커밋에 도달하면 중지하고 준비 영역에서 커밋의 원래 변경 사항을 제공합니다. 이제는 변경 사항을 unstaging하거나 새 변경 사항을 추가하여 이러한 변경 사항을 적용 할 수 있습니다.

스테이징 영역에 커밋에 필요한 모든 변경 사항이 포함되는 즉시 변경 사항을 적용하십시오. 이전 커밋 메시지가 표시되고 새 커밋을 반영하도록 조정할 수 있습니다.

단일 커밋을 여러개로 나누기

커밋을했지만 나중에이 커밋을 두 개 이상의 커밋으로 나눌 수 있다고 결정했다. 이전과 같은 명령을 사용하여 pickedit 바꾸고 Enter를 누르십시오.

이제 git은 편집을 위해 표시 한 커밋에서 멈추고 모든 내용을 준비 영역에 배치합니다. 이 시점에서 git reset HEAD^ 를 실행하여 커밋을 작업 디렉토리에 넣을 수 있습니다. 그런 다음 파일을 다른 순서로 추가하고 커밋 할 수 있습니다. 궁극적으로 단일 커밋을 n 개의 커밋으로 나눕니다.

여러 커밋을 하나의 커밋으로 스쿼시하기

어떤 작업을하고 여러 번의 커밋을 한 번 해본다고 가정 해 봅시다. 이를 위해 git rebase -i HEAD~3 을 수행하여 3 을 적절한 커밋 양으로 대체하십시오.

이 시간은 대체 picksquash 대신. 리베이스하는 동안, 당신이 부숴 야한다고 명령 한 커밋은 이전 커밋의 맨 위에 스쿼시됩니다. 대신에 하나의 커밋으로 바꾼다.

대화 형 Rebase 중단

대화 형 리베이스를 시작했습니다. 커밋을 선택하는 편집기에서 무언가가 잘못되었다고 판단한 경우 (예 : 커밋이 누락되었거나 잘못된 리베이스 대상을 선택한 경우) 리베이스를 중단하려고합니다.

이렇게하려면 모든 커밋과 동작을 삭제하면됩니다 (즉, # 기호로 시작하지 않는 모든 줄). 그러면 rebase가 중단됩니다!

편집기의 도움말 텍스트는 실제로이 힌트를 제공합니다.

# Rebase 36d15de..612f2f7 onto 36d15de (3 command(s))
#
# 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
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Note that empty commits are commented out

리베이스 후 밀기

때로는 rebase로 다시 쓰기 기록이 필요하지만 git push 는 기록을 다시 써서 그렇게하는 것에 대해 불평합니다.

이것은 git push --force 로 해결할 수 있지만 git push --force-with-lease 고려하면 로컬 원격 추적 분기가 원격의 분기 (예 : 누군가와 다른 경우)가 실패하기를 원한다는 것을 나타냅니다. 그렇지 않으면 마지막으로 가져온 후 리모컨으로 푸시됩니다. 이렇게하면 실수로 다른 사람이 최근에 올린 내용을 덮어 쓰지 않아도됩니다.

참고 : git push --force - 심지어 그 문제에 대한 --force-with-lease 브랜치의 히스토리를 다시 써주기 때문에 위험한 명령이 될 수 있습니다. 강요 당하기 전에 다른 사람이 브랜치를 당긴 경우, 로컬 히스토리와 원격 히스토리가 서로 다르기 때문에 git pull 또는 git fetch 오류가 발생합니다. 이로 인해 사용자에게 예기치 않은 오류가 발생할 수 있습니다. reflog를 충분히 살펴보면 다른 사용자의 작업을 복구 할 수 있지만 낭비되는 시간이 많이 걸릴 수 있습니다. 다른 참여자가있는 지사에 강제로 밀어 넣어야하는 경우 오류를 처리 할 필요가 없도록 조정을 시도하십시오.

초기 커밋으로 다시베이스하기

Git 1.7.12 부터 루트 커밋까지 리베이스 할 수있다. 루트 커밋은 저장소에서 만들어진 첫 번째 커밋이며 일반적으로 편집 할 수 없습니다. 다음 명령을 사용하십시오.

git rebase -i --root

코드 검토 전에 리베이스

개요

이 목표는 흩어져있는 모든 커밋을보다 의미있는 커밋으로 재구성하여보다 쉽게 ​​코드를 검토하는 것입니다. 한 번에 너무 많은 파일에 변경 레이어가 너무 많으면 코드 검토가 더 어려워집니다. 연대 기적으로 작성된 커밋을 주제별 커밋으로 재구성 할 수 있다면 코드 검토 프로세스가 더 쉬워집니다 (그리고 코드 검토 프로세스의 버그가 줄어들 가능성이 있습니다).

이 지나치게 간소화 된 예제는 더 나은 코드 리뷰를 수행 할 때 git을 사용하는 유일한 전략은 아닙니다. 그것은 내가하는 방식이며, 다른 사람들에게 코드 리뷰와 git history를 더 쉽고 / 좋게 만드는 방법을 고려하도록 고무시키는 것입니다.

이것은 또한 일반적으로 rebase의 힘을 교육적으로 보여줍니다.

이 예에서는 대화식 리베이스에 대해 알고 있다고 가정합니다.


가정 :

  • 당신은 master의 feature branch에서 작업하고 있습니다.
  • 귀하의 기능은 프론트 엔드, 백엔드, DB
  • 기능 브랜치에서 작업하는 동안 많은 커밋을 수행했습니다. 각 커밋은 한꺼번에 여러 레이어에 적용됩니다.
  • 당신은 (결국) 당신의 지사에서 단지 3 개의 커밋을 원한다.
    • 하나는 모든 프런트 엔드 변경 사항을 포함합니다.
    • 하나는 모든 백엔드 변경 사항을 포함합니다.
    • 하나는 모든 DB 변경 사항을 포함합니다.

계략:

  • 우리는 연대순 커밋을 "화제"커밋으로 변경하려고합니다.
  • 먼저 모든 커밋을 여러 개의 작은 커밋으로 나눕니다. 각 커밋은 한 번에 하나의 항목 만 포함합니다 (이 예에서는 주제가 프론트 엔드, 백엔드, DB 변경)
  • 그런 다음 주제별 커밋을 다시 정렬하고 단일 주제 커밋으로 '스쿼시'하세요.

예:

$ git log --oneline master..
975430b db adding works: db.sql logic.rb
3702650 trying to allow adding todo items: page.html logic.rb
43b075a first draft: page.html and db.sql
$ git rebase -i master

이것은 텍스트 편집기에 표시됩니다.

pick 43b075a first draft: page.html and db.sql
pick 3702650 trying to allow adding todo items: page.html logic.rb
pick 975430b db adding works: db.sql logic.rb

그것을 다음과 같이 변경하십시오.

e 43b075a first draft: page.html and db.sql
e 3702650 trying to allow adding todo items: page.html logic.rb
e 975430b db adding works: db.sql logic.rb

그러면 git은 한 번에 하나의 커밋을 적용합니다. 각 커밋 후에 프롬프트가 표시되고 다음을 수행 할 수 있습니다.

Stopped at 43b075a92a952faf999e76c4e4d7fa0f44576579... first draft: page.html and db.sql
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

$ git status
rebase in progress; onto 4975ae9
You are currently editing a commit while rebasing branch 'feature' on '4975ae9'.
  (use "git commit --amend" to amend the current commit)
  (use "git rebase --continue" once you are satisfied with your changes)

nothing to commit, working directory clean
$ git reset HEAD^ #This 'uncommits' all the changes in this commit.
$ git status -s
 M db.sql
 M page.html
$ git add db.sql  #now we will create the smaller topical commits
$ git commit -m "first draft: db.sql"
$ git add page.html
$ git commit -m "first draft: page.html"
$ git rebase --continue

그런 다음 모든 커밋에 대해 이러한 단계를 반복합니다. 결국, 당신은 이것을 가지고 있습니다 :

$ git log --oneline
0309336 db adding works: logic.rb
06f81c9 db adding works: db.sql
3264de2 adding todo items: page.html
675a02b adding todo items: logic.rb
272c674 first draft: page.html
08c275d first draft: db.sql

이제 rebase와 squash를 위해 rebase를 한 번 더 실행합니다.

$ git rebase -i master

이것은 텍스트 편집기에 표시됩니다.

pick 08c275d first draft: db.sql
pick 272c674 first draft: page.html
pick 675a02b adding todo items: logic.rb
pick 3264de2 adding todo items: page.html
pick 06f81c9 db adding works: db.sql
pick 0309336 db adding works: logic.rb

그것을 다음과 같이 변경하십시오.

pick 08c275d first draft: db.sql
s 06f81c9 db adding works: db.sql
pick 675a02b adding todo items: logic.rb
s 0309336 db adding works: logic.rb
pick 272c674 first draft: page.html
s  3264de2 adding todo items: page.html

주의 사항 : 시간순으로 커밋 된 순서대로 작은 항목의 커밋을 적용 / 스쿼시하도록 git rebase에 지시하십시오 . 그렇지 않으면 처리 할 거짓, 불필요한 병합 충돌이 발생할 수 있습니다.

대화식 rebase가 모두 끝나고 완료되면 다음과 같이 표시됩니다.

$ git log --oneline master..
74bdd5f adding todos: GUI layer
e8d8f7e adding todos: business logic layer
121c578 adding todos: DB layer

요약하다

이제 연대기 커밋을 주제 커밋으로 리베이스했습니다. 실생활에서는 매번이 작업을 수행 할 필요가 없지만,이를 원할 때나해야 할 때 지금 할 수 있습니다. 게다가, 잘하면 git rebase에 대해 더 많이 배웠다.

병합 대신 rebase를 자동으로 수행하도록 git-pull을 설정하십시오.

팀이 리베이스 기반 워크 플로우를 따르고 있다면, git pull 중에 새로 생성 된 각 브랜치가 병합 작업 대신 rebase 작업을 수행하도록 git을 설정하는 것이 좋습니다.

모든 브랜치가 자동으로 rebase되도록 설정하려면 .gitconfig 또는 .git/config 다음을 추가하십시오.

[branch]
autosetuprebase = always

명령 줄 : git config [--global] branch.autosetuprebase always

또는 --rebase 옵션이 전달 된 것처럼 항상 동작하도록 git pull 명령을 설정할 수 있습니다.

[pull]
rebase = true

명령 줄 : git config [--global] pull.rebase true

rebase 중 모든 커밋 테스트

pull 요청을하기 전에, 컴파일이 성공하고 테스트가 브랜치의 각 커밋에 대해 전달되는지 확인하는 것이 유용합니다. -x 매개 변수를 사용하여 자동으로 수행 할 수 있습니다.

예 :

git rebase -i -x make

대화 형 rebase를 수행 make 를 실행하기 make 각각의 커밋 후에 중지합니다. make 가 실패 make 경우, git은 문제를 수정하고 다음 과제를 선택하기 전에 커밋을 수정할 기회를 제공하기 위해 중단됩니다.

자동 저장 구성

Autostash는 로컬 변경에 rebase를 사용할 때 매우 유용한 구성 옵션입니다. 흔히 업스트림 브랜치에서 커밋을 가져와야 할 수도 있지만 아직 커밋 할 준비가되지 않은 경우가 많습니다.

그러나 작업 디렉토리가 깨끗하지 않으면 Git은 rebase를 시작할 수 없습니다. 구조에 Autostash :

git config --global rebase.autostash    # one time configuration
git rebase @{u}                         # example rebase on upstream branch

rebase가 끝날 때마다 autostash가 적용됩니다. rebase가 성공적으로 완료되었는지 또는 중단되었는지 여부는 중요하지 않습니다. 어느 쪽이든, 자동문이 적용됩니다. 리베이스가 성공하고 기본 커밋이 변경되면 자동 종료와 새로운 커밋간에 충돌이있을 수 있습니다. 이 경우 커밋하기 전에 충돌을 해결해야합니다. 이것은 수동으로 은닉 한 다음 적용한 경우와 다를 바 없으므로 자동으로 수행 할 때 단점은 없습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow