Коли рекомендується використовувати Git rebase vs. Git merge?
Чи потрібно все-таки об'єднатись після успішної бази даних?
Коли рекомендується використовувати Git rebase vs. Git merge?
Чи потрібно все-таки об'єднатись після успішної бази даних?
Відповіді:
Отже, коли ви використовуєте будь-який з них?
init
новим репо, add
файлом та commit
. Оформити нову гілку функції ( checkout -b feature
.) Змініть текстовий файл, введіть і повторіть так, щоб на гілці функції були два нові коміти. Тоді checkout master
і merge feature
. В log
, я бачу , моє початкове зобов'язання на господаря, а потім два , які були об'єднані з функцією. Якщо ви merge --squash feature
, функція об'єднана в головний, але не скоєна, тож єдиним новим зобов’язанням майстра буде той, який ви зробите самі.
Це просто. За допомогою бази даних ви говорите про використання іншої гілки як нової бази для вашої роботи.
Якщо у вас є, наприклад, гілка master
, ви створюєте гілку, щоб реалізувати нову функцію, і кажете, що ви її називали cool-feature
, звичайно, головна гілка є базою для вашої нової функції.
Тепер у певний момент ви хочете додати нову функцію, яку ви реалізували у master
галузі. Ви можете просто перейти на галузь master
і об'єднати її cool-feature
:
$ git checkout master
$ git merge cool-feature
Але таким чином додається новий фіктивний комітет. Якщо ви хочете уникнути історії спагетті, ви можете перезавантажити :
$ git checkout cool-feature
$ git rebase master
А потім об'єднайте його в master
:
$ git checkout master
$ git merge cool-feature
Цього разу, оскільки тематична галузь має ті ж завдання, що і головна, а також номери з новою функцією, злиття буде просто швидким вперед.
but this way a new dummy commit is added, if you want to avoid spaghetti-history
- як це погано?
Sean Schofield
додає це в коментарі: "Rebase також приємно, тому що, як тільки ти зрештою зливаєш ур речі назад у майстер (що тривіально, як уже було описано), ти маєш його сидіти на" вершині "історії ур. Фіксації. На більшій проекти, де функції можуть бути записані, але об'єднані через кілька тижнів, ви не хочете просто об'єднати їх у майстер, тому що вони "набиваються" на головний шлях ще в історії. Особисто мені подобається вміти робити журнал git і бачити ця остання функція прямо у верхній частині. Зверніть увагу, що дати фіксації збережені - база даних не змінює цю інформацію ".
merge
, rebase
, fast-forward
і т.д.) , мають в виду конкретних маніпуляцій спрямованого ациклического графа. Їм стає простіше міркувати про цю ментальну модель.
Щоб доповнити мою власну відповідь, згадану TSamper ,
Реалізація часто є хорошою ідеєю зробити перед об'єднанням, оскільки ідея полягає в тому, щоб ви інтегрували у свою галузь Y
роботу гілки, B
на якій ви будете об'єднуватися.
Але знову ж таки, перш ніж об’єднатись, ви вирішите будь-який конфлікт у вашій гілці (тобто: "rebase", як у "повторі моєї роботи у моїй гілці, починаючи з недавньої точки від гілки B
).
Якщо це зробити правильно, наступне злиття з вашої гілки гілка B
може бути швидкою вперед.
злиття безпосередньо впливає на гілку призначення B
, а це означає, що злиття краще бути тривіальними, інакше ця гілка B
може задовго повернутися до стабільного стану (час для вирішення всіх конфліктів)
точка злиття після перезавантаження?
У випадку, який я описую, я переїжджаю B
на свою гілку, просто щоб мати можливість відтворити свою роботу з більш пізнього моменту B
, але залишаючись у своєму відділенні.
У цьому випадку для зближення моїх "перетворених" робіт все-таки потрібне злиття B
.
Інший сценарій ( описаний, наприклад, у Git Ready ), полягає в тому, щоб залучити вашу роботу безпосередньо за B
допомогою ребайз (що дозволяє зберегти всі ваші приємні зобов’язання або навіть дати вам можливість повторно замовити їх через інтерактивну базу даних).
У тому випадку (де ви перезавантажуєтесь, перебуваючи у відділенні B), ви маєте рацію: більше злиття не потрібно:
Дерево Git за замовчуванням, коли ми не об'єднали і не перезавантажили
ми отримуємо шляхом звільнення:
Цей другий сценарій - це те, як повернути нову функцію в майстер.
Моя думка, описуючи перший сценарій перезавантаження, полягає в тому, щоб нагадати всім, що повторне використання також може бути використане як попередній крок до цього (що таке "повернення нової функції в майстер").
Ви можете використовувати ребазу для того, щоб спочатку привести головну "в" нову гілку функції: ребаза відтворить нові функції комітетів із HEAD master
, але все ще в новій гілці функції, ефективно переміщуючи вихідну точку вашої гілки зі старої основної комісії HEAD-master
.
Це дозволяє вирішувати будь-які конфлікти у вашій галузі (тобто, ізольовано, одночасно дозволяючи майстру продовжувати розвиватися паралельно, якщо етап розв'язання конфлікту триватиме занадто довго).
Тоді ви можете переключитися на "master" та "об'єднати" new-feature
(або перезавантажити new-feature
на них), master
якщо ви хочете зберегти виконані вами комісіїnew-feature
відділення).
Тому:
master
.Якщо у вас є сумніви, використовуйте об'єднання.
Єдині відмінності між базою даних і об'єднанням:
Отже, коротка відповідь - вибрати ребаунд або об'єднати, виходячи з того, на що ви хочете виглядати ваші історії .
Є кілька факторів, які слід враховувати, вибираючи, яку операцію використовувати.
Якщо так, не перезавантажуйте. Rebase знищує гілку, і ті розробники матимуть зламані / непослідовні сховища, якщо вони не використовують git pull --rebase
. Це хороший спосіб швидко засмутити інших розробників.
База даних - це руйнівна операція. Це означає, що якщо ви не застосовуєте його правильно, ви можете втратити віддану роботу та / або порушити послідовність сховищ інших розробників.
Я працював над командами, де розробники походили з тих часів, коли компанії могли дозволити собі спеціалістів, що займаються розгалуженням та об'єднанням. Ці розробники мало що знають про Git і не хочуть багато чого знати. У цих командах я б не ризикував рекомендувати відшкодування з будь-якої причини.
Деякі команди використовують модель розгалуження на особливості, де кожна гілка представляє особливість (або помилку, або підфункцію тощо). У цій моделі гілка допомагає визначити набори пов’язаних комітетів. Наприклад, можна швидко відновити функцію, повернувши об'єднання цієї гілки (якщо справедливо, це рідкісна операція). Або розрізняйте особливість, порівнюючи дві гілки (більш поширені). База даних знищила б гілку, і це не було б просто.
Я також працював над командами, які використовували модель філії на розробника (ми всі були там). У цьому випадку філія сама не передає додаткової інформації (у комітеті вже є автор). Не було б шкоди при відновленні.
Повернення (як і при скасуванні) ребазування є значно складним та / або неможливим (якщо в ребасті були конфлікти) порівняно з ревертуванням злиття. Якщо ви думаєте, що є ймовірність, що вам захочеться повернутись, скористайтеся об'єднанням.
Операції з базою даних повинні бути виконані відповідною git pull --rebase
. Якщо ви працюєте самостійно, ви, можливо, зможете запам'ятати, який слід використовувати у відповідний час. Якщо ви працюєте над командою, координувати це буде дуже важко. Ось чому більшість робочих процесів відновлення рекомендують використовувати rebase для всіх злиттів (і git pull --rebase
для всіх витяг).
Припустимо, що у вас є таке злиття:
B -- C
/ \
A--------D
Деякі люди заявляють, що злиття "знищує" історію фіксації, тому що якби ви подивилися на журнал лише головного відділення (A - D), ви пропустили б важливі повідомлення комісій, що містяться в B і C.
Якби це було правдою, у нас не було б таких питань . В основному, ви побачите B і C, якщо ви прямо не попросите їх не бачити (використовуючи - first-parent). Це дуже просто спробувати на собі.
Два підходи зливаються по-різному, але незрозуміло, що один завжди кращий за інший, і це може залежати від робочого процесу розробника. Наприклад, якщо розробник прагне регулярно брати на себе зобов’язання (наприклад, можливо, вони беруть на себе зобов’язання двічі на день, переходячи з роботи додому), то для даної галузі може бути багато комісій. Багато з цих комісій можуть не виглядати як кінцевий продукт (я схильний перетворювати свій підхід один чи два рази за функцію). Якщо хтось інший працював над суміжною областю коду, і вони намагалися відновити мої зміни, це може бути досить копіткою операцією.
Якщо вам подобається псевдонім, rm
щоб rm -rf
"заощадити час", можливо, перезавантаження саме для вас.
Я завжди думаю, що коли-небудь я натраплю на сценарій, коли Git rebase - це дивовижний інструмент, який вирішує проблему. Начебто я думаю, що я натраплю на сценарій, коли Git reflog - це чудовий інструмент, який вирішує мою проблему. Я працюю з Git вже більше п’яти років. Це не сталося.
Брудні історії ніколи насправді не були проблемою для мене. Я ніколи не просто читаю свою історію подій, як захоплюючий роман. Більшу частину часу мені потрібна історія, я все одно буду користуватися виною Git або Git bisect. У такому випадку, якщо зробити об'єкт злиття, мені фактично корисно, тому що якщо злиття запровадило проблему, це для мене змістовна інформація.
Мені потрібно обов'язково зазначити, що я особисто пом'якшив використання бази даних, хоча моя загальна порада все ще існує. Останнім часом я дуже багато взаємодію з проектом Angular 2 Material . Вони використовували базу даних, щоб зберегти дуже чисту історію фіксації. Це дозволило мені дуже легко побачити, яка фіксація виправлена певним дефектом і включила чи ні ця комісія у реліз. Він слугує прекрасним прикладом правильного використання rebase.
Тут багато відповідей говорить про те, що об'єднання перетворює всі ваші зобов’язання в одне ціле, а тому пропонуємо використовувати ребайн для збереження ваших комітетів. Це неправильно. І погана ідея, якщо ви вже підштовхнули свої зобов'язання .
Об'єднання не знищує ваші зобов’язання. Об’єднання зберігає історію! (просто подивіться на gitk) Rebase переписує історію, яка є поганою річчю після того, як ви її натиснули .
Використовуйте об'єднання - не перезавантажуйте кожен раз, коли ви вже натиснули.
Ось Лінус (автор Git) взяти його на себе (зараз він розміщений у моєму власному блозі, як його відновила машина Wayback ). Це справді добре прочитане.
Або ви можете прочитати мою власну версію тієї самої ідеї нижче.
Випуск філії на майстер:
На відміну від цього, об’єднання галузевої теми в головну:
TLDR: Це залежить від того, що є найважливішим - охайна історія чи правдиве подання послідовності розвитку
Якщо охайна історія є найважливішою, то ви б спочатку перезавантажили, а потім злили свої зміни, тож зрозуміло, що саме новий код. Якщо ви вже натиснули свою філію, не здійснюйте перезавантаження, якщо не зможете боротися з наслідками.
Якщо справжнє подання послідовності є найважливішим, ви б злилися без повторного скасування.
Об'єднання означає: Створіть нову нову комісію, яка об'єднує мої зміни в пункт призначення. Примітка. Ця нова комісія матиме двох батьків - остання фіксація з вашої рядки комітетів та остання комісія з іншої гілки, яку ви об’єднуєте.
Rebase означає: Створіть цілу нову серію комітетів, використовуючи мій поточний набір комітетів як підказки. Іншими словами, порахуйте, як виглядали б мої зміни, якби я почав вносити їх з того моменту, на який я відмовляюся. Тому після повторної бази даних, можливо, вам доведеться повторно перевірити свої зміни, і під час перезавантаження, можливо, виникнуть кілька конфліктів.
З огляду на це, чому ви б переобладнали? Просто, щоб історія розвитку була чистою. Скажімо, ви працюєте над функцією X, і коли ви закінчите, ви з’єднуєте свої зміни. Призначення тепер матиме єдиний комітет, який би сказав щось про те, що відповідає "Додана функція X". Тепер, замість злиття, якщо ви перезавантажувались, а потім об'єднувались, історія розвитку пункту призначення містила б усі індивідуальні комісії в єдиний логічний прогрес. Це набагато полегшує перегляд змін згодом. Уявіть, як важко вам переглядати історію розробок, якби 50 розробників постійно об’єднували різні функції.
Це означає, що якщо ви вже натиснули гілку, над якою працюєте вище, не слід перезавантажуватись, а зливатися. Для гілок, які не були висунуті вгору за течією, перезавантажте, протестуйте та з’єднайте.
Інший раз, коли ви захочете перезавантажити, це коли ви хочете позбутися від комісій зі своєї філії перед тим, як натиснути вище за течією. Наприклад: Коміти, які вводять якийсь код налагодження на початку, а інші здійснюють подальше очищення цього коду. Єдиний спосіб зробити це - виконати інтерактивну базу даних:git rebase -i <branch/commit/tag>
ОНОВЛЕННЯ: Ви також хочете використовувати ребазування, коли ви використовуєте Git для інтерфейсу до системи управління версіями, яка не підтримує нелінійну історію (наприклад, Subversion ). Під час використання моста git-svn дуже важливо, щоб зміни, які ви зливаєте назад у Subversion, були послідовним переліком змін на початку останніх змін у магістралі. Для цього є лише два способи: (1) відновити зміни вручну та (2) за допомогою команди rebase, що набагато швидше.
ОНОВЛЕННЯ 2: Один додатковий спосіб продумати ребайн - це те, що він дає змогу відобразити своєрідне відображення від вашого стилю розробки до стилю, прийнятого в сховищі, в яке ви збираєтесь. Скажімо, ви любите робити маленькі крихітні шматочки. У вас є одна фіксація виправлення помилки друку, одна фіксація для позбавлення від невикористаного коду тощо. На той час, коли ви закінчите те, що вам потрібно зробити, у вас є довга серія зобов'язань. Тепер скажімо, що сховище, яке ви здійснюєте, заохочує великі комісії, тому для роботи, яку ви виконуєте, можна було б очікувати одного чи, можливо, двох комітів. Як ви приймаєте рядок комітетів і стискаєте їх до того, що очікується? Ви б використовували інтерактивну базу даних і розбивали свої крихітні комбінезони на менші розміри. Те ж саме, якщо потрібен зворотній бік - якщо у вашому стилі було кілька великих змін, але сховище вимагало довгих рядків невеликих комітетів. Ви також використовуєте для цього ребазу. Якщо ви зробили об'єднання замість цього, ви тепер перенесли свій стиль фіксації в основний сховище. Якщо розробників багато, ви можете собі уявити, як важко буде прослідкувати історію з декількома різними стилями фіксації через деякий час.
ОНОВЛЕННЯ 3: Does one still need to merge after a successful rebase?
Так, ви робите. Причина полягає в тому, що ребазація по суті передбачає "зміщення" комітетів. Як я вже говорив вище, ці коміти обчислюються, але якщо у вас було 14 коміттів з точки розгалуження, то припускаючи, що з вашою базою даних нічого не виходить, ви будете на 14 комірок вперед (від точки, на яку ви відновлюєте) після робиться ребаза. Ви мали відділення перед ребауз. Після цього у вас буде гілка такої ж довжини. Перед публікацією змін вам потрібно злитись. Іншими словами, перезавантажте стільки разів, скільки вам потрібно (знову ж таки, лише якщо ви не підштовхнули зміни вгору за течією). Об’єднайтеся лише після перезавантаження.
git merge
підтримує --no-ff
опцію, яка змушує її здійснити об'єднання.
Хоча злиття, безумовно, є найпростішим і найпоширенішим способом інтеграції змін, але це не єдине: Rebase - це альтернативний засіб інтеграції.
Розуміння злиття трохи краще
Коли Git здійснює злиття, він шукає три коміти:
Швидкий перемотка вперед або об'єднання
У дуже простих випадках одна з двох гілок не має нових зобов’язань, оскільки відбулося розгалуження - остання фіксація все ще є загальним предком.
У цьому випадку виконання інтеграції є мертвим простим: Git може просто додати всі комітети іншої гілки на вершині загальної передачі предків. У Git цю найпростішу форму інтеграції називають "швидким вперед" злиттям. Тоді обидві гілки мають точну історію.
Однак у багатьох випадках обидві гілки рухалися вперед окремо.
Щоб здійснити інтеграцію, Git доведеться створити нову комісію, яка містить відмінності між ними - комісію злиття.
Людські коміти та об'єднання комітетів
Зазвичай, людина старанно створюється людиною. Це змістовна одиниця, яка обгортає лише пов'язані зміни та коментує їх коментарем.
Коміт злиття дещо інший: замість того, щоб створювати його розробник, він автоматично створюється Git. І замість того, щоб обгортати набір пов’язаних змін, його мета - з'єднати дві гілки, подібно до вузла. Якщо ви хочете зрозуміти операцію злиття пізніше, вам слід ознайомитись з історією обох гілок та відповідним графіком фіксації.
Інтеграція з Rebase
Деякі люди вважають за краще пройти без таких автоматичних об'єднань. Натомість вони хочуть, щоб історія проекту виглядала так, ніби він розвивався в єдину пряму лінію. Не залишається вказівки на те, що в якийсь момент він був розбитий на кілька гілок.
Давайте покроково проходимо операцію ребаїнгу. Сценарій такий самий, як і в попередніх прикладах: ми хочемо інтегрувати зміни з гілки B в гілку-A, але тепер, використовуючи rebase.
Ми зробимо це в три етапи
git rebase branch-A // Synchronises the history with branch-A
git checkout branch-A // Change the current branch to branch-A
git merge branch-B // Merge/take the changes from branch-B to branch-A
По-перше, Git "скасує" всі комірки на гілці-A, що сталося після того, як рядки почали розгалужуватися (після того, як загальні предки здійснюють). Однак, звичайно, це не відкине їх: натомість ви можете вважати ці зобов'язання "тимчасово збереженими".
Далі, він застосовує комітети з гілки B, які ми хочемо інтегрувати. У цей момент обидві гілки виглядають абсолютно однаково.
На останньому кроці нові комітети для гілки-А тепер повторно застосовуються - але на новій позиції, поверх інтегрованих комітетів із гілки-В (вони засновані заново).
Результат виглядає так, що розвиток відбувався по прямій лінії. Замість комірки злиття, який містить усі об'єднані зміни, початкова структура комісії була збережена.
Нарешті, ви отримуєте чисту гілку гілки-A без небажаних та автоматично створених комісій.
Примітка: Взято з дивовижному поста по git-tower
. У мінуси від rebase
також добре прочитати в тій же посаді.
Перед об'єднанням / відновленням:
A <- B <- C [master]
^
\
D <- E [branch]
Після git merge master
:
A <- B <- C
^ ^
\ \
D <- E <- F
Після git rebase master
:
A <- B <- C <- D' <- E'
(A, B, C, D, E і F - коміти)
Цей приклад та набагато більш добре проілюстровану інформацію про Git можна знайти у навчальному посібнику з основ Git .
Це речення отримує:
Взагалі спосіб отримати найкраще з обох світів - це перезавантажити зміни, які ви внесли, але ще не поділилися, перш ніж натиснути на них, щоб очистити свою історію, але ніколи не перезавантажуйте все, що ви кудись натиснули .
Ця відповідь широко орієнтована навколо Git Flow . Таблиці були згенеровані за допомогою приємного генератора таблиць ASCII та дерев історії з цією чудовою командою ( псевдонімом як git lg
):
git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
Таблиці є у зворотному хронологічному порядку, щоб вони більше відповідали деревам історії. Дивіться також різницю між першим git merge
та git merge --no-ff
(як правило, ви хочете використовувати git merge --no-ff
його, оскільки це робить вашу історію ближче до реальності):
git merge
Команди:
Time Branch "develop" Branch "features/foo"
------- ------------------------------ -------------------------------
15:04 git merge features/foo
15:03 git commit -m "Third commit"
15:02 git commit -m "Second commit"
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Результат:
* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
| Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
| Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git merge --no-ff
Команди:
Time Branch "develop" Branch "features/foo"
------- -------------------------------- -------------------------------
15:04 git merge --no-ff features/foo
15:03 git commit -m "Third commit"
15:02 git commit -m "Second commit"
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Результат:
* 1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/ Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git merge
проти git rebase
Перший момент: завжди об’єднуйте функції в розробку, ніколи не перетворюйте на основі функцій . Це наслідок Золотого правила звільнення :
Золоте правило
git rebase
- ніколи не використовувати його на громадських відділеннях.
Ніколи не переставляйте що-небудь, що десь штовхнули.
Я особисто додам: якщо це не особлива галузь І ви та ваша команда знаєте про наслідки .
Тож питання відносно git merge
vs git rebase
стосується майже лише галузей функцій (у наступних прикладах --no-ff
завжди використовується при об'єднанні). Зауважте, що оскільки я не впевнений, що є одне краще рішення ( дебати існують ), я розкажу лише про те, як поводяться обидві команди. У моєму випадку я вважаю за краще використовувати, git rebase
оскільки це створює приємніше дерево історії :)
git merge
Команди:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git merge --no-ff features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Результат:
* c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\ Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | | Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | | Fourth commit - Christophe
* | | 98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \ Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git rebase
Команди:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git rebase features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Результат:
* 7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | Fourth commit - Christophe
* | 189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
develop
до функції функціїgit merge
Команди:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git commit -m "Sixth commit"
15:08 git merge --no-ff develop
15:07 git merge --no-ff features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Результат:
* 9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\ Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* | 5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | | Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ / Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/ Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git rebase
Команди:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git commit -m "Sixth commit"
15:08 git rebase develop
15:07 git merge --no-ff features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Результат:
* b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/ Fourth commit - Christophe
* 856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git cherry-pick
Коли вам просто потрібна одна конкретна фіксація, git cherry-pick
це приємне рішення ( -x
опція додає рядок із написом " (вишня, вибрана з фіксації ...) " до початкового органу повідомлення про фіксацію, тому зазвичай корисно використовувати це - git log <commit_sha1>
побачити це):
Команди:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -----------------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git cherry-pick -x <second_commit_sha1>
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
Результат:
* 50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| | Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | Fourth commit - Christophe
* | 1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git pull --rebase
Я не впевнений, що можу це пояснити краще, ніж Дерек Гурлай ... В основному, використовуйте git pull --rebase
замість git pull
:) Однак, що у статті не вистачає, це те, що ви можете ввімкнути це за замовчуванням :
git config --global pull.rebase true
git rerere
Знову добре, тут пояснили . Але простіше кажучи, якщо ви це увімкнете, вам більше не доведеться вирішувати один і той же конфлікт кілька разів.
У книзі Pro Git є дійсно гарне пояснення на перезавантажувальній сторінці .
В основному злиття займе два коміти та об'єднає їх.
Повторна база перейде до загального предка на двох і поступово застосувати зміни один на одного. Це сприяє більш чистій та лінійній історії.
Але коли ви перезавантажуєтесь, ви відмовляєтесь від попередніх комісій і створюєте нові. Тож ніколи не слід перезавантажувати сховище, яке є загальнодоступним. Інші люди, які працюють у сховищі, будуть вас ненавидіти.
Тільки з цієї причини я майже виключно зливаюся. У 99% часу мої гілки не так сильно відрізняються, тож якщо є конфлікти, це лише в одному чи двох місцях.
Git rebase використовується для того, щоб зробити шляхи розгалуження історії більш чистими та структуру сховищ лінійними.
Він також використовується для збереження створених вами гілок приватними, тому що після видалення та натискання змін на сервері, якщо ви видалите свою гілку, не буде жодних доказів роботи над вашою галуззю. Тож ваше відділення зараз є вашим місцевим питанням.
Зробивши ребауз, ми також позбудемося додаткової комісії, яку ми звикли бачити, чи робимо ми нормальне злиття.
І так, все-таки потрібно зробити злиття після успішної ребави, оскільки команда rebase просто ставить вашу роботу поверх тієї гілки, про яку ви згадали під час ребазування, скажімо, майстер, і робить першу фіксацію вашої гілки як безпосередній нащадок основної гілки. . Це означає, що тепер ми можемо зробити швидке злиття вперед, щоб внести зміни з цієї гілки в головну гілку.
Деякі практичні приклади, дещо пов'язані з масштабною розробкою, де Герріт використовується для інтеграції огляду та доставки:
Я зливаюся, коли піднімаю свою гілку функції до нового віддаленого майстра. Це дає мінімальну роботу з підвищення кваліфікації і легко слідкувати за історією розвитку функції, наприклад, gitk .
git fetch
git checkout origin/my_feature
git merge origin/master
git commit
git push origin HEAD:refs/for/my_feature
Я зливаюсь, коли готую доставку.
git fetch
git checkout origin/master
git merge --squash origin/my_feature
git commit
git push origin HEAD:refs/for/master
Я перезавантажую, коли моя доставка з будь-якої причини не вдається інтегрувати, і мені потрібно оновити її до нового віддаленого майстра.
git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase origin/master
git push origin HEAD:refs/for/master
Неодноразово пояснювалося, що таке база даних і що таке злиття, але коли слід використовувати що?
Коли слід використовувати rebase?
По мірі того, як Git Rebase змінює історію. Тому ви не повинні використовувати його, коли хтось інший працює над тією ж гілкою / якщо ви натиснули на неї. Але якщо у вас є локальна філія, ви можете зробити майстер відновлення злиття, перш ніж об'єднати свою гілку назад у головну, щоб зберегти більш чисту історію. Зробивши це, після злиття в головну гілку не буде видно, що ви використовували гілку в головній гілці - історія "чистіша", оскільки у вас немає автоматично створеного "об'єднаного ..", але все ж є повна історія у вашій головній галузі без автоматичної генерації "об'єднаних ..".
Переконайтеся, що ви використовуєте git merge feature-branch --ff-only
для того, щоб не було конфліктів, створюючи єдиний фіксатор, коли ви об’єднуєте свою функцію до основної. Це цікаво, якщо ви використовуєте гілки функцій для кожного завдання, над яким ви працюєте, коли ви отримуєте історію гілки функцій, але не виконуються "об'єднані .."
Другий сценарій був би, якщо ви відгалужитеся від гілки і хочете знати, що змінилося в головній гілці. Rebase надає вам інформацію, оскільки вона включає кожну комісію.
Коли слід використовувати злиття?
Коли вам не потрібно або хочете мати всю історію гілки функцій у вашій головній гілці або якщо інші працюють над тією самою гілкою / ви натиснули її. Якщо ви все ще хочете мати історію, просто об'єднайте головний у гілку функції, перш ніж об'єднати гілку функції в головну. Це призведе до швидкого злиття вперед, де у вас є історія гілки функцій у вашому майстрі (включаючи комісію злиття, яка була у вашій гілці функцій, тому що ви об'єднали в неї головний майстер).
Коли я використовую git rebase
? Майже ніколи, бо вона переписує історію. git merge
майже завжди є кращим вибором, оскільки він поважає те, що насправді відбулося у вашому проекті.