1 //! # libgit2 bindings for Rust
2 //!
3 //! This library contains bindings to the [libgit2][1] C library which is used
4 //! to manage git repositories. The library itself is a work in progress and is
5 //! likely lacking some bindings here and there, so be warned.
6 //!
7 //! [1]: https://libgit2.github.com/
8 //!
9 //! The git2-rs library strives to be as close to libgit2 as possible, but also
10 //! strives to make using libgit2 as safe as possible. All resource management
11 //! is automatic as well as adding strong types to all interfaces (including
12 //! `Result`)
13 //!
14 //! ## Creating a `Repository`
15 //!
16 //! The `Repository` is the source from which almost all other objects in git-rs
17 //! are spawned. A repository can be created through opening, initializing, or
18 //! cloning.
19 //!
20 //! ### Initializing a new repository
21 //!
22 //! The `init` method will create a new repository, assuming one does not
23 //! already exist.
24 //!
25 //! ```no_run
26 //! # #![allow(unstable)]
27 //! use git2::Repository;
28 //!
29 //! let repo = match Repository::init("/path/to/a/repo") {
30 //!     Ok(repo) => repo,
31 //!     Err(e) => panic!("failed to init: {}", e),
32 //! };
33 //! ```
34 //!
35 //! ### Opening an existing repository
36 //!
37 //! ```no_run
38 //! # #![allow(unstable)]
39 //! use git2::Repository;
40 //!
41 //! let repo = match Repository::open("/path/to/a/repo") {
42 //!     Ok(repo) => repo,
43 //!     Err(e) => panic!("failed to open: {}", e),
44 //! };
45 //! ```
46 //!
47 //! ### Cloning an existing repository
48 //!
49 //! ```no_run
50 //! # #![allow(unstable)]
51 //! use git2::Repository;
52 //!
53 //! let url = "https://github.com/alexcrichton/git2-rs";
54 //! let repo = match Repository::clone(url, "/path/to/a/repo") {
55 //!     Ok(repo) => repo,
56 //!     Err(e) => panic!("failed to clone: {}", e),
57 //! };
58 //! ```
59 //!
60 //! To clone using SSH, refer to [RepoBuilder](./build/struct.RepoBuilder.html).
61 //!
62 //! ## Working with a `Repository`
63 //!
64 //! All derivative objects, references, etc are attached to the lifetime of the
65 //! source `Repository`, to ensure that they do not outlive the repository
66 //! itself.
67 
68 #![doc(html_root_url = "https://docs.rs/git2/0.13")]
69 #![allow(trivial_numeric_casts, trivial_casts)]
70 #![deny(missing_docs)]
71 #![warn(rust_2018_idioms)]
72 #![cfg_attr(test, deny(warnings))]
73 
74 use bitflags::bitflags;
75 use libgit2_sys as raw;
76 
77 use std::ffi::{CStr, CString};
78 use std::fmt;
79 use std::str;
80 use std::sync::Once;
81 
82 pub use crate::apply::{ApplyLocation, ApplyOptions};
83 pub use crate::attr::AttrValue;
84 pub use crate::blame::{Blame, BlameHunk, BlameIter, BlameOptions};
85 pub use crate::blob::{Blob, BlobWriter};
86 pub use crate::branch::{Branch, Branches};
87 pub use crate::buf::Buf;
88 pub use crate::cherrypick::CherrypickOptions;
89 pub use crate::commit::{Commit, Parents};
90 pub use crate::config::{Config, ConfigEntries, ConfigEntry};
91 pub use crate::cred::{Cred, CredentialHelper};
92 pub use crate::describe::{Describe, DescribeFormatOptions, DescribeOptions};
93 pub use crate::diff::{Deltas, Diff, DiffDelta, DiffFile, DiffOptions};
94 pub use crate::diff::{DiffBinary, DiffBinaryFile, DiffBinaryKind};
95 pub use crate::diff::{DiffFindOptions, DiffHunk, DiffLine, DiffLineType, DiffStats};
96 pub use crate::error::Error;
97 pub use crate::index::{
98     Index, IndexConflict, IndexConflicts, IndexEntries, IndexEntry, IndexMatchedPath,
99 };
100 pub use crate::indexer::{IndexerProgress, Progress};
101 pub use crate::mailmap::Mailmap;
102 pub use crate::mempack::Mempack;
103 pub use crate::merge::{AnnotatedCommit, MergeOptions};
104 pub use crate::message::{message_prettify, DEFAULT_COMMENT_CHAR};
105 pub use crate::note::{Note, Notes};
106 pub use crate::object::Object;
107 pub use crate::odb::{Odb, OdbObject, OdbPackwriter, OdbReader, OdbWriter};
108 pub use crate::oid::Oid;
109 pub use crate::packbuilder::{PackBuilder, PackBuilderStage};
110 pub use crate::patch::Patch;
111 pub use crate::pathspec::{Pathspec, PathspecFailedEntries, PathspecMatchList};
112 pub use crate::pathspec::{PathspecDiffEntries, PathspecEntries};
113 pub use crate::proxy_options::ProxyOptions;
114 pub use crate::rebase::{Rebase, RebaseOperation, RebaseOperationType, RebaseOptions};
115 pub use crate::reference::{Reference, ReferenceNames, References};
116 pub use crate::reflog::{Reflog, ReflogEntry, ReflogIter};
117 pub use crate::refspec::Refspec;
118 pub use crate::remote::{
119     FetchOptions, PushOptions, Refspecs, Remote, RemoteConnection, RemoteHead,
120 };
121 pub use crate::remote_callbacks::{Credentials, RemoteCallbacks};
122 pub use crate::remote_callbacks::{TransportMessage, UpdateTips};
123 pub use crate::repo::{Repository, RepositoryInitOptions};
124 pub use crate::revert::RevertOptions;
125 pub use crate::revspec::Revspec;
126 pub use crate::revwalk::Revwalk;
127 pub use crate::signature::Signature;
128 pub use crate::stash::{StashApplyOptions, StashApplyProgressCb, StashCb};
129 pub use crate::status::{StatusEntry, StatusIter, StatusOptions, StatusShow, Statuses};
130 pub use crate::submodule::{Submodule, SubmoduleUpdateOptions};
131 pub use crate::tag::Tag;
132 pub use crate::time::{IndexTime, Time};
133 pub use crate::transaction::Transaction;
134 pub use crate::tree::{Tree, TreeEntry, TreeIter, TreeWalkMode, TreeWalkResult};
135 pub use crate::treebuilder::TreeBuilder;
136 pub use crate::util::IntoCString;
137 pub use crate::worktree::{Worktree, WorktreeAddOptions, WorktreeLockStatus, WorktreePruneOptions};
138 
139 // Create a convinience method on bitflag struct which checks the given flag
140 macro_rules! is_bit_set {
141     ($name:ident, $flag:expr) => {
142         #[allow(missing_docs)]
143         pub fn $name(&self) -> bool {
144             self.intersects($flag)
145         }
146     };
147 }
148 
149 /// An enumeration of possible errors that can happen when working with a git
150 /// repository.
151 // Note: We omit a few native error codes, as they are unlikely to be propagated
152 // to the library user. Currently:
153 //
154 // * GIT_EPASSTHROUGH
155 // * GIT_ITEROVER
156 // * GIT_RETRY
157 #[derive(PartialEq, Eq, Clone, Debug, Copy)]
158 pub enum ErrorCode {
159     /// Generic error
160     GenericError,
161     /// Requested object could not be found
162     NotFound,
163     /// Object exists preventing operation
164     Exists,
165     /// More than one object matches
166     Ambiguous,
167     /// Output buffer too short to hold data
168     BufSize,
169     /// User-generated error
170     User,
171     /// Operation not allowed on bare repository
172     BareRepo,
173     /// HEAD refers to branch with no commits
174     UnbornBranch,
175     /// Merge in progress prevented operation
176     Unmerged,
177     /// Reference was not fast-forwardable
178     NotFastForward,
179     /// Name/ref spec was not in a valid format
180     InvalidSpec,
181     /// Checkout conflicts prevented operation
182     Conflict,
183     /// Lock file prevented operation
184     Locked,
185     /// Reference value does not match expected
186     Modified,
187     /// Authentication error
188     Auth,
189     /// Server certificate is invalid
190     Certificate,
191     /// Patch/merge has already been applied
192     Applied,
193     /// The requested peel operation is not possible
194     Peel,
195     /// Unexpected EOF
196     Eof,
197     /// Invalid operation or input
198     Invalid,
199     /// Uncommitted changes in index prevented operation
200     Uncommitted,
201     /// Operation was not valid for a directory
202     Directory,
203     /// A merge conflict exists and cannot continue
204     MergeConflict,
205     /// Hashsum mismatch in object
206     HashsumMismatch,
207     /// Unsaved changes in the index would be overwritten
208     IndexDirty,
209     /// Patch application failed
210     ApplyFail,
211 }
212 
213 /// An enumeration of possible categories of things that can have
214 /// errors when working with a git repository.
215 #[derive(PartialEq, Eq, Clone, Debug, Copy)]
216 pub enum ErrorClass {
217     /// Uncategorized
218     None,
219     /// Out of memory or insufficient allocated space
220     NoMemory,
221     /// Syscall or standard system library error
222     Os,
223     /// Invalid input
224     Invalid,
225     /// Error resolving or manipulating a reference
226     Reference,
227     /// ZLib failure
228     Zlib,
229     /// Bad repository state
230     Repository,
231     /// Bad configuration
232     Config,
233     /// Regex failure
234     Regex,
235     /// Bad object
236     Odb,
237     /// Invalid index data
238     Index,
239     /// Error creating or obtaining an object
240     Object,
241     /// Network error
242     Net,
243     /// Error manpulating a tag
244     Tag,
245     /// Invalid value in tree
246     Tree,
247     /// Hashing or packing error
248     Indexer,
249     /// Error from SSL
250     Ssl,
251     /// Error involing submodules
252     Submodule,
253     /// Threading error
254     Thread,
255     /// Error manipulating a stash
256     Stash,
257     /// Checkout failure
258     Checkout,
259     /// Invalid FETCH_HEAD
260     FetchHead,
261     /// Merge failure
262     Merge,
263     /// SSH failure
264     Ssh,
265     /// Error manipulating filters
266     Filter,
267     /// Error reverting commit
268     Revert,
269     /// Error from a user callback
270     Callback,
271     /// Error cherry-picking commit
272     CherryPick,
273     /// Can't describe object
274     Describe,
275     /// Error during rebase
276     Rebase,
277     /// Filesystem-related error
278     Filesystem,
279     /// Invalid patch data
280     Patch,
281     /// Error involving worktrees
282     Worktree,
283     /// Hash library error or SHA-1 collision
284     Sha1,
285     /// HTTP error
286     Http,
287 }
288 
289 /// A listing of the possible states that a repository can be in.
290 #[derive(PartialEq, Eq, Clone, Debug, Copy)]
291 #[allow(missing_docs)]
292 pub enum RepositoryState {
293     Clean,
294     Merge,
295     Revert,
296     RevertSequence,
297     CherryPick,
298     CherryPickSequence,
299     Bisect,
300     Rebase,
301     RebaseInteractive,
302     RebaseMerge,
303     ApplyMailbox,
304     ApplyMailboxOrRebase,
305 }
306 
307 /// An enumeration of the possible directions for a remote.
308 #[derive(Copy, Clone)]
309 pub enum Direction {
310     /// Data will be fetched (read) from this remote.
311     Fetch,
312     /// Data will be pushed (written) to this remote.
313     Push,
314 }
315 
316 /// An enumeration of the operations that can be performed for the `reset`
317 /// method on a `Repository`.
318 #[derive(Copy, Clone)]
319 pub enum ResetType {
320     /// Move the head to the given commit.
321     Soft,
322     /// Soft plus reset the index to the commit.
323     Mixed,
324     /// Mixed plus changes in the working tree are discarded.
325     Hard,
326 }
327 
328 /// An enumeration all possible kinds objects may have.
329 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
330 pub enum ObjectType {
331     /// Any kind of git object
332     Any,
333     /// An object which corresponds to a git commit
334     Commit,
335     /// An object which corresponds to a git tree
336     Tree,
337     /// An object which corresponds to a git blob
338     Blob,
339     /// An object which corresponds to a git tag
340     Tag,
341 }
342 
343 /// An enumeration of all possile kinds of references.
344 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
345 pub enum ReferenceType {
346     /// A reference which points at an object id.
347     Direct,
348 
349     /// A reference which points at another reference.
350     Symbolic,
351 }
352 
353 /// An enumeration for the possible types of branches
354 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
355 pub enum BranchType {
356     /// A local branch not on a remote.
357     Local,
358     /// A branch for a remote.
359     Remote,
360 }
361 
362 /// An enumeration of the possible priority levels of a config file.
363 ///
364 /// The levels corresponding to the escalation logic (higher to lower) when
365 /// searching for config entries.
366 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
367 pub enum ConfigLevel {
368     /// System-wide on Windows, for compatibility with portable git
369     ProgramData = 1,
370     /// System-wide configuration file, e.g. /etc/gitconfig
371     System,
372     /// XDG-compatible configuration file, e.g. ~/.config/git/config
373     XDG,
374     /// User-specific configuration, e.g. ~/.gitconfig
375     Global,
376     /// Repository specific config, e.g. $PWD/.git/config
377     Local,
378     /// Application specific configuration file
379     App,
380     /// Highest level available
381     Highest = -1,
382 }
383 
384 /// Merge file favor options for `MergeOptions` instruct the file-level
385 /// merging functionality how to deal with conflicting regions of the files.
386 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
387 pub enum FileFavor {
388     /// When a region of a file is changed in both branches, a conflict will be
389     /// recorded in the index so that git_checkout can produce a merge file with
390     /// conflict markers in the working directory. This is the default.
391     Normal,
392     /// When a region of a file is changed in both branches, the file created
393     /// in the index will contain the "ours" side of any conflicting region.
394     /// The index will not record a conflict.
395     Ours,
396     /// When a region of a file is changed in both branches, the file created
397     /// in the index will contain the "theirs" side of any conflicting region.
398     /// The index will not record a conflict.
399     Theirs,
400     /// When a region of a file is changed in both branches, the file created
401     /// in the index will contain each unique line from each side, which has
402     /// the result of combining both files. The index will not record a conflict.
403     Union,
404 }
405 
406 bitflags! {
407     /// Orderings that may be specified for Revwalk iteration.
408     pub struct Sort: u32 {
409         /// Sort the repository contents in no particular ordering.
410         ///
411         /// This sorting is arbitrary, implementation-specific, and subject to
412         /// change at any time. This is the default sorting for new walkers.
413         const NONE = raw::GIT_SORT_NONE as u32;
414 
415         /// Sort the repository contents in topological order (children before
416         /// parents).
417         ///
418         /// This sorting mode can be combined with time sorting.
419         const TOPOLOGICAL = raw::GIT_SORT_TOPOLOGICAL as u32;
420 
421         /// Sort the repository contents by commit time.
422         ///
423         /// This sorting mode can be combined with topological sorting.
424         const TIME = raw::GIT_SORT_TIME as u32;
425 
426         /// Iterate through the repository contents in reverse order.
427         ///
428         /// This sorting mode can be combined with any others.
429         const REVERSE = raw::GIT_SORT_REVERSE as u32;
430     }
431 }
432 
433 impl Sort {
434     is_bit_set!(is_none, Sort::NONE);
435     is_bit_set!(is_topological, Sort::TOPOLOGICAL);
436     is_bit_set!(is_time, Sort::TIME);
437     is_bit_set!(is_reverse, Sort::REVERSE);
438 }
439 
440 bitflags! {
441     /// Types of credentials that can be requested by a credential callback.
442     pub struct CredentialType: u32 {
443         #[allow(missing_docs)]
444         const USER_PASS_PLAINTEXT = raw::GIT_CREDTYPE_USERPASS_PLAINTEXT as u32;
445         #[allow(missing_docs)]
446         const SSH_KEY = raw::GIT_CREDTYPE_SSH_KEY as u32;
447         #[allow(missing_docs)]
448         const SSH_MEMORY = raw::GIT_CREDTYPE_SSH_MEMORY as u32;
449         #[allow(missing_docs)]
450         const SSH_CUSTOM = raw::GIT_CREDTYPE_SSH_CUSTOM as u32;
451         #[allow(missing_docs)]
452         const DEFAULT = raw::GIT_CREDTYPE_DEFAULT as u32;
453         #[allow(missing_docs)]
454         const SSH_INTERACTIVE = raw::GIT_CREDTYPE_SSH_INTERACTIVE as u32;
455         #[allow(missing_docs)]
456         const USERNAME = raw::GIT_CREDTYPE_USERNAME as u32;
457     }
458 }
459 
460 impl CredentialType {
461     is_bit_set!(is_user_pass_plaintext, CredentialType::USER_PASS_PLAINTEXT);
462     is_bit_set!(is_ssh_key, CredentialType::SSH_KEY);
463     is_bit_set!(is_ssh_memory, CredentialType::SSH_MEMORY);
464     is_bit_set!(is_ssh_custom, CredentialType::SSH_CUSTOM);
465     is_bit_set!(is_default, CredentialType::DEFAULT);
466     is_bit_set!(is_ssh_interactive, CredentialType::SSH_INTERACTIVE);
467     is_bit_set!(is_username, CredentialType::USERNAME);
468 }
469 
470 impl Default for CredentialType {
default() -> Self471     fn default() -> Self {
472         CredentialType::DEFAULT
473     }
474 }
475 
476 bitflags! {
477     /// Flags for the `flags` field of an IndexEntry.
478     pub struct IndexEntryFlag: u16 {
479         /// Set when the `extended_flags` field is valid.
480         const EXTENDED = raw::GIT_INDEX_ENTRY_EXTENDED as u16;
481         /// "Assume valid" flag
482         const VALID = raw::GIT_INDEX_ENTRY_VALID as u16;
483     }
484 }
485 
486 impl IndexEntryFlag {
487     is_bit_set!(is_extended, IndexEntryFlag::EXTENDED);
488     is_bit_set!(is_valid, IndexEntryFlag::VALID);
489 }
490 
491 bitflags! {
492     /// Flags for the `extended_flags` field of an IndexEntry.
493     pub struct IndexEntryExtendedFlag: u16 {
494         /// An "intent to add" entry from "git add -N"
495         const INTENT_TO_ADD = raw::GIT_INDEX_ENTRY_INTENT_TO_ADD as u16;
496         /// Skip the associated worktree file, for sparse checkouts
497         const SKIP_WORKTREE = raw::GIT_INDEX_ENTRY_SKIP_WORKTREE as u16;
498 
499         #[allow(missing_docs)]
500         const UPTODATE = raw::GIT_INDEX_ENTRY_UPTODATE as u16;
501     }
502 }
503 
504 impl IndexEntryExtendedFlag {
505     is_bit_set!(is_intent_to_add, IndexEntryExtendedFlag::INTENT_TO_ADD);
506     is_bit_set!(is_skip_worktree, IndexEntryExtendedFlag::SKIP_WORKTREE);
507     is_bit_set!(is_up_to_date, IndexEntryExtendedFlag::UPTODATE);
508 }
509 
510 bitflags! {
511     /// Flags for APIs that add files matching pathspec
512     pub struct IndexAddOption: u32 {
513         #[allow(missing_docs)]
514         const DEFAULT = raw::GIT_INDEX_ADD_DEFAULT as u32;
515         #[allow(missing_docs)]
516         const FORCE = raw::GIT_INDEX_ADD_FORCE as u32;
517         #[allow(missing_docs)]
518         const DISABLE_PATHSPEC_MATCH =
519                 raw::GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH as u32;
520         #[allow(missing_docs)]
521         const CHECK_PATHSPEC = raw::GIT_INDEX_ADD_CHECK_PATHSPEC as u32;
522     }
523 }
524 
525 impl IndexAddOption {
526     is_bit_set!(is_default, IndexAddOption::DEFAULT);
527     is_bit_set!(is_force, IndexAddOption::FORCE);
528     is_bit_set!(
529         is_disable_pathspec_match,
530         IndexAddOption::DISABLE_PATHSPEC_MATCH
531     );
532     is_bit_set!(is_check_pathspec, IndexAddOption::CHECK_PATHSPEC);
533 }
534 
535 impl Default for IndexAddOption {
default() -> Self536     fn default() -> Self {
537         IndexAddOption::DEFAULT
538     }
539 }
540 
541 bitflags! {
542     /// Flags for `Repository::open_ext`
543     pub struct RepositoryOpenFlags: u32 {
544         /// Only open the specified path; don't walk upward searching.
545         const NO_SEARCH = raw::GIT_REPOSITORY_OPEN_NO_SEARCH as u32;
546         /// Search across filesystem boundaries.
547         const CROSS_FS = raw::GIT_REPOSITORY_OPEN_CROSS_FS as u32;
548         /// Force opening as bare repository, and defer loading its config.
549         const BARE = raw::GIT_REPOSITORY_OPEN_BARE as u32;
550         /// Don't try appending `/.git` to the specified repository path.
551         const NO_DOTGIT = raw::GIT_REPOSITORY_OPEN_NO_DOTGIT as u32;
552         /// Respect environment variables like `$GIT_DIR`.
553         const FROM_ENV = raw::GIT_REPOSITORY_OPEN_FROM_ENV as u32;
554     }
555 }
556 
557 impl RepositoryOpenFlags {
558     is_bit_set!(is_no_search, RepositoryOpenFlags::NO_SEARCH);
559     is_bit_set!(is_cross_fs, RepositoryOpenFlags::CROSS_FS);
560     is_bit_set!(is_bare, RepositoryOpenFlags::BARE);
561     is_bit_set!(is_no_dotgit, RepositoryOpenFlags::NO_DOTGIT);
562     is_bit_set!(is_from_env, RepositoryOpenFlags::FROM_ENV);
563 }
564 
565 bitflags! {
566     /// Flags for the return value of `Repository::revparse`
567     pub struct RevparseMode: u32 {
568         /// The spec targeted a single object
569         const SINGLE = raw::GIT_REVPARSE_SINGLE as u32;
570         /// The spec targeted a range of commits
571         const RANGE = raw::GIT_REVPARSE_RANGE as u32;
572         /// The spec used the `...` operator, which invokes special semantics.
573         const MERGE_BASE = raw::GIT_REVPARSE_MERGE_BASE as u32;
574     }
575 }
576 
577 impl RevparseMode {
578     is_bit_set!(is_no_single, RevparseMode::SINGLE);
579     is_bit_set!(is_range, RevparseMode::RANGE);
580     is_bit_set!(is_merge_base, RevparseMode::MERGE_BASE);
581 }
582 
583 bitflags! {
584     /// The results of `merge_analysis` indicating the merge opportunities.
585     pub struct MergeAnalysis: u32 {
586         /// No merge is possible.
587         const ANALYSIS_NONE = raw::GIT_MERGE_ANALYSIS_NONE as u32;
588         /// A "normal" merge; both HEAD and the given merge input have diverged
589         /// from their common ancestor. The divergent commits must be merged.
590         const ANALYSIS_NORMAL = raw::GIT_MERGE_ANALYSIS_NORMAL as u32;
591         /// All given merge inputs are reachable from HEAD, meaning the
592         /// repository is up-to-date and no merge needs to be performed.
593         const ANALYSIS_UP_TO_DATE = raw::GIT_MERGE_ANALYSIS_UP_TO_DATE as u32;
594         /// The given merge input is a fast-forward from HEAD and no merge
595         /// needs to be performed.  Instead, the client can check out the
596         /// given merge input.
597         const ANALYSIS_FASTFORWARD = raw::GIT_MERGE_ANALYSIS_FASTFORWARD as u32;
598         /// The HEAD of the current repository is "unborn" and does not point to
599         /// a valid commit.  No merge can be performed, but the caller may wish
600         /// to simply set HEAD to the target commit(s).
601         const ANALYSIS_UNBORN = raw::GIT_MERGE_ANALYSIS_UNBORN as u32;
602     }
603 }
604 
605 impl MergeAnalysis {
606     is_bit_set!(is_none, MergeAnalysis::ANALYSIS_NONE);
607     is_bit_set!(is_normal, MergeAnalysis::ANALYSIS_NORMAL);
608     is_bit_set!(is_up_to_date, MergeAnalysis::ANALYSIS_UP_TO_DATE);
609     is_bit_set!(is_fast_forward, MergeAnalysis::ANALYSIS_FASTFORWARD);
610     is_bit_set!(is_unborn, MergeAnalysis::ANALYSIS_UNBORN);
611 }
612 
613 bitflags! {
614     /// The user's stated preference for merges.
615     pub struct MergePreference: u32 {
616         /// No configuration was found that suggests a preferred behavior for
617         /// merge.
618         const NONE = raw::GIT_MERGE_PREFERENCE_NONE as u32;
619         /// There is a `merge.ff=false` configuration setting, suggesting that
620         /// the user does not want to allow a fast-forward merge.
621         const NO_FAST_FORWARD = raw::GIT_MERGE_PREFERENCE_NO_FASTFORWARD as u32;
622         /// There is a `merge.ff=only` configuration setting, suggesting that
623         /// the user only wants fast-forward merges.
624         const FASTFORWARD_ONLY = raw::GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY as u32;
625     }
626 }
627 
628 impl MergePreference {
629     is_bit_set!(is_none, MergePreference::NONE);
630     is_bit_set!(is_no_fast_forward, MergePreference::NO_FAST_FORWARD);
631     is_bit_set!(is_fastforward_only, MergePreference::FASTFORWARD_ONLY);
632 }
633 
634 #[cfg(test)]
635 #[macro_use]
636 mod test;
637 #[macro_use]
638 mod panic;
639 mod attr;
640 mod call;
641 mod util;
642 
643 pub mod build;
644 pub mod cert;
645 pub mod oid_array;
646 pub mod opts;
647 pub mod string_array;
648 pub mod transport;
649 
650 mod apply;
651 mod blame;
652 mod blob;
653 mod branch;
654 mod buf;
655 mod cherrypick;
656 mod commit;
657 mod config;
658 mod cred;
659 mod describe;
660 mod diff;
661 mod error;
662 mod index;
663 mod indexer;
664 mod mailmap;
665 mod mempack;
666 mod merge;
667 mod message;
668 mod note;
669 mod object;
670 mod odb;
671 mod oid;
672 mod packbuilder;
673 mod patch;
674 mod pathspec;
675 mod proxy_options;
676 mod rebase;
677 mod reference;
678 mod reflog;
679 mod refspec;
680 mod remote;
681 mod remote_callbacks;
682 mod repo;
683 mod revert;
684 mod revspec;
685 mod revwalk;
686 mod signature;
687 mod stash;
688 mod status;
689 mod submodule;
690 mod tag;
691 mod tagforeach;
692 mod time;
693 mod transaction;
694 mod tree;
695 mod treebuilder;
696 mod worktree;
697 
init()698 fn init() {
699     static INIT: Once = Once::new();
700 
701     INIT.call_once(|| {
702         openssl_env_init();
703     });
704 
705     raw::init();
706 }
707 
708 #[cfg(all(
709     unix,
710     not(target_os = "macos"),
711     not(target_os = "ios"),
712     feature = "https"
713 ))]
openssl_env_init()714 fn openssl_env_init() {
715     // Currently, libgit2 leverages OpenSSL for SSL support when cloning
716     // repositories over HTTPS. This means that we're picking up an OpenSSL
717     // dependency on non-Windows platforms (where it has its own HTTPS
718     // subsystem). As a result, we need to link to OpenSSL.
719     //
720     // Now actually *linking* to OpenSSL isn't so hard. We just need to make
721     // sure to use pkg-config to discover any relevant system dependencies for
722     // differences between distributions like CentOS and Ubuntu. The actual
723     // trickiness comes about when we start *distributing* the resulting
724     // binaries. Currently Cargo is distributed in binary form as nightlies,
725     // which means we're distributing a binary with OpenSSL linked in.
726     //
727     // For historical reasons, the Linux nightly builder is running a CentOS
728     // distribution in order to have as much ABI compatibility with other
729     // distributions as possible. Sadly, however, this compatibility does not
730     // extend to OpenSSL. Currently OpenSSL has two major versions, 0.9 and 1.0,
731     // which are incompatible (many ABI differences). The CentOS builder we
732     // build on has version 1.0, as do most distributions today. Some still have
733     // 0.9, however. This means that if we are to distribute the binaries built
734     // by the CentOS machine, we would only be compatible with OpenSSL 1.0 and
735     // we would fail to run (a dynamic linker error at runtime) on systems with
736     // only 9.8 installed (hopefully).
737     //
738     // But wait, the plot thickens! Apparently CentOS has dubbed their OpenSSL
739     // library as `libssl.so.10`, notably the `10` is included at the end. On
740     // the other hand Ubuntu, for example, only distributes `libssl.so`. This
741     // means that the binaries created at CentOS are hard-wired to probe for a
742     // file called `libssl.so.10` at runtime (using the LD_LIBRARY_PATH), which
743     // will not be found on ubuntu. The conclusion of this is that binaries
744     // built on CentOS cannot be distributed to Ubuntu and run successfully.
745     //
746     // There are a number of sneaky things we could do, including, but not
747     // limited to:
748     //
749     // 1. Create a shim program which runs "just before" cargo runs. The
750     //    responsibility of this shim program would be to locate `libssl.so`,
751     //    whatever it's called, on the current system, make sure there's a
752     //    symlink *somewhere* called `libssl.so.10`, and then set up
753     //    LD_LIBRARY_PATH and run the actual cargo.
754     //
755     //    This approach definitely seems unconventional, and is borderline
756     //    overkill for this problem. It's also dubious if we can find a
757     //    libssl.so reliably on the target system.
758     //
759     // 2. Somehow re-work the CentOS installation so that the linked-against
760     //    library is called libssl.so instead of libssl.so.10
761     //
762     //    The problem with this approach is that systems with 0.9 installed will
763     //    start to silently fail, due to also having libraries called libssl.so
764     //    (probably symlinked under a more appropriate version).
765     //
766     // 3. Compile Cargo against both OpenSSL 1.0 *and* OpenSSL 0.9, and
767     //    distribute both. Also make sure that the linked-against name of the
768     //    library is `libssl.so`. At runtime we determine which version is
769     //    installed, and we then the appropriate binary.
770     //
771     //    This approach clearly has drawbacks in terms of infrastructure and
772     //    feasibility.
773     //
774     // 4. Build a nightly of Cargo for each distribution we'd like to support.
775     //    You would then pick the appropriate Cargo nightly to install locally.
776     //
777     // So, with all this in mind, the decision was made to *statically* link
778     // OpenSSL. This solves any problem of relying on a downstream OpenSSL
779     // version being available. This does, however, open a can of worms related
780     // to security issues. It's generally a good idea to dynamically link
781     // OpenSSL as you'll get security updates over time without having to do
782     // anything (the system administrator will update the local openssl
783     // package). By statically linking, we're forfeiting this feature.
784     //
785     // The conclusion was made it is likely appropriate for the Cargo nightlies
786     // to statically link OpenSSL, but highly encourage distributions and
787     // packagers of Cargo to dynamically link OpenSSL. Packagers are targeting
788     // one system and are distributing to only that system, so none of the
789     // problems mentioned above would arise.
790     //
791     // In order to support this, a new package was made: openssl-static-sys.
792     // This package currently performs a fairly simple task:
793     //
794     // 1. Run pkg-config to discover where openssl is installed.
795     // 2. If openssl is installed in a nonstandard location, *and* static copies
796     //    of the libraries are available, copy them to $OUT_DIR.
797     //
798     // This library will bring in libssl.a and libcrypto.a into the local build,
799     // allowing them to be picked up by this crate. This allows us to configure
800     // our own buildbots to have pkg-config point to these local pre-built
801     // copies of a static OpenSSL (with very few dependencies) while allowing
802     // most other builds of Cargo to naturally dynamically link OpenSSL.
803     //
804     // So in summary, if you're with me so far, we've statically linked OpenSSL
805     // to the Cargo binary (or any binary, for that matter) and we're ready to
806     // distribute it to *all* linux distributions. Remember that our original
807     // intent for openssl was for HTTPS support, which implies that we need some
808     // for of CA certificate store to validate certificates. This is normally
809     // installed in a standard system location.
810     //
811     // Unfortunately, as one might imagine, OpenSSL is configured for where this
812     // standard location is at *build time*, but it often varies widely
813     // per-system. Consequently, it was discovered that OpenSSL will respect the
814     // SSL_CERT_FILE and SSL_CERT_DIR environment variables in order to assist
815     // in discovering the location of this file (hurray!).
816     //
817     // So, finally getting to the point, this function solely exists to support
818     // our static builds of OpenSSL by probing for the "standard system
819     // location" of certificates and setting relevant environment variable to
820     // point to them.
821     //
822     // Ah, and as a final note, this is only a problem on Linux, not on OS X. On
823     // OS X the OpenSSL binaries are stable enough that we can just rely on
824     // dynamic linkage (plus they have some weird modifications to OpenSSL which
825     // means we wouldn't want to link statically).
826     openssl_probe::init_ssl_cert_env_vars();
827 }
828 
829 #[cfg(any(
830     windows,
831     target_os = "macos",
832     target_os = "ios",
833     not(feature = "https")
834 ))]
openssl_env_init()835 fn openssl_env_init() {}
836 
opt_bytes<'a, T>(_anchor: &'a T, c: *const libc::c_char) -> Option<&'a [u8]>837 unsafe fn opt_bytes<'a, T>(_anchor: &'a T, c: *const libc::c_char) -> Option<&'a [u8]> {
838     if c.is_null() {
839         None
840     } else {
841         Some(CStr::from_ptr(c).to_bytes())
842     }
843 }
844 
opt_cstr<T: IntoCString>(o: Option<T>) -> Result<Option<CString>, Error>845 fn opt_cstr<T: IntoCString>(o: Option<T>) -> Result<Option<CString>, Error> {
846     match o {
847         Some(s) => s.into_c_string().map(Some),
848         None => Ok(None),
849     }
850 }
851 
852 impl ObjectType {
853     /// Convert an object type to its string representation.
str(&self) -> &'static str854     pub fn str(&self) -> &'static str {
855         unsafe {
856             let ptr = call!(raw::git_object_type2string(*self)) as *const _;
857             let data = CStr::from_ptr(ptr).to_bytes();
858             str::from_utf8(data).unwrap()
859         }
860     }
861 
862     /// Determine if the given git_object_t is a valid loose object type.
is_loose(&self) -> bool863     pub fn is_loose(&self) -> bool {
864         unsafe { call!(raw::git_object_typeisloose(*self)) == 1 }
865     }
866 
867     /// Convert a raw git_object_t to an ObjectType
from_raw(raw: raw::git_object_t) -> Option<ObjectType>868     pub fn from_raw(raw: raw::git_object_t) -> Option<ObjectType> {
869         match raw {
870             raw::GIT_OBJECT_ANY => Some(ObjectType::Any),
871             raw::GIT_OBJECT_COMMIT => Some(ObjectType::Commit),
872             raw::GIT_OBJECT_TREE => Some(ObjectType::Tree),
873             raw::GIT_OBJECT_BLOB => Some(ObjectType::Blob),
874             raw::GIT_OBJECT_TAG => Some(ObjectType::Tag),
875             _ => None,
876         }
877     }
878 
879     /// Convert this kind into its raw representation
raw(&self) -> raw::git_object_t880     pub fn raw(&self) -> raw::git_object_t {
881         call::convert(self)
882     }
883 
884     /// Convert a string object type representation to its object type.
from_str(s: &str) -> Option<ObjectType>885     pub fn from_str(s: &str) -> Option<ObjectType> {
886         let raw = unsafe { call!(raw::git_object_string2type(CString::new(s).unwrap())) };
887         ObjectType::from_raw(raw)
888     }
889 }
890 
891 impl fmt::Display for ObjectType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result892     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
893         self.str().fmt(f)
894     }
895 }
896 
897 impl ReferenceType {
898     /// Convert an object type to its string representation.
str(&self) -> &'static str899     pub fn str(&self) -> &'static str {
900         match self {
901             ReferenceType::Direct => "direct",
902             ReferenceType::Symbolic => "symbolic",
903         }
904     }
905 
906     /// Convert a raw git_reference_t to a ReferenceType.
from_raw(raw: raw::git_reference_t) -> Option<ReferenceType>907     pub fn from_raw(raw: raw::git_reference_t) -> Option<ReferenceType> {
908         match raw {
909             raw::GIT_REFERENCE_DIRECT => Some(ReferenceType::Direct),
910             raw::GIT_REFERENCE_SYMBOLIC => Some(ReferenceType::Symbolic),
911             _ => None,
912         }
913     }
914 }
915 
916 impl fmt::Display for ReferenceType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result917     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
918         self.str().fmt(f)
919     }
920 }
921 
922 impl ConfigLevel {
923     /// Converts a raw configuration level to a ConfigLevel
from_raw(raw: raw::git_config_level_t) -> ConfigLevel924     pub fn from_raw(raw: raw::git_config_level_t) -> ConfigLevel {
925         match raw {
926             raw::GIT_CONFIG_LEVEL_PROGRAMDATA => ConfigLevel::ProgramData,
927             raw::GIT_CONFIG_LEVEL_SYSTEM => ConfigLevel::System,
928             raw::GIT_CONFIG_LEVEL_XDG => ConfigLevel::XDG,
929             raw::GIT_CONFIG_LEVEL_GLOBAL => ConfigLevel::Global,
930             raw::GIT_CONFIG_LEVEL_LOCAL => ConfigLevel::Local,
931             raw::GIT_CONFIG_LEVEL_APP => ConfigLevel::App,
932             raw::GIT_CONFIG_HIGHEST_LEVEL => ConfigLevel::Highest,
933             n => panic!("unknown config level: {}", n),
934         }
935     }
936 }
937 
938 impl SubmoduleIgnore {
939     /// Converts a [`raw::git_submodule_ignore_t`] to a [`SubmoduleIgnore`]
from_raw(raw: raw::git_submodule_ignore_t) -> Self940     pub fn from_raw(raw: raw::git_submodule_ignore_t) -> Self {
941         match raw {
942             raw::GIT_SUBMODULE_IGNORE_UNSPECIFIED => SubmoduleIgnore::Unspecified,
943             raw::GIT_SUBMODULE_IGNORE_NONE => SubmoduleIgnore::None,
944             raw::GIT_SUBMODULE_IGNORE_UNTRACKED => SubmoduleIgnore::Untracked,
945             raw::GIT_SUBMODULE_IGNORE_DIRTY => SubmoduleIgnore::Dirty,
946             raw::GIT_SUBMODULE_IGNORE_ALL => SubmoduleIgnore::All,
947             n => panic!("unknown submodule ignore rule: {}", n),
948         }
949     }
950 }
951 
952 impl SubmoduleUpdate {
953     /// Converts a [`raw::git_submodule_update_t`] to a [`SubmoduleUpdate`]
from_raw(raw: raw::git_submodule_update_t) -> Self954     pub fn from_raw(raw: raw::git_submodule_update_t) -> Self {
955         match raw {
956             raw::GIT_SUBMODULE_UPDATE_CHECKOUT => SubmoduleUpdate::Checkout,
957             raw::GIT_SUBMODULE_UPDATE_REBASE => SubmoduleUpdate::Rebase,
958             raw::GIT_SUBMODULE_UPDATE_MERGE => SubmoduleUpdate::Merge,
959             raw::GIT_SUBMODULE_UPDATE_NONE => SubmoduleUpdate::None,
960             raw::GIT_SUBMODULE_UPDATE_DEFAULT => SubmoduleUpdate::Default,
961             n => panic!("unknown submodule update strategy: {}", n),
962         }
963     }
964 }
965 
966 bitflags! {
967     /// Status flags for a single file
968     ///
969     /// A combination of these values will be returned to indicate the status of
970     /// a file.  Status compares the working directory, the index, and the
971     /// current HEAD of the repository.  The `STATUS_INDEX_*` set of flags
972     /// represents the status of file in the index relative to the HEAD, and the
973     /// `STATUS_WT_*` set of flags represent the status of the file in the
974     /// working directory relative to the index.
975     pub struct Status: u32 {
976         #[allow(missing_docs)]
977         const CURRENT = raw::GIT_STATUS_CURRENT as u32;
978 
979         #[allow(missing_docs)]
980         const INDEX_NEW = raw::GIT_STATUS_INDEX_NEW as u32;
981         #[allow(missing_docs)]
982         const INDEX_MODIFIED = raw::GIT_STATUS_INDEX_MODIFIED as u32;
983         #[allow(missing_docs)]
984         const INDEX_DELETED = raw::GIT_STATUS_INDEX_DELETED as u32;
985         #[allow(missing_docs)]
986         const INDEX_RENAMED = raw::GIT_STATUS_INDEX_RENAMED as u32;
987         #[allow(missing_docs)]
988         const INDEX_TYPECHANGE = raw::GIT_STATUS_INDEX_TYPECHANGE as u32;
989 
990         #[allow(missing_docs)]
991         const WT_NEW = raw::GIT_STATUS_WT_NEW as u32;
992         #[allow(missing_docs)]
993         const WT_MODIFIED = raw::GIT_STATUS_WT_MODIFIED as u32;
994         #[allow(missing_docs)]
995         const WT_DELETED = raw::GIT_STATUS_WT_DELETED as u32;
996         #[allow(missing_docs)]
997         const WT_TYPECHANGE = raw::GIT_STATUS_WT_TYPECHANGE as u32;
998         #[allow(missing_docs)]
999         const WT_RENAMED = raw::GIT_STATUS_WT_RENAMED as u32;
1000 
1001         #[allow(missing_docs)]
1002         const IGNORED = raw::GIT_STATUS_IGNORED as u32;
1003         #[allow(missing_docs)]
1004         const CONFLICTED = raw::GIT_STATUS_CONFLICTED as u32;
1005     }
1006 }
1007 
1008 impl Status {
1009     is_bit_set!(is_index_new, Status::INDEX_NEW);
1010     is_bit_set!(is_index_modified, Status::INDEX_MODIFIED);
1011     is_bit_set!(is_index_deleted, Status::INDEX_DELETED);
1012     is_bit_set!(is_index_renamed, Status::INDEX_RENAMED);
1013     is_bit_set!(is_index_typechange, Status::INDEX_TYPECHANGE);
1014     is_bit_set!(is_wt_new, Status::WT_NEW);
1015     is_bit_set!(is_wt_modified, Status::WT_MODIFIED);
1016     is_bit_set!(is_wt_deleted, Status::WT_DELETED);
1017     is_bit_set!(is_wt_typechange, Status::WT_TYPECHANGE);
1018     is_bit_set!(is_wt_renamed, Status::WT_RENAMED);
1019     is_bit_set!(is_ignored, Status::IGNORED);
1020     is_bit_set!(is_conflicted, Status::CONFLICTED);
1021 }
1022 
1023 bitflags! {
1024     /// Mode options for RepositoryInitOptions
1025     pub struct RepositoryInitMode: u32 {
1026         /// Use permissions configured by umask - the default
1027         const SHARED_UMASK = raw::GIT_REPOSITORY_INIT_SHARED_UMASK as u32;
1028         /// Use `--shared=group` behavior, chmod'ing the new repo to be
1029         /// group writable and \"g+sx\" for sticky group assignment
1030         const SHARED_GROUP = raw::GIT_REPOSITORY_INIT_SHARED_GROUP as u32;
1031         /// Use `--shared=all` behavior, adding world readability.
1032         const SHARED_ALL = raw::GIT_REPOSITORY_INIT_SHARED_ALL as u32;
1033     }
1034 }
1035 
1036 impl RepositoryInitMode {
1037     is_bit_set!(is_shared_umask, RepositoryInitMode::SHARED_UMASK);
1038     is_bit_set!(is_shared_group, RepositoryInitMode::SHARED_GROUP);
1039     is_bit_set!(is_shared_all, RepositoryInitMode::SHARED_ALL);
1040 }
1041 
1042 /// What type of change is described by a `DiffDelta`?
1043 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1044 pub enum Delta {
1045     /// No changes
1046     Unmodified,
1047     /// Entry does not exist in old version
1048     Added,
1049     /// Entry does not exist in new version
1050     Deleted,
1051     /// Entry content changed between old and new
1052     Modified,
1053     /// Entry was renamed between old and new
1054     Renamed,
1055     /// Entry was copied from another old entry
1056     Copied,
1057     /// Entry is ignored item in workdir
1058     Ignored,
1059     /// Entry is untracked item in workdir
1060     Untracked,
1061     /// Type of entry changed between old and new
1062     Typechange,
1063     /// Entry is unreadable
1064     Unreadable,
1065     /// Entry in the index is conflicted
1066     Conflicted,
1067 }
1068 
1069 /// Valid modes for index and tree entries.
1070 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1071 pub enum FileMode {
1072     /// Unreadable
1073     Unreadable,
1074     /// Tree
1075     Tree,
1076     /// Blob
1077     Blob,
1078     /// Blob executable
1079     BlobExecutable,
1080     /// Link
1081     Link,
1082     /// Commit
1083     Commit,
1084 }
1085 
1086 impl From<FileMode> for i32 {
from(mode: FileMode) -> i321087     fn from(mode: FileMode) -> i32 {
1088         match mode {
1089             FileMode::Unreadable => raw::GIT_FILEMODE_UNREADABLE as i32,
1090             FileMode::Tree => raw::GIT_FILEMODE_TREE as i32,
1091             FileMode::Blob => raw::GIT_FILEMODE_BLOB as i32,
1092             FileMode::BlobExecutable => raw::GIT_FILEMODE_BLOB_EXECUTABLE as i32,
1093             FileMode::Link => raw::GIT_FILEMODE_LINK as i32,
1094             FileMode::Commit => raw::GIT_FILEMODE_COMMIT as i32,
1095         }
1096     }
1097 }
1098 
1099 impl From<FileMode> for u32 {
from(mode: FileMode) -> u321100     fn from(mode: FileMode) -> u32 {
1101         match mode {
1102             FileMode::Unreadable => raw::GIT_FILEMODE_UNREADABLE as u32,
1103             FileMode::Tree => raw::GIT_FILEMODE_TREE as u32,
1104             FileMode::Blob => raw::GIT_FILEMODE_BLOB as u32,
1105             FileMode::BlobExecutable => raw::GIT_FILEMODE_BLOB_EXECUTABLE as u32,
1106             FileMode::Link => raw::GIT_FILEMODE_LINK as u32,
1107             FileMode::Commit => raw::GIT_FILEMODE_COMMIT as u32,
1108         }
1109     }
1110 }
1111 
1112 bitflags! {
1113     /// Return codes for submodule status.
1114     ///
1115     /// A combination of these flags will be returned to describe the status of a
1116     /// submodule.  Depending on the "ignore" property of the submodule, some of
1117     /// the flags may never be returned because they indicate changes that are
1118     /// supposed to be ignored.
1119     ///
1120     /// Submodule info is contained in 4 places: the HEAD tree, the index, config
1121     /// files (both .git/config and .gitmodules), and the working directory.  Any
1122     /// or all of those places might be missing information about the submodule
1123     /// depending on what state the repo is in.  We consider all four places to
1124     /// build the combination of status flags.
1125     ///
1126     /// There are four values that are not really status, but give basic info
1127     /// about what sources of submodule data are available.  These will be
1128     /// returned even if ignore is set to "ALL".
1129     ///
1130     /// * IN_HEAD   - superproject head contains submodule
1131     /// * IN_INDEX  - superproject index contains submodule
1132     /// * IN_CONFIG - superproject gitmodules has submodule
1133     /// * IN_WD     - superproject workdir has submodule
1134     ///
1135     /// The following values will be returned so long as ignore is not "ALL".
1136     ///
1137     /// * INDEX_ADDED       - in index, not in head
1138     /// * INDEX_DELETED     - in head, not in index
1139     /// * INDEX_MODIFIED    - index and head don't match
1140     /// * WD_UNINITIALIZED  - workdir contains empty directory
1141     /// * WD_ADDED          - in workdir, not index
1142     /// * WD_DELETED        - in index, not workdir
1143     /// * WD_MODIFIED       - index and workdir head don't match
1144     ///
1145     /// The following can only be returned if ignore is "NONE" or "UNTRACKED".
1146     ///
1147     /// * WD_INDEX_MODIFIED - submodule workdir index is dirty
1148     /// * WD_WD_MODIFIED    - submodule workdir has modified files
1149     ///
1150     /// Lastly, the following will only be returned for ignore "NONE".
1151     ///
1152     /// * WD_UNTRACKED      - wd contains untracked files
1153     pub struct SubmoduleStatus: u32 {
1154         #[allow(missing_docs)]
1155         const IN_HEAD = raw::GIT_SUBMODULE_STATUS_IN_HEAD as u32;
1156         #[allow(missing_docs)]
1157         const IN_INDEX = raw::GIT_SUBMODULE_STATUS_IN_INDEX as u32;
1158         #[allow(missing_docs)]
1159         const IN_CONFIG = raw::GIT_SUBMODULE_STATUS_IN_CONFIG as u32;
1160         #[allow(missing_docs)]
1161         const IN_WD = raw::GIT_SUBMODULE_STATUS_IN_WD as u32;
1162         #[allow(missing_docs)]
1163         const INDEX_ADDED = raw::GIT_SUBMODULE_STATUS_INDEX_ADDED as u32;
1164         #[allow(missing_docs)]
1165         const INDEX_DELETED = raw::GIT_SUBMODULE_STATUS_INDEX_DELETED as u32;
1166         #[allow(missing_docs)]
1167         const INDEX_MODIFIED = raw::GIT_SUBMODULE_STATUS_INDEX_MODIFIED as u32;
1168         #[allow(missing_docs)]
1169         const WD_UNINITIALIZED =
1170                 raw::GIT_SUBMODULE_STATUS_WD_UNINITIALIZED as u32;
1171         #[allow(missing_docs)]
1172         const WD_ADDED = raw::GIT_SUBMODULE_STATUS_WD_ADDED as u32;
1173         #[allow(missing_docs)]
1174         const WD_DELETED = raw::GIT_SUBMODULE_STATUS_WD_DELETED as u32;
1175         #[allow(missing_docs)]
1176         const WD_MODIFIED = raw::GIT_SUBMODULE_STATUS_WD_MODIFIED as u32;
1177         #[allow(missing_docs)]
1178         const WD_INDEX_MODIFIED =
1179                 raw::GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED as u32;
1180         #[allow(missing_docs)]
1181         const WD_WD_MODIFIED = raw::GIT_SUBMODULE_STATUS_WD_WD_MODIFIED as u32;
1182         #[allow(missing_docs)]
1183         const WD_UNTRACKED = raw::GIT_SUBMODULE_STATUS_WD_UNTRACKED as u32;
1184     }
1185 }
1186 
1187 impl SubmoduleStatus {
1188     is_bit_set!(is_in_head, SubmoduleStatus::IN_HEAD);
1189     is_bit_set!(is_in_index, SubmoduleStatus::IN_INDEX);
1190     is_bit_set!(is_in_config, SubmoduleStatus::IN_CONFIG);
1191     is_bit_set!(is_in_wd, SubmoduleStatus::IN_WD);
1192     is_bit_set!(is_index_added, SubmoduleStatus::INDEX_ADDED);
1193     is_bit_set!(is_index_deleted, SubmoduleStatus::INDEX_DELETED);
1194     is_bit_set!(is_index_modified, SubmoduleStatus::INDEX_MODIFIED);
1195     is_bit_set!(is_wd_uninitialized, SubmoduleStatus::WD_UNINITIALIZED);
1196     is_bit_set!(is_wd_added, SubmoduleStatus::WD_ADDED);
1197     is_bit_set!(is_wd_deleted, SubmoduleStatus::WD_DELETED);
1198     is_bit_set!(is_wd_modified, SubmoduleStatus::WD_MODIFIED);
1199     is_bit_set!(is_wd_wd_modified, SubmoduleStatus::WD_WD_MODIFIED);
1200     is_bit_set!(is_wd_untracked, SubmoduleStatus::WD_UNTRACKED);
1201 }
1202 
1203 /// Submodule ignore values
1204 ///
1205 /// These values represent settings for the `submodule.$name.ignore`
1206 /// configuration value which says how deeply to look at the working
1207 /// directory when getting the submodule status.
1208 #[derive(Debug)]
1209 pub enum SubmoduleIgnore {
1210     /// Use the submodule's configuration
1211     Unspecified,
1212     /// Any change or untracked file is considered dirty
1213     None,
1214     /// Only dirty if tracked files have changed
1215     Untracked,
1216     /// Only dirty if HEAD has moved
1217     Dirty,
1218     /// Never dirty
1219     All,
1220 }
1221 
1222 /// Submodule update values
1223 ///
1224 /// These values represent settings for the `submodule.$name.update`
1225 /// configuration value which says how to handle `git submodule update`
1226 /// for this submodule. The value is usually set in the ".gitmodules"
1227 /// file and copied to ".git/config" when the submodule is initialized.
1228 #[derive(Debug)]
1229 pub enum SubmoduleUpdate {
1230     /// The default; when a submodule is updated, checkout the new detached
1231     /// HEAD to the submodule directory.
1232     Checkout,
1233     /// Update by rebasing the current checked out branch onto the commit from
1234     /// the superproject.
1235     Rebase,
1236     /// Update by merging the commit in the superproject into the current
1237     /// checkout out branch of the submodule.
1238     Merge,
1239     /// Do not update this submodule even when the commit in the superproject
1240     /// is updated.
1241     None,
1242     /// Not used except as static initializer when we don't want any particular
1243     /// update rule to be specified.
1244     Default,
1245 }
1246 
1247 bitflags! {
1248     /// ...
1249     pub struct PathspecFlags: u32 {
1250         /// Use the default pathspec matching configuration.
1251         const DEFAULT = raw::GIT_PATHSPEC_DEFAULT as u32;
1252         /// Force matching to ignore case, otherwise matching will use native
1253         /// case sensitivity fo the platform filesystem.
1254         const IGNORE_CASE = raw::GIT_PATHSPEC_IGNORE_CASE as u32;
1255         /// Force case sensitive matches, otherwise match will use the native
1256         /// case sensitivity of the platform filesystem.
1257         const USE_CASE = raw::GIT_PATHSPEC_USE_CASE as u32;
1258         /// Disable glob patterns and just use simple string comparison for
1259         /// matching.
1260         const NO_GLOB = raw::GIT_PATHSPEC_NO_GLOB as u32;
1261         /// Means that match functions return the error code `NotFound` if no
1262         /// matches are found. By default no matches is a success.
1263         const NO_MATCH_ERROR = raw::GIT_PATHSPEC_NO_MATCH_ERROR as u32;
1264         /// Means that the list returned should track which patterns matched
1265         /// which files so that at the end of the match we can identify patterns
1266         /// that did not match any files.
1267         const FIND_FAILURES = raw::GIT_PATHSPEC_FIND_FAILURES as u32;
1268         /// Means that the list returned does not need to keep the actual
1269         /// matching filenames. Use this to just test if there were any matches
1270         /// at all or in combination with `PATHSPEC_FAILURES` to validate a
1271         /// pathspec.
1272         const FAILURES_ONLY = raw::GIT_PATHSPEC_FAILURES_ONLY as u32;
1273     }
1274 }
1275 
1276 impl PathspecFlags {
1277     is_bit_set!(is_default, PathspecFlags::DEFAULT);
1278     is_bit_set!(is_ignore_case, PathspecFlags::IGNORE_CASE);
1279     is_bit_set!(is_use_case, PathspecFlags::USE_CASE);
1280     is_bit_set!(is_no_glob, PathspecFlags::NO_GLOB);
1281     is_bit_set!(is_no_match_error, PathspecFlags::NO_MATCH_ERROR);
1282     is_bit_set!(is_find_failures, PathspecFlags::FIND_FAILURES);
1283     is_bit_set!(is_failures_only, PathspecFlags::FAILURES_ONLY);
1284 }
1285 
1286 impl Default for PathspecFlags {
default() -> Self1287     fn default() -> Self {
1288         PathspecFlags::DEFAULT
1289     }
1290 }
1291 
1292 bitflags! {
1293     /// Types of notifications emitted from checkouts.
1294     pub struct CheckoutNotificationType: u32 {
1295         /// Notification about a conflict.
1296         const CONFLICT = raw::GIT_CHECKOUT_NOTIFY_CONFLICT as u32;
1297         /// Notification about a dirty file.
1298         const DIRTY = raw::GIT_CHECKOUT_NOTIFY_DIRTY as u32;
1299         /// Notification about an updated file.
1300         const UPDATED = raw::GIT_CHECKOUT_NOTIFY_UPDATED as u32;
1301         /// Notification about an untracked file.
1302         const UNTRACKED = raw::GIT_CHECKOUT_NOTIFY_UNTRACKED as u32;
1303         /// Notification about an ignored file.
1304         const IGNORED = raw::GIT_CHECKOUT_NOTIFY_IGNORED as u32;
1305     }
1306 }
1307 
1308 impl CheckoutNotificationType {
1309     is_bit_set!(is_conflict, CheckoutNotificationType::CONFLICT);
1310     is_bit_set!(is_dirty, CheckoutNotificationType::DIRTY);
1311     is_bit_set!(is_updated, CheckoutNotificationType::UPDATED);
1312     is_bit_set!(is_untracked, CheckoutNotificationType::UNTRACKED);
1313     is_bit_set!(is_ignored, CheckoutNotificationType::IGNORED);
1314 }
1315 
1316 /// Possible output formats for diff data
1317 #[derive(Copy, Clone)]
1318 pub enum DiffFormat {
1319     /// full git diff
1320     Patch,
1321     /// just the headers of the patch
1322     PatchHeader,
1323     /// like git diff --raw
1324     Raw,
1325     /// like git diff --name-only
1326     NameOnly,
1327     /// like git diff --name-status
1328     NameStatus,
1329     /// git diff as used by git patch-id
1330     PatchId,
1331 }
1332 
1333 bitflags! {
1334     /// Formatting options for diff stats
1335     pub struct DiffStatsFormat: raw::git_diff_stats_format_t {
1336         /// Don't generate any stats
1337         const NONE = raw::GIT_DIFF_STATS_NONE;
1338         /// Equivalent of `--stat` in git
1339         const FULL = raw::GIT_DIFF_STATS_FULL;
1340         /// Equivalent of `--shortstat` in git
1341         const SHORT = raw::GIT_DIFF_STATS_SHORT;
1342         /// Equivalent of `--numstat` in git
1343         const NUMBER = raw::GIT_DIFF_STATS_NUMBER;
1344         /// Extended header information such as creations, renames and mode
1345         /// changes, equivalent of `--summary` in git
1346         const INCLUDE_SUMMARY = raw::GIT_DIFF_STATS_INCLUDE_SUMMARY;
1347     }
1348 }
1349 
1350 impl DiffStatsFormat {
1351     is_bit_set!(is_none, DiffStatsFormat::NONE);
1352     is_bit_set!(is_full, DiffStatsFormat::FULL);
1353     is_bit_set!(is_short, DiffStatsFormat::SHORT);
1354     is_bit_set!(is_number, DiffStatsFormat::NUMBER);
1355     is_bit_set!(is_include_summary, DiffStatsFormat::INCLUDE_SUMMARY);
1356 }
1357 
1358 /// Automatic tag following options.
1359 pub enum AutotagOption {
1360     /// Use the setting from the remote's configuration
1361     Unspecified,
1362     /// Ask the server for tags pointing to objects we're already downloading
1363     Auto,
1364     /// Don't ask for any tags beyond the refspecs
1365     None,
1366     /// Ask for all the tags
1367     All,
1368 }
1369 
1370 /// Configuration for how pruning is done on a fetch
1371 pub enum FetchPrune {
1372     /// Use the setting from the configuration
1373     Unspecified,
1374     /// Force pruning on
1375     On,
1376     /// Force pruning off
1377     Off,
1378 }
1379 
1380 #[allow(missing_docs)]
1381 #[derive(Debug)]
1382 pub enum StashApplyProgress {
1383     /// None
1384     None,
1385     /// Loading the stashed data from the object database
1386     LoadingStash,
1387     /// The stored index is being analyzed
1388     AnalyzeIndex,
1389     /// The modified files are being analyzed
1390     AnalyzeModified,
1391     /// The untracked and ignored files are being analyzed
1392     AnalyzeUntracked,
1393     /// The untracked files are being written to disk
1394     CheckoutUntracked,
1395     /// The modified files are being written to disk
1396     CheckoutModified,
1397     /// The stash was applied successfully
1398     Done,
1399 }
1400 
1401 bitflags! {
1402     #[allow(missing_docs)]
1403     pub struct StashApplyFlags: u32 {
1404         #[allow(missing_docs)]
1405         const DEFAULT = raw::GIT_STASH_APPLY_DEFAULT as u32;
1406         /// Try to reinstate not only the working tree's changes,
1407         /// but also the index's changes.
1408         const REINSTATE_INDEX = raw::GIT_STASH_APPLY_REINSTATE_INDEX as u32;
1409     }
1410 }
1411 
1412 impl StashApplyFlags {
1413     is_bit_set!(is_default, StashApplyFlags::DEFAULT);
1414     is_bit_set!(is_reinstate_index, StashApplyFlags::REINSTATE_INDEX);
1415 }
1416 
1417 impl Default for StashApplyFlags {
default() -> Self1418     fn default() -> Self {
1419         StashApplyFlags::DEFAULT
1420     }
1421 }
1422 
1423 bitflags! {
1424     #[allow(missing_docs)]
1425     pub struct StashFlags: u32 {
1426         #[allow(missing_docs)]
1427         const DEFAULT = raw::GIT_STASH_DEFAULT as u32;
1428         /// All changes already added to the index are left intact in
1429         /// the working directory
1430         const KEEP_INDEX = raw::GIT_STASH_KEEP_INDEX as u32;
1431         /// All untracked files are also stashed and then cleaned up
1432         /// from the working directory
1433         const INCLUDE_UNTRACKED = raw::GIT_STASH_INCLUDE_UNTRACKED as u32;
1434         /// All ignored files are also stashed and then cleaned up from
1435         /// the working directory
1436         const INCLUDE_IGNORED = raw::GIT_STASH_INCLUDE_IGNORED as u32;
1437     }
1438 }
1439 
1440 impl StashFlags {
1441     is_bit_set!(is_default, StashFlags::DEFAULT);
1442     is_bit_set!(is_keep_index, StashFlags::KEEP_INDEX);
1443     is_bit_set!(is_include_untracked, StashFlags::INCLUDE_UNTRACKED);
1444     is_bit_set!(is_include_ignored, StashFlags::INCLUDE_IGNORED);
1445 }
1446 
1447 impl Default for StashFlags {
default() -> Self1448     fn default() -> Self {
1449         StashFlags::DEFAULT
1450     }
1451 }
1452 
1453 bitflags! {
1454     #[allow(missing_docs)]
1455     pub struct AttrCheckFlags: u32 {
1456         /// Check the working directory, then the index.
1457         const FILE_THEN_INDEX = raw::GIT_ATTR_CHECK_FILE_THEN_INDEX as u32;
1458         /// Check the index, then the working directory.
1459         const INDEX_THEN_FILE = raw::GIT_ATTR_CHECK_INDEX_THEN_FILE as u32;
1460         /// Check the index only.
1461         const INDEX_ONLY = raw::GIT_ATTR_CHECK_INDEX_ONLY as u32;
1462         /// Do not use the system gitattributes file.
1463         const NO_SYSTEM = raw::GIT_ATTR_CHECK_NO_SYSTEM as u32;
1464     }
1465 }
1466 
1467 impl Default for AttrCheckFlags {
default() -> Self1468     fn default() -> Self {
1469         AttrCheckFlags::FILE_THEN_INDEX
1470     }
1471 }
1472 
1473 bitflags! {
1474     #[allow(missing_docs)]
1475     pub struct DiffFlags: u32 {
1476         /// File(s) treated as binary data.
1477         const BINARY = raw::GIT_DIFF_FLAG_BINARY as u32;
1478         /// File(s) treated as text data.
1479         const NOT_BINARY = raw::GIT_DIFF_FLAG_NOT_BINARY as u32;
1480         /// `id` value is known correct.
1481         const VALID_ID = raw::GIT_DIFF_FLAG_VALID_ID as u32;
1482         /// File exists at this side of the delta.
1483         const EXISTS = raw::GIT_DIFF_FLAG_EXISTS as u32;
1484     }
1485 }
1486 
1487 impl DiffFlags {
1488     is_bit_set!(is_binary, DiffFlags::BINARY);
1489     is_bit_set!(is_not_binary, DiffFlags::NOT_BINARY);
1490     is_bit_set!(has_valid_id, DiffFlags::VALID_ID);
1491     is_bit_set!(exists, DiffFlags::EXISTS);
1492 }
1493 
1494 bitflags! {
1495     /// Options for [`Reference::normalize_name`].
1496     pub struct ReferenceFormat: u32 {
1497         /// No particular normalization.
1498         const NORMAL = raw::GIT_REFERENCE_FORMAT_NORMAL as u32;
1499         /// Constrol whether one-level refname are accepted (i.e., refnames that
1500         /// do not contain multiple `/`-separated components). Those are
1501         /// expected to be written only using uppercase letters and underscore
1502         /// (e.g. `HEAD`, `FETCH_HEAD`).
1503         const ALLOW_ONELEVEL = raw::GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL as u32;
1504         /// Interpret the provided name as a reference pattern for a refspec (as
1505         /// used with remote repositories). If this option is enabled, the name
1506         /// is allowed to contain a single `*` in place of a full pathname
1507         /// components (e.g., `foo/*/bar` but not `foo/bar*`).
1508         const REFSPEC_PATTERN = raw::GIT_REFERENCE_FORMAT_REFSPEC_PATTERN as u32;
1509         /// Interpret the name as part of a refspec in shorthand form so the
1510         /// `ALLOW_ONELEVEL` naming rules aren't enforced and `main` becomes a
1511         /// valid name.
1512         const REFSPEC_SHORTHAND = raw::GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND as u32;
1513     }
1514 }
1515 
1516 impl ReferenceFormat {
1517     is_bit_set!(is_allow_onelevel, ReferenceFormat::ALLOW_ONELEVEL);
1518     is_bit_set!(is_refspec_pattern, ReferenceFormat::REFSPEC_PATTERN);
1519     is_bit_set!(is_refspec_shorthand, ReferenceFormat::REFSPEC_SHORTHAND);
1520 }
1521 
1522 impl Default for ReferenceFormat {
default() -> Self1523     fn default() -> Self {
1524         ReferenceFormat::NORMAL
1525     }
1526 }
1527 
1528 #[cfg(test)]
1529 mod tests {
1530     use super::{FileMode, ObjectType};
1531 
1532     #[test]
convert()1533     fn convert() {
1534         assert_eq!(ObjectType::Blob.str(), "blob");
1535         assert_eq!(ObjectType::from_str("blob"), Some(ObjectType::Blob));
1536         assert!(ObjectType::Blob.is_loose());
1537     }
1538 
1539     #[test]
convert_filemode()1540     fn convert_filemode() {
1541         assert_eq!(i32::from(FileMode::Blob), 0o100644);
1542         assert_eq!(i32::from(FileMode::BlobExecutable), 0o100755);
1543         assert_eq!(u32::from(FileMode::Blob), 0o100644);
1544         assert_eq!(u32::from(FileMode::BlobExecutable), 0o100755);
1545     }
1546 }
1547