Как раздавить слитный git changeset
Можно ли отбросить коммиты как #9701282
в Git
история?
Я не имею в виду репо выше #b372fa5
должен измениться,
просто график должен быть упрощен в этом месте.
Коммит в фиолетовой ветке выглядит как лишний.
Это не должно быть очень трудно применить его изменения внутри #b372fa5
точка слияния
Какие методы существуют для реализации этого действия?
3 ответа
Git походит на классические машины времени старых научно-фантастических фильмов. Вы можете вернуться назад во времени, но если вы измените прошлое, вы окажете влияние на настоящее.
Вы можете использовать одну из самых мощных функций git rebase, чтобы делать практически все, что вы хотите, однако имена объектов после внесенных изменений и включая их будут изменены.
Если вы сотрудничаете с другими, желательно не делать этого, поскольку им придется восстанавливаться после операции.
Вот пример до и после того, как я только что побежал в качестве примера:
git log --oneline --graph
* d3959f3 Something
* 9e58b42 Modify new
* ad1dea6 Merge branch 'mybranch'
|\
| * e75658b somechange
* | 1076214 New File
* | 49fe418 Updated on master
|/
* b94640d Updated
* da15c9c Initial commit
git log --oneline --graph
* 89fe296 Something
* d9620cc Modify new
* 6301614 New File - somechange
* 49fe418 Updated on master
* b94640d Updated
* da15c9c Initial commit
Для выполнения операции я использовал:
git rebase -i ad1dea6~2
# a more common form is to modify n number of commits starting at HEAD
git rebase -i HEAD~n
Это откроет сконфигурированный редактор с изменениями, которые вы указали в "списке задач", что позволит вам интерактивно выбирать, складывать, перефразировать, отбрасывать, переупорядочивать и даже запускать произвольные команды оболочки с exec.
Вот как это выглядит в vi:
pick 1076214 New File
pick e75658b somechange
pick 9e58b42 Modify new
pick d3959f3 Something
# Rebase 49fe418..d3959f3 onto 49fe418
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
Я выбрал самый простой вариант для отмены изменений, который даже не требовал разрешения конфликтов, но действительно запрашивает подтверждение коммита (что, как вы видите, я изменил).
После того, как я сохранил сообщение об изменении коммита, git автоматически переписал остальную часть истории без дальнейших подсказок.
Я даже смог опробовать несколько различных вариантов этого, прибегнув к удобству мерзавца reflog
команда.
git reflog
В git могут быть восстановлены даже осиротевшие изменения, если они не были собраны в gc
запустить. Вы можете вызвать сборщик мусора в любое время с помощью gc
но некоторые команды делают это периодически в любом случае.
Один из способов оправиться от плохого состояния с reflog
чтобы найти точку в reflog
Вы заинтересованы в том, чтобы вернуться и запустить:
git reset --hard <SHA>
Использование rebase в рабочем процессе
Предыдущее обсуждение было сосредоточено на использовании rebase
изменить историю с rebase -i
, На самом деле это довольно полезная функция для локального рабочего процесса, где вы хотите периодически совершать коммиты, работая над функцией, а затем перед объединением в ветку для совместной работы с другими вы можете реорганизовать ваши локальные коммиты, чтобы сделать вашу историю проще для чтения или комбинировать коммиты в создать рабочий код при каждом коммите.
Второй вариант использования при выполнении rebase
слияния. Это можно сделать, заменив использование merge
с ребазой.
git rebase master
Лучший способ описать, как это работает, - представить, что все изменения в вашей текущей ветке хранятся отдельно, оставляя вам общий коммит, в котором две ветки расходятся. Затем ветка "быстро пересылается" на самый последний коммит в целевой ветке. Наконец, сохраненные коммиты применяются один за другим поверх нового HEAD, что дает вам возможность разрешать конфликты при каждом коммите (в отличие от слияния, когда вы решаете только один раз, формируя коммит слияния). Результатом является новый новый набор коммитов (новые отметки времени и все, возможно, измененные с изменениями разрешения конфликтов), создающие впечатление, что эти изменения были внесены последовательно после целевой ветки HEAD.
Вы также можете использовать --rebase
вариант с тягой.
ПРИМЕЧАНИЕ. Некоторые рабочие места не любят изменять историю коммитов и предпочитают даже отключать ускоренное слияние с --no-ff
при выполнении слияния. Очевидно, вам решать, когда использовать перебазирование и имеет ли это смысл для вашей ситуации. Вы часто можете по-прежнему использовать локальную интерактивную форму для настройки собственного рабочего процесса, поскольку эти изменения еще не были переданы на удаленный компьютер.
Некоторые из них я взял из своего недавнего поста в блоге об общем использовании git. Я пытался включить больше, чем в среднем информацию, сохраняя ее настолько компактной, насколько я мог.
git branch -d branch_name
удаляет объединенные ветви (не беспокойтесь, ничего не удалит, если не объединить, для этого вам понадобится git branch -D)
Чтобы увидеть все ветки слияния, попробуйте:
git branch --merged
Если вы хотите сохранить свою историю линейной, я бы предложил использовать git rebase
В общем, иногда полезно сохранить историю.
Как обычно, я бы рекомендовал https://git-scm.com/book/en/v2 главу 3. Это действительно поможет вам лучше понять все.
Если вы действительно хотите удалить коммит (удаление ветки только делает их недоступными, тогда я советую прочитать о reflogs - будьте осторожны, хотя некоторые вещи в git могут испортить ваш репозиторий и навсегда удалить ваш код, но это может быть только один из них)
Если деревья всех коммитов верны, если нужно поменять только родителей, то это очень легко сделать с помощью прививки и git filter-branch
,
Во-первых, притвориться, что b372fa5^
является b372fa5
Единственный родитель.
echo $(git rev-parse b372fa5 b372fa5^) > .git/info/grafts
Затем осмотрите историю и проверьте, верна ли она:
git log --graph
Затем перепишите коммиты, чтобы сделать этот трансплантат постоянным:
git filter-branch
И, наконец, очистить
rm .git/info/grafts