Re: [PATCH v7 11/31] $GIT_COMMON_DIR: a new environment variable

2014-07-22 Thread Eric Sunshine
On Sun, Jul 13, 2014 at 12:50 AM, Nguyễn Thái Ngọc Duy
pclo...@gmail.com wrote:
 This variable is intended to support multiple working directories
 attached to a repository. Such a repository may have a main working
 directory, created by either git init or git clone and one or more
 linked working directories. These working directories and the main
 repository share the same repository directory.

 Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
 ---
 diff --git a/Documentation/gitrepository-layout.txt 
 b/Documentation/gitrepository-layout.txt
 index 17d2ea6..7629e38 100644
 --- a/Documentation/gitrepository-layout.txt
 +++ b/Documentation/gitrepository-layout.txt
 @@ -133,6 +138,11 @@ being a symref to point at the current branch.  Such a 
 state
  is often called 'detached HEAD.'  See linkgit:git-checkout[1]
  for details.

 +config::
 +   Repository specific configuration file. This file is ignored

s/ignored/ignored if/

 +   $GIT_COMMON_DIR is set and $GIT_COMMON_DIR/config will be
 +   used instead.
 +
  branches::
 A slightly deprecated way to store shorthands to be used
 to specify a URL to 'git fetch', 'git pull' and 'git push'.
 diff --git a/environment.c b/environment.c
 index fee12a6..6b74f68 100644
 --- a/environment.c
 +++ b/environment.c
 @@ -149,9 +149,18 @@ static void setup_git_env(void)
 git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
 gitfile = read_gitfile(git_dir);
 git_dir = xstrdup(gitfile ? gitfile : git_dir);
 -   git_object_dir = git_path_from_env(DB_ENVIRONMENT, objects, 
 git_db_env);
 -   git_index_file = git_path_from_env(INDEX_ENVIRONMENT, index, 
 git_index_env);
 -   git_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, info/grafts, 
 git_graft_env);
 +   git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
 +   if (git_common_dir) {
 +   git_common_dir_env = 1;
 +   git_common_dir = xstrdup(git_common_dir);
 +   } else
 +   git_common_dir = git_dir;
 +   git_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir,
 +  objects, git_db_env);
 +   git_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir,
 +  index, git_index_env);
 +   git_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, git_dir,
 +  info/grafts, git_graft_env);

Replacement refs come from git_common_dir, but grafts come from
git_dir. Is the inconsistency intentional?

 if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
 check_replace_refs = 0;
 namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
 diff --git a/path.c b/path.c
 index 3deb80c..8a6586c 100644
 --- a/path.c
 +++ b/path.c
 @@ -90,6 +90,38 @@ static void replace_dir(struct strbuf *buf, int len, const 
 char *newdir)
 buf-buf[newlen] = '/';
  }

 +static const char *common_list[] = {
 +   /branches, /hooks, /info, /logs, /lost-found, /modules,
 +   /objects, /refs, /remotes, /rr-cache, /svn,
 +   config, gc.pid, packed-refs, shallow,
 +   NULL
 +};
 +
 +static void update_common_dir(struct strbuf *buf, int git_dir_len)
 +{
 +   char *base = buf-buf + git_dir_len;
 +   const char **p;
 +
 +   if (is_dir_file(base, logs, HEAD))
 +   return; /* keep this in $GIT_DIR */
 +   for (p = common_list; *p; p++) {
 +   const char *path = *p;
 +   int is_dir = 0;
 +   if (*path == '/') {
 +   path++;
 +   is_dir = 1;
 +   }
 +   if (is_dir  dir_prefix(base, path)) {
 +   replace_dir(buf, git_dir_len, get_git_common_dir());
 +   return;
 +   }
 +   if (!is_dir  !strcmp(base, path)) {
 +   replace_dir(buf, git_dir_len, get_git_common_dir());
 +   return;
 +   }

The bodies of these two conditionals are identical. Would it make
sense to combine them (or does a later patch take advantage of the
distinction)?

if ((is_dir  dir_prefix(base, path)) ||
   (!is_dir  !strcmp(base, path))) {
replace_dir(buf, git_dir_len, get_git_common_dir());
return;
}

 +   }
 +}
 +
  static void adjust_git_path(struct strbuf *buf, int git_dir_len)
  {
 const char *base = buf-buf + git_dir_len;
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 11/31] $GIT_COMMON_DIR: a new environment variable

2014-07-12 Thread Nguyễn Thái Ngọc Duy
This variable is intended to support multiple working directories
attached to a repository. Such a repository may have a main working
directory, created by either git init or git clone and one or more
linked working directories. These working directories and the main
repository share the same repository directory.

In linked working directories, $GIT_COMMON_DIR must be defined to point
to the real repository directory and $GIT_DIR points to an unused
subdirectory inside $GIT_COMMON_DIR. File locations inside the
repository are reorganized from the linked worktree view point:

 - worktree-specific such as HEAD, logs/HEAD, index, other top-level
   refs and unrecognized files are from $GIT_DIR.

 - the rest like objects, refs, info, hooks, packed-refs, shallow...
   are from $GIT_COMMON_DIR (except info/sparse-checkout, but that's
   a separate patch)

Scripts are supposed to retrieve paths in $GIT_DIR with git rev-parse
--git-path, which will take care of $GIT_DIR vs $GIT_COMMON_DIR
business.

The redirection is done by git_path(), git_pathdup() and
strbuf_git_path(). The selected list of paths goes to $GIT_COMMON_DIR,
not the other way around in case a developer adds a new
worktree-specific file and it's accidentally promoted to be shared
across repositories (this includes unknown files added by third party
commands)

The list of known files that belong to $GIT_DIR are:

ADD_EDIT.patch BISECT_ANCESTORS_OK BISECT_EXPECTED_REV BISECT_LOG
BISECT_NAMES CHERRY_PICK_HEAD COMMIT_MSG FETCH_HEAD HEAD MERGE_HEAD
MERGE_MODE MERGE_RR NOTES_EDITMSG NOTES_MERGE_WORKTREE ORIG_HEAD
REVERT_HEAD SQUASH_MSG TAG_EDITMSG fast_import_crash_* logs/HEAD
next-index-* rebase-apply rebase-merge rsync-refs-* sequencer/*
shallow_*

Path mapping is NOT done for git_path_submodule(). Multi-checkouts are
not supported as submodules.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 Documentation/git.txt  |  8 +++
 Documentation/gitrepository-layout.txt | 42 ++
 cache.h|  4 +++-
 environment.c  | 28 +--
 path.c | 34 +++
 t/t0060-path-utils.sh  | 15 
 6 files changed, 114 insertions(+), 17 deletions(-)

diff --git a/Documentation/git.txt b/Documentation/git.txt
index 7924209..749052f 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -788,6 +788,14 @@ Git so take care if using Cogito etc.
an explicit repository directory set via 'GIT_DIR' or on the
command line.
 
+'GIT_COMMON_DIR'::
+   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
+   details. This variable has lower precedence than other path
+   variables such as GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY...
+
 Git Commits
 ~~~
 'GIT_AUTHOR_NAME'::
diff --git a/Documentation/gitrepository-layout.txt 
b/Documentation/gitrepository-layout.txt
index 17d2ea6..7629e38 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -46,6 +46,9 @@ of incomplete object store is not suitable to be published for
 use with dumb transports but otherwise is OK as long as
 `objects/info/alternates` points at the object stores it
 borrows from.
++
+This directory is ignored if $GIT_COMMON_DIR is set and
+$GIT_COMMON_DIR/objects will be used instead.
 
 objects/[0-9a-f][0-9a-f]::
A newly created object is stored in its own file.
@@ -92,7 +95,8 @@ refs::
References are stored in subdirectories of this
directory.  The 'git prune' command knows to preserve
objects reachable from refs found in this directory and
-   its subdirectories.
+   its subdirectories. This directory is ignored if $GIT_COMMON_DIR
+   is set and $GIT_COMMON_DIR/refs will be used instead.
 
 refs/heads/`name`::
records tip-of-the-tree commit objects of branch `name`
@@ -114,7 +118,8 @@ refs/replace/`obj-sha1`::
 packed-refs::
records the same information as refs/heads/, refs/tags/,
and friends record in a more efficient way.  See
-   linkgit:git-pack-refs[1].
+   linkgit:git-pack-refs[1]. This file is ignored if $GIT_COMMON_DIR
+   is set and $GIT_COMMON_DIR/packed-refs will be used instead.
 
 HEAD::
A symref (see glossary) to the `refs/heads/` namespace
@@ -133,6 +138,11 @@ being a symref to point at the current branch.  Such a 
state
 is often called 'detached HEAD.'  See linkgit:git-checkout[1]
 for details.
 
+config::
+   Repository specific configuration file. This file is ignored
+   $GIT_COMMON_DIR is set and $GIT_COMMON_DIR/config will be
+   used instead.
+
 branches::
A slightly deprecated way to store