Как переделать ветку с переустановленной ветки?
Итак, моя история выглядит так:
o---o---o---o master
\
o---o---o A
\
o B
Итак, чтобы объяснить:
- У меня есть ветвь
A
, которая была запущена из master
- У меня есть ветвь
B
(только с 1 фиксацией), которая была запущена из A
Я хочу это:
o---o---o---o master
\
o---o---o A
\
o B
Что я сделал:
1).
git checkout A
git rebase master
Это привело к множеству конфликтов, которые после некоторого значительного времени, потраченного на исправление, возникли:
o---o---o---o master
\
o---o---o A
Это именно то, что я хотел.
(я не знаю, где B
сейчас)
2).
После этого я сделал много сквотов и изменил порядок фиксаций на A
, чтобы история выглядела так, как будто я хочу.
3).
Теперь я также хочу:
git checkout B
git rebase A
Однако это не работает, и я не знаю, почему. Если я делаю git log
, я вижу коммиты, которые были там до того, как я сделал шаг 1.
Кроме того, я получаю такое же огромное количество конфликтов, которые я уже решил на шаге 1. Я потратил значительное время на это, не хочу делать это снова.
Этот пример предложил использовать --onto
, который я сделал:
git checkout B
git rebase --onto A
Но это полностью удаляет фиксацию на B
и делает A
и B
указывать на то же самое commit, то есть последнее на A
.
Мой вопрос: Как я могу эффективно сбрасывать B с A так, чтобы он выглядел так, как B начинался с A? (что в действительности было истинным в начале).
Мое лучшее предположение, что я использую --onto
неправильно. Или что я должен использовать что-то еще (например, cherry-pick
).
Ответы
Ответ 1
Короткий ответ на вопрос Как эффективно перебазировать B с A, чтобы он выглядел так, как будто B начинался с A?
Предполагая, что вы хотите переместить ровно один коммит:
git rebase --onto A B~ B
Если вы хотите переместить более одного использования коммита:
git rebase --onto A old_A B
Остальная часть ответа.
Ваша ветвь B все еще существует (вы можете проверить это), но ее родитель все еще является точным объектом фиксации, который был A
раньше.
чтобы увидеть графическое представление этого я использую:
git log --graph --decorate --all
чтобы увидеть все ветки и их расположение относительно друг друга.
Что у вас изначально было:
o---o---o---o master
\
o---o---o A
\
o B
Что у вас сейчас есть:
o---o---o-----------o master
\ \
o---o---o(B~) o---o---o A
\
o B
С точки зрения использования --onto
у вас должна быть начальная точка и конечная точка.
Использование:
git rebase --onto [target] [rebasing stops] [rebasing head]
git rebase --onto A B~ B
И что вы получаете:
o---o---o----------o master
\ \
o---o---o o---o---o A
(old_A) \
o B
[branch_name]~
указывает родительский коммит ветки.
B~
- это ветка, которую вы не хотите менять. (Это старый A
)
В качестве альтернативы, если B был единственным коммитом, у которого A был родительским (то есть, B является концом цепочки коммитов, ответвляющихся от master), вы могли бы сделать
git checkout B
git rebase master
git checkout B~ # this is the commit before B (the A commit)
git branch -d A # remove the old A branch (it was rebased, and so is now invalid
git branch A # recreate the A branch on the commit that is based on the original A
Ответ 2
У меня та же проблема с моим потоком мерзавцев, и я нашел лучший и быстрый способ сделать это.
(1) История проекта в начале:
master ---A---B---C
\
D---E---F feature1
\
G---H feature2
(2) Перебазировать feature1 на мастер и нажать принудительно:
master ---A---B------------------------C
\ \
D---E---F feature1(old) D---E---F feature1
\
G---H feature2
(3) переназначить feature2 на featrue1 (новый)
master ---A---B------------------------C
\
D---E---F feature1
\
G---H feature2
Самая запутанная часть - как это сделать (3).. но никто не имеет четкого ответа на это.
Я полагаю, что многие люди сталкивались с той же проблемой, что и я, когда мы пытались выполнить "rebase --onto", мы обнаружили, что feature1 (old) на самом деле не существует!
git rebase --onto feature1 feature1(old) feature2
Решение - использовать ниже:
git rebase --onto feature1 [email protected]{1} feature2
Синтаксис feature1 @{1} означает "последнее известное состояние feature1 перед перебазировкой", ответ отсылается из https://coderwall.com/p/xzsr9g/rebasing-dependent-branches-with-git
Ответ 3
Если вы уже основали букву A. Это должно быть так, что B точно там, где вы его оставили. Ветвь (указатель), которая была A, просто переместила в нее новое местоположение.
То, что я рекомендовал бы эффективно переустанавливать B на A, как вы предположили, использовать "cherry-pick". Эта команда пытается применить изменения, сделанные в фиксации к ветки, на которой вы ее запустили.
Итак, если идентификаторы фиксации фиксации, к которой B первоначально указывал, были "123456", тогда я бы рекомендовал переместить текущий "B" на то же место, что и новый "A" с git branch -f B A
, а затем запустить git cherry-pick 123456
, который применит изменения на A.
Я полагаю, что флаг --onto
используется для установки целевого местоположения, из которого применяется коммит. По умолчанию используется "восходящий поток" (источник: http://git-scm.com/docs/git-rebase).
То, как мне нравится думать о команде rebase, выглядит следующим образом:
git rebase --onto <Starting here> <Apply all commits from HERE> <TO HERE>
Используя это, вероятно, было бы проще переустановить B на master, а затем на точку A до фиксации, предшествующей B.
git rebase master B
(поскольку начальная точка (--onto) неявно "master" )
то для использования git branch -f A B^
(the ^ означает "родительский элемент" )