remote remove: remove all of the remote 34fad4a92451
It blanked remote.NAME.url and nothing else: the token, CA and store settings stayed in .oxy/config, and the remote's tracking bookmarks in the view, read later as if current. Repo::remove_remote unsets every remote.NAME.* key of the repository's config, drops the tracking bookmarks in an operation of its own, and deletes a store remote's mirror under .oxy/remotes/NAME; an unknown name is refused. closes #86
- Author
- Andy McCall @andymccall <[email protected]>
- When
- · 2026-10-10 21:56 UTC
- Signature
- ✔ signed by Andy McCall
- Hash
34fad4a924514f17dd1f2f9f3d0471933027dfa03c33dfe5818ac5438906e7a1- Depends on
- 8fd78eb52ad2 94084087a876 982864068a59 cb8b8082fa73 d6e0d5b8b339 e2a5edbf1395 f8c695764c95 fce44ae9ad29
- Depended on by
- d3b270909c78 efad40f9ac8e c86270b7c670 4294602ee66f ebb9210bad0c 31d3e932e97a 5d79b5c2de88 7fc365369758 aa4939e07a09 9b723f69b032 fe9586d93fb1 b689779e9e74 530a0fc650a2 9d580f2132f3
- In bookmarks
- bare-hashes carried-not-removed carry-identical doctor-trust identical-sides keyless-tags main merge-remote-bookmark only-help-103 paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state switch-says
- In tags
- v0.10.0 v0.11.0 v0.4.4 v0.4.5 v0.4.6 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
- Edits
- 5 atoms, 0 tree operations, 4 files
Browse the tree at this change
modified CHANGELOG.md +4 −0
| 1 | 1 | # Changelog |
|
| 2 | 2 | ||
| 3 | + | ## Unreleased |
|
| 4 | + | ||
| 5 | + | - **`oxy remote remove` removes all of a remote (#86).** It blanked the URL alone: the token, CA and store settings stayed in the config and the remote's tracking bookmarks in the view, read later as if current. Now every `remote.NAME.*` key goes, with its tracking bookmarks and a store remote's mirror; an unknown name is refused. |
|
| 6 | + | ||
| 3 | 7 | ## 0.4.3 (2026-10-10) |
|
| 4 | 8 | ||
| 5 | 9 | - **Claim your own commits in a Git import (#97).** `oxy git import --claim` and `oxy git fetch --claim` set `git.claim`: a commit whose Git author email is your identity's email is authored with your key (and sealed by you on push), so a forge credits it to your account; anyone else's commits keep the zero key, as before. |
|
| … | 164 unchanged lines |
modified crates/oxy-core/src/repo/sync.rs +34 −0
| … | 1638 unchanged lines |
||
| 1639 | 1639 | Ok(results) |
|
| 1640 | 1640 | } |
|
| 1641 | 1641 | ||
| 1642 | + | /// Remove remote `name` (oxygen#86): every `remote.NAME.*` key of this |
|
| 1643 | + | /// repository's config (its URL, token, CA and store settings), its |
|
| 1644 | + | /// tracking bookmarks in the view, and a store remote's mirror under |
|
| 1645 | + | /// `.oxy/remotes/NAME`. Nothing stays to be read as if it were current. |
|
| 1646 | + | pub fn remove_remote(&mut self, name: &str) -> Result<()> { |
|
| 1647 | + | if !self.config.remotes.contains_key(name) { |
|
| 1648 | + | return fail(format!("no remote {name}: `oxy remote list` shows them")); |
|
| 1649 | + | } |
|
| 1650 | + | let prefix = format!("remote.{name}."); |
|
| 1651 | + | let keys: Vec<String> = self |
|
| 1652 | + | .config |
|
| 1653 | + | .repo_layer() |
|
| 1654 | + | .keys() |
|
| 1655 | + | .filter(|k| k.starts_with(&prefix)) |
|
| 1656 | + | .cloned() |
|
| 1657 | + | .collect(); |
|
| 1658 | + | for k in keys { |
|
| 1659 | + | self.config.set(&k, "")?; |
|
| 1660 | + | } |
|
| 1661 | + | self.config.remotes.remove(name); |
|
| 1662 | + | self.save_config()?; |
|
| 1663 | + | let (op_ref, op) = self.head_op()?; |
|
| 1664 | + | if op.view.remotes.contains_key(name) { |
|
| 1665 | + | let mut view = op.view.clone(); |
|
| 1666 | + | view.remotes.remove(name); |
|
| 1667 | + | self.record_op(&[op_ref], &format!("oxy remote remove {name}"), view)?; |
|
| 1668 | + | } |
|
| 1669 | + | let mirror = self.oxy.join("remotes").join(name); |
|
| 1670 | + | if mirror.is_dir() { |
|
| 1671 | + | fs::remove_dir_all(&mirror)?; |
|
| 1672 | + | } |
|
| 1673 | + | Ok(()) |
|
| 1674 | + | } |
|
| 1675 | + | ||
| 1642 | 1676 | /// `changes`, in dependency order, cut into batches of about |
|
| 1643 | 1677 | /// `push.batch-bytes` by what each change and its texts and blobs weigh. |
|
| 1644 | 1678 | /// There is always one, perhaps empty. |
|
| … | 452 unchanged lines |
modified crates/oxy-core/src/repo/tests.rs +55 −0
| … | 8241 unchanged lines |
||
| 8242 | 8242 | assert_eq!(by_message["mine"], key, "her own commit, any case of email"); |
|
| 8243 | 8243 | assert_eq!(by_message["someone else's"], ObjectRef::ZERO, "not hers"); |
|
| 8244 | 8244 | } |
|
| 8245 | + | ||
| 8246 | + | /// oxygen#86: removing a remote removes all of it: every `remote.NAME.*` |
|
| 8247 | + | /// key (URL, token, CA), its tracking bookmarks, and nothing else. |
|
| 8248 | + | #[test] |
|
| 8249 | + | fn removing_a_remote_leaves_nothing_of_it() { |
|
| 8250 | + | hermetic(); |
|
| 8251 | + | let dir = tempfile::tempdir().unwrap(); |
|
| 8252 | + | let origin = dir.path().join("origin"); |
|
| 8253 | + | Repo::init_bare_unbound(&origin).unwrap(); |
|
| 8254 | + | let main = dir.path().join("main"); |
|
| 8255 | + | let mut repo = Repo::init(&main).unwrap(); |
|
| 8256 | + | repo.config |
|
| 8257 | + | .set("remote.origin.url", &origin.to_string_lossy()) |
|
| 8258 | + | .unwrap(); |
|
| 8259 | + | repo.config |
|
| 8260 | + | .set("remote.origin.token", "secret-ish") |
|
| 8261 | + | .unwrap(); |
|
| 8262 | + | repo.config |
|
| 8263 | + | .set("remote.keep.url", &origin.to_string_lossy()) |
|
| 8264 | + | .unwrap(); |
|
| 8265 | + | repo.save_config().unwrap(); |
|
| 8266 | + | write(&main, "a.txt", b"a\n"); |
|
| 8267 | + | repo.commit("a", &[]).unwrap(); |
|
| 8268 | + | assert!(repo.push("origin", false).unwrap()[0].ok); |
|
| 8269 | + | assert!( |
|
| 8270 | + | repo.view().unwrap().remotes.contains_key("origin"), |
|
| 8271 | + | "a tracking bookmark" |
|
| 8272 | + | ); |
|
| 8273 | + | ||
| 8274 | + | repo.remove_remote("origin").unwrap(); |
|
| 8275 | + | let again = Repo::open(&main).unwrap(); |
|
| 8276 | + | assert!( |
|
| 8277 | + | !again |
|
| 8278 | + | .config |
|
| 8279 | + | .repo_layer() |
|
| 8280 | + | .keys() |
|
| 8281 | + | .any(|k| k.starts_with("remote.origin.")), |
|
| 8282 | + | "{:?}", |
|
| 8283 | + | again.config.repo_layer() |
|
| 8284 | + | ); |
|
| 8285 | + | assert!(!again.config.remotes.contains_key("origin")); |
|
| 8286 | + | assert!( |
|
| 8287 | + | !again.view().unwrap().remotes.contains_key("origin"), |
|
| 8288 | + | "its tracking bookmarks go" |
|
| 8289 | + | ); |
|
| 8290 | + | assert!( |
|
| 8291 | + | again.config.remotes.contains_key("keep"), |
|
| 8292 | + | "another remote stays" |
|
| 8293 | + | ); |
|
| 8294 | + | let mut again = again; |
|
| 8295 | + | assert!( |
|
| 8296 | + | again.remove_remote("origin").is_err(), |
|
| 8297 | + | "a second removal is refused" |
|
| 8298 | + | ); |
|
| 8299 | + | } |
modified src/cli/sync.rs +1 −2
| … | 295 unchanged lines |
||
| 296 | 296 | ||
| 297 | 297 | pub fn remote_remove(name: &str) -> Result<i32> { |
|
| 298 | 298 | let mut repo = open()?; |
|
| 299 | - | repo.config.set(&format!("remote.{name}.url"), "")?; |
|
| 300 | - | repo.save_config()?; |
|
| 299 | + | repo.remove_remote(name)?; |
|
| 301 | 300 | println!("{} remote {}", ui::done("Removed"), ui::bookmark(name)); |
|
| 302 | 301 | Ok(0) |
|
| 303 | 302 | } |
|
| … | 836 unchanged lines |