Welcome to the 134th edition of Git Rev News, a digest of all things Git. For our goals, the archives, the way we work, and how to contribute or to subscribe, see the Git Rev News page on git.github.io.
This edition covers what happened during the months of March and April 2026.
[PATCH 0/4] line-log: route -L output through the standard diff pipeline
git log -L lets users follow the history of a specified line range
inside a file, for example by passing -L:funcname:file.c to track
the evolution of a function. Since the feature was introduced,
however, its diff output has been generated by a hand-rolled helper
called dump_diff_hacky() rather than by Git’s standard diff
pipeline, with a NEEDSWORK comment in line-log.c openly
admitting:
/*
* NEEDSWORK: manually building a diff here is not the Right
* Thing(tm). log -L should be built into the diff pipeline.
*/
The practical consequence is that almost every diff formatting
option that users have come to rely on (--word-diff,
--color-moved, the -w/-b whitespace options, --no-prefix,
--src-prefix/--dst-prefix, --full-index, --abbrev, -R,
--output-indicator-*, the pickaxe options -S/-G, and so on) is
silently ignored when combined with -L. The hand-rolled output
also omits the index lines, new file mode headers, and funcname
context in @@ hunk headers that the standard pipeline produces.
Michael Montalbo opened the discussion by sending a four-patch
series that finally addressed this long-standing limitation. The
series explicitly replaced an earlier attempt of him,
“line-log: fix -L with pickaxe options”,
which had taken the opposite approach of rejecting -S/-G when
combined with -L; the new direction is to make those options
work instead. Patch 1 carries over a crash fix from that previous
attempt unchanged, patch 2 contains the core change, patch 3 adds an
extensive set of tests for the newly-working options, and patch 4
updates the documentation.
In detail, patch 1 fixes a real assertion failure that could be triggered by
combining -L with pickaxe options across a merge that contains a
rename, an issue originally reported by Matthew Hughes. Inside
queue_diffs(), the caller’s diff_options was being reused for
rename detection, which meant that any user-specified pickaxe state
(-G, -S, or --find-object) would run inside diffcore_std()
and silently discard diff pairs that the rename machinery still
needed. The fix builds a private diff_options for the
rename-detection path, mirroring the pattern already used in git
blame’s find_rename(), and isolates the rename machinery from
unrelated user options.
Patch 2 is where the heavy lifting happens. Instead of formatting
output by hand, -L now feeds its filepairs through
builtin_diff() and fn_out_consume(), the same path used by
git diff and git log -p. The mechanism is a pair of callback
wrappers that sit between xdi_diff_outf() and fn_out_consume(),
filtering xdiff’s output down to only the tracked line ranges. To
make sure xdiff actually emits every line within each tracked range
as context, the context length is inflated to span the largest
range. The tracked line ranges themselves are now carried on struct
diff_filepair as a borrowed pointer, so that each file’s ranges
travel with its filepair through the rest of the pipeline. As a side
effect, line_log_print() shrinks down to little more than a
diffcore_std() call followed by diff_flush(), the
“-L implies --patch” default is wired up in revision setup rather
than forced at output time, and diff_filepair_dup() is switched
from xmalloc to xcalloc so that newly added fields (including
the line_ranges) are zero-initialized.
Because diffcore_std() now actually runs at output time, options
such as -S, -G, --orderfile, and --diff-filter come along
for the ride and start working with -L for the first time. Michael
also notes in the commit message that the context-length inflation
means xdiff might process more output than strictly needed for very
wide ranges, but his benchmarks on files up to 7800 lines showed no
measurable regression.
There is, of course, a user-visible output change: -L output now
includes index lines, new file mode headers, and funcname
context in @@ hunk headers that were previously absent. Tools that
parse -L output may need to handle these additional lines. The
cover letter is upfront about this, and also lists two limitations
that are deliberately left for follow-up work: line_log_print()
still calling show_log() and diff_flush() directly rather than
going through log_tree_diff_flush(), and the non-patch diff
formats (--raw, --numstat, --stat, etc.) remaining unimplemented
for -L.
Junio Hamano, the Git maintainer, replied to the cover letter the same day with a single word: “Exciting.” He approved the deliberate incremental scope, observing that since “previously all the output routines were hand-rolled, but this reduces the extent of deviation — as long as we are moving in the right direction, it is a good idea to find a good place to stop and leave the rest for later.” On the note about non-patch diff formats, Junio remarked that “it would not hurt if these are omitted”, which led to a small back-and-forth where Michael initially thought he was being asked to do something extra in a follow-up; Junio clarified that the series was already omitting them (“You are already omitting, no? I took ‘remain unimplemented’ to mean exactly that”), and that simply mentioning the omission, as the cover letter already did, was the right thing to do.
Junio also pointed out that the “Michael Montalbo (4): … block in
the cover letter looked like a reflowed duplicate of the proper
commit list right below” it. Michael acknowledged that as a mistake
in crafting the cover letter and offered to add a few names from
git shortlog --no-merges -s -n line-log.[ch] to the Cc list to
attract more reviewers.
On the documentation patch (4/4), Kristoffer Haugsbakk caught a subtle AsciiDoc problem: by indenting the new paragraph with tabs, Michael had inadvertently turned the new prose into a code block. Kristoffer recommended dropping the indentation in favour of a plain list-continuation marker so the text would render as regular paragraph text, that is, “flush to the left.” Michael thanked him and folded the fix into his next iteration.
For readers less familiar with the relevant pieces of the diff stack, a few words of context may help.
git log -L is itself a relatively unusual citizen in Git’s command
zoo: most git log machinery walks commits and emits whatever its
configured formatters dictate, but -L additionally carries a set
of line ranges per file, narrowing the history to commits that touch
those ranges. Mapping that range-aware view onto the standard diff
output machinery is non-trivial because xdiff itself does not know
anything about the user’s tracked ranges; it just produces a unified
diff for two blobs. The new callback wrappers introduced in patch 2
bridge that gap by intercepting xdiff’s output as it is generated
and discarding hunks that fall outside the requested ranges.
The diffcore_std() function is the standard point at which Git
applies a number of cross-cutting transformations to a queued set of
diff pairs: rename detection, the pickaxe filters (-S, -G,
--find-object), the orderfile sort, and the --diff-filter
filter, among others. Once -L actually feeds its pairs through
this function, all of those features become available essentially
“for free.” That is also why patch 1 has to be careful: rename
detection performed during the line-history walk must not let a
user’s pickaxe filter inadvertently throw away the very pairs the
rename machinery needs to do its job.
After the initial round of review, Michael sent
version 2
of the series. The only structural change from v1 is that patch 4
now uses a list-continuation marker instead of indentation in
Documentation/line-range-options.adoc, addressing Kristoffer’s
review feedback so the new paragraph renders correctly. The
crash-fix patch (1/4) also gained an explanatory comment in its test
file about commit-level filtering with pickaxe still being a known
limitation: show_log() prints the commit header before
diffcore_std() runs, so commits cannot yet be suppressed even when
no diff pairs survive filtering. Fixing that would require deferring
show_log() until after diffcore_std(), which is again a larger
log-tree restructuring that v2 explicitly leaves for later.
Junio reviewed v2 patch 2 again and was generally positive. He noted
that “huge diff to the test material mostly comes from the addition
of the diff headers like the index line, etc., which makes this
patch scary but is very welcome addition”, and on the new field
line_ranges carried on struct diff_filepair, simply replied
“OK.” On the rewrite of line_log_print() itself, which now queues
a duplicated filepair per range, attaches the borrowed
line_ranges, and calls diffcore_std() followed by
diff_flush(), he wrote: “Very welcome change.”
Some weeks later, after no further substantive review arrived, Junio came back to the v2 cover letter and wrote, in a slightly resigned but encouraging tone: “The central part of the series (i.e., patch #2) looked quite sensible. I haven’t read the tests very carefully, though. I was hoping that we will see another set of eyes or two to help review this series, but nothing has happened in the past few weeks, so let’s mark the topic for ‘next’.” The series was later merged into ‘master’ and these improvements have been released as part of Git v2.54.0.
This is an example of long-standing technical debt finally being
paid down. A NEEDSWORK comment that has lived in line-log.c for
many years is finally retired; an entire family of diff options
(formatting, whitespace, pickaxe, output-indicator, prefix,
color-moved, and more) becomes available with -L for the first
time; and a real assertion failure involving merges, renames, and
pickaxe filters is fixed along the way.
Editor’s note: This edition features a retrospective interview with a contributor who contributed to Git through a mentoring program. We hope the reflections shared by the GSoC contributor will provide an insightful perspective that benefits the community. As always, we welcome your thoughts and feedback!
Who are you and what do you do?
I’m Meet, a final-year Computer Engineering student from Ahmedabad, India. I’ve
done GSoC twice - first with the Python Software Foundation working on cve-bin-tool,
and then with Git working on the git-refs command.
I also did an LFX Mentorship with Microcks under CNCF between the two GSoCs.
Currently I’m doing an internship at an early-stage stealth startup alongside
finishing up my degree.
How did you initially become interested in contributing to Git, and what motivated you to choose it as your GSoC project?
Back in 2021, a friend showed me a video about GSoC, and it seemed completely out of reach at the time. Fast forward to late 2023, the same friend suggested we finally give it a real shot. We both spent about 4 months contributing to open-source projects to build up experience. Both of us got selected for GSoC 2024. I got into the Python Software Foundation. After finishing GSoC with PSF, I loved the experience so much that I wanted to do it again. I decided to try Git for GSoC 2025. I started by sending some small patches to get familiar with the codebase and the mailing list workflow, reviewed patches from other prospective GSoC students, and eventually proposed the git-refs consolidation project.
Is there any aspect of Git that you now see differently after having contributed to it?
Before contributing, I only really knew about Git’s porcelain commands - push,
pull, fetch, rebase, checkout, the stuff you use every day. I had no
idea how much was happening underneath. Once I started reading the Git Internals
chapters from the Pro Git book and diving into
the source code, I discovered this whole world of plumbing commands -
cat-file, hash-object, update-index, for-each-ref, update-ref, rev-parse,
ls-tree, write-tree - there are way more of them than the porcelain
commands most people interact with.
I learned that Git is fundamentally a content-addressable filesystem with a VCS interface built on top. Everything is an object - blobs hold file contents, trees represent directories, commits are snapshots pointing to trees, and refs are just pointers into this object graph. The objects are addressed by their SHA-1 hashes, and everything you do through the familiar commands is just a thin layer operating on this object database. Understanding all of this completely changed how I think about version control. When something goes wrong in Git, I no longer feel lost - I can reason about what’s actually happening at the object level.
How do you balance your contributions with other responsibilities like work or school?
During GSoC, I was mostly focused on Git full-time. My university schedule was flexible enough that I could dedicate most of my working hours to the project. That said, there were stretches where college reviews and submissions piled up at the same time as a patch series needed revisions, and that got a little hectic. I ended up working on weekends sometimes to make up for lost time and stay on track with the project timeline. The trickier part was the mailing list workflow itself - reviews could come at any time given the global nature of the community, so I had to stay responsive even during busy college weeks.
Can you share how GSoC helped enhance your technical and non-technical skills (like communication, project management, etc.)?
On the technical side, working on Git taught me a lot about writing C code that has to be clean enough for others to maintain long after you’re gone. The Git codebase has strict coding standards and the review process enforces them. I got much better at designing modular code, writing meaningful commit messages, and structuring patch series so that each patch tells a clear story.
On the non-technical side, the mailing list workflow was probably the biggest growth area. All communication is public, asynchronous, and text-based. There’s no hiding behind a quick Slack message - you have to articulate your design decisions clearly in writing. I also learned how to take feedback without taking it personally. Early on, getting a review that asked me to rethink my approach felt discouraging. Over time I realized that the reviewers were investing their time in making my code better, and that changed my perspective entirely.
What was your biggest takeaway or learning from GSoC that you now apply regularly in your work?
Community consensus matters more than being technically correct. In Git, you can write perfectly functional code, but if the community doesn’t agree with the design direction, it won’t get merged. My project depended heavily on consensus around how the git-refs command should behave and what it should consolidate. I spent a fair amount of time not just writing code, but defending design choices and sometimes accepting that a different approach was better [ patch series ]. That taught me to separate my ego from my code. I try to apply that everywhere now - when someone pushes back on something I wrote, my first reaction is to understand why, not to defend.
What was the biggest challenge you faced during your contributions to Git, and how did you overcome it?
The mailing list workflow. Before Git, all of my open-source contributions were
made on GitHub through pull requests. Git uses email-based patches, which was a
completely different process - formatting patches with git send-email, making
sure the threading is correct, handling version updates to a patch series. The
first few times I felt like I was fighting the tooling more than the actual
code.
But it got easier. After a few rounds, it started to feel like second nature. The bigger challenge was the review process itself. Git’s mailing list reviews are thorough. Reviewers will question your variable naming, your commit message wording, your design rationale - everything. Having to defend code changes and push features to near-perfection was time consuming, but it made me a much better programmer. I overcame it by just sticking with it and treating every review comment as a learning opportunity rather than criticism.
Have you thought about mentoring new GSoC / Outreachy students?
Yes, I’d love to. After my GSoC 2024 with PSF, a lot of students reached out to me for guidance on open source and GSoC applications. I helped several of them with finding the right organizations, reviewing proposals, and getting started with contributions. Three of them got selected for GSoC 2025, which I’m really proud of.
For Git specifically, I’d like to mentor in the future, but I want to be in a position where I can give it the time it deserves. Right now I’m occupied with finishing my degree, an internship at a startup, and job hunting, so it wouldn’t be fair to a mentee if I signed up and couldn’t be fully present. But it’s definitely something I want to do - the mentorship I received from Patrick Steinhardt and Jialuo She was really valuable, and I’d like to pay that forward.
What upcoming features or changes in Git are you particularly excited about?
The introduction of Rust into the Git codebase. Git 2.52 was the first release to optionally include Rust code, starting with variable-width integer encoding. Rust will become mandatory for Git 3.0. As someone who’s written C code for Git, I find this really interesting - Rust brings memory safety guarantees that could prevent entire classes of bugs.
What is your toolbox for interacting with the mailing list and for development of Git?
For writing code, I use AstroNvim as my editor. For
sending patches, I use git send-email configured
with Gmail’s SMTP. For reading and replying to mailing list threads, I just
use Gmail’s web interface - it works well enough for following discussions and replying inline.
I develop and test on Linux, which I’ve been using as my daily driver since 2020.
What is your advice for people who want to start Git development? Where and how should they start?
Read the Pro Git book first, especially the Git Internals chapters. It gives you a mental model of how Git actually works underneath, which makes reading the source code much less intimidating.
Then, start small. Subscribe to the mailing list and just read for a week or two. Look at what kind of patches are being sent, how reviews work, how people structure their patch series. The Git project has a document called “MyFirstContribution” in the Documentation folder that walks you through the entire process of submitting your first patch.
For your first contribution, look for something small - a documentation fix, a test improvement, a minor bug fix. The goal isn’t to make a big impact right away. The goal is to get comfortable with the workflow: formatting patches, sending them via email, responding to reviews. Once you’ve done that once or twice, everything else gets easier.
And don’t be afraid of the mailing list. It looks intimidating from the outside, but the community is genuinely helpful. Reviewers invest real time into helping newcomers improve their patches. Take that feedback seriously and you’ll grow fast.
Would you recommend other students or contributors to participate in the GSoC, Outreachy or other mentoring programs, working on Git? Why? Do you have advice for them?
Absolutely. GSoC with Git was one of the best experiences I’ve had. The community is welcoming, the mentors are invested in your success, and the codebase is one of the most widely used pieces of software in the world. There’s something special about knowing that the code you wrote is running on millions of machines.
My advice: start contributing early, well before the application period. Don’t
just pick Git because it looks good on a resume - pick it because you’re
genuinely curious about how it works. The people reviewing your patches can
tell the difference. Also, get comfortable with the mailing list workflow
before GSoC starts. It’s the single biggest adjustment for most newcomers, and
if you spend your GSoC period still figuring out git send-email, you’ll lose
valuable time.
And finally, be patient with yourself. The Git codebase is large and the standards are high. Your first patches will probably need multiple revisions. That’s normal. Every contributor who came before you went through the same thing.
Various
git history command,
a native replacement for git-sizer(1): git repo structure,
and new infrastructure for repository maintenance.git history,
config-based hooks,
geometric repacking during maintenance by default,
and other changes.extensions.submodulePathConfig and submodule.*.gitdir).git history,
setting up Git hooks in repository configuration,
and getting some git repository stats with git repo structure.Light reading
commitlint in Edition #81,
and Conventional Commits in #52.git diff driver and
Using oasdiff for rich Git diffs of OpenAPI spec changes
by Jamie Tanna on their blog.includeIf directive (and core.sshCommand together with gpg "ssh".allowedSignersFile
configuration options) by James Mead on his blog..git directory read only on top
of the project’s directory inside the container.
By Micah R. Ledbetter on their blog.jj) is a Git-compatible version control system,
written in Rust, which was first mentioned in Git Rev News Edition #85.Git Dibs, an April Fool’s 2026 joke on Andy G’s Blog (which included actually creating the gitdibs.com service).
Easy watching
gitoxide is an implementation of git written in Rust,
first mentioned in Git Rev News Edition #67.Git tools and sites
git-meta is an open specification and reference CLI tool
for attaching arbitrary, fine-grained metadata to Git objects — provenance,
ownership, reviews, attestations — stored locally for fast queries
and exchanged using normal Git transfer protocols and servers.git meta as a more performant, scalable, flexible and collaborative
git notes.rebase -i
(interactive rebase) for Mac. Drag-reorder commits,
split one commit into many by assigning hunks, reword in place.
git-ls list the files in the current directory
along with a useful summary of their Git status and helpful hyperlinks
(in terminals that supports OSC8 links such as kitty, iterm or wezterm).
The output is nicely colored.
Written in Go and HTML, under Unlicense license.git-kv is a Bash script
that adds a lightweight key-value store on top of your Git repository.
It uses Git notes
to store and manage key-value pairs associated with commits.
Under BSD-3-Clause license.
.mailmap against the full commit history.
It groups authors and committers by email address and email local-part
so duplicates are caught even across domain changes.
Written in Python, under MIT license.gitleaks (API keys, tokens, credentials, private keys)
and PII via OpenAI Privacy Filter (emails, phone numbers, names, addresses).
Written in Python, under MIT license.
no-mistakes puts a local git proxy
in front of your real remote. Push to no-mistakes instead of origin,
and it spins up a disposable worktree, runs an AI-driven validation pipeline,
forwards upstream only after every check passes, and opens a clean PR automatically.
Documentation at https://kunchenguid.github.io/no-mistakes/.
Agent agnostic: claude, codex, rovodev, opencode, or pi.
Written in Go, under MIT license.git-sync mirrors refs
from a source remote (you can fetch from) to a target remote (you can push to)
without creating a local checkout. It uses an in-memory
go-git object store
and talks smart HTTP directly. Written in Go, under MIT license.
git str) (a tool to send and receive Git patches over Nostr,
using NIP-34),
which was first mentioned in Git Rev News Edition #109,cargo install freenet-git and a running local Freenet node.
Written in Rust, under LGPL-3.0 license.
zizmor is a static analysis tool for GitHub Actions.
It can find and fix many common security issues in typical GitHub Actions CI/CD setups.
Written in Rust, under MIT license.forge is a Go library and CLI
for working with git forges. Supports GitHub, GitLab, Gitea/Forgejo,
and Bitbucket Cloud through a single interface.
Under MIT license.git replace instead of obsolete grafts,
and adding some tags missing from linux/kernel/git/history/history.git
repository on kernel.orgThis edition of Git Rev News was curated by Christian Couder <christian.couder@gmail.com>, Jakub Narębski <jnareb@gmail.com>, Markus Jansen <mja@jansen-preisler.de> and Kaartic Sivaraam <kaartic.sivaraam@gmail.com> with help from Meet Soni, Toon Claes and Paulo Gomes.