Skip to content

bug: sl amend invalidates git index in .git mode, causing first sl status to be 10-15x slower than subsequent onesΒ #1316

@AkshatRaj00

Description

@AkshatRaj00

πŸ› Bug Report

Sapling version: 0.2.20250521-115337-25ed6ac4
Mode: .git (existing git repo, no .sl directory)
OS: macOS (Apple Silicon / ARM64) β€” also reproducible on Linux


Summary

After running sl amend in .git mode on a large repository, the first subsequent sl status (or git status) takes 10-15x longer than normal. All following sl status calls are fast. The root cause is that sl amend writes the working directory tree in a way that invalidates git's mtime-based index cache, forcing a full index refresh on the next status check.

This is a significant daily-driver pain point for teams using Sapling as a drop-in Git client on large monorepos.


Steps to Reproduce

# Clone a large repo (linux kernel used as benchmark)
git clone https://github.com/torvalds/linux
cd linux

# Create a test commit
touch test.txt
sl add test.txt
sl commit -m "test"

# Benchmark: amend + status with git native
time git commit --amend -m 'test' && time git status
# Result: ~0.4s amend, ~0.4s status

# Benchmark: amend + status with sapling
time sl amend && time sl status
# Result: ~2.7s amend, ~14s status (!)

The slow sl status call internally spawns:

git --git-dir=.../.git status --porcelain=1 --ignore-submodules=dirty --untracked-files=all --no-renames -z --ignored=no

...and this triggers a full Refresh index: 100% (90498/90498) pass.

Second sl status call immediately after: ~0.5s. Normal.


Root Cause Analysis

Git's index uses file mtime + inode to detect changes without reading file content. When the index is valid, git status is O(index entries). When the index is invalidated, git must do a full stat pass over the working tree β€” O(all files).

git commit --amend preserves the index validity because it only changes the commit object and ref pointer, leaving the working tree and index untouched.

sl amend appears to rewrite the working directory or touch index metadata in a way that invalidates git's cached mtimes, causing the next git status to rebuild the index from scratch. This likely happens because Sapling's internal amend path writes through its own abstraction layer without preserving the git index state.


Comparison

Operation Amend time First status Second status
git commit --amend ~0.4s ~0.4s βœ… ~0.4s
sl amend ~2.7s ~14s ❌ ~0.5s

Impact

This affects every developer using Sapling in .git mode on a large repository. After any sl amend (one of the most frequent operations in a Sapling workflow), the next status check β€” whether from the CLI or from ISL β€” blocks for 10-15 seconds. On a team using ISL, this manifests as ISL appearing to hang after every amend.

See also the related issue #1186 (.git mode constantly refreshing index) which describes a similar symptom from the ISL side.


Possible Fix Direction

After sl amend rewrites the commit in .git mode, Sapling should run the equivalent of:

git update-index --refresh

...or otherwise ensure the index mtimes are brought in sync with the new working tree state before handing control back. This is what git commit --amend does implicitly through its normal index update path.

Alternatively, the .git mode bridge could avoid touching the working directory altogether during an amend that only changes the commit message (i.e., sl amend -m ... with no file changes).


Environment

  • Sapling: 0.2.20250521-115337-25ed6ac4
  • Git: 2.50.1
  • macOS: 24.6.0 Darwin Kernel (ARM64 T6041)
  • Repo tested: torvalds/linux (~90,000 index entries)

Related: #1186, #1117

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions