Re: [PATCH v5] Add another option for receive.denyCurrentBranch

2014-11-30 Thread Johannes Schindelin
Hi Junio,

On Sun, 30 Nov 2014, Junio C Hamano wrote:

> Thanks, will queue.

Thanks!

> I think we would need a bit more tests to protect the feature from
> future changes, if you care about the cleanliness requirement of
> this feature which is a lot stricter than that of "git checkout".
> 
> Perhaps like this one on top.

Thanks again!
Dscho
--
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] git-svn: Support for git-svn propset

2014-11-30 Thread Alfred Perlstein
This change allows git-svn to support setting subversion properties.

Very useful for manually setting properties when committing to a
subversion repo that *requires* properties to be set without requiring
moving your changeset to separate subversion checkout in order to
set props.

This change is initially from David Fraser 
Appearing here: http://marc.info/?l=git&m=125259772625008&w=2

They are now forward ported to most recent git along with fixes to
deal with files in subdirectories.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or

(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or

(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.

(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.

Signed-off-by: Alfred Perlstein 
---
 git-svn.perl   | 50 +-
 perl/Git/SVN/Editor.pm | 47 +++
 2 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/git-svn.perl b/git-svn.perl
index b6e2186..91423a8 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -115,7 +115,7 @@ my ($_stdin, $_help, $_edit,
$_before, $_after,
$_merge, $_strategy, $_preserve_merges, $_dry_run, $_parents, $_local,
$_prefix, $_no_checkout, $_url, $_verbose,
-   $_commit_url, $_tag, $_merge_info, $_interactive);
+   $_commit_url, $_tag, $_merge_info, $_interactive, $_set_svn_props);
 
 # This is a refactoring artifact so Git::SVN can get at this git-svn switch.
 sub opt_prefix { return $_prefix || '' }
@@ -193,6 +193,7 @@ my %cmd = (
  'dry-run|n' => \$_dry_run,
  'fetch-all|all' => \$_fetch_all,
  'commit-url=s' => \$_commit_url,
+ 'set-svn-props=s' => \$_set_svn_props,
  'revision|r=i' => \$_revision,
  'no-rebase' => \$_no_rebase,
  'mergeinfo=s' => \$_merge_info,
@@ -228,6 +229,9 @@ my %cmd = (
 'propget' => [ \&cmd_propget,
   'Print the value of a property on a file or directory',
   { 'revision|r=i' => \$_revision } ],
+'propset' => [ \&cmd_propset,
+  'Set the value of a property on a file or directory - 
will be set on commit',
+  {} ],
 'proplist' => [ \&cmd_proplist,
   'List all properties of a file or directory',
   { 'revision|r=i' => \$_revision } ],
@@ -1376,6 +1380,50 @@ sub cmd_propget {
print $props->{$prop} . "\n";
 }
 
+# cmd_propset (PROPNAME, PROPVAL, PATH)
+# 
+# Adjust the SVN property PROPNAME to PROPVAL for PATH.
+sub cmd_propset {
+   my ($propname, $propval, $path) = @_;
+   $path = '.' if not defined $path;
+   $path = $cmd_dir_prefix . $path;
+   usage(1) if not defined $propname;
+   usage(1) if not defined $propval;
+   my $file = basename($path);
+   my $dn = dirname($path);
+   # diff has check_attr locally, so just call direct
+   #my $current_properties = check_attr( "svn-properties", $path );
+   my $current_properties = Git::SVN::Editor::check_attr( 
"svn-properties", $path );
+   my $new_properties = "";
+   if ($current_properties eq "unset" || $current_properties eq "" || 
$current_properties eq "set") {
+   $new_properties = "$propname=$propval";
+   } else {
+   # TODO: handle combining properties better
+   my @props = split(/;/, $current_properties);
+   my $replaced_prop = 0;
+   foreach my $prop (@props) {
+   # Parse 'name=value' syntax and set the property.
+   if ($prop =~ /([^=]+)=(.*)/) {
+   my ($n,$v) = ($1,$2);
+   if ($n eq $propname)
+   

[PATCH] git-svn: Support for propset

2014-11-30 Thread Alfred Perlstein
Hello folks,

I have resurrected the code submitted by David Fraser to facilitate
git-svn to set properties on files.

This is my very first patch submission to git(1) so please be gentle.

I have tried my best to abide with all the instructions located
here:

https://github.com/git/git/blob/master/Documentation/SubmittingPatches

I've cc'd the top 4 people who have been active in the area:
~/git/git % git log --since '2010-01-01' git-svn.perl |grep Author | sort  | 
uniq -c | sort -n | tail -4
   6 Author: Eric Wong 
   9 Author: Jonathan Nieder 
  13 Author: Junio C Hamano 
  19 Author: Michael G. Schwern 
And of course: git@vger.kernel.org

We (FreeBSD) and my company that uses FreeBSD are starting to use
git-svn to collaborate with each other, however our (FreeBSD's)
central repo is subversion and requires us to set properties in
order to commit.  This change would be tremendously helpful for a
number of us in order to cut overhead of the git<->subversion bridge.
Effectively with this patch we can commit directly to FreeBSD and
FreeBSD ports using git.

The next email should have the patch in format that is consumable 
by "git am" when applied against the master branch.

I have been testing this and have done a number of commits directly
to FreeBSD kernel and FreeBSD ports (packages) system using this
patch successfully.

Alfred Perlstein (1):
  git-svn: Support for git-svn propset

 git-svn.perl   | 50 +-
 perl/Git/SVN/Editor.pm | 47 +++
 2 files changed, 96 insertions(+), 1 deletion(-)

-- 
2.1.2

--
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] compat: convert modes to use portable file type values

2014-11-30 Thread Torsten Bögershausen

On 12/01/2014 04:40 AM, David Michael wrote:

On Sun, Nov 30, 2014 at 3:16 PM, Torsten Bögershausen  wrote:
[snip]

Could the code be more human-readable ?
static inline mode_t mode_native_to_git(mode_t native_mode)
{
 int perm_bits = native_mode & 0;
 if (S_ISREG(native_mode))
 return 010 | perm_bits;
 if (S_ISDIR(native_mode))
 return 004 | perm_bits;
 if (S_ISLNK(native_mode))
 return 012 | perm_bits;
 if (S_ISBLK(native_mode))
 return 006 | perm_bits;
 if (S_ISCHR(native_mode))
 return 002 | perm_bits;
 if (S_ISFIFO(native_mode))
 return 001 | perm_bits;
 /* Non-standard type bits were given. */
 /* Shouldn't we die() here ?? */
 return perm_bits;
}

Sure, I can send an updated patch with the new variable and without the "else"s.

Regarding the question in the last comment:  I was assuming if this
case was ever reached, Git would handle the returned mode the same way
as if it encountered an unknown/non-standard file type on a normal
operating system, which could die() if needed in the function that
called stat().

Should I send an updated patch that die()s there?

David

Not yet, please wait with a V2 patch until I finished my thinking ;-)

I take back the suggestion with the die(). I was thinking how to handle
unforeseen types, which may show up on the z/OS some day,
So die() is not a good idea, it is better to ignore them, what the code 
does.


Knowing that Git does not track block devices, nor character devices nor 
sockets,
the above code could be simplyfied even more, by mapping everything which
is not a directory, a file or a softlink to "device type 0)

This is just a suggestion, I want to here from others as well:

int perm_bits = native_mode & 0;
if (S_ISREG(native_mode))
return 010 | perm_bits;
if (S_ISDIR(native_mode))
return 004 | perm_bits;
if (S_ISLNK(native_mode))
return 012 | perm_bits;
/* Git does not track S_IFCHR, S_IFBLK, S_IFIFO, S_IFSOCK  */
return perm_bits;




--
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: Deprecation warnings under XCode

2014-11-30 Thread Torsten Bögershausen

On 12/01/2014 04:02 AM, Michael Blume wrote:

I have no idea whether this should concern anyone, but my mac build of git shows

 CC imap-send.o
imap-send.c:183:36: warning: 'ERR_error_string' is deprecated: first
deprecated in OS X 10.7 [-Wdeprecated-declarations]
 fprintf(stderr, "%s: %s\n", func,
ERR_error_string(ERR_get_error(), NULL));
   ^

[]
Isn't the warning a warning ;-)
I don't see this warnings because my openssl comes from 
/opt/local/include (Mac ports)

Does anybody know which new functions exist in Mac OS X versions >= 10.7  ?

--
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] introduce git root

2014-11-30 Thread Junio C Hamano
Christian Couder  writes:

> I wonder if we could reuse "git config" which is already a "kitchen
> synk" command to get/set a lot of parameters.

I doubt it makes much sense.

 * Things like toplevel and cdup are not even something you
   configure.  It is where you are, the current state of you.
   "git config" does not make any sense at all.

 * manpath and execpath and friends _might_ be something you may
   want to configure, and teach relevant codepaths to pay attention
   to the new configuration values.  But until that happens, it does
   not make sense to have that information in "git config".  "git
   config" does not show values that are not actually configured, so
   it won't be a replacement for "git --man-path" for those who do
   not have nonstandard place configured.

So...
--
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] introduce git root

2014-11-30 Thread Christian Couder
On Mon, Dec 1, 2014 at 4:04 AM, Junio C Hamano  wrote:
>
> If I were redoing this today, I would probably nominate the "git"
> potty as such a "kitchen synk" command.  We have "--man-path" that
> shows the location of the manual pages, "--exec-path[=path]" that
> either shows or allows us to override the path to the subcommands,
> and "--show-prefix", "--show-toplevel", and friends may feel quite
> at home there.

I wonder if we could reuse "git config" which is already a "kitchen
synk" command to get/set a lot of parameters.
Maybe we could dedicate a "git" or "virtual" or "proc" or "sys" (like
/proc or /sys  in Linux) namespace for these special config parameters
that would not necessarily reflect something in the config file.

"git config git.man-path" would be the same as "git --man-path".
"git config git.root" would be the same as "git rev-parse --show-toplevel".
"git config git.exec-path mypath" would allow us to override the path
to the subcommands, probably by saving something in the config file.

If we wanted for example to try just once a special exec-path we could use:

git -c git.exec-path=/path/to/git-foo foo

Best,
Christian.
--
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] compat: convert modes to use portable file type values

2014-11-30 Thread David Michael
On Sun, Nov 30, 2014 at 3:16 PM, Torsten Bögershausen  wrote:
[snip]
> Could the code be more human-readable ?
> static inline mode_t mode_native_to_git(mode_t native_mode)
> {
> int perm_bits = native_mode & 0;
> if (S_ISREG(native_mode))
> return 010 | perm_bits;
> if (S_ISDIR(native_mode))
> return 004 | perm_bits;
> if (S_ISLNK(native_mode))
> return 012 | perm_bits;
> if (S_ISBLK(native_mode))
> return 006 | perm_bits;
> if (S_ISCHR(native_mode))
> return 002 | perm_bits;
> if (S_ISFIFO(native_mode))
> return 001 | perm_bits;
> /* Non-standard type bits were given. */
> /* Shouldn't we die() here ?? */
> return perm_bits;
> }

Sure, I can send an updated patch with the new variable and without the "else"s.

Regarding the question in the last comment:  I was assuming if this
case was ever reached, Git would handle the returned mode the same way
as if it encountered an unknown/non-standard file type on a normal
operating system, which could die() if needed in the function that
called stat().

Should I send an updated patch that die()s there?

David
--
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 v5] Add another option for receive.denyCurrentBranch

2014-11-30 Thread Junio C Hamano
Thanks, will queue.

I think we would need a bit more tests to protect the feature from
future changes, if you care about the cleanliness requirement of
this feature which is a lot stricter than that of "git checkout".

Perhaps like this one on top.

-- >8 --
From: Junio C Hamano 
Date: Sun, 30 Nov 2014 17:54:30 -0800
Subject: [PATCH] t5516: more tests for receive.denyCurrentBranch=updateInstead

The previous one tests only the case where a path to be updated by
the push-to-deploy has an incompatible change in the target's
working tree that has already been added to the index, but the
feature itself wants to require the working tree to be a lot cleaner
than what is tested.  Add a handful more tests to protect the
feature from future changes that mistakenly (from the viewpoint of
the inventor of the feature) loosens the cleanliness requirement,
namely:

 - A change only to the working tree but not to the index is still a
   change to be protected;

 - An untracked file in the working tree that would be overwritten
   by a push-to-deploy needs to be protected;

 - A change that happens to make a file identical to what is being
   pushed is still a change to be protected (i.e. the feature's
   cleanliness requirement is more strict than that of checkout).

Also, test that a stat-only change to the working tree is not a
reason to reject a push-to-deploy.

Signed-off-by: Junio C Hamano 
---
 t/t5516-fetch-push.sh | 96 ++-
 1 file changed, 87 insertions(+), 9 deletions(-)

diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 7b353d0..85c7fec 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1332,28 +1332,106 @@ test_expect_success 'fetch into bare respects 
core.logallrefupdates' '
 
 test_expect_success 'receive.denyCurrentBranch = updateInstead' '
git push testrepo master &&
-   (cd testrepo &&
+   (
+   cd testrepo &&
git reset --hard &&
git config receive.denyCurrentBranch updateInstead
) &&
test_commit third path2 &&
+
+   # Try pushing into a repository with pristine working tree
git push testrepo master &&
-   test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
-   test third = "$(cat testrepo/path2)" &&
-   (cd testrepo &&
+   (
+   cd testrepo &&
+   git update-index -q --refresh &&
+   git diff-files --quiet -- &&
+   git diff-index --quiet --cached HEAD -- &&
+   test third = "$(cat path2)" &&
+   test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
+   ) &&
+
+   # Try pushing into a repository with working tree needing a refresh
+   (
+   cd testrepo &&
+   git reset --hard HEAD^ &&
+   test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+   test-chmtime +100 path1
+   ) &&
+   git push testrepo master &&
+   (
+   cd testrepo &&
git update-index -q --refresh &&
git diff-files --quiet -- &&
git diff-index --quiet --cached HEAD -- &&
-   echo changed >path2 &&
-   git add path2
+   test_cmp ../path1 path1 &&
+   test third = "$(cat path2)" &&
+   test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
) &&
+
+   # Update what is to be pushed
test_commit fourth path2 &&
+
+   # Try pushing into a repository with a dirty working tree
+   # (1) the working tree updated
+   (
+   cd testrepo &&
+   echo changed >path1
+   ) &&
test_must_fail git push testrepo master &&
-   test $(git rev-parse HEAD^) = $(git -C testrepo rev-parse HEAD) &&
-   (cd testrepo &&
+   (
+   cd testrepo &&
+   test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+   git diff --quiet --cached &&
+   test changed = "$(cat path1)"
+   ) &&
+
+   # (2) the index updated
+   (
+   cd testrepo &&
+   echo changed >path1 &&
+   git add path1
+   ) &&
+   test_must_fail git push testrepo master &&
+   (
+   cd testrepo &&
+   test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+   git diff --quiet &&
+   test changed = "$(cat path1)"
+   ) &&
+
+   # Introduce a new file in the update
+   test_commit fifth path3 &&
+
+   # (3) the working tree has an untracked file that would interfere
+   (
+   cd testrepo &&
+   git reset --hard &&
+   echo changed >path3
+   ) &&
+   test_must_fail git push testrepo master &&
+   (
+   cd testrepo &&
+   test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) &&
+   git diff --qu

Re: [PATCH] compat: convert modes to use portable file type values

2014-11-30 Thread Junio C Hamano
David Michael  writes:

> This is my most recent attempt at solving the problem of z/OS using
> different file type values than every other OS.  I believe it should be
> safe as long as the file type bits don't ever need to be converted back
> to their native values (and I didn't see any instances of that).
>
> I've been testing it by making commits to the same repositories on
> different operating systems and pushing those changes around, and so far
> there have been no issues.
>
> Can anyone foresee any problems with this method?

I cannot offhand comment on the last question above, but the
reliance on exact S_IFxxx bit assignment was identified as a
potential problem from very early days of Git that we have known
about but didn't have need to address on any system that mattered.

This is a long overdue issue and I am happy to see it getting
tackled.  The patch seems to be a sensible implementation of your
design decision to use the one-way conversion.

> diff --git a/compat/stat.c b/compat/stat.c
> new file mode 100644
> index 000..0ff1f2f
> --- /dev/null
> +++ b/compat/stat.c
> @@ -0,0 +1,49 @@
> +#define _POSIX_SOURCE
> +#include /* NULL */
> +#include   /* *stat, S_IS* */
> +#include  /* mode_t   */
> +
> +static inline mode_t mode_native_to_git(mode_t native_mode)
> +{
> + if (S_ISREG(native_mode))
> + return 010 | (native_mode & 0);
> + else if (S_ISDIR(native_mode))
> + return 004 | (native_mode & 0);
> + else if (S_ISLNK(native_mode))
> + return 012 | (native_mode & 0);
> + else if (S_ISBLK(native_mode))
> + return 006 | (native_mode & 0);
> + else if (S_ISCHR(native_mode))
> + return 002 | (native_mode & 0);
> + else if (S_ISFIFO(native_mode))
> + return 001 | (native_mode & 0);
> + else /* Non-standard type bits were given. */
> + return native_mode & 0;
> +}

--
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] introduce git root

2014-11-30 Thread Junio C Hamano
Matthieu Moy  writes:

> ... git rev-parse --show-toplevel is not just long,
> it's just not the place where people would look for (it's neither about
> revision nor about parsing, so clearly, "rev-parse" is not a good place
> to host the feature in the UI).

For the record, "rev-parse" is not about revisions in the first
place.  It started purely as a helper to implement "git log" in
terms of "git rev-list" piped to "git diff-tree --stdin", which
requires you to sift a command line argument list given to such
a scripted "git log" into those to be passed to "rev-list" (i.e.
primarily revision ranges) and those to be passed to "diff-tree"
(i.e. primarily diff options and pathspecs).

Various subcommands "rev-parse" takes such as --show-git-dir were
added only because there wasn't any single best "kitchen sink"
command to tuck such a small feature that do not deserve a
standalone command (e.g. "git root", which makes it sound as if the
top-level of the working tree is the most important thing in the
world, and adding other useful things such as --show-prefix to it,
while it would make sense to have them there from the implementation
point of view, would be hard to justify against the connotation the
word "root" gives us), and we happened to pick "rev-parse" as a
"kitchen sink" place, which is not better or worse as anything else.

If I were redoing this today, I would probably nominate the "git"
potty as such a "kitchen synk" command.  We have "--man-path" that
shows the location of the manual pages, "--exec-path[=path]" that
either shows or allows us to override the path to the subcommands,
and "--show-prefix", "--show-toplevel", and friends may feel quite
at home there.
--
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


Deprecation warnings under XCode

2014-11-30 Thread Michael Blume
I have no idea whether this should concern anyone, but my mac build of git shows

CC imap-send.o
imap-send.c:183:36: warning: 'ERR_error_string' is deprecated: first
deprecated in OS X 10.7 [-Wdeprecated-declarations]
fprintf(stderr, "%s: %s\n", func,
ERR_error_string(ERR_get_error(), NULL));
  ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/openssl/err.h:279:7:
note: 'ERR_error_string' has been explicitly marked deprecated here
char *ERR_error_string(unsigned long e,char *buf)
DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;
  ^
imap-send.c:183:53: warning: 'ERR_get_error' is deprecated: first
deprecated in OS X 10.7 [-Wdeprecated-declarations]
fprintf(stderr, "%s: %s\n", func,
ERR_error_string(ERR_get_error(), NULL));
   ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/openssl/err.h:266:15:
note: 'ERR_get_error' has been explicitly marked deprecated here
unsigned long ERR_get_error(void) DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;
  ^
imap-send.c:191:16: warning: 'SSL_get_error' is deprecated: first
deprecated in OS X 10.7 [-Wdeprecated-declarations]
int sslerr = SSL_get_error(sock->ssl, ret);
 ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/openssl/ssl.h:1506:5:
note: 'SSL_get_error' has been explicitly marked deprecated here
int SSL_get_error(const SSL *s,int ret_code)
DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;
^
imap-send.c:243:24: warning: 'X509_get_ext_d2i' is deprecated: first
deprecated in OS X 10.7 [-Wdeprecated-declarations]
if ((subj_alt_names = X509_get_ext_d2i(cert,
NID_subject_alt_name, NULL, NULL))) {
  ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/openssl/x509.h:1151:8:
note: 'X509_get_ext_d2i' has been explicitly marked deprecated here
void*   X509_get_ext_d2i(X509 *x, int nid, int *crit, int
*idx) DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;
^
imap-send.c:244:28: warning: 'sk_num' is deprecated: first deprecated
in OS X 10.7 [-Wdeprecated-declarations]
int num_subj_alt_names = sk_GENERAL_NAME_num(subj_alt_names);
 ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/openssl/safestack.h:684:33:
note: expanded from macro 'sk_GENERAL_NAME_num'
#define sk_GENERAL_NAME_num(st) SKM_sk_num(GENERAL_NAME, (st))
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/openssl/safestack.h:168:2:
note: expanded from macro 'SKM_sk_num'
sk_num(st)
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/openssl/stack.h:81:5:
note: 'sk_num' has been explicitly marked deprecated here
int sk_num(const STACK *) DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;
^
imap-send.c:246:34: warning: 'sk_value' is deprecated: first
deprecated in OS X 10.7 [-Wdeprecated-declarations]
GENERAL_NAME *subj_alt_name =
sk_GENERAL_NAME_value(subj_alt_names, i);
  ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/openssl/safestack.h:685:38:
note: expanded from macro 'sk_GENERAL_NAME_value'
#define sk_GENERAL_NAME_value(st, i) SKM_sk_value(GENERAL_NAME, (st), (i))
 ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/openssl/safestack.h:170:11:
note: expanded from macro 'SKM_sk_value'
((type *)sk_value(st, i))
 ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/openssl/stack.h:82:7:
note: 'sk_value' has been explicitly marked deprecated here
char *sk_value(const STACK *, int)
DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;
  ^
imap-send.c:252:3: warning: 'sk_pop_free' is deprecated: first
deprecated in OS X 10.7 [-Wdeprecated-declarations]
sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free);
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/openssl/safestack.h:697:49:
note: expanded from macro 'sk_GENERAL_NAME_pop_free'
#define sk_GENERAL_NAME_pop_free(st, free_func)
SKM_sk_pop_free(GENERAL_NAME, (st), (free_func))
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platf

Re: Our cumbersome mailing list workflow

2014-11-30 Thread Junio C Hamano
Michael Haggerty  writes:

> It seems like a few desirable features are being talked about here, and
> summarizing the discussion as "centralized" vs "decentralized" is too
> simplistic. What is really important?
>
> 1. Convenient and efficient, including for newcomers
> 2. Usable while offline
> 3. Usable in pure-text mode
> 4. Decentralized
>
> Something else?

As a reviewer / contributor (not speaking as the top maintainer), I
would say that everything in one place, and for that one place
mailbox is preferrable.

"Somebody commented on (this instance of | the central) Gerrit, come
look at it" is not usable; sending that comment out to those who
work in their MUA, and allowing them to respond via their MUA
probably adding their response as a new comment to Gerrit) would be
usable.

When I had to view a large-ish series by Ronnie on Gerrit, it was
fairly painful.  The interaction on an individual patch might be
more convenient and efficient using a system like Gerrit than via
e-mailed patch with reply messages, but as a vehicle to review a
large series and see how the whole thing fits together, I did not
find pages that made it usable (I am avoiding to say "I found it
unusable", as that impression may be purely from that I couldn't
find a more suitable pages that showed the same information in more
usable form, i.e. user inexperience).

Speaking of the "whole picture", I am hesitant to see us pushed into
the "here is a central system (or here are federated systems) to
handle only the patch reviews" direction; our changes result after
discussing unrelated features, wishes, or bugs that happen outside
of any specific patches with enough frequency, and that is why I
prefer "everything in one place" aspect of the development based on
the mailing list.  That is not to say that the "one place" has
forever to be the mailing list, though.  But the tooling around an
e-mail based workflow (e.g. marking threads as "worth revisiting"
for later inspection, saving chosen messages into a mailbox and
running "git am" on it) is already something I am used to.  Whatever
system we might end up migrating to, the convenience it offers has
to beat the convenience of existing workflow to be worth switching
to, at least to me as a reviewer/contributor.

As the maintainer, I am not worried too much.  As long as the
mechanism can (1) reach "here is a series that is accepted by
reviewers whose opinions are trusted" efficiently, and (2) allow
me to queue the result without mistakes, I can go along with
anything reasonable.

--
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: [PATCHv3 2/3] mailmap: use higher level string list functions

2014-11-30 Thread Stefan Beller
On 30.11.2014 16:47, Junio C Hamano wrote:
> Eric Sunshine  writes:
> 
>> On Thu, Nov 27, 2014 at 1:44 PM, Michael Blume  wrote:
>>> The variable index seems to be unused/uninitialized now -- it's still
>>> printed in debug messages, but if I'm reading correctly, its contents are
>>> going to be nonsense.
>>
>> Nice catch.
> 
> Let's do something like this squashed in, then.

Michael, thanks for catching that!

Junio, the squash-in looks fine with me.

> 
>  mailmap.c | 7 +++
>  1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/mailmap.c b/mailmap.c
> index 3b00a65..cb26af0 100644
> --- a/mailmap.c
> +++ b/mailmap.c
> @@ -90,8 +90,8 @@ static void add_mapping(struct string_list *map,
>   }
>  
>   if (old_name == NULL) {
> - debug_mm("mailmap: adding (simple) entry for %s at index %d\n",
> -  old_email, index);
> + debug_mm("mailmap: adding (simple) entry for '%s'\n", 
> old_email);
> +
>   /* Replace current name and new email for simple entry */
>   if (new_name) {
>   free(me->name);
> @@ -103,8 +103,7 @@ static void add_mapping(struct string_list *map,
>   }
>   } else {
>   struct mailmap_info *mi = xcalloc(1, sizeof(struct 
> mailmap_info));
> - debug_mm("mailmap: adding (complex) entry for %s at index %d\n",
> -  old_email, index);
> + debug_mm("mailmap: adding (complex) entry for '%s'\n", 
> old_email);
>   if (new_name)
>   mi->name = xstrdup(new_name);
>   if (new_email)
> --
> 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
> 

--
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: 'simple' push check that branch name matches does not work if push.default is unset (and hence implicitly simple)

2014-11-30 Thread Junio C Hamano
Jeff King  writes:

> There is some other magic with "simple", too, around triangular
> workflows. Describing it in detail would probably be too verbose in this
> message, but we do refer to the description of push.default, which is
> probably enough.  Technically this new bit you are adding here is
> covered there, too. But since we can improve the description by adding
> such a small amount of text in this case, it seems like a reasonable
> tradeoff.
>
> I suppose we could also customize the message based on the triangular
> and non-triangular cases. I dunno.

Yeah, I vaguely recall suggesting to polish advice message further
to help users along a similar line, but probably that fell in the
cracks.

Thanks for a quick fix.
--
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: What's cooking in git.git (Nov 2014, #04; Wed, 26)

2014-11-30 Thread Junio C Hamano
"brian m. carlson"  writes:

> On Wed, Nov 26, 2014 at 03:09:45PM -0800, Junio C Hamano wrote:
>> * nd/untracked-cache (2014-10-27) 19 commits
>> ...
>>  - dir.c: optionally compute sha-1 of a .gitignore file
>
> You didn't comment on the status of this branch, and I'm interested.

I think we already saw a few comments responded by the author with
"thanks, will include in a reroll", and that is why the listed are
not even the latest round.

The status was "waiting for a reroll".  I haven't caught up with the
traffic for the past few days, though.
--
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] commit: inform pre-commit if --amend is used

2014-11-30 Thread Junio C Hamano
Mark Levedahl  writes:

> On 11/28/2014 12:18 AM, Jeff King wrote:
>
>> Thanks for the links; I had no recollection of that thread.
>> Unsurprisingly, I like the "HEAD"/"HEAD~1" suggestion. That "peff" guy
>> seems really clever (and handsome, too, I'll bet).
>>
>> I'd still be OK with any of the suggestions given in this thread,
>> though.
>>
>> -Peff
>> ars
>
> Apparently our combined handsome-foo was insufficient to get this
> accepted way back when, hopefully the current submitter has more :^)
>
> In any event, I've carried the patches using HEAD/HEAD~1 in my tree
> for the last 4+ years, have a widely used pre-commit script that
> depends upon those. So, I personally would be very happy to see this
> finally show up in Junio's tree, would prefer HEAD/HEAD~1 but can
> adapt to whatever.

One thing to be careful about is that the approach HEAD, HEAD~,
etc. does allow this to be extended to cover merge cases as the old
thread speculated, it will make it impossible to pass any kind of
information, other than "here are the parents of the results", to
the hook.

Of course, there are ways to make sure that we won't paint us into
an unescapable corner, e.g. an obvious example (not necessarily the
best) being to pass "HEAD", "HEAD~", "b76b088 b260d26" etc., in
other words, passing these parents still as a single argument,
multiple parents concatenated with some delimiters, so that "$1"
will always be "who are the parent(s)" even when we needed to later
pass other sorts of information.
--
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: [PATCHv3 2/3] mailmap: use higher level string list functions

2014-11-30 Thread Junio C Hamano
Eric Sunshine  writes:

> On Thu, Nov 27, 2014 at 1:44 PM, Michael Blume  wrote:
>> The variable index seems to be unused/uninitialized now -- it's still
>> printed in debug messages, but if I'm reading correctly, its contents are
>> going to be nonsense.
>
> Nice catch.

Let's do something like this squashed in, then.

 mailmap.c | 7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/mailmap.c b/mailmap.c
index 3b00a65..cb26af0 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -90,8 +90,8 @@ static void add_mapping(struct string_list *map,
}
 
if (old_name == NULL) {
-   debug_mm("mailmap: adding (simple) entry for %s at index %d\n",
-old_email, index);
+   debug_mm("mailmap: adding (simple) entry for '%s'\n", 
old_email);
+
/* Replace current name and new email for simple entry */
if (new_name) {
free(me->name);
@@ -103,8 +103,7 @@ static void add_mapping(struct string_list *map,
}
} else {
struct mailmap_info *mi = xcalloc(1, sizeof(struct 
mailmap_info));
-   debug_mm("mailmap: adding (complex) entry for %s at index %d\n",
-old_email, index);
+   debug_mm("mailmap: adding (complex) entry for '%s'\n", 
old_email);
if (new_name)
mi->name = xstrdup(new_name);
if (new_email)
--
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/RFC v2] Squashed changes for multiple worktrees vs. submodules

2014-11-30 Thread Max Kirillov
builtin/checkout.c: use absolute path instead of given argument for
 picking worktree name, it happens to be needed because for submodule
 checkout the new worktree is always "."
environment.c: add GIT_COMMON_DIR to local_repo_env
git-submodule.sh: implement automatic cloning of main repository
 and checkout to new worktree at "submodule update --init"
path.c, setup.c, submodule.c: fix "diff --submodule" when
 submodule is a linked worktree
t/t7410-submodule-checkout-to.sh: tests for all the above

Signed-off-by: Max Kirillov 
---
Hi.

Thanks for including my 2 patches.

But, while hacking the submodule init I became more convinced that the
modules directory should be common and submodules in checkout should be
a checkouts of the submodule. Because this is looks like concept of
submodules, that they are unique for the lifetime of repository, even if
they do not exist in all revisions. And if anybody want to use fully
independent checkout they can be always checked out manually. Actually,
after a submodule is initialized and have a proper gitlink, it can be
updated and inquired regardless of where it points to.

So that one I think is not needed. I have instead some changes to
git-submodule, but have not prepared them yet as an exportable history.

I am submitting here squashed changes which I have so far, to give an
idea where it goes. I'll try to prepare a proper patch series as soon as
I can.

They contain change $gmane/258173, which I think is important,
especially because it is required not only for initialization but for
regular work also, and changes for initialization of submodules.

They are rebased on top of you patches excluding the 34/34 patch.

 builtin/checkout.c   |  25 ++---
 cache.h  |   1 +
 environment.c|   1 +
 git-submodule.sh |  94 ++
 path.c   |  24 -
 setup.c  |  17 +++-
 submodule.c  |  28 ++
 t/t7410-submodule-checkout-to.sh | 201 +++
 8 files changed, 332 insertions(+), 59 deletions(-)
 create mode 100755 t/t7410-submodule-checkout-to.sh

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 953b763..78154ae 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -858,27 +858,29 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
 {
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT;
-   const char *path = opts->new_worktree, *name;
+   struct strbuf sb_path = STRBUF_INIT;
+   const char *name;
struct stat st;
struct child_process cp;
int counter = 0, len, ret;
 
if (!new->commit)
die(_("no branch specified"));
-   if (file_exists(path) && !is_empty_dir(path))
-   die(_("'%s' already exists"), path);
+   strbuf_add_absolute_path(&sb_path, opts->new_worktree);
+   if (file_exists(sb_path.buf) && !is_empty_dir(sb_path.buf))
+   die(_("'%s' already exists"), sb_path.buf);
 
-   len = strlen(path);
-   while (len && is_dir_sep(path[len - 1]))
+   len = sb_path.len;
+   while (len && is_dir_sep(sb_path.buf[len - 1]))
len--;
 
-   for (name = path + len - 1; name > path; name--)
+   for (name = sb_path.buf + len - 1; name > sb_path.buf; name--)
if (is_dir_sep(*name)) {
name++;
break;
}
strbuf_addstr(&sb_repo,
- git_path("worktrees/%.*s", (int)(path + len - name), 
name));
+ git_path("worktrees/%.*s", (int)(sb_path.buf + len - 
name), name));
len = sb_repo.len;
if (safe_create_leading_directories_const(sb_repo.buf))
die_errno(_("could not create leading directories of '%s'"),
@@ -906,11 +908,11 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
strbuf_addf(&sb, "%s/locked", sb_repo.buf);
write_file(sb.buf, 1, "initializing\n");
 
-   strbuf_addf(&sb_git, "%s/.git", path);
+   strbuf_addf(&sb_git, "%s/.git", sb_path.buf);
if (safe_create_leading_directories_const(sb_git.buf))
die_errno(_("could not create leading directories of '%s'"),
  sb_git.buf);
-   junk_work_tree = xstrdup(path);
+   junk_work_tree = xstrdup(sb_path.buf);
 
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
@@ -931,11 +933,11 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
write_file(sb.buf, 1, "../..\n");
 
if (!opts->quiet)
-   fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
+   fprintf_ln(stderr, _("Enter %s (identifier %s)"), sb_path.buf, 
name);
 
setenv("GIT_CHECKOUT_NEW_WORKTREE", "1", 1);
setenv(GIT_DIR_ENVIRONMENT, 

Re: [PATCH] compat: convert modes to use portable file type values

2014-11-30 Thread Torsten Bögershausen
On 2014-11-30 03.41, David Michael wrote:
Some minor comments:
> +static inline mode_t mode_native_to_git(mode_t native_mode)
> +{
> + if (S_ISREG(native_mode))
> + return 010 | (native_mode & 0);
> + else if (S_ISDIR(native_mode))
> + return 004 | (native_mode & 0);
> + else if (S_ISLNK(native_mode))
> + return 012 | (native_mode & 0);
> + else if (S_ISBLK(native_mode))
> + return 006 | (native_mode & 0);
> + else if (S_ISCHR(native_mode))
> + return 002 | (native_mode & 0);
> + else if (S_ISFIFO(native_mode))
> + return 001 | (native_mode & 0);
> + else /* Non-standard type bits were given. */
> + return native_mode & 0;
> +}
Could the code be more human-readable ?
static inline mode_t mode_native_to_git(mode_t native_mode)
{
int perm_bits = native_mode & 0;
if (S_ISREG(native_mode))
return 010 | perm_bits;
if (S_ISDIR(native_mode))
return 004 | perm_bits;
if (S_ISLNK(native_mode))
return 012 | perm_bits;
if (S_ISBLK(native_mode))
return 006 | perm_bits;
if (S_ISCHR(native_mode))
return 002 | perm_bits;
if (S_ISFIFO(native_mode))
return 001 | perm_bits;
/* Non-standard type bits were given. */
/* Shouldn't we die() here ?? */
return perm_bits;
}

--
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 v2] t0027: check the eol conversion warnings

2014-11-30 Thread Torsten Bögershausen
Depending on the file content, eol parameters and .gitattributes
"git add" may give a warning when the eol of a file will change
when the file is checked out again.

There are 2 different warnings, either "CRLF will be replaced..." or
"LF will be replaced...".

Let t0027 check for these warnings:
call create_file_in_repo() with additional parameters,
which will be used to call check_warning().

When a file has eol=lf or eol=crlf in .gitattributes, it is handled
as text and should be normalized.
Add missing test cases in t0027.

Signed-off-by: Torsten Bögershausen 
---
Changes since V1:
- Simplified the diff
- Fixed a bug (LF_mix_CR.err was mixed with CRLF_mix_LF)
- Changed the commit message
 t/t0027-auto-crlf.sh | 82 ++--
 1 file changed, 66 insertions(+), 16 deletions(-)

diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index 2a4a6c1..452320d 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -55,16 +55,41 @@ create_gitattributes () {
esac
 }
 
+check_warning () {
+   case "$1" in
+   LF_CRLF) grep "LF will be replaced by CRLF" $2;;
+   CRLF_LF) grep "CRLF will be replaced by LF" $2;;
+   '')
+   >expect
+   grep "will be replaced by" $2 >actual
+   test_cmp expect actual
+   ;;
+   *) false ;;
+   esac
+}
+
 create_file_in_repo () {
crlf=$1
attr=$2
+   lfname=$3
+   crlfname=$4
+   lfmixcrlf=$5
+   lfmixcr=$6
+   crlfnul=$7
create_gitattributes "$attr" &&
+   pfx=crlf_${crlf}_attr_${attr}
for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul
do
-   pfx=crlf_${crlf}_attr_${attr}_$f.txt &&
-   cp $f $pfx && git -c core.autocrlf=$crlf add $pfx
+   fname=${pfx}_$f.txt &&
+   cp $f $fname &&
+   git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err"
done &&
-   git commit -m "core.autocrlf $crlf"
+   git commit -m "core.autocrlf $crlf" &&
+   check_warning "$lfname" ${pfx}_LF.err &&
+   check_warning "$crlfname" ${pfx}_CRLF.err &&
+   check_warning "$lfmixcrlf" ${pfx}_CRLF_mix_LF.err &&
+   check_warning "$lfmixcr" ${pfx}_LF_mix_CR.err &&
+   check_warning "$crlfnul" ${pfx}_CRLF_nul.err
 }
 
 check_files_in_repo () {
@@ -140,22 +165,47 @@ test_expect_success 'setup master' '
 '
 
 
-test_expect_success 'create files' '
-   create_file_in_repo false "" &&
-   create_file_in_repo true  "" &&
-   create_file_in_repo input "" &&
 
-   create_file_in_repo false "auto" &&
-   create_file_in_repo true  "auto" &&
-   create_file_in_repo input "auto" &&
+warn_LF_CRLF="LF will be replaced by CRLF"
+warn_CRLF_LF="CRLF will be replaced by LF"
+
+test_expect_success 'add files empty attr' '
+   create_file_in_repo false "" """"""""   
 "" &&
+   create_file_in_repo true  "" "LF_CRLF" """LF_CRLF" ""   
 "" &&
+   create_file_in_repo input "" """CRLF_LF" "CRLF_LF" ""   
 ""
+'
+
+test_expect_success 'add files attr=auto' '
+   create_file_in_repo false "auto" """CRLF_LF" "CRLF_LF" ""   
 "" &&
+   create_file_in_repo true  "auto" "LF_CRLF" """LF_CRLF" ""   
 "" &&
+   create_file_in_repo input "auto" """CRLF_LF" "CRLF_LF" ""   
 ""
+'
+
+test_expect_success 'add files attr=text' '
+   create_file_in_repo false "text" """CRLF_LF" "CRLF_LF" ""   
 "CRLF_LF" &&
+   create_file_in_repo true  "text" "LF_CRLF" """LF_CRLF" 
"LF_CRLF" ""&&
+   create_file_in_repo input "text" """CRLF_LF" "CRLF_LF" ""   
 "CRLF_LF"
+'
+
+test_expect_success 'add files attr=-text' '
+   create_file_in_repo false "-text" ""   """"""   
 "" &&
+   create_file_in_repo true  "-text" ""   """"""   
 "" &&
+   create_file_in_repo input "-text" ""   """"""   
 ""
+'
+
+test_expect_success 'add files attr=lf' '
+   create_file_in_repo false "lf"""   "CRLF_LF" "CRLF_LF"  ""  
 "CRLF_LF" &&
+   create_file_in_repo true  "lf"""   "CRLF_LF" "CRLF_LF"  ""  
 "CRLF_LF" &&
+   create_file_in_repo input "lf"""   "CRLF_LF" "CRLF_LF"  ""  
 "CRLF_LF"
+'
 
-   create_file_in_repo false "text" &&
-   create_file_in_repo true  "text" &&
-   create_file_in_repo input "text" &&
+test_expect_success 'add files attr=crlf' '
+   create_file_in_repo false "crlf" "LF_CRLF" """LF_CRLF" 
"LF_CRLF" "" &&
+   create_file_in_repo true  "crlf" "LF_CRLF" """LF_CRLF" 
"LF_CRLF" "" &&
+   create_file_in_repo input "crlf" "LF_CRLF" """LF_CRLF" 
"LF_CRLF" ""
+'
 
-   create_file_in_repo false "-text" &&
-   create_file_in_repo true  "-text" &&
-   create_file_in_repo input "-text" &&
+test_expect_success 

Re: What's cooking in git.git (Nov 2014, #04; Wed, 26)

2014-11-30 Thread brian m. carlson
On Sun, Nov 30, 2014 at 03:35:33PM +0700, Duy Nguyen wrote:
> I'm not Junio :) but I think the core changes are done. I wanted to
> actually add watchman support on top of untracked cache as well to see
> if it needs any more changes. I think I can see how it could be done
> now (not easy, but not terribly hard). I'm going to resend soon to fix
> some minor bugs (in a reroll that Junio has not picked up) and change
> file format to be more compact.

Excellent.  I want to see if this improves performance over sshfs, but I
don't want to enable it until I can put it on the server machine as well
to prevent incompatibilities.
-- 
brian m. carlson / brian with sandals: Houston, Texas, US
+1 832 623 2791 | http://www.crustytoothpaste.net/~bmc | My opinion only
OpenPGP: RSA v4 4096b: 88AC E9B2 9196 305B A994 7552 F1BA 225C 0223 B187


signature.asc
Description: Digital signature


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

2014-11-30 Thread Mark Levedahl

On 11/30/2014 03:24 AM, Nguyễn Thái Ngọc Duy wrote:

One branch obviously can't be checked out at two places (but detached
heads are ok). Give the user a choice in this case: --detach, -b
new-branch, switch branch in the other checkout first or simply 'cd'
and continue to work there.



This seems too restrictive and is not "obvious" to me: I currently use 
git-new-workdir to have multiple checkouts of the same branch, with no 
ill effect. While those who do not understand what is going on 
underneath might be confused by one checkout suddenly showing 
uncommitted diffs, I don't accept that as a reason to outright prevent 
such use. I suggest, at the very least, that this behavior be overridden 
by a --force flag?


Mark

--
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: Force git submodule update --remote for some branches

2014-11-30 Thread Jens Lehmann

Am 28.11.2014 um 18:54 schrieb Timothy M. Redaelli:

I have a repository with a submodule and I'd like to force git to
checkout the LAST version of the submodule and not the stored one (like
git submodule update --remote), but only on some branches and without
the need to remember to add --remote every time you are on this branch.

Is there any way to do it? Maybe using .gitmodules?


Not yet.

But yes, .gitmodules would be the right place to put such a
configuration as then it would be per submodule and also per
(superproject-)branch.

By the way, what do you think the output of git status and
git diff should look like when you updated a submodule to
its branch tip which differs from the commit recorded in
the superproject? Should these changes be displayed or not?
And only if the new tip is a fast-forward of the old or
always?
--
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: Thinning a repository

2014-11-30 Thread Yuri D'Elia
On 11/30/2014 01:34 PM, Fredrik Gustafsson wrote:
> On Sun, Nov 30, 2014 at 01:18:34PM +0100, Yuri D'Elia wrote:
>> Is there a quick way to reproduce the effect of a shallow clone on a
>> local repository that doesn't involve filter-branch and/or re-clone?
> 
> I'm curious, why is it a bad thing to do a re-clone? If you clone your
> local repo it would be really fast.

I see no reason to involve the workspace.
I would also want to keep the current remote/origin as it is.

I expect a 'thin' command to be faster by not touching the workspace at all.


--
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: Thinning a repository

2014-11-30 Thread Fredrik Gustafsson
On Sun, Nov 30, 2014 at 01:18:34PM +0100, Yuri D'Elia wrote:
> Is there a quick way to reproduce the effect of a shallow clone on a
> local repository that doesn't involve filter-branch and/or re-clone?

I'm curious, why is it a bad thing to do a re-clone? If you clone your
local repo it would be really fast.

-- 
Med vänlig hälsning
Fredrik Gustafsson

tel: 0733-608274
e-post: iv...@iveqy.com
--
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


Thinning a repository

2014-11-30 Thread Yuri D'Elia
Hi everyone,

Is there a quick way to reproduce the effect of a shallow clone on a
local repository that doesn't involve filter-branch and/or re-clone?

My motivation is to reduce the local size of repositories I'm only
following, by trimming the history without prejudice to a [N] set of
last commits. It feels stupid that the quickest way I'm aware of right
now to achieve this is to "git clone --depth N ..." again. filter-branch
is ridiculously slow, as it iterates through history.

I've tried using graft points, but the combination of:

echo [sha] > .git/info/grafts
git reflog expire --expire=0 --all
git repack -Ad

doesn't really save any space and/or reduce the object count as I would
expect. It means there's probably still reachable?

I'd really love to have a 'git thin [depth]' subcommand to perform the
above however. I don't really want to have to iterate through refs just
to check if they are still reachable within [n] commits just to delete them.

Thanks for any pointer.

--
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] introduce git root

2014-11-30 Thread Matthieu Moy
Arjun Sreedharan  writes:

> On 30 November 2014 at 04:38, Philip Oakley  wrote:
>> From: "Arjun Sreedharan" 
>>>
>>> This introduces `git root` which outputs the root directory
>>> (the directory that contains .git).
>>> The same can be accomplished by `git rev-parse --show-toplevel`.
>>> `git root` is much more intuitive and easy to remember.
>>> All it does is set the arguments for rev-parse
>>
>>
>> This may be better as an alias.
>> I've added it to my aliases list.
>>
>
> I know that. I am suggesting this to be a built-in command, without having the
> need to add as an alias.

Indeed, suggesting people to add an alias does not solve the
discoverability issue. git rev-parse --show-toplevel is not just long,
it's just not the place where people would look for (it's neither about
revision nor about parsing, so clearly, "rev-parse" is not a good place
to host the feature in the UI).

If we were to rewrite Git from scratch, then I would be all for having a
"git root" command. Given that we already have rev-parse
--show-toplevel, and that we'll have to keep it anyway for backward
compatibility, I'm a bit more hesitant ("Git is hard to use because it
doesn't have enough commands" is not a complain I hear so often ;-) ),
but still mostly positive.

If we go this way, then the documentation must be updated too. I think
the doc should still recommend "git rev-parse --show-toplevel" for
scripting until Git versions implementing "git root" are widely deployed
enough.

Also, there are other options of git rev-parse which should be dealt
with: at least --show-cdup (could be eg. "git root --relative") and
--show-prefix, but probably also others from the "Options for Files" in
the man of git-rev-parse.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/
--
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 3/3] ls-tree: disable negative pathspec because it's not supported

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 builtin/ls-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 053edb2..3b04a0f 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -174,7 +174,8 @@ int cmd_ls_tree(int argc, const char **argv, const char 
*prefix)
 * cannot be lifted until it is converted to use
 * match_pathspec() or tree_entry_interesting()
 */
-   parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE,
+   parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |
+ PATHSPEC_EXCLUDE,
   PATHSPEC_PREFER_CWD,
   prefix, argv + 1);
for (i = 0; i < pathspec.nr; i++)
-- 
2.2.0.60.gb7b3c64

--
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 2/3] ls-tree: remove path filtering logic in show_tree

2014-11-30 Thread Nguyễn Thái Ngọc Duy
ls-tree uses read_tree_recursive() which already does path filtering
using pathspec. No need to filter one more time based on prefix
only. "ls-tree ../somewhere" does not work because of
this. write_name_quotedpfx() can now be retired because nobody else
uses it.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 builtin/ls-tree.c| 14 +++---
 quote.c  | 21 -
 quote.h  |  2 --
 t/t3102-ls-tree-wildcards.sh |  8 
 4 files changed, 15 insertions(+), 30 deletions(-)

diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 1ab0381..053edb2 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -65,6 +65,7 @@ static int show_tree(const unsigned char *sha1, struct strbuf 
*base,
const char *pathname, unsigned mode, int stage, void *context)
 {
int retval = 0;
+   int baselen;
const char *type = blob_type;
 
if (S_ISGITLINK(mode)) {
@@ -89,11 +90,6 @@ static int show_tree(const unsigned char *sha1, struct 
strbuf *base,
else if (ls_options & LS_TREE_ONLY)
return 0;
 
-   if (chomp_prefix &&
-   (base->len < chomp_prefix ||
-memcmp(ls_tree_prefix, base->buf, chomp_prefix)))
-   return 0;
-
if (!(ls_options & LS_NAME_ONLY)) {
if (ls_options & LS_SHOW_SIZE) {
char size_text[24];
@@ -113,8 +109,12 @@ static int show_tree(const unsigned char *sha1, struct 
strbuf *base,
printf("%06o %s %s\t", mode, type,
   find_unique_abbrev(sha1, abbrev));
}
-   write_name_quotedpfx(base->buf + chomp_prefix, base->len - chomp_prefix,
- pathname, stdout, line_termination);
+   baselen = base->len;
+   strbuf_addstr(base, pathname);
+   write_name_quoted_relative(base->buf,
+  chomp_prefix ? ls_tree_prefix : NULL,
+  stdout, line_termination);
+   strbuf_setlen(base, baselen);
return retval;
 }
 
diff --git a/quote.c b/quote.c
index 45e3db1..7920e18 100644
--- a/quote.c
+++ b/quote.c
@@ -274,27 +274,6 @@ void write_name_quoted(const char *name, FILE *fp, int 
terminator)
fputc(terminator, fp);
 }
 
-void write_name_quotedpfx(const char *pfx, size_t pfxlen,
- const char *name, FILE *fp, int terminator)
-{
-   int needquote = 0;
-
-   if (terminator) {
-   needquote = next_quote_pos(pfx, pfxlen) < pfxlen
-   || name[next_quote_pos(name, -1)];
-   }
-   if (needquote) {
-   fputc('"', fp);
-   quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
-   quote_c_style(name, NULL, fp, 1);
-   fputc('"', fp);
-   } else {
-   fwrite(pfx, pfxlen, 1, fp);
-   fputs(name, fp);
-   }
-   fputc(terminator, fp);
-}
-
 void write_name_quoted_relative(const char *name, const char *prefix,
FILE *fp, int terminator)
 {
diff --git a/quote.h b/quote.h
index 71dcc3a..99e04d3 100644
--- a/quote.h
+++ b/quote.h
@@ -56,8 +56,6 @@ extern size_t quote_c_style(const char *name, struct strbuf 
*, FILE *, int no_dq
 extern void quote_two_c_style(struct strbuf *, const char *, const char *, 
int);
 
 extern void write_name_quoted(const char *name, FILE *, int terminator);
-extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
- const char *name, FILE *, int terminator);
 extern void write_name_quoted_relative(const char *name, const char *prefix,
FILE *fp, int terminator);
 
diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854..83fca8d 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -19,4 +19,12 @@ EOF
test_cmp expected actual
 '
 
+test_expect_success 'ls-tree outside prefix' '
+   cat >expected 

[PATCH 1/3] tree.c: update read_tree_recursive callback to pass strbuf as base

2014-11-30 Thread Nguyễn Thái Ngọc Duy
This allows the callback to use 'base' as a temporary buffer to
quickly assemble full path "without" extra allocation. The callback
has to restore it afterwards of course.

Helped-by: Eric Sunshine 
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 archive.c  | 34 +-
 builtin/checkout.c |  8 
 builtin/log.c  |  2 +-
 builtin/ls-tree.c  |  9 +
 merge-recursive.c  | 15 ++-
 tree.c | 16 +++-
 tree.h |  3 ++-
 7 files changed, 50 insertions(+), 37 deletions(-)

diff --git a/archive.c b/archive.c
index 94a9981..9e30246 100644
--- a/archive.c
+++ b/archive.c
@@ -157,18 +157,26 @@ static int write_archive_entry(const unsigned char *sha1, 
const char *base,
return write_entry(args, sha1, path.buf, path.len, mode);
 }
 
+static int write_archive_entry_buf(const unsigned char *sha1, struct strbuf 
*base,
+   const char *filename, unsigned mode, int stage,
+   void *context)
+{
+   return write_archive_entry(sha1, base->buf, base->len,
+filename, mode, stage, context);
+}
+
 static void queue_directory(const unsigned char *sha1,
-   const char *base, int baselen, const char *filename,
+   struct strbuf *base, const char *filename,
unsigned mode, int stage, struct archiver_context *c)
 {
struct directory *d;
-   d = xmallocz(sizeof(*d) + baselen + 1 + strlen(filename));
+   d = xmallocz(sizeof(*d) + base->len + 1 + strlen(filename));
d->up  = c->bottom;
-   d->baselen = baselen;
+   d->baselen = base->len;
d->mode= mode;
d->stage   = stage;
c->bottom  = d;
-   d->len = sprintf(d->path, "%.*s%s/", baselen, base, filename);
+   d->len = sprintf(d->path, "%.*s%s/", (int)base->len, base->buf, 
filename);
hashcpy(d->sha1, sha1);
 }
 
@@ -191,28 +199,28 @@ static int write_directory(struct archiver_context *c)
 }
 
 static int queue_or_write_archive_entry(const unsigned char *sha1,
-   const char *base, int baselen, const char *filename,
+   struct strbuf *base, const char *filename,
unsigned mode, int stage, void *context)
 {
struct archiver_context *c = context;
 
while (c->bottom &&
-  !(baselen >= c->bottom->len &&
-!strncmp(base, c->bottom->path, c->bottom->len))) {
+  !(base->len >= c->bottom->len &&
+!strncmp(base->buf, c->bottom->path, c->bottom->len))) {
struct directory *next = c->bottom->up;
free(c->bottom);
c->bottom = next;
}
 
if (S_ISDIR(mode)) {
-   queue_directory(sha1, base, baselen, filename,
+   queue_directory(sha1, base, filename,
mode, stage, c);
return READ_TREE_RECURSIVE;
}
 
if (write_directory(c))
return -1;
-   return write_archive_entry(sha1, base, baselen, filename, mode,
+   return write_archive_entry(sha1, base->buf, base->len, filename, mode,
   stage, context);
 }
 
@@ -260,7 +268,7 @@ int write_archive_entries(struct archiver_args *args,
err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
  args->pathspec.has_wildcard ?
  queue_or_write_archive_entry :
- write_archive_entry,
+ write_archive_entry_buf,
  &context);
if (err == READ_TREE_RECURSIVE)
err = 0;
@@ -286,14 +294,14 @@ static const struct archiver *lookup_archiver(const char 
*name)
return NULL;
 }
 
-static int reject_entry(const unsigned char *sha1, const char *base,
-   int baselen, const char *filename, unsigned mode,
+static int reject_entry(const unsigned char *sha1, struct strbuf *base,
+   const char *filename, unsigned mode,
int stage, void *context)
 {
int ret = -1;
if (S_ISDIR(mode)) {
struct strbuf sb = STRBUF_INIT;
-   strbuf_addstr(&sb, base);
+   strbuf_addbuf(&sb, base);
strbuf_addstr(&sb, filename);
if (!match_pathspec(context, sb.buf, sb.len, 0, NULL, 1))
ret = READ_TREE_RECURSIVE;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 5410dac..8adf48d 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -62,7 +62,7 @@ static int post_checkout_hook(struct commit *old, struct 
commit *new,
 
 }
 
-static int update_some(const unsigned char *sha1, const char *base, int 
baselen,
+static int update_some(const unsigned char *sha1, struct strbuf *base,
const char *pathname, unsigned mode, int stage, void *contex

[PATCH 0/3] ls-tree fixes

2014-11-30 Thread Nguyễn Thái Ngọc Duy
The first two fix ls-tree's unable to handle relative paths outside
$PWD. The last one rejects negative pathspec. This is a resend from

http://thread.gmane.org/gmane.comp.version-control.git/259233/focus=259264

Nguyễn Thái Ngọc Duy (3):
  tree.c: update read_tree_recursive callback to pass strbuf as base
  ls-tree: remove path filtering logic in show_tree
  ls-tree: disable negative pathspec because it's not supported

 archive.c| 34 +-
 builtin/checkout.c   |  8 
 builtin/log.c|  2 +-
 builtin/ls-tree.c| 20 +++-
 merge-recursive.c| 15 ++-
 quote.c  | 21 -
 quote.h  |  2 --
 t/t3102-ls-tree-wildcards.sh |  8 
 tree.c   | 16 +++-
 tree.h   |  3 ++-
 10 files changed, 64 insertions(+), 65 deletions(-)

-- 
2.2.0.60.gb7b3c64

--
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 15/19] list-files: do not show duplicate cached entries

2014-11-30 Thread Nguyễn Thái Ngọc Duy
With the current show_files() "list-files -tcm" will show

  foo.c
M foo.c

The first item is redundant. If "foo.c" is modified, we know it's in
the cache. Introduce show_files_compact to do that because ls-files is
plumbing and scripts may already depend on current display behavior.

Another difference in show_files_compact() is it does not show
skip-worktree (aka outside sparse checkout) entries anymore, which
makes sense in porcelain context.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 builtin/ls-files.c | 52 +++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 42c530d..fc70265 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -333,6 +333,53 @@ static void show_files(struct dir_struct *dir)
}
 }
 
+static void show_files_compact(struct dir_struct *dir)
+{
+   int i;
+
+   /* For cached/deleted files we don't need to even do the readdir */
+   if (show_others || show_killed) {
+   if (!show_others)
+   dir->flags |= DIR_COLLECT_KILLED_ONLY;
+   fill_directory(dir, &pathspec);
+   if (show_others)
+   show_other_files(dir);
+   if (show_killed)
+   show_killed_files(dir);
+   }
+   if (!(show_cached || show_stage || show_deleted || show_modified))
+   return;
+   for (i = 0; i < active_nr; i++) {
+   const struct cache_entry *ce = active_cache[i];
+   struct stat st;
+   int err, shown = 0;
+   if ((dir->flags & DIR_SHOW_IGNORED) &&
+   !ce_excluded(dir, ce))
+   continue;
+   if (show_unmerged && !ce_stage(ce))
+   continue;
+   if (ce->ce_flags & CE_UPDATE)
+   continue;
+   if (ce_skip_worktree(ce))
+   continue;
+   err = lstat(ce->name, &st);
+   if (show_deleted && err) {
+   show_ce_entry(tag_removed, ce);
+   shown = 1;
+   }
+   if (show_modified && (err || ce_modified(ce, &st, 0))) {
+   show_ce_entry(tag_modified, ce);
+   shown = 1;
+   }
+   if (ce_stage(ce)) {
+   show_ce_entry(tag_unmerged, ce);
+   shown = 1;
+   }
+   if (!shown && show_cached)
+   show_ce_entry(tag_cached, ce);
+   }
+}
+
 /*
  * Prune the index to only contain stuff starting with "prefix"
  */
@@ -743,7 +790,10 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);
setup_pager();
}
-   show_files(&dir);
+   if (porcelain)
+   show_files_compact(&dir);
+   else
+   show_files(&dir);
if (show_resolve_undo)
show_ru_info();
 
-- 
2.2.0.60.gb7b3c64

--
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 13/19] list-files: add -t back

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Tag "H" (cached) is not shown though because it's usually the majority
and becomes noise. Not showing it makes the other tags stand out. -t
is on by default if more than one file category is selected.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/git-list-files.txt |  6 ++
 builtin/ls-files.c   | 27 +--
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index 725a236..0ef616b 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -45,6 +45,12 @@ OPTIONS
 --unmerged::
Show unmerged files
 
+-t::
+--[no-]tag::
+   Show a tag to indicate file type. Automatically turned on with
+   multiple file selections. See linkgit::git-ls-files[1] option
+   `-t` for more information.
+
 -R::
 --recursive::
Equivalent of `--max-depth=-1` (infinite recursion).
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index be9a39c..c7aaade 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -596,6 +596,8 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
N_("show untracked files")),
OPT_SET_INT('R', "recursive", &max_depth,
N_("shortcut for --max-depth=-1"), -1),
+   OPT_BOOL('t', "tag", &show_tag,
+   N_("identify the file status with tags")),
OPT_BIT('i', "ignored", &dir.flags,
N_("show ignored files"),
DIR_SHOW_IGNORED),
@@ -636,6 +638,7 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
setup_standard_excludes(&dir);
use_color = -1;
max_depth = 0;
+   show_tag = -1;
git_config(git_ls_config, NULL);
} else
git_config(git_default_config, NULL);
@@ -648,16 +651,6 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
for (i = 0; i < exclude_list.nr; i++) {
add_exclude(exclude_list.items[i].string, "", 0, el, 
--exclude_args);
}
-   if (show_tag || show_valid_bit) {
-   tag_cached = "H ";
-   tag_unmerged = "M ";
-   tag_removed = "R ";
-   tag_modified = "C ";
-   tag_other = "? ";
-   tag_killed = "K ";
-   tag_skip_worktree = "S ";
-   tag_resolve_undo = "U ";
-   }
if (show_modified || show_others || show_deleted || (dir.flags & 
DIR_SHOW_IGNORED) || show_killed)
require_work_tree = 1;
if (show_unmerged && !porcelain)
@@ -711,6 +704,20 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
  show_killed || show_modified || show_resolve_undo))
show_cached = 1;
 
+   if (show_tag == -1)
+   show_tag = (show_cached + show_deleted + show_others +
+   show_unmerged + show_killed + show_modified) > 1;
+   if (show_tag || show_valid_bit) {
+   tag_cached = porcelain ? "  " : "H ";
+   tag_unmerged = "M ";
+   tag_removed = "R ";
+   tag_modified = "C ";
+   tag_other = "? ";
+   tag_killed = "K ";
+   tag_skip_worktree = "S ";
+   tag_resolve_undo = "U ";
+   }
+
if (max_prefix)
prune_cache(max_prefix);
if (with_tree) {
-- 
2.2.0.60.gb7b3c64

--
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 16/19] list-files: show directories as well as files

2014-11-30 Thread Nguyễn Thái Ngọc Duy
The index does not store directories explicitly (except submodules) so
we have to figure them out from file list. The function
show_directories() deliberately generates duplicate directories and
expects the previous patch to remove duplicates.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 builtin/ls-files.c | 44 +++-
 1 file changed, 43 insertions(+), 1 deletion(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index fc70265..41efdaa 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -27,6 +27,8 @@ static int show_resolve_undo;
 static int show_modified;
 static int show_killed;
 static int show_valid_bit;
+static int show_tag;
+static int show_dirs;
 static int line_terminator = '\n';
 static int debug_mode;
 static int use_color;
@@ -333,6 +335,43 @@ static void show_files(struct dir_struct *dir)
}
 }
 
+static void show_directories(const struct cache_entry *ce)
+{
+   static const char *last_directory;
+   struct strbuf sb = STRBUF_INIT;
+   const char *p = ce->name + prefix_len;
+   const char *sep;
+
+   if (last_directory) {
+   int len = strlen(last_directory);
+   if (!strncmp(ce->name, last_directory, len) &&
+   ce->name[len] == '/')
+   p += len + 1;
+   }
+
+   while (*p && (sep = strchr(p, '/'))) {
+   struct strbuf sb2 = STRBUF_INIT;
+   strbuf_reset(&sb);
+   strbuf_add(&sb, ce->name, sep - ce->name);
+   p = sep + 1;
+   if (!match_pathspec(&pathspec, sb.buf, sb.len,
+   prefix_len, NULL, 1))
+   continue;
+   write_name(&sb2, sb.buf);
+   if (want_color(use_color)) {
+   struct strbuf sb3 = STRBUF_INIT;
+   color_filename(&sb3, ce->name, sb2.buf, S_IFDIR, 1);
+   strbuf_release(&sb2);
+   sb2 = sb3;
+   }
+   if (show_tag)
+   strbuf_insert(&sb2, 0, tag_cached, strlen(tag_cached));
+   last_directory = strbuf_detach(&sb, NULL);
+   strbuf_fputs(&sb2, last_directory, NULL);
+   strbuf_release(&sb2);
+   }
+}
+
 static void show_files_compact(struct dir_struct *dir)
 {
int i;
@@ -353,6 +392,8 @@ static void show_files_compact(struct dir_struct *dir)
const struct cache_entry *ce = active_cache[i];
struct stat st;
int err, shown = 0;
+   if (show_dirs)
+   show_directories(ce);
if ((dir->flags & DIR_SHOW_IGNORED) &&
!ce_excluded(dir, ce))
continue;
@@ -575,7 +616,7 @@ static int git_ls_config(const char *var, const char 
*value, void *cb)
 
 int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 {
-   int require_work_tree = 0, show_tag = 0, i;
+   int require_work_tree = 0, i;
int max_depth = -1;
const char *max_prefix;
struct dir_struct dir;
@@ -696,6 +737,7 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
use_color = -1;
max_depth = 0;
show_tag = -1;
+   show_dirs = 1;
git_config(git_ls_config, NULL);
} else
git_config(git_default_config, NULL);
-- 
2.2.0.60.gb7b3c64

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


git@vger.kernel.org

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/git-list-files.txt | 4 ++--
 builtin/ls-files.c   | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index 22084eb..c57129b 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -53,8 +53,8 @@ OPTIONS
 
 -F::
 --classify::
-   Append indicator (one of `*/=>@|`, which is executable,
-   directory, socket, Solaris door, symlink, or fifo
+   Append indicator (one of `*/=>@|&`, which is executable,
+   directory, socket, Solaris door, symlink, fifo, or submodule
respectively) to entries.
 
 -R::
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 28737cb..5b5a068 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -92,6 +92,8 @@ static void append_indicator(struct strbuf *sb, mode_t mode)
c = '|';
else if (S_ISSOCK(mode))
c = '=';
+   else if (S_ISGITLINK(mode))
+   c = '&';
 #ifdef S_ISDOOR
else if (S_ISDOOR(mode))
c = '>';
-- 
2.2.0.60.gb7b3c64

--
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 19/19] list-files: -M aka diff-cached

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 builtin/ls-files.c | 57 +++---
 1 file changed, 54 insertions(+), 3 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 5b5a068..08ae206 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -16,6 +16,9 @@
 #include "pathspec.h"
 #include "color.h"
 #include "column.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "revision.h"
 
 static int abbrev;
 static int show_deleted;
@@ -25,6 +28,7 @@ static int show_stage;
 static int show_unmerged;
 static int show_resolve_undo;
 static int show_modified;
+static int show_diff_cached;
 static int show_killed;
 static int show_valid_bit;
 static int show_tag;
@@ -53,6 +57,7 @@ static const char *tag_removed = "";
 static const char *tag_other = "";
 static const char *tag_killed = "";
 static const char *tag_modified = "";
+static const char *tag_diff_cached = "";
 static const char *tag_skip_worktree = "";
 static const char *tag_resolve_undo = "";
 
@@ -343,7 +348,7 @@ static void show_files(struct dir_struct *dir)
(ce_skip_worktree(ce) ? tag_skip_worktree : 
tag_cached), ce);
}
}
-   if (show_deleted || show_modified) {
+   if (show_deleted || show_modified || show_diff_cached) {
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
struct stat st;
@@ -358,7 +363,15 @@ static void show_files(struct dir_struct *dir)
err = lstat(ce->name, &st);
if (show_deleted && err)
show_ce_entry(tag_removed, ce);
-   if (show_modified && ce_modified(ce, &st, 0))
+   if (show_diff_cached && (ce->ce_flags & CE_MATCHED)) {
+   show_ce_entry(tag_diff_cached, ce);
+   /*
+* if we don't clear, it'll confuse 
write_ce_name()
+* when show_ce_entry(tag_modified, ce) is 
called
+*/
+   active_cache[i]->ce_flags &= ~CE_MATCHED;
+   }
+   if (show_modified && (err || ce_modified(ce, &st, 0)))
show_ce_entry(tag_modified, ce);
}
}
@@ -452,6 +465,38 @@ static void show_files_compact(struct dir_struct *dir)
}
 }
 
+static void mark_diff_cached(struct diff_queue_struct *q,
+struct diff_options *options,
+void *data)
+{
+   int i;
+
+   for (i = 0; i < q->nr; i++) {
+   struct diff_filepair *p = q->queue[i];
+   int pos = cache_name_pos(p->two->path, strlen(p->two->path));
+   if (pos < 0)
+   continue;
+   active_cache[pos]->ce_flags |= CE_MATCHED;
+   }
+}
+
+static void diff_cached(struct pathspec *pathspec)
+{
+   struct rev_info rev;
+   const char *argv[] = { "ls-files", "HEAD", NULL };
+
+   init_revisions(&rev, NULL);
+   setup_revisions(2, argv, &rev, NULL);
+
+   rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+   rev.diffopt.format_callback = mark_diff_cached;
+   rev.diffopt.detect_rename = 1;
+   rev.diffopt.rename_limit = 200;
+   rev.diffopt.break_opt = 0;
+   copy_pathspec(&rev.prune_data, pathspec);
+   run_diff_index(&rev, 1);
+}
+
 /*
  * Prune the index to only contain stuff starting with "prefix"
  */
@@ -721,6 +766,8 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
N_("show cached files that are deleted on working 
directory")),
OPT_BOOL('m', "modified", &show_modified,
N_("show cached files that have modification on working 
directory")),
+   OPT_BOOL('M', "modified", &show_diff_cached,
+   N_("show modified files in the cache")),
OPT_BOOL('o', "others", &show_others,
N_("show untracked files")),
OPT_SET_INT('R', "recursive", &max_depth,
@@ -833,11 +880,12 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
 
/* With no flags, we default to showing the cached files */
if (!(show_stage || show_deleted || show_others || show_unmerged ||
- show_killed || show_modified || show_resolve_undo))
+ show_killed || show_modified || show_resolve_undo || 
show_diff_cached))
show_cached = 1;
 
if (show_tag == -1)
show_tag = (show_cached + show_deleted + show_others +
+   show_diff_cached +
show_unmerged + show_killed + show_modified) > 1;
if (show_tag || show_valid_bit) {
tag_cached = por

[PATCH 14/19] list-files: sort output and remove duplicates

2014-11-30 Thread Nguyễn Thái Ngọc Duy
When you mix different file types, with ls-files you may get separate
listing. For example, "ls-files -cm" will show file "abc" twice: one
as part of cached list, one of modified list. With "ls" (and this
patch) they will be in a single sorted list (easier for the eye).

Duplicate entries are also removed. Note that display content is
compared, so if you have "-t" on, or you color file types differently,
you will get duplicate textual entries. This is good imo.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 builtin/ls-files.c | 36 
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index c7aaade..42c530d 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -53,6 +53,13 @@ static const char *tag_modified = "";
 static const char *tag_skip_worktree = "";
 static const char *tag_resolve_undo = "";
 
+static int compare_output(const void *a_, const void *b_)
+{
+   const struct string_list_item *a = a_;
+   const struct string_list_item *b = b_;
+   return strcmp(a->util, b->util);
+}
+
 static void write_name(struct strbuf *sb, const char *name)
 {
/*
@@ -68,10 +75,12 @@ static void write_name(struct strbuf *sb, const char *name)
quote_path_relative(name, real_prefix, sb);
 }
 
-static void strbuf_fputs(struct strbuf *sb, FILE *fp)
+static void strbuf_fputs(struct strbuf *sb, const char *full_name, FILE *fp)
 {
-   if (column_active(colopts)) {
-   string_list_append(&output, strbuf_detach(sb, NULL));
+   if (column_active(colopts) || porcelain) {
+   struct string_list_item *it;
+   it = string_list_append(&output, strbuf_detach(sb, NULL));
+   it->util = (void*)full_name;
return;
}
fwrite(sb->buf, sb->len, 1, fp);
@@ -106,7 +115,7 @@ static void show_dir_entry(const char *tag, struct 
dir_entry *ent)
strbuf_reset(&sb);
strbuf_addstr(&sb, tag);
write_dir_entry(&sb, ent);
-   strbuf_fputs(&sb, stdout);
+   strbuf_fputs(&sb, ent->name, stdout);
 }
 
 static void show_other_files(struct dir_struct *dir)
@@ -223,7 +232,7 @@ static void show_ce_entry(const char *tag, const struct 
cache_entry *ce)
ce_stage(ce));
}
write_ce_name(&sb, ce);
-   strbuf_fputs(&sb, stdout);
+   strbuf_fputs(&sb, ce->name, stdout);
if (debug_mode) {
const struct stat_data *sd = &ce->ce_stat_data;
 
@@ -524,6 +533,7 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
const char *max_prefix;
struct dir_struct dir;
struct exclude_list *el;
+   struct column_options copts;
struct string_list exclude_list = STRING_LIST_INIT_NODUP;
struct option builtin_ls_files_options[] = {
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
@@ -671,7 +681,7 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
if (debug_mode)
die(_("--column and --debug are incompatible"));
}
-   if (column_active(colopts))
+   if (column_active(colopts) || porcelain)
line_terminator = 0;
 
if (require_work_tree && !is_inside_work_tree())
@@ -737,13 +747,15 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
if (show_resolve_undo)
show_ru_info();
 
-   if (column_active(colopts)) {
-   struct column_options copts;
-   memset(&copts, 0, sizeof(copts));
-   copts.padding = 2;
-   print_columns(&output, colopts, &copts);
-   string_list_clear(&output, 0);
+   memset(&copts, 0, sizeof(copts));
+   copts.padding = 2;
+   if (porcelain) {
+   qsort(output.items, output.nr, sizeof(*output.items),
+ compare_output);
+   string_list_remove_duplicates(&output, 0);
}
+   print_columns(&output, colopts, &copts);
+   string_list_clear(&output, 0);
 
if (ps_matched) {
int bad;
-- 
2.2.0.60.gb7b3c64

--
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 17/19] list-files: add -F/--classify

2014-11-30 Thread Nguyễn Thái Ngọc Duy
This appends an indicator after the file name if it's executable, a
directory and so on, like in GNU ls. In fact append_indicator() is a
rewrite from get_type_indicator() in coreutils.git commit
7326d1f1a67edf21947ae98194f98c38b6e9e527.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/git-list-files.txt |  6 ++
 builtin/ls-files.c   | 31 +++
 2 files changed, 37 insertions(+)

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index 0ef616b..22084eb 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -51,6 +51,12 @@ OPTIONS
multiple file selections. See linkgit::git-ls-files[1] option
`-t` for more information.
 
+-F::
+--classify::
+   Append indicator (one of `*/=>@|`, which is executable,
+   directory, socket, Solaris door, symlink, or fifo
+   respectively) to entries.
+
 -R::
 --recursive::
Equivalent of `--max-depth=-1` (infinite recursion).
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 41efdaa..28737cb 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -29,6 +29,7 @@ static int show_killed;
 static int show_valid_bit;
 static int show_tag;
 static int show_dirs;
+static int show_indicator;
 static int line_terminator = '\n';
 static int debug_mode;
 static int use_color;
@@ -77,6 +78,28 @@ static void write_name(struct strbuf *sb, const char *name)
quote_path_relative(name, real_prefix, sb);
 }
 
+static void append_indicator(struct strbuf *sb, mode_t mode)
+{
+   char c = 0;
+   if (S_ISREG(mode)) {
+   if (mode & (S_IXUSR | S_IXGRP | S_IXOTH))
+   c = '*';
+   } else if (S_ISDIR(mode))
+   c = '/';
+   else if (S_ISLNK(mode))
+   c = '@';
+   else if (S_ISFIFO(mode))
+   c = '|';
+   else if (S_ISSOCK(mode))
+   c = '=';
+#ifdef S_ISDOOR
+   else if (S_ISDOOR(mode))
+   c = '>';
+#endif
+   if (c)
+   strbuf_addch(sb, c);
+}
+
 static void strbuf_fputs(struct strbuf *sb, const char *full_name, FILE *fp)
 {
if (column_active(colopts) || porcelain) {
@@ -99,6 +122,8 @@ static void write_dir_entry(struct strbuf *sb, const struct 
dir_entry *ent)
color_filename(sb, ent->name, quoted.buf, st.st_mode, 1);
else
strbuf_addbuf(sb, "ed);
+   if (show_indicator && st.st_mode)
+   append_indicator(sb, st.st_mode);
strbuf_addch(sb, line_terminator);
strbuf_release("ed);
 }
@@ -189,6 +214,8 @@ static void write_ce_name(struct strbuf *sb, const struct 
cache_entry *ce)
color_filename(sb, ce->name, quoted.buf, ce->ce_mode, 1);
else
strbuf_addbuf(sb, "ed);
+   if (show_indicator)
+   append_indicator(sb, ce->ce_mode);
strbuf_addch(sb, line_terminator);
strbuf_release("ed);
 }
@@ -366,6 +393,8 @@ static void show_directories(const struct cache_entry *ce)
}
if (show_tag)
strbuf_insert(&sb2, 0, tag_cached, strlen(tag_cached));
+   if (show_indicator)
+   append_indicator(&sb2, S_IFDIR);
last_directory = strbuf_detach(&sb, NULL);
strbuf_fputs(&sb2, last_directory, NULL);
strbuf_release(&sb2);
@@ -701,6 +730,8 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
DIR_SHOW_IGNORED),
OPT_BOOL('u', "unmerged", &show_unmerged,
N_("show unmerged files")),
+   OPT_BOOL('F', "classify", &show_indicator,
+N_("append indicator (one of */=>@|) to entries")),
OPT__COLOR(&use_color, N_("show color")),
OPT_COLUMN(0, "column", &colopts, N_("show files in columns")),
OPT_SET_INT('1', NULL, &colopts,
-- 
2.2.0.60.gb7b3c64

--
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 09/19] Add git-list-files, a user friendly version of ls-files and more

2014-11-30 Thread Nguyễn Thái Ngọc Duy
This is more user friendly version of ls-files:

* it's automatically colored and columnized
* it refreshes the index like all porcelain commands
* it defaults to non-recursive behavior like ls
* :(glob) is on by default so '*.c' means a.c but not a/b.c, use
  '**/*.c' for that.
* auto pager

The name 'ls' is not taken. It is left for the user to make an alias
with better default options.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 .gitignore |  1 +
 Documentation/config.txt   | 10 +
 Documentation/git-list-files.txt (new) | 80 ++
 Makefile   |  1 +
 builtin/ls-files.c | 69 +++--
 command-list.txt   |  1 +
 git.c  |  1 +
 7 files changed, 159 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/git-list-files.txt

diff --git a/.gitignore b/.gitignore
index a052419..9727ecc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,6 +76,7 @@
 /git-init-db
 /git-interpret-trailers
 /git-instaweb
+/git-list-files
 /git-log
 /git-ls-files
 /git-ls-remote
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 2290c47..74da715 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -940,6 +940,12 @@ color.status.::
to red). The values of these variables may be specified as in
color.branch..
 
+color.list-files::
+   A boolean to enable/disable color in the output of
+   linkgit:git-list-files[1]. May be set to `always`, `false` (or
+   `never`) or `auto` (or `true`), in which case colors are used
+   only when the output is to a terminal. Defaults to false.
+
 color.ls.::
Use customized color for file name colorization. If not set
and the environment variable LS_COLORS is set, color settings
@@ -1012,6 +1018,10 @@ column.clean::
Specify the layout when list items in `git clean -i`, which always
shows files and directories in columns. See `column.ui` for details.
 
+column.list-files::
+   Specify whether to output tag listing in `git list-files` in columns.
+   See `column.ui` for details.
+
 column.status::
Specify whether to output untracked files in `git status` in columns.
See `column.ui` for details.
diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
new file mode 100644
index 000..3039e1e
--- /dev/null
+++ b/Documentation/git-list-files.txt
@@ -0,0 +1,80 @@
+git-list-files(1)
+===
+
+NAME
+
+git-list-files - List files
+
+SYNOPSIS
+
+[verse]
+'git list-files [options] [...]
+
+DESCRIPTION
+---
+List files (by default in current working directory) that are in the
+index. Depending on the chosen options, maybe only modified files in
+working tree are shown, or untracked files...
+
+OPTIONS
+---
+-c::
+--cached::
+   Show cached files (default)
+
+-d::
+--deleted::
+   Show cached files that are deleted on working directory
+
+-m::
+--modified::
+   Show cached files that have modification on working directory
+
+-o::
+--others::
+   Show untracked files (and only unignored ones unless -i is
+   specified)
+
+-i::
+--ignored::
+   Show only ignored files. When showing files in the index,
+   print only those matched by an exclude pattern. When showing
+   "other" files, show only those matched by an exclude pattern.
+
+-u::
+--unmerged::
+   Show unmerged files
+
+--color[=]::
+--no-color::
+   Color file names. The value must be `always`, `never`, or
+   `auto`. `--no-color` is equivalent to
+   `--color=never`. `--color` is equivalent to
+   `--color=auto`. See configuration variable `color.list-files`
+   for the default settings.
+
+--column[=]::
+--no-column::
+   Display files in columns. See configuration variable column.ui
+   for option syntax. `--column` and `--no-column` without options
+   are equivalent to 'always' and 'never' respectively.
+
+--max-depth=::
+   For each  given on command line, descend at most 
+   levels of directories. A negative value means no limit.
+   This option is ignored if  contains active wildcards.
+   In other words if "a*" matches a directory named "a*",
+   "*" is matched literally so --max-depth is still effective.
+   The default is `--max-depth=0`.
+
+::
+   Files to show. :(glob) magic is enabled and recursion disabled
+   by default.
+
+SEE ALSO
+
+linkgit:git-ls-files[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 459121d..23a0751 100644
--- a/Makefile
+++ b/Makefile
@@ -587,6 +587,7 @@ BUILT_INS += git-cherry-pick$X
 BUILT_INS += git-format-patch$X
 BUILT_INS += git-fsck-objects$X
 BUILT_INS += git-init$X
+BUILT_INS += git-list-files$X
 BUILT_INS += git-merge-subtree$X
 BUILT_INS += git-show$X
 BUILT_INS += git-stage$X
diff --git

[PATCH 11/19] list-files: add -R/--recursive short for --max-depth=-1

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/git-list-files.txt | 4 
 builtin/ls-files.c   | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index 3039e1e..5dccbbc 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -45,6 +45,10 @@ OPTIONS
 --unmerged::
Show unmerged files
 
+-R::
+--recursive::
+   Equivalent of `--max-depth=-1` (infinite recursion).
+
 --color[=]::
 --no-color::
Color file names. The value must be `always`, `never`, or
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index f2b62b5..d0d39bd 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -594,6 +594,8 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
N_("show cached files that have modification on working 
directory")),
OPT_BOOL('o', "others", &show_others,
N_("show untracked files")),
+   OPT_SET_INT('R', "recursive", &max_depth,
+   N_("shortcut for --max-depth=-1"), -1),
OPT_BIT('i', "ignored", &dir.flags,
N_("show ignored files"),
DIR_SHOW_IGNORED),
-- 
2.2.0.60.gb7b3c64

--
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 12/19] list-files: add -1 short for --no-column

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/git-list-files.txt | 3 +++
 builtin/ls-files.c   | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index 5dccbbc..725a236 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -49,6 +49,9 @@ OPTIONS
 --recursive::
Equivalent of `--max-depth=-1` (infinite recursion).
 
+-1::
+   Equivalent of --no-column.
+
 --color[=]::
 --no-color::
Color file names. The value must be `always`, `never`, or
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index d0d39bd..be9a39c 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -603,6 +603,8 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
N_("show unmerged files")),
OPT__COLOR(&use_color, N_("show color")),
OPT_COLUMN(0, "column", &colopts, N_("show files in columns")),
+   OPT_SET_INT('1', NULL, &colopts,
+   N_("shortcut for --no-column"), COL_PARSEOPT),
{ OPTION_INTEGER, 0, "max-depth", &max_depth, N_("depth"),
N_("descend at most  levels"), PARSE_OPT_NONEG,
NULL, 1 },
-- 
2.2.0.60.gb7b3c64

--
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 10/19] list-files: -u does not imply showing stages

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Showing full index entry information is something for ls-files
only. The users of "git list-files" may just want to know what entries
are not unmerged.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 builtin/ls-files.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index f3873a8..f2b62b5 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -656,7 +656,7 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
}
if (show_modified || show_others || show_deleted || (dir.flags & 
DIR_SHOW_IGNORED) || show_killed)
require_work_tree = 1;
-   if (show_unmerged)
+   if (show_unmerged && !porcelain)
/*
 * There's no point in showing unmerged unless
 * you also show the stage information.
-- 
2.2.0.60.gb7b3c64

--
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 07/19] ls-files: add --column

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/git-ls-files.txt |  6 ++
 builtin/ls-files.c | 28 
 2 files changed, 34 insertions(+)

diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 148f226..99328b9 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -154,6 +154,12 @@ a space) at the start of each line:
`--color=never`. `--color` is equivalent to
`--color=auto`.
 
+--column[=]::
+--no-column::
+   Display files in columns. See configuration variable column.ui
+   for option syntax. `--column` and `--no-column` without options
+   are equivalent to 'always' and 'never' respectively.
+
 \--::
Do not interpret any more arguments as options.
 
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 4ddd49f..79e1944 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -15,6 +15,7 @@
 #include "string-list.h"
 #include "pathspec.h"
 #include "color.h"
+#include "column.h"
 
 static int abbrev;
 static int show_deleted;
@@ -29,6 +30,7 @@ static int show_valid_bit;
 static int line_terminator = '\n';
 static int debug_mode;
 static int use_color;
+static unsigned int colopts;
 
 static const char *prefix;
 static int max_prefix_len;
@@ -39,6 +41,7 @@ static char *ps_matched;
 static const char *with_tree;
 static int exc_given;
 static int exclude_args;
+static struct string_list output = STRING_LIST_INIT_NODUP;
 
 static const char *tag_cached = "";
 static const char *tag_unmerged = "";
@@ -66,6 +69,10 @@ static void write_name(struct strbuf *sb, const char *name)
 
 static void strbuf_fputs(struct strbuf *sb, FILE *fp)
 {
+   if (column_active(colopts)) {
+   string_list_append(&output, strbuf_detach(sb, NULL));
+   return;
+   }
fwrite(sb->buf, sb->len, 1, fp);
 }
 
@@ -552,6 +559,7 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"),
N_("pretend that paths removed since  are 
still present")),
OPT__COLOR(&use_color, N_("show color")),
+   OPT_COLUMN(0, "column", &colopts, N_("show files in columns")),
OPT__ABBREV(&abbrev),
OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
OPT_END()
@@ -596,6 +604,18 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
if (dir.exclude_per_dir)
exc_given = 1;
 
+   finalize_colopts(&colopts, -1);
+   if (explicitly_enable_column(colopts)) {
+   if (!line_terminator)
+   die(_("--column and -z are incompatible"));
+   if (show_resolve_undo)
+   die(_("--column and --resolve-undo are incompatible"));
+   if (debug_mode)
+   die(_("--column and --debug are incompatible"));
+   }
+   if (column_active(colopts))
+   line_terminator = 0;
+
if (require_work_tree && !is_inside_work_tree())
setup_work_tree();
 
@@ -638,6 +658,14 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
if (show_resolve_undo)
show_ru_info();
 
+   if (column_active(colopts)) {
+   struct column_options copts;
+   memset(&copts, 0, sizeof(copts));
+   copts.padding = 2;
+   print_columns(&output, colopts, &copts);
+   string_list_clear(&output, 0);
+   }
+
if (ps_matched) {
int bad;
bad = report_path_error(ps_matched, &pathspec, prefix);
-- 
2.2.0.60.gb7b3c64

--
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 08/19] ls-files: support --max-depth

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/git-ls-files.txt | 7 +++
 builtin/ls-files.c | 7 +++
 2 files changed, 14 insertions(+)

diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 99328b9..3d921eb 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -160,6 +160,13 @@ a space) at the start of each line:
for option syntax. `--column` and `--no-column` without options
are equivalent to 'always' and 'never' respectively.
 
+--max-depth=::
+   For each  given on command line, descend at most 
+   levels of directories. A negative value means no limit (default).
+   This option is ignored if  contains active wildcards.
+   In other words if "a*" matches a directory named "a*",
+   "*" is matched literally so --max-depth is still effective.
+
 \--::
Do not interpret any more arguments as options.
 
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 79e1944..40fe0f2 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -503,6 +503,7 @@ static int option_parse_exclude_standard(const struct 
option *opt,
 int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 {
int require_work_tree = 0, show_tag = 0, i;
+   int max_depth = -1;
const char *max_prefix;
struct dir_struct dir;
struct exclude_list *el;
@@ -560,6 +561,9 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
N_("pretend that paths removed since  are 
still present")),
OPT__COLOR(&use_color, N_("show color")),
OPT_COLUMN(0, "column", &colopts, N_("show files in columns")),
+   { OPTION_INTEGER, 0, "max-depth", &max_depth, N_("depth"),
+   N_("descend at most  levels"), PARSE_OPT_NONEG,
+   NULL, 1 },
OPT__ABBREV(&abbrev),
OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
OPT_END()
@@ -624,8 +628,11 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
 
parse_pathspec(&pathspec, 0,
   PATHSPEC_PREFER_CWD |
+  (max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0) |
   PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
   prefix, argv);
+   pathspec.max_depth = max_depth;
+   pathspec.recursive = 1;
 
/* Find common prefix for all pathspec's */
max_prefix = common_prefix(&pathspec);
-- 
2.2.0.60.gb7b3c64

--
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 06/19] ls-files: add --color to highlight file names

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/git-ls-files.txt |  7 +++
 builtin/ls-files.c | 38 +++---
 2 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index e26f01f..148f226 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -147,6 +147,13 @@ a space) at the start of each line:
possible for manual inspection; the exact format may change at
any time.
 
+--color[=]::
+--no-color::
+   Color file names. The value must be `always`, `never`, or
+   `auto`. `--no-color` is equivalent to
+   `--color=never`. `--color` is equivalent to
+   `--color=auto`.
+
 \--::
Do not interpret any more arguments as options.
 
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index f20c0fd..4ddd49f 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -14,6 +14,7 @@
 #include "resolve-undo.h"
 #include "string-list.h"
 #include "pathspec.h"
+#include "color.h"
 
 static int abbrev;
 static int show_deleted;
@@ -27,6 +28,7 @@ static int show_killed;
 static int show_valid_bit;
 static int line_terminator = '\n';
 static int debug_mode;
+static int use_color;
 
 static const char *prefix;
 static int max_prefix_len;
@@ -60,7 +62,6 @@ static void write_name(struct strbuf *sb, const char *name)
strbuf_release(&sb2);
} else
quote_path_relative(name, real_prefix, sb);
-   strbuf_addch(sb, line_terminator);
 }
 
 static void strbuf_fputs(struct strbuf *sb, FILE *fp)
@@ -68,6 +69,21 @@ static void strbuf_fputs(struct strbuf *sb, FILE *fp)
fwrite(sb->buf, sb->len, 1, fp);
 }
 
+static void write_dir_entry(struct strbuf *sb, const struct dir_entry *ent)
+{
+   struct strbuf quoted = STRBUF_INIT;
+   struct stat st;
+   if (stat(ent->name, &st))
+   st.st_mode = 0;
+   write_name("ed, ent->name);
+   if (want_color(use_color))
+   color_filename(sb, ent->name, quoted.buf, st.st_mode, 1);
+   else
+   strbuf_addbuf(sb, "ed);
+   strbuf_addch(sb, line_terminator);
+   strbuf_release("ed);
+}
+
 static void show_dir_entry(const char *tag, struct dir_entry *ent)
 {
static struct strbuf sb = STRBUF_INIT;
@@ -81,7 +97,7 @@ static void show_dir_entry(const char *tag, struct dir_entry 
*ent)
 
strbuf_reset(&sb);
strbuf_addstr(&sb, tag);
-   write_name(&sb, ent->name);
+   write_dir_entry(&sb, ent);
strbuf_fputs(&sb, stdout);
 }
 
@@ -146,6 +162,18 @@ static void show_killed_files(struct dir_struct *dir)
}
 }
 
+static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)
+{
+   struct strbuf quoted = STRBUF_INIT;
+   write_name("ed, ce->name);
+   if (want_color(use_color))
+   color_filename(sb, ce->name, quoted.buf, ce->ce_mode, 1);
+   else
+   strbuf_addbuf(sb, "ed);
+   strbuf_addch(sb, line_terminator);
+   strbuf_release("ed);
+}
+
 static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 {
static struct strbuf sb = STRBUF_INIT;
@@ -186,7 +214,7 @@ static void show_ce_entry(const char *tag, const struct 
cache_entry *ce)
find_unique_abbrev(ce->sha1,abbrev),
ce_stage(ce));
}
-   write_name(&sb, ce->name);
+   write_ce_name(&sb, ce);
strbuf_fputs(&sb, stdout);
if (debug_mode) {
const struct stat_data *sd = &ce->ce_stat_data;
@@ -523,6 +551,7 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
N_("if any  is not in the index, treat this as an 
error")),
OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"),
N_("pretend that paths removed since  are 
still present")),
+   OPT__COLOR(&use_color, N_("show color")),
OPT__ABBREV(&abbrev),
OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
OPT_END()
@@ -570,6 +599,9 @@ int cmd_ls_files(int argc, const char **argv, const char 
*cmd_prefix)
if (require_work_tree && !is_inside_work_tree())
setup_work_tree();
 
+   if (want_color(use_color))
+   parse_ls_color();
+
parse_pathspec(&pathspec, 0,
   PATHSPEC_PREFER_CWD |
   PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
-- 
2.2.0.60.gb7b3c64

--
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 05/19] ls-files: buffer full item in strbuf before printing

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Buffering so that we can manipulate the strings (e.g. coloring)
further before finally printing them.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 builtin/ls-files.c | 48 +++-
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 99cee20..f20c0fd 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -47,18 +47,30 @@ static const char *tag_modified = "";
 static const char *tag_skip_worktree = "";
 static const char *tag_resolve_undo = "";
 
-static void write_name(const char *name)
+static void write_name(struct strbuf *sb, const char *name)
 {
/*
 * With "--full-name", prefix_len=0; this caller needs to pass
 * an empty string in that case (a NULL is good for "").
 */
-   write_name_quoted_relative(name, prefix_len ? prefix : NULL,
-  stdout, line_terminator);
+   const char *real_prefix = prefix_len ? prefix : NULL;
+   if (!line_terminator) {
+   struct strbuf sb2 = STRBUF_INIT;
+   strbuf_addstr(sb, relative_path(name, real_prefix, &sb2));
+   strbuf_release(&sb2);
+   } else
+   quote_path_relative(name, real_prefix, sb);
+   strbuf_addch(sb, line_terminator);
+}
+
+static void strbuf_fputs(struct strbuf *sb, FILE *fp)
+{
+   fwrite(sb->buf, sb->len, 1, fp);
 }
 
 static void show_dir_entry(const char *tag, struct dir_entry *ent)
 {
+   static struct strbuf sb = STRBUF_INIT;
int len = max_prefix_len;
 
if (len >= ent->len)
@@ -67,8 +79,10 @@ static void show_dir_entry(const char *tag, struct dir_entry 
*ent)
if (!dir_path_match(ent, &pathspec, len, ps_matched))
return;
 
-   fputs(tag, stdout);
-   write_name(ent->name);
+   strbuf_reset(&sb);
+   strbuf_addstr(&sb, tag);
+   write_name(&sb, ent->name);
+   strbuf_fputs(&sb, stdout);
 }
 
 static void show_other_files(struct dir_struct *dir)
@@ -134,6 +148,7 @@ static void show_killed_files(struct dir_struct *dir)
 
 static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 {
+   static struct strbuf sb = STRBUF_INIT;
int len = max_prefix_len;
 
if (len >= ce_namelen(ce))
@@ -161,16 +176,18 @@ static void show_ce_entry(const char *tag, const struct 
cache_entry *ce)
tag = alttag;
}
 
+   strbuf_reset(&sb);
if (!show_stage) {
-   fputs(tag, stdout);
+   strbuf_addstr(&sb, tag);
} else {
-   printf("%s%06o %s %d\t",
-  tag,
-  ce->ce_mode,
-  find_unique_abbrev(ce->sha1,abbrev),
-  ce_stage(ce));
+   strbuf_addf(&sb, "%s%06o %s %d\t",
+   tag,
+   ce->ce_mode,
+   find_unique_abbrev(ce->sha1,abbrev),
+   ce_stage(ce));
}
-   write_name(ce->name);
+   write_name(&sb, ce->name);
+   strbuf_fputs(&sb, stdout);
if (debug_mode) {
const struct stat_data *sd = &ce->ce_stat_data;
 
@@ -206,7 +223,12 @@ static void show_ru_info(void)
printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
   find_unique_abbrev(ui->sha1[i], abbrev),
   i + 1);
-   write_name(path);
+   /*
+* With "--full-name", prefix_len=0; this caller needs 
to pass
+* an empty string in that case (a NULL is good for "").
+*/
+   write_name_quoted_relative(path, prefix_len ? prefix : 
NULL,
+  stdout, line_terminator);
}
}
 }
-- 
2.2.0.60.gb7b3c64

--
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 01/19] ls_colors.c: add $LS_COLORS parsing code

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Reusing color settings from $LS_COLORS could give a native look and
feel on file coloring.

This code is basically from coreutils.git [1], rewritten to fit Git.

As this is from GNU ls, the environment variable CLICOLOR is not
tested. It is to be decided later whether we should ignore $LS_COLORS
if $CLICOLOR is not set on Mac or FreeBSD.

[1] commit 7326d1f1a67edf21947ae98194f98c38b6e9e527 file
src/ls.c. This is the last GPL-2 commit before coreutils turns to
GPL-3.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Makefile  |   1 +
 color.h   |   8 ++
 ls_colors.c (new) | 398 ++
 3 files changed, 407 insertions(+)
 create mode 100644 ls_colors.c

diff --git a/Makefile b/Makefile
index 827006b..459121d 100644
--- a/Makefile
+++ b/Makefile
@@ -703,6 +703,7 @@ LIB_OBJS += list-objects.o
 LIB_OBJS += ll-merge.o
 LIB_OBJS += lockfile.o
 LIB_OBJS += log-tree.o
+LIB_OBJS += ls_colors.o
 LIB_OBJS += mailmap.o
 LIB_OBJS += match-trees.o
 LIB_OBJS += merge.o
diff --git a/color.h b/color.h
index f5beab1..3eaa5bd 100644
--- a/color.h
+++ b/color.h
@@ -45,6 +45,12 @@ struct strbuf;
 #define GIT_COLOR_BG_MAGENTA   "\033[45m"
 #define GIT_COLOR_BG_CYAN  "\033[46m"
 
+#define GIT_COLOR_WHITE_ON_RED"\033[37;41m"
+#define GIT_COLOR_WHITE_ON_BLUE   "\033[37;44m"
+#define GIT_COLOR_BLACK_ON_YELLOW "\033[30;43m"
+#define GIT_COLOR_BLUE_ON_GREEN   "\033[34;42m"
+#define GIT_COLOR_BLACK_ON_GREEN  "\033[30;42m"
+
 /* A special value meaning "no color selected" */
 #define GIT_COLOR_NIL "NIL"
 
@@ -87,4 +93,6 @@ void color_print_strbuf(FILE *fp, const char *color, const 
struct strbuf *sb);
 
 int color_is_nil(const char *color);
 
+void parse_ls_color(void);
+
 #endif /* COLOR_H */
diff --git a/ls_colors.c b/ls_colors.c
new file mode 100644
index 000..eb944f4
--- /dev/null
+++ b/ls_colors.c
@@ -0,0 +1,398 @@
+#include "cache.h"
+#include "color.h"
+
+enum color_ls {
+   LS_LC,  /* left, unused */
+   LS_RC,  /* right, unused */
+   LS_EC,  /* end color, unused */
+   LS_RS,  /* reset */
+   LS_NO,  /* normal */
+   LS_FL,  /* file, default */
+   LS_DI,  /* directory */
+   LS_LN,  /* symlink */
+
+   LS_PI,  /* pipe */
+   LS_SO,  /* socket */
+   LS_BD,  /* block device */
+   LS_CD,  /* char device */
+   LS_MI,  /* missing file */
+   LS_OR,  /* orphaned symlink */
+   LS_EX,  /* executable */
+   LS_DO,  /* Solaris door */
+
+   LS_SU,  /* setuid */
+   LS_SG,  /* setgid */
+   LS_ST,  /* sticky */
+   LS_OW,  /* other-writable */
+   LS_TW,  /* ow with sticky */
+   LS_CA,  /* cap */
+   LS_MH,  /* multi hardlink */
+   LS_CL,  /* clear end of line */
+
+   MAX_LS
+};
+
+static char ls_colors[MAX_LS][COLOR_MAXLEN] = {
+   "",
+   "",
+   "",
+   GIT_COLOR_RESET,
+   GIT_COLOR_NORMAL,
+   GIT_COLOR_NORMAL,
+   GIT_COLOR_BOLD_BLUE,
+   GIT_COLOR_BOLD_CYAN,
+
+   GIT_COLOR_YELLOW,
+   GIT_COLOR_BOLD_MAGENTA,
+   GIT_COLOR_BOLD_YELLOW,
+   GIT_COLOR_BOLD_YELLOW,
+   GIT_COLOR_NORMAL,
+   GIT_COLOR_NORMAL,
+   GIT_COLOR_BOLD_GREEN,
+   GIT_COLOR_BOLD_MAGENTA,
+
+   GIT_COLOR_WHITE_ON_RED,
+   GIT_COLOR_BLACK_ON_YELLOW,
+   GIT_COLOR_WHITE_ON_BLUE,
+   GIT_COLOR_BLUE_ON_GREEN,
+   GIT_COLOR_BLACK_ON_GREEN,
+   "",
+   "",
+   ""
+};
+
+static const char *const indicator_name[] = {
+   "lc", "rc", "ec", "rs", "no", "fi", "di", "ln",
+   "pi", "so", "bd", "cd", "mi", "or", "ex", "do",
+   "su", "sg", "st", "ow", "tw", "ca", "mh", "cl",
+   NULL
+};
+
+struct bin_str {
+   size_t len; /* Number of bytes */
+   const char *string; /* Pointer to the same */
+};
+
+struct color_ext_type {
+   struct bin_str ext; /* The extension we're looking for */
+   struct bin_str seq; /* The sequence to output when we do */
+   struct color_ext_type *next;/* Next in list */
+};
+
+static struct color_ext_type *color_ext_list = NULL;
+
+/*
+ * When true, in a color listing, color each symlink name according to the
+ * type of file it points to.  Otherwise, color them according to the `ln'
+ * directive in LS_COLORS.  Dangling (orphan) symlinks are treated specially,
+ * regardless.  This is set when `ln=target' appears in LS_COLORS.
+ */
+static int color_symlink_as_referent;
+
+/*
+ * Parse a string as part of the LS_COLORS variable; this may involve
+ * decoding all kinds of escape characters.  If equal

[PATCH 04/19] ls_colors.c: highlight submodules like directories

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/config.txt | 3 ++-
 ls_colors.c  | 8 +++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 2090866..2290c47 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -944,7 +944,8 @@ color.ls.::
Use customized color for file name colorization. If not set
and the environment variable LS_COLORS is set, color settings
from $LS_COLORS are used. `` can be `normal`, `file`,
-   `directory`, `symlink`, `fifo`, `socket`, `block`, `char`,
+   `directory`, `submodule`,
+   `symlink`, `fifo`, `socket`, `block`, `char`,
`missing`, `orphan`, `executable`, `door`, `setuid`, `setgid`,
`sticky`, `otherwritable`, `stickyotherwritable`, `cap`,
`multihardlink`. The values of these variables may be
diff --git a/ls_colors.c b/ls_colors.c
index a58da9e..e62e74b 100644
--- a/ls_colors.c
+++ b/ls_colors.c
@@ -29,6 +29,8 @@ enum color_ls {
LS_MH,  /* multi hardlink */
LS_CL,  /* clear end of line */
 
+   LS_SUBMODULE,
+
MAX_LS
 };
 
@@ -58,7 +60,8 @@ static char ls_colors[MAX_LS][COLOR_MAXLEN] = {
GIT_COLOR_BLACK_ON_GREEN,
"",
"",
-   ""
+   "",
+   GIT_COLOR_BOLD_BLUE
 };
 
 static const char *const indicator_name[] = {
@@ -73,6 +76,7 @@ static const char* const config_name[] = {
"fifo", "socket", "block", "char", "missing", "orphan", "executable",
"door", "setuid", "setgid", "sticky", "otherwritable",
"stickyotherwritable", "cap", "multihardlink", "",
+   "submodule",
NULL
 };
 
@@ -448,6 +452,8 @@ void color_filename(struct strbuf *sb, const char *name,
type = LS_DI;
} else if (S_ISLNK (mode))
type = (!linkok && *ls_colors[LS_OR]) ? LS_OR : LS_LN;
+   else if (S_ISGITLINK(mode))
+   type = LS_SUBMODULE;
else if (S_ISFIFO (mode))
type = LS_PI;
else if (S_ISSOCK (mode))
-- 
2.2.0.60.gb7b3c64

--
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 03/19] ls_colors.c: add a function to color a file name

2014-11-30 Thread Nguyễn Thái Ngọc Duy
The new function is based on print_color_indicator() from commit
7326d1f1a67edf21947ae98194f98c38b6e9e527 in coreutils.git.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 color.h |  2 ++
 ls_colors.c | 66 +
 2 files changed, 68 insertions(+)

diff --git a/color.h b/color.h
index 3eaa5bd..b6904a3 100644
--- a/color.h
+++ b/color.h
@@ -94,5 +94,7 @@ void color_print_strbuf(FILE *fp, const char *color, const 
struct strbuf *sb);
 int color_is_nil(const char *color);
 
 void parse_ls_color(void);
+void color_filename(struct strbuf *sb, const char *name,
+   const char *display_name, mode_t mode, int linkok);
 
 #endif /* COLOR_H */
diff --git a/ls_colors.c b/ls_colors.c
index 3e35ffe..a58da9e 100644
--- a/ls_colors.c
+++ b/ls_colors.c
@@ -422,3 +422,69 @@ void parse_ls_color(void)
color_symlink_as_referent = 1;
git_config(ls_colors_config, NULL);
 }
+
+void color_filename(struct strbuf *sb, const char *name,
+   const char *display_name, mode_t mode, int linkok)
+{
+   int type;
+   struct color_ext_type *ext; /* Color extension */
+
+   if (S_ISREG (mode)) {
+   type = LS_FL;
+   if ((mode & S_ISUID) != 0)
+   type = LS_SU;
+   else if ((mode & S_ISGID) != 0)
+   type = LS_SG;
+   else if ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)
+   type = LS_EX;
+   } else if (S_ISDIR (mode)) {
+   if ((mode & S_ISVTX) && (mode & S_IWOTH))
+   type = LS_TW;
+   else if ((mode & S_IWOTH) != 0)
+   type = LS_OW;
+   else if ((mode & S_ISVTX) != 0)
+   type = LS_ST;
+   else
+   type = LS_DI;
+   } else if (S_ISLNK (mode))
+   type = (!linkok && *ls_colors[LS_OR]) ? LS_OR : LS_LN;
+   else if (S_ISFIFO (mode))
+   type = LS_PI;
+   else if (S_ISSOCK (mode))
+   type = LS_SO;
+   else if (S_ISBLK (mode))
+   type = LS_BD;
+   else if (S_ISCHR (mode))
+   type = LS_CD;
+#ifdef S_ISDOOR
+   else if (S_ISDOOR (mode))
+   type = LS_DO;
+#endif
+   else
+   /* Classify a file of some other type as C_ORPHAN.  */
+   type = LS_OR;
+
+   /* Check the file's suffix only if still classified as C_FILE.  */
+   ext = NULL;
+   if (type == LS_FL) {
+   /* Test if NAME has a recognized suffix.  */
+   size_t len = strlen(name);
+   const char *p = name + len; /* Pointer to final \0. 
 */
+   for (ext = color_ext_list; ext != NULL; ext = ext->next) {
+   if (ext->ext.len <= len &&
+   !strncmp(p - ext->ext.len, ext->ext.string, 
ext->ext.len))
+   break;
+   }
+   }
+
+   if (display_name)
+   name = display_name;
+   if (ext)
+   strbuf_addf(sb, "\033[%.*sm%s%s",
+   (int)ext->seq.len, ext->seq.string,
+   name, GIT_COLOR_RESET);
+   else if (*ls_colors[type])
+   strbuf_addf(sb, "%s%s%s", ls_colors[type], name, 
GIT_COLOR_RESET);
+   else
+   strbuf_addstr(sb, name);
+}
-- 
2.2.0.60.gb7b3c64

--
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 00/19] Add git-list-files

2014-11-30 Thread Nguyễn Thái Ngọc Duy
This is something else that's been sitting in my tree for a while now.
It adds "git list-files", intended to be aliased as "ls" with your
favourite display options.

As you can guess it's a friendlier version (and pretty close to GNU
ls) of ls-files. On one hand, I think this is a nice addition. On the
other hand, code bloat. Last version on the list is

http://thread.gmane.org/gmane.comp.version-control.git/244530/focus=245464

Nguyễn Thái Ngọc Duy (19):
  ls_colors.c: add $LS_COLORS parsing code
  ls_colors.c: parse color.ls.* from config file
  ls_colors.c: add a function to color a file name
  ls_colors.c: highlight submodules like directories
  ls-files: buffer full item in strbuf before printing
  ls-files: add --color to highlight file names
  ls-files: add --column
  ls-files: support --max-depth
  Add git-list-files, a user friendly version of ls-files and more
  list-files: -u does not imply showing stages
  list-files: add -R/--recursive short for --max-depth=-1
  list-files: add -1 short for --no-column
  list-files: add -t back
  list-files: sort output and remove duplicates
  list-files: do not show duplicate cached entries
  list-files: show directories as well as files
  list-files: add -F/--classify
  list-files -F: show submodules with the new indicator '&'
  list-files: -M aka diff-cached

 .gitignore |   1 +
 Documentation/config.txt   |  22 ++
 Documentation/git-list-files.txt (new) |  99 +++
 Documentation/git-ls-files.txt |  20 ++
 Makefile   |   2 +
 builtin/ls-files.c | 415 ---
 color.h|  10 +
 command-list.txt   |   1 +
 git.c  |   1 +
 ls_colors.c (new)  | 496 +
 10 files changed, 1034 insertions(+), 33 deletions(-)
 create mode 100644 Documentation/git-list-files.txt
 create mode 100644 ls_colors.c

-- 
2.2.0.60.gb7b3c64

--
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 02/19] ls_colors.c: parse color.ls.* from config file

2014-11-30 Thread Nguyễn Thái Ngọc Duy
This is the second (and preferred) source for color information. This
will override $LS_COLORS.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/config.txt | 11 +++
 ls_colors.c  | 26 ++
 2 files changed, 37 insertions(+)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 9220725..2090866 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -940,6 +940,17 @@ color.status.::
to red). The values of these variables may be specified as in
color.branch..
 
+color.ls.::
+   Use customized color for file name colorization. If not set
+   and the environment variable LS_COLORS is set, color settings
+   from $LS_COLORS are used. `` can be `normal`, `file`,
+   `directory`, `symlink`, `fifo`, `socket`, `block`, `char`,
+   `missing`, `orphan`, `executable`, `door`, `setuid`, `setgid`,
+   `sticky`, `otherwritable`, `stickyotherwritable`, `cap`,
+   `multihardlink`. The values of these variables may be
+   specified as in color.branch..
+
+
 color.ui::
This variable determines the default value for variables such
as `color.diff` and `color.grep` that control the use of color
diff --git a/ls_colors.c b/ls_colors.c
index eb944f4..3e35ffe 100644
--- a/ls_colors.c
+++ b/ls_colors.c
@@ -68,6 +68,14 @@ static const char *const indicator_name[] = {
NULL
 };
 
+static const char* const config_name[] = {
+   "", "", "", "", "normal", "file", "directory", "symlink",
+   "fifo", "socket", "block", "char", "missing", "orphan", "executable",
+   "door", "setuid", "setgid", "sticky", "otherwritable",
+   "stickyotherwritable", "cap", "multihardlink", "",
+   NULL
+};
+
 struct bin_str {
size_t len; /* Number of bytes */
const char *string; /* Pointer to the same */
@@ -285,6 +293,23 @@ static int get_funky_string(char **dest, const char **src, 
int equals_end,
return state != ST_ERROR;
 }
 
+static int ls_colors_config(const char *var, const char *value, void *cb)
+{
+   int slot;
+   if (!starts_with(var, "color.ls."))
+   return 0;
+   var += 9;
+   for (slot = 0; config_name[slot]; slot++)
+   if (!strcasecmp(var, config_name[slot]))
+   break;
+   if (!config_name[slot])
+   return 0;
+   if (!value)
+   return config_error_nonbool(var);
+   color_parse(value, ls_colors[slot]);
+   return 0;
+}
+
 void parse_ls_color(void)
 {
const char *p;  /* Pointer to character being parsed */
@@ -395,4 +420,5 @@ void parse_ls_color(void)
 
if (!strcmp(ls_colors[LS_LN], "target"))
color_symlink_as_referent = 1;
+   git_config(ls_colors_config, NULL);
 }
-- 
2.2.0.60.gb7b3c64

--
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: What's cooking in git.git (Nov 2014, #04; Wed, 26)

2014-11-30 Thread Duy Nguyen
On Fri, Nov 28, 2014 at 1:39 AM, brian m. carlson
 wrote:
> On Wed, Nov 26, 2014 at 03:09:45PM -0800, Junio C Hamano wrote:
>> * nd/untracked-cache (2014-10-27) 19 commits
>>  - t7063: tests for untracked cache
>>  - update-index: test the system before enabling untracked cache
>>  - update-index: manually enable or disable untracked cache
>>  - status: enable untracked cache
>>  - untracked cache: mark index dirty if untracked cache is updated
>>  - untracked cache: print stats with $GIT_TRACE_UNTRACKED_STATS
>>  - untracked cache: avoid racy timestamps
>>  - read-cache.c: split racy stat test to a separate function
>>  - untracked cache: invalidate at index addition or removal
>>  - untracked cache: load from UNTR index extension
>>  - untracked cache: save to an index extension
>>  - untracked cache: don't open non-existent .gitignore
>>  - untracked cache: mark what dirs should be recursed/saved
>>  - untracked cache: record/validate dir mtime and reuse cached output
>>  - untracked cache: make a wrapper around {open,read,close}dir()
>>  - untracked cache: invalidate dirs recursively if .gitignore changes
>>  - untracked cache: initial untracked cache validation
>>  - untracked cache: record .gitignore information and dir hierarchy
>>  - dir.c: optionally compute sha-1 of a .gitignore file
>
> You didn't comment on the status of this branch, and I'm interested.

I'm not Junio :) but I think the core changes are done. I wanted to
actually add watchman support on top of untracked cache as well to see
if it needs any more changes. I think I can see how it could be done
now (not easy, but not terribly hard). I'm going to resend soon to fix
some minor bugs (in a reroll that Junio has not picked up) and change
file format to be more compact.
-- 
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


[PATCH 34/34] git-common-dir: make "modules/" per-working-directory directory

2014-11-30 Thread Nguyễn Thái Ngọc Duy
From: Max Kirillov 

Each working directory of main repository has its own working directory
of submodule, and in most cases they should be checked out to different
revisions. So they should be separated.

It looks logical to make submodule instances in different working
directories to reuse the submodule directory in the common dir of
the main repository, and probably this is how "checkout --to" should
initialize them called on the main repository, but they also should work
fine being completely separated clones.

Testfile t7410-submodule-checkout-to.sh demostrates the behavior.

Signed-off-by: Max Kirillov 
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/gitrepository-layout.txt|  4 +--
 path.c|  2 +-
 t/t7410-submodule-checkout-to.sh (new +x) | 50 +++
 3 files changed, 52 insertions(+), 4 deletions(-)
 create mode 100755 t/t7410-submodule-checkout-to.sh

diff --git a/Documentation/gitrepository-layout.txt 
b/Documentation/gitrepository-layout.txt
index 2b30a92..7173b38 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -248,9 +248,7 @@ commondir::
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
-   "$GIT_COMMON_DIR/modules" will be used instead.
+   Contains the git-repositories of the submodules.
 
 worktrees::
Contains worktree specific information of linked
diff --git a/path.c b/path.c
index 35d498e..a5c51a3 100644
--- a/path.c
+++ b/path.c
@@ -92,7 +92,7 @@ static void replace_dir(struct strbuf *buf, int len, const 
char *newdir)
 }
 
 static const char *common_list[] = {
-   "/branches", "/hooks", "/info", "!/logs", "/lost-found", "/modules",
+   "/branches", "/hooks", "/info", "!/logs", "/lost-found",
"/objects", "/refs", "/remotes", "/worktrees", "/rr-cache", "/svn",
"config", "!gc.pid", "packed-refs", "shallow",
NULL
diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh
new file mode 100755
index 000..8f30aed
--- /dev/null
+++ b/t/t7410-submodule-checkout-to.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='Combination of submodules and multiple workdirs'
+
+. ./test-lib.sh
+
+base_path=$(pwd -P)
+
+test_expect_success 'setup: make origin' \
+'mkdir -p origin/sub && ( cd origin/sub && git init &&
+   echo file1 >file1 &&
+   git add file1 &&
+   git commit -m file1 ) &&
+mkdir -p origin/main && ( cd origin/main && git init &&
+   git submodule add ../sub &&
+   git commit -m "add sub" ) &&
+( cd origin/sub &&
+   echo file1updated >file1 &&
+   git add file1 &&
+   git commit -m "file1 updated" ) &&
+( cd origin/main/sub && git pull ) &&
+( cd origin/main &&
+   git add sub &&
+   git commit -m "sub updated" )'
+
+test_expect_success 'setup: clone' \
+'mkdir clone && ( cd clone &&
+   git clone --recursive "$base_path/origin/main")'
+
+rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q 
"HEAD~1")
+rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q 
"HEAD~1")
+
+test_expect_success 'checkout main' \
+'mkdir default_checkout &&
+(cd clone/main &&
+   git checkout --to "$base_path/default_checkout/main" "$rev1_hash_main")'
+
+test_expect_failure 'can see submodule diffs just after checkout' \
+'(cd default_checkout/main && git diff --submodule master"^!" | grep 
"file1 updated")'
+
+test_expect_success 'checkout main and initialize independed clones' \
+'mkdir fully_cloned_submodule &&
+(cd clone/main &&
+   git checkout --to "$base_path/fully_cloned_submodule/main" 
"$rev1_hash_main") &&
+(cd fully_cloned_submodule/main && git submodule update)'
+
+test_expect_success 'can see submodule diffs after independed cloning' \
+'(cd fully_cloned_submodule/main && git diff --submodule master"^!" | grep 
"file1 updated")'
+
+test_done
-- 
2.1.0.rc0.78.gc0d8480

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


[PATCH 25/34] checkout: clean up half-prepared directories in --to mode

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

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

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


[PATCH 23/34] prune: strategies for linked checkouts

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

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

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

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

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

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

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

[PATCH 33/34] checkout: do not fail if target is an empty directory

2014-11-30 Thread Nguyễn Thái Ngọc Duy
From: Max Kirillov 

Non-recursive checkout creates empty directpries in place of submodules.
If then I try to "checkout --to" submodules there, it refuses to do so,
because directory already exists.

Fix by allowing checking out to empty directory. Add test and modify the
existing one so that it uses non-empty directory.

Signed-off-by: Max Kirillov 
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 builtin/checkout.c | 2 +-
 t/t2025-checkout-to.sh | 7 ++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 8c5276c..953b763 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -865,7 +865,7 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
 
if (!new->commit)
die(_("no branch specified"));
-   if (file_exists(path))
+   if (file_exists(path) && !is_empty_dir(path))
die(_("'%s' already exists"), path);
 
len = strlen(path);
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
index eddd325..915b506 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-checkout-to.sh
@@ -13,10 +13,15 @@ test_expect_success 'checkout --to not updating paths' '
 '
 
 test_expect_success 'checkout --to an existing worktree' '
-   mkdir existing &&
+   mkdir -p existing/subtree &&
test_must_fail git checkout --detach --to existing master
 '
 
+test_expect_success 'checkout --to an existing empty worktree' '
+   mkdir existing_empty &&
+   git checkout --detach --to existing_empty master
+'
+
 test_expect_success 'checkout --to refuses to checkout locked branch' '
test_must_fail git checkout --to zere master &&
! test -d zere &&
-- 
2.1.0.rc0.78.gc0d8480

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


[PATCH 28/34] gc: support prune --worktrees

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

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

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


[PATCH 26/34] gc: style change -- no SP before closing parenthesis

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

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

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


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

2014-11-30 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 " on a sparse checkout will create
 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 
---
 path.c| 3 ++-
 t/t0060-path-utils.sh | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

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

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


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

2014-11-30 Thread Nguyễn Thái Ngọc Duy
From: Dennis Kaarsemaker 

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 
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 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 5dfdbda..8c5276c 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1364,6 +1364,9 @@ int cmd_checkout(int argc, const char **argv, const char 
*prefix)
if (opts.new_worktree_mode)
opts.new_worktree = NULL;
 
+   if (!opts.new_worktree)
+   setup_work_tree();
+
if (conflict_style) {
opts.merge = 1; /* implied */
git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
diff --git a/git.c b/git.c
index 18fbf79..160896a 100644
--- a/git.c
+++ b/git.c
@@ -383,7 +383,7 @@ static struct cmd_struct commands[] = {
{ "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
{ "check-mailmap", cmd_check_mailmap, RUN_SETUP },
{ "check-ref-format", cmd_check_ref_format },
-   { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
+   { "checkout", cmd_checkout, RUN_SETUP },
{ "checkout-index", cmd_checkout_index,
RUN_SETUP | NEED_WORK_TREE},
{ "cherry", cmd_cherry, RUN_SETUP },
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
index e2db078..4bd1df4 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-checkout-to.sh
@@ -81,4 +81,19 @@ test_expect_success 'not die on re-checking out current 
branch' '
)
 '
 
+test_expect_success 'checkout --to from a bare repo' '
+   (
+   git clone --bare . bare &&
+   cd bare &&
+   git checkout --to ../there2 -b bare-master master
+   )
+'
+
+test_expect_success 'checkout from a bare repo without --to' '
+   (
+   cd bare &&
+   test_must_fail git checkout master
+   )
+'
+
 test_done
-- 
2.1.0.rc0.78.gc0d8480

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


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

2014-11-30 Thread Nguyễn Thái Ngọc Duy
"git checkout --to" sets up a new working directory with a .git file
pointing to $GIT_DIR/worktrees/. It then executes "git checkout"
again on the new worktree with the same arguments except "--to" is
taken out. The second checkout execution, which is not contaminated
with any info from the current repository, will actually check out and
everything that normal "git checkout" does.

Helped-by: Marc Branchaud 
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/git-checkout.txt | 46 
 Documentation/git.txt  |  3 +-
 Documentation/gitrepository-layout.txt |  7 +++
 builtin/checkout.c | 95 +-
 path.c |  2 +-
 t/t2025-checkout-to.sh (new +x)| 63 ++
 6 files changed, 212 insertions(+), 4 deletions(-)
 create mode 100755 t/t2025-checkout-to.sh

diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 33ad2ad..c101575 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -225,6 +225,13 @@ This means that you can use `git checkout -p` to 
selectively discard
 edits from your current working tree. See the ``Interactive Mode''
 section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
 
+--to=::
+   Check out a branch in a separate working directory at
+   ``. A new working directory is linked to the current
+   repository, sharing everything except working directory
+   specific files such as HEAD, index... See "MULTIPLE WORKING
+   TREES" section for more information.
+
 ::
Branch to checkout; if it refers to a branch (i.e., a name that,
when prepended with "refs/heads/", is a valid ref), then that
@@ -388,6 +395,45 @@ $ git reflog -2 HEAD # or
 $ git log -g -2 HEAD
 
 
+MULTIPLE WORKING TREES
+--
+
+A git repository can support multiple working trees, allowing you to check
+out more than one branch at a time.  With `git checkout --to` a new working
+tree is associated with the repository.  This new working tree is called a
+"linked working tree" as opposed to the "main working tree" prepared by "git
+init" or "git clone".  A repository has one main working tree (if it's not a
+bare repository) and zero or more linked working trees.
+
+Each linked working tree has a private sub-directory in the repository's
+$GIT_DIR/worktrees directory.  The private sub-directory's name is usually
+the base name of the linked working tree's path, possibly appended with a
+number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the
+command `git checkout --to /path/other/test-next next` creates the linked
+working tree in `/path/other/test-next` and also creates a
+`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`
+if `test-next` is already taken).
+
+Within a linked working tree, $GIT_DIR is set to point to this private
+directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and
+$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR
+(e.g. `/path/main/.git`). These settings are made in a `.git` file located at
+the top directory of the linked working tree.
+
+Path resolution via `git rev-parse --git-path` uses either
+$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the
+linked working tree `git rev-parse --git-path HEAD` returns
+`/path/main/.git/worktrees/test-next/HEAD` (not
+`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
+rev-parse --git-path refs/heads/master` uses
+$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,
+since refs are shared across all working trees.
+
+See linkgit:gitrepository-layout[5] for more information. The rule of
+thumb is do not make any assumption about whether a path belongs to
+$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
+inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
+
 EXAMPLES
 
 
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 96354af..0c2dcfa 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -813,7 +813,8 @@ Git so take care if using Cogito etc.
If this variable is set to a path, non-worktree files that are
normally in $GIT_DIR will be taken from this path
instead. Worktree-specific files such as HEAD or index are
-   taken from $GIT_DIR. See linkgit:gitrepository-layout[5] for
+   taken from $GIT_DIR. See linkgit:gitrepository-layout[5] and
+   the section 'MULTIPLE CHECKOUT MODE' in linkgit:checkout[1]
details. This variable has lower precedence than other path
variables such as GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY...
 
diff --git a/Documentation/gitrepository-layout.txt 
b/Documentation/gitrepository-layout.txt
index 2dc5667..8228450 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt

[PATCH 32/34] t2025: add a test to make sure grafts is working from a linked checkout

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

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

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


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

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

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

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

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

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 builtin/gc.c | 22 --
 1 file changed, 12 insertions(+), 10 deletions(-)

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

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


[PATCH 29/34] count-objects: report unused files in $GIT_DIR/worktrees/...

2014-11-30 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 
---
 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 e47ef0b..ad0c799 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -70,8 +70,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();
+   }
 
for_each_loose_file_in_objdir(get_object_directory(),
  count_loose, count_cruft, NULL, NULL);
diff --git a/cache.h b/cache.h
index f8e75a1..3f60a11 100644
--- a/cache.h
+++ b/cache.h
@@ -695,6 +695,7 @@ extern const char *mkpath(const char *fmt, ...) 
__attribute__((format (printf, 1
 extern const char *git_path(const char *fmt, ...) __attribute__((format 
(printf, 1, 2)));
 extern const char *git_path_submodule(const char *path, const char *fmt, ...)
__attribute__((format (printf, 2, 3)));
+extern void report_linked_checkout_garbage(void);
 
 /*
  * Return the name of the file in the local object database that would
diff --git a/path.c b/path.c
index 72eca6d..cd8e2d6 100644
--- a/path.c
+++ b/path.c
@@ -4,6 +4,7 @@
 #include "cache.h"
 #include "strbuf.h"
 #include "string-list.h"
+#include "dir.h"
 
 static int get_st_mode_bits(const char *path, int *mode)
 {
@@ -91,9 +92,9 @@ static void replace_dir(struct strbuf *buf, int len, const 
char *newdir)
 }
 
 static const char *common_list[] = {
-   "/branches", "/hooks", "/info", "/logs", "/lost-found", "/modules",
+   "/branches", "/hooks", "/info", "!/logs", "/lost-found", "/modules",
"/objects", "/refs", "/remotes", "/worktrees", "/rr-cache", "/svn",
-   "config", "gc.pid", "packed-refs", "shallow",
+   "config", "!gc.pid", "packed-refs", "shallow",
NULL
 };
 
@@ -107,6 +108,8 @@ static void update_common_dir(struct strbuf *buf, int 
git_dir_len)
for (p = common_list; *p; p++) {
const char *path = *p;
int is_dir = 0;
+   if (*path == '!')
+   path++;
if (*path == '/') {
path++;
is_dir = 1;
@@ -122,6 +125,28 @@ static void update_common_dir(struct strbuf *buf, int 
git_dir_len)
}
 }
 
+void report_linked_checkout_garbage(void)
+{
+   struct strbuf sb = STRBUF_INIT;
+   const char **p;
+   int len;
+
+   if (!git_common_dir_env)
+   return;
+   strbuf_addf(&sb, "%s/", get_git_dir());
+   len = sb.len;
+   for (p = common_list; *p; p++) {
+   const char *path = *p;
+   if (*path == '!')
+   continue;
+   strbuf_setlen(&sb, len);
+   strbuf_addstr(&sb, path);
+   if (file_exists(sb.buf))
+   report_garbage("unused in linked checkout", sb.buf);
+   }
+   strbuf_release(&sb);
+}
+
 static void adjust_git_path(struct strbuf *buf, int git_dir_len)
 {
const char *base = buf->buf + git_dir_len;
-- 
2.1.0.rc0.78.gc0d8480

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


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

2014-11-30 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 
---
 Documentation/gitrepository-layout.txt |  7 ++
 setup.c| 43 +-
 2 files changed, 44 insertions(+), 6 deletions(-)

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

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


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

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

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

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


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

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

diff --git a/cache.h b/cache.h
index 9dc6ae0..f8e75a1 100644
--- a/cache.h
+++ b/cache.h
@@ -1499,6 +1499,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 007ec0d..a2dff8e 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -550,3 +550,34 @@ char *xgetcwd(void)
die_errno(_("unable to get current working directory"));
return strbuf_detach(&sb, NULL);
 }
+
+int write_file(const char *path, int fatal, const char *fmt, ...)
+{
+   struct strbuf sb = STRBUF_INIT;
+   va_list params;
+   int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
+   if (fd < 0) {
+   if (fatal)
+   die_errno(_("could not open %s for writing"), path);
+   return -1;
+   }
+   va_start(params, fmt);
+   strbuf_vaddf(&sb, fmt, params);
+   va_end(params);
+   if (write_in_full(fd, sb.buf, sb.len) != sb.len) {
+   int err = errno;
+   close(fd);
+   strbuf_release(&sb);
+   errno = err;
+   if (fatal)
+   die_errno(_("could not write to %s"), path);
+   return -1;
+   }
+   strbuf_release(&sb);
+   if (close(fd)) {
+   if (fatal)
+   die_errno(_("could not close %s"), path);
+   return -1;
+   }
+   return 0;
+}
-- 
2.1.0.rc0.78.gc0d8480

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


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

2014-11-30 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 
---
 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 3b79c50..1a475d8 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -764,7 +764,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;
@@ -777,8 +776,7 @@ static int edit_branch_description(const char *branch_name)
"  %s\n"
"Lines starting with '%c' will be stripped.\n",
branch_name, comment_line_char);
-   fp = fopen(git_path(edit_description), "w");
-   if ((fwrite(buf.buf, 1, buf.len, fp) < buf.len) || fclose(fp)) {
+   if (write_file(git_path(edit_description), 0, "%s", buf.buf)) {
strbuf_release(&buf);
return error(_("could not write branch description template: 
%s"),
 strerror(errno));
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 587a505..6b7fa5f 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -342,7 +342,6 @@ int set_git_dir_init(const char *git_dir, const char 
*real_git_dir,
 static void separate_git_dir(const char *git_dir)
 {
struct stat st;
-   FILE *fp;
 
if (!stat(git_link, &st)) {
const char *src;
@@ -358,11 +357,7 @@ static void separate_git_dir(const char *git_dir)
die_errno(_("unable to move %s to %s"), src, git_dir);
}
 
-   fp = fopen(git_link, "w");
-   if (!fp)
-   die(_("Could not create git link %s"), git_link);
-   fprintf(fp, "gitdir: %s\n", git_dir);
-   fclose(fp);
+   write_file(git_link, 1, "gitdir: %s\n", git_dir);
 }
 
 int init_db(const char *template_dir, unsigned int flags)
diff --git a/daemon.c b/daemon.c
index 54a03bd..60bbab6 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1070,15 +1070,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)
 {
@@ -1289,7 +1280,7 @@ int main(int argc, char **argv)
sanitize_stdfds();
 
if (pid_file)
-   store_pid(pid_file);
+   write_file(pid_file, 1, "%"PRIuMAX"\n", (uintmax_t) getpid());
 
/* prepare argv for serving-processes */
cld_argv = xmalloc(sizeof (char *) * (argc + 2));
diff --git a/submodule.c b/submodule.c
index 0690dc5..34094f5 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1102,16 +1102,11 @@ void connect_work_tree_and_git_dir(const char 
*work_tree, const char *git_dir)
struct strbuf file_name = STRBUF_INIT;
struct strbuf rel_path = STRBUF_INIT;
const char *real_work_tree = xstrdup(real_path(work_tree));
-   FILE *fp;
 
/* Update gitfile */
strbuf_addf(&file_name, "%s/.git", work_tree);
-   fp = fopen(file_name.buf, "w");
-   if (!fp)
-   die(_("Could not create git link %s"), file_name.buf);
-   fprintf(fp, "gitdir: %s\n", relative_path(git_dir, real_work_tree,
- &rel_path));
-   fclose(fp);
+   write_file(file_name.buf, 1, "gitdir: %s\n",
+  relative_path(git_dir, real_work_tree, &rel_path));
 
/* Update core.worktree setting */
strbuf_reset(&file_name);
diff --git a/transport.c b/transport.c
index 70d38e4..051b7ac 100644
--- a/transport.c
+++ b/transport.c
@@ -283,7 +283,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/") &&
@@ -292,10 +291,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->b

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

2014-11-30 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 
---
 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 d968760..94a5c6d 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -344,7 +344,7 @@ git_dir_init () {
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)"}
 }
 
 if test -z "$NONGIT_OK"
-- 
2.1.0.rc0.78.gc0d8480

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


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

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

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

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


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

2014-11-30 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 
---
 git-am.sh  | 22 +++---
 git-rebase--interactive.sh |  6 +++---
 git-rebase--merge.sh   |  6 ++
 git-rebase.sh  |  4 ++--
 templates/hooks--applypatch-msg.sample |  4 ++--
 templates/hooks--pre-applypatch.sample |  4 ++--
 6 files changed, 22 insertions(+), 24 deletions(-)

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

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

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

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

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


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

2014-11-30 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.

Helped-by: Johannes Sixt 
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 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 9220725..e1623ec 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -393,6 +393,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 2103bbf..97fc703 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -216,6 +216,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 4cd44aa..5799f35 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -762,6 +762,10 @@ int cmd_rev_parse(int argc, const char **argv, const char 
*prefix)
free(cwd);
continue;
}
+   if (!strcmp(arg, "--git-common-dir")) {
+   puts(get_git_common_dir());
+   continue;
+   }
if (!strcmp(arg, "--resolve-git-dir")) {
const char *gitdir = argv[++i];
if (!gitdir)
diff --git a/cache.h b/cache.h
index bce1a7d..9dc6ae0 100644
--- a/cache.h
+++ b/cache.h
@@ -437,6 +437,7 @@ extern char *get_object_directory(void);
 extern char *get_index_file(void);
 extern char *get_graft_file(void);
 extern int set_git_dir(const char *path);
+extern int get_common_dir(struct strbuf *sb, const char *gitdir);
 extern const char *get_git_namespace(void);
 extern const char *strip_namespace(const char *namespaced_ref);
 extern const char *get_git_work_tree(void);
diff --git a/environment.c b/environment.c
index 050f160..8351007 100644
--- a/environment.c
+++ b/environment.c
@@ -142,6 +142,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;
 
@@ -150,12 +151,9 @@ static void setup_git_env(void)
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
gitfile = read_gitfile(git_dir);
git_dir = xstrdup(gitfile ? gitfile : git_dir);
-   git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
-   if (git_common_dir) {
+   if (get_common_dir(&sb, git_dir))
git_common_dir_env = 1;
-   git_common_dir = xstrdup(git_common_dir);
-   } else
-   git_common_dir = git_dir;
+   git_common_dir = strbuf_detach(&sb, NULL);
git_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir,
   "objects", &git_db_env);
git_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir,
diff --git a/setup.c b/setup.c
index 1d4f1aa..b99bdd3 100644
--- a/setup.c
+++ b/setup.c
@@ -224,14 +224,15 @@ void verify_non_filename(const char *prefix, const char 
*arg)
"'git  [...] -- [...]'", 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);
+   int ret = 0;
if (git_common

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

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

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

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


[PATCH 10/34] commit: use SEQ_DIR instead of hardcoding "sequencer"

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

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

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


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

2014-11-30 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.

Helped-by: Jens Lehmann 
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/git.txt  |  8 ++
 Documentation/gitrepository-layout.txt | 45 +-
 cache.h|  4 ++-
 environment.c  | 29 --
 path.c | 34 +
 t/t0060-path-utils.sh  | 16 
 6 files changed, 117 insertions(+), 19 deletions(-)

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

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

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

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

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


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

2014-11-30 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 
---
 builtin/reflog.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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

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


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

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 git-pull.sh  | 2 +-
 git-stash.sh | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

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

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


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

2014-11-30 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 
---
 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 d6de42f..2103bbf 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -233,6 +233,13 @@ print a message to stderr and exit with nonzero status.
repository.  If  is a gitfile then the resolved path
to the real repository is printed.
 
+--git-path ::
+   Resolve "$GIT_DIR/" 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 35d3c43..4cd44aa 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -533,6 +533,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 56643cf..7da2ffb 100644
--- a/cache.h
+++ b/cache.h
@@ -617,6 +617,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 05/34] path.c: group git_path(), git_pathdup() and strbuf_git_path() together

2014-11-30 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 path.c | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

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

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


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

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

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

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


[PATCH 00/34] nd/multiple-work-trees reroll

2014-11-30 Thread Nguyễn Thái Ngọc Duy
This is rebased so the diff below (against the version on Junio's
repo) is only approximate. Changes include test fixes for Windows
port, $GIT_COMMON_DIR and $GIT_DIR/modules problems with submodules.
Patch 03/34 is rewritten to touch less in refs.c to reduce conflicts.
A lot of changes there are just revert.

diff --git a/Documentation/gitrepository-layout.txt 
b/Documentation/gitrepository-layout.txt
index 2b30a92..7173b38 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -248,9 +248,7 @@ commondir::
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
-   "$GIT_COMMON_DIR/modules" will be used instead.
+   Contains the git-repositories of the submodules.
 
 worktrees::
Contains worktree specific information of linked
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 01d0f2f..e70e66c 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -865,7 +865,7 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
 
if (!new->commit)
die(_("no branch specified"));
-   if (file_exists(path))
+   if (file_exists(path) && !is_empty_dir(path))
die(_("'%s' already exists"), path);
 
len = strlen(path);
@@ -1207,7 +1207,7 @@ static int parse_branchname_arg(int argc, const char 
**argv,
if (new->path && !force_detach && !*new_branch) {
unsigned char sha1[20];
int flag;
-   char *head_ref = resolve_refdup("HEAD", sha1, 0, &flag);
+   char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
if (head_ref &&
(!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
check_linked_checkouts(new);
diff --git a/environment.c b/environment.c
index d5b0788..8351007 100644
--- a/environment.c
+++ b/environment.c
@@ -101,6 +101,7 @@ const char * const local_repo_env[] = {
NO_REPLACE_OBJECTS_ENVIRONMENT,
GIT_PREFIX_ENVIRONMENT,
GIT_SHALLOW_FILE_ENVIRONMENT,
+   GIT_COMMON_DIR_ENVIRONMENT,
NULL
 };
 
diff --git a/path.c b/path.c
index 35d498e..a5c51a3 100644
--- a/path.c
+++ b/path.c
@@ -92,7 +92,7 @@ static void replace_dir(struct strbuf *buf, int len, const 
char *newdir)
 }
 
 static const char *common_list[] = {
-   "/branches", "/hooks", "/info", "!/logs", "/lost-found", "/modules",
+   "/branches", "/hooks", "/info", "!/logs", "/lost-found",
"/objects", "/refs", "/remotes", "/worktrees", "/rr-cache", "/svn",
"config", "!gc.pid", "packed-refs", "shallow",
NULL
diff --git a/refs.c b/refs.c
index 3cefbd3..f7e48b0 100644
--- a/refs.c
+++ b/refs.c
@@ -1398,14 +1398,16 @@ static const char *handle_missing_loose_ref(const char 
*refname,
 }
 
 /* This function needs to return a meaningful errno on failure */
-const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int 
reading, int *flag)
+static const char *resolve_ref_unsafe_1(const char *refname,
+   unsigned char *sha1,
+   int reading,
+   int *flags,
+   struct strbuf *sb_path)
 {
-   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;
@@ -1423,12 +1425,12 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
 
if (--depth < 0) {
errno = ELOOP;
-   goto fail;
+   return NULL;
}
 
-   strbuf_reset(&sb_path);
-   strbuf_git_path(&sb_path, "%s", refname);
-   path = sb_path.buf;
+   strbuf_reset(sb_path);
+   strbuf_git_path(sb_path, "%s", refname);
+   path = sb_path->buf;
 
/*
 * We might have to loop back here to avoid a race
@@ -1442,11 +1444,10 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
stat_ref:
if (lstat(path, &st) < 0) {
if (errno == ENOENT)
-   ret = handle_missing_loose_ref(refname, sha1,
-  reading, flag);
+   return handle_missing_loose_ref(refname, sha1,
+   reading, flag);
else
-   ret = NULL;
-   goto done;
+   return NULL;
}
 
/* Foll

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

2014-11-30 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 
---
 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 5410dac..c600ec1 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -589,7 +589,7 @@ static void update_refs_for_switch(const struct 
checkout_opts *opts,
if (opts->new_branch_log && !log_all_ref_updates) {
int temp;
char log_file[PATH_MAX];
-   char *ref_name = mkpath("refs/heads/%s", 
opts->new_orphan_branch);
+   const char *ref_name = mkpath("refs/heads/%s", 
opts->new_orphan_branch);
 
temp = log_all_ref_updates;
log_all_ref_updates = 1;
diff --git a/builtin/clone.c b/builtin/clone.c
index d5e7532..a9af3f2 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -290,16 +290,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 7b84d35..cb54936 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -587,7 +587,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");
@@ -821,7 +822,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 a27515a..b92aeff 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 32fc540..3b8f420 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -869,7 +869,7 @@ st

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

2014-11-30 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 
---
 builtin/checkout.c | 13 -
 cache.h|  4 ++--
 path.c | 11 ++-
 refs.c | 51 ++-
 refs.h |  2 +-
 5 files changed, 55 insertions(+), 26 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index c600ec1..195aca7 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -588,18 +588,21 @@ static void update_refs_for_switch(const struct 
checkout_opts *opts,
if (opts->new_orphan_branch) {
if (opts->new_branch_log && !log_all_ref_updates) {
int temp;
-   char log_file[PATH_MAX];
-   const char *ref_name = mkpath("refs/heads/%s", 
opts->new_orphan_branch);
+   struct strbuf log_file = STRBUF_INIT;
+   int ret;
+   const char *ref_name;
 
+   ref_name = mkpath("refs/heads/%s", 
opts->new_orphan_branch);
temp = log_all_ref_updates;
log_all_ref_updates = 1;
-   if (log_ref_setup(ref_name, log_file, 
sizeof(log_file))) {
+   ret = log_ref_setup(ref_name, &log_file);
+   log_all_ref_updates = temp;
+   strbuf_release(&log_file);
+   if (ret) {
fprintf(stderr, _("Can not do reflog 
for '%s'\n"),
opts->new_orphan_branch);
-   log_all_ref_updates = temp;
return;
}
-   log_all_ref_updates = temp;
}
}
else
diff --git a/cache.h b/cache.h
index dbee0a3..56643cf 100644
--- a/cache.h
+++ b/cache.h
@@ -679,8 +679,8 @@ extern int check_repository_format(void);
 
 extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
-extern char *git_snpath(char *buf, size_t n, const char *fmt, ...)
-   __attribute__((format (printf, 3, 4)));
+extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
+   __attribute__((format (printf, 2, 3)));
 extern char *git_pathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2)));
 extern char *mkpathdup(const char *fmt, ...)
diff --git a/path.c b/path.c
index a7ceea2..47753aa 100644
--- a/path.c
+++ b/path.c
@@ -70,19 +70,12 @@ static void vsnpath(struct strbuf *buf, const char *fmt, 
va_list args)
strbuf_cleanup_path(buf);
 }
 
-char *git_snpath(char *buf, size_t n, const char *fmt, ...)
+void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
 {
-   struct strbuf sb = STRBUF_INIT;
va_list args;
va_start(args, fmt);
-   vsnpath(&sb, fmt, args);
+   vsnpath(sb, fmt, args);
va_end(args);
-   if (sb.len >= n)
-   strlcpy(buf, bad_path, n);
-   else
-   memcpy(buf, sb.buf, sb.len + 1);
-   strbuf_release(&sb);
-   return buf;
 }
 
 char *git_pathdup(const char *fmt, ...)
diff --git a/refs.c b/refs.c
index 23617e0..5ed991b 100644
--- a/refs.c
+++ b/refs.c
@@ -1444,7 +1444,11 @@ static int resolve_missing_loose_ref(const char *refname,
 }
 
 /* This function needs to return a meaningful errno on failure */
-const char *resolve_ref_unsafe(const char *refname, int resolve_flags, 
unsigned char *sha1, int *flags)
+static const char *resolve_ref_unsafe_1(const char *refname,
+   int resolve_flags,
+   unsigned char *sha1,
+   int *flags,
+   struct strbuf *sb_path)
 {
int depth = MAXDEPTH;
ssize_t len;
@@ -1475,7 +1479,7 @@ const char *resolve_ref_unsafe(const char *refname, int 
resolve_flags, unsigned
bad_name = 1;
}
for (;;) {
-   char path[PATH_MAX];
+   const char *path;
struct stat st;
char *buf;
int fd;
@@ -1485,7 +1489,9 @@ const char *resolve_ref_unsafe(const char *refname, int 
resol

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

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

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