]> git.proxmox.com Git - libgit2.git/commitdiff
submodule: resolve URLs relative to main worktree
authorPatrick Steinhardt <ps@pks.im>
Wed, 15 Mar 2017 12:38:54 +0000 (13:38 +0100)
committerPatrick Steinhardt <ps@pks.im>
Fri, 17 Mar 2017 08:27:56 +0000 (09:27 +0100)
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.

src/submodule.c
tests/resources/submodules/testrepo/.gitted/config
tests/worktree/submodule.c

index 095bbb0907388c95c315e1562500dd76842be2be..ff65591d229a56d413c4c884ab1e74b080f4a863 100644 (file)
@@ -22,6 +22,7 @@
 #include "iterator.h"
 #include "path.h"
 #include "index.h"
+#include "worktree.h"
 
 #define GIT_MODULES_FILE ".gitmodules"
 
@@ -2030,17 +2031,28 @@ static int lookup_default_remote(git_remote **remote, git_repository *repo)
 static int get_url_base(git_buf *url, git_repository *repo)
 {
        int error;
+       git_worktree *wt = NULL;
        git_remote *remote = NULL;
 
-       if (!(error = lookup_default_remote(&remote, repo))) {
+       if ((error = lookup_default_remote(&remote, repo)) == 0) {
                error = git_buf_sets(url, git_remote_url(remote));
-               git_remote_free(remote);
-       }
-       else if (error == GIT_ENOTFOUND) {
-               /* if repository does not have a default remote, use workdir instead */
+               goto out;
+       } else if (error != GIT_ENOTFOUND)
+               goto out;
+       else
                giterr_clear();
+
+       /* if repository does not have a default remote, use workdir instead */
+       if (git_repository_is_worktree(repo)) {
+               if ((error = git_worktree_open_from_repository(&wt, repo)) < 0)
+                       goto out;
+               error = git_buf_sets(url, wt->parent_path);
+       } else
                error = git_buf_sets(url, git_repository_workdir(repo));
-       }
+
+out:
+       git_remote_free(remote);
+       git_worktree_free(wt);
 
        return error;
 }
index d6dcad12b3e80886731a6358d7c1fc5408050a39..8e557119184b82b0622f9b335fc104b1089e82f3 100644 (file)
@@ -4,9 +4,6 @@
        bare = false
        logallrefupdates = true
        ignorecase = true
-[remote "origin"]
-       fetch = +refs/heads/*:refs/remotes/origin/*
-       url = /Users/rb/src/libgit2/tests/resources/testrepo.git
 [branch "master"]
        remote = origin
        merge = refs/heads/master
index b4350704556c46ee08e407e3624116928cdc9b4b..5620775970b9f8617264489fba330292d5820305 100644 (file)
@@ -1,5 +1,6 @@
 #include "clar_libgit2.h"
 #include "repository.h"
+#include "worktree.h"
 #include "worktree_helpers.h"
 
 #define WORKTREE_PARENT "submodules-worktree-parent"
@@ -57,3 +58,35 @@ void test_worktree_submodule__open_discovered_submodule_worktree(void)
        git_buf_free(&path);
        git_repository_free(repo);
 }
+
+void test_worktree_submodule__resolve_relative_url(void)
+{
+       git_buf wt_path = GIT_BUF_INIT;
+       git_buf sm_relative_path = GIT_BUF_INIT, wt_relative_path = GIT_BUF_INIT;
+       git_repository *repo;
+       git_worktree *wt;
+
+       cl_git_pass(git_futils_mkdir("subdir", 0755, GIT_MKDIR_PATH));
+       cl_git_pass(git_path_prettify_dir(&wt_path, "subdir", NULL));
+       cl_git_pass(git_buf_joinpath(&wt_path, wt_path.ptr, "wt"));
+
+       /* Open child repository, which is a submodule */
+       cl_git_pass(git_repository_open(&child.repo, WORKTREE_CHILD));
+
+       /* Create worktree of submodule repository */
+       cl_git_pass(git_worktree_add(&wt, child.repo, "subdir", wt_path.ptr));
+       cl_git_pass(git_repository_open_from_worktree(&repo, wt));
+
+       cl_git_pass(git_submodule_resolve_url(&sm_relative_path, repo,
+                   "../" WORKTREE_CHILD));
+       cl_git_pass(git_submodule_resolve_url(&wt_relative_path, child.repo,
+                   "../" WORKTREE_CHILD));
+
+       cl_assert_equal_s(sm_relative_path.ptr, wt_relative_path.ptr);
+
+       git_worktree_free(wt);
+       git_repository_free(repo);
+       git_buf_free(&wt_path);
+       git_buf_free(&sm_relative_path);
+       git_buf_free(&wt_relative_path);
+}