From 96f5057b17312dcb472592eade0c4e9dbc068f14 Mon Sep 17 00:00:00 2001 From: nasso Date: Sat, 12 Nov 2022 01:25:36 -0800 Subject: [PATCH] Add `Reference::symbolic_set_target` --- libgit2-sys/lib.rs | 6 ++++++ src/reference.rs | 37 +++++++++++++++++++++++++++++++++++++ src/repo.rs | 13 +++++++++++++ 3 files changed, 56 insertions(+) diff --git a/libgit2-sys/lib.rs b/libgit2-sys/lib.rs index a113a29526..5e943c0d09 100644 --- a/libgit2-sys/lib.rs +++ b/libgit2-sys/lib.rs @@ -2437,6 +2437,12 @@ extern "C" { id: *const git_oid, log_message: *const c_char, ) -> c_int; + pub fn git_reference_symbolic_set_target( + out: *mut *mut git_reference, + r: *mut git_reference, + target: *const c_char, + log_message: *const c_char, + ) -> c_int; pub fn git_reference_type(r: *const git_reference) -> git_reference_t; pub fn git_reference_iterator_new( out: *mut *mut git_reference_iterator, diff --git a/src/reference.rs b/src/reference.rs index 479252a5cc..e017c8de4d 100644 --- a/src/reference.rs +++ b/src/reference.rs @@ -361,6 +361,35 @@ impl<'repo> Reference<'repo> { Ok(Binding::from_raw(raw)) } } + + /// Create a new reference with the same name as the given reference but a + /// different symbolic target. The reference must be a symbolic reference, + /// otherwise this will fail. + /// + /// The new reference will be written to disk, overwriting the given + /// reference. + /// + /// The target name will be checked for validity. See + /// [`Repository::reference_symbolic`] for rules about valid names. + /// + /// The message for the reflog will be ignored if the reference does not + /// belong in the standard set (HEAD, branches and remote-tracking + /// branches) and it does not have a reflog. + pub fn symbolic_set_target( + &mut self, + target: &str, + reflog_msg: &str, + ) -> Result, Error> { + let mut raw = ptr::null_mut(); + let target = CString::new(target)?; + let msg = CString::new(reflog_msg)?; + unsafe { + try_call!(raw::git_reference_symbolic_set_target( + &mut raw, self.raw, target, msg + )); + Ok(Binding::from_raw(raw)) + } + } } impl<'repo> PartialOrd for Reference<'repo> { @@ -512,6 +541,14 @@ mod tests { .reference_symbolic("refs/tags/tag1", "refs/heads/main", false, "test") .unwrap(); assert_eq!(sym1.kind().unwrap(), ReferenceType::Symbolic); + let mut sym2 = repo + .reference_symbolic("refs/tags/tag2", "refs/heads/main", false, "test") + .unwrap() + .symbolic_set_target("refs/tags/tag1", "test") + .unwrap(); + assert_eq!(sym2.kind().unwrap(), ReferenceType::Symbolic); + assert_eq!(sym2.symbolic_target().unwrap(), "refs/tags/tag1"); + sym2.delete().unwrap(); sym1.delete().unwrap(); { diff --git a/src/repo.rs b/src/repo.rs index f0be8c5a76..98d450a075 100644 --- a/src/repo.rs +++ b/src/repo.rs @@ -1480,6 +1480,19 @@ impl Repository { /// Create a new symbolic reference. /// + /// A symbolic reference is a reference name that refers to another + /// reference name. If the other name moves, the symbolic name will move, + /// too. As a simple example, the "HEAD" reference might refer to + /// "refs/heads/master" while on the "master" branch of a repository. + /// + /// Valid reference names must follow one of two patterns: + /// + /// 1. Top-level names must contain only capital letters and underscores, + /// and must begin and end with a letter. (e.g. "HEAD", "ORIG_HEAD"). + /// 2. Names prefixed with "refs/" can be almost anything. You must avoid + /// the characters '~', '^', ':', '\\', '?', '[', and '*', and the + /// sequences ".." and "@{" which have special meaning to revparse. + /// /// This function will return an error if a reference already exists with /// the given name unless force is true, in which case it will be /// overwritten.