Git объединить мастер в ветке функций


1018

Допустим, у нас есть следующая ситуация в 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. Разработка на feature1 продолжается:

    git checkout feature1
    

Скажем, мне нужно исправление в моей ветке функций, возможно, потому что ошибка также происходит там. Как я могу добиться этого, не дублируя коммиты в моей ветке функций?

Я хочу запретить получение двух новых коммитов в моей ветви функций, которые не имеют отношения к реализации функции. Это особенно важно для меня, если я использую pull-запросы: все эти коммиты также будут включены в pull-запрос и должны быть проверены, хотя это уже было сделано (так как исправление уже есть в master).

Я не могу сделать git merge master --ff-only: «роковым: невозможно выполнить перемотку вперед, прерывание». Но я не уверен, помогло ли это мне.


8
Если филиал feature1полностью локальный, посмотрите git rebase.
— Jokester

19
Спасибо, как начинающий мерзавец, git rebaseдля меня это похоже на черную магию ...
— theomega

13
если ветвь является функциональной - только исправление ошибки не должно происходить там (по крайней мере, если это не блокирующая ошибка), так как цель этой ветви - показать новую функцию. Ошибка будет исправлена ​​при объединении с мастером, где присутствует фиксация с исправлением.
— Джипи

21
Наверное, стоит отметить для начинающих, что в 3. git branch feature1и git checkout feature1можно объединить в git checkout -b feature14. и можно полностью сократить доgit checkout -b hotfix1 master
— Наруто Семпай

3
Хотели бы вы вернуться и изменить принятый ответ, потому что текущий принятый ответ ужасен?
— всевозможный

Ответы:


1220

Как мы объединяем основную ветку с функциональной веткой? Легко:

git checkout feature1
git merge master

Здесь нет смысла форсировать слияние в прямом направлении, поскольку это невозможно. Вы зафиксировали как в ветви функций, так и в основной ветви. Быстрая перемотка вперед невозможна.

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

Итак, что вы делали прямо в своем рабочем процессе? У вас есть две ветви для работы, ваша ветка feature1 - это, по сути, ветвь «разработки» в модели GitFlow.

Вы создали ветку исправлений из master и объединили ее обратно. И теперь вы застряли.

Модель GitFlow просит вас также добавить исправление в ветку разработки, которая в вашем случае является «feature1».

Таким образом, реальный ответ будет:

git checkout feature1
git merge --no-ff hotfix1

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

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


7
Нет. Фиксация, исправляющая ошибку, появляется только один раз в ветви исправлений, даже если имя ветви удаляется после объединения с ветвями master и devel. Фиксация слияния показывает только изменения, внесенные слиянием, которое выглядит как дублирующий коммит. Но так работает git: ветвь и сливай обратно. Реальная работа по разработке происходит только при фиксации без слияния, и слияние допускается только в том случае, если в результате получается работающее программное обеспечение.
— Свен

42
Это должен быть принятый ответ. Он также хорошо работает с функцией запросов GitHub.
— Nostalg.io

125
Я думаю, что стоит отметить, что a git merge masterобъединится с вашей локальной копией master, так что даже если вы сделали a git pullв своей ветви функций после того, как кто-то еще слил другую ветку в master, вам потребуется git checkout master, затем git pull, затем git checkout feature1снова и ТО git merge master,
— Дамик

50
@ Damick Или просто git fetchиgit merge origin/master
— Ингвар Кристиансен

20
@damick @ yngvar-kristiansen git pull origin masterавтоматически объединится orgin/masterс текущей веткой
— L422Y

614

Вы должны быть в состоянии перебазировать свою ветку на master:

git checkout feature1
git rebase master

Управляйте всеми конфликтами, которые возникают. Когда вы доберетесь до коммитов с исправлениями ошибок (уже в master), Git скажет, что изменений не было и, возможно, они уже были применены. Затем вы продолжаете ребаз (пропуская коммиты уже в мастере) с

git rebase --skip

Если вы выполните a git logв своей ветви функций, вы увидите, что фиксация исправления появляется только один раз и в основной части.

Для более подробного обсуждения, посмотрите документацию Git на git rebase( https://git-scm.com/docs/git-rebase ), которая описывает именно этот вариант использования.

================ Изменить для дополнительного контекста ====================

Этот ответ был предоставлен специально для вопроса, заданного @theomega, с учетом его конкретной ситуации. Обратите внимание на эту часть:

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

Перебазирование его частной ветки на master - именно то, что даст этот результат. Напротив, слияние master с его веткой точно сделало бы то, чего он конкретно не хочет : добавление коммита, не связанного с реализацией функции, над которой он работает, через его ветку.

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

  • только перебазировать частные ветки (то есть, которые существуют только в вашем локальном репозитории и не были переданы другим). Перебазировка общих веток «сломает» копии, которые могут иметь другие люди.
  • если вы хотите интегрировать изменения из ветви (будь то основная или другая ветка) в открытую ветку (например, вы подтолкнули ветку, чтобы открыть запрос на извлечение, но теперь есть конфликты с мастером, и вам необходимо обновить ваша ветвь, чтобы разрешить эти конфликты), вам нужно объединить их (например, git merge masterкак в ответе @ Sven).
  • Вы также можете объединить ветки в свои локальные частные ветки, если вы предпочитаете это, но помните, что это приведет к «чужим» коммитам в вашей ветке.

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


136
Нет, это небезопасно: если вы перебазируете, вы измените историю ветки, что повлияет на разработчиков, которые потянули ветку. inf act, git по умолчанию не позволяет вам выдвигать перебазированную ветку: вам нужно принудительно обновлять при -fнажатии, чтобы перезаписать ветку перебазированной версией. Быть осторожен!
— Дэвид Сульк

17
Как профессиональные команды, использующие git, справляются с этой проблемой? Стоит ли просто обратить внимание, тщательно продумать, а потом сделать -f? Или мой полный рабочий процесс испорчен, потому что мне нужен -f?
— Theomega

30
Что ж, я бы рискнул «священным» правилом, состоящим в том, что вы не перемещаете (или иным образом не изменяете историю коммитов) код, который был передан: это только для вашего локального кода. По сути, вы должны отменить изменения, чтобы «очистить» их, прежде чем делиться ими. В вашем случае вы можете выдвинуть новую перебазированную ветвь (с другим именем) и попросить коллег основать свои изменения на этой ветке (то есть, перебазировав свою локальную ветку с новой, как указано выше). Затем удалите feature1из Github.
— Дэвид Сульк

19
Большинство профессиональных команд, над которыми я работал, почти никогда не используют rebase - они просто объединяют все по умолчанию, так что никаких изменений в истории не происходит. Это мой любимый способ работы. С другой стороны, некоторые команды используют rebase для «очистки» коммитов до того, как они их подтолкнули (но никогда после них).
— Джонатан Хартли,

11
Да, вы никогда не должны перебазировать публичные ветки. Однако вопрос OP, казалось, касался интеграции новых коммитов, сделанных masterв частную ветвь (он упоминает «свою» местную ветвь). В этом случае rebaseвсе в порядке и тот же случай использования, что и упомянутая вами «очистка».
— Дэвид Сульк

69

Основываясь на этой статье , вы должны:

  • создать новую ветку, основанную на новой версии мастера

    git branch -b newmaster

  • объединить вашу старую функциональную ветку в новую

    git checkout newmaster

  • разрешить конфликт в новой ветви функций

Первые две команды могут быть объединены в git checkout -b newmaster.

Таким образом, ваша история остается ясной, потому что вам не нужны обратные слияния. И вам не нужно быть очень осторожным, потому что вам не нужно делать ребаз.


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чтобы попасть на ветку hotfix1. Затем выполните 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
— Гильденстерн,

0

Я нахожусь на ветке Feature и сделал рефакторинги. Теперь я хочу объединить основные изменения с моей веткой функций. Я далеко позади. Примечание. Я не хочу переносить основные изменения в локальную версию, поскольку в моей ветви функций есть модули, перемещенные из одного места в другое. Я нашел только выполнение ниже без тяги не работает. он говорит: «Уже в курсе».

 //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.