Aidan Feldman
Aidan Feldman

Reputation: 5457

How do I get the list of branches not merged into master, ordered by most recent commit?

For our buildbot, I want to display the most recently-updated active (non-released) branches. Let's say I have a master branch, as well as the following, from oldest to newest commit:

I am able to get each of these lists separately... e.g. to get all the branches not merged into master:

$ git branch -r --no-merged origin/master
origin/branch1
origin/branch3

Or to get the top fifteen branches, ordered by most recent commit (via https://coderwall.com/p/ndinba):

$ git for-each-ref --sort=-committerdate --format='%(committerdate:short) %(refname:short)' --count=15 refs/remotes/origin/
2013-03-22 origin/branch3
2013-03-22 origin/branch2
2013-03-22 origin/master
2013-03-22 origin/branch1

So I basically want that second list, minus branch2 (with or without master). Hope that makes sense?

Upvotes: 11

Views: 5546

Answers (3)

VonC
VonC

Reputation: 1328602

With git 2.7 (Q4 2015), git for-each-ref, will support the --no-merged option

git for-each-ref --no-merged master refs/heads/

With the doc:

--no-merged [<object>]:

Only list refs whose tips are not reachable from the specified commit (HEAD if not specified).


See commit 4a71109, commit ee2bd06, commit f266c91, commit 9d306b5, commit 7c32834, commit 35257aa, commit 5afcb90, ..., commit b2172fd (07 Jul 2015), and commit af83baf (09 Jul 2015) by Karthik Nayak (KarthikNayak).
(Merged by Junio C Hamano -- gitster -- in commit 9958dd8, 05 Oct 2015)

Some features from "git tag -l" and "git branch -l" have been made available to "git for-each-ref" so that eventually the unified implementation can be shared across all three, in a follow-up series or two.

* kn/for-each-tag-branch:
  for-each-ref: add '--contains' option
  ref-filter: implement '--contains' option
  parse-options.h: add macros for '--contains' option
  parse-option: rename parse_opt_with_commit()
  for-each-ref: add '--merged' and '--no-merged' options
  ref-filter: implement '--merged' and '--no-merged' options
  ref-filter: add parse_opt_merge_filter()
  for-each-ref: add '--points-at' option
  ref-filter: implement '--points-at' option  

With Git 2.29 (Q4 2020), "git for-each-ref"(man) and friends that list refs used to allow only one --merged or --no-merged to filter them; they learned to take combination of both kind of filtering.

See commit b59cdff, commit a1b19aa (18 Sep 2020), and commit 21bf933, commit 415af72, commit b775d81 (15 Sep 2020) by Aaron Lipman (alipman88).
(Merged by Junio C Hamano -- gitster -- in commit 26a3728, 22 Sep 2020)

ref-filter: allow merged and no-merged filters

Signed-off-by: Aaron Lipman

Enable ref-filter to process multiple merged and no-merged filters, and extend functionality to git branch(man) , git tag git(man) and for-each-ref.
This provides an easy way to check for branches that are "graduation candidates:

$ git branch --no-merged master --merged next

If passed more than one merged (or more than one no-merged) filter, refs must be reachable from any one of the merged commits, and reachable from none of the no-merged commits.

filters now includes in its man page:

When combining multiple --merged and --no-merged filters, only references that are reachable from at least one of the --merged commits and from none of the --no-merged commits are shown.

Note: the same Git 2.29 (Q4 2020) adds an hotfix.

See commit 5336d50 (26 Sep 2020) by René Scharfe (rscharfe).
(Merged by Junio C Hamano -- gitster -- in commit 03b0198, 04 Oct 2020)

ref-filter: plug memory leak in reach_filter()

Signed-off-by: René Scharfe

21bf933928 ("ref-filter: allow merged and no-merged filters", 2020-09-15, Git v2.29.0 -- merge listed in batch #16) added an early return to reach_filter().
Avoid leaking the memory of a then unused array by postponing its allocation until we know we need it.

Upvotes: 1

twalberg
twalberg

Reputation: 62489

You could combine the two, like this:

git for-each-ref --sort=-committerdate --format="%(committerdate:short) %(refname:short)" --count=15 $(git branch -r --no-merged origin/master | sed -e 's#^ *#refs/remotes/#')

That will limit the for-each-ref to processing only the branches that branch --no-merged reports...

Edit: fixed formatting of git branch output after actually testing...

Upvotes: 14

spitzanator
spitzanator

Reputation: 1897

Can't you just grep out branch2?

Basically, something like:

for branch in `git branch -r --no-merged origin/master`; do git for-each-ref --sort=-committerdate --format='%(committerdate:short) %(refname:short)' --count=15 refs/remotes/origin/ | grep $branch; done;

That worked for me given your sample output.

Upvotes: 1

Related Questions