diff --git a/book/10-git-internals/sections/maintenance.asc b/book/10-git-internals/sections/maintenance.asc index f96b4f49..a51ad4aa 100644 --- a/book/10-git-internals/sections/maintenance.asc +++ b/book/10-git-internals/sections/maintenance.asc @@ -8,7 +8,7 @@ Время от времени Git выполняет автоматическую сборку мусора. Чаще всего эта команда ничего не делает. -Однако, если у вас накопилось слишком много «рыхлых» объектов (не в pack-файлах), или, наоборот, отдельных pack-файлов, Git запускает полноценный сборщик -- `git gc` (здесь «gc» это сокращение от «garbage collect», что означает «сборка мусора»). +Однако если у вас накопилось слишком много «рыхлых» объектов (не в pack-файлах), или, наоборот, отдельных pack-файлов, Git запускает полноценный сборщик -- `git gc` (здесь `gc` -- это сокращение от «garbage collect», что означает «сборка мусора»). Эта команда выполняет несколько действий: собирает все «рыхлые» объекты и упаковывает их в pack-файлы; объединяет несколько упакованных файлов в один большой; удаляет недостижимые объекты, хранящиеся дольше нескольких месяцев. Сборку мусора можно запустить вручную следующим образом: @@ -22,7 +22,7 @@ $ git gc --auto Нужно иметь примерно 7000 несжатых объектов или более 50 pack-файлов, чтобы запустился настоящий `gc`. Эти значения можно изменить с помощью параметров `gc.auto` и `gc.autopacklimit` соответственно. -Ещё одно действие, выполняемое `gc` -- упаковка ссылок в единый файл. +Ещё одно действие, выполняемое `gc`, -- упаковка ссылок в единый файл. Предположим, репозиторий содержит следующие ветки и теги: [source,console] @@ -50,7 +50,7 @@ cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0 При обновлении ссылки Git не будет редактировать этот файл, а добавит новый файл в `refs/heads`. Для получения хеша, соответствующего нужной ссылке, Git сначала проверит наличие файла ссылки в каталоге `refs`, а к файлу `packed-refs` обратится только в случае отсутствия оного. -Так что, если вы не можете найти ссылку в каталоге `refs`, скорее всего она упакована в файле `packed-refs`. +Так что если вы не можете найти ссылку в каталоге `refs`, скорее всего, она упакована в файле `packed-refs`. Обратите внимание, последняя строка файла начинается с `^`. Это означает, что предыдущая строка является аннотированным тегом, а текущая строка -- это коммит, на который указывает аннотированный тег. @@ -63,7 +63,7 @@ cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0 Как же в таком случае вернуть свои коммиты обратно? Ниже приведён пример, в котором мы сбрасываем ветку `master` с потерей данных до более раннего состояния, а затем восстанавливаем потерянные коммиты. -Для начала, давайте посмотрим, как сейчас выглядит история изменений: +Для начала давайте посмотрим, как сейчас выглядит история изменений: [source,console] ---- @@ -88,14 +88,14 @@ fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit ---- Итак, теперь два последних коммита по-настоящему потеряны -- они не достижимы ни из одной ветки. -Необходимо найти SHA-1 хеш последнего коммита и создать ветку, указывающую на него. +Необходимо найти SHA-1-хеш последнего коммита и создать ветку, указывающую на него. Сложность в том, чтобы узнать этот самый SHA-1, ведь вряд ли вы его запомнили, да? Зачастую самый быстрый способ -- использование команды `git reflog`. -Дело в том, что во время вашей работы Git записывает все изменения HEAD. -Каждый раз при переключении веток и коммитов изменений, добавляется запись в reflog. -reflog также обновляется командой `git update-ref` -- это, кстати, хорошая причина использовать именно эту команду, а не вручную записывать SHA-1 в ref-файлы, как было показано в <>. -Вы можете посмотреть где находился указатель HEAD в любой момент времени, запустив `git reflog`: +Дело в том, что во время вашей работы Git записывает все изменения `HEAD`. +Каждый раз при переключении веток и записи коммитов изменений добавляется запись в `reflog`. +`reflog` также обновляется командой `git update-ref` -- это, кстати, хорошая причина использовать именно эту команду, а не вручную записывать SHA-1 в ref-файлы, как было показано в <>. +Вы можете посмотреть где находился указатель `HEAD` в любой момент времени, запустив `git reflog`: [source,console] ---- @@ -105,8 +105,8 @@ ab1afef HEAD@{1}: commit: Modify repo.rb a bit 484a592 HEAD@{2}: commit: Create repo.rb ---- -Здесь мы видим два коммита, на которые когда-то указывал HEAD, однако информации не так уж и много. -Для получения информации в более удобном виде, можно воспользоваться командой `git log -g`, которая выведет лог записей из reflog в привычном формате: +Здесь мы видим два коммита, на которые когда-то указывал `HEAD`, однако информации не так уж и много. +Для получения информации в более удобном виде можно воспользоваться командой `git log -g`, которая выведет лог записей из `reflog` в привычном формате: [source,console] ---- @@ -152,7 +152,7 @@ $ rm -Rf .git/logs/ ---- В этом случае два первых коммита недоступны ниоткуда. -Так как данные reflog хранятся в каталоге `.git/logs/`, которую мы только что удалили, то теперь у нас нет reflog. +Так как данные `reflog` хранятся в каталоге `.git/logs/`, которую мы только что удалили, то теперь у нас нет `reflog`. Как теперь восстановить коммиты? Один из вариантов -- использование утилиты `git fsck`, проверяющую внутреннюю базу данных на целостность. Если выполнить её с ключом `--full`, будут показаны все объекты, недостижимые из других объектов: @@ -176,10 +176,10 @@ dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293 Git -- замечательный инструмент с кучей классных возможностей, но некоторые из них способны стать источником проблем; например, команда `git clone` загружает проект вместе со всей историей, включая все версии всех файлов. Это нормально, если в репозитории хранится только исходный код, так как Git хорошо оптимизирован под такой тип данных и может эффективно сжимать их. -Однако, если когда-либо в проект был добавлен большой файл, каждый, кто потом захочет клонировать проект, будет вынужден скачивать этот файл, даже если он был удалён в следующем коммите. -Он будет в базе всегда, просто потому, что он доступен в истории. +Однако если когда-либо в проект был добавлен большой файл, каждый, кто потом захочет клонировать проект, будет вынужден скачивать этот файл, даже если он был удалён в следующем коммите. +Он будет в базе всегда -- просто потому что он доступен в истории. -Это может стать большой проблемой при конвертации Subversion или Perforce репозиториев в Git. +Это может стать большой проблемой при конвертации Subversion- или Perforce-репозиториев в Git. В этих системах вам не нужно загружать всю историю, поэтому добавление больших файлов не имеет там особых последствий. Если при импорте из другой системы или при каких-либо других обстоятельствах стало ясно, что ваш репозиторий намного больше, чем он должен быть, то как раз сейчас мы расскажем, как можно найти и удалить большие объекты. @@ -246,10 +246,10 @@ size-garbage: 0 Давайте же исправим это! Для начала найдём проблемный файл. -В данном случае, мы уже знаем, что это за файл. +В данном случае мы уже знаем, что это за файл. Но если бы не знали, как можно было бы определить, какие файлы занимают много места? -При вызове `git gc` все объекты упаковываются в один pack-файл, но, несмотря на это, определить самые крупные файлы можно, запустив служебную команду `git verify-pack` и отсортировав её вывод по третьей колонке, в которой записан размер файла. -Так как нас интересуют самые крупный файлы, оставим три последние строки с помощью `tail`: +При вызове `git gc` все объекты упаковываются в один `pack`-файл, но, несмотря на это, определить самые крупные файлы можно, запустив служебную команду `git verify-pack` и отсортировав её вывод по третьей колонке, в которой записан размер файла. +Так как нас интересуют самые крупные файлы, оставим три последние строки с помощью `tail`: [source,console] ---- @@ -261,10 +261,10 @@ dadf7258d699da2c8d89b09ef6670edb7d5f91b4 commit 229 159 12 82c99a3e86bb1267b236a4b6eff7868d97489af1 blob 4975916 4976258 1438 ---- -Большой объект внизу списка, его размер -- 5 МБ. +Большой объект в низу списка, его размер -- 5 МБ. Для того чтобы узнать, что это за файл, воспользуемся командой `rev-list`, которая уже упоминалась в разделе <> главы 8. Если передать ей ключ `--objects`, она выдаст хеши всех коммитов, а также хеши объектов и соответствующие им имена файлов. -Воспользуемся этим для определения имени выбранного объекта: +Воспользуемся ей для определения имени выбранного объекта: [source,console] ---- @@ -296,15 +296,15 @@ Ref 'refs/heads/master' was rewritten Опция `--index-filter` похожа на `--tree-filter`, использовавшуюся в разделе <> главы 7, за исключением того, что вместо передачи команды, модифицирующей файлы на диске, мы используем команду, изменяющую файлы в индексе. -Вместо удаления файла чем-то вроде `rm file`, мы используем `git rm --cached`, так как нам надо удалить файл из индекса, а не с диска. -Причина, по которой мы делаем именно так -- скорость: нет необходимости извлекать каждую ревизию на диск, чтобы применить фильтр, а это может очень сильно ускорить процесс. +Вместо удаления файла чем-то вроде `rm file` мы используем `git rm --cached`, так как нам надо удалить файл из индекса, а не с диска. +Причина, по которой мы делаем именно так, -- скорость: нет необходимости извлекать каждую ревизию на диск, чтобы применить фильтр, а это может очень сильно ускорить процесс. Если хотите, можете использовать и `tree-filter` для получения аналогичного результата. Опция `--ignore-unmatch` команды `git rm` отключает вывод сообщения об ошибке в случае отсутствия файлов, соответствующих шаблону. Ещё один момент: мы указали команде `filter-branch` переписывать историю, начиная с коммита `7b30847`, потому что мы знаем, что именно в нём впервые появилась проблема. По умолчанию перезапись начинается с самого первого коммита, что потребовало бы гораздо больше времени. Теперь история не содержит ссылок на данный файл. -Однако, в reflog и в новом наборе ссылок, добавленном Git в `.git/refs/original` после выполнения `filter-branch`, ссылки на него всё ещё присутствуют, поэтому необходимо их удалить, а затем переупаковать базу. +Однако в reflog и в новом наборе ссылок, добавленном Git в `.git/refs/original` после выполнения `filter-branch`, ссылки на него всё ещё присутствуют, поэтому необходимо их удалить, а затем переупаковать базу. Необходимо избавиться от всех возможных ссылок на старые коммиты перед переупаковкой: [source,console]