Определите, что мешает удалить коммит из git - PullRequest
0 голосов
/ 05 сентября 2018

Как определить, что препятствует удалению комита из git с помощью следующих команд?

git reflog expire --expire=now --all

git gc --prune=now

Детали

Я хочу полностью удалить коммит (например, с хэшем коммита XYZ) из моего клона. Если вышеупомянутое не является правильной командой для этого (или если какие-либо из моих следующих команд / выводов неправильны), пожалуйста, сообщите мне.

Я знаю, что XYZ остается в моем клоне после запуска вышеуказанного удаления, потому что следующее возвращает список журналов:

git log XYZ

Я знаю, что XYZ нет ни в одной ветви, потому что следующее ничего не выводит:

git branch --contains XYZ

Я думал, что XYZ не было в тайнике, потому что следующее ничего не выводит:

git stash list

XYZ, однако, фактически находился в тайнике, но из-за ошибки в git список тайника не был указан.

1 Ответ

0 голосов
/ 05 сентября 2018

Если нет тайников и у вас истек срок действия рефлогов, кажется разумным предположить, что фиксация достижима из некоторых ссылок, но не все ссылки являются ветвями.

Вы можете попробовать это:

git for-each-ref --format='%(refname)' |xargs -I {} git rev-list {} --format="%H {}" |grep ^<hash>

где <hash> - идентификатор коммита, от которого вы хотите избавиться. В простом тесте я запустил

git for-each-ref --format='%(refname)' |xargs -I {} git rev-list {} --format="%H {}" |grep ^80c0ab

и получил вывод как

80c0ab39850d7b3ef4969ab934d834f22959a317 refs/original/refs/heads/master

говорит мне, что моя целевая фиксация была сохранена с помощью ссылки под refs/original - в этом случае предварительно перезаписывается "резервная ссылка", созданная git filter-branch


Обновление - Некоторые последующие действия основаны на комментариях.

Вы заметили, что приведенная выше команда возвращает refs/stash, но список тайников (для git stash list) пуст.

Дело в том, что в списке хранилищ используется сильно измененный журнал. И команда, которую вы использовали для очистки reflogs

git reflog expire --expire=now --all

уничтожит ключ reflog. Так что теперь команды stash не знают, что делать, и действуют так, как если бы не было тайников, но ссылка stash все еще существует, сохраняя что-либо из самого последнего тайника (или полной истории коммитов, доступной из коммита на который этот тайник был создан) жив локально [1].

ИМО, что можно считать ошибкой. Запланированное истечение срока действия рефлога по умолчанию оставляет stash в покое (по ... ну ... этой причине). Возможно, аргумент гласит, что вы специально указали, что срок действия всех reflogs определен, но я бы сказал, что "все reflogs, кроме stash" были бы более полезным определением --all в этом случае.

Ну, как угодно.

Если вы уверены, что вас не волнует, что было спрятано

git update-ref -d refs/stash

и затем возобновите уборку.


[1] "живы локально ", потому что, по крайней мере по умолчанию, stash не используется совместно. Вполне вероятно, что клонирование репо или помещение его ссылок в пустой пульт не приведет к нарушению. Однако это зависит от предположения, что git отправит минимальный пакет - и AFAIK не гарантирует, что это будет сделано. Так что если вам нужно фиксация прошла, то самым безопасным будет достичь точки, где она не существует локально, а затем перестроить все удаленные (и т. Д.) Из этого чистого локального репо.

...