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: «роковым: невозможно выполнить перемотку вперед, прерывание». Но я не уверен, помогло ли это мне.

theomega
источник
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, таких как вы.

Sven
источник
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.

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

zimi
источник
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
xgqfrms
источник
Чувствуется, что ребаз был раскручен! Старое доброе слияние :)!
навсегда
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. В новой ветке разрешите все конфликты между вашей функцией и главной веткой.

Выполнено! Теперь используйте новую ветку, чтобы продолжить развивать свою функцию.

jkdev
источник
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
Тони
источник