mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-29 07:59:00 +00:00
init: add support for creating new repo backed by bare git repo in .jj/git/
It's annoying to have to have the Git repo and Jujube repo in separate directories. This commit adds `jj init --git`, which creates a new Jujube repo with an empty, bare git repo in `.jj/git/`. Hopefully the `jj git` subcommands will eventually provide enough functionality for working with the Git repo that the user won't have to use Git commands directly. If they still do, they can run them from inside `.jj/git/`, or create a new worktree based on that bare repo. The implementation is quite straight-forward. One thing to note is that I made `.jj/store` support relative paths to the Git repo. That's mostly so the Jujube repo can be moved around freely.
This commit is contained in:
parent
e82197d981
commit
a8a9f7dedd
6 changed files with 116 additions and 7 deletions
|
@ -91,7 +91,22 @@ impl ReadonlyRepo {
|
|||
ReadonlyRepo::init(settings, repo_path, wc_path, store)
|
||||
}
|
||||
|
||||
pub fn init_git(
|
||||
/// Initializes a repo with a new Git store in .jj/git/ (bare Git repo)
|
||||
pub fn init_internal_git(settings: &UserSettings, wc_path: PathBuf) -> Arc<ReadonlyRepo> {
|
||||
let repo_path = wc_path.join(".jj");
|
||||
fs::create_dir(repo_path.clone()).unwrap();
|
||||
let git_store_path = repo_path.join("git");
|
||||
git2::Repository::init_bare(&git_store_path).unwrap();
|
||||
let store_path = repo_path.join("store");
|
||||
let git_store_path = fs::canonicalize(git_store_path).unwrap();
|
||||
let mut store_file = File::create(store_path).unwrap();
|
||||
store_file.write_all(b"git: git").unwrap();
|
||||
let store = Box::new(GitStore::load(git_store_path));
|
||||
ReadonlyRepo::init(settings, repo_path, wc_path, store)
|
||||
}
|
||||
|
||||
/// Initializes a repo with an existing Git store at the specified path
|
||||
pub fn init_external_git(
|
||||
settings: &UserSettings,
|
||||
wc_path: PathBuf,
|
||||
git_store_path: PathBuf,
|
||||
|
@ -102,7 +117,7 @@ impl ReadonlyRepo {
|
|||
let git_store_path = fs::canonicalize(git_store_path).unwrap();
|
||||
let mut store_file = File::create(store_path).unwrap();
|
||||
store_file
|
||||
.write_all((String::from("git: ") + git_store_path.to_str().unwrap()).as_bytes())
|
||||
.write_all(format!("git: {}", git_store_path.to_str().unwrap()).as_bytes())
|
||||
.unwrap();
|
||||
let store = Box::new(GitStore::load(git_store_path));
|
||||
ReadonlyRepo::init(settings, repo_path, wc_path, store)
|
||||
|
@ -183,7 +198,8 @@ impl ReadonlyRepo {
|
|||
let contents = String::from_utf8(buf).unwrap();
|
||||
assert!(contents.starts_with("git: "));
|
||||
let git_store_path_str = contents[5..].to_string();
|
||||
let git_store_path = PathBuf::from(git_store_path_str);
|
||||
let git_store_path =
|
||||
fs::canonicalize(repo_path.join(PathBuf::from(git_store_path_str))).unwrap();
|
||||
store = Box::new(GitStore::load(git_store_path));
|
||||
}
|
||||
let store = StoreWrapper::new(store);
|
||||
|
|
|
@ -44,7 +44,7 @@ pub fn init_repo(settings: &UserSettings, use_git: bool) -> (TempDir, Arc<Readon
|
|||
let repo = if use_git {
|
||||
let git_path = temp_dir.path().join("git-repo");
|
||||
git2::Repository::init(&git_path).unwrap();
|
||||
ReadonlyRepo::init_git(&settings, wc_path, git_path)
|
||||
ReadonlyRepo::init_external_git(&settings, wc_path, git_path)
|
||||
} else {
|
||||
ReadonlyRepo::init_local(&settings, wc_path)
|
||||
};
|
||||
|
|
|
@ -62,7 +62,7 @@ fn set_up_push_repos(settings: &UserSettings, temp_dir: &TempDir) -> PushTestSet
|
|||
create_repo_clone(&source_repo_dir, &clone_repo_dir);
|
||||
std::fs::create_dir(&jj_repo_dir).unwrap();
|
||||
let mut jj_repo =
|
||||
ReadonlyRepo::init_git(&settings, jj_repo_dir.clone(), clone_repo_dir.clone());
|
||||
ReadonlyRepo::init_external_git(&settings, jj_repo_dir.clone(), clone_repo_dir.clone());
|
||||
let new_commit = testutils::create_random_commit(&settings, &jj_repo)
|
||||
.set_parents(vec![initial_commit_id.clone()])
|
||||
.write_to_new_transaction(&jj_repo, "test");
|
||||
|
|
67
lib/tests/test_init.rs
Normal file
67
lib/tests/test_init.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use jj_lib::repo::ReadonlyRepo;
|
||||
use jj_lib::testutils;
|
||||
|
||||
#[test]
|
||||
fn test_init_local() {
|
||||
let settings = testutils::user_settings();
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let wc_path = temp_dir.path().to_owned();
|
||||
let repo = ReadonlyRepo::init_local(&settings, wc_path.clone());
|
||||
assert!(repo.store().git_repo().is_none());
|
||||
assert_eq!(repo.working_copy_path(), &wc_path);
|
||||
assert_eq!(repo.repo_path(), &wc_path.join(".jj"));
|
||||
|
||||
// Just test that we write a commit to the store
|
||||
let mut tx = repo.start_transaction("test");
|
||||
testutils::create_random_commit(&settings, &repo).write_to_transaction(&mut tx);
|
||||
tx.discard();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_init_internal_git() {
|
||||
let settings = testutils::user_settings();
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let wc_path = temp_dir.path().to_owned();
|
||||
let repo = ReadonlyRepo::init_internal_git(&settings, wc_path.clone());
|
||||
assert!(repo.store().git_repo().is_some());
|
||||
assert_eq!(repo.working_copy_path(), &wc_path);
|
||||
assert_eq!(repo.repo_path(), &wc_path.join(".jj"));
|
||||
|
||||
// Just test that we write a commit to the store
|
||||
let mut tx = repo.start_transaction("test");
|
||||
testutils::create_random_commit(&settings, &repo).write_to_transaction(&mut tx);
|
||||
tx.discard();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_init_external_git() {
|
||||
let settings = testutils::user_settings();
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let git_repo_path = temp_dir.path().join("git");
|
||||
git2::Repository::init(&git_repo_path).unwrap();
|
||||
let wc_path = temp_dir.path().join("jj");
|
||||
std::fs::create_dir(&wc_path).unwrap();
|
||||
let repo = ReadonlyRepo::init_external_git(&settings, wc_path.clone(), git_repo_path);
|
||||
assert!(repo.store().git_repo().is_some());
|
||||
assert_eq!(repo.working_copy_path(), &wc_path);
|
||||
assert_eq!(repo.repo_path(), &wc_path.join(".jj"));
|
||||
|
||||
// Just test that we write a commit to the store
|
||||
let mut tx = repo.start_transaction("test");
|
||||
testutils::create_random_commit(&settings, &repo).write_to_transaction(&mut tx);
|
||||
tx.discard();
|
||||
}
|
|
@ -270,6 +270,7 @@ fn get_app<'a, 'b>() -> App<'a, 'b> {
|
|||
let init_command = SubCommand::with_name("init")
|
||||
.about("initialize a repo")
|
||||
.arg(Arg::with_name("destination").index(1).default_value("."))
|
||||
.arg(Arg::with_name("git").long("git"))
|
||||
.arg(
|
||||
Arg::with_name("git-store")
|
||||
.long("git-store")
|
||||
|
@ -541,6 +542,11 @@ fn cmd_init(
|
|||
_matches: &ArgMatches,
|
||||
sub_matches: &ArgMatches,
|
||||
) -> Result<(), CommandError> {
|
||||
if sub_matches.is_present("git") && sub_matches.is_present("git-store") {
|
||||
return Err(CommandError::UserError(String::from(
|
||||
"--git cannot be used with --git-store",
|
||||
)));
|
||||
}
|
||||
let wc_path_str = sub_matches.value_of("destination").unwrap();
|
||||
let wc_path = ui.cwd().join(wc_path_str);
|
||||
if wc_path.exists() {
|
||||
|
@ -552,7 +558,9 @@ fn cmd_init(
|
|||
let repo;
|
||||
if let Some(git_store_str) = sub_matches.value_of("git-store") {
|
||||
let git_store_path = ui.cwd().join(git_store_str);
|
||||
repo = ReadonlyRepo::init_git(ui.settings(), wc_path, git_store_path);
|
||||
repo = ReadonlyRepo::init_external_git(ui.settings(), wc_path, git_store_path);
|
||||
} else if sub_matches.is_present("git") {
|
||||
repo = ReadonlyRepo::init_internal_git(ui.settings(), wc_path);
|
||||
} else {
|
||||
repo = ReadonlyRepo::init_local(ui.settings(), wc_path);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,25 @@
|
|||
use jj::testutils;
|
||||
|
||||
#[test]
|
||||
fn test_init_git() {
|
||||
fn test_init_git_internal() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let output = testutils::CommandRunner::new(temp_dir.path()).run(vec!["init", "repo", "--git"]);
|
||||
assert_eq!(output.status, 0);
|
||||
|
||||
let repo_path = temp_dir.path().join("repo");
|
||||
assert!(repo_path.is_dir());
|
||||
assert!(repo_path.join(".jj").is_dir());
|
||||
assert!(repo_path.join(".jj").join("git").is_dir());
|
||||
let store_file_contents = std::fs::read_to_string(repo_path.join(".jj").join("store")).unwrap();
|
||||
assert_eq!(store_file_contents, "git: git");
|
||||
assert_eq!(
|
||||
output.stdout_string(),
|
||||
format!("Initialized repo in \"{}\"\n", repo_path.to_str().unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_init_git_external() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let git_repo_path = temp_dir.path().join("git-repo");
|
||||
git2::Repository::init(git_repo_path.clone()).unwrap();
|
||||
|
|
Loading…
Reference in a new issue