Skip to content

Commit 57c9ecc

Browse files
committed
Intial support for working with worktrees
1 parent 2a6d566 commit 57c9ecc

File tree

6 files changed

+423
-1
lines changed

6 files changed

+423
-1
lines changed

libgit2-sys/lib.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,34 @@ git_enum! {
17581758
}
17591759
}
17601760

1761+
#[repr(C)]
1762+
pub struct git_worktree_add_options {
1763+
pub version: c_uint,
1764+
pub lock: c_int,
1765+
pub reference: *mut git_reference
1766+
}
1767+
1768+
pub const GIT_WORKTREE_ADD_OPTIONS_VERSION: u32 = 1;
1769+
1770+
git_enum! {
1771+
pub enum git_worktree_prune_t {
1772+
/* Prune working tree even if working tree is valid */
1773+
GIT_WORKTREE_PRUNE_VALID = 1 << 0,
1774+
/* Prune working tree even if it is locked */
1775+
GIT_WORKTREE_PRUNE_LOCKED = 1 << 1,
1776+
/* Prune checked out working tree */
1777+
GIT_WORKTREE_PRUNE_WORKING_TREE = 1 << 2,
1778+
}
1779+
}
1780+
1781+
#[repr(C)]
1782+
pub struct git_worktree_prune_options {
1783+
pub version: c_uint,
1784+
pub flags: u32
1785+
}
1786+
1787+
pub const GIT_WORKTREE_PRUNE_OPTIONS_VERSION: u32 = 1;
1788+
17611789
extern "C" {
17621790
// threads
17631791
pub fn git_libgit2_init() -> c_int;
@@ -3645,6 +3673,27 @@ extern "C" {
36453673
location: git_apply_location_t,
36463674
options: *const git_apply_options,
36473675
) -> c_int;
3676+
3677+
// Worktrees
3678+
pub fn git_worktree_list(out: *mut git_strarray, repo: *mut git_repository) -> c_int;
3679+
pub fn git_worktree_lookup(out: *mut *mut git_worktree, repo: *mut git_repository, name: *const c_char) -> c_int;
3680+
pub fn git_worktree_open_from_repository(out: *mut *mut git_worktree, repo: *mut git_repository) -> c_int;
3681+
pub fn git_worktree_free(wt: *mut git_worktree);
3682+
pub fn git_worktree_validate(wt: *const git_worktree) -> c_int;
3683+
pub fn git_worktree_add_init_options(opts: *mut git_worktree_add_options, version: c_uint) -> c_int;
3684+
pub fn git_worktree_add(out: *mut *mut git_worktree,
3685+
repo: *mut git_repository,
3686+
name: *const c_char,
3687+
path: *const c_char,
3688+
opts: *const git_worktree_add_options) -> c_int;
3689+
pub fn git_worktree_lock(wt: *mut git_worktree, reason: *const c_char) -> c_int;
3690+
pub fn git_worktree_unlock(wt: *mut git_worktree) -> c_int;
3691+
pub fn git_worktree_is_locked(reason: *mut git_buf, wt: *const git_worktree) -> c_int;
3692+
pub fn git_worktree_name(wt: *const git_worktree) -> *const c_char;
3693+
pub fn git_worktree_path(wt: *const git_worktree) -> *const c_char;
3694+
pub fn git_worktree_prune_init_options(opts: *mut git_worktree_prune_options, version: c_uint) -> c_int;
3695+
pub fn git_worktree_is_prunable(wt: *mut git_worktree, opts: *mut git_worktree_prune_options) -> c_int;
3696+
pub fn git_worktree_prune(wt: *mut git_worktree, opts:*mut git_worktree_prune_options) -> c_int;
36483697
}
36493698

36503699
pub fn init() {

src/call.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ mod impls {
9292
self.as_ptr()
9393
}
9494
}
95+
96+
impl Convert<*mut libc::c_char> for CString {
97+
fn convert(&self) -> *mut libc::c_char { self.as_ptr() as *mut libc::c_char }
98+
}
9599

96100
impl<T, U: Convert<*const T>> Convert<*const T> for Option<U> {
97101
fn convert(&self) -> *const T {

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ pub use crate::time::{IndexTime, Time};
129129
pub use crate::tree::{Tree, TreeEntry, TreeIter, TreeWalkMode, TreeWalkResult};
130130
pub use crate::treebuilder::TreeBuilder;
131131
pub use crate::util::IntoCString;
132+
pub use crate::worktree::{Worktree,WorktreeAddOptions,WorktreeLockStatus,WorktreePruneOptions};
133+
132134

133135
// Create a convinience method on bitflag struct which checks the given flag
134136
macro_rules! is_bit_set {
@@ -666,6 +668,7 @@ mod tag;
666668
mod time;
667669
mod tree;
668670
mod treebuilder;
671+
mod worktree;
669672

670673
fn init() {
671674
static INIT: Once = Once::new();

src/repo.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::oid_array::OidArray;
1515
use crate::stash::{stash_cb, StashApplyOptions, StashCbData};
1616
use crate::string_array::StringArray;
1717
use crate::util::{self, path_to_repo_path, Binding};
18+
use crate::worktree::{Worktree, WorktreeAddOptions};
1819
use crate::CherrypickOptions;
1920
use crate::{
2021
init, raw, AttrCheckFlags, Buf, Error, Object, Remote, RepositoryOpenFlags, RepositoryState,
@@ -2700,6 +2701,57 @@ impl Repository {
27002701
Ok(())
27012702
}
27022703
}
2704+
2705+
2706+
/// Lists all the worktrees for the repository
2707+
pub fn worktrees(&self) -> Result<StringArray, Error> {
2708+
let mut arr = raw::git_strarray {
2709+
strings: 0 as *mut *mut c_char,
2710+
count: 0,
2711+
};
2712+
unsafe {
2713+
try_call!(raw::git_worktree_list(&mut arr, self.raw));
2714+
Ok(Binding::from_raw(arr))
2715+
}
2716+
}
2717+
2718+
/// Opens a worktree by name for the given repository
2719+
///
2720+
/// This can open any worktree that the worktrees method returns.
2721+
pub fn worktree_lookup(&self, name: &str) -> Result<Worktree, Error> {
2722+
let mut raw = ptr::null_mut();
2723+
let raw_name = CString::new(name)?;
2724+
unsafe {
2725+
try_call!(raw::git_worktree_lookup(&mut raw, self.raw, raw_name));
2726+
Ok(Binding::from_raw(raw))
2727+
}
2728+
}
2729+
2730+
/// Open a worktree of a the repository
2731+
///
2732+
/// If a repository is not the main tree but a worktree, this
2733+
/// function will look up the worktree inside the parent
2734+
/// repository and create a new `git_worktree` structure.
2735+
pub fn worktree_open_from_repository(&self) -> Result<Worktree, Error> {
2736+
let mut raw = ptr::null_mut();
2737+
unsafe {
2738+
try_call!(raw::git_worktree_open_from_repository(&mut raw, self.raw));
2739+
Ok(Binding::from_raw(raw))
2740+
}
2741+
}
2742+
2743+
/// Creates a new worktree for the repository
2744+
pub fn worktree_add(&self, name: &str, path: &Path, opts: &WorktreeAddOptions<'_>) -> Result<Worktree, Error> {
2745+
let mut raw = ptr::null_mut();
2746+
let raw_name = CString::new(name)?;
2747+
let raw_path = path.into_c_string()?;
2748+
2749+
unsafe {
2750+
try_call!(raw::git_worktree_add(&mut raw, self.raw, raw_name, raw_path, &opts.raw()));
2751+
Ok(Binding::from_raw(raw))
2752+
}
2753+
}
2754+
27032755
}
27042756

27052757
impl Binding for Repository {

src/test.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::ptr;
66
use tempfile::TempDir;
77
use url::Url;
88

9-
use crate::{Oid, Repository};
9+
use crate::{Branch, Oid, Repository};
1010

1111
macro_rules! t {
1212
($e:expr) => {
@@ -54,6 +54,15 @@ pub fn path2url(path: &Path) -> String {
5454
Url::from_file_path(path).unwrap().to_string()
5555
}
5656

57+
pub fn worktrees_env_init(repo: &Repository) -> (TempDir, Branch<'_>) {
58+
let oid = repo.head().unwrap().target().unwrap();
59+
let commit = repo.find_commit(oid).unwrap();
60+
let branch = repo.branch("wt-branch", &commit, true).unwrap();
61+
let wtdir = TempDir::new().unwrap();
62+
(wtdir, branch)
63+
}
64+
65+
5766
#[cfg(windows)]
5867
pub fn realpath(original: &Path) -> io::Result<PathBuf> {
5968
Ok(original.to_path_buf())

0 commit comments

Comments
 (0)