git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Johan Herland <johan@herland.net>
To: Junio C Hamano <gitster@pobox.com>
Cc: Johan Herland <johan@herland.net>,
	Johannes Sixt <j.sixt@viscovery.net>,
	git@vger.kernel.org, david@tethera.net, pclouds@gmail.com
Subject: [PATCH 3/2] notes-merge: Don't remove .git/NOTES_MERGE_WORKTREE; it may be the user's cwd
Date: Thu, 15 Mar 2012 00:55:33 +0100	[thread overview]
Message-ID: <1331769333-13890-1-git-send-email-johan@herland.net> (raw)
In-Reply-To: <7vlin3qdpt.fsf@alter.siamese.dyndns.org>

When a manual notes merge is committed or aborted, we need to remove the
temporary worktree at .git/NOTES_MERGE_WORKTREE. However, removing the
entire directory is not good if the user ran the 'git notes merge
--commit/--abort' from within that directory. On Windows, the directory
removal would simply fail, while on POSIX systems, users would suddenly
find themselves in an invalid current directory.

Therefore, instead of deleting the entire directory, we delete everything
_within_ the directory, and leave the (empty) directory in place.

This would cause a subsequent notes merge to abort, complaining about a
previous - unfinished - notes merge (due to the presence of
.git/NOTES_MERGE_WORKTREE), so we also need to adjust this check to only
trigger when .git/NOTES_MERGE_WORKTREE is non-empty.

Finally, adjust the t3310 manual notes merge testcases to correctly handle
the existence of an empty .git/NOTES_MERGE_WORKTREE directory.

Inspired-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Johan Herland <johan@herland.net>
---

How about this solution? I believe it should solve all the cases.

I'm torn about the new remove_everything_inside_dir(). Obviously it's a
copy-paste-modify of dir.c:remove_dir_recursively(), and could instead be
implemented by adding an extra flag to remove_dir_recursively(). However,
adding a "#define REMOVE_DIR_CONTENTS_BUT_NOT_DIR_ITSELF 04" seemed even
uglier to me...

What do you think?


...Johan


 notes-merge.c                         |   52 ++++++++++++++++++++++++++++++---
 t/t3310-notes-merge-manual-resolve.sh |    8 ++---
 2 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/notes-merge.c b/notes-merge.c
index 3a16af2..bf080fb 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -267,7 +267,8 @@ static void check_notes_merge_worktree(struct notes_merge_options *o)
 		 * Must establish NOTES_MERGE_WORKTREE.
 		 * Abort if NOTES_MERGE_WORKTREE already exists
 		 */
-		if (file_exists(git_path(NOTES_MERGE_WORKTREE))) {
+		if (file_exists(git_path(NOTES_MERGE_WORKTREE)) &&
+		    !is_empty_dir(git_path(NOTES_MERGE_WORKTREE))) {
 			if (advice_resolve_conflict)
 				die("You have not concluded your previous "
 				    "notes merge (%s exists).\nPlease, use "
@@ -754,16 +755,59 @@ int notes_merge_commit(struct notes_merge_options *o,
 	return 0;
 }
 
+/* Based on dir.c:remove_dir_recursively() */
+static int remove_everything_inside_dir(struct strbuf *path)
+{
+	DIR *dir;
+	struct dirent *e;
+	int ret = 0, original_len = path->len, len;
+
+	dir = opendir(path->buf);
+	if (!dir)
+		return -1;
+	if (path->buf[original_len - 1] != '/')
+		strbuf_addch(path, '/');
+
+	len = path->len;
+	while ((e = readdir(dir)) != NULL) {
+		struct stat st;
+		if (is_dot_or_dotdot(e->d_name))
+			continue;
+
+		strbuf_setlen(path, len);
+		strbuf_addstr(path, e->d_name);
+		if (lstat(path->buf, &st))
+			; /* fall thru */
+		else if (S_ISDIR(st.st_mode)) {
+			if (!remove_dir_recursively(path, 0))
+				continue; /* happy */
+		} else if (!unlink(path->buf))
+			continue; /* happy, too */
+
+		/* path too long, stat fails, or non-directory still exists */
+		ret = -1;
+		break;
+	}
+	closedir(dir);
+
+	strbuf_setlen(path, original_len);
+	return ret;
+}
+
 int notes_merge_abort(struct notes_merge_options *o)
 {
-	/* Remove .git/NOTES_MERGE_WORKTREE directory and all files within */
+	/*
+	 * Remove all files within .git/NOTES_MERGE_WORKTREE. We do not remove
+	 * the .git/NOTES_MERGE_WORKTREE directory itself, since it might be
+	 * the current working directory of the user.
+	 */
 	struct strbuf buf = STRBUF_INIT;
 	int ret;
 
 	strbuf_addstr(&buf, git_path(NOTES_MERGE_WORKTREE));
 	if (o->verbosity >= 3)
-		printf("Removing notes merge worktree at %s\n", buf.buf);
-	ret = remove_dir_recursively(&buf, 0);
+		printf("Removing notes merge worktree at %s/*\n", buf.buf);
+	ret = remove_everything_inside_dir(&buf);
 	strbuf_release(&buf);
 	return ret;
 }
diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh
index d6d6ac6..195bb97 100755
--- a/t/t3310-notes-merge-manual-resolve.sh
+++ b/t/t3310-notes-merge-manual-resolve.sh
@@ -324,7 +324,7 @@ y and z notes on 4th commit
 EOF
 	git notes merge --commit &&
 	# No .git/NOTES_MERGE_* files left
-	test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
+	test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
 	test_cmp /dev/null output &&
 	# Merge commit has pre-merge y and pre-merge z as parents
 	test "$(git rev-parse refs/notes/m^1)" = "$(cat pre_merge_y)" &&
@@ -386,7 +386,7 @@ test_expect_success 'redo merge of z into m (== y) with default ("manual") resol
 test_expect_success 'abort notes merge' '
 	git notes merge --abort &&
 	# No .git/NOTES_MERGE_* files left
-	test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
+	test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
 	test_cmp /dev/null output &&
 	# m has not moved (still == y)
 	test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)" &&
@@ -453,7 +453,7 @@ EOF
 	# Finalize merge
 	git notes merge --commit &&
 	# No .git/NOTES_MERGE_* files left
-	test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
+	test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
 	test_cmp /dev/null output &&
 	# Merge commit has pre-merge y and pre-merge z as parents
 	test "$(git rev-parse refs/notes/m^1)" = "$(cat pre_merge_y)" &&
@@ -542,7 +542,7 @@ EOF
 test_expect_success 'resolve situation by aborting the notes merge' '
 	git notes merge --abort &&
 	# No .git/NOTES_MERGE_* files left
-	test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
+	test_might_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)" &&
-- 
1.7.10.rc0.43.g35011

  reply	other threads:[~2012-03-14 23:56 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-10-24  6:36 [PATCH/WIP 00/11] read_directory() rewrite to support struct pathspec Nguyễn Thái Ngọc Duy
2011-10-24  6:36 ` [PATCH/WIP 01/11] Introduce "check-attr --excluded" as a replacement for "add --ignore-missing" Nguyễn Thái Ngọc Duy
2011-10-27 18:08   ` Junio C Hamano
2011-10-28 20:51     ` Nguyen Thai Ngoc Duy
2011-10-24  6:36 ` [PATCH/WIP 02/11] notes-merge: use opendir/readdir instead of using read_directory() Nguyễn Thái Ngọc Duy
2011-10-25 19:27   ` Junio C Hamano
2011-10-26  0:08     ` Nguyen Thai Ngoc Duy
2011-10-26 17:37       ` Junio C Hamano
2011-10-27  7:51         ` Nguyen Thai Ngoc Duy
2011-10-27 17:23           ` Junio C Hamano
2011-10-28 20:47             ` Nguyen Thai Ngoc Duy
2012-03-12 14:47   ` [PATCH 1/2] t3310: Add testcase demonstrating failure to --commit from within another dir Johan Herland
2012-03-12 14:47     ` [PATCH 2/2] notes-merge: use opendir/readdir instead of using read_directory() Johan Herland
2012-03-12 14:53       ` Nguyen Thai Ngoc Duy
2012-03-14  8:39       ` [PATCH jh/notes-merge-in-git-dir-worktree] fixup! t3310 on Windows Johannes Sixt
2012-03-14 11:39         ` Johan Herland
2012-03-14 11:59           ` Johannes Sixt
2012-03-14 12:20             ` David Bremner
2012-03-14 12:56             ` Johan Herland
2012-03-14 17:44               ` Junio C Hamano
2012-03-14 23:55                 ` Johan Herland [this message]
2012-03-15  7:02                   ` [PATCH 3/2] notes-merge: Don't remove .git/NOTES_MERGE_WORKTREE; it may be the user's cwd Junio C Hamano
2012-03-15  7:16                     ` Junio C Hamano
2012-03-15  7:39                       ` Johan Herland
2012-03-15  8:04                         ` Re* " Junio C Hamano
2012-03-15  8:12                         ` Junio C Hamano
2012-03-15  8:12                   ` Johannes Sixt
2011-10-24  6:36 ` [PATCH/WIP 03/11] t5403: avoid doing "git add foo/bar" where foo/.git exists Nguyễn Thái Ngọc Duy
2011-10-25 19:19   ` Junio C Hamano
2011-10-26  0:18     ` Nguyen Thai Ngoc Duy
2011-10-26 17:26       ` Junio C Hamano
2011-10-27  8:06         ` Nguyen Thai Ngoc Duy
2011-10-27 17:41           ` Junio C Hamano
2011-10-30  5:55             ` Nguyen Thai Ngoc Duy
2011-10-30  7:08               ` Junio C Hamano
2011-10-30  9:55                 ` Nguyen Thai Ngoc Duy
2011-10-30 23:47                   ` Junio C Hamano
2011-10-24  6:36 ` [PATCH/WIP 04/11] tree-walk.c: do not leak internal structure in tree_entry_len() Nguyễn Thái Ngọc Duy
2011-10-25 19:20   ` Junio C Hamano
2011-10-24  6:36 ` [PATCH/WIP 05/11] symbolize return values of tree_entry_interesting() Nguyễn Thái Ngọc Duy
2011-10-25 19:24   ` Junio C Hamano
2011-10-27 18:36   ` Junio C Hamano
2011-10-30  9:17     ` Nguyen Thai Ngoc Duy
2011-10-24  6:36 ` [PATCH/WIP 06/11] read_directory_recursive: reduce one indentation level Nguyễn Thái Ngọc Duy
2011-10-24  6:36 ` [PATCH/WIP 07/11] tree_entry_interesting: make use of local pointer "item" Nguyễn Thái Ngọc Duy
2011-10-24  6:36 ` [PATCH/WIP 08/11] tree-walk: mark useful pathspecs Nguyễn Thái Ngọc Duy
2011-10-24  6:36 ` [PATCH/WIP 09/11] tree_entry_interesting: differentiate partial vs full match Nguyễn Thái Ngọc Duy
2011-10-24  6:36 ` [PATCH/WIP 10/11] read-dir: stop using path_simplify code in favor of tree_entry_interesting() Nguyễn Thái Ngọc Duy
2011-10-24  6:36 ` [PATCH/WIP 11/11] dir.c: remove dead code after read_directory() rewrite Nguyễn Thái Ngọc Duy
2011-10-24 17:10 ` [PATCH/WIP 00/11] read_directory() rewrite to support struct pathspec Junio C Hamano

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=1331769333-13890-1-git-send-email-johan@herland.net \
    --to=johan@herland.net \
    --cc=david@tethera.net \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=j.sixt@viscovery.net \
    --cc=pclouds@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).