Skip to content
4 changes: 2 additions & 2 deletions component/impl/network_clone_bootstrap_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
test "component impl: clone bootstrap helpers initialize repo and origin config" {
let fs = @bit.TestFs::new()

net_prepare_clone_repo(fs, "/repo", "git@github.com:user/repo.git")
net_prepare_clone_repo(fs, "/repo", component_impl_fixture_remote_url)

assert_true(fs.is_dir("/repo"))
assert_true(fs.is_dir("/repo/.git"))
let config = fs.read_string("/repo/.git/config")
inspect(config.contains("[remote \"origin\"]"), content="true")
inspect(
config.contains("\turl = git@github.com:user/repo.git"),
config.contains("\turl = " + component_impl_fixture_remote_url),
content="true",
)
}
4 changes: 2 additions & 2 deletions component/impl/network_clone_config_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ test "component impl: clone config helpers write origin remote config" {
@bitlib.init_repo(fs, "/repo")

net_write_clone_remote_config(
fs, "/repo/.git", "git@github.com:user/repo.git",
fs, "/repo/.git", component_impl_fixture_remote_url,
)

let config = fs.read_string("/repo/.git/config")
inspect(config.contains("[remote \"origin\"]"), content="true")
inspect(
config.contains("\turl = git@github.com:user/repo.git"),
config.contains("\turl = " + component_impl_fixture_remote_url),
content="true",
)
inspect(
Expand Down
2 changes: 1 addition & 1 deletion component/impl/network_clone_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ test "component impl: clone_with_transport materializes repo with injected trans
clone_with_transport(
fs,
fs,
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
"/repo",
"",
0,
Expand Down
2 changes: 1 addition & 1 deletion component/impl/network_discovery_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ test "component impl: discover refs accepts scp-style ssh remote" {
let get_calls : Array[String] = []
let post_calls : Array[String] = []
let (refs, _caps, version, symrefs) = discover_refs_sync(
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
true,
fn(
url : String,
Expand Down
2 changes: 1 addition & 1 deletion component/impl/network_fetch_ops_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test "component impl: fetch_with_transport materializes fetched state" {
fs,
fs,
"/repo",
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
fn(
_url : String,
_headers : Map[String, String],
Expand Down
2 changes: 1 addition & 1 deletion component/impl/network_fetch_pack_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ test "component impl: fetch_pack_sync returns pack payload through injected tran
let (adv, lsrefs, fetch) = component_impl_fixture_upload_pack_responses()

let pack = fetch_pack_sync(
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
[@bit.ObjectId::from_hex(component_impl_fixture_commit)],
true,
0,
Expand Down
6 changes: 6 additions & 0 deletions component/impl/network_fixture_codec_helpers_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,9 @@ let component_impl_fetch_hex : String = "303030647061636b66696c650a3030643501504

///|
let component_impl_fixture_commit : String = "30c9f208acc7601773a29aef394157adf960d104"

///|
let component_impl_fixture_remote_url : String = "git@github.com:user/repo.git"

///|
let component_impl_fixture_default_branch : String = "refs/heads/main"
2 changes: 1 addition & 1 deletion component/impl/network_push_exchange_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ test "component impl: push exchange helpers execute receive-pack flow" {
let get_calls : Array[String] = []
let post_calls : Array[String] = []
let result = net_execute_push_request(
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
"refs/heads/main",
@bit.ObjectId::from_hex(component_impl_fixture_commit),
Bytes::from_array([1, 2, 3, 4]),
Expand Down
2 changes: 1 addition & 1 deletion component/impl/network_push_ops_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ test "component impl: push_with_transport accepts scp-style ssh remote" {
let result = push_with_transport(
fs,
"/repo",
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
"",
fn(
url : String,
Expand Down
2 changes: 1 addition & 1 deletion component/impl/network_push_sync_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ test "component impl: push sync helpers prepare state and execute request" {
let result = net_sync_push_target(
fs,
"/repo",
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
"",
fn(
url : String,
Expand Down
4 changes: 2 additions & 2 deletions component/impl/network_receive_pack_request_wbtest.mbt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
///|
test "component impl: receive-pack request helpers normalize ssh remote" {
let (info_url, info_headers) = receive_pack_info_refs_request(
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
)

let pack = Bytes::from_array([1, 2, 3, 4])
let (push_url, push_body, push_headers) = receive_pack_service_request(
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
@bit.ObjectId::from_hex(component_impl_fixture_commit),
@bit.ObjectId::zero(),
"refs/heads/main",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
///|
test "component impl: receive-pack response fixture helpers assert request and response expectations" {
let (receive_info_url, receive_info_headers) = receive_pack_info_refs_request(
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
)
let pack = Bytes::from_array([1, 2, 3, 4])
let (push_url, push_body, push_headers) = receive_pack_service_request(
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
@bit.ObjectId::from_hex(component_impl_fixture_commit),
@bit.ObjectId::zero(),
"refs/heads/main",
Expand Down
6 changes: 2 additions & 4 deletions component/impl/network_remote_fetch_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ test "component impl: remote fetch helpers choose default target and fetch pack"
let (adv, lsrefs, fetch) = component_impl_fixture_upload_pack_responses()

let (refname, commit_id, pack) = net_fetch_remote_target(
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
0,
"No default branch found",
fn(
Expand All @@ -29,7 +29,5 @@ test "component impl: remote fetch helpers choose default target and fetch pack"
},
)

assert_eq(refname, "refs/heads/main")
inspect(commit_id.to_hex(), content=component_impl_fixture_commit)
assert_true(pack.length() > 0)
component_impl_assert_remote_fetch_target(refname, commit_id, pack)
}
2 changes: 1 addition & 1 deletion component/impl/network_remote_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ test "component impl: network remote helpers normalize ssh remotes" {
content="https://github.com/mizchi/bit-vcs.git",
)

let remote = net_http_remote("git@github.com:user/repo.git")
let remote = net_http_remote(component_impl_fixture_remote_url)
inspect(
remote.info_refs_url(),
content="https://github.com/user/repo/info/refs?service=git-receive-pack",
Expand Down
11 changes: 11 additions & 0 deletions component/impl/network_repo_fetch_state_fixture_helpers_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,14 @@ fn component_impl_assert_fetch_only_state(
)
assert_eq(fs.read_string(root + "/hello.txt"), "hello\n")
}

///|
fn component_impl_assert_remote_fetch_target(
refname : String,
commit_id : @bit.ObjectId,
pack : Bytes,
) -> Unit {
assert_eq(refname, component_impl_fixture_default_branch)
inspect(commit_id.to_hex(), content=component_impl_fixture_commit)
assert_true(pack.length() > 0)
}
2 changes: 1 addition & 1 deletion component/impl/network_repo_sync_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test "component impl: repo sync helpers fetch remote target and apply fetched st
fs,
fs,
"/repo",
"git@github.com:user/repo.git",
component_impl_fixture_remote_url,
0,
"No refs found on remote",
fn(
Expand Down
4 changes: 2 additions & 2 deletions component/impl/network_upload_pack_http_request_wbtest.mbt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
///|
test "component impl: upload-pack http request helpers normalize ssh remote" {
let (info_url, info_headers) = upload_pack_info_refs_request(
"git@github.com:user/repo.git", true,
component_impl_fixture_remote_url, true,
)
let (post_url, post_headers) = upload_pack_service_request(
"git@github.com:user/repo.git", true,
component_impl_fixture_remote_url, true,
)
component_impl_assert_upload_pack_request(
info_url, info_headers, post_url, post_headers, "https://github.com/user/repo",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ test "component impl: upload-pack transport fixture helpers assert request expec
)

let (upload_info_url, upload_info_headers) = upload_pack_info_refs_request(
"git@github.com:user/repo.git", true,
component_impl_fixture_remote_url, true,
)
let (upload_post_url, upload_post_headers) = upload_pack_service_request(
"git@github.com:user/repo.git", true,
component_impl_fixture_remote_url, true,
)
component_impl_assert_upload_pack_request(
upload_info_url, upload_info_headers, upload_post_url, upload_post_headers, "https://github.com/user/repo",
Expand Down
143 changes: 143 additions & 0 deletions modules/bit/src/cmd/bit/commit_graph.mbt
Original file line number Diff line number Diff line change
@@ -1,3 +1,146 @@
///| Commit-graph command handler and utilities

///|
async fn handle_commit_graph(args : Array[String]) -> Unit raise Error {
let fs = OsFs::new()
let git_dir = find_git_dir(fs)
let mut subcommand : String? = None
let mut object_dir : String? = None
let mut reachable = false
let mut stdin_packs = false
let mut stdin_commits = false
let mut append = false
let mut verify_shallow = false
let mut progress = false
let mut i = 0
while i < args.length() {
let arg = args[i]
match arg {
"write" | "verify" => subcommand = Some(arg)
"--reachable" => reachable = true
"--stdin-packs" => stdin_packs = true
"--stdin-commits" => stdin_commits = true
"--append" => append = true
"--shallow" => verify_shallow = true
"--progress" => progress = true
"--no-progress" => progress = false
"--object-dir" if i + 1 < args.length() => {
object_dir = Some(args[i + 1])
i += 2
continue
}
_ if arg.has_prefix("--object-dir=") =>
object_dir = Some(arg[13:].to_owned())
// Accepted but ignored options
"--changed-paths" | "--no-changed-paths" => ()
_ if arg.has_prefix("--max-new-filters") => ()
_ if arg.has_prefix("--split") => ()
_ if arg.has_prefix("--expire-time") => ()
_ if arg.has_prefix("--no-expire-time") => ()
_ if arg.has_prefix("-") => warn_unimplemented_arg("commit-graph", arg)
_ => ()
}
i += 1
}
ignore(append)
ignore(progress)
ignore(verify_shallow)
// --object-dir points to the objects directory; git_dir is one level up.
// If not specified, use the detected git_dir.
let effective_git_dir = match object_dir {
Some(d) => {
let resolved = resolve_in_cwd(d)
// Strip trailing "/objects" suffix if present to get git_dir
if resolved.has_suffix("/objects") {
String::unsafe_substring(
resolved,
start=0,
end=resolved.length() - 8,
)
} else {
// Assume it IS the git_dir (e.g. bare repo)
resolved
}
}
None => git_dir
}
match subcommand {
None | Some("write") => {
if stdin_commits {
write_commit_graph_from_stdin_commits(fs, effective_git_dir)
} else if stdin_packs {
write_commit_graph(fs, effective_git_dir, false)
} else if reachable {
write_commit_graph(fs, effective_git_dir, true)
} else {
write_commit_graph(fs, effective_git_dir, false)
}
}
Some("verify") => cgraph_verify(fs, effective_git_dir)
Some(other) => {
eprint_line("error: unknown subcommand: " + other)
@sys.exit(1)
}
}
}

///|
async fn write_commit_graph_from_stdin_commits(
fs : OsFs,
git_dir : String,
) -> Unit raise Error {
// --stdin-commits: fall back to full reachable walk (stdin parsing not yet implemented)
write_commit_graph(fs, git_dir, true)
}

///|
async fn cgraph_verify(fs : OsFs, git_dir : String) -> Unit raise Error {
let rfs : &@bitcore.RepoFileSystem = fs
let graph_path = git_dir + "/objects/info/commit-graph"
if !rfs.is_file(graph_path) {
eprint_line("error: commit-graph file not found")
@sys.exit(1)
}
let data = rfs.read_file(graph_path)
if data.length() < 8 {
eprint_line("error: commit-graph file too small")
@sys.exit(1)
}
let sig = (data[0].to_int() << 24) |
(data[1].to_int() << 16) |
(data[2].to_int() << 8) |
data[3].to_int()
if sig != 0x43475048 {
eprint_line("error: commit-graph signature mismatch")
@sys.exit(1)
}
let hash_version = data[5].to_int()
let hash_size = if hash_version == 2 { 32 } else { 20 }
let expected_hash_version = commit_graph_repo_hash_version(rfs, git_dir)
if hash_version != expected_hash_version {
eprint_line(
"error: commit-graph hash version \{hash_version} does not match repository hash version \{expected_hash_version}",
)
@sys.exit(1)
}
// Verify checksum trailer
if data.length() < hash_size {
eprint_line("error: commit-graph file too small for checksum")
@sys.exit(1)
}
let body_len = data.length() - hash_size
let stored_trailer = @bitcore.ObjectId::from_bytes_at(
data, body_len, hash_size~,
)
let expected_trailer = @bitcore.hash_prefix(data, body_len, hash_size~)
if stored_trailer != expected_trailer {
eprint_line("error: commit-graph checksum mismatch")
@sys.exit(1)
}
// Verify all commits exist
check_commit_graph_paranoia(fs, git_dir)
}

///| Commit-graph file reader (minimal: header validation + hash version check)

///|
Expand Down
28 changes: 28 additions & 0 deletions modules/bit/src/cmd/bit/commit_graph_write_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,31 @@ async test "cgraph: write_commit_graph uses sha256 trailer in sha256 repo" {
assert_true(graph_file.find_commit(commit_id) >= 0)
cleanup_tree(fs, root)
}

///|
async test "cgraph: verify passes for valid commit-graph" {
@bitnative.init_native_io()
let fs = OsFs::new()
let root = "/tmp/bit-test-cgraph-verify-" + get_current_timestamp().to_string()
cleanup_tree(fs, root)
let (git_dir, _commit_id) = cgraph_setup_sha256_repo(fs, root)
write_commit_graph(fs, git_dir, true)
// verify should not exit(1)
cgraph_verify(fs, git_dir)
cleanup_tree(fs, root)
}

///|
async test "cgraph: handle_commit_graph write --reachable" {
@bitnative.init_native_io()
let fs = OsFs::new()
let root = "/tmp/bit-test-cgraph-cmd-" + get_current_timestamp().to_string()
cleanup_tree(fs, root)
let (git_dir, _) = cgraph_setup_sha256_repo(fs, root)
let graph_path = git_dir + "/objects/info/commit-graph"
assert_false(fs.is_file(graph_path))
// simulate: git commit-graph write --reachable --object-dir <git_dir>/objects
handle_commit_graph(["write", "--reachable", "--object-dir", git_dir + "/objects"])
assert_true(fs.is_file(graph_path))
cleanup_tree(fs, root)
}
Loading
Loading