Подтвердить что ты не робот

Можно ли сказать Гитубу, что моя ветка была объединена с ведущим мастером?

Я использовал локальную ветвь feature для создания PR для репликации github (у меня нет доступа на запись к нему). Позже я решил, что хочу отделить его последний коммит в автономном PR, поэтому я переместил feature один фиксатор назад:

git checkout feature
git branch feature2
git reset --hard @~
git push -f

Первый PR объединяется вверх по течению, поэтому теперь я хочу создать второй PR:

git checkout master
git pull upstream master
git push origin
git checkout feature2
git rebase master

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

Почему Github потеряла информацию о том, что feature была объединена в master через восходящий PR? Есть ли способ предоставить Github эту информацию?

В конце концов, мне пришлось прибегать к:

git checkout master
git checkout -b feature2_new
git cherry-pick feature2

К счастью, мне нужно было только позаботиться о одной фиксации. И даже с одной фиксацией, я думаю, что слияние с истинной базой (если бы git знал об этом) было бы лучше, чем cherry-pick, потому что git сможет использовать свои знания истории, чтобы разрешить больше конфликтов автоматически.

Обратите внимание, что если бы я должен был объединить feature в master локально вместо того, чтобы делать PR для github, никакая информация не была бы потеряна. Конечно, тогда мой master не будет синхронизироваться с восходящим репо, поэтому было бы бессмысленно.

4b9b3361

Ответ 1

Github теперь поддерживает 3 метода для слияния запросов на тягу:

  • Слияние: создает фиксацию слияния (без быстрой перемотки вперед) + извлекает все исходные коммиты из ветки PR
  • Сквош и слияние: создает одиночную фиксацию
  • Rebase и merge: создает столько коммитов, что и PR-ветвь, но они переустанавливаются на master

Только регулярное слияние сохраняет знание о том, что мои локальные коммиты являются частью PR, объединенного в master. Если бы он был использован, я бы не столкнулся с проблемой, которую я описал в вопросе.

Другие два метода теряют это знание - и я ничего не могу сделать, чтобы создать его задним числом (без изменения ведущего мастера). Это цена за более простую историю.

Интуитивно, для того чтобы git знать, что ведущее объявление верхнего уровня U связано с моим локальным фиксацией L, должна быть указана стрелка от U до L.

Концептуально, есть два способа добиться этого.

Во-первых, U может иметь двух родителей: один соединяет его с L, а другой соединяет его со всеми предыдущими коммитами на восходящем потоке master. Именно это делает метод Github merge.

Во-вторых, U может иметь L как своего единственного родителя, если L уже указывает на все предыдущие коммиты на восходящем потоке master. Github, возможно, поддержал это, разрешив перемотку вперед с помощью метода merge, но он решил не делать этого.

Если Github PR объединяется либо с squash, либо слиянием или rebase и merge, все фиксации, созданные на ведущем сервере, имеют только один родитель; между ними и моими локальными коммитами нет стрелок.

Edit:

И теперь я считаю, что потеря истории, о которой я спрашивала, в первую очередь не была большой проблемой. IIUC, конфликты, с которыми я столкнулся с git cherry-pick, на самом деле совпадают с конфликтами с git rebase, если master был связан с feature2 с помощью регулярного коммита. И если бы у меня было более 1 фиксации в отдельном PR, вишня-pick тоже справилась бы с этим.

Ответ 2

Чтобы ответить на заданные вопросы,

Можно ли сообщить Гитубу, что моя ветка была объединена с ведущим мастером? [...] Почему Github потерял информацию о том, что функция была объединена в master через PR вверх?

Да, конечно, возможно записать слияние. Это обычно.

Кто-то решил сказать git (и github), чтобы он не записывал этот, поэтому эффекты появились на ведущей ветке вверх по течению без следа, откуда они пришли.

То, что вы смотрите, - это результат того, кто хочет развести историю магистрали из истории, которую вы предложили. Почему они решили это сделать, вам нужно будет узнать от них. Это общий и широко используемый вариант, по каким причинам любое количество людей будет очень рада описать. Линеаризационная история выглядит красиво, но включает компромиссы, там, в любом случае, и разные люди, и разные ситуации будут отклонять баланс по-своему.

Независимо от того, после получения результата у вас теперь есть незаписанное слияние, которое прекрасно, чистое и денди, пока вы никогда не пытаетесь объединить последующую работу по-прежнему на основе незарегистрированного родителя.

Что с этим делать?

Опция, которую вы выбрали, которая может также и более гибко (она обрабатывает многопользовательские функции1..файлы2), должна быть заполнена как

git rebase --onto master feature1 feature2

как правило, самый чистый: вверх по течению отказался от истории вашей функции1, поэтому вы отказываетесь от него, перегружая свою функцию2 на контент, который у них есть сейчас.

Если по какой-то причине вы действительно не хотите отказываться от истории feature1 в своем собственном репозитории, возможно, у вас есть больше, чем просто функция2, основанная на старой подсказке feature1, и перезагрузка начнет утомиться - вы также может добавить локальную запись слияния.

echo $(git rev-parse origin/master origin/master~ feature1) >>.git/info/grafts

Это указывает локальному git, что текущее согласование происхождения/хозяина имеет как родительское, так и зафиксированное его первое родительское commit, а также локальную функцию commit1. Поскольку восходящий поток отказался от фиксации функции1, а у вас его нет, все механизмы git теперь корректно работают как здесь, так и вверх по течению.

Различные проекты имеют разные правила для того, на чем должны основываться истории pull-request, некоторые хотят, чтобы все основывалось на некоторых последних советах, другие хотели, чтобы все было основано на теге тега обслуживания, а другие нуждаются в исправлениях на основе коммита, который ввел ошибку (Я думаю, что это должно быть гораздо чаще). Некоторым все равно, потому что все так знакомы с кодовой базой, что переустановка по-прежнему прост.

Но важная часть здесь заключается в том, что rebase-before-pushing - это ваша последняя возможность, чтобы быть уверенным, что то, что вы нажимаете, совершенно правильно. Это отличная привычка проникать, и трансплантаты прекрасно работают в этом рабочем процессе.

Ответ 3

Основная причина ваших проблем заключается в том, что при завершении запроса на растяжение для feature (ветвь функции с одним откатным завершением) это приводит к фиксации слияния в master. Вот диаграмма, показывающая, как выглядят master и feature2 после завершения запроса на растяжение feature в master:

master:   ... A -- B -- C -- M
                         \
feature:                  D
                           \
feature2:                   E

Здесь мы можем видеть, что feature разветвлено с master на commit C, а feature2 является просто продолжением feature с одним дополнительным фиксацией. Merge commit M находится в верхней части master, и он представляет всю дополнительную работу, выполненную в feature. Обратите внимание, что это объединение слиянием и, следовательно, не имеет ничего общего с историей feature2.

Затем вы выполнили следующую перезагрузку feature2 на master:

git checkout feature2
git rebase master

После этого rebase feature2 будет выглядеть так:

feature2: ... A -- B -- C -- M -- D' -- E'

Обратите внимание, что фиксация слияния остается частью истории. Хотя функционально говоря это может показаться ненужным, потому что commit D содержит все необходимое для совершения этого слияния, эта фиксация все еще появляется.

Если вам интересно, что вы можете сделать, чтобы избежать этого, одним из вариантов было бы сохранение истории master linear. Недостатком был запрос на растяжение, который закончился слиянием. Если вместо этого вы выполнили коммиты с feature непосредственно поверх master, тогда у вас не было бы этой проблемы. Рассмотрим следующие команды:

git checkout feature
git rebase master

Затем сделайте быстрое слияние вперед master с feature:

git checkout master
git merge feature

Это оставило бы master и feature2 следующим образом:

master:   ... A -- B -- C -- D
feature2: ... A -- B -- C -- D -- E

Теперь, если вы должны были объединить feature2 в master, Git просто воспроизвести фиксацию E, а не вернуться к исходной точке, откуда master и feature расходится.

Ответ 4

Да, нормально. Но git отвечает на этот вопрос, глядя на историю, а не на изменения. Если вы используете сквош Github (т.е. Nuke the history), то вы теряете способность использовать эту историю; а именно git способность обнаруживать, существует ли часть этой истории в восходящем потоке.

Основываясь на диаграмме, созданной Тимом Бигелейзеном:

master:   ... A -- B -- C -- M
                         \  /
feature:                  D
                           \
feature2:                   E

Когда вы переходите на функцию rebase feature2 на master, вы должны на самом деле видеть эту историю:

master:   ... A -- B -- C -- M
                         \  /  \
feature:                  D     \
                                 \
feature2:                         E'

Поскольку rebase никогда не воссоздает фиксацию, которая уже существует в целевом объекте. Он будет знать, что D уже находится в мастер-истории.

Когда вы перекомпилировали feature2 на master, вы увидели, что логические записи уже присутствовали в master. Это может произойти только в следующем сценарии.

До слияния вы переписываете некоторые функции коммитов:

                 D'   feature
               / 
... A -- B -- C 
               \  
                D 
                 \
                  E  feature2

выполнить слияние:

                 D'   feature
               /   \
... A -- B -- C --- M   master
               \  
                D 
                 \
                  E  feature2

а затем попробовал функцию rebasing feature2 поверх мастера:

                 D'   feature
               /   \
... A -- B -- C --- M   master
                     \  
                      D'' 
                       \
                        E'  feature2