git удалить самые старые версии файла - PullRequest
20 голосов
/ 31 мая 2009

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

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

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

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

Для идентификации больших файлов в моем хранилище я использую git-large-blob от Аристотеля Пагальциса .

Ответы [ 3 ]

16 голосов
/ 31 мая 2009

Я думаю, что вы на правильном пути с командой 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? Если нет, то стоит попробовать.

15 голосов
/ 31 мая 2009

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


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

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

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

Или вы можете использовать неглубокий клон , используя --depth <depth> опцию git clone .



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

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

    $ git branch cleanup f020285b^
    
  2. Во-вторых, удалите файл из истории, начинающейся с 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.

  3. Далее, соедините переписанную часть истории с остальной историей, используя механизм пересадки:

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

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

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

    $ git filter-branch cleanup..HEAD
    

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

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

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

3 голосов
/ 31 мая 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...