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