Перенести коммит в другую ветку git: используем cherry-pick для переноса commit в другую ветку
используем cherry-pick для переноса commit в другую ветку
Нередко возникает ситуация, когда срочно требуется выполнить небольшую задачу. Разработчик быстро пробегается глазами по ТЗ и старается максимально оперативно вникнуть в суть задачи. При этом можно попросту забыть создать новую ветку, и понять об ошибке уже после финального каммита.
В такой ситуации, когда возникает необходимость перенести commit из одной ветки в другую на помощь приходит команда git cherry-pick
, применяющая к дереву проекта изменения, которые были внесены указанным каммитом.
Синтаксис команды git cherry-pick
Рассмотрим ситуацию на примере. Мы находились в master
и сделали в него случайно коммит. Тогда чтобы вынести его в отдельную ветку и отправить на merge request нам потребуется выполнить следующие команды:
1. Смотрим историю изменений и запоминаем хэш коммита <hash-commit-0>
, соответствующего правильному состоянию ветки master
, то есть когда ещё в неё не было добавлено лишних коммитов по ошибке.
git log
2. Также следует запомнить хэш коммита <hash-commit-1>
, который был лишним в ветке master
. Иногда бывает, что лишними оказываются сразу несколько коммитов, тогда если они расположены последовательно друг за другом следует запомнить самый давний <hash-commit-begin>
и самый последний <hash-commit-end>
.
3. Перейдём на найденный коммит <hash-commit-0>
. Другими словами переходим на то состояние ветки master
, от которого нам нужно создать новую ветку.
git checkout <hash-commit-0>
4. Создадим новую ветку, в которую планируется вынести неверно расположенный коммит, и перейдем на неё.
git checkout -b <name-branch>
5. Переносим коммит в новую ветку.
git cherry-pick <hash-commit-1>
В случае, когда необходимо перенести последний коммит ветки master
, можно вместо хэша коммита просто написать master
, поскольку в данный момент указатель master
ссылается на последний коммит.
git cherry-pick master
Если же нужно перенести не один, а несколько подряд идущих коммитов от <hash-commit-begin>
до <hash-commit-end>
, то это делается похожим образом.
git cherry-pick <hash-commit-begin>..<hash-commit-end>
Если же вы хотите, чтобы при переносе изменений коммит не создавался, то используйте параметр -n (—no-commit):
git cherry-pick -n d112ecf96
Как и при операции git rebase
в процессе переноса коммита могут возникнуть конфликты. Как и при обычном git merge
их следует разрешить, добавить изменения в индекс с помощью git add
, а затем продолжить запустив git cherry-pick --continue
.
6. Теперь когда коммиты перенесены в ветку <name-branch>
, следует удалить их из ветки master
. Поэтому переключаемся на ветку master
git checkout master
Смещаем указать master
на коммит <hash-commit-0>
git reset --hard <hash-commit-0>
Понравилась статья? — Ставь лайк!
Как влить определённый коммит из одной ветки в другую git
git cherry-pick
— применение к дереву проекта изменений, внесенных определённым коммитом.
git cherry-pick <hash коммита>
— найдёт коммит по его хэшу и вольёт его в текущую ветку. Применятся изменения только конкретного коммита, причём изменения сразу же будут проиндексированы и будет создан новый коммит в активной ветке с таким же именем, как коммит и назывался. При наличии конфиликтных изменений, нужно будет решить конфликты, как и при «рядном» merge.
Если вам нужно перенести изменения в ветку из определённого коммита другой ветки так, чтобы коммит автоматически не создавался, то нужно использовать параметр -n
(—no-commit). Пример:
git cherry-pick -n d3edb354cd3c080b28d13dcb92448de81e543297
Все поддериживаемые параметры cherry-pick:
$ git cherry-pick
использование: git cherry-pick [options] <commit-ish>…
или: git cherry-pick <subcommand>
—quit end revert or cherry-pick sequence
—continue resume revert or cherry-pick sequence
—abort cancel revert or cherry-pick sequence
-n, —no-commit don’t automatically commit
-e, —edit edit the commit message
-s, —signoff add Signed-off-by:
-m, —mainline <n> parent number
—rerere-autoupdate update the index with reused conflict resolution if possible
—strategy <strategy>
merge strategy
-X, —strategy-option <option>
option for merge strategy
-x append commit name
—ff allow fast-forward
—allow-empty preserve initially empty commits
—allow-empty-message
allow commits with empty messages
—keep-redundant-commits
keep redundant, empty commits
Как перенести коммиты в другую ветку? — git
Я бы хотел перенести мои последние несколько коммитов от мастера в их собственную ветвь.
Дерево на моем PC выглядит именно так:
W (some branch)
/
X1--X2--X3--X4--Y--Z1--Z2 (master)
Я бы хотел, чтобы это выглядело так:
W (some branch)
/
X1--X2--X3--X4 (master)
\
Y--Z1--Z2 (my new branch)
Однако дерево в GitHub выглядит следующим образом:
W (some branch)
/
X1--X2--X3--X4--Y (master)
Это то, что я видел как решение для перемещения последних коммитов в другую ветвь:
git checkout master
git branch my_new_branch
git reset <commit_id>
Мой вопрос заключается в следующем: смогу ли я успешно нажать на GitHub после перемещения коммитов в новую ветвь и если да, то потребуется ли делать что-то еще, кроме этих трех команд?
git
branch
push
commit
Поделиться
Источник
Albus Dumbledore
17 мая 2011 в 18:57
3 Ответа
18
(Я предполагаю, что <commit_id>
— это имя объекта X4
…)
Эти команды действительно приведут вас к тому, что вы хотите локально. (Возможно, вы захотите использовать git reset --hard
, чтобы сохранить рабочее дерево и индекс таким же, как и фиксация, к которой вы сбрасываете, но, как обычно, будьте очень осторожны, чтобы git status
был чистым, прежде чем использовать эту команду.)
Если после этого вы попытаетесь нажать master на GitHub, он скажет вам, что все уже обновлено, потому что master
на GitHub-это один коммит вперед. Вы можете принудительно нажать кнопку, чтобы мастер был сброшен на GitHub, но это переписывание публичной истории, поэтому вы должны сделать это только в том случае, если (А) вы единственный, кто получит master
из GitHub или (б) вы можете сообщить своим сотрудникам, что делать, чтобы они случайно не слили Y
обратно. Если это OK, вы можете сделать:
git push --force origin master
…
и тогда master
на GitHub будет таким же, как ваша локальная версия.
Поделиться
Mark Longair
17 мая 2011 в 19:13
3
Это должно сработать, но вам понадобится:
- to
push -f origin master
(принудительный толчок, который будет означать неприятности, если кто-то еще уже клонировал ваше РЕПО) - чтобы нажать затем вашу новую ветвь (которая затем найдет
X4
sha1, поверх которой будет установлена указанная новая ветвь).
Поделиться
VonC
17 мая 2011 в 19:13
0
Никто не упоминал о том, что вы можете просто вишнево выбрать коммит в другую ветвь. Таким образом, ваше сообщение о фиксации все еще будет там для вас.
Просто скопируйте идентификатор ревизии вашего коммита, который вы хотите переместить.
git log --oneline
Чем создать новую ветвь поверх прежней фиксации и изменить ее:
git checkout -b "$newBranchName" HEAD~$n
(HEAD~$n расшифровывается как n-th commit)
или
git checkout -b "$newBranchName" $formerRevsion
Теперь вам просто нужно выбрать вишню, которую вы хотите совершить:
git cherry-pick $revision
Старый коммит все еще будет находиться в другой ветке, но вы можете исправить это с помощью rebase. Вернитесь в свою старую ветку и используйте rebase:
git rebase -i HEAD~$n
Просто удалите строку фиксации выбранного вишневого коммита, и ваша ветвь будет перебазирована без него. Вы должны использовать git push -f
, потому что ревизии всех ребазированных коммитов изменились.
Поделиться
Devpool
28 августа 2017 в 14:11
Похожие вопросы:
Как нажать на другую ветку с hg-git?
Пока я работал над своим клоном репозитория Git, удаленный контент изменился: $ hg push … abort: refs/heads/master changed on the server, please pull and merge before pushing Вместо слияния я хочу…
Как перенести многократные коммиты из одной ветви в другую с помощью git?
Есть две ветви: — производственная ветвь, содержащая продукт, принятый заказчиком — разработать ветку, где разработчики проводят свои жуткие эксперименты Однажды молодой разработчик решил отделить…
Git — как получить все новые коммиты из master в мою ветку
У меня есть мастер, из которого я создал другую ветвь и сделал некоторые коммиты на этой новой ветви. Между тем в это же время в master также происходили некоторые другие работы/коммиты. Итак,…
Переместить некоторые уже существующие и толкаемые коммиты в новую ветку
У меня есть ветвь функций по теме X, но в этой ветви я сделал коммиты, которые были бы лучше в ветви функций Y, но я забыл создать ее перед началом. Есть ли способ перенести этот коммит в новую…
Переместить коммиты из линейной истории в отдельную ветвь
Это не то же самое, что разделить ветку git на две ветви? а не как перенести определенные коммиты в другую ветку в git? У меня есть линейная история B—C , ветвящаяся от мастера: Master —A \ Foo…
Git : как протолкнуть некоторые коммиты на другую ветку
Это мой git : x—x—v2—x—x—x — dev / x—x—x—x—v1 — prod Теперь я хотел бы протолкнуть все коммиты до v2 из ветки dev в ветку prod, но v2 не является моим последним коммитом на ветке dev. Как я…
перемещение измененных файлов в другую ветку для регистрации
Это часто случается со мной: я пишу какой-то код, иду проверить свои изменения, а затем понимаю, что я не в той ветке, чтобы проверить эти изменения. Однако я не могу переключиться на другую ветку…
Переместить некоторые коммиты в другую ветку
У меня есть git РЕПО только в одной ветке A-B-C-D-E (master) Я хочу разделить коммиты B, C и D на другую ветку под названием develop A-E (master) \ B-C-D (develop) Каков самый простой способ сделать…
Как исключить коммиты из master в другую ветку
Некоторые из наших разработчиков совершили нерабочие коммиты на мастере. Я хотел бы очистить его, чтобы каждая фиксация на мастере была рабочей версией. Предположим, что у нас есть следующие…
Переместить коммиты в другую ветку
Я сделал три коммита на мастер-ветку и отодвинул их на дистанционное управление. Изменения должны были быть незначительными (применяя исправленный выпуск фреймворка), но столкнулись с действительно…
Как переместить определенные коммиты в другую ветку в git?
ситуация:
- мастер находится на X
- quickfix1 находится на X + 2 коммитов
такое, что:
o-o-X (master HEAD)
\
q1a--q1b (quickfix1 HEAD)
затем я начал работать над quickfix2, но случайно взял quickfix1 в качестве исходной ветви для копирования, а не мастера. Теперь quickfix2 находится в X + 2 commits + 2 соответствующих коммитов.
o-o-X (master HEAD)
\
q1a--q1b (quickfix1 HEAD)
\
q2a--q2b (quickfix2 HEAD)
Теперь я хочу иметь ветку с quickfix2, но без 2 коммитов, которые принадлежат quickfix1.
q2a'--q2b' (quickfix2 HEAD)
/
o-o-X (master HEAD)
\
q1a--q1b (quickfix1 HEAD)
Я попытался создать патч из определенной ревизии в quickfix2, но патч не сохраняет историю фиксации. Есть ли способ сохранить историю фиксации, но иметь ветку без изменений в quickfix1?
320
автор: Steve Eynon
5 ответов
Это классический случай rebase --onto
:
# let's go to current master (X, where quickfix2 should begin)
git checkout master
# replay every commit *after* quickfix1 up to quickfix2 HEAD.
git rebase --onto master quickfix1 quickfix2
так что вы должны пойти от
o-o-X (master HEAD)
\
q1a--q1b (quickfix1 HEAD)
\
q2a--q2b (quickfix2 HEAD)
в:
q2a'--q2b' (new quickfix2 HEAD)
/
o-o-X (master HEAD)
\
q1a--q1b (quickfix1 HEAD)
это лучше всего сделать на чистом рабочем дереве.
посмотреть git config --global rebase.autostash true
, особенно после Git 2.10.
можно использовать git cherry-pick
чтобы просто выбрать фиксацию,которую вы хотите скопировать.
вероятно, лучший способ-создать ветвь из master, а затем в этой ветви использовать git cherry-pick
на 2 коммитов из quickfix2, которые вы хотите.
самое простое, что вы можете сделать, это выбрать нужный ассортимент. Он делает то же самое, что и rebase --onto
но легче для глаз 🙂
git cherry-pick quickfix1..quickfix2
110
автор: Christoph
Я считаю, что это:
git checkout master
git checkout -b good_quickfix2
git cherry-pick quickfix2^
git cherry-pick quickfix2
22
автор: Matthew Flaschen
единственный рабочий способ, который я нашел:
git show>~/some_file.txt
git checkout master
git checkout -b new_branch
git apply -stat ~/some_file.txt
git apply -check ~/some_file.txt
git apply ~/some_file.txt
затем вам нужно снова зафиксировать изменения, но это намного проще, чем делать это вручную…
-3
автор: Ziv Barber
Переместить самые последние коммиты в новую ветку с помощью Git – 8 Ответов
Большинство предыдущих ответов опасно ошибочны!
НЕ делайте этого:
git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch
Как в следующий раз, когда вы запустите git rebase
(или git pull --rebase
), эти 3 фиксации будут отброшены без изменений из newbranch
! (см. пояснение ниже)
Вместо этого сделайте следующее:
git reset --keep HEAD~3
git checkout -t -b newbranch
git cherry-pick ..HEAD@{2}
- Сначала он отбрасывает 3 последних коммита (
--keep
похож на--hard
, но более безопасен, так как он терпит неудачу, а не выбрасывает незафиксированные изменения). - Затем он отключает
newbranch
. - Затем он вишневый выбирает, что эти 3 берет обратно на
newbranch
. Поскольку они больше не ссылаются на ветку, это делает это с помощью git reflog:HEAD@{2}
является фиксацией, которуюHEAD
используется для ссылки до 2-х операций назад, т.е. до того, как мы 1. проверилиnewbranch
и 2. использовалиgit reset
, чтобы отбросить 3 коммита.
Предупреждение: reflog включен по умолчанию, но если вы отключили его вручную (например, используя «голый» репозиторий git), вы не сможете получить 3 фиксации после запуска git reset --keep HEAD~3
.
Альтернативой, которая не полагается на reflog, является:
# newbranch will omit the 3 most recent commits.
git checkout -b newbranch HEAD~3
git branch --set-upstream-to=oldbranch
# Cherry-picks the extra commits from oldbranch.
git cherry-pick ..oldbranch
# Discards the 3 most recent commits from oldbranch.
git branch --force oldbranch oldbranch~3
(если вы предпочитаете писать @{-1}
— ранее выданную ветку — вместо oldbranch
).
Техническое объяснение
Почему git rebase
отказаться от 3-х коммитов после первого примера? Это потому, что git rebase
без аргументов по умолчанию использует параметр --fork-point
, который использует локальный рефлок, чтобы попытаться быть надежным против того, чтобы восходящая ветка была принудительно нажата.
Предположим, что вы разветвлялись от источника/хозяина, когда он содержал коммиты M1, M2, M3, а затем сделал три фиксации:
M1--M2--M3 <-- origin/master
\
T1--T2--T3 <-- topic
но затем кто-то переписывает историю с помощью принудительного толчка origin/master для удаления M2:
M1--M3' <-- origin/master
\
M2--M3--T1--T2--T3 <-- topic
Используя ваш локальный рефлок, git rebase
может видеть, что вы разветвлялись из более раннего воплощения ветки origin/master и, следовательно, коммиты M2 и M3 на самом деле не являются частью вашей ветки темы. Следовательно, он разумно предполагает, что, поскольку M2 был удален из ветки восходящего потока, вы больше не хотите его в своей ветки темы либо после того, как ветка темы будет пересоздана:
M1--M3' <-- origin/master
\
T1'--T2'--T3' <-- topic (rebased)
Такое поведение имеет смысл, и, как правило, это правильно делать при перезагрузке.
Итак, причина, по которой выполняются следующие команды:
git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch
заключается в том, что они оставляют reflog в неправильном состоянии. git видит newbranch
как разветвленную ветвь вверх по ревизии, которая включает в себя 3 коммита, затем reset --hard
перезаписывает историю восходящего потока, чтобы удалить коммиты, и поэтому в следующий раз при запуске git rebase
он отбрасывает их как любой другой фиксатор, который был удален из восходящего потока.
Но в этом конкретном случае мы хотим, чтобы эти 3 фиксации рассматривались как часть ветки темы. Чтобы достичь этого, нам нужно отбросить вверх по течению при более раннем пересмотре, который не включает 3 коммита. Это то, что мои предлагаемые решения делают, поэтому они оба оставляют reflog в правильном состоянии.
Подробнее см. определение --fork-point
в git rebase и git merge- базы.
Как скопировать коммиты из одной ветки в другую?
Решение
Вы действительно должны иметь рабочий процесс, который позволяет вам делать все это путем слияния:
- x - x - x (v2) - x - x - x (v2.1)
\
x - x - x (wss)
Так что все, что вам нужно сделать, это git checkout v2.1
и git merge wss
. Если по какой-то причине вы действительно не можете этого сделать и не можете использовать git rebase, чтобы переместить ветку wss в нужное место, команда для получения одного коммита и его применения в другом месте — это git cherry-pick . Просто отметьте ветку, в которой вы хотите ее применить, и запустите git cherry-pick <SHA of commit to cherry-pick>
.
Некоторые из способов rebase могут спасти вас:
Если ваша история выглядит так:
- x - x - x (v2) - x - x - x (v2.1)
\
x - x - x (v2-only) - x - x - x (wss)
Вы можете использовать git rebase --onto v2 v2-only wss
для перемещения WSS непосредственно на v2:
- x - x - x (v2) - x - x - x (v2.1)
|\
| x - x - x (v2-only)
\
x - x - x (wss)
Тогда вы можете слить! Если вы действительно, действительно, действительно не можете добраться до точки, где вы можете объединиться, вы все равно можете использовать rebase для эффективного выполнения нескольких вишневых выборов одновременно:
# wss-starting-point is the SHA1/branch immediately before the first commit to rebase
git branch wss-to-rebase wss
git rebase --onto v2.1 wss-starting-point wss-to-rebase
git checkout v2.1
git merge wss-to-rebase
Примечание: причина того, что для этого требуется дополнительная работа, заключается в том, что он создает дублирующие коммиты в вашем хранилище. Это на самом деле не очень хорошая вещь — весь смысл простого ветвления и слияния заключается в том, чтобы иметь возможность делать все, делая коммиты в одном месте и объединяя их там, где они нужны. Двойные коммиты означают намерение никогда не объединять эти две ветви (если вы решите, что захотите позже, вы получите конфликты).
Автор: Cascabel
Размещён: 19.03.2010 12:59
Перенос изменений произвольных файлов между ветками в git / Песочница / Хабр
Представим себе следующую ситуацию. Команда разработчиков, используя git в качестве системы контроля версий, работает несколько дней над одной из фич (feature). Назовем ее условно mega-feature. Произведено несколько десятков коммитов (commit) в ветку (branch) develop-mega-feature, которая была создана от ветки develop. В определенный момент времени возникает необходимость добавить результат работы над mega-feature в основную ветку (назовем ее master). При этом возникает следующая проблема, требующая нестандартного подхода: как перенести функционал mega-feature в виде отдельных файлов, в которых производились изменения, разбросанные по разным коммитам?
Один из наиболее популярных применяемых подходов к организации структуры веток в git-репозиториях, подробно описанный в следующем посте, изображен ниже:
Основная идея состоит в том, чтобы основная масса коммитов осуществлялась в ветку develop; для каждой из фич создавалась отдельная ветка, которая в последствии мержится (merge) в develop; слияние (merge) из develop в master осуществляется в моменты выхода очередных релизов (release). То есть в основной ветке хранится стабильная весия кода, который был, или будет выпущен.
При вышеописанной схеме решение проблемы добавления части функционала из экпериментальной ветки develop-mega-feature в master стандартными подходами, которые основаны на слиянии отдельных коммитов, довольно проблематично. В git существует возможность добавления из одной ветки в другую произвольно выбранных коммитов (опять же, коммитов, но не файлов!) с помощью git-cherry-pick, однако это не является решением описанной выше проблемы.
Существует достаточно элегантное решение, которое позволяет осуществлять добавление изменений, относящихся к недавно-разработанному функционалу mega-feature.
Итак, представим, что для переноса функционала mega-feature в master, необходимо добавить из ветки develop-mega-feature следующие новые файлы: megafeature/implementation.code, megafeature/description.txt и следующий модифицированный файл projectfeatures.code.
Находясь в ветке master, выполняем
git checkout develop-mega-feature megafeature/implementation.code megafeature/description.txt projectfeatures.code
в качестве аргументов указываем ветку, из которой собираемся добавлять функционал и список файлов, относящихся к функционалу mega-feature. Завершаем операцию командой
git commit -m "added mega-feature functionality"
Цель достигнута. Надеюсь приведенная выше информация будет полезна тем, кто столкнется с подобными проблемами в будущем.
Переместить любую фиксацию Git из одной ветки в другую
Переполнение стека
- Около
Продукты
- Для команд
Переполнение стека
Общественные вопросы и ответыПереполнение стека для команд
Где разработчики и технологи делятся частными знаниями с коллегамиВакансии
Программирование и связанные с ним технические возможности карьерного ростаТалант
Нанимайте технических специалистов и создавайте свой бренд работодателяРеклама
Обратитесь к разработчикам и технологам со всего мира- О компании
Загрузка…
.
Как переместить старую фиксацию в другую ветку в git?
Переполнение стека
- Около
Продукты
- Для команд
Переполнение стека
Общественные вопросы и ответыПереполнение стека для команд
Где разработчики и технологи делятся частными знаниями с коллегамиВакансии
Программирование и связанные с ним технические возможности карьерного ростаТалант
Нанимайте технических специалистов и создавайте свой бренд работодателяРеклама
Обратитесь к разработчикам и технологам со всего мира- О компании
Загрузка…
.