summaryrefslogtreecommitdiff
path: root/src/repository.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/repository.c')
-rw-r--r--src/repository.c92
1 files changed, 83 insertions, 9 deletions
diff --git a/src/repository.c b/src/repository.c
index bee7b3ee6..a2931713e 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -741,15 +741,24 @@ static int repo_init_config(const char *git_dir, bool is_bare, bool is_reinit)
#define GIT_DESC_CONTENT "Unnamed repository; edit this file 'description' to name the repository.\n"
static int repo_write_template(
- const char *git_dir, const char *file, mode_t mode, const char *content)
+ const char *git_dir,
+ bool allow_overwrite,
+ const char *file,
+ mode_t mode,
+ const char *content)
{
git_buf path = GIT_BUF_INIT;
- int fd, error = 0;
+ int fd, error = 0, flags;
if (git_buf_joinpath(&path, git_dir, file) < 0)
return -1;
- fd = p_open(git_buf_cstr(&path), O_WRONLY | O_CREAT | O_EXCL, mode);
+ if (allow_overwrite)
+ flags = O_WRONLY | O_CREAT | O_TRUNC;
+ else
+ flags = O_WRONLY | O_CREAT | O_EXCL;
+
+ fd = p_open(git_buf_cstr(&path), flags, mode);
if (fd >= 0) {
error = p_write(fd, content, strlen(content));
@@ -811,7 +820,7 @@ static int repo_init_structure(const char *git_dir, int is_bare)
/* Make template files as needed */
for (i = 0; tmpl[i].file != NULL; ++i) {
if (repo_write_template(
- git_dir, tmpl[i].file, tmpl[i].mode, tmpl[i].content) < 0)
+ git_dir, false, tmpl[i].file, tmpl[i].mode, tmpl[i].content) < 0)
return -1;
}
@@ -943,8 +952,47 @@ const char *git_repository_workdir(git_repository *repo)
return repo->workdir;
}
-int git_repository_set_workdir(git_repository *repo, const char *workdir)
+static int write_gitlink(
+ const char *in_dir, const char *to_repo)
+{
+ int error;
+ git_buf buf = GIT_BUF_INIT;
+ struct stat st;
+
+ if (git_path_dirname_r(&buf, to_repo) < 0 ||
+ git_path_to_dir(&buf) < 0)
+ return -1;
+
+ /* don't write gitlink to natural workdir */
+ if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 &&
+ strcmp(in_dir, buf.ptr) == 0)
+ return GIT_PASSTHROUGH;
+
+ if (git_buf_joinpath(&buf, in_dir, DOT_GIT) < 0)
+ return -1;
+
+ if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) {
+ giterr_set(GITERR_REPOSITORY,
+ "Cannot overwrite gitlink file into path '%s'", in_dir);
+ return GIT_EEXISTS;
+ }
+
+ git_buf_clear(&buf);
+
+ if (git_buf_printf(&buf, "%s %s", GIT_FILE_CONTENT_PREFIX, to_repo) < 0)
+ return -1;
+
+ error = repo_write_template(in_dir, true, DOT_GIT, 0644, buf.ptr);
+
+ git_buf_free(&buf);
+
+ return error;
+}
+
+int git_repository_set_workdir(
+ git_repository *repo, const char *workdir, int update_gitlink)
{
+ int error = 0;
git_buf path = GIT_BUF_INIT;
assert(repo && workdir);
@@ -952,11 +1000,37 @@ int git_repository_set_workdir(git_repository *repo, const char *workdir)
if (git_path_prettify_dir(&path, workdir, NULL) < 0)
return -1;
- git__free(repo->workdir);
+ if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0)
+ return 0;
- repo->workdir = git_buf_detach(&path);
- repo->is_bare = 0;
- return 0;
+ if (update_gitlink) {
+ git_config *config;
+
+ if (git_repository_config__weakptr(&config, repo) < 0)
+ return -1;
+
+ error = write_gitlink(path.ptr, git_repository_path(repo));
+
+ /* passthrough error means gitlink is unnecessary */
+ if (error == GIT_PASSTHROUGH)
+ error = git_config_delete(config, "core.worktree");
+ else if (!error)
+ error = git_config_set_string(config, "core.worktree", path.ptr);
+
+ if (!error)
+ error = git_config_set_bool(config, "core.bare", false);
+ }
+
+ if (!error) {
+ char *old_workdir = repo->workdir;
+
+ repo->workdir = git_buf_detach(&path);
+ repo->is_bare = 0;
+
+ git__free(old_workdir);
+ }
+
+ return error;
}
int git_repository_is_bare(git_repository *repo)