Git development
 help / color / mirror / Atom feed
* 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

* [RFC PATCH v3 2/8] Avoid writing to buffer in 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-2-git-send-email-pclouds@gmail.com>

In the next patch, the buffer that is being used within
add_excludes_from_file_1() comes from another function and does not
have extra space to put \n at the end.

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

diff --git a/dir.c b/dir.c
index e05b850..1170d64 100644
--- a/dir.c
+++ b/dir.c
@@ -229,10 +229,9 @@ static int add_excludes_from_file_1(const char *fname,
 
 	if (buf_p)
 		*buf_p = buf;
-	buf[size++] = '\n';
 	entry = buf;
-	for (i = 0; i < size; i++) {
-		if (buf[i] == '\n') {
+	for (i = 0; i <= size; i++) {
+		if (i == size || buf[i] == '\n') {
 			if (entry != buf + i && entry[0] != '#') {
 				buf[i - (i && buf[i-1] == '\r')] = 0;
 				add_exclude(entry, base, baselen, which);
-- 
1.6.3.GIT

^ permalink raw reply related

* [RFC PATCH v3 1/8] Prevent diff machinery from examining assume-unchanged entries on worktree
From: Nguyễn Thái Ngọc Duy @ 2009-08-11 15:43 UTC (permalink / raw)
  To: git, Johannes Schindelin, Junio C Hamano
  Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1250005446-12047-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 diff-lib.c                       |    6 ++++--
 t/t4039-diff-assume-unchanged.sh |   31 +++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 2 deletions(-)
 create mode 100755 t/t4039-diff-assume-unchanged.sh

diff --git a/diff-lib.c b/diff-lib.c
index b7813af..e5b9fe0 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -162,7 +162,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
 		if (ce_uptodate(ce))
 			continue;
 
-		changed = check_removed(ce, &st);
+		/* If CE_VALID is set, don't look at workdir for file removal */
+		changed = (ce->ce_flags & CE_VALID) ? 0 : check_removed(ce, &st);
 		if (changed) {
 			if (changed < 0) {
 				perror(ce->name);
@@ -337,6 +338,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,
 	struct rev_info *revs = o->unpack_data;
 	int match_missing, cached;
 
+	/* if the entry is not checked out, don't examine work tree */
+	cached = o->index_only || (idx && (idx->ce_flags & CE_VALID));
 	/*
 	 * Backward compatibility wart - "diff-index -m" does
 	 * not mean "do not ignore merges", but "match_missing".
@@ -344,7 +347,6 @@ static void do_oneway_diff(struct unpack_trees_options *o,
 	 * But with the revision flag parsing, that's found in
 	 * "!revs->ignore_merges".
 	 */
-	cached = o->index_only;
 	match_missing = !revs->ignore_merges;
 
 	if (cached && idx && ce_stage(idx)) {
diff --git a/t/t4039-diff-assume-unchanged.sh b/t/t4039-diff-assume-unchanged.sh
new file mode 100755
index 0000000..9d9498b
--- /dev/null
+++ b/t/t4039-diff-assume-unchanged.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+test_description='diff with assume-unchanged entries'
+
+. ./test-lib.sh
+
+# external diff has been tested in t4020-diff-external.sh
+
+test_expect_success 'setup' '
+	echo zero > zero &&
+	git add zero &&
+	git commit -m zero &&
+	echo one > one &&
+	echo two > two &&
+	git add one two &&
+	git commit -m onetwo &&
+	git update-index --assume-unchanged one &&
+	echo borked >> one &&
+	test "$(git ls-files -v one)" = "h one"
+'
+
+test_expect_success 'diff-index does not examine assume-unchanged entries' '
+	git diff-index HEAD^ -- one | grep -q 5626abf0f72e58d7a153368ba57db4c673c0e171
+'
+
+test_expect_success 'diff-files does not examine assume-unchanged entries' '
+	rm one &&
+	test -z "$(git diff-files -- one)"
+'
+
+test_done
-- 
1.6.3.GIT

^ permalink raw reply related

* [RFC PATCH v3 0/8] Sparse checkout
From: Nguyễn Thái Ngọc Duy @ 2009-08-11 15:43 UTC (permalink / raw)
  To: git, Johannes Schindelin, Junio C Hamano
  Cc: Nguyễn Thái Ngọc Duy

Continuing the endless RFCs of sparse checkout, this series drops the sparse hook
in favor of .git/info/sparse. Changes from the last version


  Prevent diff machinery from examining assume-unchanged entries on worktree

    "if (ce_uptodate(ce) || CE_VALID)" is updated, as well as the corresponding test


  Avoid writing to buffer in add_excludes_from_file_1()

    Splitted out from the old second patch, as suggested by Johannes


  Read .gitignore from index if it is assume-unchanged

    read_index_data() is renamed. Commit message mentions add_excludes_from_file()


  excluded_1(): support exclude "directories" in index

    This one is new because index does not have "directory", more comments in the patch


  dir.c: export excluded_1() and add_excludes_from_file_1()

    New too, exported for use in unpack-trees.c


  unpack-trees.c: generalize verify_* functions

    Splitted out of the old third patch for easier review


  Support sparse checkout in unpack_trees() and read-tree

    Read .git/info/sparse instead of .git/hooks/sparse

    
  --sparse for porcelains
    RFC patch

 Documentation/technical/api-directory-listing.txt |    3 +
 builtin-checkout.c                                |    4 +
 builtin-clean.c                                   |    5 +-
 builtin-ls-files.c                                |    4 +-
 builtin-merge.c                                   |    5 +-
 builtin-read-tree.c                               |    4 +-
 cache.h                                           |    3 +
 diff-lib.c                                        |    6 +-
 dir.c                                             |  101 +++++++++++------
 dir.h                                             |    4 +
 git-pull.sh                                       |    6 +-
 t/t1009-read-tree-sparse.sh                       |   47 ++++++++
 t/t3001-ls-files-others-exclude.sh                |   22 ++++
 t/t4039-diff-assume-unchanged.sh                  |   31 ++++++
 t/t7300-clean.sh                                  |   19 ++++
 unpack-trees.c                                    |  121 ++++++++++++++++++++-
 unpack-trees.h                                    |    3 +
 17 files changed, 340 insertions(+), 48 deletions(-)
 create mode 100755 t/t1009-read-tree-sparse.sh
 create mode 100755 t/t4039-diff-assume-unchanged.sh

^ permalink raw reply

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



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

			Linus

^ permalink raw reply

* Re: [PATCH 5/8] Add a config option for remotes to specify a foreign  vcs
From: Bert Wesarg @ 2009-08-11 15:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Daniel Barkalow, git, Brian Gernhardt
In-Reply-To: <7v1vnk79lt.fsf@alter.siamese.dyndns.org>

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

Bert

^ permalink raw reply

* RFC for 1.7: Do not checkout -b master origin/master on clone
From: Michael J Gruber @ 2009-08-11 15:17 UTC (permalink / raw)
  To: Git Mailing List

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

- Why does git svn set up a local branch with an svn upstream which is
determined by latest svn commit at the time of the first git svn fetch?

This behaviour not only is hard to justify; in fact it gives users a
completely wrong impression: by pretending that master is special, 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.

So, I suggest that starting with git 1.7:

- git clone does not set up any local branches at all
- git svn fetch does not set up any local branches at all

Ducking under my desk...
Michael

^ permalink raw reply

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

On Mon, 10 Aug 2009, Linus Torvalds wrote:

> 
> For x86 performance (especially in 32-bit mode) I added that hack to write 
> the SHA1 internal temporary hash using a volatile pointer, in order to get 
> gcc to not try to cache the array contents. Because gcc will do all the 
> wrong things, and then spill things in insane random ways.
> 
> But on architectures like PPC, where you have 32 registers, it's actually 
> perfectly reasonable to put the whole temporary array[] into the register 
> set, and gcc can do so.
> 
> So make the 'volatile unsigned int *' cast be dependent on a 
> SMALL_REGISTER_SET preprocessor symbol, and enable it (currently) on just 
> x86 and x86-64.  With that, the routine is fairly reasonable even when 
> compared to the hand-scheduled PPC version. Ben Herrenschmidt reports on 
> a G5:
> 
>  * Paulus asm version:       about 3.67s
>  * Yours with no change:     about 5.74s
>  * Yours without "volatile": about 3.78s
> 
> so with this the C version is within about 3% of the asm one.
> 
> And add a lot of commentary on what the heck is going on.
> 
> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
> ---
> 
> I also asked David Miller to test the non-volatile version on Sparc, but I 
> suspect it will have the same pattern. ia64 likewise (but I have not asked 
> anybody to test).
> 
> Of the other architectures, ARM probably would wants SMALL_REGISTER_SET, 
> but I suspect the problem there is the htonl() (on little-endian), and 
> possibly the unaligned loads - at least on older ARM. The latter is 
> something gcc could be taught about, though (the SHA_SRC macro would just 
> need to use a pointer that goes through a packed struct member or 
> something).

The "older" ARM (those that don't perform unaligned accesses in 
hardware) are still the majority by far in the field.

Here some numbers on ARM for 203247018 bytes.

MOZILLA_SHA1:	14.520s
ARM_SHA1:	 5.600s
OPENSSL:	 5.530s

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.

However the above BLK_SHA1 works only for aligned source buffers.  So 
let's define our own SHA_SRC to replace the htonl() (which should 
probably be ntohl() by the way) like this:

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

Of course the BLK_SHA1 version is a pig since it is totally unrolled

   text    data     bss     dec     hex filename
   1220       0       0    1220     4c4 mozilla-sha1/sha1.o
    852       0       0     852     354 arm/sha1_arm.o
   6292       0       0    6292    1894 block-sha1/sha1.o

so the speed advantage has a significant (but relative) code size cost.


Nicolas

^ permalink raw reply

* Re: [PATCH] Re: [TRIVIAL] Documentation: add: <filepattern>... is optional
From: Paul Bolle @ 2009-08-11 15:06 UTC (permalink / raw)
  To: Nicolas Sebrecht; +Cc: Junio C Hamano, git
In-Reply-To: <20090811145041.GB12956@vidovic>

On Tue, 2009-08-11 at 16:50 +0200, Nicolas Sebrecht wrote:
> The 11/08/09, Paul Bolle wrote:
> 
> > <filepattern>... is optional (e.g. when the --all or --update
> > options are used) so use square brackets in the synopsis.
> 
> So <filepattern> is needed in all other cases.

Since it is an optional argument in those cases I'd say it is better to
indicate that it is optional in the synopsis too.


Paul Bolle

^ permalink raw reply

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



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?

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

		Linus

---
 block-sha1/sha1.c |   13 ++++++++++++-
 1 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/block-sha1/sha1.c b/block-sha1/sha1.c
index 9bc8b8a..df27e66 100644
--- a/block-sha1/sha1.c
+++ b/block-sha1/sha1.c
@@ -25,6 +25,12 @@ void blk_SHA1_Init(blk_SHA_CTX *ctx)
 	ctx->H[4] = 0xc3d2e1f0;
 }
 
+#ifdef REALLY_SLOW_UNALIGNED
+  #define is_unaligned(ptr) (3 & (unsigned long)(ptr))
+#else
+  #define is_unaligned(ptr) 0
+#endif
+
 
 void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *data, unsigned long len)
 {
@@ -47,7 +53,12 @@ void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *data, unsigned long len)
 		blk_SHA1Block(ctx, ctx->W);
 	}
 	while (len >= 64) {
-		blk_SHA1Block(ctx, data);
+		const unsigned int *block = data;
+		if (is_unaligned(data)) {
+			memcpy(ctx->W, data, 64);
+			block = ctx->W;
+		}
+		blk_SHA1Block(ctx, block);
 		data += 64;
 		len -= 64;
 	}

^ permalink raw reply related

* Re: [PATCH] Re: [TRIVIAL] Documentation: merge: one <remote> is required
From: Paul Bolle @ 2009-08-11 14:58 UTC (permalink / raw)
  To: Nicolas Sebrecht; +Cc: Junio C Hamano, git
In-Reply-To: <20090811144253.GA12956@vidovic>

On Tue, 2009-08-11 at 16:42 +0200, Nicolas Sebrecht wrote:
> The 11/08/09, Paul Bolle wrote:
> >  'git merge' [-n] [--stat] [--no-commit] [--squash] [-s <strategy>]...
> > -	[-m <msg>] <remote> <remote>...
> > +	[-m <msg>] <remote>...
> >  'git merge' <msg> HEAD <remote>...
> 
> Shoudn't be 
> 
>    [-m <msg>] <remote> [<remote>...]

No, since "<remote>..." means one or more instances of the "<remote>"
option.  

> or
> 
>    [-m <msg>] <remote>[...]

Is "<$something>[...]" used anywhere? It makes little sense to me.

> instead?

Paul Bolle

^ permalink raw reply

* Re: Unable to checkout a branch after cloning
From: Matthew Lear @ 2009-08-11 14:54 UTC (permalink / raw)
  To: Michael J Gruber; +Cc: git
In-Reply-To: <4A818119.6000302@drmicha.warpmail.net>

Michael J Gruber wrote:
> Matthew Lear venit, vidit, dixit 11.08.2009 16:24:
>> Michael J Gruber wrote:
>>> Matthew Lear venit, vidit, dixit 11.08.2009 14:17:
>>>> Hi Michael - thanks for your reply.
>>>> Michael J Gruber wrote:
>>>>> Matthew Lear venit, vidit, dixit 11.08.2009 12:10:
>>>>>> Hi all,
>>>>>>
>>>>>> Apologies for perhaps a silly question, but I'd very much appreciate a
>>>>>> little bit of assistance.
>>>>>>
>>>>>> I've set up a git repository on a machine accessible from the internet
>>>>>> with the intention to share code with another developer. We clone the
>>>>>> repository, commit changes then push back as you'd expect. The server
>>>>>> runs gitweb for repository browsing. Clients are running git v1.6.0.6.
>>>>>>
>>>>>> When I created the initial repository I also created two additional
>>>>>> branches - 'upstream' and 'custom'. The former is to act as a 'vendor
>>>>>> branch' and the latter contains code specific to the custom platform
>>>>>> that we're working on. The master branch contains merges from the
>>>>>> upstream branch and also changes that we've made. The custom branch
>>>>>> contains merges from master with custom platform specific changes.
>>>>>>
>>>>>> I've committed changes and on both upstream and custom branches as work
>>>>>> progressed, merged them where appropriate, added tags etc and pushed
>>>>>> everything to the remote repository. No problem. I can view the
>>>>>> branches, tags etc in gitweb and everything looks fine.
>>>>>>
>>>>>> However, I can clone a new repository just fine but I'm unable to
>>>>>> checkout the upstream or custom branches. After cloning, only the master
>>>>>> branch is available, ie:
>>>>>>
>>>>>>> git checkout upstream
>>>>>> error: pathspec 'upstream' did not match any file(s) known to git.
>>>>>>
>>>>>>> git branch -a
>>>>>> * master
>>>>>>   origin/HEAD
>>>>>>   origin/master
>>>>>>
>>>>>> .git/config:
>>>>>>
>>>>>> [core]
>>>>>>         repositoryformatversion = 0
>>>>>>         filemode = true
>>>>>>         bare = false
>>>>>>         logallrefupdates = true
>>>>>> [remote "origin"]
>>>>>>         url = https://mysite/git/project.git
>>>>>>         fetch = +refs/heads/*:refs/remotes/origin/*
>>>>>> [branch "master"]
>>>>>>         remote = origin
>>>>>>         merge = refs/heads/master
>>>>>>
>>>>>> But the initial local repository where I work (ie created the branches,
>>>>>> committed changes, tag, push etc) seems to be fine, ie
>>>>>>
>>>>>>> git checkout upstream
>>>>>> Switched to branch "upstream"
>>>>>>
>>>>>>> git branch -a
>>>>>>   custom
>>>>>> * master
>>>>>>   upstream
>>>>>>
>>>>>> .git/config:
>>>>>>
>>>>>> [core]
>>>>>>         repositoryformatversion = 0
>>>>>>         filemode = true
>>>>>>         bare = false
>>>>>>         logallrefupdates = true
>>>>>> [remote "origin"]
>>>>>>         url = https://mysite/git/project.git
>>>>>>         fetch = +refs/heads/*:refs/remotes/origin/*
>>>>>>
>>>>>>
>>>>>> Developers need to be able to clone the repository and then switch to
>>>>>> the appropriate branch in order to work. However it seems that after a
>>>>>> clone, only the master branch is available.
>>>>>>
>>>>>> Why is this?
>>>>>>
>>>>>> Any help would be much appreciated indeed.
>>>>> If I understand you correctly you have 3 repos: the "initial" one on
>>>>> which everything is as expected, the "server" one and the "new clone"
>>>>> which is missing branches.
>>>> Yes, that's correct.
>>>>
>>>>> Now: How's the server one doing, i.e. what does "git ls-remote
>>>>> https://mysite/git/project.git" say? I suspect that one either does not
>>>>> have the branches (you haven't told us how you pushed) or in the wrong
>>>>> place (remotes/).
>>>>> git ls-remote https://mysite/git/project.git
>>>> 065f5f13d5f8e786729db1623cc53767c963e959        HEAD
>>>> 065f5f13d5f8e786729db1623cc53767c963e959        refs/heads/master
>>>>
>>>> Hmm. So it seems that the branches are not actually on the server
>>>> repository. So how come I can see them with gitweb..?
>>>>
>>>> I've been pushing from the 'initial' repository with git push --all and
>>>> git push --tags.
>>>>
>>>> However, when I try a git push from the initial repository I get the
>>>> following:
>>>>
>>>>> git push --all
>>>> Fetching remote heads...
>>>>   refs/
>>>>   refs/heads/
>>>>   refs/tags/
>>>> 'refs/heads/custom': up-to-date
>>>> 'refs/heads/master': up-to-date
>>>> 'refs/heads/upstream': up-to-date
>>>>
>>>> -- Matt
>>> Does the situation improve if, on the server, you run git
>>> update-server-info? Do you have a post-update hook there?
>>>
>>> Michael
>> I ran git update-server-info on the server machine. I read about this
>> and thought I had made the necessary change to add it as a post commit
>> hook. I guess not (so will double check). However, something is still
>> not quite right upon cloning:
>>
>>> git clone https://mysite/git/project.git
>> Initialized empty Git repository in /home/matt/git-repos/project/.git/
>> Checking out files: 100% (26747/26747), done.
>>
>>> git branch -a
>> * master
>>   origin/HEAD
>>   origin/custom
>>   origin/master
>>   origin/upstream
> 
> We're making progress, that's good ;)
> Re. the hook: Make sure it's executable and the extension .sample is
> removed.
> 
> (gitweb and http access are two different things, which is a common
> source of confusion)
> 
>>> git checkout upstream
>> error: pathspec 'upstream' did not match any file(s) known to git.
>>
>> So it seems that the cloned repository is now aware of the branches
>> (improvement) but I'm still unable to switch to a branch.
>>
>> This is probably now a case of me reading the manual but I'd appreciate
>> your thoughts nonetheless.
> 
> Well, there is no branch names upstream. There's only one named
> origin/upstream, and it's a remote branch. Meaning: checking it out will
> produce a detached head, which may or may not be what you want. If you
> want to create a branch to work on upstream, do something like
> 
> git checkout -b myupstream origin/upstream
> 
> (git does something like git checkout -b master origin/master
> automatically when cloning, which I think is a common source of confusion)

I've fixed the server hook scripts (embarrassingly, they were executable
but still had the .sample suffix - that's really not going to work!).

I've actually just read through the manual about detached heads. This is
not what I want but your solution to create a branch to track the remote
branch is exactly what I need.

Where ever you are in the world, many thanks for your continued help and
assistance. Very much appreciated indeed.

Cheers,
--  Matt

^ permalink raw reply


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