Skip to content

Commit b0c9bc9

Browse files
committed
submodule: resolve URLs relative to main worktree
It is possible to specify submodule URLs relative to the repository location. E.g. having a submodule with URL "../submodule" will look for the submodule at "repo/../submodule". With the introduction of worktrees, though, we cannot simply resolve the URL relative to the repository location itself. If the repository for which a URL is to be resolved is a working tree, we have to resolve the URL relative to the parent's repository path. Otherwise, the URL would change depending on where the working tree is located. Fix this by special-casing when we have a working tree while getting the URL base.
1 parent 097f010 commit b0c9bc9

File tree

3 files changed

+51
-9
lines changed

3 files changed

+51
-9
lines changed

src/submodule.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "iterator.h"
2323
#include "path.h"
2424
#include "index.h"
25+
#include "worktree.h"
2526

2627
#define GIT_MODULES_FILE ".gitmodules"
2728

@@ -2030,17 +2031,28 @@ static int lookup_default_remote(git_remote **remote, git_repository *repo)
20302031
static int get_url_base(git_buf *url, git_repository *repo)
20312032
{
20322033
int error;
2034+
git_worktree *wt = NULL;
20332035
git_remote *remote = NULL;
20342036

2035-
if (!(error = lookup_default_remote(&remote, repo))) {
2037+
if ((error = lookup_default_remote(&remote, repo)) == 0) {
20362038
error = git_buf_sets(url, git_remote_url(remote));
2037-
git_remote_free(remote);
2038-
}
2039-
else if (error == GIT_ENOTFOUND) {
2040-
/* if repository does not have a default remote, use workdir instead */
2039+
goto out;
2040+
} else if (error != GIT_ENOTFOUND)
2041+
goto out;
2042+
else
20412043
giterr_clear();
2044+
2045+
/* if repository does not have a default remote, use workdir instead */
2046+
if (git_repository_is_worktree(repo)) {
2047+
if ((error = git_worktree_open_from_repository(&wt, repo)) < 0)
2048+
goto out;
2049+
error = git_buf_sets(url, wt->parent_path);
2050+
} else
20422051
error = git_buf_sets(url, git_repository_workdir(repo));
2043-
}
2052+
2053+
out:
2054+
git_remote_free(remote);
2055+
git_worktree_free(wt);
20442056

20452057
return error;
20462058
}

tests/resources/submodules/testrepo/.gitted/config

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
bare = false
55
logallrefupdates = true
66
ignorecase = true
7-
[remote "origin"]
8-
fetch = +refs/heads/*:refs/remotes/origin/*
9-
url = /Users/rb/src/libgit2/tests/resources/testrepo.git
107
[branch "master"]
118
remote = origin
129
merge = refs/heads/master

tests/worktree/submodule.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "clar_libgit2.h"
22
#include "repository.h"
3+
#include "worktree.h"
34
#include "worktree_helpers.h"
45

56
#define WORKTREE_PARENT "submodules-worktree-parent"
@@ -57,3 +58,35 @@ void test_worktree_submodule__open_discovered_submodule_worktree(void)
5758
git_buf_free(&path);
5859
git_repository_free(repo);
5960
}
61+
62+
void test_worktree_submodule__resolve_relative_url(void)
63+
{
64+
git_buf wt_path = GIT_BUF_INIT;
65+
git_buf sm_relative_path = GIT_BUF_INIT, wt_relative_path = GIT_BUF_INIT;
66+
git_repository *repo;
67+
git_worktree *wt;
68+
69+
cl_git_pass(git_futils_mkdir("subdir", 0755, GIT_MKDIR_PATH));
70+
cl_git_pass(git_path_prettify_dir(&wt_path, "subdir", NULL));
71+
cl_git_pass(git_buf_joinpath(&wt_path, wt_path.ptr, "wt"));
72+
73+
/* Open child repository, which is a submodule */
74+
cl_git_pass(git_repository_open(&child.repo, WORKTREE_CHILD));
75+
76+
/* Create worktree of submodule repository */
77+
cl_git_pass(git_worktree_add(&wt, child.repo, "subdir", wt_path.ptr));
78+
cl_git_pass(git_repository_open_from_worktree(&repo, wt));
79+
80+
cl_git_pass(git_submodule_resolve_url(&sm_relative_path, repo,
81+
"../" WORKTREE_CHILD));
82+
cl_git_pass(git_submodule_resolve_url(&wt_relative_path, child.repo,
83+
"../" WORKTREE_CHILD));
84+
85+
cl_assert_equal_s(sm_relative_path.ptr, wt_relative_path.ptr);
86+
87+
git_worktree_free(wt);
88+
git_repository_free(repo);
89+
git_buf_free(&wt_path);
90+
git_buf_free(&sm_relative_path);
91+
git_buf_free(&wt_relative_path);
92+
}

0 commit comments

Comments
 (0)