Skip to main content

git_spawn/command/
init.rs

1//! `git init` — create an empty Git repository or reinitialize an existing one.
2
3use crate::command::{CommandExecutor, GitCommand};
4use crate::error::Result;
5use crate::repo::Repository;
6use async_trait::async_trait;
7use std::path::PathBuf;
8
9/// Builder for `git init`.
10#[derive(Debug, Clone, Default)]
11pub struct InitCommand {
12    /// Shared executor (args, cwd, env, timeout).
13    pub executor: CommandExecutor,
14    /// Directory to initialize. If `None`, uses the executor's cwd.
15    pub directory: Option<PathBuf>,
16    /// Create a bare repository (`--bare`).
17    pub bare: bool,
18    /// Suppress output (`-q`, `--quiet`).
19    pub quiet: bool,
20    /// Initial branch name (`--initial-branch`).
21    pub initial_branch: Option<String>,
22    /// Shared repository mode (`--shared`).
23    pub shared: Option<String>,
24    /// Template directory (`--template`).
25    pub template: Option<PathBuf>,
26    /// Separate git dir (`--separate-git-dir`).
27    pub separate_git_dir: Option<PathBuf>,
28}
29
30impl InitCommand {
31    /// Build an `init` with no directory argument (uses cwd).
32    #[must_use]
33    pub fn new() -> Self {
34        Self::default()
35    }
36
37    /// Build an `init` for the given directory.
38    #[must_use]
39    pub fn in_directory(path: impl Into<PathBuf>) -> Self {
40        Self {
41            directory: Some(path.into()),
42            ..Self::default()
43        }
44    }
45
46    /// Create a bare repository.
47    pub fn bare(&mut self) -> &mut Self {
48        self.bare = true;
49        self
50    }
51
52    /// Suppress stdout.
53    pub fn quiet(&mut self) -> &mut Self {
54        self.quiet = true;
55        self
56    }
57
58    /// Set the initial branch name (default on modern git: `main`).
59    pub fn initial_branch(&mut self, name: impl Into<String>) -> &mut Self {
60        self.initial_branch = Some(name.into());
61        self
62    }
63
64    /// Enable sharing mode (e.g. `"group"`, `"all"`, `"0660"`).
65    pub fn shared(&mut self, mode: impl Into<String>) -> &mut Self {
66        self.shared = Some(mode.into());
67        self
68    }
69
70    /// Use a template directory.
71    pub fn template(&mut self, path: impl Into<PathBuf>) -> &mut Self {
72        self.template = Some(path.into());
73        self
74    }
75
76    /// Store the git dir separately from the working tree.
77    pub fn separate_git_dir(&mut self, path: impl Into<PathBuf>) -> &mut Self {
78        self.separate_git_dir = Some(path.into());
79        self
80    }
81}
82
83#[async_trait]
84impl GitCommand for InitCommand {
85    type Output = Repository;
86
87    fn get_executor(&self) -> &CommandExecutor {
88        &self.executor
89    }
90
91    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
92        &mut self.executor
93    }
94
95    fn build_command_args(&self) -> Vec<String> {
96        let mut args = vec!["init".to_string()];
97        if self.bare {
98            args.push("--bare".into());
99        }
100        if self.quiet {
101            args.push("--quiet".into());
102        }
103        if let Some(branch) = &self.initial_branch {
104            args.push(format!("--initial-branch={branch}"));
105        }
106        if let Some(mode) = &self.shared {
107            args.push(format!("--shared={mode}"));
108        }
109        if let Some(t) = &self.template {
110            args.push(format!("--template={}", t.display()));
111        }
112        if let Some(g) = &self.separate_git_dir {
113            args.push(format!("--separate-git-dir={}", g.display()));
114        }
115        if let Some(d) = &self.directory {
116            args.push(d.display().to_string());
117        }
118        args
119    }
120
121    async fn execute(&self) -> Result<Repository> {
122        self.execute_raw().await?;
123        let path = self
124            .directory
125            .clone()
126            .or_else(|| self.executor.cwd.clone())
127            .unwrap_or_else(|| std::env::current_dir().unwrap_or_default());
128        Ok(Repository::new_unchecked(path))
129    }
130}