git rebase и git push: без перемотки вперед, зачем использовать?

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

К сожалению, каждый раз, когда я делаю «git rebase», а затем пытаюсь нажать, это приводит к сообщению «без перемотки вперед» и прерыванию нажатия. Единственный способ нажать здесь - использовать --force. Означает ли это, что я должен использовать «git merge» вместо перезагрузки, если моя ветка стала общедоступной и над ней работают другие?


person snitko    schedule 18.02.2009    source источник


Ответы (2)


Несколько примечаний о том, как работает git (не технические):

Когда вы перебазируете, git берет нужные коммиты и «повторяет» их поверх чистой истории. Это сделано для того, чтобы в истории не отображались:

Description: tree -> mywork -> merge -> mywork -> merge -> mywork -> merge
Commit SHA1: aaaa -> bbbb   -> cccc  -> dddd   -> eeee  -> ffff   -> gggg

После перебазирования это может выглядеть так (или аналогично):

Description: tree -> rebase
Commit SHA1: aaaa -> hhhh

Проблема в том, что новый коммит, который вы пытаетесь отправить, является НЕ потомком коммита на кончике ветки, на которую вы нажимаете.

Теперь вы знаете, что та же информация содержится в коммитах, но за это отвечает git, а не просто перезаписывает те коммиты (bbbb-gggg в приведенном выше примере).


Общая модель репо

Если вы используете общий репозиторий, подобные вещи могут сильно запутать. Позвольте мне объяснить почему. Допустим, другой разработчик отключил ветку, и у него есть коммиты aaaa -> gggg в своей ветке. Затем они совершают фиксацию iiii

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

Description: tree -> rebase
Commit SHA1: aaaa -> hhhh

Когда другой разработчик пытается нажать, он получает сообщение «без перемотки вперед». Когда он выполняет слияние, обе истории ПОВТОРНО СВЯЗАНЫ, и получается беспорядок.

Примерно так (беспорядочно):

Description: tree -> rebase -> mywork -> merge -> mywork -> merge -> mywork -> merge -> devwork -> merge 
Commit SHA1: aaaa -> hhhh   -> bbbb   -> cccc  -> dddd   -> eeee  -> ffff   -> gggg -> iiii    -> jjjj

Другими словами, если другие тянут И толкают, лучше придерживаться git merge или ИЗБЕГАЙТЕ НАЖАТИЯ до тех пор, пока не произойдет перебазирование (и только перебазируете свою работу).


Модель общедоступного репозитория

Возможно, вы используете другую (более мерзкую) модель, в которой просто хотите, чтобы люди могли получать информацию из вашего репо. В этом случае git push --force не так уж и плохо, потому что тогда они могут справиться с этим. Они могут переустановить свои изменения, чтобы они находились в верхней части ваших изменений, прежде чем передавать вам свои исправления. Это предотвращает перепутывание вашего репо.

Однако для вас может быть лучший способ. git push --mirror

http://www.kernel.org/pub/software/scm/git/docs/git-push.html

Вместо того, чтобы именовать каждую ссылку для отправки, указывает, что все ссылки в $ GIT_DIR / refs / (которые включают, но не ограничиваются, refs / Heads /, refs / remotes / и refs / tags /) должны быть отражены в удаленном репозитории. Вновь созданные локальные ссылки будут отправлены на удаленный конец, локально обновленные ссылки будут принудительно обновлены на удаленном конце, а удаленные ссылки будут удалены с удаленного конца. Это значение по умолчанию, если установлена ​​опция конфигурации remote..mirror.


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

person gahooa    schedule 18.02.2009
comment
Err, на самом деле слияние создает коммиты слияния, в которых отсутствует ненужное разъяснение. Вместо этого было бы здорово git fetch, git rebase origin/master разрешить все ваши локальные конфликты с помощью главной (централизованной) ветки, а затем продвигать чистые коммиты, которые продвигаются только вперед. git pull --rebase имеет аналогичный рабочий процесс. Это мощный вариант, но вы должны быть осторожны с ним, так как сброс неправильных вещей может перезаписать коммиты, которые уже находятся в origin / master. Например. не перебазируйте другие ветки, если они сначала не перебазируют текущее происхождение / мастер. - person Kzqai; 24.12.2010
comment
Согласитесь, следует избегать коммитов слияния при выполнении git pull. Тем не менее, я думаю, что их хорошо сохранить при намеренном слиянии ветки функции в master. - person ndbroadbent; 04.02.2012
comment
Мне нравится объяснение того, почему возникает проблема, при нажатии на перебазированную ветку. Но я не уверен, чего добивается --mirror. Чтение описания - указывает, что все ссылки будут зеркалироваться - меня беспокоит. Я не хочу, чтобы все ссылки были зеркальными, только одна ветка. :) Будет ли название ветки только отражать ее? Мне это не ясно из документации git. - person John C; 20.07.2012

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

person Val    schedule 11.01.2013