Merge branch 'fix/git-since-live-sync'

This commit is contained in:
2026-02-13 18:13:42 +01:00
2 changed files with 70 additions and 8 deletions

View File

@@ -41,14 +41,41 @@ function reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualIn
invariant("Cannot reify an instance not present in virtualInstances\nID: {}", id) invariant("Cannot reify an instance not present in virtualInstances\nID: {}", id)
end end
-- Instance.new can fail if we're passing in something that can't be -- Before creating a new instance, check if the parent already has an
-- created, like a service, something enabled with a feature flag, or -- untracked child with the same Name and ClassName. This enables "late
-- something that requires higher security than we have. -- adoption" of instances that exist in Studio but weren't in the initial
local createSuccess, instance = pcall(Instance.new, virtualInstance.ClassName) -- Rojo tree (e.g., when using --git-since filtering). Without this,
-- newly acknowledged files would create duplicate instances.
local adoptedExisting = false
local instance = nil
if not createSuccess then for _, child in ipairs(parentInstance:GetChildren()) do
addAllToPatch(unappliedPatch, virtualInstances, id) local accessSuccess, name, className = pcall(function()
return return child.Name, child.ClassName
end)
if accessSuccess
and name == virtualInstance.Name
and className == virtualInstance.ClassName
and instanceMap.fromInstances[child] == nil
then
instance = child
adoptedExisting = true
break
end
end
if not adoptedExisting then
-- Instance.new can fail if we're passing in something that can't be
-- created, like a service, something enabled with a feature flag, or
-- something that requires higher security than we have.
local createSuccess
createSuccess, instance = pcall(Instance.new, virtualInstance.ClassName)
if not createSuccess then
addAllToPatch(unappliedPatch, virtualInstances, id)
return
end
end end
-- TODO: Can this fail? Previous versions of Rojo guarded against this, but -- TODO: Can this fail? Previous versions of Rojo guarded against this, but
@@ -96,7 +123,9 @@ function reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualIn
reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, childId, instance) reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, childId, instance)
end end
instance.Parent = parentInstance if not adoptedExisting then
instance.Parent = parentInstance
end
instanceMap:insert(id, instance) instanceMap:insert(id, instance)
end end

View File

@@ -83,6 +83,19 @@ pub fn snapshot_project(
// file being updated. // file being updated.
snapshot.metadata.relevant_paths.push(path.to_path_buf()); snapshot.metadata.relevant_paths.push(path.to_path_buf());
// When git filter is active, also register the project folder as a
// relevant path. This serves as a catch-all so that file changes
// not under any specific $path node can still walk up the directory
// tree and trigger a re-snapshot of the entire project.
if context.has_git_filter() {
if let Some(folder) = path.parent() {
let normalized = vfs
.canonicalize(folder)
.unwrap_or_else(|_| folder.to_path_buf());
snapshot.metadata.relevant_paths.push(normalized);
}
}
Ok(Some(snapshot)) Ok(Some(snapshot))
} }
None => Ok(None), None => Ok(None),
@@ -137,6 +150,26 @@ pub fn snapshot_project_node(
// Take the snapshot's metadata as-is, which will be mutated later // Take the snapshot's metadata as-is, which will be mutated later
// on. // on.
metadata = snapshot.metadata; metadata = snapshot.metadata;
} else if context.has_git_filter() {
// When the git filter is active and the $path was filtered out
// (no acknowledged files yet), we still need to register the path
// in relevant_paths. This allows the change processor to map file
// changes in this directory back to this project node instance,
// triggering a re-snapshot that will pick up newly modified files.
let normalized = vfs
.canonicalize(full_path.as_ref())
.unwrap_or_else(|_| full_path.to_path_buf());
metadata.relevant_paths.push(normalized);
// The VFS only sets up file watches via read() and read_dir(),
// not via metadata(). Since the git filter caused snapshot_from_vfs
// to return early (before read_dir was called), the VFS is not
// watching this path. We must read the directory here to ensure
// the VFS sets up a recursive watch, otherwise file change events
// will never fire and live sync won't detect modifications.
if full_path.is_dir() {
let _ = vfs.read_dir(&full_path);
}
} }
} }