Skip to content

libgit2 1.9.4: git_stash_apply doesn't update the working directory (breaks SwiftGit stash apply/pop/branch) #1

Description

@odrobnik

Summary

When SwiftPorts' SwiftGit is built against GitKit (libgit2 1.9.4), its
git stash apply / pop / branch operations no longer restore the stashed
change to the working tree. The exact same SwiftGit code passes against the
odrobnik/libgit2 fork SwiftPorts used previously. This blocked SwiftPorts'
adoption of GitKit and was decoupled in Cocoanetics/SwiftPorts#59 (reverted to
the fork to keep stash working).

Repro (SwiftGit GitClientStashTests)

  1. git init, commit file.txt = v1.
  2. Write file.txt = v2 (working-tree change).
  3. git_stash_save → working tree correctly reverts to v1. ✅
  4. git_stash_apply(index: 0) → working tree should become v2, but stays v1. ❌

save / list / drop / show / clear all pass; only the operations that
go through git_stash_apply (apply / pop / branch) fail. So git_stash_apply
computes the merge but never writes the working directory.

What I ruled out

  • Explicitly setting apply_opts.checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE before git_stash_apply is a no-op — the tests still
    fail with it set.
  • In src/libgit2/stash.c, normalize_apply_options() only ORs in
    GIT_CHECKOUT_NO_REFRESH; it does not default the strategy to SAFE
    (unlike what some older versions did). The apply path then
    git_checkout_index(modified_index, …) with that strategy.

Hypothesis (needs confirmation)

After the merge yields modified_index, GIT_CHECKOUT_SAFE skips writing the
file because the working-tree copy looks "modified" relative to the post-merge
index baseline — so nothing is written. The fix is likely an explicit checkout
baseline (HEAD tree) for the stash-apply checkout, or this is a genuine
libgit2 1.9.x change worth an upstream report. GIT_CHECKOUT_FORCE makes the
test pass but can clobber unrelated uncommitted changes, so it's not a safe fix.

Impact / next step

Re-adopting GitKit in SwiftPorts needs either a SwiftGit stashApply fix that
works under libgit2 1.9.4, or confirmation + an upstream libgit2 fix. Until
then SwiftPorts stays on the fork.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions