Re: Topic sk/mingw-unicode-spawn-args breaks tests

2014-07-12 Thread Stepan Kasal
Hello Hannes,

 Am 10.07.2014 22:05, schrieb Johannes Sixt:
  It looks like I totally missed the topic sk/mingw-unicode-spawn-args.
...
  Am I doing something wrong? Does the topic depend on a particular
  version of MSYS (or DLL)?

unfortunately, I paused my submissions at random point.

I'm sorry for breaking your setup.  I was not aware there is any
working Windows setup beyond msysGit.  Thus I did not object when the
half-done work was going to be moved ot master.

I'll try to submit the patches needed so that your setup works again.

Karsten writes:
 At first glance, t0050 seems to fail because the unicode file
 name patches are still missing.

Indeed, this is a pair of patches on the tip of my queue.

 t4041 tries to pass ISO-8859-1 encoded bytes on the command line,
 which simply doesn't work on Windows (all OS APIs 'talk' UTF-16).
 We have a fix for this in the msysgit fork [1] (but unfortunately
 in another branch, so Stepan couldn't know the patch is related).

There is a whole branch named win-tests or some such.  I remember I
was hunting for not-yet resolved instances of this bug.  This
convinced me that the test suite of vanilla git cannot work on
Windows.  I was not aware about the fact that this problem was masked
in the versions before Karsten's unicode patches.

Hannes, I'd like to submit the patches mentioned here during the
following week and I'd be glad to hear from you.

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


Re: 745224e0 gcc-4.9 emmintrin.h build error

2014-07-12 Thread Tuncer Ayaz
On Sat, Jul 12, 2014 at 6:56 AM, Jeff King wrote:
 On Fri, Jul 11, 2014 at 12:12:55AM +0200, Tuncer Ayaz wrote:

  Sorry, didn't test properly when I tried with/without config.mak,
  and PROFILE=BUILD was the problem. I had that in config.mak based
  on information gathered from INSTALL and Makefile. To be clear, is
  PROFILE=BUILD (still) supported?

 I think none of the regular devs uses PROFILE, and it bit-rotted
 somewhat. Andi Kleen recently posted a series to fix it[1]. I can
 reproduce your problem without that series, but compiling with
 ak/profile-feedback-build merged in seems to work OK.

 [1] http://thread.gmane.org/gmane.comp.version-control.git/253005

Yes, Andi's patch works.

Any idea when ak/profile-feedback-build will land in master?
--
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


Re: 745224e0 gcc-4.9 emmintrin.h build error

2014-07-12 Thread Tuncer Ayaz
On Sat, Jul 12, 2014 at 6:56 AM, Jeff King wrote:

 I think none of the regular devs uses PROFILE, and it bit-rotted

By the way, is there no build (CI) server for git.git to regularly
test branches on different platforms or at least different build
configs on the same platform?
--
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


Re: [PATCH] http: Add Accept-Language header if possible

2014-07-12 Thread Peter Krefting

Jeff King:


If that is the case, though, I wonder if we should actually be adding it
as a git-protocol header so that all transports can benefit (i.e., we
could be localizing human-readable error messages in upload-pack,
receive-pack, etc).


That would be very nice, thre is a lot of language mixing going on at 
the moment.


--
\\// Peter - http://www.softwolves.pp.se/
--
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


Re: [PATCH v3] http: Add Accept-Language header if possible

2014-07-12 Thread Peter Krefting

Yi EungJun:


Add an Accept-Language header which indicates the user's preferred
languages defined by $LANGUAGE, $LC_ALL, $LC_MESSAGES and $LANG.


This one seems to fix all the issues I had with the first patch, 
thanks!


--
\\// Peter - http://www.softwolves.pp.se/
--
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


Re: [PATCH v6 26/32] checkout: detach if the branch is already checked out elsewhere

2014-07-12 Thread Max Kirillov
On Wed, Jul 09, 2014 at 02:33:11PM +0700, Nguyễn Thái Ngọc Duy wrote:
 +static int check_linked_checkout(struct branch_info *new,
 +   const char *name, const char *path)
 +{
...
 + if (!strncmp(start, new-path, end - start) 
 + new-path[end - start] == '\0') {

This also detaches if the holding checkout is _this_
checkout, that is, when you are checking out the currently
checked our branch.

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


Re: [PATCH 2/7] move setting of object-type to alloc_* functions

2014-07-12 Thread Ramsay Jones
On 11/07/14 09:46, Jeff King wrote:
 The struct object type implements basic object
 polymorphism.  Individual instances are allocated as
 concrete types (or as a union type that can store any
 object), and a struct object * can be cast into its real
 type after examining its type enum.  This means it is
 dangerous to have a type field that does not match the
 allocation (e.g., setting the type field of a struct blob
 to OBJ_COMMIT would mean that a reader might read past the
 allocated memory).
 
 In most of the current code this is not a problem; the first
 thing we do after allocating an object is usually to set its
 type field by passing it to create_object. However, the
 virtual commits we create in merge-recursive.c do not ever
 get their type set. This does not seem to have caused
 problems in practice, though (presumably because we always
 pass around a struct commit pointer and never even look at
 the type).
 
 We can fix this oversight and also make it harder for future
 code to get it wrong by setting the type directly in the
 object allocation functions.
 
 This will also make it easier to fix problems with commit
 index allocation, as we know that any object allocated by
 alloc_commit_node will meet the invariant that an object
 with an OBJ_COMMIT type field will have a unique index
 number.
 
 Signed-off-by: Jeff King p...@peff.net
 ---
  alloc.c | 18 ++
  blob.c  |  2 +-
  builtin/blame.c |  1 -
  commit.c|  2 +-
  object.c|  5 ++---
  object.h|  2 +-
  tag.c   |  2 +-
  tree.c  |  2 +-
  8 files changed, 17 insertions(+), 17 deletions(-)
 
 diff --git a/alloc.c b/alloc.c
 index d7c3605..fd5fcb7 100644
 --- a/alloc.c
 +++ b/alloc.c
 @@ -18,11 +18,11 @@
  
  #define BLOCKING 1024
  
 -#define DEFINE_ALLOCATOR(name, type) \
 +#define DEFINE_ALLOCATOR(name, flag, type)   \
  static struct alloc_state name##_state;  \
  void *alloc_##name##_node(void)  \
  {\
 - return alloc_node(name##_state, sizeof(type)); \
 + return alloc_node(name##_state, flag, sizeof(type));   \
  }

I don't particularly like 'flag' here. (not a massive dislike, mind you:)

Perhaps: flag-object_type, type-node_type?
Or, if that's too verbose, maybe just: flag-type, type-node?

ATB,
Ramsay Jones


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


Re: [PATCH 2/7] move setting of object-type to alloc_* functions

2014-07-12 Thread Ramsay Jones
On 11/07/14 09:46, Jeff King wrote:

[snip]

Sorry, hit send too early ...

 diff --git a/blob.c b/blob.c
 index ae320bd..5720a38 100644
 --- a/blob.c
 +++ b/blob.c
 @@ -7,7 +7,7 @@ struct blob *lookup_blob(const unsigned char *sha1)
  {
   struct object *obj = lookup_object(sha1);
   if (!obj)
 - return create_object(sha1, OBJ_BLOB, alloc_blob_node());
 + return create_object(sha1, alloc_blob_node());
   if (!obj-type)
   obj-type = OBJ_BLOB;
   if (obj-type != OBJ_BLOB) {
 diff --git a/builtin/blame.c b/builtin/blame.c
 index d3b256e..8f3e311 100644
 --- a/builtin/blame.c
 +++ b/builtin/blame.c
 @@ -2287,7 +2287,6 @@ static struct commit *fake_working_tree_commit(struct 
 diff_options *opt,
   commit = alloc_commit_node();
   commit-object.parsed = 1;
   commit-date = now;
 - commit-object.type = OBJ_COMMIT;
   parent_tail = commit-parents;
  
   if (!resolve_ref_unsafe(HEAD, head_sha1, 1, NULL))
 diff --git a/commit.c b/commit.c
 index fb7897c..21ed310 100644
 --- a/commit.c
 +++ b/commit.c
 @@ -63,7 +63,7 @@ struct commit *lookup_commit(const unsigned char *sha1)
   struct object *obj = lookup_object(sha1);
   if (!obj) {
   struct commit *c = alloc_commit_node();
 - return create_object(sha1, OBJ_COMMIT, c);
 + return create_object(sha1, c);
   }

perhaps:
if (!obj)
return create_object(sha1, alloc_commit_node());

(increasing similarity with other calls here ...)

   if (!obj-type)
   obj-type = OBJ_COMMIT;
 diff --git a/object.c b/object.c
 index 9c31e9a..a950b85 100644
 --- a/object.c
 +++ b/object.c
 @@ -141,13 +141,12 @@ static void grow_object_hash(void)
   obj_hash_size = new_hash_size;
  }
  
 -void *create_object(const unsigned char *sha1, int type, void *o)
 +void *create_object(const unsigned char *sha1, void *o)
  {
   struct object *obj = o;
  
   obj-parsed = 0;
   obj-used = 0;
 - obj-type = type;
   obj-flags = 0;
   hashcpy(obj-sha1, sha1);
  
 @@ -163,7 +162,7 @@ struct object *lookup_unknown_object(const unsigned char 
 *sha1)
  {
   struct object *obj = lookup_object(sha1);
   if (!obj)
 - obj = create_object(sha1, OBJ_NONE, alloc_object_node());
 + obj = create_object(sha1, alloc_object_node());
   return obj;
  }
  
 diff --git a/object.h b/object.h
 index 6e12f2c..8020ace 100644
 --- a/object.h
 +++ b/object.h
 @@ -79,7 +79,7 @@ extern struct object *get_indexed_object(unsigned int);
   */
  struct object *lookup_object(const unsigned char *sha1);
  
 -extern void *create_object(const unsigned char *sha1, int type, void *obj);
 +extern void *create_object(const unsigned char *sha1, void *obj);
  
  /*
   * Returns the object, having parsed it to find out what it is.
 diff --git a/tag.c b/tag.c
 index 7b07921..79552c7 100644
 --- a/tag.c
 +++ b/tag.c
 @@ -40,7 +40,7 @@ struct tag *lookup_tag(const unsigned char *sha1)
  {
   struct object *obj = lookup_object(sha1);
   if (!obj)
 - return create_object(sha1, OBJ_TAG, alloc_tag_node());
 + return create_object(sha1, alloc_tag_node());
   if (!obj-type)
   obj-type = OBJ_TAG;
   if (obj-type != OBJ_TAG) {
 diff --git a/tree.c b/tree.c
 index c8c49d7..ed66575 100644
 --- a/tree.c
 +++ b/tree.c
 @@ -183,7 +183,7 @@ struct tree *lookup_tree(const unsigned char *sha1)
  {
   struct object *obj = lookup_object(sha1);
   if (!obj)
 - return create_object(sha1, OBJ_TREE, alloc_tree_node());
 + return create_object(sha1, alloc_tree_node());
   if (!obj-type)
   obj-type = OBJ_TREE;
   if (obj-type != OBJ_TREE) {
 

ATB,
Ramsay Jones



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


Re: git-p4 and initial import

2014-07-12 Thread Pete Wyckoff
lcharri...@promptu.com wrote on Thu, 10 Jul 2014 15:45 +0200:
 I've used git-p4 for several years now and it's generally working well for
 me.
 
 The only thing that bugs me at this time is having to re-clone regularly.
 Here is how this happens:
 
 * Say my p4 client maps //foo/bar/... to /home/jdoe/perforce/foo/bar/... (I
 don't want to clone the entire repo, because it's too big).
 * I do git p4 clone --use-client-spec //foo /home/jdoe/git/foo, work with
 it, all goes well.
 * Meanwhile, at some point somebody else adds //foo/baz.
 * Eventually I need //foo/baz. I add it to my p4 client.
 * Naturally, git-p4 won't pick up the changes, because they happened before
 I added //foo/baz to my client.
 * So I git reset --hard to the first commit, delete even that using git
 update-ref -d HEAD, then again I do git p4 clone //foo /home/jdoe/git/foo.
 When the repo gets big, this takes a lot of time.
 
 So, I have a few questions:
 1. Am I doing this wrong? Is there another way I could proceed?

What you observe makes sense.  You do need somehow to sync in the
change that added the files in //foo/baz.  Say that path was
added in change 5, and you already synced change 5 but did not 
have //foo/baz in your client spec.  It would not be in the git
commit corresponding to change 5.

Now you don't have to reset all the way back to the first commit,
you can just rewind back to the one that introduced //foo/baz.
This still is disruptive and takes a while, depending on how long
between when //foo/baz got added and when you decided you needed
it.

Say there's just a few changes to //foo/baz, among the thousands
of ones you've already synced.  You can surgically go in and
re-sync just those few changes, rebasing the rest of the changes
after each one.  Something like:

p4change=3227  ;# want to reimport this one as it added baz
sha=$(git rev-parse :/change = $p4change)
git update-ref refs/remotes/p4/master $sha^
git p4 sync @$p4change  ;# re-sync 3227, now with baz
git rebase --onto p4/master $sha  ;# put everything back on top

Now you don't have to re-import change 3228 etc.  Repeat until
you've fixed up all the baz.  Of course the rebases might be
slow...

If you don't care about your history, you could make a new branch
and import just //foo/baz into the new branch.

git p4 sync --branch refs/remotes/p4/baz //foo/baz

Then merge it into your main branch.  You may have to use a
different client spec to put the baz files in the right subdir
name.  Or filter-branch --subdirectory-filter.  Now adjust your
main client spec and future git p4 sync will grab both //foo/bar
and //foo/baz.  Of course you have this odd wart in your history
where they got glued together.

If you do script up something cool, be sure to send it in for
contrib/ or even a magic option in git-p4.

 2. It occurred to me that when I re-clone a repository using
 --use-client-spec, I already have everything I need in my local copy of the
 p4 client. Why does git-p4 need to redownload everything from the
 repository? Could we find a way to tell it to p4 sync, then fetch the files
 from the local copy? Or is there a way I can copy everything over from my
 local client and pretend this is the initial import?

That should work in theory.  We've got all the blobs (file
objects) already. If we had a database that mapped each p4
file#revision to a blob, git p4 sync could look at that and see
if it already has the blob.  Possibly with
.git/objects/info/alternates to grab them from somewhere nearby.

But we don't have that database.  Git p4 knew the mapping when it
did the syncs, but didn't write them down.  You could script up
something to recreate this by asking p4 for the revision of each
file for each change already in git.  And git already knows the
blob for each of files in those changes.  With this mapping, you
could modify git p4 to check for the blob first, before doing p4
print on the file#rev.  See also git-p4raw from Sam Vilain that
builds up SQL from a raw p4 db.

Fun bit of work maybe if you're motivated.

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


Re: [PATCH 2/7] move setting of object-type to alloc_* functions

2014-07-12 Thread Jeff King
On Sat, Jul 12, 2014 at 03:44:06PM +0100, Ramsay Jones wrote:

  -   return alloc_node(name##_state, sizeof(type)); \
  +   return alloc_node(name##_state, flag, sizeof(type));   \
   }
 
 I don't particularly like 'flag' here. (not a massive dislike, mind you:)
 
 Perhaps: flag-object_type, type-node_type?
 Or, if that's too verbose, maybe just: flag-type, type-node?

Me either, but as you noticed, type was taken. Your suggestions seem
fine. We could also just do away with the macro as discussed earlier (we
already do in the commit_node case, anyway...).

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


Re: [PATCH 2/7] move setting of object-type to alloc_* functions

2014-07-12 Thread Jeff King
On Sat, Jul 12, 2014 at 03:55:35PM +0100, Ramsay Jones wrote:

  if (!obj) {
  struct commit *c = alloc_commit_node();
  -   return create_object(sha1, OBJ_COMMIT, c);
  +   return create_object(sha1, c);
  }
 
 perhaps:
   if (!obj)
   return create_object(sha1, alloc_commit_node());
 
 (increasing similarity with other calls here ...)

Yeah, I noticed that but didn't change it to keep the diff small. The
one that should have is 969eba6, but it is not a big deal to do it here.

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


Re: git p4 diff-tree ambiguous argument error

2014-07-12 Thread Pete Wyckoff
duanemur...@mac.com wrote on Thu, 10 Jul 2014 12:19 -0700:
 Some additional investigation. 
 
 I am working in a copy of a repository that was originally used to pull the 
 data 
 from Perforce. As part of my experiments to figure out this problem, I 
 deleted 
 the contents of .git/git-p4-tmp/. 
 
 I noticed that git-p4 would continue if those files were present. I have now 
 copied the files that were in .git/git-p4-tmp/ from the other repository. 
 
 git-p4 is not crashing now, but I also noticed that none of the dates on 
 these files
 have changed. These files should have been touched each time that a branch is 
 taken,
 but these files have not changed while the sync is running.
 
 That seems significant. 
 
 I expect git-p4 to crash again on a new commit that is not in 
 .git/git-p4-tmp/. 
 Then I have to start the 8-12 hour process over again (did I mention 70k 
 commits?).

Bizarre.  That directory is really supposed to be temporary, and
live only during a single git p4 invocation.  It's just a bunch
of branch heads for the temporary commits.  I don't know why
those branches, and the git-p4-tmp directory, hang around after
you run git p4.  Might be worth your investigation.

The second weirdness is why a new run doesn't create the branch.
This maybe points to self.checkpoint() not really checkpointing.
It does send a checkpoint down the git fast-import stream,
which is supposed to make it write the branches out.  You might
consider grabbing the fast-import process in a debugger and see
why it's not writing out the branch head.

There's lots of changes since v1.7.12.4, but nothing obvious I
can see that would cause this.  Sorry,

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


Re: [PATCH 00/14] Add submodule test harness

2014-07-12 Thread Jens Lehmann
Am 10.07.2014 22:52, schrieb Junio C Hamano:
 Junio C Hamano gits...@pobox.com writes:
 
 Jens Lehmann jens.lehm...@web.de writes:

 I agree, but this case is special. The test asserts that nobody
 added, modified or removed *anything* inside the .git directory.
 The reason for problem we are seeing here is that I have to
 remove the core.worktree setting when moving the git directory
 from .git/modules into the submodule work tree.

 Hmph.  Comparing the files with core.worktree removed sounds like a
 workaround that knows too much about the implementation detail of
 what is being tested.  I am just wondering if core.worktree will
 stay forever be the only thing that is special, or there may come
 other things (perhaps as a fallout of integrating things like Duy's
 multiple-worktree stuff).

 But perhaps we cannot do better than this.
 
 One thing we should be able to do (and must do) better is to
 validate that core.worktree in the relocated config file actually
 points at the right place.  Unsetting before comparing may let us
 compare the relocated one in .git/modules/$1/config with the one
 that is embedded in the working tree (hence no .git/config), but the
 way your how about this? patch does, we wouldn't catch a possible
 breakage to the relocation code to point core.worktree to a bogus
 location, I'm afraid.

Indeed.

 Perhaps squashing this to 7e8e5af9 instead?

Yes please, this is much better than my first attempt.

  t/lib-submodule-update.sh | 19 ---
  1 file changed, 12 insertions(+), 7 deletions(-)
 
 diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
 index e441b98..fc1da84 100755
 --- a/t/lib-submodule-update.sh
 +++ b/t/lib-submodule-update.sh
 @@ -110,18 +110,23 @@ replace_gitfile_with_git_dir () {
  }
  
  # Test that the .git directory in the submodule is unchanged (except for the
 -# core.worktree setting, which we temporarily restore). Call this function
 -# before test_submodule_content as the latter might write the index file
 -# leading to false positive index differences.
 +# core.worktree setting, which appears only in $GIT_DIR/modules/$1/config).
 +# Call this function before test_submodule_content as the latter might
 +# write the index file leading to false positive index differences.
  test_git_directory_is_unchanged () {
   (
 - cd $1 
 - git config core.worktree ../../../$1
 + cd .git/modules/$1 
 + # does core.worktree point at the right place?
 + test $(git config core.worktree) = ../../../$1 
 + # remove it temporarily before comparing, as
 + # $1/.git/config lacks it...
 + git config --unset core.worktree
   ) 
   diff -r .git/modules/$1 $1/.git 
   (
 - cd $1 
 - GIT_WORK_TREE=. git config --unset core.worktree
 + # ... and then restore.
 + cd .git/modules/$1 
 + git config core.worktree ../../../$1
   )
  }
  
 

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


Re: [PATCH v3] http: Add Accept-Language header if possible

2014-07-12 Thread Yi, EungJun
Thanks for your detailed review and nice suggestions. I will accept
most of them.

2014-07-12 2:35 GMT+09:00 Jeff King p...@peff.net:
 + /* Decide the precision for q-factor on number of preferred languages. 
 */
 + if (num_langs + 1  100) { /* +1 is for '*' */
 + q_precision = 0.001;
 + q_format = ; q=%.3f;
 + } else if (num_langs + 1  10) { /* +1 is for '*' */
 + q_precision = 0.01;
 + q_format = ; q=%.2f;
 + }

 I don't mind this auto-precision too much, but I'm not sure it buys us
 anything. We are still setting a hard-limit at 100, and it just means we
 write 0.1 instead of 0.001 sometimes.

It means we use 0.1 if possible.

From my observation, many major web browsers doesn't or didn't send
q-factor of 2 or 3 decimal places. Google chrome doesn't currently and
Mozilla firefox also didn't before 2012 [1]. I think it means some old
and naive web servers may not support q-factor of 2 or 3 decimal
places because major web browsers don't send it. So I think we should
use 0.1 if possible for interoperability with the buggy servers.

But, quite frankly, it is just a possibility and I have no evidence
which proves that such kind of buggy servers really exist. Please let
me know if anybody know about it.

[1]: http://hg.mozilla.org/integration/mozilla-inbound/rev/b0b07ef904ea
--
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


Re: git p4 diff-tree ambiguous argument error

2014-07-12 Thread Duane Murphy
On Jul 12, 2014, at 11:10 AM, Pete Wyckoff p...@padd.com wrote:

 Some additional investigation. 
 
 I am working in a copy of a repository that was originally used to pull the 
 data 
 from Perforce. As part of my experiments to figure out this problem, I 
 deleted 
 the contents of .git/git-p4-tmp/. 
 
 I noticed that git-p4 would continue if those files were present. I have now 
 copied the files that were in .git/git-p4-tmp/ from the other repository. 
 
 git-p4 is not crashing now, but I also noticed that none of the dates on 
 these files
 have changed. These files should have been touched each time that a branch 
 is taken,
 but these files have not changed while the sync is running.
 
 That seems significant. 
 
 I expect git-p4 to crash again on a new commit that is not in 
 .git/git-p4-tmp/. 
 Then I have to start the 8-12 hour process over again (did I mention 70k 
 commits?).
 
 Bizarre.  That directory is really supposed to be temporary, and
 live only during a single git p4 invocation.  It's just a bunch
 of branch heads for the temporary commits.  I don't know why
 those branches, and the git-p4-tmp directory, hang around after
 you run git p4.  Might be worth your investigation.

The reason the files are still there is because git-p4 crashes (exits with an 
error) and doesn't clean them up.

When git-p4 exits cleanly, the directory is fine. My experience is that git-p4 
exists abnormally often enough. 

 The second weirdness is why a new run doesn't create the branch.
 This maybe points to self.checkpoint() not really checkpointing.
 It does send a checkpoint down the git fast-import stream,
 which is supposed to make it write the branches out.  You might
 consider grabbing the fast-import process in a debugger and see
 why it's not writing out the branch head.

I started looking at the code for fast-import. There's a lot of code there, so 
didn't go down that path.

I've posted another message indicating that I sincerely believe the problem is 
in git-fast-import. My current working theory is that 
because the file matches another commit (that's the point of writing the 
commit) git-fast-import doesn't flush the file. I've clearly 
stopped git-p4 immediately after the checkpoint and there is no file. When the 
program exits (abnormally of course), the file appears
(thanks to the file system). Seems like a flush problem somewhere.

I was hoping someone who knows git-fast-import would have a clue as to the 
problem.

 There's lots of changes since v1.7.12.4, but nothing obvious I
 can see that would cause this.  Sorry,

Thanks for taking a look.


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


Re: [PATCH 3/3] tag: support configuring --sort via .gitconfig

2014-07-12 Thread Eric Sunshine
On Fri, Jul 11, 2014 at 6:55 PM, Jacob Keller jacob.e.kel...@intel.com wrote:
 Add support for configuring default sort ordering for git tags. Command
 line option will override this configured value, using the exact same
 syntax.

 Cc: Jeff King p...@peff.net
 Signed-off-by: Jacob Keller jacob.e.kel...@intel.com
 ---
 Made parse_sort_string take a var parameter, and if given will only warn
 about invalid parameter, instead of error.

This seems unnecessarily ugly since it's hard-coding specialized
knowledge of the callers' error-reporting requirements into what
should be a generalized parsing function. If you instead make
parse_sort_string() responsible only for attempting to parse the
value, but leave error-reporting to the callers, then this ugliness
goes away. See below.

 diff --git a/builtin/tag.c b/builtin/tag.c
 index 9d7643f127e7..97c5317c28e5 100644
 --- a/builtin/tag.c
 +++ b/builtin/tag.c
 @@ -32,6 +32,8 @@ static const char * const git_tag_usage[] = {
  #define SORT_MASK   0x7fff
  #define REVERSE_SORT0x8000

 +static int tag_sort;
 +
  struct tag_filter {
 const char **patterns;
 int lines;
 @@ -346,9 +348,49 @@ static const char tag_template_nocleanup[] =
 Lines starting with '%c' will be kept; you may remove them
  yourself if you want to.\n);

 +/*
 + * Parse a sort string, and return 0 if parsed successfully. Will return
 + * non-zero when the sort string does not parse into a known type.
 + */
 +static int parse_sort_string(const char *var, const char *value, int *sort)
 +{
 +   int type = 0, flags = 0;
 +
 +   if (skip_prefix(value, -, value))
 +   flags |= REVERSE_SORT;
 +
 +   if (skip_prefix(value, version:, value) || skip_prefix(value, 
 v:, value))
 +   type = VERCMP_SORT;
 +   else
 +   type = STRCMP_SORT;
 +
 +   if (strcmp(value, refname)) {
 +   if (!var)
 +   return error(_(unsupported sort specification 
 '%s'), value);
 +   else {
 +   warning(_(unsupported sort specification '%s' in 
 variable '%s'),
 +   var, value);
 +   return -1;

Just return -1 here, but don't print any diagnostics. Let the callers
do that. (See below.)

 +   }
 +   }
 +
 +   *sort = (type | flags);
 +
 +   return 0;
 +}
 +
  static int git_tag_config(const char *var, const char *value, void *cb)
  {
 -   int status = git_gpg_config(var, value, cb);
 +   int status;
 +
 +   if (!strcmp(var, tag.sort)) {
 +   if (!value)
 +   return config_error_nonbool(var);
 +   parse_sort_string(var, value, tag_sort);

if (parse_sort_string(value, tag_sort))
warning(_(unsupported sort specification '%s' in variable '%s'),
var, value);

 +   return 0;
 +   }
 +
 +   status = git_gpg_config(var, value, cb);
 if (status)
 return status;
 if (starts_with(var, column.))
 @@ -522,20 +564,8 @@ static int parse_opt_points_at(const struct option *opt 
 __attribute__((unused)),
  static int parse_opt_sort(const struct option *opt, const char *arg, int 
 unset)
  {
 int *sort = opt-value;
 -   int flags = 0;

 -   if (skip_prefix(arg, -, arg))
 -   flags |= REVERSE_SORT;
 -
 -   if (skip_prefix(arg, version:, arg) || skip_prefix(arg, v:, 
 arg))
 -   *sort = VERCMP_SORT;
 -   else
 -   *sort = STRCMP_SORT;
 -
 -   if (strcmp(arg, refname))
 -   die(_(unsupported sort specification %s), arg);
 -   *sort |= flags;
 -   return 0;
 +   return parse_sort_string(NULL, arg, sort);

if (parse_sort_string(arg, sort))
return error(_(unsupported sort specification '%s'), arg);
return 0;

  }

  int cmd_tag(int argc, const char **argv, const char *prefix)
 @@ -548,7 +578,7 @@ int cmd_tag(int argc, const char **argv, const char 
 *prefix)
 struct create_tag_options opt;
 char *cleanup_arg = NULL;
 int annotate = 0, force = 0, lines = -1;
 -   int cmdmode = 0, sort = 0;
 +   int cmdmode = 0;
 const char *msgfile = NULL, *keyid = NULL;
 struct msg_arg msg = { 0, STRBUF_INIT };
 struct commit_list *with_commit = NULL;
 @@ -574,7 +604,7 @@ int cmd_tag(int argc, const char **argv, const char 
 *prefix)
 OPT__FORCE(force, N_(replace the tag if exists)),
 OPT_COLUMN(0, column, colopts, N_(show tag list in 
 columns)),
 {
 -   OPTION_CALLBACK, 0, sort, sort, N_(type), 
 N_(sort tags),
 +   OPTION_CALLBACK, 0, sort, tag_sort, N_(type), 
 N_(sort tags),
 PARSE_OPT_NONEG, parse_opt_sort
 },

 @@ -630,9 +660,9 @@ int cmd_tag(int argc, const char **argv, const char 
 *prefix)
 

Re: [PATCH v3] http: Add Accept-Language header if possible

2014-07-12 Thread Eric Sunshine
On Fri, Jul 11, 2014 at 12:52 PM, Yi EungJun semtlen...@gmail.com wrote:
 Add an Accept-Language header which indicates the user's preferred
 languages defined by $LANGUAGE, $LC_ALL, $LC_MESSAGES and $LANG.

 Examples:
   LANGUAGE= - 
   LANGUAGE=ko:en - Accept-Language: ko, en; q=0.9, *; q=0.1
   LANGUAGE=ko LANG=en_US.UTF-8 - Accept-Language: ko, *; q=0.1
   LANGUAGE= LANG=en_US.UTF-8 - Accept-Language: en-US, *; q=0.1

 This gives git servers a chance to display remote error messages in
 the user's preferred language.

 Signed-off-by: Yi EungJun eungjun...@navercorp.com
 ---
 diff --git a/http.c b/http.c
 index 3a28b21..a20f3e2 100644
 --- a/http.c
 +++ b/http.c
 @@ -983,6 +983,129 @@ static void extract_content_type(struct strbuf *raw, 
 struct strbuf *type,
 strbuf_addstr(charset, ISO-8859-1);
  }

 +/*
 + * Guess the user's preferred languages from the value in LANGUAGE 
 environment
 + * variable and LC_MESSAGES locale category.
 + *
 + * The result can be a colon-separated list like ko:ja:en.
 + */
 +static const char* get_preferred_languages() {
 +const char* retval;
 +
 +   retval = getenv(LANGUAGE);
 +   if (retval != NULL  retval[0] != '\0')
 +   return retval;
 +
 +   retval = setlocale(LC_MESSAGES, NULL);
 +   if (retval != NULL  retval[0] != '\0'
 +strcmp(retval, C) != 0
 +strcmp(retval, POSIX) != 0)
 +   return retval;
 +
 +   return NULL;
 +}
 +
 +/*
 + * Add an Accept-Language header which indicates user's preferred languages.
 + *
 + * Examples:
 + *   LANGUAGE= - 
 + *   LANGUAGE=ko:en - Accept-Language: ko, en; q=0.9, *; q=0.1
 + *   LANGUAGE=ko_KR.UTF-8:sr@latin - Accept-Language: ko-KR, sr; q=0.9, *; 
 q=0.1
 + *   LANGUAGE=ko LANG=en_US.UTF-8 - Accept-Language: ko, *; q=0.1
 + *   LANGUAGE= LANG=en_US.UTF-8 - Accept-Language: en-US, *; q=0.1
 + *   LANGUAGE= LANG=C - 
 + */
 +static struct curl_slist* add_accept_language(struct curl_slist *headers)
 +{
 +   const char *p1, *p2, *p3;
 +   struct strbuf buf = STRBUF_INIT;
 +   float q = 1.0;
 +   float q_precision = 0.1;
 +   int num_langs = 1;
 +   char* q_format = ; q=%.1f;

This can be 'const char *'.

 +
 +   p1 = get_preferred_languages();
 +
 +   /* Don't add Accept-Language header if no language is preferred. */
 +   if (p1 == NULL || p1[0] == '\0') {
 +   strbuf_release(buf);
 +   return headers;
 +   }
 +
 +   /* Count number of preferred languages to decide precision of 
 q-factor */
 +   for (p3 = p1; *p3 != '\0'; p3++) {
 +   if (*p3 == ':') {
 +   num_langs++;
 +   }
 +   }
 +
 +   /* Decide the precision for q-factor on number of preferred 
 languages. */
 +   if (num_langs + 1  100) { /* +1 is for '*' */
 +   q_precision = 0.001;
 +   q_format = ; q=%.3f;
 +   } else if (num_langs + 1  10) { /* +1 is for '*' */
 +   q_precision = 0.01;
 +   q_format = ; q=%.2f;
 +   }

It might make sense to have a final 'else' here which sets these
variables for the 0.1 case so that the reader of the code doesn't have
to refer back to the top of the function to figure out what is going
on.

} else {
q_precision = 0.1;
q_format = ; q=%.1f;
}

Better yet, would it be possible to compute these values rather than
having to set them manually via a cascading if-chain?

 +
 +   strbuf_addstr(buf, Accept-Language: );
 +
 +   for (p2 = p1; q  q_precision; p2++) {
 +   if ((*p2 == ':' || *p2 == '\0')  p1 != p2) {
 +   if (q  1.0) {
 +   strbuf_addstr(buf, , );
 +   }
 +
 +   for (p3 = p1; p3  p2; p3++) {
 +   /* Replace '_' with '-'. */
 +   if (*p3 == '_') {
 +   strbuf_add(buf, p1, p3 - p1);
 +   strbuf_addstr(buf, -);
 +   p1 = p3 + 1;
 +   }
 +
 +   /* Chop off anything after '.' or '@'. */
 +   if ((*p3 == '.' || *p3 == '@')) {
 +   break;
 +   }
 +   }
 +
 +   if (p3  p1) {
 +   strbuf_add(buf, p1, p3 - p1);
 +   }
 +
 +   /* Put the q factor if only it is less than 1.0. */
 +   if (q  1.0) {
 +   strbuf_addf(buf, q_format, q);
 +   }
 +
 +   q -= q_precision;
 +   p1 = p2 + 1;
 +
 +   if (*p2 == '\0') {
 +   break;
 +   }
 +   }
 +   

[PATCH v7 00/31] Support multiple checkouts

2014-07-12 Thread Nguyễn Thái Ngọc Duy
v7 fixes all comments from Eric and Max. Jeff's two patches are
dropped because they have landed in latest master now. Diff against
v6:

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 470f979..57999fa 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1215,7 +1215,7 @@ gc.prunereposexpire::
When 'git gc' is run, it will call
'prune --repos --expire 3.months.ago'.
Override the grace period with this config variable. The value
-   now may be used to disable the grace period and always prune
+   now may be used to disable the grace period and prune
$GIT_DIR/repos immediately.
 
 gc.reflogexpire::
diff --git a/builtin/checkout.c b/builtin/checkout.c
index dc8503a..c83f476 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1010,15 +1010,13 @@ static int check_linked_checkout(struct branch_info 
*new,
  const char *name, const char *path)
 {
struct strbuf sb = STRBUF_INIT;
-   char *start, *end;
-   if (strbuf_read_file(sb, path, 0)  0)
-   return 0;
-   if (!starts_with(sb.buf, ref:)) {
+   const char *start, *end;
+   if (strbuf_read_file(sb, path, 0)  0 ||
+   !skip_prefix(sb.buf, ref:, start)) {
strbuf_release(sb);
return 0;
}
 
-   start = sb.buf + 4;
while (isspace(*start))
start++;
end = start;
@@ -1200,8 +1198,14 @@ static int parse_branchname_arg(int argc, const char 
**argv,
else
new-path = NULL; /* not an existing branch */
 
-   if (new-path)
-   check_linked_checkouts(new);
+   if (new-path) {
+   unsigned char sha1[20];
+   int flag;
+   char *head_ref = resolve_refdup(HEAD, sha1, 0, flag);
+   if (!(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) {
diff --git a/builtin/gc.c b/builtin/gc.c
index 1190183..0c65808 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -57,6 +57,17 @@ static void remove_pidfile_on_signal(int signo)
raise(signo);
 }
 
+static int git_config_date_string(const char **output,
+ const char *var, const char *value)
+{
+   if (value  strcmp(value, now)) {
+   unsigned long now = approxidate(now);
+   if (approxidate(value) = now)
+   return error(_(Invalid %s: '%s'), var, value);
+   }
+   return git_config_string(output, var, value);
+}
+
 static int gc_config(const char *var, const char *value, void *cb)
 {
if (!strcmp(var, gc.packrefs)) {
@@ -86,22 +97,10 @@ static int gc_config(const char *var, const char *value, 
void *cb)
detach_auto = git_config_bool(var, value);
return 0;
}
-   if (!strcmp(var, gc.pruneexpire)) {
-   if (value  strcmp(value, now)) {
-   unsigned long now = approxidate(now);
-   if (approxidate(value) = now)
-   return error(_(Invalid %s: '%s'), var, value);
-   }
-   return git_config_string(prune_expire, var, value);
-   }
-   if (!strcmp(var, gc.prunereposexpire)) {
-   if (value  strcmp(value, now)) {
-   unsigned long now = approxidate(now);
-   if (approxidate(value) = now)
-   return error(_(Invalid %s: '%s'), var, value);
-   }
-   return git_config_string(prune_repos_expire, var, value);
-   }
+   if (!strcmp(var, gc.pruneexpire))
+   return git_config_date_string(prune_expire, var, value);
+   if (!strcmp(var, gc.prunereposexpire))
+   return git_config_date_string(prune_repos_expire, var, value);
return git_default_config(var, value, cb);
 }
 
@@ -295,7 +294,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
OPT__QUIET(quiet, N_(suppress progress reporting)),
{ OPTION_STRING, 0, prune, prune_expire, N_(date),
N_(prune unreferenced objects),
-   PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire},
+   PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
OPT_BOOL(0, aggressive, aggressive, N_(be more thorough 
(increased runtime))),
OPT_BOOL(0, auto, auto_gc, N_(enable auto-gc mode)),
OPT_BOOL(0, force, force, N_(force running gc even if there 
may be another gc running)),
diff --git a/builtin/prune.c b/builtin/prune.c
index 6db6bcc..28b7adf 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -112,23 +112,41 @@ static void prune_object_dir(const char *path)
}
 }
 

[PATCH v7 06/31] git_path(): be aware of file relocation in $GIT_DIR

2014-07-12 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
---
 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 987395d..9465399 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 1a6122d..7606d43 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -529,6 +529,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 279b581..0128b9a 100644
--- a/cache.h
+++ b/cache.h
@@ -612,6 +612,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;
gitfile = read_gitfile(git_dir);

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

2014-07-12 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 path.c | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/path.c b/path.c
index 2cb2e61..65881aa 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);
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 03/31] git_snpath(): retire and replace with strbuf_git_path()

2014-07-12 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
---
 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 3abcef1..8023987 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -584,18 +584,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 707408b..279b581 100644
--- a/cache.h
+++ b/cache.h
@@ -674,8 +674,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 a3f8826..e545064 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 dbd131e..00b2312 100644
--- a/refs.c
+++ b/refs.c
@@ -1535,10 +1535,12 @@ static const char *handle_missing_loose_ref(const char 
*refname,
 
 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;
@@ -1547,15 +1549,17 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
return NULL;
 
for (;;) {
-   char path[PATH_MAX];
+   const char *path;
struct stat st;
char *buf;
int fd;
 
if (--depth  0)
-   return NULL;
+   goto fail;
 
-   git_snpath(path, sizeof(path), %s, refname);
+   strbuf_reset(sb_path);
+   strbuf_git_path(sb_path, %s, refname);
+  

[PATCH v7 02/31] path.c: make get_pathname() call sites return const char *

2014-07-12 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
---
 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 463cfee..3abcef1 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -585,7 +585,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 e15ca33..91fac9d 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 e8d0cca..9522b1b 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 8aadca1..d414962 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 18458e8..ed11e7e 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -599,7 +599,7 @@ static void 

[PATCH v7 04/31] path.c: rename vsnpath() to do_git_path()

2014-07-12 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
---
 path.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/path.c b/path.c
index e545064..2cb2e61 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;
 }
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 01/31] path.c: make get_pathname() return strbuf instead of static buffer

2014-07-12 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
---
 path.c | 120 -
 1 file changed, 51 insertions(+), 69 deletions(-)

diff --git a/path.c b/path.c
index bc804a3..42ef3af 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)
@@ -158,41 +154,27 @@ void home_config_paths(char **global, char **xdg, char 
*file)
 
 char *git_path_submodule(const char *path, const char *fmt, ...)
 {
-  

[PATCH v7 07/31] *.sh: respect $GIT_INDEX_FILE

2014-07-12 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.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 18a394f..6ab0c31 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 bcc757b..393e1ec 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
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 10/31] commit: use SEQ_DIR instead of hardcoding sequencer

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

diff --git a/builtin/commit.c b/builtin/commit.c
index 461c3b1..4b9f012 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -156,7 +156,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
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

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

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

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

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

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

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

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

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

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

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

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

[PATCH v7 17/31] setup.c: convert check_repository_format_gently to use strbuf

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

diff --git a/setup.c b/setup.c
index 176d505..a17389f 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;
 }
 
 /*
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 16/31] setup.c: detect $GIT_COMMON_DIR in is_git_directory()

2014-07-12 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
---
 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 7629e38..0f341fc 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -237,6 +237,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 425fd79..176d505 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);
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 21/31] use new wrapper write_file() for simple file writing

2014-07-12 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
---
 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 0591b22..e4265a1 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -754,7 +754,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;
@@ -767,8 +766,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 56f85e2..ce8416a 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 1eb6631..dd638a9 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1094,15 +1094,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)
 {
@@ -1313,7 +1304,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 b80ecac..b7b6059 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1112,16 +1112,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 59c9727..1b779bb 100644
--- a/transport.c
+++ b/transport.c
@@ -296,7 +296,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/) 
@@ -305,10 +304,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);
+   write_file(buf-buf, 0, %s\n, 

[PATCH v7 19/31] setup.c: support multi-checkout repo setup

2014-07-12 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
---
 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 1d718bd..286e539 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 9465399..f1867d3 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 7606d43..29475c5 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -757,6 +757,10 @@ int cmd_rev_parse(int argc, const char **argv, const char 
*prefix)
printf(%s%s.git\n, cwd, len  cwd[len-1] != 
'/' ? / : );
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 b606ee4..e3ff7dc 100644
--- a/cache.h
+++ b/cache.h
@@ -422,6 +422,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 6b74f68..50ed40a 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 79f79f2..8f90bc3 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 v7 08/31] reflog: avoid constructing .lock path with git_path

2014-07-12 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
---
 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);
}
 
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

2014-07-12 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
---
 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 () {
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 13/31] *.sh: avoid hardcoding $GIT_DIR/hooks/...

2014-07-12 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
---
 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 7e1eda0..e8995f9 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 06c810b..d60e710 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -201,9 +201,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
--- a/templates/hooks--pre-applypatch.sample
+++ 

[PATCH v7 22/31] checkout: support checking out into a new working directory

2014-07-12 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/repos/id. It then executes git checkout again
on the new worktree with the same arguments except --to is taken
out. The second checkout execution, which is not contaminated with any
info from the current repository, will actually check out and
everything that normal git checkout does.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 Documentation/git-checkout.txt | 34 +
 Documentation/git.txt  |  3 +-
 Documentation/gitrepository-layout.txt |  7 +++
 builtin/checkout.c | 93 +-
 path.c |  2 +-
 t/t2025-checkout-to.sh (new +x)| 48 ++
 6 files changed, 183 insertions(+), 4 deletions(-)
 create mode 100755 t/t2025-checkout-to.sh

diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 33ad2ad..fcf73b2 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -225,6 +225,13 @@ This means that you can use `git checkout -p` to 
selectively discard
 edits from your current working tree. See the ``Interactive Mode''
 section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
 
+--to=path::
+   Check out a new branch in a separate working directory at
+   `path`. A new working directory is linked to the current
+   repository, sharing everything except working directory
+   specific files such as HEAD, index... See MULTIPLE CHECKOUT
+   MODE section for more information.
+
 branch::
Branch to checkout; if it refers to a branch (i.e., a name that,
when prepended with refs/heads/, is a valid ref), then that
@@ -388,6 +395,33 @@ $ git reflog -2 HEAD # or
 $ git log -g -2 HEAD
 
 
+MULTIPLE CHECKOUT MODE
+---
+Normally a working directory is attached to repository. When git
+checkout --to is used, a new working directory is attached to the
+current repository. This new working directory is called linked
+checkout as compared to the main checkout prepared by git init or
+git clone. A repository has one main checkout and zero or more
+linked checkouts.
+
+All checkouts share the same repository. Linked checkouts see the
+repository a bit different from the main checkout. When the checkout
+new reads the path $GIT_DIR/HEAD for example, the actual path
+returned could be $GIT_DIR/repos/new/HEAD. This ensures checkouts
+won't step on each other.
+
+Each linked checkout has a private space in $GIT_DIR/repos, usually
+named after the base name of the working directory with a number added
+to make it unique. The linked checkout's $GIT_DIR points to this
+private space while $GIT_COMMON_DIR points to the main checkout's
+$GIT_DIR. These settings are done by git checkout --to.
+
+Because in this mode $GIT_DIR becomes a lightweight virtual file
+system where a path could be rewritten to some place else, accessing
+$GIT_DIR from scripts should use `git rev-parse --git-path` to resolve
+a path instead of using it directly unless the path is known to be
+private to the working directory.
+
 EXAMPLES
 
 
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 749052f..c0a4940 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -792,7 +792,8 @@ Git so take care if using Cogito etc.
If this variable is set to a path, non-worktree files that are
normally in $GIT_DIR will be taken from this path
instead. Worktree-specific files such as HEAD or index are
-   taken from $GIT_DIR. See linkgit:gitrepository-layout[5] for
+   taken from $GIT_DIR. See linkgit:gitrepository-layout[5] and
+   the section 'MULTIPLE CHECKOUT MODE' in linkgit:checkout[1]
details. This variable has lower precedence than other path
variables such as GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY...
 
diff --git a/Documentation/gitrepository-layout.txt 
b/Documentation/gitrepository-layout.txt
index 0f341fc..543d874 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -249,6 +249,13 @@ modules::
directory is ignored if $GIT_COMMON_DIR is set and
$GIT_COMMON_DIR/modules will be used instead.
 
+repos::
+   Contains worktree specific information of linked
+   checkouts. Each subdirectory contains the worktree-related
+   part of a linked checkout. This directory is ignored
+   $GIT_COMMON_DIR is set and $GIT_COMMON_DIR/repos will be
+   used instead.
+
 SEE ALSO
 
 linkgit:git-init[1],
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 8023987..81adb74 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -48,6 +48,10 @@ struct checkout_opts {
const char *prefix;
struct pathspec pathspec;
struct tree *source_tree;
+
+   const char *new_worktree;
+   const char **saved_argv;
+   

[PATCH v7 18/31] setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()

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

diff --git a/setup.c b/setup.c
index a17389f..79f79f2 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)
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 09/31] fast-import: use git_path() for accessing .git dir instead of get_git_dir()

2014-07-12 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
---
 fast-import.c | 5 +
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/fast-import.c b/fast-import.c
index d9c068b..ea426c4 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -3103,12 +3103,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,
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 15/31] setup.c: convert is_git_directory() to use strbuf

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

diff --git a/setup.c b/setup.c
index 0a22f8b..425fd79 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)
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 14/31] git-stash: avoid hardcoding $GIT_DIR/logs/....

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

diff --git a/git-stash.sh b/git-stash.sh
index 393e1ec..41f8f6b 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
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

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

diff --git a/cache.h b/cache.h
index e3ff7dc..bf4d15e 100644
--- a/cache.h
+++ b/cache.h
@@ -1359,6 +1359,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 bc1bfb8..9d7b9ac 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -493,3 +493,34 @@ struct passwd *xgetpwuid_self(void)
errno ? strerror(errno) : _(no such user));
return pw;
 }
+
+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;
+}
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 27/31] gc: factor out gc.pruneexpire parsing code

2014-07-12 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 builtin/gc.c | 21 +
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 3bfb990..e38c902 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -55,6 +55,17 @@ static void remove_pidfile_on_signal(int signo)
raise(signo);
 }
 
+static int git_config_date_string(const char **output,
+ const char *var, const char *value)
+{
+   if (value  strcmp(value, now)) {
+   unsigned long now = approxidate(now);
+   if (approxidate(value) = now)
+   return error(_(Invalid %s: '%s'), var, value);
+   }
+   return git_config_string(output, var, value);
+}
+
 static int gc_config(const char *var, const char *value, void *cb)
 {
if (!strcmp(var, gc.packrefs)) {
@@ -84,14 +95,8 @@ static int gc_config(const char *var, const char *value, 
void *cb)
detach_auto = git_config_bool(var, value);
return 0;
}
-   if (!strcmp(var, gc.pruneexpire)) {
-   if (value  strcmp(value, now)) {
-   unsigned long now = approxidate(now);
-   if (approxidate(value) = now)
-   return error(_(Invalid %s: '%s'), var, value);
-   }
-   return git_config_string(prune_expire, var, value);
-   }
+   if (!strcmp(var, gc.pruneexpire))
+   return git_config_date_string(prune_expire, var, value);
return git_default_config(var, value, cb);
 }
 
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 28/31] gc: support prune --repos

2014-07-12 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 Documentation/config.txt |  7 +++
 builtin/gc.c | 11 +++
 2 files changed, 18 insertions(+)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 286e539..57999fa 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1211,6 +1211,13 @@ gc.pruneexpire::
now may be used to disable this  grace period and always prune
unreachable objects immediately.
 
+gc.prunereposexpire::
+   When 'git gc' is run, it will call
+   'prune --repos --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/repos immediately.
+
 gc.reflogexpire::
 gc.pattern.reflogexpire::
'git reflog expire' removes reflog entries older than
diff --git a/builtin/gc.c b/builtin/gc.c
index e38c902..0c65808 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_repos_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_repos = ARGV_ARRAY_INIT;
 static struct argv_array rerere = ARGV_ARRAY_INIT;
 
 static char *pidfile;
@@ -97,6 +99,8 @@ static int gc_config(const char *var, const char *value, void 
*cb)
}
if (!strcmp(var, gc.pruneexpire))
return git_config_date_string(prune_expire, var, value);
+   if (!strcmp(var, gc.prunereposexpire))
+   return git_config_date_string(prune_repos_expire, var, value);
return git_default_config(var, value, cb);
 }
 
@@ -304,6 +308,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_repos, prune, --repos, --expire, NULL);
argv_array_pushl(rerere, rerere, gc, NULL);
 
git_config(gc_config, NULL);
@@ -373,6 +378,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
return error(FAILED_RUN, prune.argv[0]);
}
 
+   if (prune_repos_expire) {
+   argv_array_push(prune_repos, prune_repos_expire);
+   if (run_command_v_opt(prune_repos.argv, RUN_GIT_CMD))
+   return error(FAILED_RUN, prune_repos.argv[0]);
+   }
+
if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
return error(FAILED_RUN, rerere.argv[0]);
 
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 29/31] count-objects: report unused files in $GIT_DIR/repos/...

2014-07-12 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 bf4d15e..12f0fc0 100644
--- a/cache.h
+++ b/cache.h
@@ -690,6 +690,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 e41d6b3..b5af137 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, /repos, /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;
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 23/31] checkout: clean up half-prepared directories in --to mode

2014-07-12 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 builtin/checkout.c | 49 +++--
 1 file changed, 47 insertions(+), 2 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 81adb74..3167fd2 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),
@@ -814,6 +815,35 @@ static int switch_branches(const struct checkout_opts 
*opts,
return ret || writeout_error;
 }
 
+static const char *junk_work_tree;
+static const 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)
 {
@@ -822,7 +852,7 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
const char *path = opts-new_worktree, *name;
struct stat st;
struct child_process cp;
-   int counter = 0, len;
+   int counter = 0, len, ret;
 
if (!new-commit)
die(_(no branch specified));
@@ -848,13 +878,21 @@ 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 = sb_repo.buf;
+   is_junk = 1;
 
strbuf_addf(sb_git, %s/.git, path);
if (safe_create_leading_directories_const(sb_git.buf))
die_errno(_(could not create leading directories of '%s'),
  sb_git.buf);
+   junk_work_tree = path;
 
write_file(sb_git.buf, 1, gitdir: %s/repos/%s\n,
   real_path(get_git_common_dir()), name);
@@ -879,7 +917,14 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
memset(cp, 0, sizeof(cp));
cp.git_cmd = 1;
cp.argv = opts-saved_argv;
-   return run_command(cp);
+   ret = run_command(cp);
+   if (!ret)
+   is_junk = 0;
+   strbuf_release(sb);
+   strbuf_release(sb_repo);
+   strbuf_release(sb_git);
+   return ret;
+
 }
 
 static int git_checkout_config(const char *var, const char *value, void *cb)
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 26/31] gc: style change -- no SP before closing bracket

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

diff --git a/builtin/gc.c b/builtin/gc.c
index 8d219d8..3bfb990 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -298,7 +298,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);
 
git_config(gc_config, NULL);
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 25/31] prune: strategies for linked checkouts

2014-07-12 Thread Nguyễn Thái Ngọc Duy
(alias R=$GIT_COMMON_DIR/repos/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,
   repos/id is to be pruned.

 - If $R/locked exists, repos/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.

Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com
---
 Documentation/git-prune.txt|  3 +
 Documentation/gitrepository-layout.txt | 19 ++
 builtin/checkout.c | 14 +
 builtin/prune.c| 99 ++
 setup.c| 13 
 t/t2026-prune-linked-checkouts.sh (new +x) | 84 +
 6 files changed, 232 insertions(+)
 create mode 100755 t/t2026-prune-linked-checkouts.sh

diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt
index 7a493c8..50e39ec 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.
 
+--repos::
+   Prune directories in $GIT_DIR/repos.
+
 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 543d874..bed4f1a 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -256,6 +256,25 @@ repos::
$GIT_COMMON_DIR is set and $GIT_COMMON_DIR/repos will be
used instead.
 
+repos/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.
+
+repos/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 `repos/id` could be
+   removed. The file's content contains a reason string on why
+   the repository is locked.
+
+repos/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 fe24766..5b93f49 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -898,12 +898,22 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
junk_git_dir = sb_repo.buf;
is_junk = 1;
 
+   /*
+* lock the incomplete repo so prune won't delete it, unlock
+* after the preparation is over.
+*/
+   strbuf_addf(sb, %s/locked, sb_repo.buf);
+   write_file(sb.buf, 1, initializing\n);
+
strbuf_addf(sb_git, %s/.git, path);
if (safe_create_leading_directories_const(sb_git.buf))
die_errno(_(could not create leading directories of '%s'),
  sb_git.buf);
junk_work_tree = path;
 
+   strbuf_reset(sb);
+   strbuf_addf(sb, %s/gitdir, sb_repo.buf);
+   write_file(sb.buf, 1, %s\n, real_path(sb_git.buf));
write_file(sb_git.buf, 1, gitdir: %s/repos/%s\n,
   real_path(get_git_common_dir()), name);
/*
@@ -912,6 +922,7 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
 * value would do because this value will be ignored and
 * replaced at the next (real) checkout.
 */
+   strbuf_reset(sb);
strbuf_addf(sb, %s/HEAD, sb_repo.buf);
write_file(sb.buf, 1, %s\n, sha1_to_hex(new-commit-object.sha1));
strbuf_reset(sb);
@@ -930,6 +941,9 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
ret = run_command(cp);
if (!ret)
is_junk = 0;
+   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);
diff --git a/builtin/prune.c b/builtin/prune.c
index 144a3bd..28b7adf 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -112,6 +112,95 @@ static void prune_object_dir(const char *path)
}
 }
 
+static int prune_repo_dir(const char *id, struct stat *st, struct 

[PATCH v7 30/31] git_path(): keep info/sparse-checkout per work-tree

2014-07-12 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
---
 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 b5af137..b1dd2bc 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 2dabcef..da82aab 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -269,6 +269,7 @@ test_git_path GIT_COMMON_DIR=bar logs/HEAD
.git/logs/HEAD
 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/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
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 24/31] checkout: detach if the branch is already checked out elsewhere

2014-07-12 Thread Nguyễn Thái Ngọc Duy
The normal rule is anything outside refs/heads/ is detached. This
increases strictness of the rule a bit more: if the branch is checked
out (either in $GIT_COMMON_DIR/HEAD or any $GIT_DIR/repos/.../HEAD)
then it's detached as well.

A hint is given so the user knows where to go and do something there
if they still want to checkout undetached here.

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

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 3167fd2..fe24766 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -432,6 +432,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)
@@ -640,6 +645,11 @@ static void update_refs_for_switch(const struct 
checkout_opts *opts,
if (old-path  advice_detached_head)
detach_advice(new-name);
describe_detached_head(_(HEAD is now at), 
new-commit);
+   if (new-checkout  !*new-checkout)
+   fprintf(stderr, _(hint: the main checkout is 
holding this branch\n));
+   else if (new-checkout)
+   fprintf(stderr, _(hint: the linked checkout %s 
is holding this branch\n),
+   new-checkout);
}
} else if (new-path) { /* Switch branches. */
create_symref(HEAD, new-path, msg.buf);
@@ -982,6 +992,71 @@ static const char *unique_tracking_name(const char *name, 
unsigned char *sha1)
return NULL;
 }
 
+static int check_linked_checkout(struct branch_info *new,
+ const char *name, const char *path)
+{
+   struct strbuf sb = STRBUF_INIT;
+   const char *start, *end;
+   if (strbuf_read_file(sb, path, 0)  0 ||
+   !skip_prefix(sb.buf, ref:, start)) {
+   strbuf_release(sb);
+   return 0;
+   }
+
+   while (isspace(*start))
+   start++;
+   end = start;
+   while (*end  !isspace(*end))
+   end++;
+   if (!strncmp(start, new-path, end - start) 
+   new-path[end - start] == '\0') {
+   strbuf_release(sb);
+   new-path = NULL; /* detach */
+   new-checkout = xstrdup(name); /* reason */
+   return 1;
+   }
+   strbuf_release(sb);
+   return 0;
+}
+
+static void check_linked_checkouts(struct branch_info *new)
+{
+   struct strbuf path = STRBUF_INIT;
+   DIR *dir;
+   struct dirent *d;
+
+   strbuf_addf(path, %s/repos, get_git_common_dir());
+   if ((dir = opendir(path.buf)) == NULL) {
+   strbuf_release(path);
+   return;
+   }
+
+   strbuf_reset(path);
+   strbuf_addf(path, %s/HEAD, get_git_common_dir());
+   /*
+* $GIT_COMMON_DIR/HEAD is practically outside
+* $GIT_DIR so resolve_ref_unsafe() won't work (it
+* uses git_path). Parse the ref ourselves.
+*/
+   if (check_linked_checkout(new, , path.buf)) {
+   strbuf_release(path);
+   closedir(dir);
+   return;
+   }
+
+   while ((d = readdir(dir)) != NULL) {
+   if (!strcmp(d-d_name, .) || !strcmp(d-d_name, ..))
+   continue;
+   strbuf_reset(path);
+   strbuf_addf(path, %s/repos/%s/HEAD,
+   get_git_common_dir(), d-d_name);
+   if (check_linked_checkout(new, d-d_name, path.buf))
+   break;
+   }
+   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,
@@ -1109,6 +1184,15 @@ static int parse_branchname_arg(int argc, const char 
**argv,
else
new-path = NULL; /* not an existing branch */
 
+   if (new-path) {
+   unsigned char sha1[20];
+   int flag;
+   char *head_ref = resolve_refdup(HEAD, sha1, 0, flag);
+   if (!(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 */
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
index 

[PATCH v7 31/31] checkout: don't require a work tree when checking out into a new one

2014-07-12 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 5b93f49..c83f476 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1357,6 +1357,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 5b6c761..7426651 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 20e3dc7..b0d97a0 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-checkout-to.sh
@@ -62,4 +62,19 @@ test_expect_success 'not detach 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 master
+   )
+'
+
+test_expect_success 'checkout from a bare repo without --to' '
+   (
+   cd bare 
+   test_must_fail git checkout master
+   )
+'
+
 test_done
-- 
1.9.1.346.ga2b5940

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


Re: [PATCH v8 4/4] cache-tree: Write updated cache-tree after commit

2014-07-12 Thread Duy Nguyen
On Sat, Jul 12, 2014 at 11:44 AM, David Turner dtur...@twopensource.com wrote:
 @@ -342,6 +342,15 @@ static char *prepare_index(int argc, const char **argv, 
 const char *prefix,

 discard_cache();
 read_cache_from(index_lock.filename);
 +   if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
 +   fd = open(index_lock.filename, O_WRONLY);
 +   if (fd = 0)
 +   if (write_cache(fd, active_cache, active_nr) 
 == 0) {
 +   close_lock_file(index_lock);

If write_cache() returns a negative value, index.lock is probably
corrupted. Should we die() instead of moving on and returning
index_lock.filename to the caller? The caller may move index.lock to
index later on and officially ruin index.

 +   }
 +   }
 +   else
 +   fprintf(stderr, FAiled to update main cache tree\n);

make the above line something like this for i18n support:

fprintf_ln(stderr, _(Failed to update main cache tree));


 commit_style = COMMIT_NORMAL;
 return index_lock.filename;
-- 
Duy
--
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