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

Re: [PATCH 22/32] checkout: support checking out into a new working directory

From
Philip Oakley <philipoakley@iee.org>
Date
Aug 30, 2014, 20:50 UTC
Message-ID
<70985AC885404243A2B95F534083A0E9@PhilipOakley>
In-Reply-To
<1409387642-24492-23-git-send-email-pclouds@gmail.com>
From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Show 32 quoted lines
> "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                     | 95 
> +++++++++++++++++++++++++++++++++-
> path.c                                 |  2 +-
> t/t2025-checkout-to.sh (new +x)        | 63 ++++++++++++++++++++++
> 6 files changed, 200 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..38c70c5 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
Is this actually a 'new' branch? Perhaps s/new //. More below.
Show 25 quoted lines
> + `<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

I was caught out by "new" (in quotes) here. I see that the commit msg in patch 24 uses 'new-branch', while in patch 30 <new> is used. Is this "new" (above) refering to the branch name (or detatched head), or a nmemonic for the path? The use of "new working directory" in the previous paragraph is a well qualified use of new, so I'm looking to ensure that it's well qualified here.

My immediate reaction was that a consistent use of <new> in the three patches may be all that's needed

> +returned could be $GIT_DIR/repos/new/HEAD. This ensures checkouts

surely s/could/would/? or have I misunderstood? Also maybe s/new/<new-name>/, given the 'usually named' below, or s/new/<id>/ based on the commit message.

Show 315 quoted lines
> +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 749052f..c0a4940 100644
> --- a/Documentation/git.txt
> +++ b/Documentation/git.txt
> @@ -792,7 +792,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 58d1087..fab398a 100644
> --- a/Documentation/gitrepository-layout.txt
> +++ b/Documentation/gitrepository-layout.txt
> @@ -248,6 +248,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 if
> + $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 8023987..6373823 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);
> @@ -485,7 +492,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);
> @@ -796,7 +803,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);
> @@ -806,6 +814,76 @@ 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"));
> + if (file_exists(path))
> + die(_("'%s' already exists"), path);
> +
> + 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")) {
> @@ -1067,6 +1145,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;
> @@ -1109,6 +1190,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_FILENAME(0, "to", &opts.new_worktree,
> +    N_("check a branch out in a separate working directory")),
>  OPT_END(),
>  };
>
> @@ -1117,6 +1200,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);
>
> @@ -1125,6 +1211,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 8a6586c..e41d6b3 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..8c73b18
> --- /dev/null
> +++ b/t/t2025-checkout-to.sh
> @@ -0,0 +1,63 @@
> +#!/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 an existing worktree' '
> + mkdir existing &&
> + test_must_fail git checkout --detach --to existing master
> +'
> +
> +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 a new worktree from a subdir' '
> + (
> + mkdir sub &&
> + cd sub &&
> + git checkout --detach --to here master &&
> + cd here &&
> + test_cmp ../../init.t init.t
> + )
> +'
> +
> +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
> -- 
> 2.1.0.rc0.78.gc0d8480
>
> --
Philip 
Previous: Nguyễn Thái Ngọc DuyNext: Duy Nguyen
Message 24 of 134 in “nd/multiple-work-trees cleanup”
  1. 00/32 nd/multiple-work-trees cleanupNguyễn Thái Ngọc Duy, Aug 30, 2014
  2. 01/32 path.c: make get_pathname() return strbuf instead of static bufferNguyễn Thái Ngọc Duy, Aug 30, 2014
  3. 02/32 path.c: make get_pathname() call sites return const char *Nguyễn Thái Ngọc Duy, Aug 30, 2014
  4. 03/32 git_snpath(): retire and replace with strbuf_git_path()Nguyễn Thái Ngọc Duy, Aug 30, 2014
  5. 04/32 path.c: rename vsnpath() to do_git_path()Nguyễn Thái Ngọc Duy, Aug 30, 2014
  6. 05/32 path.c: group git_path(), git_pathdup() and strbuf_git_path() togetherNguyễn Thái Ngọc Duy, Aug 30, 2014
  7. 06/32 git_path(): be aware of file relocation in $GIT_DIRNguyễn Thái Ngọc Duy, Aug 30, 2014
  8. 07/32 *.sh: respect $GIT_INDEX_FILENguyễn Thái Ngọc Duy, Aug 30, 2014
  9. 08/32 reflog: avoid constructing .lock path with git_pathNguyễn Thái Ngọc Duy, Aug 30, 2014
  10. 09/32 fast-import: use git_path() for accessing .git dir instead of get_git_dir()Nguyễn Thái Ngọc Duy, Aug 30, 2014
  11. 10/32 commit: use SEQ_DIR instead of hardcoding "sequencer"Nguyễn Thái Ngọc Duy, Aug 30, 2014
  12. 11/32 $GIT_COMMON_DIR: a new environment variableNguyễn Thái Ngọc Duy, Aug 30, 2014
  13. 12/32 git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objectsNguyễn Thái Ngọc Duy, Aug 30, 2014
  14. 13/32 *.sh: avoid hardcoding $GIT_DIR/hooks/...Nguyễn Thái Ngọc Duy, Aug 30, 2014
  15. 14/32 git-stash: avoid hardcoding $GIT_DIR/logs/....Nguyễn Thái Ngọc Duy, Aug 30, 2014
  16. 15/32 setup.c: convert is_git_directory() to use strbufNguyễn Thái Ngọc Duy, Aug 30, 2014
  17. 16/32 setup.c: detect $GIT_COMMON_DIR in is_git_directory()Nguyễn Thái Ngọc Duy, Aug 30, 2014
  18. 17/32 setup.c: convert check_repository_format_gently to use strbufNguyễn Thái Ngọc Duy, Aug 30, 2014
  19. 18/32 setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()Nguyễn Thái Ngọc Duy, Aug 30, 2014
  20. 19/32 setup.c: support multi-checkout repo setupNguyễn Thái Ngọc Duy, Aug 30, 2014
  21. 20/32 wrapper.c: wrapper to open a file, fprintf then closeNguyễn Thái Ngọc Duy, Aug 30, 2014
  22. 21/32 use new wrapper write_file() for simple file writingNguyễn Thái Ngọc Duy, Aug 30, 2014
  23. 22/32 checkout: support checking out into a new working directoryNguyễn Thái Ngọc Duy, Aug 30, 2014
  24. Philip OakleyAug 30, 2014
  25. Duy NguyenAug 31, 2014
  26. Duy NguyenAug 31, 2014
  27. Philip OakleyAug 31, 2014
  28. Duy NguyenSep 2, 2014
  29. Marc BranchaudSep 2, 2014
  30. Junio C HamanoSep 2, 2014
  31. Duy NguyenSep 4, 2014
  32. Duy NguyenSep 8, 2014
  33. Marc BranchaudSep 8, 2014
  34. Scott SchmitSep 5, 2014
  35. Duy NguyenSep 5, 2014
  36. 23/32 checkout: clean up half-prepared directories in --to modeNguyễn Thái Ngọc Duy, Aug 30, 2014
  37. 24/32 checkout: reject if the branch is already checked out elsewhereNguyễn Thái Ngọc Duy, Aug 30, 2014
  38. 25/32 prune: strategies for linked checkoutsNguyễn Thái Ngọc Duy, Aug 30, 2014
  39. 26/32 gc: style change -- no SP before closing parenthesisNguyễn Thái Ngọc Duy, Aug 30, 2014
  40. 27/32 gc: factor out gc.pruneexpire parsing codeNguyễn Thái Ngọc Duy, Aug 30, 2014
  41. 28/32 gc: support prune --reposNguyễn Thái Ngọc Duy, Aug 30, 2014
  42. 29/32 count-objects: report unused files in $GIT_DIR/repos/...Nguyễn Thái Ngọc Duy, Aug 30, 2014
  43. 30/32 git_path(): keep "info/sparse-checkout" per work-treeNguyễn Thái Ngọc Duy, Aug 30, 2014
  44. 31/32 checkout: don't require a work tree when checking out into a new oneNguyễn Thái Ngọc Duy, Aug 30, 2014
  45. 32/32 t2025: add a test to make sure grafts is working from a linked checkoutNguyễn Thái Ngọc Duy, Aug 30, 2014
  46. Eric SunshineAug 30, 2014
  47. Duy NguyenAug 30, 2014
  48. Junio C HamanoSep 2, 2014
  49. 00/32 nd/multiple-work-treesNguyễn Thái Ngọc Duy, Sep 10, 2014
  50. 01/32 path.c: make get_pathname() return strbuf instead of static bufferNguyễn Thái Ngọc Duy, Sep 10, 2014
  51. 02/32 path.c: make get_pathname() call sites return const char *Nguyễn Thái Ngọc Duy, Sep 10, 2014
  52. 03/32 git_snpath(): retire and replace with strbuf_git_path()Nguyễn Thái Ngọc Duy, Sep 10, 2014
  53. 04/32 path.c: rename vsnpath() to do_git_path()Nguyễn Thái Ngọc Duy, Sep 10, 2014
  54. 05/32 path.c: group git_path(), git_pathdup() and strbuf_git_path() togetherNguyễn Thái Ngọc Duy, Sep 10, 2014
  55. 06/32 git_path(): be aware of file relocation in $GIT_DIRNguyễn Thái Ngọc Duy, Sep 10, 2014
  56. 07/32 *.sh: respect $GIT_INDEX_FILENguyễn Thái Ngọc Duy, Sep 10, 2014
  57. 08/32 reflog: avoid constructing .lock path with git_pathNguyễn Thái Ngọc Duy, Sep 10, 2014
  58. 09/32 fast-import: use git_path() for accessing .git dir instead of get_git_dir()Nguyễn Thái Ngọc Duy, Sep 10, 2014
  59. 10/32 commit: use SEQ_DIR instead of hardcoding "sequencer"Nguyễn Thái Ngọc Duy, Sep 10, 2014
  60. 11/32 $GIT_COMMON_DIR: a new environment variableNguyễn Thái Ngọc Duy, Sep 10, 2014
  61. 12/32 git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objectsNguyễn Thái Ngọc Duy, Sep 10, 2014
  62. 13/32 *.sh: avoid hardcoding $GIT_DIR/hooks/...Nguyễn Thái Ngọc Duy, Sep 10, 2014
  63. 14/32 git-stash: avoid hardcoding $GIT_DIR/logs/....Nguyễn Thái Ngọc Duy, Sep 10, 2014
  64. 15/32 setup.c: convert is_git_directory() to use strbufNguyễn Thái Ngọc Duy, Sep 10, 2014
  65. 16/32 setup.c: detect $GIT_COMMON_DIR in is_git_directory()Nguyễn Thái Ngọc Duy, Sep 10, 2014
  66. 17/32 setup.c: convert check_repository_format_gently to use strbufNguyễn Thái Ngọc Duy, Sep 10, 2014
  67. 18/32 setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()Nguyễn Thái Ngọc Duy, Sep 10, 2014
  68. 19/32 setup.c: support multi-checkout repo setupNguyễn Thái Ngọc Duy, Sep 10, 2014
  69. 20/32 wrapper.c: wrapper to open a file, fprintf then closeNguyễn Thái Ngọc Duy, Sep 10, 2014
  70. 21/32 use new wrapper write_file() for simple file writingNguyễn Thái Ngọc Duy, Sep 10, 2014
  71. 22/32 checkout: support checking out into a new working directoryNguyễn Thái Ngọc Duy, Sep 10, 2014
  72. Marc BranchaudSep 11, 2014
  73. Duy NguyenSep 21, 2014
  74. Eric SunshineSep 21, 2014
  75. Duy NguyenSep 21, 2014
  76. Marc BranchaudSep 22, 2014
  77. Eric SunshineSep 22, 2014
  78. 23/32 prune: strategies for linked checkoutsNguyễn Thái Ngọc Duy, Sep 10, 2014
  79. Marc BranchaudSep 11, 2014
  80. Eric SunshineSep 12, 2014
  81. Marc BranchaudSep 12, 2014
  82. Duy NguyenSep 21, 2014
  83. Eric SunshineSep 21, 2014
  84. Duy NguyenSep 21, 2014
  85. Marc BranchaudSep 22, 2014
  86. Eric SunshineSep 22, 2014
  87. 24/32 checkout: reject if the branch is already checked out elsewhereNguyễn Thái Ngọc Duy, Sep 10, 2014
  88. 25/32 checkout: clean up half-prepared directories in --to modeNguyễn Thái Ngọc Duy, Sep 10, 2014
  89. 26/32 gc: style change -- no SP before closing parenthesisNguyễn Thái Ngọc Duy, Sep 10, 2014
  90. 27/32 gc: factor out gc.pruneexpire parsing codeNguyễn Thái Ngọc Duy, Sep 10, 2014
  91. 28/32 gc: support prune --worktreesNguyễn Thái Ngọc Duy, Sep 10, 2014
  92. Duy NguyenSep 21, 2014
  93. Marc BranchaudSep 22, 2014
  94. 29/32 count-objects: report unused files in $GIT_DIR/worktrees/...Nguyễn Thái Ngọc Duy, Sep 10, 2014
  95. 30/32 git_path(): keep "info/sparse-checkout" per work-treeNguyễn Thái Ngọc Duy, Sep 10, 2014
  96. 31/32 checkout: don't require a work tree when checking out into a new oneNguyễn Thái Ngọc Duy, Sep 10, 2014
  97. 32/32 t2025: add a test to make sure grafts is working from a linked checkoutNguyễn Thái Ngọc Duy, Sep 10, 2014
  98. Junio C HamanoSep 25, 2014
  99. 00/32 nd/multiple-work-treesNguyễn Thái Ngọc Duy, Sep 28, 2014
  100. 01/32 path.c: make get_pathname() return strbuf instead of static bufferNguyễn Thái Ngọc Duy, Sep 28, 2014
  101. 02/32 path.c: make get_pathname() call sites return const char *Nguyễn Thái Ngọc Duy, Sep 28, 2014
  102. 03/32 git_snpath(): retire and replace with strbuf_git_path()Nguyễn Thái Ngọc Duy, Sep 28, 2014
  103. 04/32 path.c: rename vsnpath() to do_git_path()Nguyễn Thái Ngọc Duy, Sep 28, 2014
  104. 05/32 path.c: group git_path(), git_pathdup() and strbuf_git_path() togetherNguyễn Thái Ngọc Duy, Sep 28, 2014
  105. 06/32 git_path(): be aware of file relocation in $GIT_DIRNguyễn Thái Ngọc Duy, Sep 28, 2014
  106. 07/32 *.sh: respect $GIT_INDEX_FILENguyễn Thái Ngọc Duy, Sep 28, 2014
  107. 08/32 reflog: avoid constructing .lock path with git_pathNguyễn Thái Ngọc Duy, Sep 28, 2014
  108. 09/32 fast-import: use git_path() for accessing .git dir instead of get_git_dir()Nguyễn Thái Ngọc Duy, Sep 28, 2014
  109. 10/32 commit: use SEQ_DIR instead of hardcoding "sequencer"Nguyễn Thái Ngọc Duy, Sep 28, 2014
  110. 11/32 $GIT_COMMON_DIR: a new environment variableNguyễn Thái Ngọc Duy, Sep 28, 2014
  111. 12/32 git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objectsNguyễn Thái Ngọc Duy, Sep 28, 2014
  112. 13/32 *.sh: avoid hardcoding $GIT_DIR/hooks/...Nguyễn Thái Ngọc Duy, Sep 28, 2014
  113. 14/32 git-stash: avoid hardcoding $GIT_DIR/logs/....Nguyễn Thái Ngọc Duy, Sep 28, 2014
  114. 15/32 setup.c: convert is_git_directory() to use strbufNguyễn Thái Ngọc Duy, Sep 28, 2014
  115. 16/32 setup.c: detect $GIT_COMMON_DIR in is_git_directory()Nguyễn Thái Ngọc Duy, Sep 28, 2014
  116. 17/32 setup.c: convert check_repository_format_gently to use strbufNguyễn Thái Ngọc Duy, Sep 28, 2014
  117. 18/32 setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()Nguyễn Thái Ngọc Duy, Sep 28, 2014
  118. 19/32 setup.c: support multi-checkout repo setupNguyễn Thái Ngọc Duy, Sep 28, 2014
  119. Johannes SixtOct 1, 2014
  120. 20/32 wrapper.c: wrapper to open a file, fprintf then closeNguyễn Thái Ngọc Duy, Sep 28, 2014
  121. 21/32 use new wrapper write_file() for simple file writingNguyễn Thái Ngọc Duy, Sep 28, 2014
  122. 22/32 checkout: support checking out into a new working directoryNguyễn Thái Ngọc Duy, Sep 28, 2014
  123. 23/32 prune: strategies for linked checkoutsNguyễn Thái Ngọc Duy, Sep 28, 2014
  124. Johannes SixtOct 1, 2014
  125. 24/32 checkout: reject if the branch is already checked out elsewhereNguyễn Thái Ngọc Duy, Sep 28, 2014
  126. 25/32 checkout: clean up half-prepared directories in --to modeNguyễn Thái Ngọc Duy, Sep 28, 2014
  127. 26/32 gc: style change -- no SP before closing parenthesisNguyễn Thái Ngọc Duy, Sep 28, 2014
  128. 27/32 gc: factor out gc.pruneexpire parsing codeNguyễn Thái Ngọc Duy, Sep 28, 2014
  129. 28/32 gc: support prune --worktreesNguyễn Thái Ngọc Duy, Sep 28, 2014
  130. 29/32 count-objects: report unused files in $GIT_DIR/worktrees/...Nguyễn Thái Ngọc Duy, Sep 28, 2014
  131. 30/32 git_path(): keep "info/sparse-checkout" per work-treeNguyễn Thái Ngọc Duy, Sep 28, 2014
  132. 31/32 checkout: don't require a work tree when checking out into a new oneNguyễn Thái Ngọc Duy, Sep 28, 2014
  133. 32/32 t2025: add a test to make sure grafts is working from a linked checkoutNguyễn Thái Ngọc Duy, Sep 28, 2014
  134. Junio C HamanoSep 28, 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.