git rebase
по подразбиране пребазира само към една линия на хронологията на ангажиментите, защото това е по-често това, което хората искат. Ако не му кажете друго, то ще го направи за клона, който сте проверили (във вашия случай това беше master
). Ето защо завършихте с пребазиран master
клон с foo
ангажименти, присадени, вместо обединени, и със самия foo
непроменен и вече несвързан.
Ако имате git версия 2.18 или по-нова, можете да използвате опцията --rebase-merges
*, за да кажете на git да пресъздаде хронологията на сливането, вместо да я линеаризира, както прави по подразбиране. Пребазираната хронология ще има същите разклонения и сливания обратно. По-долу ще ви преведа през стъпките за постигане на това, което искате, като използвате --rebase-merges
.
Тези стъпки предполагат точното репо, което показвате във вашия въпрос.
git checkout master
git rebase -i --rebase-merges f0e0796
- in the interactive rebase
todo
file:
- remove the two commits you wanted to drop (or comment them out, or change
pick
to drop
or d
)
- на нов ред непосредствено след ред
label foo
добавете следното:
exec git branch -f foo head
(see below for explanation)
- запазете и затворете todo файла и voilà, git ще пребазира ангажиментите, като графиката изглежда точно както искате.
файлът todo
е обяснен
git rebase
просто автоматизира поредица от стъпки, които можете също така да правите ръчно. Тази последователност от стъпки е представена във файла todo
. git rebase --interactive
ви позволява да промените последователността, преди да се изпълни.
Ще го поясня с обяснение, включително как бихте го направили ръчно (добър опит за учене). Важно е да усетите това, ако правите много пребазирания в бъдеще, така че да имате добра ориентация, когато възникнат конфликти при сливане, или когато кажете на пребазирането да паузира в точки, за да можете да направите някои ръчни модификации.
label onto // labels "rebase onto" commit (f0e0796)
// this is what you would do in your head
// if doing this manually
# Branch foo
reset onto // git reset --hard <onto>
drop 5ccb371 add B // skip this commit
drop a46df1c modify B // skip this commit
pick 8eb025b add C // git cherry-pick 8eb025b
label branch-point // label this commit so we can reset back to it later
pick f5b0116 add 1 // git cherry-pick f5b0116
pick 175e01f add 2 // git cherry-pick 175e01f
label foo // label this commit so we can merge it later
// This is just a rebase internal label.
// It does not affect the `foo` branch ref.
exec git branch -f foo head // point the `foo` branch ref to this commit
reset branch-point # add C // git reset --hard <branch-point>
merge -C b763a46 foo # Merge branch 'foo' // git merge --no-ff foo
// use comment from b763a46
exec git branch -f foo head
обяснено
Както споменах по-горе, git rebase работи само на един клон. Това, което тази exec
команда прави, е да промени реф foo
, за да сочи към текущия head
. Както можете да видите в последователността в todo файла, вие му казвате да направи това веднага след като е извършил последния комит на клона foo
("добавяне 2"), който е удобно означен като label foo
във todo файла.
Ако вече не се нуждаете от foo
ref (напр. това е клон на функция и това е последното му сливане), можете да пропуснете добавянето на този ред към файла със задачи.
Можете също така да пропуснете добавянето на този ред и отделно да насочите отново foo
към ангажимента, който искате, след като повторното базиране е направено:
git branch -f foo <hash of the rebased commit that should be the new head of `foo`>
Уведомете ме, ако имате въпроси.
*Ако имате по-стара версия на git, можете да използвате вече остарялата опция --preserve-merges
, въпреки че тя не е съвместима с интерактивния режим на rebase.
person
Inigo
schedule
24.04.2020
git rebase
или ръчно (отговорът ми показва и двете), е начинът да пренапишете, а не да промените историята . - person Inigo   schedule 24.04.2020