worktree: detect branch-name/detached and error conditions locally

git-worktree currently conflates setting of HEAD in the new worktree with initial worktree population via a single git-checkout invocation, which requires git-checkout to have special knowledge that it is operating in a newly created worktree. The eventual goal is to separate these operations and rid git-checkout of that overly-intimate knowledge. Once these operations are separate, git-worktree will no longer be able to rely upon git-branch to determine the state of the worktree (branch name or detached), or to check for error conditions, such as the requested branch already checked out elsewhere, or an invalid reference. Therefore, imbue git-worktree with the intelligence to determine a branch name or detached state locally, and to perform error checking on its own. Signed-off-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Eric Sunshine committed Jul 17, 2015 at 19:00 UTC f7c9dac1b037e453e934c272d77cc648d56d5477
1 file changed +18
builtin/worktree.c
+18
@@ -3,6 +3,8 @@
3 #include "dir.h"
4 #include "parse-options.h"
5 #include "argv-array.h"
6 +#include "branch.h"
7 +#include "refs.h"
8 #include "run-command.h"
9 #include "sigchain.h"
10
@@ -188,11 +190,26 @@ static int add_worktree(const char *path, const char *refname,
190 struct child_process cp;
191 struct argv_array child_env = ARGV_ARRAY_INIT;
192 int counter = 0, len, ret;
193 + struct strbuf symref = STRBUF_INIT;
194 + struct commit *commit = NULL;
195 unsigned char rev[20];
196
197 if (file_exists(path) && !is_empty_dir(path))
198 die(_("'%s' already exists"), path);
199
200 + /* is 'refname' a branch or commit? */
201 + if (opts->force_new_branch) /* definitely a branch */
202 + ;
203 + else if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
204 + ref_exists(symref.buf)) { /* it's a branch */
205 + if (!opts->force)
206 + die_if_checked_out(symref.buf);
207 + } else { /* must be a commit */
208 + commit = lookup_commit_reference_by_name(refname);
209 + if (!commit)
210 + die(_("invalid reference: %s"), refname);
211 + }
212 +
213 name = worktree_basename(path, &len);
214 strbuf_addstr(&sb_repo,
215 git_path("worktrees/%.*s", (int)(path + len - name), name));
@@ -281,6 +298,7 @@ static int add_worktree(const char *path, const char *refname,
298 unlink_or_warn(sb.buf);
299 argv_array_clear(&child_env);
300 strbuf_release(&sb);
301 + strbuf_release(&symref);
302 strbuf_release(&sb_repo);
303 strbuf_release(&sb_git);
304 return ret;