I'm housekeeping my repo and want to delete some old branches that are not used anymore. There are plenty info on how to delete those. However, I'm not sure if these solutions would be safe for me as I merged branches using --no-ff
.
Imagine my log looks like this:
master *--*--*--------*--*--*--*
\ / /
\ / |
feature_a *--*--* |
\ |
\ /
feature_b *--*--*
Question: How to remove feature_a
and feature_b
branches without losing neither data nor log-structure?
Basically I want that git branch
returns only *master
, and that the log graph still looks like above (i.e. no rewriting commits of feature_a
and _b
onto master
).
All you need to do is delete the extra branch names (git branch -d feature_a feature_b
for instance). The commits themselves are safe, protected by the branch name master
. The accepted answer to the linked question is one way to automate this.
It is, I think, helpful to draw the branches differently, because Git works differently (from most other version control systems, and from what you're thinking). Instead of:
master *--*--*--------*--*--*--*
\ / /
\ / |
feature_a *--*--* |
\ |
\ /
feature_b *--*--*
draw them like this:
*--*--*--------M--*--m--* <-- master
\ / /
*---*---* <- / ------ feature_a
\ /
*--*--* <-- feature_b
The reason to do this is that this is how Git works: the names actually point directly to specific commits. Git calls these three pointed-to commits the tip commits of the three branches. The commits themselves—all of them; all the *
s in the graph—exist on their own; but they are found by starting with one of the names. The name locates the tip commit, and then Git works backwards (leftwards) from there to find the rest of the commits on the branch.
Merge commits—I've marked the two in this graph with the letters M
and m
—have the feature of pointing backwards to two commits at the same time. When Git follows commits backwards, it must follow all paths "simultaneously" (or as close as it can get). This means that the bottom-row commits are not just on branch feature_b
, but also on branch master
. Two of the middle-row commits are on all three branches.
When you delete a branch name, the commit to which it points—its tip—lose its name. If that's the only name by which you can find that commit, it also loses its protection against the Grim Reaper of Commits, Git's garbage collector (git gc
: GC = garbage collector, or as I like to call it, the Grim Collector :-) ). But if it has some other branch name, or even a tag or anything else that lets you find it, it remains protected.
The same goes for all the commits "behind" that tip commit: if they're reachable from some name, they are protected from the Grim Collector. So the names do have a dual purpose, but once the branch tip is merged, the "protect the commits" purpose is no longer required. (Of course if you add new commits, that moves the branch tip, and its dual purpose resumes.)
Note as well that remote-tracking branch names like origin/master
work exactly the same way, except that instead of moving when you add new commits, they move when you git fetch
new commits from the corresponding remote.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With