Unified · Split
| @@ -192,11 +192,11 @@ impl<'a> Transaction<'a> { · 191 unmodified lines | ||
| 192 | 192 | } |
| 193 | 193 | |
| 194 | 194 | for change in self.updates.iter_mut() { |
| 195 | + assert!(!change.update.deref, "Deref mode is turned into splits and turned off"); | |
| 195 | 196 | match &change.update.change { |
| 196 | 197 | Change::Update { .. } => {} |
| 197 | − Change::Delete { deref, mode, .. } => { | |
| 198 | + Change::Delete { mode, .. } => { | |
| 198 | 199 | let lock = change.lock.take().expect("each ref is locked, even deletions"); |
| 199 | − assert!(!deref, "Deref mode is turned into splits and turned off"); | |
| 200 | 200 | let (rm_reflog, rm_ref) = match mode { |
| 201 | 201 | DeleteMode::RefAndRefLog => (true, true), |
| 202 | 202 | DeleteMode::RefLogOnly => (true, false), |
| @@ -38,9 +38,6 @@ pub enum Change { · 37 unmodified lines | ||
| 38 | 38 | Update { |
| 39 | 39 | /// How to treat the reference log. |
| 40 | 40 | mode: UpdateMode, |
| 41 | − /// If set, symbolic references will be dereferenced so the change gets applied to their target. Has no effect if the reference | |
| 42 | − /// isn't symbolic. | |
| 43 | − deref: bool, | |
| 44 | 41 | /// The previous value of the ref, which will be used to assure the ref is still in the known `previous` state before |
| 45 | 42 | /// updating it. It will also be filled in automatically for use in the reflog, if applicable. |
| 46 | 43 | previous: Option<Target>, |
| @@ -56,9 +53,6 @@ pub enum Change { · 9 unmodified lines | ||
| 56 | 53 | previous: Option<Target>, |
| 57 | 54 | /// How to thread the reference log during deletion. |
| 58 | 55 | mode: DeleteMode, |
| 59 | − /// If set, symbolic references will be dereferenced so the change gets applied to their target. Has no effect if the reference | |
| 60 | − /// isn't symbolic. | |
| 61 | − deref: bool, | |
| 62 | 56 | }, |
| 63 | 57 | } |
| 64 | 58 | |
| @@ -69,6 +63,38 @@ pub struct RefEdit { · 4 unmodified lines | ||
| 69 | 63 | pub change: Change, |
| 70 | 64 | /// The name of the reference to apply the change to |
| 71 | 65 | pub name: FullName, |
| 66 | + /// If set, symbolic references identified by `name` will be dereferenced to have the `change` applied to their target. | |
| 67 | + /// This flag has no effect if the reference isn't symbolic. | |
| 68 | + pub deref: bool, | |
| 69 | +} | |
| 70 | + | |
| 71 | +/// The way to deal with the Reflog in deletions. | |
| 72 | +#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] | |
| 73 | +pub enum DeleteMode { | |
| 74 | + /// Delete the reference and the log | |
| 75 | + RefAndRefLog, | |
| 76 | + /// Delete only the reflog | |
| 77 | + RefLogOnly, | |
| 78 | +} | |
| 79 | + | |
| 80 | +/// The way to deal with the Reflog in a particular edit | |
| 81 | +/// | |
| 82 | +/// If the `create_unconditionally` field is set, create a reflog even if it otherwise wouldn't be created, | |
| 83 | +/// as is the case for tags. | |
| 84 | +#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] | |
| 85 | +pub enum UpdateMode { | |
| 86 | + /// As symbolic references only ever see this when you want to detach them, we won't try to dereference them | |
| 87 | + /// in this case and apply the change to it directly. | |
| 88 | + RefAndRefLog { | |
| 89 | + /// If set, update the reflog even if it otherwise wouldn't. | |
| 90 | + create_unconditionally: bool, | |
| 91 | + }, | |
| 92 | + /// Only update the reflog but require this to be a symbolic ref so the actual update can be performed on the | |
| 93 | + /// referent. | |
| 94 | + RefLogOnly { | |
| 95 | + /// If set, update the reflog even if it otherwise wouldn't. | |
| 96 | + create_unconditionally: bool, | |
| 97 | + }, | |
| 72 | 98 | } |
| 73 | 99 | |
| 74 | 100 | mod ext { |
| @@ -115,13 +141,13 @@ mod ext { · 40 unmodified lines | ||
| 115 | 141 | for edit in self.iter_mut() { |
| 116 | 142 | let edit = edit.borrow_mut(); |
| 117 | 143 | match edit.change { |
| 118 | − Change::Delete { ref mut deref, .. } | Change::Update { ref mut deref, .. } => { | |
| 144 | + Change::Delete { .. } | Change::Update { .. } => { | |
| 119 | 145 | match store.find_one_existing(edit.name.to_partial()).ok() { |
| 120 | 146 | Some(Target::Symbolic(_name)) => { |
| 121 | 147 | // todo!("split into new edit") |
| 122 | 148 | } |
| 123 | 149 | Some(Target::Peeled(_)) => { |
| 124 | − *deref = false; | |
| 150 | + edit.deref = false; | |
| 125 | 151 | } |
| 126 | 152 | None => {} |
| 127 | 153 | } |
| @@ -134,32 +160,3 @@ mod ext { · 6 unmodified lines | ||
| 134 | 160 | } |
| 135 | 161 | } |
| 136 | 162 | pub use ext::RefEditsExt; |
| 137 | − | |
| 138 | −/// The way to deal with the Reflog in deletions. | |
| 139 | −#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] | |
| 140 | −pub enum DeleteMode { | |
| 141 | − /// Delete the reference and the log | |
| 142 | − RefAndRefLog, | |
| 143 | − /// Delete only the reflog | |
| 144 | − RefLogOnly, | |
| 145 | −} | |
| 146 | − | |
| 147 | −/// The way to deal with the Reflog in a particular edit | |
| 148 | −/// | |
| 149 | −/// If the `create_unconditionally` field is set, create a reflog even if it otherwise wouldn't be created, | |
| 150 | −/// as is the case for tags. | |
| 151 | −#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] | |
| 152 | −pub enum UpdateMode { | |
| 153 | − /// As symbolic references only ever see this when you want to detach them, we won't try to dereference them | |
| 154 | − /// in this case and apply the change to it directly. | |
| 155 | − RefAndRefLog { | |
| 156 | − /// If set, update the reflog even if it otherwise wouldn't. | |
| 157 | − create_unconditionally: bool, | |
| 158 | − }, | |
| 159 | − /// Only update the reflog but require this to be a symbolic ref so the actual update can be performed on the | |
| 160 | − /// referent. | |
| 161 | − RefLogOnly { | |
| 162 | − /// If set, update the reflog even if it otherwise wouldn't. | |
| 163 | − create_unconditionally: bool, | |
| 164 | − }, | |
| 165 | −} | |
| @@ -52,9 +52,9 @@ mod prepare_and_commit { · 51 unmodified lines | ||
| 52 | 52 | }, |
| 53 | 53 | new: Target::Symbolic(referent.try_into()?), |
| 54 | 54 | previous: None, // TODO: check failure if it doesn't exist |
| 55 | − deref: false, | |
| 56 | 55 | }, |
| 57 | 56 | name: "HEAD".try_into()?, |
| 57 | + deref: false, | |
| 58 | 58 | }), |
| 59 | 59 | Fail::Immediately, |
| 60 | 60 | ); |
| @@ -107,9 +107,9 @@ mod prepare_and_commit { · 46 unmodified lines | ||
| 107 | 107 | change: Change::Delete { |
| 108 | 108 | previous: None, |
| 109 | 109 | mode: DeleteMode::RefAndRefLog, |
| 110 | − deref: false, | |
| 111 | 110 | }, |
| 112 | 111 | name: "DOES_NOT_EXIST".try_into().unwrap(), |
| 112 | + deref: false, | |
| 113 | 113 | }), |
| 114 | 114 | Fail::Immediately, |
| 115 | 115 | ) |
| @@ -127,9 +127,9 @@ mod prepare_and_commit { · 11 unmodified lines | ||
| 127 | 127 | change: Change::Delete { |
| 128 | 128 | previous: Some(Target::Peeled(ObjectId::null_sha1())), |
| 129 | 129 | mode: DeleteMode::RefAndRefLog, |
| 130 | − deref: false, | |
| 131 | 130 | }, |
| 132 | 131 | name: "DOES_NOT_EXIST".try_into().unwrap(), |
| 132 | + deref: false, | |
| 133 | 133 | }), |
| 134 | 134 | Fail::Immediately, |
| 135 | 135 | ) |
| @@ -156,9 +156,9 @@ mod prepare_and_commit { · 20 unmodified lines | ||
| 156 | 156 | change: Change::Delete { |
| 157 | 157 | previous: Some(Target::Peeled(ObjectId::null_sha1())), |
| 158 | 158 | mode: DeleteMode::RefAndRefLog, |
| 159 | − deref: false, | |
| 160 | 159 | }, |
| 161 | 160 | name: head.name().into(), |
| 161 | + deref: false, | |
| 162 | 162 | }), |
| 163 | 163 | Fail::Immediately, |
| 164 | 164 | ) |
| @@ -170,9 +170,9 @@ mod prepare_and_commit { · 5 unmodified lines | ||
| 170 | 170 | change: Change::Delete { |
| 171 | 171 | previous: Some(Target::Symbolic("refs/heads/main".try_into()?)), |
| 172 | 172 | mode: DeleteMode::RefAndRefLog, |
| 173 | − deref: false | |
| 174 | 173 | }, |
| 175 | 174 | name: head.name().into(), |
| 175 | + deref: false | |
| 176 | 176 | }], |
| 177 | 177 | "the previous value was updated with the actual one" |
| 178 | 178 | ); |
| @@ -197,9 +197,9 @@ mod prepare_and_commit { · 18 unmodified lines | ||
| 197 | 197 | change: Change::Delete { |
| 198 | 198 | previous: Some(Target::Symbolic("refs/heads/main".try_into()?)), |
| 199 | 199 | mode: DeleteMode::RefLogOnly, |
| 200 | − deref: false, | |
| 201 | 200 | }, |
| 202 | 201 | name: head.name().into(), |
| 202 | + deref: false, | |
| 203 | 203 | }), |
| 204 | 204 | Fail::Immediately, |
| 205 | 205 | ) |
| @@ -231,9 +231,9 @@ mod prepare_and_commit { · 25 unmodified lines | ||
| 231 | 231 | change: Change::Delete { |
| 232 | 232 | previous: Some(Target::Symbolic("refs/heads/main".try_into().unwrap())), |
| 233 | 233 | mode: DeleteMode::RefLogOnly, |
| 234 | − deref: true, | |
| 235 | 234 | }, |
| 236 | 235 | name: head.name().into(), |
| 236 | + deref: true, | |
| 237 | 237 | }), |
| 238 | 238 | Fail::Immediately, |
| 239 | 239 | ) |
| @@ -11,9 +11,9 @@ mod transaction { · 10 unmodified lines | ||
| 11 | 11 | change: Change::Delete { |
| 12 | 12 | previous: None, |
| 13 | 13 | mode: DeleteMode::RefAndRefLog, |
| 14 | − deref: false, | |
| 15 | 14 | }, |
| 16 | 15 | name: name.try_into().expect("valid name"), |
| 16 | + deref: false, | |
| 17 | 17 | } |
| 18 | 18 | } |
| 19 | 19 | |
| @@ -78,12 +78,6 @@ mod transaction { · 58 unmodified lines | ||
| 78 | 78 | } |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | − fn is_deref(edit: &RefEdit) -> bool { | |
| 82 | − match edit.change { | |
| 83 | − Change::Delete { deref, .. } | Change::Update { deref, .. } => deref, | |
| 84 | − } | |
| 85 | − } | |
| 86 | − | |
| 87 | 81 | fn find<'a>(edits: &'a [RefEdit], name: &str) -> &'a RefEdit { |
| 88 | 82 | let name: FullName = name.try_into().unwrap(); |
| 89 | 83 | edits |
| @@ -103,36 +97,36 @@ mod transaction { · 13 unmodified lines | ||
| 103 | 97 | change: Change::Delete { |
| 104 | 98 | previous: None, |
| 105 | 99 | mode: DeleteMode::RefAndRefLog, |
| 106 | − deref: false, | |
| 107 | 100 | }, |
| 108 | 101 | name: "SYMBOLIC_PROBABLY_BUT_DEREF_IS_FALSE_SO_IGNORED".try_into()?, |
| 102 | + deref: false, | |
| 109 | 103 | }, |
| 110 | 104 | RefEdit { |
| 111 | 105 | change: Change::Delete { |
| 112 | 106 | previous: None, |
| 113 | 107 | mode: DeleteMode::RefAndRefLog, |
| 114 | − deref: true, | |
| 115 | 108 | }, |
| 116 | 109 | name: "refs/heads/anything-but-not-symbolic".try_into()?, |
| 110 | + deref: true, | |
| 117 | 111 | }, |
| 118 | 112 | RefEdit { |
| 119 | 113 | change: Change::Delete { |
| 120 | 114 | previous: None, |
| 121 | 115 | mode: DeleteMode::RefAndRefLog, |
| 122 | − deref: true, | |
| 123 | 116 | }, |
| 124 | 117 | name: "refs/heads/does-not-exist-and-deref-is-ignored".try_into()?, |
| 118 | + deref: true, | |
| 125 | 119 | }, |
| 126 | 120 | ]; |
| 127 | 121 | |
| 128 | 122 | edits.extend_with_splits_of_symbolic_refs(&store, |_| panic!("should not be called"))?; |
| 129 | 123 | assert_eq!(edits.len(), 3, "no edit was added"); |
| 130 | 124 | assert!( |
| 131 | − !is_deref(find(&edits, "refs/heads/anything-but-not-symbolic")), | |
| 125 | + !find(&edits, "refs/heads/anything-but-not-symbolic").deref, | |
| 132 | 126 | "the algorithm corrects these flags" |
| 133 | 127 | ); |
| 134 | 128 | assert!( |
| 135 | − is_deref(find(&edits, "refs/heads/does-not-exist-and-deref-is-ignored")), | |
| 129 | + find(&edits, "refs/heads/does-not-exist-and-deref-is-ignored").deref, | |
| 136 | 130 | "non-existing refs won't change the flag" |
| 137 | 131 | ); |
| 138 | 132 | store.assert_empty(); |