git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Johan Herland <johan@herland.net>
To: git@vger.kernel.org
Cc: johan@herland.net, jrnieder@gmail.com, bebarino@gmail.com,
	avarab@gmail.com, gitster@pobox.com
Subject: [PATCHv3 18/21] git notes merge: --commit should fail if underlying notes ref has moved
Date: Sat,  9 Oct 2010 03:15:53 +0200	[thread overview]
Message-ID: <1286586956-3714-19-git-send-email-johan@herland.net> (raw)
In-Reply-To: <Message-Id: <1286586528-3473-1-git-send-email-johan@herland.net>

When manually resolving a notes merge, if the merging ref has moved since
the merge started, we should fail to complete the merge, and alert the user
to what's going on.

This situation may arise if you start a 'git notes merge' which results in
conflicts, and you then update the current notes ref (using for example
'git notes add/copy/amend/edit/remove/prune', 'git update-ref', etc.),
before you get around to resolving the notes conflicts and calling
'git notes merge --commit'.

We detect this situation by comparing the first parent of the partial merge
commit (which was created when the merge started) to the current value of the
merging notes ref (pointed to by the .git/NOTES_MERGE_REF symref).

If we don't fail in this situation, the notes merge commit would overwrite
the updated notes ref, thus losing the changes that happened in the meantime.

The patch includes a testcase verifying that we fail correctly in this
situation.

Signed-off-by: Johan Herland <johan@herland.net>
---
 builtin/notes.c                       |   11 ++++-
 t/t3310-notes-merge-manual-resolve.sh |   76 +++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/builtin/notes.c b/builtin/notes.c
index 3c373ec..d3754ab 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -786,7 +786,7 @@ static int merge_reset(struct notes_merge_options *o)
 static int merge_commit(struct notes_merge_options *o)
 {
 	struct strbuf msg = STRBUF_INIT;
-	unsigned char sha1[20];
+	unsigned char sha1[20], parent_sha1[20];
 	struct notes_tree *t;
 	struct commit *partial;
 	struct pretty_print_context pretty_ctx;
@@ -803,6 +803,11 @@ static int merge_commit(struct notes_merge_options *o)
 	else if (parse_commit(partial))
 		die("Could not parse commit from NOTES_MERGE_PARTIAL.");
 
+	if (partial->parents)
+		hashcpy(parent_sha1, partial->parents->item->object.sha1);
+	else
+		hashclr(parent_sha1);
+
 	t = xcalloc(1, sizeof(struct notes_tree));
 	init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
 
@@ -818,7 +823,9 @@ static int merge_commit(struct notes_merge_options *o)
 	format_commit_message(partial, "%s", &msg, &pretty_ctx);
 	strbuf_trim(&msg);
 	strbuf_insert(&msg, 0, "notes: ", 7);
-	update_ref(msg.buf, o->local_ref, sha1, NULL, 0, DIE_ON_ERR);
+	update_ref(msg.buf, o->local_ref, sha1,
+		   is_null_sha1(parent_sha1) ? NULL : parent_sha1,
+		   0, DIE_ON_ERR);
 
 	free_notes(t);
 	strbuf_release(&msg);
diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh
index 8568307..dfd4954 100755
--- a/t/t3310-notes-merge-manual-resolve.sh
+++ b/t/t3310-notes-merge-manual-resolve.sh
@@ -477,4 +477,80 @@ EOF
 	verify_notes z
 '
 
+cp expect_notes_y expect_notes_m
+cp expect_log_y expect_log_m
+
+test_expect_success 'redo merge of z into m (== y) with default ("manual") resolver => Conflicting 3-way merge' '
+	git update-ref refs/notes/m refs/notes/y &&
+	test_must_fail git notes merge z >output &&
+	# Output should point to where to resolve conflicts
+	grep -q "\\.git/NOTES_MERGE_WORKTREE" output &&
+	# Inspect merge conflicts
+	ls .git/NOTES_MERGE_WORKTREE >output_conflicts &&
+	test_cmp expect_conflicts output_conflicts &&
+	( for f in $(cat expect_conflicts); do
+		test_cmp "expect_conflict_$f" ".git/NOTES_MERGE_WORKTREE/$f" ||
+		exit 1
+	done ) &&
+	# Verify that current notes tree (pre-merge) has not changed (m == y)
+	verify_notes y &&
+	verify_notes m &&
+	test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)"
+'
+
+cp expect_notes_w expect_notes_m
+cp expect_log_w expect_log_m
+
+test_expect_success 'reset notes ref m to somewhere else (w)' '
+	git update-ref refs/notes/m refs/notes/w &&
+	verify_notes m &&
+	test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)"
+'
+
+test_expect_success 'fail to finalize conflicting merge if underlying ref has moved in the meantime (m != NOTES_MERGE_PARTIAL^1)' '
+	# Resolve conflicts
+	cat >.git/NOTES_MERGE_WORKTREE/$commit_sha1 <<EOF &&
+y and z notes on 1st commit
+EOF
+	cat >.git/NOTES_MERGE_WORKTREE/$commit_sha4 <<EOF &&
+y and z notes on 4th commit
+EOF
+	# Fail to finalize merge
+	test_must_fail git notes merge --commit >output 2>&1 &&
+	# .git/NOTES_MERGE_* must remain
+	test -f .git/NOTES_MERGE_PARTIAL &&
+	test -f .git/NOTES_MERGE_REF &&
+	test -f .git/NOTES_MERGE_WORKTREE/$commit_sha1 &&
+	test -f .git/NOTES_MERGE_WORKTREE/$commit_sha2 &&
+	test -f .git/NOTES_MERGE_WORKTREE/$commit_sha3 &&
+	test -f .git/NOTES_MERGE_WORKTREE/$commit_sha4 &&
+	# Refs are unchanged
+	test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)"
+	test "$(git rev-parse refs/notes/y)" = "$(git rev-parse NOTES_MERGE_PARTIAL^1)"
+	test "$(git rev-parse refs/notes/m)" != "$(git rev-parse NOTES_MERGE_PARTIAL^1)"
+	# Mention refs/notes/m, and its current and expected value in output
+	grep -q "refs/notes/m" output &&
+	grep -q "$(git rev-parse refs/notes/m)" output &&
+	grep -q "$(git rev-parse NOTES_MERGE_PARTIAL^1)" output &&
+	# Verify that other notes refs has not changed (w, x, y and z)
+	verify_notes w &&
+	verify_notes x &&
+	verify_notes y &&
+	verify_notes z
+'
+
+test_expect_success 'resolve situation by aborting the notes merge' '
+	git notes merge --reset &&
+	# No .git/NOTES_MERGE_* files left
+	test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
+	test_cmp /dev/null output &&
+	# m has not moved (still == w)
+	test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)"
+	# Verify that other notes refs has not changed (w, x, y and z)
+	verify_notes w &&
+	verify_notes x &&
+	verify_notes y &&
+	verify_notes z
+'
+
 test_done
-- 
1.7.3.1.104.g92b87a

  parent reply	other threads:[~2010-10-09  1:17 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <Message-Id: <1286586528-3473-1-git-send-email-johan@herland.net>
2010-10-09  1:11 ` [PATCHv3 05/21] notes.h/c: Clarify the handling of notes objects that are == null_sha1 Johan Herland
2010-10-09  1:11 ` [PATCHv3 06/21] notes.h/c: Propagate combine_notes_fn return value to add_note() and beyond Johan Herland
2010-10-09  1:11 ` [PATCHv3 07/21] (trivial) t3303: Indent with tabs instead of spaces for consistency Johan Herland
2010-10-09  1:11 ` [PATCHv3 08/21] notes.c: Use two newlines (instead of one) when concatenating notes Johan Herland
2010-10-09  1:11 ` [PATCHv3 09/21] builtin/notes.c: Split notes ref DWIMmery into a separate function Johan Herland
2010-10-09  1:13 ` [PATCHv3 10/21] git notes merge: Initial implementation handling trivial merges only Johan Herland
2010-10-09  1:13 ` [PATCHv3 11/21] builtin/notes.c: Refactor creation of notes commits Johan Herland
2010-10-09  1:13 ` [PATCHv3 12/21] git notes merge: Handle real, non-conflicting notes merges Johan Herland
2010-10-09  1:13 ` [PATCHv3 13/21] git notes merge: Add automatic conflict resolvers (ours, theirs, union) Johan Herland
2010-10-09  1:13 ` [PATCHv3 14/21] Documentation: Preliminary docs on 'git notes merge' Johan Herland
2010-10-09  1:15 ` [PATCHv3 15/21] git notes merge: Manual conflict resolution, part 1/2 Johan Herland
2010-10-09  1:15 ` [PATCHv3 16/21] git notes merge: Manual conflict resolution, part 2/2 Johan Herland
2010-10-09  1:15 ` [PATCHv3 17/21] git notes merge: List conflicting notes in notes merge commit message Johan Herland
2010-10-09  1:15 ` Johan Herland [this message]
2010-10-09  1:15 ` [PATCHv3 19/21] git notes merge: Add another auto-resolving strategy: "cat_sort_uniq" Johan Herland
2010-10-09  1:16 ` [PATCHv3 20/21] git notes merge: Add testcases for merging notes trees at different fanouts Johan Herland
2010-10-09  1:16 ` [PATCHv3 21/21] Provide 'git notes get-ref' to easily retrieve current notes ref Johan Herland

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=1286586956-3714-19-git-send-email-johan@herland.net \
    --to=johan@herland.net \
    --cc=avarab@gmail.com \
    --cc=bebarino@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=jrnieder@gmail.com \
    /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).