Как использовать git filter-branch для удаления файла с блоба SHA1?
Большинство примеров git filter-branch, которые я видел, которые удаляли файлы, были для удаления файлов на основе имени файла. Я не обязательно хочу сделать это. Вместо этого я идентифицировал несколько BLA-файлов (а не коммитов) файлов, которые я хочу удалить, независимо от того, где они находятся в хранилище. (Из-за нашей истории репо файлы, как правило, перемещаются в кучу без изменений.)
Как лучше всего сказать git filter-branch удалить файлы, основываясь на их BLA-объекте SHA1?
4 ответа
Ваша задача - удалить BLOB-объекты из истории Git по хеш-идентификатору. Вы можете найти это быстрее и проще использовать BFG, а не git-filter-branch
специально используя --strip-blobs-with-ids
флаг:
-bi, --strip-blobs-with-id
<blob-ids-file>
... удалить BLOB-объекты с указанными идентификаторами объектов Git
Внимательно следуйте инструкциям по использованию, основная часть просто так:
$ java -jar bfg.jar --strip-blobs-with-ids <blob-ids-file> my-repo.git
Обратите внимание, что<blob-ids-file>
Файл должен содержать идентификаторы объектов Git, а не простые SHA-1-хэши содержимого BLOB-объекта.
Для данного файла вы можете вычислить идентификатор объекта Git с помощьюgit hash-object
:
$ git hash-object README.md
a63b49c2e93788cd71c81015818307c7b70963bf
Вы можете видеть, что это значение отличается от простого хэша SHA-1:
$ sha1sum README.md
7b833f7b37550e2df719b57e8c4994c93a865aa9 README.md
... это потому, что идентификатор объекта Git хэширует заголовок Git вместе с содержимым файла, даже если он использует тот же алгоритм SHA-1.
BFG обычно по крайней мере в 10-50 раз быстрее, чем бег git-filter-branch
и вообще проще в использовании.
Полное раскрытие: я являюсь автором BFG Repo-Cleaner.
git filter branch --index-filter
итеративно помещает каждый коммит в индекс, чтобы можно было восстановить имя файла из хеша с помощью git ls-files -s
,
Я делаю это для удаления BLOB-объектов с хэшами 2d341f0223ff, 6a4558fa76d1 и 4d0a90cba061:
git filter-branch --force --index-filter "git ls-files -cdmo -s | grep ' 2d341f0223ff\| 6a4558fa76d1\| 4d0a90cba061' | awk '{print $4}' | xargs git rm --cached --ignore-unmatch 656565randomstring546464" --prune-empty --tag-name-filter cat -- --all
Случайная строка должна избежать git rm
выдает ошибку, когда grep
не возвращает совпадений.
Как отметил @RobertTyley в своем ответе, вам, вероятно, лучше использовать BFG. Тем не менее, чтобы ответить на вопрос, как задано (как это сделать с filter-branch
):
К сожалению, нет хорошего пути. Вы можете написать скрипт, чтобы получить все имена файлов, связанные со значением SHA в индексе. В качестве отправной точки, если вы удаляете файл с хешем DEADC0DE
git rev-list -n 1 --objects HEAD |grep ^DEADC0DE |cut -c 42-
Затем вы будете кормить каждую строку (возможно, с xargs
?) как <filename>
в
git rm --cached <filename>
И вы бы использовали этот скрипт в качестве вашего index-filter
значение (потому что использование его в качестве древовидного фильтра только сделает медленный подход еще медленнее).
Версия ветки фильтра может выглядеть примерно так внутри index-filter:
git ls-files -s |
sed -r '/ 02c97746d64fbfe13007a1ab4e9b9e4bbd99f42f /s/^100(644|755)/0/' |
git update-index --index-info
То есть, прочитайте формат index-info, найдите интересующий BLOB-объект и установите режим на 0 (пометив его для удаления), затем запишите его обратно в индекс.