Как я могу архивировать ветки Git?

305

В моем git-репозитории есть несколько старых веток, которые больше не находятся в активной разработке. Я хотел бы заархивировать ветки, чтобы они не показывались по умолчанию при запуске git branch -l -r. Я не хочу их удалять, потому что я хочу сохранить историю. Как я могу это сделать?

Я знаю, что возможно создать реф за пределами рефсов / голов. Например, refs/archive/old_branch. Есть ли какие-либо последствия этого?

DAN-Мангес
источник
git-rm не удаляет ресурсы из репозитория, он только удаляет их из индекса kernel.org/pub/software/scm/git/docs/git-rm.html Вы можете легко восстановить эти ресурсы, используяgit checkout [rev] file
Дана Сэйн
1
Не то, что я знаю о. Я использую Attic/<branchname>легкие теги для архивирования веток, хотя.
Якуб Наребски
теги - это быстрый, безопасный и вменяемый выбор.
KCH

Ответы:

401

Я считаю, что правильный способ сделать это - пометить ветку. Если вы удалите ветку после того, как отметили ее, то вы фактически сохранили ветку, но она не загромождает ваш список ветвей.

Если вам нужно вернуться в ветку, просто проверьте тег. Это эффективно восстановит ветку из тега.

Для архивации и удаления ветки:

git tag archive/<branchname> <branchname>
git branch -d <branchname>

Чтобы восстановить ветку через некоторое время:

git checkout -b <branchname> archive/<branchname>

История ветки будет сохранена точно так, как это было, когда вы пометили ее.

Джереми Уолл
источник
11
Я новичок в Git, но, пробуя это, я думаю, что правильная команда для восстановления ветки:git checkout -b <branchname> archive/<branchname>
Стив
6
Есть ли причина не использовать тег объекта в этом случае? Возможность узнать, кто заархивировал ветку и когда это может быть интересно.
Грегори Иосиф
7
@ GrégoryJoseph: Это так называемый «аннотированный тег». И да, использование этого может иметь большой смысл, я бы сказал.
onnodb
22
небольшая заметка, которую вы, вероятно, захотите, branch -Dпоскольку, скорее всего, она не будет полностью объединена, если вы архивируете ее таким образом
Аркадий Кукаркин
5
Очень хорошо. Вот полный учебник с объяснениями.
Guyaloni
123

Ответ Джереми в принципе верен, но ИМХО команды, которые он указывает, не совсем верны.

Вот как заархивировать ветку в тег без необходимости извлекать ветку (и, следовательно, без необходимости извлекать ветку в другую ветку, прежде чем вы сможете удалить эту ветку):

> git tag archive/<branchname> <branchname>
> git branch -D <branchname>

А вот как восстановить ветку:

> git checkout -b <branchname> archive/<branchname>
Стив
источник
18
Я думаю, у вас еще не было достаточно очков, но было бы лучше, если бы вы просто отредактировали существующий ответ - +1 в любом случае, хотя :)
jkp
5
@jkp редактирование кода и команд других пользователей, как правило, вызывает недовольство, потому что едва заметные изменения в команде git могут привести к совершенно разным вещам, и вы можете не понять, почему первоначальный автор написал что-то так, как они это сделали. Лучше просто сделать свой ответ или оставить комментарий.
Дэн
Или даже хуже, чем радикально разные вещи, незначительные изменения в командах или коде могут привести к едва различимым результатам, что может быть очень трудно понять, я бы предложил оставить в качестве комментария, чтобы автор ответа мог отредактировать себя или ответить со встречным иском, ссылающимся на потенциально разные результаты (которые встречаются довольно часто)
Николас Пипитоне
22

Да, вы можете создать ссылку с нестандартным префиксом, используя git update-ref. например

  • Архив ветки: git update-ref refs/archive/old-topic topic && git branch -D topic
  • Восстановить ветку (при необходимости): git branch topic refs/archive/old-topic

Рефы с нестандартным префиксом (здесь refs/archive) не будут отображаться на обычном git branch, git logни git tag. Тем не менее, вы можете перечислить их с git for-each-ref.

Я использую следующие псевдонимы:

[alias]
    add-archive = "!git update-ref refs/archive/$(date '+%Y%m%d-%s')"
    list-archive = for-each-ref --sort=-authordate --format='%(refname) %(objectname:short) %(contents:subject)' refs/archive/
    rem = !git add-archive
    lsrem = !git list-archive

Кроме того, вы можете настроить удаленные устройства, такие как push = +refs/archive/*:refs/archive/*автоматическое добавление архивных веток (или git push origin refs/archive/*:refs/archive/*для однократного).

Другой способ - записать SHA1 где-нибудь перед удалением ветки, но у него есть ограничения. Коммиты без каких-либо ссылок будут GC'd через 3 месяца (или пару недель без рефлога) , не говоря уже о руководстве git gc --prune. Комитеты, указанные рефери, защищены от GC.

Редактировать: нашел реализацию perl той же идеи @ap :git-attic

Редактировать ^ 2: нашел сообщение в блоге, где сам Гитстер использовал ту же технику.

snipsnipsnip
источник
3
Отлично, кроме всех остальных в этой теме, вы действительно ответили на вопрос.
17
20

Расширяя ответ Стива, чтобы отразить изменения на пульте, я сделал

 git tag archive/<branchname> <branchname>
 git branch -D <branchname>
 git branch -d -r origin/<branchname>
 git push --tags
 git push origin :<branchname>

Чтобы восстановить с пульта см. Этот вопрос .

Liam
источник
18

Вы можете заархивировать ветки в другом хранилище. Не так элегантно, но я бы сказал, что это жизнеспособная альтернатива.

git push git://yourthing.com/myproject-archive-branches.git yourbranch
git branch -d yourbranch
Август Лиллеас
источник
4
Вы можете создать git-bundleвместо отдельного хранилища.
Якуб Наребски
9

Вот псевдоним для этого:

arc    = "! f() { git tag archive/$1 $1 && git branch -D $1;}; f"

Добавьте это так:

git config --global alias.arc '! f() { git tag archive/$1 $1 && git branch -D $1;}; f'

Имейте в виду, что git archiveкоманда уже существует, поэтому вы не можете использовать ее archiveв качестве псевдонима.

Также вы можете определить псевдоним для просмотра списка «архивных» веток:

arcl   = "! f() { git tag | grep '^archive/';}; f"

о добавлении псевдонимов

Алексей
источник
3
В более новых версиях git (как здесь предлагается ) этот псевдоним дает завершение:!git tag archive/$1 $1 && git branch -D
Отсутствие
5

Я использую следующие псевдонимы, чтобы скрыть заархивированные ветви:

[alias]
    br = branch --no-merge master # show only branches not merged into master
    bra = branch                  # show all branches

Таким образом, git brпоказать активно развивающиеся ветки и git braпоказать все ветки, в том числе и «заархивированные» .

Pitr
источник
5
То, была ли ветвь объединена с главной, не имеет никакого отношения к ее состоянию архива. Например, в моей команде разработчиков у нас есть несколько веток, которые были созданы специально для тестирования. Мы хотим сохранить эти ветки в нашем архиве, но мы определенно не хотим объединять их в master.
Барт
4

Я бы не архивировал ветки. Иными словами, ветки архивируют сами. Вы хотите, чтобы информация, относящаяся к археологам, была надежно найдена. Надежный в том, что он помогает в ежедневном развитии и не добавляет дополнительного шага к процессу выполнения работы. То есть, я не верю, что люди не забудут добавить тег, как только они закончат работу с веткой.

Вот два простых шага, которые очень помогут археологии и развитию.

  1. Свяжите каждую ветку задач со связанной проблемой в системе отслеживания проблем, используя простое соглашение об именах .
  2. Всегда используйте git merge --no-ffдля объединения веток задач; Вы хотите, чтобы коммит слияния и история всплыли, даже для одного коммита.

Вот и все. Зачем? Потому что, как археолог-программист, я редко начинаю с того, что хочу узнать, какая работа была проделана на ветке. Гораздо чаще именно поэтому во всех кричащих девочках код написан таким образом ?! Мне нужно изменить код, но у него есть некоторые странные особенности, и мне нужно разобраться с ними, чтобы не нарушать что-то важное.

Следующий шаг - git blameнайти связанные коммиты, а затем надеяться, что сообщение журнала будет пояснительным. Если мне нужно будет покопаться глубже, я выясню, была ли работа выполнена в ветке, и прочту всю ветку в целом (вместе с ее комментарием в трекере проблем).

Скажем, git blameуказывает на коммит XYZ. Я открываю браузер истории Git (gitk, GitX git log --decorate --graphи т. Д.), Нахожу коммит XYZ и вижу ...

AA - BB - CC - DD - EE - FF - GG - II ...
     \                       /
      QQ - UU - XYZ - JJ - MM

Там моя ветка! Я знаю, что QQ, UU, XYZ, JJ и MM все являются частью одной и той же ветви, и я должен посмотреть на их сообщения журнала для деталей. Я знаю, что GG будет коммитом слияния и будет иметь название ветви, которая, возможно, связана с проблемой в трекере.

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

Вот что я имею в виду, когда говорю, что филиалы сами архивируют.

Добавление тегов к каждой ветви добавляет ненужную работу для достижения цели (критический процесс, который должен быть безжалостно упорядочен), объединяет список тегов (не говоря о производительности, но удобочитаемости) сотнями тегов, которые очень полезны лишь изредка, и не ' даже очень полезно для археологии.

Schwern
источник
2
Но как насчет беспорядка? Возможно, если бы был способ спрятать старые ветви под 10 кубических ярдов грязи.
Bvj
1
Это полезно, но не применимо к неразделенным ветвям. Иногда эксперимент проводился на ветке, и вы хотите сохранить содержимое на случай, если часть из него станет полезной позже.
Нил Мэйхью
1
@bvj Я думаю, что этот ответ предполагает, что вы всегда должны удалять объединенные ветви, потому что вы всегда можете вернуться к ним через коммит слияния. Я согласен с этим.
Нил Мэйхью
@NeilMayhew Да, у меня есть около 10 открытых филиалов, которые открываются сами. Каждый из них связан с открытой задачей, поэтому я могу вспомнить, чем я занимался. Я либо сделаю с ними что-нибудь, либо они станут такими устаревшими, что они больше не актуальны, и я их удалю. Я работал над проектом, абсолютно утопающим в ветках «Мне может понадобиться позже», поэтому мы едва могли видеть, что делаем. Это было действительно оправданием для некоторых разработчиков, чтобы они не убирали за собой. Немного свободы, это хорошо, но не позволяйте ей выйти из-под контроля.
Шверн
@ Шверн Я согласен. Я тоже был в подобных проектах. Я думаю, что преобразование веток в теги - это хороший способ избавиться от беспорядка, потому что список тегов всегда будет расти, а список ветвей не должен (потому что он представляет объем работы, которая продолжается). Использование пространства имен для тегов делает список более управляемым, но тенденциям к пакетированию определенно необходимо сопротивляться. Разработчик должен сохранять коммиты на своей машине, если только у них нет шансов, что кто-нибудь еще их использует.
Нил Мэйхью
2

Мой подход состоит в том, чтобы переименовать все ветви, которые меня не интересуют, с префиксом trash_, а затем использовать:

git branch | grep -v trash

(с привязкой ключа оболочки)

Чтобы сохранить окраску активной ветви, потребуется:

git branch --color=always | grep --color=never --invert-match trash
Шридхар Сарнобат
источник
2
Если вы переименовываете ветки, вы также можете поместить их в пространство имен «archive /»
qneill
1

Вы можете использовать скрипт, который заархивирует ветку для вас

archbranch

Он создает для вас тег с префиксом архива /, а затем удаляет ветку. Но проверьте код, прежде чем использовать его.


Использование - $/your/location/of/script/archbranch [branchname] [defaultbranch]

Если вы хотите запустить скрипт без указания местоположения, добавьте его в свой путь

Тогда вы можете позвонить по

$ archbranch [branchname] [defaultbranch]

Это [defaultbranch]ветвь, к которой он перейдет, когда архивирование будет завершено. Есть некоторые проблемы с цветовым кодированием, но кроме того, что оно должно работать. Я давно использую его в проектах, но он все еще находится в стадии разработки.

Banezaka
источник
1
Для получения справки о переполнении стека вам необходимо указать свою принадлежность к вашему продукту.
LittleBobbyTables - Au Revoir
Ой, прости, не знал. Я автор сценария.
Banezaka
0

Я иногда архивирую ветки следующим образом:

  1. Сгенерируйте файлы патчей, например, format-patch <branchName> <firstHash>^..<lastHash>(используйте firstHash и lastHash, используя git log <branchName>.
  2. Переместить сгенерированные файлы патчей в каталог на файловом сервере.
  3. Удалить ветку, например, git branch -D <branchName>

«Примените» патч, когда вам нужно снова использовать ветку; однако применение файлов исправлений (см. git am) может быть сложным в зависимости от состояния целевой ветви. С другой стороны, этот подход имеет то преимущество, что позволяет коммитам ветки собирать мусор и экономить место в вашем репо.

Билл Хоаг
источник