[GIT PULL] some updates from German l10n team

2014-09-27 Thread Jiang Xin
Hi Junio,

Please pull German l10n updates to the maint branch, and
merge them back to the master branch later.

The following changes since commit 96db324a73fdada6fbe7b63221986f8f18cc63b0:

  Merge git://github.com/git-l10n/git-po (2014-08-29 10:18:22 -0700)

are available in the git repository at:

  git://github.com/git-l10n/git-po maint

for you to fetch changes up to 061540fcf7a4dba5392462bc5b07d6c12d3afc61:

  l10n: de.po: use comma before um (2014-09-25 20:26:27 +0200)


Phillip Sz (2):
  l10n: de.po: change Email to E-Mail
  l10n: de.po: use comma before um

Ralf Thielow (1):
  po/TEAMS: add new member to German translation team

 po/TEAMS |   1 +
 po/de.po | 100 +++
 2 files changed, 51 insertions(+), 50 deletions(-)
--
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] init - Honour the global core.filemode setting

2014-09-27 Thread Hilco Wijbenga
If ~/.gitconfig contains a core.filemode entry then git init
should honour that setting.

Signed-off-by: Hilco Wijbenga hilco.wijbe...@gmail.com
---
This bit me at work where I have to work with Windows. Git on Cygwin
and the Eclipse Git plugin do not agree on file attributes so I had
set filemode = false in ~/.gitconfig.

A few weeks later, I did a git init and, some time later yet, I
noticed the strange behaviour of Cygwin/Eclipse again. This was very
surprising because things had been working well until then. It took
quite a bit of research before I realized that git init always sets
filemode. I think filemode should only be set if not set already
in the global config (similar to log_all_ref_updates).

The usual caveat applies: this is my first patch. Having said that,
please feel free to be pedantic and strict. It's a small patch so I
would imagine that fixing any problems should not take long (assuming
it is acceptable at all, of course). I'd like to know I did it right.
:-)

AFAICT, all tests passed. Should a separate test be added for this change?

(I used git format-patch and git imap-send to send this patch to
the ML but looking below I still do not see tabs? In fact, I do not
see any indentation.)
 builtin/init-db.c | 19 +++
 environment.c |  2 +-
 2 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index 56f85e2..19cdc58 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -248,15 +248,18 @@ static int create_default_files(const char *template_path)
  path[len] = 0;
  strcpy(path + len, config);

- /* Check filemode trustability */
- filemode = TEST_FILEMODE;
- if (TEST_FILEMODE  !lstat(path, st1)) {
- struct stat st2;
- filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) 
- !lstat(path, st2) 
- st1.st_mode != st2.st_mode);
+ /* Do not override the global filemode setting. */
+ if (trust_executable_bit == -1) {
+ /* Check filemode trustability */
+ filemode = TEST_FILEMODE;
+ if (TEST_FILEMODE  !lstat(path, st1)) {
+ struct stat st2;
+ filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) 
+ !lstat(path, st2) 
+ st1.st_mode != st2.st_mode);
+ }
+ git_config_set(core.filemode, filemode ? true : false);
  }
- git_config_set(core.filemode, filemode ? true : false);

  if (is_bare_repository())
  git_config_set(core.bare, true);
diff --git a/environment.c b/environment.c
index 565f652..875a498 100644
--- a/environment.c
+++ b/environment.c
@@ -12,7 +12,7 @@
 #include fmt-merge-msg.h
 #include commit.h

-int trust_executable_bit = 1;
+int trust_executable_bit = -1;
 int trust_ctime = 1;
 int check_stat = 1;
 int has_symlinks = 1;
-- 
2.1.1.dirty
--
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 v3 00/32] nd/multiple-work-trees

2014-09-27 Thread Nguyễn Thái Ngọc Duy
On Fri, Sep 26, 2014 at 4:20 AM, Junio C Hamano gits...@pobox.com wrote:
 It has been a while since the last review exchanges were seen.  Will
 it be time for v3 soon?

Sorry I've been slow on picking up feedback from v2. v3 is rebased on
latest master. Other changes are mostly *.txt, and one broken 
chain.

Dennis Kaarsemaker (1):
  checkout: don't require a work tree when checking out into a new one

Nguyễn Thái Ngọc Duy (31):
  path.c: make get_pathname() return strbuf instead of static buffer
  path.c: make get_pathname() call sites return const char *
  git_snpath(): retire and replace with strbuf_git_path()
  path.c: rename vsnpath() to do_git_path()
  path.c: group git_path(), git_pathdup() and strbuf_git_path() together
  git_path(): be aware of file relocation in $GIT_DIR
  *.sh: respect $GIT_INDEX_FILE
  reflog: avoid constructing .lock path with git_path
  fast-import: use git_path() for accessing .git dir instead of get_git_dir()
  commit: use SEQ_DIR instead of hardcoding sequencer
  $GIT_COMMON_DIR: a new environment variable
  git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objects
  *.sh: avoid hardcoding $GIT_DIR/hooks/...
  git-stash: avoid hardcoding $GIT_DIR/logs/
  setup.c: convert is_git_directory() to use strbuf
  setup.c: detect $GIT_COMMON_DIR in is_git_directory()
  setup.c: convert check_repository_format_gently to use strbuf
  setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()
  setup.c: support multi-checkout repo setup
  wrapper.c: wrapper to open a file, fprintf then close
  use new wrapper write_file() for simple file writing
  checkout: support checking out into a new working directory
  prune: strategies for linked checkouts
  checkout: reject if the branch is already checked out elsewhere
  checkout: clean up half-prepared directories in --to mode
  gc: style change -- no SP before closing parenthesis
  gc: factor out gc.pruneexpire parsing code
  gc: support prune --worktrees
  count-objects: report unused files in $GIT_DIR/worktrees/...
  git_path(): keep info/sparse-checkout per work-tree
  t2025: add a test to make sure grafts is working from a linked checkout

 Documentation/config.txt   |   9 +
 Documentation/git-checkout.txt |  69 
 Documentation/git-prune.txt|   3 +
 Documentation/git-rev-parse.txt|  10 ++
 Documentation/git.txt  |   9 +
 Documentation/gitrepository-layout.txt |  78 +++--
 builtin/branch.c   |   4 +-
 builtin/checkout.c | 260 -
 builtin/clone.c|   9 +-
 builtin/commit.c   |   2 +-
 builtin/count-objects.c|   4 +-
 builtin/fetch.c|   5 +-
 builtin/fsck.c |   4 +-
 builtin/gc.c   |  34 ++--
 builtin/init-db.c  |   7 +-
 builtin/prune.c|  95 +++
 builtin/receive-pack.c |   2 +-
 builtin/reflog.c   |   2 +-
 builtin/remote.c   |   2 +-
 builtin/repack.c   |   8 +-
 builtin/rev-parse.c|  11 ++
 cache.h|  17 +-
 daemon.c   |  11 +-
 environment.c  |  33 +++-
 fast-import.c  |   7 +-
 git-am.sh  |  22 +--
 git-pull.sh|   2 +-
 git-rebase--interactive.sh |   6 +-
 git-rebase--merge.sh   |   6 +-
 git-rebase.sh  |   4 +-
 git-sh-setup.sh|   2 +-
 git-stash.sh   |   6 +-
 git.c  |   2 +-
 notes-merge.c  |   6 +-
 path.c | 234 +-
 refs.c |  86 ++
 refs.h |   2 +-
 run-command.c  |   4 +-
 run-command.h  |   2 +-
 setup.c| 124 +++---
 sha1_file.c|   2 +-
 submodule.c|   9 +-
 t/t0060-path-utils.sh  |  36 
 t/t1501-worktree.sh|  76 +
 t/t1510-repo-setup.sh  |   1 +
 t/t2025-checkout-to.sh (new +x)| 117 +
 t/t2026-prune-linked-checkouts.sh (new +x) |  84 ++
 templates/hooks--applypatch-msg.sample |   4 +-
 templates/hooks--pre-applypatch.sample |   4 +-
 trace.c|   1 +
 transport.c|   8 +-
 

[PATCH v3 03/32] git_snpath(): retire and replace with strbuf_git_path()

2014-09-27 Thread Nguyễn Thái Ngọc Duy
In the previous patch, git_snpath() is modified to allocate a new
strbuf buffer because vsnpath() needs that. But that makes it
awkward because git_snpath() receives a pre-allocated buffer from
outside and has to copy data back. Rename it to strbuf_git_path()
and make it receive strbuf directly.

Using git_path() in update_refs_for_switch() which used to call
git_snpath() is safe because that function and all of its callers do
not keep any pointer to the round-robin buffer pool allocated by
get_pathname().

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 builtin/checkout.c | 13 +
 cache.h|  4 +--
 path.c | 11 ++--
 refs.c | 78 +-
 refs.h |  2 +-
 5 files changed, 61 insertions(+), 47 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index d402d7a..220f80e 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -588,18 +588,21 @@ static void update_refs_for_switch(const struct 
checkout_opts *opts,
if (opts-new_orphan_branch) {
if (opts-new_branch_log  !log_all_ref_updates) {
int temp;
-   char log_file[PATH_MAX];
-   const char *ref_name = mkpath(refs/heads/%s, 
opts-new_orphan_branch);
+   struct strbuf log_file = STRBUF_INIT;
+   int ret;
+   const char *ref_name;
 
+   ref_name = mkpath(refs/heads/%s, 
opts-new_orphan_branch);
temp = log_all_ref_updates;
log_all_ref_updates = 1;
-   if (log_ref_setup(ref_name, log_file, 
sizeof(log_file))) {
+   ret = log_ref_setup(ref_name, log_file);
+   log_all_ref_updates = temp;
+   strbuf_release(log_file);
+   if (ret) {
fprintf(stderr, _(Can not do reflog 
for '%s'\n),
opts-new_orphan_branch);
-   log_all_ref_updates = temp;
return;
}
-   log_all_ref_updates = temp;
}
}
else
diff --git a/cache.h b/cache.h
index 2e4d88f..f487c0e 100644
--- a/cache.h
+++ b/cache.h
@@ -697,8 +697,8 @@ extern int check_repository_format(void);
 
 extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
-extern char *git_snpath(char *buf, size_t n, const char *fmt, ...)
-   __attribute__((format (printf, 3, 4)));
+extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
+   __attribute__((format (printf, 2, 3)));
 extern char *git_pathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2)));
 extern char *mkpathdup(const char *fmt, ...)
diff --git a/path.c b/path.c
index a7ceea2..47753aa 100644
--- a/path.c
+++ b/path.c
@@ -70,19 +70,12 @@ static void vsnpath(struct strbuf *buf, const char *fmt, 
va_list args)
strbuf_cleanup_path(buf);
 }
 
-char *git_snpath(char *buf, size_t n, const char *fmt, ...)
+void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
 {
-   struct strbuf sb = STRBUF_INIT;
va_list args;
va_start(args, fmt);
-   vsnpath(sb, fmt, args);
+   vsnpath(sb, fmt, args);
va_end(args);
-   if (sb.len = n)
-   strlcpy(buf, bad_path, n);
-   else
-   memcpy(buf, sb.buf, sb.len + 1);
-   strbuf_release(sb);
-   return buf;
 }
 
 char *git_pathdup(const char *fmt, ...)
diff --git a/refs.c b/refs.c
index f616adc..3cefbd3 100644
--- a/refs.c
+++ b/refs.c
@@ -1400,10 +1400,12 @@ 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)
 {
+   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;
@@ -1414,17 +1416,19 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
}
 
for (;;) {
-   char path[PATH_MAX];
+   const char *path;
struct stat st;
char *buf;
int fd;
 
if (--depth  0) {
errno = ELOOP;
-   return NULL;
+   goto fail;
}
 
-   

[PATCH v3 07/32] *.sh: respect $GIT_INDEX_FILE

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 git-pull.sh  | 2 +-
 git-stash.sh | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/git-pull.sh b/git-pull.sh
index 4d4fc77..ad44226 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -240,7 +240,7 @@ test true = $rebase  {
if ! git rev-parse -q --verify HEAD /dev/null
then
# On an unborn branch
-   if test -f $GIT_DIR/index
+   if test -f $(git rev-parse --git-path index)
then
die $(gettext updating an unborn branch with changes 
added to the index)
fi
diff --git a/git-stash.sh b/git-stash.sh
index 0158c73..4294aa0 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -20,7 +20,7 @@ require_work_tree
 cd_to_toplevel
 
 TMP=$GIT_DIR/.git-stash.$$
-TMPindex=${GIT_INDEX_FILE-$GIT_DIR/index}.stash.$$
+TMPindex=${GIT_INDEX_FILE-$(git rev-parse --git-path index)}.stash.$$
 trap 'rm -f $TMP-* $TMPindex' 0
 
 ref_stash=refs/stash
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 04/32] path.c: rename vsnpath() to do_git_path()

2014-09-27 Thread Nguyễn Thái Ngọc Duy
The name vsnpath() gives an impression that this is general path
handling function. It's not. This is the underlying implementation of
git_path(), git_pathdup() and strbuf_git_path() which will prefix
$GIT_DIR in the result string.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 path.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/path.c b/path.c
index 47753aa..6991103 100644
--- a/path.c
+++ b/path.c
@@ -60,7 +60,7 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...)
return cleanup_path(buf);
 }
 
-static void vsnpath(struct strbuf *buf, const char *fmt, va_list args)
+static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)
 {
const char *git_dir = get_git_dir();
strbuf_addstr(buf, git_dir);
@@ -74,7 +74,7 @@ void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
 {
va_list args;
va_start(args, fmt);
-   vsnpath(sb, fmt, args);
+   do_git_path(sb, fmt, args);
va_end(args);
 }
 
@@ -83,7 +83,7 @@ char *git_pathdup(const char *fmt, ...)
struct strbuf path = STRBUF_INIT;
va_list args;
va_start(args, fmt);
-   vsnpath(path, fmt, args);
+   do_git_path(path, fmt, args);
va_end(args);
return strbuf_detach(path, NULL);
 }
@@ -114,7 +114,7 @@ const char *git_path(const char *fmt, ...)
struct strbuf *pathname = get_pathname();
va_list args;
va_start(args, fmt);
-   vsnpath(pathname, fmt, args);
+   do_git_path(pathname, fmt, args);
va_end(args);
return pathname-buf;
 }
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 01/32] path.c: make get_pathname() return strbuf instead of static buffer

2014-09-27 Thread Nguyễn Thái Ngọc Duy
We've been avoiding PATH_MAX whenever possible. This patch makes
get_pathname() return a strbuf and updates the callers to take
advantage of this. The code is simplified as we no longer need to
worry about buffer overflow.

vsnpath() behavior is changed slightly: previously it always clears
the buffer before writing, now it just appends. Fortunately this is a
static function and all of its callers prepare the buffer properly:
git_path() gets the buffer from get_pathname() which resets the
buffer, the remaining call sites start with STRBUF_INIT'd buffer.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 path.c | 120 -
 1 file changed, 51 insertions(+), 69 deletions(-)

diff --git a/path.c b/path.c
index f68df0c..015c0e4 100644
--- a/path.c
+++ b/path.c
@@ -16,11 +16,15 @@ static int get_st_mode_bits(const char *path, int *mode)
 
 static char bad_path[] = /bad-path/;
 
-static char *get_pathname(void)
+static struct strbuf *get_pathname(void)
 {
-   static char pathname_array[4][PATH_MAX];
+   static struct strbuf pathname_array[4] = {
+   STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+   };
static int index;
-   return pathname_array[3  ++index];
+   struct strbuf *sb = pathname_array[3  ++index];
+   strbuf_reset(sb);
+   return sb;
 }
 
 static char *cleanup_path(char *path)
@@ -34,6 +38,13 @@ static char *cleanup_path(char *path)
return path;
 }
 
+static void strbuf_cleanup_path(struct strbuf *sb)
+{
+   char *path = cleanup_path(sb-buf);
+   if (path  sb-buf)
+   strbuf_remove(sb, 0, path - sb-buf);
+}
+
 char *mksnpath(char *buf, size_t n, const char *fmt, ...)
 {
va_list args;
@@ -49,85 +60,70 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...)
return cleanup_path(buf);
 }
 
-static char *vsnpath(char *buf, size_t n, const char *fmt, va_list args)
+static void vsnpath(struct strbuf *buf, const char *fmt, va_list args)
 {
const char *git_dir = get_git_dir();
-   size_t len;
-
-   len = strlen(git_dir);
-   if (n  len + 1)
-   goto bad;
-   memcpy(buf, git_dir, len);
-   if (len  !is_dir_sep(git_dir[len-1]))
-   buf[len++] = '/';
-   len += vsnprintf(buf + len, n - len, fmt, args);
-   if (len = n)
-   goto bad;
-   return cleanup_path(buf);
-bad:
-   strlcpy(buf, bad_path, n);
-   return buf;
+   strbuf_addstr(buf, git_dir);
+   if (buf-len  !is_dir_sep(buf-buf[buf-len - 1]))
+   strbuf_addch(buf, '/');
+   strbuf_vaddf(buf, fmt, args);
+   strbuf_cleanup_path(buf);
 }
 
 char *git_snpath(char *buf, size_t n, const char *fmt, ...)
 {
-   char *ret;
+   struct strbuf sb = STRBUF_INIT;
va_list args;
va_start(args, fmt);
-   ret = vsnpath(buf, n, fmt, args);
+   vsnpath(sb, fmt, args);
va_end(args);
-   return ret;
+   if (sb.len = n)
+   strlcpy(buf, bad_path, n);
+   else
+   memcpy(buf, sb.buf, sb.len + 1);
+   strbuf_release(sb);
+   return buf;
 }
 
 char *git_pathdup(const char *fmt, ...)
 {
-   char path[PATH_MAX], *ret;
+   struct strbuf path = STRBUF_INIT;
va_list args;
va_start(args, fmt);
-   ret = vsnpath(path, sizeof(path), fmt, args);
+   vsnpath(path, fmt, args);
va_end(args);
-   return xstrdup(ret);
+   return strbuf_detach(path, NULL);
 }
 
 char *mkpathdup(const char *fmt, ...)
 {
-   char *path;
struct strbuf sb = STRBUF_INIT;
va_list args;
-
va_start(args, fmt);
strbuf_vaddf(sb, fmt, args);
va_end(args);
-   path = xstrdup(cleanup_path(sb.buf));
-
-   strbuf_release(sb);
-   return path;
+   strbuf_cleanup_path(sb);
+   return strbuf_detach(sb, NULL);
 }
 
 char *mkpath(const char *fmt, ...)
 {
va_list args;
-   unsigned len;
-   char *pathname = get_pathname();
-
+   struct strbuf *pathname = get_pathname();
va_start(args, fmt);
-   len = vsnprintf(pathname, PATH_MAX, fmt, args);
+   strbuf_vaddf(pathname, fmt, args);
va_end(args);
-   if (len = PATH_MAX)
-   return bad_path;
-   return cleanup_path(pathname);
+   return cleanup_path(pathname-buf);
 }
 
 char *git_path(const char *fmt, ...)
 {
-   char *pathname = get_pathname();
+   struct strbuf *pathname = get_pathname();
va_list args;
-   char *ret;
-
va_start(args, fmt);
-   ret = vsnpath(pathname, PATH_MAX, fmt, args);
+   vsnpath(pathname, fmt, args);
va_end(args);
-   return ret;
+   return pathname-buf;
 }
 
 void home_config_paths(char **global, char **xdg, char *file)
@@ -160,41 +156,27 @@ void home_config_paths(char **global, char **xdg, char 
*file)
 
 char 

[PATCH v3 05/32] path.c: group git_path(), git_pathdup() and strbuf_git_path() together

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 path.c | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/path.c b/path.c
index 6991103..df0f75b 100644
--- a/path.c
+++ b/path.c
@@ -78,6 +78,16 @@ void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
va_end(args);
 }
 
+const char *git_path(const char *fmt, ...)
+{
+   struct strbuf *pathname = get_pathname();
+   va_list args;
+   va_start(args, fmt);
+   do_git_path(pathname, fmt, args);
+   va_end(args);
+   return pathname-buf;
+}
+
 char *git_pathdup(const char *fmt, ...)
 {
struct strbuf path = STRBUF_INIT;
@@ -109,16 +119,6 @@ const char *mkpath(const char *fmt, ...)
return cleanup_path(pathname-buf);
 }
 
-const char *git_path(const char *fmt, ...)
-{
-   struct strbuf *pathname = get_pathname();
-   va_list args;
-   va_start(args, fmt);
-   do_git_path(pathname, fmt, args);
-   va_end(args);
-   return pathname-buf;
-}
-
 void home_config_paths(char **global, char **xdg, char *file)
 {
char *xdg_home = getenv(XDG_CONFIG_HOME);
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 02/32] path.c: make get_pathname() call sites return const char *

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Before the previous commit, get_pathname returns an array of PATH_MAX
length. Even if git_path() and similar functions does not use the
whole array, git_path() caller can, in theory.

After the commit, get_pathname() may return a buffer that has just
enough room for the returned string and git_path() caller should never
write beyond that.

Make git_path(), mkpath() and git_path_submodule() return a const
buffer to make sure callers do not write in it at all.

This could have been part of the previous commit, but the const
conversion is too much distraction from the core changes in path.c.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 builtin/checkout.c | 2 +-
 builtin/clone.c| 9 +
 builtin/fetch.c| 5 +++--
 builtin/fsck.c | 4 ++--
 builtin/receive-pack.c | 2 +-
 builtin/remote.c   | 2 +-
 builtin/repack.c   | 8 +---
 cache.h| 6 +++---
 fast-import.c  | 2 +-
 notes-merge.c  | 6 +++---
 path.c | 6 +++---
 refs.c | 8 
 run-command.c  | 4 ++--
 run-command.h  | 2 +-
 sha1_file.c| 2 +-
 15 files changed, 36 insertions(+), 32 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 8afdf2b..d402d7a 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -589,7 +589,7 @@ static void update_refs_for_switch(const struct 
checkout_opts *opts,
if (opts-new_branch_log  !log_all_ref_updates) {
int temp;
char log_file[PATH_MAX];
-   char *ref_name = mkpath(refs/heads/%s, 
opts-new_orphan_branch);
+   const char *ref_name = mkpath(refs/heads/%s, 
opts-new_orphan_branch);
 
temp = log_all_ref_updates;
log_all_ref_updates = 1;
diff --git a/builtin/clone.c b/builtin/clone.c
index 3927edf..180bc89 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -289,16 +289,17 @@ static void copy_alternates(struct strbuf *src, struct 
strbuf *dst,
struct strbuf line = STRBUF_INIT;
 
while (strbuf_getline(line, in, '\n') != EOF) {
-   char *abs_path, abs_buf[PATH_MAX];
+   char *abs_path;
if (!line.len || line.buf[0] == '#')
continue;
if (is_absolute_path(line.buf)) {
add_to_alternates_file(line.buf);
continue;
}
-   abs_path = mkpath(%s/objects/%s, src_repo, line.buf);
-   normalize_path_copy(abs_buf, abs_path);
-   add_to_alternates_file(abs_buf);
+   abs_path = mkpathdup(%s/objects/%s, src_repo, line.buf);
+   normalize_path_copy(abs_path, abs_path);
+   add_to_alternates_file(abs_path);
+   free(abs_path);
}
strbuf_release(line);
fclose(in);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 159fb7e..3f8c8f5 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -573,7 +573,8 @@ static int store_updated_refs(const char *raw_url, const 
char *remote_name,
struct strbuf note = STRBUF_INIT;
const char *what, *kind;
struct ref *rm;
-   char *url, *filename = dry_run ? /dev/null : git_path(FETCH_HEAD);
+   char *url;
+   const char *filename = dry_run ? /dev/null : git_path(FETCH_HEAD);
int want_status;
 
fp = fopen(filename, a);
@@ -807,7 +808,7 @@ static void check_not_current_branch(struct ref *ref_map)
 
 static int truncate_fetch_head(void)
 {
-   char *filename = git_path(FETCH_HEAD);
+   const char *filename = git_path(FETCH_HEAD);
FILE *fp = fopen(filename, w);
 
if (!fp)
diff --git a/builtin/fsck.c b/builtin/fsck.c
index e9ba576..0082a0e 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -225,12 +225,12 @@ static void check_unreachable_object(struct object *obj)
printf(dangling %s %s\n, typename(obj-type),
   sha1_to_hex(obj-sha1));
if (write_lost_and_found) {
-   char *filename = git_path(lost-found/%s/%s,
+   const char *filename = git_path(lost-found/%s/%s,
obj-type == OBJ_COMMIT ? commit : other,
sha1_to_hex(obj-sha1));
FILE *f;
 
-   if (safe_create_leading_directories(filename)) {
+   if (safe_create_leading_directories_const(filename)) {
error(Could not create lost-found);
return;
}
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index daf0600..3a49d1a 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ 

[PATCH v3 08/32] reflog: avoid constructing .lock path with git_path

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Among pathnames in $GIT_DIR, e.g. index or packed-refs, we want to
automatically and silently map some of them to the $GIT_DIR of the
repository we are borrowing from via $GIT_COMMON_DIR mechanism.  When
we formulate the pathname for its lockfile, we want it to be in the
same location as its final destination.  index is not shared and
needs to remain in the borrowing repository, while packed-refs is
shared and needs to go to the borrowed repository.

git_path() could be taught about the .lock suffix and map
index.lock and packed-refs.lock the same way their basenames are
mapped, but instead the caller can help by asking where the basename
(e.g. index) is mapped to git_path() and then appending .lock
after the mapping is done.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 builtin/reflog.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/reflog.c b/builtin/reflog.c
index e8a8fb1..9bd874d 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -372,7 +372,7 @@ static int expire_reflog(const char *ref, const unsigned 
char *sha1, int unused,
if (!reflog_exists(ref))
goto finish;
if (!cmd-dry_run) {
-   newlog_path = git_pathdup(logs/%s.lock, ref);
+   newlog_path = mkpathdup(%s.lock, log_file);
cb.newlog = fopen(newlog_path, w);
}
 
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 06/32] git_path(): be aware of file relocation in $GIT_DIR

2014-09-27 Thread Nguyễn Thái Ngọc Duy
We allow the user to relocate certain paths out of $GIT_DIR via
environment variables, e.g. GIT_OBJECT_DIRECTORY, GIT_INDEX_FILE and
GIT_GRAFT_FILE. Callers are not supposed to use git_path() or
git_pathdup() to get those paths. Instead they must use
get_object_directory(), get_index_file() and get_graft_file()
respectively. This is inconvenient and could be missed in review (for
example, there's git_path(objects/info/alternates) somewhere in
sha1_file.c).

This patch makes git_path() and git_pathdup() understand those
environment variables. So if you set GIT_OBJECT_DIRECTORY to /foo/bar,
git_path(objects/abc) should return /foo/bar/abc. The same is done
for the two remaining env variables.

git rev-parse --git-path is the wrapper for script use.

This patch kinda reverts a0279e1 (setup_git_env: use git_pathdup
instead of xmalloc + sprintf - 2014-06-19) because using git_pathdup
here would result in infinite recursion:

  setup_git_env() - git_pathdup(objects) - .. - adjust_git_path()
  - get_object_directory() - oops, git_object_directory is NOT set
  yet - setup_git_env()

I wanted to make git_pathdup_literal() that skips adjust_git_path().
But that won't work because later on when $GIT_COMMON_DIR is
introduced, git_pathdup_literal(objects) needs adjust_git_path() to
replace $GIT_DIR with $GIT_COMMON_DIR.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 Documentation/git-rev-parse.txt |  7 ++
 builtin/rev-parse.c |  7 ++
 cache.h |  1 +
 environment.c   | 19 +++-
 path.c  | 49 +++--
 t/t0060-path-utils.sh   | 19 
 6 files changed, 95 insertions(+), 7 deletions(-)

diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 0b84769..0fed5a4 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -232,6 +232,13 @@ print a message to stderr and exit with nonzero status.
repository.  If path is a gitfile then the resolved path
to the real repository is printed.
 
+--git-path path::
+   Resolve $GIT_DIR/path and takes other path relocation
+   variables such as $GIT_OBJECT_DIRECTORY,
+   $GIT_INDEX_FILE... into account. For example, if
+   $GIT_OBJECT_DIRECTORY is set to /foo/bar then git rev-parse
+   --git-path objects/abc returns /foo/bar/abc.
+
 --show-cdup::
When the command is invoked from a subdirectory, show the
path of the top-level directory relative to the current
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index c911b45..a6f4697 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -531,6 +531,13 @@ int cmd_rev_parse(int argc, const char **argv, const char 
*prefix)
for (i = 1; i  argc; i++) {
const char *arg = argv[i];
 
+   if (!strcmp(arg, --git-path)) {
+   if (!argv[i + 1])
+   die(--git-path requires an argument);
+   puts(git_path(%s, argv[i + 1]));
+   i++;
+   continue;
+   }
if (as_is) {
if (show_file(arg, output_prefix)  as_is  2)
verify_filename(prefix, arg, 0);
diff --git a/cache.h b/cache.h
index f487c0e..161dbd5 100644
--- a/cache.h
+++ b/cache.h
@@ -635,6 +635,7 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 extern int precomposed_unicode;
+extern int git_db_env, git_index_env, git_graft_env;
 
 /*
  * The character that begins a commented line in user-editable file
diff --git a/environment.c b/environment.c
index 565f652..fee12a6 100644
--- a/environment.c
+++ b/environment.c
@@ -83,6 +83,7 @@ static size_t namespace_len;
 
 static const char *git_dir;
 static char *git_object_dir, *git_index_file, *git_graft_file;
+int git_db_env, git_index_env, git_graft_env;
 
 /*
  * Repository-local GIT_* environment variables; see cache.h for details.
@@ -124,10 +125,18 @@ static char *expand_namespace(const char *raw_namespace)
return strbuf_detach(buf, NULL);
 }
 
-static char *git_path_from_env(const char *envvar, const char *path)
+static char *git_path_from_env(const char *envvar, const char *path,
+  int *fromenv)
 {
const char *value = getenv(envvar);
-   return value ? xstrdup(value) : git_pathdup(%s, path);
+   if (!value) {
+   char *buf = xmalloc(strlen(git_dir) + strlen(path) + 2);
+   sprintf(buf, %s/%s, git_dir, path);
+   return buf;
+   }
+   if (fromenv)
+   *fromenv = 1;
+   return xstrdup(value);
 }
 
 static void setup_git_env(void)
@@ -140,9 +149,9 @@ static void setup_git_env(void)
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
   

[PATCH v3 11/32] $GIT_COMMON_DIR: a new environment variable

2014-09-27 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 | 45 +-
 cache.h|  4 ++-
 environment.c  | 28 +++--
 path.c | 34 +
 t/t0060-path-utils.sh  | 16 
 6 files changed, 116 insertions(+), 19 deletions(-)

diff --git a/Documentation/git.txt b/Documentation/git.txt
index 8b2c542..176d37c 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -802,6 +802,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 79653f3..2b5966a 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
+   if $GIT_COMMON_DIR is set and $GIT_COMMON_DIR/config will be
+   used instead.
+
 branches::
A slightly deprecated way to store shorthands 

[PATCH v3 12/32] git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objects

2014-09-27 Thread Nguyễn Thái Ngọc Duy
If $GIT_COMMON_DIR is set, $GIT_OBJECT_DIRECTORY should be
$GIT_COMMON_DIR/objects, not $GIT_DIR/objects. Just let rev-parse
--git-path handle it.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 git-sh-setup.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 9447980..d3dbb2f 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -345,7 +345,7 @@ then
echo 2 Unable to determine absolute path of git directory
exit 1
}
-   : ${GIT_OBJECT_DIRECTORY=$GIT_DIR/objects}
+   : ${GIT_OBJECT_DIRECTORY=$(git rev-parse --git-path objects)}
 fi
 
 peel_committish () {
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 10/32] commit: use SEQ_DIR instead of hardcoding sequencer

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 builtin/commit.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index b0fe784..08df727 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -169,7 +169,7 @@ static void determine_whence(struct wt_status *s)
whence = FROM_MERGE;
else if (file_exists(git_path(CHERRY_PICK_HEAD))) {
whence = FROM_CHERRY_PICK;
-   if (file_exists(git_path(sequencer)))
+   if (file_exists(git_path(SEQ_DIR)))
sequencer_in_use = 1;
}
else
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 09/32] fast-import: use git_path() for accessing .git dir instead of get_git_dir()

2014-09-27 Thread Nguyễn Thái Ngọc Duy
This allows git_path() to redirect info/fast-import to another place
if needed

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 fast-import.c | 5 +
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/fast-import.c b/fast-import.c
index 9ddcd3b..69e4c3f 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -3130,12 +3130,9 @@ static void parse_progress(void)
 
 static char* make_fast_import_path(const char *path)
 {
-   struct strbuf abs_path = STRBUF_INIT;
-
if (!relative_marks_paths || is_absolute_path(path))
return xstrdup(path);
-   strbuf_addf(abs_path, %s/info/fast-import/%s, get_git_dir(), path);
-   return strbuf_detach(abs_path, NULL);
+   return xstrdup(git_path(info/fast-import/%s, path));
 }
 
 static void option_import_marks(const char *marks,
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 16/32] setup.c: detect $GIT_COMMON_DIR in is_git_directory()

2014-09-27 Thread Nguyễn Thái Ngọc Duy
If the file $GIT_DIR/commondir exists, it contains the value of
$GIT_COMMON_DIR.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 Documentation/gitrepository-layout.txt |  7 ++
 setup.c| 43 +-
 2 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/Documentation/gitrepository-layout.txt 
b/Documentation/gitrepository-layout.txt
index 2b5966a..2dc5667 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -240,6 +240,13 @@ shallow::
file is ignored if $GIT_COMMON_DIR is set and
$GIT_COMMON_DIR/shallow will be used instead.
 
+commondir::
+   If this file exists, $GIT_COMMON_DIR (see linkgit:git[1]) will
+   be set to the path specified in this file if it is not
+   explicitly set. If the specified path is relative, it is
+   relative to $GIT_DIR. The repository with commondir is
+   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
diff --git a/setup.c b/setup.c
index afd6742..6c52f75 100644
--- a/setup.c
+++ b/setup.c
@@ -224,6 +224,33 @@ void verify_non_filename(const char *prefix, const char 
*arg)
'git command [revision...] -- [file...]', arg);
 }
 
+static void get_common_dir(struct strbuf *sb, const char *gitdir)
+{
+   struct strbuf data = STRBUF_INIT;
+   struct strbuf path = STRBUF_INIT;
+   const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
+   if (git_common_dir) {
+   strbuf_addstr(sb, git_common_dir);
+   return;
+   }
+   strbuf_addf(path, %s/commondir, gitdir);
+   if (file_exists(path.buf)) {
+   if (strbuf_read_file(data, path.buf, 0) = 0)
+   die_errno(_(failed to read %s), path.buf);
+   while (data.len  (data.buf[data.len - 1] == '\n' ||
+   data.buf[data.len - 1] == '\r'))
+   data.len--;
+   data.buf[data.len] = '\0';
+   strbuf_reset(path);
+   if (!is_absolute_path(data.buf))
+   strbuf_addf(path, %s/, gitdir);
+   strbuf_addbuf(path, data);
+   strbuf_addstr(sb, real_path(path.buf));
+   } else
+   strbuf_addstr(sb, gitdir);
+   strbuf_release(data);
+   strbuf_release(path);
+}
 
 /*
  * Test if it looks like we're at a git directory.
@@ -242,13 +269,22 @@ int is_git_directory(const char *suspect)
int ret = 0;
size_t len;
 
-   strbuf_addstr(path, suspect);
+   /* Check worktree-related signatures */
+   strbuf_addf(path, %s/HEAD, suspect);
+   if (validate_headref(path.buf))
+   goto done;
+
+   strbuf_reset(path);
+   get_common_dir(path, suspect);
len = path.len;
+
+   /* Check non-worktree-related signatures */
if (getenv(DB_ENVIRONMENT)) {
if (access(getenv(DB_ENVIRONMENT), X_OK))
goto done;
}
else {
+   strbuf_setlen(path, len);
strbuf_addstr(path, /objects);
if (access(path.buf, X_OK))
goto done;
@@ -259,11 +295,6 @@ int is_git_directory(const char *suspect)
if (access(path.buf, X_OK))
goto done;
 
-   strbuf_setlen(path, len);
-   strbuf_addstr(path, /HEAD);
-   if (validate_headref(path.buf))
-   goto done;
-
ret = 1;
 done:
strbuf_release(path);
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 14/32] git-stash: avoid hardcoding $GIT_DIR/logs/....

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 git-stash.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/git-stash.sh b/git-stash.sh
index 4294aa0..2784f8b 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -184,7 +184,7 @@ store_stash () {
fi
 
# Make sure the reflog for stash is kept.
-   : $GIT_DIR/logs/$ref_stash
+   : $(git rev-parse --git-path logs/$ref_stash)
git update-ref -m $stash_msg $ref_stash $w_commit
ret=$?
test $ret != 0  test -z $quiet 
@@ -259,7 +259,7 @@ save_stash () {
say $(gettext No local changes to save)
exit 0
fi
-   test -f $GIT_DIR/logs/$ref_stash ||
+   test -f $(git rev-parse --git-path logs/$ref_stash) ||
clear_stash || die $(gettext Cannot initialize stash)
 
create_stash $stash_msg $untracked
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 15/32] setup.c: convert is_git_directory() to use strbuf

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 setup.c | 37 +
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/setup.c b/setup.c
index 979b13f..afd6742 100644
--- a/setup.c
+++ b/setup.c
@@ -238,31 +238,36 @@ void verify_non_filename(const char *prefix, const char 
*arg)
  */
 int is_git_directory(const char *suspect)
 {
-   char path[PATH_MAX];
-   size_t len = strlen(suspect);
+   struct strbuf path = STRBUF_INIT;
+   int ret = 0;
+   size_t len;
 
-   if (PATH_MAX = len + strlen(/objects))
-   die(Too long path: %.*s, 60, suspect);
-   strcpy(path, suspect);
+   strbuf_addstr(path, suspect);
+   len = path.len;
if (getenv(DB_ENVIRONMENT)) {
if (access(getenv(DB_ENVIRONMENT), X_OK))
-   return 0;
+   goto done;
}
else {
-   strcpy(path + len, /objects);
-   if (access(path, X_OK))
-   return 0;
+   strbuf_addstr(path, /objects);
+   if (access(path.buf, X_OK))
+   goto done;
}
 
-   strcpy(path + len, /refs);
-   if (access(path, X_OK))
-   return 0;
+   strbuf_setlen(path, len);
+   strbuf_addstr(path, /refs);
+   if (access(path.buf, X_OK))
+   goto done;
 
-   strcpy(path + len, /HEAD);
-   if (validate_headref(path))
-   return 0;
+   strbuf_setlen(path, len);
+   strbuf_addstr(path, /HEAD);
+   if (validate_headref(path.buf))
+   goto done;
 
-   return 1;
+   ret = 1;
+done:
+   strbuf_release(path);
+   return ret;
 }
 
 int is_inside_git_dir(void)
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 17/32] setup.c: convert check_repository_format_gently to use strbuf

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 setup.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/setup.c b/setup.c
index 6c52f75..00a23e6 100644
--- a/setup.c
+++ b/setup.c
@@ -342,7 +342,9 @@ void setup_work_tree(void)
 
 static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 {
-   char repo_config[PATH_MAX+1];
+   struct strbuf sb = STRBUF_INIT;
+   const char *repo_config;
+   int ret = 0;
 
/*
 * git_config() can't be used here because it calls git_pathdup()
@@ -353,7 +355,8 @@ static int check_repository_format_gently(const char 
*gitdir, int *nongit_ok)
 * Use a gentler version of git_config() to check if this repo
 * is a good one.
 */
-   snprintf(repo_config, PATH_MAX, %s/config, gitdir);
+   strbuf_addf(sb, %s/config, gitdir);
+   repo_config = sb.buf;
git_config_early(check_repository_format_version, NULL, repo_config);
if (GIT_REPO_VERSION  repository_format_version) {
if (!nongit_ok)
@@ -363,9 +366,10 @@ static int check_repository_format_gently(const char 
*gitdir, int *nongit_ok)
GIT_REPO_VERSION, repository_format_version);
warning(Please upgrade Git);
*nongit_ok = -1;
-   return -1;
+   ret = -1;
}
-   return 0;
+   strbuf_release(sb);
+   return ret;
 }
 
 /*
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 13/32] *.sh: avoid hardcoding $GIT_DIR/hooks/...

2014-09-27 Thread Nguyễn Thái Ngọc Duy
If $GIT_COMMON_DIR is set, it should be $GIT_COMMON_DIR/hooks/, not
$GIT_DIR/hooks/. Just let rev-parse --git-path handle it.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 git-am.sh  | 22 +++---
 git-rebase--interactive.sh |  6 +++---
 git-rebase--merge.sh   |  6 ++
 git-rebase.sh  |  4 ++--
 templates/hooks--applypatch-msg.sample |  4 ++--
 templates/hooks--pre-applypatch.sample |  4 ++--
 6 files changed, 22 insertions(+), 24 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index ee61a77..66803d1 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -810,10 +810,10 @@ To restore the original branch and stop patching run 
\\$cmdline --abort\.
continue
fi
 
-   if test -x $GIT_DIR/hooks/applypatch-msg
+   hook=$(git rev-parse --git-path hooks/applypatch-msg)
+   if test -x $hook
then
-   $GIT_DIR/hooks/applypatch-msg $dotest/final-commit ||
-   stop_here $this
+   $hook $dotest/final-commit || stop_here $this
fi
 
if test -f $dotest/final-commit
@@ -887,9 +887,10 @@ did you forget to use 'git add'?
stop_here_user_resolve $this
fi
 
-   if test -x $GIT_DIR/hooks/pre-applypatch
+   hook=$(git rev-parse --git-path hooks/pre-applypatch)
+   if test -x $hook
then
-   $GIT_DIR/hooks/pre-applypatch || stop_here $this
+   $hook || stop_here $this
fi
 
tree=$(git write-tree) 
@@ -916,18 +917,17 @@ did you forget to use 'git add'?
echo $(cat $dotest/original-commit) $commit  
$dotest/rewritten
fi
 
-   if test -x $GIT_DIR/hooks/post-applypatch
-   then
-   $GIT_DIR/hooks/post-applypatch
-   fi
+   hook=$(git rev-parse --git-path hooks/post-applypatch)
+   test -x $hook  $hook
 
go_next
 done
 
 if test -s $dotest/rewritten; then
 git notes copy --for-rewrite=rebase  $dotest/rewritten
-if test -x $GIT_DIR/hooks/post-rewrite; then
-   $GIT_DIR/hooks/post-rewrite rebase  $dotest/rewritten
+hook=$(git rev-parse --git-path hooks/post-rewrite)
+if test -x $hook; then
+   $hook rebase  $dotest/rewritten
 fi
 fi
 
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index b64dd28..b32f797 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -642,9 +642,9 @@ do_next () {
git notes copy --for-rewrite=rebase  $rewritten_list ||
true # we don't care if this copying failed
} 
-   if test -x $GIT_DIR/hooks/post-rewrite 
-   test -s $rewritten_list; then
-   $GIT_DIR/hooks/post-rewrite rebase  $rewritten_list
+   hook=$(git rev-parse --git-path hooks/post-rewrite)
+   if test -x $hook  test -s $rewritten_list; then
+   $hook rebase  $rewritten_list
true # we don't care if this hook failed
fi 
warn Successfully rebased and updated $head_name.
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
index d3fb67d..2cc2a6d 100644
--- a/git-rebase--merge.sh
+++ b/git-rebase--merge.sh
@@ -94,10 +94,8 @@ finish_rb_merge () {
if test -s $state_dir/rewritten
then
git notes copy --for-rewrite=rebase $state_dir/rewritten
-   if test -x $GIT_DIR/hooks/post-rewrite
-   then
-   $GIT_DIR/hooks/post-rewrite rebase 
$state_dir/rewritten
-   fi
+   hook=$(git rev-parse --git-path hooks/post-rewrite)
+   test -x $hook  $hook rebase $state_dir/rewritten
fi
say All done.
 }
diff --git a/git-rebase.sh b/git-rebase.sh
index 55da9db..fb935a0 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -202,9 +202,9 @@ run_specific_rebase () {
 
 run_pre_rebase_hook () {
if test -z $ok_to_skip_pre_rebase 
-  test -x $GIT_DIR/hooks/pre-rebase
+  test -x $(git rev-parse --git-path hooks/pre-rebase)
then
-   $GIT_DIR/hooks/pre-rebase ${1+$@} ||
+   $(git rev-parse --git-path hooks/pre-rebase) ${1+$@} ||
die $(gettext The pre-rebase hook refused to rebase.)
fi
 }
diff --git a/templates/hooks--applypatch-msg.sample 
b/templates/hooks--applypatch-msg.sample
index 8b2a2fe..a5d7b84 100755
--- a/templates/hooks--applypatch-msg.sample
+++ b/templates/hooks--applypatch-msg.sample
@@ -10,6 +10,6 @@
 # To enable this hook, rename this file to applypatch-msg.
 
 . git-sh-setup
-test -x $GIT_DIR/hooks/commit-msg 
-   exec $GIT_DIR/hooks/commit-msg ${1+$@}
+commitmsg=$(git rev-parse --git-path hooks/commit-msg)
+test -x $commitmsg  exec $commitmsg ${1+$@}
 :
diff --git a/templates/hooks--pre-applypatch.sample 
b/templates/hooks--pre-applypatch.sample
index b1f187c..4142082 100755
--- 

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

2014-09-27 Thread Nguyễn Thái Ngọc Duy
git checkout --to sets up a new working directory with a .git file
pointing to $GIT_DIR/worktrees/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.

Helped-by: Marc Branchaud marcn...@xiplink.com
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 Documentation/git-checkout.txt | 46 
 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, 212 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..c101575 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 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 WORKING
+   TREES 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,45 @@ $ git reflog -2 HEAD # or
 $ git log -g -2 HEAD
 
 
+MULTIPLE WORKING TREES
+--
+
+A git repository can support multiple working trees, allowing you to check
+out more than one branch at a time.  With `git checkout --to` a new working
+tree is associated with the repository.  This new working tree is called a
+linked working tree as opposed to the main working tree prepared by git
+init or git clone.  A repository has one main working tree (if it's not a
+bare repository) and zero or more linked working trees.
+
+Each linked working tree has a private sub-directory in the repository's
+$GIT_DIR/worktrees directory.  The private sub-directory's name is usually
+the base name of the linked working tree's path, possibly appended with a
+number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the
+command `git checkout --to /path/other/test-next next` creates the linked
+working tree in `/path/other/test-next` and also creates a
+`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`
+if `test-next` is already taken).
+
+Within a linked working tree, $GIT_DIR is set to point to this private
+directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and
+$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR
+(e.g. `/path/main/.git`). These settings are made in a `.git` file located at
+the top directory of the linked working tree.
+
+Path resolution via `git rev-parse --git-path` uses either
+$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the
+linked working tree `git rev-parse --git-path HEAD` returns
+`/path/main/.git/worktrees/test-next/HEAD` (not
+`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
+rev-parse --git-path refs/heads/master` uses
+$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,
+since refs are shared across all working trees.
+
+See linkgit:gitrepository-layout[5] for more information. The rule of
+thumb is do not make any assumption about whether a path belongs to
+$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
+inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
+
 EXAMPLES
 
 
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 176d37c..54c9fb6 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -806,7 +806,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 2dc5667..8228450 100644
--- a/Documentation/gitrepository-layout.txt
+++ 

[PATCH v3 24/32] checkout: reject if the branch is already checked out elsewhere

2014-09-27 Thread Nguyễn Thái Ngọc Duy
One branch obviously can't be checked out at two places (but detached
heads are ok). Give the user a choice in this case: --detach, -b
new-branch, switch branch in the other checkout first or simply 'cd'
and continue to work there.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 builtin/checkout.c | 86 --
 t/t2025-checkout-to.sh | 25 ---
 2 files changed, 104 insertions(+), 7 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index ab46af9..6d68913 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -430,6 +430,11 @@ struct branch_info {
const char *name; /* The short name used */
const char *path; /* The full name of a real branch */
struct commit *commit; /* The named commit */
+   /*
+* if not null the branch is detached because it's already
+* checked out in this checkout
+*/
+   char *checkout;
 };
 
 static void setup_branch_path(struct branch_info *branch)
@@ -958,12 +963,78 @@ static const char *unique_tracking_name(const char *name, 
unsigned char *sha1)
return NULL;
 }
 
+static void check_linked_checkout(struct branch_info *new, const char *id)
+{
+   struct strbuf sb = STRBUF_INIT;
+   struct strbuf path = STRBUF_INIT;
+   struct strbuf gitdir = STRBUF_INIT;
+   const char *start, *end;
+
+   if (id)
+   strbuf_addf(path, %s/worktrees/%s/HEAD, 
get_git_common_dir(), id);
+   else
+   strbuf_addf(path, %s/HEAD, get_git_common_dir());
+
+   if (strbuf_read_file(sb, path.buf, 0)  0 ||
+   !skip_prefix(sb.buf, ref:, start))
+   goto done;
+   while (isspace(*start))
+   start++;
+   end = start;
+   while (*end  !isspace(*end))
+   end++;
+   if (strncmp(start, new-path, end - start) || new-path[end - start] != 
'\0')
+   goto done;
+   if (id) {
+   strbuf_reset(path);
+   strbuf_addf(path, %s/worktrees/%s/gitdir, 
get_git_common_dir(), id);
+   if (strbuf_read_file(gitdir, path.buf, 0) = 0)
+   goto done;
+   strbuf_rtrim(gitdir);
+   } else
+   strbuf_addstr(gitdir, get_git_common_dir());
+   die(_('%s' is already checked out at '%s'), new-name, gitdir.buf);
+done:
+   strbuf_release(path);
+   strbuf_release(sb);
+   strbuf_release(gitdir);
+}
+
+static void check_linked_checkouts(struct branch_info *new)
+{
+   struct strbuf path = STRBUF_INIT;
+   DIR *dir;
+   struct dirent *d;
+
+   strbuf_addf(path, %s/worktrees, get_git_common_dir());
+   if ((dir = opendir(path.buf)) == NULL) {
+   strbuf_release(path);
+   return;
+   }
+
+   /*
+* $GIT_COMMON_DIR/HEAD is practically outside
+* $GIT_DIR so resolve_ref_unsafe() won't work (it
+* uses git_path). Parse the ref ourselves.
+*/
+   check_linked_checkout(new, NULL);
+
+   while ((d = readdir(dir)) != NULL) {
+   if (!strcmp(d-d_name, .) || !strcmp(d-d_name, ..))
+   continue;
+   check_linked_checkout(new, d-d_name);
+   }
+   strbuf_release(path);
+   closedir(dir);
+}
+
 static int parse_branchname_arg(int argc, const char **argv,
int dwim_new_local_branch_ok,
struct branch_info *new,
struct tree **source_tree,
unsigned char rev[20],
-   const char **new_branch)
+   const char **new_branch,
+   int force_detach)
 {
int argcount = 0;
unsigned char branch_rev[20];
@@ -1085,6 +1156,16 @@ static int parse_branchname_arg(int argc, const char 
**argv,
else
new-path = NULL; /* not an existing branch */
 
+   if (new-path  !force_detach  !*new_branch) {
+   unsigned char sha1[20];
+   int flag;
+   char *head_ref = resolve_refdup(HEAD, sha1, 0, flag);
+   if (head_ref 
+   (!(flag  REF_ISSYMREF) || strcmp(head_ref, new-path)))
+   check_linked_checkouts(new);
+   free(head_ref);
+   }
+
new-commit = lookup_commit_reference_gently(rev, 1);
if (!new-commit) {
/* not a commit */
@@ -1291,7 +1372,8 @@ int cmd_checkout(int argc, const char **argv, const char 
*prefix)
!opts.new_branch;
int n = parse_branchname_arg(argc, argv, dwim_ok,
 new, opts.source_tree,
-rev, opts.new_branch);
+rev, opts.new_branch,
+opts.force_detach);
   

[PATCH v3 23/32] prune: strategies for linked checkouts

2014-09-27 Thread Nguyễn Thái Ngọc Duy
(alias R=$GIT_COMMON_DIR/worktrees/id)

 - linked checkouts are supposed to keep its location in $R/gitdir up
   to date. The use case is auto fixup after a manual checkout move.

 - linked checkouts are supposed to update mtime of $R/gitdir. If
   $R/gitdir's mtime is older than a limit, and it points to nowhere,
   worktrees/id is to be pruned.

 - If $R/locked exists, worktrees/id is not supposed to be pruned. If
   $R/locked exists and $R/gitdir's mtime is older than a really long
   limit, warn about old unused repo.

 - git checkout --to is supposed to make a hard link named $R/link
   pointing to the .git file on supported file systems to help detect
   the user manually deleting the checkout. If $R/link exists and its
   link count is greated than 1, the repo is kept.

Helped-by: Marc Branchaud marcn...@xiplink.com
Helped-by: Eric Sunshine sunsh...@sunshineco.com
Signed-off-by: Marc Branchaud marcn...@xiplink.com
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 Documentation/git-checkout.txt | 20 +++
 Documentation/git-prune.txt|  3 +
 Documentation/gitrepository-layout.txt | 19 ++
 builtin/checkout.c | 19 +-
 builtin/prune.c| 95 ++
 setup.c| 13 
 t/t2026-prune-linked-checkouts.sh (new +x) | 84 ++
 7 files changed, 251 insertions(+), 2 deletions(-)
 create mode 100755 t/t2026-prune-linked-checkouts.sh

diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index c101575..35675da 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -434,6 +434,26 @@ thumb is do not make any assumption about whether a path 
belongs to
 $GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
 inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
 
+When you are done with a linked working tree you can simply delete it.
+You can clean up any stale $GIT_DIR/worktrees entries via `git prune
+--worktrees` in the main or any linked working tree.
+
+If you move a linked working directory to another file system, or
+within a file system that does not support hard links, you need to run
+at least one git command inside the linked working directory
+(e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees
+so that it does not get automatically removed.
+
+To prevent `git prune --worktrees` from deleting a $GIT_DIR/worktrees
+entry (which can be useful in some situations, such as when the
+entry's working tree is stored on a portable device), add a file named
+'locked' to the entry's directory. The file contains the reason in
+plain text. For example, if a linked working tree's `.git` file points
+to `/path/main/.git/worktrees/test-next` then a file named
+`/path/main/.git/worktrees/test-next/locked` will prevent the
+`test-next` entry from being pruned.  See
+linkgit:gitrepository-layout[5] for details.
+
 EXAMPLES
 
 
diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt
index 7a493c8..1cf3bed 100644
--- a/Documentation/git-prune.txt
+++ b/Documentation/git-prune.txt
@@ -48,6 +48,9 @@ OPTIONS
 --expire time::
Only expire loose objects older than time.
 
+--worktrees::
+   Prune dead working tree information in $GIT_DIR/worktrees.
+
 head...::
In addition to objects
reachable from any of our references, keep objects
diff --git a/Documentation/gitrepository-layout.txt 
b/Documentation/gitrepository-layout.txt
index 8228450..2b30a92 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -259,6 +259,25 @@ worktrees::
$GIT_COMMON_DIR is set and $GIT_COMMON_DIR/worktrees will be
used instead.
 
+worktrees/id/gitdir::
+   A text file containing the absolute path back to the .git file
+   that points to here. This is used to check if the linked
+   repository has been manually removed and there is no need to
+   keep this directory any more. mtime of this file should be
+   updated every time the linked repository is accessed.
+
+worktrees/id/locked::
+   If this file exists, the linked repository may be on a
+   portable device and not available. It does not mean that the
+   linked repository is gone and `worktrees/id` could be
+   removed. The file's content contains a reason string on why
+   the repository is locked.
+
+worktrees/id/link::
+   If this file exists, it is a hard link to the linked .git
+   file. It is used to detect if the linked repository is
+   manually removed.
+
 SEE ALSO
 
 linkgit:git-init[1],
diff --git a/builtin/checkout.c b/builtin/checkout.c
index ad10f99..ab46af9 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -826,7 +826,7 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
const char *path = 

[PATCH v3 20/32] wrapper.c: wrapper to open a file, fprintf then close

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 cache.h   |  2 ++
 wrapper.c | 31 +++
 2 files changed, 33 insertions(+)

diff --git a/cache.h b/cache.h
index 1784fc6..aedfd05 100644
--- a/cache.h
+++ b/cache.h
@@ -1452,6 +1452,8 @@ static inline ssize_t write_str_in_full(int fd, const 
char *str)
 {
return write_in_full(fd, str, strlen(str));
 }
+__attribute__((format (printf,3,4)))
+extern int write_file(const char *path, int fatal, const char *fmt, ...);
 
 /* pager.c */
 extern void setup_pager(void);
diff --git a/wrapper.c b/wrapper.c
index 25074d7..d53a3b3 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -537,3 +537,34 @@ char *xgetcwd(void)
die_errno(_(unable to get current working directory));
return strbuf_detach(sb, NULL);
 }
+
+int write_file(const char *path, int fatal, const char *fmt, ...)
+{
+   struct strbuf sb = STRBUF_INIT;
+   va_list params;
+   int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
+   if (fd  0) {
+   if (fatal)
+   die_errno(_(could not open %s for writing), path);
+   return -1;
+   }
+   va_start(params, fmt);
+   strbuf_vaddf(sb, fmt, params);
+   va_end(params);
+   if (write_in_full(fd, sb.buf, sb.len) != sb.len) {
+   int err = errno;
+   close(fd);
+   strbuf_release(sb);
+   errno = err;
+   if (fatal)
+   die_errno(_(could not write to %s), path);
+   return -1;
+   }
+   strbuf_release(sb);
+   if (close(fd)) {
+   if (fatal)
+   die_errno(_(could not close %s), path);
+   return -1;
+   }
+   return 0;
+}
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 27/32] gc: factor out gc.pruneexpire parsing code

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 builtin/gc.c | 22 --
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index b690929..849a87c 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -55,6 +55,17 @@ static void remove_pidfile_on_signal(int signo)
raise(signo);
 }
 
+static void git_config_date_string(const char *key, const char **output)
+{
+   if (git_config_get_string_const(key, output))
+   return;
+   if (strcmp(*output, now)) {
+   unsigned long now = approxidate(now);
+   if (approxidate(*output) = now)
+   git_die_config(key, _(Invalid %s: '%s'), key, 
*output);
+   }
+}
+
 static void gc_config(void)
 {
const char *value;
@@ -71,16 +82,7 @@ static void gc_config(void)
git_config_get_int(gc.auto, gc_auto_threshold);
git_config_get_int(gc.autopacklimit, gc_auto_pack_limit);
git_config_get_bool(gc.autodetach, detach_auto);
-
-   if (!git_config_get_string_const(gc.pruneexpire, prune_expire)) {
-   if (strcmp(prune_expire, now)) {
-   unsigned long now = approxidate(now);
-   if (approxidate(prune_expire) = now) {
-   git_die_config(gc.pruneexpire, _(Invalid 
gc.pruneexpire: '%s'),
-   prune_expire);
-   }
-   }
-   }
+   git_config_date_string(gc.pruneexpire, prune_expire);
git_config(git_default_config, NULL);
 }
 
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 26/32] gc: style change -- no SP before closing parenthesis

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 builtin/gc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index ced1456..b690929 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -287,7 +287,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
argv_array_pushl(pack_refs_cmd, pack-refs, --all, --prune, NULL);
argv_array_pushl(reflog, reflog, expire, --all, NULL);
argv_array_pushl(repack, repack, -d, -l, NULL);
-   argv_array_pushl(prune, prune, --expire, NULL );
+   argv_array_pushl(prune, prune, --expire, NULL);
argv_array_pushl(rerere, rerere, gc, NULL);
 
gc_config();
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 21/32] use new wrapper write_file() for simple file writing

2014-09-27 Thread Nguyễn Thái Ngọc Duy
This fixes common problems in these code about error handling,
forgetting to close the file handle after fprintf() fails, or not
printing out the error string..

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 builtin/branch.c  |  4 +---
 builtin/init-db.c |  7 +--
 daemon.c  | 11 +--
 submodule.c   |  9 ++---
 transport.c   |  8 +++-
 5 files changed, 8 insertions(+), 31 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 9e4666f..a8b79bf 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -761,7 +761,6 @@ static const char edit_description[] = BRANCH_DESCRIPTION;
 
 static int edit_branch_description(const char *branch_name)
 {
-   FILE *fp;
int status;
struct strbuf buf = STRBUF_INIT;
struct strbuf name = STRBUF_INIT;
@@ -774,8 +773,7 @@ static int edit_branch_description(const char *branch_name)
  %s\n
Lines starting with '%c' will be stripped.\n,
branch_name, comment_line_char);
-   fp = fopen(git_path(edit_description), w);
-   if ((fwrite(buf.buf, 1, buf.len, fp)  buf.len) || fclose(fp)) {
+   if (write_file(git_path(edit_description), 0, %s, buf.buf)) {
strbuf_release(buf);
return error(_(could not write branch description template: 
%s),
 strerror(errno));
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 587a505..6b7fa5f 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -342,7 +342,6 @@ int set_git_dir_init(const char *git_dir, const char 
*real_git_dir,
 static void separate_git_dir(const char *git_dir)
 {
struct stat st;
-   FILE *fp;
 
if (!stat(git_link, st)) {
const char *src;
@@ -358,11 +357,7 @@ static void separate_git_dir(const char *git_dir)
die_errno(_(unable to move %s to %s), src, git_dir);
}
 
-   fp = fopen(git_link, w);
-   if (!fp)
-   die(_(Could not create git link %s), git_link);
-   fprintf(fp, gitdir: %s\n, git_dir);
-   fclose(fp);
+   write_file(git_link, 1, gitdir: %s\n, git_dir);
 }
 
 int init_db(const char *template_dir, unsigned int flags)
diff --git a/daemon.c b/daemon.c
index 4dcfff9..8420fdb 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1073,15 +1073,6 @@ static struct credentials *prepare_credentials(const 
char *user_name,
 }
 #endif
 
-static void store_pid(const char *path)
-{
-   FILE *f = fopen(path, w);
-   if (!f)
-   die_errno(cannot open pid file '%s', path);
-   if (fprintf(f, %PRIuMAX\n, (uintmax_t) getpid())  0 || fclose(f) 
!= 0)
-   die_errno(failed to write pid file '%s', path);
-}
-
 static int serve(struct string_list *listen_addr, int listen_port,
 struct credentials *cred)
 {
@@ -1292,7 +1283,7 @@ int main(int argc, char **argv)
sanitize_stdfds();
 
if (pid_file)
-   store_pid(pid_file);
+   write_file(pid_file, 1, %PRIuMAX\n, (uintmax_t) getpid());
 
/* prepare argv for serving-processes */
cld_argv = xmalloc(sizeof (char *) * (argc + 2));
diff --git a/submodule.c b/submodule.c
index 0690dc5..34094f5 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1102,16 +1102,11 @@ void connect_work_tree_and_git_dir(const char 
*work_tree, const char *git_dir)
struct strbuf file_name = STRBUF_INIT;
struct strbuf rel_path = STRBUF_INIT;
const char *real_work_tree = xstrdup(real_path(work_tree));
-   FILE *fp;
 
/* Update gitfile */
strbuf_addf(file_name, %s/.git, work_tree);
-   fp = fopen(file_name.buf, w);
-   if (!fp)
-   die(_(Could not create git link %s), file_name.buf);
-   fprintf(fp, gitdir: %s\n, relative_path(git_dir, real_work_tree,
- rel_path));
-   fclose(fp);
+   write_file(file_name.buf, 1, gitdir: %s\n,
+  relative_path(git_dir, real_work_tree, rel_path));
 
/* Update core.worktree setting */
strbuf_reset(file_name);
diff --git a/transport.c b/transport.c
index 7388bb8..0bb15ee 100644
--- a/transport.c
+++ b/transport.c
@@ -282,7 +282,6 @@ static int write_one_ref(const char *name, const unsigned 
char *sha1,
 {
struct strbuf *buf = data;
int len = buf-len;
-   FILE *f;
 
/* when called via for_each_ref(), flags is non-zero */
if (flags  !starts_with(name, refs/heads/) 
@@ -291,10 +290,9 @@ static int write_one_ref(const char *name, const unsigned 
char *sha1,
 
strbuf_addstr(buf, name);
if (safe_create_leading_directories(buf-buf) ||
-   !(f = fopen(buf-buf, w)) ||
-   fprintf(f, %s\n, sha1_to_hex(sha1))  0 ||
-   fclose(f))
-   return error(problems writing temporary file %s, buf-buf);

[PATCH v3 28/32] gc: support prune --worktrees

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Helped-by: Marc Branchaud marcn...@xiplink.com
Signed-off-by: Marc Branchaud marcn...@xiplink.com
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 Documentation/config.txt   |  7 +++
 Documentation/git-checkout.txt | 11 +++
 builtin/gc.c   | 10 ++
 3 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 98b8ef0..8351c8a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1212,6 +1212,13 @@ gc.pruneexpire::
now may be used to disable this  grace period and always prune
unreachable objects immediately.
 
+gc.pruneworktreesexpire::
+   When 'git gc' is run, it will call
+   'prune --worktrees --expire 3.months.ago'.
+   Override the grace period with this config variable. The value
+   now may be used to disable the grace period and prune
+   $GIT_DIR/worktrees immediately.
+
 gc.reflogexpire::
 gc.pattern.reflogexpire::
'git reflog expire' removes reflog entries older than
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 35675da..0c13825 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -435,8 +435,11 @@ $GIT_DIR or $GIT_COMMON_DIR when you need to directly 
access something
 inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
 
 When you are done with a linked working tree you can simply delete it.
-You can clean up any stale $GIT_DIR/worktrees entries via `git prune
---worktrees` in the main or any linked working tree.
+The working tree's entry in the repository's $GIT_DIR/worktrees
+directory will eventually be removed automatically (see
+`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run
+`git prune --worktrees` in the main or any linked working tree to
+clean up any stale entries in $GIT_DIR/worktrees.
 
 If you move a linked working directory to another file system, or
 within a file system that does not support hard links, you need to run
@@ -444,8 +447,8 @@ at least one git command inside the linked working directory
 (e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees
 so that it does not get automatically removed.
 
-To prevent `git prune --worktrees` from deleting a $GIT_DIR/worktrees
-entry (which can be useful in some situations, such as when the
+To prevent a $GIT_DIR/worktrees entry from from being pruned (which
+can be useful in some situations, such as when the
 entry's working tree is stored on a portable device), add a file named
 'locked' to the entry's directory. The file contains the reason in
 plain text. For example, if a linked working tree's `.git` file points
diff --git a/builtin/gc.c b/builtin/gc.c
index 849a87c..35542f3 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -33,11 +33,13 @@ static int gc_auto_threshold = 6700;
 static int gc_auto_pack_limit = 50;
 static int detach_auto = 1;
 static const char *prune_expire = 2.weeks.ago;
+static const char *prune_worktrees_expire = 3.months.ago;
 
 static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT;
 static struct argv_array reflog = ARGV_ARRAY_INIT;
 static struct argv_array repack = ARGV_ARRAY_INIT;
 static struct argv_array prune = ARGV_ARRAY_INIT;
+static struct argv_array prune_worktrees = ARGV_ARRAY_INIT;
 static struct argv_array rerere = ARGV_ARRAY_INIT;
 
 static char *pidfile;
@@ -83,6 +85,7 @@ static void gc_config(void)
git_config_get_int(gc.autopacklimit, gc_auto_pack_limit);
git_config_get_bool(gc.autodetach, detach_auto);
git_config_date_string(gc.pruneexpire, prune_expire);
+   git_config_date_string(gc.pruneworktreesexpire, 
prune_worktrees_expire);
git_config(git_default_config, NULL);
 }
 
@@ -290,6 +293,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
argv_array_pushl(reflog, reflog, expire, --all, NULL);
argv_array_pushl(repack, repack, -d, -l, NULL);
argv_array_pushl(prune, prune, --expire, NULL);
+   argv_array_pushl(prune_worktrees, prune, --worktrees, --expire, 
NULL);
argv_array_pushl(rerere, rerere, gc, NULL);
 
gc_config();
@@ -359,6 +363,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
return error(FAILED_RUN, prune.argv[0]);
}
 
+   if (prune_worktrees_expire) {
+   argv_array_push(prune_worktrees, prune_worktrees_expire);
+   if (run_command_v_opt(prune_worktrees.argv, RUN_GIT_CMD))
+   return error(FAILED_RUN, prune_worktrees.argv[0]);
+   }
+
if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
return error(FAILED_RUN, rerere.argv[0]);
 
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 19/32] setup.c: support multi-checkout repo setup

2014-09-27 Thread Nguyễn Thái Ngọc Duy
The repo setup procedure is updated to detect $GIT_DIR/commondir and
set $GIT_COMMON_DIR properly.

The core.worktree is ignored when $GIT_COMMON_DIR is set. This is
because the config file is shared in multi-checkout setup, but
checkout directories _are_ different. Making core.worktree effective
in all checkouts mean it's back to a single checkout.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 Documentation/config.txt|  2 ++
 Documentation/git-rev-parse.txt |  3 ++
 builtin/rev-parse.c |  4 +++
 cache.h |  1 +
 environment.c   |  8 ++---
 setup.c | 33 +-
 t/t1501-worktree.sh | 76 +
 t/t1510-repo-setup.sh   |  1 +
 trace.c |  1 +
 9 files changed, 115 insertions(+), 14 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 3b5b24a..98b8ef0 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -380,6 +380,8 @@ false), while all other repositories are assumed to be bare 
(bare
 
 core.worktree::
Set the path to the root of the working tree.
+   If GIT_COMMON_DIR environment variable is set, core.worktree
+   is ignored and not used for determining the root of working tree.
This can be overridden by the GIT_WORK_TREE environment
variable and the '--work-tree' command-line option.
The value can be an absolute path or relative to the path to
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 0fed5a4..c10cc62 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -215,6 +215,9 @@ If `$GIT_DIR` is not defined and the current directory
 is not detected to lie in a Git repository or work tree
 print a message to stderr and exit with nonzero status.
 
+--git-common-dir::
+   Show `$GIT_COMMON_DIR` if defined, else `$GIT_DIR`.
+
 --is-inside-git-dir::
When the current working directory is below the repository
directory print true, otherwise false.
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index a6f4697..1ce73e8 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -759,6 +759,10 @@ int cmd_rev_parse(int argc, const char **argv, const char 
*prefix)
free(cwd);
continue;
}
+   if (!strcmp(arg, --git-common-dir)) {
+   puts(get_git_common_dir());
+   continue;
+   }
if (!strcmp(arg, --resolve-git-dir)) {
const char *gitdir = argv[++i];
if (!gitdir)
diff --git a/cache.h b/cache.h
index bf26301..1784fc6 100644
--- a/cache.h
+++ b/cache.h
@@ -437,6 +437,7 @@ extern char *get_object_directory(void);
 extern char *get_index_file(void);
 extern char *get_graft_file(void);
 extern int set_git_dir(const char *path);
+extern int get_common_dir(struct strbuf *sb, const char *gitdir);
 extern const char *get_git_namespace(void);
 extern const char *strip_namespace(const char *namespaced_ref);
 extern const char *get_git_work_tree(void);
diff --git a/environment.c b/environment.c
index 78a07e4..d5b0788 100644
--- a/environment.c
+++ b/environment.c
@@ -141,6 +141,7 @@ static char *git_path_from_env(const char *envvar, const 
char *git_dir,
 
 static void setup_git_env(void)
 {
+   struct strbuf sb = STRBUF_INIT;
const char *gitfile;
const char *shallow_file;
 
@@ -149,12 +150,9 @@ 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_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
-   if (git_common_dir) {
+   if (get_common_dir(sb, git_dir))
git_common_dir_env = 1;
-   git_common_dir = xstrdup(git_common_dir);
-   } else
-   git_common_dir = git_dir;
+   git_common_dir = strbuf_detach(sb, NULL);
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,
diff --git a/setup.c b/setup.c
index 1d4f1aa..b99bdd3 100644
--- a/setup.c
+++ b/setup.c
@@ -224,14 +224,15 @@ void verify_non_filename(const char *prefix, const char 
*arg)
'git command [revision...] -- [file...]', arg);
 }
 
-static void get_common_dir(struct strbuf *sb, const char *gitdir)
+int get_common_dir(struct strbuf *sb, const char *gitdir)
 {
struct strbuf data = STRBUF_INIT;
struct strbuf path = STRBUF_INIT;
const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);

[PATCH v3 18/32] setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 setup.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/setup.c b/setup.c
index 00a23e6..1d4f1aa 100644
--- a/setup.c
+++ b/setup.c
@@ -346,6 +346,10 @@ static int check_repository_format_gently(const char 
*gitdir, int *nongit_ok)
const char *repo_config;
int ret = 0;
 
+   get_common_dir(sb, gitdir);
+   strbuf_addstr(sb, /config);
+   repo_config = sb.buf;
+
/*
 * git_config() can't be used here because it calls git_pathdup()
 * to get $GIT_CONFIG/config. That call will make setup_git_env()
@@ -355,8 +359,6 @@ static int check_repository_format_gently(const char 
*gitdir, int *nongit_ok)
 * Use a gentler version of git_config() to check if this repo
 * is a good one.
 */
-   strbuf_addf(sb, %s/config, gitdir);
-   repo_config = sb.buf;
git_config_early(check_repository_format_version, NULL, repo_config);
if (GIT_REPO_VERSION  repository_format_version) {
if (!nongit_ok)
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 25/32] checkout: clean up half-prepared directories in --to mode

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 builtin/checkout.c | 48 
 t/t2025-checkout-to.sh |  6 ++
 2 files changed, 54 insertions(+)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 6d68913..bd0e2d5 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -20,6 +20,7 @@
 #include resolve-undo.h
 #include submodule.h
 #include argv-array.h
+#include sigchain.h
 
 static const char * const checkout_usage[] = {
N_(git checkout [options] branch),
@@ -823,6 +824,35 @@ static int switch_branches(const struct checkout_opts 
*opts,
return ret || writeout_error;
 }
 
+static char *junk_work_tree;
+static char *junk_git_dir;
+static int is_junk;
+static pid_t junk_pid;
+
+static void remove_junk(void)
+{
+   struct strbuf sb = STRBUF_INIT;
+   if (!is_junk || getpid() != junk_pid)
+   return;
+   if (junk_git_dir) {
+   strbuf_addstr(sb, junk_git_dir);
+   remove_dir_recursively(sb, 0);
+   strbuf_reset(sb);
+   }
+   if (junk_work_tree) {
+   strbuf_addstr(sb, junk_work_tree);
+   remove_dir_recursively(sb, 0);
+   }
+   strbuf_release(sb);
+}
+
+static void remove_junk_on_signal(int signo)
+{
+   remove_junk();
+   sigchain_pop(signo);
+   raise(signo);
+}
+
 static int prepare_linked_checkout(const struct checkout_opts *opts,
   struct branch_info *new)
 {
@@ -859,8 +889,15 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
strbuf_addf(sb_repo, %d, counter);
}
name = strrchr(sb_repo.buf, '/') + 1;
+
+   junk_pid = getpid();
+   atexit(remove_junk);
+   sigchain_push_common(remove_junk_on_signal);
+
if (mkdir(sb_repo.buf, 0777))
die_errno(_(could not create directory of '%s'), sb_repo.buf);
+   junk_git_dir = xstrdup(sb_repo.buf);
+   is_junk = 1;
 
/*
 * lock the incomplete repo so prune won't delete it, unlock
@@ -873,6 +910,7 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
if (safe_create_leading_directories_const(sb_git.buf))
die_errno(_(could not create leading directories of '%s'),
  sb_git.buf);
+   junk_work_tree = xstrdup(path);
 
strbuf_reset(sb);
strbuf_addf(sb, %s/gitdir, sb_repo.buf);
@@ -902,9 +940,19 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
cp.git_cmd = 1;
cp.argv = opts-saved_argv;
ret = run_command(cp);
+   if (!ret) {
+   is_junk = 0;
+   free(junk_work_tree);
+   free(junk_git_dir);
+   junk_work_tree = NULL;
+   junk_git_dir = NULL;
+   }
strbuf_reset(sb);
strbuf_addf(sb, %s/locked, sb_repo.buf);
unlink_or_warn(sb.buf);
+   strbuf_release(sb);
+   strbuf_release(sb_repo);
+   strbuf_release(sb_git);
return ret;
 }
 
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
index edd3404..e2db078 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-checkout-to.sh
@@ -17,6 +17,12 @@ test_expect_success 'checkout --to an existing worktree' '
test_must_fail git checkout --detach --to existing master
 '
 
+test_expect_success 'checkout --to refuses to checkout locked branch' '
+   test_must_fail git checkout --to zere master 
+   ! test -d zere 
+   ! test -d .git/worktrees/zere
+'
+
 test_expect_success 'checkout --to a new worktree' '
git rev-parse HEAD expect 
git checkout --detach --to here master 
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 32/32] t2025: add a test to make sure grafts is working from a linked checkout

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 t/t2025-checkout-to.sh | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
index 4bd1df4..eddd325 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-checkout-to.sh
@@ -96,4 +96,22 @@ test_expect_success 'checkout from a bare repo without --to' 
'
)
 '
 
+test_expect_success 'checkout with grafts' '
+   test_when_finished rm .git/info/grafts 
+   test_commit abc 
+   SHA1=`git rev-parse HEAD` 
+   test_commit def 
+   test_commit xyz 
+   echo `git rev-parse HEAD` $SHA1 .git/info/grafts 
+   cat expected -\EOF 
+   xyz
+   abc
+   EOF
+   git log --format=%s -2 actual 
+   test_cmp expected actual 
+   git checkout --detach --to grafted master 
+   git --git-dir=grafted/.git log --format=%s -2 actual 
+   test_cmp expected actual
+'
+
 test_done
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 31/32] checkout: don't require a work tree when checking out into a new one

2014-09-27 Thread Nguyễn Thái Ngọc Duy
From: Dennis Kaarsemaker den...@kaarsemaker.net

For normal use cases, it does not make sense for 'checkout' to work on
a bare repository, without a worktree. But checkout --to is an
exception because it _creates_ a new worktree. Allow this option to
run on bare repositories.

People who check out from a bare repository should remember that
core.logallrefupdates is off by default and it should be turned back
on. `--to` cannot do this automatically behind the user's back because
some user may deliberately want no reflog.

For people interested in repository setup/discovery code,
is_bare_repository_cfg (aka core.bare) is unchanged by this patch,
which means 'true' by default for bare repos. Fortunately when we get
the repo through a linked checkout, is_bare_repository_cfg is never
used. So all is still good.

[nd: commit message]

Signed-off-by: Dennis Kaarsemaker den...@kaarsemaker.net
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 builtin/checkout.c |  3 +++
 git.c  |  2 +-
 t/t2025-checkout-to.sh | 15 +++
 3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index bd0e2d5..01d0f2f 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1364,6 +1364,9 @@ int cmd_checkout(int argc, const char **argv, const char 
*prefix)
if (opts.new_worktree_mode)
opts.new_worktree = NULL;
 
+   if (!opts.new_worktree)
+   setup_work_tree();
+
if (conflict_style) {
opts.merge = 1; /* implied */
git_xmerge_config(merge.conflictstyle, conflict_style, NULL);
diff --git a/git.c b/git.c
index 4076b01..6c1ac0c 100644
--- a/git.c
+++ b/git.c
@@ -383,7 +383,7 @@ static struct cmd_struct commands[] = {
{ check-ignore, cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
{ check-mailmap, cmd_check_mailmap, RUN_SETUP },
{ check-ref-format, cmd_check_ref_format },
-   { checkout, cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
+   { checkout, cmd_checkout, RUN_SETUP },
{ checkout-index, cmd_checkout_index,
RUN_SETUP | NEED_WORK_TREE},
{ cherry, cmd_cherry, RUN_SETUP },
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
index e2db078..4bd1df4 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-checkout-to.sh
@@ -81,4 +81,19 @@ test_expect_success 'not die on re-checking out current 
branch' '
)
 '
 
+test_expect_success 'checkout --to from a bare repo' '
+   (
+   git clone --bare . bare 
+   cd bare 
+   git checkout --to ../there2 -b bare-master master
+   )
+'
+
+test_expect_success 'checkout from a bare repo without --to' '
+   (
+   cd bare 
+   test_must_fail git checkout master
+   )
+'
+
 test_done
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 30/32] git_path(): keep info/sparse-checkout per work-tree

2014-09-27 Thread Nguyễn Thái Ngọc Duy
Currently git_path(info/sparse-checkout) resolves to
$GIT_COMMON_DIR/info/sparse-checkout in multiple worktree mode. It
makes more sense for the sparse checkout patterns to be per worktree,
so you can have multiple checkouts with different parts of the tree.

With this, git checkout --to new on a sparse checkout will create
new as a full checkout. Which is expected, it's how a new checkout
is made. The user can reshape the worktree afterwards.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
Signed-off-by: Junio C Hamano gits...@pobox.com
---
 path.c| 3 ++-
 t/t0060-path-utils.sh | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/path.c b/path.c
index cd8e2d6..35d498e 100644
--- a/path.c
+++ b/path.c
@@ -103,7 +103,8 @@ 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))
+   if (is_dir_file(base, logs, HEAD) ||
+   is_dir_file(base, info, sparse-checkout))
return; /* keep this in $GIT_DIR */
for (p = common_list; *p; p++) {
const char *path = *p;
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index f5d6f80..93605f4 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -270,6 +270,7 @@ test_git_path GIT_COMMON_DIR=bar objects  
bar/objects
 test_git_path GIT_COMMON_DIR=bar objects/bar  bar/objects/bar
 test_git_path GIT_COMMON_DIR=bar info/exclude bar/info/exclude
 test_git_path GIT_COMMON_DIR=bar info/grafts  bar/info/grafts
+test_git_path GIT_COMMON_DIR=bar info/sparse-checkout 
.git/info/sparse-checkout
 test_git_path GIT_COMMON_DIR=bar remotes/bar  bar/remotes/bar
 test_git_path GIT_COMMON_DIR=bar branches/bar bar/branches/bar
 test_git_path GIT_COMMON_DIR=bar logs/refs/heads/master   
bar/logs/refs/heads/master
-- 
2.1.0.rc0.78.gc0d8480

--
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 v3 29/32] count-objects: report unused files in $GIT_DIR/worktrees/...

2014-09-27 Thread Nguyễn Thái Ngọc Duy
In linked checkouts, borrowed parts like config is taken from
$GIT_COMMON_DIR. $GIT_DIR/config is never used. Report them as
garbage.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 builtin/count-objects.c |  4 +++-
 cache.h |  1 +
 path.c  | 29 +++--
 3 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index a7f70cb..d3a1620 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -102,8 +102,10 @@ int cmd_count_objects(int argc, const char **argv, const 
char *prefix)
/* we do not take arguments other than flags for now */
if (argc)
usage_with_options(count_objects_usage, opts);
-   if (verbose)
+   if (verbose) {
report_garbage = real_report_garbage;
+   report_linked_checkout_garbage();
+   }
memcpy(path, objdir, len);
if (len  objdir[len-1] != '/')
path[len++] = '/';
diff --git a/cache.h b/cache.h
index aedfd05..ab3adb6 100644
--- a/cache.h
+++ b/cache.h
@@ -713,6 +713,7 @@ extern const char *mkpath(const char *fmt, ...) 
__attribute__((format (printf, 1
 extern const char *git_path(const char *fmt, ...) __attribute__((format 
(printf, 1, 2)));
 extern const char *git_path_submodule(const char *path, const char *fmt, ...)
__attribute__((format (printf, 2, 3)));
+extern void report_linked_checkout_garbage(void);
 
 /*
  * Return the name of the file in the local object database that would
diff --git a/path.c b/path.c
index 72eca6d..cd8e2d6 100644
--- a/path.c
+++ b/path.c
@@ -4,6 +4,7 @@
 #include cache.h
 #include strbuf.h
 #include string-list.h
+#include dir.h
 
 static int get_st_mode_bits(const char *path, int *mode)
 {
@@ -91,9 +92,9 @@ 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, /modules,
/objects, /refs, /remotes, /worktrees, /rr-cache, /svn,
-   config, gc.pid, packed-refs, shallow,
+   config, !gc.pid, packed-refs, shallow,
NULL
 };
 
@@ -107,6 +108,8 @@ static void update_common_dir(struct strbuf *buf, int 
git_dir_len)
for (p = common_list; *p; p++) {
const char *path = *p;
int is_dir = 0;
+   if (*path == '!')
+   path++;
if (*path == '/') {
path++;
is_dir = 1;
@@ -122,6 +125,28 @@ static void update_common_dir(struct strbuf *buf, int 
git_dir_len)
}
 }
 
+void report_linked_checkout_garbage(void)
+{
+   struct strbuf sb = STRBUF_INIT;
+   const char **p;
+   int len;
+
+   if (!git_common_dir_env)
+   return;
+   strbuf_addf(sb, %s/, get_git_dir());
+   len = sb.len;
+   for (p = common_list; *p; p++) {
+   const char *path = *p;
+   if (*path == '!')
+   continue;
+   strbuf_setlen(sb, len);
+   strbuf_addstr(sb, path);
+   if (file_exists(sb.buf))
+   report_garbage(unused in linked checkout, sb.buf);
+   }
+   strbuf_release(sb);
+}
+
 static void adjust_git_path(struct strbuf *buf, int git_dir_len)
 {
const char *base = buf-buf + git_dir_len;
-- 
2.1.0.rc0.78.gc0d8480

--
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