Skip to content

cargo publish produces "X files in the working directory contain changes that were not yet committed into git" for .gitignored files #16547

@Byron

Description

@Byron

Problem

I see this regularly when publishing gitoxide crates and thought this was fixed with the switch to gitoxide, using cargo 1.92.0 (344c456 2025-10-21).

error: 4 files in the working directory contain changes that were not yet committed into git:

gix-dir/tests/fixtures/generated-do-not-edit/many/613585535-unix/slash-in-root-and-negated/.github/workflow.yml
gix-dir/tests/fixtures/generated-do-not-edit/many/613585535-unix/slash-in-subdir-and-negated/sub/.github/workflow.yml
gix-dir/tests/fixtures/generated-do-not-edit/many/613585535-unix/star-in-root-and-negated/.github/workflow.yml
gix-dir/tests/fixtures/generated-do-not-edit/many/613585535-unix/star-in-subdir-and-negated/sub/.github/workflow.yml

The commit that introduces gix into the cargo publish is old enough to be included.
Then again, the src_files seem to depend on the ignore crate via this commit.

This might be the culprit.

let mut exclude_builder = GitignoreBuilder::new(root);

Is there interest in having this gitoxide'ified?

Reproduction

The reproduction based on Byron#3 (comment) .

#[cargo_test]
fn gitignored_nested_repo_not_treated_as_uncommitted() {
    // Test for issue rust-lang/cargo#16547
    // https://github.com/rust-lang/cargo/issues/16547
    //
    // When a nested git repository is .gitignored, files within it should NOT be
    // treated as uncommitted changes by `cargo publish`.
    //
    // This test verifies that the issue is fixed. If the bug were present, cargo publish
    // would fail with an error like:
    //   "ERROR: 1 files in the working directory contain changes that were not yet committed into git:
    //    tests/fixtures/nested-repo/.github/workflow.yml"
    //
    // With the fix, cargo publish correctly ignores the nested repository and proceeds
    // without errors.

    // Use local registry for faster test times
    let registry = registry::init();

    let p = project().no_manifest().build();

    // Create main repository with a cargo project
    let main_repo = repo(&paths::root().join("foo"))
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                version = "0.0.1"
                edition = "2015"
                authors = []
                license = "MIT"
                description = "foo"
                documentation = "foo"
                homepage = "foo"
                repository = "foo"
            "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(".gitignore", "**/generated-do-not-edit/")
        .build();

    // Create a nested git repository in tests/fixtures/ that is gitignored
    // This simulates test fixtures that are git repositories (like gix-dir test fixtures)
    let repo_base = main_repo.root().join(
        "tests/fixtures/generated-to-not-edit/many/613585535-unix/slash-in-root-and-negated/",
    );
    fs::create_dir_all(&repo_base).unwrap();
    let nested_repo = git::init(&repo_base);

    // Add files to the nested repository (similar to the .github/workflow.yml in the issue)
    let content_dir = repo_base.join(".github");
    fs::create_dir_all(&content_dir).unwrap();
    fs::write(content_dir.join("workflow.yml"), "# workflow file").unwrap();

    // Commit the file in the nested repository
    git::add(&nested_repo);
    git::commit(&nested_repo);

    fs::write(
        content_dir.join("untracked-in-hidden-dir"),
        "not needed for reproduction, but good to see that it picks up everything apparently",
    )
    .unwrap();

    fs::write(
        repo_base.join("untracked-in-root"),
        "not needed for reproduction, but good to see that it picks up everything apparently",
    )
    .unwrap();

    // Try to publish - this should succeed without errors about uncommitted files.
    // If the bug from issue #16547 were present, this would fail with an error about
    // uncommitted changes in the nested repository.
    p.cargo("publish --no-verify --dry-run")
        .replace_crates_io(registry.index_url())
        .with_stderr_data(str![[r#"
TODO: fill in the actual
...
"#]])
        .run();
}

This fails with exit code 101:

test failed running `/Users/byron/dev/github.com/rust-lang/cargo/target/debug/cargo publish --no-verify --dry-run`
error: process exited with code 101 (expected 0)
--- stdout

--- stderr
    Updating crates.io index
error: 3 files in the working directory contain changes that were not yet committed into git:

tests/fixtures/generated-to-not-edit/many/613585535-unix/slash-in-root-and-negated/.github/untracked-in-hidden-dir
tests/fixtures/generated-to-not-edit/many/613585535-unix/slash-in-root-and-negated/.github/workflow.yml
tests/fixtures/generated-to-not-edit/many/613585535-unix/slash-in-root-and-negated/untracked-in-root

to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag

Possible Solution(s)

Switch to gitoxide for ignore-dir detection. In theory, gix-dir should be very suitable for that as it is made to traverse directories just like Git would.

Notes

CC @weihanglo

Version


Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: bugS-triageStatus: This issue is waiting on initial triage.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions