2009-05-30 2 views
20

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

Из-за этого мой голый хранилище становится огромным.

Я попытался следующий .. но он удаляет файл полностью

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

Для определения больших файлов в моем хранилище я использую git-large-blob by Aristotle Pagaltzis.

+0

Я думаю, что это поможет, если вы дадите дополнительную информацию об этом файле и о том, что вы пытаетесь сделать. Это будет одно событие или вы планируете очистить файл и регулярно переписывать историю репозитория? Почему вы отслеживаете файл в git, если вам не нужно сохранять свою историю? Насколько велик ваш голый репозиторий, и действительно ли это проблема, если он большой? –

+0

это руководство для моей программы, я пишу с помощью Apple Pages (текстовый процессор) и включает в себя множество изображений. Я храню его в GIT в основном, поэтому я могу поделиться им между моим стационарным компьютером и моим ноутбуком, и поэтому я и отменяю, если что-то пойдет не так. В настоящее время репозиторий составляет 450 МБ. Я не решаюсь работать с файлом, потому что я знаю, что размер репозитория увеличивается. Вместо того, чтобы переосмыслить мое решение для резервного копирования, я подумал, что лучше избавиться от самых старых версий. Я ежедневно делаю полный снимок репозитория и загружаю его, но дисковая квота - 3 ГБ. – neoneye

+0

Да, я надеюсь, что это возможно сделать время от времени. – neoneye

ответ

16

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

+1

это решение! Он прошел все 312 пересмотра и отбросил самые старые версии, совершенные. Это было очень воспитательно. Для циклов, rev-list .. и вызова filter-branch без какого-либо commit id, который кажется неинтуитивным (придется исследовать, как работает эта магия), но он сработал. Спасибо вам за это. Иногда я использую git-gc и fsck, но это еще не автоматическое. Давайте не будем говорить о моем мнении о VCS :-) – neoneye

+1

>> Давайте не будем говорить о моем мнении о VCS :-) Достаточно справедливо :) Я рад, что это сработало для вас. Что касается магии не указывать ревизию, git-filter-branch внутренне вызывает git-rev-list, чтобы получить список коммитов для перезаписи. Он передаст «HEAD» в git-rev-list как ref ref, если вы его не укажете. Поэтому не указывать ничего похожего на указание «HEAD» (как вы делали в вашем примере). –

+0

Спасибо за скрипт. Я сделал это в файле сценария bash и нашел, что мне нужно немного его отрегулировать ' #!/bin/bash KEEP = 10 I = 0 NUM_COMMITS = $ (git rev-list master | wc -l) \ git filter-branch --index-filter \ 'if [$ {I} -lt $ ((NUM_COMMITS - KEEP))]; затем git rm --cached --ignore-unmatch file-to-delete.tar; fi; I = $ ((I + 1)) ' ' –

15

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


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

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

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

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



Вы можете использовать трансплантатов удалить часть истории одного файла (что было первоначально запрошенной) используя шаги описаны ниже. Это решение состоит из нескольких шагов, чем solution proposed by Dan Moulding, но каждый из шагов проще, и вы можете проверить промежуточные этапы, используя «git log» или средство просмотра графической истории.

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

    $ git branch cleanup f020285b^ 
    
  2. Во-вторых, удалить файл из истории, начиная с cleanup (т.е. f020285b^) с использованием ГИТ-фильтра-ветви, как показано в разделе «Примеры» из git-filter-branch страницы руководства:

    $ 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 
    

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

  4. Последнее, сделать трансплантаты постоянным (это сделало бы все трансплантаты постоянно, но давайте предположим, что здесь вы не использовать трансплантаты в противном случае) с использованием ГИТ-фильтра-ветви,

    $ git filter-branch cleanup..HEAD 
    

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

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

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

+0

интересный. попытаюсь. – neoneye

+0

Да, механизм трансплантатов действительно кажется намеченным способом сделать это. Спасибо, что сообщили мне об этом. К сожалению, у меня нет времени экспериментировать с этим сегодня. – neoneye

+0

Метод графтов goud работает в некоторых случаях, но он избавится от истории для всех файлов. В этом случае neoneye хочет удалить историю только для * некоторых * файлов. Поэтому я не уверен, что прививки будут подходящим решением. И неглубокий клон не может быть и речи, потому что мелкие хранилища искалечены (см. Git-clone docs для описания их ограничений). –

3

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

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

+0

хорошо пункт. Я не знал о подмодулях git. – neoneye

Смежные вопросы