From: Jay Soffian <jaysoffian@gmail.com>
To: git@vger.kernel.org
Cc: Jay Soffian <jaysoffian@gmail.com>
Subject: [RFC/PATCH] Add multiple workdir support to branch/checkout
Date: Tue, 4 Oct 2011 23:43:24 -0400 [thread overview]
Message-ID: <1317786204-57335-1-git-send-email-jaysoffian@gmail.com> (raw)
When using 'git new-workdir', there is no safety mechanism to prevent the
same branch from being checked out twice, nor to prevent a checked out
branch from being deleted.
By teaching 'checkout' to record the workdir path using
'branch.<name>.checkout' when switching branches, we can easily check if a
branch is already checked out in another workdir before switching to that
branch. Similarly, we can now add a check before deleting a branch.
Allow 'checkout -f' to force the checkout and issue a warning
instead of an error.
Guard this behavior behind 'core.recordCheckouts', which we will
teach 'git new-workdir' to set in a followup commit.
Note: when switching away from a branch, we set 'branch.<name>.checkout'
to the empty string, instead of deleting it entirely, since git_config()
otherwise leaves behind an empty section which it does not re-use.
Signed-off-by: Jay Soffian <jaysoffian@gmail.com>
---
builtin/branch.c | 10 ++++++++++
builtin/checkout.c | 39 +++++++++++++++++++++++++++++++++++++++
remote.c | 4 ++++
remote.h | 1 +
4 files changed, 54 insertions(+), 0 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c
index f49596f826..6ce1a5b133 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -182,6 +182,16 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
ret = 1;
continue;
}
+ if (kinds == REF_LOCAL_BRANCH) {
+ struct branch *branch = branch_get(bname.buf);
+ if (branch->work_tree && strlen(branch->work_tree)) {
+ error(_("Cannot delete the branch '%s' "
+ "which is currently checked out in '%s'"),
+ bname.buf, branch->work_tree);
+ ret = 1;
+ continue;
+ }
+ }
free(name);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 5e356a6c61..26259a41a7 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -33,6 +33,7 @@ struct checkout_opts {
int force_detach;
int writeout_stage;
int writeout_error;
+ int record_checkouts;
/* not set by parse_options */
int branch_exists;
@@ -709,12 +710,35 @@ static void orphaned_commit_warning(struct commit *commit)
for_each_ref(clear_commit_marks_from_one_ref, NULL);
}
+static void record_checkout(const char *name, const char *work_tree)
+{
+ struct strbuf key = STRBUF_INIT;
+ strbuf_addf(&key, "branch.%s.checkout", name);
+ git_config_set(key.buf, work_tree);
+ strbuf_release(&key);
+}
+
+static void check_if_checked_out(struct checkout_opts *opts, const char *name)
+{
+ struct branch *branch = branch_get(name);
+ if (branch->work_tree && strlen(branch->work_tree) &&
+ strcmp(branch->work_tree, get_git_work_tree())) {
+ if (opts->force)
+ warning(_("branch '%s' is currently checked out"
+ " in '%s'"), name, branch->work_tree);
+ else
+ die(_("branch '%s' is currently checked out"
+ " in '%s'"), name, branch->work_tree);
+ }
+}
+
static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
{
int ret = 0;
struct branch_info old;
unsigned char rev[20];
int flag;
+
memset(&old, 0, sizeof(old));
old.path = xstrdup(resolve_ref("HEAD", rev, 0, &flag));
old.commit = lookup_commit_reference_gently(rev, 1);
@@ -734,6 +758,9 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
parse_commit(new->commit);
}
+ if (opts->record_checkouts)
+ check_if_checked_out(opts, new->name);
+
ret = merge_working_tree(opts, &old, new);
if (ret)
return ret;
@@ -743,6 +770,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
update_refs_for_switch(opts, &old, new);
+ if (opts->record_checkouts) {
+ const char *work_tree = get_git_work_tree();
+ struct branch *branch = branch_get(old.name);
+ if (branch->work_tree && !strcmp(branch->work_tree, work_tree))
+ record_checkout(old.name, "");
+ record_checkout(new->name, work_tree);
+ }
+
ret = post_checkout_hook(old.commit, new->commit, 1);
free((char *)old.path);
return ret || opts->writeout_error;
@@ -756,6 +791,10 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
return 0;
}
+ if (!strcmp(var, "core.recordcheckouts")) {
+ struct checkout_opts *opts = cb;
+ opts->record_checkouts = git_config_bool(var, value);
+ }
if (!prefixcmp(var, "submodule."))
return parse_submodule_config_option(var, value);
diff --git a/remote.c b/remote.c
index b8ecfa5d95..2bc063dae8 100644
--- a/remote.c
+++ b/remote.c
@@ -364,6 +364,10 @@ static int handle_config(const char *key, const char *value, void *cb)
if (!value)
return config_error_nonbool(key);
add_merge(branch, xstrdup(value));
+ } else if (!strcmp(subkey, ".checkout")) {
+ if (!value)
+ return config_error_nonbool(key);
+ branch->work_tree = xstrdup(value);
}
return 0;
}
diff --git a/remote.h b/remote.h
index 9a30a9dba6..4103ec7e31 100644
--- a/remote.h
+++ b/remote.h
@@ -126,6 +126,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec);
struct branch {
const char *name;
const char *refname;
+ const char *work_tree;
const char *remote_name;
struct remote *remote;
--
1.7.7.4.g39e02c
next reply other threads:[~2011-10-05 3:43 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-05 3:43 Jay Soffian [this message]
2011-10-05 3:48 ` [RFC/PATCH] Add multiple workdir support to branch/checkout Jay Soffian
2011-10-05 4:02 ` Nguyen Thai Ngoc Duy
2011-10-05 13:11 ` Jay Soffian
2011-10-05 16:46 ` Junio C Hamano
2011-10-05 17:17 ` Jay Soffian
2011-10-05 18:19 ` Junio C Hamano
2011-10-05 19:11 ` Jay Soffian
2011-10-05 20:00 ` Andreas Krey
2011-10-05 20:50 ` Jay Soffian
2011-10-05 21:30 ` Jonathan Nieder
2011-10-05 21:52 ` Jay Soffian
2011-10-05 21:57 ` Jonathan Nieder
2011-10-05 21:29 ` Junio C Hamano
2011-10-05 21:49 ` Jay Soffian
2011-10-05 19:14 ` Jay Soffian
2011-10-05 22:47 ` Nguyen Thai Ngoc Duy
2011-10-05 22:56 ` Junio C Hamano
2011-10-05 23:11 ` Nguyen Thai Ngoc Duy
2011-10-05 23:49 ` Junio C Hamano
2011-10-06 0:33 ` Jay Soffian
2011-10-06 0:43 ` Junio C Hamano
2011-10-06 0:57 ` Jay Soffian
2011-10-06 1:15 ` Junio C Hamano
2011-10-06 1:38 ` Jay Soffian
2011-10-06 1:57 ` Junio C Hamano
2011-10-06 4:02 ` Jay Soffian
2011-10-06 2:06 ` Nguyen Thai Ngoc Duy
2011-10-06 11:25 ` Bernhard R. Link
2011-10-06 14:42 ` Jeff King
2011-10-05 22:38 ` Nguyen Thai Ngoc Duy
2011-10-05 4:07 ` Junio C Hamano
2011-10-05 15:24 ` Jay Soffian
2011-10-05 16:01 ` Jay Soffian
2011-10-08 22:55 ` Julián Landerreche
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1317786204-57335-1-git-send-email-jaysoffian@gmail.com \
--to=jaysoffian@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).