Мастер об’єднання Git у гілку функцій


1013

Скажімо, у Git у нас є така ситуація:

  1. Створене сховище:

    mkdir GitTest2
    cd GitTest2
    git init
    
  2. Деякі зміни в майстрі відбуваються і приймаються:

    echo "On Master" > file
    git commit -a -m "Initial commit"
    
  3. Feature1 відгалужений майстер, і виконується деяка робота:

    git branch feature1
    git checkout feature1
    echo "Feature1" > featureFile
    git commit -a -m "Commit for feature1"
    
  4. Тим часом у майстер-коді виявлено помилку і встановлюється виправлення-гілка:

    git checkout master
    git branch hotfix1
    git checkout hotfix1
    
  5. Помилка виправляється у гілці виправлень та об’єднується назад у головний майстер (можливо після перегляду запиту / коду):

    echo "Bugfix" > bugfixFile
    git commit -a -m "Bugfix Commit"
    git checkout master
    git merge --no-ff hotfix1
    
  6. Розвиток на функцію1 триває:

    git checkout feature1
    

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

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

Я не можу зробити git merge master --ff-only: "фатально: Неможливо перемотати вперед, перериваючи життя", але я не впевнений, чи це мені допомогло.


8
Якщо філія feature1повністю локальна, погляньте git rebase.
Джокер

19
Дякую, як для початківців git, git rebaseмені здається чорною магією ....
theomega

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

21
Напевно, варто відзначити початківцям, що в 3. git branch feature1і їх git checkout feature1можна об’єднати в git checkout -b feature14. і цілком можна звести доgit checkout -b hotfix1 master
Наруто Семпай

3
Чи готові ви повернутися та змінити прийняту відповідь, адже поточна прийнята відповідь жахлива.
всезначний

Відповіді:


1214

Як ми об'єднаємо головну гілку в гілку функції? Легко:

git checkout feature1
git merge master

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

Погляньте на GitFlow . Це розгалужена модель для git, яку можна дотримуватися, і ви це підсвідомо вже зробили. Це також є розширенням до Git, яке додає деякі команди для нових кроків робочого процесу, які роблять автоматичні дії, які б інакше потрібно було робити вручну.

Отже, що ти зробив правильно у своєму робочому процесі? У вас є дві гілки, з якими ви працюєте, ваша особливість1 - це в основному гілка "розвивати" в моделі GitFlow.

Ви створили гілку виправлень у майстра та об’єднали її назад. А тепер ти застряг.

Модель GitFlow просить ви об'єднати виправлення також до гілки розвитку, яка є "функцією1" у вашому випадку.

Тож справжня відповідь була б:

git checkout feature1
git merge --no-ff hotfix1

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

Будьте дуже обережні з перезавантаженням. Перезавантажте лише те, якщо зміни, які ви внесли, залишилися локальними для вашого сховища, наприклад, якщо ви не пересували жодні гілки до іншого сховища. Rebasing - це чудовий інструмент для того, щоб влаштувати свої місцеві зобов’язання в корисне замовлення перед тим, як виштовхувати його у світ, але звільнення після цього зіпсує речі для початківців git, як ви.


7
Ні. Фіксація помилки фіксується лише один раз у гілці виправлення, навіть якщо ім'я гілки видаляється, коли вона об'єднується у гілки master та devel. Коміт злиття показує лише зміни, внесені об'єднанням, що виглядає як дублікат. Але ось як працює git: Відділіться і зливайтеся назад. Справжня робота з розробки відбувається лише в комісіях, що не об'єднуються, і злиття приймається лише в тому випадку, якщо в результаті працює програмне забезпечення.
Свен

42
Це має бути прийнятою відповіддю. Він також добре працює з функцією запиту на витяг GitHub.
Nostalg.io

125
Я думаю, що варто зауважити, що git merge masterзлиття з вашої локальної копії майстра, тому навіть якщо ви зробили git pullу своїй функції гілки після того, як хтось інший об'єднав іншу гілку в головну, вам потрібно буде git checkout masterпотім git pull, потім git checkout feature1ще раз git merge master.
Дамік

50
@damick Або просто git fetchіgit merge origin/master
Yngvar Kristiansen

20
@damick @ yngvar-kristiansen git pull origin masterавтоматично приєднається orgin/masterдо поточної гілки
L422Y

612

Ви повинні мати можливість відновити базу даних своєї гілки на головній:

git checkout feature1
git rebase master

Управління всіма конфліктами, що виникають. Коли ви дістанетесь до комітетів із виправленнями помилок (вже в master), Git скаже, що змін не було і можливо, вони вже були застосовані. Потім ви продовжуєте ребазування (пропускаючи комітети, які вже знаходяться в програмі master) з

git rebase --skip

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

Для більш детальної дискусії подивіться документацію Git book git rebase( https://git-scm.com/docs/git-rebase ), яка висвітлює цей конкретний випадок використання.

================ Редагувати для додаткового контексту =====================

Ця відповідь була надана спеціально на запитання, задане @theomega, враховуючи його конкретну ситуацію. Зверніть увагу на цю частину:

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

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

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

  • лише базувати приватні відділення (тобто такі, що існують лише у вашому локальному сховищі та не мають спільного доступу з іншими). Випуск спільних гілок "зламає" копії інших людей.
  • якщо ви хочете інтегрувати зміни з гілки (будь то головна чи інша гілка) у публічну гілку (наприклад, ви підштовхнули гілку, щоб відкрити запит на витяг, але зараз з конфліктом є головний, і вам потрібно оновити для вирішення цих конфліктів вам потрібно буде об'єднати їх (наприклад, git merge masterяк у відповіді @ Sven).
  • Ви також можете об'єднати гілки у ваші місцеві приватні філії, якщо це вам подобається, але пам’ятайте, що це призведе до «іноземних» зобов’язань у вашій філії.

Нарешті, якщо ви незадоволені тим, що ця відповідь не найкраще підходить для вашої ситуації, навіть якщо це було для @theomega, додавання коментаря нижче не буде особливо корисним: я не контролюю, яку відповідь обрано, тільки @theomega робить.


136
Ні, це не безпечно: якщо ви перезавантажуєтесь, ви змінюєте історію філії, що вплине на розробників, які витягнули гілку. inf act, git не дозволить вам натиснути скасовану гілку за замовчуванням: вам потрібно змусити оновлення, -fнатиснувши, щоб перезаписати гілку з версією на основі версії. Будь обережний!
Девід Сулк

17
Як професійні команди, що використовують git, вирішують це питання? Чи просто зверніть увагу, ретельно подумайте, а потім зробіть -f? Або мій повний робочий процес недосконалий, тому що мені потрібен -f?
theomega

30
Що ж, я б ризикнув "священним" правилом, якщо ви не перезавантажуєте (або іншим чином змінюєте історію фіксації) на код, яким поділився: це лише для вашого локального коду. По суті, ви повинні повторно змінити свої зміни, щоб "очистити", перш ніж поділитися ними. У вашому випадку ви можете висунути нову відновлювану гілку (з іншою назвою) і попросити колег базувати свої зміни на цій гілці (тобто, перезавантаживши їх локальну гілку на нову, як вище). Потім видаліть feature1з Github.
Девід Сулк

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

11
Так, вам НІКОЛИ не слід проводити оновлення публічних відділень. Однак питання ОП, здавалося, стосується інтеграції нових комісій, прийнятих masterу приватну галузь (він згадує "свою" місцеву гілку). У цьому випадку rebaseце нормально і це той самий випадок використання, що і «очищення», яке ви згадуєте.
Девід Сулк

69

На основі цієї статті вам слід:

  • створити нову гілку, яка базується на новій версії master

    git branch -b newmaster

  • об'єднайте свою стару гілку функції в нову

    git checkout newmaster

  • вирішити конфлікт на новій функції

Перші дві команди можна комбінувати до git checkout -b newmaster.

Таким чином ваша історія залишається чистою, тому що вам не потрібно назад злиття. І вам не потрібно бути настільки обережними, оскільки вам не потрібно робити Git rebase.


7
Було б добре, якби ви зробили відповідну команду git дотримуватися кожного пункту. Інакше мені здається, що це дійсно більш безпечний і чистий варіант.
VirgileD

@zimi Що робити, якщо у нас є віддалений відділення? Чи будемо ми знову відтворити нову гілку функцій оновлення? Або ми можемо просто встановити віддалений вгору за течією?
БАЙЛ

@VirgileD Я щойно опублікував власну відповідь з більш детальною інформацією, включаючи відповідні команди git.
jkdev

29

git merge

ви можете виконати наведені нижче кроки

1. злиття origin/masterгілки до featureгілки

# step1: change branch to master, and pull to update all commits
$ git checkout master
$ git pull

# step2: change branch to target, and pull to update commits
$ git checkout feature
$ git pull

# step3: merge master to feature(⚠️ current is feature branch)
$ git merge master

2. злиття featureгілки до origin/masterгілки

origin/masterє віддаленим головним відділенням, тоді masterяк місцевим головним відділенням

$ git checkout master
$ git pull origin/master

$ git merge feature
$ git push origin/master




Відчуває, що ребауз переглянуто! Добре старе злиття :)!
Раніше

27

Відповідь Зімі загалом описує цей процес. Ось специфіка:

  1. Створіть та перейдіть на нову гілку. Переконайтеся, що нова гілка заснована на masterтому, що вона буде включати останні виправлення.

    git checkout master
    git branch feature1_new
    git checkout feature1_new
    
    # Or, combined into one command:
    git checkout -b feature1_new master
    
  2. Після переходу на нову гілку об'єднайте зміни з існуючою гілкою функцій. Це додасть ваші зобов’язання, не дублюючи виправлення.

    git merge feature1
    
  3. На новій гілці вирішіть будь-які конфлікти між вашою функцією та основною гілкою.

Готово! Тепер використовуйте нову гілку, щоб продовжувати розвивати свою функцію.


2
Проблема в цьому полягає в тому, що розробник витрачає час, постійно нерестуючи нові гілки, коли їм потрібно оновитись проти головного. Ми робимо багато-багато відділень, ймовірно, 3 рази на день під час активної роботи. Ви маєте написати інструкції щодо очищення всіх місцевих гілок сміття та способів позбавлення від них також на віддаленому. Нам також потрібні поради щодо назви всіх цих гілок, щоб ми не плуталися. Без цього шматочка це перетворить галузеву систему в хаос.
pauljohn32

4
Ти маєш рацію, цього не слід робити постійно. Тільки тоді, коли (1) зміни в master є необхідними для вашої функції, або (2) ви збираєтеся об'єднати свою гілку з master і можуть виникнути конфлікти. А щоб уникнути безладу, ви можете видалити свою гілку після її об’єднання.
jkdev

11

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

Сценарій виконує наступні дії:

  • Перемикається на головну гілку
  • Тягне головну гілку
  • Перемикається назад на поточну гілку
  • Об’єднує головну гілку у вашу поточну гілку

Збережіть цей код як пакетний файл (.bat) та розмістіть скрипт у будь-якому місці вашого сховища. Потім натисніть на нього, щоб запустити його і ви налаштовані.

:: This batch file pulls current master and merges into current branch

@echo off

:: Option to use the batch file outside the repo and pass the repo path as an arg
set repoPath=%1
cd %repoPath%

FOR /F "tokens=*" %%g IN ('git rev-parse --abbrev-ref HEAD') do (SET currentBranch=%%g)

echo current branch is %currentBranch%
echo switching to master
git checkout master
echo.
echo pulling origin master
git pull origin master
echo.
echo switching back to %currentBranch%
git checkout %currentBranch%
echo.
echo attemting merge master into %currentBranch%
git merge master
echo.
echo script finished successfully
PAUSE

10

Можливо, вам вдасться зробити "вишню", щоб виконати точні фіксації, які вам потрібні для вашої функції функції.

Виконайте, git checkout hotfix1щоб потрапити на гілку виправлення1. Потім зробіть a, git logщоб отримати хеш SHA-1 (велика послідовність випадкових букв і цифр, що однозначно ідентифікує фіксацію) відповідного коміту. Скопіюйте це (або перші 10 символів).

Потім, git checkout feature1щоб повернутися до своєї функції.

Тоді, git cherry-pick <the SHA-1 hash that you just copied>

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

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


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

1
"Коли, врешті-решт, ви здійснюєте чергове злиття з однієї гілки у вашу функціональну гілку (або навпаки), git визнає, що ви вже об'єднали [...]" - так це насправді працює? Я не думаю, що це git mergeпрацює у цій програмі "повторного скоєння", на яку ви, схоже, натякаєте ("і просто пропустіть її"). Змішування збирання та злиття вишні, очевидно, може призвести до проблем; дивіться: news.ycombinator.com/item?id=3947950
Guildenstern

0

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

 //below does not get the latest from remote master to my local feature branch without git pull
    git checkout master 
    git fetch 
    git checkout my-feature-branch 
    git merge master

Це нижче працює, зверніть увагу на використання git merge origin / master:

 git checkout master 
    git fetch 
    git checkout my-feature-branch 
    git merge origin/master
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.