agent: Clean up git exclusions after emergency (#38775)

In some rare cases, the auto-generated block gets stuck in
`.git/info/exclude`. We now auto-clean it.

Closes #38374

Release Notes:

- Remove auto-generated block from git excludes if it gets stuck there.
This commit is contained in:
Oleksiy Syvokon
2025-09-24 13:58:39 +03:00
committed by GitHub
parent 5612a961b0
commit c5219e8fd2

View File

@@ -242,8 +242,20 @@ pub struct GitExcludeOverride {
}
impl GitExcludeOverride {
const START_BLOCK_MARKER: &str = "\n\n# ====== Auto-added by Zed: =======\n";
const END_BLOCK_MARKER: &str = "\n# ====== End of auto-added by Zed =======\n";
pub async fn new(git_exclude_path: PathBuf) -> Result<Self> {
let original_excludes = smol::fs::read_to_string(&git_exclude_path).await.ok();
let original_excludes =
smol::fs::read_to_string(&git_exclude_path)
.await
.ok()
.map(|content| {
// Auto-generated lines are normally cleaned up in
// `restore_original()` or `drop()`, but may stuck in rare cases.
// Make sure to remove them.
Self::remove_auto_generated_block(&content)
});
Ok(GitExcludeOverride {
git_exclude_path,
@@ -260,9 +272,10 @@ impl GitExcludeOverride {
});
let mut content = self.original_excludes.clone().unwrap_or_default();
content.push_str("\n\n# ====== Auto-added by Zed: =======\n");
content.push_str(Self::START_BLOCK_MARKER);
content.push_str(self.added_excludes.as_ref().unwrap());
content.push('\n');
content.push_str(Self::END_BLOCK_MARKER);
smol::fs::write(&self.git_exclude_path, content).await?;
Ok(())
@@ -279,6 +292,33 @@ impl GitExcludeOverride {
Ok(())
}
fn remove_auto_generated_block(content: &str) -> String {
let start_marker = Self::START_BLOCK_MARKER;
let end_marker = Self::END_BLOCK_MARKER;
let mut content = content.to_string();
let start_index = content.find(start_marker);
let end_index = content.rfind(end_marker);
if let (Some(start), Some(end)) = (start_index, end_index) {
if end > start {
content.replace_range(start..end + end_marker.len(), "");
}
}
// Older versions of Zed didn't have end-of-block markers,
// so it's impossible to determine auto-generated lines.
// Conservatively remove the standard list of excludes
let standard_excludes = format!(
"{}{}",
Self::START_BLOCK_MARKER,
include_str!("./checkpoint.gitignore")
);
content = content.replace(&standard_excludes, "");
content
}
}
impl Drop for GitExcludeOverride {