I have some old branches in my git repository that are no longer under active development. I would like to archive the branches so that they don\'t show up by default when r
I would not archive branches. Put another way, branches archive themselves. What you want is to ensure the information relevant to archeologists can be found by reliable means. Reliable in that they aid daily development and doesn't add an extra step to the process of getting work done. That is, I don't believe people will remember to add a tag once they're done with a branch.
Here's two simple steps that will greatly help archeology and development.
git merge --no-ff
to merge task branches; you want that merge commit and history bubble, even for just one commit.That's it. Why? Because as a code archeologist, rarely do I start with wanting to know what work was done on a branch. Far more often it's why in all the screaming nine hells is the code written this way?! I need to change code, but it has some odd features, and I need to puzzle them out to avoid breaking something important.
The next step is git blame
to find the associated commits and then hope the log message is explanatory. If I need to dig deeper, I'll find out if the work was done in a branch and read the branch as a whole (along with its commentary in the issue tracker).
Let's say git blame
points at commit XYZ. I open up a Git history browser (gitk, GitX, git log --decorate --graph
, etc...), find commit XYZ and see...
AA - BB - CC - DD - EE - FF - GG - II ...
\ /
QQ - UU - XYZ - JJ - MM
There's my branch! I know QQ, UU, XYZ, JJ and MM are all part of the same branch and I should look at their log messages for details. I know GG will be a merge commit and have the name of the branch which hopefully is associated with an issue in the tracker.
If, for some reason, I want to find an old branch I can run git log
and search for the branch name in the merge commit. It is fast enough even on very large repositories.
That is what I mean when I say that branches archives themselves.
Tagging every branch adds unnecessary work to getting things done (a critical process which should be ruthlessly streamlined), gums up the tag list (not speaking of performance, but human readability) with hundreds of tags that are only very occasionally useful, and isn't even very useful for archeology.
You can use a script that will archive the branch for you
archbranch
It creates a tag for you with the prefix archive/ and then deletes the branch. But check the code before you use it.
Usage - $/your/location/of/script/archbranch [branchname] [defaultbranch]
If you want to run the script without writing the location to it add it to your path
Then you can call it by
$ archbranch [branchname] [defaultbranch]
The [defaultbranch]
is the branch that it will go to when the archiving is done. There are some issues with the color coding but other then that it should work. I've been using it in projects for a long time, but it is still under development.
Here is an alias for that:
arc = "! f() { git tag archive/$1 $1 && git branch -D $1;}; f"
Add it like this:
git config --global alias.arc '! f() { git tag archive/$1 $1 && git branch -D $1;}; f'
Bear in mind there is git archive
command already so you cannot use archive
as an alias name.
Also you can define alias to view the list of the 'archived' branches:
arcl = "! f() { git tag | grep '^archive/';}; f"
about adding aliases
Yes, you can create a ref with some non-standard prefix using git update-ref. e.g.
git update-ref refs/archive/old-topic topic && git branch -D topic
git branch topic refs/archive/old-topic
Refs with non-standard prefix (here refs/archive
) won't show up on usual git branch
, git log
nor git tag
. Still, you can list them with git for-each-ref.
I'm using following aliases:
[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
Also, you may want to configure remotes like push = +refs/archive/*:refs/archive/*
to push archived branches automatically (or just specify on push like git push origin refs/archive/*:refs/archive/*
for one-shot ).
Another way is to writing down SHA1 somewhere before deleting branch, but it has limitations. Commits without any ref will be GC'd after 3 months (or a couple of weeks without reflog), let alone manual git gc --prune
. Commits pointed by refs are safe from GC.
Edit: Found a perl implementation of the same idea by @ap: git-attic
Edit^2: Found a blog post where Gitster himself using the same technique. He named it git hold
.
I sometimes archive branches as follows:
format-patch <branchName> <firstHash>^..<lastHash>
(get firstHash and lastHash using git log <branchName>
.git branch -D <branchName>
"Apply" the patch when you need to use the branch again; however, applying the patch files (see git am
) can be challenging depending on the state of the target branch. On the plus side, this approach has the benefit of allowing the branch's commits to be garbage-collected and saving space in your repo.
You could archive the branches in another repository. Not quite as elegant, but I'd say it's a viable alternative.
git push git://yourthing.com/myproject-archive-branches.git yourbranch
git branch -d yourbranch