╭ changed ────────╮ │src/serve_ssh.zig│ ╰─────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │370 │ │371 const parsed = parseGitCommand(allocator, exec.command) catch return writeError(sess, "unsupported command (expected git-upload-pack or git-receive-pack)"); │ │372 defer parsed.deinit(allocator); │ │373 - const path = std.mem.trimStart(u8, parsed.dir, "/"); │ │374 - const fork_prefix = "fork/"; │ │373 + const repo_identity = std.mem.trimStart(u8, parsed.dir, "/"); │ │374 │ │376 - if (std.mem.startsWith(u8, path, fork_prefix)) { │ │377 - return runForkSession(handler, sess, path[fork_prefix.len..], parsed.service, protocol_version, &reader.interface, &writer.interface); │ │375 + // a "+" names a fork's patch draft │ │376 + if (std.mem.indexOfScalar(u8, repo_identity, '+') != null) { │ │377 + return runForkSession(handler, sess, repo_identity, parsed.service, protocol_version, &reader.interface, &writer.interface); │ │378 } │ │379 │ │380 - const repo_prefix = "repo/"; │ │381 - const repo_identity = if (std.mem.startsWith(u8, path, repo_prefix)) path[repo_prefix.len..] else path; │ │382 - │ │380 const create_if_missing = parsed.service == .receive_pack; │ │381 │ │385 - const owner_repo = evt.parseOwnerRepoPath(repo_identity) orelse return writeError(sess, "repo path must be <owner>/<repo>"); │ │382 + const owner_repo = evt.parseOwnerRepoPath(repo_identity) orelse return writeError(sess, "repo path must be <owner>:<repo>"); │ │383 var author_arena = std.heap.ArenaAllocator.init(allocator); │ │384 defer author_arena.deinit(); │ │385 const author = switch (try authorizeRepoKey(io, &author_arena, handler.admin_repo_path, handler.users_dir, owner_repo.owner, owner_repo.name, parsed.service, &sess.fingerprint)) {│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │423 │ │424 const route = fork.parseRoute(fork_path) orelse return writeError(sess, "invalid fork path"); │ │425 // the route names the forker and the target repo │ │429 - const forker_repo = evt.parseOwnerRepoPath(route.identity) orelse return writeError(sess, "repo path must be <forker>/<repo>");│ │426 + const forker_repo = evt.parseOwnerRepoPath(route.identity) orelse return writeError(sess, "repo path must be <forker>:<repo>");│ │427 │ │428 var admin = try rp.Repo(.xit, evt.admin_repo_opts).open(io, allocator, .{ .path = handler.admin_repo_path }); │ │429 defer admin.deinit(io, allocator); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯