All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/34] nd/multiple-work-trees reroll
@ 2014-11-30  8:24 Nguyễn Thái Ngọc Duy
  2014-11-30  8:24 ` [PATCH 01/34] path.c: make get_pathname() return strbuf instead of static buffer Nguyễn Thái Ngọc Duy
                   ` (33 more replies)
  0 siblings, 34 replies; 45+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:24 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This is rebased so the diff below (against the version on Junio's
repo) is only approximate. Changes include test fixes for Windows
port, $GIT_COMMON_DIR and $GIT_DIR/modules problems with submodules.
Patch 03/34 is rewritten to touch less in refs.c to reduce conflicts.
A lot of changes there are just revert.

diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index 2b30a92..7173b38 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -248,9 +248,7 @@ commondir::
 	incomplete without the repository pointed by "commondir".
 
 modules::
-	Contains the git-repositories of the submodules. This
-	directory is ignored if $GIT_COMMON_DIR is set and
-	"$GIT_COMMON_DIR/modules" will be used instead.
+	Contains the git-repositories of the submodules.
 
 worktrees::
 	Contains worktree specific information of linked
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 01d0f2f..e70e66c 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -865,7 +865,7 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,
 
 	if (!new->commit)
 		die(_("no branch specified"));
-	if (file_exists(path))
+	if (file_exists(path) && !is_empty_dir(path))
 		die(_("'%s' already exists"), path);
 
 	len = strlen(path);
@@ -1207,7 +1207,7 @@ static int parse_branchname_arg(int argc, const char **argv,
 	if (new->path && !force_detach && !*new_branch) {
 		unsigned char sha1[20];
 		int flag;
-		char *head_ref = resolve_refdup("HEAD", sha1, 0, &flag);
+		char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
 		if (head_ref &&
 		    (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
 			check_linked_checkouts(new);
diff --git a/environment.c b/environment.c
index d5b0788..8351007 100644
--- a/environment.c
+++ b/environment.c
@@ -101,6 +101,7 @@ const char * const local_repo_env[] = {
 	NO_REPLACE_OBJECTS_ENVIRONMENT,
 	GIT_PREFIX_ENVIRONMENT,
 	GIT_SHALLOW_FILE_ENVIRONMENT,
+	GIT_COMMON_DIR_ENVIRONMENT,
 	NULL
 };
 
diff --git a/path.c b/path.c
index 35d498e..a5c51a3 100644
--- a/path.c
+++ b/path.c
@@ -92,7 +92,7 @@ static void replace_dir(struct strbuf *buf, int len, const char *newdir)
 }
 
 static const char *common_list[] = {
-	"/branches", "/hooks", "/info", "!/logs", "/lost-found", "/modules",
+	"/branches", "/hooks", "/info", "!/logs", "/lost-found",
 	"/objects", "/refs", "/remotes", "/worktrees", "/rr-cache", "/svn",
 	"config", "!gc.pid", "packed-refs", "shallow",
 	NULL
diff --git a/refs.c b/refs.c
index 3cefbd3..f7e48b0 100644
--- a/refs.c
+++ b/refs.c
@@ -1398,14 +1398,16 @@ static const char *handle_missing_loose_ref(const char *refname,
 }
 
 /* This function needs to return a meaningful errno on failure */
-const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int reading, int *flag)
+static const char *resolve_ref_unsafe_1(const char *refname,
+					unsigned char *sha1,
+					int reading,
+					int *flags,
+					struct strbuf *sb_path)
 {
-	struct strbuf sb_path = STRBUF_INIT;
 	int depth = MAXDEPTH;
 	ssize_t len;
 	char buffer[256];
 	static char refname_buffer[256];
-	const char *ret;
 
 	if (flag)
 		*flag = 0;
@@ -1423,12 +1425,12 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
 
 		if (--depth < 0) {
 			errno = ELOOP;
-			goto fail;
+			return NULL;
 		}
 
-		strbuf_reset(&sb_path);
-		strbuf_git_path(&sb_path, "%s", refname);
-		path = sb_path.buf;
+		strbuf_reset(sb_path);
+		strbuf_git_path(sb_path, "%s", refname);
+		path = sb_path->buf;
 
 		/*
 		 * We might have to loop back here to avoid a race
@@ -1442,11 +1444,10 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
 	stat_ref:
 		if (lstat(path, &st) < 0) {
 			if (errno == ENOENT)
-				ret = handle_missing_loose_ref(refname, sha1,
-							       reading, flag);
+				return handle_missing_loose_ref(refname, sha1,
+								reading, flag);
 			else
-				ret = NULL;
-			goto done;
+				return NULL;
 		}
 
 		/* Follow "normalized" - ie "refs/.." symlinks by hand */
@@ -1457,7 +1458,7 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
 					/* inconsistent with lstat; retry */
 					goto stat_ref;
 				else
-					goto fail;
+					return NULL;
 			}
 			buffer[len] = 0;
 			if (starts_with(buffer, "refs/") &&
@@ -1473,7 +1474,7 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
 		/* Is it a directory? */
 		if (S_ISDIR(st.st_mode)) {
 			errno = EISDIR;
-			goto fail;
+			return NULL;
 		}
 
 		/*
@@ -1486,15 +1487,14 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
 				/* inconsistent with lstat; retry */
 				goto stat_ref;
 			else
-				goto fail;
+				return NULL;
 		}
-
 		len = read_in_full(fd, buffer, sizeof(buffer)-1);
 		if (len < 0) {
 			int save_errno = errno;
 			close(fd);
 			errno = save_errno;
-			goto fail;
+			return NULL;
 		}
 		close(fd);
 		while (len && isspace(buffer[len-1]))
@@ -1514,10 +1514,9 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
 				if (flag)
 					*flag |= REF_ISBROKEN;
 				errno = EINVAL;
-				goto fail;
+				return NULL;
 			}
-			ret = refname;
-			goto done;
+			return refname;
 		}
 		if (flag)
 			*flag |= REF_ISSYMREF;
@@ -1528,13 +1527,17 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
 			if (flag)
 				*flag |= REF_ISBROKEN;
 			errno = EINVAL;
-			goto fail;
+			return NULL;
 		}
 		refname = strcpy(refname_buffer, buf);
 	}
-fail:
-	ret = NULL;
-done:
+}
+
+const char *resolve_ref_unsafe(const char *refname, int reading,
+			       unsigned char *sha1, int *flags)
+{
+	struct strbuf sb_path = STRBUF_INIT;
+	const char *ret = resolve_ref_unsafe_1(refname, reading,, sha1, flags, &sb_path);
 	strbuf_release(&sb_path);
 	return ret;
 }
@@ -2844,62 +2847,66 @@ static int copy_msg(char *buf, const char *msg)
 }
 
 /* This function must set a meaningful errno on failure */
-int log_ref_setup(const char *refname, struct strbuf *logfile)
+int log_ref_setup(const char *refname, struct strbuf *sb_logfile)
 {
 	int logfd, oflags = O_APPEND | O_WRONLY;
+	char *logfile;
 
-	strbuf_git_path(logfile, "logs/%s", refname);
+	strbuf_git_path(sb_logfile, "logs/%s", refname);
+	logfile = sb_logfile->buf;
+	/* make sure the rest of the function can't change "logfile" */
+	sb_logfile = NULL;
 	if (log_all_ref_updates &&
 	    (starts_with(refname, "refs/heads/") ||
 	     starts_with(refname, "refs/remotes/") ||
 	     starts_with(refname, "refs/notes/") ||
 	     !strcmp(refname, "HEAD"))) {
-		if (safe_create_leading_directories(logfile->buf) < 0) {
+		if (safe_create_leading_directories(logfile) < 0) {
 			int save_errno = errno;
-			error("unable to create directory for %s", logfile->buf);
+			error("unable to create directory for %s", logfile);
 			errno = save_errno;
 			return -1;
 		}
 		oflags |= O_CREAT;
 	}
 
-	logfd = open(logfile->buf, oflags, 0666);
+	logfd = open(logfile, oflags, 0666);
 	if (logfd < 0) {
 		if (!(oflags & O_CREAT) && errno == ENOENT)
 			return 0;
 
 		if ((oflags & O_CREAT) && errno == EISDIR) {
-			if (remove_empty_directories(logfile->buf)) {
+			if (remove_empty_directories(logfile)) {
 				int save_errno = errno;
 				error("There are still logs under '%s'",
-				      logfile->buf);
+				      logfile);
 				errno = save_errno;
 				return -1;
 			}
-			logfd = open(logfile->buf, oflags, 0666);
+			logfd = open(logfile, oflags, 0666);
 		}
 
 		if (logfd < 0) {
 			int save_errno = errno;
-			error("Unable to append to %s: %s", logfile->buf,
+			error("Unable to append to %s: %s", logfile,
 			      strerror(errno));
 			errno = save_errno;
 			return -1;
 		}
 	}
 
-	adjust_shared_perm(logfile->buf);
+	adjust_shared_perm(logfile);
 	close(logfd);
 	return 0;
 }
 
-static int log_ref_write(const char *refname, const unsigned char *old_sha1,
-			 const unsigned char *new_sha1, const char *msg)
+static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,
+			   const unsigned char *new_sha1, const char *msg,
+			   struct strbuf *sb_log_file)
 {
 	int logfd, result, written, oflags = O_APPEND | O_WRONLY;
 	unsigned maxlen, len;
 	int msglen;
-	struct strbuf sb_log_file = STRBUF_INIT;
 	const char *log_file;
 	char *logrec;
 	const char *committer;
@@ -2907,14 +2914,16 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,
 	if (log_all_ref_updates < 0)
 		log_all_ref_updates = !is_bare_repository();
 
-	result = log_ref_setup(refname, &sb_log_file);
+	result = log_ref_setup(refname, sb_log_file);
 	if (result)
-		goto done;
-	log_file = sb_log_file.buf;
+		return result;
+	log_file = sb_log_file->buf;
+	/* make sure the rest of the function can't change "log_file" */
+	sb_log_file = NULL;
 
 	logfd = open(log_file, oflags);
 	if (logfd < 0)
-		goto done;
+		return 0;
 	msglen = msg ? strlen(msg) : 0;
 	committer = git_committer_info(0);
 	maxlen = strlen(committer) + msglen + 100;
@@ -2932,19 +2941,24 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,
 		close(logfd);
 		error("Unable to append to %s", log_file);
 		errno = save_errno;
-		result = -1;
-		goto done;
+		return -1;
 	}
 	if (close(logfd)) {
 		int save_errno = errno;
 		error("Unable to append to %s", log_file);
 		errno = save_errno;
-		result = -1;
-		goto done;
+		return -1;
 	}
-done:
-	strbuf_release(&sb_log_file);
-	return result;
+	return 0;
+}
+
+static int log_ref_write(const char *refname, const unsigned char *old_sha1,
+			 const unsigned char *new_sha1, const char *msg)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb);
+	strbuf_release(&sb);
+	return ret;
 }
 
 int is_branch(const char *refname)
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e6ac7a4..4df7a2f 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -366,7 +366,7 @@ test_expect_success 'GIT_DIR set (1)' '
 
 test_expect_success 'GIT_DIR set (2)' '
 	echo "gitdir: repo.git/repos/foo" >gitfile &&
-	echo "$TRASH_DIRECTORY/repo.git" >repo.git/repos/foo/commondir &&
+	echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir &&
 	(
 		cd work &&
 		GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
index eddd325..915b506 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-checkout-to.sh
@@ -13,10 +13,15 @@ test_expect_success 'checkout --to not updating paths' '
 '
 
 test_expect_success 'checkout --to an existing worktree' '
-	mkdir existing &&
+	mkdir -p existing/subtree &&
 	test_must_fail git checkout --detach --to existing master
 '
 
+test_expect_success 'checkout --to an existing empty worktree' '
+	mkdir existing_empty &&
+	git checkout --detach --to existing_empty master
+'
+
 test_expect_success 'checkout --to refuses to checkout locked branch' '
 	test_must_fail git checkout --to zere master &&
 	! test -d zere &&
diff --git a/t/t2026-prune-linked-checkouts.sh b/t/t2026-prune-linked-checkouts.sh
index 3622800..170aefe 100755
--- a/t/t2026-prune-linked-checkouts.sh
+++ b/t/t2026-prune-linked-checkouts.sh
@@ -57,7 +57,7 @@ test_expect_success 'prune directories with invalid gitdir' '
 test_expect_success 'prune directories with gitdir pointing to nowhere' '
 	mkdir -p .git/worktrees/def/abc &&
 	: >.git/worktrees/def/def &&
-	echo "$TRASH_DIRECTORY"/nowhere >.git/worktrees/def/gitdir &&
+	echo "$(pwd)"/nowhere >.git/worktrees/def/gitdir &&
 	git prune --worktrees --verbose >actual &&
 	test_i18ngrep "Removing worktrees/def: gitdir file points to non-existent location" actual &&
 	! test -d .git/worktrees/def &&
@@ -76,7 +76,7 @@ test_expect_success 'not prune recent checkouts' '
 	test_when_finished rm -r .git/worktrees
 	mkdir zz &&
 	mkdir -p .git/worktrees/jlm &&
-	echo "$TRASH_DIRECTORY"/zz >.git/worktrees/jlm/gitdir &&
+	echo "$(pwd)"/zz >.git/worktrees/jlm/gitdir &&
 	git prune --worktrees --verbose --expire=2.days.ago &&
 	test -d .git/worktrees/jlm
 '
diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh
new file mode 100755
index 0000000..8f30aed
--- /dev/null
+++ b/t/t7410-submodule-checkout-to.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='Combination of submodules and multiple workdirs'
+
+. ./test-lib.sh
+
+base_path=$(pwd -P)
+
+test_expect_success 'setup: make origin' \
+    'mkdir -p origin/sub && ( cd origin/sub && git init &&
+	echo file1 >file1 &&
+	git add file1 &&
+	git commit -m file1 ) &&
+    mkdir -p origin/main && ( cd origin/main && git init &&
+	git submodule add ../sub &&
+	git commit -m "add sub" ) &&
+    ( cd origin/sub &&
+	echo file1updated >file1 &&
+	git add file1 &&
+	git commit -m "file1 updated" ) &&
+    ( cd origin/main/sub && git pull ) &&
+    ( cd origin/main &&
+	git add sub &&
+	git commit -m "sub updated" )'
+
+test_expect_success 'setup: clone' \
+    'mkdir clone && ( cd clone &&
+	git clone --recursive "$base_path/origin/main")'
+
+rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q "HEAD~1")
+rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q "HEAD~1")
+
+test_expect_success 'checkout main' \
+    'mkdir default_checkout &&
+    (cd clone/main &&
+	git checkout --to "$base_path/default_checkout/main" "$rev1_hash_main")'
+
+test_expect_failure 'can see submodule diffs just after checkout' \
+    '(cd default_checkout/main && git diff --submodule master"^!" | grep "file1 updated")'
+
+test_expect_success 'checkout main and initialize independed clones' \
+    'mkdir fully_cloned_submodule &&
+    (cd clone/main &&
+	git checkout --to "$base_path/fully_cloned_submodule/main" "$rev1_hash_main") &&
+    (cd fully_cloned_submodule/main && git submodule update)'
+
+test_expect_success 'can see submodule diffs after independed cloning' \
+    '(cd fully_cloned_submodule/main && git diff --submodule master"^!" | grep "file1 updated")'
+
+test_done

^ permalink raw reply related	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2014-12-03 15:54 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-30  8:24 [PATCH 00/34] nd/multiple-work-trees reroll Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 01/34] path.c: make get_pathname() return strbuf instead of static buffer Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 02/34] path.c: make get_pathname() call sites return const char * Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 03/34] git_snpath(): retire and replace with strbuf_git_path() Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 04/34] path.c: rename vsnpath() to do_git_path() Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 05/34] path.c: group git_path(), git_pathdup() and strbuf_git_path() together Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 06/34] git_path(): be aware of file relocation in $GIT_DIR Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 07/34] *.sh: respect $GIT_INDEX_FILE Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 08/34] reflog: avoid constructing .lock path with git_path Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 09/34] fast-import: use git_path() for accessing .git dir instead of get_git_dir() Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 10/34] commit: use SEQ_DIR instead of hardcoding "sequencer" Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 11/34] $GIT_COMMON_DIR: a new environment variable Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 12/34] git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objects Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 13/34] *.sh: avoid hardcoding $GIT_DIR/hooks/ Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 14/34] git-stash: avoid hardcoding $GIT_DIR/logs/ Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 15/34] setup.c: convert is_git_directory() to use strbuf Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 16/34] setup.c: detect $GIT_COMMON_DIR in is_git_directory() Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 17/34] setup.c: convert check_repository_format_gently to use strbuf Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 18/34] setup.c: detect $GIT_COMMON_DIR check_repository_format_gently() Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 19/34] setup.c: support multi-checkout repo setup Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 20/34] wrapper.c: wrapper to open a file, fprintf then close Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 21/34] use new wrapper write_file() for simple file writing Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 22/34] checkout: support checking out into a new working directory Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 23/34] prune: strategies for linked checkouts Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 24/34] checkout: reject if the branch is already checked out elsewhere Nguyễn Thái Ngọc Duy
2014-11-30 17:18   ` Mark Levedahl
2014-12-01 10:38     ` Duy Nguyen
2014-12-01 17:39       ` Junio C Hamano
2014-12-02  5:04         ` Mark Levedahl
2014-12-02 12:01           ` Duy Nguyen
2014-12-02 17:30             ` Junio C Hamano
2014-12-03 11:30               ` Mark Levedahl
2014-12-03 12:50               ` Duy Nguyen
2014-12-03 15:54                 ` Junio C Hamano
2014-12-02 11:50         ` Duy Nguyen
2014-11-30  8:24 ` [PATCH 25/34] checkout: clean up half-prepared directories in --to mode Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 26/34] gc: style change -- no SP before closing parenthesis Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 27/34] gc: factor out gc.pruneexpire parsing code Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 28/34] gc: support prune --worktrees Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 29/34] count-objects: report unused files in $GIT_DIR/worktrees/ Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 30/34] git_path(): keep "info/sparse-checkout" per work-tree Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 31/34] checkout: don't require a work tree when checking out into a new one Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 32/34] t2025: add a test to make sure grafts is working from a linked checkout Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 33/34] checkout: do not fail if target is an empty directory Nguyễn Thái Ngọc Duy
2014-11-30  8:24 ` [PATCH 34/34] git-common-dir: make "modules/" per-working-directory directory Nguyễn Thái Ngọc Duy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.