Изменить базу филиала

145

У меня есть такое дерево:

(commit 1) - master
                \-- (commit 2) - (commit 3) - demo
                                                \-- (commit 4) - (commit 5) - PRO

и мне нужно переместить ветку PRO в master

(commit 1) - master
                |-- (commit 2) - (commit 3) - demo
                \-- (commit 4) - (commit 5) - PRO

Я пробовал git rebase masterот PRO ветки, но ничего не происходит.

Чтобы уточнить : я работал в мастере, а затем мне пришлось сделать демонстрацию продукта ( git checkout -b demoи некоторые коммиты). Затем по ошибке я создаю другую ветку из демо ( git checkout -b PROи некоторые коммиты), и теперь мне нужно переместить PRO ветку в мастер и оставить демо нетронутым. В конце концов, и demo, и PRO будут зависать от мастера.

Иван
источник
возможный дубликат точки отделения Change
Владимир Палант

Ответы:

284

Используйте --ontoдля этого:

git rebase --onto newBase oldBase feature/branch

Учитывая ваш случай:

git checkout PRO # Just to be clear which branch to be on.
git rebase --onto master demo PRO

По сути, вы берете все коммиты от demoдо PROи переустанавливаете их на masterкоммит.

loganfsmyth
источник
Можно ли поступить так же, если ситуация обратная? == Я проверяю -b от мастера второй ветки, но я хотел сделать это с первой. Так я и git rebase --onto first-branch second-branch second-branch
Fla
1
@Fla, в таком случае, это будетgit rebase --onto first-branch master second-branch
nVitius
9
Я прочитал это руководство по --onto, и как они написали мне помогgit rebase --onto newBase oldBase feature/branch
Гейб
@PhilipRego Это неверно. origin/newBase- это имя ветки, как newBaseв моем примере. Это будет просто зависеть от того, выполняете ли вы переустановку на ветку, которая существует в вашем локальном репозитории ( newBase), или на ветку, которая существует в удаленном ( origin/newBase).
loganfsmyth
@PhilipRego Это не независимые вещи. newBase- это имя локальной ветки и origin/newBaseимя удаленной ветки. То, что вы хотите, зависит от того, на что вы перебираете. Дело не в том, что один работает, а другой нет, дело в том, что они переключаются на разные вещи. В исходном вопросе не упоминаются пульты дистанционного управления, поэтому использование пультов в моем примере не соответствует заданному вопросу.
loganfsmyth
22

Я постараюсь быть как можно более универсальным. Сначала убедитесь, что вы находитесь на нужной ветке:

git checkout current-branch

Затем используйте следующую команду (где new-base-branchнаходится ветка, которую вы хотите использовать в качестве новой базы, и current-base-branchветка, которая является вашей текущей базой).

git rebase --onto new-base-branch current-base-branch

Если у вас нет конфликтов, то отлично - готово. Если да (в большинстве случаев), продолжайте читать.

Могут возникнуть конфликты, и вам придется разрешать их вручную. Git Теперь пытается сделать «3-полосные слияния» между вашим current-branch, current-base-branchи new-base-branch. Примерно так git будет работать внутри:

  1. Git сначала перебазирует current-base-branchсверху new-base-branch. Могут быть конфликты; который вам придется решать вручную. После того, как это сделано, вы обычно делаете git add .и git rebase --continue. Для этого будет создана новая временная фиксация temp-commit-hash.

  2. После этого Git перебазирует ваш файл current-branchповерх temp-commit-hash. Могут возникнуть новые конфликты, и вам снова придется решать их вручную. После этого вы снова продолжите работу с git add .и git rebase --continue, после чего вы успешно переустановили свой current-branchповерх new-base-branch.


Примечание. Если вы начнете ошибаться, вы можете сделать это в git rebase --abortлюбой момент во время процесса перебазирования и вернуться к исходной точке.

КОВЧЕГ
источник
Опубликованная rebaseкоманда просто дает мне «фатальный: недопустимый восходящий поток 'current-base-branch'». Кроме того, почему вообще необходимо указывать GIT, что такое текущая родительская ветвь текущей ветки - разве он уже не знает об этом?
Мэтт Арнольд,
22

Оформить заказ в PROветку, скопируйте самый старый ( commit4 ) и последний ( commit5 ) хеши фиксации этой ветки и вставьте в другое место:

$ git checkout PRO
$ git log            # see the commit history
# copy the oldest & latest commit-hash 

Удалите PROветку (на всякий случай сохраните резервную копию). Создать и оформить заказ в новую PROветку из master:

$ git branch PRO.bac    # create a new branch PRO.bac = PRO as backup

$ git checkout master
$ git branch -D PRO     # delete the local PRO branch
$ git checkout -b PRO   # create and checkout to a new 'PRO' branch from 'master'

Возьмите ( выделите ) диапазон коммитов предыдущей PROветки в новую PROветку:

$ git cherry-pick commit4^..commit5   # cherry-pick range of commits
# note the '^' after commit4

Теперь, если все в порядке, нажмите принудительно (-f) на remote PROветвь и удалите локальную PRO.bacветку:

$ git log                  # check the commit history

$ git push -f origin HEAD  # replace the remote PRO by local PRO branch history
# git branch -D PRO.bac    # delete local PRO.bac branch
Саджиб Хан
источник
1

У меня был немного другой подход с использованием сброса и тайников, который позволяет избежать удаления и повторного создания ветвей, а также избавляет от необходимости переключать ветки:

$ git checkout PRO
$ git reset commit4 # This will set PROs HEAD to be at commit 4, and leave the modified commit 5 files in ur working index
$ git stash save -m "Commit message"
$ git reset commit 3
$ git stash save -m "Commit message"
$ git reset master --hard
$ git stash pop
$ git stash pop
$ git push --force # force if its already been push remotely

Сбрасывая ветку на основе фиксации за фиксацией, вы в основном просто перематываете эту историю ветвей по фиксации за раз.

madjase
источник
Следует ли убрать пробел между «commit» и «3» в 4-й строке?
Alexis Wilke