Skip to content

Commit c135763

Browse files
committed
refactor(hm): read all git fields from one repo+remote open
The inlined accessors re-opened the worktree repo and its origin remote up to three more times on the cloud paths (remoteless registration and auto-create each re-shelled to git). Open repo + origin once in step 7, read branch/commit/repo_name/remote_url/default_branch from that single pair of handles into owned strings, and have the cloud paths reuse those values. Net fewer git subprocesses on cloud runs; local runs pay one extra symbolic-ref for default_branch, which they don't consume.
1 parent 88262a4 commit c135763

1 file changed

Lines changed: 33 additions & 46 deletions

File tree

  • crates/hm/src/commands/run

‎crates/hm/src/commands/run/mod.rs‎

Lines changed: 33 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use anyhow::{Context, Result};
44

55
use bstr::ByteSlice as _;
66
use hm_common::app_runtime::AppRuntime;
7+
use hm_common::git::{GitBranch, GitRemote, GitRepo};
78
use hm_dsl_engine::{DslEngine, detect};
89
use human_units::FormatSize as _;
910

@@ -129,14 +130,18 @@ pub async fn handle(args: RunArgs, ctx: RunContext) -> Result<i32> {
129130
);
130131
}
131132

132-
// 7. Assemble the run request. Read branch, commit, and repo name from git
133-
// in one borrow of `repo_root` (best-effort; an explicit `--branch` wins,
134-
// and missing values fall back to `HEAD` / the zero SHA). The block yields
135-
// owned strings so `repo_root` is free to move into the request below.
136-
let git = AppRuntime::git();
137-
let (branch, commit, repo_name) = {
133+
// 7. Assemble the run request. Open the worktree's repo and its `origin`
134+
// remote once, and read every git-derived field from that single pair of
135+
// handles — all best-effort. An explicit `--branch` wins; a missing branch
136+
// or commit falls back to `HEAD` / the zero SHA. The block yields owned
137+
// strings so `repo_root` can move into the request, and the cloud paths
138+
// below reuse `remote_url` / `default_branch` instead of re-shelling to git.
139+
let (branch, commit, repo_name, remote_url, default_branch) = {
140+
let git = AppRuntime::git();
138141
let repo = git.repo(&repo_root).ok();
139-
let head = repo.as_ref().and_then(hm_common::git::GitRepo::current_branch);
142+
let head = repo.as_ref().and_then(GitRepo::current_branch);
143+
let remote = repo.as_ref().and_then(|r| r.remote("origin"));
144+
140145
let branch = args
141146
.branch
142147
.clone()
@@ -145,15 +150,25 @@ pub async fn handle(args: RunArgs, ctx: RunContext) -> Result<i32> {
145150
.unwrap_or_else(|| "HEAD".to_string());
146151
let commit = head
147152
.as_ref()
148-
.and_then(hm_common::git::GitBranch::head_commit)
153+
.and_then(GitBranch::head_commit)
149154
.map(|c| c.to_str_lossy().into_owned())
150155
.filter(|s| !s.is_empty())
151156
.unwrap_or_else(|| "0".repeat(40));
152-
let repo_name = repo
157+
let repo_name = remote
153158
.as_ref()
154-
.and_then(|r| r.remote("origin")?.gh_repo_name())
159+
.and_then(GitRemote::gh_repo_name)
155160
.map(|n| n.to_str_lossy().into_owned());
156-
(branch, commit, repo_name)
161+
let remote_url = remote
162+
.as_ref()
163+
.map(|r| r.url().to_str_lossy().into_owned())
164+
.filter(|u| !u.is_empty());
165+
// `origin/HEAD`; `None` when unset (fresh clones without `set-head`).
166+
let default_branch = remote
167+
.as_ref()
168+
.and_then(GitRemote::default_branch)
169+
.map(|b| b.name().to_str_lossy().into_owned());
170+
171+
(branch, commit, repo_name, remote_url, default_branch)
157172
};
158173
let mut req = hm_exec::RunRequest {
159174
plan,
@@ -183,20 +198,8 @@ pub async fn handle(args: RunArgs, ctx: RunContext) -> Result<i32> {
183198
if let Some(slug) = ctx.config.cloud.pipeline.clone() {
184199
req.cloud_pipeline_slug = Some(slug);
185200
} else if req.source.repo_name.is_none() {
186-
// Default branch from `origin/HEAD`; falls back to the run's branch
187-
// when unset (fresh clones without `git remote set-head`).
188-
let default_branch = git
189-
.repo(&req.repo_root)
190-
.ok()
191-
.and_then(|r| {
192-
Some(
193-
r.remote("origin")?
194-
.default_branch()?
195-
.name()
196-
.to_str_lossy()
197-
.into_owned(),
198-
)
199-
})
201+
let default_branch = default_branch
202+
.clone()
200203
.unwrap_or_else(|| req.source.branch.clone());
201204
let slug = register_remoteless_pipeline(
202205
client,
@@ -210,32 +213,16 @@ pub async fn handle(args: RunArgs, ctx: RunContext) -> Result<i32> {
210213
}
211214
}
212215

213-
// Cloud-only auto-create context. Borrow `req` here (before it's moved into
214-
// `start`): the repository URL and default branch come from the worktree's
215-
// git remote; the pipeline name is the in-repo source slug.
216+
// Cloud-only auto-create context, from the git fields read in step 7: the
217+
// `origin` remote URL is the pipeline's `repository`, `default_branch` falls
218+
// back to the run's branch, and the pipeline name is the in-repo source slug.
216219
let autocreate = autocreate_client.map(|(client, org)| AutoCreate {
217220
client,
218221
org,
219222
repo_name: req.source.repo_name.clone(),
220-
// The pipeline's `repository`: the worktree's `origin` remote URL.
221-
repository: git.repo(&req.repo_root).ok().and_then(|r| {
222-
let url = r.remote("origin")?.url().to_str_lossy().into_owned();
223-
(!url.is_empty()).then_some(url)
224-
}),
223+
repository: remote_url,
225224
name: req.pipeline_slug.clone(),
226-
default_branch: git
227-
.repo(&req.repo_root)
228-
.ok()
229-
.and_then(|r| {
230-
Some(
231-
r.remote("origin")?
232-
.default_branch()?
233-
.name()
234-
.to_str_lossy()
235-
.into_owned(),
236-
)
237-
})
238-
.unwrap_or_else(|| req.source.branch.clone()),
225+
default_branch: default_branch.unwrap_or_else(|| req.source.branch.clone()),
239226
});
240227

241228
// 8. Start, drive events, own Ctrl-C, await the outcome.

0 commit comments

Comments
 (0)