git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v5 22/28] checkout: support checking out into a new working directory

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Mar 8, 2014, 02:48 UTC
Message-ID
<1394246900-31535-23-git-send-email-pclouds@gmail.com>
In-Reply-To
<1394246900-31535-1-git-send-email-pclouds@gmail.com>

"git checkout --to" sets up a new working directory with a .git file pointing to $GIT_DIR/repos/<id>. It then executes "git checkout" again on the new worktree with the same arguments except "--to" is taken out. The second checkout execution, which is not contaminated with any info from the current repository, will actually check out and everything that normal "git checkout" does.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-checkout.txt         | 34 +++++++++++++
 Documentation/git.txt                  |  3 +-
 Documentation/gitrepository-layout.txt |  7 +++
 builtin/checkout.c                     | 93 +++++++++++++++++++++++++++++++++-
 path.c                                 |  2 +-
 t/t2025-checkout-to.sh (new +x)        | 48 ++++++++++++++++++
 6 files changed, 183 insertions(+), 4 deletions(-)
 create mode 100755 t/t2025-checkout-to.sh
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 33ad2ad..fcf73b2 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -225,6 +225,13 @@ This means that you can use `git checkout -p` to selectively discard
 edits from your current working tree. See the ``Interactive Mode''
 section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
 
+--to=<path>::
+	Check out a new branch in a separate working directory at
+	`<path>`. A new working directory is linked to the current
+	repository, sharing everything except working directory
+	specific files such as HEAD, index... See "MULTIPLE CHECKOUT
+	MODE" section for more information.
+
 <branch>::
 	Branch to checkout; if it refers to a branch (i.e., a name that,
 	when prepended with "refs/heads/", is a valid ref), then that
@@ -388,6 +395,33 @@ $ git reflog -2 HEAD # or
 $ git log -g -2 HEAD
 ------------
 
+MULTIPLE CHECKOUT MODE
+-------------------------------
+Normally a working directory is attached to repository. When "git
+checkout --to" is used, a new working directory is attached to the
+current repository. This new working directory is called "linked
+checkout" as compared to the "main checkout" prepared by "git init" or
+"git clone". A repository has one main checkout and zero or more
+linked checkouts.
+
+All checkouts share the same repository. Linked checkouts see the
+repository a bit different from the main checkout. When the checkout
+"new" reads the path $GIT_DIR/HEAD for example, the actual path
+returned could be $GIT_DIR/repos/new/HEAD. This ensures checkouts
+won't step on each other.
+
+Each linked checkout has a private space in $GIT_DIR/repos, usually
+named after the base name of the working directory with a number added
+to make it unique. The linked checkout's $GIT_DIR points to this
+private space while $GIT_COMMON_DIR points to the main checkout's
+$GIT_DIR. These settings are done by "git checkout --to".
+
+Because in this mode $GIT_DIR becomes a lightweight virtual file
+system where a path could be rewritten to some place else, accessing
+$GIT_DIR from scripts should use `git rev-parse --git-path` to resolve
+a path instead of using it directly unless the path is known to be
+private to the working directory.
+
 EXAMPLES
 --------
 
diff --git a/Documentation/git.txt b/Documentation/git.txt
index b094b1f..bdb9b0f 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -777,7 +777,8 @@ Git so take care if using Cogito etc.
 	If this variable is set to a path, non-worktree files that are
 	normally in $GIT_DIR will be taken from this path
 	instead. Worktree-specific files such as HEAD or index are
-	taken from $GIT_DIR. See linkgit:gitrepository-layout[5] for
+	taken from $GIT_DIR. See linkgit:gitrepository-layout[5] and
+	the section 'MULTIPLE CHECKOUT MODE' in linkgit:checkout[1]
 	details. This variable has lower precedence than other path
 	variables such as GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY...
 
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index c6f3649..2206f35 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -245,6 +245,13 @@ modules::
 	directory is ignored if $GIT_COMMON_DIR is set and
 	"$GIT_COMMON_DIR/modules" will be used instead.
 
+repos::
+	Contains worktree specific information of linked
+	checkouts. Each subdirectory contains the worktree-related
+	part of a linked checkout. This directory is ignored
+	$GIT_COMMON_DIR is set and "$GIT_COMMON_DIR/repos" will be
+	used instead.
+
 SEE ALSO
 --------
 linkgit:git-init[1],
diff --git a/builtin/checkout.c b/builtin/checkout.c
index efb5e2f..aa4ffd1 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -48,6 +48,10 @@ struct checkout_opts {
 	const char *prefix;
 	struct pathspec pathspec;
 	struct tree *source_tree;
+
+	const char *new_worktree;
+	const char **saved_argv;
+	int new_worktree_mode;
 };
 
 static int post_checkout_hook(struct commit *old, struct commit *new,
@@ -250,6 +254,9 @@ static int checkout_paths(const struct checkout_opts *opts,
 		die(_("Cannot update paths and switch to branch '%s' at the same time."),
 		    opts->new_branch);
 
+	if (opts->new_worktree)
+		die(_("'%s' cannot be used with updating paths"), "--to");
+
 	if (opts->patch_mode)
 		return run_add_interactive(revision, "--patch=checkout",
 					   &opts->pathspec);
@@ -486,7 +493,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
 			topts.dir->flags |= DIR_SHOW_IGNORED;
 			setup_standard_excludes(topts.dir);
 		}
-		tree = parse_tree_indirect(old->commit ?
+		tree = parse_tree_indirect(old->commit && !opts->new_worktree_mode ?
 					   old->commit->object.sha1 :
 					   EMPTY_TREE_SHA1_BIN);
 		init_tree_desc(&trees[0], tree->buffer, tree->size);
@@ -797,7 +804,8 @@ static int switch_branches(const struct checkout_opts *opts,
 		return ret;
 	}
 
-	if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
+	if (!opts->quiet && !old.path && old.commit &&
+	    new->commit != old.commit && !opts->new_worktree_mode)
 		orphaned_commit_warning(old.commit, new->commit);
 
 	update_refs_for_switch(opts, &old, new);
@@ -807,6 +815,74 @@ static int switch_branches(const struct checkout_opts *opts,
 	return ret || writeout_error;
 }
 
+static int prepare_linked_checkout(const struct checkout_opts *opts,
+				   struct branch_info *new)
+{
+	struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
+	struct strbuf sb = STRBUF_INIT;
+	const char *path = opts->new_worktree, *name;
+	struct stat st;
+	struct child_process cp;
+	int counter = 0, len;
+
+	if (!new->commit)
+		die(_("no branch specified"));
+
+	len = strlen(path);
+	while (len && is_dir_sep(path[len - 1]))
+		len--;
+
+	for (name = path + len - 1; name > path; name--)
+		if (is_dir_sep(*name)) {
+			name++;
+			break;
+		}
+	strbuf_addstr(&sb_repo,
+		      git_path("repos/%.*s", (int)(path + len - name), name));
+	len = sb_repo.len;
+	if (safe_create_leading_directories_const(sb_repo.buf))
+		die_errno(_("could not create leading directories of '%s'"),
+			  sb_repo.buf);
+	while (!stat(sb_repo.buf, &st)) {
+		counter++;
+		strbuf_setlen(&sb_repo, len);
+		strbuf_addf(&sb_repo, "%d", counter);
+	}
+	name = strrchr(sb_repo.buf, '/') + 1;
+	if (mkdir(sb_repo.buf, 0777))
+		die_errno(_("could not create directory of '%s'"), sb_repo.buf);
+
+	strbuf_addf(&sb_git, "%s/.git", path);
+	if (safe_create_leading_directories_const(sb_git.buf))
+		die_errno(_("could not create leading directories of '%s'"),
+			  sb_git.buf);
+
+	write_file(sb_git.buf, 1, "gitdir: %s/repos/%s\n",
+		   real_path(get_git_common_dir()), name);
+	/*
+	 * This is to keep resolve_ref() happy. We need a valid HEAD
+	 * or is_git_directory() will reject the directory. Any valid
+	 * value would do because this value will be ignored and
+	 * replaced at the next (real) checkout.
+	 */
+	strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
+	write_file(sb.buf, 1, "%s\n", sha1_to_hex(new->commit->object.sha1));
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
+	write_file(sb.buf, 1, "../..\n");
+
+	if (!opts->quiet)
+		fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
+
+	setenv("GIT_CHECKOUT_NEW_WORKTREE", "1", 1);
+	setenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);
+	setenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);
+	memset(&cp, 0, sizeof(cp));
+	cp.git_cmd = 1;
+	cp.argv = opts->saved_argv;
+	return run_command(&cp);
+}
+
 static int git_checkout_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "diff.ignoresubmodules")) {
@@ -1068,6 +1144,9 @@ static int checkout_branch(struct checkout_opts *opts,
 		die(_("Cannot switch branch to a non-commit '%s'"),
 		    new->name);
 
+	if (opts->new_worktree)
+		return prepare_linked_checkout(opts, new);
+
 	if (!new->commit && opts->new_branch) {
 		unsigned char rev[20];
 		int flag;
@@ -1110,6 +1189,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 			 N_("do not limit pathspecs to sparse entries only")),
 		OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
 				N_("second guess 'git checkout no-such-branch'")),
+		OPT_STRING(0, "to", &opts.new_worktree, N_("path"),
+			   N_("check a branch out in a separate working directory")),
 		OPT_END(),
 	};
 
@@ -1118,6 +1199,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 	opts.overwrite_ignore = 1;
 	opts.prefix = prefix;
 
+	opts.saved_argv = xmalloc(sizeof(const char *) * (argc + 2));
+	memcpy(opts.saved_argv, argv, sizeof(const char *) * (argc + 1));
+
 	gitmodules_config();
 	git_config(git_checkout_config, &opts);
 
@@ -1126,6 +1210,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, options, checkout_usage,
 			     PARSE_OPT_KEEP_DASHDASH);
 
+	/* recursive execution from checkout_new_worktree() */
+	opts.new_worktree_mode = getenv("GIT_CHECKOUT_NEW_WORKTREE") != NULL;
+	if (opts.new_worktree_mode)
+		opts.new_worktree = NULL;
+
 	if (conflict_style) {
 		opts.merge = 1; /* implied */
 		git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
diff --git a/path.c b/path.c
index 8453687..ddb5962 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",
-	"/objects", "/refs", "/remotes", "/rr-cache", "/svn",
+	"/objects", "/refs", "/remotes", "/repos", "/rr-cache", "/svn",
 	"config", "gc.pid", "packed-refs", "shallow",
 	NULL
 };
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
new file mode 100755
index 0000000..5ec49e2
--- /dev/null
+++ b/t/t2025-checkout-to.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+test_description='test git checkout --to'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_commit init
+'
+
+test_expect_success 'checkout --to not updating paths' '
+	test_must_fail git checkout --to -- init.t
+'
+
+test_expect_success 'checkout --to a new worktree' '
+	git checkout --to here master &&
+	(
+		cd here &&
+		test_cmp ../init.t init.t &&
+		git symbolic-ref HEAD >actual &&
+		echo refs/heads/master >expect &&
+		test_cmp expect actual &&
+		git fsck
+	)
+'
+
+test_expect_success 'checkout --to from a linked checkout' '
+	(
+		cd here &&
+		git checkout --to nested-here master
+		cd nested-here &&
+		git fsck
+	)
+'
+
+test_expect_success 'checkout --to a new worktree creating new branch' '
+	git checkout --to there -b newmaster master &&
+	(
+		cd there &&
+		test_cmp ../init.t init.t &&
+		git symbolic-ref HEAD >actual &&
+		echo refs/heads/newmaster >expect &&
+		test_cmp expect actual &&
+		git fsck
+	)
+'
+
+test_done
-- 
1.9.0.40.gaa8c3ea
Previous: Nguyễn Thái Ngọc DuyNext: Nguyễn Thái Ngọc Duy
Message 155 of 169 in “Support multiple checkouts”
  1. 00/25 Support multiple checkoutsNguyễn Thái Ngọc Duy, Feb 18, 2014
  2. 01/25 path.c: make get_pathname() return strbuf instead of static bufferNguyễn Thái Ngọc Duy, Feb 18, 2014
  3. Junio C HamanoFeb 19, 2014
  4. Junio C HamanoFeb 19, 2014
  5. Duy NguyenMar 1, 2014
  6. Junio C HamanoMar 3, 2014
  7. 02/25 Convert git_snpath() to strbuf_git_path()Nguyễn Thái Ngọc Duy, Feb 18, 2014
  8. Junio C HamanoFeb 19, 2014
  9. Duy NguyenFeb 19, 2014
  10. Junio C HamanoFeb 20, 2014
  11. Duy NguyenFeb 20, 2014
  12. Junio C HamanoFeb 20, 2014
  13. Junio C HamanoFeb 20, 2014
  14. 03/25 path.c: rename vsnpath() to do_git_path()Nguyễn Thái Ngọc Duy, Feb 18, 2014
  15. 04/25 path.c: group git_path(), git_pathdup() and strbuf_git_path() togetherNguyễn Thái Ngọc Duy, Feb 18, 2014
  16. 05/25 Make git_path() aware of file relocation in $GIT_DIRNguyễn Thái Ngọc Duy, Feb 18, 2014
  17. 06/25 *.sh: respect $GIT_INDEX_FILENguyễn Thái Ngọc Duy, Feb 18, 2014
  18. 07/25 reflog: avoid constructing .lock path with git_pathNguyễn Thái Ngọc Duy, Feb 18, 2014
  19. Junio C HamanoFeb 25, 2014
  20. Duy NguyenMar 1, 2014
  21. Junio C HamanoMar 3, 2014
  22. 08/25 fast-import: use git_path() for accessing .git dir instead of get_git_dir()Nguyễn Thái Ngọc Duy, Feb 18, 2014
  23. 09/25 commit: use SEQ_DIR instead of hardcoding "sequencer"Nguyễn Thái Ngọc Duy, Feb 18, 2014
  24. 10/25 Add new environment variable $GIT_COMMON_DIRNguyễn Thái Ngọc Duy, Feb 18, 2014
  25. Eric SunshineFeb 26, 2014
  26. Duy NguyenFeb 26, 2014
  27. Philip OakleyFeb 26, 2014
  28. Eric SunshineFeb 26, 2014
  29. Eric SunshineFeb 26, 2014
  30. Junio C HamanoFeb 26, 2014
  31. Duy NguyenFeb 27, 2014
  32. 11/25 git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objectsNguyễn Thái Ngọc Duy, Feb 18, 2014
  33. Junio C HamanoFeb 27, 2014
  34. 12/25 *.sh: avoid hardcoding $GIT_DIR/hooks/...Nguyễn Thái Ngọc Duy, Feb 18, 2014
  35. 13/25 git-stash: avoid hardcoding $GIT_DIR/logs/....Nguyễn Thái Ngọc Duy, Feb 18, 2014
  36. 14/25 setup.c: convert is_git_directory() to use strbufNguyễn Thái Ngọc Duy, Feb 18, 2014
  37. Junio C HamanoFeb 19, 2014
  38. Duy NguyenFeb 20, 2014
  39. Junio C HamanoFeb 20, 2014
  40. Junio C HamanoFeb 20, 2014
  41. strbuf: style fix -- top opening bracket on a separate lineNguyễn Thái Ngọc Duy, Mar 1, 2014
  42. Eric SunshineFeb 21, 2014
  43. 15/25 setup.c: detect $GIT_COMMON_DIR in is_git_directory()Nguyễn Thái Ngọc Duy, Feb 18, 2014
  44. Junio C HamanoFeb 27, 2014
  45. Duy NguyenMar 1, 2014
  46. 16/25 setup.c: convert check_repository_format_gently to use strbufNguyễn Thái Ngọc Duy, Feb 18, 2014
  47. Junio C HamanoFeb 27, 2014
  48. 17/25 setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()Nguyễn Thái Ngọc Duy, Feb 18, 2014
  49. Junio C HamanoFeb 27, 2014
  50. Duy NguyenFeb 27, 2014
  51. Junio C HamanoFeb 27, 2014
  52. 18/25 setup.c: support multi-checkout repo setupNguyễn Thái Ngọc Duy, Feb 18, 2014
  53. Junio C HamanoFeb 19, 2014
  54. Junio C HamanoFeb 27, 2014
  55. Torsten BögershausenMar 24, 2014
  56. Duy NguyenMar 25, 2014
  57. Duy NguyenMar 25, 2014
  58. Junio C HamanoMar 26, 2014
  59. 19/25 wrapper.c: wrapper to open a file, fprintf then closeNguyễn Thái Ngọc Duy, Feb 18, 2014
  60. 20/25 use new wrapper write_file() for simple file writingNguyễn Thái Ngọc Duy, Feb 18, 2014
  61. 21/25 checkout: support checking out into a new working directoryNguyễn Thái Ngọc Duy, Feb 18, 2014
  62. Eric SunshineFeb 26, 2014
  63. Duy NguyenFeb 26, 2014
  64. Eric SunshineFeb 27, 2014
  65. 22/25 checkout: clean up half-prepared directories in --to modeNguyễn Thái Ngọc Duy, Feb 18, 2014
  66. 23/25 checkout: detach if the branch is already checked out elsewhereNguyễn Thái Ngọc Duy, Feb 18, 2014
  67. Junio C HamanoFeb 19, 2014
  68. Eric SunshineFeb 19, 2014
  69. 24/25 prune: strategies for linked checkoutsNguyễn Thái Ngọc Duy, Feb 18, 2014
  70. Junio C HamanoFeb 19, 2014
  71. Junio C HamanoFeb 19, 2014
  72. Duy NguyenFeb 20, 2014
  73. Junio C HamanoFeb 20, 2014
  74. Eric SunshineFeb 19, 2014
  75. Eric SunshineFeb 19, 2014
  76. Duy NguyenFeb 20, 2014
  77. 25/25 gc: support prune --reposNguyễn Thái Ngọc Duy, Feb 18, 2014
  78. Junio C HamanoFeb 19, 2014
  79. Junio C HamanoFeb 19, 2014
  80. 00/27 Support multiple checkoutsNguyễn Thái Ngọc Duy, Mar 1, 2014
  81. 01/27 path.c: make get_pathname() return strbuf instead of static bufferNguyễn Thái Ngọc Duy, Mar 1, 2014
  82. Eric SunshineMar 2, 2014
  83. Duy NguyenMar 3, 2014
  84. 02/27 Convert git_snpath() to strbuf_git_path()Nguyễn Thái Ngọc Duy, Mar 1, 2014
  85. Eric SunshineMar 3, 2014
  86. Duy NguyenMar 3, 2014
  87. Duy NguyenMar 7, 2014
  88. Eric SunshineMar 7, 2014
  89. 03/27 path.c: rename vsnpath() to do_git_path()Nguyễn Thái Ngọc Duy, Mar 1, 2014
  90. 04/27 path.c: group git_path(), git_pathdup() and strbuf_git_path() togetherNguyễn Thái Ngọc Duy, Mar 1, 2014
  91. 05/27 Make git_path() aware of file relocation in $GIT_DIRNguyễn Thái Ngọc Duy, Mar 1, 2014
  92. Eric SunshineMar 3, 2014
  93. 06/27 *.sh: respect $GIT_INDEX_FILENguyễn Thái Ngọc Duy, Mar 1, 2014
  94. 07/27 reflog: avoid constructing .lock path with git_pathNguyễn Thái Ngọc Duy, Mar 1, 2014
  95. 08/27 fast-import: use git_path() for accessing .git dir instead of get_git_dir()Nguyễn Thái Ngọc Duy, Mar 1, 2014
  96. 09/27 commit: use SEQ_DIR instead of hardcoding "sequencer"Nguyễn Thái Ngọc Duy, Mar 1, 2014
  97. 10/27 Add new environment variable $GIT_COMMON_DIRNguyễn Thái Ngọc Duy, Mar 1, 2014
  98. Eric SunshineMar 3, 2014
  99. 11/27 git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objectsNguyễn Thái Ngọc Duy, Mar 1, 2014
  100. 12/27 *.sh: avoid hardcoding $GIT_DIR/hooks/...Nguyễn Thái Ngọc Duy, Mar 1, 2014
  101. Eric SunshineMar 3, 2014
  102. 13/27 git-stash: avoid hardcoding $GIT_DIR/logs/....Nguyễn Thái Ngọc Duy, Mar 1, 2014
  103. Torsten BögershausenMar 1, 2014
  104. 14/27 setup.c: convert is_git_directory() to use strbufNguyễn Thái Ngọc Duy, Mar 1, 2014
  105. 15/27 setup.c: detect $GIT_COMMON_DIR in is_git_directory()Nguyễn Thái Ngọc Duy, Mar 1, 2014
  106. 16/27 setup.c: convert check_repository_format_gently to use strbufNguyễn Thái Ngọc Duy, Mar 1, 2014
  107. 17/27 setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()Nguyễn Thái Ngọc Duy, Mar 1, 2014
  108. 18/27 setup.c: support multi-checkout repo setupNguyễn Thái Ngọc Duy, Mar 1, 2014
  109. Junio C HamanoMar 5, 2014
  110. Duy NguyenMar 8, 2014
  111. 19/27 wrapper.c: wrapper to open a file, fprintf then closeNguyễn Thái Ngọc Duy, Mar 1, 2014
  112. Torsten BögershausenMar 1, 2014
  113. Eric SunshineMar 4, 2014
  114. 20/27 use new wrapper write_file() for simple file writingNguyễn Thái Ngọc Duy, Mar 1, 2014
  115. 21/27 checkout: support checking out into a new working directoryNguyễn Thái Ngọc Duy, Mar 1, 2014
  116. 22/27 checkout: clean up half-prepared directories in --to modeNguyễn Thái Ngọc Duy, Mar 1, 2014
  117. Eric SunshineMar 6, 2014
  118. 23/27 checkout: detach if the branch is already checked out elsewhereNguyễn Thái Ngọc Duy, Mar 1, 2014
  119. 24/27 prune: strategies for linked checkoutsNguyễn Thái Ngọc Duy, Mar 1, 2014
  120. Torsten BögershausenMar 1, 2014
  121. Duy NguyenMar 2, 2014
  122. Junio C HamanoMar 5, 2014
  123. 25/27 gc: style change -- no SP before closing bracketNguyễn Thái Ngọc Duy, Mar 1, 2014
  124. 26/27 gc: support prune --reposNguyễn Thái Ngọc Duy, Mar 1, 2014
  125. Eric SunshineMar 7, 2014
  126. 27/27 count-objects: report unused files in $GIT_DIR/repos/...Nguyễn Thái Ngọc Duy, Mar 1, 2014
  127. Eric SunshineMar 5, 2014
  128. Duy NguyenMar 5, 2014
  129. 00/28 Support multiple checkoutsNguyễn Thái Ngọc Duy, Mar 8, 2014
  130. 01/28 path.c: make get_pathname() return strbuf instead of static bufferNguyễn Thái Ngọc Duy, Mar 8, 2014
  131. Torsten BögershausenMar 8, 2014
  132. Duy NguyenMar 8, 2014
  133. 02/28 path.c: make get_pathname() call sites return const char *Nguyễn Thái Ngọc Duy, Mar 8, 2014
  134. 03/28 Convert git_snpath() to strbuf_git_path()Nguyễn Thái Ngọc Duy, Mar 8, 2014
  135. Junio C HamanoMar 17, 2014
  136. 04/28 path.c: rename vsnpath() to do_git_path()Nguyễn Thái Ngọc Duy, Mar 8, 2014
  137. 05/28 path.c: group git_path(), git_pathdup() and strbuf_git_path() togetherNguyễn Thái Ngọc Duy, Mar 8, 2014
  138. 06/28 Make git_path() aware of file relocation in $GIT_DIRNguyễn Thái Ngọc Duy, Mar 8, 2014
  139. Eric SunshineMar 9, 2014
  140. 07/28 *.sh: respect $GIT_INDEX_FILENguyễn Thái Ngọc Duy, Mar 8, 2014
  141. 08/28 reflog: avoid constructing .lock path with git_pathNguyễn Thái Ngọc Duy, Mar 8, 2014
  142. 09/28 fast-import: use git_path() for accessing .git dir instead of get_git_dir()Nguyễn Thái Ngọc Duy, Mar 8, 2014
  143. 10/28 commit: use SEQ_DIR instead of hardcoding "sequencer"Nguyễn Thái Ngọc Duy, Mar 8, 2014
  144. 11/28 Add new environment variable $GIT_COMMON_DIRNguyễn Thái Ngọc Duy, Mar 8, 2014
  145. 12/28 git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objectsNguyễn Thái Ngọc Duy, Mar 8, 2014
  146. 13/28 *.sh: avoid hardcoding $GIT_DIR/hooks/...Nguyễn Thái Ngọc Duy, Mar 8, 2014
  147. 14/28 git-stash: avoid hardcoding $GIT_DIR/logs/....Nguyễn Thái Ngọc Duy, Mar 8, 2014
  148. 15/28 setup.c: convert is_git_directory() to use strbufNguyễn Thái Ngọc Duy, Mar 8, 2014
  149. 16/28 setup.c: detect $GIT_COMMON_DIR in is_git_directory()Nguyễn Thái Ngọc Duy, Mar 8, 2014
  150. 17/28 setup.c: convert check_repository_format_gently to use strbufNguyễn Thái Ngọc Duy, Mar 8, 2014
  151. 18/28 setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()Nguyễn Thái Ngọc Duy, Mar 8, 2014
  152. 19/28 setup.c: support multi-checkout repo setupNguyễn Thái Ngọc Duy, Mar 8, 2014
  153. 20/28 wrapper.c: wrapper to open a file, fprintf then closeNguyễn Thái Ngọc Duy, Mar 8, 2014
  154. 21/28 use new wrapper write_file() for simple file writingNguyễn Thái Ngọc Duy, Mar 8, 2014
  155. 22/28 checkout: support checking out into a new working directoryNguyễn Thái Ngọc Duy, Mar 8, 2014
  156. 23/28 checkout: clean up half-prepared directories in --to modeNguyễn Thái Ngọc Duy, Mar 8, 2014
  157. 24/28 checkout: detach if the branch is already checked out elsewhereNguyễn Thái Ngọc Duy, Mar 8, 2014
  158. 25/28 prune: strategies for linked checkoutsNguyễn Thái Ngọc Duy, Mar 8, 2014
  159. Eric SunshineMar 9, 2014
  160. 26/28 gc: style change -- no SP before closing bracketNguyễn Thái Ngọc Duy, Mar 8, 2014
  161. 27/28 gc: support prune --reposNguyễn Thái Ngọc Duy, Mar 8, 2014
  162. 28/28 count-objects: report unused files in $GIT_DIR/repos/...Nguyễn Thái Ngọc Duy, Mar 8, 2014
  163. Eric SunshineMar 9, 2014
  164. Duy NguyenMar 9, 2014
  165. Eric SunshineMar 9, 2014
  166. Max KirillovJul 6, 2014
  167. Duy NguyenJul 7, 2014
  168. Dennis KaarsemakerJul 7, 2014
  169. Max KirillovJul 7, 2014

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.