···372372/// Reads the last seen state of git refs from a file, updates it with the
373373/// provided function, and writes the result back to disk.
374374///
375375+/// This cannot be done concurrently, and is thus done under a lock.
376376+///
375377/// The state currently tracks only the local branches.
376378fn with_last_seen_refs<Ret, Err, Err2: From<GitRefViewError> + From<Err>>(
377379 repo_path: PathBuf,
378380 f: impl FnOnce(&GitRefView) -> Result<(GitRefView, Ret), Err>,
379381) -> Result<Ret, Err2> {
380380- // Short-term TODO 1: Modification of this file, as well as the git refs in the
381381- // git storage, should be protected by a lock.
382382+ // TODO 1: It might be better to lock using a libgit2 lock or a git-native lock,
383383+ // if feasible.
384384+ //
385385+ // See also https://github.com/git/git/blob/f285f68a/lockfile.h.
382386 //
383387 // TODO 2: Conceptually, this state should contain all the information in the
384388 // repo that's not stored by git and should not be affected by `jj undo`. In
···390394 // View object. This would allow us to treat the state exported to the git repo
391395 // similar to any other remote and unify `jj git push` and `jj git export` to a
392396 // large degree.
397397+ let lock = crate::lock::FileLock::lock(repo_path.join("git_refs.lock"));
393398 let last_seen_refs_path = repo_path.join("git_last_seen_refs");
394399 let old_view = GitRefView::read_view_from_file(last_seen_refs_path.clone())
395400 // TODO: Do different things on errors other than "not found"?
···397402 .unwrap_or(GitRefView::default());
398403 let (new_view, ret) = f(&old_view)?;
399404 new_view.write_view_to_file(last_seen_refs_path)?;
405405+ // TODO: Create a test that checks the lock lives long enough. I don't know if
406406+ // removing the following line would break such a test.
407407+ drop(lock);
400408 Ok(ret)
401409}
402410