Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]>
---
builtin/worktree.c | 130 +++++++++++++++++++++++++++++++++--------------------
1 file changed, 81 insertions(+), 49 deletions(-)
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 8d59199..3ebb9e9 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -184,34 +184,15 @@ static const char *worktree_basename(const char *path,
int *olen)
return name;
}
-static int add_worktree(const char *path, const char *refname,
- const struct add_opts *opts)
+static void prepare_new_worktree(const char *path,
+ struct worktree *wt,
+ int create_gitdir_and_head)
{
+ const char *name;
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT;
- const char *name;
struct stat st;
- struct child_process cp;
- struct argv_array child_env = ARGV_ARRAY_INIT;
- int counter = 0, len, ret;
- struct strbuf symref = STRBUF_INIT;
- struct commit *commit = NULL;
-
- if (file_exists(path) && !is_empty_dir(path))
- die(_("'%s' already exists"), path);
-
- /* is 'refname' a branch or commit? */
- if (opts->force_new_branch) /* definitely a branch */
- ;
- else if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
- ref_exists(symref.buf)) { /* it's a branch */
- if (!opts->force)
- die_if_checked_out(symref.buf);
- } else { /* must be a commit */
- commit = lookup_commit_reference_by_name(refname);
- if (!commit)
- die(_("invalid reference: %s"), refname);
- }
+ int counter = 0, len;
name = worktree_basename(path, &len);
strbuf_addstr(&sb_repo,
@@ -227,6 +208,10 @@ static int add_worktree(const char *path, const char
*refname,
}
name = strrchr(sb_repo.buf, '/') + 1;
+ memset(wt, 0, sizeof(*wt));
+ wt->path = xstrdup(path);
+ wt->id = xstrdup(name);
+
junk_pid = getpid();
atexit(remove_junk);
sigchain_push_common(remove_junk_on_signal);
@@ -252,25 +237,81 @@ static int add_worktree(const char *path, const char
*refname,
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
write_file(sb.buf, "%s", real_path(sb_git.buf));
- write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
- real_path(get_git_common_dir()), name);
- /*
- * This is to keep resolve_ref() happy. We need a valid HEAD
- * or is_git_directory() will reject the directory. Any value which
- * looks like an object ID will do since it will be immediately
- * replaced by the symbolic-ref or update-ref invocation in the new
- * worktree.
- */
- strbuf_reset(&sb);
- strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
- write_file(sb.buf, sha1_to_hex(null_sha1));
+ if (create_gitdir_and_head) {
+ write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
+ real_path(get_git_common_dir()), name);
+
+ /*
+ * This is to keep resolve_ref() happy. We need a valid HEAD
+ * or is_git_directory() will reject the directory. Any value
which
+ * looks like an object ID will do since it will be immediately
+ * replaced by the symbolic-ref or update-ref invocation in the
new
+ * worktree.
+ */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
+ write_file(sb.buf, sha1_to_hex(null_sha1));
+ }
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
- fprintf_ln(stderr, _("Preparing %s (identifier %s)"), path, name);
+ strbuf_release(&sb);
+ strbuf_release(&sb_repo);
+ strbuf_release(&sb_git);
+}
+
+static void new_worktree_complete(void)
+{
+ is_junk = 0;
+ free(junk_work_tree);
+ free(junk_git_dir);
+ junk_work_tree = NULL;
+ junk_git_dir = NULL;
+}
+
+static void cleanup_new_worktree(struct worktree *wt)
+{
+ struct strbuf sb = STRBUF_INIT;
+
+ strbuf_git_common_path(&sb, "worktrees/%s/locked", wt->id);
+ unlink_or_warn(sb.buf);
+ strbuf_release(&sb);
+ clear_worktree(wt);
+}
+
+static int add_worktree(const char *path, const char *refname,
+ const struct add_opts *opts)
+{
+ struct worktree wt;
+ struct child_process cp;
+ struct argv_array child_env = ARGV_ARRAY_INIT;
+ int ret;
+ struct strbuf symref = STRBUF_INIT;
+ struct commit *commit = NULL;
+
+ /* is 'refname' a branch or commit? */
+ if (opts->force_new_branch) /* definitely a branch */
+ ;
+ else if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
+ ref_exists(symref.buf)) { /* it's a branch */
+ if (!opts->force)
+ die_if_checked_out(symref.buf);
+ } else { /* must be a commit */
+ commit = lookup_commit_reference_by_name(refname);
+ if (!commit)
+ die(_("invalid reference: %s"), refname);
+ }
+
+ if (file_exists(path) && !is_empty_dir(path))
+ die(_("'%s' already exists"), path);
+
+ prepare_new_worktree(path, &wt, 1);
- argv_array_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
+ fprintf_ln(stderr, _("Preparing %s (identifier %s)"), path, wt.id);
+
+ argv_array_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT,
+ get_worktree_git_dir(&wt));
argv_array_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
memset(&cp, 0, sizeof(cp));
cp.git_cmd = 1;
@@ -292,21 +333,12 @@ static int add_worktree(const char *path, const char
*refname,
cp.env = child_env.argv;
ret = run_command(&cp);
if (!ret) {
- is_junk = 0;
- free(junk_work_tree);
- free(junk_git_dir);
- junk_work_tree = NULL;
- junk_git_dir = NULL;
+ new_worktree_complete();
}
done:
- strbuf_reset(&sb);
- strbuf_addf(&sb, "%s/locked", sb_repo.buf);
- unlink_or_warn(sb.buf);
argv_array_clear(&child_env);
- strbuf_release(&sb);
strbuf_release(&symref);
- strbuf_release(&sb_repo);
- strbuf_release(&sb_git);
+ cleanup_new_worktree(&wt);
return ret;
}
--
2.7.0.377.g4cd97dd
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html