{"record":{"id":"30fab49f0fd19841","repo":"GitoxideLabs/gitoxide","slug":"a-reference-named-name-has-multiple-edits","errorCode":null,"errorMessage":"A reference named '{name}' has multiple edits","messagePattern":"A reference named '(.+?)' has multiple edits","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-ref/src/transaction/ext.rs","lineNumber":35,"sourceCode":"    ///\n    /// Note no action is performed if deref isn't specified.\n    fn extend_with_splits_of_symbolic_refs(\n        &mut self,\n        find: &mut dyn FnMut(&PartialNameRef) -> Option<Target>,\n        make_entry: &mut dyn FnMut(usize, RefEdit) -> T,\n    ) -> Result<(), std::io::Error>;\n\n    /// All processing steps in one and in the correct order.\n    ///\n    /// Users call this to assure derefs are honored and duplicate checks are done.\n    fn pre_process(\n        &mut self,\n        find: &mut dyn FnMut(&PartialNameRef) -> Option<Target>,\n        make_entry: &mut dyn FnMut(usize, RefEdit) -> T,\n    ) -> Result<(), std::io::Error> {\n        self.extend_with_splits_of_symbolic_refs(find, make_entry)?;\n        self.assure_one_name_has_one_edit().map_err(|name| {\n            std::io::Error::new(\n                std::io::ErrorKind::AlreadyExists,\n                format!(\"A reference named '{name}' has multiple edits\"),\n            )\n        })\n    }\n}\n\nimpl<E> RefEditsExt<E> for Vec<E>\nwhere\n    E: std::borrow::Borrow<RefEdit> + std::borrow::BorrowMut<RefEdit>,\n{\n    fn assure_one_name_has_one_edit(&self) -> Result<(), BString> {\n        let mut names: Vec<_> = self.iter().map(|e| &e.borrow().name).collect();\n        names.sort();\n        match names.windows(2).find(|v| v[0] == v[1]) {\n            Some(name) => Err(name[0].as_bstr().to_owned()),\n            None => Ok(()),\n        }","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-ref/src/transaction/ext.rs#L17-L53","documentation":"During reference transaction pre-processing, gix-ref checks that each reference name appears in at most one edit; if `assure_one_name_has_one_edit` finds duplicates, pre_process returns an io::Error of kind AlreadyExists: \"A reference named '{name}' has multiple edits\". Git semantics forbid two conflicting updates to the same ref within one transaction.","triggerScenarios":"Calling `gix_ref::transaction::Transaction::pre_process` (with a `find` lookup and `make_entry` factory) after adding two RefEdits for the same reference name into the same transaction.","commonSituations":"Application logic queuing e.g. both a create and an update for HEAD or the same branch; concurrent code paths each adding an edit for the same ref; migration scripts replaying edits twice.","solutions":["Deduplicate RefEdits by reference name before preparing the transaction (later edit wins)","Split conflicting operations into separate sequential transactions","Audit code paths that build edit lists to ensure they don't both touch the same ref","If intentional replace is needed, remove the earlier edit rather than appending a second one"],"exampleFix":"// before\nlet tx = repo.edit_reference(edits::Reference::Create(name, target1, msg));\n// ... elsewhere\ntransaction.prepare(edits2) // edits2 contains a second edit for `name`\n\n// after\nlet mut edits: Vec<RefEdit> = edits1.into_iter()\n    .chain(edits2)\n    .fold(BTreeMap::new(), |mut m, e| { m.insert(e.name.clone(), e); m })\n    .into_values().collect();","handlingStrategy":"validation","validationCode":"// before preparing the transaction\necho \"checking for duplicate ref edits\" >&2;\nlet mut names = std::collections::HashSet::new();\nfor edit in &edits {\n    if !names.insert(edit.name.as_bstr().to_vec()) {\n        return Err(format!(\"duplicate edit for {}\", edit.name));\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Deduplicate edits by ref name before transaction prepare","Never queue multiple edits for the same ref in one transaction","Centralize ref-edit construction to avoid double-queueing"],"tags":["ref","transaction","duplicate","git"],"backgroundTag":"file-already-exists","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}