0

Assume the following commit structure:

master:      A-B-C-D-E----------------
                  \                   \
branch a:          F-G-H     branch d: N-O
                      \
branch b:              I-J
                          \
branch c:                  K-L-M

I want to delete all branches descending from branch a (in this case, b and c). Is there a way to detect that branch b and c descended from branch a?

Right now I'm thinking of accomplishing this by discovering which branches the common ancestor (G) exists on; which will return a, b, and c; and then comparing the time the branches were provisioned. Afterwards, delete all but the earliest branch.

I'm wondering if there is a cleaner way to do this, and if not, how can I retrieve the timestamp for branch creation?

Desired result:

master:      A-B-C-D-E----------------
                  \                   \
branch a:          F-H'      branch d: N-O
melder
  • 463
  • 2
  • 5
  • 9
  • 2
    Btw. you are missing what branches are: Branches are pointers to single commits; commits are not exclusive to some branches. – poke Oct 22 '12 at 21:46
  • By deleting branches which are explicitly not merged into anything else, you're effectively losing commits. Is this what you're trying to do? – user229044 Oct 22 '12 at 21:55
  • @poke: I understand that. But at initial glance I thought branches had some sort of hierarchy as well, because a branch must originate from an existing branch, right? – melder Oct 22 '12 at 23:00
  • @meager: yes. I'm trying to get rid of a potential set of bad commits. – melder Oct 22 '12 at 23:00
  • 2
    @melder No, you can make branches point to anywhere, and you can also change what they point to all the time, so there is no hierarchy or further meaning of actual *branching* whatsoever. The branching in the history comes from diverging commits and merging, but at that point there is no branch require to point at anything of it. That’s why you usually show Git timelines as simply commit graphs, with branches pointing to single elements. So master would point to `E`, branch a to `H`, b to `J`, c to `M` and d to `O`. – poke Oct 22 '12 at 23:12
  • @poke So what would be the correct way to achieve the result? (I edited the question) – melder Oct 22 '12 at 23:24
  • What is `H'` supposed to be in contrast to `H`? – Tilman Vogel Oct 22 '12 at 23:36
  • @TilmanVogel it's to represent that G and H were squashed together. Not quite the same as H although the data is essentially the same. See here: http://stackoverflow.com/questions/495345/git-removing-selected-commit-log-entries-for-a-repository – melder Oct 22 '12 at 23:40
  • @melder Thanks, that's what I wanted to know. But this can obviously be a second step. Does not `git branch --contains G` (or F) help? I am also a bit puzzled by the timestamp approach: Don't you know ahead of time that branch `a` is the one to keep? – Tilman Vogel Oct 22 '12 at 23:48
  • @TilmanVogel I want to automate this process. As I wrote in the question, the contains will return a, b, and c. How then do we determine which branches to delete? Also you can assume there are no merges in the history. – melder Oct 22 '12 at 23:55

3 Answers3

0

Ok, this may not be the most elegant way, but the following seems to do the trick:

git reflog <branch>

Running this on "b", from the example above, will return something similar:

137c91f b@{0}: branch: Created from a

It's possible to reconstruct the branching tree by running this command on every branch associated to the target commit.

melder
  • 463
  • 2
  • 5
  • 9
0

I would use a very small shell script.

#!/bin/bash

# identify the bad commit
BAD_COMMIT=$(git rev-parse "$1")

# loop through branches
for BRANCH in $(git for-each-ref --format="%(refname)" refs/heads); do
  # detect if the branch is in the history, for which fgrep will exit 0
  if (git rev-list $BRANCH | fgrep -q $BAD_COMMIT); then
    echo "Deleting $BRANCH"
    git branch -D $BRANCH
  else
    echo "Keeping $BRANCH"
  fi
done

See also: SO Answer: Iterating through branches

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
0

1) delete branch C 2) delete branch B I'm not sure what the H' is; I'm going to guess you want to squash commit H into commit G.

Kenrick Chien
  • 1,036
  • 8
  • 22
  • Presumably H' is a version of H that skipped commit G. I'm not sure any script would know to treat `branch a` differently, but it is always possible to run `git rebase --interactive` to remove G from `branch a`'s history. – Jeff Bowman Oct 23 '12 at 08:42