Git development
 help / color / mirror / Atom feed
* Re: How do gmail users try out patches from this list?
From: Emmanuel Trillaud @ 2009-08-11 21:24 UTC (permalink / raw)
  To: Sverre Rabbelier; +Cc: git
In-Reply-To: <fabb9a1e0908111355m1a15d81cs7f33e1bbc5e1701b@mail.gmail.com>

Huuu! Sorry!
I read your mail too fast.
If you manage to save the interresting mails localy in the mailbox
format (claws mail and thunderbird can do that), you can
then use 'git am' to apply the patches (an example:
http://www.kernel.org/pub/software/scm/git/docs/everyday.html#Integrator).

Best regards

Emmanuel Trillaud

Le Tue, 11 Aug 2009 13:55:38 -0700,
Sverre Rabbelier <srabbelier@gmail.com> a écrit :

> Heya,
> 
> On Tue, Aug 11, 2009 at 13:47, Emmanuel Trillaud<etrillaud@gmail.com>
> wrote:
> > To quote Documentation/SubmittingPatches:
> 
> Not relevant, these instructions are for the other way around; that
> is, sending your patches _to_ the ML, rather than getting patches
> _from_ the ML.
> 

^ permalink raw reply

* Re: block-sha1: improve code on large-register-set machines
From: Brandon Casey @ 2009-08-11 21:20 UTC (permalink / raw)
  To: Nicolas Pitre; +Cc: Linus Torvalds, Git Mailing List, Junio C Hamano
In-Reply-To: <alpine.LFD.2.00.0908111517390.10633@xanadu.home>

Nicolas Pitre wrote:
> On Tue, 11 Aug 2009, Nicolas Pitre wrote:
> 
>> On Tue, 11 Aug 2009, Linus Torvalds wrote:
>>
>>> On Tue, 11 Aug 2009, Nicolas Pitre wrote:
>>>> #define SHA_SRC(t) \
>>>>   ({ unsigned char *__d = (unsigned char *)&data[t]; \
>>>>      (__d[0] << 24) | (__d[1] << 16) | (__d[2] << 8) | (__d[3] << 0); })
>>>>
>>>> And this provides the exact same performance as the ntohl() based 
>>>> version (4.980s) except that this now cope with unaligned buffers too.
>>> The actual object SHA1 calculations are likely not aligned (we do that 
>>> object header thing), and if you can't do the htonl() any better way I 
>>> guess the byte-based thing is the way to go..
> 
> OK, even better: 4.400s.
> 
> This is with this instead of the above:
> 
> #define SHA_SRC(t) \
>    ({   unsigned char *__d = (unsigned char *)data; \
>         (__d[(t)*4 + 0] << 24) | (__d[(t)*4 + 1] << 16) | \
>         (__d[(t)*4 + 2] <<  8) | (__d[(t)*4 + 3] <<  0); })
> 
> The previous version would allocate a new register for __d and then 
> index it with an offset of 0, 1, 2 or 3.  This version always uses the 
> register containing the data pointer with absolute offsets.  The binary 
> is a bit smaller too.

In that case, why not change the interface of blk_SHA1Block() so that its
second argument is const unsigned char* and get rid of __d and the { } ?

Then it will look like this:

   static void blk_SHA1Block(blk_SHA_CTX *ctx, const unsigned char *data);

   ...

   #define SHA_SRC(t) \
       ( (data[(t)*4 + 0] << 24) | (data[(t)*4 + 1] << 16) | \
         (data[(t)*4 + 2] <<  8) | (data[(t)*4 + 3] <<  0) )


Plus, we need something like the following to handle storing the hash to
an unaligned buffer (warning copy/pasted):

@@ -73,8 +74,12 @@ void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *c
 
        /* Output hash
         */
-       for (i = 0; i < 5; i++)
-               ((unsigned int *)hashout)[i] = htonl(ctx->H[i]);
+       for (i = 0; i < 5; i++) {
+               *hashout++ = (unsigned char) (ctx->H[i] >> 24);
+               *hashout++ = (unsigned char) (ctx->H[i] >> 16);
+               *hashout++ = (unsigned char) (ctx->H[i] >> 8);
+               *hashout++ = (unsigned char) (ctx->H[i] >> 0);
+       }
 }
 
 #if defined(__i386__) || defined(__x86_64__)


With these two changes plus a few other minor tweaks, the block-sha1 code compiles
and passes the test suite on sparc (solaris 7) and mips (irix 6.5).

-brandon

^ permalink raw reply

* Re: [RFC PATCH v3 7/8] Support sparse checkout in unpack_trees() and  read-tree
From: skillzero @ 2009-08-11 21:18 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: git, Johannes Schindelin, Junio C Hamano
In-Reply-To: <1250005446-12047-8-git-send-email-pclouds@gmail.com>

2009/8/11 Nguyễn Thái Ngọc Duy <pclouds@gmail.com>:
> [1] .git/info/sparse has the same syntax as .git/info/exclude. Files
> that match the patterns will be set as CE_VALID.

Does this mean it will only support excluding paths you don't want
rather than letting you only include paths you do want?

I'm currently using your other patch series that lets you include or
exclude paths (via config variable) and I find that I mostly use the
include side of it with only a few excluded paths. This is because I
typically want to include only a small subset of the repository so
using excludes would require a pretty large list and any time somebody
adds new files, I'd have to update the exclude list.

I appreciate the flexibility of the script to control what is included
or excluded, but like some other comments here, I like the simplicity
of having built-in support for including/excluding paths without
having to write a script to do it. Some of my projects run on Windows
so scripting is more difficult there.

^ permalink raw reply

* Re: RFC for 1.7: Do not checkout -b master origin/master on clone
From: Santi Béjar @ 2009-08-11 21:06 UTC (permalink / raw)
  To: Michael J Gruber; +Cc: Git Mailing List
In-Reply-To: <4A818B90.9050206@drmicha.warpmail.net>

2009/8/11 Michael J Gruber <git@drmicha.warpmail.net>:
> One common source of confusion for newcomers is the fact that master is
> given such a special treatment in git. While it is certainly okay and
> helpful to set up a default branch in a new repository (git init) it is
> not at all clear why it should be treated specially in any other
> situation, such as:
>
> - Why is master the only local branch which git clone sets up (git
> checkout -b master origin/master)?

Because master is the default branch in the remote repository?

[...]

> This behaviour not only is hard to justify; in fact it gives users a
> completely wrong impression: by pretending that master is special,

It is not hard to justify (the git clone behavior). master is not
special, it is just the default branch, but you can change it changing
the HEAD symlink.

> but
> also by hiding core concepts (distinguishing local/remote branches,
> detached heads) from the user at a point where that very hiding leads to
> confusion.
>
> Under the hood, it is of course HEAD which is given special treatment
> (and which in the majority of repos points to master), and git clone
> sets up a local branch according to HEAD (and does some other guess work
> when cloning bare repos), which means that git clone shows the same
> "random" behaviour which git svn clone does: Which local branch is set
> up by default depends on the current value of HEAD/most recent commit at
> the time of the cloning operation.

It's not random. And please don't mix the "git clone" and "git svn" case.

> So, I suggest that starting with git 1.7:
>
> - git clone does not set up any local branches at all

I think you should first think if this is going to really help
newcomers. I think this would be worst.

Instead of "why only 'master'?" the question will be "why I don't get
any files in the workdir?"

"git clone checks out the default branch, and this is 'master' by
default" is not that hard.

HTH,
Santi

^ permalink raw reply

* Re: [RFC PATCH v2 4/4] read-tree: add --no-sparse to turn off sparse  hook
From: Nguyen Thai Ngoc Duy @ 2009-08-11  7:08 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Junio C Hamano, git
In-Reply-To: <alpine.DEB.1.00.0908110846050.4638@intel-tinevez-2-302>

On Tue, Aug 11, 2009 at 1:50 PM, Johannes
Schindelin<Johannes.Schindelin@gmx.de> wrote:
>> Why not making the hook to be skipped by default, and pass an explicit
>> option to trigger the hook?
>>
>> I like Dscho's other suggestion to use patterns like .gitignore instead
>> of using hook scripts that needs to be ported across platforms, by the
>> way.
>
> I forgot to mention that I checked dir.c to verify that
> add_excludes_from_file_1() (which is static, so you'll either need to use
> it in the same file, or even better, export it renaming it to something
> like add_excludes_from_file_to_list()) and excluded_1() (same here)
> already do a large part of what you need.

Indeed (and I have that code too). I still like the hook though
because you have more freedom in defining your worktree (and yes, less
portable). I wanted to make something generic enough that you can
build higher "strategies" on top, like .gitignore-based patterns.
Anyway I'll send out another patch for .gitignore patterns tonight and
see how it goes.
-- 
Duy

^ permalink raw reply

* Re: How do gmail users try out patches from this list?
From: Sverre Rabbelier @ 2009-08-11 20:55 UTC (permalink / raw)
  To: Emmanuel Trillaud; +Cc: skillzero, git
In-Reply-To: <20090811224717.785dcd27@eleanor>

Heya,

On Tue, Aug 11, 2009 at 13:47, Emmanuel Trillaud<etrillaud@gmail.com> wrote:
> To quote Documentation/SubmittingPatches:

Not relevant, these instructions are for the other way around; that
is, sending your patches _to_ the ML, rather than getting patches
_from_ the ML.

-- 
Cheers,

Sverre Rabbelier

^ permalink raw reply

* Re: How do gmail users try out patches from this list?
From: Emmanuel Trillaud @ 2009-08-11 20:47 UTC (permalink / raw)
  To: skillzero; +Cc: git
In-Reply-To: <2729632a0908111343v73fa475fqb6353dcf2f718101@mail.gmail.com>

To quote Documentation/SubmittingPatches:

GMail does not appear to have any way to turn off line wrapping in the web
interface, so this will mangle any emails that you send.  You can however
use any IMAP email client to connect to the google imap server, and
forward the emails through that.  Just make sure to disable line wrapping
in that email client.  Alternatively, use "git send-email" instead.

Submitting properly formatted patches via Gmail is simple now that
IMAP support is available. First, edit your ~/.gitconfig to specify your
account settings:

[imap]
	folder = "[Gmail]/Drafts"
	host = imaps://imap.gmail.com
	user = user@gmail.com
	pass = p4ssw0rd
	port = 993
	sslverify = false

You might need to instead use: folder = "[Google Mail]/Drafts" if you get
an error that the "Folder doesn't exist".

Next, ensure that your Gmail settings are correct. In "Settings" the
"Use Unicode (UTF-8) encoding for outgoing messages" should be checked.

Once your commits are ready to send to the mailing list, run the following
command to send the patch emails to your Gmail Drafts folder.

	$ git format-patch -M --stdout origin/master | git imap-send

Go to your Gmail account, open the Drafts folder, find the patch email,
fill in the To: and CC: fields and send away!

Best Regards

Emmanuel Trillaud

Le Tue, 11 Aug 2009 13:43:13 -0700,
skillzero@gmail.com a écrit :

> Sorry if this is dumb question, but I didn't see any good info in my
> searches.
> 
> How do gmail users normally apply patches that come through the list?
> Do you just manually copy and paste the email to patch files and use
> git apply? Do you use a tool to export to mbox files and use git am?
> 
> I've been just doing it manually via copy and paste, but it's kinda
> tedious. --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] Limit git-gui to display a maximum number of files
From: Dan Zwell @ 2009-08-11 18:50 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Git Mailing List, raa.lkml
In-Reply-To: <20090811202927.GZ1033@spearce.org>

When there is a large number of new or modified files,
"display_all_files" takes a long time, and git-gui appears to
hang. This change limits the number of files that are displayed.
This limit can be set as gui.maxfilesdisplayed, and is
5000 by default.

A warning is shown when the list of files is truncated.

Signed-off-by: Dan Zwell <dzwell@zwell.net>
---
 git-gui.sh     |   17 ++++++++++++++++-
 po/git-gui.pot |    5 +++++
 2 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/git-gui.sh b/git-gui.sh
index 3c0ce26..eae1f81 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -745,6 +745,8 @@ set default_config(gui.newbranchtemplate) {}
 set default_config(gui.spellingdictionary) {}
 set default_config(gui.fontui) [font configure font_ui]
 set default_config(gui.fontdiff) [font configure font_diff]
+# TODO: this option should be added to the git-config documentation
+set default_config(gui.maxfilesdisplayed) 5000
 set font_descs {
 	{fontui   font_ui   {mc "Main Font"}}
 	{fontdiff font_diff {mc "Diff/Console Font"}}
@@ -1698,10 +1700,12 @@ proc display_all_files_helper {w path icon_name m} {
 	$w insert end "[escape_path $path]\n"
 }
 
+set files_warning 0
 proc display_all_files {} {
 	global ui_index ui_workdir
 	global file_states file_lists
 	global last_clicked
+	global files_warning
 
 	$ui_index conf -state normal
 	$ui_workdir conf -state normal
@@ -1713,7 +1717,18 @@ proc display_all_files {} {
 	set file_lists($ui_index) [list]
 	set file_lists($ui_workdir) [list]
 
-	foreach path [lsort [array names file_states]] {
+	set to_display [lsort [array names file_states]]
+	set display_limit [get_config gui.maxfilesdisplayed]
+	if {[llength $to_display] > $display_limit} {
+		if {!$files_warning} {
+			# do not repeatedly warn:
+			set files_warning 1
+			info_popup [mc "Displaying only %s of %s files." \
+				$display_limit [llength $to_display]]
+		}
+		set to_display [lrange $to_display 0 [expr {$display_limit-1}]]
+	}
+	foreach path $to_display {
 		set s $file_states($path)
 		set m [lindex $s 0]
 		set icon_name [lindex $s 1]
diff --git a/po/git-gui.pot b/po/git-gui.pot
index 53b7d36..074582d 100644
--- a/po/git-gui.pot
+++ b/po/git-gui.pot
@@ -90,6 +90,11 @@ msgstr ""
 msgid "Ready."
 msgstr ""
 
+#: git-gui.sh:1726
+#, tcl-format
+msgid "Displaying only %s of %s files."
+msgstr ""
+
 #: git-gui.sh:1819
 msgid "Unmodified"
 msgstr ""
-- 
1.6.4

^ permalink raw reply related

* Re: unpack a single object
From: Bryan Donlan @ 2009-08-11 20:49 UTC (permalink / raw)
  To: tarmigan; +Cc: Git Mailing List
In-Reply-To: <3e8340490908111348o5df64aa1md1ad8901e857ecb6@mail.gmail.com>

On Tue, Aug 11, 2009 at 4:48 PM, Bryan Donlan<bdonlan@gmail.com> wrote:
> On Tue, Aug 11, 2009 at 4:15 PM, tarmigan<tarmigan+lists@gmail.com> wrote:
>> Hi,
>>
>> At work we use SVN.  To deal with this I mirror the svn repo with
>> git-svn and have a cron job that runs git svn rebase every hour, and
>> then I rebase from that git repo.
>>
>> Unfortunately, on the computer that runs the cron job, /home ran out
>> of space.  After making more space and deleting the
>> svn/trunk/.rev_map, my 'git svn rebase' dies with a
>>> git svn rebase
>> Rebuilding .git/svn/trunk/.rev_map.4279b43a-dd95-8640-b069-b0d2992e4ff2 ...
>> error: Could not read 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce
>> fatal: Failed to traverse parents of commit
>> 31c4379db99f05d0942e7c204b38f7b587fb4d3b
>> rev-list --pretty=raw --no-color --reverse refs/remotes/trunk --:
>> command returned error: 128
>>
>> So I look for corruption with
>>> git fsck --full --strict
>> broken link from  commit 31c4379db99f05d0942e7c204b38f7b587fb4d3b
>>              to  commit 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce
>> dangling blob a6027cd01178f19243342c0f6ccaef8fb798dcf4
>>                <snipped more dangling blobs>
>> dangling blob 4348d7ebd189208716b44bcf4198c1f29d18e6c3
>> missing commit 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce  ******
>> dangling blob 22757bac2e3433cccd9d7e32fa79d90031e14353
>> dangling blob 1276575eca02976ff677b61a6873562db7db31d7
>> dangling blob f98343007ac9d2f33a81fe25f4d446b045c3167a
>> dangling blob d29043a6e2b87cd0be1f3fb39f0c88283b79409b
>> dangling blob f7d08b39830709c044279d17d3d85cbe813998bb
>> dangling blob 64f14b305164f65c788dc9970deb7dfc79ac7446
>>
>> Thankfully, I have copies of the repo and this object (3d4c2b) in
>> other location and that passes git-fsck.  Strangely, it is a commit
>> object from about 18 month ago and should have been in a pack for a
>> long time, so maybe running out of disk space was not the cause.
>>
>> I would rather not copy the whole good repo back to the one that ran
>> out of space because it's multiple gigs.  My plan is to just explode
>> the bad pack on of the corrupted repo, explode good pack and then,
>> copy the corrupted object back.  So my question is how do I tell which
>> pack contains that object?  (I would rather not explode all the packs
>> because of the repo size.)  Is there a way to extract a single object
>> from a pack without exploding the whole pack?
>
> You should be able to just extract the single object in question:
>
> goodrepo$ git cat-file commit 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce
>  > ~/commit.dat
> goodrepo$ cd ~/badrepo
> badrepo$ git read-file -t commit ~/commit.dat
> (should output 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce)
>
> At this point your repo should be repaired.
>

Err, that should read git hash-object, not git read-file.

^ permalink raw reply

* Re: unpack a single object
From: Bryan Donlan @ 2009-08-11 20:48 UTC (permalink / raw)
  To: tarmigan; +Cc: Git Mailing List
In-Reply-To: <905315640908111315j459b81f2jc414f2a09c6b830e@mail.gmail.com>

On Tue, Aug 11, 2009 at 4:15 PM, tarmigan<tarmigan+lists@gmail.com> wrote:
> Hi,
>
> At work we use SVN.  To deal with this I mirror the svn repo with
> git-svn and have a cron job that runs git svn rebase every hour, and
> then I rebase from that git repo.
>
> Unfortunately, on the computer that runs the cron job, /home ran out
> of space.  After making more space and deleting the
> svn/trunk/.rev_map, my 'git svn rebase' dies with a
>> git svn rebase
> Rebuilding .git/svn/trunk/.rev_map.4279b43a-dd95-8640-b069-b0d2992e4ff2 ...
> error: Could not read 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce
> fatal: Failed to traverse parents of commit
> 31c4379db99f05d0942e7c204b38f7b587fb4d3b
> rev-list --pretty=raw --no-color --reverse refs/remotes/trunk --:
> command returned error: 128
>
> So I look for corruption with
>> git fsck --full --strict
> broken link from  commit 31c4379db99f05d0942e7c204b38f7b587fb4d3b
>              to  commit 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce
> dangling blob a6027cd01178f19243342c0f6ccaef8fb798dcf4
>                <snipped more dangling blobs>
> dangling blob 4348d7ebd189208716b44bcf4198c1f29d18e6c3
> missing commit 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce  ******
> dangling blob 22757bac2e3433cccd9d7e32fa79d90031e14353
> dangling blob 1276575eca02976ff677b61a6873562db7db31d7
> dangling blob f98343007ac9d2f33a81fe25f4d446b045c3167a
> dangling blob d29043a6e2b87cd0be1f3fb39f0c88283b79409b
> dangling blob f7d08b39830709c044279d17d3d85cbe813998bb
> dangling blob 64f14b305164f65c788dc9970deb7dfc79ac7446
>
> Thankfully, I have copies of the repo and this object (3d4c2b) in
> other location and that passes git-fsck.  Strangely, it is a commit
> object from about 18 month ago and should have been in a pack for a
> long time, so maybe running out of disk space was not the cause.
>
> I would rather not copy the whole good repo back to the one that ran
> out of space because it's multiple gigs.  My plan is to just explode
> the bad pack on of the corrupted repo, explode good pack and then,
> copy the corrupted object back.  So my question is how do I tell which
> pack contains that object?  (I would rather not explode all the packs
> because of the repo size.)  Is there a way to extract a single object
> from a pack without exploding the whole pack?

You should be able to just extract the single object in question:

goodrepo$ git cat-file commit 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce
 > ~/commit.dat
goodrepo$ cd ~/badrepo
badrepo$ git read-file -t commit ~/commit.dat
(should output 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce)

At this point your repo should be repaired.

^ permalink raw reply

* Re: How do gmail users try out patches from this list?
From: Russ Dill @ 2009-08-11 20:47 UTC (permalink / raw)
  To: skillzero; +Cc: git
In-Reply-To: <2729632a0908111343v73fa475fqb6353dcf2f718101@mail.gmail.com>

> Sorry if this is dumb question, but I didn't see any good info in my searches.
>
> How do gmail users normally apply patches that come through the list?
> Do you just manually copy and paste the email to patch files and use
> git apply? Do you use a tool to export to mbox files and use git am?
>
> I've been just doing it manually via copy and paste, but it's kinda tedious.

Use the POP or IMAP to access your gmail account.

^ permalink raw reply

* How do gmail users try out patches from this list?
From: skillzero @ 2009-08-11 20:43 UTC (permalink / raw)
  To: git

Sorry if this is dumb question, but I didn't see any good info in my searches.

How do gmail users normally apply patches that come through the list?
Do you just manually copy and paste the email to patch files and use
git apply? Do you use a tool to export to mbox files and use git am?

I've been just doing it manually via copy and paste, but it's kinda tedious.

^ permalink raw reply

* Re: [PATCH] Limit git-gui to display a maximum number of files
From: Shawn O. Pearce @ 2009-08-11 20:29 UTC (permalink / raw)
  To: Dan Zwell; +Cc: Git Mailing List, raa.lkml
In-Reply-To: <4A81B738.7090507@zwell.net>

Dan Zwell <dzwell@zwell.net> wrote:
> When there is a large number of new or modified files,
> "display_all_files" takes a long time, and git-gui appears to
> hang. This change limits the number of files that are displayed.
> This limit can be set as gui.maxfilesdisplayed, and is
> 5000 by default.
>
> A warning is shown when the list of files is truncated.
>
> Signed-off-by: Dan Zwell <dzwell@zwell.net>
> ---
> By the way, is the right way to deal with strings to be
> translated? See the end of the patch.

No.

> +			set warning "Displaying only $display_limit of "
> +			append warning "[llength $to_display] files."
> +			info_popup [mc $warning]

This should be:

info_popup [mc "Displaying only %s of %s files." $display_limit [llength $to_display]]

> +msgid "Displaying only %s of %s files."
> +msgstr ""

So that then the placeholders are available here...

-- 
Shawn.

^ permalink raw reply

* Re: [PATCH] Limit git-gui to display a maximum number of files
From: Dan Zwell @ 2009-08-11 18:23 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Git Mailing List, raa.lkml
In-Reply-To: <20090810153859.GT1033@spearce.org>

When there is a large number of new or modified files,
"display_all_files" takes a long time, and git-gui appears to
hang. This change limits the number of files that are displayed.
This limit can be set as gui.maxfilesdisplayed, and is
5000 by default.

A warning is shown when the list of files is truncated.

Signed-off-by: Dan Zwell <dzwell@zwell.net>
---
By the way, is the right way to deal with strings to be
translated? See the end of the patch.

 git-gui.sh     |   18 +++++++++++++++++-
 po/git-gui.pot |    5 +++++
 2 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/git-gui.sh b/git-gui.sh
index 3c0ce26..a4dde9e 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -745,6 +745,8 @@ set default_config(gui.newbranchtemplate) {}
 set default_config(gui.spellingdictionary) {}
 set default_config(gui.fontui) [font configure font_ui]
 set default_config(gui.fontdiff) [font configure font_diff]
+# TODO: this option should be added to the git-config documentation
+set default_config(gui.maxfilesdisplayed) 5000
 set font_descs {
 	{fontui   font_ui   {mc "Main Font"}}
 	{fontdiff font_diff {mc "Diff/Console Font"}}
@@ -1698,10 +1700,12 @@ proc display_all_files_helper {w path icon_name m} {
 	$w insert end "[escape_path $path]\n"
 }
 
+set files_warning 0
 proc display_all_files {} {
 	global ui_index ui_workdir
 	global file_states file_lists
 	global last_clicked
+	global files_warning
 
 	$ui_index conf -state normal
 	$ui_workdir conf -state normal
@@ -1713,7 +1717,19 @@ proc display_all_files {} {
 	set file_lists($ui_index) [list]
 	set file_lists($ui_workdir) [list]
 
-	foreach path [lsort [array names file_states]] {
+	set to_display [lsort [array names file_states]]
+	set display_limit [get_config gui.maxfilesdisplayed]
+	if {[llength $to_display] > $display_limit} {
+		if {!$files_warning} {
+			# do not repeatedly warn:
+			set files_warning 1
+			set warning "Displaying only $display_limit of "
+			append warning "[llength $to_display] files."
+			info_popup [mc $warning]
+		}
+		set to_display [lrange $to_display 0 [expr {$display_limit-1}]]
+	}
+	foreach path $to_display {
 		set s $file_states($path)
 		set m [lindex $s 0]
 		set icon_name [lindex $s 1]
diff --git a/po/git-gui.pot b/po/git-gui.pot
index 53b7d36..fb60472 100644
--- a/po/git-gui.pot
+++ b/po/git-gui.pot
@@ -90,6 +90,11 @@ msgstr ""
 msgid "Ready."
 msgstr ""
 
+#: git-gui.sh:1725
+#, tcl-format
+msgid "Displaying only %s of %s files."
+msgstr ""
+
 #: git-gui.sh:1819
 msgid "Unmodified"
 msgstr ""
-- 
1.6.4


Shawn O. Pearce wrote:

> Dan Zwell <dzwell@gmail.com> wrote:
>   
>> When there is a large number of new or modified files,
>> "display_all_files" takes a long time, and git-gui appears to
>> hang. Limit the display to 5000 files, by default. This number
>> is configurable as gui.maxfilesdisplayed.
>>
>> Show a warning if the list of files is truncated.
>>     
>
>   
>> @@ -1713,7 +1717,18 @@ proc display_all_files {} {
>> 	set file_lists($ui_index) [list]
>> 	set file_lists($ui_workdir) [list]
>>
>> -	foreach path [lsort [array names file_states]] {
>> +	set to_display [lsort [array names file_states]]
>> +	set display_limit $default_config(gui.maxfilesdisplayed)
>>     
>
> This should use [get_config gui.maxfilesdisplayed] so that the
> user can actually set this property in a configuration file and
> have git-gui honor it.  Reading from $default_config means you are
> only looking at the hardcoded value you set in git-gui.sh.
>
>   
>> +	if {[llength $to_display] > $display_limit} {
>> +		if {![info exists files_warning] || !$files_warning} {
>>     
>
> Wouldn't it be easier to just set files_warning to 0 at the start
> of the script, so that you don't need to do this info exists test?
>
>   
>> +			set warning "Displaying only $display_limit of "
>> +			append warning "[llength $to_display] files."
>> +			info_popup [mc $warning]
>>     
>
> This needs to be in the translated strings.
>
>   

^ permalink raw reply related

* unpack a single object
From: tarmigan @ 2009-08-11 20:15 UTC (permalink / raw)
  To: Git Mailing List

Hi,

At work we use SVN.  To deal with this I mirror the svn repo with
git-svn and have a cron job that runs git svn rebase every hour, and
then I rebase from that git repo.

Unfortunately, on the computer that runs the cron job, /home ran out
of space.  After making more space and deleting the
svn/trunk/.rev_map, my 'git svn rebase' dies with a
> git svn rebase
Rebuilding .git/svn/trunk/.rev_map.4279b43a-dd95-8640-b069-b0d2992e4ff2 ...
error: Could not read 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce
fatal: Failed to traverse parents of commit
31c4379db99f05d0942e7c204b38f7b587fb4d3b
rev-list --pretty=raw --no-color --reverse refs/remotes/trunk --:
command returned error: 128

So I look for corruption with
> git fsck --full --strict
broken link from  commit 31c4379db99f05d0942e7c204b38f7b587fb4d3b
              to  commit 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce
dangling blob a6027cd01178f19243342c0f6ccaef8fb798dcf4
                <snipped more dangling blobs>
dangling blob 4348d7ebd189208716b44bcf4198c1f29d18e6c3
missing commit 3d4c2b0225e7605a7e2a38ffc44dcb888589f4ce  ******
dangling blob 22757bac2e3433cccd9d7e32fa79d90031e14353
dangling blob 1276575eca02976ff677b61a6873562db7db31d7
dangling blob f98343007ac9d2f33a81fe25f4d446b045c3167a
dangling blob d29043a6e2b87cd0be1f3fb39f0c88283b79409b
dangling blob f7d08b39830709c044279d17d3d85cbe813998bb
dangling blob 64f14b305164f65c788dc9970deb7dfc79ac7446

Thankfully, I have copies of the repo and this object (3d4c2b) in
other location and that passes git-fsck.  Strangely, it is a commit
object from about 18 month ago and should have been in a pack for a
long time, so maybe running out of disk space was not the cause.

I would rather not copy the whole good repo back to the one that ran
out of space because it's multiple gigs.  My plan is to just explode
the bad pack on of the corrupted repo, explode good pack and then,
copy the corrupted object back.  So my question is how do I tell which
pack contains that object?  (I would rather not explode all the packs
because of the repo size.)  Is there a way to extract a single object
from a pack without exploding the whole pack?

git is version 1.6.4 on CentOS 5.3

Thanks,
Tarmigan

^ permalink raw reply

* Re: block-sha1: improve code on large-register-set machines
From: Nicolas Pitre @ 2009-08-11 20:03 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Git Mailing List, Junio C Hamano
In-Reply-To: <alpine.LFD.2.01.0908110810410.3417@localhost.localdomain>

On Tue, 11 Aug 2009, Linus Torvalds wrote:

> On Tue, 11 Aug 2009, Nicolas Pitre wrote:
> > 
> > BLK_SHA1:	 5.280s		[original]
> > BLK_SHA1:	 7.410s		[with SMALL_REGISTER_SET defined]
> > BLK_SHA1:	 7.480s		[with 'W(x)=(val);asm("":"+m" (W(x)))']
> > BLK_SHA1:	 4.980s		[with 'W(x)=(val);asm("":::"memory")']
> > 
> > At this point the generated assembly is pretty slick.  I bet the full 
> > memory barrier might help on x86 as well.
> 
> No, I had tested that earlier - single-word memory barrier for some reason 
> gets _much_ better numbers at least on x86-64. We're talking
> 
> 	linus            1.46       418.2
> vs
> 	linus           2.004       304.6
> 
> kind of differences. With the "+m" it outperforms openssl (375-380MB/s).
> 
> The "volatile unsigned int *" cast looks pretty much like the "+m" version 
> to me, but Arthur got a speedup from whatever gcc code generation 
> differences on his P4.

The volatile pointer forces a write to memory but the cached value in 
the processor's register remains valid, whereas the "+m" forces gcc to 
assume the register copy is not valid anymore.  That certainly gives the 
compiler a different clue about register availability, etc.

> The really fundamental and basic problem with gcc on this code is that gcc 
> does not see _any_ difference what-so-ever between the five variables 
> declared with
> 
> 	unsigned int A, B, C, D, E;
> 
> and the sixteen variables declared with
> 
> 	unsigned int array[16];
> 
> and considers those all to be 21 local variables. It really seems to think 
> that they are all 100% equivalent, and gcc totally ignores me doing things 
> like adding "register" to the A-E ones etc.
> 
> And if you are a compiler, and think that the routine has 21 equal 
> register variables, you're going to do crazy reload sh*t when you have 
> only 7 (or 15) GP registers. So doing that full memory barrier seems to 
> just take that random situation, and force some random variable to be 
> spilled (this is all from looking at the generated code, not from looking 
> at gcc).
> 
> In contrast, with the _targeted_ thing ("you'd better write back into 
> array[]") we force gcc to spill the array[16] values, and not the A-E 
> ones, and that's why it seems to make such a big difference.
> 
> And no, I'm not sure why ARM apparently doesn't show the same behavior. Or 
> maybe it does, but with an in-order core it doesn't matter as much which 
> registers you keep reloading - you'll be serialized all the time _anyway_. 

Well... gcc is really strange in this case (and similar other ones) with 
ARM compilation.  A good indicator of the quality of the code is the 
size of the stack frame.  When using the "+m" then gcc creates a 816 
byte stack frame, the generated binary grows by approx 3000 bytes, and 
performances is almost halved (7.600s).  Looking at the assembly result 
I just can't figure out all the crazy moves taking place.  Even the 
version with no barrier what so ever produces better assembly with a 
stack frame of 560 bytes.

The volatile version is second to worst with a 808 byte stack frame with 
similar bad performances.

With the full "memory" the stack frame shrinks to 280 bytes and best 
performances so far is obtained.  And none of the A B C D E or data 
variables are ever spilled onto the stack either, only the array[16] 
gets allocated stack slots, and the TEMP variable.


Nicolas

^ permalink raw reply

* Re: block-sha1: improve code on large-register-set machines
From: Nicolas Pitre @ 2009-08-11 19:31 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Git Mailing List, Junio C Hamano
In-Reply-To: <alpine.LFD.2.00.0908111254290.10633@xanadu.home>

On Tue, 11 Aug 2009, Nicolas Pitre wrote:

> On Tue, 11 Aug 2009, Linus Torvalds wrote:
> 
> > On Tue, 11 Aug 2009, Nicolas Pitre wrote:
> > > 
> > > #define SHA_SRC(t) \
> > >   ({ unsigned char *__d = (unsigned char *)&data[t]; \
> > >      (__d[0] << 24) | (__d[1] << 16) | (__d[2] << 8) | (__d[3] << 0); })
> > > 
> > > And this provides the exact same performance as the ntohl() based 
> > > version (4.980s) except that this now cope with unaligned buffers too.
> > 
> > The actual object SHA1 calculations are likely not aligned (we do that 
> > object header thing), and if you can't do the htonl() any better way I 
> > guess the byte-based thing is the way to go..

OK, even better: 4.400s.

This is with this instead of the above:

#define SHA_SRC(t) \
   ({   unsigned char *__d = (unsigned char *)data; \
        (__d[(t)*4 + 0] << 24) | (__d[(t)*4 + 1] << 16) | \
        (__d[(t)*4 + 2] <<  8) | (__d[(t)*4 + 3] <<  0); })

The previous version would allocate a new register for __d and then 
index it with an offset of 0, 1, 2 or 3.  This version always uses the 
register containing the data pointer with absolute offsets.  The binary 
is a bit smaller too.


Nicolas

^ permalink raw reply

* Re: block-sha1: improve code on large-register-set machines
From: Nicolas Pitre @ 2009-08-11 18:00 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Git Mailing List, Junio C Hamano
In-Reply-To: <alpine.LFD.2.01.0908110758160.3417@localhost.localdomain>

On Tue, 11 Aug 2009, Linus Torvalds wrote:

> On Tue, 11 Aug 2009, Nicolas Pitre wrote:
> > 
> > #define SHA_SRC(t) \
> >   ({ unsigned char *__d = (unsigned char *)&data[t]; \
> >      (__d[0] << 24) | (__d[1] << 16) | (__d[2] << 8) | (__d[3] << 0); })
> > 
> > And this provides the exact same performance as the ntohl() based 
> > version (4.980s) except that this now cope with unaligned buffers too.
> 
> Is it better to do a (conditional) memcpy up front? Or is the byte-based 
> one better just because you always end up doing the shifting anyway due to 
> most ARM situations being little-endian?

The vast majority of ARM processors where git might be run are using a 
LE environment.

> I _suspect_ that most large SHA1 calls from git are pre-aligned. The big 
> SHA1 calls are for pack-file verification in fsck, which should all be 
> aligned. Same goes for index file integrity checking.
> 
> The actual object SHA1 calculations are likely not aligned (we do that 
> object header thing), and if you can't do the htonl() any better way I 
> guess the byte-based thing is the way to go..

Let's see.  The default ntohl() provided by glibc generates this code:

        ldr     r3, [r0, #0]
        mov     r0, r3, lsr #24
        and     r2, r3, #0x00ff0000
        orr     r0, r0, r3, asl #24
        orr     r0, r0, r2, lsr #8
        and     r3, r3, #0x0000ff00
        orr     r0, r0, r3, asl #8

Ignoring the load result delay that gcc should properly schedule anyway, 
that makes for 7 cycles.

Using the smarter ARM swab32 implementation from Linux we get:

        ldr     r3, [r0, #0]
        eor     r0, r3, r3, ror #16
        bic     r0, r0, #0x00ff0000
        mov     r0, r0, lsr #8
        eor     r0, r0, r3, ror #8

So we're down to 5 cycles.  And the SHA1 test is a bit faster too: 
4.570s down from 4.980s.  However this is still using purely aligned 
buffers.

Adding your patch using memcpy() to align the data in the unaligned case 
gives me wild results.  Sometimes it is 4.930s, sometimes it is 5.560s.  
I suspect the icache starts to get tight and sometimes the SHA1 code 
and/or the special unaligned memcpy path get evicted sometimes.

Using the byte access version we get:

        ldrb    r3, [r0, #3]
        ldrb    r2, [r0, #0]
        ldrb    r1, [r0, #1]
        orr     r3, r3, r2, asl #24
        ldrb    r0, [r0, #2]
        orr     r3, r3, r1, asl #16
        orr     r0, r3, r0, asl #8

Again 7 cycles, like the ntohl() based version, which is coherent with 
the fact that they both make for 4.980s..  However this time any buffer 
alignment is supported.  And in fact the extra 2 cycles over the 
swab32() version should actually be less overhead per word than the 
unaligned memcpy which is around 4 cycles per word.


Nicolas

^ permalink raw reply

* Re: [PATCH 5/8] Add a config option for remotes to specify a foreign vcs
From: Johannes Schindelin @ 2009-08-11 16:20 UTC (permalink / raw)
  To: Bert Wesarg; +Cc: Junio C Hamano, Daniel Barkalow, git, Brian Gernhardt
In-Reply-To: <36ca99e90908110831g2ad52a5ar4a755723a6682f77@mail.gmail.com>

Hi,

On Tue, 11 Aug 2009, Bert Wesarg wrote:

> On Mon, Aug 10, 2009 at 03:15, Junio C Hamano<gitster@pobox.com> wrote:
> > Daniel Barkalow <barkalow@iabervon.org> writes:
> >
> >> If this is set, the url is not required, and the transport always uses
> >> a helper named "git-remote-<value>".
> >>
> >> It is a separate configuration option in order to allow a sensible
> >> configuration for foreign systems which either have no meaningful urls
> >> for repositories or which require urls that do not specify the system
> >> used by the repository at that location. However, this only affects
> >> how the name of the helper is determined, not anything about the
> >> interaction with the helper, and the contruction is such that, if the
> >> foreign scm does happen to use a co-named url method, a url with that
> >> method may be used directly.
> >
> > Personally, I do not like this.
> >
> > Why isn't it enough to define the canonical remote name git takes as
> > "<name of the helper>:<whatever string the helper understands>"?
> 
> May I ask what will happen to these supported URL notations:
> 
> 
>        o   [user@]host.xz:/path/to/repo.git/
> 
>        o   [user@]host.xz:~user/path/to/repo.git/
> 
>        o   [user@]host.xz:path/to/repo.git
> 
> this will bite you, if you have an ssh host alias named "<your
> favorite helper name>".

That is a valid concern.  I'd suggest to disallow @ and . in the protocol 
name (maybe even everything non-alnum).  For shortcuts that really read 
like "svn", I think it is not too much asked for to require adjusting the 
URL (by prefixing ssh:// and adjusting the path).

If there is really anybody who uses Git via ssh to access a server called 
"svn", we could just as well have a little fun with them, don't you agree?

Ciao,
Dscho

^ permalink raw reply

* [RFC PATCH v3 8/8] --sparse for porcelains
From: Nguyễn Thái Ngọc Duy @ 2009-08-11 15:44 UTC (permalink / raw)
  To: git, Johannes Schindelin, Junio C Hamano
  Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1250005446-12047-8-git-send-email-pclouds@gmail.com>

This series is useless until now because no one would use read-tree to
checkout. At least with this, you can really use/test the series.
Porcelain design was originally "if you have .git/info/sparse,
porcelains will use it, if you don't like that, remove
.git/info/sparse" while plumblings have an option to
enable/disable this feature.

And I still like that behavior. How about we enable sparse checkout
by default for porcelains and make a config option to disable it?

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin-checkout.c |    4 ++++
 builtin-merge.c    |    5 ++++-
 git-pull.sh        |    6 +++++-
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/builtin-checkout.c b/builtin-checkout.c
index 446cac7..cec21ab 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -30,6 +30,7 @@ struct checkout_opts {
 	int force;
 	int writeout_stage;
 	int writeout_error;
+	int apply_sparse;
 
 	const char *new_branch;
 	int new_branch_log;
@@ -402,6 +403,7 @@ static int merge_working_tree(struct checkout_opts *opts,
 		topts.dir = xcalloc(1, sizeof(*topts.dir));
 		topts.dir->flags |= DIR_SHOW_IGNORED;
 		topts.dir->exclude_per_dir = ".gitignore";
+		topts.apply_sparse = opts->apply_sparse;
 		tree = parse_tree_indirect(old->commit->object.sha1);
 		init_tree_desc(&trees[0], tree->buffer, tree->size);
 		tree = parse_tree_indirect(new->commit->object.sha1);
@@ -594,6 +596,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 		OPT_BOOLEAN('m', "merge", &opts.merge, "merge"),
 		OPT_STRING(0, "conflict", &conflict_style, "style",
 			   "conflict style (merge or diff3)"),
+		OPT_SET_INT(0, "sparse", &opts.apply_sparse,
+			    "apply sparse checkout filter", 1),
 		OPT_END(),
 	};
 	int has_dash_dash;
diff --git a/builtin-merge.c b/builtin-merge.c
index 0b12fb3..c14b91d 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -43,7 +43,7 @@ static const char * const builtin_merge_usage[] = {
 
 static int show_diffstat = 1, option_log, squash;
 static int option_commit = 1, allow_fast_forward = 1;
-static int allow_trivial = 1, have_message;
+static int allow_trivial = 1, have_message, apply_sparse;
 static struct strbuf merge_msg;
 static struct commit_list *remoteheads;
 static unsigned char head[20], stash[20];
@@ -172,6 +172,7 @@ static struct option builtin_merge_options[] = {
 	OPT_CALLBACK('m', "message", &merge_msg, "message",
 		"message to be used for the merge commit (if any)",
 		option_parse_message),
+	OPT_SET_INT(0, "sparse", &apply_sparse, "apply sparse checkout filter", 1),
 	OPT__VERBOSITY(&verbosity),
 	OPT_END()
 };
@@ -494,6 +495,7 @@ static int read_tree_trivial(unsigned char *common, unsigned char *head,
 	opts.verbose_update = 1;
 	opts.trivial_merges_only = 1;
 	opts.merge = 1;
+	opts.apply_sparse = apply_sparse;
 	trees[nr_trees] = parse_tree_indirect(common);
 	if (!trees[nr_trees++])
 		return -1;
@@ -646,6 +648,7 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote)
 	opts.verbose_update = 1;
 	opts.merge = 1;
 	opts.fn = twoway_merge;
+	opts.apply_sparse = apply_sparse;
 
 	trees[nr_trees] = parse_tree_indirect(head);
 	if (!trees[nr_trees++])
diff --git a/git-pull.sh b/git-pull.sh
index 0f24182..ba583bf 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -20,6 +20,7 @@ strategy_args= diffstat= no_commit= squash= no_ff= log_arg= verbosity=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short=$(echo "$curr_branch" | sed "s|refs/heads/||")
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
+sparse=
 while :
 do
 	case "$1" in
@@ -65,6 +66,9 @@ do
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
 		rebase=false
 		;;
+	--sparse)
+		sparse=--sparse
+		;;
 	-h|--h|--he|--hel|--help)
 		usage
 		;;
@@ -201,5 +205,5 @@ merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 test true = "$rebase" &&
 	exec git-rebase $diffstat $strategy_args --onto $merge_head \
 	${oldremoteref:-$merge_head}
-exec git-merge $diffstat $no_commit $squash $no_ff $log_arg $strategy_args \
+exec git-merge $sparse $diffstat $no_commit $squash $no_ff $log_arg $strategy_args \
 	"$merge_name" HEAD $merge_head $verbosity
-- 
1.6.3.GIT

^ permalink raw reply related

* [RFC PATCH v3 7/8] Support sparse checkout in unpack_trees() and read-tree
From: Nguyễn Thái Ngọc Duy @ 2009-08-11 15:44 UTC (permalink / raw)
  To: git, Johannes Schindelin, Junio C Hamano
  Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1250005446-12047-7-git-send-email-pclouds@gmail.com>

This patch makes unpack_trees() look at .git/info/sparse [1] to
determine which files should stay in working directory, after
merging, by:

 - setting CE_VALID properly so that other operations correctly ignore
   missing files
 - driving check_updates() to add/remove files in accordance to
   CE_VALID

The feature is disabled by default. Use "read-tree --sparse" to enable it.

[1] .git/info/sparse has the same syntax as .git/info/exclude. Files
that match the patterns will be set as CE_VALID.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin-read-tree.c         |    4 +-
 cache.h                     |    3 +
 t/t1009-read-tree-sparse.sh |   47 ++++++++++++++++++++
 unpack-trees.c              |   98 ++++++++++++++++++++++++++++++++++++++++++-
 unpack-trees.h              |    3 +
 5 files changed, 153 insertions(+), 2 deletions(-)
 create mode 100755 t/t1009-read-tree-sparse.sh

diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 9c2d634..888f136 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -31,7 +31,7 @@ static int list_tree(unsigned char *sha1)
 }
 
 static const char * const read_tree_usage[] = {
-	"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]]  [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]]",
+	"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--sparse] [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]]",
 	NULL
 };
 
@@ -98,6 +98,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
 		  PARSE_OPT_NONEG, exclude_per_directory_cb },
 		OPT_SET_INT('i', NULL, &opts.index_only,
 			    "don't check the working tree after merging", 1),
+		OPT_SET_INT(0, "sparse", &opts.apply_sparse,
+			    "apply sparse checkout filter", 1),
 		OPT_END()
 	};
 
diff --git a/cache.h b/cache.h
index 1a2a3c9..dfad54a 100644
--- a/cache.h
+++ b/cache.h
@@ -177,6 +177,9 @@ struct cache_entry {
 #define CE_HASHED    (0x100000)
 #define CE_UNHASHED  (0x200000)
 
+/* Only remove in work directory, not index */
+#define CE_WT_REMOVE (0x400000)
+
 /*
  * Extended on-disk flags
  */
diff --git a/t/t1009-read-tree-sparse.sh b/t/t1009-read-tree-sparse.sh
new file mode 100755
index 0000000..f70852c
--- /dev/null
+++ b/t/t1009-read-tree-sparse.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+test_description='sparse checkout tests'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_commit one &&
+	mkdir two &&
+	test_commit two two/two.t two.t
+'
+
+test_expect_success 'read-tree without .git/info/sparse' '
+	git read-tree --sparse -m -u HEAD &&
+	test -f one.t &&
+	test -f two/two.t
+'
+
+test_expect_success 'read-tree with empty .git/info/sparse' '
+	echo > .git/info/sparse &&
+	git read-tree --sparse -m -u HEAD &&
+	test -f one.t &&
+	test -f two/two.t
+'
+
+test_expect_success 'read-tree --sparse' '
+	echo "one.t" > .git/info/sparse &&
+	git read-tree --sparse -m -u HEAD &&
+	test ! -f one.t &&
+	test -f two/two.t
+'
+
+test_expect_success 'read-tree --sparse foo where foo is "directory"' '
+	echo "two" > .git/info/sparse &&
+	git read-tree --sparse -m -u HEAD &&
+	test -f one.t &&
+	test -f two/two.t
+'
+
+test_expect_success 'read-tree --sparse foo/' '
+	echo "two/" > .git/info/sparse &&
+	git read-tree --sparse -m -u HEAD &&
+	test -f one.t &&
+	test ! -f two/two.t
+'
+
+test_done
diff --git a/unpack-trees.c b/unpack-trees.c
index 02ea236..d18d333 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -32,6 +32,12 @@ static struct unpack_trees_error_msgs unpack_plumbing_errors = {
 
 	/* bind_overlap */
 	"Entry '%s' overlaps with '%s'.  Cannot bind.",
+
+	/* sparse_not_uptodate_file */
+	"Entry '%s' not uptodate. Cannot update sparse checkout.",
+
+	/* would_lose_orphaned */
+	"Working tree file '%s' would be %s by sparse checkout update.",
 };
 
 #define ERRORMSG(o,fld) \
@@ -78,7 +84,7 @@ static int check_updates(struct unpack_trees_options *o)
 	if (o->update && o->verbose_update) {
 		for (total = cnt = 0; cnt < index->cache_nr; cnt++) {
 			struct cache_entry *ce = index->cache[cnt];
-			if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
+			if (ce->ce_flags & (CE_UPDATE | CE_REMOVE | CE_WT_REMOVE))
 				total++;
 		}
 
@@ -92,6 +98,13 @@ static int check_updates(struct unpack_trees_options *o)
 	for (i = 0; i < index->cache_nr; i++) {
 		struct cache_entry *ce = index->cache[i];
 
+		if (ce->ce_flags & CE_WT_REMOVE) {
+			display_progress(progress, ++cnt);
+			if (o->update)
+				unlink_entry(ce);
+			continue;
+		}
+
 		if (ce->ce_flags & CE_REMOVE) {
 			display_progress(progress, ++cnt);
 			if (o->update)
@@ -118,6 +131,74 @@ static int check_updates(struct unpack_trees_options *o)
 	return errs != 0;
 }
 
+static int verify_uptodate_sparse(struct cache_entry *ce, struct unpack_trees_options *o);
+static int verify_absent_sparse(struct cache_entry *ce, const char *action, struct unpack_trees_options *o);
+static int apply_sparse_checkout(struct unpack_trees_options *o)
+{
+	struct index_state *index = &o->result;
+	struct exclude_list el;
+	int i, ret = 0;
+
+	memset(&el, 0, sizeof(el));
+	if (add_excludes_from_file_to_list(git_path("info/sparse"), "", 0, NULL, &el, 0) < 0)
+		return 0;
+
+	for (i = 0; i < index->cache_nr; i++) {
+		struct cache_entry *ce = index->cache[i];
+		const char *basename;
+		int was_valid = ce->ce_flags & CE_VALID;
+
+		if (ce_stage(ce))
+			continue;
+
+		basename = strrchr(ce->name, '/');
+		basename = basename ? basename+1 : ce->name;
+		if (excluded_from_list(ce->name, ce_namelen(ce), basename, NULL, &el) > 0)
+			ce->ce_flags |= CE_VALID;
+		else
+			ce->ce_flags &= ~CE_VALID;
+
+		/*
+		 * We only care about files getting into the checkout area
+		 * If merge strategies want to remove some, go ahead
+		 */
+		if (ce->ce_flags & CE_REMOVE)
+			continue;
+
+		if (!was_valid && (ce->ce_flags & CE_VALID)) {
+			/*
+			 * If CE_UPDATE is set, verify_uptodate() must be called already
+			 * also stat info may have lost after merged_entry() so calling
+			 * verify_uptodate() again may fail
+			 */
+			if (!(ce->ce_flags & CE_UPDATE) && verify_uptodate_sparse(ce, o)) {
+				ret = -1;
+				break;
+			}
+			ce->ce_flags |= CE_WT_REMOVE;
+		}
+		if (was_valid && !(ce->ce_flags & CE_VALID)) {
+			if (verify_absent_sparse(ce, "overwritten", o)) {
+				ret = -1;
+				break;
+			}
+			ce->ce_flags |= CE_UPDATE;
+		}
+
+		/* merge strategies may set CE_UPDATE outside checkout area */
+		if (ce->ce_flags & CE_VALID)
+			ce->ce_flags &= ~CE_UPDATE;
+
+	}
+
+	for (i = 0;i < el.nr;i++)
+		free(el.excludes[i]);
+	if (el.excludes)
+		free(el.excludes);
+
+	return ret;
+}
+
 static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o)
 {
 	int ret = o->fn(src, o);
@@ -416,6 +497,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 	if (o->trivial_merges_only && o->nontrivial_merge)
 		return unpack_failed(o, "Merge requires file-level merging");
 
+	if (o->apply_sparse && apply_sparse_checkout(o))
+		return unpack_failed(o, NULL);
+
 	o->src_index = NULL;
 	ret = check_updates(o) ? (-2) : 0;
 	if (o->dst_index)
@@ -481,6 +565,12 @@ static int verify_uptodate(struct cache_entry *ce,
 	return verify_uptodate_1(ce, o, ERRORMSG(o, not_uptodate_file));
 }
 
+static int verify_uptodate_sparse(struct cache_entry *ce,
+				  struct unpack_trees_options *o)
+{
+	return verify_uptodate_1(ce, o, ERRORMSG(o, sparse_not_uptodate_file));
+}
+
 static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)
 {
 	if (ce)
@@ -674,6 +764,12 @@ static int verify_absent(struct cache_entry *ce, const char *action,
 	return verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_untracked));
 }
 
+static int verify_absent_sparse(struct cache_entry *ce, const char *action,
+			 struct unpack_trees_options *o)
+{
+	return verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_orphaned));
+}
+
 static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
 		struct unpack_trees_options *o)
 {
diff --git a/unpack-trees.h b/unpack-trees.h
index d19df44..a09077b 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -14,6 +14,8 @@ struct unpack_trees_error_msgs {
 	const char *not_uptodate_dir;
 	const char *would_lose_untracked;
 	const char *bind_overlap;
+	const char *sparse_not_uptodate_file;
+	const char *would_lose_orphaned;
 };
 
 struct unpack_trees_options {
@@ -28,6 +30,7 @@ struct unpack_trees_options {
 		     skip_unmerged,
 		     initial_checkout,
 		     diff_index_cached,
+		     apply_sparse,
 		     gently;
 	const char *prefix;
 	int pos;
-- 
1.6.3.GIT

^ permalink raw reply related

* [RFC PATCH v3 6/8] unpack-trees.c: generalize verify_* functions
From: Nguyễn Thái Ngọc Duy @ 2009-08-11 15:44 UTC (permalink / raw)
  To: git, Johannes Schindelin, Junio C Hamano
  Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1250005446-12047-6-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 unpack-trees.c |   23 ++++++++++++++++++-----
 1 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/unpack-trees.c b/unpack-trees.c
index 720f7a1..02ea236 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -445,8 +445,9 @@ static int same(struct cache_entry *a, struct cache_entry *b)
  * When a CE gets turned into an unmerged entry, we
  * want it to be up-to-date
  */
-static int verify_uptodate(struct cache_entry *ce,
-		struct unpack_trees_options *o)
+static int verify_uptodate_1(struct cache_entry *ce,
+				   struct unpack_trees_options *o,
+				   const char *error_msg)
 {
 	struct stat st;
 
@@ -471,7 +472,13 @@ static int verify_uptodate(struct cache_entry *ce,
 	if (errno == ENOENT)
 		return 0;
 	return o->gently ? -1 :
-		error(ERRORMSG(o, not_uptodate_file), ce->name);
+		error(error_msg, ce->name);
+}
+
+static int verify_uptodate(struct cache_entry *ce,
+			   struct unpack_trees_options *o)
+{
+	return verify_uptodate_1(ce, o, ERRORMSG(o, not_uptodate_file));
 }
 
 static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)
@@ -579,8 +586,9 @@ static int icase_exists(struct unpack_trees_options *o, struct cache_entry *dst,
  * We do not want to remove or overwrite a working tree file that
  * is not tracked, unless it is ignored.
  */
-static int verify_absent(struct cache_entry *ce, const char *action,
-			 struct unpack_trees_options *o)
+static int verify_absent_1(struct cache_entry *ce, const char *action,
+				 struct unpack_trees_options *o,
+				 const char *error_msg)
 {
 	struct stat st;
 
@@ -660,6 +668,11 @@ static int verify_absent(struct cache_entry *ce, const char *action,
 	}
 	return 0;
 }
+static int verify_absent(struct cache_entry *ce, const char *action,
+			 struct unpack_trees_options *o)
+{
+	return verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_untracked));
+}
 
 static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
 		struct unpack_trees_options *o)
-- 
1.6.3.GIT

^ permalink raw reply related

* [RFC PATCH v3 5/8] dir.c: export excluded_1() and add_excludes_from_file_1()
From: Nguyễn Thái Ngọc Duy @ 2009-08-11 15:44 UTC (permalink / raw)
  To: git, Johannes Schindelin, Junio C Hamano
  Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1250005446-12047-5-git-send-email-pclouds@gmail.com>

These functions are used to handle .gitignore. They are now exported
so that sparse checkout can reuse.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 dir.c |   32 ++++++++++++++++----------------
 dir.h |    4 ++++
 2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/dir.c b/dir.c
index c990938..bc35586 100644
--- a/dir.c
+++ b/dir.c
@@ -224,12 +224,12 @@ static void *read_assume_unchanged_from_index(const char *path, size_t *size)
 	return data;
 }
 
-static int add_excludes_from_file_1(const char *fname,
-				    const char *base,
-				    int baselen,
-				    char **buf_p,
-				    struct exclude_list *which,
-				    int check_index)
+int add_excludes_from_file_to_list(const char *fname,
+				   const char *base,
+				   int baselen,
+				   char **buf_p,
+				   struct exclude_list *which,
+				   int check_index)
 {
 	struct stat st;
 	int fd, i;
@@ -275,8 +275,8 @@ static int add_excludes_from_file_1(const char *fname,
 
 void add_excludes_from_file(struct dir_struct *dir, const char *fname)
 {
-	if (add_excludes_from_file_1(fname, "", 0, NULL,
-				     &dir->exclude_list[EXC_FILE], 0) < 0)
+	if (add_excludes_from_file_to_list(fname, "", 0, NULL,
+					   &dir->exclude_list[EXC_FILE], 0) < 0)
 		die("cannot use %s as an exclude file", fname);
 }
 
@@ -325,9 +325,9 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
 		memcpy(dir->basebuf + current, base + current,
 		       stk->baselen - current);
 		strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
-		add_excludes_from_file_1(dir->basebuf,
-					 dir->basebuf, stk->baselen,
-					 &stk->filebuf, el, 1);
+		add_excludes_from_file_to_list(dir->basebuf,
+					       dir->basebuf, stk->baselen,
+					       &stk->filebuf, el, 1);
 		dir->exclude_stack = stk;
 		current = stk->baselen;
 	}
@@ -337,9 +337,9 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
 /* Scan the list and let the last match determine the fate.
  * Return 1 for exclude, 0 for include and -1 for undecided.
  */
-static int excluded_1(const char *pathname,
-		      int pathlen, const char *basename, int *dtype,
-		      struct exclude_list *el)
+int excluded_from_list(const char *pathname,
+		       int pathlen, const char *basename, int *dtype,
+		       struct exclude_list *el)
 {
 	int i;
 
@@ -413,8 +413,8 @@ int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
 
 	prep_exclude(dir, pathname, basename-pathname);
 	for (st = EXC_CMDL; st <= EXC_FILE; st++) {
-		switch (excluded_1(pathname, pathlen, basename,
-				   dtype_p, &dir->exclude_list[st])) {
+		switch (excluded_from_list(pathname, pathlen, basename,
+					   dtype_p, &dir->exclude_list[st])) {
 		case 0:
 			return 0;
 		case 1:
diff --git a/dir.h b/dir.h
index a631446..472e11e 100644
--- a/dir.h
+++ b/dir.h
@@ -69,7 +69,11 @@ extern int match_pathspec(const char **pathspec, const char *name, int namelen,
 extern int fill_directory(struct dir_struct *dir, const char **pathspec);
 extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);
 
+extern int excluded_from_list(const char *pathname, int pathlen, const char *basename,
+			      int *dtype, struct exclude_list *el);
 extern int excluded(struct dir_struct *, const char *, int *);
+extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
+					  char **buf_p, struct exclude_list *which, int check_index);
 extern void add_excludes_from_file(struct dir_struct *, const char *fname);
 extern void add_exclude(const char *string, const char *base,
 			int baselen, struct exclude_list *which);
-- 
1.6.3.GIT

^ permalink raw reply related

* [RFC PATCH v3 3/8] Read .gitignore from index if it is assume-unchanged
From: Nguyễn Thái Ngọc Duy @ 2009-08-11 15:44 UTC (permalink / raw)
  To: git, Johannes Schindelin, Junio C Hamano
  Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1250005446-12047-3-git-send-email-pclouds@gmail.com>

In sparse checkout mode (aka CE_VALID or assume-unchanged) some files
may be missing from working directory. If some of those files are
.gitignore, it will affect how git excludes files.

Because those files are by definition "assume unchanged" we can
instead read them from index. This adds index as a prerequisite for
directory listing. At the moment directory listing is used by "git
clean", "git add", "git ls-files" and "git status"/"git commit" and
unpack_trees()-related commands.  These commands have been
checked/modified to populate index before doing directory listing.

add_excludes_from_file() does not enable this feature, because it
is used to read .git/info/exclude and some explicit files specified
by "git ls-files".

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/technical/api-directory-listing.txt |    3 +
 builtin-clean.c                                   |    5 +-
 builtin-ls-files.c                                |    4 +-
 dir.c                                             |   66 ++++++++++++++------
 t/t3001-ls-files-others-exclude.sh                |   22 +++++++
 t/t7300-clean.sh                                  |   19 ++++++
 6 files changed, 97 insertions(+), 22 deletions(-)

diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt
index 5bbd18f..7d0e282 100644
--- a/Documentation/technical/api-directory-listing.txt
+++ b/Documentation/technical/api-directory-listing.txt
@@ -58,6 +58,9 @@ The result of the enumeration is left in these fields::
 Calling sequence
 ----------------
 
+* Ensure the_index is populated as it may have CE_VALID entries that
+  affect directory listing.
+
 * Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
   sizeof(dir))`.
 
diff --git a/builtin-clean.c b/builtin-clean.c
index 2d8c735..d917472 100644
--- a/builtin-clean.c
+++ b/builtin-clean.c
@@ -71,8 +71,11 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 
 	dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
 
-	if (!ignored)
+	if (!ignored) {
+		if (read_cache() < 0)
+			die("index file corrupt");
 		setup_standard_excludes(&dir);
+	}
 
 	pathspec = get_pathspec(prefix, argv);
 	read_cache();
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index f473220..d1a23c4 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -481,6 +481,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 		prefix_offset = strlen(prefix);
 	git_config(git_default_config, NULL);
 
+	if (read_cache() < 0)
+		die("index file corrupt");
+
 	argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
 			ls_files_usage, 0);
 	if (show_tag || show_valid_bit) {
@@ -508,7 +511,6 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 	pathspec = get_pathspec(prefix, argv);
 
 	/* be nice with submodule paths ending in a slash */
-	read_cache();
 	if (pathspec)
 		strip_trailing_slash_from_submodules();
 
diff --git a/dir.c b/dir.c
index 1170d64..66b485c 100644
--- a/dir.c
+++ b/dir.c
@@ -200,11 +200,36 @@ void add_exclude(const char *string, const char *base,
 	which->excludes[which->nr++] = x;
 }
 
+static void *read_assume_unchanged_from_index(const char *path, size_t *size)
+{
+	int pos, len;
+	unsigned long sz;
+	enum object_type type;
+	void *data;
+	struct index_state *istate = &the_index;
+
+	len = strlen(path);
+	pos = index_name_pos(istate, path, len);
+	if (pos < 0)
+		return NULL;
+	/* only applies to CE_VALID entries */
+	if (!(istate->cache[pos]->ce_flags & CE_VALID))
+		return NULL;
+	data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
+	if (!data || type != OBJ_BLOB) {
+		free(data);
+		return NULL;
+	}
+	*size = xsize_t(sz);
+	return data;
+}
+
 static int add_excludes_from_file_1(const char *fname,
 				    const char *base,
 				    int baselen,
 				    char **buf_p,
-				    struct exclude_list *which)
+				    struct exclude_list *which,
+				    int check_index)
 {
 	struct stat st;
 	int fd, i;
@@ -212,20 +237,26 @@ static int add_excludes_from_file_1(const char *fname,
 	char *buf, *entry;
 
 	fd = open(fname, O_RDONLY);
-	if (fd < 0 || fstat(fd, &st) < 0)
-		goto err;
-	size = xsize_t(st.st_size);
-	if (size == 0) {
-		close(fd);
-		return 0;
+	if (fd < 0 || fstat(fd, &st) < 0) {
+		if (0 <= fd)
+			close(fd);
+		if (!check_index ||
+		    (buf = read_assume_unchanged_from_index(fname, &size)) == NULL)
+			return -1;
 	}
-	buf = xmalloc(size+1);
-	if (read_in_full(fd, buf, size) != size)
-	{
-		free(buf);
-		goto err;
+	else {
+		size = xsize_t(st.st_size);
+		if (size == 0) {
+			close(fd);
+			return 0;
+		}
+		buf = xmalloc(size);
+		if (read_in_full(fd, buf, size) != size) {
+			close(fd);
+			return -1;
+		}
+		close(fd);
 	}
-	close(fd);
 
 	if (buf_p)
 		*buf_p = buf;
@@ -240,17 +271,12 @@ static int add_excludes_from_file_1(const char *fname,
 		}
 	}
 	return 0;
-
- err:
-	if (0 <= fd)
-		close(fd);
-	return -1;
 }
 
 void add_excludes_from_file(struct dir_struct *dir, const char *fname)
 {
 	if (add_excludes_from_file_1(fname, "", 0, NULL,
-				     &dir->exclude_list[EXC_FILE]) < 0)
+				     &dir->exclude_list[EXC_FILE], 0) < 0)
 		die("cannot use %s as an exclude file", fname);
 }
 
@@ -301,7 +327,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
 		strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
 		add_excludes_from_file_1(dir->basebuf,
 					 dir->basebuf, stk->baselen,
-					 &stk->filebuf, el);
+					 &stk->filebuf, el, 1);
 		dir->exclude_stack = stk;
 		current = stk->baselen;
 	}
diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh
index c65bca8..fdd5dd8 100755
--- a/t/t3001-ls-files-others-exclude.sh
+++ b/t/t3001-ls-files-others-exclude.sh
@@ -64,6 +64,8 @@ two/*.4
 echo '!*.2
 !*.8' >one/two/.gitignore
 
+allignores='.gitignore one/.gitignore one/two/.gitignore'
+
 test_expect_success \
     'git ls-files --others with various exclude options.' \
     'git ls-files --others \
@@ -85,6 +87,26 @@ test_expect_success \
        >output &&
      test_cmp expect output'
 
+test_expect_success 'setup sparse gitignore' '
+	git add $allignores &&
+	git update-index --assume-unchanged $allignores &&
+	rm $allignores
+'
+
+test_expect_success \
+    'git ls-files --others with various exclude options.' \
+    'git ls-files --others \
+       --exclude=\*.6 \
+       --exclude-per-directory=.gitignore \
+       --exclude-from=.git/ignore \
+       >output &&
+     test_cmp expect output'
+
+test_expect_success 'restore gitignore' '
+	git checkout $allignores &&
+	rm .git/index
+'
+
 cat > excludes-file <<\EOF
 *.[1-8]
 e*
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index 929d5d4..4886d5f 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -22,6 +22,25 @@ test_expect_success 'setup' '
 
 '
 
+test_expect_success 'git clean with assume-unchanged .gitignore' '
+	git update-index --assume-unchanged .gitignore &&
+	rm .gitignore &&
+	mkdir -p build docs &&
+	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
+	git clean &&
+	test -f Makefile &&
+	test -f README &&
+	test -f src/part1.c &&
+	test -f src/part2.c &&
+	test ! -f a.out &&
+	test ! -f src/part3.c &&
+	test -f docs/manual.txt &&
+	test -f obj.o &&
+	test -f build/lib.so &&
+	git update-index --no-assume-unchanged .gitignore &&
+	git checkout .gitignore
+'
+
 test_expect_success 'git clean' '
 
 	mkdir -p build docs &&
-- 
1.6.3.GIT

^ permalink raw reply related

* [RFC PATCH v3 4/8] excluded_1(): support exclude "directories" in index
From: Nguyễn Thái Ngọc Duy @ 2009-08-11 15:44 UTC (permalink / raw)
  To: git, Johannes Schindelin, Junio C Hamano
  Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1250005446-12047-4-git-send-email-pclouds@gmail.com>

Index does not really have "directories", attempts to match "foo/"
against index will fail unless someone tries to reconstruct directories
from a list of file.

Observing that dtype in this function can never be NULL (otherwise
it would segfault), dtype NULL will be used to say "hey.. you are
matching against index" and behave properly.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
  Having dtype to segfault when dtype is NULL is nice, but I found
  no way else to sneak the new code in. Defining DT_INDEX may clash
  existing system definitions..


 dir.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/dir.c b/dir.c
index 66b485c..c990938 100644
--- a/dir.c
+++ b/dir.c
@@ -350,6 +350,12 @@ static int excluded_1(const char *pathname,
 			int to_exclude = x->to_exclude;
 
 			if (x->flags & EXC_FLAG_MUSTBEDIR) {
+				if (!dtype) {
+					if (!prefixcmp(pathname, exclude))
+						return to_exclude;
+					else
+						continue;
+				}
 				if (*dtype == DT_UNKNOWN)
 					*dtype = get_dtype(NULL, pathname, pathlen);
 				if (*dtype != DT_DIR)
-- 
1.6.3.GIT

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox