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