/* * libgit2 "init" example - shows how to initialize a new repo * * Written by the libgit2 contributors * * To the extent possible under law, the author(s) have dedicated all copyright * and related and neighboring rights to this software to the public domain * worldwide. This software is distributed without any warranty. * * You should have received a copy of the CC0 Public Domain Dedication along * with this software. If not, see * . */ #![deny(warnings)] use git2::{Error, Repository, RepositoryInitMode, RepositoryInitOptions}; use std::path::{Path, PathBuf}; use structopt::StructOpt; #[derive(StructOpt)] struct Args { #[structopt(name = "directory")] arg_directory: String, #[structopt(name = "quiet", short, long)] /// don't print information to stdout flag_quiet: bool, #[structopt(name = "bare", long)] /// initialize a new bare repository flag_bare: bool, #[structopt(name = "dir", long = "template")] /// use as an initialization template flag_template: Option, #[structopt(name = "separate-git-dir", long)] /// use as the .git directory flag_separate_git_dir: Option, #[structopt(name = "initial-commit", long)] /// create an initial empty commit flag_initial_commit: bool, #[structopt(name = "perms", long = "shared")] /// permissions to create the repository with flag_shared: Option, } fn run(args: &Args) -> Result<(), Error> { let mut path = PathBuf::from(&args.arg_directory); let repo = if !args.flag_bare && args.flag_template.is_none() && args.flag_shared.is_none() && args.flag_separate_git_dir.is_none() { Repository::init(&path)? } else { let mut opts = RepositoryInitOptions::new(); opts.bare(args.flag_bare); if let Some(ref s) = args.flag_template { opts.template_path(Path::new(s)); } // If you specified a separate git directory, then initialize // the repository at that path and use the second path as the // working directory of the repository (with a git-link file) if let Some(ref s) = args.flag_separate_git_dir { opts.workdir_path(&path); path = PathBuf::from(s); } if let Some(ref s) = args.flag_shared { opts.mode(parse_shared(s)?); } Repository::init_opts(&path, &opts)? }; // Print a message to stdout like "git init" does if !args.flag_quiet { if args.flag_bare || args.flag_separate_git_dir.is_some() { path = repo.path().to_path_buf(); } else { path = repo.workdir().unwrap().to_path_buf(); } println!("Initialized empty Git repository in {}", path.display()); } if args.flag_initial_commit { create_initial_commit(&repo)?; println!("Created empty initial commit"); } Ok(()) } /// Unlike regular "git init", this example shows how to create an initial empty /// commit in the repository. This is the helper function that does that. fn create_initial_commit(repo: &Repository) -> Result<(), Error> { // First use the config to initialize a commit signature for the user. let sig = repo.signature()?; // Now let's create an empty tree for this commit let tree_id = { let mut index = repo.index()?; // Outside of this example, you could call index.add_path() // here to put actual files into the index. For our purposes, we'll // leave it empty for now. index.write_tree()? }; let tree = repo.find_tree(tree_id)?; // Ready to create the initial commit. // // Normally creating a commit would involve looking up the current HEAD // commit and making that be the parent of the initial commit, but here this // is the first commit so there will be no parent. repo.commit(Some("HEAD"), &sig, &sig, "Initial commit", &tree, &[])?; Ok(()) } fn parse_shared(shared: &str) -> Result { match shared { "false" | "umask" => Ok(git2::RepositoryInitMode::SHARED_UMASK), "true" | "group" => Ok(git2::RepositoryInitMode::SHARED_GROUP), "all" | "world" => Ok(git2::RepositoryInitMode::SHARED_ALL), _ => { if shared.starts_with('0') { match u32::from_str_radix(&shared[1..], 8).ok() { Some(n) => Ok(RepositoryInitMode::from_bits_truncate(n)), None => Err(Error::from_str("invalid octal value for --shared")), } } else { Err(Error::from_str("unknown value for --shared")) } } } } fn main() { let args = Args::from_args(); match run(&args) { Ok(()) => {} Err(e) => println!("error: {}", e), } }