Git development
 help / color / mirror / Atom feed
* Re: [PATCH] gitweb: Paginate history output
From: Junio C Hamano @ 2006-08-22  6:15 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <200608220053.10741.jnareb@gmail.com>

Jakub Narebski <jnareb@gmail.com> writes:

> @@ -1559,6 +1562,7 @@ sub git_history_body {
>  			next;
>  		}
>  
> +		#my $ref = defined $refs ? format_ref_marker($refs, $commit) : '';
>  		my $ref = format_ref_marker($refs, $commit);
>  
>  		if ($alternate) {

Do you want to change this or not?  Make up your mind.

> +		$paging_nav .= " &sdot; " .
> +			$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
> +			                       file_name=>$file_name, page=>$page-1),
> +			         -accesskey => "p", -title => "Alt-p"}, "prev");

This is something you inherited from the original and not your
fault, but I am not sure if these -title entries are of good
taste (we have corresponding "Alt-n" for "next").  Something
more descriptive like "<Alt-p> for 100 newer changes", perhaps?

Also, "first", "prev" and "next" have always confused me.  Maybe
"latest", "older" and "newer" are better labels for them?

Is 100 a good default?  It feels a bit unbalanced compared to
the height of the default summary page with descriptions, 16
shortlog entries, 16 tags and 12 heads.

^ permalink raw reply

* Hey baby, found this site and wanted you to check it out first
From: Brant @ 2006-08-21 23:10 UTC (permalink / raw)
  To: git


Hey man, self ok I had to send you this site, view I ordered a Gold package and these things work amazingly !
For real,   I've tried a bunch of other ones but they don't work- these ones are the real deal though sell.
If cooking becomes an art form rather than a means of providing a reasonable diet, then something is clearly wrong.
soon Check out the site for yourself:
http://www.neroplaresampit.com/
I do not read advertisements. I would spend all of my time wanting things.

^ permalink raw reply

* Re: git clone dies (large git repository)
From: Jakub Narebski @ 2006-08-22  0:42 UTC (permalink / raw)
  To: git
In-Reply-To: <7v3bbpty7j.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:

> "Troy Telford" <ttelford@linuxnetworx.com> writes:
> 
>> I'm thinking of it as an option for git-repack-- that the user can set
>> the maximum size of any individual pack, and after that limit is
>> reached, a  new pack file is started.  (ie. --max-size 2GB) and will
>> end up with two  packs, each 2GB in size.
> 
> The way I would suggest you do it is not by size but by distance
> from the latest.  If you want to split the kernel history for
> example, you repack up to 2.6.14 for example, and then repack
> the remainder.  That way, you can optimize for size for older
> (presumably less frequently used) data while optimizing for
> speed for more reent stuff.

If there would be some enhancement to pack files allowing either limiting
the size of pack (e.g. filesystem limits, mmap limits) and/or mmaping only
fragment or fragments of pack file, the maximal size of the pack, or
maximal size of the mmapped fragment should be configurable per repository,
not olny as an option to some command (git-repack for example).

Probably would need some enhancement to git-fetch/git-clone too...

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* Re: git clone dies (large git repository)
From: Junio C Hamano @ 2006-08-22  0:23 UTC (permalink / raw)
  To: Troy Telford; +Cc: git
In-Reply-To: <op.tenp9fv1ies9li@rygel.lnxi.com>

"Troy Telford" <ttelford@linuxnetworx.com> writes:

> I'm thinking of it as an option for git-repack-- that the user can set
> the maximum size of any individual pack, and after that limit is
> reached, a  new pack file is started.  (ie. --max-size 2GB) and will
> end up with two  packs, each 2GB in size.

The way I would suggest you do it is not by size but by distance
from the latest.  If you want to split the kernel history for
example, you repack up to 2.6.14 for example, and then repack
the remainder.  That way, you can optimize for size for older
(presumably less frequently used) data while optimizing for
speed for more reent stuff.

There is no wrapper support for the above splitting in
git-repack.  The low-level plumbing tools can be used this way
for example:

	name=`
                git rev-list --objects $list_old_tags_here |
                git pack-objects --window=50 --depth=50 --non-empty .tmp-pack
        ` &&
        mv -f .tmp-pack-$name.{pack,idx} .git/objects/pack/

	name=`
		git revlist --objects --all --not $list_old_tags_here |
		git pack-objects --non-empty .tmp-pack
	` &&
        mv -f .tmp-pack-$name.{pack,idx} .git/objects/pack/

If you are splitting into more than two, you would instead have
more than one $list_old_tags_here list, and iterate them
through, something like:

	pack_between () {
        	already_done="$1"
                do_this_time="$2"
                w=${3-10}
		name=`
			git rev-list --objects \
                        	$do_this_time \
                                --not $already_done |
			git pack-objects --window=$w --depth=$w \
                        	--non-empty .tmp-pack
                ` &&
                mv -f .tmp-pack-$name.{pack,idx} .git/objects/pack/
	}

	pack_between "" "$prehistoric_tag_list" 100
	pack_between "$prehistoric_tag_list" "$more_recent_tag_list" 50
	pack_between "$more_recent_tag_list" --all

All untested, of course, so do not play with it in your precious
repository you do not have any other copy, but hopefully you get
an idea ;-).

^ permalink raw reply

* Re: git clone dies (large git repository)
From: Troy Telford @ 2006-08-21 23:30 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vfyfs313t.fsf@assigned-by-dhcp.cox.net>

On Sat, 19 Aug 2006 14:46:30 -0600, Junio C Hamano <junkio@cox.net> wrote:

> What is interesting is that .pack format does not have (as far
> as I know) inherent size limitation.  However, .idx file has
> hardcoded 32-bit offsets into .pack -- hence, in practice, you
> cannot use a .pack that is over 4GB locally.

Confessing my (complete, total, frightening) ignorance about git:  Is it  
even possible to take a large pack file and split it into smaller packs?

I'm thinking of it as an option for git-repack-- that the user can set the  
maximum size of any individual pack, and after that limit is reached, a  
new pack file is started.  (ie. --max-size 2GB) and will end up with two  
packs, each 2GB in size.

That being said -- I've been able to work around it (although I haven't  
tried your suggestion yet); it's not a 'critical' problem.  I'm now just  
curious if my fantasy (above) makes sense.
-- 
Troy Telford

^ permalink raw reply

* [PATCH] gitweb: Paginate history output
From: Jakub Narebski @ 2006-08-21 22:53 UTC (permalink / raw)
  To: git

git_history output is now divided into pages, like git_shortlog,
git_tags and git_heads output. As whole git-rev-list output is now
read into array before writing anything, it allows for better
signaling of errors.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Based on 'next' branch, but should apply to 'master as well.

 gitweb/gitweb.perl |   59 ++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 52 insertions(+), 7 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 31a1824..90157d5 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1544,12 +1544,15 @@ sub git_shortlog_body {
 
 sub git_history_body {
 	# Warning: assumes constant type (blob or tree) during history
-	my ($fd, $refs, $hash_base, $ftype, $extra) = @_;
+	my ($revlist, $from, $to, $refs, $hash_base, $ftype, $extra) = @_;
+
+	$from = 0 unless defined $from;
+	$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
 
 	print "<table class=\"history\" cellspacing=\"0\">\n";
 	my $alternate = 0;
-	while (my $line = <$fd>) {
-		if ($line !~ m/^([0-9a-fA-F]{40})/) {
+	for (my $i = $from; $i <= $to; $i++) {
+		if ($revlist->[$i] !~ m/^([0-9a-fA-F]{40})/) {
 			next;
 		}
 
@@ -1559,6 +1562,7 @@ sub git_history_body {
 			next;
 		}
 
+		#my $ref = defined $refs ? format_ref_marker($refs, $commit) : '';
 		my $ref = format_ref_marker($refs, $commit);
 
 		if ($alternate) {
@@ -2651,21 +2655,62 @@ sub git_history {
 	if (!%co) {
 		die_error(undef, "Unknown commit object");
 	}
+
 	my $refs = git_get_references();
-	git_header_html();
-	git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base);
-	git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
+	my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
+
 	if (!defined $hash && defined $file_name) {
 		$hash = git_get_hash_by_path($hash_base, $file_name);
 	}
 	if (defined $hash) {
 		$ftype = git_get_type($hash);
 	}
+
+	open my $fd, "-|",
+		$GIT, "rev-list", $limit, "--full-history", $hash_base, "--", $file_name
+			or die_error(undef, "Open git-rev-list-failed");
+	my @revlist = map { chomp; $_ } <$fd>;
+	close $fd;
+
+	my $paging_nav = '';
+	if ($page > 0) {
+		$paging_nav .=
+			$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
+			                       file_name=>$file_name)},
+			        "first");
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
+			                       file_name=>$file_name, page=>$page-1),
+			         -accesskey => "p", -title => "Alt-p"}, "prev");
+	} else {
+		$paging_nav .= "first";
+		$paging_nav .= " &sdot; prev";
+	}
+	if ($#revlist >= (100 * ($page+1)-1)) {
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
+			                       file_name=>$file_name, page=>$page+1),
+			         -accesskey => "n", -title => "Alt-n"}, "next");
+	} else {
+		$paging_nav .= " &sdot; next";
+	}
+	my $next_link = '';
+	if ($#revlist >= (100 * ($page+1)-1)) {
+		$next_link =
+			$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
+			                       file_name=>$file_name, page=>$page+1),
+			         -title => "Alt-n"}, "next");
+	}
+
+	git_header_html();
+	git_print_page_nav('history','', $hash_base,$co{'tree'},$hash_base, $paging_nav);
+	git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
 	git_print_page_path($file_name, $ftype, $hash_base);
 
 	open my $fd, "-|",
 		$GIT, "rev-list", "--full-history", $hash_base, "--", $file_name;
-	git_history_body($fd, $refs, $hash_base, $ftype);
+	git_history_body(\@revlist, ($page * 100), $#revlist,
+	                 $refs, $hash_base, $ftype, $next_link);
 
 	close $fd;
 	git_footer_html();
-- 
1.4.1.1

^ permalink raw reply related

* Want to shave a few pounds?
From: Roosevelt @ 2006-08-21 21:27 UTC (permalink / raw)
  To: git-owner

Yo Git-owner!.!




Amazing weight loss stories here:


http://www.vestera.net/n/?52&consortbatik


I've always had trouble with my weight ever since I was young. Of course I tried all the "best" fat loss products, nothing helped very much. It wasn't til I tried Anatrim that I saw the pounds seriously start to melt away! Nothing helped me lose weight faster. I literally saw 15 pounds melt away within the first few weeks! There's nothing more exciting than watching pounds disappear, especially when you've tried all sorts of different methods and products before. I've since read up on Anatrim and am amazed at the number of people who have benefited from its amazing results. I'm halfway to my goal, Anatrim will get me the rest of the way ;)

Jordan McKenzie, New York




http://www.obesor.net/hd/?52&connorsactuarial

^ permalink raw reply

* Re: [PATCH] branch as a builtin (again)
From: Johannes Schindelin @ 2006-08-21 21:25 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: git
In-Reply-To: <59ad55d30608211337jabd515bra3566fbd0f7ba5a0@mail.gmail.com>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 928 bytes --]

Hi,

On Mon, 21 Aug 2006, Kristian Høgsberg wrote:

> On 8/21/06, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> > Hi,
> > 
> > On Mon, 21 Aug 2006, Kristian Høgsberg wrote:
> > 
> > > Thanks to all who reviewed the patch, here's an updated version which
> > > should address all issues.
> > 
> > I would have preferred the use of path_list instead of rolling your own
> > thing with qsort(), but oh well.
> 
> Yeah, I saw that, but since I got flack for computing
> lookup_commit_reference(head_sha1) inside the delete_branches loop, I
> couldn't possibly risk the performance bottle neck of listing the
> branches using a O(n^2) insertion sort.

Insertion sort, as implemented in path_list, has an average O(n log(n)) 
runtime, and a worst-case O(n^2) runtime. Same as qsort...

Besides, it is not like we are dealing with millions of branches here. And 
using path_list _would_ make the code shorter.

Ciao,
Dscho

^ permalink raw reply

* git 1.4.2 RPMS for i386 on kernel.org
From: Jakub Narebski @ 2006-08-21 21:14 UTC (permalink / raw)
  To: git

Could anyone please generate RPMS for i386 architecture for git version
1.4.2 on kernel.org?
  http://www.kernel.org/pub/software/scm/git/RPMS/i386/

Thanks in advance
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* [PATCH 2/2] gitweb: Use parse_difftree_raw_line in git_difftree_body
From: Jakub Narebski @ 2006-08-21 21:08 UTC (permalink / raw)
  To: git
In-Reply-To: <200608212307.00712.jnareb@gmail.com>

Use newly introduced parse_difftree_raw_line function in the
git_difftree_body subroutine.  While at it correct error in
parse_difftree_raw_line (unquote is unprototyped function), and
add comment explaining this function.

It also refactors git_difftree_body somewhat, and tries to fit
it in 80 columns.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
These two patches probably could be collapsed into one commit.

 gitweb/gitweb.perl |  178 ++++++++++++++++++++++++++++------------------------
 1 files changed, 97 insertions(+), 81 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 824fc53..31a1824 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -918,6 +918,7 @@ sub parse_ref {
 	return %ref_item;
 }
 
+# parse line of git-diff-tree "raw" output
 sub parse_difftree_raw_line {
 	my $line = shift;
 	my %res;
@@ -932,7 +933,7 @@ sub parse_difftree_raw_line {
 		$res{'status'} = $5;
 		$res{'similarity'} = $6;
 		if ($res{'status'} eq 'R' || $res{'status'} eq 'C') { # renamed or copied
-			($res{'from_file'}, $res{'to_file'}) = map(unquote, split("\t", $7));
+			($res{'from_file'}, $res{'to_file'}) = map { unquote($_) } split("\t", $7);
 		} else {
 			$res{'file'} = unquote($7);
 		}
@@ -1355,18 +1356,7 @@ sub git_difftree_body {
 	print "<table class=\"diff_tree\">\n";
 	my $alternate = 0;
 	foreach my $line (@{$difftree}) {
-		# ':100644 100644 03b218260e99b78c6df0ed378e59ed9205ccc96d 3b93d5e7cc7f7dd4ebed13a5cc1a4ad976fc94d8 M	ls-files.c'
-		# ':100644 100644 7f9281985086971d3877aca27704f2aaf9c448ce bc190ebc71bbd923f2b728e505408f5e54bd073a M	rev-tree.c'
-		if ($line !~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/) {
-			next;
-		}
-		my $from_mode = $1;
-		my $to_mode = $2;
-		my $from_id = $3;
-		my $to_id = $4;
-		my $status = $5;
-		my $similarity = $6; # score
-		my $file = validate_input(unquote($7));
+		my %diff = parse_difftree_raw_line($line);
 
 		if ($alternate) {
 			print "<tr class=\"dark\">\n";
@@ -1375,105 +1365,131 @@ sub git_difftree_body {
 		}
 		$alternate ^= 1;
 
-		if ($status eq "A") { # created
-			my $mode_chng = "";
-			if (S_ISREG(oct $to_mode)) {
-				$mode_chng = sprintf(" with mode: %04o", (oct $to_mode) & 0777);
+		my ($to_mode_oct, $to_mode_str, $to_file_type);
+		my ($from_mode_oct, $from_mode_str, $from_file_type);
+		if ($diff{'to_mode'} ne ('0' x 6)) {
+			$to_mode_oct = oct $diff{'to_mode'};
+			if (S_ISREG($to_mode_oct)) { # only for regular file
+				$to_mode_str = sprintf("%04o", $to_mode_oct & 0777); # permission bits
 			}
+			$to_file_type = file_type($diff{'to_mode'});
+		}
+		if ($diff{'from_mode'} ne ('0' x 6)) {
+			$from_mode_oct = oct $diff{'from_mode'};
+			if (S_ISREG($to_mode_oct)) { # only for regular file
+				$from_mode_str = sprintf("%04o", $from_mode_oct & 0777); # permission bits
+			}
+			$from_file_type = file_type($diff{'from_mode'});
+		}
+
+		if ($diff{'status'} eq "A") { # created
+			my $mode_chng = "<span class=\"file_status new\">[new $to_file_type";
+			$mode_chng   .= " with mode: $to_mode_str" if $to_mode_str;
+			$mode_chng   .= "]</span>";
 			print "<td>" .
-			      $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file),
-			              -class => "list"}, esc_html($file)) .
+			      $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
+			                             hash_base=>$hash, file_name=>$diff{'file'}),
+			              -class => "list"}, esc_html($diff{'file'})) .
 			      "</td>\n" .
-			      "<td><span class=\"file_status new\">[new " . file_type($to_mode) . "$mode_chng]</span></td>\n" .
+			      "<td>$mode_chng</td>\n" .
 			      "<td class=\"link\">" .
-			      $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, "blob") .
+			      $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
+			                             hash_base=>$hash, file_name=>$diff{'file'})},
+			              "blob") .
 			      "</td>\n";
 
-		} elsif ($status eq "D") { # deleted
+		} elsif ($diff{'status'} eq "D") { # deleted
+			my $mode_chng = "<span class=\"file_status deleted\">[deleted $from_file_type]</span>";
 			print "<td>" .
-			      $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$file),
-			               -class => "list"}, esc_html($file)) . "</td>\n" .
-			      "<td><span class=\"file_status deleted\">[deleted " . file_type($from_mode). "]</span></td>\n" .
+			      $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'},
+			                             hash_base=>$parent, file_name=>$diff{'file'}),
+			               -class => "list"}, esc_html($diff{'file'})) .
+			      "</td>\n" .
+			      "<td>$mode_chng</td>\n" .
 			      "<td class=\"link\">" .
-			      $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$file)}, "blob") . " | " .
-			      $cgi->a({-href => href(action=>"history", hash_base=>$parent, file_name=>$file)}, "history") .
-			      "</td>\n"
+			      $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'},
+			                             hash_base=>$parent, file_name=>$diff{'file'})},
+			              "blob") .
+			      " | " .
+			      $cgi->a({-href => href(action=>"history", hash_base=>$parent,
+			                             file_name=>$diff{'file'})},\
+			              "history") .
+			      "</td>\n";
 
-		} elsif ($status eq "M" || $status eq "T") { # modified, or type changed
+		} elsif ($diff{'status'} eq "M" || $diff{'status'} eq "T") { # modified, or type changed
 			my $mode_chnge = "";
-			if ($from_mode != $to_mode) {
-				$mode_chnge = " <span class=\"file_status mode_chnge\">[changed";
-				if (((oct $from_mode) & S_IFMT) != ((oct $to_mode) & S_IFMT)) {
-					$mode_chnge .= " from " . file_type($from_mode) . " to " . file_type($to_mode);
+			if ($diff{'from_mode'} != $diff{'to_mode'}) {
+				$mode_chnge = "<span class=\"file_status mode_chnge\">[changed";
+				if ($from_file_type != $to_file_type) {
+					$mode_chnge .= " from $from_file_type to $to_file_type";
 				}
-				if (((oct $from_mode) & 0777) != ((oct $to_mode) & 0777)) {
-					if (S_ISREG($from_mode) && S_ISREG($to_mode)) {
-						$mode_chnge .= sprintf(" mode: %04o->%04o", (oct $from_mode) & 0777, (oct $to_mode) & 0777);
-					} elsif (S_ISREG($to_mode)) {
-						$mode_chnge .= sprintf(" mode: %04o", (oct $to_mode) & 0777);
+				if (($from_mode_oct & 0777) != ($to_mode_oct & 0777)) {
+					if ($from_mode_str && $to_mode_str) {
+						$mode_chnge .= " mode: $from_mode_str->$to_mode_str";
+					} elsif ($to_mode_str) {
+						$mode_chnge .= " mode: $to_mode_str";
 					}
 				}
 				$mode_chnge .= "]</span>\n";
 			}
 			print "<td>";
-			if ($to_id ne $from_id) { # modified
-				print $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$file),
-				              -class => "list"}, esc_html($file));
-			} else { # mode changed
-				print $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file),
-				              -class => "list"}, esc_html($file));
+			if ($diff{'to_id'} ne $diff{'from_id'}) { # modified
+				print $cgi->a({-href => href(action=>"blobdiff", hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
+				                             hash_base=>$hash, file_name=>$diff{'file'}),
+				              -class => "list"}, esc_html($diff{'file'}));
+			} else { # only mode changed
+				print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
+				                             hash_base=>$hash, file_name=>$diff{'file'}),
+				              -class => "list"}, esc_html($diff{'file'}));
 			}
 			print "</td>\n" .
 			      "<td>$mode_chnge</td>\n" .
 			      "<td class=\"link\">" .
-				$cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, "blob");
-			if ($to_id ne $from_id) { # modified
-				print " | " . $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$file)}, "diff");
-			}
-			print " | " . $cgi->a({-href => href(action=>"history", hash_base=>$hash, file_name=>$file)}, "history") . "\n";
-			print "</td>\n";
-
-		} elsif ($status eq "R") { # renamed
-			my ($from_file, $to_file) = split "\t", $file;
-			my $mode_chng = "";
-			if ($from_mode != $to_mode) {
-				$mode_chng = sprintf(", mode: %04o", (oct $to_mode) & 0777);
-			}
-			print "<td>" .
-			      $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file),
-			              -class => "list"}, esc_html($to_file)) . "</td>\n" .
-			      "<td><span class=\"file_status moved\">[moved from " .
-			      $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$from_file),
-			              -class => "list"}, esc_html($from_file)) .
-			      " with " . (int $similarity) . "% similarity$mode_chng]</span></td>\n" .
-			      "<td class=\"link\">" .
-			      $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file)}, "blob");
-			if ($to_id ne $from_id) {
+				$cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
+				                       hash_base=>$hash, file_name=>$diff{'file'})},
+				        "blob");
+			if ($diff{'to_id'} ne $diff{'from_id'}) { # modified
 				print " | " .
-				      $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$to_file, file_parent=>$from_file)}, "diff");
+					$cgi->a({-href => href(action=>"blobdiff", hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
+					                       hash_base=>$hash, file_name=>$diff{'file'})},
+					        "diff");
 			}
+			print " | " .
+				$cgi->a({-href => href(action=>"history",
+				                       hash_base=>$hash, file_name=>$diff{'file'})},
+				        "history");
 			print "</td>\n";
 
-		} elsif ($status eq "C") { # copied
-			my ($from_file, $to_file) = split "\t", $file;
+		} elsif ($diff{'status'} eq "R" || $diff{'status'} eq "C") { # renamed or copied
+			my %status_name = ('R' => 'moved', 'C' => 'copied');
+			my $nstatus = $status_name{$diff{'status'}};
 			my $mode_chng = "";
-			if ($from_mode != $to_mode) {
-				$mode_chng = sprintf(", mode: %04o", (oct $to_mode) & 0777);
+			if ($diff{'from_mode'} != $diff{'to_mode'}) {
+				# mode also for directories, so we cannot use $to_mode_str
+				$mode_chng = sprintf(", mode: %04o", $to_mode_oct & 0777);
 			}
 			print "<td>" .
-			      $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file),
-			              -class => "list"}, esc_html($to_file)) . "</td>\n" .
-			      "<td><span class=\"file_status copied\">[copied from " .
-			      $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$from_file),
-			              -class => "list"}, esc_html($from_file)) .
-			      " with " . (int $similarity) . "% similarity$mode_chng]</span></td>\n" .
+			      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
+			                             hash=>$diff{'to_id'}, file_name=>$diff{'to_file'}),
+			              -class => "list"}, esc_html($diff{'to_file'})) . "</td>\n" .
+			      "<td><span class=\"file_status $nstatus\">[$nstatus from " .
+			      $cgi->a({-href => href(action=>"blob", hash_base=>$parent,
+			                             hash=>$diff{'from_id'}, file_name=>$diff{'from_file'}),
+			              -class => "list"}, esc_html($diff{'from_file'})) .
+			      " with " . (int $diff{'similarity'}) . "% similarity$mode_chng]</span></td>\n" .
 			      "<td class=\"link\">" .
-			      $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file)}, "blob");
-			if ($to_id ne $from_id) {
+			      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
+			                             hash=>$diff{'to_id'}, file_name=>$diff{'to_file'})},
+			              "blob");
+			if ($diff{'to_id'} ne $diff{'from_id'}) {
 				print " | " .
-				      $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$to_file, file_parent=>$from_file)}, "diff");
+					$cgi->a({-href => href(action=>"blobdiff", hash_base=>$hash,
+					                       hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
+					                       file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})},
+					        "diff");
 			}
 			print "</td>\n";
+
 		} # we should not encounter Unmerged (U) or Unknown (X) status
 		print "</tr>\n";
 	}
-- 
1.4.1.1

^ permalink raw reply related

* [PATCH 1/2] gitweb: Added parse_difftree_raw_line function for later use
From: Jakub Narebski @ 2006-08-21 21:07 UTC (permalink / raw)
  To: git

Adds parse_difftree_raw_line function which parses one line of "raw"
format diff-tree output into a hash.

For later use in git_difftree_body, git_commitdiff and
git_commitdiff_plain, git_search.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Based on 'next' branch, commit v1.4.2-gfec6879

>From the four functions which parse git-diff-tree raw format, 
git_commitdiff and git_commitdiff_plain are to be rewriten to
use patch (or patch + raw) format of git-diff-tree, and
git_search is to be split into git_search_commit and 
git_search_pickaxe.

Patch introducing parse_difftree_raw_line to git_difftree_body
is next.

 gitweb/gitweb.perl |   27 +++++++++++++++++++++++++++
 1 files changed, 27 insertions(+), 0 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 063735d..824fc53 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -918,6 +918,33 @@ sub parse_ref {
 	return %ref_item;
 }
 
+sub parse_difftree_raw_line {
+	my $line = shift;
+	my %res;
+
+	# ':100644 100644 03b218260e99b78c6df0ed378e59ed9205ccc96d 3b93d5e7cc7f7dd4ebed13a5cc1a4ad976fc94d8 M	ls-files.c'
+	# ':100644 100644 7f9281985086971d3877aca27704f2aaf9c448ce bc190ebc71bbd923f2b728e505408f5e54bd073a M	rev-tree.c'
+	if ($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/) {
+		$res{'from_mode'} = $1;
+		$res{'to_mode'} = $2;
+		$res{'from_id'} = $3;
+		$res{'to_id'} = $4;
+		$res{'status'} = $5;
+		$res{'similarity'} = $6;
+		if ($res{'status'} eq 'R' || $res{'status'} eq 'C') { # renamed or copied
+			($res{'from_file'}, $res{'to_file'}) = map(unquote, split("\t", $7));
+		} else {
+			$res{'file'} = unquote($7);
+		}
+	}
+	# 'c512b523472485aef4fff9e57b229d9d243c967f'
+	#elsif ($line =~ m/^([0-9a-fA-F]{40})$/) {
+	#	$res{'commit'} = $1;
+	#}
+
+	return wantarray ? %res : \%res;
+}
+
 ## ......................................................................
 ## parse to array of hashes functions
 
-- 
1.4.1.1

^ permalink raw reply related

* Re: [PATCH] branch as a builtin (again)
From: Kristian Høgsberg @ 2006-08-21 21:07 UTC (permalink / raw)
  To: git
In-Reply-To: <Pine.LNX.4.63.0608212227040.28360@wbgn013.biozentrum.uni-wuerzburg.de>

On 8/21/06, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> Hi,
>
> On Mon, 21 Aug 2006, Kristian Hxgsberg wrote:
>
> > Thanks to all who reviewed the patch, here's an updated version which
> > should address all issues.
>
> I would have preferred the use of path_list instead of rolling your own
> thing with qsort(), but oh well.

Yeah, I saw that, but since I got flack for computing
lookup_commit_reference(head_sha1) inside the delete_branches loop, I
couldn't possibly risk the performance bottle neck of listing the
branches using a O(n^2) insertion sort.

Kristian

^ permalink raw reply

* Re: use case
From: Johannes Schindelin @ 2006-08-21 20:47 UTC (permalink / raw)
  To: Blu Corater; +Cc: git
In-Reply-To: <20060821182338.GA21395@daga.cl>

Hi,

On Mon, 21 Aug 2006, Blu Corater wrote:

> The main problem I am facing now is that I have been unable to make an
> octopus merge from all the branches to consolidate them. When I do a
> "git-pull . branch1 branch2..." git tells me "Unable to find common commit
> with 5f83..." where 5f83... is the sha1 of the head commit of the first
> branch on the command line.

Ideally, you really would have a common revision to start from. Since you 
do not have that yet, you have to go low-level for the first octopus.

Suppose you have the last common version as tip of branch "ancestor", you 
could do

	git merge-octopus ancestor -- HEAD branch1 branch2 ...

After this -- if everything went well -- you should have a committable 
state in the index. Before you commit, you should do

	git rev-parse branch1 > .git/MERGE_HEAD
	git rev-parse branch2 >> .git/MERGE_HEAD
	git rev-parse branch3 >> .git/MERGE_HEAD
	...

to tell git that you want to commit an octopus merge. This will tell 
git-commit what the parents of the merge are.

The next time you do an octopus, you _will_ have a common ancestor, so no 
need to jump through hoops after the first octopus.

Hth,
Dscho

^ permalink raw reply

* Re: [PATCH] branch as a builtin (again)
From: Kristian Høgsberg @ 2006-08-21 20:45 UTC (permalink / raw)
  To: David Rientjes; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0608211319180.8662@chino.corp.google.com>

[-- Attachment #1: Type: text/plain, Size: 241 bytes --]

Ok, once more without the spaces.  I have to state that it's against
my personal beliefs using pointers as boolean values, but I can go
with the flow here.  For extra bonus, I'm using xrealloc instead of
plain realloc now.

cheers,
Kristian

[-- Attachment #2: builtin-branch.c --]
[-- Type: application/octet-stream, Size: 5250 bytes --]

/*
 * Builtin "git branch"
 *
 * Copyright (c) 2006 Kristian Høgsberg <krh@redhat.com>
 * Based on git-branch.sh by Junio C Hamano.
 */

#include "cache.h"
#include "refs.h"
#include "commit.h"
#include "builtin.h"

static const char builtin_branch_usage[] =
"git-branch [(-d | -D) <branchname>] | [[-f] <branchname> [<start-point>]] | -r";


static const char *head;
static unsigned char head_sha1[20];

static int in_merge_bases(const unsigned char *sha1,
			  struct commit *rev1,
			  struct commit *rev2)
{
	struct commit_list *bases, *b;
	int ret = 0;

	bases = get_merge_bases(rev1, rev2, 1);
	for (b = bases; b; b = b->next) {
		if (!hashcmp(sha1, b->item->object.sha1)) {
			ret = 1;
			break;
		}
	}

	free_commit_list(bases);
	return ret;
}

static void delete_branches(int argc, const char **argv, int force)
{
	struct commit *rev, *head_rev;
	unsigned char sha1[20];
	const char *name, *reflog;
	int i;

	head_rev = lookup_commit_reference(head_sha1);
	for (i = 0; i < argc; i++) {
		if (!strcmp(head, argv[i]))
			die("Cannot delete the branch you are currently on.");

		name = git_path("refs/heads/%s", argv[i]);
		if (!resolve_ref(name, sha1, 1))
			die("Branch '%s' not found.", argv[i]);

		rev = lookup_commit_reference(sha1);
		if (!rev || !head_rev)
			die("Couldn't look up commit objects.");

		/* This checks whether the merge bases of branch and
		 * HEAD contains branch -- which means that the HEAD
		 * contains everything in both.
		 */

		if (!force &&
		    !in_merge_bases(sha1, rev, head_rev)) {
			fprintf(stderr,
				"The branch '%s' is not a strict subset of your current HEAD.\n"
				"If you are sure you want to delete it, run 'git branch -D %s'.\n",
				argv[i], argv[i]);
			exit(1);
		}

		unlink(name);

		/* Unlink reflog if it exists. */
		reflog = git_path("logs/refs/heads/%s", argv[i]);
		unlink(reflog);

		printf("Deleted branch %s.\n", argv[i]);
	}
}

static int ref_index, ref_alloc;
static char **ref_list;

static int append_ref(const char *refname, const unsigned char *sha1)
{
	if (ref_index >= ref_alloc) {
		ref_alloc = ref_alloc > 0 ? ref_alloc * 2 : 16;
		ref_list = xrealloc(ref_list, ref_alloc * sizeof(char *));
	}

	ref_list[ref_index++] = strdup(refname);

	return 0;
}

static int ref_cmp(const void *r1, const void *r2)
{
	return strcmp(*(char **)r1, *(char **)r2);
}

static void print_ref_list(int remote_only)
{
	int i;

	if (remote_only)
		for_each_remote_ref(append_ref);
	else
		for_each_branch_ref(append_ref);

	qsort(ref_list, ref_index, sizeof(char *), ref_cmp);

	for (i = 0; i < ref_index; i++) {
		if (!strcmp(ref_list[i], head))
			printf("* %s\n", ref_list[i]);
		else
			printf("  %s\n", ref_list[i]);
	}
}

static void create_reflog(struct ref_lock *lock)
{
	struct stat stbuf;
	int fd;

	if (!stat(lock->log_file, &stbuf) && S_ISREG(stbuf.st_mode))
		return;
	if (safe_create_leading_directories(lock->log_file) < 0)
		die("Unable to create directory for %s.", lock->log_file);
	fd = open(lock->log_file, O_CREAT | O_TRUNC | O_WRONLY, 0666);
	if (fd < 0)
		die("Unable to create ref log %s: %s.",
		    lock->log_file, strerror(errno));
	close(fd);
}

static void create_branch(const char *name, const char *start,
			  int force, int reflog)
{
	struct ref_lock *lock;
	unsigned char sha1[20];
	char ref[PATH_MAX], msg[PATH_MAX + 20];

	snprintf(ref, sizeof ref, "refs/heads/%s", name);
	if (check_ref_format(ref))
		die("'%s' is not a valid branch name.", name);

	if (resolve_ref(git_path(ref), sha1, 1)) {
		if (!force)
			die("A branch named '%s' already exists.", name);
		else if (!strcmp(head, name))
			die("Cannot force update the current branch.");
	}

	if (get_sha1(start, sha1))
		die("Not a valid branch point: '%s'.", start);

	lock = lock_any_ref_for_update(ref, NULL, 0);
	if (!lock)
		die("Failed to lock ref for update: %s.", strerror(errno));
	if (reflog)
		create_reflog(lock);
	snprintf(msg, sizeof msg, "branch: Created from %s", start);
	if (write_ref_sha1(lock, sha1, msg) < 0)
		die("Failed to write ref: %s.", strerror(errno));
}

int cmd_branch(int argc, const char **argv, const char *prefix)
{
	int delete = 0, force_delete = 0, force_create = 0, remote_only = 0;
	int reflog = 0;
	int i, prefix_length;
	const char *p;

	git_config(git_default_config);

	for (i = 1; i < argc; i++) {
		const char *arg = argv[i];

		if (arg[0] != '-')
			break;
		if (!strcmp(arg, "--")) {
			i++;
			break;
		}
		if (!strcmp(arg, "-d")) {
			delete = 1;
			continue;
		}
		if (!strcmp(arg, "-D")) {
			delete = 1;
			force_delete = 1;
			continue;
		}
		if (!strcmp(arg, "-f")) {
			force_create = 1;
			continue;
		}
		if (!strcmp(arg, "-r")) {
			remote_only = 1;
			continue;
		}
		if (!strcmp(arg, "-l")) {
			reflog = 1;
			continue;
		}
		usage(builtin_branch_usage);
	}

	prefix_length = strlen(git_path("refs/heads/"));
	p = resolve_ref(git_path("HEAD"), head_sha1, 0);
	if (!p)
		die("Failed to resolve HEAD as a valid ref.");
	head = strdup(p + prefix_length);

	if (delete)
		delete_branches(argc - i, argv + i, force_delete);
	else if (i == argc)
		print_ref_list(remote_only);
	else if (argc - i == 1)
		create_branch(argv[i], head, force_create, reflog);
	else
		create_branch(argv[i], argv[i + 1], force_create, reflog);

	return 0;
}

^ permalink raw reply

* Re: [RFC] adding support for md5
From: Chris Wedgwood @ 2006-08-21 20:44 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: David Rientjes, git
In-Reply-To: <Pine.LNX.4.64.0608191339010.11811@g5.osdl.org>

On Sat, Aug 19, 2006 at 01:50:32PM -0700, Linus Torvalds wrote:

> I can see the point of configurable hashes, but it would be for a
> stronger hash than sha1, not for a (much) weaker one.

Why any configuration option at all?  What in practice does it really
buy?

If someone (eventually) wants to do something malicious (which right
now requires some effort and would probably not go undetected) there
are probably easier ways to achieve this (like posting a patch with a
non-obvious subtle side-effect).

^ permalink raw reply

* Re: [PATCH] branch as a builtin (again)
From: Shawn Pearce @ 2006-08-21 20:41 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: Jonas Fonseca, git
In-Reply-To: <59ad55d30608211312u51a4657eyd52311314a6ee03c@mail.gmail.com>

Kristian H?gsberg <krh@bitplanet.net> wrote:
> +static void delete_branches(int argc, const char **argv, int force)
[snip]
> +		name = git_path("refs/heads/%s", argv[i]);
> +		if (!resolve_ref(name, sha1, 1))
> +			die("Branch '%s' not found.", argv[i]);
[snip]
> +		unlink(name);
> +
> +		/* Unlink reflog if it exists. */
> +		reflog = git_path("logs/refs/heads/%s", argv[i]);
> +		unlink(reflog);

Hmm.  So git-branch.sh doesn't deal with symrefs, eh?  I guess this
is OK but I'm wondering why not put this code into refs.c to lock
the ref (refs.c:lock_ref_sha1) then instead of unlocking it delete
it and its log (add new function to do this).

The downside of this is that we'll chase a symref, which means that
if refs/heads/FOO is a symref to refs/heads/master and the user calls
`git-branch -D FOO` we'll kill refs/heads/master.  Maybe that's not
what the the user would want to have happen.  :-)

> +static void create_reflog(struct ref_lock *lock)
> +{
> +	struct stat stbuf;
> +	int fd;
> +
> +	if (!stat(lock->log_file, &stbuf) && S_ISREG(stbuf.st_mode))
> +		return;
> +	if (safe_create_leading_directories(lock->log_file) < 0)
> +		die("Unable to create directory for %s.", lock->log_file);
> +	fd = open(lock->log_file, O_CREAT | O_TRUNC | O_WRONLY, 0666);
> +	if (fd < 0)
> +		die("Unable to create ref log %s: %s.",
> +		    lock->log_file, strerror(errno));
> +	close(fd);
> +}

This probably should move into refs.c.  Look at log_ref_write,
specifically around the if (log_all_ref_updates).  If this took
an additional parameter to force creation of the log even if the log
isn't present and OR'd against log_all_ref_updates then it would
be possible to have the refs.c code create the log for you in the
"library" part of GIT.

Or maybe it is better to add this as a flag to the struct ref_lock,
defaulting to false and letting the caller set it to true before
invoking write_ref_sha1.  I only suggest this because of the number
of parameters already in play here.

> +static void create_branch(const char *name, const char *start,
> +			  int force, int reflog)

This all looked correct to me, at least as far as dealing with
the reflog.  :-)

^ permalink raw reply

* Re: [PATCH] branch as a builtin (again)
From: Johannes Schindelin @ 2006-08-21 20:27 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: git
In-Reply-To: <59ad55d30608211312u51a4657eyd52311314a6ee03c@mail.gmail.com>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 297 bytes --]

Hi,

On Mon, 21 Aug 2006, Kristian Høgsberg wrote:

> Thanks to all who reviewed the patch, here's an updated version which
> should address all issues.

I would have preferred the use of path_list instead of rolling your own 
thing with qsort(), but oh well.

Rest looks fine to me.

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] branch as a builtin (again)
From: David Rientjes @ 2006-08-21 20:23 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: Jonas Fonseca, Shawn Pearce, git
In-Reply-To: <59ad55d30608211312u51a4657eyd52311314a6ee03c@mail.gmail.com>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 6228 bytes --]

On Mon, 21 Aug 2006, Kristian Høgsberg wrote:

> diff --git a/builtin-branch.c b/builtin-branch.c
> new file mode 100644
> index 0000000..4e8fa7d
> --- /dev/null
> +++ b/builtin-branch.c
> @@ -0,0 +1,227 @@
> +/*
> + * Builtin "git branch"
> + *
> + * Copyright (c) 2006 Kristian Høgsberg <krh@redhat.com>
> + * Based on git-branch.sh by Junio C Hamano.
> + */
> +
> +#include "cache.h"
> +#include "refs.h"
> +#include "commit.h"
> +#include "builtin.h"
> +
> +static const char builtin_branch_usage[] =
> +"git-branch [(-d | -D) <branchname>] | [[-f] <branchname> [<start-point>]] | -r";
> +
> +
> +static const char *head;
> +static unsigned char head_sha1[20];
> +
> +static int in_merge_bases(const unsigned char *sha1,
> +			  struct commit *rev1,
> +			  struct commit *rev2)
> +{
> +	struct commit_list *bases, *b;
> +	int ret = 0;
> +
> +	bases = get_merge_bases(rev1, rev2, 1);
> +	for (b = bases; b != NULL; b = b->next) {

for (b = bases; b; b = b->next) {

> +		if (!hashcmp(sha1, b->item->object.sha1)) {
> +			ret = 1;
> +			break;
> +		}
> +	}
> +
> +	free_commit_list(bases);
> +	return ret;
> +}
> +
> +static void delete_branches(int argc, const char **argv, int force)
> +{
> +	struct commit *rev, *head_rev;
> +	unsigned char sha1[20];
> +	const char *name, *reflog;
> +	int i;
> +
> +	head_rev = lookup_commit_reference(head_sha1);
> +	for (i = 0; i < argc; i++) {
> +		if (!strcmp(head, argv[i]))
> +			die("Cannot delete the branch you are currently on.");
> +
> +		name = git_path("refs/heads/%s", argv[i]);
> +		if (!resolve_ref(name, sha1, 1))
> +			die("Branch '%s' not found.", argv[i]);
> +
> +		rev = lookup_commit_reference(sha1);
> +		if (!rev || !head_rev)
> +			die("Couldn't look up commit objects.");
> +
> +		/* This checks whether the merge bases of branch and
> +		 * HEAD contains branch -- which means that the HEAD
> +		 * contains everything in both.
> +		 */
> +
> +		if (!force &&
> +		    !in_merge_bases(sha1, rev, head_rev)) {
> +			fprintf(stderr,
> +				"The branch '%s' is not a strict subset of your current HEAD.\n"
> +				"If you are sure you want to delete it, run 'git branch -D %s'.\n",
> +				argv[i], argv[i]);
> +			exit(1);
> +		}
> +
> +		unlink(name);
> +
> +		/* Unlink reflog if it exists. */
> +		reflog = git_path("logs/refs/heads/%s", argv[i]);
> +		unlink(reflog);
> +
> +		printf("Deleted branch %s.\n", argv[i]);
> +	}
> +}
> +
> +static int ref_index, ref_alloc;
> +static char **ref_list;
> +
> +static int append_ref(const char *refname, const unsigned char *sha1)
> +{
> +	if (ref_index >= ref_alloc) {
> +		ref_alloc = ref_alloc > 0 ? ref_alloc * 2 : 16;
> +		ref_list = realloc(ref_list, ref_alloc * sizeof (char *));

No space

> +	}
> +
> +	ref_list[ref_index++] = strdup(refname);
> +
> +	return 0;
> +}
> +
> +static int ref_cmp (const void *r1, const void *r2)

No space

> +{
> +	return strcmp (*(char **)r1, *(char **)r2);

No space

> +}
> +
> +static void print_ref_list(int remote_only)
> +{
> +	int i;
> +
> +	if (remote_only)
> +		for_each_remote_ref(append_ref);
> +	else
> +		for_each_branch_ref(append_ref);
> +
> +	qsort(ref_list, ref_index, sizeof (char *), ref_cmp);
> +

No space

> +	for (i = 0; i < ref_index; i++) {
> +		if (!strcmp(ref_list[i], head))
> +			printf("* %s\n", ref_list[i]);
> +		else
> +			printf("  %s\n", ref_list[i]);
> +	}
> +}
> +
> +static void create_reflog(struct ref_lock *lock)
> +{
> +	struct stat stbuf;
> +	int fd;
> +
> +	if (!stat(lock->log_file, &stbuf) && S_ISREG(stbuf.st_mode))
> +		return;
> +	if (safe_create_leading_directories(lock->log_file) < 0)
> +		die("Unable to create directory for %s.", lock->log_file);
> +	fd = open(lock->log_file, O_CREAT | O_TRUNC | O_WRONLY, 0666);
> +	if (fd < 0)
> +		die("Unable to create ref log %s: %s.",
> +		    lock->log_file, strerror(errno));
> +	close(fd);
> +}
> +
> +static void create_branch(const char *name, const char *start,
> +			  int force, int reflog)
> +{
> +	struct ref_lock *lock;
> +	unsigned char sha1[20];
> +	char ref[PATH_MAX], msg[PATH_MAX + 20];
> +
> +	snprintf(ref, sizeof ref, "refs/heads/%s", name);
> +	if (check_ref_format(ref))
> +		die("'%s' is not a valid branch name.", name);
> +
> +	if (resolve_ref(git_path(ref), sha1, 1)) {
> +		if (!force)
> +			die("A branch named '%s' already exists.", name);
> +		else if (!strcmp(head, name))
> +			die("Cannot force update the current branch.");
> +	}
> +
> +	if (get_sha1(start, sha1))
> +		die("Not a valid branch point: '%s'.", start);
> +
> +	lock = lock_any_ref_for_update(ref, NULL, 0);
> +	if (!lock)
> +		die("Failed to lock ref for update: %s.", strerror(errno));
> +	if (reflog)
> +		create_reflog(lock);
> +	snprintf(msg, sizeof msg, "branch: Created from %s", start);
> +	if (write_ref_sha1(lock, sha1, msg) < 0)
> +		die("Failed to write ref: %s.", strerror(errno));
> +}
> +
> +int cmd_branch(int argc, const char **argv, const char *prefix)
> +{
> +	int delete = 0, force_delete = 0, force_create = 0, remote_only = 0;
> +	int reflog = 0;
> +	int i, prefix_length;
> +	const char *p;
> +
> +	git_config(git_default_config);
> +
> +	for (i = 1; i < argc; i++) {
> +		const char *arg = argv[i];
> +
> +		if (arg[0] != '-')
> +			break;
> +		if (!strcmp(arg, "--")) {
> +			i++;
> +			break;
> +		}
> +		if (!strcmp(arg, "-d")) {
> +			delete = 1;
> +			continue;
> +		}
> +		if (!strcmp(arg, "-D")) {
> +			delete = 1;
> +			force_delete = 1;
> +			continue;
> +		}
> +		if (!strcmp(arg, "-f")) {
> +			force_create = 1;
> +			continue;
> +		}
> +		if (!strcmp(arg, "-r")) {
> +			remote_only = 1;
> +			continue;
> +		}
> +		if (!strcmp(arg, "-l")) {
> +			reflog = 1;
> +			continue;
> +		}
> +		usage(builtin_branch_usage);
> +	}
> +
> +	prefix_length = strlen(git_path("refs/heads/"));
> +	p = resolve_ref(git_path("HEAD"), head_sha1, 0);
> +	if (!p)
> +		die("Failed to resolve HEAD as a valid ref.");
> +	head = strdup(p + prefix_length);
> +
> +	if (delete)
> +		delete_branches(argc - i, argv + i, force_delete);
> +	else if (i == argc)
> +		print_ref_list(remote_only);
> +	else if (argc - i == 1)
> +		create_branch(argv[i], head, force_create, reflog);
> +	else
> +		create_branch(argv[i], argv[i + 1], force_create, reflog);
> +
> +	return 0;
> +}

^ permalink raw reply

* [PATCH] git-mv: fix off-by-one error
From: Johannes Schindelin @ 2006-08-21 20:22 UTC (permalink / raw)
  To: git, junkio


Embarassing.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---

	This bug made t7001-mv.sh fail with the patch in
	http://article.gmane.org/gmane.comp.version-control.git/25647
	when XMALLOC_POISON was set, which was probably the reason it
	was not yet applied...

 builtin-mv.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/builtin-mv.c b/builtin-mv.c
index 6e7062b..ff882be 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -26,7 +26,7 @@ static const char **copy_pathspec(const 
 		if (length > 0 && result[i][length - 1] == '/') {
 			char *without_slash = xmalloc(length);
 			memcpy(without_slash, result[i], length - 1);
-			without_slash[length] = '\0';
+			without_slash[length - 1] = '\0';
 			result[i] = without_slash;
 		}
 		if (base_name) {
-- 
1.4.2.gc69d

^ permalink raw reply related

* Re: [PATCH] branch as a builtin (again)
From: Kristian Høgsberg @ 2006-08-21 20:12 UTC (permalink / raw)
  To: Jonas Fonseca, Shawn Pearce; +Cc: git
In-Reply-To: <20060821101346.GA527@diku.dk>

[-- Attachment #1: Type: text/plain, Size: 905 bytes --]

Thanks to all who reviewed the patch, here's an updated version which
should address all issues.  In particular, thanks to Jonas who spotted
the missing git_path() before resolve_ref() - this caused git branch
to always overwrite existing branches because it failed to resolve the
ref.

As for the missing reflog functionality - when I first did the shell
to C port, git branch didn't have this feature, and this time I just
updated the old patch which is how I forgot about the reflog option.
The new patch attached here should have the same reflog behavior as
the current shell script.  Shawn, could you check that it has the
correct sematics?  I wasn't sure whether git branch -f foo should
truncate the old log or just keep appending.  The shell script does a
'touch <logfile>' on creation, which means keep appending when
forcibly overwriting a branch ref, so I kept that behavior.

cheers,
Kristian

[-- Attachment #2: builtin-branch.patch --]
[-- Type: application/octet-stream, Size: 10364 bytes --]

commit d5d82b9c4493df467ee31776cadff808563f00b1
Author: Kristian Høgsberg <krh@redhat.com>
Date:   Sun Aug 20 17:04:14 2006 -0400

    Rewrite branch in C and make it a builtin.

diff --git a/Makefile b/Makefile
index 23cd8a0..adf043e 100644
--- a/Makefile
+++ b/Makefile
@@ -149,7 +149,7 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powe
 ### --- END CONFIGURATION SECTION ---
 
 SCRIPT_SH = \
-	git-bisect.sh git-branch.sh git-checkout.sh \
+	git-bisect.sh git-checkout.sh \
 	git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
 	git-fetch.sh \
 	git-ls-remote.sh \
@@ -253,6 +253,7 @@ LIB_OBJS = \
 BUILTIN_OBJS = \
 	builtin-add.o \
 	builtin-apply.o \
+	builtin-branch.o \
 	builtin-cat-file.o \
 	builtin-checkout-index.o \
 	builtin-check-ref-format.o \
diff --git a/builtin-branch.c b/builtin-branch.c
new file mode 100644
index 0000000..4e8fa7d
--- /dev/null
+++ b/builtin-branch.c
@@ -0,0 +1,227 @@
+/*
+ * Builtin "git branch"
+ *
+ * Copyright (c) 2006 Kristian Høgsberg <krh@redhat.com>
+ * Based on git-branch.sh by Junio C Hamano.
+ */
+
+#include "cache.h"
+#include "refs.h"
+#include "commit.h"
+#include "builtin.h"
+
+static const char builtin_branch_usage[] =
+"git-branch [(-d | -D) <branchname>] | [[-f] <branchname> [<start-point>]] | -r";
+
+
+static const char *head;
+static unsigned char head_sha1[20];
+
+static int in_merge_bases(const unsigned char *sha1,
+			  struct commit *rev1,
+			  struct commit *rev2)
+{
+	struct commit_list *bases, *b;
+	int ret = 0;
+
+	bases = get_merge_bases(rev1, rev2, 1);
+	for (b = bases; b != NULL; b = b->next) {
+		if (!hashcmp(sha1, b->item->object.sha1)) {
+			ret = 1;
+			break;
+		}
+	}
+
+	free_commit_list(bases);
+	return ret;
+}
+
+static void delete_branches(int argc, const char **argv, int force)
+{
+	struct commit *rev, *head_rev;
+	unsigned char sha1[20];
+	const char *name, *reflog;
+	int i;
+
+	head_rev = lookup_commit_reference(head_sha1);
+	for (i = 0; i < argc; i++) {
+		if (!strcmp(head, argv[i]))
+			die("Cannot delete the branch you are currently on.");
+
+		name = git_path("refs/heads/%s", argv[i]);
+		if (!resolve_ref(name, sha1, 1))
+			die("Branch '%s' not found.", argv[i]);
+
+		rev = lookup_commit_reference(sha1);
+		if (!rev || !head_rev)
+			die("Couldn't look up commit objects.");
+
+		/* This checks whether the merge bases of branch and
+		 * HEAD contains branch -- which means that the HEAD
+		 * contains everything in both.
+		 */
+
+		if (!force &&
+		    !in_merge_bases(sha1, rev, head_rev)) {
+			fprintf(stderr,
+				"The branch '%s' is not a strict subset of your current HEAD.\n"
+				"If you are sure you want to delete it, run 'git branch -D %s'.\n",
+				argv[i], argv[i]);
+			exit(1);
+		}
+
+		unlink(name);
+
+		/* Unlink reflog if it exists. */
+		reflog = git_path("logs/refs/heads/%s", argv[i]);
+		unlink(reflog);
+
+		printf("Deleted branch %s.\n", argv[i]);
+	}
+}
+
+static int ref_index, ref_alloc;
+static char **ref_list;
+
+static int append_ref(const char *refname, const unsigned char *sha1)
+{
+	if (ref_index >= ref_alloc) {
+		ref_alloc = ref_alloc > 0 ? ref_alloc * 2 : 16;
+		ref_list = realloc(ref_list, ref_alloc * sizeof (char *));
+	}
+
+	ref_list[ref_index++] = strdup(refname);
+
+	return 0;
+}
+
+static int ref_cmp (const void *r1, const void *r2)
+{
+	return strcmp (*(char **)r1, *(char **)r2);
+}
+
+static void print_ref_list(int remote_only)
+{
+	int i;
+
+	if (remote_only)
+		for_each_remote_ref(append_ref);
+	else
+		for_each_branch_ref(append_ref);
+
+	qsort(ref_list, ref_index, sizeof (char *), ref_cmp);
+
+	for (i = 0; i < ref_index; i++) {
+		if (!strcmp(ref_list[i], head))
+			printf("* %s\n", ref_list[i]);
+		else
+			printf("  %s\n", ref_list[i]);
+	}
+}
+
+static void create_reflog(struct ref_lock *lock)
+{
+	struct stat stbuf;
+	int fd;
+
+	if (!stat(lock->log_file, &stbuf) && S_ISREG(stbuf.st_mode))
+		return;
+	if (safe_create_leading_directories(lock->log_file) < 0)
+		die("Unable to create directory for %s.", lock->log_file);
+	fd = open(lock->log_file, O_CREAT | O_TRUNC | O_WRONLY, 0666);
+	if (fd < 0)
+		die("Unable to create ref log %s: %s.",
+		    lock->log_file, strerror(errno));
+	close(fd);
+}
+
+static void create_branch(const char *name, const char *start,
+			  int force, int reflog)
+{
+	struct ref_lock *lock;
+	unsigned char sha1[20];
+	char ref[PATH_MAX], msg[PATH_MAX + 20];
+
+	snprintf(ref, sizeof ref, "refs/heads/%s", name);
+	if (check_ref_format(ref))
+		die("'%s' is not a valid branch name.", name);
+
+	if (resolve_ref(git_path(ref), sha1, 1)) {
+		if (!force)
+			die("A branch named '%s' already exists.", name);
+		else if (!strcmp(head, name))
+			die("Cannot force update the current branch.");
+	}
+
+	if (get_sha1(start, sha1))
+		die("Not a valid branch point: '%s'.", start);
+
+	lock = lock_any_ref_for_update(ref, NULL, 0);
+	if (!lock)
+		die("Failed to lock ref for update: %s.", strerror(errno));
+	if (reflog)
+		create_reflog(lock);
+	snprintf(msg, sizeof msg, "branch: Created from %s", start);
+	if (write_ref_sha1(lock, sha1, msg) < 0)
+		die("Failed to write ref: %s.", strerror(errno));
+}
+
+int cmd_branch(int argc, const char **argv, const char *prefix)
+{
+	int delete = 0, force_delete = 0, force_create = 0, remote_only = 0;
+	int reflog = 0;
+	int i, prefix_length;
+	const char *p;
+
+	git_config(git_default_config);
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (arg[0] != '-')
+			break;
+		if (!strcmp(arg, "--")) {
+			i++;
+			break;
+		}
+		if (!strcmp(arg, "-d")) {
+			delete = 1;
+			continue;
+		}
+		if (!strcmp(arg, "-D")) {
+			delete = 1;
+			force_delete = 1;
+			continue;
+		}
+		if (!strcmp(arg, "-f")) {
+			force_create = 1;
+			continue;
+		}
+		if (!strcmp(arg, "-r")) {
+			remote_only = 1;
+			continue;
+		}
+		if (!strcmp(arg, "-l")) {
+			reflog = 1;
+			continue;
+		}
+		usage(builtin_branch_usage);
+	}
+
+	prefix_length = strlen(git_path("refs/heads/"));
+	p = resolve_ref(git_path("HEAD"), head_sha1, 0);
+	if (!p)
+		die("Failed to resolve HEAD as a valid ref.");
+	head = strdup(p + prefix_length);
+
+	if (delete)
+		delete_branches(argc - i, argv + i, force_delete);
+	else if (i == argc)
+		print_ref_list(remote_only);
+	else if (argc - i == 1)
+		create_branch(argv[i], head, force_create, reflog);
+	else
+		create_branch(argv[i], argv[i + 1], force_create, reflog);
+
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index ade58c4..eb28986 100644
--- a/builtin.h
+++ b/builtin.h
@@ -15,6 +15,7 @@ extern int write_tree(unsigned char *sha
 
 extern int cmd_add(int argc, const char **argv, const char *prefix);
 extern int cmd_apply(int argc, const char **argv, const char *prefix);
+extern int cmd_branch(int argc, const char **argv, const char *prefix);
 extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
 extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
 extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
diff --git a/git-branch.sh b/git-branch.sh
deleted file mode 100755
index e0501ec..0000000
--- a/git-branch.sh
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/bin/sh
-
-USAGE='[-l] [(-d | -D) <branchname>] | [[-f] <branchname> [<start-point>]] | -r'
-LONG_USAGE='If no arguments, show available branches and mark current branch with a star.
-If one argument, create a new branch <branchname> based off of current HEAD.
-If two arguments, create a new branch <branchname> based off of <start-point>.'
-
-SUBDIRECTORY_OK='Yes'
-. git-sh-setup
-
-headref=$(git-symbolic-ref HEAD | sed -e 's|^refs/heads/||')
-
-delete_branch () {
-    option="$1"
-    shift
-    for branch_name
-    do
-	case ",$headref," in
-	",$branch_name,")
-	    die "Cannot delete the branch you are on." ;;
-	,,)
-	    die "What branch are you on anyway?" ;;
-	esac
-	branch=$(cat "$GIT_DIR/refs/heads/$branch_name") &&
-	    branch=$(git-rev-parse --verify "$branch^0") ||
-		die "Seriously, what branch are you talking about?"
-	case "$option" in
-	-D)
-	    ;;
-	*)
-	    mbs=$(git-merge-base -a "$branch" HEAD | tr '\012' ' ')
-	    case " $mbs " in
-	    *' '$branch' '*)
-		# the merge base of branch and HEAD contains branch --
-		# which means that the HEAD contains everything in both.
-		;;
-	    *)
-		echo >&2 "The branch '$branch_name' is not a strict subset of your current HEAD.
-If you are sure you want to delete it, run 'git branch -D $branch_name'."
-		exit 1
-		;;
-	    esac
-	    ;;
-	esac
-	rm -f "$GIT_DIR/logs/refs/heads/$branch_name"
-	rm -f "$GIT_DIR/refs/heads/$branch_name"
-	echo "Deleted branch $branch_name."
-    done
-    exit 0
-}
-
-ls_remote_branches () {
-    git-rev-parse --symbolic --all |
-    sed -ne 's|^refs/\(remotes/\)|\1|p' |
-    sort
-}
-
-force=
-create_log=
-while case "$#,$1" in 0,*) break ;; *,-*) ;; *) break ;; esac
-do
-	case "$1" in
-	-d | -D)
-		delete_branch "$@"
-		exit
-		;;
-	-r)
-		ls_remote_branches
-		exit
-		;;
-	-f)
-		force="$1"
-		;;
-	-l)
-		create_log="yes"
-		;;
-	--)
-		shift
-		break
-		;;
-	-*)
-		usage
-		;;
-	esac
-	shift
-done
-
-case "$#" in
-0)
-	git-rev-parse --symbolic --branches |
-	sort |
-	while read ref
-	do
-		if test "$headref" = "$ref"
-		then
-			pfx='*'
-		else
-			pfx=' '
-		fi
-		echo "$pfx $ref"
-	done
-	exit 0 ;;
-1)
-	head=HEAD ;;
-2)
-	head="$2^0" ;;
-esac
-branchname="$1"
-
-rev=$(git-rev-parse --verify "$head") || exit
-
-git-check-ref-format "heads/$branchname" ||
-	die "we do not like '$branchname' as a branch name."
-
-if [ -e "$GIT_DIR/refs/heads/$branchname" ]
-then
-	if test '' = "$force"
-	then
-		die "$branchname already exists."
-	elif test "$branchname" = "$headref"
-	then
-		die "cannot force-update the current branch."
-	fi
-fi
-if test "$create_log" = 'yes'
-then
-	mkdir -p $(dirname "$GIT_DIR/logs/refs/heads/$branchname")
-	touch "$GIT_DIR/logs/refs/heads/$branchname"
-fi
-git update-ref -m "branch: Created from $head" "refs/heads/$branchname" $rev
diff --git a/git.c b/git.c
index 930998b..5738cb4 100644
--- a/git.c
+++ b/git.c
@@ -226,6 +226,7 @@ static void handle_internal_command(int 
 	} commands[] = {
 		{ "add", cmd_add, RUN_SETUP },
 		{ "apply", cmd_apply },
+		{ "branch", cmd_branch, RUN_SETUP },
 		{ "cat-file", cmd_cat_file, RUN_SETUP },
 		{ "checkout-index", cmd_checkout_index, RUN_SETUP },
 		{ "check-ref-format", cmd_check_ref_format },

^ permalink raw reply related

* Re: [RFD] gitweb: href() function to generate URLs for CGI
From: Jakub Narebski @ 2006-08-21 18:38 UTC (permalink / raw)
  To: git
In-Reply-To: <7v1wrauex2.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:

> Jakub Narebski <jnareb@gmail.com> writes:
> 
>> In first version of href() function we had
>> (commit 06a9d86b49b826562e2b12b5c7e831e20b8f7dce)
>>
>>      my $href = "$my_uri?";
>>      $href .= esc_param( join(";",
>>              map {
>>                      "$mapping{$_}=$params{$_}"
>>              } keys %params
>>      ) );
>>
>> First, there was a question what happend if someone would enter 
>> parameter name incorrectly, and some key of %params is not found in 
>> %mapping hash. The above code would generate warnings (which web admins 
>> frown upon), and empty (because undef) parameters corresponding to e.g. 
>> mistyped parameter name. 
> 
> The one in "next" seems to do this (the diff is between "master"
> and "next"):
> 
> @@ -204,7 +277,9 @@ sub href(%) {
>  
>       my $href = "$my_uri?";
>       $href .= esc_param( join(";",
> -             map { "$mapping{$_}=$params{$_}" } keys %params
> +             map {
> +                     "$mapping{$_}=$params{$_}" if defined $params{$_}
> +             } keys %params
>       ) );
>  
>       return $href;
> 

This doesn't work as expected. Map works on _every_ element of list; if
expression doesn't return anything it just puts undef I think. For example
while

        print join(";", 
                map { 
                        "a/$_" if ($_ eq lc($_)) 
                } ("a", "b", "C", "d")),
                "\n";'

returns "a/a;a/b;;a/d" (notice the doubled ';'), the correct way would be to
use grep instead:

        print join(";",
                map {
                        "a/$_"
                } grep { 
                        ($_ eq lc($_)) 
                } ("a", "b", "C", "d")),
                "\n";

returns correct "a/a;a/b;a/d". So the fragment should read what I wrote:

        my $href = "$my_uri?";
        $href .= esc_param( join(";",
                map {
                        "$mapping{$_}=$params{$_}"
                } grep { exists $mapping{$_} } keys %params
        ) );

>> Second problem is that using href() function, although it consolidates 
>> to generate URL for CGI, it changes the order of CGI parameters. It 
>> used to be that 'p' (project) parameter was first, then 'a' (action) 
>> parameter, then hashes ('h', 'hp', 'hb'), last 'f' (filename) or 
>> 'p' (page) or 's' (searchtext). The simplest and fastest solution would 
>> be to create array with all keys of %mapping in appropriate order and 
>> do something like this:
>>
>>      my @mapping_sorted = ('project', 'action', 'hash',
>>              'hash_parent', 'hash_base', 'file_name', 'searchtext');
>>
>>      my $href = "$my_uri?";
>>      $href .= esc_param( join(";",
>>              map {
>>                      "$mapping{$_}=$params{$_}"
>>              } grep { exists $params{$_}} @mapping_sorted;
>>      ) );
>>
>> The problem is of course updating both %mappings and @mapping_sorted.
>>
>> Is this really a problem, should this (ordering of CGI parameters)
>> addressed?
> 
> Keeping the generated URL stable would be a very desirable
> feature.  Perhaps something like this?
> 
> sub href(%) {
>         my @mapping = ( project => "p",
>                         action => "a",
>                         hash => "h",
>                         hash_parent => "hp",
>                         hash_base => "hb",
>                         file_name => "f",
>                         file_parent => "fp",
>                         page => "pg",
>                         searchtext => "s",
>                         );
>       my %mapping;                        
>         for (my $i = 0; $i < @mapping; $i += 2) {
>               my ($k, $v) = ($mapping[$i], $mapping[$i+1]);
>                 $mapping{$k} = [$i, $v];
>         }
>       my %params = @_;
>       $params{"project"} ||= $project;
> 
>       my $href = "$my_uri?";
>       $href .= esc_param( join(";",
>               map { $_->[1] }
>               sort { $a->[0] <=> $b->[0] }
>               map {
>                       (defined $params{$_} && exists $mapping{$_})
>                       ? [ $mapping{$_}[0], "$mapping{$_}[1]=$params{$_}" ]
>                         : ();
>               } keys %params
>       ) );
> 
>       return $href;
> }

What about my proposed solution? Don't sort, use sorted keys instead, i.e.
something like (after unmangling whitespace)

sub href(%) {
        my @mapping = ( project => "p",
                        action => "a",
                        hash => "h",
                        hash_parent => "hp",
                        hash_base => "hb",
                        file_name => "f",
                        file_parent => "fp",
                        page => "pg",
                        searchtext => "s",
                        );
        my %mapping;
        my @mapping_keys;                        
        for (my $i = 0; $i < @mapping; $i += 2) {
                my ($k, $v) = ($mapping[$i], $mapping[$i+1]);
                $mapping{$k} = $v;
                push @mapping_keys, $k;
        }
        my %params = @_;
        $params{"project"} ||= $project;

        my $href = "$my_uri?";
        $href .= esc_param( join(";",
                map { "$mapping{$_}=$params{$_}" }
                grep { exists $params{$_} } 
                @mapping_keys
        ) );

        return $href;
}

This has the advantage and disadvantage of constant cost, linear with number
of %mapping keys, instead of N log N cost where N is number of parameters.

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* use case
From: Blu Corater @ 2006-08-21 18:23 UTC (permalink / raw)
  To: git

Hello all.

I've just recently started to put my projects under git, and I have found
a, maybe unusual, use case in which I am not sure how to procede or even
if git is the right tool. Advice from more seasoned users is welcome.

The picture is like this. I've just have to took over the maintenance of a
piece of software which was not kept under scm. The previous developer
used to just hack on the production systems and make a backup once in a
while. No release policy or anything like that. The software runs on
several machines and controls similar but not identical equipment. The
machines should be swapable, therefore the software running should be
identical in all of them and detect the working environment at runtime.

In top of all, my predecesor was fired a few months before I took control
and, in the meantime, people have been doing random modifications to the
software on the production machines to satisfy new requirements, but not
consolidating them, so the present state is slightly divergent and
incompatible versions of the software on each production machine and the
machines are not swapable any more.

My contingency plan, while I manage to refactor the code and establish
a more sane workflow, was to create a git repository on each production
machine, so I can track and audit changes made by random hackers (I have
been unable to convince all of them to ask me to do it instead), and pull
from all of them to a git repository on my develpment machine to produce a
consolidated version.

I am keeping local branches on my devel repo corresponding to each
production machine and pulling from them every time somebody makes a
modification (after commiting on the production machine of course).

The main problem I am facing now is that I have been unable to make an
octopus merge from all the branches to consolidate them. When I do a
"git-pull . branch1 branch2..." git tells me "Unable to find common commit
with 5f83..." where 5f83... is the sha1 of the head commit of the first
branch on the command line. I am merging every branch with my master
branch one by one now, but it is a very time consumming and error prone
process. I would very much like to octopus merge the branches, with all
the conflicts, and then fix the master branch and release a consolidated
version.

Any hints?

-- 
Blu.

^ permalink raw reply

* Re: [RFD] gitweb: href() function to generate URLs for CGI
From: Junio C Hamano @ 2006-08-21 18:22 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <200608211739.32993.jnareb@gmail.com>

Jakub Narebski <jnareb@gmail.com> writes:

> In first version of href() function we had
> (commit 06a9d86b49b826562e2b12b5c7e831e20b8f7dce)
>
> 	my $href = "$my_uri?";
> 	$href .= esc_param( join(";",
> 		map {
> 			"$mapping{$_}=$params{$_}"
> 		} keys %params
> 	) );
>
> First, there was a question what happend if someone would enter 
> parameter name incorrectly, and some key of %params is not found in 
> %mapping hash. The above code would generate warnings (which web admins 
> frown upon), and empty (because undef) parameters corresponding to e.g. 
> mistyped parameter name. 

The one in "next" seems to do this (the diff is between "master"
and "next"):

@@ -204,7 +277,9 @@ sub href(%) {
 
 	my $href = "$my_uri?";
 	$href .= esc_param( join(";",
-		map { "$mapping{$_}=$params{$_}" } keys %params
+		map {
+			"$mapping{$_}=$params{$_}" if defined $params{$_}
+		} keys %params
 	) );
 
 	return $href;

So we perhaps would want to say:

	if (defined $params{$_} && exists $mapping{$_})

instead there?

> Second problem is that using href() function, although it consolidates 
> to generate URL for CGI, it changes the order of CGI parameters. It 
> used to be that 'p' (project) parameter was first, then 'a' (action) 
> parameter, then hashes ('h', 'hp', 'hb'), last 'f' (filename) or 
> 'p' (page) or 's' (searchtext). The simplest and fastest solution would 
> be to create array with all keys of %mapping in appropriate order and 
> do something like this:
>
> 	my @mapping_sorted = ('project', 'action', 'hash',
> 		'hash_parent', 'hash_base', 'file_name', 'searchtext');
>
> 	my $href = "$my_uri?";
> 	$href .= esc_param( join(";",
> 		map {
> 			"$mapping{$_}=$params{$_}"
> 		} grep { exists $params{$_}} @mapping_sorted;
> 	) );
>
> The problem is of course updating both %mappings and @mapping_sorted.
>
> Is this really a problem, should this (ordering of CGI parameters)
> addressed?

Keeping the generated URL stable would be a very desirable
feature.  Perhaps something like this?

sub href(%) {
        my @mapping = ( project => "p",
                        action => "a",
                        hash => "h",
                        hash_parent => "hp",
                        hash_base => "hb",
                        file_name => "f",
                        file_parent => "fp",
                        page => "pg",
                        searchtext => "s",
                        );
	my %mapping;                        
        for (my $i = 0; $i < @mapping; $i += 2) {
        	my ($k, $v) = ($mapping[$i], $mapping[$i+1]);
                $mapping{$k} = [$i, $v];
        }
	my %params = @_;
	$params{"project"} ||= $project;

	my $href = "$my_uri?";
	$href .= esc_param( join(";",
		map { $_->[1] }
		sort { $a->[0] <=> $b->[0] }
		map {
                	(defined $params{$_} && exists $mapping{$_})
			? [ $mapping{$_}[0], "$mapping{$_}[1]=$params{$_}" ]
                        : ();
		} keys %params
	) );

	return $href;
}

^ permalink raw reply

* Re: Huge win, compressing a window of delta runs as a unit
From: Nicolas Pitre @ 2006-08-21 18:01 UTC (permalink / raw)
  To: Jon Smirl; +Cc: Shawn Pearce, git
In-Reply-To: <Pine.LNX.4.64.0608211350430.3851@localhost.localdomain>

On Mon, 21 Aug 2006, Nicolas Pitre wrote:

> On Mon, 21 Aug 2006, Nicolas Pitre wrote:
> 
> > If for example each object has 2 delta childs, and each of those deltas 
> > also have 2 delta childs, you could have up to 39366 delta objects 
> > attached to a _single_ undeltified base object.
> 
> Sorry I've got the math wrong.  That is 3582 deltas, given a 
> conservative number of delta childs = 2.

OK I just can't count.  That is 2046.

But since I made a fool of myself already, why not try with 3 delta 
childs for a delta depth of 10 just for fun, now that I should have it 
right.  The answer is 88572.

Anyway I hope you've got my point now.  ;-)


Nicolas

^ permalink raw reply

* Re: Huge win, compressing a window of delta runs as a unit
From: Nicolas Pitre @ 2006-08-21 17:55 UTC (permalink / raw)
  To: Jon Smirl; +Cc: Shawn Pearce, git
In-Reply-To: <Pine.LNX.4.64.0608211309270.3851@localhost.localdomain>

On Mon, 21 Aug 2006, Nicolas Pitre wrote:

> If for example each object has 2 delta childs, and each of those deltas 
> also have 2 delta childs, you could have up to 39366 delta objects 
> attached to a _single_ undeltified base object.

Sorry I've got the math wrong.  That is 3582 deltas, given a 
conservative number of delta childs = 2.


Nicolas

^ 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