Skip to main content

gix/
lib.rs

1//! This crate provides the [`Repository`] abstraction which serves as a hub into all the functionality of git.
2//!
3//! It's powerful and won't sacrifice performance while still increasing convenience compared to using the sub-crates
4//! individually. Sometimes it may hide complexity under the assumption that the performance difference doesn't matter
5//! for all but the fewest tools out there, which would be using the underlying crates directly or file an issue.
6//!
7//! ### The Trust Model
8//!
9//! It is very simple - based on the ownership of the repository compared to the user of the current process [Trust](sec::Trust)
10//! is assigned. This can be [overridden](open::Options::with()) as well. Further, git configuration files track their trust level
11//! per section based on and sensitive values like paths to executables or certain values will be skipped if they are from a source
12//! that isn't [fully](sec::Trust::Full) trusted.
13//!
14//! That way, data can safely be obtained without risking to execute untrusted executables.
15//!
16//! Note that it's possible to let `gix` act like `git` or `git2` by setting the [open::Options::bail_if_untrusted()] option.
17//!
18//! ### The prelude and extensions
19//!
20//! With `use git_repository::prelude::*` you should be ready to go as it pulls in various extension traits to make functionality
21//! available on objects that may use it.
22//!
23//! The method signatures are still complex and may require various arguments for configuration and cache control.
24//!
25//! Most extensions to existing objects provide an `obj_with_extension.attach(&repo).an_easier_version_of_a_method()` for simpler
26//! call signatures.
27//!
28//! ### `ThreadSafe` Mode
29//!
30//! By default, the [`Repository`] isn't `Sync` and thus can't be used in certain contexts which require the `Sync` trait.
31//!
32//! To help with this, convert it with [`Repository::into_sync()`] into a [`ThreadSafeRepository`].
33//!
34//! ### Object-Access Performance
35//!
36//! Accessing objects quickly is the bread-and-butter of working with git, right after accessing references. Hence it's vital
37//! to understand which cache levels exist and how to leverage them.
38//!
39//! When accessing an object, the first cache that's queried is a  memory-capped LRU object cache, mapping their id to data and kind.
40//! It has to be specifically enabled on a [`Repository`].
41//! On miss, the object is looked up and if a pack is hit, there is a small fixed-size cache for delta-base objects.
42//!
43//! In scenarios where the same objects are accessed multiple times, the object cache can be useful and is to be configured specifically
44//! using the [`Repository::object_cache_size()`] method.
45//!
46//! Use the `cache-efficiency-debug` cargo feature to learn how efficient the cache actually is - it's easy to end up with lowered
47//! performance if the cache is not hit in 50% of the time.
48//!
49//! ### Terminology
50//!
51//! #### `WorkingTree` and `WorkTree`
52//!
53//! When reading the documentation of the canonical gix-worktree program one gets the impression work tree and working tree are used
54//! interchangeably. We use the term _work tree_ only and try to do so consistently as its shorter and assumed to be the same.
55//!
56//! ### Plumbing Crates
57//!
58//! To make using  _sub-crates_ and their types easier, these are re-exported into the root of this crate. Here we list how to access nested plumbing
59//! crates which are otherwise harder to discover:
60//!
61//! **`git_repository::`**
62//! * [`odb`]
63//!   * [`pack`][odb::pack]
64//! * [`protocol`]
65//!   * [`transport`][protocol::transport]
66//!     * [`packetline`][protocol::transport::packetline]
67//!
68//! ### `libgit2` API to `gix`
69//!
70//! This doc-aliases are used to help finding methods under a possibly changed name. Just search in the docs.
71//! Entering `git2` into the search field will also surface all methods with such annotations.
72//!
73//! What follows is a list of methods you might be missing, along with workarounds if available.
74//! * [`git2::Repository::open_bare()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.open_bare) ➡ ❌ - use [`open()`] and discard if it is not bare.
75//! * [`git2::build::CheckoutBuilder::disable_filters()`](https://docs.rs/git2/*/git2/build/struct.CheckoutBuilder.html#method.disable_filters) ➡ ❌ *(filters are always applied during checkouts)*
76//! * [`git2::Repository::submodule_status()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.submodule_status) ➡ [`Submodule::state()`] - status provides more information and conveniences though, and an actual worktree status isn't performed.
77//!
78//! #### Integrity checks
79//!
80//! `git2` by default performs integrity checks via [`strict_hash_verification()`](https://docs.rs/git2/latest/git2/opts/fn.strict_hash_verification.html) and
81//! [`strict_object_creation`](https://docs.rs/git2/latest/git2/opts/fn.strict_object_creation.html) which `gitoxide` *currently* **does not have**.
82//!
83//! ### Feature Flags
84#![cfg_attr(
85    all(doc, feature = "document-features"),
86    doc = ::document_features::document_features!()
87)]
88#![cfg_attr(all(doc, feature = "document-features"), feature(doc_cfg))]
89#![deny(missing_docs, unsafe_code)]
90#![allow(clippy::result_large_err)]
91
92// Re-exports to make this a potential one-stop shop crate avoiding people from having to reference various crates themselves.
93// This also means that their major version changes affect our major version, but that's alright as we directly expose their
94// APIs/instances anyway.
95pub use gix_actor as actor;
96#[cfg(feature = "attributes")]
97pub use gix_attributes as attrs;
98#[cfg(feature = "blame")]
99pub use gix_blame as blame;
100#[cfg(feature = "command")]
101pub use gix_command as command;
102pub use gix_commitgraph as commitgraph;
103#[cfg(feature = "credentials")]
104pub use gix_credentials as credentials;
105pub use gix_date as date;
106#[cfg(feature = "dirwalk")]
107pub use gix_dir as dir;
108pub use gix_error as error;
109pub use gix_features as features;
110use gix_features::threading::OwnShared;
111pub use gix_features::{
112    parallel,
113    progress::{Count, DynNestedProgress, NestedProgress, Progress},
114    threading,
115};
116pub use gix_fs as fs;
117pub use gix_glob as glob;
118pub use gix_hash as hash;
119pub use gix_hashtable as hashtable;
120#[cfg(feature = "excludes")]
121pub use gix_ignore as ignore;
122#[doc(inline)]
123#[cfg(feature = "index")]
124pub use gix_index as index;
125pub use gix_lock as lock;
126#[cfg(feature = "credentials")]
127pub use gix_negotiate as negotiate;
128pub use gix_object as objs;
129pub use gix_object::bstr;
130pub use gix_odb as odb;
131#[cfg(feature = "credentials")]
132pub use gix_prompt as prompt;
133pub use gix_protocol as protocol;
134pub use gix_ref as refs;
135pub use gix_refspec as refspec;
136pub use gix_revwalk as revwalk;
137pub use gix_sec as sec;
138pub use gix_tempfile as tempfile;
139pub use gix_trace as trace;
140pub use gix_traverse as traverse;
141pub use gix_url as url;
142#[doc(inline)]
143pub use gix_url::Url;
144pub use gix_utils as utils;
145pub use gix_validate as validate;
146pub use hash::{oid, ObjectId};
147
148pub use gix_error::{Error, Exn};
149
150pub mod interrupt;
151
152mod ext;
153///
154pub mod prelude;
155
156#[cfg(feature = "excludes")]
157mod attribute_stack;
158
159///
160pub mod path;
161
162/// The standard type for a store to handle git references.
163pub type RefStore = gix_ref::file::Store;
164/// A handle for finding objects in an object database, abstracting away caches for thread-local use.
165pub type OdbHandle = gix_odb::memory::Proxy<gix_odb::Handle>;
166/// A handle for finding objects in an object database, abstracting away caches for moving across threads.
167pub type OdbHandleArc = gix_odb::memory::Proxy<gix_odb::HandleArc>;
168
169/// A way to access git configuration
170pub(crate) type Config = OwnShared<gix_config::File<'static>>;
171
172mod types;
173#[cfg(any(feature = "excludes", feature = "attributes"))]
174pub use types::AttributeStack;
175pub use types::{
176    Blob, Commit, Head, Id, Object, ObjectDetached, Reference, Remote, Repository, Tag, ThreadSafeRepository, Tree,
177    Worktree,
178};
179#[cfg(feature = "attributes")]
180pub use types::{Pathspec, PathspecDetached, Submodule};
181
182///
183pub mod clone;
184pub mod commit;
185///
186#[cfg(feature = "dirwalk")]
187pub mod dirwalk;
188pub mod head;
189pub mod id;
190pub mod object;
191#[cfg(feature = "attributes")]
192pub mod pathspec;
193pub mod reference;
194pub mod repository;
195#[cfg(feature = "attributes")]
196pub mod submodule;
197pub mod tag;
198#[cfg(any(feature = "dirwalk", feature = "status"))]
199pub(crate) mod util;
200
201///
202pub mod progress;
203///
204pub mod push;
205
206///
207pub mod diff;
208
209///
210#[cfg(feature = "merge")]
211pub mod merge;
212
213/// Try to open a git repository in `directory` and search upwards through its parents until one is found,
214/// using default trust options which matters in case the found repository isn't owned by the current user.
215///
216/// For details, see [`ThreadSafeRepository::discover()`].
217///
218/// # Note
219///
220/// **The discovered repository might not be suitable for any operation that requires authentication with remotes**
221/// as it doesn't see the relevant git configuration.
222///
223/// To achieve that, one has to [enable `git_binary` configuration](https://github.com/GitoxideLabs/gitoxide/blob/9723e1addf52cc336d59322de039ea0537cdca36/src/plumbing/main.rs#L86)
224/// in the open-options and use [`ThreadSafeRepository::discover_opts()`] instead. Alternatively, it might be well-known
225/// that the tool is going to run in a neatly configured environment without relying on bundled configuration.
226#[allow(clippy::result_large_err)]
227pub fn discover(directory: impl AsRef<std::path::Path>) -> Result<Repository, discover::Error> {
228    ThreadSafeRepository::discover(directory).map(Into::into)
229}
230
231/// Try to discover a git repository directly from the environment.
232///
233/// For details, see [`ThreadSafeRepository::discover_with_environment_overrides_opts()`].
234#[allow(clippy::result_large_err)]
235pub fn discover_with_environment_overrides(
236    directory: impl AsRef<std::path::Path>,
237) -> Result<Repository, discover::Error> {
238    ThreadSafeRepository::discover_with_environment_overrides(directory).map(Into::into)
239}
240
241/// Try to open a git repository directly from the environment.
242///
243/// See [`ThreadSafeRepository::open_with_environment_overrides()`].
244#[allow(clippy::result_large_err)]
245pub fn open_with_environment_overrides(directory: impl Into<std::path::PathBuf>) -> Result<Repository, open::Error> {
246    ThreadSafeRepository::open_with_environment_overrides(directory, Default::default()).map(Into::into)
247}
248
249/// See [`ThreadSafeRepository::init()`], but returns a [`Repository`] instead.
250#[allow(clippy::result_large_err)]
251pub fn init(directory: impl AsRef<std::path::Path>) -> Result<Repository, init::Error> {
252    ThreadSafeRepository::init(directory, create::Kind::WithWorktree, create::Options::default()).map(Into::into)
253}
254
255/// See [`ThreadSafeRepository::init()`], but returns a [`Repository`] instead.
256#[allow(clippy::result_large_err)]
257pub fn init_bare(directory: impl AsRef<std::path::Path>) -> Result<Repository, init::Error> {
258    ThreadSafeRepository::init(directory, create::Kind::Bare, create::Options::default()).map(Into::into)
259}
260
261/// Create a platform for configuring a bare clone from `url` to the local `path`, using default options for opening it (but
262/// amended with using configuration from the git installation to ensure all authentication options are honored).
263///
264/// See [`clone::PrepareFetch::new()`] for a function to take full control over all options.
265#[allow(clippy::result_large_err)]
266pub fn prepare_clone_bare<Url, E>(
267    url: Url,
268    path: impl AsRef<std::path::Path>,
269) -> Result<clone::PrepareFetch, clone::Error>
270where
271    Url: std::convert::TryInto<gix_url::Url, Error = E>,
272    gix_url::parse::Error: From<E>,
273{
274    clone::PrepareFetch::new(
275        url,
276        path,
277        create::Kind::Bare,
278        create::Options::default(),
279        open_opts_with_git_binary_config(),
280    )
281}
282
283/// Create a platform for configuring a clone with main working tree from `url` to the local `path`, using default options for opening it
284/// (but amended with using configuration from the git installation to ensure all authentication options are honored).
285///
286/// See [`clone::PrepareFetch::new()`] for a function to take full control over all options.
287#[allow(clippy::result_large_err)]
288pub fn prepare_clone<Url, E>(url: Url, path: impl AsRef<std::path::Path>) -> Result<clone::PrepareFetch, clone::Error>
289where
290    Url: std::convert::TryInto<gix_url::Url, Error = E>,
291    gix_url::parse::Error: From<E>,
292{
293    clone::PrepareFetch::new(
294        url,
295        path,
296        create::Kind::WithWorktree,
297        create::Options::default(),
298        open_opts_with_git_binary_config(),
299    )
300}
301
302fn open_opts_with_git_binary_config() -> open::Options {
303    use gix_sec::trust::DefaultForLevel;
304    let mut opts = open::Options::default_for_level(gix_sec::Trust::Full);
305    opts.permissions.config.git_binary = true;
306    opts
307}
308
309/// See [`ThreadSafeRepository::open()`], but returns a [`Repository`] instead.
310#[allow(clippy::result_large_err)]
311#[doc(alias = "git2")]
312pub fn open(directory: impl Into<std::path::PathBuf>) -> Result<Repository, open::Error> {
313    ThreadSafeRepository::open(directory).map(Into::into)
314}
315
316/// See [`ThreadSafeRepository::open_opts()`], but returns a [`Repository`] instead.
317#[allow(clippy::result_large_err)]
318#[doc(alias = "open_ext", alias = "git2")]
319pub fn open_opts(directory: impl Into<std::path::PathBuf>, options: open::Options) -> Result<Repository, open::Error> {
320    ThreadSafeRepository::open_opts(directory, options).map(Into::into)
321}
322
323///
324pub mod create;
325
326///
327pub mod open;
328
329///
330pub mod config;
331
332///
333#[cfg(feature = "mailmap")]
334pub mod mailmap;
335
336///
337pub mod worktree;
338
339pub mod revision;
340
341#[cfg(feature = "attributes")]
342pub mod filter;
343
344///
345pub mod remote;
346
347///
348pub mod init;
349
350/// Not to be confused with 'status'.
351pub mod state;
352
353///
354#[cfg(feature = "status")]
355pub mod status;
356
357///
358pub mod shallow;
359
360///
361pub mod discover;
362
363pub mod env;
364
365#[cfg(feature = "attributes")]
366fn is_dir_to_mode(is_dir: bool) -> gix_index::entry::Mode {
367    if is_dir {
368        gix_index::entry::Mode::DIR
369    } else {
370        gix_index::entry::Mode::FILE
371    }
372}