codex
codex copied to clipboard
Ghost snapshot warns about ignored directories
What version of Codex is running?
0.63
What subscription do you have?
ChatGPT
Which model were you using?
No response
What platform is your computer?
No response
What issue are you seeing?
As me and many others have found (see #7369 #7313 #7067), we are getting "Repository snapshot encountered large untracked directories" despite the directories correctly listed in .gitignore. I had Codex work on it to provide you with additional context.
Summary
- Large untracked warnings were firing for directories already listed in
.gitignore(e.g.,logs/,tmp/). - Fixed the warning pre-scan to exclude ignored paths while keeping ignored paths for snapshot/restore bookkeeping.
- Added a regression test to ensure ignored large directories no longer trigger the warning.
Files touched
codex-rs/utils/git/src/ghost_commits.rs
Details
- Pre-warning scan now calls
capture_existing_untracked(..., include_ignored = false), so git-ignored dirs are omitted from the “large untracked” check. - Snapshot creation and restore still run with
include_ignored = trueto preserve/remove ignored files correctly. - New test
ignored_large_directories_do_not_trigger_warningverifies ignored dirs don’t raise the warning.
Why it matters
- Users saw “Repository snapshot encountered large untracked directories” even when the dirs were already ignored; this was noisy and confusing. The warning now aligns with
.gitignore.
diff --git a/codex-rs/utils/git/src/ghost_commits.rs b/codex-rs/utils/git/src/ghost_commits.rs
index 01987bb5e..145843e18 100644
--- a/codex-rs/utils/git/src/ghost_commits.rs
+++ b/codex-rs/utils/git/src/ghost_commits.rs
@@ -146,7 +146,7 @@ pub fn capture_ghost_snapshot_report(
let repo_root = resolve_repository_root(options.repo_path)?;
let repo_prefix = repo_subdir(repo_root.as_path(), options.repo_path);
let existing_untracked =
- capture_existing_untracked(repo_root.as_path(), repo_prefix.as_deref())?;
+ capture_existing_untracked(repo_root.as_path(), repo_prefix.as_deref(), false)?;
let warning_files = existing_untracked
.files
@@ -174,7 +174,7 @@ pub fn create_ghost_commit_with_report(
let repo_prefix = repo_subdir(repo_root.as_path(), options.repo_path);
let parent = resolve_head(repo_root.as_path())?;
let existing_untracked =
- capture_existing_untracked(repo_root.as_path(), repo_prefix.as_deref())?;
+ capture_existing_untracked(repo_root.as_path(), repo_prefix.as_deref(), true)?;
let warning_files = existing_untracked
.files
@@ -277,7 +277,7 @@ pub fn restore_ghost_commit(repo_path: &Path, commit: &GhostCommit) -> Result<()
let repo_root = resolve_repository_root(repo_path)?;
let repo_prefix = repo_subdir(repo_root.as_path(), repo_path);
let current_untracked =
- capture_existing_untracked(repo_root.as_path(), repo_prefix.as_deref())?;
+ capture_existing_untracked(repo_root.as_path(), repo_prefix.as_deref(), true)?;
restore_to_commit_inner(repo_root.as_path(), repo_prefix.as_deref(), commit.id())?;
remove_new_untracked(
repo_root.as_path(),
@@ -327,21 +327,28 @@ struct UntrackedSnapshot {
dirs: Vec<PathBuf>,
}
-/// Captures the untracked and ignored entries under `repo_root`, optionally limited by `repo_prefix`.
-/// Returns the result as an `UntrackedSnapshot`.
+/// Captures the untracked entries under `repo_root`, optionally limited by `repo_prefix`.
+/// When `include_ignored` is true, ignored paths are included as well. Returns the result as an
+/// `UntrackedSnapshot`.
fn capture_existing_untracked(
repo_root: &Path,
repo_prefix: Option<&Path>,
+ include_ignored: bool,
) -> Result<UntrackedSnapshot, GitToolingError> {
// Ask git for the zero-delimited porcelain status so we can enumerate
- // every untracked or ignored path (including ones filtered by prefix).
+ // every untracked path, optionally including ignored entries (including ones filtered by
+ // prefix).
let mut args = vec![
OsString::from("status"),
OsString::from("--porcelain=2"),
OsString::from("-z"),
- OsString::from("--ignored=matching"),
OsString::from("--untracked-files=all"),
];
+ if include_ignored {
+ args.push(OsString::from("--ignored=matching"));
+ } else {
+ args.push(OsString::from("--ignored=no"));
+ }
if let Some(prefix) = repo_prefix {
args.push(OsString::from("--"));
args.push(prefix.as_os_str().to_os_string());
@@ -621,6 +628,26 @@ mod tests {
Ok(())
}
+ #[test]
+ fn ignored_large_directories_do_not_trigger_warning() -> Result<(), GitToolingError> {
+ let temp = tempfile::tempdir()?;
+ let repo = temp.path();
+ init_test_repo(repo);
+
+ std::fs::write(repo.join(".gitignore"), "logs/\n")?;
+ let logs = repo.join("logs");
+ std::fs::create_dir_all(&logs)?;
+ for idx in 0..=LARGE_UNTRACKED_WARNING_THRESHOLD {
+ let file = logs.join(format!("file-{idx}.txt"));
+ std::fs::write(file, "ignored data\n")?;
+ }
+
+ let report = capture_ghost_snapshot_report(&CreateGhostCommitOptions::new(repo))?;
+ assert!(report.large_untracked_dirs.is_empty());
+
+ Ok(())
+ }
+
#[test]
fn create_snapshot_reports_nested_large_untracked_dirs_under_tracked_parent()
-> Result<(), GitToolingError> {
What steps can reproduce the bug?
Have a folder with lots of files in .gitignore, start codex, still get warning.
What is the expected behavior?
No response
Additional information
No response
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
- #7369
- #7313
- #7133
- #7067
- #6977
Powered by Codex Action