Стандартный процесс отмены коммитов неразрушающим способом заключается в использовании git revert
. Эта команда в основном берет обратную разницу целевого коммита и пытается применить ее. Таким образом, вы получаете новый коммит, который отменяет все изменения.
Чтобы отменить сразу несколько коммитов, вы также можете указать диапазон коммитов. Учитывая, что у вас есть только два диапазона, которые вы хотели бы отменить (те, что между этими исправлениями), это было бы действительно управляемо.
Вы также можете использовать флаг --no-commit
или -n
, чтобы не автоматически создавать фиксацию. Это позволяет вам объединять несколько команд git revert -n <commit>
в цепочку друг за другом, не создавая откатную фиксацию для каждой. Затем, когда вы закончите выбирать все коммиты или диапазоны коммитов, которые хотите отменить, вы можете сделать один коммит, который объединяет их все.
В вашем случае, поскольку у вас есть другая ветка с точным состоянием (рабочий каталог), в которое вы хотите поместить свою ветку develop
, сделать это намного проще. Все, что вам нужно сделать, это проверить рабочее дерево для master
в вашей ветке develop
и зафиксировать это состояние в ветке develop
. Вы бы сделали это, используя git checkout master -- .
. К сожалению, это не будет работать для путей, неизвестных ветке master
. Таким образом, если вы добавили новые файлы в ветку develop
, они сохраняются, и вам придется удалять их отдельно.
Вместо этого мы начинаем новую ветку с master
(которая затем имеет точно такое же содержимое) и сбрасываем эту ветку, чтобы вместо этого она основывалась на develop
. Таким образом, мы сохраняем состояние рабочего каталога от master
, но вместо этого фиксация будет следовать за develop
. После этого мы можем перемотать вперед develop
этот коммит:
# checkout a new branch off master
git checkout -b new-develop master
# make a soft reset to develop
git reset --soft develop
# commit the changes
git commit
# get back to develop and fast forward
git checkout develop
git merge --ff-only new-develop
git branch -d new-develop
Это приведет к тому же результату, что и при объединении git revert -n
со всеми коммитами, исключительными для develop
. Есть несколько других способов достичь этого состояния, но это действительно самый простой.
Независимо от того, какой способ вы используете, чтобы добраться до этого состояния, вы должны рассмотреть возможность последующего слияния. Слияние на самом деле ничего не сделает (поскольку обе ветки имеют одинаковый контент), но объединит ветки в истории, так что вы видите, что они на самом деле сходятся.
Итак, предполагая, что история изначально выглядит так:
master
↓
* ------------ h1 ------ h2
\ \ \
* -- * -- * -- * -- * -- *
↑
develop
Вы хотели бы превратить его в это:
master
↓
* ------------ h1 ------ h2 ----- M
\ \ \ / ↖
* -- * -- * -- * -- * -- * -- F develop
F
— это исправление, которое мы создали выше. Это предполагает, что вы хотите объединить develop
в master
(git merge develop
в то время как master
), а затем перемотать вперед develop
(git merge master
в то время как develop
), чтобы начать разработку заново с этой точки. Конечно, вы можете сделать это и в другом направлении, если вам так больше нравится.
В качестве альтернативы мы также можем выполнить это слияние M
и исправление F
за один шаг. Вы бы эффективно объединили develop
в master
и объединили все таким образом, чтобы получить содержимое master
. Это будет выглядеть так:
master
↓
* ------------ h1 ------ h2 ---- FM
\ \ \ / ↖
* -- * -- * -- * -- * -- * ---/ develop
Вы можете добраться туда вручную следующим образом:
# since we merge into master, we start there
git checkout master
# start the merge, but don’t attempt to fast-forward and do not
# commit the merge automatically (since we want to change it)
git merge --no-ff --no-commit develop
# reset the index that was prepared during the merge
git reset
# now checkout the files from master and commit the merge
git checkout master -- .
git add .
git commit
И на самом деле, это настолько распространенный сценарий, что git merge
поставляется со стратегией слияния, которая делает именно это. Таким образом, вместо вышеописанного мы можем просто использовать стратегию слияния ours
и отбрасывать все из ветки, которую мы объединяем в текущую:
git checkout master
git merge -s ours develop
person
poke
schedule
30.06.2016
reset
это легко, я могу просто указать ветку, и она будет сброшена, чтобы выглядеть точно так же, какmaster
. - person Andrius   schedule 30.06.2016