Как переделать ветку с переустановленной ветки?

Итак, моя история выглядит так:

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 ^ означает "родительский элемент" )