Удалите пустые коммиты в git

Я просто перенес проект с Mercurial на Git. Mercurial добавляет пустые коммиты при добавлении тегов, поэтому я закончил с пустыми коммитами в Git, которые я хотел бы удалить.

Как удалить пустые коммиты (коммиты, которые не имеют в них файлов) из Git?

Спасибо.

Ответ 1

Один простой (но медленный) способ сделать это с git filter-branch и --prune-empty. Без других фильтров никакие другие коммиты не будут изменены, но любые пустые будут отброшены (что приведет к тому, что все последующие коммиты будут иметь новые родительские идентификаторы и, следовательно, все еще "перезаписывают историю": неважно, если это ваш первоначальный импортировать из hg в git, но это большое дело, если другие используют этот репозиторий уже).

Обратите внимание на все обычные оговорки с ветвью фильтра. (Кроме того, в качестве побочного примечания "пустая фиксация" на самом деле имеет тот, который имеет то же дерево, что и предыдущее: это не то, что у него нет файлов вообще, он имеет все те же файлы с одинаковыми режимами, и то же содержимое, что и его родительский commit.Это происходит потому, что git хранит полные снимки для каждой фиксации, а не различия от одной фиксации к следующей.)


Вот крошечный пример, который скрывает множество мест, где вы можете делать более интересные вещи:

$ ... create repository ...
$ cd some-tmp-dir; git clone --mirror file://path-to-original

(Этот первый клон-шаг для безопасности: filter-branch может быть довольно разрушительным, поэтому всегда полезно начинать его с нового клона, а не с оригинала. Использование --mirror означает, что все его ветки и теги зеркалируются в этой копии, тоже.)

$ git filter-branch --prune-empty --tag-name-filter cat -- --all

(Теперь подождите очень долгое время, см. документацию по методам, чтобы немного ускорить это.)

$ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d

(Этот шаг скопирован из документации: он отбрасывает все исходные ветки перед запуском фильтра. Другими словами, он делает фильтрацию постоянной. Поскольку это клон, который достаточно безопасен, даже если фильтр пошло не так.)

$ cd third-tmp-dir; git clone --mirror file://path-to-filtered-tmp

(Это делает чистую, красиво сжатую копию отфильтрованной копии, без оставшихся объектов на этапах фильтрации.)

$ git log     # and other commands to inspect

Как только вы уверены, что клон отфильтрованного клона хорош, вам не нужен отфильтрованный клон и он может использовать последний клон вместо первого. (То есть вы можете заменить "истинный оригинал" на окончательный клон.)

Ответ 2

Использование -commit-фильтра должно быть быстрее, чем использование --prune-empty

$ git filter-branch --tag-name-filter cat --commit-filter 'git_commit_non_empty_tree "[email protected]"' -- --all

Затем очистите резервные копии, как в torek answer

$ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d

Взято отсюда: Git - удалить коммит с пустым набором изменений с помощью ветки фильтра