diff --git a/src/terminal/git_data.rs b/src/terminal/git_data.rs index 42e4c25c..f69da8ab 100644 --- a/src/terminal/git_data.rs +++ b/src/terminal/git_data.rs @@ -885,7 +885,11 @@ impl Tty7App { return None; } let open = code.active_file()?; - let host = self.spawn_host(cx); + // The file's host, not the window's. They are the same for everything + // the tree can open, but a buffer read over SFTP carries a path from + // another machine, and pairing it with this one's host would resolve + // it against a local repository that merely shares the path. + let host = open.host.id(); let root = cx .try_global::()? .repo_root_for(host, open.path.parent()?)?; diff --git a/src/ui/code_editor.rs b/src/ui/code_editor.rs index dcd8ca78..150b49b4 100644 --- a/src/ui/code_editor.rs +++ b/src/ui/code_editor.rs @@ -294,8 +294,14 @@ impl Tty7App { fn editor_rebuild_watcher(&mut self, cx: &mut Context) { // Only files on the host the watch itself runs on. A path from // another machine — an SFTP file, say — does not exist under that - // watcher's feet, and hosts without watching (SFTP again) fall back - // to the save-time conflict check instead. + // watcher's feet, and would either miss or, worse, match a local file + // that happens to share its name. + // + // A host that cannot watch therefore gets no external-change + // detection at all: an SFTP buffer will not notice the file changing + // underneath it, and saving overwrites whatever is there. Catching + // that at save time needs a "keep mine" that survives to the next + // save, which the conflict banner does not have yet. let watch_host = self.spawn_host(cx); let files: HashSet = self .tabs