Как перенести коммиты в другую ветку?
Как синхронизировать теперь ветку controller_test, приняв fix-ы из master?

Turbid ★★★★★
04.06.21 14:54:41 MSK

можно сделать rebase controller_test master , можно merge master controller_test . оба варианта имеют свои преимущества и недостатки. конкретно в случае rebase тебе нужно быть внимательным, если ты не один работаешь этой веткой. тебе придётся сделать push —force , что может быть недоступно иногда. а другим людям придётся сделать pull —force и возможно потерять свои локальные коммиты
eternal_sorrow ★★★★★
( 04.06.21 15:14:38 MSK )
Ответ на: комментарий от eternal_sorrow 04.06.21 15:14:38 MSK
Есть очень простое правило — работать с веткой только одному. Нет никаких препятствий сделать ветку только для себя. И в ней делай что хочешь. Не забывай только фетчить изменения из основной ветки и переносить свои правки на них (я имею в виду rebase). При переносе своих правок поверх правок в основной ветке да, конфликты возможны, но эти либо следствие кривой архитектуры когда два разных разработчика, решая разные проблемы, изменяют один и тот же код, либо кривая организация труда, когда два разных разработчика решают очень похожие задачи и поэтому работают над одним и тем же кодом.
anonymous
( 04.06.21 15:24:34 MSK )
Ответ на: комментарий от anonymous 04.06.21 15:24:34 MSK

Есть очень простое правило — работать с веткой только одному.
я согласен. но не все этому правилу следуют.
eternal_sorrow ★★★★★
( 04.06.21 15:26:06 MSK )
Ответ на: комментарий от eternal_sorrow 04.06.21 15:26:06 MSK
Да я просто пытался уточнить какой вариант лучше. Так то ответ у тебя исчерпывающий. Просто хотел подтолкнуть ТСа в сторону rebase, т.к. слияние (merge) может превратить лог в кашу, хоть и избавит от конфликтов, которые могут возникнуть при переносе.
Я вообще из секты линейной истории и считаю что разрешение конфликтов небольшая плата за чистый лог.
anonymous
( 04.06.21 15:31:19 MSK )
Ответ на: комментарий от eternal_sorrow 04.06.21 15:14:38 MSK

rebase controller_test master, можно merge master controller_test
а мне в какой ветке нужно быть в данный момент когда я делаю это?
Turbid ★★★★★
( 04.06.21 15:48:49 MSK ) автор топика
Ответ на: комментарий от Turbid 04.06.21 15:48:49 MSK

если явно указывать что и куда мержить/ребейзить, то неважно
eternal_sorrow ★★★★★
( 04.06.21 15:51:44 MSK )
Ответ на: комментарий от Turbid 04.06.21 15:48:49 MSK

~/dev/vc (controller_test) $ git rebase controller_test master Successfully rebased and updated refs/heads/master. ~/dev/vc (master) $ git log --graph --full-history --all --oneline * 54b9ed0 (HEAD -> master) fixed microphone position again * fa0bbea the 7th summator has been deleted * 379576b fixed microphone position * 7844ca2 (origin/controller_test, controller_test) added cyclic polling * 76dec1b added summator counting * 1e64d9e mic state refactoring * 429bb32 mic state logging refactoring * 2aeaed7 some logging refactoring * a3dbe93 added ayncio.open_connection example * 517c45e added .vscode folder to .gitingnore * 6f9bd59 some ipc and d12 tests | * c7a9e55 (tag: 0.0.2, origin/master, origin/HEAD) fixed microphone position again | * c002049 the 7th summator has been deleted | * 18b4041 fixed microphone position |/ * 7ca9b68 (tag: 0.0.1) init project in current state
Turbid ★★★★★
( 04.06.21 15:52:18 MSK ) автор топика
Ответ на: комментарий от Turbid 04.06.21 15:52:18 MSK

eternal_sorrow ★★★★★
( 04.06.21 15:56:13 MSK )
Ответ на: комментарий от Turbid 04.06.21 15:52:18 MSK

сделай git reset c7a9e55 а потом git rebase master controller_test
eternal_sorrow ★★★★★
( 04.06.21 15:59:15 MSK )
Ответ на: комментарий от eternal_sorrow 04.06.21 15:59:15 MSK

~/dev/vc (master) $ git reset c7a9e55 Unstaged changes after reset: M .gitignore M d12/__init__.py M example.py M example2.py M ipcontroller/__init__.py ~/dev/vc (master) $ git log --graph --full-history --all --oneline * c7a9e55 (HEAD -> master, tag: 0.0.2, origin/master, origin/HEAD) fixed microphone position again * c002049 the 7th summator has been deleted * 18b4041 fixed microphone position | * 7844ca2 (origin/controller_test, controller_test) added cyclic polling | * 76dec1b added summator counting | * 1e64d9e mic state refactoring | * 429bb32 mic state logging refactoring | * 2aeaed7 some logging refactoring | * a3dbe93 added ayncio.open_connection example | * 517c45e added .vscode folder to .gitingnore | * 6f9bd59 some ipc and d12 tests |/ * 7ca9b68 (tag: 0.0.1) init project in current state ~/dev/vc (master) $ git rebase master controller_test error: cannot rebase: You have unstaged changes. error: Please commit or stash them.
Таки пойду я читать букварь…
Turbid ★★★★★
( 04.06.21 16:03:35 MSK ) автор топика
Ответ на: комментарий от Turbid 04.06.21 16:03:35 MSK

пойди, ага. я не сказал тебе сделать reset —hard потому что возможно у тебя были незакоммиченные изменения (которые бы удалились), но очевидно, тогда мы тебе не удалось сделать rebase. так что сделай reset —hard c7a9e55 , а потом rebase, как я сказал тебе ранее.
eternal_sorrow ★★★★★
( 04.06.21 16:11:07 MSK )
Ответ на: комментарий от Turbid 04.06.21 16:03:35 MSK
Ты просто перепутал местами аргументы и из-за этого получился другой результат. Ничего страшного, бывает. Тебе нужно просто откатиться назад, на тот коммит, где все еще хорошо (c7a9e55). Откатиться можно через reset, но он изменения оставляет в виде unstaged changes, чтобы они не пропали (что вполне разумно и делает работу с git безопасной). Но эти же изменения тебе мешают сделать rebase (что тоже разумно и тоже сделано из-за соображения безопасности). Выходов тут два — либо спрятать эти изменения, чтобы не мешали через stash ( git stash ), либо вообще их удалить, если ты знаешь что они не нужны/либо присутствуют в другой ветке. Второй вариант это сделать сразу hard reset git reset —hard c7a9e55 , тогда эти изменения буду удалены сразу.
Сделай git stash и затем git rebase master controller_test
git как перенести коммит из одной ветки в другую?
Как в git перенести коммит из одной ветки в другую?
Нужно перенести только изменения, которые затрагивает конкретный коммит, а не все изменения ветки.
Такая необходимость возникла, когда я отпочковался не от ветки master, а от другой ветки (по ошибке). Затем сделал пару коммитов. Как можно перенести эти пару коммитов в новую ветку, чтобы создать новый ПР относительно мастер? Чтобы 2 независимых ПР получилось?
короткая ссылка на этот вопрос: close
спросил 8 лет назад
1 ответ
git cherry-pick — применение к дереву проекта изменений, внесенных определённым коммитом.
git cherry-pick — найдёт коммит по его хэшу и вольёт его в текущую ветку. Применятся изменения только конкретного коммита, причём изменения сразу же будут проиндексированы и будет создан новый коммит в активной ветке с таким же именем, как коммит и назывался. При наличии конфиликтных изменений, нужно будет решить конфликты, как и при «рядном» merge.
Если вам нужно перенести изменения в ветку из определённого коммита другой ветки так, чтобы коммит автоматически не создавался, то нужно использовать параметр -n (—no-commit). Пример:
git cherry-pick -n d3edb354cd3c080b28d13dcb92448de81e543297
Все поддериживаемые параметры cherry-pick:
3.6 Ветвление в Git — Перебазирование
В Git есть два способа внести изменения из одной ветки в другую: слияние и перебазирование. В этом разделе вы узнаете, что такое перебазирование, как его осуществлять и в каких случаях этот удивительный инструмент использовать не следует.
Простейшее перебазирование
Если вы вернётесь к более раннему примеру из Основы слияния, вы увидите, что разделили свою работу и сделали коммиты в две разные ветки.

Рисунок 35. История коммитов простого разделения
Как мы выяснили ранее, простейший способ выполнить слияние двух веток — это команда merge . Она осуществляет трёхстороннее слияние между двумя последними снимками сливаемых веток ( C3 и C4 ) и самого недавнего общего для этих веток родительского снимка ( C2 ), создавая новый снимок (и коммит).

Рисунок 36. Слияние разделённой истории коммитов
Тем не менее есть и другой способ: вы можете взять те изменения, что были представлены в C4 , и применить их поверх C3 . В Git это называется перебазированием. С помощью команды rebase вы можете взять все коммиты из одной ветки и в том же порядке применить их к другой ветке.
В данном примере переключимся на ветку experiment и перебазируем её относительно ветки master следующим образом:
$ git checkout experiment $ git rebase master First, rewinding head to replay your work on top of it. Applying: added staged command
Это работает следующим образом: берётся общий родительский снимок двух веток (текущей, и той, поверх которой вы выполняете перебазирование), определяется дельта каждого коммита текущей ветки и сохраняется во временный файл, текущая ветка устанавливается на последний коммит ветки, поверх которой вы выполняете перебазирование, а затем по очереди применяются дельты из временных файлов.

Рисунок 37. Перебазирование изменений из C4 поверх C3
После этого вы можете переключиться обратно на ветку master и выполнить слияние перемоткой.
$ git checkout master $ git merge experiment

Рисунок 38. Перемотка ветки master
Теперь снимок, на который указывает C4′ абсолютно такой же, как тот, на который указывал C5 в примере с трёхсторонним слиянием. Нет абсолютно никакой разницы в конечном результате между двумя показанными примерами, но перебазирование делает историю коммитов чище. Если вы взглянете на историю перебазированной ветки, то увидите, что она выглядит абсолютно линейной: будто все операции были выполнены последовательно, даже если изначально они совершались параллельно.
Часто вы будете делать так для уверенности, что ваши коммиты могут быть бесконфликтно слиты в удалённую ветку — возможно, в проекте, куда вы пытаетесь внести вклад, но владельцем которого вы не являетесь. В этом случае вам следует работать в своей ветке и затем перебазировать вашу работу поверх origin/master , когда вы будете готовы отправить свои изменения в основной проект. Тогда владельцу проекта не придётся делать никакой лишней работы — всё решится простой перемоткой или бесконфликтным слиянием.
Учтите, что снимок, на который ссылается ваш последний коммит — является ли он последним коммитом после перебазирования или коммитом слияния после слияния — в обоих случаях это один и тот же снимок, отличаются только истории коммитов. Перебазирование повторяет изменения из одной ветки поверх другой в том порядке, в котором эти изменения были сделаны, в то время как слияние берет две конечные точки и сливает их вместе.
Более интересные перемещения
Также возможно сделать так, чтобы при перебазировании воспроизведение коммитов применялось к совершенно другой ветке. Для примера возьмём История разработки с тематической веткой, ответвлённой от другой тематической ветки. Вы создаёте тематическую ветку server , чтобы добавить в проект некоторую функциональность для серверной части, и делаете коммит. Затем вы выполнили ответвление, чтобы сделать изменения для клиентской части, и создали несколько коммитов. Наконец, вы вернулись на ветку server и сделали ещё несколько коммитов.

Рисунок 39. История разработки с тематической веткой, ответвлённой от другой тематической ветки
Предположим, вы решили, что хотите внести изменения клиентской части в основную линию разработки для релиза, но при этом не хотите добавлять изменения серверной части до полного тестирования. Вы можете взять изменения из ветки client , которых нет в server ( C8 и C9 ), и применить их на ветке master при помощи опции —onto команды git rebase :
$ git rebase --onto master server client
В этой команде говорится: «Переключись на ветку client , найди изменения относительно ветки server и примени их для ветки master ». Несмотря на некоторую сложность этого способа, результат впечатляет.

Рисунок 40. Перемещение тематической ветки, ответвлённой от другой тематической ветки
Теперь вы можете выполнить перемотку (fast-forward) для ветки master (см Перемотка ветки master для добавления изменений из ветки client ):
$ git checkout master $ git merge client

Рисунок 41. Перемотка ветки master для добавления изменений из ветки client
Представим, что вы решили добавить наработки и из ветки server . Вы можете выполнить перебазирование ветки server относительно ветки master без предварительного переключения на неё при помощи команды git rebase , которая извлечёт тематическую ветку (в данном случае server ) и применит изменения в ней к базовой ветке ( master ):
$ git rebase master server
Это повторит работу, сделанную в ветке server поверх ветки master , как показано на рисунке:

Рисунок 42. Перебазирование ветки server на вершину ветки master
После чего вы сможете выполнить перемотку основной ветки ( master ):
$ git checkout master $ git merge server
Теперь вы можете удалить ветки client и server , поскольку весь ваш прогресс уже интегрирован и тематические ветки больше не нужны, а полную историю вашего рабочего процесса отражает рисунок Окончательная история коммитов:
$ git branch -d client $ git branch -d server

Рисунок 43. Окончательная история коммитов
Опасности перемещения
Но даже перебазирование, при всех своих достоинствах, не лишено недостатков, которые можно выразить одной строчкой:
Не перемещайте коммиты, уже отправленные в публичный репозиторий
Если вы будете придерживаться этого правила, всё будет хорошо. Если не будете, люди возненавидят вас, а ваши друзья и семья будут вас презирать.
Когда вы что-то перемещаете, вы отменяете существующие коммиты и создаёте новые, похожие на старые, но являющиеся другими. Если вы куда-нибудь отправляете свои коммиты и другие люди забирают их себе и в дальнейшем основывают на них свою работу, а затем вы переделываете эти коммиты командой git rebase и выкладываете их снова, то ваши коллеги будут вынуждены заново выполнять слияние для своих наработок. В итоге, когда вы в очередной раз попытаетесь включить их работу в свою, вы получите путаницу.
Давайте рассмотрим пример того, как перемещение публично доступных наработок может вызвать проблемы. Предположим, вы клонировали репозиторий с сервера и сделали какую-то работу. И ваша история коммитов выглядит так:

Рисунок 44. Клонирование репозитория и выполнение в нём какой-то работы
Теперь кто-то другой внёс свои изменения, слил их и отправил на сервер. Вы стягиваете их к себе, включая новую удалённую ветку, что изменяет вашу историю следующим образом:

Рисунок 45. Извлекаем ещё коммиты и сливаем их со своей работой
Затем автор коммита слияния решает вернуться назад и перебазировать свою ветку; выполнив git push —force , он перезаписывает историю на сервере. При получении изменений с сервера вы получите и новые коммиты.

Рисунок 46. Кто-то выложил перебазированные коммиты, отменяя коммиты, на которых основывалась ваша работа
Теперь вы оба в неловком положении. Если вы выполните git pull , вы создадите коммит слияния, включающий обе линии истории, и ваш репозиторий будет выглядеть следующим образом:

Рисунок 47. Вы снова выполняете слияние для той же самой работы в новый коммит слияния
Если вы посмотрите git log в этот момент, вы увидите два коммита с одинаковыми авторами, датой и сообщением, что может сбить с толку. Помимо этого, если вы отправите свою историю на удалённый сервер в таком состоянии, вы вернёте все эти перебазированные коммиты на сервер, что ещё больше всех запутает. Логично предположить, что разработчик не хочет, чтобы C4 и C6 были в истории, и именно поэтому она перебазируется в первую очередь.
Меняя базу, меняй основание
Если вы попали в такую ситуацию, у Git есть особая магия чтобы вам помочь. Если кто-то в вашей команде форсирует отправку изменений на сервер, переписывающих работу, на которых базировалась ваша работа, то ваша задача будет состоять в определении того, что именно было ваше, а что было переписано ими.
Оказывается, что помимо контрольной суммы коммита SHA-1, Git также вычисляет контрольную сумму отдельно для патча, входящего в этот коммит. Это контрольная сумма называется «patch-id».
Если вы скачаете перезаписанную историю и перебазируете её поверх новых коммитов вашего коллеги, в большинстве случаев Git успешно определит, какие именно изменения были внесены вами, и применит их поверх новой ветки.
К примеру, если в предыдущем сценарии вместо слияния в Кто-то выложил перебазированные коммиты, отменяя коммиты, на которых основывалась ваша работа мы выполним git rebase teamone/master , Git будет:
- Определять, какая работа уникальна для вашей ветки (C2, C3, C4, C6, C7)
- Определять, какие коммиты не были коммитами слияния (C2, C3, C4)
- Определять, что не было перезаписано в основной ветке (только C2 и C3, поскольку C4 — это тот же патч, что и C4′)
- Применять эти коммиты к ветке teamone/master

Рисунок 48. Перемещение в начало force-pushed перемещённой работы
Это возможно, если C4 и C4′ фактически являются одним и тем же патчем, который был сделан вашим коллегой. В противном случае rebase не сможет определить дубликат и создаст ещё один патч, подобный C4 (который с большой вероятностью не удастся применить чисто, поскольку в нём уже присутствуют некоторые изменения).
Вы можете это упростить, применив git pull —rebase вместо обычного git pull . Или сделать это вручную с помощью git fetch , а затем git rebase teamone/master .
Если вы используете git pull и хотите использовать —rebase по умолчанию, вы можете установить соответствующее значение конфигурации pull.rebase с помощью команды git config —global pull.rebase true .
Если вы рассматриваете перебазирование как способ наведения порядка и работаете с коммитами локально до их отправки или ваши коммиты никогда не будут доступны публично — у вас всё будет хорошо. Однако, если вы перемещаете коммиты, отправленные в публичный репозиторий, и есть вероятность, что работа некоторых людей основывается на этих коммитах, то ваши действия могут вызвать существенные проблемы, а вы — вызвать презрение вашей команды.
Если в какой-то момент вы или ваш коллега находите необходимость в этом, убедитесь, что все знают, как применять команду git pull —rebase для минимизации последствий от подобных действий.
Перемещение vs. Слияние
Теперь, когда вы увидели перемещение и слияние в действии, вы можете задаться вопросом, что из них лучше. Прежде чем ответить на этот вопрос, давайте вернёмся немного назад и поговорим о том, что означает история.
Одна из точек зрения заключается в том, что история коммитов в вашем репозитории — это запись того, что на самом деле произошло. Это исторический документ, ценный сам по себе, и его нельзя подделывать. С этой точки зрения изменение истории коммитов практически кощунственно; вы лжёте о том, что на самом деле произошло. Но что, если произошла путаница в коммитах слияния? Если это случается, репозиторий должен сохранить это для потомков.
Противоположная точка зрения заключается в том, что история коммитов — это история того, как был сделан ваш проект. Вы не публикуете первый черновик книги или инструкции по поддержке вашего программного обеспечения, так как это нуждается в тщательном редактировании. Сторонники этого лагеря считают использование инструментов rebase и filter-branch способом рассказать историю проекта наилучшим образом для будущих читателей.
Теперь к вопросу о том, что лучше — слияние или перебазирование: надеюсь, вы видите, что это не так просто. Git — мощный инструмент, позволяющий вам делать многое с вашей историей, однако каждая команда и каждый проект индивидуален. Теперь, когда вы знаете, как работают оба эти приёма, выбор — какой из них будет лучше в вашей ситуации — зависит от вас.
При этом, вы можете взять лучшее от обоих миров: использовать перебазирование для наведения порядка в истории ваших локальных изменений, но никогда не применять его для уже отправленных куда-нибудь изменений.
Как в Git перенести commit из одной ветки в другую?
Нередко возникает ситуация, когда срочно требуется выполнить небольшую задачу. Разработчик быстро пробегается глазами по ТЗ и старается максимально оперативно вникнуть в суть задачи. При этом можно попросту забыть создать новую ветку, и понять об ошибке уже после финального каммита.
В такой ситуации, когда возникает необходимость перенести commit из одной ветки в другую на помощь приходит команда git cherry-pick , применяющая к дереву проекта изменения, которые были внесены указанным каммитом.
Синтаксис команды git cherry-pick
Рассмотрим ситуацию на примере. Мы находились в master и сделали в него случайно коммит. Тогда чтобы вынести его в отдельную ветку и отправить на merge request нам потребуется выполнить следующие команды:
1. Смотрим историю изменений и запоминаем хэш коммита , соответствующего правильному состоянию ветки master , то есть когда ещё в неё не было добавлено лишних коммитов по ошибке.
git log
2. Также следует запомнить хэш коммита , который был лишним в ветке master . Иногда бывает, что лишними оказываются сразу несколько коммитов, тогда если они расположены последовательно друг за другом следует запомнить самый давний и самый последний .
3. Перейдём на найденный коммит . Другими словами переходим на то состояние ветки master , от которого нам нужно создать новую ветку.
git checkout
4. Создадим новую ветку, в которую планируется вынести неверно расположенный коммит, и перейдем на неё.
git checkout -b
5. Переносим коммит в новую ветку.
git cherry-pick
В случае, когда необходимо перенести последний коммит ветки master , можно вместо хэша коммита просто написать master , поскольку в данный момент указатель master ссылается на последний коммит.
git cherry-pick master
Если же нужно перенести не один, а несколько подряд идущих коммитов от до , то это делается похожим образом.
git cherry-pick ..
Если же вы хотите, чтобы при переносе изменений коммит не создавался, то используйте параметр -n (—no-commit):
git cherry-pick -n d112ecf96
Как и при операции git rebase в процессе переноса коммита могут возникнуть конфликты. Как и при обычном git merge их следует разрешить, добавить изменения в индекс с помощью git add , а затем продолжить запустив git cherry-pick —continue .
6. Теперь когда коммиты перенесены в ветку , следует удалить их из ветки master . Поэтому переключаемся на ветку master
git checkout master
Смещаем указать master на коммит