{"record":{"id":"da541762bc2bca5a","repo":"GitoxideLabs/gitoxide","slug":"an-empty-commit-needs-a-title","errorCode":null,"errorMessage":"an empty commit needs a title","messagePattern":"an empty commit needs a title","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/todo.rs","lineNumber":988,"sourceCode":"                } else {\n                    (resolve_commit(repo, value)?, false)\n                };\n                if !scope.contains(&id) {\n                    anyhow::bail!(\"a pick is outside the editable history\");\n                }\n                if picked.contains_key(&id) {\n                    anyhow::bail!(\"a commit is picked more than once\");\n                }\n                if resolved {\n                    rebase::PlanCommit::Resolved(id)\n                } else {\n                    rebase::PlanCommit::Pick(id)\n                }\n            }\n            \"empty\" => {\n                let title = if value.trim().is_empty() { tail } else { value.trim() };\n                if title.is_empty() {\n                    anyhow::bail!(\"an empty commit needs a title\");\n                }\n                rebase::PlanCommit::Empty(BString::from(title))\n            }\n            _ => anyhow::bail!(\"unsupported rebase todo command {verb:?}\"),\n        };\n        let index = steps.len();\n        if let rebase::PlanCommit::Pick(id) | rebase::PlanCommit::Resolved(id) = commit {\n            picked.insert(id, index);\n        }\n        steps.push(rebase::PlanStep {\n            parent,\n            commit,\n            squash: Vec::new(),\n        });\n        cursor = Some(rebase::PlanParent::Step(index));\n        section_last_step = Some(index);\n        if marked {\n            let target = rebase::PlanParent::Step(index);","sourceCodeStart":970,"sourceCodeEnd":1006,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/todo.rs#L970-L1006","documentation":"Thrown when an `empty` todo command yields no title. An `empty` step creates a commit without changes, which still requires a commit message; the title is taken from the command's value or falls back to the previous line's `tail`, and both being empty is invalid.","triggerScenarios":"`parse_plan` reads `empty` (or `empty ` with only whitespace) on a line where the fallback `tail` is also empty.","commonSituations":"Writing a bare `empty` line in a todo intending a placeholder commit; scripted generation that forgets to include a title; trimming that stripped the intended message.","solutions":["Provide a title after the `empty` command, e.g. `empty WIP checkpoint`","Ensure the preceding line provides a usable `tail` if relying on the fallback","Remove the `empty` line if no empty commit is needed"],"exampleFix":"// before\nempty\n// after\nempty add TODO notes","handlingStrategy":"validation","validationCode":"for line in todo.lines() {\n    if let Some(verb) = line.split_whitespace().next() {\n        if verb == \"empty\" {\n            let title = line[\"empty\".len()..].trim();\n            if title.is_empty() { anyhow::bail!(\"empty commit needs a title\"); }\n        }\n    }\n}","typeGuard":"fn empty_line_has_title(line: &str) -> bool {\n    !line.strip_prefix(\"empty\").map_or(false, str::trim)\n        .map_or(true, str::is_empty) || line.split_whitespace().count() > 1\n}","tryCatchPattern":"match parse_plan(...) {\n    Err(e) if e.to_string().contains(\"needs a title\") => { /* supply a title for the empty line */ }\n    other => other?,\n}","preventionTips":["Always write `empty <title>` with a non-empty title","Do not rely on the tail fallback unless the previous line provides one","Validate todo lines for a non-empty title before parsing"],"tags":["git","rebase","empty-commit","validation"],"backgroundTag":"empty-required-field","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}