Skip to content

Cache git repository info to avoid repeated subprocess calls #32

@zhisme

Description

@zhisme

Problem

When using {remote_url} in format strings, the plugin makes 4 separate subprocess calls on every copy operation:

  1. git rev-parse --is-inside-work-tree - check if git repo
  2. git remote -v - get remote URL
  3. git rev-parse HEAD - get current commit SHA
  4. git ls-files --full-name <file> - get repo-relative path

Subprocess spawning is expensive (~10-50ms each depending on system), resulting in 40-200ms of overhead per copy when using remote URLs.

Location: lua/copy_with_context/git.lua - get_git_info() function

Proposed Solution

Implement a caching layer with appropriate invalidation triggers.

What Can Be Cached

Data Cacheable? Invalidation Trigger
is_git_repo Yes CWD change
remote_url Yes Almost never changes
parsed_remote (provider/owner/repo) Yes Same as above
current_commit Tricky Git operations (commit, pull, checkout)
file_git_path Per-buffer Buffer changes / new file

Implementation Approach

1. Repository-level cache (clear on DirChanged)

local repo_cache = {
  is_git_repo = nil,       -- bool
  remote_url = nil,        -- string
  parsed_remote = nil,     -- {provider, owner, repo}
  commit_sha = nil,        -- string (with staleness caveat)
}

2. Buffer-level cache (clear on BufEnter/BufFilePost)

local buffer_cache = {}  -- bufnr -> {git_path = "..."}

3. Autocmds for cache invalidation

vim.api.nvim_create_autocmd("DirChanged", {
  callback = function()
    -- Clear repo cache
  end
})

vim.api.nvim_create_autocmd("BufEnter", {
  callback = function()
    -- Clear/populate buffer cache entry lazily
  end
})

Commit SHA Staleness

The commit SHA is tricky because it changes on git operations. Two options:

Option A (Simple): Cache at startup/DirChanged, accept staleness

  • Pro: Fast, simple
  • Con: URL might point to wrong commit after committing

Option B (Smarter): Watch .git/HEAD with vim.loop.fs_event or invalidate on ShellCmdPost for git commands

Recommendation: Start with Option A and add a manual refresh command (:CopyWithContextRefresh) for users who need accurate commit refs.

Acceptance Criteria

  • Repository info (remote URL, parsed provider) cached per working directory
  • Buffer-level git paths cached per buffer
  • Cache invalidated on DirChanged autocmd
  • Optional: Manual refresh command for commit SHA
  • No regression in existing functionality
  • Tests for cache invalidation scenarios

Notes

  • Non-git operations (vim.fn.expand("%"), line extraction) are already fast and don't need caching
  • This optimization primarily benefits users who use {remote_url} in their formats
  • Consider whether the complexity is worth it based on actual user feedback

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions