History

fix: allow to open split worktree repositories

Sebastian Thiel committed 3 years ago

Commit 20f962e1 parent e9295dc8 files · +121 −25Browse files

Unified · Split

8 files
  1. gix/src/create.rs +1 −1
  2. gix/src/open/repository.rs +13 −3
  3. gix/src/repository/kind.rs +1 −1
  4. gix/tests/fixtures/make_worktree_repo.sh +32 −8
  5. gix/tests/repository/open.rs +54 −0
  6. gix/tests/repository/worktree.rs +9 −9
  7. gix/tests/submodule/mod.rs +5 −1
  8. gix/tests/util/mod.rs +6 −2
gix/src/create.rs+1−1
@@ -230,7 +230,7 @@ pub fn into( · 229 unmodified lines
230 Ok(gix_discover::repository::Path::from_dot_git_dir(230 Ok(gix_discover::repository::Path::from_dot_git_dir(
231 dot_git,231 dot_git,
232 if bare {232 if bare {
233 gix_discover::repository::Kind::Bare233 gix_discover::repository::Kind::PossiblyBare
234 } else {234 } else {
235 gix_discover::repository::Kind::WorkTree { linked_git_dir: None }235 gix_discover::repository::Kind::WorkTree { linked_git_dir: None }
236 },236 },
gix/src/open/repository.rs+13−3
@@ -240,10 +240,20 @@ impl ThreadSafeRepository { · 239 unmodified lines
240 let wt_path = wt240 let wt_path = wt
241 .interpolate(interpolate_context(git_install_dir.as_deref(), home.as_deref()))241 .interpolate(interpolate_context(git_install_dir.as_deref(), home.as_deref()))
242 .map_err(config::Error::PathInterpolation)?;242 .map_err(config::Error::PathInterpolation)?;
243 worktree_dir = {243 worktree_dir = gix_path::normalize(git_dir.join(wt_path).into(), current_dir).map(Cow::into_owned);
244 gix_path::normalize(git_dir.join(wt_path).into(), current_dir)244 #[allow(unused_variables)]
245 .and_then(|wt| wt.as_ref().is_dir().then(|| wt.into_owned()))245 if let Some(worktree_path) = worktree_dir.as_deref().filter(|wtd| !wtd.is_dir()) {
246 gix_trace::warn!("The configured worktree path '{}' is not a directory or doesn't exist - `core.worktree` may be misleading", worktree_path.display());
246 }247 }
248 } else if !config.lenient_config
249 && config
250 .resolved
251 .boolean_filter("core", None, Core::WORKTREE.name, &mut filter_config_section)
252 .is_some()
253 {
254 return Err(Error::from(config::Error::ConfigTypedString(
255 config::key::GenericErrorWithValue::from(&Core::WORKTREE),
256 )));
247 }257 }
248 }258 }
249 259
gix/src/repository/kind.rs+1−1
@@ -13,7 +13,7 @@ impl From<gix_discover::repository::Kind> for Kind { · 12 unmodified lines
13 gix_discover::repository::Kind::Submodule { .. } | gix_discover::repository::Kind::SubmoduleGitDir => {13 gix_discover::repository::Kind::Submodule { .. } | gix_discover::repository::Kind::SubmoduleGitDir => {
14 Kind::WorkTree { is_linked: false }14 Kind::WorkTree { is_linked: false }
15 }15 }
16 gix_discover::repository::Kind::Bare => Kind::Bare,16 gix_discover::repository::Kind::PossiblyBare => Kind::Bare,
17 gix_discover::repository::Kind::WorkTreeGitDir { .. } => Kind::WorkTree { is_linked: true },17 gix_discover::repository::Kind::WorkTreeGitDir { .. } => Kind::WorkTree { is_linked: true },
18 gix_discover::repository::Kind::WorkTree { linked_git_dir } => Kind::WorkTree {18 gix_discover::repository::Kind::WorkTree { linked_git_dir } => Kind::WorkTree {
19 is_linked: linked_git_dir.is_some(),19 is_linked: linked_git_dir.is_some(),
gix/tests/fixtures/make_worktree_repo.sh+32−8
@@ -17,18 +17,42 @@ mkdir repo · 16 unmodified lines
17 git commit -q -am c217 git commit -q -am c2
18)18)
19 19
20if [ "$bare" == "bare" ]; then20(if [ "$bare" == "bare" ]; then
21 git clone --bare --shared repo repo.git21 git clone --bare --shared repo repo.git
22 cd repo.git22 cd repo.git
23else23else
24 cd repo24 cd repo
25fi25fi
26 26
27git worktree add ../wt-a27 git worktree add ../wt-a
28git worktree add ../prev/wt-a HEAD~128 git worktree add ../prev/wt-a HEAD~1
29git worktree add ../wt-b HEAD~129 git worktree add ../wt-b HEAD~1
30git worktree add ../wt-a/nested-wt-b HEAD~130 git worktree add ../wt-a/nested-wt-b HEAD~1
31git worktree add --lock ../wt-c-locked31 git worktree add --lock ../wt-c-locked
32git worktree add ../wt-deleted && rm -Rf ../wt-deleted32 git worktree add ../wt-deleted && rm -Rf ../wt-deleted
33 33
34git worktree list --porcelain > ../worktree-list.baseline34 git worktree list --porcelain > ../worktree-list.baseline
35)
36
37
38git --git-dir=repo-with-worktree-in-config-unborn-no-worktreedir --work-tree=does-not-exist-yet init
39worktree=repo-with-worktree-in-config-unborn-worktree
40git --git-dir=repo-with-worktree-in-config-unborn --work-tree=$worktree init && mkdir $worktree
41
42repo=repo-with-worktree-in-config-unborn-empty-worktreedir
43git --git-dir=$repo --work-tree="." init
44git -C $repo config core.worktree ''
45
46repo=repo-with-worktree-in-config-unborn-worktreedir-missing-value
47git --git-dir=$repo init
48touch $repo/index
49git -C $repo config core.bare false
50echo " worktree" >> $repo/config
51
52worktree=repo-with-worktree-in-config-worktree
53git --git-dir=repo-with-worktree-in-config --work-tree=$worktree init
54mkdir $worktree && touch $worktree/file
55(cd repo-with-worktree-in-config
56 git add file
57 git commit -m "make sure na index exists"
58)
gix/tests/repository/open.rs+54−0
@@ -1,4 +1,5 @@
1use crate::util::named_subrepo_opts;1use crate::util::named_subrepo_opts;
2use std::error::Error;
2 3
3#[test]4#[test]
4fn bare_repo_with_index() -> crate::Result {5fn bare_repo_with_index() -> crate::Result {
@@ -26,6 +27,59 @@ fn none_bare_repo_without_index() -> crate::Result { · 21 unmodified lines
26 Ok(())27 Ok(())
27}28}
28 29
30#[test]
31fn non_bare_split_worktree() -> crate::Result {
32 for (name, worktree_exists) in [
33 ("repo-with-worktree-in-config-unborn-no-worktreedir", false),
34 ("repo-with-worktree-in-config-unborn", true),
35 ("repo-with-worktree-in-config", true),
36 ] {
37 let repo = named_subrepo_opts("make_worktree_repo.sh", name, gix::open::Options::isolated())?;
38 assert!(repo.git_dir().is_dir());
39 assert!(
40 !repo.is_bare(),
41 "worktree is actually configured, and it's non-bare by configuration"
42 );
43 assert_eq!(
44 repo.work_dir().expect("worktree is configured").is_dir(),
45 worktree_exists
46 );
47 }
48 Ok(())
49}
50
51#[test]
52fn non_bare_split_worktree_invalid_worktree_path_boolean() -> crate::Result {
53 let err = named_subrepo_opts(
54 "make_worktree_repo.sh",
55 "repo-with-worktree-in-config-unborn-worktreedir-missing-value",
56 gix::open::Options::isolated().strict_config(true),
57 )
58 .unwrap_err();
59 assert_eq!(
60 err.source().expect("present").to_string(),
61 "The key \"core.worktree\" (possibly from GIT_WORK_TREE) was invalid",
62 "in strict mode, we fail just like git does"
63 );
64 Ok(())
65}
66
67#[test]
68fn non_bare_split_worktree_invalid_worktree_path_empty() -> crate::Result {
69 // "repo-with-worktree-in-config-unborn-worktreedir-missing-value",
70 let err = named_subrepo_opts(
71 "make_worktree_repo.sh",
72 "repo-with-worktree-in-config-unborn-empty-worktreedir",
73 gix::open::Options::isolated(),
74 )
75 .unwrap_err();
76 assert!(
77 matches!(err, gix::open::Error::Config(gix::config::Error::PathInterpolation(_))),
78 "DEVIATION: could not read path at core.worktree as empty is always invalid, git tries to use an empty path, even though it's better to reject it"
79 );
80 Ok(())
81}
82
29mod missing_config_file {83mod missing_config_file {
30 84
31 use crate::util::named_subrepo_opts;85 use crate::util::named_subrepo_opts;
gix/tests/repository/worktree.rs+9−9
@@ -91,10 +91,10 @@ mod with_core_worktree_config { · 90 unmodified lines
91 "git can't chdir into missing worktrees, has no error handling there"91 "git can't chdir into missing worktrees, has no error handling there"
92 );92 );
93 93
94 assert_eq!(94 assert!(
95 repo.work_dir(),95 !repo.work_dir().expect("configured").exists(),
96 repo.git_dir().parent(),96 "non-existing or invalid worktrees (this one is a file) are taken verbatim and \
97 "we just ignore missing configured worktree dirs and fall back to the default one"97 may lead to errors later - just like in `git` and we explicitly do not try to be smart about it"
98 )98 )
99 }99 }
100 100
@@ -103,11 +103,11 @@ mod with_core_worktree_config { · 2 unmodified lines
103 let repo = repo("relative-worktree-file");103 let repo = repo("relative-worktree-file");
104 assert_eq!(count_deleted(repo.git_dir()), 0, "git can't chdir into a file");104 assert_eq!(count_deleted(repo.git_dir()), 0, "git can't chdir into a file");
105 105
106 assert_eq!(106 assert!(
107 repo.work_dir(),107 repo.work_dir().expect("configured").is_file(),
108 repo.git_dir().parent(),108 "non-existing or invalid worktrees (this one is a file) are taken verbatim and \
109 "we just ignore missing configured worktree dirs and fall back to the default one"109 may lead to errors later - just like in `git` and we explicitly do not try to be smart about it"
110 )110 );
111 }111 }
112 112
113 #[test]113 #[test]
gix/tests/submodule/mod.rs+5−1
@@ -1,6 +1,10 @@
1pub fn repo(name: &str) -> crate::Result<gix::Repository> {1pub fn repo(name: &str) -> crate::Result<gix::Repository> {
2 use crate::util::named_subrepo_opts;2 use crate::util::named_subrepo_opts;
3 named_subrepo_opts("make_submodules.sh", name, gix::open::Options::isolated())3 Ok(named_subrepo_opts(
4 "make_submodules.sh",
5 name,
6 gix::open::Options::isolated(),
7 )?)
4}8}
5 9
6mod open {10mod open {
gix/tests/util/mod.rs+6−2
@@ -34,8 +34,12 @@ pub fn named_repo(name: &str) -> Result<Repository> { · 33 unmodified lines
34 Ok(ThreadSafeRepository::open_opts(repo_path, restricted())?.to_thread_local())34 Ok(ThreadSafeRepository::open_opts(repo_path, restricted())?.to_thread_local())
35}35}
36 36
37pub fn named_subrepo_opts(fixture: &str, name: &str, opts: open::Options) -> Result<Repository> {37pub fn named_subrepo_opts(
38 let repo_path = gix_testtools::scripted_fixture_read_only(fixture)?.join(name);38 fixture: &str,
39 name: &str,
40 opts: open::Options,
41) -> std::result::Result<Repository, gix::open::Error> {
42 let repo_path = gix_testtools::scripted_fixture_read_only(fixture).unwrap().join(name);
39 Ok(ThreadSafeRepository::open_opts(repo_path, opts)?.to_thread_local())43 Ok(ThreadSafeRepository::open_opts(repo_path, opts)?.to_thread_local())
40}44}
41 45