Короткий ответ - нет: ничто в коммите не может быть изменено. Есть одна вещь, которую вы можете сделать, но она немного жестока.
Что вы можете сделать
Лучшее, что вы можете сделать (помимо игнорирования жалобы), - это создать новый и улучшенный коммит: тот, который точно похож на оригинал, за исключением ошибки. Но это новый коммит с новым и другим хеш-идентификатором, а не коммит 5adc29a
. Так что теперь вам нужно найти все коммиты, у которых 5adc29a
есть их родитель (ы), и сделать копии тех коммитов , которые имеют новый коммит в качестве нового и улучшенного родителя (и любых оригинальных коммитов). кроме 5adc29a
в качестве другого родителя (ей)).
Изменив и 5adc29a
и его ближайших детей, теперь вы должны найти детей от детей 5adc29a
. Им тоже нужно найти новых и улучшенных родителей. Тогда вам нужно найти их детей и так далее. Это изменение, по сути, распространяется по всей истории, вплоть до всех кончиков ветвей, которые происходят от плохого - теперь замененного - коммита. Затем каждая ветка - name указывает на обновленную ветку - tip .
Существует команда Git, которая делает все это: git filter-branch
. По сути, то, что git filter-branch
делает - или может делать - это циклически повторять каждый коммит в репозитории, применяя некоторые фильтры, а затем фиксируя результат. Если результат по битам идентичен оригиналу, результат равен оригиналу и ничего не меняется. Если же результат будет другим, то этот коммит теперь будет иметь новые и улучшенные заменители и , и каждый последующий дочерний коммит будет переименован соответствующим образом. Это, конечно, меняет дочерний элемент, так что копия дочернего элемента также является новым коммитом, пронизывающим всю остальную историю, вплоть до всех подсказок ветвей, которые произошли от оригинала - теперь заменены - коммит.
Следовательно, «все», что вам нужно сделать, - это запустить команду git filter-branch
, которая заменяет неверный коммит новым и улучшенным. Запустите это для каждого коммита, ветки и имени тега в вашем репозитории, и это:
root--c1--c2--...--bad--c1001--c1002--c1003 <-- master
\
c1004--c1005 <-- develop
становится:
bad--c1001--c1002--c1003 [original master]
/ \
/ c1004--c1005 [original develop]
/
root--c1--c2--...--fixed--c1006--c1007--c1008 <-- master
\
c1009--c1010 <-- develop
Поскольку каждый наконечник ветки был перенумерован, и все коммиты от них обратно к плохому (теперь заменяются перенумерованным коммитом) также перенумерованы, каждый с клоном плохого хранилища должен выбросить его и вместо этого переключитесь на этот новый и улучшенный. В противном случае у них все еще будет плохой коммит и все его потомки, и они, скорее всего, заново представят всю эту плохую историю, которую вы хотите удалить.
Сборка заменителя
Вы можете сделать это с помощью фильтра ответвления фильтра. Это самый прямой путь, но также трудно понять, как правильно. Гораздо проще использовать git replace
.
То, что делает git replace
, - это коммиты на замену. Такие замены на самом деле не являются заменами , они просто дополнительные коммиты, которые вы говорите своему Git использовать вместо оригиналов (и они не помогут с эта жалоба git fsck
, так как оригиналы все еще там). По сути, если фиксация 5adc29a
плохая, вы можете сделать улучшенную фиксацию с тем же parent (s), что и 5adc29a
, но с хорошим содержанием. Затем вы говорите своему Git: Когда бы вы ни посмотрели на 5adc29a
, вместо этого посмотрите на этот другой коммит.
Несколько команд Git, включая git gc
и git fsck
, намеренно не не подчиняются заменам. Всем командам Git можно сказать не подчиняться, чтобы увидеть, что там на самом деле. Но большинство, включая git filter-branch
, по умолчанию подчиняются заменам.
Что тон имеет в виду, что вы можете создать замену, убедиться, что все выглядит хорошо, а затем просто запустить git filter-branch
с --all
(и соответствующим --tag-name-filter
, если необходимо), но без других фильтров, которые, по сути, цементируют замену вместо.Затем вы удаляете все имена refs/original/
, которые git filter-branch
использует в качестве ремней безопасности и подушек безопасности в случае, если фильтрация не работает, и теперь у вас есть хранилище, в котором плохие объекты больше не появляются (и git gc
будетв конце концов удалите их по-настоящему).
Этот репозиторий больше не совместим с плохим, или, скорее, он полностью совместим с слишком , и его соответствие плохому вызовет неудачный коммитчтобы вернуться, вместе со всеми дочерними элементами, которые вы заменили с шагом ответвления фильтра.Вам решать, стоит ли боль такого флага дня выгоды.