Как выбрать ряд коммитов и слияние в другую ветвь?
-
22-09-2019 - |
Вопрос
У меня есть следующий макет репозитория:
- главная филиал (производство)
- интеграция
- работающий
Чего я хочу достичь, так это выбрать ряд коммитов из рабочей филиала и объединить его в филиал интеграции. Я довольно новичок в GIT, и я не могу понять, как именно это сделать (выбор вишневой дистанции в одной операции, а не слияние), не испортив репозиторий. Есть указатели или мысли по этому поводу? Спасибо!
Решение
Когда дело доходит до ряда коммитов, вишня является был не практично.
В качестве упомянуто ниже по Кит Ким, GIT 1.7.2+ представил способность вишнить ряд коммитов (но вам все еще нужно знать о Следствие вымывания вишни для будущего слияния)
git cherry-pick "научился выбрать ряд коммитов
(например, "cherry-pick A..B
" а также "cherry-pick --stdin
"), тоже"git revert
"; Они не поддерживают более приятный контроль секвенирования"rebase [-i]
"есть, хотя.
Дамиан Комментарии и предупреждает нас:
В "
cherry-pick A..B
" форма,A
должен быть старше, чемB
.
Если они не в том же порядке, команда молча потерпит неудачу.
Если вы хотите выбрать диапазон B
через D
(включительно) это было бы B^..D
.
Видеть "Git создать филиал из линейки предыдущих коммитов?"Как иллюстрация.
В качестве Джубобс упоминания В комментариях:
Это предполагает это
B
не является корневым коммитом; ты получишь "unknown revision
"Ошибка в противном случае.
Примечание. По состоянию на GIT 2.9.x/2.10 (Q3 2016) вы можете выбрать ряд коммита непосредственно на ветви сироты (пустая головка): см. "Как сделать существующую ветвь сиротой в git".
Оригинальный ответ (январь 2010 г.)
А rebase --onto
было бы лучше, когда вы воспроизводите диапазон коммита в верхней части вашей филиала интеграции, как Чарльз Бэйли описал здесь.
(Кроме того, ищите «Вот как вы бы пересадировали ветвь темы, основанную на одной ветви в другую» в Git Rebase Man Page, чтобы увидеть практическое пример git rebase --onto
)
Если ваша текущая филиал интеграция:
# Checkout a new temporary branch at the current location
git checkout -b tmp
# Move the integration branch to the head of the new patchset
git branch -f integration last_SHA-1_of_working_branch_range
# Rebase the patchset onto tmp, the old location of integration
git rebase --onto tmp first_SHA-1_of_working_branch_range~1 integration
Это воспроизводит все между:
- после родителей
first_SHA-1_of_working_branch_range
(следовательно~1
): первый коммит, который вы хотите воспроизвести - вплоть до "
integration
"(Что указывает на последний коммит, который вы хотите воспроизвести изworking
ответвляться)
к "tmp
"(Что указывает на то, где integration
указывал раньше)
Если есть какой -либо конфликт, когда один из этих коммитов воспроизводится:
- Либо решайте и бегите "
git rebase --continue
". - или пропустите этот патч и вместо этого беги "
git rebase --skip
" - или отмените все с помощью "
git rebase --abort
"(и вернитеintegration
ветвь наtmp
ответвляться)
После того rebase --onto
, integration
Вернутся в последнюю филиал интеграции (то есть "tmp
"Ветвь + все воспроизводимые коммиты)
С вишней или rebase --onto
, не забывайте, что это имеет последствия для последующих слияний, как описано здесь.
Чистый "cherry-pick
"Решение есть обсуждается здесь, и будет включать что -то вроде:
Если вы хотите использовать подход к патчам, то ваши варианты «GIT Format-Patch | Git Am» и «Git Cherry».
В настоящее время,git cherry-pick
принимает только один коммит, но если вы хотите выбрать диапазонB
черезD
это было быB^..D
в git lingo, так что
git rev-list --reverse --topo-order B^..D | while read rev
do
git cherry-pick $rev || break
done
Но в любом случае, когда вам нужно «воспроизвести» диапазон коммитов, слово «воспроизведение» должно подтолкнуть вас к использованию «rebase
"Особенность git.
Другие советы
По состоянию на git v1.7.2 Cherry Pick может принять ряд коммитов:
git cherry-pick
научился выбрать ряд коммитов (например,cherry-pick A..B
а такжеcherry-pick --stdin
), так и сделалgit revert
; Они не поддерживают более приятный контроль секвенированияrebase [-i]
есть, хотя.
Предположим, что у вас есть 2 ветви,
«Brancha»: включает в себя коммиты, которые вы хотите скопировать (от «Commita» в «Комплект»
«BranchB»: ветвь, которую вы хотите, чтобы коммиты были переданы из "Brancha"
1)
git checkout <branchA>
2) Получите идентификаторы "Commica" и "Commineb"
3)
git checkout <branchB>
4)
git cherry-pick <commitA>^..<commitB>
5) В случае, если у вас есть конфликт, решайте его и введите
git cherry-pick --continue
Чтобы продолжить процесс вишни.
Вы уверены, что не хотите на самом деле объединять ветви? Если у рабочего филиала есть несколько недавних коммитов, которые вам не нужны, вы можете просто создать новую филиал с головой в той точке, которую вы хотите.
Теперь, если вы действительно хотите выбрать ряд коммитов, по какой-то причине, элегантный способ сделать это-просто вытащить патч и применить его к новой филиале интеграции:
git format-patch A..B
git checkout integration
git am *.patch
По сути, это то, что делает git-rebase в любом случае, но без необходимости играть в игры. Можете добавить --3way
к git-am
Если вам нужно слиться. Убедитесь, что в каталоге уже нет других файлов.
Я завернулся Код VONC в короткий сценарий, git-multi-cherry-pick
, для легкого бега:
#!/bin/bash
if [ -z $1 ]; then
echo "Equivalent to running git-cherry-pick on each of the commits in the range specified.";
echo "";
echo "Usage: $0 start^..end";
echo "";
exit 1;
fi
git rev-list --reverse --topo-order $1 | while read rev
do
git cherry-pick $rev || break
done
В настоящее время я использую это, так как перестраиваю историю проекта, в котором как код 3-й стороны, так и настройки смешаны в одном и том же стволе SVN. Сейчас я разделяю основной код сторонних сторон, сторонние модули и настройки на их собственные филиалы GIT для лучшего понимания настройки в будущем. git-cherry-pick
полезен в этой ситуации, так как у меня есть два дерева в том же хранилище, но без общего предка.
Все вышеперечисленные варианты побуждают вас разрешить конфликты слияния. Если вы объединяете изменения, совершенные для команды, трудно разрешить конфликты слияния от разработчиков и продолжить. Тем не менее, «Git Merge» сделает слияние за один выстрел, но вы не можете передать ряд пересмотров в качестве аргумента. Мы должны использовать команды «GIT Diff» и «GIT Apply», чтобы выполнить диапазон слияний Revs. Я заметил, что «GIT Apply» не будет сбой, если в файле Patch есть DIFF для слишком большого количества файла, поэтому мы должны создать патч на файл, а затем применить. Обратите внимание, что скрипт не сможет удалить файлы, удаленные в источнике. Это редкий случай, вы можете вручную удалить такие файлы из целевой ветви. Статус выхода «GIT Apply» не равен нулю, если он не сможет применить патч, однако, если вы используете опцию -3way, он вернется к 3 -ым способу слияния, и вам не нужно беспокоиться об этой неудаче.
Ниже приведен сценарий.
enter code here
#!/bin/bash
# This script will merge the diff between two git revisions to checked out branch
# Make sure to cd to git source area and checkout the target branch
# Make sure that checked out branch is clean run "git reset --hard HEAD"
START=$1
END=$2
echo Start version: $START
echo End version: $END
mkdir -p ~/temp
echo > /tmp/status
#get files
git --no-pager diff --name-only ${START}..${END} > ~/temp/files
echo > ~/temp/error.log
# merge every file
for file in `cat ~/temp/files`
do
git --no-pager diff --binary ${START}..${END} $file > ~/temp/git-diff
if [ $? -ne 0 ]
then
# Diff usually fail if the file got deleted
echo Skipping the merge: git diff command failed for $file >> ~/temp/error.log
echo Skipping the merge: git diff command failed for $file
echo "STATUS: FAILED $file" >> /tmp/status
echo "STATUS: FAILED $file"
# skip the merge for this file and continue the merge for others
rm -f ~/temp/git-diff
continue
fi
git apply --ignore-space-change --ignore-whitespace --3way --allow-binary-replacement ~/temp/git-diff
if [ $? -ne 0 ]
then
# apply failed, but it will fall back to 3-way merge, you can ignore this failure
echo "git apply command filed for $file"
fi
echo
STATUS=`git status -s $file`
if [ ! "$STATUS" ]
then
# status is null if the merged diffs are already present in the target file
echo "STATUS:NOT_MERGED $file"
echo "STATUS: NOT_MERGED $file$" >> /tmp/status
else
# 3 way merge is successful
echo STATUS: $STATUS
echo "STATUS: $STATUS" >> /tmp/status
fi
done
echo GIT merge failed for below listed files
cat ~/temp/error.log
echo "Git merge status per file is available in /tmp/status"
Другой вариант может заключаться в том, чтобы слиться со стратегией нашей коммитировкой перед диапазоном, а затем «нормальное» слияние с последним коммитом этого диапазона (или ветви, когда он последний). Поэтому предположим, что только 2345 и 3456 Commits Master будут объединены в филиал:
master: 1234 2345 3456 4567
В филиале:
git merge -s ours 4567 git merge 2345