1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
#![allow(clippy::result_large_err)]
use std::{borrow::Cow, convert::TryInto, path::Path};
use gix_ref::{
store::WriteReflog,
transaction::{PreviousValue, RefEdit},
FullName, Target,
};
use crate::{bstr::BString, config::tree::Init, ThreadSafeRepository};
/// The name of the branch to use if non is configured via git configuration.
///
/// # Deviation
///
/// We use `main` instead of `master`.
pub const DEFAULT_BRANCH_NAME: &str = "main";
/// The error returned by [`crate::init()`].
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error("Could not obtain the current directory")]
CurrentDir(#[from] std::io::Error),
#[error(transparent)]
Init(#[from] crate::create::Error),
#[error(transparent)]
Open(#[from] crate::open::Error),
#[error("Invalid default branch name: {name:?}")]
InvalidBranchName {
name: BString,
source: gix_validate::refname::Error,
},
#[error("Could not edit HEAD reference with new default name")]
EditHeadForDefaultBranch(#[from] crate::reference::edit::Error),
}
impl ThreadSafeRepository {
/// Create a repository with work-tree within `directory`, creating intermediate directories as needed.
///
/// Fails without action if there is already a `.git` repository inside of `directory`, but
/// won't mind if the `directory` otherwise is non-empty.
pub fn init(
directory: impl AsRef<Path>,
kind: crate::create::Kind,
options: crate::create::Options,
) -> Result<Self, Error> {
use gix_sec::trust::DefaultForLevel;
let open_options = crate::open::Options::default_for_level(gix_sec::Trust::Full);
Self::init_opts(directory, kind, options, open_options)
}
/// Similar to [`init`][Self::init()], but allows to determine how exactly to open the newly created repository.
///
/// # Deviation
///
/// Instead of naming the default branch `master`, we name it `main` unless configured explicitly using the `init.defaultBranch`
/// configuration key.
pub fn init_opts(
directory: impl AsRef<Path>,
kind: crate::create::Kind,
create_options: crate::create::Options,
mut open_options: crate::open::Options,
) -> Result<Self, Error> {
let path = crate::create::into(directory.as_ref(), kind, create_options)?;
let (git_dir, worktree_dir) = path.into_repository_and_work_tree_directories();
open_options.git_dir_trust = Some(gix_sec::Trust::Full);
open_options.current_dir = std::env::current_dir()?.into();
let repo = ThreadSafeRepository::open_from_paths(git_dir, worktree_dir, open_options)?;
let branch_name = repo
.config
.resolved
.string("init", None, Init::DEFAULT_BRANCH.name)
.unwrap_or_else(|| Cow::Borrowed(DEFAULT_BRANCH_NAME.into()));
if branch_name.as_ref() != DEFAULT_BRANCH_NAME {
let sym_ref: FullName =
format!("refs/heads/{branch_name}")
.try_into()
.map_err(|err| Error::InvalidBranchName {
name: branch_name.into_owned(),
source: err,
})?;
let mut repo = repo.to_thread_local();
let prev_write_reflog = repo.refs.write_reflog;
repo.refs.write_reflog = WriteReflog::Disable;
repo.edit_reference(RefEdit {
change: gix_ref::transaction::Change::Update {
log: Default::default(),
expected: PreviousValue::Any,
new: Target::Symbolic(sym_ref),
},
name: "HEAD".try_into().expect("valid"),
deref: false,
})?;
repo.refs.write_reflog = prev_write_reflog;
}
Ok(repo)
}
}
|