Thanks to visit codestin.com
Credit goes to docs.rs

Skip to main content

git2/
lib.rs

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