notes: handle multiple worktrees

Before creating NOTES_MERGE_REF, check NOTES_MERGE_REF using find_shared_symref and die if we find one. This prevents simultaneous merges to the same notes branch from different worktrees. Signed-off-by: David Turner <dturner@twopensource.com> Reviewed-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

David Turner committed Aug 10, 2015 at 13:52 UTC b02e8595e263e284e45a6262b92ef158b6966478
2 files changed +78
builtin/notes.c
+6
@@ -19,6 +19,7 @@
19 #include "string-list.h"
20 #include "notes-merge.h"
21 #include "notes-utils.h"
22 +#include "branch.h"
23
24 static const char * const git_notes_usage[] = {
25 N_("git notes [--ref <notes_ref>] [list [<object>]]"),
@@ -813,10 +814,15 @@ static int merge(int argc, const char **argv, const char *prefix)
814 update_ref(msg.buf, default_notes_ref(), result_sha1, NULL,
815 0, UPDATE_REFS_DIE_ON_ERR);
816 else { /* Merge has unresolved conflicts */
817 + char *existing;
818 /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
819 update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_sha1, NULL,
820 0, UPDATE_REFS_DIE_ON_ERR);
821 /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
822 + existing = find_shared_symref("NOTES_MERGE_REF", default_notes_ref());
823 + if (existing)
824 + die(_("A notes merge into %s is already in-progress at %s"),
825 + default_notes_ref(), existing);
826 if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
827 die("Failed to store link to current notes ref (%s)",
828 default_notes_ref());
t/t3320-notes-merge-worktrees.sh new
+72
@@ -0,0 +1,72 @@
1 +#!/bin/sh
2 +#
3 +# Copyright (c) 2015 Twitter, Inc
4 +#
5 +
6 +test_description='Test merging of notes trees in multiple worktrees'
7 +
8 +. ./test-lib.sh
9 +
10 +test_expect_success 'setup commit' '
11 + test_commit tantrum
12 +'
13 +
14 +commit_tantrum=$(git rev-parse tantrum^{commit})
15 +
16 +test_expect_success 'setup notes ref (x)' '
17 + git config core.notesRef refs/notes/x &&
18 + git notes add -m "x notes on tantrum" tantrum
19 +'
20 +
21 +test_expect_success 'setup local branch (y)' '
22 + git update-ref refs/notes/y refs/notes/x &&
23 + git config core.notesRef refs/notes/y &&
24 + git notes remove tantrum
25 +'
26 +
27 +test_expect_success 'setup remote branch (z)' '
28 + git update-ref refs/notes/z refs/notes/x &&
29 + git config core.notesRef refs/notes/z &&
30 + git notes add -f -m "conflicting notes on tantrum" tantrum
31 +'
32 +
33 +test_expect_success 'modify notes ref ourselves (x)' '
34 + git config core.notesRef refs/notes/x &&
35 + git notes add -f -m "more conflicting notes on tantrum" tantrum
36 +'
37 +
38 +test_expect_success 'create some new worktrees' '
39 + git worktree add -b newbranch worktree master &&
40 + git worktree add -b newbranch2 worktree2 master
41 +'
42 +
43 +test_expect_success 'merge z into y fails and sets NOTES_MERGE_REF' '
44 + git config core.notesRef refs/notes/y &&
45 + test_must_fail git notes merge z &&
46 + echo "ref: refs/notes/y" >expect &&
47 + test_cmp .git/NOTES_MERGE_REF expect
48 +'
49 +
50 +test_expect_success 'merge z into y while mid-merge in another workdir fails' '
51 + (
52 + cd worktree &&
53 + git config core.notesRef refs/notes/y &&
54 + test_must_fail git notes merge z 2>err &&
55 + grep "A notes merge into refs/notes/y is already in-progress at" err
56 + ) &&
57 + test_path_is_missing .git/worktrees/worktree/NOTES_MERGE_REF
58 +'
59 +
60 +test_expect_success 'merge z into x while mid-merge on y succeeds' '
61 + (
62 + cd worktree2 &&
63 + git config core.notesRef refs/notes/x &&
64 + test_must_fail git notes merge z 2>&1 >out &&
65 + grep "Automatic notes merge failed" out &&
66 + grep -v "A notes merge into refs/notes/x is already in-progress in" out
67 + ) &&
68 + echo "ref: refs/notes/x" >expect &&
69 + test_cmp .git/worktrees/worktree2/NOTES_MERGE_REF expect
70 +'
71 +
72 +test_done