git rebase --onto의 동작을 이해할 수 없습니다
git 명령을 따르는 두 블록이 다른 동작을하며 그 이유를 이해하지 못합니다.
나는 하나와 분기 A
하는 B
지점과commit
---COMMIT--- (A)
\
--- (B)
가장 마지막에 B
지점 을 리베이스하고 싶습니다 A
(및 지점에 커밋을 가짐 B
)
---COMMIT--- (A)
\
--- (B)
내가해도 문제가 없습니다.
checkout B
rebase A
그러나 내가하면 :
checkout B
rebase --onto B A
전혀 작동하지 않으며 아무 일도 일어나지 않습니다. 두 동작이 다른 이유를 이해하지 못합니다.
Phpstorm git 클라이언트는 두 번째 구문을 사용하므로 완전히 깨진 것처럼 보이 므로이 구문 문제를 묻습니다.
tl; dr
귀하의 경우 B
에 A
사용 하는 것 외에 rebase하는 올바른 구문 git rebase --onto
은 다음과 같습니다.
git checkout B
git rebase --onto A B^
또는 REBASE B
의 상단 A
으로부터 시작하는 그의 부모 커밋B
로 참조 B^
하거나 B~1
.
당신 git rebase <branch>
과 의 차이점에 관심이 있다면 git rebase --onto <branch>
.
빠른 : 자식 리베이스
git rebase <branch>
에 의해 참조 현재 체크 아웃 한 분기를, 리베이스 것입니다 HEAD
의 상단에, 최신가에 도달 할 수 커밋 에서 <branch>
하지만, 하지 에서 HEAD
.
이것은 가장 일반적인 rebasing의 경우이며 아마도 계획을 덜 필요로하는 경우입니다.
Before After
A---B---C---F---G (branch) A---B---C---F---G (branch)
\ \
D---E (HEAD) D---E (HEAD)
이 예에서 F
및 G
에서 도달 할 수 branch
있지만에서 도달 할 수 없는 커밋입니다 HEAD
. 말하는 git rebase branch
소요됩니다 D
(가) 먼저 분기 시점 이후 커밋입니다, 그리고 그것을 리베이스 (즉, 부모를 변경 에서 연결할 최신의 상단에) 커밋 branch
아니라에서 HEAD
입니다, G
.
정확한 : git rebase --onto 2 arguments
git rebase --onto
특정 커밋에서 시작 하여 리베이스 할 수 있습니다 . 리베이트 대상과 위치를 정확하게 제어 할 수 있습니다. 이것은 정확해야하는 시나리오를위한 것입니다.
예를 들어에서 시작하여 HEAD
정확하게 리베이스해야한다고 가정 해 봅시다 . 우리는 작업 지점으로 가져 오는 데 관심이 있지만 동시에 호환되지 않는 변경 사항이 포함되어 있기 때문에 유지하고 싶지 않습니다.F
E
F
D
Before After
A---B---C---F---G (branch) A---B---C---F---G (branch)
\ \
D---E---H---I (HEAD) E---H---I (HEAD)
이 경우에는이라고 말할 것 git rebase --onto F D
입니다. 이것은 다음을 의미합니다.
HEAD
부모가D
에 도달 할 수있는 커밋을 리베이스합니다F
.
즉, 의 부모 를 E
에서 D
로 변경하십시오F
. 의 구문은 git rebase --onto
입니다 git rebase --onto <newparent> <oldparent>
.
이것이 유용한 또 다른 시나리오는 대화식 리베이스 를 수행하지 않고 현재 분기에서 일부 커밋을 신속하게 제거하려는 경우입니다 .
Before After
A---B---C---E---F (HEAD) A---B---F (HEAD)
이 예에서 순서대로 제거하기 C
와 E
순서에서 당신은 말할 것입니다 git rebase --onto B E
, 또는 리베이스 HEAD
위에 B
오래된 부모가 어디 E
.
외과 의사 : git rebase --onto 3 arguments
git rebase --onto
정밀도 측면에서 한 단계 더 나아갈 수 있습니다. 실제로, 임의의 커밋 범위 를 다른 커밋 위에 리베이스 할 수 있습니다 .
예를 들면 다음과 같습니다.
Before After
A---B---C---F---G (branch) A---B---C---F---G (branch)
\ \
D---E---H---I (HEAD) E---H (HEAD)
이 경우, 우리는 정확한 범위 리베이스 할 E---H
위에을 F
위치를 무시하고, HEAD
현재 가리키고 있습니다. 우리는 다음과 같이 말함으로써 그렇게 할 수 있습니다 git rebase --onto F D H
.
부모 커밋의 범위 리베이스
D
까지H
의 위에을F
.
그러면 커밋 범위git rebase --onto
가있는 구문 이됩니다 . 트릭은 여기에 의해 참조 커밋 것을 기억한다 됩니다 포함 범위와 새로운 될 것 REBASE가 완료된 후.git rebase --onto <newparent> <oldparent> <until>
<until>
HEAD
이것은 당신이 알아야 할 모든 것입니다 --onto
:
git rebase --onto <newparent> <oldparent>
커밋에서 부모를 전환하고 있지만 커밋의 샤를 제공하지 않고 현재 (오래된) 부모의 샤만 제공합니다.
간단히, git rebase --onto
커밋 범위를 선택하고 커밋을 매개 변수로 지정하여 리베이스합니다.
의 매뉴얼 페이지를 읽고 git rebase
"onto"를 검색하십시오. 예제는 매우 좋습니다 :
example of --onto option is to rebase part of a branch. If we have the following situation:
H---I---J topicB
/
E---F---G topicA
/
A---B---C---D master
then the command
git rebase --onto master topicA topicB
would result in:
H'--I'--J' topicB
/
| E---F---G topicA
|/
A---B---C---D master
이 경우 git에게 커밋을에서 rebase로 리베이스하도록 topicA
지시 topicB
합니다 master
.
다음과 같이 주어진다 :
Before rebase After rebase
A---B---C---F---G (branch) A---B---C---F---G (branch)
\ \ \
D---E---H---I (HEAD) \ E'---H' (HEAD)
\
D---E---H---I
git rebase --onto F D H
Which is the same as (because --onto
takes one argument):
git rebase D H --onto F
Means rebase commits in range (D, H] on top of F. Notice the range is left-hand exclusive. It's exclusive because it's easier to specify 1st commit by typing e.g. branch
to let git
find the 1st diverged commit from branch
i.e. D
which leads to H
.
OP case
o---o (A)
\
o (B)(HEAD)
git checkout B
git rebase --onto B A
Can be changed to single command:
git rebase --onto B A B
What looks like error here is placement of B
which means "move some commits which lead to branch B
on top of B
". The questions is what "some commits" are. If you add -i
flag you will see it is single commit pointed by HEAD
. The commit is skipped because it is already applied to --onto
target B
and so nothing happens.
The command is nonsense in any case where branch name is repeated like that. This is because the range of commits will be some commits which are already in that branch and during rebase all of them will be skipped.
Further explanation and applicable usage of git rebase <upstream> <branch> --onto <newbase>
.
git rebase
defaults.
git rebase master
Expands to either :
git rebase --onto master master HEAD
git rebase --onto master master current_branch
Automatic checkout after rebase.
When used in standard way, like:
git checkout branch
git rebase master
You won't notice that after rebase git
moves branch
to most recently rebased commit and does git checkout branch
(see git reflog
history). What is interesting when 2nd argument is commit hash instead branch name rebase still works but there is no branch to move so you end up in "detached HEAD" instead being checked out to moved branch.
Omit primary diverged commits.
The master
in --onto
is taken from 1st git rebase
argument.
git rebase master
/ \
git rebase --onto master master
So practicaly it can be any other commit or branch. This way you can limit number of rebase commits by taking the latest ones and leaving primary diverged commits.
git rebase --onto master HEAD~
git rebase --onto master HEAD~ HEAD # Expanded.
Will rebase single commit pointed by HEAD
to master
and end up in "detached HEAD".
Avoid explicit checkouts.
The default HEAD
or current_branch
argument is contextually taken from place you're in. This is why most people checkout to branch which they want to rebase. But when 2nd rebase argument is given explicitly you don't have to checkout before rebase to pass it in implicit way.
(branch) $ git rebase master
(branch) $ git rebase master branch # Expanded.
(branch) $ git rebase master $(git rev-parse --abbrev-ref HEAD) # Kind of what git does.
This means you can rebase commits and branches from any place. So together with Automatic checkout after rebase. you don't have to separately checkout rebased branch before or after rebase.
(master) $ git rebase master branch
(branch) $ # Rebased. Notice checkout.
For onto
you need two additional branches. With that command you can apply commits from branchB
that are based on branchA
onto another branch e.g. master
. In the sample below branchB
is based on branchA
and you want to apply the changes of branchB
on master
without applying the changes of branchA
.
o---o (master)
\
o---o---o---o (branchA)
\
o---o (branchB)
by using the commands:
checkout master
rebase --onto branchA branchB
you will get following commit hierarchy.
o'---o' (branchB)
/
o---o (master)
\
o---o---o---o (branchA)
There is another case where git rebase --onto
is hard to grasp: when you rebase onto a commit resulting of a symmetric difference selector (the three dots '...
')
Git 2.24 (Q4 2019) does a better job of managing that case:
See commit 414d924, commit 4effc5b, commit c0efb4c, commit 2b318aa (27 Aug 2019), and commit 793ac7e, commit 359eceb (25 Aug 2019) by Denton Liu (Denton-L
).
Helped-by: Eric Sunshine (sunshineco
), Junio C Hamano (gitster
), Ævar Arnfjörð Bjarmason (avar
), and Johannes Schindelin (dscho
).
See commit 6330209, commit c9efc21 (27 Aug 2019), and commit 4336d36 (25 Aug 2019) by Ævar Arnfjörð Bjarmason (avar
).
Helped-by: Eric Sunshine (sunshineco
), Junio C Hamano (gitster
), Ævar Arnfjörð Bjarmason (avar
), and Johannes Schindelin (dscho
).
(Merged by Junio C Hamano -- gitster
-- in commit 640f9cd, 30 Sep 2019)
rebase
: fast-forward--onto
in more casesBefore, when we had the following graph,
A---B---C (master) \ D (side)
running '
git rebase --onto master... master side
' would result inD
being always rebased, no matter what.
At this point, read "What are the differences between double-dot '..
' and triple-dot "...
" in Git diff commit ranges?"
Here: "master...
" refers to master...HEAD
, which is B
: HEAD is side HEAD (currently checked out): you are rebasing onto B
.
What are you rebasing? Any commit not in master, and reachable from side
branch: there is only one commit fitting that description: D
... which is already on top of B
!
Again, before Git 2.24, such a rebase --onto
would result in D
being always rebased, no matter what.
However, the desired behavior is that rebase should notice that this is fast-forwardable and do that instead.
That is akin to the rebase --onto B A
of the OP, which did nothing.
Add detection to
can_fast_forward
so that this case can be detected and a fast-forward will be performed.
First of all, rewrite the function to use gotos which simplifies the logic.
Next, since theoptions.upstream && !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)
conditions were removed in
cmd_rebase
, we reintroduce a substitute incan_fast_forward
.
In particular, checking the merge bases ofupstream
andhead
fixes a failing case int3416
.The abbreviated graph for t3416 is as follows:
F---G topic
/
A---B---C---D---E master
and the failing command was
git rebase --onto master...topic F topic
Before, Git would see that there was one merge base (
C
, result ofmaster...topic
), and the merge and onto were the same so it would incorrectly return 1, indicating that we could fast-forward. This would cause the rebased graph to be 'ABCFG
' when we were expecting 'ABCG
'.
A rebase --onto C F topic
means any commit after F
, reachable by topic
HEAD: that is G
only, not F
itself.
Fast-forwarding in this case would include F
in the rebased branch, which is wrong.
With the additional logic, we detect that upstream and head's merge base is
F
. Since onto isn'tF
, it means we're not rebasing the full set of commits frommaster..topic
.
Since we're excluding some commits, a fast-forward cannot be performed and so we correctly return 0.Add '
-f
' to test cases that failed as a result of this change because they were not expecting a fast-forward so that a rebase is forced.
참고URL : https://stackoverflow.com/questions/29914052/i-cant-understand-the-behaviour-of-git-rebase-onto
'development' 카테고리의 다른 글
장고 디버그 툴바가 표시되지 않음 (0) | 2020.07.02 |
---|---|
현재 시간이 시간 범위에 속하는지 확인 (0) | 2020.07.02 |
iPhone 5 CSS 미디어 쿼리 (0) | 2020.07.02 |
Android : 갤러리에서로드 된 비트 맵이 ImageView에서 회전 됨 (0) | 2020.07.02 |
Google Maps V3-특정 범위의 확대 / 축소 수준을 계산하는 방법 (0) | 2020.07.02 |