Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to git init #588

Merged
merged 2 commits into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion git-branchless-lib/src/core/repo_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ at path: {:?}.
These branches exist: {:?}
Either create it, or update the main branch setting by running:

git config branchless.core.mainBranch <branch>
git branchless init --main-branch <branch>
",
get_main_branch_name(self)?,
self.get_path(),
Expand Down
29 changes: 29 additions & 0 deletions git-branchless-lib/src/git/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ pub enum Error {
#[error("could not open repository: {0}")]
OpenRepo(#[source] git2::Error),

#[error("could not find repository to open for worktree {path:?}")]
OpenParentWorktreeRepository { path: PathBuf },

#[error("could not open repository: {0}")]
UnsupportedExtensionWorktreeConfig(#[source] git2::Error),

Expand Down Expand Up @@ -520,6 +523,32 @@ impl Repo {
Ok(Index { inner: index })
}

/// If this repository is a worktree for another "parent" repository, return a [`Repo`] object
/// corresponding to that repository.
#[instrument]
pub fn open_worktree_parent_repo(&self) -> Result<Option<Self>> {
if !self.inner.is_worktree() {
return Ok(None);
}

// `git2` doesn't seem to support a way to directly look up the parent repository for the
// worktree.
let worktree_info_dir = self.get_path();
let parent_repo_path = match worktree_info_dir
.parent() // remove `.git`
.and_then(|path| path.parent()) // remove worktree name
.and_then(|path| path.parent()) // remove `worktrees`
{
Some(path) => path,
None => {
return Err(Error::OpenParentWorktreeRepository {
path: worktree_info_dir.to_owned()});
},
};
let parent_repo = Self::from_dir(parent_repo_path)?;
Ok(Some(parent_repo))
}

/// Get the configuration object for the repository.
///
/// **Warning**: This object should only be used for read operations. Write
Expand Down
22 changes: 22 additions & 0 deletions git-branchless-lib/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -604,3 +604,25 @@ pub fn make_git_with_remote_repo() -> eyre::Result<GitWrapperWithRemoteRepo> {
cloned_repo,
})
}

/// Represents a Git worktree for an existing Git repository on disk.
pub struct GitWorktreeWrapper {
/// Guard to clean up the containing temporary directory. Make sure to bind
/// this to a local variable not named `_`.
pub temp_dir: TempDir,

/// A wrapper around the worktree.
pub worktree: Git,
}

/// Create a new worktree for the provided repository.
pub fn make_git_worktree(git: &Git, worktree_name: &str) -> eyre::Result<GitWorktreeWrapper> {
let temp_dir = tempfile::tempdir()?;
let worktree_path = temp_dir.path().join(worktree_name);
git.run(&["worktree", "add", worktree_path.to_str().unwrap()])?;
let worktree = Git {
repo_path: worktree_path,
..git.clone()
};
Ok(GitWorktreeWrapper { temp_dir, worktree })
}
6 changes: 4 additions & 2 deletions git-branchless/src/commands/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ fn set_configs(
)?;
writeln!(
effects.get_output_stream(),
"If this is incorrect, run: git config branchless.core.mainBranch <branch>"
"If this is incorrect, run: git branchless init --main-branch <branch>"
)?;
main_branch_name
}
Expand Down Expand Up @@ -556,7 +556,9 @@ pub fn init(
main_branch_name: Option<&str>,
) -> eyre::Result<()> {
let mut in_ = BufReader::new(stdin());
let mut repo = Repo::from_current_dir()?;
let repo = Repo::from_current_dir()?;
let mut repo = repo.open_worktree_parent_repo()?.unwrap_or(repo);

let default_config = Config::open_default()?;
let readonly_config = repo.get_readonly_config()?;
let mut config = create_isolated_config(effects, &repo, readonly_config.into_config())?;
Expand Down
38 changes: 33 additions & 5 deletions git-branchless/tests/command/test_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use crate::util::trim_lines;

use eyre::Context;
use lib::git::GitVersion;
use lib::testing::{make_git, GitInitOptions, GitRunOptions};
use lib::testing::{
make_git, make_git_worktree, GitInitOptions, GitRunOptions, GitWorktreeWrapper,
};

#[test]
fn test_hook_installed() -> eyre::Result<()> {
Expand Down Expand Up @@ -182,7 +184,7 @@ fn test_old_git_version_warning() -> eyre::Result<()> {
insta::assert_snapshot!(stdout, @r###"
Created config file at <repo-path>/.git/branchless/config
Auto-detected your main branch as: master
If this is incorrect, run: git config branchless.core.mainBranch <branch>
If this is incorrect, run: git branchless init --main-branch <branch>
Installing hook: post-commit
Installing hook: post-merge
Installing hook: post-rewrite
Expand Down Expand Up @@ -227,7 +229,7 @@ fn test_init_basic() -> eyre::Result<()> {
insta::assert_snapshot!(stdout, @r###"
Created config file at <repo-path>/.git/branchless/config
Auto-detected your main branch as: master
If this is incorrect, run: git config branchless.core.mainBranch <branch>
If this is incorrect, run: git branchless init --main-branch <branch>
Installing hook: post-commit
Installing hook: post-merge
Installing hook: post-rewrite
Expand Down Expand Up @@ -334,7 +336,7 @@ fn test_main_branch_not_found_error_message() -> eyre::Result<()> {
These branches exist: []
Either create it, or update the main branch setting by running:

git config branchless.core.mainBranch <branch>
git branchless init --main-branch <branch>


Backtrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it.
Expand Down Expand Up @@ -551,7 +553,7 @@ fn test_init_core_hooks_path_warning() -> eyre::Result<()> {
insta::assert_snapshot!(stdout, @r###"
Created config file at <repo-path>/.git/branchless/config
Auto-detected your main branch as: master
If this is incorrect, run: git config branchless.core.mainBranch <branch>
If this is incorrect, run: git branchless init --main-branch <branch>
Installing hook: post-commit
Installing hook: post-merge
Installing hook: post-rewrite
Expand All @@ -567,3 +569,29 @@ fn test_init_core_hooks_path_warning() -> eyre::Result<()> {

Ok(())
}

#[test]
fn test_init_worktree() -> eyre::Result<()> {
let git = make_git()?;
git.init_repo_with_options(&GitInitOptions {
run_branchless_init: false,
make_initial_commit: true,
})?;
git.commit_file("test1", 1)?;
git.commit_file("test2", 2)?;

let GitWorktreeWrapper {
temp_dir: _temp_dir,
worktree,
} = make_git_worktree(&git, "new-worktree")?;
worktree.run(&["branchless", "init"])?;
{
let (stdout, _stderr) = worktree.run(&["smartlog"])?;
insta::assert_snapshot!(stdout, @r###"
:
@ 96d1c37 (> new-worktree, master) create test2.txt
"###);
}

Ok(())
}