Допустим, у нас есть следующая ситуация в git:
-
Созданный репозиторий:
mkdir GitTest2
cd GitTest2
git init
-
Некоторые изменения в мастере происходят и совершаются.
echo "On Master" > file
git commit -a -m "Initial commit"
-
Feature1 разветвлен от мастера, и некоторая работа сделана:
git branch feature1
git checkout feature1
echo "Feature1" > featureFile
git commit -a -m "Commit for feature1"
-
Тем временем в мастер-коде обнаружена ошибка и установлена ветка хотфикса
git checkout master
git branch hotfix1
git checkout hotfix1
-
Ошибка исправлена в ветке исправлений и объединена с мастером (возможно, после запроса на просмотр/проверки кода):
echo "Bugfix" > bugfixFile
git commit -a -m "Bugfix Commit"
git checkout master
git merge --no-ff hotfix1
-
Разработка на feature1 продолжается:
git checkout feature1
Теперь мой вопрос: скажем, мне нужно исправление в моей ветке функций, возможно, потому что там также происходит ошибка. Как я могу достичь этого, не дублируя коммиты в моей ветке функций? Я хочу запретить получение двух новых коммитов в моей ветки функций, которые не имеют отношения к реализации функции. Это особенно важно для меня, если я использую Pull Requests: все эти коммиты также будут включены в Pull Request и должны быть рассмотрены, хотя это уже было сделано (так как исправление уже есть в мастере).
Я не могу сделать git merge master --ff-only
: "fatal: невозможно выполнить перемотку вперед, прерывание.", Но я не уверен, помогло ли это мне.
Ответ 1
Вы должны иметь возможность перебазировать свою ветку на master:
git checkout feature1
git rebase master
Управляйте всеми конфликтами, которые возникают. Когда вы доберетесь до коммитов с исправлениями ошибок (уже в master), git скажет, что изменений не было и, возможно, они уже были применены. Затем вы продолжаете ребаз (пропуская коммиты уже в мастере) с
git rebase --skip
Если вы выполните git log
в своей ветки функций, вы увидите, что фиксация исправления появляется только один раз и в основной части.
Для более подробного обсуждения взгляните на документацию Git по git rebase
(https://git-scm.com/docs/git-rebase), которая охватывает именно этот вариант использования.
================ Изменить для дополнительного контекста ====================
Этот ответ был предоставлен специально для вопроса, заданного @theomega, с учетом его конкретной ситуации. Обратите внимание на эту часть:
Я хочу запретить коммиты [...] в моей ветки функций, которые не имеют отношения к реализации функций.
Перебазирование его частной ветки на master - именно то, что даст этот результат. Напротив, слияние master с его веткой точно сделало бы то, чего он конкретно не хочет: добавление коммита, не связанного с реализацией функции, над которой он работает, через его ветку.
Чтобы обратиться к пользователям, которые читают заголовок вопроса, пропустите реальное содержание и контекст вопроса, а затем только вслепую прочитайте верхний ответ, предполагая, что он всегда будет применяться к их (другому) варианту использования, позвольте мне уточнить:
- только перебазировать частные ветки (то есть, которые существуют только в вашем локальном репо и не были переданы другим). Перебазировка общих веток "сломает" копии, которые могут иметь другие люди.
- если вы хотите интегрировать изменения из ветки (будь то master или другая ветвь) в общедоступную ветку (например, вы подтолкнули ветку, чтобы открыть запрос на извлечение, но теперь есть конфликты с master, и вам нужно обновить ветвь для разрешения этих конфликтов) вам нужно объединить их (например, с помощью
git merge master
как в ответе @Sven). - Вы также можете объединить ветки в свои локальные частные ветки, если это ваше предпочтение, но помните, что это приведет к "чужим" коммитам в вашей ветке.
Наконец, если вы недовольны тем фактом, что этот ответ не совсем подходит для вашей ситуации, даже если он был для @theomega, добавление комментария ниже не будет особенно полезным: я не контролирую, какой ответ выбран, только @theomega делает.
Ответ 2
Как объединить ведущую ветвь в ветвь функции? Легко:
git checkout feature1
git merge master
Нет смысла форсировать быстрое переключение вперед, поскольку это невозможно. Вы передали как в ветки функции, так и в главную ветвь. Быстрая перемотка вперед невозможна.
Посмотрите gitflow. Это модель ветвления для git, которой можно следовать, и вы бессознательно уже сделали. Он также является расширением для git, который добавляет некоторые команды для новых шагов рабочего процесса, которые делают вещи автоматически, которые вам в противном случае нужно было бы сделать вручную.
Итак, что вы делали прямо в своем рабочем процессе? У вас есть две ветки для работы, ваша ветвь feature1 - это, в основном, "развитая" ветвь в модели gitflow.
Вы создали ветвь исправления от мастера и объединили ее. И теперь вы застряли.
Модель gitflow просит объединить исправление также в ветку devel, которая является "feature1" в вашем случае.
Итак, реальный ответ:
git checkout feature1
git merge --no-ff hotfix1
Это добавляет все изменения, которые были внесены в исправление в ветвь функции, но ТОЛЬКО эти изменения. Они могут конфликтовать с другими изменениями развития в ветки, но они не будут конфликтовать с ведущей веткой, если вы в конечном итоге объедините ветвь функции обратно в мастер.
Будьте очень осторожны при перезагрузке. Переустановите только в том случае, если изменения, которые вы сделали, остались локальными в вашем репозитории, например. вы не нажимали какие-либо ветки на другой репозиторий. Rebasing - отличный инструмент для того, чтобы вы могли организовать свои локальные коммиты в полезный порядок, прежде чем выталкивать его в мир, но после этого буйство будет бесполезно для начинающих, таких как вы.
Ответ 3
Основываясь на этой статье, вы должны:
-
создать новую ветку, основанную на новой версии мастера
git branch -b newmaster
-
объединить вашу старую функциональную ветку в новую
git checkout newmaster
-
разрешить конфликт в новой ветки функций
Первые две команды могут быть объединены для git checkout -b newmaster
Таким образом, ваша история остается ясной, потому что вам не нужны обратные слияния. И вам не нужно быть очень осторожным, потому что вам не нужен git rebase
Ответ 4
Ответ Zimi описывает этот процесс в целом. Вот специфика:
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) В новой ветке разрешите любые конфликты между вашей функцией и главной ветвью.
Готово! Теперь используйте новую ветку, чтобы продолжить разработку вашей функции.
Ответ 5
Возможно, вы сможете сделать "вишневый выбор", чтобы вытащить точные фиксации, которые вам нужны, в свою ветку функций.
Сделайте git checkout hotfix1
, чтобы попасть в ветвь hotfix1. Затем выполните git log
, чтобы получить хэш SHA1 (большая последовательность случайных букв и цифр, которые однозначно идентифицируют фиксацию) рассматриваемого коммита. Скопируйте это (или первые 10 или около того символов).
Затем git checkout feature1
вернемся к вашей ветке свойств.
Тогда git cherry-pick <the SHA1 hash that you just copied>
Это приведет к тому, что фиксация и только фиксация произойдет в вашей ветке свойств. Это изменение будет в ветке - вы просто "вишнево" выбрали его. Затем возобновите работу, отредактируйте, зафиксируйте, нажимайте и т.д. На ваш сердечный контент.
Когда, в конце концов, вы выполняете другое слияние из одной ветки в свою ветвь функции (или наоборот), git распознает, что вы уже слились в этом конкретном коммите, знайте, что ей не нужно делать это снова, и просто "пропустите" его.
Ответ 6
Вот скрипт, который вы можете использовать, чтобы объединить вашу основную ветку с вашей текущей веткой.
Сценарий выполняет следующие действия:
- Переключается на главную ветку
- Тянет мастер ветку
- Переключается обратно на вашу текущую ветку
- Объединяет основную ветку с вашей текущей веткой
Сохраните этот код в виде пакетного файла (.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