| |
Ok(())
|
| |
}
|
| |
|
| + |
fn patch_base(
|
| + |
head: &git::Oid,
|
| + |
opts: &Options,
|
| + |
stored: &storage::git::Repository,
|
| + |
) -> Result<git::Oid, Error> {
|
| + |
let base = if let Some(base) = opts.base {
|
| + |
base
|
| + |
} else {
|
| + |
// Computation of the canonical head is required only if the user
|
| + |
// did not specify a base explicitly. This allows the user to
|
| + |
// continue updating patches even while the canonical head cannot
|
| + |
// be computed, e.g. while they wait for their fellow delegates
|
| + |
// to converge and sync.
|
| + |
let (_, target) = stored.canonical_head()?;
|
| + |
stored.merge_base(&target, head)?
|
| + |
};
|
| + |
|
| + |
if base == *head {
|
| + |
Err(Error::EmptyPatch)
|
| + |
} else {
|
| + |
Ok(base)
|
| + |
}
|
| + |
}
|
| + |
|
| |
/// Open a new patch.
|
| |
fn patch_open<G>(
|
| |
src: &git::Oid,
|
| |
let head = *src;
|
| |
let dst = git::refs::storage::staging::patch(nid, head);
|
| |
|
| + |
let base = patch_base(&head, &opts, stored)?;
|
| + |
|
| + |
let (title, description) =
|
| + |
term::patch::get_create_message(opts.message, &stored.backend, &base, &head)?;
|
| + |
|
| |
// Before creating the patch, we must push the associated git objects to storage.
|
| |
// Unfortunately, we don't have an easy way to transfer the missing objects without
|
| |
// creating a temporary reference on the remote. The temporary reference is deleted
|
| |
// not fail, since the reference will already exist with the correct OID.
|
| |
push_ref(src, &dst, false, stored.raw(), opts.verbosity)?;
|
| |
|
| - |
let (_, target) = stored.canonical_head()?;
|
| - |
let base = if let Some(base) = opts.base {
|
| - |
base
|
| - |
} else {
|
| - |
stored.merge_base(&target, &head)?
|
| - |
};
|
| - |
if base == head {
|
| - |
return Err(Error::EmptyPatch);
|
| - |
}
|
| - |
let (title, description) =
|
| - |
term::patch::get_create_message(opts.message, &stored.backend, &base, &head)?;
|
| - |
|
| |
let patch = if opts.draft {
|
| |
patches.draft(
|
| |
title,
|
| |
where
|
| |
G: crypto::signature::Signer<crypto::Signature>,
|
| |
{
|
| - |
let commit = *src;
|
| + |
let head = *head;
|
| |
let dst = dst.with_namespace(nid.into());
|
| |
|
| - |
push_ref(src, &dst, force, stored.raw(), opts.verbosity)?;
|
| - |
|
| |
let Ok(Some(patch)) = patches.get(&patch_id) else {
|
| |
return Err(Error::NotFound(patch_id));
|
| |
};
|
| |
|
| + |
let base = patch_base(&head, &opts, stored)?;
|
| + |
|
| |
// Don't update patch if it already has a revision matching this commit.
|
| - |
if patch.revisions().any(|(_, r)| r.head() == commit) {
|
| + |
if patch.revisions().any(|(_, r)| r.head() == head) {
|
| |
return Ok(None);
|
| |
}
|
| |
|
| |
let (latest_id, latest) = patch.latest();
|
| |
let latest = latest.clone();
|
| |
|
| - |
let message = term::patch::get_update_message(opts.message, &stored.backend, &latest, &commit)?;
|
| + |
let message = term::patch::get_update_message(opts.message, &stored.backend, &latest, &head)?;
|
| |
|
| - |
let (_, target) = stored.canonical_head()?;
|
| - |
let head: git::Oid = commit;
|
| - |
let base = if let Some(base) = opts.base {
|
| - |
base
|
| - |
} else {
|
| - |
stored.merge_base(&target, &head)?
|
| - |
};
|
| + |
push_ref(&head, &dst, force, stored.raw(), opts.verbosity)?;
|
| |
|
| |
let mut patch_mut = patch::PatchMut::new(patch_id, patch, &mut patches);
|
| |
let revision = patch_mut.update(message, base, head, signer)?;
|