Git: объединить ветки, но сохранить историю фиксации

В моем рабочем процессе git у нас есть один основной репозиторий и один ветки, мастер. Все тянут от удаленного мастера, и все нажимают на удаленный мастер. Я хочу работать в своей ветке, пока я готовлю эту функцию. Пока что моя история выглядит примерно так:

git pull --rebase
git checkout -b new_feature
<make some commits>
git checkout master
git pull --rebase

Теперь я хочу объединить ветку и вот что мне нужно:

  • В моей локальной ветки мастера не происходит слияния.
  • Все коммиты, сделанные в моей ветке new_feature, сливаются с мастером, как если бы я сделал их мастером.
  • Все объединенные коммиты объединяются где-то поверх моего локального указателя удаленной головки.

Моя самая большая проблема - пункт 3, когда это необходимо, чтобы я мог безопасно подталкивать изменения. Если объединенные коммиты переплетаются с коммитами перед головой, тогда у меня будут проблемы с нажатием, см. Связанную с этим проблему: git: нажатие одиночных коммитов, переупорядочение с помощью rebase, дублирование записей.

Я читал следующее:

И я думаю, что мне нужно сделать:

git checkout master
git pull --rebase
git checkout new_feature
git rebase master
git checkout master
git rebase new_feature
git push

Я понимаю, что

git checkout new_feature
git rebase master

сделает new_feature таким, как если бы он был отделен от новой текущей головы. Это правда? И что

git checkout master
git rebase new_feature

поместит new_feature поверх мастера. Это верно? Если это так, это основной момент моей путаницы. Если "git мастер переадресации" помещает мастер в нижнюю часть new_feature, тогда почему "git rebase new_feature" помещает new_feature в верхнюю часть ведущего, т.е. Почему он не делает обратное?

Ответ 1

Ответ

Вот рабочий процесс, который вы можете использовать, который выполняет именно то, что вам нужно.

git checkout master
git pull --rebase                             (1)
git checkout new_feature                      
<do a bunch of commits>
git rebase master                             (2)
git checkout master
git merge new_feature                         (3)
git branch -D new_feature                     (4)

Объяснение

(1) git pull --rebase сначала выберет origin/master, а затем вернет вам локальный master. Обратите внимание, что в журнале примера ваши локальные коммиты находятся поверх вашего локального указателя удаленной HEAD.

> git log --oneline --all -10 --decorate

d34d34c (HEAD, master) Local commit message.
d3434r2 Local commit message.
d234d4c Local commit message.
er3ede3 (origin/master, origin/HEAD) Remote commit message.
sfe3fd3 Remote commit message.

Теперь вы можете checkout и работать с веткой new_feature на некоторое время. Когда вы закончите...

(2) git rebase master будет воспроизводиться new_feature поверх master. Опять же, ваши локальные коммиты остаются на вершине вашего локального указателя удаленной HEAD.

> git log --oneline --all -10 --decorate

fc5773d (new_feature) Local new_feature commit.
9282838 Local new_feature commit.
d34d34c (HEAD, master) Local commit.
d3434r2 Local commit.
d234d4c Local commit.
er3ede3 (origin/master, origin/HEAD) Remote commit.
sfe3fd3 Remote commit.

Команда rebase просто поместит new_feature впереди ведущего, и чтобы выровнять их, вам нужно запустить...

(3) git merge new_feature, который будет выполнять ускоренное слияние. Теперь HEAD, new_feature и master все указывают на одну и ту же фиксацию.

> git log --oneline --all -10 --decorate

fc5773d (HEAD, new_feature, master) Local new_feature commit.
9282838 Local new_feature commit.
d34d34c Local commit.
d3434r2 Local commit.
d234d4c Local commit.
er3ede3 (origin/master, origin/HEAD) Remote commit.
sfe3fd3 Remote commit.

(4) После этого вы можете безопасно удалить ветвь new_feature. Ваш последний журнал перед нажатием будет выглядеть так:

> git log --oneline --all -10 --decorate

fc5773d (HEAD, master) Local new_feature commit 2
9282838 Local new_feature commit.
d34d34c Local commit.
d3434r2 Local commit.
d234d4c Local commit.
er3ede3 (origin/master, origin/HEAD) Remote commit.
sfe3fd3 Remote commit.

Ответ 2

Не нужно запускать git rebase new_feature в главной ветке после запуска git rebase master в ветке new_feature. После того, как вы запустили git rebase master в ветке new_feature, вы можете слить new_feature в master - это будет быстрое слияние и не будет вводить фиксацию слияния.

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

Кроме того, вам не нужно беспокоиться о том, чтобы перетаскивать коммиты, которые находятся ниже вашего удаленного/главного подсказки - пульт отклонит ваш push, если вы попытаетесь (если вы не предоставите опцию -f, а это не так). И если ваш локальный мастер отслеживает ваш удаленный мастер, git status сообщит, отклонился ли ваш локальный узел от удаленной ветки.