Skip to content

Conversation

@robobun
Copy link
Collaborator

@robobun robobun commented Jan 16, 2026

Summary

  • Introduces a new bun:git module that provides a comprehensive, idiomatic JavaScript API for git operations
  • Uses libgit2 as the backing library for efficient native git operations
  • Implements JSC C++ classes for Repository, Commit, Branch, and Signature

Features

Repository class:

  • Repository.find(path?) - Find and open a git repository
  • Repository.init(path, options?) - Initialize a new repository
  • new Repository(path?) - Open repository from path or current directory
  • Properties: path, gitDir, isBare, isClean, head, branch
  • Methods: getCommit(ref), status(options?), add(paths), commit(message)

Commit class:

  • Properties: sha, shortSha, message, summary, author, committer, parents
  • Methods: parent(index), isAncestorOf(other)

Branch class:

  • Properties: name, fullName, isHead, isRemote, commit, upstream, ahead, behind

Signature class:

  • Properties: name, email, date, timezone
  • Methods: toString()

Test plan

  • All 50 tests pass in test/js/bun/git/git.test.ts
  • Module exports correctly: Repository, Commit, Branch, Signature
  • Repository operations: find, init, status, add, commit
  • Commit operations: lookup, parent traversal, ancestry checking
  • Branch operations: current branch, properties
  • Signature operations: author/committer info, formatting
  • Error handling: invalid paths, invalid refs

🤖 Generated with Claude Code

Claude Bot and others added 8 commits January 16, 2026 06:49
- Add libgit2 as a dependency in CMake build system
- Register bun:git module in HardcodedModule.zig and isBuiltinModule.cpp
- Create JSGit.h with class declarations for Repository, Commit, Branch, etc.
- Implement JSGitRepository with constructor, static methods (find, init, clone)
- Implement JSGitCommit with sha, message, author, parents, diff, getFile
- Add iso subspaces for all git classes
- Add structure caching in ZigGlobalObject

Co-Authored-By: Claude <noreply@anthropic.com>
- Add structure initializers in ZigGlobalObject.cpp for all git classes
- Create comprehensive TypeScript wrapper (src/js/bun/git.ts)
- Implement Repository, Commit, Branch, Remote, Config, Index, Diff, Blob wrappers
- Add StatusEntry class with helper properties
- Add GitError and related error classes
- Export both named exports and default module object

Co-Authored-By: Claude <noreply@anthropic.com>
Tests cover:
- Repository constructor, find(), init()
- Repository properties (path, gitDir, isBare, head, branch, isClean)
- Repository methods (getCommit, getBranch, getRemote, status, add, commit, reset)
- Commit properties (sha, shortSha, message, summary, author, committer, parents, tree)
- Commit methods (parent, listFiles, getFile, isAncestorOf, diff)
- Config get/set operations
- StatusEntry properties
- Diff operations
- Error classes

Co-Authored-By: Claude <noreply@anthropic.com>
- Update createJSGitRepositoryConstructor to return JSValue
- Add function declarations to JSGit.h

Co-Authored-By: Claude <noreply@anthropic.com>
- Add libgit2 CMake build target
- Register bun:git native module
- Implement JSGitRepository class with:
  - Constructor and static find/init methods
  - Properties: path, gitDir, isBare, isClean, head, branch
  - Methods: getCommit, status, add, commit
- Implement JSGitCommit class with:
  - Properties: sha, shortSha, message, summary, author, committer, tree, parents
  - Methods: parent, isAncestorOf
- Implement JSGitBranch class with:
  - Properties: name, fullName, isRemote, isHead, commit, upstream, ahead, behind
  - Methods: delete, rename
- Implement JSGitSignature class with:
  - Properties: name, email, date, timezone
  - Methods: toString

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix static methods (Repository.find, Repository.init) not being attached
- Reorganize code to ensure proper method initialization order
- Add bun:git to isBuiltinModule.cpp in correct sorted position
- Fix libgit2 CMake LIB_PATH configuration
- Add comprehensive test suite with 50 tests covering:
  - Module exports validation
  - Repository.find() with path discovery
  - Repository.init() for normal and bare repos
  - Commit operations (getCommit, parent, isAncestorOf)
  - Branch operations (name, fullName, isHead, commit)
  - Status operations (workTreeStatus, indexStatus)
  - Add and commit functionality
  - Signature properties (name, email, date, timezone)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ations

- Remove duplicate git/ subdirectory files from remote merge
- Remove duplicate LazyProperty-based Git structure entries
- Consolidate to single LazyClassStructure-based implementation
- Remove duplicate IsoSubspace declarations
- Fix namespace references to use Bun:: prefix
- Clean up CMake duplicate targets (BuildLibGit2 vs BuildLibgit2)
- Remove TypeScript wrapper (git.ts) in favor of pure C++ implementation

All 50 tests pass.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add libgit2 as a git submodule in vendor/
- Fix cmake configuration to use proper ARGS instead of CMAKE_ARGS
- Use correct TARGETS (libgit2package) to build static library
- Disable NTLM and GSSAPI which require HTTPS backend

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@robobun
Copy link
Collaborator Author

robobun commented Jan 16, 2026

Updated 2:10 AM PT - Jan 16th, 2026

❌ Your commit 6653c96f has 2 failures in Build #35013 (All Failures)


🧪   To try this PR locally:

bunx bun-pr 26163

That installs a local version of the PR into your bun-26163 executable, so you can run:

bun-26163 --bun

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 16, 2026

Walkthrough

Introduces a comprehensive bun:git module providing Git repository operations. Integrates libgit2 as a build dependency and implements C++ bindings for Repository, Commit, Branch, and Signature objects with corresponding JavaScript API surface, including factory methods, property accessors, and operations.

Changes

Cohort / File(s) Summary
Build Configuration & Dependencies
.gitmodules, cmake/targets/BuildBun.cmake, cmake/targets/BuildLibgit2.cmake
Adds libgit2 submodule and CMake build target with disabled shared libs, tests, SSH/HTTPS, and custom SHA/regex/HTTP backends.
C++ Header Bindings
src/bun.js/bindings/JSGit.h
Declares repository, commit, branch, and signature wrapper classes with lifecycle management and JS engine integration scaffolding.
C++ Repository Binding
src/bun.js/bindings/JSGitRepository.cpp
Implements repository wrapper with libgit2 lifecycle, static factory methods (find, init), property getters (path, gitDir, isBare, isClean), and operations (getCommit, status, add, commit).
C++ Commit Binding
src/bun.js/bindings/JSGitCommit.cpp
Implements commit wrapper with properties (sha, shortSha, message, author, committer) and methods (parent resolution, ancestor checking).
C++ Branch Binding
src/bun.js/bindings/JSGitBranch.cpp
Implements branch wrapper with properties (name, isRemote, isHead) and operations (delete, rename, upstream tracking).
C++ Signature Binding
src/bun.js/bindings/JSGitSignature.cpp
Implements signature wrapper exposing author/committer details (name, email, date, timezone) with string representation.
Global Object Integration
src/bun.js/bindings/ZigGlobalObject.h, src/bun.js/bindings/ZigGlobalObject.cpp
Adds class structure accessors and initialization for Repository, Commit, Branch, Signature.
Garbage Collection Support
src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h, src/bun.js/bindings/webcore/DOMIsoSubspaces.h
Declares isolated subspace members for Git binding objects.
Module Infrastructure
src/bun.js/HardcodedModule.zig, src/bun.js/bindings/isBuiltinModule.cpp, src/bun.js/modules/_NativeModule.h, src/bun.js/modules/BunGitModule.h
Registers bun:git as hardcoded/builtin module and exports Repository, Commit, Branch, Signature constructors.
API Documentation
docs/git-api-reference.md
Comprehensive API reference defining class signatures, methods, properties, error types, and usage examples for bun:git module.
Test Suite
test/js/bun/git/git.test.ts
Tests repository discovery/creation, commit/branch operations, status, add, commit, signatures, and error scenarios.
External Dependency
vendor/libgit2
Submodule pointer to libgit2 source.

Possibly related PRs

  • oven-sh/bun#22888: Modifies builtin module aliasing surface which overlaps with HardcodedModule changes in this PR.

Suggested reviewers

  • dylan-conway
  • nektro
  • taylordotfish
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding a new bun:git module backed by libgit2, which is the primary objective of this substantial changeset.
Description check ✅ Passed The PR description is well-structured with summary, features, and test plan sections. It covers the main changes (Repository, Commit, Branch, Signature classes), key functionality, and verification details. However, it lacks the 'How did you verify your code works?' section explicitly required by the template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Fix all issues with AI agents
In @.gitmodules:
- Around line 1-3: CI checkout steps are not fetching the vendor/libgit2
submodule, causing builds that reference libgit2 (see
src/bun.js/bindings/JSGit.h and src/cli/create_command.zig) to fail; update
relevant GitHub Actions workflow checkout steps to include submodules: recursive
in actions/checkout@v4 or add an explicit step that runs git submodule update
--init --recursive after checkout so the vendor/libgit2 submodule is initialized
before the build.

In `@cmake/targets/BuildLibgit2.cmake`:
- Around line 1-23: The CMake invocation sets invalid/incorrect SHA backend
options: change or remove the USE_SHA1 and USE_SHA256 entries in the
register_cmake_command block so libgit2 receives valid values; replace
USE_SHA1=Builtin with a supported backend name (e.g.,
USE_SHA1=CollisionDetection or USE_SHA1=OpenSSL) or remove the line to use the
default, and correct USE_SHA256=Builtin to the proper lowercase/valid value
(e.g., USE_SHA256=builtin if that backend is intended or
USE_SHA256=CollisionDetection/OpenSSL/etc.), referencing the USE_SHA1 and
USE_SHA256 arguments in the diff.

In `@docs/git-api-reference.md`:
- Line 513: The file ends without a trailing newline at the end of the "9.
Config - Config get/set" section; add a single newline character at the end of
docs/git-api-reference.md (so the file ends with exactly one trailing newline)
to satisfy MD047.
- Around line 7-61: Update the git API docs to match the actual implemented
native bindings by removing or annotating unimplemented types and methods
(Remote, Worktree, Diff, Index, Config, Stash, Blob, and their methods) and
instead document only the classes and members that exist (Repository, Commit,
Branch, Signature and their actual methods/properties such as
Repository.find/init/clone/path/gitDir/head/branch/status/commit/checkout/resetHard),
or clearly mark the rest as "Planned" or move them to a separate design doc;
ensure each documented symbol reflects the real runtime API so consumers of
bun:git aren’t misled.

In `@src/bun.js/bindings/JSGit.h`:
- Around line 24-26: The shutdownLibgit2() function is never registered to run
at process exit, causing libgit2 resources to leak; fix this by registering
shutdownLibgit2() with Bun's exit handler (e.g., call
Bun__atexit(shutdownLibgit2) or atexit(shutdownLibgit2) during initialization)
so that git_libgit2_shutdown() is invoked on shutdown; add that registration in
the same initialization path where initializeLibgit2() (which calls
git_libgit2_init() via std::call_once) is invoked so the shutdown is guaranteed
to run on process exit.

In `@src/bun.js/bindings/JSGitBranch.cpp`:
- Around line 249-269: The delete host function jsGitBranchProtoFunc_delete
frees the underlying libgit2 reference but leaves the JSGitBranch instance's
internal pointer (m_ref) dangling, causing undefined behavior on later property
access; modify JSGitBranch to provide either a public invalidate() method or a
setter to clear m_ref and call that from jsGitBranchProtoFunc_delete after
git_branch_delete succeeds (e.g., JSGitBranch::invalidate() which sets m_ref =
nullptr), and add null checks in JSGitBranch getters (or document immutability)
to throw or return safely when m_ref is null.
- Around line 135-159: The code calls git_reference_target(resolved) to get an
oid, then frees the resolved reference (git_reference_free(resolved)) before
passing that oid to git_commit_lookup, which risks a use-after-free; fix by
copying the oid contents into a local git_oid (e.g. git_oid oid_copy =
*git_reference_target(resolved)) immediately after resolving and before freeing
the reference, then pass &oid_copy to git_commit_lookup (or alternatively keep
the resolved reference alive until after git_commit_lookup); update the block
around git_reference_resolve, git_reference_free, and git_commit_lookup in
JSGitBranch.cpp so the oid used by git_commit_lookup is a safe copy rather than
a pointer into a freed reference.

In `@test/js/bun/git/git.test.ts`:
- Around line 483-489: The time window in the "signature has date property" test
is too tight (60s) and can cause CI flakes; update the assertion that checks
sig.date.getTime() to allow a wider window (e.g., 5 minutes / 300000 ms) so the
test asserts sig.date.getTime() is greaterThan(Date.now() - 300000) instead of
60000; keep the other checks (instanceOf Date and <= Date.now()) and change only
the lower-bound comparison in the test that uses repo.getCommit(repo.head.sha)
and sig.author.
- Line 3: The test imports and calls mkdtemp (from fs/promises); update the
import to remove mkdtemp and instead import tempDir from the test harness, then
replace any mkdtemp(join(tmpdir(), "bun-git-test-")) (or similar mkdtemp usage)
with a call to tempDir() in the test file (git.test.ts) so the test uses the
harness-provided temporary directory helper; ensure any uses of tmpdir()/join
tied to mkdtemp are removed and the new tempDir() return value is used where the
temporary path was previously used.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bcbb4fc and 6653c96.

📒 Files selected for processing (19)
  • .gitmodules
  • cmake/targets/BuildBun.cmake
  • cmake/targets/BuildLibgit2.cmake
  • docs/git-api-reference.md
  • src/bun.js/HardcodedModule.zig
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/JSGitRepository.cpp
  • src/bun.js/bindings/JSGitSignature.cpp
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/bindings/ZigGlobalObject.h
  • src/bun.js/bindings/isBuiltinModule.cpp
  • src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
  • src/bun.js/bindings/webcore/DOMIsoSubspaces.h
  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/modules/_NativeModule.h
  • test/js/bun/git/git.test.ts
  • vendor/libgit2
🧰 Additional context used
📓 Path-based instructions (4)
src/bun.js/bindings/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

When implementing JavaScript classes in C++, create three classes if there's a public constructor: class inheriting from JSDestructibleObject, a Prototype class, and a Constructor class

Files:

  • src/bun.js/bindings/isBuiltinModule.cpp
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGitRepository.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/JSGitSignature.cpp
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Use the # prefix for private fields in Zig structs, e.g., struct { #foo: u32 };
Use Decl literals in Zig, e.g., const decl: Decl = .{ .binding = 0, .value = 0 };
Place @import statements at the bottom of the file in Zig (auto formatter will handle positioning)
Never use @import() inline inside functions in Zig; always place imports at the bottom of the file or containing struct

Files:

  • src/bun.js/HardcodedModule.zig
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Use bun bd test <...test file> to run tests with compiled code changes. Do not use bun test as it will not include your changes.
Use bun:test for files ending in *.test.{ts,js,jsx,tsx,mjs,cjs}. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use bun bd <file> instead of bun bd test <file> since they expect exit code 0.
Do not set a timeout on tests. Bun already has timeouts built-in.

Files:

  • test/js/bun/git/git.test.ts
test/**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.test.ts: Use Bun's Jest-compatible test runner with proper test fixtures and imports from harness
Always use port: 0 when binding to ports in tests - never hardcode ports or use custom random port functions
Use normalizeBunSnapshot to normalize snapshot output in tests
Never write tests that check for 'panic', 'uncaught exception', or similar strings in test output as these will never fail in CI
Use tempDir from harness to create temporary directories in tests - do not use tmpdirSync or fs.mkdtempSync
In spawned process tests, use expect(stdout).toBe(...) BEFORE expect(exitCode).toBe(0) for more useful error messages
Do not use setTimeout in tests - await the condition to be met instead, as you are testing the CONDITION not TIME PASSING

Files:

  • test/js/bun/git/git.test.ts
🧠 Learnings (49)
📓 Common learnings
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 24880
File: packages/bun-vscode/package.json:382-385
Timestamp: 2025-11-20T19:51:32.288Z
Learning: In the Bun repository, dependencies may be explicitly added to package.json files (even when not directly imported in code) to force version upgrades on transitive dependencies, particularly as part of Aikido security scanner remediation to ensure vulnerable transitive dependencies resolve to patched versions.
📚 Learning: 2025-11-20T19:51:32.288Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 24880
File: packages/bun-vscode/package.json:382-385
Timestamp: 2025-11-20T19:51:32.288Z
Learning: In the Bun repository, dependencies may be explicitly added to package.json files (even when not directly imported in code) to force version upgrades on transitive dependencies, particularly as part of Aikido security scanner remediation to ensure vulnerable transitive dependencies resolve to patched versions.

Applied to files:

  • cmake/targets/BuildBun.cmake
  • src/bun.js/HardcodedModule.zig
📚 Learning: 2026-01-15T03:22:50.711Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T03:22:50.711Z
Learning: Only push changes after running `bun bd test <file>` and ensuring tests pass

Applied to files:

  • cmake/targets/BuildBun.cmake
📚 Learning: 2025-10-01T21:48:38.278Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/Bindgen/IDLTypes.h:1-3
Timestamp: 2025-10-01T21:48:38.278Z
Learning: In the Bun codebase, for `BunIDL*` and `Bindgen*` headers (e.g., BunIDLTypes.h, Bindgen/IDLTypes.h), it's acceptable to rely on transitive includes for standard library headers like <type_traits> and <utility> rather than including them explicitly.

Applied to files:

  • cmake/targets/BuildBun.cmake
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms

Applied to files:

  • cmake/targets/BuildBun.cmake
  • src/bun.js/bindings/isBuiltinModule.cpp
  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/HardcodedModule.zig
  • src/bun.js/bindings/webcore/DOMIsoSubspaces.h
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/modules/_NativeModule.h
  • src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/JSGitRepository.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/ZigGlobalObject.h
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2025-09-04T04:16:49.322Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22391
File: src/bun.js/modules/NodeModuleModule.cpp:911-913
Timestamp: 2025-09-04T04:16:49.322Z
Learning: In the Bun codebase, LUT header files (like NodeModuleModule.lut.h) are automatically regenerated by the CI system during the build process, so developers do not need to manually regenerate them when editing LUT source blocks.

Applied to files:

  • cmake/targets/BuildBun.cmake
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/bun.js/bindings/isBuiltinModule.cpp
  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/HardcodedModule.zig
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/modules/_NativeModule.h
  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/JSGitRepository.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/ZigGlobalObject.h
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.txt : Add symbol names without leading underscore to src/symbols.txt for each new V8 API method

Applied to files:

  • src/bun.js/bindings/isBuiltinModule.cpp
  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/HardcodedModule.zig
  • src/bun.js/bindings/webcore/DOMIsoSubspaces.h
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/modules/_NativeModule.h
  • src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/JSGitRepository.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/ZigGlobalObject.h
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes

Applied to files:

  • src/bun.js/bindings/isBuiltinModule.cpp
  • src/bun.js/HardcodedModule.zig
  • test/js/bun/git/git.test.ts
  • src/bun.js/modules/_NativeModule.h
  • src/bun.js/bindings/JSGitBranch.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.dyn : Add symbol names with leading underscore and semicolons in braces to src/symbols.dyn for each new V8 API method

Applied to files:

  • src/bun.js/bindings/isBuiltinModule.cpp
  • src/bun.js/bindings/webcore/DOMIsoSubspaces.h
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/modules/_NativeModule.h
  • src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/ZigGlobalObject.h
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Applied to files:

  • src/bun.js/bindings/isBuiltinModule.cpp
  • test/js/bun/git/git.test.ts
  • src/bun.js/modules/_NativeModule.h
  • src/bun.js/bindings/JSGitBranch.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Register new V8 API test functions in the Init method using NODE_SET_METHOD with exports object

Applied to files:

  • src/bun.js/bindings/isBuiltinModule.cpp
  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/modules/_NativeModule.h
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Create V8 class headers with .h extension following the pattern V8ClassName.h that include pragma once, v8.h, V8Local.h, V8Isolate.h, and declare classes extending from Data with BUN_EXPORT static methods

Applied to files:

  • src/bun.js/bindings/isBuiltinModule.cpp
  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/bindings/webcore/DOMIsoSubspaces.h
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/modules/_NativeModule.h
  • src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/JSGitRepository.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/ZigGlobalObject.h
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Create V8 class implementations with .cpp extension following the pattern V8ClassName.cpp that include the header, v8_compatibility_assertions.h, use ASSERT_V8_TYPE_LAYOUT_MATCHES macro, and implement methods using isolate->currentHandleScope()->createLocal<T>() for handle creation

Applied to files:

  • src/bun.js/bindings/isBuiltinModule.cpp
  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/bindings/webcore/DOMIsoSubspaces.h
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/JSGitRepository.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/ZigGlobalObject.h
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun bd test <...test file>` to run tests with compiled code changes. Do not use `bun test` as it will not include your changes.

Applied to files:

  • src/bun.js/bindings/isBuiltinModule.cpp
  • test/js/bun/git/git.test.ts
  • src/bun.js/modules/_NativeModule.h
📚 Learning: 2025-09-20T05:35:57.318Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 22534
File: src/bun.js/bindings/headers.h:729-731
Timestamp: 2025-09-20T05:35:57.318Z
Learning: symbols.txt in the Bun codebase is specifically for V8 API mangled symbols (without leading underscore), not for general Bun host functions declared with BUN_DECLARE_HOST_FUNCTION. Host functions are handled through different build mechanisms.

Applied to files:

  • src/bun.js/bindings/isBuiltinModule.cpp
  • src/bun.js/HardcodedModule.zig
  • src/bun.js/modules/_NativeModule.h
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/napi/napi.zig : For each new V8 C++ method, add both GCC/Clang and MSVC mangled symbol names to the V8API struct in src/napi/napi.zig using extern fn declarations

Applied to files:

  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/HardcodedModule.zig
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/modules/_NativeModule.h
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/ZigGlobalObject.h
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2026-01-15T03:22:50.711Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T03:22:50.711Z
Learning: Applies to src/bun.js/bindings/*.cpp : When implementing JavaScript classes in C++, create three classes if there's a public constructor: class inheriting from JSDestructibleObject, a Prototype class, and a Constructor class

Applied to files:

  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/JSGitRepository.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/ZigGlobalObject.h
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2025-08-30T09:09:18.384Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22231
File: src/bundler/bundle_v2.zig:48-48
Timestamp: 2025-08-30T09:09:18.384Z
Learning: In Zig, when a module exports a top-level struct, import("./Module.zig") directly returns that struct type and can be used as a type alias without needing to access a field within the module. This is a common pattern in the Bun codebase.

Applied to files:

  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/HardcodedModule.zig
📚 Learning: 2025-10-11T15:19:30.301Z
Learnt from: mastermakrela
Repo: oven-sh/bun PR: 19167
File: src/bun.js/api.zig:31-31
Timestamp: 2025-10-11T15:19:30.301Z
Learning: The learnings about `pub const js = JSC.Codegen.JS<ClassName>` and re-exporting toJS/fromJS/fromJSDirect apply to class-based Zig bindings with constructors and prototype methods (e.g., those with `new` constructors). They do NOT apply to simple namespace-style API objects like TOMLObject, YAMLObject, and CSVObject which expose static functions via a `create()` method that returns a plain JS object.

Applied to files:

  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/bindings/ZigGlobalObject.h
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2026-01-15T03:22:50.711Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T03:22:50.711Z
Learning: C++ code for JavaScriptCore bindings should be placed in `src/bun.js/bindings/*.cpp`

Applied to files:

  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/JSGitRepository.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2025-10-18T20:50:47.750Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:366-373
Timestamp: 2025-10-18T20:50:47.750Z
Learning: In Bun's Zig codebase (src/bun.js/bindings/JSValue.zig), the JSValue enum uses `.null` (not `.js_null`) for JavaScript's null value. Only `js_undefined` has the `js_` prefix to avoid collision with Zig's built-in `undefined` keyword. The correct enum fields are: `js_undefined`, `null`, `true`, `false`, and `zero`.

Applied to files:

  • src/bun.js/modules/BunGitModule.h
📚 Learning: 2026-01-15T03:22:50.711Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T03:22:50.711Z
Learning: Zig code should be organized in `src/*.zig` for core runtime, JavaScript bindings, and package manager

Applied to files:

  • src/bun.js/modules/BunGitModule.h
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.

Applied to files:

  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/bindings/ZigGlobalObject.cpp
  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/ZigGlobalObject.h
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2025-09-02T17:14:46.924Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22227
File: src/safety/alloc.zig:93-95
Timestamp: 2025-09-02T17:14:46.924Z
Learning: In bun's Zig codebase, they use a custom extension of Zig that supports private field syntax with the `#` prefix (e.g., `#allocator`, `#trace`). This is not standard Zig syntax but is valid in their custom implementation. Fields prefixed with `#` are private fields that cannot be accessed from outside the defining struct.

Applied to files:

  • src/bun.js/modules/BunGitModule.h
  • src/bun.js/HardcodedModule.zig
  • src/bun.js/bindings/ZigGlobalObject.h
📚 Learning: 2026-01-15T03:22:50.711Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T03:22:50.711Z
Learning: Code generation happens automatically during the build process via scripts in `src/codegen/` - bundled modules can be reloaded without rebuilding Zig by running `bun run build`

Applied to files:

  • src/bun.js/HardcodedModule.zig
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun:test` for files ending in `*.test.{ts,js,jsx,tsx,mjs,cjs}`. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use `bun bd <file>` instead of `bun bd test <file>` since they expect exit code 0.

Applied to files:

  • src/bun.js/HardcodedModule.zig
  • test/js/bun/git/git.test.ts
  • src/bun.js/modules/_NativeModule.h
📚 Learning: 2025-10-19T02:44:46.354Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/context-propagation.test.ts:1-1
Timestamp: 2025-10-19T02:44:46.354Z
Learning: In the Bun repository, standalone packages under packages/ (e.g., bun-vscode, bun-inspector-protocol, bun-plugin-yaml, bun-plugin-svelte, bun-debug-adapter-protocol, bun-otel) co-locate their tests with package source code using *.test.ts files. This follows standard npm/monorepo patterns. The test/ directory hierarchy (test/js/bun/, test/cli/, test/js/node/) is reserved for testing Bun's core runtime APIs and built-in functionality, not standalone packages.

Applied to files:

  • src/bun.js/HardcodedModule.zig
  • test/js/bun/git/git.test.ts
  • src/bun.js/modules/_NativeModule.h
  • docs/git-api-reference.md
📚 Learning: 2025-10-08T13:56:00.875Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: src/bun.js/api/BunObject.zig:2514-2521
Timestamp: 2025-10-08T13:56:00.875Z
Learning: For Bun codebase: prefer using `bun.path` utilities (e.g., `bun.path.joinAbsStringBuf`, `bun.path.join`) over `std.fs.path` functions for path operations.

Applied to files:

  • src/bun.js/HardcodedModule.zig
📚 Learning: 2026-01-05T16:32:07.551Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:07.551Z
Learning: In Zig codebases (e.g., Bun), treat std.posix.sigaction as returning void and do not perform runtime error handling for its failure. The Zig standard library views sigaction failures as programmer errors (unreachable) because they only occur with invalid signals like SIGKILL/SIGSTOP. Apply this pattern across Zig files that call sigaction (e.g., crash_handler.zig, main.zig, filter_run.zig, process.zig) and ensure failures are not handled as recoverable errors; prefer reaching an explicit unreachable/compile-time assumption when such failures are detected.

Applied to files:

  • src/bun.js/HardcodedModule.zig
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Organize unit tests by module in directories like `/test/js/bun/` and `/test/js/node/`.

Applied to files:

  • test/js/bun/git/git.test.ts
📚 Learning: 2026-01-15T03:22:50.711Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T03:22:50.711Z
Learning: Applies to test/**/*.test.ts : Use Bun's Jest-compatible test runner with proper test fixtures and imports from `harness`

Applied to files:

  • test/js/bun/git/git.test.ts
📚 Learning: 2026-01-15T03:22:50.711Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T03:22:50.711Z
Learning: Applies to test/**/*.test.ts : Use `normalizeBunSnapshot` to normalize snapshot output in tests

Applied to files:

  • test/js/bun/git/git.test.ts
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Ensure V8 API tests compare identical C++ code output between Node.js and Bun through the test suite validation process

Applied to files:

  • test/js/bun/git/git.test.ts
📚 Learning: 2025-11-14T16:07:01.064Z
Learnt from: RiskyMH
Repo: oven-sh/bun PR: 24719
File: docs/bundler/executables.mdx:527-560
Timestamp: 2025-11-14T16:07:01.064Z
Learning: In the Bun repository, certain bundler features like compile with code splitting (--compile --splitting) are CLI-only and not supported in the Bun.build() JavaScript API. Tests for CLI-only features use backend: "cli" flag (e.g., test/bundler/bundler_compile_splitting.test.ts). The CompileBuildConfig interface correctly restricts these with splitting?: never;. When documenting CLI-only bundler features, add a note clarifying they're not available via the programmatic API.

Applied to files:

  • test/js/bun/git/git.test.ts
  • docs/git-api-reference.md
📚 Learning: 2026-01-14T21:08:10.438Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/js/node/test/parallel/CLAUDE.md:0-0
Timestamp: 2026-01-14T21:08:10.438Z
Learning: These are Node.js compatibility tests not written by Bun and cannot be modified

Applied to files:

  • test/js/bun/git/git.test.ts
  • src/bun.js/modules/_NativeModule.h
📚 Learning: 2025-10-08T13:48:02.430Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: test/js/bun/tarball/extract.test.ts:107-111
Timestamp: 2025-10-08T13:48:02.430Z
Learning: In Bun's test runner, use `expect(async () => { await ... }).toThrow()` to assert async rejections. Unlike Jest/Vitest, Bun does not require `await expect(...).rejects.toThrow()` - the async function wrapper with `.toThrow()` is the correct pattern for async error assertions in Bun tests.

Applied to files:

  • test/js/bun/git/git.test.ts
📚 Learning: 2025-10-26T01:32:04.844Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 24082
File: test/cli/test/coverage.test.ts:60-112
Timestamp: 2025-10-26T01:32:04.844Z
Learning: In the Bun repository test files (test/cli/test/*.test.ts), when spawning Bun CLI commands with Bun.spawnSync for testing, prefer using stdio: ["inherit", "inherit", "inherit"] to inherit stdio streams rather than piping them.

Applied to files:

  • test/js/bun/git/git.test.ts
📚 Learning: 2025-10-01T21:59:54.571Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h:47-74
Timestamp: 2025-10-01T21:59:54.571Z
Learning: In the new bindings generator (bindgenv2) for `src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h`, the context-aware enumeration conversion overloads intentionally use stricter validation (requiring `value.isString()` without ToString coercion), diverging from Web IDL semantics. This is a design decision documented in comments.

Applied to files:

  • src/bun.js/bindings/webcore/DOMIsoSubspaces.h
  • src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2025-12-23T06:50:31.577Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 25429
File: src/bun.js/bindings/helpers.h:422-422
Timestamp: 2025-12-23T06:50:31.577Z
Learning: In Bun's C++ bindings, when returning an empty JSC::Identifier and a VM is accessible, prefer using vm.propertyNames->emptyIdentifier over constructing with JSC::Identifier(JSC::Identifier::EmptyIdentifierFlag::EmptyIdentifier). The cached identifier from the VM's property names table is more efficient and consistent with WebKit upgrade patterns. Apply this guidance to src/bun.js/bindings/helpers.h and similar header files in the same bindings directory (i.e., any file that constructs an EmptyIdentifier).

Applied to files:

  • src/bun.js/bindings/webcore/DOMIsoSubspaces.h
  • src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/ZigGlobalObject.h
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Organize code into `builtins/` for individual functions, `node/` for Node.js modules, `bun/` for Bun modules, `thirdparty/` for NPM replacements, and `internal/` for internal modules

Applied to files:

  • src/bun.js/modules/_NativeModule.h
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use JSC::WriteBarrier for heap-allocated references in V8 objects and implement visitChildren() for custom heap objects to support garbage collection

Applied to files:

  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGit.h
  • src/bun.js/bindings/JSGitRepository.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/ZigGlobalObject.h
📚 Learning: 2025-12-23T06:50:41.142Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 25429
File: src/bun.js/bindings/helpers.h:422-422
Timestamp: 2025-12-23T06:50:41.142Z
Learning: In Bun's C++ bindings (src/bun.js/bindings/helpers.h and similar files), when returning an empty JSC::Identifier and a VM is accessible, prefer using `vm.propertyNames->emptyIdentifier` over constructing with `JSC::Identifier(JSC::Identifier::EmptyIdentifierFlag::EmptyIdentifier)`. The cached identifier from the VM's property names table is more efficient and consistent with WebKit upgrade patterns.

Applied to files:

  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use localToJSValue() to convert V8 handles to JSC values and perform JSC operations within V8 method implementations

Applied to files:

  • src/bun.js/bindings/JSGitBranch.cpp
  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/JSGitSignature.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use isolate->currentHandleScope()->createLocal<T>() to create local V8 handles and ensure all V8 values are created within an active handle scope

Applied to files:

  • src/bun.js/bindings/JSGitCommit.cpp
  • src/bun.js/bindings/ZigGlobalObject.h
📚 Learning: 2026-01-07T23:45:24.551Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2026-01-07T23:45:24.551Z
Learning: Applies to src/**/*.zig : Use the `#` prefix for private fields in Zig structs, e.g., `struct { `#foo`: u32 };`

Applied to files:

  • src/bun.js/bindings/ZigGlobalObject.h
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Include ASSERT_V8_TYPE_LAYOUT_MATCHES(v8::ClassName) macro at the beginning of each V8 class implementation file to verify type layout compatibility with V8

Applied to files:

  • src/bun.js/bindings/ZigGlobalObject.h
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : For objects that need internal fields, extend InternalFieldObject class instead of directly extending Data

Applied to files:

  • src/bun.js/bindings/ZigGlobalObject.h
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use V8_UNIMPLEMENTED() macro for functions not yet implemented in V8 compatibility classes

Applied to files:

  • src/bun.js/bindings/ZigGlobalObject.h
🧬 Code graph analysis (7)
src/bun.js/modules/BunGitModule.h (1)
src/bun.js/modules/_NativeModule.h (1)
  • Zig (111-118)
test/js/bun/git/git.test.ts (1)
src/bun.js/bindings/JSGit.h (2)
  • repo (77-77)
  • commit (198-198)
src/bun.js/bindings/JSGitBranch.cpp (1)
src/bun.js/bindings/JSGit.h (11)
  • JSGitBranch (273-328)
  • repo (77-77)
  • commit (198-198)
  • create (61-66)
  • create (87-92)
  • create (182-187)
  • create (210-215)
  • create (304-309)
  • create (334-339)
  • create (429-434)
  • create (459-464)
src/bun.js/bindings/JSGitRepository.cpp (1)
src/bun.js/bindings/JSGit.h (11)
  • JSGitRepository (32-81)
  • create (61-66)
  • create (87-92)
  • create (182-187)
  • create (210-215)
  • create (304-309)
  • create (334-339)
  • create (429-434)
  • create (459-464)
  • JSGitRepositoryPrototype (83-117)
  • repo (77-77)
src/bun.js/bindings/JSGitCommit.cpp (3)
src/bun.js/bindings/JSGit.h (10)
  • JSGitCommit (152-204)
  • repo (77-77)
  • create (61-66)
  • create (87-92)
  • create (182-187)
  • create (210-215)
  • create (304-309)
  • create (334-339)
  • create (429-434)
  • create (459-464)
src/bun.js/bindings/JSGitSignature.cpp (8)
  • finishCreation (32-41)
  • finishCreation (32-32)
  • finishCreation (146-151)
  • finishCreation (146-146)
  • subspaceForImpl (22-30)
  • subspaceForImpl (22-22)
  • create (159-164)
  • create (159-159)
src/bun.js/bindings/helpers.h (1)
  • throwException (335-339)
src/bun.js/bindings/ZigGlobalObject.h (1)
src/bun.js/bindings/JSGit.h (4)
  • JSGitRepositoryPrototype (83-117)
  • JSGitCommitPrototype (206-240)
  • JSGitBranchPrototype (330-364)
  • JSGitSignaturePrototype (455-489)
src/bun.js/bindings/JSGitSignature.cpp (3)
src/bun.js/bindings/JSGit.h (10)
  • JSGitSignature (397-453)
  • create (61-66)
  • create (87-92)
  • create (182-187)
  • create (210-215)
  • create (304-309)
  • create (334-339)
  • create (429-434)
  • create (459-464)
  • JSGitSignaturePrototype (455-489)
src/bun.js/bindings/JSGitRepository.cpp (12)
  • subspaceForImpl (62-70)
  • subspaceForImpl (62-62)
  • finishCreation (57-60)
  • finishCreation (57-57)
  • finishCreation (563-568)
  • finishCreation (563-563)
  • create (653-658)
  • create (653-653)
  • construct (668-702)
  • construct (668-668)
  • call (704-710)
  • call (704-704)
src/bun.js/bindings/helpers.h (1)
  • throwException (335-339)
🪛 Cppcheck (2.19.0)
src/bun.js/bindings/JSGitBranch.cpp

[information] 42-42: Include file

(missingInclude)


[information] 52-52: Include file

(missingIncludeSystem)


[information] 59-59: Include file

(missingIncludeSystem)


[error] 66-66: failed to evaluate #if condition, undefined function-like macro invocation

(syntaxError)

src/bun.js/bindings/JSGitRepository.cpp

[information] 42-42: Include file

(missingInclude)


[information] 52-52: Include file

(missingIncludeSystem)


[information] 59-59: Include file

(missingIncludeSystem)


[error] 66-66: failed to evaluate #if condition, undefined function-like macro invocation

(syntaxError)

src/bun.js/bindings/JSGitCommit.cpp

[information] 42-42: Include file

(missingInclude)


[information] 52-52: Include file

(missingIncludeSystem)


[information] 59-59: Include file

(missingIncludeSystem)


[error] 66-66: failed to evaluate #if condition, undefined function-like macro invocation

(syntaxError)

src/bun.js/bindings/JSGitSignature.cpp

[information] 42-42: Include file

(missingInclude)


[information] 52-52: Include file

(missingIncludeSystem)


[information] 59-59: Include file

(missingIncludeSystem)


[error] 66-66: failed to evaluate #if condition, undefined function-like macro invocation

(syntaxError)

🪛 markdownlint-cli2 (0.18.1)
docs/git-api-reference.md

1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


513-513: Files should end with a single newline character

(MD047, single-trailing-newline)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Mintlify Deployment
🔇 Additional comments (56)
vendor/libgit2 (1)

1-1: Use a stable libgit2 release tag instead of the main branch.

The submodule currently points to d90800046420c694f93285600f3d325c38ed2691 on the main branch. For better maintainability and version tracking, pin to a stable release tag like v1.9.2 instead. This also ensures known vulnerabilities (CVE-2024-24577, CVE-2024-24575) remain patched in future builds.

⛔ Skipped due to learnings
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 24607
File: packages/bun-usockets/src/crypto/root_certs.h:3589-3618
Timestamp: 2025-11-11T22:08:38.015Z
Learning: For PRs that update certificate data (e.g., packages/bun-usockets/src/crypto/root_certs.h or packages/bun-usockets/certdata.txt), treat these files as generated artifacts and avoid review comments unless there is a clear build/runtime breakage.
src/bun.js/HardcodedModule.zig (3)

8-8: Enum entry for bun:git is consistent.


97-97: Module map entry looks correct.


365-365: Alias table update is aligned with new builtin.

src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h (1)

18-26: Git GC subspaces are added cleanly.

src/bun.js/bindings/isBuiltinModule.cpp (1)

34-36: Builtin module list updated appropriately.

cmake/targets/BuildBun.cmake (1)

51-58: Libgit2 dependency is properly wired.

The BuildLibgit2.cmake target exists with correct definitions, and the automatic include pattern at line 1272 (include(Build${dependency})) ensures BuildLibgit2.cmake is included for all dependencies in BUN_DEPENDENCIES. Adding Libgit2 to the list correctly resolves link and include paths across platforms.

src/bun.js/modules/_NativeModule.h (1)

27-37: LGTM: bun:git registered in the native module table.

This wires bun:git into both ESM and CJS native module resolution as intended.

src/bun.js/bindings/webcore/DOMIsoSubspaces.h (1)

21-26: LGTM: Git GC subspaces added.

These new subspace members align with the added Git bindings.

src/bun.js/modules/BunGitModule.h (1)

10-35: LGTM: BunGit exports wired to constructors.

Repository, Commit, Branch, and Signature are exposed cleanly via the native module.

src/bun.js/bindings/ZigGlobalObject.cpp (2)

128-128: LGTM: JSGit.h include added for Git bindings.

Necessary to reference the new Git classes here.


2415-2462: No action required — Git class structures are already in the GC visitation list.

The m_JSGit*ClassStructure members are already included in FOR_EACH_GLOBALOBJECT_GC_MEMBER on lines 582–585 of ZigGlobalObject.h, so their prototypes and constructors will be properly protected from premature garbage collection.

test/js/bun/git/git.test.ts (9)

9-49: LGTM!

The module exports tests properly validate that constructors are exported and that non-public constructors (Commit, Branch, Signature) throw when directly constructed.


51-110: LGTM!

Repository.find() tests cover the key scenarios: exact path, subdirectory traversal, default cwd, and not-found cases. The try/finally pattern for process.chdir restoration is correct.


112-153: LGTM!

Repository.init() tests properly validate standard and bare repository creation, as well as automatic directory creation by libgit2.


155-243: LGTM!

Comprehensive commit tests covering head resolution, commit properties (sha, shortSha, message, summary), author/committer signatures, parent traversal, and ancestry checking.


245-308: LGTM!

Branch tests comprehensively cover name properties, head/remote flags, commit association, and upstream/ahead/behind behavior for local branches.


310-378: LGTM!

Status tests properly verify clean/dirty detection, untracked and modified file status, and the isClean property. Good test isolation with proper cleanup.


380-448: LGTM!

Add and commit tests properly verify file staging (single and multiple), commit creation, SHA generation, and message persistence.


504-523: LGTM!

Error handling tests verify graceful behavior for invalid arguments, missing required parameters, and invalid SHA references.


525-551: LGTM!

Integration tests using the actual Bun repository provide good validation that the API works with real-world Git data.

src/bun.js/bindings/JSGitSignature.cpp (6)

1-11: LGTM!

Proper includes and namespace setup for the JSGitSignature binding implementation.


22-30: LGTM!

Subspace implementation follows the established pattern for GC integration.


32-41: LGTM!

finishCreation properly copies signature data with null-safety for name and email fields.


43-110: LGTM!

Property getters properly validate this type, convert git_time_t to JavaScript Date milliseconds, and format timezone offsets correctly.


112-126: LGTM!

toString() correctly formats the signature as "Name " using efficient string concatenation.


128-187: LGTM!

Prototype and constructor implementation correctly follows the three-class pattern (JSDestructibleObject, Prototype, Constructor) per coding guidelines, with proper prevention of direct construction.

src/bun.js/bindings/JSGitBranch.cpp (5)

1-54: LGTM!

Proper includes, namespace, class info, destructor (freeing git_reference), finishCreation, visitChildrenImpl (GC integration), and subspace implementation.


56-120: LGTM!

Basic property getters (name, fullName, isRemote, isHead) are correctly implemented with proper type checking and safe null handling.


161-187: LGTM!

Upstream getter properly handles the GIT_ENOTFOUND case by returning null and correctly transfers ownership of the upstream reference to the new JSGitBranch.


189-247: LGTM!

Ahead/behind getters properly compute divergence counts using git_graph_ahead_behind and correctly free the upstream reference after use.


303-367: LGTM!

Prototype table and constructor correctly implement the binding pattern, preventing direct construction and exposing all branch properties and methods.

src/bun.js/bindings/JSGitRepository.cpp (9)

1-70: LGTM!

Proper includes, libgit2 initialization with std::once_flag for thread-safety, helper function for git errors, destructor, finishCreation, and subspace implementation.


76-124: LGTM!

Path, gitDir, and isBare getters correctly handle bare vs. non-bare repositories with appropriate fallback logic.


126-153: LGTM!

isClean getter correctly checks for any uncommitted changes including untracked files, with proper cleanup of the status list.


155-222: LGTM!

Head and branch getters correctly handle unborn branches, resolve references, and properly manage memory (freeing reference after use or transferring ownership to JSGitBranch).


224-266: LGTM!

getCommit correctly parses references using git_revparse_single, handles not-found cases gracefully, and properly manages object lifecycle.


268-360: LGTM!

status() method correctly builds status entries with proper handling of index vs. worktree status, rename tracking, and options parsing.


362-423: LGTM!

add() method properly handles both single file and array of files, with correct index lifecycle management across all code paths.


425-538: LGTM!

commit() method correctly manages multiple resources (index, tree, signature, parent commit) with proper cleanup in all error and success paths.


540-711: LGTM!

Static methods (find returning null on failure, init throwing on error) and constructor (throwing on failure) provide the expected API semantics. Constructor and prototype table are properly wired.

src/bun.js/bindings/JSGitCommit.cpp (6)

1-62: LGTM!

Proper includes, class info, destructor (freeing git_commit), finishCreation, visitChildrenImpl, subspaceForImpl, and helper function for OID string conversion.


64-128: LGTM!

SHA, message, and summary getters correctly format OIDs and handle null strings from libgit2.


130-164: LGTM!

Author and committer getters safely pass signature pointers to JSGitSignature, which correctly copies the data in its finishCreation.


166-214: LGTM!

Tree getter returns the tree OID as a string, and parents getter correctly creates JSGitCommit objects for each parent with proper ownership transfer.


216-296: LGTM!

parent(n) and isAncestorOf methods correctly handle optional arguments, different input types (Commit object vs. ref string), and properly manage libgit2 resources.


298-362: LGTM!

Prototype table and constructor correctly implement the binding pattern per coding guidelines, with all commit properties and methods exposed and direct construction prevented.

src/bun.js/bindings/JSGit.h (6)

1-6: LGTM!

Header guards, includes, and namespace setup follow the established pattern for Bun's JSC bindings.


32-81: LGTM!

JSGitRepository follows the correct pattern for JSC bindings:

  • Inherits from JSDestructibleObject
  • Implements proper subspaceFor, createStructure, create, and destroy methods
  • Stores raw git_repository* pointer and cleans it up in destructor
  • No DECLARE_VISIT_CHILDREN needed since no WriteBarrier members

152-204: LGTM!

JSGitCommit correctly:

  • Declares DECLARE_VISIT_CHILDREN for GC tracing of WriteBarrier<JSGitRepository> m_repo
  • Stores both git_commit* and a reference to the owning repository
  • Uses WriteBarrier for the GC-managed repository reference

Based on learnings, this follows the pattern of using WriteBarrier for heap-allocated references and implementing visitChildren() for GC support.


273-328: LGTM!

JSGitBranch correctly:

  • Declares DECLARE_VISIT_CHILDREN for GC tracing of WriteBarrier<JSGitRepository> m_repo
  • Stores git_reference*, repository reference, and m_isRemote flag
  • The isRemote accessor provides read access to the flag

397-453: LGTM!

JSGitSignature takes a different approach by copying data from const git_signature* instead of holding a pointer. This is appropriate because:

  • Signatures are typically short-lived in libgit2 (tied to commit lifetime)
  • Copying name/email/time/offset is cheap and avoids lifetime management complexity
  • No DECLARE_VISIT_CHILDREN needed since String members are handled automatically by JSC

119-146: The declared initializeProperties in JSGitRepositoryConstructor is unused dead code; static methods are attached via reifyStaticProperties in finishCreation instead.

JSGitRepositoryConstructor declares initializeProperties (line 132) but it is never implemented or called. The static methods (Repository.find() and Repository.init()) are actually attached through reifyStaticProperties(vm, info(), JSGitRepositoryConstructorTableValues, *this) in the finishCreation method (JSGitRepository.cpp:664). Since JSGitCommitConstructor, JSGitBranchConstructor, and JSGitSignatureConstructor don't have static methods, they correctly lack both initializeProperties and static method tables. If any of these constructors needed static methods in the future, they would follow the same reifyStaticProperties pattern used by Repository.

src/bun.js/bindings/ZigGlobalObject.h (2)

266-280: LGTM!

The accessor methods for Git class structures follow the established pattern used by other classes in this file (e.g., NodeVMScript, JSBuffer). Each provides:

  • Structure() - returns the lazily-initialized structure
  • Constructor() - returns the lazily-initialized constructor object
  • Prototype() - returns the lazily-initialized prototype value

582-586: LGTM!

Adding the four LazyClassStructure members to FOR_EACH_GLOBALOBJECT_GC_MEMBER ensures they are properly visited during garbage collection. The public visibility and naming convention (m_JSGit*ClassStructure) are consistent with other class structures in this file.

docs/git-api-reference.md (1)

1-3: Add proper markdown heading format.

The first line should be a top-level heading for proper markdown structure. This was flagged by markdownlint.

📝 Suggested fix
-bun:git Module API Design (Class-Based)
+# bun:git Module API Design (Class-Based)
 
-  Core Classes
+## Core Classes
⛔ Skipped due to learnings
Learnt from: mastermakrela
Repo: oven-sh/bun PR: 19167
File: docs/api/csv.md:1-20
Timestamp: 2025-10-13T13:26:39.391Z
Learning: In the Bun repository, documentation files in docs/api/ should NOT include H1 headings. The page titles are provided via the nav.ts file using the page() function's title parameter, and the documentation framework generates the H1 heading automatically. This is the consistent pattern across all API documentation files.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +1 to +3
[submodule "vendor/libgit2"]
path = vendor/libgit2
url = https://github.com/libgit2/libgit2.git
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check .gitmodules file content
echo "=== .gitmodules content ==="
cat .gitmodules

echo -e "\n=== Submodule status ==="
git submodule status --recursive

echo -e "\n=== Look for CI configuration files ==="
find . -maxdepth 2 -type f \( -name ".travis.yml" -o -name ".github" -o -name ".gitlab-ci.yml" -o -name "*.yml" -o -name "*.yaml" \) | grep -E "(\.github|\.travis|\.gitlab)" | head -20

Repository: oven-sh/bun

Length of output: 304


🏁 Script executed:

#!/bin/bash
# Search for CI/workflow files more broadly
echo "=== GitHub Actions workflows ==="
find .github/workflows -type f 2>/dev/null | head -20

echo -e "\n=== All .github files ==="
find .github -type f 2>/dev/null | head -30

echo -e "\n=== Search for any CI config ==="
find . -maxdepth 3 -type f -name "*ci*" -o -name "*workflow*" -o -name "*action*" 2>/dev/null | grep -v node_modules | head -20

echo -e "\n=== Root level config files ==="
ls -la | grep -E "\.(yml|yaml|json|sh)$|Makefile|Dockerfile|^-.*\..*"

Repository: oven-sh/bun

Length of output: 5192


🏁 Script executed:

#!/bin/bash
# Check setup-bun action
echo "=== setup-bun action ==="
cat .github/actions/setup-bun/action.yml

echo -e "\n=== packages-ci workflow ==="
cat .github/workflows/packages-ci.yml

echo -e "\n=== buildkite CI config (first 100 lines) ==="
head -100 .buildkite/ci.mjs

Repository: oven-sh/bun

Length of output: 5057


🏁 Script executed:

#!/bin/bash
# Search for submodule references in CI files
echo "=== Search for 'submodule' in CI/workflows ==="
grep -r "submodule" .github/ .buildkite/ 2>/dev/null

echo -e "\n=== Search for 'submodule' in build files ==="
grep -r "submodule" build.zig CMakeLists.txt 2>/dev/null

echo -e "\n=== Check if libgit2 is referenced in build ==="
grep -r "libgit2" build.zig CMakeLists.txt | head -20

echo -e "\n=== All workflows that might build/compile ==="
ls -1 .github/workflows/*.yml | xargs -I {} basename {} | sort

Repository: oven-sh/bun

Length of output: 642


🏁 Script executed:

#!/bin/bash
# Check git submodule config
echo "=== Git config for submodule ==="
git config --file .gitmodules --get-regexp libgit2

echo -e "\n=== Submodule details ==="
git ls-files --stage | grep vendor/libgit2

echo -e "\n=== Check if vendor/libgit2 directory exists ==="
ls -la vendor/ 2>/dev/null | head -20

echo -e "\n=== update-vendor.yml workflow ==="
cat .github/workflows/update-vendor.yml

echo -e "\n=== release.yml workflow (first 150 lines) ==="
head -150 .github/workflows/release.yml

Repository: oven-sh/bun

Length of output: 8271


🏁 Script executed:

#!/bin/bash
# Search for libgit2 references anywhere in the codebase
echo "=== Search for libgit2 usage in code ==="
grep -r "libgit2" --include="*.zig" --include="*.ts" --include="*.js" --include="*.c" --include="*.h" --include="*.json" . 2>/dev/null | grep -v node_modules | grep -v ".git/" | head -30

echo -e "\n=== Check git submodule update steps in any script ==="
grep -r "git.*submodule" . --include="*.sh" --include="*.mjs" --include="*.yml" 2>/dev/null | grep -v ".git/"

echo -e "\n=== Check if libgit2 is in .gitignore or excluded ==="
grep -i "libgit2\|vendor" .gitignore 2>/dev/null

Repository: oven-sh/bun

Length of output: 418


🏁 Script executed:

#!/bin/bash
# Check .gitignore for vendor
echo "=== Check .gitignore for /vendor ==="
grep -n "^/vendor\|^vendor/" .gitignore

echo -e "\n=== Full .gitignore context around vendor ==="
grep -n -B2 -A2 "vendor" .gitignore

echo -e "\n=== Verify vendor/libgit2 is actually tracked ==="
git ls-tree -r HEAD | grep vendor/libgit2

echo -e "\n=== Check if any CI uses submodules: recursive or git submodule update ==="
find .github/workflows .buildkite -type f \( -name "*.yml" -o -name "*.yaml" -o -name "*.mjs" \) -exec grep -l "submodules" {} \;

Repository: oven-sh/bun

Length of output: 422


Submodule is pinned correctly, but CI doesn't fetch it. The commit hash is recorded (d90800046420c694f93285600f3d325c38ed2691), but none of the GitHub Actions workflows include submodules: recursive in their checkout steps, and no workflows run git submodule update. Since libgit2 is referenced in the codebase (src/bun.js/bindings/JSGit.h, src/cli/create_command.zig), CI builds will fail without the submodule initialized. Update the checkout steps in relevant workflows to fetch submodules:

- uses: actions/checkout@v4
  with:
    submodules: recursive

Or alternatively, add a manual submodule initialization step if recursive fetch isn't suitable.

🤖 Prompt for AI Agents
In @.gitmodules around lines 1 - 3, CI checkout steps are not fetching the
vendor/libgit2 submodule, causing builds that reference libgit2 (see
src/bun.js/bindings/JSGit.h and src/cli/create_command.zig) to fail; update
relevant GitHub Actions workflow checkout steps to include submodules: recursive
in actions/checkout@v4 or add an explicit step that runs git submodule update
--init --recursive after checkout so the vendor/libgit2 submodule is initialized
before the build.

Comment on lines +1 to +23
register_cmake_command(
TARGET
libgit2
TARGETS
libgit2package
LIBRARIES
git2
ARGS
-DBUILD_SHARED_LIBS=OFF
-DBUILD_TESTS=OFF
-DBUILD_CLI=OFF
-DUSE_SSH=OFF
-DUSE_HTTPS=OFF
-DUSE_NTLMCLIENT=OFF
-DUSE_GSSAPI=OFF
-DUSE_SHA1=Builtin
-DUSE_SHA256=Builtin
-DUSE_BUNDLED_ZLIB=ON
-DREGEX_BACKEND=builtin
-DUSE_HTTP_PARSER=builtin
INCLUDES
include
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find libgit2 in vendor directory
echo "=== Searching for libgit2 in vendor directory ==="
fd -a -t d "libgit2" vendor 2>/dev/null || echo "libgit2 directory not found"

# List vendor contents
echo "=== Contents of vendor/ ==="
ls -la vendor/ 2>/dev/null | head -20 || echo "vendor directory listing failed"

Repository: oven-sh/bun

Length of output: 338


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Contents of vendor/libgit2 ==="
ls -la vendor/libgit2/

echo -e "\n=== Find CMake files in vendor/libgit2 ==="
fd -t f "CMakeLists.txt|\.cmake$" vendor/libgit2/ 2>/dev/null | head -20

echo -e "\n=== Recursive file count in vendor/libgit2 ==="
find vendor/libgit2 -type f | wc -l

echo -e "\n=== All files in vendor/libgit2 (first 50) ==="
find vendor/libgit2 -type f | head -50

Repository: oven-sh/bun

Length of output: 338


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check .gitmodules for libgit2 ==="
if [[ -f .gitmodules ]]; then
  cat .gitmodules
else
  echo ".gitmodules not found"
fi

echo -e "\n=== Examine BuildLibgit2.cmake ==="
cat -n cmake/targets/BuildLibgit2.cmake

echo -e "\n=== Search for register_cmake_command definition ==="
rg -n "register_cmake_command" --type cmake -A 5 | head -50

echo -e "\n=== Check if libgit2 is referenced elsewhere ==="
rg -n "libgit2|git2" cmake/ --type cmake | head -30

Repository: oven-sh/bun

Length of output: 3196


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Search for register_cmake_command definition ==="
rg -n "^\s*(function|macro)\s*\(\s*register_cmake_command" cmake/ -A 30 | head -80

echo -e "\n=== Check git submodule version/commit for libgit2 ==="
git config -f .gitmodules --get submodule.vendor/libgit2.url
if [[ -f .git/config ]]; then
  git config --get-all submodule.vendor/libgit2.url 2>/dev/null || echo "No specific version pinned in .git/config"
fi

echo -e "\n=== Check git log for recent libgit2 submodule updates ==="
git log --oneline -- vendor/libgit2 2>/dev/null | head -10 || echo "No git history available"

echo -e "\n=== Find cmake files that define macros ==="
fd -t f "\.cmake$" cmake/ | head -10

Repository: oven-sh/bun

Length of output: 2382


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Full register_cmake_command function ==="
sed -n '729,850p' cmake/Globals.cmake

echo -e "\n=== Check CMAKE_ARGS usage ==="
rg -n "CMAKE_ARGS" cmake/Globals.cmake -B 2 -A 2 | head -20

Repository: oven-sh/bun

Length of output: 3868


🌐 Web query:

libgit2 cmake options USE_SHA1 USE_SHA256 USE_HTTP_PARSER REGEX_BACKEND

💡 Result:

Summary of those libgit2 CMake options (values shown are the common allowed choices and typical defaults):

  • USE_SHA1 — selects SHA-1 provider. Allowed: CollisionDetection (default), HTTPS (use system HTTPS provider), OpenSSL / OpenSSL-Dynamic / OpenSSL-FIPS, CommonCrypto, Schannel, etc. (kept for backward compatibility). [1][2]

  • USE_SHA256 — selects SHA-256 provider. Allowed: HTTPS (default), builtin, OpenSSL / OpenSSL-Dynamic / OpenSSL-FIPS, CommonCrypto, Schannel, etc. (there is also an EXPERIMENTAL_SHA256 feature flag for enabling API-incompatible SHA256 support). [1][2]

  • USE_HTTP_PARSER — selects HTTP parser implementation. Allowed: builtin (default), http-parser (external), llhttp (external). [1][2]

  • REGEX_BACKEND — selects regular-expression backend. Allowed: regcomp_l, pcre2, pcre, regcomp, builtin. Default selection: regcomp_l where available, then PCRE if found, otherwise builtin. [1][3]

References:

  • libgit2 project README / CMake options. [1]
  • libgit2 CMakeLists / packaged bindings (examples showing cache strings and defaults). [2][3]

🌐 Web query:

libgit2 CMakeLists.txt USE_SHA1 Builtin case sensitive

💡 Result:

Short answer: The SHA1 backend name is chosen by the CMake option (older branches used SHA1_BACKEND as a CACHE STRING). The accepted backend identifiers (e.g. CollisionDetection, OpenSSL, Generic, Win32, CommonCrypto, mbedTLS) are specified in the CMake scripts and should be used exactly as shown — they are treated as literal strings (i.e. effectively case-sensitive). The libgit2 tree does not use a "builtin" SHA1 token (a past commit explicitly removed checks for SHA1_TYPE == "builtin"). [1][2]

Sources:

  • Current CMake options listing USE_SHA1 / backend lines in CMakeLists.txt. [1]
  • Commit/log note: "drop unset SHA1_TYPE — We never set SHA1_TYPE to builtin. Don't bother testing for it." [2]

🌐 Web query:

libgit2 USE_SHA256 builtin case sensitive CMakeLists

💡 Result:

Short answer: Yes — the USE_SHA256 value is matched case-sensitively in libgit2's CMake logic, so you must supply the exact string the CMake scripts check for.

Evidence:

  • libgit2's selection logic uses STREQUAL comparisons for USE_SHA256 (e.g. if(USE_SHA256 STREQUAL "HTTPS")), so comparisons are exact. (fossies.org)
  • CMake's STREQUAL/string comparisons are case‑sensitive. (manpages.debian.org)

Recommendation: pass the backend name exactly as the project expects (match the capitalization used in the repo's CMake files). If you want, tell me which value you tried and I’ll point to the exact string the current libgit2 CMake checks for.

Citations:


🌐 Web query:

libgit2 CMakeLists.txt USE_SHA1 CollisionDetection default

💡 Result:

Default: libgit2 selects the CollisionDetection (SHA1DC) provider for SHA-1 by default. The CMake option USE_SHA1 is exposed (string/option) and its default is CollisionDetection (often shown as ON / "CollisionDetection"). See libgit2's CMakeLists (defaults and description). [1][2]

To override: pass -DUSE_SHA1=CollisionDetection (explicit) or -DUSE_SHA1=HTTPS or -DUSE_SHA1=OFF (or another provider name) when running CMake. [1][2]

Sources:

  • libgit2 CMakeLists (backend/defaults). [1]
  • libgit2-sys (packaging) CMake description showing default = CollisionDetection. [2]

Fix libgit2 CMake SHA option names and capitalization.

USE_SHA1=Builtin is unsupported—libgit2 does not accept "Builtin" as a SHA1 backend option. Valid values are CollisionDetection (default), OpenSSL, Generic, Win32, CommonCrypto, or mbedTLS. This will be silently ignored and libgit2 will use its default (CollisionDetection).

Additionally, USE_SHA256=Builtin has incorrect capitalization. CMake option comparisons are case-sensitive; it should be USE_SHA256=builtin (lowercase). The current value will similarly be silently ignored, causing libgit2 to use its default SHA256 backend (HTTPS).

Either remove these options to accept libgit2's defaults, or correct the values as appropriate for your configuration.

🤖 Prompt for AI Agents
In `@cmake/targets/BuildLibgit2.cmake` around lines 1 - 23, The CMake invocation
sets invalid/incorrect SHA backend options: change or remove the USE_SHA1 and
USE_SHA256 entries in the register_cmake_command block so libgit2 receives valid
values; replace USE_SHA1=Builtin with a supported backend name (e.g.,
USE_SHA1=CollisionDetection or USE_SHA1=OpenSSL) or remove the line to use the
default, and correct USE_SHA256=Builtin to the proper lowercase/valid value
(e.g., USE_SHA256=builtin if that backend is intended or
USE_SHA256=CollisionDetection/OpenSSL/etc.), referencing the USE_SHA1 and
USE_SHA256 arguments in the diff.

Comment on lines +7 to +61
class Repository {
constructor(path?: string) // Finds git root from path, throws if not a repo

static find(startPath?: string): Repository | null // Non-throwing factory
static init(path: string, options?: { bare?: boolean; initialBranch?: string }):
Repository
static clone(url: string, targetPath: string, options?: CloneOptions): Repository

readonly path: string // Repo root (worktree root)
readonly gitDir: string // .git directory path
readonly isBare: boolean

// State
get head(): Commit
get branch(): Branch | null // null if detached HEAD
get isClean(): boolean
get isTransient(): boolean // merge/rebase/cherry-pick in progress

// References
getCommit(ref: string): Commit | null
getBranch(name: string): Branch | null
getRemote(name?: string): Remote | null // default: "origin"
getDefaultBranch(): Branch | null

// Collections
get branches(): BranchCollection
get remotes(): RemoteCollection
get worktrees(): WorktreeCollection
get stash(): StashCollection
get config(): Config

// Working tree
status(options?: StatusOptions): StatusEntry[]
diff(options?: DiffOptions): Diff

// Index operations
add(paths: string | string[]): void
reset(paths?: string | string[]): void // Unstage

// Commit
commit(message: string, options?: CommitOptions): Commit

// Checkout
checkout(ref: string | Branch | Commit, options?: CheckoutOptions): void

// Reset working tree
resetHard(ref?: string | Commit): void
clean(options?: CleanOptions): void

// Abort transient states
abortMerge(): void
abortRebase(): void
abortCherryPick(): void
abortRevert(): void
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Documentation does not match current implementation.

The API documented here (Remote, Worktree, Diff, Index, Config, Stash, Blob classes with extensive methods) appears to significantly exceed what's implemented in the PR. Based on the PR summary and AI-generated context, only Repository, Commit, Branch, and Signature classes are implemented in the native bindings.

Consider either:

  1. Marking unimplemented sections as "Planned" or "Future"
  2. Moving this to a separate design document
  3. Reducing documentation to match the current implementation scope

This avoids confusion about what's actually available in the bun:git module.

🤖 Prompt for AI Agents
In `@docs/git-api-reference.md` around lines 7 - 61, Update the git API docs to
match the actual implemented native bindings by removing or annotating
unimplemented types and methods (Remote, Worktree, Diff, Index, Config, Stash,
Blob, and their methods) and instead document only the classes and members that
exist (Repository, Commit, Branch, Signature and their actual methods/properties
such as
Repository.find/init/clone/path/gitDir/head/branch/status/commit/checkout/resetHard),
or clearly mark the rest as "Planned" or move them to a separate design doc;
ensure each documented symbol reflects the real runtime API so consumers of
bun:git aren’t misled.

6. Remote - url, fetch()
7. Worktree - Full worktree support
8. Stash - Stash operations
9. Config - Config get/set No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add trailing newline.

Files should end with a single newline character per markdown conventions (MD047).

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

513-513: Files should end with a single newline character

(MD047, single-trailing-newline)

🤖 Prompt for AI Agents
In `@docs/git-api-reference.md` at line 513, The file ends without a trailing
newline at the end of the "9. Config - Config get/set" section; add a single
newline character at the end of docs/git-api-reference.md (so the file ends with
exactly one trailing newline) to satisfy MD047.

Comment on lines +24 to +26
// Initialize libgit2 (call once at startup)
void initializeLibgit2();
void shutdownLibgit2();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for initializeLibgit2 and shutdownLibgit2 call sites
echo "=== initializeLibgit2 call sites ==="
rg -n 'initializeLibgit2\s*\(\)' --type cpp

echo ""
echo "=== shutdownLibgit2 call sites ==="
rg -n 'shutdownLibgit2\s*\(\)' --type cpp

echo ""
echo "=== Implementation of init/shutdown ==="
rg -nA10 'void (initializeLibgit2|shutdownLibgit2)\s*\(\)' --type cpp

echo ""
echo "=== Search in all file types (not just cpp) ==="
rg -n 'initializeLibgit2|shutdownLibgit2' --type-list | head -20

echo ""
rg -rn 'initializeLibgit2|shutdownLibgit2' src/

Repository: oven-sh/bun

Length of output: 3397


🏁 Script executed:

#!/bin/bash
# Search for shutdown/cleanup related code
echo "=== Search for atexit or shutdown handlers ==="
rg -n 'atexit|shutdown|cleanup|onShutdown' src/bun.js/bindings/ --type cpp --type h

echo ""
echo "=== Check context around shutdownLibgit2 definition ==="
rg -nB5 -A15 'void shutdownLibgit2\(\)' src/bun.js/bindings/

echo ""
echo "=== Check the file header/includes for shutdown patterns ==="
head -50 src/bun.js/bindings/JSGitRepository.cpp

echo ""
echo "=== Search for where git_libgit2_init is used ==="
rg -n 'git_libgit2_init|git_libgit2_shutdown' src/

Repository: oven-sh/bun

Length of output: 16389


Call shutdownLibgit2() during Bun shutdown to prevent resource leaks.

While initializeLibgit2() correctly uses std::call_once() to ensure git_libgit2_init() is called exactly once, shutdownLibgit2() is defined but never invoked. This leaves libgit2 resources unreleased on process exit. Register shutdownLibgit2() with the Bun exit handler (e.g., via atexit() or Bun__atexit()) to ensure git_libgit2_shutdown() is called during shutdown.

🤖 Prompt for AI Agents
In `@src/bun.js/bindings/JSGit.h` around lines 24 - 26, The shutdownLibgit2()
function is never registered to run at process exit, causing libgit2 resources
to leak; fix this by registering shutdownLibgit2() with Bun's exit handler
(e.g., call Bun__atexit(shutdownLibgit2) or atexit(shutdownLibgit2) during
initialization) so that git_libgit2_shutdown() is invoked on shutdown; add that
registration in the same initialization path where initializeLibgit2() (which
calls git_libgit2_init() via std::call_once) is invoked so the shutdown is
guaranteed to run on process exit.

Comment on lines +135 to +159
const git_oid* oid = git_reference_target(thisObject->ref());
if (!oid) {
// Symbolic reference, need to resolve
git_reference* resolved = nullptr;
int error = git_reference_resolve(&resolved, thisObject->ref());
if (error < 0) {
const git_error* err = git_error_last();
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(err ? err->message : "Failed to resolve branch")));
return {};
}
oid = git_reference_target(resolved);
git_reference_free(resolved);
}

git_commit* commit = nullptr;
int error = git_commit_lookup(&commit, thisObject->repository()->repo(), oid);
if (error < 0) {
const git_error* err = git_error_last();
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(err ? err->message : "Failed to get commit")));
return {};
}

auto* structure = globalObject->JSGitCommitStructure();
return JSValue::encode(JSGitCommit::create(vm, lexicalGlobalObject, structure, commit, thisObject->repository()));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Use-after-free risk when resolving symbolic references.

After git_reference_free(resolved) on line 146, the oid pointer obtained from git_reference_target(resolved) on line 145 may be invalid since it points to internal memory owned by the reference. The OID should be copied before freeing the reference.

🐛 Proposed fix
     if (!oid) {
         // Symbolic reference, need to resolve
         git_reference* resolved = nullptr;
         int error = git_reference_resolve(&resolved, thisObject->ref());
         if (error < 0) {
             const git_error* err = git_error_last();
             throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(err ? err->message : "Failed to resolve branch")));
             return {};
         }
-        oid = git_reference_target(resolved);
-        git_reference_free(resolved);
+        git_oid resolvedOid;
+        git_oid_cpy(&resolvedOid, git_reference_target(resolved));
+        git_reference_free(resolved);
+        
+        git_commit* commit = nullptr;
+        error = git_commit_lookup(&commit, thisObject->repository()->repo(), &resolvedOid);
+        if (error < 0) {
+            const git_error* err = git_error_last();
+            throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(err ? err->message : "Failed to get commit")));
+            return {};
+        }
+        
+        auto* structure = globalObject->JSGitCommitStructure();
+        return JSValue::encode(JSGitCommit::create(vm, lexicalGlobalObject, structure, commit, thisObject->repository()));
     }

Alternatively, restructure to keep the resolved reference alive until after git_commit_lookup.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const git_oid* oid = git_reference_target(thisObject->ref());
if (!oid) {
// Symbolic reference, need to resolve
git_reference* resolved = nullptr;
int error = git_reference_resolve(&resolved, thisObject->ref());
if (error < 0) {
const git_error* err = git_error_last();
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(err ? err->message : "Failed to resolve branch")));
return {};
}
oid = git_reference_target(resolved);
git_reference_free(resolved);
}
git_commit* commit = nullptr;
int error = git_commit_lookup(&commit, thisObject->repository()->repo(), oid);
if (error < 0) {
const git_error* err = git_error_last();
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(err ? err->message : "Failed to get commit")));
return {};
}
auto* structure = globalObject->JSGitCommitStructure();
return JSValue::encode(JSGitCommit::create(vm, lexicalGlobalObject, structure, commit, thisObject->repository()));
}
const git_oid* oid = git_reference_target(thisObject->ref());
if (!oid) {
// Symbolic reference, need to resolve
git_reference* resolved = nullptr;
int error = git_reference_resolve(&resolved, thisObject->ref());
if (error < 0) {
const git_error* err = git_error_last();
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(err ? err->message : "Failed to resolve branch")));
return {};
}
git_oid resolvedOid;
git_oid_cpy(&resolvedOid, git_reference_target(resolved));
git_reference_free(resolved);
git_commit* commit = nullptr;
int error = git_commit_lookup(&commit, thisObject->repository()->repo(), &resolvedOid);
if (error < 0) {
const git_error* err = git_error_last();
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(err ? err->message : "Failed to get commit")));
return {};
}
auto* structure = globalObject->JSGitCommitStructure();
return JSValue::encode(JSGitCommit::create(vm, lexicalGlobalObject, structure, commit, thisObject->repository()));
}
git_commit* commit = nullptr;
int error = git_commit_lookup(&commit, thisObject->repository()->repo(), oid);
if (error < 0) {
const git_error* err = git_error_last();
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(err ? err->message : "Failed to get commit")));
return {};
}
auto* structure = globalObject->JSGitCommitStructure();
return JSValue::encode(JSGitCommit::create(vm, lexicalGlobalObject, structure, commit, thisObject->repository()));
🤖 Prompt for AI Agents
In `@src/bun.js/bindings/JSGitBranch.cpp` around lines 135 - 159, The code calls
git_reference_target(resolved) to get an oid, then frees the resolved reference
(git_reference_free(resolved)) before passing that oid to git_commit_lookup,
which risks a use-after-free; fix by copying the oid contents into a local
git_oid (e.g. git_oid oid_copy = *git_reference_target(resolved)) immediately
after resolving and before freeing the reference, then pass &oid_copy to
git_commit_lookup (or alternatively keep the resolved reference alive until
after git_commit_lookup); update the block around git_reference_resolve,
git_reference_free, and git_commit_lookup in JSGitBranch.cpp so the oid used by
git_commit_lookup is a safe copy rather than a pointer into a freed reference.

Comment on lines +249 to +269
// Method: delete(force?)
JSC_DEFINE_HOST_FUNCTION(jsGitBranchProtoFunc_delete, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);

auto* thisObject = jsDynamicCast<JSGitBranch*>(callFrame->thisValue());
if (!thisObject) {
throwThisTypeError(*globalObject, scope, "Branch"_s, "delete"_s);
return {};
}

int error = git_branch_delete(thisObject->ref());
if (error < 0) {
const git_error* err = git_error_last();
throwException(globalObject, scope, createError(globalObject, WTF::String::fromUTF8(err ? err->message : "Failed to delete branch")));
return {};
}

return JSValue::encode(jsUndefined());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Branch object becomes unusable after delete.

After git_branch_delete succeeds, the underlying git_reference is freed by libgit2, but m_ref in the JSGitBranch object still points to freed memory. Subsequent property accesses would cause undefined behavior.

Consider setting m_ref = nullptr after deletion, and adding null checks in getters, or documenting that the branch object should not be used after deletion.

🔧 Suggested improvement
     int error = git_branch_delete(thisObject->ref());
     if (error < 0) {
         const git_error* err = git_error_last();
         throwException(globalObject, scope, createError(globalObject, WTF::String::fromUTF8(err ? err->message : "Failed to delete branch")));
         return {};
     }

+    // Invalidate the reference since it's been deleted
+    thisObject->m_ref = nullptr;
+
     return JSValue::encode(jsUndefined());

Note: This requires making m_ref accessible or adding an invalidate() method.

🤖 Prompt for AI Agents
In `@src/bun.js/bindings/JSGitBranch.cpp` around lines 249 - 269, The delete host
function jsGitBranchProtoFunc_delete frees the underlying libgit2 reference but
leaves the JSGitBranch instance's internal pointer (m_ref) dangling, causing
undefined behavior on later property access; modify JSGitBranch to provide
either a public invalidate() method or a setter to clear m_ref and call that
from jsGitBranchProtoFunc_delete after git_branch_delete succeeds (e.g.,
JSGitBranch::invalidate() which sets m_ref = nullptr), and add null checks in
JSGitBranch getters (or document immutability) to throw or return safely when
m_ref is null.

@@ -0,0 +1,551 @@
import * as git from "bun:git";
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { mkdir, mkdtemp, rm, stat, writeFile } from "fs/promises";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Use tempDir from harness instead of mkdtemp.

Per coding guidelines, tests should use tempDir from harness to create temporary directories instead of fs.mkdtempSync or mkdtemp.

♻️ Suggested import change
-import { mkdir, mkdtemp, rm, stat, writeFile } from "fs/promises";
+import { mkdir, rm, stat, writeFile } from "fs/promises";
+import { tempDir } from "harness";

Then replace mkdtemp(join(tmpdir(), "bun-git-test-")) patterns with tempDir().

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { mkdir, mkdtemp, rm, stat, writeFile } from "fs/promises";
import { mkdir, rm, stat, writeFile } from "fs/promises";
import { tempDir } from "harness";
🤖 Prompt for AI Agents
In `@test/js/bun/git/git.test.ts` at line 3, The test imports and calls mkdtemp
(from fs/promises); update the import to remove mkdtemp and instead import
tempDir from the test harness, then replace any mkdtemp(join(tmpdir(),
"bun-git-test-")) (or similar mkdtemp usage) with a call to tempDir() in the
test file (git.test.ts) so the test uses the harness-provided temporary
directory helper; ensure any uses of tmpdir()/join tied to mkdtemp are removed
and the new tempDir() return value is used where the temporary path was
previously used.

Comment on lines +483 to +489
test("signature has date property", () => {
const commit = repo.getCommit(repo.head.sha);
const sig = commit!.author;
expect(sig.date).toBeInstanceOf(Date);
expect(sig.date.getTime()).toBeLessThanOrEqual(Date.now());
expect(sig.date.getTime()).toBeGreaterThan(Date.now() - 60000); // Within last minute
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider widening the time window for CI stability.

The 60-second window for date validation may be tight on slow CI runners. Consider using a wider window (e.g., 5 minutes) to avoid flaky tests.

♻️ Suggested fix
     expect(sig.date.getTime()).toBeLessThanOrEqual(Date.now());
-    expect(sig.date.getTime()).toBeGreaterThan(Date.now() - 60000); // Within last minute
+    expect(sig.date.getTime()).toBeGreaterThan(Date.now() - 300000); // Within last 5 minutes
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test("signature has date property", () => {
const commit = repo.getCommit(repo.head.sha);
const sig = commit!.author;
expect(sig.date).toBeInstanceOf(Date);
expect(sig.date.getTime()).toBeLessThanOrEqual(Date.now());
expect(sig.date.getTime()).toBeGreaterThan(Date.now() - 60000); // Within last minute
});
test("signature has date property", () => {
const commit = repo.getCommit(repo.head.sha);
const sig = commit!.author;
expect(sig.date).toBeInstanceOf(Date);
expect(sig.date.getTime()).toBeLessThanOrEqual(Date.now());
expect(sig.date.getTime()).toBeGreaterThan(Date.now() - 300000); // Within last 5 minutes
});
🤖 Prompt for AI Agents
In `@test/js/bun/git/git.test.ts` around lines 483 - 489, The time window in the
"signature has date property" test is too tight (60s) and can cause CI flakes;
update the assertion that checks sig.date.getTime() to allow a wider window
(e.g., 5 minutes / 300000 ms) so the test asserts sig.date.getTime() is
greaterThan(Date.now() - 300000) instead of 60000; keep the other checks
(instanceOf Date and <= Date.now()) and change only the lower-bound comparison
in the test that uses repo.getCommit(repo.head.sha) and sig.author.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants