git: enable Rust build support (drop NO_RUST=1) to match upstream defaults
# git: enable Rust build support (drop `NO_RUST=1`) to match upstream defaults
## Summary
Since **Git 2.55**, Rust support is **enabled by default** in upstream Git's build
system. The `Formula/g/git.rb` formula, however, is currently pinned to the legacy
C-only configuration by passing **`NO_RUST=1`** to `make`. As a result Homebrew's
`git` bottle ships **without** the memory-safe Rust subsystems that every
default upstream build (and most other distributions moving to 2.55) now
includes.
This issue proposes enabling Rust in the formula so the bottle matches upstream
defaults and is ready for **Git 3.0**, where Rust becomes a **mandatory,
non-optional** build requirement.
- Formula: `Formula/g/git.rb`
- Current stable in formula: `git 2.55.0`
- Offending line (in `install`):
```ruby
args = %W[
...
NO_TCLTK=1
NO_RUST=1 # <-- opts out of upstream's default Rust build
]
```
- No `depends_on "rust"` is declared.
## Background: what changed upstream in 2.55
Git's build system reversed the Rust opt-in/opt-out polarity in 2.55. From the
upstream `Makefile` (`v2.55.0`):
```make
# == Optional Rust support ==
#
# Define NO_RUST if you want to disable features and subsystems written in Rust
# from being compiled into Git. For now, Rust is still an optional feature of
# the build process. With Git 3.0 though, Rust will always be enabled.
#
# Building Rust code requires Cargo.
```
And the migration plan is documented explicitly in
`Documentation/BreakingChanges.adoc` (`v2.55.0`):
> There will be multiple milestones for the introduction of Rust:
> 1. Initially, with Git 2.52, support for Rust will be auto-detected by Meson […]
> 2. **In Git 2.55, both build systems will default-enable support for Rust.**
> Consequently, builds will break by default if Rust is not available on the
> build host. The use of Rust can still be explicitly disabled via build
> options.
> 3. **In Git 3.0, the build options will be removed and support for Rust is
> [mandatory].**
Key mechanical facts (verified against `v2.55.0` `Makefile`):
- The old `WITH_RUST` knob was **renamed to `NO_RUST`** (semantics inverted:
opt-in → opt-out).
- When Rust is enabled, the build compiles the `gitcore` crate from
`RUST_SOURCES`:
```
src/csum_file.rs
src/hash.rs
src/lib.rs
src/loose.rs
src/varint.rs
```
and links `-DWITH_RUST` + `$(RUST_LIB)` into `git`.
- The Meson build sets `option('rust', type: 'feature', value: 'enabled')`.
## The concrete problem in `git.rb`
There are two distinct issues:
1. **We opt out of the upstream default.** By passing `NO_RUST=1`, the Homebrew
`git` is built from a configuration that upstream no longer builds by default
and that will **cease to exist** at Git 3.0. When 3.0 lands, `NO_RUST=1` will
be an *unrecognized/removed* option and the formula will need this change
anyway — better to make the (small, safe) transition now, on our schedule,
than under a hard deadline.
2. **A subtle correctness detail around `varint`.** The `NO_RUST` code path is
*not* a pure no-op — it swaps implementations. In the `Makefile`:
```make
ifdef NO_RUST
LIB_OBJS += varint.o # C implementation
endif
...
RUST_SOURCES += src/varint.rs # Rust implementation (used when NO_RUST unset)
```
So today Homebrew ships the **C** `varint`; upstream's default 2.55 build
ships the **Rust** `varint` (via `gitcore`). Enabling Rust aligns us with the
implementation upstream actually tests and ships by default.
## Why enable it (impact on dependencies, performance, security)
### Dependencies
- Adds a single **build-time-only** dependency: `depends_on "rust" => :build`.
`rust` is already a well-maintained core formula (currently `1.96.0`), used as
a build dep by many formulae, so this does not introduce a new runtime dep and
does not change `git`'s runtime dependency graph or bottle linkage for end
users.
- No new *runtime* libraries: the Rust code is statically linked into `git`
(`$(RUST_LIB)` → `libgitcore.a`), so there is no added `dylib` and no change to
`otool -L`/`ldd` output for consumers.
- Aligns Homebrew with other distributions that are declaring a Rust build dep
for their 2.55 packaging cycle.
### Security (the primary upstream motivation)
- The subsystems being migrated to Rust are exactly the historically
memory-unsafe hot spots: object/loose-object handling (`loose.rs`), hashing and
checksum streaming (`hash.rs`, `csum_file.rs`), and variable-length integer
decoding (`varint.rs`). These parse untrusted, attacker-controllable repository
data.
- Rust's ownership/borrow model eliminates whole bug classes (buffer overflow,
use-after-free, out-of-bounds reads) **at compile time** in these paths.
Shipping the Rust build means Homebrew users get the memory-safety hardening
upstream intends for the default build, rather than the legacy C path.
### Performance
- Upstream frames 2.55 primarily as a **safety** milestone, not a performance
one, and the migrated crates are designed as zero-/low-overhead replacements
(`RUST_TARGET_DIR = target/release`, i.e. optimized). Expect **parity** on the
migrated subsystems today, with headroom for future Rust-side optimizations
(e.g. packfile/merge machinery) that Homebrew users would only receive if the
Rust build is enabled.
### Future-proofing
- Git 3.0 (targeted late 2026) removes the opt-out entirely. Making git's bottle
Rust-enabled now de-risks the 3.0 bump: the `depends_on "rust"` machinery and
bottle rebuild will already be proven.
## Proposed fix
1. Add `depends_on "rust" => :build`.
2. Remove `NO_RUST=1` from the `make` args (let upstream default enable Rust).
3. Add a `test do` assertion that the produced binary actually links the Rust
subsystems, to guard against a silent regression back to a `NO_RUST` build.
A Rust-enabled 2.55 binary reports this via `git version --build-options`:
```
$ git version --build-options
git version 2.55.0
...
rust: enabled # <-- present only when built without NO_RUST
...
```
A PR implementing exactly this is attached (see the linked PR). The diff is
minimal and touches only `Formula/g/git.rb`.
## Notes / prior art
- Upstream already fixed a related edge case for building the macOS keychain
helper *without* Rust (`js/osxkeychain-build-wo-rust`, merged for 2.55) — a
reminder that the C-only path is increasingly a special case rather than the
default.
- The `contrib/credential/osxkeychain` helper that this formula builds separately
is unaffected by enabling Rust for the main build; it continues to build with
the same `args` (now without `NO_RUST`).
## Checklist
- [x] Verified against upstream `v2.55.0` `Makefile`, `meson_options.txt`, and
`Documentation/BreakingChanges.adoc`.
- [x] Confirmed `rust` formula is available as a build dependency.
- [x] Built `git 2.55.0` from source with Rust enabled locally (rustc/cargo
1.96.0) — build succeeds, links `target/release/libgitcore.a`, and
`git version --build-options` reports `rust: enabled`.
- [ ] `brew install --build-from-source git` + `brew test git` on a CI runner
(bottle rebuild).
关闭于 2026-07-02 1 条评论