Чому git за замовчуванням виконує злиття вперед?


641

Виходячи з меркуріалу, я використовую гілки для організації функцій. Природно, я хочу бачити цей робочий процес і в моїй історії.

Я розпочав свій новий проект за допомогою git і закінчив свою першу функцію. Під час об'єднання функції я зрозумів, що git використовує швидку перемотку вперед, тобто він застосовує мої зміни безпосередньо до головної гілки, якщо це можливо, і забуває про свою гілку.

Отже, щоб задуматися про майбутнє: я єдиний, хто працює над цим проектом. Якщо я використовую підхід за замовчуванням git (швидке злиття вперед), моя історія призведе до однієї гігантської гілки майстра. Ніхто не знає, що я використовував окрему гілку для кожної функції, бо врешті-решт у мене буде лише ця гігантська гілка. Це не буде виглядати непрофесійно?

Цим міркуванням я не хочу швидкого злиття вперед і не можу зрозуміти, чому це за замовчуванням. Що в цьому хорошого?


38
Примітка. Дивіться також sandofsky.com/blog/git-workflow.html , а також уникайте " no-ff" з його "контрольно-пропускними пунктами", які порушують бісект або вину.
VonC

15
Ви шкодуєте, що використовуєте git для одного чоловіка?
HaveAGuess

27
Абсолютно ні! У моїй робочій папці є 7 проектів для чоловіків, де я використовую git. Дозвольте перефразувати це: я розпочав багато проектів з тих пір, як я задав це питання, і всі вони розглядаються через git. Наскільки я знаю, лише git та mercurial підтримують локальну версію, що для мене важливо, оскільки я звик до цього. Це легко встановити, і ви завжди маєте з собою всю історію. У групових проектах це ще краще, оскільки ви можете взяти на себе зобов’язання, не втручаючись нікого у свій незакінчений код. Крім того, я використовую github, щоб поділитися деякими своїми проектами (наприклад, мікро-optparse), де git є обов'язковою умовою.
Флоріан Пільц

7
@Cawas правда, -no-ffрідко є хорошою ідеєю, але все ж може допомогти зберегти історію внутрішньої функції, записуючи лише одну фіксацію на головну гілку. Це має сенс для тривалої історії функцій, коли час від часу ви з’єднуєте її просування по головній гілці.
VonC

12
До речі, на ваше запитання "Чи не виглядає це [історія лінійної гілки] непрофесійно?". Немає нічого непрофесійного в використанні системи вихідного коду з її замовчуванням. Йдеться не про професіоналізм. Йдеться про визначення того, яку філософію розгалуження ви передплачуєте. Наприклад, @VonC пов'язує зі статтею Сандофського, де він перемагає, використовуючи швидкий форвард як переважний підхід. Не правильно чи неправильно, просто різні філософії для різних контекстів.
Marplesoft

Відповіді:


718

Швидке з’єднання вперед має сенс для короткочасних гілок, але в більш складній історії нешвидке з’єднання вперед може полегшити розуміння історії та полегшити відновлення групи комітетів.

Попередження : Нешвидкісний пересилання також має потенційні побічні ефекти. Перегляньте https://sandofsky.com/blog/git-workflow.html , уникайте "no-ff" з його "контрольно-пропускними пунктами", які порушують бісект або звинувачення, і уважно подумайте, чи має це бути вашим підходом за замовчуванням master.

alt текст
(Від nvie.com , Вінсент Дріссен , пост " Успішна модель розгалуження Гіта ")

Включення готової функції в розробку

Готові функції можуть бути об'єднані в гілку розробки, щоб додати їх до майбутнього випуску:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

--no-ffПрапор викликає злиття завжди створювати новий об'єкт коммітов, навіть якщо злиття може бути виконана з швидкого перемотування вперед. Це дозволяє уникнути втрати інформації про історичне існування відгалуження та об'єднує всі комісії, які разом додали функцію.

Якуб Narębski також згадує про конфігураціїmerge.ff :

За замовчуванням Git не створює додаткових комірок злиття під час об'єднання комісії, яка є нащадком поточної комісії. Натомість кінчик поточної гілки швидко пересувається.
Якщо встановлено значення false, ця змінна повідомляє Git створити додатковий комітет злиття в такому випадку (еквівалентному наданню --no-ffпараметра з командного рядка).
Якщо встановлено значення " only", дозволяються лише такі швидкі злиття вперед (що еквівалентно наданню --ff-onlyопції з командного рядка).


Перемотка вперед - це за замовчуванням, оскільки:

  • короткотривалі гілки дуже легко створити та використовувати в Git
  • недовговічні гілки часто виділяють багато комітетів, які можна вільно реорганізувати у межах цієї гілки
  • ці комісії фактично є частиною основної галузі: після реорганізації головна гілка швидко переходить до їх включення.

Але якщо ви передбачаєте повторний робочий процес з однієї галузі / теми (тобто я зливаюсь, потім я повертаюсь до цієї гілки функцій і додаю ще кілька комісій), тоді корисно буде включати лише об'єднання в основну гілку, а не всі проміжні комітети гілки функцій.

У цьому випадку ви можете закінчити налаштування такого типу конфігураційного файлу :

[branch "master"]
# This is the list of cmdline options that should be added to git-merge 
# when I merge commits into the master branch.

# The option --no-commit instructs git not to commit the merge
# by default. This allows me to do some final adjustment to the commit log
# message before it gets commited. I often use this to add extra info to
# the merge message or rewrite my local branch names in the commit message
# to branch names that are more understandable to the casual reader of the git log.

# Option --no-ff instructs git to always record a merge commit, even if
# the branch being merged into can be fast-forwarded. This is often the
# case when you create a short-lived topic branch which tracks master, do
# some changes on the topic branch and then merge the changes into the
# master which remained unchanged while you were doing your work on the
# topic branch. In this case the master branch can be fast-forwarded (that
# is the tip of the master branch can be updated to point to the tip of
# the topic branch) and this is what git does by default. With --no-ff
# option set, git creates a real merge commit which records the fact that
# another branch was merged. I find this easier to understand and read in
# the log.

mergeoptions = --no-commit --no-ff

ОП додає в коментарях:

Я бачу деякий сенс у швидкому переході до [короткотривалих] гілок, але зробити це дією за замовчуванням означає, що git передбачає вас ... часто є [недовговічні] гілки. Розумні?

Джефромі відповідає:

Я думаю, термін експлуатації філій сильно відрізняється від користувача до користувача. Серед досвідчених користувачів, мабуть, існує тенденція до того, що є набагато більше короткочасних відділень.

Для мене короткотривала гілка - це те, що я створюю для того, щоб полегшити певну операцію (звільнення, швидше за все, або швидке виправлення та тестування), а потім негайно видалити, як тільки я закінчу.
Це означає, що вона, ймовірно, повинна бути поглинена темою, з якої вона розщелена , і тематична гілка буде об'єднана як одна гілка. Нікому не потрібно знати, що я робив всередині, щоб створити ряд комісій, що реалізують цю функцію.

Більш загально додати:

це дійсно залежить від вашого робочого процесу розвитку :

  • якщо вона лінійна, одна гілка має сенс.
  • Якщо вам потрібно ізолювати функції та працювати над ними протягом тривалого періоду та багаторазово їх об’єднувати, кілька гілок мають сенс.

Див. " Коли ви маєте відділитись? "

Насправді, якщо розглядати модель гілки Mercurial, вона є її сутністю однією гілкою на сховище (навіть якщо ви можете створювати анонімні заголовки, закладки та навіть названі гілки ).
Див. "Git and Mercurial - Порівняйте та контрастуйте" .

Mercurial за замовчуванням використовує анонімні полегшені коделі, які в своїй термінології називаються "голови".
Git використовує легкі гілки з назвою, з інжективним відображенням для відображення назв гілок у віддаленому сховищі до назв гілок віддаленого відстеження.
Git "змушує" вас називати гілки (ну, за винятком однієї безіменної гілки; ситуація називається " відокремленою ГОЛОВОЮ "), але я думаю, що це краще працює з важкими галузями робочих процесів, таких як тематичний робочий потік, тобто кілька гілок в одній парадигмі сховища.


Нічого собі, це було швидко. ;) Я знаю про варіант --no-ff, але дізнаюся про швидке перемотування вперед лише після того, як я перекрутив свою функцію. Я бачу певний сенс у швидкому переході до коротких живих гілок, але, якщо зробити це дією за замовчуванням, означає, що git передбачає, що у вас найчастіше є такі короткоживучі гілки. Розумні?
Флоріан Пільц

@Florian: Я вважаю, що це розумний погляд на процес. Я додав приклад конфігурації, який налаштує спосіб управління об'єднанням для master.
VonC

Дякуємо, що конфігураційний файл повинен допомогти уникнути подібних випадків. :) Застосовувати цю конфігурацію можна лише локально з "git config branch.master.mergeoptions '--no-ff'"
Флоріан Пільц

2
@BehrangSaeedzadeh: ребаузинг - це інша тема (про яку не згадувалося на цій сторінці): доки ви не підштовхнете свою featureфілію до публічного репо, ви можете її відновити на вершині masterстільки разів, скільки захочете. Див stackoverflow.com/questions/5250817 / ...
VonC

4
@BehrangSaeedzadeh: сама по собі база даних не зробить історію лінійною. Саме так ви інтегруєте зміни вашої featureгілки назад у masterте, що робить згадану історію лінійною чи ні. Просте злиття, яке швидко переходить вперед, зробить його лінійним. Що має сенс, якщо ви очистили історію цієї featureгілки перед швидким злиттям вперед, залишивши лише значні комісії, про що йдеться в stackoverflow.com/questions/7425541/… .
VonC

42

Дозвольте трохи розповісти про дуже вичерпну відповідь VonC :


По-перше, якщо я правильно його пам’ятаю, той факт, що Git за замовчуванням не створює об'єднаних комітетів у випадку швидкого переходу , походить від розгляду однорозгалужених «рівних сховищ», де взаємний потяг використовується для синхронізації цих двох сховищ (a робочий процес ви можете знайти як перший приклад у документації більшості користувачів, включаючи "Посібник користувача Git" та "Контроль версій за прикладом"). У цьому випадку ви не використовуєте pull для злиття повністю реалізованої гілки, ви використовуєте її, щоб не відставати від інших робіт. Ви не хочете мати ефемерний та неважливий факт, коли вам трапляється синхронізація, збережена та збережена у сховищі, збережена на майбутнє.

Зауважте, що корисність функціональних гілок та наявність декількох гілок в одному сховищі з'явилися лише пізніше, при більш широкому використанні VCS з хорошою підтримкою злиття та при спробі різних робочих процесів на основі злиття. Ось чому, наприклад, Mercurial спочатку підтримував лише одну гілку на сховище (плюс анонімні поради щодо відстеження віддалених гілок), як це було показано в попередніх версіях "Mercurial: The Definitive Guide".


По-друге, дотримуючись кращих практик використання гілок функцій , а саме, що гілки функцій повинні починатись із стабільної версії (як правило, з останнього випуску), щоб мати змогу вибирати вишні та вибирати, які функції включати, вибираючи, які гілки функцій об’єднувати, ви зазвичай не перебувають у швидкій ситуації ... що робить це питання спірним. Вам потрібно потурбуватися про створення справжнього злиття, а не просуватися вперед при злитті найпершої гілки (якщо припустити, що ви не змінюєте одноразові зміни безпосередньо на "master"); всі інші пізніші злиття, звичайно, знаходяться в не швидкій ситуації вперед.

HTH


Щодо гілок функцій із стабільних версій: Що робити, якщо функція, яку я розробляю для наступного випуску, залежить від змін для іншої функції, яку я вже розробив і об'єднав у головний? Напевно це означає, що я повинен створити цю другу гілку функції у майстра?
dOxxx

1
@dOxxx: Так, є винятки, наприклад, коли одна гілка будується на іншій (або безпосередньо, або після об'єднання попереднього в головний).
Якуб Нарбський
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.