Подтвердить что ты не робот

Git удалить старые версии файла

У меня есть большой файл размером 33 МБ, где я хочу навсегда удалить самые старые версии этого файла, поэтому я поддерживаю только последние версии X. Как это сделать?

Из-за этого мой голый репозиторий стал огромным.

Я пробовал следующее.. но он полностью удаляет файл

git filter-branch --index-filter 'git rm --cached --ignore-unmatch big_manual.txt' HEAD

Чтобы идентифицировать большие файлы в моем репозитории, я использую git -большой-блоб Aristotle Pagaltzis.

4b9b3361

Ответ 1

Я думаю, что вы на правильном пути с помощью команды git filter-branch, которую вы пробовали. Проблема в том, что вы не сказали ему хранить файл в каких-либо коммитах, поэтому он удаляется из всех них. Теперь я не думаю, что есть способ прямо сказать git-filter-branch пропустить любые коммиты. Однако, поскольку команды выполняются в контексте оболочки, не должно быть слишком сложно использовать оболочку для удаления всех, кроме последнего числа X исправлений. Что-то вроде этого:

KEEP=10 I=0 NUM_COMMITS=$(git rev-list master | wc -l) \
git filter-branch --index-filter \
'if [[ ${I} -lt $((NUM_COMMITS - KEEP)) ]]; then
     git rm --cached --ignore-unmatch big_manual.txt;
 fi;
 I=$((I + 1))'

Это сохранит big_manual.txt за последние 10 коммитов.

Как сказал Чарльз, я не уверен, что это лучший подход, поскольку вы фактически уничтожаете всю точку VCS, удаляя старые версии.

Вы уже пытались оптимизировать репозиторий git с помощью git-gc и/или git-repack? Если нет, возможно, стоит попробовать.

Ответ 2

Примечание: этот ответ посвящен сокращению истории целого проекта, а не удалению одного файла из более старой истории, о чем был вопрос!


Самый простой способ сократить историю всего проекта с помощью git filter-branch будет использовать механизм трансплантатов (см. макет репозитория), чтобы сократить историю:

$ echo "$commit_id" >> .git/info/grafts

где $commit_id - это фиксация, которую вы хотите быть корнем (первая фиксация) нового репозитория. Посмотрите, используя "Git журнал" или средство просмотра графической истории, такое как gitk, что история выглядит так, как вы хотите, и запустите "Git filter-branch -all"; использование графтов описано в документации git -filter-branch.

Или вы можете использовать мелкий клон с помощью опции --depth <depth> git.



Вы можете использовать трансплантаты, чтобы удалить историю деталей одного файла (изначально запрошенная), используя шаги, описанные ниже. Это решение состоит из нескольких шагов, чем решение, предложенное Dan Molding, но каждый из шагов проще, и вы можете проверить промежуточные шаги с помощью "Git log" или графической истории зритель.

  • Сначала выберите точку, в которой вы хотите удалить файл, и отметьте эти фиксации, создав ветки в этих точках. Например, если вы хотите, чтобы файл впервые отображался в commit f020285b и удалил его во всех его предках, пометьте его предком (предполагая, что это обычное, не слияние), используя

    $ git branch cleanup f020285b^
    
  • Во-вторых, удалите файл из истории, начинающейся с cleanup (т.е. f020285b^), используя git -filter-branch, как показано в разделе "Примеры" git-filter-branch manpage:

    $ git filter-branch --index-filter 'git rm --cached --ignore-unmatch big_manual.txt' cleanup
    

    Если вы хотите удалить все коммиты, которые были изменены только на удаленный файл, вы можете дополнительно использовать опцию --prune-empty для git -filter-branch.

  • Затем присоедините перезаписанную часть истории с остальной историей, используя механизм трансплантатов:

    $ echo $(git-rev-parse f020285b) $(git rev-parse cleanup) >> .git/info/grafts
    

    Затем вы можете проверить историю, чтобы проверить, правильно ли она присоединена.

  • Наконец, сделайте трансплантаты перманентными (это сделает все трансплантаты постоянными, но позволяет предположить, что вы не используете трансплантаты в противном случае) с помощью git -filter-branch,

    $ git filter-branch cleanup..HEAD
    

    и удалите графты (поскольку они больше не нужны) и ветвь cleanup

    $ rm .git/info/grafts
    $ git branch -d cleanup
    

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

Ответ 3

Возможно, вы захотите использовать git подмодули. Таким образом, вы можете хранить изображения и другие большие файлы в другом репозитории git, а репозиторий с исходными кодами может ссылаться на конкретную ревизию этого другого репозитория.

Это поможет вам синхронизировать ревизии репозитория, поскольку родительский репозиторий содержит ссылку на конкретную ревизию промежуточного репозитория. Он также позволит вам удалить/переустановить старые версии в субрепозиторе, не затрагивая родительский репозиторий, где ваш исходный код - удаление старых ревизий в субрепозиторе не испортит историю родительского репозитория, потому что вы просто обновите версию, на которую указывает ссылка субрепозитария в родительском репозитории.