4

Suppose I have some branches with names beginning with inactive-. As their names suggest, these branches are inactive; I'm keeping around for archival purposes.

I want to tell gitk to ignore those branches, even if I also pass it the --all flag. Is there a way to do this?

Alternatively, is there some other convenient way to tell gitk to include all branches except those whose name matches inactive-*?


P.S. I did try

gitk --branches='!inactive-*'

...and variations thereof, but none worked.

kjo
  • 33,683
  • 52
  • 148
  • 265
  • Related: http://stackoverflow.com/questions/20977520/is-there-any-way-to-exclude-branches-from-showing-in-gitk – Samir Aguiar Feb 13 '17 at 19:35
  • 1
    One workaround that I could imagine is to make a clone of the repository in which the inactive branches are kept, and to delete them in the "active" repository. – mkrieger1 Feb 13 '17 at 20:10

2 Answers2

3

2014: as j6t comments, gitk already provide a solution (requested and documented by jt6):

gitk --exclude=inactive-\* --branches

Before Git 1.9 (Q4 2013), people often wished a way to tell "git log --branches"(man) (and "git log --remotes --not --branches"(man)) to exclude some local branches from the expansion of "--branches" (similarly for "--tags", "--all" and "--glob=<pattern>").
Now they have one.

See commit 9dc01bf, commit ff32d34, commit 751a2ac (01 Nov 2013), and commit e7b432c (30 Aug 2013) by Junio C Hamano (gitster).
See commit 574d370 (02 Sep 2013) by Johannes Sixt (j6t).
(Merged by Junio C Hamano -- gitster -- in commit 10167eb, 05 Dec 2013)

rev-parse: introduce --exclude= to tame wildcards

Teach "rev-parse" the same "I'm going to glob, but omit the ones that match these patterns" feature as "rev-list".

git rev-parse now includes in its man page:

--exclude=<glob-pattern>

Do not include refs matching '' that the next --all, --branches, --tags, --remotes, or --glob would otherwise consider. Repetitions of this option accumulate exclusion patterns up to the next --all, --branches, --tags, --remotes, or --glob option (other options or arguments do not clear accumlated patterns).

The patterns given should not begin with refs/heads, refs/tags, or refs/remotes when applied to --branches, --tags, or --remotes, respectively, and they must begin with refs/ when applied to --glob or --all. If a trailing '/{asterisk}' is intended, it must be given explicitly.


But, if you have to use git for-each-ref, to echo torek's 2017 answer:

2023 (6+ years later): Yes, there is now a convenient way to do this

With Git 2.42 (Q3 2023), enumerating refs in the packed-refs file, while excluding refs that match certain patterns, has been optimized.

And that means you can use git for-each-ref with the new --exclude option:

git for-each-ref --format="%(refname:short)" --exclude="inactive-" refs/heads

(The pattern follows fnmatch though, it is not a true regex)

So:

gitk $(git for-each-ref --format="%(refname:short)" --exclude="inactive-" refs/heads)

See commit 284c55d, commit b571fb9, commit 311bfe1, commit b9f7daa, commit bf1377a (10 Jul 2023) by Jeff King (peff).
See commit 98456ef, commit 18b6b1b, commit cc2a1f9, commit 15af64d, commit e6bf24d, commit c45841f, commit c489f47, commit 59c35fa, commit d22d941, commit b269ac5, commit 8255dd8 (10 Jul 2023) by Taylor Blau (ttaylorr).
(Merged by Junio C Hamano -- gitster -- in commit 39fe402, 21 Jul 2023)

builtin/for-each-ref.c: add --exclude option

Co-authored-by: Jeff King
Signed-off-by: Jeff King
Signed-off-by: Taylor Blau

When using for-each-ref, it is sometimes convenient for the caller to be able to exclude certain parts of the references.

For example, if there are many refs/__hidden__/* references, the caller may want to emit all references except the hidden ones.
Currently, the only way to do this is to post-process the output, like:

$ git for-each-ref --format='%(refname)' | grep -v '^refs/hidden/'

Which is do-able, but requires processing a potentially large quantity of references.

Teach git for-each-ref(man) a new --exclude=<pattern> option, which excludes references from the results if they match one or more excluded patterns.

This patch provides a naive implementation where the ref_filter still sees all references (including ones that it will discard) and is left to check whether each reference matches any excluded pattern(s) before emitting them.

By culling out references we know the caller doesn't care about, we can avoid allocating memory for their storage, as well as spending time sorting the output (among other things).
Even the naive implementation provides a significant speed-up on a modified copy of linux.git (that has a hidden ref pointing at each commit):

$ hyperfine \
  'git.compile for-each-ref --format="%(objectname) %(refname)" | grep -vE "[0-9a-f]{40} refs/pull/"' \
  'git.compile for-each-ref --format="%(objectname) %(refname)" --exclude refs/pull/'
Benchmark 1: git.compile for-each-ref --format="%(objectname) %(refname)" | grep -vE "[0-9a-f]{40} refs/pull/"
  Time (mean ± σ):     820.1 ms ±   2.0 ms    [User: 703.7 ms, System: 152.0 ms]
  Range (min … max):   817.7 ms … 823.3 ms    10 runs

Benchmark 2: git.compile for-each-ref --format="%(objectname) %(refname)" --exclude refs/pull/
  Time (mean ± σ):     106.6 ms ±   1.1 ms    [User: 99.4 ms, System: 7.1 ms]
  Range (min … max):   104.7 ms … 109.1 ms    27 runs

Summary
  'git.compile for-each-ref --format="%(objectname) %(refname)" --exclude refs/pull/' ran
    7.69 ± 0.08 times faster than 'git.compile for-each-ref --format="%(objectname) %(refname)" | grep -vE "[0-9a-f]{40} refs/pull/"'

Subsequent patches will improve on this by avoiding visiting excluded sections of the packed-refs file in certain cases.

git for-each-ref now includes in its man page:

--exclude=<pattern>

If one or more patterns are given, only refs which do not match any excluded pattern(s) are shown. Matching is done using the same rules as <pattern> above.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    Why that `git for-each-ref` complexity? `gitk --exclude=inactive-\* --branches` has worked since the inception of `--exclude` in [commit 10167eb251e1](https://github.com/git/git/commit/10167eb251e177349eebf24650d3c0cc26bd0d75) (2014). This was in fact the use-case for which I asked for that feature. – j6t Jul 22 '23 at 06:46
  • @j6t I agree. This is just to illustrate the new git for-each feature – VonC Jul 22 '23 at 06:48
  • @j6t I have edited the answer to include first your Git 1.9 `git rev-parse --exclude` feature. – VonC Jul 22 '23 at 06:56
  • Thanks, but the feature was implemented by Junio; I only wrote the text in the manual pages. – j6t Jul 22 '23 at 07:05
  • @j6t OK, I have edited the answer accordingly. – VonC Jul 22 '23 at 07:07
2

No, there's no really convenient way to do this.

Here's a slightly inconvenient way to achieve a similar result to "--all except for invalid-*":

gitk $(git for-each-ref --format="%(refname:short)" refs/heads | grep -v '^inactive-')

That is, we use git for-each-ref to find all branch names (everything in refs/heads/*), then use grep -v to discard those whose name starts with inactive-. The resulting list is the set of arguments to gitk.

(You could modify gitk to do this fairly easily, since gitk is just a gigantic Tcl/Tk script.)

torek
  • 448,244
  • 59
  • 642
  • 775