c3643bd4833e

bind a clone to the repo it was stolen from so a rename cannot fork it (3.0.11)

time
2026-09-23 22:01 UTC · 2 weeks ago
machine
koh2
agent
claude-opus-5-5
session
koh 3 review fixes
parent
7d49e0453acd
5 files VERSION+1 −1src/cli/cmd_steal.v+4 −0src/sync/sync.v+6 −0tests/cli_test.v+28 −0v.mod+1 −1
VERSION+1 −1
@@ -1 +1 @@1-3.0.101+3.0.11

view file

src/cli/cmd_steal.v+4 −0
@@ -157,6 +157,10 @@157157 		store.rollback()158158 		return refuse(args.json(), err.msg())159159 	}160+	sync.remember_repo(store, name) or {161+		store.rollback()162+		return refuse(args.json(), err.msg())163+	}160164 	store.commit() or { return refuse(args.json(), err.msg()) }161165 	files := history.files_of(store, fetched.head) or { return refuse(args.json(), err.msg()) }162166 	snapshot.restore_files(store, target, snapshot.Ignore{}, files, []) or {

view file

src/sync/sync.v+6 −0
@@ -31,6 +31,12 @@3131 	head    string3232 }3333 34+// remember_repo binds a repo to its name on the remote. A clone does it at35+// once: its folder may be renamed before it ever offers.36+pub fn remember_repo(store &storage.Store, name string) ! {37+	store.set_state(repo_state_key, name)!38+}39+3440 // repo_name is the folder's name at first offer, remembered in the repo so3541 // renaming the folder later changes nothing.3642 pub fn repo_name(store &storage.Store, mut backend remote.Backend) !string {

view file

tests/cli_test.v+28 −0
@@ -431,6 +431,34 @@431431 	assert run_home(dir, home, 'remote', '--json').out.contains('"configured":false')432432 }433433 434+// A clone belongs to the repo it was stolen from, whatever its folder is435+// called later: renaming it must not start a second repo on the remote.436+fn test_a_renamed_clone_keeps_offering_to_its_repo() {437+	syncroot := temp_repo('rename-clone')438+	home := temp_repo('rename-clone-home')439+	defer {440+		os.rmdir_all(syncroot) or {}441+		os.rmdir_all(home) or {}442+	}443+	remote := os.join_path(syncroot, 'remote')444+	a := os.join_path(syncroot, 'A', 'proj')445+	b_parent := os.join_path(syncroot, 'B')446+	os.mkdir_all(a) or { panic(err) }447+	os.mkdir_all(b_parent) or { panic(err) }448+	init_repo(a)449+	write(a, 'a.txt', 'from A\n')450+	assert run_home(a, home, 'remote', 'folder', remote).code == 0451+	assert run_home(a, home, 'save', 'A first').code == 0452+	assert run_home(b_parent, home, 'steal', 'proj').code == 0453+	renamed := os.join_path(b_parent, 'renamed')454+	os.mv(os.join_path(b_parent, 'proj'), renamed) or { panic(err) }455+	write(renamed, 'b.txt', 'from B\n')456+	assert run_home(renamed, home, 'save', 'B first').code == 0457+	assert !os.exists(os.join_path(remote, 'renamed'))458+	assert run_home(a, home, 'steal').code == 0459+	assert os.read_file(os.join_path(a, 'b.txt'))! == 'from B\n'460+}461+434462 fn test_offer_steal_folder_remote() {435463 	syncroot := temp_repo('sync')436464 	home := temp_repo('sync-home')

view file

v.mod+1 −1
@@ -1,6 +1,6 @@11 Module {22 	name: 'koh3'3-	version: '3.0.10'3+	version: '3.0.11'44 	description: 'One SQLite file per repo, one line of history.'55 	license: 'MIT'66 }

view file