Skip to content

Commit 21a245c

Browse files
committed
feed correct stdin to pre-push hook
1 parent 8fbd693 commit 21a245c

File tree

5 files changed

+413
-97
lines changed

5 files changed

+413
-97
lines changed

asyncgit/src/sync/hooks.rs

Lines changed: 107 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use super::{repository::repo, RepoPath};
2-
use crate::error::Result;
3-
pub use git2_hooks::PrepareCommitMsgSource;
2+
use crate::{
3+
error::Result, sync::remotes::tags::tags_missing_remote,
4+
};
5+
use git2::BranchType;
6+
pub use git2_hooks::{PrePushRef, PrepareCommitMsgSource};
47
use scopetime::scope_time;
58

69
///
@@ -30,6 +33,38 @@ impl From<git2_hooks::HookResult> for HookResult {
3033
}
3134
}
3235

36+
fn pre_push_branch_update(
37+
repo: &git2::Repository,
38+
remote: Option<&str>,
39+
branch_name: &str,
40+
remote_branch_name: Option<&str>,
41+
delete: bool,
42+
) -> PrePushRef {
43+
let local_ref = format!("refs/heads/{branch_name}");
44+
let local_oid = (!delete)
45+
.then(|| {
46+
repo.find_branch(branch_name, BranchType::Local)
47+
.ok()
48+
.and_then(|branch| branch.get().peel_to_commit().ok())
49+
.map(|commit| commit.id())
50+
})
51+
.flatten();
52+
53+
let remote_branch = remote_branch_name.unwrap_or(branch_name);
54+
let remote_ref = format!("refs/heads/{remote_branch}");
55+
56+
let remote_oid = remote.and_then(|remote_name| {
57+
repo.find_reference(&format!(
58+
"refs/remotes/{remote_name}/{remote_branch}"
59+
))
60+
.ok()
61+
.and_then(|r| r.peel_to_commit().ok())
62+
.map(|c| c.id())
63+
});
64+
65+
PrePushRef::new(local_ref, local_oid, remote_ref, remote_oid)
66+
}
67+
3368
/// see `git2_hooks::hooks_commit_msg`
3469
pub fn hooks_commit_msg(
3570
repo_path: &RepoPath,
@@ -81,22 +116,81 @@ pub fn hooks_pre_push(
81116
repo_path: &RepoPath,
82117
remote: Option<&str>,
83118
url: &str,
84-
branch_name: Option<&str>,
85-
remote_branch_name: Option<&str>,
119+
updates: &[PrePushRef],
86120
) -> Result<HookResult> {
87121
scope_time!("hooks_pre_push");
88122

89123
let repo = repo(repo_path)?;
90124

91-
Ok(git2_hooks::hooks_pre_push(
92-
&repo,
93-
None,
94-
remote,
95-
url,
96-
branch_name,
97-
remote_branch_name,
98-
)?
99-
.into())
125+
Ok(
126+
git2_hooks::hooks_pre_push(
127+
&repo, None, remote, url, updates,
128+
)?
129+
.into(),
130+
)
131+
}
132+
133+
/// Build a single pre-push update line for a branch.
134+
pub fn pre_push_branch_update(
135+
repo_path: &RepoPath,
136+
remote: Option<&str>,
137+
branch_name: &str,
138+
remote_branch_name: Option<&str>,
139+
delete: bool,
140+
) -> Result<PrePushRef> {
141+
let repo = repo(repo_path)?;
142+
let local_ref = format!("refs/heads/{branch_name}");
143+
let local_oid = (!delete)
144+
.then(|| {
145+
repo.find_branch(branch_name, BranchType::Local)
146+
.ok()
147+
.and_then(|branch| branch.get().peel_to_commit().ok())
148+
.map(|commit| commit.id())
149+
})
150+
.flatten();
151+
152+
let remote_branch = remote_branch_name.unwrap_or(branch_name);
153+
let remote_ref = format!("refs/heads/{remote_branch}");
154+
155+
let remote_oid = remote.and_then(|remote_name| {
156+
repo.find_reference(&format!(
157+
"refs/remotes/{remote_name}/{remote_branch}"
158+
))
159+
.ok()
160+
.and_then(|r| r.peel_to_commit().ok())
161+
.map(|c| c.id())
162+
});
163+
164+
Ok(PrePushRef::new(
165+
local_ref, local_oid, remote_ref, remote_oid,
166+
))
167+
}
168+
169+
/// Build pre-push updates for tags that are missing on the remote.
170+
pub fn pre_push_tag_updates(
171+
repo_path: &RepoPath,
172+
remote: &str,
173+
) -> Result<Vec<PrePushRef>> {
174+
let repo = repo(repo_path)?;
175+
let tags = tags_missing_remote(repo_path, remote, None)?;
176+
let mut updates = Vec::with_capacity(tags.len());
177+
178+
for tag_ref in tags {
179+
if let Ok(reference) = repo.find_reference(&tag_ref) {
180+
let tag_oid = reference.target().or_else(|| {
181+
reference.peel_to_commit().ok().map(|c| c.id())
182+
});
183+
184+
updates.push(PrePushRef::new(
185+
tag_ref.clone(),
186+
tag_oid,
187+
tag_ref,
188+
None,
189+
));
190+
}
191+
}
192+
193+
Ok(updates)
100194
}
101195

102196
#[cfg(test)]

asyncgit/src/sync/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ pub use diff::get_diff_commit;
6767
pub use git2::BranchType;
6868
pub use hooks::{
6969
hooks_commit_msg, hooks_post_commit, hooks_pre_commit,
70-
hooks_pre_push, hooks_prepare_commit_msg, HookResult,
70+
hooks_pre_push, hooks_prepare_commit_msg, pre_push_branch_update,
71+
pre_push_tag_updates, HookResult, PrePushRef,
7172
PrepareCommitMsgSource,
7273
};
7374
pub use hunks::{reset_hunk, stage_hunk, unstage_hunk};

0 commit comments

Comments
 (0)