aboutsummaryrefslogtreecommitdiff
path: root/worktree.c
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2016-04-22 20:01:33 +0700
committerJunio C Hamano <gitster@pobox.com>2016-04-22 14:09:38 -0700
commit8d9fdd7087d0c2700a56e20043d5d79c9951f64f (patch)
tree00c03f667e1bb5cb7ef5357f9f46424adbbcdec3 /worktree.c
parentc8717148d02c48340ffd6a01ca52c31fa374bf3c (diff)
downloadgit-8d9fdd7087d0c2700a56e20043d5d79c9951f64f.tar.gz
git-8d9fdd7087d0c2700a56e20043d5d79c9951f64f.tar.xz
worktree.c: check whether branch is rebased in another worktree
This function find_shared_symref() is used in a couple places: 1) in builtin/branch.c: it's used to detect if a branch is checked out elsewhere and refuse to delete the branch. 2) in builtin/notes.c: it's used to detect if a note is being merged in another worktree 3) in branch.c, the function die_if_checked_out() is actually used by "git checkout" and "git worktree add" to see if a branch is already checked out elsewhere and refuse the operation. In cases 1 and 3, if a rebase is ongoing, "HEAD" will be in detached mode, find_shared_symref() fails to detect it and declares "no branch is checked out here", which is not really what we want. This patch tightens the test. If the given symref is "HEAD", we try to detect if rebase is ongoing. If so return the branch being rebased. This makes checkout and branch delete operations safer because you can't checkout a branch being rebased in another place, or delete it. Special case for checkout. If the current branch is being rebased, git-rebase.sh may use "git checkout" to abort and return back to the original branch. The updated test in find_shared_symref() will prevent that and "git rebase --abort" will fail as a result. find_shared_symref() and die_if_checked_out() have to learn a new option ignore_current_worktree to loosen the test a bit. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'worktree.c')
-rw-r--r--worktree.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/worktree.c b/worktree.c
index 927905b7a..504375666 100644
--- a/worktree.c
+++ b/worktree.c
@@ -3,6 +3,7 @@
#include "strbuf.h"
#include "worktree.h"
#include "dir.h"
+#include "wt-status.h"
void free_worktrees(struct worktree **worktrees)
{
@@ -215,6 +216,30 @@ const char *get_worktree_git_dir(const struct worktree *wt)
return git_common_path("worktrees/%s", wt->id);
}
+static int is_worktree_being_rebased(const struct worktree *wt,
+ const char *target)
+{
+ struct wt_status_state state;
+ int found_rebase;
+
+ memset(&state, 0, sizeof(state));
+ found_rebase = wt_status_check_rebase(wt, &state) &&
+ ((state.rebase_in_progress ||
+ state.rebase_interactive_in_progress) &&
+ state.branch &&
+ starts_with(target, "refs/heads/") &&
+ !strcmp(state.branch, target + strlen("refs/heads/")));
+ free(state.branch);
+ free(state.onto);
+ return found_rebase;
+}
+
+/*
+ * note: this function should be able to detect shared symref even if
+ * HEAD is temporarily detached (e.g. in the middle of rebase or
+ * bisect). New commands that do similar things should update this
+ * function as well.
+ */
const struct worktree *find_shared_symref(const char *symref,
const char *target)
{
@@ -231,6 +256,13 @@ const struct worktree *find_shared_symref(const char *symref,
for (i = 0; worktrees[i]; i++) {
struct worktree *wt = worktrees[i];
+ if (wt->is_detached && !strcmp(symref, "HEAD")) {
+ if (is_worktree_being_rebased(wt, target)) {
+ existing = wt;
+ break;
+ }
+ }
+
strbuf_reset(&path);
strbuf_reset(&sb);
strbuf_addf(&path, "%s/%s",