1 use libc::{c_char, c_int, c_uint, c_void, size_t};
2 use std::env;
3 use std::ffi::{CStr, CString, OsStr};
4 use std::iter::IntoIterator;
5 use std::mem;
6 use std::path::Path;
7 use std::ptr;
8 use std::str;
9 
10 use crate::build::{CheckoutBuilder, RepoBuilder};
11 use crate::diff::{
12     binary_cb_c, file_cb_c, hunk_cb_c, line_cb_c, BinaryCb, DiffCallbacks, FileCb, HunkCb, LineCb,
13 };
14 use crate::oid_array::OidArray;
15 use crate::stash::{stash_cb, StashApplyOptions, StashCbData};
16 use crate::string_array::StringArray;
17 use crate::tagforeach::{tag_foreach_cb, TagForeachCB, TagForeachData};
18 use crate::util::{self, path_to_repo_path, Binding};
19 use crate::worktree::{Worktree, WorktreeAddOptions};
20 use crate::CherrypickOptions;
21 use crate::RevertOptions;
22 use crate::{mailmap::Mailmap, panic};
23 use crate::{
24     raw, AttrCheckFlags, Buf, Error, Object, Remote, RepositoryOpenFlags, RepositoryState, Revspec,
25     StashFlags,
26 };
27 use crate::{
28     AnnotatedCommit, MergeAnalysis, MergeOptions, MergePreference, SubmoduleIgnore,
29     SubmoduleStatus, SubmoduleUpdate,
30 };
31 use crate::{ApplyLocation, ApplyOptions, Rebase, RebaseOptions};
32 use crate::{Blame, BlameOptions, Reference, References, ResetType, Signature, Submodule};
33 use crate::{Blob, BlobWriter, Branch, BranchType, Branches, Commit, Config, Index, Oid, Tree};
34 use crate::{Describe, IntoCString, Reflog, RepositoryInitMode, RevparseMode};
35 use crate::{DescribeOptions, Diff, DiffOptions, Odb, PackBuilder, TreeBuilder};
36 use crate::{Note, Notes, ObjectType, Revwalk, Status, StatusOptions, Statuses, Tag, Transaction};
37 
38 type MergeheadForeachCb<'a> = dyn FnMut(&Oid) -> bool + 'a;
39 type FetchheadForeachCb<'a> = dyn FnMut(&str, &[u8], &Oid, bool) -> bool + 'a;
40 
41 struct FetchheadForeachCbData<'a> {
42     callback: &'a mut FetchheadForeachCb<'a>,
43 }
44 
45 struct MergeheadForeachCbData<'a> {
46     callback: &'a mut MergeheadForeachCb<'a>,
47 }
48 
mergehead_foreach_cb(oid: *const raw::git_oid, payload: *mut c_void) -> c_int49 extern "C" fn mergehead_foreach_cb(oid: *const raw::git_oid, payload: *mut c_void) -> c_int {
50     panic::wrap(|| unsafe {
51         let data = &mut *(payload as *mut MergeheadForeachCbData<'_>);
52         let res = {
53             let callback = &mut data.callback;
54             callback(&Binding::from_raw(oid))
55         };
56 
57         if res {
58             0
59         } else {
60             1
61         }
62     })
63     .unwrap_or(1)
64 }
65 
fetchhead_foreach_cb( ref_name: *const c_char, remote_url: *const c_char, oid: *const raw::git_oid, is_merge: c_uint, payload: *mut c_void, ) -> c_int66 extern "C" fn fetchhead_foreach_cb(
67     ref_name: *const c_char,
68     remote_url: *const c_char,
69     oid: *const raw::git_oid,
70     is_merge: c_uint,
71     payload: *mut c_void,
72 ) -> c_int {
73     panic::wrap(|| unsafe {
74         let data = &mut *(payload as *mut FetchheadForeachCbData<'_>);
75         let res = {
76             let callback = &mut data.callback;
77 
78             assert!(!ref_name.is_null());
79             assert!(!remote_url.is_null());
80             assert!(!oid.is_null());
81 
82             let ref_name = str::from_utf8(CStr::from_ptr(ref_name).to_bytes()).unwrap();
83             let remote_url = CStr::from_ptr(remote_url).to_bytes();
84             let oid = Binding::from_raw(oid);
85             let is_merge = is_merge == 1;
86 
87             callback(&ref_name, remote_url, &oid, is_merge)
88         };
89 
90         if res {
91             0
92         } else {
93             1
94         }
95     })
96     .unwrap_or(1)
97 }
98 
99 /// An owned git repository, representing all state associated with the
100 /// underlying filesystem.
101 ///
102 /// This structure corresponds to a `git_repository` in libgit2. Many other
103 /// types in git2-rs are derivative from this structure and are attached to its
104 /// lifetime.
105 ///
106 /// When a repository goes out of scope it is freed in memory but not deleted
107 /// from the filesystem.
108 pub struct Repository {
109     raw: *mut raw::git_repository,
110 }
111 
112 // It is the current belief that a `Repository` can be sent among threads, or
113 // even shared among threads in a mutex.
114 unsafe impl Send for Repository {}
115 
116 /// Options which can be used to configure how a repository is initialized
117 pub struct RepositoryInitOptions {
118     flags: u32,
119     mode: u32,
120     workdir_path: Option<CString>,
121     description: Option<CString>,
122     template_path: Option<CString>,
123     initial_head: Option<CString>,
124     origin_url: Option<CString>,
125 }
126 
127 impl Repository {
128     /// Attempt to open an already-existing repository at `path`.
129     ///
130     /// The path can point to either a normal or bare repository.
open<P: AsRef<Path>>(path: P) -> Result<Repository, Error>131     pub fn open<P: AsRef<Path>>(path: P) -> Result<Repository, Error> {
132         crate::init();
133         // Normal file path OK (does not need Windows conversion).
134         let path = path.as_ref().into_c_string()?;
135         let mut ret = ptr::null_mut();
136         unsafe {
137             try_call!(raw::git_repository_open(&mut ret, path));
138             Ok(Binding::from_raw(ret))
139         }
140     }
141 
142     /// Attempt to open an already-existing bare repository at `path`.
143     ///
144     /// The path can point to only a bare repository.
open_bare<P: AsRef<Path>>(path: P) -> Result<Repository, Error>145     pub fn open_bare<P: AsRef<Path>>(path: P) -> Result<Repository, Error> {
146         crate::init();
147         // Normal file path OK (does not need Windows conversion).
148         let path = path.as_ref().into_c_string()?;
149         let mut ret = ptr::null_mut();
150         unsafe {
151             try_call!(raw::git_repository_open_bare(&mut ret, path));
152             Ok(Binding::from_raw(ret))
153         }
154     }
155 
156     /// Find and open an existing repository, respecting git environment
157     /// variables.  This acts like `open_ext` with the
158     /// `REPOSITORY_OPEN_FROM_ENV` flag, but additionally respects `$GIT_DIR`.
159     /// With `$GIT_DIR` unset, this will search for a repository starting in
160     /// the current directory.
open_from_env() -> Result<Repository, Error>161     pub fn open_from_env() -> Result<Repository, Error> {
162         crate::init();
163         let mut ret = ptr::null_mut();
164         let flags = raw::GIT_REPOSITORY_OPEN_FROM_ENV;
165         unsafe {
166             try_call!(raw::git_repository_open_ext(
167                 &mut ret,
168                 ptr::null(),
169                 flags as c_uint,
170                 ptr::null()
171             ));
172             Ok(Binding::from_raw(ret))
173         }
174     }
175 
176     /// Find and open an existing repository, with additional options.
177     ///
178     /// If flags contains REPOSITORY_OPEN_NO_SEARCH, the path must point
179     /// directly to a repository; otherwise, this may point to a subdirectory
180     /// of a repository, and `open_ext` will search up through parent
181     /// directories.
182     ///
183     /// If flags contains REPOSITORY_OPEN_CROSS_FS, the search through parent
184     /// directories will not cross a filesystem boundary (detected when the
185     /// stat st_dev field changes).
186     ///
187     /// If flags contains REPOSITORY_OPEN_BARE, force opening the repository as
188     /// bare even if it isn't, ignoring any working directory, and defer
189     /// loading the repository configuration for performance.
190     ///
191     /// If flags contains REPOSITORY_OPEN_NO_DOTGIT, don't try appending
192     /// `/.git` to `path`.
193     ///
194     /// If flags contains REPOSITORY_OPEN_FROM_ENV, `open_ext` will ignore
195     /// other flags and `ceiling_dirs`, and respect the same environment
196     /// variables git does. Note, however, that `path` overrides `$GIT_DIR`; to
197     /// respect `$GIT_DIR` as well, use `open_from_env`.
198     ///
199     /// ceiling_dirs specifies a list of paths that the search through parent
200     /// directories will stop before entering.  Use the functions in std::env
201     /// to construct or manipulate such a path list.
open_ext<P, O, I>( path: P, flags: RepositoryOpenFlags, ceiling_dirs: I, ) -> Result<Repository, Error> where P: AsRef<Path>, O: AsRef<OsStr>, I: IntoIterator<Item = O>,202     pub fn open_ext<P, O, I>(
203         path: P,
204         flags: RepositoryOpenFlags,
205         ceiling_dirs: I,
206     ) -> Result<Repository, Error>
207     where
208         P: AsRef<Path>,
209         O: AsRef<OsStr>,
210         I: IntoIterator<Item = O>,
211     {
212         crate::init();
213         // Normal file path OK (does not need Windows conversion).
214         let path = path.as_ref().into_c_string()?;
215         let ceiling_dirs_os = env::join_paths(ceiling_dirs)?;
216         let ceiling_dirs = ceiling_dirs_os.into_c_string()?;
217         let mut ret = ptr::null_mut();
218         unsafe {
219             try_call!(raw::git_repository_open_ext(
220                 &mut ret,
221                 path,
222                 flags.bits() as c_uint,
223                 ceiling_dirs
224             ));
225             Ok(Binding::from_raw(ret))
226         }
227     }
228 
229     /// Attempt to open an already-existing repository from a worktree.
open_from_worktree(worktree: &Worktree) -> Result<Repository, Error>230     pub fn open_from_worktree(worktree: &Worktree) -> Result<Repository, Error> {
231         let mut ret = ptr::null_mut();
232         unsafe {
233             try_call!(raw::git_repository_open_from_worktree(
234                 &mut ret,
235                 worktree.raw()
236             ));
237             Ok(Binding::from_raw(ret))
238         }
239     }
240 
241     /// Attempt to open an already-existing repository at or above `path`
242     ///
243     /// This starts at `path` and looks up the filesystem hierarchy
244     /// until it finds a repository.
discover<P: AsRef<Path>>(path: P) -> Result<Repository, Error>245     pub fn discover<P: AsRef<Path>>(path: P) -> Result<Repository, Error> {
246         // TODO: this diverges significantly from the libgit2 API
247         crate::init();
248         let buf = Buf::new();
249         // Normal file path OK (does not need Windows conversion).
250         let path = path.as_ref().into_c_string()?;
251         unsafe {
252             try_call!(raw::git_repository_discover(
253                 buf.raw(),
254                 path,
255                 1,
256                 ptr::null()
257             ));
258         }
259         Repository::open(util::bytes2path(&*buf))
260     }
261 
262     /// Creates a new repository in the specified folder.
263     ///
264     /// This by default will create any necessary directories to create the
265     /// repository, and it will read any user-specified templates when creating
266     /// the repository. This behavior can be configured through `init_opts`.
init<P: AsRef<Path>>(path: P) -> Result<Repository, Error>267     pub fn init<P: AsRef<Path>>(path: P) -> Result<Repository, Error> {
268         Repository::init_opts(path, &RepositoryInitOptions::new())
269     }
270 
271     /// Creates a new `--bare` repository in the specified folder.
272     ///
273     /// The folder must exist prior to invoking this function.
init_bare<P: AsRef<Path>>(path: P) -> Result<Repository, Error>274     pub fn init_bare<P: AsRef<Path>>(path: P) -> Result<Repository, Error> {
275         Repository::init_opts(path, RepositoryInitOptions::new().bare(true))
276     }
277 
278     /// Creates a new repository in the specified folder with the given options.
279     ///
280     /// See `RepositoryInitOptions` struct for more information.
init_opts<P: AsRef<Path>>( path: P, opts: &RepositoryInitOptions, ) -> Result<Repository, Error>281     pub fn init_opts<P: AsRef<Path>>(
282         path: P,
283         opts: &RepositoryInitOptions,
284     ) -> Result<Repository, Error> {
285         crate::init();
286         // Normal file path OK (does not need Windows conversion).
287         let path = path.as_ref().into_c_string()?;
288         let mut ret = ptr::null_mut();
289         unsafe {
290             let mut opts = opts.raw();
291             try_call!(raw::git_repository_init_ext(&mut ret, path, &mut opts));
292             Ok(Binding::from_raw(ret))
293         }
294     }
295 
296     /// Clone a remote repository.
297     ///
298     /// See the `RepoBuilder` struct for more information. This function will
299     /// delegate to a fresh `RepoBuilder`
clone<P: AsRef<Path>>(url: &str, into: P) -> Result<Repository, Error>300     pub fn clone<P: AsRef<Path>>(url: &str, into: P) -> Result<Repository, Error> {
301         crate::init();
302         RepoBuilder::new().clone(url, into.as_ref())
303     }
304 
305     /// Clone a remote repository, initialize and update its submodules
306     /// recursively.
307     ///
308     /// This is similar to `git clone --recursive`.
clone_recurse<P: AsRef<Path>>(url: &str, into: P) -> Result<Repository, Error>309     pub fn clone_recurse<P: AsRef<Path>>(url: &str, into: P) -> Result<Repository, Error> {
310         let repo = Repository::clone(url, into)?;
311         repo.update_submodules()?;
312         Ok(repo)
313     }
314 
315     /// Attempt to wrap an object database as a repository.
from_odb(odb: Odb<'_>) -> Result<Repository, Error>316     pub fn from_odb(odb: Odb<'_>) -> Result<Repository, Error> {
317         crate::init();
318         let mut ret = ptr::null_mut();
319         unsafe {
320             try_call!(raw::git_repository_wrap_odb(&mut ret, odb.raw()));
321             Ok(Binding::from_raw(ret))
322         }
323     }
324 
325     /// Update submodules recursively.
326     ///
327     /// Uninitialized submodules will be initialized.
update_submodules(&self) -> Result<(), Error>328     fn update_submodules(&self) -> Result<(), Error> {
329         fn add_subrepos(repo: &Repository, list: &mut Vec<Repository>) -> Result<(), Error> {
330             for mut subm in repo.submodules()? {
331                 subm.update(true, None)?;
332                 list.push(subm.open()?);
333             }
334             Ok(())
335         }
336 
337         let mut repos = Vec::new();
338         add_subrepos(self, &mut repos)?;
339         while let Some(repo) = repos.pop() {
340             add_subrepos(&repo, &mut repos)?;
341         }
342         Ok(())
343     }
344 
345     /// Execute a rev-parse operation against the `spec` listed.
346     ///
347     /// The resulting revision specification is returned, or an error is
348     /// returned if one occurs.
revparse(&self, spec: &str) -> Result<Revspec<'_>, Error>349     pub fn revparse(&self, spec: &str) -> Result<Revspec<'_>, Error> {
350         let mut raw = raw::git_revspec {
351             from: ptr::null_mut(),
352             to: ptr::null_mut(),
353             flags: 0,
354         };
355         let spec = CString::new(spec)?;
356         unsafe {
357             try_call!(raw::git_revparse(&mut raw, self.raw, spec));
358             let to = Binding::from_raw_opt(raw.to);
359             let from = Binding::from_raw_opt(raw.from);
360             let mode = RevparseMode::from_bits_truncate(raw.flags as u32);
361             Ok(Revspec::from_objects(from, to, mode))
362         }
363     }
364 
365     /// Find a single object, as specified by a revision string.
revparse_single(&self, spec: &str) -> Result<Object<'_>, Error>366     pub fn revparse_single(&self, spec: &str) -> Result<Object<'_>, Error> {
367         let spec = CString::new(spec)?;
368         let mut obj = ptr::null_mut();
369         unsafe {
370             try_call!(raw::git_revparse_single(&mut obj, self.raw, spec));
371             assert!(!obj.is_null());
372             Ok(Binding::from_raw(obj))
373         }
374     }
375 
376     /// Find a single object and intermediate reference by a revision string.
377     ///
378     /// See `man gitrevisions`, or
379     /// <http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions> for
380     /// information on the syntax accepted.
381     ///
382     /// In some cases (`@{<-n>}` or `<branchname>@{upstream}`), the expression
383     /// may point to an intermediate reference. When such expressions are being
384     /// passed in, this intermediate reference is returned.
revparse_ext(&self, spec: &str) -> Result<(Object<'_>, Option<Reference<'_>>), Error>385     pub fn revparse_ext(&self, spec: &str) -> Result<(Object<'_>, Option<Reference<'_>>), Error> {
386         let spec = CString::new(spec)?;
387         let mut git_obj = ptr::null_mut();
388         let mut git_ref = ptr::null_mut();
389         unsafe {
390             try_call!(raw::git_revparse_ext(
391                 &mut git_obj,
392                 &mut git_ref,
393                 self.raw,
394                 spec
395             ));
396             assert!(!git_obj.is_null());
397             Ok((Binding::from_raw(git_obj), Binding::from_raw_opt(git_ref)))
398         }
399     }
400 
401     /// Tests whether this repository is a bare repository or not.
is_bare(&self) -> bool402     pub fn is_bare(&self) -> bool {
403         unsafe { raw::git_repository_is_bare(self.raw) == 1 }
404     }
405 
406     /// Tests whether this repository is a shallow clone.
is_shallow(&self) -> bool407     pub fn is_shallow(&self) -> bool {
408         unsafe { raw::git_repository_is_shallow(self.raw) == 1 }
409     }
410 
411     /// Tests whether this repository is a worktree.
is_worktree(&self) -> bool412     pub fn is_worktree(&self) -> bool {
413         unsafe { raw::git_repository_is_worktree(self.raw) == 1 }
414     }
415 
416     /// Tests whether this repository is empty.
is_empty(&self) -> Result<bool, Error>417     pub fn is_empty(&self) -> Result<bool, Error> {
418         let empty = unsafe { try_call!(raw::git_repository_is_empty(self.raw)) };
419         Ok(empty == 1)
420     }
421 
422     /// Returns the path to the `.git` folder for normal repositories or the
423     /// repository itself for bare repositories.
path(&self) -> &Path424     pub fn path(&self) -> &Path {
425         unsafe {
426             let ptr = raw::git_repository_path(self.raw);
427             util::bytes2path(crate::opt_bytes(self, ptr).unwrap())
428         }
429     }
430 
431     /// Returns the current state of this repository
state(&self) -> RepositoryState432     pub fn state(&self) -> RepositoryState {
433         let state = unsafe { raw::git_repository_state(self.raw) };
434         macro_rules! check( ($($raw:ident => $real:ident),*) => (
435             $(if state == raw::$raw as c_int {
436                 super::RepositoryState::$real
437             }) else *
438             else {
439                 panic!("unknown repository state: {}", state)
440             }
441         ) );
442 
443         check!(
444             GIT_REPOSITORY_STATE_NONE => Clean,
445             GIT_REPOSITORY_STATE_MERGE => Merge,
446             GIT_REPOSITORY_STATE_REVERT => Revert,
447             GIT_REPOSITORY_STATE_REVERT_SEQUENCE => RevertSequence,
448             GIT_REPOSITORY_STATE_CHERRYPICK => CherryPick,
449             GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE => CherryPickSequence,
450             GIT_REPOSITORY_STATE_BISECT => Bisect,
451             GIT_REPOSITORY_STATE_REBASE => Rebase,
452             GIT_REPOSITORY_STATE_REBASE_INTERACTIVE => RebaseInteractive,
453             GIT_REPOSITORY_STATE_REBASE_MERGE => RebaseMerge,
454             GIT_REPOSITORY_STATE_APPLY_MAILBOX => ApplyMailbox,
455             GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE => ApplyMailboxOrRebase
456         )
457     }
458 
459     /// Get the path of the working directory for this repository.
460     ///
461     /// If this repository is bare, then `None` is returned.
workdir(&self) -> Option<&Path>462     pub fn workdir(&self) -> Option<&Path> {
463         unsafe {
464             let ptr = raw::git_repository_workdir(self.raw);
465             if ptr.is_null() {
466                 None
467             } else {
468                 Some(util::bytes2path(CStr::from_ptr(ptr).to_bytes()))
469             }
470         }
471     }
472 
473     /// Set the path to the working directory for this repository.
474     ///
475     /// If `update_link` is true, create/update the gitlink file in the workdir
476     /// and set config "core.worktree" (if workdir is not the parent of the .git
477     /// directory).
set_workdir(&self, path: &Path, update_gitlink: bool) -> Result<(), Error>478     pub fn set_workdir(&self, path: &Path, update_gitlink: bool) -> Result<(), Error> {
479         // Normal file path OK (does not need Windows conversion).
480         let path = path.into_c_string()?;
481         unsafe {
482             try_call!(raw::git_repository_set_workdir(
483                 self.raw(),
484                 path,
485                 update_gitlink
486             ));
487         }
488         Ok(())
489     }
490 
491     /// Get the currently active namespace for this repository.
492     ///
493     /// If there is no namespace, or the namespace is not a valid utf8 string,
494     /// `None` is returned.
namespace(&self) -> Option<&str>495     pub fn namespace(&self) -> Option<&str> {
496         self.namespace_bytes().and_then(|s| str::from_utf8(s).ok())
497     }
498 
499     /// Get the currently active namespace for this repository as a byte array.
500     ///
501     /// If there is no namespace, `None` is returned.
namespace_bytes(&self) -> Option<&[u8]>502     pub fn namespace_bytes(&self) -> Option<&[u8]> {
503         unsafe { crate::opt_bytes(self, raw::git_repository_get_namespace(self.raw)) }
504     }
505 
506     /// Set the active namespace for this repository.
set_namespace(&self, namespace: &str) -> Result<(), Error>507     pub fn set_namespace(&self, namespace: &str) -> Result<(), Error> {
508         self.set_namespace_bytes(namespace.as_bytes())
509     }
510 
511     /// Set the active namespace for this repository as a byte array.
set_namespace_bytes(&self, namespace: &[u8]) -> Result<(), Error>512     pub fn set_namespace_bytes(&self, namespace: &[u8]) -> Result<(), Error> {
513         unsafe {
514             let namespace = CString::new(namespace)?;
515             try_call!(raw::git_repository_set_namespace(self.raw, namespace));
516             Ok(())
517         }
518     }
519 
520     /// Remove the active namespace for this repository.
remove_namespace(&self) -> Result<(), Error>521     pub fn remove_namespace(&self) -> Result<(), Error> {
522         unsafe {
523             try_call!(raw::git_repository_set_namespace(self.raw, ptr::null()));
524             Ok(())
525         }
526     }
527 
528     /// Retrieves the Git merge message.
529     /// Remember to remove the message when finished.
message(&self) -> Result<String, Error>530     pub fn message(&self) -> Result<String, Error> {
531         unsafe {
532             let buf = Buf::new();
533             try_call!(raw::git_repository_message(buf.raw(), self.raw));
534             Ok(str::from_utf8(&buf).unwrap().to_string())
535         }
536     }
537 
538     /// Remove the Git merge message.
remove_message(&self) -> Result<(), Error>539     pub fn remove_message(&self) -> Result<(), Error> {
540         unsafe {
541             try_call!(raw::git_repository_message_remove(self.raw));
542             Ok(())
543         }
544     }
545 
546     /// List all remotes for a given repository
remotes(&self) -> Result<StringArray, Error>547     pub fn remotes(&self) -> Result<StringArray, Error> {
548         let mut arr = raw::git_strarray {
549             strings: ptr::null_mut(),
550             count: 0,
551         };
552         unsafe {
553             try_call!(raw::git_remote_list(&mut arr, self.raw));
554             Ok(Binding::from_raw(arr))
555         }
556     }
557 
558     /// Get the information for a particular remote
find_remote(&self, name: &str) -> Result<Remote<'_>, Error>559     pub fn find_remote(&self, name: &str) -> Result<Remote<'_>, Error> {
560         let mut ret = ptr::null_mut();
561         let name = CString::new(name)?;
562         unsafe {
563             try_call!(raw::git_remote_lookup(&mut ret, self.raw, name));
564             Ok(Binding::from_raw(ret))
565         }
566     }
567 
568     /// Add a remote with the default fetch refspec to the repository's
569     /// configuration.
remote(&self, name: &str, url: &str) -> Result<Remote<'_>, Error>570     pub fn remote(&self, name: &str, url: &str) -> Result<Remote<'_>, Error> {
571         let mut ret = ptr::null_mut();
572         let name = CString::new(name)?;
573         let url = CString::new(url)?;
574         unsafe {
575             try_call!(raw::git_remote_create(&mut ret, self.raw, name, url));
576             Ok(Binding::from_raw(ret))
577         }
578     }
579 
580     /// Add a remote with the provided fetch refspec to the repository's
581     /// configuration.
remote_with_fetch( &self, name: &str, url: &str, fetch: &str, ) -> Result<Remote<'_>, Error>582     pub fn remote_with_fetch(
583         &self,
584         name: &str,
585         url: &str,
586         fetch: &str,
587     ) -> Result<Remote<'_>, Error> {
588         let mut ret = ptr::null_mut();
589         let name = CString::new(name)?;
590         let url = CString::new(url)?;
591         let fetch = CString::new(fetch)?;
592         unsafe {
593             try_call!(raw::git_remote_create_with_fetchspec(
594                 &mut ret, self.raw, name, url, fetch
595             ));
596             Ok(Binding::from_raw(ret))
597         }
598     }
599 
600     /// Create an anonymous remote
601     ///
602     /// Create a remote with the given url and refspec in memory. You can use
603     /// this when you have a URL instead of a remote's name. Note that anonymous
604     /// remotes cannot be converted to persisted remotes.
remote_anonymous(&self, url: &str) -> Result<Remote<'_>, Error>605     pub fn remote_anonymous(&self, url: &str) -> Result<Remote<'_>, Error> {
606         let mut ret = ptr::null_mut();
607         let url = CString::new(url)?;
608         unsafe {
609             try_call!(raw::git_remote_create_anonymous(&mut ret, self.raw, url));
610             Ok(Binding::from_raw(ret))
611         }
612     }
613 
614     /// Give a remote a new name
615     ///
616     /// All remote-tracking branches and configuration settings for the remote
617     /// are updated.
618     ///
619     /// A temporary in-memory remote cannot be given a name with this method.
620     ///
621     /// No loaded instances of the remote with the old name will change their
622     /// name or their list of refspecs.
623     ///
624     /// The returned array of strings is a list of the non-default refspecs
625     /// which cannot be renamed and are returned for further processing by the
626     /// caller.
remote_rename(&self, name: &str, new_name: &str) -> Result<StringArray, Error>627     pub fn remote_rename(&self, name: &str, new_name: &str) -> Result<StringArray, Error> {
628         let name = CString::new(name)?;
629         let new_name = CString::new(new_name)?;
630         let mut problems = raw::git_strarray {
631             count: 0,
632             strings: ptr::null_mut(),
633         };
634         unsafe {
635             try_call!(raw::git_remote_rename(
636                 &mut problems,
637                 self.raw,
638                 name,
639                 new_name
640             ));
641             Ok(Binding::from_raw(problems))
642         }
643     }
644 
645     /// Delete an existing persisted remote.
646     ///
647     /// All remote-tracking branches and configuration settings for the remote
648     /// will be removed.
remote_delete(&self, name: &str) -> Result<(), Error>649     pub fn remote_delete(&self, name: &str) -> Result<(), Error> {
650         let name = CString::new(name)?;
651         unsafe {
652             try_call!(raw::git_remote_delete(self.raw, name));
653         }
654         Ok(())
655     }
656 
657     /// Add a fetch refspec to the remote's configuration
658     ///
659     /// Add the given refspec to the fetch list in the configuration. No loaded
660     /// remote instances will be affected.
remote_add_fetch(&self, name: &str, spec: &str) -> Result<(), Error>661     pub fn remote_add_fetch(&self, name: &str, spec: &str) -> Result<(), Error> {
662         let name = CString::new(name)?;
663         let spec = CString::new(spec)?;
664         unsafe {
665             try_call!(raw::git_remote_add_fetch(self.raw, name, spec));
666         }
667         Ok(())
668     }
669 
670     /// Add a push refspec to the remote's configuration.
671     ///
672     /// Add the given refspec to the push list in the configuration. No
673     /// loaded remote instances will be affected.
remote_add_push(&self, name: &str, spec: &str) -> Result<(), Error>674     pub fn remote_add_push(&self, name: &str, spec: &str) -> Result<(), Error> {
675         let name = CString::new(name)?;
676         let spec = CString::new(spec)?;
677         unsafe {
678             try_call!(raw::git_remote_add_push(self.raw, name, spec));
679         }
680         Ok(())
681     }
682 
683     /// Set the remote's url in the configuration
684     ///
685     /// Remote objects already in memory will not be affected. This assumes
686     /// the common case of a single-url remote and will otherwise return an
687     /// error.
remote_set_url(&self, name: &str, url: &str) -> Result<(), Error>688     pub fn remote_set_url(&self, name: &str, url: &str) -> Result<(), Error> {
689         let name = CString::new(name)?;
690         let url = CString::new(url)?;
691         unsafe {
692             try_call!(raw::git_remote_set_url(self.raw, name, url));
693         }
694         Ok(())
695     }
696 
697     /// Set the remote's url for pushing in the configuration.
698     ///
699     /// Remote objects already in memory will not be affected. This assumes
700     /// the common case of a single-url remote and will otherwise return an
701     /// error.
702     ///
703     /// `None` indicates that it should be cleared.
remote_set_pushurl(&self, name: &str, pushurl: Option<&str>) -> Result<(), Error>704     pub fn remote_set_pushurl(&self, name: &str, pushurl: Option<&str>) -> Result<(), Error> {
705         let name = CString::new(name)?;
706         let pushurl = crate::opt_cstr(pushurl)?;
707         unsafe {
708             try_call!(raw::git_remote_set_pushurl(self.raw, name, pushurl));
709         }
710         Ok(())
711     }
712 
713     /// Sets the current head to the specified object and optionally resets
714     /// the index and working tree to match.
715     ///
716     /// A soft reset means the head will be moved to the commit.
717     ///
718     /// A mixed reset will trigger a soft reset, plus the index will be
719     /// replaced with the content of the commit tree.
720     ///
721     /// A hard reset will trigger a mixed reset and the working directory will
722     /// be replaced with the content of the index. (Untracked and ignored files
723     /// will be left alone, however.)
724     ///
725     /// The `target` is a commit-ish to which the head should be moved to. The
726     /// object can either be a commit or a tag, but tags must be dereferenceable
727     /// to a commit.
728     ///
729     /// The `checkout` options will only be used for a hard reset.
reset( &self, target: &Object<'_>, kind: ResetType, checkout: Option<&mut CheckoutBuilder<'_>>, ) -> Result<(), Error>730     pub fn reset(
731         &self,
732         target: &Object<'_>,
733         kind: ResetType,
734         checkout: Option<&mut CheckoutBuilder<'_>>,
735     ) -> Result<(), Error> {
736         unsafe {
737             let mut opts: raw::git_checkout_options = mem::zeroed();
738             try_call!(raw::git_checkout_init_options(
739                 &mut opts,
740                 raw::GIT_CHECKOUT_OPTIONS_VERSION
741             ));
742             let opts = checkout.map(|c| {
743                 c.configure(&mut opts);
744                 &mut opts
745             });
746             try_call!(raw::git_reset(self.raw, target.raw(), kind, opts));
747         }
748         Ok(())
749     }
750 
751     /// Updates some entries in the index from the target commit tree.
752     ///
753     /// The scope of the updated entries is determined by the paths being
754     /// in the iterator provided.
755     ///
756     /// Passing a `None` target will result in removing entries in the index
757     /// matching the provided pathspecs.
reset_default<T, I>(&self, target: Option<&Object<'_>>, paths: I) -> Result<(), Error> where T: IntoCString, I: IntoIterator<Item = T>,758     pub fn reset_default<T, I>(&self, target: Option<&Object<'_>>, paths: I) -> Result<(), Error>
759     where
760         T: IntoCString,
761         I: IntoIterator<Item = T>,
762     {
763         let (_a, _b, mut arr) = crate::util::iter2cstrs_paths(paths)?;
764         let target = target.map(|t| t.raw());
765         unsafe {
766             try_call!(raw::git_reset_default(self.raw, target, &mut arr));
767         }
768         Ok(())
769     }
770 
771     /// Retrieve and resolve the reference pointed at by HEAD.
head(&self) -> Result<Reference<'_>, Error>772     pub fn head(&self) -> Result<Reference<'_>, Error> {
773         let mut ret = ptr::null_mut();
774         unsafe {
775             try_call!(raw::git_repository_head(&mut ret, self.raw));
776             Ok(Binding::from_raw(ret))
777         }
778     }
779 
780     /// Make the repository HEAD point to the specified reference.
781     ///
782     /// If the provided reference points to a tree or a blob, the HEAD is
783     /// unaltered and an error is returned.
784     ///
785     /// If the provided reference points to a branch, the HEAD will point to
786     /// that branch, staying attached, or become attached if it isn't yet. If
787     /// the branch doesn't exist yet, no error will be returned. The HEAD will
788     /// then be attached to an unborn branch.
789     ///
790     /// Otherwise, the HEAD will be detached and will directly point to the
791     /// commit.
set_head(&self, refname: &str) -> Result<(), Error>792     pub fn set_head(&self, refname: &str) -> Result<(), Error> {
793         let refname = CString::new(refname)?;
794         unsafe {
795             try_call!(raw::git_repository_set_head(self.raw, refname));
796         }
797         Ok(())
798     }
799 
800     /// Determines whether the repository HEAD is detached.
head_detached(&self) -> Result<bool, Error>801     pub fn head_detached(&self) -> Result<bool, Error> {
802         unsafe {
803             let value = raw::git_repository_head_detached(self.raw);
804             match value {
805                 0 => Ok(false),
806                 1 => Ok(true),
807                 _ => Err(Error::last_error(value).unwrap()),
808             }
809         }
810     }
811 
812     /// Make the repository HEAD directly point to the commit.
813     ///
814     /// If the provided committish cannot be found in the repository, the HEAD
815     /// is unaltered and an error is returned.
816     ///
817     /// If the provided commitish cannot be peeled into a commit, the HEAD is
818     /// unaltered and an error is returned.
819     ///
820     /// Otherwise, the HEAD will eventually be detached and will directly point
821     /// to the peeled commit.
set_head_detached(&self, commitish: Oid) -> Result<(), Error>822     pub fn set_head_detached(&self, commitish: Oid) -> Result<(), Error> {
823         unsafe {
824             try_call!(raw::git_repository_set_head_detached(
825                 self.raw,
826                 commitish.raw()
827             ));
828         }
829         Ok(())
830     }
831 
832     /// Make the repository HEAD directly point to the commit.
833     ///
834     /// If the provided committish cannot be found in the repository, the HEAD
835     /// is unaltered and an error is returned.
836     /// If the provided commitish cannot be peeled into a commit, the HEAD is
837     /// unaltered and an error is returned.
838     /// Otherwise, the HEAD will eventually be detached and will directly point
839     /// to the peeled commit.
set_head_detached_from_annotated( &self, commitish: AnnotatedCommit<'_>, ) -> Result<(), Error>840     pub fn set_head_detached_from_annotated(
841         &self,
842         commitish: AnnotatedCommit<'_>,
843     ) -> Result<(), Error> {
844         unsafe {
845             try_call!(raw::git_repository_set_head_detached_from_annotated(
846                 self.raw,
847                 commitish.raw()
848             ));
849         }
850         Ok(())
851     }
852 
853     /// Create an iterator for the repo's references
references(&self) -> Result<References<'_>, Error>854     pub fn references(&self) -> Result<References<'_>, Error> {
855         let mut ret = ptr::null_mut();
856         unsafe {
857             try_call!(raw::git_reference_iterator_new(&mut ret, self.raw));
858             Ok(Binding::from_raw(ret))
859         }
860     }
861 
862     /// Create an iterator for the repo's references that match the specified
863     /// glob
references_glob(&self, glob: &str) -> Result<References<'_>, Error>864     pub fn references_glob(&self, glob: &str) -> Result<References<'_>, Error> {
865         let mut ret = ptr::null_mut();
866         let glob = CString::new(glob)?;
867         unsafe {
868             try_call!(raw::git_reference_iterator_glob_new(
869                 &mut ret, self.raw, glob
870             ));
871 
872             Ok(Binding::from_raw(ret))
873         }
874     }
875 
876     /// Load all submodules for this repository and return them.
submodules(&self) -> Result<Vec<Submodule<'_>>, Error>877     pub fn submodules(&self) -> Result<Vec<Submodule<'_>>, Error> {
878         struct Data<'a, 'b> {
879             repo: &'b Repository,
880             ret: &'a mut Vec<Submodule<'b>>,
881         }
882         let mut ret = Vec::new();
883 
884         unsafe {
885             let mut data = Data {
886                 repo: self,
887                 ret: &mut ret,
888             };
889             let cb: raw::git_submodule_cb = Some(append);
890             try_call!(raw::git_submodule_foreach(
891                 self.raw,
892                 cb,
893                 &mut data as *mut _ as *mut c_void
894             ));
895         }
896 
897         return Ok(ret);
898 
899         extern "C" fn append(
900             _repo: *mut raw::git_submodule,
901             name: *const c_char,
902             data: *mut c_void,
903         ) -> c_int {
904             unsafe {
905                 let data = &mut *(data as *mut Data<'_, '_>);
906                 let mut raw = ptr::null_mut();
907                 let rc = raw::git_submodule_lookup(&mut raw, data.repo.raw(), name);
908                 assert_eq!(rc, 0);
909                 data.ret.push(Binding::from_raw(raw));
910             }
911             0
912         }
913     }
914 
915     /// Gather file status information and populate the returned structure.
916     ///
917     /// Note that if a pathspec is given in the options to filter the
918     /// status, then the results from rename detection (if you enable it) may
919     /// not be accurate. To do rename detection properly, this must be called
920     /// with no pathspec so that all files can be considered.
statuses(&self, options: Option<&mut StatusOptions>) -> Result<Statuses<'_>, Error>921     pub fn statuses(&self, options: Option<&mut StatusOptions>) -> Result<Statuses<'_>, Error> {
922         let mut ret = ptr::null_mut();
923         unsafe {
924             try_call!(raw::git_status_list_new(
925                 &mut ret,
926                 self.raw,
927                 options.map(|s| s.raw()).unwrap_or(ptr::null())
928             ));
929             Ok(Binding::from_raw(ret))
930         }
931     }
932 
933     /// Test if the ignore rules apply to a given file.
934     ///
935     /// This function checks the ignore rules to see if they would apply to the
936     /// given file. This indicates if the file would be ignored regardless of
937     /// whether the file is already in the index or committed to the repository.
938     ///
939     /// One way to think of this is if you were to do "git add ." on the
940     /// directory containing the file, would it be added or not?
status_should_ignore(&self, path: &Path) -> Result<bool, Error>941     pub fn status_should_ignore(&self, path: &Path) -> Result<bool, Error> {
942         let mut ret = 0 as c_int;
943         let path = util::cstring_to_repo_path(path)?;
944         unsafe {
945             try_call!(raw::git_status_should_ignore(&mut ret, self.raw, path));
946         }
947         Ok(ret != 0)
948     }
949 
950     /// Get file status for a single file.
951     ///
952     /// This tries to get status for the filename that you give. If no files
953     /// match that name (in either the HEAD, index, or working directory), this
954     /// returns NotFound.
955     ///
956     /// If the name matches multiple files (for example, if the path names a
957     /// directory or if running on a case- insensitive filesystem and yet the
958     /// HEAD has two entries that both match the path), then this returns
959     /// Ambiguous because it cannot give correct results.
960     ///
961     /// This does not do any sort of rename detection. Renames require a set of
962     /// targets and because of the path filtering, there is not enough
963     /// information to check renames correctly. To check file status with rename
964     /// detection, there is no choice but to do a full `statuses` and scan
965     /// through looking for the path that you are interested in.
status_file(&self, path: &Path) -> Result<Status, Error>966     pub fn status_file(&self, path: &Path) -> Result<Status, Error> {
967         let mut ret = 0 as c_uint;
968         let path = path_to_repo_path(path)?;
969         unsafe {
970             try_call!(raw::git_status_file(&mut ret, self.raw, path));
971         }
972         Ok(Status::from_bits_truncate(ret as u32))
973     }
974 
975     /// Create an iterator which loops over the requested branches.
branches(&self, filter: Option<BranchType>) -> Result<Branches<'_>, Error>976     pub fn branches(&self, filter: Option<BranchType>) -> Result<Branches<'_>, Error> {
977         let mut raw = ptr::null_mut();
978         unsafe {
979             try_call!(raw::git_branch_iterator_new(&mut raw, self.raw(), filter));
980             Ok(Branches::from_raw(raw))
981         }
982     }
983 
984     /// Get the Index file for this repository.
985     ///
986     /// If a custom index has not been set, the default index for the repository
987     /// will be returned (the one located in .git/index).
index(&self) -> Result<Index, Error>988     pub fn index(&self) -> Result<Index, Error> {
989         let mut raw = ptr::null_mut();
990         unsafe {
991             try_call!(raw::git_repository_index(&mut raw, self.raw()));
992             Ok(Binding::from_raw(raw))
993         }
994     }
995 
996     /// Set the Index file for this repository.
set_index(&self, index: &mut Index) -> Result<(), Error>997     pub fn set_index(&self, index: &mut Index) -> Result<(), Error> {
998         unsafe {
999             try_call!(raw::git_repository_set_index(self.raw(), index.raw()));
1000         }
1001         Ok(())
1002     }
1003 
1004     /// Get the configuration file for this repository.
1005     ///
1006     /// If a configuration file has not been set, the default config set for the
1007     /// repository will be returned, including global and system configurations
1008     /// (if they are available).
config(&self) -> Result<Config, Error>1009     pub fn config(&self) -> Result<Config, Error> {
1010         let mut raw = ptr::null_mut();
1011         unsafe {
1012             try_call!(raw::git_repository_config(&mut raw, self.raw()));
1013             Ok(Binding::from_raw(raw))
1014         }
1015     }
1016 
1017     /// Get the value of a git attribute for a path as a string.
1018     ///
1019     /// This function will return a special string if the attribute is set to a special value.
1020     /// Interpreting the special string is discouraged. You should always use
1021     /// [`AttrValue::from_string`](crate::AttrValue::from_string) to interpret the return value
1022     /// and avoid the special string.
1023     ///
1024     /// As such, the return type of this function will probably be changed in the next major version
1025     /// to prevent interpreting the returned string without checking whether it's special.
get_attr( &self, path: &Path, name: &str, flags: AttrCheckFlags, ) -> Result<Option<&str>, Error>1026     pub fn get_attr(
1027         &self,
1028         path: &Path,
1029         name: &str,
1030         flags: AttrCheckFlags,
1031     ) -> Result<Option<&str>, Error> {
1032         Ok(self
1033             .get_attr_bytes(path, name, flags)?
1034             .and_then(|a| str::from_utf8(a).ok()))
1035     }
1036 
1037     /// Get the value of a git attribute for a path as a byte slice.
1038     ///
1039     /// This function will return a special byte slice if the attribute is set to a special value.
1040     /// Interpreting the special byte slice is discouraged. You should always use
1041     /// [`AttrValue::from_bytes`](crate::AttrValue::from_bytes) to interpret the return value and
1042     /// avoid the special string.
1043     ///
1044     /// As such, the return type of this function will probably be changed in the next major version
1045     /// to prevent interpreting the returned byte slice without checking whether it's special.
get_attr_bytes( &self, path: &Path, name: &str, flags: AttrCheckFlags, ) -> Result<Option<&[u8]>, Error>1046     pub fn get_attr_bytes(
1047         &self,
1048         path: &Path,
1049         name: &str,
1050         flags: AttrCheckFlags,
1051     ) -> Result<Option<&[u8]>, Error> {
1052         let mut ret = ptr::null();
1053         let path = util::cstring_to_repo_path(path)?;
1054         let name = CString::new(name)?;
1055         unsafe {
1056             try_call!(raw::git_attr_get(
1057                 &mut ret,
1058                 self.raw(),
1059                 flags.bits(),
1060                 path,
1061                 name
1062             ));
1063             Ok(crate::opt_bytes(self, ret))
1064         }
1065     }
1066 
1067     /// Write an in-memory buffer to the ODB as a blob.
1068     ///
1069     /// The Oid returned can in turn be passed to `find_blob` to get a handle to
1070     /// the blob.
blob(&self, data: &[u8]) -> Result<Oid, Error>1071     pub fn blob(&self, data: &[u8]) -> Result<Oid, Error> {
1072         let mut raw = raw::git_oid {
1073             id: [0; raw::GIT_OID_RAWSZ],
1074         };
1075         unsafe {
1076             let ptr = data.as_ptr() as *const c_void;
1077             let len = data.len() as size_t;
1078             try_call!(raw::git_blob_create_frombuffer(
1079                 &mut raw,
1080                 self.raw(),
1081                 ptr,
1082                 len
1083             ));
1084             Ok(Binding::from_raw(&raw as *const _))
1085         }
1086     }
1087 
1088     /// Read a file from the filesystem and write its content to the Object
1089     /// Database as a loose blob
1090     ///
1091     /// The Oid returned can in turn be passed to `find_blob` to get a handle to
1092     /// the blob.
blob_path(&self, path: &Path) -> Result<Oid, Error>1093     pub fn blob_path(&self, path: &Path) -> Result<Oid, Error> {
1094         // Normal file path OK (does not need Windows conversion).
1095         let path = path.into_c_string()?;
1096         let mut raw = raw::git_oid {
1097             id: [0; raw::GIT_OID_RAWSZ],
1098         };
1099         unsafe {
1100             try_call!(raw::git_blob_create_fromdisk(&mut raw, self.raw(), path));
1101             Ok(Binding::from_raw(&raw as *const _))
1102         }
1103     }
1104 
1105     /// Create a stream to write blob
1106     ///
1107     /// This function may need to buffer the data on disk and will in general
1108     /// not be the right choice if you know the size of the data to write.
1109     ///
1110     /// Use `BlobWriter::commit()` to commit the write to the object db
1111     /// and get the object id.
1112     ///
1113     /// If the `hintpath` parameter is filled, it will be used to determine
1114     /// what git filters should be applied to the object before it is written
1115     /// to the object database.
blob_writer(&self, hintpath: Option<&Path>) -> Result<BlobWriter<'_>, Error>1116     pub fn blob_writer(&self, hintpath: Option<&Path>) -> Result<BlobWriter<'_>, Error> {
1117         let path_str = match hintpath {
1118             Some(path) => Some(path.into_c_string()?),
1119             None => None,
1120         };
1121         let path = match path_str {
1122             Some(ref path) => path.as_ptr(),
1123             None => ptr::null(),
1124         };
1125         let mut out = ptr::null_mut();
1126         unsafe {
1127             try_call!(raw::git_blob_create_fromstream(&mut out, self.raw(), path));
1128             Ok(BlobWriter::from_raw(out))
1129         }
1130     }
1131 
1132     /// Lookup a reference to one of the objects in a repository.
find_blob(&self, oid: Oid) -> Result<Blob<'_>, Error>1133     pub fn find_blob(&self, oid: Oid) -> Result<Blob<'_>, Error> {
1134         let mut raw = ptr::null_mut();
1135         unsafe {
1136             try_call!(raw::git_blob_lookup(&mut raw, self.raw(), oid.raw()));
1137             Ok(Binding::from_raw(raw))
1138         }
1139     }
1140 
1141     /// Get the object database for this repository
odb(&self) -> Result<Odb<'_>, Error>1142     pub fn odb(&self) -> Result<Odb<'_>, Error> {
1143         let mut odb = ptr::null_mut();
1144         unsafe {
1145             try_call!(raw::git_repository_odb(&mut odb, self.raw()));
1146             Ok(Odb::from_raw(odb))
1147         }
1148     }
1149 
1150     /// Override the object database for this repository
set_odb(&self, odb: &Odb<'_>) -> Result<(), Error>1151     pub fn set_odb(&self, odb: &Odb<'_>) -> Result<(), Error> {
1152         unsafe {
1153             try_call!(raw::git_repository_set_odb(self.raw(), odb.raw()));
1154         }
1155         Ok(())
1156     }
1157 
1158     /// Create a new branch pointing at a target commit
1159     ///
1160     /// A new direct reference will be created pointing to this target commit.
1161     /// If `force` is true and a reference already exists with the given name,
1162     /// it'll be replaced.
branch( &self, branch_name: &str, target: &Commit<'_>, force: bool, ) -> Result<Branch<'_>, Error>1163     pub fn branch(
1164         &self,
1165         branch_name: &str,
1166         target: &Commit<'_>,
1167         force: bool,
1168     ) -> Result<Branch<'_>, Error> {
1169         let branch_name = CString::new(branch_name)?;
1170         let mut raw = ptr::null_mut();
1171         unsafe {
1172             try_call!(raw::git_branch_create(
1173                 &mut raw,
1174                 self.raw(),
1175                 branch_name,
1176                 target.raw(),
1177                 force
1178             ));
1179             Ok(Branch::wrap(Binding::from_raw(raw)))
1180         }
1181     }
1182 
1183     /// Create a new branch pointing at a target commit
1184     ///
1185     /// This behaves like `Repository::branch()` but takes
1186     /// an annotated commit, which lets you specify which
1187     /// extended sha syntax string was specified by a user,
1188     /// allowing for more exact reflog messages.
1189     ///
1190     /// See the documentation for `Repository::branch()`
branch_from_annotated_commit( &self, branch_name: &str, target: &AnnotatedCommit<'_>, force: bool, ) -> Result<Branch<'_>, Error>1191     pub fn branch_from_annotated_commit(
1192         &self,
1193         branch_name: &str,
1194         target: &AnnotatedCommit<'_>,
1195         force: bool,
1196     ) -> Result<Branch<'_>, Error> {
1197         let branch_name = CString::new(branch_name)?;
1198         let mut raw = ptr::null_mut();
1199         unsafe {
1200             try_call!(raw::git_branch_create_from_annotated(
1201                 &mut raw,
1202                 self.raw(),
1203                 branch_name,
1204                 target.raw(),
1205                 force
1206             ));
1207             Ok(Branch::wrap(Binding::from_raw(raw)))
1208         }
1209     }
1210 
1211     /// Lookup a branch by its name in a repository.
find_branch(&self, name: &str, branch_type: BranchType) -> Result<Branch<'_>, Error>1212     pub fn find_branch(&self, name: &str, branch_type: BranchType) -> Result<Branch<'_>, Error> {
1213         let name = CString::new(name)?;
1214         let mut ret = ptr::null_mut();
1215         unsafe {
1216             try_call!(raw::git_branch_lookup(
1217                 &mut ret,
1218                 self.raw(),
1219                 name,
1220                 branch_type
1221             ));
1222             Ok(Branch::wrap(Binding::from_raw(ret)))
1223         }
1224     }
1225 
1226     /// Create new commit in the repository
1227     ///
1228     /// If the `update_ref` is not `None`, name of the reference that will be
1229     /// updated to point to this commit. If the reference is not direct, it will
1230     /// be resolved to a direct reference. Use "HEAD" to update the HEAD of the
1231     /// current branch and make it point to this commit. If the reference
1232     /// doesn't exist yet, it will be created. If it does exist, the first
1233     /// parent must be the tip of this branch.
commit( &self, update_ref: Option<&str>, author: &Signature<'_>, committer: &Signature<'_>, message: &str, tree: &Tree<'_>, parents: &[&Commit<'_>], ) -> Result<Oid, Error>1234     pub fn commit(
1235         &self,
1236         update_ref: Option<&str>,
1237         author: &Signature<'_>,
1238         committer: &Signature<'_>,
1239         message: &str,
1240         tree: &Tree<'_>,
1241         parents: &[&Commit<'_>],
1242     ) -> Result<Oid, Error> {
1243         let update_ref = crate::opt_cstr(update_ref)?;
1244         let mut parent_ptrs = parents
1245             .iter()
1246             .map(|p| p.raw() as *const raw::git_commit)
1247             .collect::<Vec<_>>();
1248         let message = CString::new(message)?;
1249         let mut raw = raw::git_oid {
1250             id: [0; raw::GIT_OID_RAWSZ],
1251         };
1252         unsafe {
1253             try_call!(raw::git_commit_create(
1254                 &mut raw,
1255                 self.raw(),
1256                 update_ref,
1257                 author.raw(),
1258                 committer.raw(),
1259                 ptr::null(),
1260                 message,
1261                 tree.raw(),
1262                 parents.len() as size_t,
1263                 parent_ptrs.as_mut_ptr()
1264             ));
1265             Ok(Binding::from_raw(&raw as *const _))
1266         }
1267     }
1268 
1269     /// Create a commit object and return that as a Buf.
1270     ///
1271     /// That can be converted to a string like this `str::from_utf8(&buf).unwrap().to_string()`.
1272     /// And that string can be passed to the `commit_signed` function,
1273     /// the arguments behave the same as in the `commit` function.
commit_create_buffer( &self, author: &Signature<'_>, committer: &Signature<'_>, message: &str, tree: &Tree<'_>, parents: &[&Commit<'_>], ) -> Result<Buf, Error>1274     pub fn commit_create_buffer(
1275         &self,
1276         author: &Signature<'_>,
1277         committer: &Signature<'_>,
1278         message: &str,
1279         tree: &Tree<'_>,
1280         parents: &[&Commit<'_>],
1281     ) -> Result<Buf, Error> {
1282         let mut parent_ptrs = parents
1283             .iter()
1284             .map(|p| p.raw() as *const raw::git_commit)
1285             .collect::<Vec<_>>();
1286         let message = CString::new(message)?;
1287         let buf = Buf::new();
1288         unsafe {
1289             try_call!(raw::git_commit_create_buffer(
1290                 buf.raw(),
1291                 self.raw(),
1292                 author.raw(),
1293                 committer.raw(),
1294                 ptr::null(),
1295                 message,
1296                 tree.raw(),
1297                 parents.len() as size_t,
1298                 parent_ptrs.as_mut_ptr()
1299             ));
1300             Ok(buf)
1301         }
1302     }
1303 
1304     /// Create a commit object from the given buffer and signature
1305     ///
1306     /// Given the unsigned commit object's contents, its signature and the
1307     /// header field in which to store the signature, attach the signature to
1308     /// the commit and write it into the given repository.
1309     ///
1310     /// Use `None` in `signature_field` to use the default of `gpgsig`, which is
1311     /// almost certainly what you want.
1312     ///
1313     /// Returns the resulting (signed) commit id.
commit_signed( &self, commit_content: &str, signature: &str, signature_field: Option<&str>, ) -> Result<Oid, Error>1314     pub fn commit_signed(
1315         &self,
1316         commit_content: &str,
1317         signature: &str,
1318         signature_field: Option<&str>,
1319     ) -> Result<Oid, Error> {
1320         let commit_content = CString::new(commit_content)?;
1321         let signature = CString::new(signature)?;
1322         let signature_field = crate::opt_cstr(signature_field)?;
1323         let mut raw = raw::git_oid {
1324             id: [0; raw::GIT_OID_RAWSZ],
1325         };
1326         unsafe {
1327             try_call!(raw::git_commit_create_with_signature(
1328                 &mut raw,
1329                 self.raw(),
1330                 commit_content,
1331                 signature,
1332                 signature_field
1333             ));
1334             Ok(Binding::from_raw(&raw as *const _))
1335         }
1336     }
1337 
1338     /// Extract the signature from a commit
1339     ///
1340     /// Returns a tuple containing the signature in the first value and the
1341     /// signed data in the second.
extract_signature( &self, commit_id: &Oid, signature_field: Option<&str>, ) -> Result<(Buf, Buf), Error>1342     pub fn extract_signature(
1343         &self,
1344         commit_id: &Oid,
1345         signature_field: Option<&str>,
1346     ) -> Result<(Buf, Buf), Error> {
1347         let signature_field = crate::opt_cstr(signature_field)?;
1348         let signature = Buf::new();
1349         let content = Buf::new();
1350         unsafe {
1351             try_call!(raw::git_commit_extract_signature(
1352                 signature.raw(),
1353                 content.raw(),
1354                 self.raw(),
1355                 commit_id.raw() as *mut _,
1356                 signature_field
1357             ));
1358             Ok((signature, content))
1359         }
1360     }
1361 
1362     /// Lookup a reference to one of the commits in a repository.
find_commit(&self, oid: Oid) -> Result<Commit<'_>, Error>1363     pub fn find_commit(&self, oid: Oid) -> Result<Commit<'_>, Error> {
1364         let mut raw = ptr::null_mut();
1365         unsafe {
1366             try_call!(raw::git_commit_lookup(&mut raw, self.raw(), oid.raw()));
1367             Ok(Binding::from_raw(raw))
1368         }
1369     }
1370 
1371     /// Creates an `AnnotatedCommit` from the given commit id.
find_annotated_commit(&self, id: Oid) -> Result<AnnotatedCommit<'_>, Error>1372     pub fn find_annotated_commit(&self, id: Oid) -> Result<AnnotatedCommit<'_>, Error> {
1373         unsafe {
1374             let mut raw = ptr::null_mut();
1375             try_call!(raw::git_annotated_commit_lookup(
1376                 &mut raw,
1377                 self.raw(),
1378                 id.raw()
1379             ));
1380             Ok(Binding::from_raw(raw))
1381         }
1382     }
1383 
1384     /// Lookup a reference to one of the objects in a repository.
find_object(&self, oid: Oid, kind: Option<ObjectType>) -> Result<Object<'_>, Error>1385     pub fn find_object(&self, oid: Oid, kind: Option<ObjectType>) -> Result<Object<'_>, Error> {
1386         let mut raw = ptr::null_mut();
1387         unsafe {
1388             try_call!(raw::git_object_lookup(
1389                 &mut raw,
1390                 self.raw(),
1391                 oid.raw(),
1392                 kind
1393             ));
1394             Ok(Binding::from_raw(raw))
1395         }
1396     }
1397 
1398     /// Create a new direct reference.
1399     ///
1400     /// This function will return an error if a reference already exists with
1401     /// the given name unless force is true, in which case it will be
1402     /// overwritten.
reference( &self, name: &str, id: Oid, force: bool, log_message: &str, ) -> Result<Reference<'_>, Error>1403     pub fn reference(
1404         &self,
1405         name: &str,
1406         id: Oid,
1407         force: bool,
1408         log_message: &str,
1409     ) -> Result<Reference<'_>, Error> {
1410         let name = CString::new(name)?;
1411         let log_message = CString::new(log_message)?;
1412         let mut raw = ptr::null_mut();
1413         unsafe {
1414             try_call!(raw::git_reference_create(
1415                 &mut raw,
1416                 self.raw(),
1417                 name,
1418                 id.raw(),
1419                 force,
1420                 log_message
1421             ));
1422             Ok(Binding::from_raw(raw))
1423         }
1424     }
1425 
1426     /// Conditionally create new direct reference.
1427     ///
1428     /// A direct reference (also called an object id reference) refers directly
1429     /// to a specific object id (a.k.a. OID or SHA) in the repository.  The id
1430     /// permanently refers to the object (although the reference itself can be
1431     /// moved).  For example, in libgit2 the direct ref "refs/tags/v0.17.0"
1432     /// refers to OID 5b9fac39d8a76b9139667c26a63e6b3f204b3977.
1433     ///
1434     /// The direct reference will be created in the repository and written to
1435     /// the disk.
1436     ///
1437     /// Valid reference names must follow one of two patterns:
1438     ///
1439     /// 1. Top-level names must contain only capital letters and underscores,
1440     ///    and must begin and end with a letter.  (e.g.  "HEAD", "ORIG_HEAD").
1441     /// 2. Names prefixed with "refs/" can be almost anything.  You must avoid
1442     ///    the characters `~`, `^`, `:`, `\\`, `?`, `[`, and `*`, and the
1443     ///    sequences ".." and "@{" which have special meaning to revparse.
1444     ///
1445     /// This function will return an error if a reference already exists with
1446     /// the given name unless `force` is true, in which case it will be
1447     /// overwritten.
1448     ///
1449     /// The message for the reflog will be ignored if the reference does not
1450     /// belong in the standard set (HEAD, branches and remote-tracking
1451     /// branches) and it does not have a reflog.
1452     ///
1453     /// It will return GIT_EMODIFIED if the reference's value at the time of
1454     /// updating does not match the one passed through `current_id` (i.e. if the
1455     /// ref has changed since the user read it).
reference_matching( &self, name: &str, id: Oid, force: bool, current_id: Oid, log_message: &str, ) -> Result<Reference<'_>, Error>1456     pub fn reference_matching(
1457         &self,
1458         name: &str,
1459         id: Oid,
1460         force: bool,
1461         current_id: Oid,
1462         log_message: &str,
1463     ) -> Result<Reference<'_>, Error> {
1464         let name = CString::new(name)?;
1465         let log_message = CString::new(log_message)?;
1466         let mut raw = ptr::null_mut();
1467         unsafe {
1468             try_call!(raw::git_reference_create_matching(
1469                 &mut raw,
1470                 self.raw(),
1471                 name,
1472                 id.raw(),
1473                 force,
1474                 current_id.raw(),
1475                 log_message
1476             ));
1477             Ok(Binding::from_raw(raw))
1478         }
1479     }
1480 
1481     /// Create a new symbolic reference.
1482     ///
1483     /// This function will return an error if a reference already exists with
1484     /// the given name unless force is true, in which case it will be
1485     /// overwritten.
reference_symbolic( &self, name: &str, target: &str, force: bool, log_message: &str, ) -> Result<Reference<'_>, Error>1486     pub fn reference_symbolic(
1487         &self,
1488         name: &str,
1489         target: &str,
1490         force: bool,
1491         log_message: &str,
1492     ) -> Result<Reference<'_>, Error> {
1493         let name = CString::new(name)?;
1494         let target = CString::new(target)?;
1495         let log_message = CString::new(log_message)?;
1496         let mut raw = ptr::null_mut();
1497         unsafe {
1498             try_call!(raw::git_reference_symbolic_create(
1499                 &mut raw,
1500                 self.raw(),
1501                 name,
1502                 target,
1503                 force,
1504                 log_message
1505             ));
1506             Ok(Binding::from_raw(raw))
1507         }
1508     }
1509 
1510     /// Create a new symbolic reference.
1511     ///
1512     /// This function will return an error if a reference already exists with
1513     /// the given name unless force is true, in which case it will be
1514     /// overwritten.
1515     ///
1516     /// It will return GIT_EMODIFIED if the reference's value at the time of
1517     /// updating does not match the one passed through current_value (i.e. if
1518     /// the ref has changed since the user read it).
reference_symbolic_matching( &self, name: &str, target: &str, force: bool, current_value: &str, log_message: &str, ) -> Result<Reference<'_>, Error>1519     pub fn reference_symbolic_matching(
1520         &self,
1521         name: &str,
1522         target: &str,
1523         force: bool,
1524         current_value: &str,
1525         log_message: &str,
1526     ) -> Result<Reference<'_>, Error> {
1527         let name = CString::new(name)?;
1528         let target = CString::new(target)?;
1529         let current_value = CString::new(current_value)?;
1530         let log_message = CString::new(log_message)?;
1531         let mut raw = ptr::null_mut();
1532         unsafe {
1533             try_call!(raw::git_reference_symbolic_create_matching(
1534                 &mut raw,
1535                 self.raw(),
1536                 name,
1537                 target,
1538                 force,
1539                 current_value,
1540                 log_message
1541             ));
1542             Ok(Binding::from_raw(raw))
1543         }
1544     }
1545 
1546     /// Lookup a reference to one of the objects in a repository.
find_reference(&self, name: &str) -> Result<Reference<'_>, Error>1547     pub fn find_reference(&self, name: &str) -> Result<Reference<'_>, Error> {
1548         let name = CString::new(name)?;
1549         let mut raw = ptr::null_mut();
1550         unsafe {
1551             try_call!(raw::git_reference_lookup(&mut raw, self.raw(), name));
1552             Ok(Binding::from_raw(raw))
1553         }
1554     }
1555 
1556     /// Lookup a reference to one of the objects in a repository.
1557     /// `Repository::find_reference` with teeth; give the method your reference in
1558     /// human-readable format e.g. 'main' instead of 'refs/heads/main', and it
1559     /// will do-what-you-mean, returning the `Reference`.
resolve_reference_from_short_name(&self, refname: &str) -> Result<Reference<'_>, Error>1560     pub fn resolve_reference_from_short_name(&self, refname: &str) -> Result<Reference<'_>, Error> {
1561         let refname = CString::new(refname)?;
1562         let mut raw = ptr::null_mut();
1563         unsafe {
1564             try_call!(raw::git_reference_dwim(&mut raw, self.raw(), refname));
1565             Ok(Binding::from_raw(raw))
1566         }
1567     }
1568 
1569     /// Lookup a reference by name and resolve immediately to OID.
1570     ///
1571     /// This function provides a quick way to resolve a reference name straight
1572     /// through to the object id that it refers to. This avoids having to
1573     /// allocate or free any `Reference` objects for simple situations.
refname_to_id(&self, name: &str) -> Result<Oid, Error>1574     pub fn refname_to_id(&self, name: &str) -> Result<Oid, Error> {
1575         let name = CString::new(name)?;
1576         let mut ret = raw::git_oid {
1577             id: [0; raw::GIT_OID_RAWSZ],
1578         };
1579         unsafe {
1580             try_call!(raw::git_reference_name_to_id(&mut ret, self.raw(), name));
1581             Ok(Binding::from_raw(&ret as *const _))
1582         }
1583     }
1584 
1585     /// Creates a git_annotated_commit from the given reference.
reference_to_annotated_commit( &self, reference: &Reference<'_>, ) -> Result<AnnotatedCommit<'_>, Error>1586     pub fn reference_to_annotated_commit(
1587         &self,
1588         reference: &Reference<'_>,
1589     ) -> Result<AnnotatedCommit<'_>, Error> {
1590         let mut ret = ptr::null_mut();
1591         unsafe {
1592             try_call!(raw::git_annotated_commit_from_ref(
1593                 &mut ret,
1594                 self.raw(),
1595                 reference.raw()
1596             ));
1597             Ok(AnnotatedCommit::from_raw(ret))
1598         }
1599     }
1600 
1601     /// Creates a git_annotated_commit from FETCH_HEAD.
annotated_commit_from_fetchhead( &self, branch_name: &str, remote_url: &str, id: &Oid, ) -> Result<AnnotatedCommit<'_>, Error>1602     pub fn annotated_commit_from_fetchhead(
1603         &self,
1604         branch_name: &str,
1605         remote_url: &str,
1606         id: &Oid,
1607     ) -> Result<AnnotatedCommit<'_>, Error> {
1608         let branch_name = CString::new(branch_name)?;
1609         let remote_url = CString::new(remote_url)?;
1610 
1611         let mut ret = ptr::null_mut();
1612         unsafe {
1613             try_call!(raw::git_annotated_commit_from_fetchhead(
1614                 &mut ret,
1615                 self.raw(),
1616                 branch_name,
1617                 remote_url,
1618                 id.raw()
1619             ));
1620             Ok(AnnotatedCommit::from_raw(ret))
1621         }
1622     }
1623 
1624     /// Create a new action signature with default user and now timestamp.
1625     ///
1626     /// This looks up the user.name and user.email from the configuration and
1627     /// uses the current time as the timestamp, and creates a new signature
1628     /// based on that information. It will return `NotFound` if either the
1629     /// user.name or user.email are not set.
signature(&self) -> Result<Signature<'static>, Error>1630     pub fn signature(&self) -> Result<Signature<'static>, Error> {
1631         let mut ret = ptr::null_mut();
1632         unsafe {
1633             try_call!(raw::git_signature_default(&mut ret, self.raw()));
1634             Ok(Binding::from_raw(ret))
1635         }
1636     }
1637 
1638     /// Set up a new git submodule for checkout.
1639     ///
1640     /// This does "git submodule add" up to the fetch and checkout of the
1641     /// submodule contents. It preps a new submodule, creates an entry in
1642     /// `.gitmodules` and creates an empty initialized repository either at the
1643     /// given path in the working directory or in `.git/modules` with a gitlink
1644     /// from the working directory to the new repo.
1645     ///
1646     /// To fully emulate "git submodule add" call this function, then `open()`
1647     /// the submodule repo and perform the clone step as needed. Lastly, call
1648     /// `add_finalize()` to wrap up adding the new submodule and `.gitmodules`
1649     /// to the index to be ready to commit.
submodule( &self, url: &str, path: &Path, use_gitlink: bool, ) -> Result<Submodule<'_>, Error>1650     pub fn submodule(
1651         &self,
1652         url: &str,
1653         path: &Path,
1654         use_gitlink: bool,
1655     ) -> Result<Submodule<'_>, Error> {
1656         let url = CString::new(url)?;
1657         let path = path_to_repo_path(path)?;
1658         let mut raw = ptr::null_mut();
1659         unsafe {
1660             try_call!(raw::git_submodule_add_setup(
1661                 &mut raw,
1662                 self.raw(),
1663                 url,
1664                 path,
1665                 use_gitlink
1666             ));
1667             Ok(Binding::from_raw(raw))
1668         }
1669     }
1670 
1671     /// Lookup submodule information by name or path.
1672     ///
1673     /// Given either the submodule name or path (they are usually the same),
1674     /// this returns a structure describing the submodule.
find_submodule(&self, name: &str) -> Result<Submodule<'_>, Error>1675     pub fn find_submodule(&self, name: &str) -> Result<Submodule<'_>, Error> {
1676         let name = CString::new(name)?;
1677         let mut raw = ptr::null_mut();
1678         unsafe {
1679             try_call!(raw::git_submodule_lookup(&mut raw, self.raw(), name));
1680             Ok(Binding::from_raw(raw))
1681         }
1682     }
1683 
1684     /// Get the status for a submodule.
1685     ///
1686     /// This looks at a submodule and tries to determine the status.  It
1687     /// will return a combination of the `SubmoduleStatus` values.
submodule_status( &self, name: &str, ignore: SubmoduleIgnore, ) -> Result<SubmoduleStatus, Error>1688     pub fn submodule_status(
1689         &self,
1690         name: &str,
1691         ignore: SubmoduleIgnore,
1692     ) -> Result<SubmoduleStatus, Error> {
1693         let mut ret = 0;
1694         let name = CString::new(name)?;
1695         unsafe {
1696             try_call!(raw::git_submodule_status(&mut ret, self.raw, name, ignore));
1697         }
1698         Ok(SubmoduleStatus::from_bits_truncate(ret as u32))
1699     }
1700 
1701     /// Set the ignore rule for the submodule in the configuration
1702     ///
1703     /// This does not affect any currently-loaded instances.
submodule_set_ignore( &mut self, name: &str, ignore: SubmoduleIgnore, ) -> Result<(), Error>1704     pub fn submodule_set_ignore(
1705         &mut self,
1706         name: &str,
1707         ignore: SubmoduleIgnore,
1708     ) -> Result<(), Error> {
1709         let name = CString::new(name)?;
1710         unsafe {
1711             try_call!(raw::git_submodule_set_ignore(self.raw(), name, ignore));
1712         }
1713         Ok(())
1714     }
1715 
1716     /// Set the update rule for the submodule in the configuration
1717     ///
1718     /// This setting won't affect any existing instances.
submodule_set_update( &mut self, name: &str, update: SubmoduleUpdate, ) -> Result<(), Error>1719     pub fn submodule_set_update(
1720         &mut self,
1721         name: &str,
1722         update: SubmoduleUpdate,
1723     ) -> Result<(), Error> {
1724         let name = CString::new(name)?;
1725         unsafe {
1726             try_call!(raw::git_submodule_set_update(self.raw(), name, update));
1727         }
1728         Ok(())
1729     }
1730 
1731     /// Set the URL for the submodule in the configuration
1732     ///
1733     /// After calling this, you may wish to call [`Submodule::sync`] to write
1734     /// the changes to the checked out submodule repository.
submodule_set_url(&mut self, name: &str, url: &str) -> Result<(), Error>1735     pub fn submodule_set_url(&mut self, name: &str, url: &str) -> Result<(), Error> {
1736         let name = CString::new(name)?;
1737         let url = CString::new(url)?;
1738         unsafe {
1739             try_call!(raw::git_submodule_set_url(self.raw(), name, url));
1740         }
1741         Ok(())
1742     }
1743 
1744     /// Set the branch for the submodule in the configuration
1745     ///
1746     /// After calling this, you may wish to call [`Submodule::sync`] to write
1747     /// the changes to the checked out submodule repository.
submodule_set_branch(&mut self, name: &str, branch_name: &str) -> Result<(), Error>1748     pub fn submodule_set_branch(&mut self, name: &str, branch_name: &str) -> Result<(), Error> {
1749         let name = CString::new(name)?;
1750         let branch_name = CString::new(branch_name)?;
1751         unsafe {
1752             try_call!(raw::git_submodule_set_branch(self.raw(), name, branch_name));
1753         }
1754         Ok(())
1755     }
1756 
1757     /// Lookup a reference to one of the objects in a repository.
find_tree(&self, oid: Oid) -> Result<Tree<'_>, Error>1758     pub fn find_tree(&self, oid: Oid) -> Result<Tree<'_>, Error> {
1759         let mut raw = ptr::null_mut();
1760         unsafe {
1761             try_call!(raw::git_tree_lookup(&mut raw, self.raw(), oid.raw()));
1762             Ok(Binding::from_raw(raw))
1763         }
1764     }
1765 
1766     /// Create a new TreeBuilder, optionally initialized with the
1767     /// entries of the given Tree.
1768     ///
1769     /// The tree builder can be used to create or modify trees in memory and
1770     /// write them as tree objects to the database.
treebuilder(&self, tree: Option<&Tree<'_>>) -> Result<TreeBuilder<'_>, Error>1771     pub fn treebuilder(&self, tree: Option<&Tree<'_>>) -> Result<TreeBuilder<'_>, Error> {
1772         unsafe {
1773             let mut ret = ptr::null_mut();
1774             let tree = match tree {
1775                 Some(tree) => tree.raw(),
1776                 None => ptr::null_mut(),
1777             };
1778             try_call!(raw::git_treebuilder_new(&mut ret, self.raw, tree));
1779             Ok(Binding::from_raw(ret))
1780         }
1781     }
1782 
1783     /// Create a new tag in the repository from an object
1784     ///
1785     /// A new reference will also be created pointing to this tag object. If
1786     /// `force` is true and a reference already exists with the given name,
1787     /// it'll be replaced.
1788     ///
1789     /// The message will not be cleaned up.
1790     ///
1791     /// The tag name will be checked for validity. You must avoid the characters
1792     /// '~', '^', ':', ' \ ', '?', '[', and '*', and the sequences ".." and " @
1793     /// {" which have special meaning to revparse.
tag( &self, name: &str, target: &Object<'_>, tagger: &Signature<'_>, message: &str, force: bool, ) -> Result<Oid, Error>1794     pub fn tag(
1795         &self,
1796         name: &str,
1797         target: &Object<'_>,
1798         tagger: &Signature<'_>,
1799         message: &str,
1800         force: bool,
1801     ) -> Result<Oid, Error> {
1802         let name = CString::new(name)?;
1803         let message = CString::new(message)?;
1804         let mut raw = raw::git_oid {
1805             id: [0; raw::GIT_OID_RAWSZ],
1806         };
1807         unsafe {
1808             try_call!(raw::git_tag_create(
1809                 &mut raw,
1810                 self.raw,
1811                 name,
1812                 target.raw(),
1813                 tagger.raw(),
1814                 message,
1815                 force
1816             ));
1817             Ok(Binding::from_raw(&raw as *const _))
1818         }
1819     }
1820 
1821     /// Create a new lightweight tag pointing at a target object
1822     ///
1823     /// A new direct reference will be created pointing to this target object.
1824     /// If force is true and a reference already exists with the given name,
1825     /// it'll be replaced.
tag_lightweight( &self, name: &str, target: &Object<'_>, force: bool, ) -> Result<Oid, Error>1826     pub fn tag_lightweight(
1827         &self,
1828         name: &str,
1829         target: &Object<'_>,
1830         force: bool,
1831     ) -> Result<Oid, Error> {
1832         let name = CString::new(name)?;
1833         let mut raw = raw::git_oid {
1834             id: [0; raw::GIT_OID_RAWSZ],
1835         };
1836         unsafe {
1837             try_call!(raw::git_tag_create_lightweight(
1838                 &mut raw,
1839                 self.raw,
1840                 name,
1841                 target.raw(),
1842                 force
1843             ));
1844             Ok(Binding::from_raw(&raw as *const _))
1845         }
1846     }
1847 
1848     /// Lookup a tag object from the repository.
find_tag(&self, id: Oid) -> Result<Tag<'_>, Error>1849     pub fn find_tag(&self, id: Oid) -> Result<Tag<'_>, Error> {
1850         let mut raw = ptr::null_mut();
1851         unsafe {
1852             try_call!(raw::git_tag_lookup(&mut raw, self.raw, id.raw()));
1853             Ok(Binding::from_raw(raw))
1854         }
1855     }
1856 
1857     /// Delete an existing tag reference.
1858     ///
1859     /// The tag name will be checked for validity, see `tag` for some rules
1860     /// about valid names.
tag_delete(&self, name: &str) -> Result<(), Error>1861     pub fn tag_delete(&self, name: &str) -> Result<(), Error> {
1862         let name = CString::new(name)?;
1863         unsafe {
1864             try_call!(raw::git_tag_delete(self.raw, name));
1865             Ok(())
1866         }
1867     }
1868 
1869     /// Get a list with all the tags in the repository.
1870     ///
1871     /// An optional fnmatch pattern can also be specified.
tag_names(&self, pattern: Option<&str>) -> Result<StringArray, Error>1872     pub fn tag_names(&self, pattern: Option<&str>) -> Result<StringArray, Error> {
1873         let mut arr = raw::git_strarray {
1874             strings: ptr::null_mut(),
1875             count: 0,
1876         };
1877         unsafe {
1878             match pattern {
1879                 Some(s) => {
1880                     let s = CString::new(s)?;
1881                     try_call!(raw::git_tag_list_match(&mut arr, s, self.raw));
1882                 }
1883                 None => {
1884                     try_call!(raw::git_tag_list(&mut arr, self.raw));
1885                 }
1886             }
1887             Ok(Binding::from_raw(arr))
1888         }
1889     }
1890 
1891     /// iterate over all tags calling `cb` on each.
1892     /// the callback is provided the tag id and name
tag_foreach<T>(&self, cb: T) -> Result<(), Error> where T: FnMut(Oid, &[u8]) -> bool,1893     pub fn tag_foreach<T>(&self, cb: T) -> Result<(), Error>
1894     where
1895         T: FnMut(Oid, &[u8]) -> bool,
1896     {
1897         let mut data = TagForeachData {
1898             cb: Box::new(cb) as TagForeachCB<'_>,
1899         };
1900 
1901         unsafe {
1902             raw::git_tag_foreach(
1903                 self.raw,
1904                 Some(tag_foreach_cb),
1905                 (&mut data) as *mut _ as *mut _,
1906             );
1907         }
1908         Ok(())
1909     }
1910 
1911     /// Updates files in the index and the working tree to match the content of
1912     /// the commit pointed at by HEAD.
checkout_head(&self, opts: Option<&mut CheckoutBuilder<'_>>) -> Result<(), Error>1913     pub fn checkout_head(&self, opts: Option<&mut CheckoutBuilder<'_>>) -> Result<(), Error> {
1914         unsafe {
1915             let mut raw_opts = mem::zeroed();
1916             try_call!(raw::git_checkout_init_options(
1917                 &mut raw_opts,
1918                 raw::GIT_CHECKOUT_OPTIONS_VERSION
1919             ));
1920             if let Some(c) = opts {
1921                 c.configure(&mut raw_opts);
1922             }
1923 
1924             try_call!(raw::git_checkout_head(self.raw, &raw_opts));
1925         }
1926         Ok(())
1927     }
1928 
1929     /// Updates files in the working tree to match the content of the index.
1930     ///
1931     /// If the index is `None`, the repository's index will be used.
checkout_index( &self, index: Option<&mut Index>, opts: Option<&mut CheckoutBuilder<'_>>, ) -> Result<(), Error>1932     pub fn checkout_index(
1933         &self,
1934         index: Option<&mut Index>,
1935         opts: Option<&mut CheckoutBuilder<'_>>,
1936     ) -> Result<(), Error> {
1937         unsafe {
1938             let mut raw_opts = mem::zeroed();
1939             try_call!(raw::git_checkout_init_options(
1940                 &mut raw_opts,
1941                 raw::GIT_CHECKOUT_OPTIONS_VERSION
1942             ));
1943             if let Some(c) = opts {
1944                 c.configure(&mut raw_opts);
1945             }
1946 
1947             try_call!(raw::git_checkout_index(
1948                 self.raw,
1949                 index.map(|i| &mut *i.raw()),
1950                 &raw_opts
1951             ));
1952         }
1953         Ok(())
1954     }
1955 
1956     /// Updates files in the index and working tree to match the content of the
1957     /// tree pointed at by the treeish.
checkout_tree( &self, treeish: &Object<'_>, opts: Option<&mut CheckoutBuilder<'_>>, ) -> Result<(), Error>1958     pub fn checkout_tree(
1959         &self,
1960         treeish: &Object<'_>,
1961         opts: Option<&mut CheckoutBuilder<'_>>,
1962     ) -> Result<(), Error> {
1963         unsafe {
1964             let mut raw_opts = mem::zeroed();
1965             try_call!(raw::git_checkout_init_options(
1966                 &mut raw_opts,
1967                 raw::GIT_CHECKOUT_OPTIONS_VERSION
1968             ));
1969             if let Some(c) = opts {
1970                 c.configure(&mut raw_opts);
1971             }
1972 
1973             try_call!(raw::git_checkout_tree(self.raw, &*treeish.raw(), &raw_opts));
1974         }
1975         Ok(())
1976     }
1977 
1978     /// Merges the given commit(s) into HEAD, writing the results into the
1979     /// working directory. Any changes are staged for commit and any conflicts
1980     /// are written to the index. Callers should inspect the repository's index
1981     /// after this completes, resolve any conflicts and prepare a commit.
1982     ///
1983     /// For compatibility with git, the repository is put into a merging state.
1984     /// Once the commit is done (or if the user wishes to abort), you should
1985     /// clear this state by calling cleanup_state().
merge( &self, annotated_commits: &[&AnnotatedCommit<'_>], merge_opts: Option<&mut MergeOptions>, checkout_opts: Option<&mut CheckoutBuilder<'_>>, ) -> Result<(), Error>1986     pub fn merge(
1987         &self,
1988         annotated_commits: &[&AnnotatedCommit<'_>],
1989         merge_opts: Option<&mut MergeOptions>,
1990         checkout_opts: Option<&mut CheckoutBuilder<'_>>,
1991     ) -> Result<(), Error> {
1992         unsafe {
1993             let mut raw_checkout_opts = mem::zeroed();
1994             try_call!(raw::git_checkout_init_options(
1995                 &mut raw_checkout_opts,
1996                 raw::GIT_CHECKOUT_OPTIONS_VERSION
1997             ));
1998             if let Some(c) = checkout_opts {
1999                 c.configure(&mut raw_checkout_opts);
2000             }
2001 
2002             let mut commit_ptrs = annotated_commits
2003                 .iter()
2004                 .map(|c| c.raw() as *const raw::git_annotated_commit)
2005                 .collect::<Vec<_>>();
2006 
2007             try_call!(raw::git_merge(
2008                 self.raw,
2009                 commit_ptrs.as_mut_ptr(),
2010                 annotated_commits.len() as size_t,
2011                 merge_opts.map(|o| o.raw()).unwrap_or(ptr::null()),
2012                 &raw_checkout_opts
2013             ));
2014         }
2015         Ok(())
2016     }
2017 
2018     /// Merge two commits, producing an index that reflects the result of
2019     /// the merge. The index may be written as-is to the working directory or
2020     /// checked out. If the index is to be converted to a tree, the caller
2021     /// should resolve any conflicts that arose as part of the merge.
merge_commits( &self, our_commit: &Commit<'_>, their_commit: &Commit<'_>, opts: Option<&MergeOptions>, ) -> Result<Index, Error>2022     pub fn merge_commits(
2023         &self,
2024         our_commit: &Commit<'_>,
2025         their_commit: &Commit<'_>,
2026         opts: Option<&MergeOptions>,
2027     ) -> Result<Index, Error> {
2028         let mut raw = ptr::null_mut();
2029         unsafe {
2030             try_call!(raw::git_merge_commits(
2031                 &mut raw,
2032                 self.raw,
2033                 our_commit.raw(),
2034                 their_commit.raw(),
2035                 opts.map(|o| o.raw())
2036             ));
2037             Ok(Binding::from_raw(raw))
2038         }
2039     }
2040 
2041     /// Merge two trees, producing an index that reflects the result of
2042     /// the merge. The index may be written as-is to the working directory or
2043     /// checked out. If the index is to be converted to a tree, the caller
2044     /// should resolve any conflicts that arose as part of the merge.
merge_trees( &self, ancestor_tree: &Tree<'_>, our_tree: &Tree<'_>, their_tree: &Tree<'_>, opts: Option<&MergeOptions>, ) -> Result<Index, Error>2045     pub fn merge_trees(
2046         &self,
2047         ancestor_tree: &Tree<'_>,
2048         our_tree: &Tree<'_>,
2049         their_tree: &Tree<'_>,
2050         opts: Option<&MergeOptions>,
2051     ) -> Result<Index, Error> {
2052         let mut raw = ptr::null_mut();
2053         unsafe {
2054             try_call!(raw::git_merge_trees(
2055                 &mut raw,
2056                 self.raw,
2057                 ancestor_tree.raw(),
2058                 our_tree.raw(),
2059                 their_tree.raw(),
2060                 opts.map(|o| o.raw())
2061             ));
2062             Ok(Binding::from_raw(raw))
2063         }
2064     }
2065 
2066     /// Remove all the metadata associated with an ongoing command like merge,
2067     /// revert, cherry-pick, etc. For example: MERGE_HEAD, MERGE_MSG, etc.
cleanup_state(&self) -> Result<(), Error>2068     pub fn cleanup_state(&self) -> Result<(), Error> {
2069         unsafe {
2070             try_call!(raw::git_repository_state_cleanup(self.raw));
2071         }
2072         Ok(())
2073     }
2074 
2075     /// Analyzes the given branch(es) and determines the opportunities for
2076     /// merging them into the HEAD of the repository.
merge_analysis( &self, their_heads: &[&AnnotatedCommit<'_>], ) -> Result<(MergeAnalysis, MergePreference), Error>2077     pub fn merge_analysis(
2078         &self,
2079         their_heads: &[&AnnotatedCommit<'_>],
2080     ) -> Result<(MergeAnalysis, MergePreference), Error> {
2081         unsafe {
2082             let mut raw_merge_analysis = 0 as raw::git_merge_analysis_t;
2083             let mut raw_merge_preference = 0 as raw::git_merge_preference_t;
2084             let mut their_heads = their_heads
2085                 .iter()
2086                 .map(|v| v.raw() as *const _)
2087                 .collect::<Vec<_>>();
2088             try_call!(raw::git_merge_analysis(
2089                 &mut raw_merge_analysis,
2090                 &mut raw_merge_preference,
2091                 self.raw,
2092                 their_heads.as_mut_ptr() as *mut _,
2093                 their_heads.len()
2094             ));
2095             Ok((
2096                 MergeAnalysis::from_bits_truncate(raw_merge_analysis as u32),
2097                 MergePreference::from_bits_truncate(raw_merge_preference as u32),
2098             ))
2099         }
2100     }
2101 
2102     /// Analyzes the given branch(es) and determines the opportunities for
2103     /// merging them into a reference.
merge_analysis_for_ref( &self, our_ref: &Reference<'_>, their_heads: &[&AnnotatedCommit<'_>], ) -> Result<(MergeAnalysis, MergePreference), Error>2104     pub fn merge_analysis_for_ref(
2105         &self,
2106         our_ref: &Reference<'_>,
2107         their_heads: &[&AnnotatedCommit<'_>],
2108     ) -> Result<(MergeAnalysis, MergePreference), Error> {
2109         unsafe {
2110             let mut raw_merge_analysis = 0 as raw::git_merge_analysis_t;
2111             let mut raw_merge_preference = 0 as raw::git_merge_preference_t;
2112             let mut their_heads = their_heads
2113                 .iter()
2114                 .map(|v| v.raw() as *const _)
2115                 .collect::<Vec<_>>();
2116             try_call!(raw::git_merge_analysis_for_ref(
2117                 &mut raw_merge_analysis,
2118                 &mut raw_merge_preference,
2119                 self.raw,
2120                 our_ref.raw(),
2121                 their_heads.as_mut_ptr() as *mut _,
2122                 their_heads.len()
2123             ));
2124             Ok((
2125                 MergeAnalysis::from_bits_truncate(raw_merge_analysis as u32),
2126                 MergePreference::from_bits_truncate(raw_merge_preference as u32),
2127             ))
2128         }
2129     }
2130 
2131     /// Initializes a rebase operation to rebase the changes in `branch`
2132     /// relative to `upstream` onto another branch. To begin the rebase process,
2133     /// call `next()`.
rebase( &self, branch: Option<&AnnotatedCommit<'_>>, upstream: Option<&AnnotatedCommit<'_>>, onto: Option<&AnnotatedCommit<'_>>, opts: Option<&mut RebaseOptions<'_>>, ) -> Result<Rebase<'_>, Error>2134     pub fn rebase(
2135         &self,
2136         branch: Option<&AnnotatedCommit<'_>>,
2137         upstream: Option<&AnnotatedCommit<'_>>,
2138         onto: Option<&AnnotatedCommit<'_>>,
2139         opts: Option<&mut RebaseOptions<'_>>,
2140     ) -> Result<Rebase<'_>, Error> {
2141         let mut rebase: *mut raw::git_rebase = ptr::null_mut();
2142         unsafe {
2143             try_call!(raw::git_rebase_init(
2144                 &mut rebase,
2145                 self.raw(),
2146                 branch.map(|c| c.raw()),
2147                 upstream.map(|c| c.raw()),
2148                 onto.map(|c| c.raw()),
2149                 opts.map(|o| o.raw()).unwrap_or(ptr::null())
2150             ));
2151 
2152             Ok(Rebase::from_raw(rebase))
2153         }
2154     }
2155 
2156     /// Opens an existing rebase that was previously started by either an
2157     /// invocation of `rebase()` or by another client.
open_rebase(&self, opts: Option<&mut RebaseOptions<'_>>) -> Result<Rebase<'_>, Error>2158     pub fn open_rebase(&self, opts: Option<&mut RebaseOptions<'_>>) -> Result<Rebase<'_>, Error> {
2159         let mut rebase: *mut raw::git_rebase = ptr::null_mut();
2160         unsafe {
2161             try_call!(raw::git_rebase_open(
2162                 &mut rebase,
2163                 self.raw(),
2164                 opts.map(|o| o.raw()).unwrap_or(ptr::null())
2165             ));
2166             Ok(Rebase::from_raw(rebase))
2167         }
2168     }
2169 
2170     /// Add a note for an object
2171     ///
2172     /// The `notes_ref` argument is the canonical name of the reference to use,
2173     /// defaulting to "refs/notes/commits". If `force` is specified then
2174     /// previous notes are overwritten.
note( &self, author: &Signature<'_>, committer: &Signature<'_>, notes_ref: Option<&str>, oid: Oid, note: &str, force: bool, ) -> Result<Oid, Error>2175     pub fn note(
2176         &self,
2177         author: &Signature<'_>,
2178         committer: &Signature<'_>,
2179         notes_ref: Option<&str>,
2180         oid: Oid,
2181         note: &str,
2182         force: bool,
2183     ) -> Result<Oid, Error> {
2184         let notes_ref = crate::opt_cstr(notes_ref)?;
2185         let note = CString::new(note)?;
2186         let mut ret = raw::git_oid {
2187             id: [0; raw::GIT_OID_RAWSZ],
2188         };
2189         unsafe {
2190             try_call!(raw::git_note_create(
2191                 &mut ret,
2192                 self.raw,
2193                 notes_ref,
2194                 author.raw(),
2195                 committer.raw(),
2196                 oid.raw(),
2197                 note,
2198                 force
2199             ));
2200             Ok(Binding::from_raw(&ret as *const _))
2201         }
2202     }
2203 
2204     /// Get the default notes reference for this repository
note_default_ref(&self) -> Result<String, Error>2205     pub fn note_default_ref(&self) -> Result<String, Error> {
2206         let ret = Buf::new();
2207         unsafe {
2208             try_call!(raw::git_note_default_ref(ret.raw(), self.raw));
2209         }
2210         Ok(str::from_utf8(&ret).unwrap().to_string())
2211     }
2212 
2213     /// Creates a new iterator for notes in this repository.
2214     ///
2215     /// The `notes_ref` argument is the canonical name of the reference to use,
2216     /// defaulting to "refs/notes/commits".
2217     ///
2218     /// The iterator returned yields pairs of (Oid, Oid) where the first element
2219     /// is the id of the note and the second id is the id the note is
2220     /// annotating.
notes(&self, notes_ref: Option<&str>) -> Result<Notes<'_>, Error>2221     pub fn notes(&self, notes_ref: Option<&str>) -> Result<Notes<'_>, Error> {
2222         let notes_ref = crate::opt_cstr(notes_ref)?;
2223         let mut ret = ptr::null_mut();
2224         unsafe {
2225             try_call!(raw::git_note_iterator_new(&mut ret, self.raw, notes_ref));
2226             Ok(Binding::from_raw(ret))
2227         }
2228     }
2229 
2230     /// Read the note for an object.
2231     ///
2232     /// The `notes_ref` argument is the canonical name of the reference to use,
2233     /// defaulting to "refs/notes/commits".
2234     ///
2235     /// The id specified is the Oid of the git object to read the note from.
find_note(&self, notes_ref: Option<&str>, id: Oid) -> Result<Note<'_>, Error>2236     pub fn find_note(&self, notes_ref: Option<&str>, id: Oid) -> Result<Note<'_>, Error> {
2237         let notes_ref = crate::opt_cstr(notes_ref)?;
2238         let mut ret = ptr::null_mut();
2239         unsafe {
2240             try_call!(raw::git_note_read(&mut ret, self.raw, notes_ref, id.raw()));
2241             Ok(Binding::from_raw(ret))
2242         }
2243     }
2244 
2245     /// Remove the note for an object.
2246     ///
2247     /// The `notes_ref` argument is the canonical name of the reference to use,
2248     /// defaulting to "refs/notes/commits".
2249     ///
2250     /// The id specified is the Oid of the git object to remove the note from.
note_delete( &self, id: Oid, notes_ref: Option<&str>, author: &Signature<'_>, committer: &Signature<'_>, ) -> Result<(), Error>2251     pub fn note_delete(
2252         &self,
2253         id: Oid,
2254         notes_ref: Option<&str>,
2255         author: &Signature<'_>,
2256         committer: &Signature<'_>,
2257     ) -> Result<(), Error> {
2258         let notes_ref = crate::opt_cstr(notes_ref)?;
2259         unsafe {
2260             try_call!(raw::git_note_remove(
2261                 self.raw,
2262                 notes_ref,
2263                 author.raw(),
2264                 committer.raw(),
2265                 id.raw()
2266             ));
2267             Ok(())
2268         }
2269     }
2270 
2271     /// Create a revwalk that can be used to traverse the commit graph.
revwalk(&self) -> Result<Revwalk<'_>, Error>2272     pub fn revwalk(&self) -> Result<Revwalk<'_>, Error> {
2273         let mut raw = ptr::null_mut();
2274         unsafe {
2275             try_call!(raw::git_revwalk_new(&mut raw, self.raw()));
2276             Ok(Binding::from_raw(raw))
2277         }
2278     }
2279 
2280     /// Get the blame for a single file.
blame_file( &self, path: &Path, opts: Option<&mut BlameOptions>, ) -> Result<Blame<'_>, Error>2281     pub fn blame_file(
2282         &self,
2283         path: &Path,
2284         opts: Option<&mut BlameOptions>,
2285     ) -> Result<Blame<'_>, Error> {
2286         let path = path_to_repo_path(path)?;
2287         let mut raw = ptr::null_mut();
2288 
2289         unsafe {
2290             try_call!(raw::git_blame_file(
2291                 &mut raw,
2292                 self.raw(),
2293                 path,
2294                 opts.map(|s| s.raw())
2295             ));
2296             Ok(Binding::from_raw(raw))
2297         }
2298     }
2299 
2300     /// Find a merge base between two commits
merge_base(&self, one: Oid, two: Oid) -> Result<Oid, Error>2301     pub fn merge_base(&self, one: Oid, two: Oid) -> Result<Oid, Error> {
2302         let mut raw = raw::git_oid {
2303             id: [0; raw::GIT_OID_RAWSZ],
2304         };
2305         unsafe {
2306             try_call!(raw::git_merge_base(
2307                 &mut raw,
2308                 self.raw,
2309                 one.raw(),
2310                 two.raw()
2311             ));
2312             Ok(Binding::from_raw(&raw as *const _))
2313         }
2314     }
2315 
2316     /// Find a merge base given a list of commits
merge_base_many(&self, oids: &[Oid]) -> Result<Oid, Error>2317     pub fn merge_base_many(&self, oids: &[Oid]) -> Result<Oid, Error> {
2318         let mut raw = raw::git_oid {
2319             id: [0; raw::GIT_OID_RAWSZ],
2320         };
2321 
2322         unsafe {
2323             try_call!(raw::git_merge_base_many(
2324                 &mut raw,
2325                 self.raw,
2326                 oids.len() as size_t,
2327                 oids.as_ptr() as *const raw::git_oid
2328             ));
2329             Ok(Binding::from_raw(&raw as *const _))
2330         }
2331     }
2332 
2333     /// Find all merge bases between two commits
merge_bases(&self, one: Oid, two: Oid) -> Result<OidArray, Error>2334     pub fn merge_bases(&self, one: Oid, two: Oid) -> Result<OidArray, Error> {
2335         let mut arr = raw::git_oidarray {
2336             ids: ptr::null_mut(),
2337             count: 0,
2338         };
2339         unsafe {
2340             try_call!(raw::git_merge_bases(
2341                 &mut arr,
2342                 self.raw,
2343                 one.raw(),
2344                 two.raw()
2345             ));
2346             Ok(Binding::from_raw(arr))
2347         }
2348     }
2349 
2350     /// Find all merge bases given a list of commits
merge_bases_many(&self, oids: &[Oid]) -> Result<OidArray, Error>2351     pub fn merge_bases_many(&self, oids: &[Oid]) -> Result<OidArray, Error> {
2352         let mut arr = raw::git_oidarray {
2353             ids: ptr::null_mut(),
2354             count: 0,
2355         };
2356         unsafe {
2357             try_call!(raw::git_merge_bases_many(
2358                 &mut arr,
2359                 self.raw,
2360                 oids.len() as size_t,
2361                 oids.as_ptr() as *const raw::git_oid
2362             ));
2363             Ok(Binding::from_raw(arr))
2364         }
2365     }
2366 
2367     /// Count the number of unique commits between two commit objects
2368     ///
2369     /// There is no need for branches containing the commits to have any
2370     /// upstream relationship, but it helps to think of one as a branch and the
2371     /// other as its upstream, the ahead and behind values will be what git
2372     /// would report for the branches.
graph_ahead_behind(&self, local: Oid, upstream: Oid) -> Result<(usize, usize), Error>2373     pub fn graph_ahead_behind(&self, local: Oid, upstream: Oid) -> Result<(usize, usize), Error> {
2374         unsafe {
2375             let mut ahead: size_t = 0;
2376             let mut behind: size_t = 0;
2377             try_call!(raw::git_graph_ahead_behind(
2378                 &mut ahead,
2379                 &mut behind,
2380                 self.raw(),
2381                 local.raw(),
2382                 upstream.raw()
2383             ));
2384             Ok((ahead as usize, behind as usize))
2385         }
2386     }
2387 
2388     /// Determine if a commit is the descendant of another commit
graph_descendant_of(&self, commit: Oid, ancestor: Oid) -> Result<bool, Error>2389     pub fn graph_descendant_of(&self, commit: Oid, ancestor: Oid) -> Result<bool, Error> {
2390         unsafe {
2391             let rv = try_call!(raw::git_graph_descendant_of(
2392                 self.raw(),
2393                 commit.raw(),
2394                 ancestor.raw()
2395             ));
2396             Ok(rv != 0)
2397         }
2398     }
2399 
2400     /// Read the reflog for the given reference
2401     ///
2402     /// If there is no reflog file for the given reference yet, an empty reflog
2403     /// object will be returned.
reflog(&self, name: &str) -> Result<Reflog, Error>2404     pub fn reflog(&self, name: &str) -> Result<Reflog, Error> {
2405         let name = CString::new(name)?;
2406         let mut ret = ptr::null_mut();
2407         unsafe {
2408             try_call!(raw::git_reflog_read(&mut ret, self.raw, name));
2409             Ok(Binding::from_raw(ret))
2410         }
2411     }
2412 
2413     /// Delete the reflog for the given reference
reflog_delete(&self, name: &str) -> Result<(), Error>2414     pub fn reflog_delete(&self, name: &str) -> Result<(), Error> {
2415         let name = CString::new(name)?;
2416         unsafe {
2417             try_call!(raw::git_reflog_delete(self.raw, name));
2418         }
2419         Ok(())
2420     }
2421 
2422     /// Rename a reflog
2423     ///
2424     /// The reflog to be renamed is expected to already exist.
reflog_rename(&self, old_name: &str, new_name: &str) -> Result<(), Error>2425     pub fn reflog_rename(&self, old_name: &str, new_name: &str) -> Result<(), Error> {
2426         let old_name = CString::new(old_name)?;
2427         let new_name = CString::new(new_name)?;
2428         unsafe {
2429             try_call!(raw::git_reflog_rename(self.raw, old_name, new_name));
2430         }
2431         Ok(())
2432     }
2433 
2434     /// Check if the given reference has a reflog.
reference_has_log(&self, name: &str) -> Result<bool, Error>2435     pub fn reference_has_log(&self, name: &str) -> Result<bool, Error> {
2436         let name = CString::new(name)?;
2437         let ret = unsafe { try_call!(raw::git_reference_has_log(self.raw, name)) };
2438         Ok(ret != 0)
2439     }
2440 
2441     /// Ensure that the given reference has a reflog.
reference_ensure_log(&self, name: &str) -> Result<(), Error>2442     pub fn reference_ensure_log(&self, name: &str) -> Result<(), Error> {
2443         let name = CString::new(name)?;
2444         unsafe {
2445             try_call!(raw::git_reference_ensure_log(self.raw, name));
2446         }
2447         Ok(())
2448     }
2449 
2450     /// Describes a commit
2451     ///
2452     /// Performs a describe operation on the current commit and the worktree.
2453     /// After performing a describe on HEAD, a status is run and description is
2454     /// considered to be dirty if there are.
describe(&self, opts: &DescribeOptions) -> Result<Describe<'_>, Error>2455     pub fn describe(&self, opts: &DescribeOptions) -> Result<Describe<'_>, Error> {
2456         let mut ret = ptr::null_mut();
2457         unsafe {
2458             try_call!(raw::git_describe_workdir(&mut ret, self.raw, opts.raw()));
2459             Ok(Binding::from_raw(ret))
2460         }
2461     }
2462 
2463     /// Directly run a diff on two blobs.
2464     ///
2465     /// Compared to a file, a blob lacks some contextual information. As such, the
2466     /// `DiffFile` given to the callback will have some fake data; i.e. mode will be
2467     /// 0 and path will be `None`.
2468     ///
2469     /// `None` is allowed for either `old_blob` or `new_blob` and will be treated
2470     /// as an empty blob, with the oid set to zero in the `DiffFile`. Passing `None`
2471     /// for both blobs is a noop; no callbacks will be made at all.
2472     ///
2473     /// We do run a binary content check on the blob content and if either blob looks
2474     /// like binary data, the `DiffFile` binary attribute will be set to 1 and no call to
2475     /// the `hunk_cb` nor `line_cb` will be made (unless you set the `force_text`
2476     /// option).
diff_blobs( &self, old_blob: Option<&Blob<'_>>, old_as_path: Option<&str>, new_blob: Option<&Blob<'_>>, new_as_path: Option<&str>, opts: Option<&mut DiffOptions>, file_cb: Option<&mut FileCb<'_>>, binary_cb: Option<&mut BinaryCb<'_>>, hunk_cb: Option<&mut HunkCb<'_>>, line_cb: Option<&mut LineCb<'_>>, ) -> Result<(), Error>2477     pub fn diff_blobs(
2478         &self,
2479         old_blob: Option<&Blob<'_>>,
2480         old_as_path: Option<&str>,
2481         new_blob: Option<&Blob<'_>>,
2482         new_as_path: Option<&str>,
2483         opts: Option<&mut DiffOptions>,
2484         file_cb: Option<&mut FileCb<'_>>,
2485         binary_cb: Option<&mut BinaryCb<'_>>,
2486         hunk_cb: Option<&mut HunkCb<'_>>,
2487         line_cb: Option<&mut LineCb<'_>>,
2488     ) -> Result<(), Error> {
2489         let old_as_path = crate::opt_cstr(old_as_path)?;
2490         let new_as_path = crate::opt_cstr(new_as_path)?;
2491         let mut cbs = DiffCallbacks {
2492             file: file_cb,
2493             binary: binary_cb,
2494             hunk: hunk_cb,
2495             line: line_cb,
2496         };
2497         let ptr = &mut cbs as *mut _;
2498         unsafe {
2499             let file_cb_c: raw::git_diff_file_cb = if cbs.file.is_some() {
2500                 Some(file_cb_c)
2501             } else {
2502                 None
2503             };
2504             let binary_cb_c: raw::git_diff_binary_cb = if cbs.binary.is_some() {
2505                 Some(binary_cb_c)
2506             } else {
2507                 None
2508             };
2509             let hunk_cb_c: raw::git_diff_hunk_cb = if cbs.hunk.is_some() {
2510                 Some(hunk_cb_c)
2511             } else {
2512                 None
2513             };
2514             let line_cb_c: raw::git_diff_line_cb = if cbs.line.is_some() {
2515                 Some(line_cb_c)
2516             } else {
2517                 None
2518             };
2519             try_call!(raw::git_diff_blobs(
2520                 old_blob.map(|s| s.raw()),
2521                 old_as_path,
2522                 new_blob.map(|s| s.raw()),
2523                 new_as_path,
2524                 opts.map(|s| s.raw()),
2525                 file_cb_c,
2526                 binary_cb_c,
2527                 hunk_cb_c,
2528                 line_cb_c,
2529                 ptr as *mut _
2530             ));
2531             Ok(())
2532         }
2533     }
2534 
2535     /// Create a diff with the difference between two tree objects.
2536     ///
2537     /// This is equivalent to `git diff <old-tree> <new-tree>`
2538     ///
2539     /// The first tree will be used for the "old_file" side of the delta and the
2540     /// second tree will be used for the "new_file" side of the delta.  You can
2541     /// pass `None` to indicate an empty tree, although it is an error to pass
2542     /// `None` for both the `old_tree` and `new_tree`.
diff_tree_to_tree( &self, old_tree: Option<&Tree<'_>>, new_tree: Option<&Tree<'_>>, opts: Option<&mut DiffOptions>, ) -> Result<Diff<'_>, Error>2543     pub fn diff_tree_to_tree(
2544         &self,
2545         old_tree: Option<&Tree<'_>>,
2546         new_tree: Option<&Tree<'_>>,
2547         opts: Option<&mut DiffOptions>,
2548     ) -> Result<Diff<'_>, Error> {
2549         let mut ret = ptr::null_mut();
2550         unsafe {
2551             try_call!(raw::git_diff_tree_to_tree(
2552                 &mut ret,
2553                 self.raw(),
2554                 old_tree.map(|s| s.raw()),
2555                 new_tree.map(|s| s.raw()),
2556                 opts.map(|s| s.raw())
2557             ));
2558             Ok(Binding::from_raw(ret))
2559         }
2560     }
2561 
2562     /// Create a diff between a tree and repository index.
2563     ///
2564     /// This is equivalent to `git diff --cached <treeish>` or if you pass
2565     /// the HEAD tree, then like `git diff --cached`.
2566     ///
2567     /// The tree you pass will be used for the "old_file" side of the delta, and
2568     /// the index will be used for the "new_file" side of the delta.
2569     ///
2570     /// If you pass `None` for the index, then the existing index of the `repo`
2571     /// will be used.  In this case, the index will be refreshed from disk
2572     /// (if it has changed) before the diff is generated.
2573     ///
2574     /// If the tree is `None`, then it is considered an empty tree.
diff_tree_to_index( &self, old_tree: Option<&Tree<'_>>, index: Option<&Index>, opts: Option<&mut DiffOptions>, ) -> Result<Diff<'_>, Error>2575     pub fn diff_tree_to_index(
2576         &self,
2577         old_tree: Option<&Tree<'_>>,
2578         index: Option<&Index>,
2579         opts: Option<&mut DiffOptions>,
2580     ) -> Result<Diff<'_>, Error> {
2581         let mut ret = ptr::null_mut();
2582         unsafe {
2583             try_call!(raw::git_diff_tree_to_index(
2584                 &mut ret,
2585                 self.raw(),
2586                 old_tree.map(|s| s.raw()),
2587                 index.map(|s| s.raw()),
2588                 opts.map(|s| s.raw())
2589             ));
2590             Ok(Binding::from_raw(ret))
2591         }
2592     }
2593 
2594     /// Create a diff between two index objects.
2595     ///
2596     /// The first index will be used for the "old_file" side of the delta, and
2597     /// the second index will be used for the "new_file" side of the delta.
diff_index_to_index( &self, old_index: &Index, new_index: &Index, opts: Option<&mut DiffOptions>, ) -> Result<Diff<'_>, Error>2598     pub fn diff_index_to_index(
2599         &self,
2600         old_index: &Index,
2601         new_index: &Index,
2602         opts: Option<&mut DiffOptions>,
2603     ) -> Result<Diff<'_>, Error> {
2604         let mut ret = ptr::null_mut();
2605         unsafe {
2606             try_call!(raw::git_diff_index_to_index(
2607                 &mut ret,
2608                 self.raw(),
2609                 old_index.raw(),
2610                 new_index.raw(),
2611                 opts.map(|s| s.raw())
2612             ));
2613             Ok(Binding::from_raw(ret))
2614         }
2615     }
2616 
2617     /// Create a diff between the repository index and the workdir directory.
2618     ///
2619     /// This matches the `git diff` command.  See the note below on
2620     /// `tree_to_workdir` for a discussion of the difference between
2621     /// `git diff` and `git diff HEAD` and how to emulate a `git diff <treeish>`
2622     /// using libgit2.
2623     ///
2624     /// The index will be used for the "old_file" side of the delta, and the
2625     /// working directory will be used for the "new_file" side of the delta.
2626     ///
2627     /// If you pass `None` for the index, then the existing index of the `repo`
2628     /// will be used.  In this case, the index will be refreshed from disk
2629     /// (if it has changed) before the diff is generated.
diff_index_to_workdir( &self, index: Option<&Index>, opts: Option<&mut DiffOptions>, ) -> Result<Diff<'_>, Error>2630     pub fn diff_index_to_workdir(
2631         &self,
2632         index: Option<&Index>,
2633         opts: Option<&mut DiffOptions>,
2634     ) -> Result<Diff<'_>, Error> {
2635         let mut ret = ptr::null_mut();
2636         unsafe {
2637             try_call!(raw::git_diff_index_to_workdir(
2638                 &mut ret,
2639                 self.raw(),
2640                 index.map(|s| s.raw()),
2641                 opts.map(|s| s.raw())
2642             ));
2643             Ok(Binding::from_raw(ret))
2644         }
2645     }
2646 
2647     /// Create a diff between a tree and the working directory.
2648     ///
2649     /// The tree you provide will be used for the "old_file" side of the delta,
2650     /// and the working directory will be used for the "new_file" side.
2651     ///
2652     /// This is not the same as `git diff <treeish>` or `git diff-index
2653     /// <treeish>`.  Those commands use information from the index, whereas this
2654     /// function strictly returns the differences between the tree and the files
2655     /// in the working directory, regardless of the state of the index.  Use
2656     /// `tree_to_workdir_with_index` to emulate those commands.
2657     ///
2658     /// To see difference between this and `tree_to_workdir_with_index`,
2659     /// consider the example of a staged file deletion where the file has then
2660     /// been put back into the working dir and further modified.  The
2661     /// tree-to-workdir diff for that file is 'modified', but `git diff` would
2662     /// show status 'deleted' since there is a staged delete.
2663     ///
2664     /// If `None` is passed for `tree`, then an empty tree is used.
diff_tree_to_workdir( &self, old_tree: Option<&Tree<'_>>, opts: Option<&mut DiffOptions>, ) -> Result<Diff<'_>, Error>2665     pub fn diff_tree_to_workdir(
2666         &self,
2667         old_tree: Option<&Tree<'_>>,
2668         opts: Option<&mut DiffOptions>,
2669     ) -> Result<Diff<'_>, Error> {
2670         let mut ret = ptr::null_mut();
2671         unsafe {
2672             try_call!(raw::git_diff_tree_to_workdir(
2673                 &mut ret,
2674                 self.raw(),
2675                 old_tree.map(|s| s.raw()),
2676                 opts.map(|s| s.raw())
2677             ));
2678             Ok(Binding::from_raw(ret))
2679         }
2680     }
2681 
2682     /// Create a diff between a tree and the working directory using index data
2683     /// to account for staged deletes, tracked files, etc.
2684     ///
2685     /// This emulates `git diff <tree>` by diffing the tree to the index and
2686     /// the index to the working directory and blending the results into a
2687     /// single diff that includes staged deleted, etc.
diff_tree_to_workdir_with_index( &self, old_tree: Option<&Tree<'_>>, opts: Option<&mut DiffOptions>, ) -> Result<Diff<'_>, Error>2688     pub fn diff_tree_to_workdir_with_index(
2689         &self,
2690         old_tree: Option<&Tree<'_>>,
2691         opts: Option<&mut DiffOptions>,
2692     ) -> Result<Diff<'_>, Error> {
2693         let mut ret = ptr::null_mut();
2694         unsafe {
2695             try_call!(raw::git_diff_tree_to_workdir_with_index(
2696                 &mut ret,
2697                 self.raw(),
2698                 old_tree.map(|s| s.raw()),
2699                 opts.map(|s| s.raw())
2700             ));
2701             Ok(Binding::from_raw(ret))
2702         }
2703     }
2704 
2705     /// Create a PackBuilder
packbuilder(&self) -> Result<PackBuilder<'_>, Error>2706     pub fn packbuilder(&self) -> Result<PackBuilder<'_>, Error> {
2707         let mut ret = ptr::null_mut();
2708         unsafe {
2709             try_call!(raw::git_packbuilder_new(&mut ret, self.raw()));
2710             Ok(Binding::from_raw(ret))
2711         }
2712     }
2713 
2714     /// Save the local modifications to a new stash.
stash_save( &mut self, stasher: &Signature<'_>, message: &str, flags: Option<StashFlags>, ) -> Result<Oid, Error>2715     pub fn stash_save(
2716         &mut self,
2717         stasher: &Signature<'_>,
2718         message: &str,
2719         flags: Option<StashFlags>,
2720     ) -> Result<Oid, Error> {
2721         self.stash_save2(stasher, Some(message), flags)
2722     }
2723 
2724     /// Save the local modifications to a new stash.
2725     /// unlike `stash_save` it allows to pass a null `message`
stash_save2( &mut self, stasher: &Signature<'_>, message: Option<&str>, flags: Option<StashFlags>, ) -> Result<Oid, Error>2726     pub fn stash_save2(
2727         &mut self,
2728         stasher: &Signature<'_>,
2729         message: Option<&str>,
2730         flags: Option<StashFlags>,
2731     ) -> Result<Oid, Error> {
2732         unsafe {
2733             let mut raw_oid = raw::git_oid {
2734                 id: [0; raw::GIT_OID_RAWSZ],
2735             };
2736             let message = crate::opt_cstr(message)?;
2737             let flags = flags.unwrap_or_else(StashFlags::empty);
2738             try_call!(raw::git_stash_save(
2739                 &mut raw_oid,
2740                 self.raw(),
2741                 stasher.raw(),
2742                 message,
2743                 flags.bits() as c_uint
2744             ));
2745             Ok(Binding::from_raw(&raw_oid as *const _))
2746         }
2747     }
2748 
2749     /// Apply a single stashed state from the stash list.
stash_apply( &mut self, index: usize, opts: Option<&mut StashApplyOptions<'_>>, ) -> Result<(), Error>2750     pub fn stash_apply(
2751         &mut self,
2752         index: usize,
2753         opts: Option<&mut StashApplyOptions<'_>>,
2754     ) -> Result<(), Error> {
2755         unsafe {
2756             let opts = opts.map(|opts| opts.raw());
2757             try_call!(raw::git_stash_apply(self.raw(), index, opts));
2758             Ok(())
2759         }
2760     }
2761 
2762     /// Loop over all the stashed states and issue a callback for each one.
2763     ///
2764     /// Return `true` to continue iterating or `false` to stop.
stash_foreach<C>(&mut self, mut callback: C) -> Result<(), Error> where C: FnMut(usize, &str, &Oid) -> bool,2765     pub fn stash_foreach<C>(&mut self, mut callback: C) -> Result<(), Error>
2766     where
2767         C: FnMut(usize, &str, &Oid) -> bool,
2768     {
2769         unsafe {
2770             let mut data = StashCbData {
2771                 callback: &mut callback,
2772             };
2773             let cb: raw::git_stash_cb = Some(stash_cb);
2774             try_call!(raw::git_stash_foreach(
2775                 self.raw(),
2776                 cb,
2777                 &mut data as *mut _ as *mut _
2778             ));
2779             Ok(())
2780         }
2781     }
2782 
2783     /// Remove a single stashed state from the stash list.
stash_drop(&mut self, index: usize) -> Result<(), Error>2784     pub fn stash_drop(&mut self, index: usize) -> Result<(), Error> {
2785         unsafe {
2786             try_call!(raw::git_stash_drop(self.raw(), index));
2787             Ok(())
2788         }
2789     }
2790 
2791     /// Apply a single stashed state from the stash list and remove it from the list if successful.
stash_pop( &mut self, index: usize, opts: Option<&mut StashApplyOptions<'_>>, ) -> Result<(), Error>2792     pub fn stash_pop(
2793         &mut self,
2794         index: usize,
2795         opts: Option<&mut StashApplyOptions<'_>>,
2796     ) -> Result<(), Error> {
2797         unsafe {
2798             let opts = opts.map(|opts| opts.raw());
2799             try_call!(raw::git_stash_pop(self.raw(), index, opts));
2800             Ok(())
2801         }
2802     }
2803 
2804     /// Add ignore rules for a repository.
2805     ///
2806     /// The format of the rules is the same one of the .gitignore file.
add_ignore_rule(&self, rules: &str) -> Result<(), Error>2807     pub fn add_ignore_rule(&self, rules: &str) -> Result<(), Error> {
2808         let rules = CString::new(rules)?;
2809         unsafe {
2810             try_call!(raw::git_ignore_add_rule(self.raw, rules));
2811         }
2812         Ok(())
2813     }
2814 
2815     /// Clear ignore rules that were explicitly added.
clear_ignore_rules(&self) -> Result<(), Error>2816     pub fn clear_ignore_rules(&self) -> Result<(), Error> {
2817         unsafe {
2818             try_call!(raw::git_ignore_clear_internal_rules(self.raw));
2819         }
2820         Ok(())
2821     }
2822 
2823     /// Test if the ignore rules apply to a given path.
is_path_ignored<P: AsRef<Path>>(&self, path: P) -> Result<bool, Error>2824     pub fn is_path_ignored<P: AsRef<Path>>(&self, path: P) -> Result<bool, Error> {
2825         let path = util::cstring_to_repo_path(path.as_ref())?;
2826         let mut ignored: c_int = 0;
2827         unsafe {
2828             try_call!(raw::git_ignore_path_is_ignored(
2829                 &mut ignored,
2830                 self.raw,
2831                 path
2832             ));
2833         }
2834         Ok(ignored == 1)
2835     }
2836 
2837     /// Perform a cherrypick
cherrypick( &self, commit: &Commit<'_>, options: Option<&mut CherrypickOptions<'_>>, ) -> Result<(), Error>2838     pub fn cherrypick(
2839         &self,
2840         commit: &Commit<'_>,
2841         options: Option<&mut CherrypickOptions<'_>>,
2842     ) -> Result<(), Error> {
2843         let raw_opts = options.map(|o| o.raw());
2844         let ptr_raw_opts = match raw_opts.as_ref() {
2845             Some(v) => v,
2846             None => std::ptr::null(),
2847         };
2848         unsafe {
2849             try_call!(raw::git_cherrypick(self.raw(), commit.raw(), ptr_raw_opts));
2850 
2851             Ok(())
2852         }
2853     }
2854 
2855     /// Create an index of uncommitted changes, representing the result of
2856     /// cherry-picking.
cherrypick_commit( &self, cherrypick_commit: &Commit<'_>, our_commit: &Commit<'_>, mainline: u32, options: Option<&MergeOptions>, ) -> Result<Index, Error>2857     pub fn cherrypick_commit(
2858         &self,
2859         cherrypick_commit: &Commit<'_>,
2860         our_commit: &Commit<'_>,
2861         mainline: u32,
2862         options: Option<&MergeOptions>,
2863     ) -> Result<Index, Error> {
2864         let mut ret = ptr::null_mut();
2865         unsafe {
2866             try_call!(raw::git_cherrypick_commit(
2867                 &mut ret,
2868                 self.raw(),
2869                 cherrypick_commit.raw(),
2870                 our_commit.raw(),
2871                 mainline,
2872                 options.map(|o| o.raw())
2873             ));
2874             Ok(Binding::from_raw(ret))
2875         }
2876     }
2877 
2878     /// Find the remote name of a remote-tracking branch
branch_remote_name(&self, refname: &str) -> Result<Buf, Error>2879     pub fn branch_remote_name(&self, refname: &str) -> Result<Buf, Error> {
2880         let refname = CString::new(refname)?;
2881         unsafe {
2882             let buf = Buf::new();
2883             try_call!(raw::git_branch_remote_name(buf.raw(), self.raw, refname));
2884             Ok(buf)
2885         }
2886     }
2887 
2888     /// Retrieves the name of the reference supporting the remote tracking branch,
2889     /// given the name of a local branch reference.
branch_upstream_name(&self, refname: &str) -> Result<Buf, Error>2890     pub fn branch_upstream_name(&self, refname: &str) -> Result<Buf, Error> {
2891         let refname = CString::new(refname)?;
2892         unsafe {
2893             let buf = Buf::new();
2894             try_call!(raw::git_branch_upstream_name(buf.raw(), self.raw, refname));
2895             Ok(buf)
2896         }
2897     }
2898 
2899     /// Retrieve the name of the upstream remote of a local branch.
branch_upstream_remote(&self, refname: &str) -> Result<Buf, Error>2900     pub fn branch_upstream_remote(&self, refname: &str) -> Result<Buf, Error> {
2901         let refname = CString::new(refname)?;
2902         unsafe {
2903             let buf = Buf::new();
2904             try_call!(raw::git_branch_upstream_remote(
2905                 buf.raw(),
2906                 self.raw,
2907                 refname
2908             ));
2909             Ok(buf)
2910         }
2911     }
2912 
2913     /// Apply a Diff to the given repo, making changes directly in the working directory, the index, or both.
apply( &self, diff: &Diff<'_>, location: ApplyLocation, options: Option<&mut ApplyOptions<'_>>, ) -> Result<(), Error>2914     pub fn apply(
2915         &self,
2916         diff: &Diff<'_>,
2917         location: ApplyLocation,
2918         options: Option<&mut ApplyOptions<'_>>,
2919     ) -> Result<(), Error> {
2920         unsafe {
2921             try_call!(raw::git_apply(
2922                 self.raw,
2923                 diff.raw(),
2924                 location.raw(),
2925                 options.map(|s| s.raw()).unwrap_or(ptr::null())
2926             ));
2927 
2928             Ok(())
2929         }
2930     }
2931 
2932     /// Apply a Diff to the provided tree, and return the resulting Index.
apply_to_tree( &self, tree: &Tree<'_>, diff: &Diff<'_>, options: Option<&mut ApplyOptions<'_>>, ) -> Result<Index, Error>2933     pub fn apply_to_tree(
2934         &self,
2935         tree: &Tree<'_>,
2936         diff: &Diff<'_>,
2937         options: Option<&mut ApplyOptions<'_>>,
2938     ) -> Result<Index, Error> {
2939         let mut ret = ptr::null_mut();
2940         unsafe {
2941             try_call!(raw::git_apply_to_tree(
2942                 &mut ret,
2943                 self.raw,
2944                 tree.raw(),
2945                 diff.raw(),
2946                 options.map(|s| s.raw()).unwrap_or(ptr::null())
2947             ));
2948             Ok(Binding::from_raw(ret))
2949         }
2950     }
2951 
2952     /// Reverts the given commit, producing changes in the index and working directory.
revert( &self, commit: &Commit<'_>, options: Option<&mut RevertOptions<'_>>, ) -> Result<(), Error>2953     pub fn revert(
2954         &self,
2955         commit: &Commit<'_>,
2956         options: Option<&mut RevertOptions<'_>>,
2957     ) -> Result<(), Error> {
2958         let raw_opts = options.map(|o| o.raw());
2959         let ptr_raw_opts = match raw_opts.as_ref() {
2960             Some(v) => v,
2961             None => 0 as *const _,
2962         };
2963         unsafe {
2964             try_call!(raw::git_revert(self.raw(), commit.raw(), ptr_raw_opts));
2965             Ok(())
2966         }
2967     }
2968 
2969     /// Reverts the given commit against the given "our" commit,
2970     /// producing an index that reflects the result of the revert.
revert_commit( &self, revert_commit: &Commit<'_>, our_commit: &Commit<'_>, mainline: u32, options: Option<&MergeOptions>, ) -> Result<Index, Error>2971     pub fn revert_commit(
2972         &self,
2973         revert_commit: &Commit<'_>,
2974         our_commit: &Commit<'_>,
2975         mainline: u32,
2976         options: Option<&MergeOptions>,
2977     ) -> Result<Index, Error> {
2978         let mut ret = ptr::null_mut();
2979         unsafe {
2980             try_call!(raw::git_revert_commit(
2981                 &mut ret,
2982                 self.raw(),
2983                 revert_commit.raw(),
2984                 our_commit.raw(),
2985                 mainline,
2986                 options.map(|o| o.raw())
2987             ));
2988             Ok(Binding::from_raw(ret))
2989         }
2990     }
2991 
2992     /// Lists all the worktrees for the repository
worktrees(&self) -> Result<StringArray, Error>2993     pub fn worktrees(&self) -> Result<StringArray, Error> {
2994         let mut arr = raw::git_strarray {
2995             strings: ptr::null_mut(),
2996             count: 0,
2997         };
2998         unsafe {
2999             try_call!(raw::git_worktree_list(&mut arr, self.raw));
3000             Ok(Binding::from_raw(arr))
3001         }
3002     }
3003 
3004     /// Opens a worktree by name for the given repository
3005     ///
3006     /// This can open any worktree that the worktrees method returns.
find_worktree(&self, name: &str) -> Result<Worktree, Error>3007     pub fn find_worktree(&self, name: &str) -> Result<Worktree, Error> {
3008         let mut raw = ptr::null_mut();
3009         let raw_name = CString::new(name)?;
3010         unsafe {
3011             try_call!(raw::git_worktree_lookup(&mut raw, self.raw, raw_name));
3012             Ok(Binding::from_raw(raw))
3013         }
3014     }
3015 
3016     /// Creates a new worktree for the repository
worktree<'a>( &'a self, name: &str, path: &Path, opts: Option<&WorktreeAddOptions<'a>>, ) -> Result<Worktree, Error>3017     pub fn worktree<'a>(
3018         &'a self,
3019         name: &str,
3020         path: &Path,
3021         opts: Option<&WorktreeAddOptions<'a>>,
3022     ) -> Result<Worktree, Error> {
3023         let mut raw = ptr::null_mut();
3024         let raw_name = CString::new(name)?;
3025         let raw_path = path.into_c_string()?;
3026 
3027         unsafe {
3028             try_call!(raw::git_worktree_add(
3029                 &mut raw,
3030                 self.raw,
3031                 raw_name,
3032                 raw_path,
3033                 opts.map(|o| o.raw())
3034             ));
3035             Ok(Binding::from_raw(raw))
3036         }
3037     }
3038 
3039     /// Create a new transaction
transaction<'a>(&'a self) -> Result<Transaction<'a>, Error>3040     pub fn transaction<'a>(&'a self) -> Result<Transaction<'a>, Error> {
3041         let mut raw = ptr::null_mut();
3042         unsafe {
3043             try_call!(raw::git_transaction_new(&mut raw, self.raw));
3044             Ok(Binding::from_raw(raw))
3045         }
3046     }
3047 
3048     /// Gets this repository's mailmap.
mailmap(&self) -> Result<Mailmap, Error>3049     pub fn mailmap(&self) -> Result<Mailmap, Error> {
3050         let mut ret = ptr::null_mut();
3051         unsafe {
3052             try_call!(raw::git_mailmap_from_repository(&mut ret, self.raw));
3053             Ok(Binding::from_raw(ret))
3054         }
3055     }
3056 
3057     ///  If a merge is in progress, invoke 'callback' for each commit ID in the
3058     ///  MERGE_HEAD file.
mergehead_foreach<C>(&mut self, mut callback: C) -> Result<(), Error> where C: FnMut(&Oid) -> bool,3059     pub fn mergehead_foreach<C>(&mut self, mut callback: C) -> Result<(), Error>
3060     where
3061         C: FnMut(&Oid) -> bool,
3062     {
3063         unsafe {
3064             let mut data = MergeheadForeachCbData {
3065                 callback: &mut callback,
3066             };
3067             let cb: raw::git_repository_mergehead_foreach_cb = Some(mergehead_foreach_cb);
3068             try_call!(raw::git_repository_mergehead_foreach(
3069                 self.raw(),
3070                 cb,
3071                 &mut data as *mut _ as *mut _
3072             ));
3073             Ok(())
3074         }
3075     }
3076 
3077     /// Invoke 'callback' for each entry in the given FETCH_HEAD file.
3078     ///
3079     /// `callback` will be called with with following arguments:
3080     ///
3081     /// - `&str`: the reference name
3082     /// - `&[u8]`: the remote url
3083     /// - `&Oid`: the reference target OID
3084     /// - `bool`: was the reference the result of a merge
fetchhead_foreach<C>(&self, mut callback: C) -> Result<(), Error> where C: FnMut(&str, &[u8], &Oid, bool) -> bool,3085     pub fn fetchhead_foreach<C>(&self, mut callback: C) -> Result<(), Error>
3086     where
3087         C: FnMut(&str, &[u8], &Oid, bool) -> bool,
3088     {
3089         unsafe {
3090             let mut data = FetchheadForeachCbData {
3091                 callback: &mut callback,
3092             };
3093             let cb: raw::git_repository_fetchhead_foreach_cb = Some(fetchhead_foreach_cb);
3094             try_call!(raw::git_repository_fetchhead_foreach(
3095                 self.raw(),
3096                 cb,
3097                 &mut data as *mut _ as *mut _
3098             ));
3099             Ok(())
3100         }
3101     }
3102 }
3103 
3104 impl Binding for Repository {
3105     type Raw = *mut raw::git_repository;
from_raw(ptr: *mut raw::git_repository) -> Repository3106     unsafe fn from_raw(ptr: *mut raw::git_repository) -> Repository {
3107         Repository { raw: ptr }
3108     }
raw(&self) -> *mut raw::git_repository3109     fn raw(&self) -> *mut raw::git_repository {
3110         self.raw
3111     }
3112 }
3113 
3114 impl Drop for Repository {
drop(&mut self)3115     fn drop(&mut self) {
3116         unsafe { raw::git_repository_free(self.raw) }
3117     }
3118 }
3119 
3120 impl RepositoryInitOptions {
3121     /// Creates a default set of initialization options.
3122     ///
3123     /// By default this will set flags for creating all necessary directories
3124     /// and initializing a directory from the user-configured templates path.
new() -> RepositoryInitOptions3125     pub fn new() -> RepositoryInitOptions {
3126         RepositoryInitOptions {
3127             flags: raw::GIT_REPOSITORY_INIT_MKDIR as u32
3128                 | raw::GIT_REPOSITORY_INIT_MKPATH as u32
3129                 | raw::GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE as u32,
3130             mode: 0,
3131             workdir_path: None,
3132             description: None,
3133             template_path: None,
3134             initial_head: None,
3135             origin_url: None,
3136         }
3137     }
3138 
3139     /// Create a bare repository with no working directory.
3140     ///
3141     /// Defaults to false.
bare(&mut self, bare: bool) -> &mut RepositoryInitOptions3142     pub fn bare(&mut self, bare: bool) -> &mut RepositoryInitOptions {
3143         self.flag(raw::GIT_REPOSITORY_INIT_BARE, bare)
3144     }
3145 
3146     /// Return an error if the repository path appears to already be a git
3147     /// repository.
3148     ///
3149     /// Defaults to false.
no_reinit(&mut self, enabled: bool) -> &mut RepositoryInitOptions3150     pub fn no_reinit(&mut self, enabled: bool) -> &mut RepositoryInitOptions {
3151         self.flag(raw::GIT_REPOSITORY_INIT_NO_REINIT, enabled)
3152     }
3153 
3154     /// Normally a '/.git/' will be appended to the repo path for non-bare repos
3155     /// (if it is not already there), but passing this flag prevents that
3156     /// behavior.
3157     ///
3158     /// Defaults to false.
no_dotgit_dir(&mut self, enabled: bool) -> &mut RepositoryInitOptions3159     pub fn no_dotgit_dir(&mut self, enabled: bool) -> &mut RepositoryInitOptions {
3160         self.flag(raw::GIT_REPOSITORY_INIT_NO_DOTGIT_DIR, enabled)
3161     }
3162 
3163     /// Make the repo path (and workdir path) as needed. The ".git" directory
3164     /// will always be created regardless of this flag.
3165     ///
3166     /// Defaults to true.
mkdir(&mut self, enabled: bool) -> &mut RepositoryInitOptions3167     pub fn mkdir(&mut self, enabled: bool) -> &mut RepositoryInitOptions {
3168         self.flag(raw::GIT_REPOSITORY_INIT_MKDIR, enabled)
3169     }
3170 
3171     /// Recursively make all components of the repo and workdir path as
3172     /// necessary.
3173     ///
3174     /// Defaults to true.
mkpath(&mut self, enabled: bool) -> &mut RepositoryInitOptions3175     pub fn mkpath(&mut self, enabled: bool) -> &mut RepositoryInitOptions {
3176         self.flag(raw::GIT_REPOSITORY_INIT_MKPATH, enabled)
3177     }
3178 
3179     /// Set to one of the `RepositoryInit` constants, or a custom value.
mode(&mut self, mode: RepositoryInitMode) -> &mut RepositoryInitOptions3180     pub fn mode(&mut self, mode: RepositoryInitMode) -> &mut RepositoryInitOptions {
3181         self.mode = mode.bits();
3182         self
3183     }
3184 
3185     /// Enable or disable using external templates.
3186     ///
3187     /// If enabled, then the `template_path` option will be queried first, then
3188     /// `init.templatedir` from the global config, and finally
3189     /// `/usr/share/git-core-templates` will be used (if it exists).
3190     ///
3191     /// Defaults to true.
external_template(&mut self, enabled: bool) -> &mut RepositoryInitOptions3192     pub fn external_template(&mut self, enabled: bool) -> &mut RepositoryInitOptions {
3193         self.flag(raw::GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE, enabled)
3194     }
3195 
flag( &mut self, flag: raw::git_repository_init_flag_t, on: bool, ) -> &mut RepositoryInitOptions3196     fn flag(
3197         &mut self,
3198         flag: raw::git_repository_init_flag_t,
3199         on: bool,
3200     ) -> &mut RepositoryInitOptions {
3201         if on {
3202             self.flags |= flag as u32;
3203         } else {
3204             self.flags &= !(flag as u32);
3205         }
3206         self
3207     }
3208 
3209     /// The path to the working directory.
3210     ///
3211     /// If this is a relative path it will be evaulated relative to the repo
3212     /// path. If this is not the "natural" working directory, a .git gitlink
3213     /// file will be created here linking to the repo path.
workdir_path(&mut self, path: &Path) -> &mut RepositoryInitOptions3214     pub fn workdir_path(&mut self, path: &Path) -> &mut RepositoryInitOptions {
3215         // Normal file path OK (does not need Windows conversion).
3216         self.workdir_path = Some(path.into_c_string().unwrap());
3217         self
3218     }
3219 
3220     /// If set, this will be used to initialize the "description" file in the
3221     /// repository instead of using the template content.
description(&mut self, desc: &str) -> &mut RepositoryInitOptions3222     pub fn description(&mut self, desc: &str) -> &mut RepositoryInitOptions {
3223         self.description = Some(CString::new(desc).unwrap());
3224         self
3225     }
3226 
3227     /// When the `external_template` option is set, this is the first location
3228     /// to check for the template directory.
3229     ///
3230     /// If this is not configured, then the default locations will be searched
3231     /// instead.
template_path(&mut self, path: &Path) -> &mut RepositoryInitOptions3232     pub fn template_path(&mut self, path: &Path) -> &mut RepositoryInitOptions {
3233         // Normal file path OK (does not need Windows conversion).
3234         self.template_path = Some(path.into_c_string().unwrap());
3235         self
3236     }
3237 
3238     /// The name of the head to point HEAD at.
3239     ///
3240     /// If not configured, this will be taken from your git configuration.
3241     /// If this begins with `refs/` it will be used verbatim;
3242     /// otherwise `refs/heads/` will be prefixed
initial_head(&mut self, head: &str) -> &mut RepositoryInitOptions3243     pub fn initial_head(&mut self, head: &str) -> &mut RepositoryInitOptions {
3244         self.initial_head = Some(CString::new(head).unwrap());
3245         self
3246     }
3247 
3248     /// If set, then after the rest of the repository initialization is
3249     /// completed an `origin` remote will be added pointing to this URL.
origin_url(&mut self, url: &str) -> &mut RepositoryInitOptions3250     pub fn origin_url(&mut self, url: &str) -> &mut RepositoryInitOptions {
3251         self.origin_url = Some(CString::new(url).unwrap());
3252         self
3253     }
3254 
3255     /// Creates a set of raw init options to be used with
3256     /// `git_repository_init_ext`.
3257     ///
3258     /// This method is unsafe as the returned value may have pointers to the
3259     /// interior of this structure.
raw(&self) -> raw::git_repository_init_options3260     pub unsafe fn raw(&self) -> raw::git_repository_init_options {
3261         let mut opts = mem::zeroed();
3262         assert_eq!(
3263             raw::git_repository_init_init_options(
3264                 &mut opts,
3265                 raw::GIT_REPOSITORY_INIT_OPTIONS_VERSION
3266             ),
3267             0
3268         );
3269         opts.flags = self.flags;
3270         opts.mode = self.mode;
3271         opts.workdir_path = crate::call::convert(&self.workdir_path);
3272         opts.description = crate::call::convert(&self.description);
3273         opts.template_path = crate::call::convert(&self.template_path);
3274         opts.initial_head = crate::call::convert(&self.initial_head);
3275         opts.origin_url = crate::call::convert(&self.origin_url);
3276         opts
3277     }
3278 }
3279 
3280 #[cfg(test)]
3281 mod tests {
3282     use crate::build::CheckoutBuilder;
3283     use crate::CherrypickOptions;
3284     use crate::{
3285         ObjectType, Oid, Repository, ResetType, Signature, SubmoduleIgnore, SubmoduleUpdate,
3286     };
3287     use std::ffi::OsStr;
3288     use std::fs;
3289     use std::path::Path;
3290     use tempfile::TempDir;
3291 
3292     #[test]
smoke_init()3293     fn smoke_init() {
3294         let td = TempDir::new().unwrap();
3295         let path = td.path();
3296 
3297         let repo = Repository::init(path).unwrap();
3298         assert!(!repo.is_bare());
3299     }
3300 
3301     #[test]
smoke_init_bare()3302     fn smoke_init_bare() {
3303         let td = TempDir::new().unwrap();
3304         let path = td.path();
3305 
3306         let repo = Repository::init_bare(path).unwrap();
3307         assert!(repo.is_bare());
3308         assert!(repo.namespace().is_none());
3309     }
3310 
3311     #[test]
smoke_open()3312     fn smoke_open() {
3313         let td = TempDir::new().unwrap();
3314         let path = td.path();
3315         Repository::init(td.path()).unwrap();
3316         let repo = Repository::open(path).unwrap();
3317         assert!(!repo.is_bare());
3318         assert!(!repo.is_shallow());
3319         assert!(repo.is_empty().unwrap());
3320         assert_eq!(
3321             crate::test::realpath(&repo.path()).unwrap(),
3322             crate::test::realpath(&td.path().join(".git/")).unwrap()
3323         );
3324         assert_eq!(repo.state(), crate::RepositoryState::Clean);
3325     }
3326 
3327     #[test]
smoke_open_bare()3328     fn smoke_open_bare() {
3329         let td = TempDir::new().unwrap();
3330         let path = td.path();
3331         Repository::init_bare(td.path()).unwrap();
3332 
3333         let repo = Repository::open(path).unwrap();
3334         assert!(repo.is_bare());
3335         assert_eq!(
3336             crate::test::realpath(&repo.path()).unwrap(),
3337             crate::test::realpath(&td.path().join("")).unwrap()
3338         );
3339     }
3340 
3341     #[test]
smoke_checkout()3342     fn smoke_checkout() {
3343         let (_td, repo) = crate::test::repo_init();
3344         repo.checkout_head(None).unwrap();
3345     }
3346 
3347     #[test]
smoke_revparse()3348     fn smoke_revparse() {
3349         let (_td, repo) = crate::test::repo_init();
3350         let rev = repo.revparse("HEAD").unwrap();
3351         assert!(rev.to().is_none());
3352         let from = rev.from().unwrap();
3353         assert!(rev.from().is_some());
3354 
3355         assert_eq!(repo.revparse_single("HEAD").unwrap().id(), from.id());
3356         let obj = repo.find_object(from.id(), None).unwrap().clone();
3357         obj.peel(ObjectType::Any).unwrap();
3358         obj.short_id().unwrap();
3359         repo.reset(&obj, ResetType::Hard, None).unwrap();
3360         let mut opts = CheckoutBuilder::new();
3361         t!(repo.reset(&obj, ResetType::Soft, Some(&mut opts)));
3362     }
3363 
3364     #[test]
makes_dirs()3365     fn makes_dirs() {
3366         let td = TempDir::new().unwrap();
3367         Repository::init(&td.path().join("a/b/c/d")).unwrap();
3368     }
3369 
3370     #[test]
smoke_discover()3371     fn smoke_discover() {
3372         let td = TempDir::new().unwrap();
3373         let subdir = td.path().join("subdi");
3374         fs::create_dir(&subdir).unwrap();
3375         Repository::init_bare(td.path()).unwrap();
3376         let repo = Repository::discover(&subdir).unwrap();
3377         assert_eq!(
3378             crate::test::realpath(&repo.path()).unwrap(),
3379             crate::test::realpath(&td.path().join("")).unwrap()
3380         );
3381     }
3382 
3383     #[test]
smoke_open_ext()3384     fn smoke_open_ext() {
3385         let td = TempDir::new().unwrap();
3386         let subdir = td.path().join("subdir");
3387         fs::create_dir(&subdir).unwrap();
3388         Repository::init(td.path()).unwrap();
3389 
3390         let repo = Repository::open_ext(
3391             &subdir,
3392             crate::RepositoryOpenFlags::empty(),
3393             &[] as &[&OsStr],
3394         )
3395         .unwrap();
3396         assert!(!repo.is_bare());
3397         assert_eq!(
3398             crate::test::realpath(&repo.path()).unwrap(),
3399             crate::test::realpath(&td.path().join(".git")).unwrap()
3400         );
3401 
3402         let repo =
3403             Repository::open_ext(&subdir, crate::RepositoryOpenFlags::BARE, &[] as &[&OsStr])
3404                 .unwrap();
3405         assert!(repo.is_bare());
3406         assert_eq!(
3407             crate::test::realpath(&repo.path()).unwrap(),
3408             crate::test::realpath(&td.path().join(".git")).unwrap()
3409         );
3410 
3411         let err = Repository::open_ext(
3412             &subdir,
3413             crate::RepositoryOpenFlags::NO_SEARCH,
3414             &[] as &[&OsStr],
3415         )
3416         .err()
3417         .unwrap();
3418         assert_eq!(err.code(), crate::ErrorCode::NotFound);
3419 
3420         assert!(
3421             Repository::open_ext(&subdir, crate::RepositoryOpenFlags::empty(), &[&subdir]).is_ok()
3422         );
3423     }
3424 
graph_repo_init() -> (TempDir, Repository)3425     fn graph_repo_init() -> (TempDir, Repository) {
3426         let (_td, repo) = crate::test::repo_init();
3427         {
3428             let head = repo.head().unwrap().target().unwrap();
3429             let head = repo.find_commit(head).unwrap();
3430 
3431             let mut index = repo.index().unwrap();
3432             let id = index.write_tree().unwrap();
3433 
3434             let tree = repo.find_tree(id).unwrap();
3435             let sig = repo.signature().unwrap();
3436             repo.commit(Some("HEAD"), &sig, &sig, "second", &tree, &[&head])
3437                 .unwrap();
3438         }
3439         (_td, repo)
3440     }
3441 
3442     #[test]
smoke_graph_ahead_behind()3443     fn smoke_graph_ahead_behind() {
3444         let (_td, repo) = graph_repo_init();
3445         let head = repo.head().unwrap().target().unwrap();
3446         let head = repo.find_commit(head).unwrap();
3447         let head_id = head.id();
3448         let head_parent_id = head.parent(0).unwrap().id();
3449         let (ahead, behind) = repo.graph_ahead_behind(head_id, head_parent_id).unwrap();
3450         assert_eq!(ahead, 1);
3451         assert_eq!(behind, 0);
3452         let (ahead, behind) = repo.graph_ahead_behind(head_parent_id, head_id).unwrap();
3453         assert_eq!(ahead, 0);
3454         assert_eq!(behind, 1);
3455     }
3456 
3457     #[test]
smoke_graph_descendant_of()3458     fn smoke_graph_descendant_of() {
3459         let (_td, repo) = graph_repo_init();
3460         let head = repo.head().unwrap().target().unwrap();
3461         let head = repo.find_commit(head).unwrap();
3462         let head_id = head.id();
3463         let head_parent_id = head.parent(0).unwrap().id();
3464         assert!(repo.graph_descendant_of(head_id, head_parent_id).unwrap());
3465         assert!(!repo.graph_descendant_of(head_parent_id, head_id).unwrap());
3466     }
3467 
3468     #[test]
smoke_reference_has_log_ensure_log()3469     fn smoke_reference_has_log_ensure_log() {
3470         let (_td, repo) = crate::test::repo_init();
3471 
3472         assert_eq!(repo.reference_has_log("HEAD").unwrap(), true);
3473         assert_eq!(repo.reference_has_log("refs/heads/main").unwrap(), true);
3474         assert_eq!(repo.reference_has_log("NOT_HEAD").unwrap(), false);
3475         let main_oid = repo.revparse_single("main").unwrap().id();
3476         assert!(repo
3477             .reference("NOT_HEAD", main_oid, false, "creating a new branch")
3478             .is_ok());
3479         assert_eq!(repo.reference_has_log("NOT_HEAD").unwrap(), false);
3480         assert!(repo.reference_ensure_log("NOT_HEAD").is_ok());
3481         assert_eq!(repo.reference_has_log("NOT_HEAD").unwrap(), true);
3482     }
3483 
3484     #[test]
smoke_set_head()3485     fn smoke_set_head() {
3486         let (_td, repo) = crate::test::repo_init();
3487 
3488         assert!(repo.set_head("refs/heads/does-not-exist").is_ok());
3489         assert!(repo.head().is_err());
3490 
3491         assert!(repo.set_head("refs/heads/main").is_ok());
3492         assert!(repo.head().is_ok());
3493 
3494         assert!(repo.set_head("*").is_err());
3495     }
3496 
3497     #[test]
smoke_set_head_detached()3498     fn smoke_set_head_detached() {
3499         let (_td, repo) = crate::test::repo_init();
3500 
3501         let void_oid = Oid::from_bytes(b"00000000000000000000").unwrap();
3502         assert!(repo.set_head_detached(void_oid).is_err());
3503 
3504         let main_oid = repo.revparse_single("main").unwrap().id();
3505         assert!(repo.set_head_detached(main_oid).is_ok());
3506         assert_eq!(repo.head().unwrap().target().unwrap(), main_oid);
3507     }
3508 
3509     /// create the following:
3510     ///    /---o4
3511     ///   /---o3
3512     /// o1---o2
3513     #[test]
smoke_merge_base()3514     fn smoke_merge_base() {
3515         let (_td, repo) = graph_repo_init();
3516         let sig = repo.signature().unwrap();
3517 
3518         // let oid1 = head
3519         let oid1 = repo.head().unwrap().target().unwrap();
3520         let commit1 = repo.find_commit(oid1).unwrap();
3521         println!("created oid1 {:?}", oid1);
3522 
3523         repo.branch("branch_a", &commit1, true).unwrap();
3524         repo.branch("branch_b", &commit1, true).unwrap();
3525         repo.branch("branch_c", &commit1, true).unwrap();
3526 
3527         // create commit oid2 on branch_a
3528         let mut index = repo.index().unwrap();
3529         let p = Path::new(repo.workdir().unwrap()).join("file_a");
3530         println!("using path {:?}", p);
3531         fs::File::create(&p).unwrap();
3532         index.add_path(Path::new("file_a")).unwrap();
3533         let id_a = index.write_tree().unwrap();
3534         let tree_a = repo.find_tree(id_a).unwrap();
3535         let oid2 = repo
3536             .commit(
3537                 Some("refs/heads/branch_a"),
3538                 &sig,
3539                 &sig,
3540                 "commit 2",
3541                 &tree_a,
3542                 &[&commit1],
3543             )
3544             .unwrap();
3545         repo.find_commit(oid2).unwrap();
3546         println!("created oid2 {:?}", oid2);
3547 
3548         t!(repo.reset(commit1.as_object(), ResetType::Hard, None));
3549 
3550         // create commit oid3 on branch_b
3551         let mut index = repo.index().unwrap();
3552         let p = Path::new(repo.workdir().unwrap()).join("file_b");
3553         fs::File::create(&p).unwrap();
3554         index.add_path(Path::new("file_b")).unwrap();
3555         let id_b = index.write_tree().unwrap();
3556         let tree_b = repo.find_tree(id_b).unwrap();
3557         let oid3 = repo
3558             .commit(
3559                 Some("refs/heads/branch_b"),
3560                 &sig,
3561                 &sig,
3562                 "commit 3",
3563                 &tree_b,
3564                 &[&commit1],
3565             )
3566             .unwrap();
3567         repo.find_commit(oid3).unwrap();
3568         println!("created oid3 {:?}", oid3);
3569 
3570         t!(repo.reset(commit1.as_object(), ResetType::Hard, None));
3571 
3572         // create commit oid4 on branch_c
3573         let mut index = repo.index().unwrap();
3574         let p = Path::new(repo.workdir().unwrap()).join("file_c");
3575         fs::File::create(&p).unwrap();
3576         index.add_path(Path::new("file_c")).unwrap();
3577         let id_c = index.write_tree().unwrap();
3578         let tree_c = repo.find_tree(id_c).unwrap();
3579         let oid4 = repo
3580             .commit(
3581                 Some("refs/heads/branch_c"),
3582                 &sig,
3583                 &sig,
3584                 "commit 3",
3585                 &tree_c,
3586                 &[&commit1],
3587             )
3588             .unwrap();
3589         repo.find_commit(oid4).unwrap();
3590         println!("created oid4 {:?}", oid4);
3591 
3592         // the merge base of (oid2,oid3) should be oid1
3593         let merge_base = repo.merge_base(oid2, oid3).unwrap();
3594         assert_eq!(merge_base, oid1);
3595 
3596         // the merge base of (oid2,oid3,oid4) should be oid1
3597         let merge_base = repo.merge_base_many(&[oid2, oid3, oid4]).unwrap();
3598         assert_eq!(merge_base, oid1);
3599     }
3600 
3601     /// create an octopus:
3602     ///   /---o2-o4
3603     /// o1      X
3604     ///   \---o3-o5
3605     /// and checks that the merge bases of (o4,o5) are (o2,o3)
3606     #[test]
smoke_merge_bases()3607     fn smoke_merge_bases() {
3608         let (_td, repo) = graph_repo_init();
3609         let sig = repo.signature().unwrap();
3610 
3611         // let oid1 = head
3612         let oid1 = repo.head().unwrap().target().unwrap();
3613         let commit1 = repo.find_commit(oid1).unwrap();
3614         println!("created oid1 {:?}", oid1);
3615 
3616         repo.branch("branch_a", &commit1, true).unwrap();
3617         repo.branch("branch_b", &commit1, true).unwrap();
3618 
3619         // create commit oid2 on branchA
3620         let mut index = repo.index().unwrap();
3621         let p = Path::new(repo.workdir().unwrap()).join("file_a");
3622         println!("using path {:?}", p);
3623         fs::File::create(&p).unwrap();
3624         index.add_path(Path::new("file_a")).unwrap();
3625         let id_a = index.write_tree().unwrap();
3626         let tree_a = repo.find_tree(id_a).unwrap();
3627         let oid2 = repo
3628             .commit(
3629                 Some("refs/heads/branch_a"),
3630                 &sig,
3631                 &sig,
3632                 "commit 2",
3633                 &tree_a,
3634                 &[&commit1],
3635             )
3636             .unwrap();
3637         let commit2 = repo.find_commit(oid2).unwrap();
3638         println!("created oid2 {:?}", oid2);
3639 
3640         t!(repo.reset(commit1.as_object(), ResetType::Hard, None));
3641 
3642         // create commit oid3 on branchB
3643         let mut index = repo.index().unwrap();
3644         let p = Path::new(repo.workdir().unwrap()).join("file_b");
3645         fs::File::create(&p).unwrap();
3646         index.add_path(Path::new("file_b")).unwrap();
3647         let id_b = index.write_tree().unwrap();
3648         let tree_b = repo.find_tree(id_b).unwrap();
3649         let oid3 = repo
3650             .commit(
3651                 Some("refs/heads/branch_b"),
3652                 &sig,
3653                 &sig,
3654                 "commit 3",
3655                 &tree_b,
3656                 &[&commit1],
3657             )
3658             .unwrap();
3659         let commit3 = repo.find_commit(oid3).unwrap();
3660         println!("created oid3 {:?}", oid3);
3661 
3662         // create merge commit oid4 on branchA with parents oid2 and oid3
3663         //let mut index4 = repo.merge_commits(&commit2, &commit3, None).unwrap();
3664         repo.set_head("refs/heads/branch_a").unwrap();
3665         repo.checkout_head(None).unwrap();
3666         let oid4 = repo
3667             .commit(
3668                 Some("refs/heads/branch_a"),
3669                 &sig,
3670                 &sig,
3671                 "commit 4",
3672                 &tree_a,
3673                 &[&commit2, &commit3],
3674             )
3675             .unwrap();
3676         //index4.write_tree_to(&repo).unwrap();
3677         println!("created oid4 {:?}", oid4);
3678 
3679         // create merge commit oid5 on branchB with parents oid2 and oid3
3680         //let mut index5 = repo.merge_commits(&commit3, &commit2, None).unwrap();
3681         repo.set_head("refs/heads/branch_b").unwrap();
3682         repo.checkout_head(None).unwrap();
3683         let oid5 = repo
3684             .commit(
3685                 Some("refs/heads/branch_b"),
3686                 &sig,
3687                 &sig,
3688                 "commit 5",
3689                 &tree_a,
3690                 &[&commit3, &commit2],
3691             )
3692             .unwrap();
3693         //index5.write_tree_to(&repo).unwrap();
3694         println!("created oid5 {:?}", oid5);
3695 
3696         // merge bases of (oid4,oid5) should be (oid2,oid3)
3697         let merge_bases = repo.merge_bases(oid4, oid5).unwrap();
3698         let mut found_oid2 = false;
3699         let mut found_oid3 = false;
3700         for mg in merge_bases.iter() {
3701             println!("found merge base {:?}", mg);
3702             if mg == &oid2 {
3703                 found_oid2 = true;
3704             } else if mg == &oid3 {
3705                 found_oid3 = true;
3706             } else {
3707                 assert!(false);
3708             }
3709         }
3710         assert!(found_oid2);
3711         assert!(found_oid3);
3712         assert_eq!(merge_bases.len(), 2);
3713 
3714         // merge bases of (oid4,oid5) should be (oid2,oid3)
3715         let merge_bases = repo.merge_bases_many(&[oid4, oid5]).unwrap();
3716         let mut found_oid2 = false;
3717         let mut found_oid3 = false;
3718         for mg in merge_bases.iter() {
3719             println!("found merge base {:?}", mg);
3720             if mg == &oid2 {
3721                 found_oid2 = true;
3722             } else if mg == &oid3 {
3723                 found_oid3 = true;
3724             } else {
3725                 assert!(false);
3726             }
3727         }
3728         assert!(found_oid2);
3729         assert!(found_oid3);
3730         assert_eq!(merge_bases.len(), 2);
3731     }
3732 
3733     #[test]
smoke_revparse_ext()3734     fn smoke_revparse_ext() {
3735         let (_td, repo) = graph_repo_init();
3736 
3737         {
3738             let short_refname = "main";
3739             let expected_refname = "refs/heads/main";
3740             let (obj, reference) = repo.revparse_ext(short_refname).unwrap();
3741             let expected_obj = repo.revparse_single(expected_refname).unwrap();
3742             assert_eq!(obj.id(), expected_obj.id());
3743             assert_eq!(reference.unwrap().name().unwrap(), expected_refname);
3744         }
3745         {
3746             let missing_refname = "refs/heads/does-not-exist";
3747             assert!(repo.revparse_ext(missing_refname).is_err());
3748         }
3749         {
3750             let (_obj, reference) = repo.revparse_ext("HEAD^").unwrap();
3751             assert!(reference.is_none());
3752         }
3753     }
3754 
3755     #[test]
smoke_is_path_ignored()3756     fn smoke_is_path_ignored() {
3757         let (_td, repo) = graph_repo_init();
3758 
3759         assert!(!repo.is_path_ignored(Path::new("foo")).unwrap());
3760 
3761         let _ = repo.add_ignore_rule("/foo");
3762         assert!(repo.is_path_ignored(Path::new("foo")).unwrap());
3763         if cfg!(windows) {
3764             assert!(repo.is_path_ignored(Path::new("foo\\thing")).unwrap());
3765         }
3766 
3767         let _ = repo.clear_ignore_rules();
3768         assert!(!repo.is_path_ignored(Path::new("foo")).unwrap());
3769         if cfg!(windows) {
3770             assert!(!repo.is_path_ignored(Path::new("foo\\thing")).unwrap());
3771         }
3772     }
3773 
3774     #[test]
smoke_cherrypick()3775     fn smoke_cherrypick() {
3776         let (_td, repo) = crate::test::repo_init();
3777         let sig = repo.signature().unwrap();
3778 
3779         let oid1 = repo.head().unwrap().target().unwrap();
3780         let commit1 = repo.find_commit(oid1).unwrap();
3781 
3782         repo.branch("branch_a", &commit1, true).unwrap();
3783 
3784         // Add 2 commits on top of the initial one in branch_a
3785         let mut index = repo.index().unwrap();
3786         let p1 = Path::new(repo.workdir().unwrap()).join("file_c");
3787         fs::File::create(&p1).unwrap();
3788         index.add_path(Path::new("file_c")).unwrap();
3789         let id = index.write_tree().unwrap();
3790         let tree_c = repo.find_tree(id).unwrap();
3791         let oid2 = repo
3792             .commit(
3793                 Some("refs/heads/branch_a"),
3794                 &sig,
3795                 &sig,
3796                 "commit 2",
3797                 &tree_c,
3798                 &[&commit1],
3799             )
3800             .unwrap();
3801         let commit2 = repo.find_commit(oid2).unwrap();
3802         println!("created oid2 {:?}", oid2);
3803         assert!(p1.exists());
3804 
3805         let mut index = repo.index().unwrap();
3806         let p2 = Path::new(repo.workdir().unwrap()).join("file_d");
3807         fs::File::create(&p2).unwrap();
3808         index.add_path(Path::new("file_d")).unwrap();
3809         let id = index.write_tree().unwrap();
3810         let tree_d = repo.find_tree(id).unwrap();
3811         let oid3 = repo
3812             .commit(
3813                 Some("refs/heads/branch_a"),
3814                 &sig,
3815                 &sig,
3816                 "commit 3",
3817                 &tree_d,
3818                 &[&commit2],
3819             )
3820             .unwrap();
3821         let commit3 = repo.find_commit(oid3).unwrap();
3822         println!("created oid3 {:?}", oid3);
3823         assert!(p1.exists());
3824         assert!(p2.exists());
3825 
3826         // cherry-pick commit3 on top of commit1 in branch b
3827         repo.reset(commit1.as_object(), ResetType::Hard, None)
3828             .unwrap();
3829         let mut cherrypick_opts = CherrypickOptions::new();
3830         repo.cherrypick(&commit3, Some(&mut cherrypick_opts))
3831             .unwrap();
3832         let id = repo.index().unwrap().write_tree().unwrap();
3833         let tree_d = repo.find_tree(id).unwrap();
3834         let oid4 = repo
3835             .commit(Some("HEAD"), &sig, &sig, "commit 4", &tree_d, &[&commit1])
3836             .unwrap();
3837         let commit4 = repo.find_commit(oid4).unwrap();
3838         // should have file from commit3, but not the file from commit2
3839         assert_eq!(commit4.parent(0).unwrap().id(), commit1.id());
3840         assert!(!p1.exists());
3841         assert!(p2.exists());
3842     }
3843 
3844     #[test]
smoke_revert()3845     fn smoke_revert() {
3846         let (_td, repo) = crate::test::repo_init();
3847         let foo_file = Path::new(repo.workdir().unwrap()).join("foo");
3848         assert!(!foo_file.exists());
3849 
3850         let (oid1, _id) = crate::test::commit(&repo);
3851         let commit1 = repo.find_commit(oid1).unwrap();
3852         t!(repo.reset(commit1.as_object(), ResetType::Hard, None));
3853         assert!(foo_file.exists());
3854 
3855         repo.revert(&commit1, None).unwrap();
3856         let id = repo.index().unwrap().write_tree().unwrap();
3857         let tree2 = repo.find_tree(id).unwrap();
3858         let sig = repo.signature().unwrap();
3859         repo.commit(Some("HEAD"), &sig, &sig, "commit 1", &tree2, &[&commit1])
3860             .unwrap();
3861         // reverting once removes `foo` file
3862         assert!(!foo_file.exists());
3863 
3864         let oid2 = repo.head().unwrap().target().unwrap();
3865         let commit2 = repo.find_commit(oid2).unwrap();
3866         repo.revert(&commit2, None).unwrap();
3867         let id = repo.index().unwrap().write_tree().unwrap();
3868         let tree3 = repo.find_tree(id).unwrap();
3869         repo.commit(Some("HEAD"), &sig, &sig, "commit 2", &tree3, &[&commit2])
3870             .unwrap();
3871         // reverting twice restores `foo` file
3872         assert!(foo_file.exists());
3873     }
3874 
3875     #[test]
smoke_config_write_and_read()3876     fn smoke_config_write_and_read() {
3877         let (td, repo) = crate::test::repo_init();
3878 
3879         let mut config = repo.config().unwrap();
3880 
3881         config.set_bool("commit.gpgsign", false).unwrap();
3882 
3883         let c = fs::read_to_string(td.path().join(".git").join("config")).unwrap();
3884 
3885         assert!(c.contains("[commit]"));
3886         assert!(c.contains("gpgsign = false"));
3887 
3888         let config = repo.config().unwrap();
3889 
3890         assert!(!config.get_bool("commit.gpgsign").unwrap());
3891     }
3892 
3893     #[test]
smoke_merge_analysis_for_ref() -> Result<(), crate::Error>3894     fn smoke_merge_analysis_for_ref() -> Result<(), crate::Error> {
3895         let (_td, repo) = graph_repo_init();
3896 
3897         // Set up this repo state:
3898         // * second (their-branch)
3899         // * initial (HEAD -> main)
3900         //
3901         // We expect that their-branch can be fast-forward merged into main.
3902 
3903         // git checkout --detach HEAD
3904         let head_commit = repo.head()?.peel_to_commit()?;
3905         repo.set_head_detached(head_commit.id())?;
3906 
3907         // git branch their-branch HEAD
3908         let their_branch = repo.branch("their-branch", &head_commit, false)?;
3909 
3910         // git branch -f main HEAD~
3911         let mut parents_iter = head_commit.parents();
3912         let parent = parents_iter.next().unwrap();
3913         assert!(parents_iter.next().is_none());
3914 
3915         let main = repo.branch("main", &parent, true)?;
3916 
3917         // git checkout main
3918         repo.set_head(main.get().name().expect("should be utf-8"))?;
3919 
3920         let (merge_analysis, _merge_preference) = repo.merge_analysis_for_ref(
3921             main.get(),
3922             &[&repo.reference_to_annotated_commit(their_branch.get())?],
3923         )?;
3924 
3925         assert!(merge_analysis.contains(crate::MergeAnalysis::ANALYSIS_FASTFORWARD));
3926 
3927         Ok(())
3928     }
3929 
3930     #[test]
smoke_submodule_set() -> Result<(), crate::Error>3931     fn smoke_submodule_set() -> Result<(), crate::Error> {
3932         let (td1, _repo) = crate::test::repo_init();
3933         let (td2, mut repo2) = crate::test::repo_init();
3934         let url = crate::test::path2url(td1.path());
3935         let name = "bar";
3936         {
3937             let mut s = repo2.submodule(&url, Path::new(name), true)?;
3938             fs::remove_dir_all(td2.path().join("bar")).unwrap();
3939             Repository::clone(&url, td2.path().join("bar"))?;
3940             s.add_to_index(false)?;
3941             s.add_finalize()?;
3942         }
3943 
3944         // update strategy
3945         repo2.submodule_set_update(name, SubmoduleUpdate::None)?;
3946         assert!(matches!(
3947             repo2.find_submodule(name)?.update_strategy(),
3948             SubmoduleUpdate::None
3949         ));
3950         repo2.submodule_set_update(name, SubmoduleUpdate::Rebase)?;
3951         assert!(matches!(
3952             repo2.find_submodule(name)?.update_strategy(),
3953             SubmoduleUpdate::Rebase
3954         ));
3955 
3956         // ignore rule
3957         repo2.submodule_set_ignore(name, SubmoduleIgnore::Untracked)?;
3958         assert!(matches!(
3959             repo2.find_submodule(name)?.ignore_rule(),
3960             SubmoduleIgnore::Untracked
3961         ));
3962         repo2.submodule_set_ignore(name, SubmoduleIgnore::Dirty)?;
3963         assert!(matches!(
3964             repo2.find_submodule(name)?.ignore_rule(),
3965             SubmoduleIgnore::Dirty
3966         ));
3967 
3968         // url
3969         repo2.submodule_set_url(name, "fake-url")?;
3970         assert_eq!(repo2.find_submodule(name)?.url(), Some("fake-url"));
3971 
3972         // branch
3973         repo2.submodule_set_branch(name, "fake-branch")?;
3974         assert_eq!(repo2.find_submodule(name)?.branch(), Some("fake-branch"));
3975 
3976         Ok(())
3977     }
3978 
3979     #[test]
smoke_mailmap_from_repository()3980     fn smoke_mailmap_from_repository() {
3981         let (_td, repo) = crate::test::repo_init();
3982 
3983         let commit = {
3984             let head = t!(repo.head()).target().unwrap();
3985             t!(repo.find_commit(head))
3986         };
3987 
3988         // This is our baseline for HEAD.
3989         let author = commit.author();
3990         let committer = commit.committer();
3991         assert_eq!(author.name(), Some("name"));
3992         assert_eq!(author.email(), Some("email"));
3993         assert_eq!(committer.name(), Some("name"));
3994         assert_eq!(committer.email(), Some("email"));
3995 
3996         // There is no .mailmap file in the test repo so all signature identities are equal.
3997         let mailmap = t!(repo.mailmap());
3998         let mailmapped_author = t!(commit.author_with_mailmap(&mailmap));
3999         let mailmapped_committer = t!(commit.committer_with_mailmap(&mailmap));
4000         assert_eq!(mailmapped_author.name(), author.name());
4001         assert_eq!(mailmapped_author.email(), author.email());
4002         assert_eq!(mailmapped_committer.name(), committer.name());
4003         assert_eq!(mailmapped_committer.email(), committer.email());
4004 
4005         let commit = {
4006             // - Add a .mailmap file to the repository.
4007             // - Commit with a signature identity different from the author's.
4008             // - Include entries for both author and committer to prove we call
4009             //   the right raw functions.
4010             let mailmap_file = Path::new(".mailmap");
4011             let p = Path::new(repo.workdir().unwrap()).join(&mailmap_file);
4012             t!(fs::write(
4013                 p,
4014                 r#"
4015 Author Name <author.proper@email> name <email>
4016 Committer Name <committer.proper@email> <committer@email>"#,
4017             ));
4018             let mut index = t!(repo.index());
4019             t!(index.add_path(&mailmap_file));
4020             let id_mailmap = t!(index.write_tree());
4021             let tree_mailmap = t!(repo.find_tree(id_mailmap));
4022 
4023             let head = t!(repo.commit(
4024                 Some("HEAD"),
4025                 &author,
4026                 t!(&Signature::now("committer", "committer@email")),
4027                 "Add mailmap",
4028                 &tree_mailmap,
4029                 &[&commit],
4030             ));
4031             t!(repo.find_commit(head))
4032         };
4033 
4034         // Sanity check that we're working with the right commit and that its
4035         // author and committer identities differ.
4036         let author = commit.author();
4037         let committer = commit.committer();
4038         assert_ne!(author.name(), committer.name());
4039         assert_ne!(author.email(), committer.email());
4040         assert_eq!(author.name(), Some("name"));
4041         assert_eq!(author.email(), Some("email"));
4042         assert_eq!(committer.name(), Some("committer"));
4043         assert_eq!(committer.email(), Some("committer@email"));
4044 
4045         // Fetch the newly added .mailmap from the repository.
4046         let mailmap = t!(repo.mailmap());
4047         let mailmapped_author = t!(commit.author_with_mailmap(&mailmap));
4048         let mailmapped_committer = t!(commit.committer_with_mailmap(&mailmap));
4049 
4050         let mm_resolve_author = t!(mailmap.resolve_signature(&author));
4051         let mm_resolve_committer = t!(mailmap.resolve_signature(&committer));
4052 
4053         // Mailmap Signature lifetime is independent of Commit lifetime.
4054         drop(author);
4055         drop(committer);
4056         drop(commit);
4057 
4058         // author_with_mailmap() + committer_with_mailmap() work
4059         assert_eq!(mailmapped_author.name(), Some("Author Name"));
4060         assert_eq!(mailmapped_author.email(), Some("author.proper@email"));
4061         assert_eq!(mailmapped_committer.name(), Some("Committer Name"));
4062         assert_eq!(mailmapped_committer.email(), Some("committer.proper@email"));
4063 
4064         // resolve_signature() works
4065         assert_eq!(mm_resolve_author.email(), mailmapped_author.email());
4066         assert_eq!(mm_resolve_committer.email(), mailmapped_committer.email());
4067     }
4068 }
4069