Jak mogę zarchiwizować gałęzie git?

305

Mam kilka starych gałęzi w moim repozytorium git, które nie są już aktywnie rozwijane. Chciałbym zarchiwizować gałęzie, aby nie wyświetlały się domyślnie podczas działania git branch -l -r. Nie chcę ich usuwać, ponieważ chcę zachować historię. W jaki sposób mogę to zrobić?

Wiem, że można utworzyć ref poza refs / heads. Na przykład refs/archive/old_branch. Czy są jakieś konsekwencje takiego postępowania?

dan-manges
źródło
git-rm nie usuwa zasobów z repozytorium, usuwa je tylko z indeksu kernel.org/pub/software/scm/git/docs/git-rm.html Możesz łatwo przywrócić te zasoby, używającgit checkout [rev] file
Dana the Sane
1
Nie żebym o tym wiedział. Attic/<branchname>Jednak do archiwizacji oddziałów używam lekkich tagów.
Jakub Narębski,
Tagi to szybki i bezpieczny i rozsądny wybór.
kch

Odpowiedzi:

401

Uważam, że właściwym sposobem jest oznaczenie gałęzi. Jeśli usuniesz gałąź po jej otagowaniu, to skutecznie ją utrzymasz, ale nie zaśmieci ona twojej listy.

Jeśli chcesz wrócić do oddziału, po prostu sprawdź tag. Skutecznie przywróci gałąź ze znacznika.

Aby zarchiwizować i usunąć gałąź:

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

Aby przywrócić gałąź jakiś czas później:

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

Historia oddziału zostanie zachowana dokładnie tak, jak wtedy, gdy go oznaczyłeś.

Jeremy Wall
źródło
11
Jestem początkującym Gitem, ale próbując tego, wydaje mi się, że właściwym poleceniem przywrócenia oddziału jest:git checkout -b <branchname> archive/<branchname>
Steve,
6
Czy w tym przypadku istnieje powód, aby nie używać znacznika obiektu? Będąc w stanie zobaczyć, kto zarchiwizował oddział i kiedy może być interesujący.
Grégory Joseph
7
@ GrégoryJoseph: To tak zwany „tag z adnotacjami”. I tak, użycie tego może mieć sens, powiedziałbym.
onnodb
22
mała uwaga, prawdopodobnie chcesz, branch -Dponieważ prawdopodobnie nie zostanie w pełni scalona, ​​jeśli zarchiwizujesz ją w ten sposób
Arkadiy Kukarkin
5
Bardzo dobrze. Oto kompletny samouczek z objaśnieniami.
guyaloni
123

Odpowiedź Jeremy'ego jest w zasadzie poprawna, ale polecenia IMHO, które określa, nie są całkiem poprawne.

Oto jak zarchiwizować gałąź do znacznika bez konieczności pobierania gałęzi (a zatem bez konieczności kasowania do innej gałęzi przed usunięciem tej gałęzi):

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

A oto jak przywrócić gałąź:

> git checkout -b <branchname> archive/<branchname>
Steve
źródło
18
Wydaje mi się, że nie masz jeszcze wystarczającej liczby punktów, ale byłoby lepiej, gdybyś po prostu edytował istniejącą odpowiedź - mimo wszystko +1 :)
jkp
5
@jkp edytowanie kodu i poleceń innych użytkowników jest zwykle niezadowolone, ponieważ subtelne zmiany w poleceniu git mogą robić drastycznie różne rzeczy i możesz nie rozumieć, dlaczego oryginalny autor napisał coś w ten sposób. lepiej po prostu stwórz własną odpowiedź lub zostaw komentarz.
Dan Bechard
Lub nawet gorzej niż drastycznie różne rzeczy, subtelna zmiana poleceń lub kodu może prowadzić do subtelnie różnych wyników, co może być naprawdę trudne do zrozumienia, sugerowałbym pozostawienie jako komentarz, aby plakat odpowiedzi mógł sam się edytować lub odpowiedzieć z roszczeniem
wzajemnym
22

Tak, możesz utworzyć odwołanie za pomocą niestandardowego prefiksu git update-ref. na przykład

  • Zarchiwizuj oddział: git update-ref refs/archive/old-topic topic && git branch -D topic
  • Przywróć gałąź (w razie potrzeby): git branch topic refs/archive/old-topic

Referencje z niestandardowym prefiksem (tutaj refs/archive) nie pojawią się zwykle git branch, git logani git tag. Nadal możesz je wymienić git for-each-ref.

Używam następujących aliasów:

[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

Możesz także skonfigurować piloty, takie jak push = +refs/archive/*:refs/archive/*automatyczne wypychanie zarchiwizowanych gałęzi (lub git push origin refs/archive/*:refs/archive/*jednorazowo).

Innym sposobem jest zapisanie SHA1 gdzieś przed usunięciem gałęzi, ale ma ona ograniczenia. Zatwierdzenia bez żadnego refrenu zostaną GC'd po 3 miesiącach (lub kilku tygodniach bez reflogu) , nie mówiąc już o ręcznym git gc --prune. Zmiany wskazane przez referencje są bezpieczne od GC.

Edycja: Znaleziono implementację perl tego samego pomysłu przez @ap :git-attic

Edytuj ^ 2: Znaleziono wpis na blogu, w którym sam Gitster używa tej samej techniki.

snipsnipsnip
źródło
3
Doskonale, oprócz wszystkich innych osób w tym wątku, faktycznie odpowiedziałeś na pytanie.
tzrlk
20

Rozszerzyłem odpowiedź Steve'a, aby odzwierciedlić zmiany na pilocie

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

Aby przywrócić z pilota, zobacz to pytanie .

Liam
źródło
18

Możesz zarchiwizować gałęzie w innym repozytorium. Nie tak elegancki, ale powiedziałbym, że to realna alternatywa.

git push git://yourthing.com/myproject-archive-branches.git yourbranch
git branch -d yourbranch
August Lilleaas
źródło
4
Możesz utworzyć git-bundlezamiast osobnego repozytorium.
Jakub Narębski,
9

Oto alias tego:

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

Dodaj to w ten sposób:

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

Pamiętaj, że istnieje git archivejuż polecenie, więc nie możesz używać go archivejako pseudonimu.

Możesz także zdefiniować alias, aby wyświetlić listę „zarchiwizowanych” gałęzi:

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

o dodawaniu aliasów

Alexey
źródło
3
W nowszych wersjach git (zgodnie z sugestią tutaj ) ten alias zapewnia zakończenie:!git tag archive/$1 $1 && git branch -D
Lack
5

Używam następujących aliasów do ukrywania zarchiwizowanych gałęzi:

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

Aby git brpokazać aktywnie rozwijane gałęzie i git brawszystkie gałęzie, w tym te „zarchiwizowane” .

Pitr
źródło
5
To, czy gałąź została scalona w master, nie ma nic wspólnego ze stanem archiwizacji. Na przykład w moim zespole deweloperów mamy kilka gałęzi, które zostały stworzone specjalnie do testowania różnych rzeczy. Chcemy zachować te gałęzie w naszym archiwum, ale zdecydowanie nie chcemy scalać ich w master.
Bart
4

Nie archiwizowałbym oddziałów. Innymi słowy, same oddziały archiwizują się. Chcemy, aby informacje istotne dla archeologów można było znaleźć w wiarygodny sposób. Niezawodny, ponieważ pomagają w codziennym rozwoju i nie stanowią dodatkowego kroku w procesie wykonywania pracy. Oznacza to, że nie sądzę, aby ludzie pamiętali, aby dodać tag po zakończeniu pracy z gałęzią.

Oto dwa proste kroki, które znacznie pomogą archeologii i rozwojowi.

  1. Połącz każdą gałąź zadania z powiązanym problemem w narzędziu do śledzenia problemów, używając prostej konwencji nazewnictwa .
  2. Zawsze używaj git merge --no-ffdo scalania gałęzi zadań; chcesz, aby scalenie zatwierdzenia i historia bąbelkowały, nawet tylko dla jednego zatwierdzenia.

Otóż ​​to. Dlaczego? Ponieważ jako archeolog kodu rzadko zaczynam od chęci dowiedzenia się, jakie prace wykonano na gałęzi. O wiele częściej to dlatego w tych wszystkich krzyczących dziewięciu piekłach kod jest napisany w ten sposób ?! Muszę zmienić kod, ale ma on pewne dziwne funkcje i muszę je rozszyfrować, aby uniknąć zepsucia czegoś ważnego.

Następnym krokiem jest git blameznalezienie powiązanych zatwierdzeń, a następnie nadzieja, że ​​komunikat dziennika jest objaśniający. Jeśli będę musiał kopać głębiej, dowiem się, czy praca została wykonana w oddziale i przeczytam gałąź jako całość (wraz z komentarzem w module do śledzenia problemów).

Powiedzmy git blamepunkty przy zatwierdzeniu XYZ. Otwieram przeglądarkę historii Git (gitk, GitX git log --decorate --graphitp.), Znajduję XYZ i widzę ...

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

Tam jest mój oddział! Wiem, że QQ, UU, XYZ, JJ i MM są częścią tego samego oddziału i powinienem zapoznać się z ich komunikatami dziennika, aby uzyskać szczegółowe informacje. Wiem, że GG będzie zatwierdzeniem scalania i będzie miało nazwę oddziału, który, mam nadzieję, jest związany z problemem w module śledzącym.

Jeśli z jakiegoś powodu chcę znaleźć starą gałąź, mogę uruchomić git logi wyszukać nazwę gałęzi w zatwierdzeniu scalania. Jest wystarczająco szybki nawet w bardzo dużych repozytoriach.

Właśnie to mam na myśli, mówiąc, że oddziały same się archiwizują.

Oznaczanie każdej gałęzi dodaje niepotrzebną pracę do wykonania zadania (krytyczny proces, który powinien być bezwzględnie usprawniony), rozbija listę tagów (nie mówiąc o wydajności, ale czytelność dla człowieka) za pomocą setek tagów, które są bardzo okazjonalnie przydatne i nie jest nawet bardzo przydatne w archeologii.

Schwern
źródło
2
Ale co z bałaganem? Być może gdyby istniał sposób na ukrycie starych gałęzi pod 10 jardami sześciennymi ziemi.
bvj
1
Jest to przydatne, ale nie dotyczy nie połączonych gałęzi. Czasami eksperyment przeprowadzono na gałęzi i chcesz zachować zawartość na wypadek, gdyby niektóre z nich stały się przydatne później.
Neil Mayhew
1
@bvj Myślę, że ta odpowiedź sugeruje, że należy zawsze usuwać scalone gałęzie, ponieważ zawsze można do nich wrócić poprzez zatwierdzenie scalania. Zgadzam się z tym.
Neil Mayhew
@NeilMayhew Tak, sam mam około 10 nie połączonych oddziałów. Każde z nich jest powiązane z otwartym zadaniem, więc pamiętam, co robiłem. Albo coś z nimi zrobię, albo staną się tak nieaktualne, że nie są już istotne i usunę je. Pracowałem nad projektem, który całkowicie utonął w gałęziach „Mogę go później potrzebować”, więc ledwo mogliśmy zobaczyć, co robimy. To była naprawdę wymówka dla niektórych deweloperów, aby nie musieli po sobie sprzątać. Trochę swobody jest w porządku, ale nie daj się wymknąć spod kontroli.
Schwern
@ Schwern Zgadzam się. Byłem też przy takich projektach. Myślę, że konwersja gałęzi do tagów jest dobrym sposobem na pozbycie się bałaganu, ponieważ lista tagów zawsze będzie się powiększać, podczas gdy lista gałęzi nie powinna (ponieważ reprezentuje ilość trwającej pracy). Używanie przestrzeni nazw dla znaczników sprawia, że ​​lista jest łatwiejsza w zarządzaniu, ale zdecydowanie należy oprzeć się tendencjom packrat. Deweloper powinien zachować zatwierdzenia na własnym komputerze, chyba że istnieje duża szansa, że ​​ktoś inny ich użyje.
Neil Mayhew
2

Moje podejście polega na zmianie nazwy wszystkich gałęzi, na których mi nie zależy, z prefiksem „kosz”, a następnie użyć:

git branch | grep -v trash

(z powiązaniem klucza powłoki)

Aby zachować kolor aktywnej gałęzi, potrzebne byłyby:

git branch --color=always | grep --color=never --invert-match trash
Sridhar Sarnobat
źródło
2
Jeśli zmienisz nazwę gałęzi, równie dobrze możesz umieścić je w przestrzeni nazw „archiwum /”
qneill
1

Możesz użyć skryptu, który zarchiwizuje gałąź dla Ciebie

archbranch

Tworzy dla ciebie tag z archiwum prefiksu /, a następnie usuwa gałąź. Ale sprawdź kod przed użyciem.


Stosowanie - $/your/location/of/script/archbranch [branchname] [defaultbranch]

Jeśli chcesz uruchomić skrypt bez zapisywania lokalizacji, dodaj go do swojej ścieżki

Następnie możesz to nazwać

$ archbranch [branchname] [defaultbranch]

Jest [defaultbranch]to gałąź, do której przejdzie po zakończeniu archiwizacji. Istnieją pewne problemy z kodowaniem kolorami, ale inne niż to powinno działać. Używam go w projektach od dłuższego czasu, ale wciąż jest w fazie rozwoju.

Banezaka
źródło
1
Aby uzyskać pomoc dotyczącą przepełnienia stosu , musisz ujawnić swoje powiązanie z produktem.
LittleBobbyTables - Au Revoir
Przepraszam, nie wiedziałem. Jestem autorem skryptu.
Banezaka,
0

Czasami archiwizuję oddziały w następujący sposób:

  1. Wygeneruj pliki łatek, np. format-patch <branchName> <firstHash>^..<lastHash>(Pobierz firstHash i lastHash używając git log <branchName>.
  2. Przenieś wygenerowane pliki łat do katalogu na serwerze plików.
  3. Usuń gałąź, np. git branch -D <branchName>

„Zastosuj” łatkę, gdy musisz ponownie użyć gałęzi; jednak stosowanie plików łatek (patrz git am) może być trudne w zależności od stanu gałęzi docelowej. Zaletą tego podejścia jest umożliwienie zbierania śmieci oddziału i oszczędność miejsca w repozytorium.

Bill Hoag
źródło