git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 0/9] for-each-ref optimizations & usability improvements

From
Victoria Dye via GitGitGadget <gitgitgadget@gmail.com>
Date
Nov 7, 2023, 01:25 UTC
Message-ID
<pull.1609.git.1699320361.gitgitgadget@gmail.com>

This series is a bit of an informal follow-up to [1], adding some more substantial optimizations and usability fixes around ref filtering/formatting. Some of the changes here affect user-facing behavior, some are internal-only, but they're all interdependent enough to warrant putting them together in one series.

[1] https://lore.kernel.org/git/pull.1594.v2.git.1696888736.gitgitgadget@gmail.com/

Patch 1 changes the behavior of the '--no-sort' option in 'for-each-ref', 'tag', and 'branch'. Currently, it just removes previous sort keys and, if no further keys are specified, falls back on ascending refname sort (which, IMO, makes the name '--no-sort' somewhat misleading).

Patch 2 updates the 'for-each-ref' docs to clearly state what happens if you use '--omit-empty' and '--count' together. I based the explanation on what the current behavior is (i.e., refs omitted with '--omit-empty' do count towards the total limited by '--count').

Patches 3-7 incrementally refactor various parts of the ref filtering/formatting workflows in order to create a 'filter_and_format_refs()' function. If certain conditions are met (sorting disabled, no reachability filtering or ahead-behind formatting), ref filtering & formatting is done within a single 'for_each_fullref_in' callback. Especially in large repositories, this makes a huge difference in memory usage & runtime for certain usages of 'for-each-ref', since it's no longer writing everything to a 'struct ref_array' then repeatedly whittling down/updating its contents.

Patch 8 introduces a new option to 'for-each-ref' called '--full-deref'. When provided, any format fields for the dereferenced value of a tag (e.g. "%(*objectname)") will be populated with the fully peeled target of the tag; right now, those fields are populated with the immediate target of a tag (which can be another tag). This avoids the need to pipe 'for-each-ref' results to 'cat-file --batch-check' to get fully-peeled tag information. It also benefits from the 'filter_and_format_refs()' single-iteration optimization, since 'peel_iterated_oid()' may be able to read the pre-computed peeled OID from a packed ref. A couple notes on this one:

 * I went with a command line option for '--full-deref' rather than another
   format specifier (like ** instead of *) because it seems unlikely that a
   user is going to want to perform a shallow dereference and a full
   dereference in the same 'for-each-ref'. There's also a NEEDSWORK going
   all the way back to the introduction of 'for-each-ref' in 9f613ddd21c
   (Add git-for-each-ref: helper for language bindings, 2006-09-15) that (to
   me) implies different dereferencing behavior corresponds to different use
   cases/user needs.
 * I'm not attached to '--full-deref' as a name - if someone has an idea for
   a more descriptive name, please suggest it!

Finally, patch 9 adds performance tests for 'for-each-ref', showing the effects of optimizations made throughout the series. Here are some sample results from my Ubuntu VM (test names shortened for space):

Test this branch ---------------------------------------------------------------------------- 6300.2: (loose) 4.78(0.89+3.82) 6300.3: (loose, no sort) 4.51(0.86+3.58) 6300.4: (loose, --count=1) 4.70(0.90+3.73) 6300.5: (loose, --count=1, no sort) 4.35(0.58+3.73) 6300.6: (loose, tags) 2.45(0.44+1.95) 6300.7: (loose, tags, no sort) 2.38(0.44+1.90) 6300.8: (loose, tags, shallow deref) 3.33(1.27+1.99) 6300.9: (loose, tags, shallow deref, no sort) 3.29(1.29+1.93) 6300.10: (loose, tags, full deref) 3.76(1.69+1.99) 6300.11: (loose, tags, full deref, no sort) 3.73(1.71+1.94) 6300.12: for-each-ref + cat-file (loose, tags) 4.25(2.16+2.17) 6300.14: (packed) 0.61(0.50+0.09) 6300.15: (packed, no sort) 0.46(0.40+0.04) 6300.16: (packed, --count=1) 0.59(0.44+0.13) 6300.17: (packed, --count=1, no sort) 0.02(0.01+0.01) 6300.18: (packed, tags) 0.28(0.18+0.09) 6300.19: (packed, tags, no sort) 0.29(0.24+0.03) 6300.20: (packed, tags, shallow deref) 1.20(1.03+0.13) 6300.21: (packed, tags, shallow deref, no sort) 1.13(0.99+0.08) 6300.22: (packed, tags, full deref) 1.57(1.45+0.11) 6300.23: (packed, tags, full deref, no sort) 1.07(1.01+0.05) 6300.24: for-each-ref + cat-file (packed, tags) 2.01(1.81+0.33)

 * Victoria
Victoria Dye (9):
  ref-filter.c: really don't sort when using --no-sort
  for-each-ref: clarify interaction of --omit-empty & --count
  ref-filter.h: add max_count and omit_empty to ref_format
  ref-filter.h: move contains caches into filter
  ref-filter.h: add functions for filter/format & format-only
  ref-filter.c: refactor to create common helper functions
  ref-filter.c: filter & format refs in the same callback
  for-each-ref: add option to fully dereference tags
  t/perf: add perf tests for for-each-ref
 Documentation/git-for-each-ref.txt |  12 +-
 builtin/branch.c                   |  42 +++--
 builtin/for-each-ref.c             |  41 ++---
 builtin/ls-remote.c                |  10 +-
 builtin/tag.c                      |  32 +---
 ref-filter.c                       | 277 ++++++++++++++++++++---------
 ref-filter.h                       |  26 +++
 t/perf/p6300-for-each-ref.sh       |  87 +++++++++
 t/t3200-branch.sh                  |  68 ++++++-
 t/t6300-for-each-ref.sh            |  55 ++++++
 t/t7004-tag.sh                     |  45 +++++
 11 files changed, 532 insertions(+), 163 deletions(-)
 create mode 100755 t/perf/p6300-for-each-ref.sh
base-commit: bc5204569f7db44d22477485afd52ea410d83743
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1609%2Fvdye%2Fvdye%2Ffor-each-ref-optimizations-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1609/vdye/vdye/for-each-ref-optimizations-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1609
-- 
gitgitgadget
Next: Victoria Dye via GitGitGadget
Message 1 of 49 in “for-each-ref optimizations & usability improvements”
  1. 0/9 for-each-ref optimizations & usability improvementsVictoria Dye via GitGitGadget, Nov 7, 2023
  2. 2/9 for-each-ref: clarify interaction of --omit-empty & --countVictoria Dye via GitGitGadget, Nov 7, 2023
  3. Øystein WalleNov 7, 2023
  4. Victoria DyeNov 7, 2023
  5. Øystein WalleNov 8, 2023
  6. Kristoffer HaugsbakkNov 8, 2023
  7. 1/9 ref-filter.c: really don't sort when using --no-sortVictoria Dye via GitGitGadget, Nov 7, 2023
  8. Patrick SteinhardtNov 7, 2023
  9. Victoria DyeNov 7, 2023
  10. 3/9 ref-filter.h: add max_count and omit_empty to ref_formatVictoria Dye via GitGitGadget, Nov 7, 2023
  11. 4/9 ref-filter.h: move contains caches into filterVictoria Dye via GitGitGadget, Nov 7, 2023
  12. Patrick SteinhardtNov 7, 2023
  13. 5/9 ref-filter.h: add functions for filter/format & format-onlyVictoria Dye via GitGitGadget, Nov 7, 2023
  14. 6/9 ref-filter.c: refactor to create common helper functionsVictoria Dye via GitGitGadget, Nov 7, 2023
  15. Patrick SteinhardtNov 7, 2023
  16. Victoria DyeNov 7, 2023
  17. 7/9 ref-filter.c: filter & format refs in the same callbackVictoria Dye via GitGitGadget, Nov 7, 2023
  18. Patrick SteinhardtNov 7, 2023
  19. Victoria DyeNov 7, 2023
  20. 8/9 for-each-ref: add option to fully dereference tagsVictoria Dye via GitGitGadget, Nov 7, 2023
  21. Patrick SteinhardtNov 7, 2023
  22. Victoria DyeNov 8, 2023
  23. Junio C HamanoNov 8, 2023
  24. Patrick SteinhardtNov 8, 2023
  25. Victoria DyeNov 8, 2023
  26. Junio C HamanoNov 9, 2023
  27. Junio C HamanoNov 9, 2023
  28. Junio C HamanoNov 9, 2023
  29. 9/9 t/perf: add perf tests for for-each-refVictoria Dye via GitGitGadget, Nov 7, 2023
  30. Junio C HamanoNov 7, 2023
  31. Victoria DyeNov 7, 2023
  32. Junio C HamanoNov 7, 2023
  33. Patrick SteinhardtNov 7, 2023
  34. Victoria DyeNov 8, 2023
  35. 00/10 for-each-ref optimizations & usability improvementsVictoria Dye via GitGitGadget, Nov 14, 2023
  36. 01/10 ref-filter.c: really don't sort when using --no-sortVictoria Dye via GitGitGadget, Nov 14, 2023
  37. Junio C HamanoNov 16, 2023
  38. 02/10 ref-filter.h: add max_count and omit_empty to ref_formatVictoria Dye via GitGitGadget, Nov 14, 2023
  39. Øystein WalleNov 16, 2023
  40. 03/10 ref-filter.h: move contains caches into filterVictoria Dye via GitGitGadget, Nov 14, 2023
  41. 04/10 ref-filter.h: add functions for filter/format & format-onlyVictoria Dye via GitGitGadget, Nov 14, 2023
  42. Junio C HamanoNov 16, 2023
  43. 05/10 ref-filter.c: rename 'ref_filter_handler()' to 'filter_one()'Victoria Dye via GitGitGadget, Nov 14, 2023
  44. 06/10 ref-filter.c: refactor to create common helper functionsVictoria Dye via GitGitGadget, Nov 14, 2023
  45. 07/10 ref-filter.c: filter & format refs in the same callbackVictoria Dye via GitGitGadget, Nov 14, 2023
  46. 08/10 for-each-ref: clean up documentation of --formatVictoria Dye via GitGitGadget, Nov 14, 2023
  47. 09/10 ref-filter.c: use peeled tag for '*' format fieldsVictoria Dye via GitGitGadget, Nov 14, 2023
  48. Junio C HamanoNov 16, 2023
  49. 10/10 t/perf: add perf tests for for-each-refVictoria Dye via GitGitGadget, Nov 14, 2023

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.