agent: Clean up git exclusions after emergency (#38775)
Oleksiy Syvokon
created 1 month ago
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.
Change summary
crates/git/src/repository.rs | 46 +++++++++++++++++++++++++++++++++++--
1 file changed, 43 insertions(+), 3 deletions(-)
Detailed changes
@@ -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 {