Close

Git prune

Команда git prune — это внутренняя служебная утилита, которая очищает объекты Git без возможности доступа или без родителя. Объектами без возможности доступа считаются те, к которым нельзя получить доступ по ссылке. Если к коммиту нельзя обратиться через ветку или тег, значит, он недоступен. Команда git prune обычно не выполняется напрямую. Это команда сбора мусора, дочерняя для команды git gc.


Обзор команды git prune


Чтобы понять, как действует команда git prune, нужно смоделировать сценарий, в котором коммит становится недоступным. Ниже приведена последовательность вызовов через командную строку, с помощью которой можно сымитировать такой случай.

~ $ cd git-prune-demo/
~/git-prune-demo $ git init .
Initialized empty Git repository in /Users/kev/Dropbox/git-prune-demo/.git/
~/git-prune-demo $ echo "hello git prune" > hello.txt
~/git-prune-demo $ git add hello.txt
~/git-prune-demo $ git commit -am "added hello.txt"

Приведенная выше последовательность команд создает новый репозиторий в каталоге под названием git-prune-demo. В репозиторий добавляется один коммит, состоящий из нового файла hello.txt с базовым содержимым «hello git prune». Далее мы изменим hello.txt и добавим коммит с этими изменениями.

~/git-prune-demo $ echo "this is second line txt" >> hello.txt
~/git-prune-demo $ cat hello.txt
hello git prune
this is second line txt
~/git-prune-demo $ git commit -am "added another line to hello.txt"
[main 5178bec] added another line to hello.txt
1 file changed, 1 insertion(+)
базы данных
Связанные материалы

Перемещение полного репозитория Git

Логотип Bitbucket
СМ. РЕШЕНИЕ

Изучите Git с помощью Bitbucket Cloud

Теперь история нашего демонстрационного репозитория содержит два коммита. Проверить это можно с помощью команды git log:

~/git-prune-demo $ git log
commit 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Author: kevzettler <kevzettler@gmail.com>
Date:   Sun Sep 30 14:49:59 2018 -0700

        added another line to hello.txt

commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date:   Sun Sep 30 09:43:41 2018 -0700

        added hello.txt

Вывод команды git log показывает два коммита и соответствующие комментарии к коммитам об изменениях, внесенных в hello.txt. На следующем шаге нужно сделать один из коммитов недоступным. Мы сделаем это с помощью команды git reset. Мы сбросим состояние репозитория до первого коммита: «added hello.txt».

~/git-prune-demo $ git reset --hard 994b122045cf4bf0b97139231b4dd52ea2643c7e
HEAD is now at 994b122 added hello.txt

Если мы теперь запустим git log для проверки состояния репозитория, то увидим, что у нас всего один коммит.

~/git-prune-demo $ git log
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date:   Sun Sep 30 09:43:41 2018 -0700

        added hello.txt

Демонстрационный репозиторий теперь находится в состоянии, содержащем открепленный коммит. Второй сделанный нами коммит с сообщением о добавленной строке («added another line to hello.txt») отображается в выводе git log и теперь откреплен. Может показаться, что мы потеряли или удалили коммит, но Git очень строго сохраняет историю. Мы можем убедиться, что он по-прежнему доступен, хоть и откреплен, переключившись на него напрямую с помощью команды git checkout:

~/git-prune-demo $ git checkout 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Note: checking out '5178becc2ca965e1728554ce1cb8de2f2c2370b1'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

      git checkout -b <new-branch-name>

HEAD is now at 5178bec... added another line to hello.txt
~/git-prune-demo $ git log
commit 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Author: kevzettler <kevzettler@gmail.com>
Date:   Sun Sep 30 14:49:59 2018 -0700

      added another line to hello.txt

commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date:   Sun Sep 30 09:43:41 2018 -0700

      added hello.txt

Когда мы переключаемся на открепленный коммит, Git любезно выводит подробное сообщение, указывающее, что мы находимся в открепленном состоянии. Если сейчас изучить журнал, мы увидим, что в нем снова появился коммит «added another line to hello.txt». Теперь мы знаем, что состояние репозитория хорошо имитирует ситуацию с открепленным коммитом, и можем попрактиковаться в использовании команды git prune. Но сначала вернемся к ветке main с помощью команды git checkout.

~/git-prune-demo $ git checkout main
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

      5178bec added another line to hello.txt

If you want to keep it by creating a new branch, this may be a good time
to do so with:

     git branch <new-branch-name> 5178bec

Switched to branch 'main'

Когда мы возвращаемся к ветке main через git checkout, Git снова любезно сообщает, что у нас остался открепленный коммит. Время его обрезать! Далее мы выполним команду git prune, но важно передать ей некоторые параметры. С флагами --dry-run и --verbose она выведет сведения об обрезаемых данных, но пока не обрежет их.

~/git-prune-demo $ git prune --dry-run --verbose

Скорее всего, вывод команды будет пустым. Это означает, что обрезка на самом деле ничего не удалит. Почему так? Скорее всего, коммит не полностью откреплен. Где-то в Git все еще существует ссылка на него. Это яркий пример того, почему git prune не стоит использовать отдельно от git gc. А еще это наглядно показывает, насколько трудно полностью потерять данные в Git.

Скорее всего, Git хранит ссылку на наш открепленный коммит в журнале ссылок. Заглянуть туда можно, выполнив команду git reflog. В ее выводе должна быть последовательность действий, которые мы предприняли, чтобы попасть в текущее состояние. Дополнительную информацию о команде git reflog можно найти на странице git reflog. Git не только сохраняет историю в журнале ссылок, но и обрезает открепленные коммиты по истечении определенных внутренних сроков. Опять же, за эти детали реализации отвечает команда git gc, поэтому git prune не стоит использовать отдельно.

Чтобы завершить демонстрацию работы git prune, очистим журнал ссылок.

~/git-prune-demo $ git reflog expire --expire=now --expire-unreachable=now --all

Приведенная выше команда принудительно удалит все записи в журнале ссылок, созданные ранее настоящего момента. Это грубая и опасная команда, которую не стоит использовать неподготовленному пользователю Git. Мы выполняем эту команду, только чтобы продемонстрировать успешное выполнение git prune. После полного удаления журнала ссылок можно вызвать git prune.

~/git-prune-demo $ git prune --dry-run --verbose --expire=now
1782293bdfac16b5408420c5cb0c9a22ddbdd985 blob
5178becc2ca965e1728554ce1cb8de2f2c2370b1 commit
a1b3b83440d2aa956ad6482535cbd121510a3280 commit
f91c3433eae245767b9cd5bdb46cd127ed38df26 tree

Эта команда выведет список ссылок на объекты Git SHA вроде показанного выше.

Использование


У git prune есть небольшой список параметров, которые мы рассмотрели в обзорном разделе.

-n --dry-run

Не выполняет обрезку. Просто выводит обрезаемые объекты.

-v --verbose

Подробно отображает все объекты и действия, выполненные при обрезке.

--progress

Выводит данные, показывающие прогресс выполнения обрезки.

--expire <time>

Принудительно завершает действие просроченных объектов.

<head>…

При указании будут сохранены все параметры ссылки на этот указатель.

Пояснения


В чем разница между git prune, git fetch --prune и git remote prune?

Команды git remote prune и git fetch --prune делают одно и то же: удаляют ссылки, которых не существует в удаленном репозитории. Это весьма полезно при командном рабочем процессе, где ветки удаляются после слияния с main. Вторая команда, git fetch --prune, перед обрезкой подключается к удаленному репозиторию и получает его последнее состояние. По сути, это сочетание команд:

git fetch --all && git remote prune

Обычная команда git prune действует совсем по-другому. Как объяснялось в обзорном разделе, git prune удаляет локально открепленные коммиты.

Как очистить устаревшие ветки?

git fetch --prune — лучшая утилита для очистки устаревших веток. Она подключатся к удаленному репозиторию с общим доступом и получает все ссылки на удаленные ветки. Затем ссылки, которые больше не используются в удаленном репозиторию, обрезаются.

Удаляет ли git remote prune origin локальную ветку?

Нет, git remote prune origin обрезает ссылки только на удаленные ветки, которые больше не существуют. Git хранит как локальные, так и удаленные ссылки. В репозитории содержатся наборы ссылок local/origin и remote/origin. git remote prune origin обрезает только ссылки remote/origin. Это безопасно для локальной работы в local/origin.

git prune: сводная информация


Команда git prune предназначена для вызова в качестве дочерней команды при запуске git gc. Крайне маловероятно, что вам когда-нибудь понадобится использовать git prune при повседневной разработке программного обеспечения. Чтобы понять, как действует git prune, необходимы другие команды. Помимо прочего, в этой статье мы использовали git log, git reflog и git checkout.


Поделитесь этой статьей
Следующая тема

Рекомендуемые статьи

Добавьте эти ресурсы в закладки, чтобы изучить типы команд DevOps или получать регулярные обновления по DevOps в Atlassian.

Люди сотрудничают друг с другом, используя стену со множеством инструментов

Блог Bitbucket

Рисунок: DevOps

Образовательные программы DevOps

Демонстрация функций в демо-зале с участием экспертов Atlassian

Как инструмент Bitbucket Cloud работает с Atlassian Open DevOps

Подпишитесь на информационную рассылку по DevOps

Thank you for signing up