Skip to content

Commit b41c3df

Browse files
committed
repo: honor GIT_WORK_TREE environment variable
When the repository is opened with `GIT_REPOSITORY_OPEN_FROM_ENV`, honor the `GIT_WORK_TREE` environment variable.
1 parent 54a22f5 commit b41c3df

File tree

2 files changed

+62
-13
lines changed

2 files changed

+62
-13
lines changed

src/libgit2/repository.c

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -337,19 +337,42 @@ static int load_config_data(git_repository *repo, const git_config *config)
337337
return 0;
338338
}
339339

340-
static int load_workdir(git_repository *repo, git_config *config, git_str *parent_path)
340+
static int load_workdir(
341+
git_repository *repo,
342+
git_config *config,
343+
git_str *parent_path)
341344
{
342-
int error;
343-
git_config_entry *ce;
345+
git_config_entry *ce = NULL;
344346
git_str worktree = GIT_STR_INIT;
345347
git_str path = GIT_STR_INIT;
348+
git_str workdir_env = GIT_STR_INIT;
349+
const char *value = NULL;
350+
int error;
346351

347352
if (repo->is_bare)
348353
return 0;
349354

350-
if ((error = git_config__lookup_entry(
351-
&ce, config, "core.worktree", false)) < 0)
352-
return error;
355+
/* Environment variables are preferred */
356+
if (repo->use_env) {
357+
error = git__getenv(&workdir_env, "GIT_WORK_TREE");
358+
359+
if (error == 0)
360+
value = workdir_env.ptr;
361+
else if (error == GIT_ENOTFOUND)
362+
error = 0;
363+
else
364+
goto cleanup;
365+
}
366+
367+
/* Examine configuration values if necessary */
368+
if (!value) {
369+
if ((error = git_config__lookup_entry(&ce, config,
370+
"core.worktree", false)) < 0)
371+
return error;
372+
373+
if (ce && ce->value)
374+
value = ce->value;
375+
}
353376

354377
if (repo->is_worktree) {
355378
char *gitlink = git_worktree__read_link(repo->gitdir, GIT_GITDIR_FILE);
@@ -367,17 +390,21 @@ static int load_workdir(git_repository *repo, git_config *config, git_str *paren
367390
}
368391

369392
repo->workdir = git_str_detach(&worktree);
370-
}
371-
else if (ce && ce->value) {
372-
if ((error = git_fs_path_prettify_dir(
373-
&worktree, ce->value, repo->gitdir)) < 0)
393+
} else if (value) {
394+
if (!*value) {
395+
git_error_set(GIT_ERROR_NET, "working directory cannot be set to empty path");
396+
error = -1;
397+
goto cleanup;
398+
}
399+
400+
if ((error = git_fs_path_prettify_dir(&worktree,
401+
value, repo->gitdir)) < 0)
374402
goto cleanup;
375403

376404
repo->workdir = git_str_detach(&worktree);
377-
}
378-
else if (parent_path && git_fs_path_isdir(parent_path->ptr))
405+
} else if (parent_path && git_fs_path_isdir(parent_path->ptr)) {
379406
repo->workdir = git_str_detach(parent_path);
380-
else {
407+
} else {
381408
if (git_fs_path_dirname_r(&worktree, repo->gitdir) < 0 ||
382409
git_fs_path_to_dir(&worktree) < 0) {
383410
error = -1;
@@ -388,8 +415,10 @@ static int load_workdir(git_repository *repo, git_config *config, git_str *paren
388415
}
389416

390417
GIT_ERROR_CHECK_ALLOC(repo->workdir);
418+
391419
cleanup:
392420
git_str_dispose(&path);
421+
git_str_dispose(&workdir_env);
393422
git_config_entry_free(ce);
394423
return error;
395424
}

tests/libgit2/repo/env.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ void test_repo_env__cleanup(void)
3131
if (git_fs_path_isdir("peeled.git"))
3232
git_futils_rmdir_r("peeled.git", NULL, GIT_RMDIR_REMOVE_FILES);
3333

34+
cl_fixture_cleanup("test_workdir");
35+
3436
clear_git_env();
3537
}
3638

@@ -275,3 +277,21 @@ void test_repo_env__open(void)
275277

276278
clear_git_env();
277279
}
280+
281+
void test_repo_env__work_tree(void)
282+
{
283+
git_repository *repo;
284+
const char *test_path;
285+
286+
cl_fixture_sandbox("attr");
287+
cl_git_pass(p_rename("attr/.gitted", "attr/.git"));
288+
289+
cl_must_pass(p_mkdir("test_workdir", 0777));
290+
test_path = cl_git_sandbox_path(1, "test_workdir", NULL);
291+
292+
cl_setenv("GIT_WORK_TREE", test_path);
293+
cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL));
294+
cl_assert_equal_s(test_path, git_repository_workdir(repo));
295+
git_repository_free(repo);
296+
cl_setenv("GIT_WORK_TREE", NULL);
297+
}

0 commit comments

Comments
 (0)