Git development
 help / color / mirror / Atom feed
* Re: Prepend the history of one git tree to another
From: Thomas Glanzmann @ 2006-02-20 12:20 UTC (permalink / raw)
  To: Ryan Anderson; +Cc: GIT
In-Reply-To: <43F9A0B3.6020304@michonline.com>

Hello,

> I wrote a program called "graft-ripple", that takes a commit, and
> rewrites the current branch's history to reflect as if it started at
> that commit. It doesn't ever actually work with diffs or anything, it
> just reads commits and trees and recreates them.

> http://www.gelato.unsw.edu.au/archives/git/0511/12965.html

that is *exactly* what I was looking for. Thanks.

> Hope this helps!

Well it does!

Thanks,
        Thomas

^ permalink raw reply

* Re: [PATCH] Convert the git faq to asciidoc
From: Thomas Riboulet @ 2006-02-20 11:14 UTC (permalink / raw)
  To: Jonas Fonseca; +Cc: git
In-Reply-To: <20060220014539.GA8759@diku.dk>

On 2/20/06, Jonas Fonseca <fonseca@diku.dk> wrote:
> Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
>
> ---
>
> Thomas Riboulet <riboulet@gmail.com> wrote Thu, Feb 16, 2006:
> > Comments and suggestions are welcome (on the content, the form, format, etc ...)
> > I'll try to add questions from the archives of this ml, I'm also open
> > to any suggestions.
>
> As promissed on the #git channel this patch converts the faq to asciidoc
> format, with a few enhancements such as links to manpages and a TOC.
>
> Previews at
> http://www.diku.dk/hjemmesider/studerende/fonseca/git/git-faq.{html,txt,xml}.
>
> ---
>
>  Makefile |   23 ++++++++
>  faq.conf |   19 +++++++
>  faq.txt  |  175 ++++++++++++++++++++++++++++++++++++++++++--------------------
>  3 files changed, 161 insertions(+), 56 deletions(-)
>
> diff --git a/Makefile b/Makefile
> new file mode 100644
> index 0000000..09f6978
> --- /dev/null
> +++ b/Makefile
> @@ -0,0 +1,23 @@
> +all: git-faq.html git-faq.xml git-faq.txt
> +
> +clean:
> +       rm -f git-faq.html git-faq.xml git-faq.txt faq-toc.txt
> +
> +git-faq.html git-faq.xml git-faq.txt: faq.txt faq-toc.txt
> +
> +git-faq.xml:
> +       asciidoc -f faq.conf -b docbook -d article -o $@ faq.txt
> +
> +git-faq.html: faq.txt faq-toc.txt
> +       asciidoc -f faq.conf -b xhtml11 -d article -o $@ faq.txt
> +
> +git-faq.txt: git-faq.html
> +       elinks --no-numbering --no-references --dump $< > $@
> +
> +faq-toc.txt: faq.txt
> +       sed -n '/^\[\[/,/--/p' < $< | while read line; do \
> +               case "$$line" in \
> +               "[["*"]]") echo -n ". <<$$line, " | sed 's/\[\[\(.*\)\]\]/\1/' ;; \
> +               --*)       echo    ">>" ;; \
> +               *)         echo -n "$$line " ;; \
> +               esac; done > $@
> diff --git a/faq.conf b/faq.conf
> new file mode 100644
> index 0000000..fa16ad6
> --- /dev/null
> +++ b/faq.conf
> @@ -0,0 +1,19 @@
> +# AsciiDoc FAQ definitions
> +
> +[attributes]
> +gitdoc-base=http://kernel.org/pub/software/scm/git/docs/
> +cgdoc-base=http://kernel.org/pub/software/scm/cogito/docs/
> +
> +ifdef::backend-docbook[]
> +[gitdoc-inlinemacro]
> +<ulink url="{gitdoc-base}{target}.html">{0}</ulink>
> +[cgdoc-inlinemacro]
> +<ulink url="{cgdoc-base}{target}.html">{0}</ulink>
> +endif::backend-docbook[]
> +
> +ifdef::backend-xhtml11[]
> +[gitdoc-inlinemacro]
> +<a href="{gitdoc-base}{target}.html">{0}</a>
> +[cgdoc-inlinemacro]
> +<a href="{cgdoc-base}{target}.html">{0}</a>
> +endif::backend-xhtml11[]
> diff --git a/faq.txt b/faq.txt
> index e719d04..9c7baa0 100644
> --- a/faq.txt
> +++ b/faq.txt
> @@ -1,68 +1,131 @@
> -Why the 'git' name ?
> -
> -As Linus' own words as the inventor of git : "git" can mean anything, depending on your mood.
> -
> -* random three-letter combination that is pronounceable, and not actually used by any common UNIX command. The fact that it is a mispronunciation of "get" may or may not be relevant.
> -*  stupid. contemptible and despicable. simple. Take your pick from the dictionary of slang.
> -* global information tracker": you're in a good mood, and it actually works for you. Angels sing, and a light suddenly fills the room.
> -* "goddamn idiotic truckload of sh*t": when it breaks
> -
> -
> -Can I share a git public repository and use it in a CVS way ?
> -
> -Use cg-admin-setuprepo -g or do git-init-db --shared and some additional stuff. It's ok that refs aren't group writable, it's enough the directory is. See Cogito README or GIT's cvs-migration doc, "Emulating the CVS Development Model" for details.
> -
> -
> -Git commit is dying telling me "fatal : empty ident <user@myhost> not allowed" , what's wrong ?
> -
> -Make sure your Full Name is not empty in chsh or the 5th field of your user line in /etc/passwd isn't empty. You can also set the GIT_AUTHOR_NAME environment variable. If you @myhost is empty make sure your hostname is correctly set.
> -What's the difference between fetch and pull ?
> -
> -Fetch : download objects and a head from another repository.
> -Pull : fetch (as defined above) and merge with the current development.
> -See man git-fetch and git-pull or the tutorials for more details.
> -
> -
> -
> -Can I tell git to ignore files ?
> -
> -Yes. If you want to ignore files localy (only for you in your local work copy) put the files path in the repository in the .git/info/exclude file.
> -
> -If you want to make the ignore matters for all and everyone who checkouts the project you have to put the files path in the .gitignore in the tree itself.
> -
> -
> -Can I import from cvs ?
> -
> -Yes. Use git-cvsimport. See the cvs-migration doc for more details.
> -
> -
> -Can I import from svn ?
> -
> -Yes. Use git-svnimport. See the svn-import doc for more details.
> +The git FAQ
> +===========
> +:Author:       Thomas Riboulet
> +:CorpAuthor:   git mailing list
> +
> +//////////////////////////////////////////////////////////////////////////////
> +A note about required info for FAQ entries. Please use the following template:
> +
> +       [[question-id]]
> +       question?
> +       ---------
> +       answer.
> +
> +The question-id + question will be used for generating a table of contents.
> +//////////////////////////////////////////////////////////////////////////////
> +
> +// DocBook derived output will (hopefully) have it's own TOC
> +ifdef::backend-xhtml11[]
> +include::faq-toc.txt[]
> +endif::backend-xhtml11[]
> +
> +[[git-name]]
> +Why the 'git' name?
> +-------------------
> +In Linus' own words as the inventor of git: "git" can mean anything, depending
> +on your mood:
> +
> + - random three-letter combination that is pronounceable, and not actually
> +   used by any common UNIX command. The fact that it is a mispronunciation of
> +   "get" may or may not be relevant.
> + - stupid. contemptible and despicable. simple. Take your pick from the
> +   dictionary of slang.
> + - global information tracker": you're in a good mood, and it actually works
> +   for you. Angels sing, and a light suddenly fills the room.
> + - "goddamn idiotic truckload of sh*t": when it breaks
> +
> +
> +[[repo-sharing]]]
> +Can I share a git public repository and use it in a CVS way?
> +------------------------------------------------------------
> +Use cg-admin-setuprepo -g or do git-init-db --shared and some additional
> +stuff. It's ok that refs aren't group writable, it's enough the directory is.
> +See Cogito README or GIT's cvs-migration doc, "Emulating the CVS Development
> +Model" for details.
> +
> +
> +[[empty-ident]]
> +Git commit is dying telling me "fatal: empty ident <user@myhost> not allowed", what's wrong?
> +--------------------------------------------------------------------------------------------
> +Make sure your Full Name is not empty in chsh or the 5th field of your user
> +line in `/etc/passwd` isn't empty. You can also set the `GIT_AUTHOR_NAME`
> +environment variable. If your @myhost is empty make sure your hostname is
> +correctly set. Use gitdoc:git-var[`git-var -l`] to make git display user
> +identity variables.
> +
> +
> +[[fetch-vs-pull]]
> +What's the difference between fetch and pull?
> +---------------------------------------------
> +The short definition is:
> +
> +Fetch::        Download objects and a head from another repository.
> +Pull:: Fetch (as defined above) and merge with the current development.
> +
> +See the gitdoc:git-fetch[git-fetch(1)] and gitdoc:git-pull[git-pull(1)]
> +manpages or the tutorials for more details.
> +
> +
> +[[gitignore]]
> +Can I tell git to ignore files?
> +-------------------------------
> +Yes. If you want to ignore files localy (only for you in your local work copy)
> +put the files path in the repository in the `.git/info/exclude` file.
> +
> +If you want to make the ignore matters for all and everyone who checkouts the
> +project you have to put the files path in the `.gitignore` in the tree itself.
> +
> +
> +[[import-cvs]]
> +Can I import from CVS?
> +----------------------
> +Yes. Use git-cvsimport. See the gitdoc:git-cvsimport[git-cvsimport(1)] or
> +gitdoc:cvs-migration[the CVS migration doc] for more detail.
> +
> +
> +[[import-svn]]
> +Can I import from svn?
> +----------------------
> +Yes. Use git-svnimport. See gitdoc:git-svnimport[git-svnimport(1)] for more
> +details.
>
>
> +[[import-arch]]
>  Can I import from arch/baz/tla?
> -
> -Yes. Use git-archimport.
> +-------------------------------
> +Yes. Use git-svnimport. See gitdoc:git-archimport[git-archimport(1)] for more
> +details.
>
>
> +[[import-others]]
>  Can I import from others?
> +-------------------------
> +Maybe -- check if http://www.darcs.net/DarcsWiki/Tailor[tailor.py] can do it.
>
> -Maybe -- check if tailor.py can do it. Check http://www.darcs.net/DarcsWiki/Tailor.
> -
> -
> -How old linus bk repos have been import to git ?
>
> +[[linux-bk]]
> +How was the old Linux BitKeeper repository imported into git?
> +-------------------------------------------------------------
>  Using the CVS gateway, via git-cvsimport.
>
>
> -What can I use to setup a public repository ?
> -
> -A ssh server, an http server, or the git-daemon. See the tutorial for more details.
> -
> -
> -Why won't git let me change to a different branch using "git checkout <branch>" or "git checkout -b <branch>"?
> -
> -Instead it just says: fatal: Entry 'foo.c' not uptodate. Cannot merge.
> +[[public-repo]]
> +What can I use to setup a public repository?
> +--------------------------------------------
> +A SSH server, an HTTP server, or the gitdoc:git-daemon[git-daemon]. See the
> +tutorial for more details.
> +
> +
> +[[change-branch]]
> +Why won't git let me change to a different branch?
> +--------------------------------------------------
> +Using "git checkout <branch>" or "git checkout -b <branch>" it just says:
> +
> +       fatal: Entry 'foo.c' not uptodate. Cannot merge.
> +
> +You have changes to files in your working directory that will be overwritten,
> +removed or otherwise lost if the checkout and change to the new branch were to
> +proceed. To fix this you may either check your changes in, create a patch of
> +your changes and revert your files, or use the "-m" flag like this:
>
> -You have changes to files in your working directory that will be overwritten, removed or otherwise lost if the checkout and change to the new branch were to proceed. To fix this you may either check your changes in, create a patch of your changes and revert your files, or use the "-m" flag like this: git checkout -m -b my-branch
> +       git checkout -m -b my-branch
>
> --
> Jonas Fonseca
>

hi,

ok seems much easier than docbook to write, I've commited your
changes, I'll push them when I'll be back home.

I've tested the docbook file generated, works fine

thanks

--
Thom/ange
http://ange.librium.org

^ permalink raw reply

* Re: Prepend the history of one git tree to another
From: Ryan Anderson @ 2006-02-20 10:57 UTC (permalink / raw)
  To: Thomas Glanzmann; +Cc: Andreas Ericsson, GIT
In-Reply-To: <20060220104345.GG26454@cip.informatik.uni-erlangen.de>

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

Thomas Glanzmann wrote:

>Hello Andreas,
>
>  
>
>>Something like this might do the trick, depending on how linear your 
>>ancestry graph is:
>>    
>>
>
>  
>
>>$ cd blastwave
>>$ first=$(git rev-list HEAD | tail -n 1)
>>$ git format-patch -k --stdout $first..HEAD > ../blw.mbox
>>$ cd ../blastwave.old
>>$ git am -k -3 ../blw.mbox
>>    
>>
>
>My graph is very linear. However. I have binaries checked into my tree.
>I am not sure if format-patch can handle this.
>  
>
I wrote a program called "graft-ripple", that takes a commit, and
rewrites the current branch's history to reflect as if it started at
that commit.

It doesn't ever actually work with diffs or anything, it just reads
commits and trees and recreates them.

It's in the list archives, but I appear to have deleted it when I was
cleaning up my archives.

http://www.gelato.unsw.edu.au/archives/git/0511/12965.html

Hope this helps!

-- 

Ryan Anderson
  sometimes Pug Majere


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]

^ permalink raw reply

* [PATCH] Add git-annotate, a tool for assigning blame.
From: Ryan Anderson @ 2006-02-20 10:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Ryan Anderson

Signed-off-by: Ryan Anderson <ryan@michonline.com>

---

(Pull from http://h4x0r5.com/~ryan/git/ryan.git/ annotate-upstream )

I'm pretty sure this version (finally) gets the edge cases correct.

I would appreciate some other testing on this, as I can't find a case
where it falls down, but the files with a lot of history tend to have a
lot of lines, making them hard to spotcheck without having been an
intimate part of that history.

Oh, this is the "functional" version, but it might not qualify as "nice
looking" yet, pleaes, feel free to complain.

 Makefile          |    1 
 git-annotate.perl |  321 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 322 insertions(+), 0 deletions(-)
 create mode 100755 git-annotate.perl

107045e8abb674a66ee7c682dd85a3d303f26e3c
diff --git a/Makefile b/Makefile
index 317be3c..86ffcf4 100644
--- a/Makefile
+++ b/Makefile
@@ -119,6 +119,7 @@ SCRIPT_SH = \
 SCRIPT_PERL = \
 	git-archimport.perl git-cvsimport.perl git-relink.perl \
 	git-shortlog.perl git-fmt-merge-msg.perl git-rerere.perl \
+	git-annotate.perl \
 	git-svnimport.perl git-mv.perl git-cvsexportcommit.perl
 
 SCRIPT_PYTHON = \
diff --git a/git-annotate.perl b/git-annotate.perl
new file mode 100755
index 0000000..8f98431
--- /dev/null
+++ b/git-annotate.perl
@@ -0,0 +1,321 @@
+#!/usr/bin/perl
+# Copyright 2006, Ryan Anderson <ryan@michonline.com>
+#
+# GPL v2 (See COPYING)
+#
+# This file is licensed under the GPL v2, or a later version
+# at the discretion of Linus Torvalds.
+
+use warnings;
+use strict;
+
+my $filename = shift @ARGV;
+
+
+my @stack = (
+	{
+		'rev' => "HEAD",
+		'filename' => $filename,
+	},
+);
+
+our (@lineoffsets, @pendinglineoffsets);
+our @filelines = ();
+open(F,"<",$filename)
+	or die "Failed to open filename: $!";
+
+while(<F>) {
+	chomp;
+	push @filelines, $_;
+}
+close(F);
+our $leftover_lines = @filelines;
+our %revs;
+our @revqueue;
+our $head;
+
+my $revsprocessed = 0;
+while (my $bound = pop @stack) {
+	my @revisions = git_rev_list($bound->{'rev'}, $bound->{'filename'});
+	foreach my $revinst (@revisions) {
+		my ($rev, @parents) = @$revinst;
+		$head ||= $rev;
+
+		$revs{$rev}{'filename'} = $bound->{'filename'};
+		if (scalar @parents > 0) {
+			$revs{$rev}{'parents'} = \@parents;
+			next;
+		}
+
+		my $newbound = find_parent_renames($rev, $bound->{'filename'});
+		if ( exists $newbound->{'filename'} && $newbound->{'filename'} ne $bound->{'filename'}) {
+			push @stack, $newbound;
+			$revs{$rev}{'parents'} = [$newbound->{'rev'}];
+		}
+	}
+}
+push @revqueue, $head;
+init_claim($head);
+$revs{$head}{'lineoffsets'} = {};
+handle_rev();
+
+
+my $i = 0;
+foreach my $l (@filelines) {
+	my ($output, $rev, $committer, $date);
+	if (ref $l eq 'ARRAY') {
+		($output, $rev, $committer, $date) = @$l;
+		if (length($rev) > 8) {
+			$rev = substr($rev,0,8);
+		}
+	} else {
+		$output = $l;
+		($rev, $committer, $date) = ('unknown', 'unknown', 'unknown');
+	}
+
+	printf("(%8s %10s %10s %d)%s\n", $rev, $committer, $date, $i++, $output);
+}
+
+sub init_claim {
+	my ($rev) = @_;
+	my %revinfo = git_commit_info($rev);
+	for (my $i = 0; $i < @filelines; $i++) {
+		$filelines[$i] = [ $filelines[$i], '', '', '', 1];
+			# line,
+			# rev,
+			# author,
+			# date,
+			# 1 <-- belongs to the original file.
+	}
+	$revs{$rev}{'lines'} = \@filelines;
+}
+
+
+sub handle_rev {
+	my $i = 0;
+	while (my $rev = shift @revqueue) {
+
+		my %revinfo = git_commit_info($rev);
+
+		foreach my $p (@{$revs{$rev}{'parents'}}) {
+
+			git_diff_parse($p, $rev, %revinfo);
+			push @revqueue, $p;
+		}
+
+
+		if (scalar @{$revs{$rev}{parents}} == 0) {
+			# We must be at the initial rev here, so claim everything that is left.
+			for (my $i = 0; $i < @{$revs{$rev}{lines}}; $i++) {
+				if (ref ${$revs{$rev}{lines}}[$i] eq '' || ${$revs{$rev}{lines}}[$i][1] eq '') {
+					claim_line($i, $rev, $revs{$rev}{lines}, %revinfo);
+				}
+			}
+		}
+	}
+}
+
+
+sub git_rev_list {
+	my ($rev, $file) = @_;
+
+	open(P,"-|","git-rev-list","--parents","--remove-empty",$rev,"--",$file)
+		or die "Failed to exec git-rev-list: $!";
+
+	my @revs;
+	while(my $line = <P>) {
+		chomp $line;
+		my ($rev, @parents) = split /\s+/, $line;
+		push @revs, [ $rev, @parents ];
+	}
+	close(P);
+
+	printf("0 revs found for rev %s (%s)\n", $rev, $file) if (@revs == 0);
+	return @revs;
+}
+
+sub find_parent_renames {
+	my ($rev, $file) = @_;
+
+	open(P,"-|","git-diff-tree", "-M50", "-r","--name-status", "-z","$rev")
+		or die "Failed to exec git-diff: $!";
+
+	local $/ = "\0";
+	my %bound;
+	my $junk = <P>;
+	while (my $change = <P>) {
+		chomp $change;
+		my $filename = <P>;
+		chomp $filename;
+
+		if ($change =~ m/^[AMD]$/ ) {
+			next;
+		} elsif ($change =~ m/^R/ ) {
+			my $oldfilename = $filename;
+			$filename = <P>;
+			chomp $filename;
+			if ( $file eq $filename ) {
+				my $parent = git_find_parent($rev, $oldfilename);
+				@bound{'rev','filename'} = ($parent, $oldfilename);
+				last;
+			}
+		}
+	}
+	close(P);
+
+	return \%bound;
+}
+
+
+sub git_find_parent {
+	my ($rev, $filename) = @_;
+
+	open(REVPARENT,"-|","git-rev-list","--remove-empty", "--parents","--max-count=1","$rev","--",$filename)
+		or die "Failed to open git-rev-list to find a single parent: $!";
+
+	my $parentline = <REVPARENT>;
+	chomp $parentline;
+	my ($revfound,$parent) = split m/\s+/, $parentline;
+
+	close(REVPARENT);
+
+	return $parent;
+}
+
+
+# Get a diff between the current revision and a parent.
+# Record the commit information that results.
+sub git_diff_parse {
+	my ($parent, $rev, %revinfo) = @_;
+
+	my ($ri, $pi) = (0,0);
+	open(DIFF,"-|","git-diff-tree","-M","-p",$rev,$parent,"--",
+			$revs{$rev}{'filename'}, $revs{$parent}{'filename'})
+		or die "Failed to call git-diff for annotation: $!";
+
+	my $slines = $revs{$rev}{'lines'};
+	my @plines;
+
+	my $gotheader = 0;
+	my ($remstart, $remlength, $addstart, $addlength);
+	my ($hunk_start, $hunk_index, $hunk_adds);
+	while(<DIFF>) {
+		chomp;
+		if (m/^@@ -(\d+),(\d+) \+(\d+),(\d+)/) {
+			($remstart, $remlength, $addstart, $addlength) = ($1, $2, $3, $4);
+			# Adjust for 0-based arrays
+			$remstart--;
+			$addstart--;
+			# Reinit hunk tracking.
+			$hunk_start = $remstart;
+			$hunk_index = 0;
+			$gotheader = 1;
+
+			for (my $i = $ri; $i < $remstart; $i++) {
+				$plines[$pi++] = $slines->[$i];
+				$ri++;
+			}
+			next;
+		} elsif (!$gotheader) {
+			next;
+		}
+
+		if (m/^\+(.*)$/) {
+			my $line = $1;
+			$plines[$pi++] = [ $line, '', '', '', 0 ];
+			next;
+
+		} elsif (m/^-(.*)$/) {
+			my $line = $1;
+			if (get_line($slines, $ri) eq $line) {
+				# Found a match, claim
+				claim_line($ri, $rev, $slines, %revinfo);
+			} else {
+				die sprintf("Sync error: %d/%d\n|%s\n|%s\n%s => %s\n",
+						$ri, $hunk_start + $hunk_index,
+						$line,
+						get_line($slines, $ri),
+						$rev, $parent);
+			}
+			$ri++;
+
+		} else {
+			if (substr($_,1) ne get_line($slines,$ri) ) {
+				die sprintf("Line %d (%d) does not match:\n|%s\n|%s\n%s => %s\n",
+						$hunk_start + $hunk_index, $ri,
+						substr($_,1),
+						get_line($slines,$ri),
+						$rev, $parent);
+			}
+			$plines[$pi++] = $slines->[$ri++];
+		}
+		$hunk_index++;
+	}
+	close(DIFF);
+	for (my $i = $ri; $i < @{$slines} ; $i++) {
+		push @plines, $slines->[$ri++];
+	}
+
+	$revs{$parent}{lines} = \@plines;
+	return;
+}
+
+sub get_line {
+	my ($lines, $index) = @_;
+
+	return ref $lines->[$index] ne '' ? $lines->[$index][0] : $lines->[$index];
+}
+
+sub git_cat_file {
+	my ($parent, $filename) = @_;
+	return () unless defined $parent && defined $filename;
+	my $blobline = `git-ls-tree $parent $filename`;
+	my ($mode, $type, $blob, $tfilename) = split(/\s+/, $blobline, 4);
+
+	open(C,"-|","git-cat-file", "blob", $blob)
+		or die "Failed to git-cat-file blob $blob (rev $parent, file $filename): " . $!;
+
+	my @lines;
+	while(<C>) {
+		chomp;
+		push @lines, $_;
+	}
+	close(C);
+
+	return @lines;
+}
+
+
+sub claim_line {
+	my ($floffset, $rev, $lines, %revinfo) = @_;
+	my $oline = get_line($lines, $floffset);
+	@{$lines->[$floffset]} = ( $oline, $rev,
+		$revinfo{'author'}, $revinfo{'author_date'} );
+	#printf("Claiming line %d with rev %s: '%s'\n",
+	#		$floffset, $rev, $oline) if 1;
+}
+
+sub git_commit_info {
+	my ($rev) = @_;
+	open(COMMIT, "-|","git-cat-file", "commit", $rev)
+		or die "Failed to call git-cat-file: $!";
+
+	my %info;
+	while(<COMMIT>) {
+		chomp;
+		last if (length $_ == 0);
+
+		if (m/^author (.*) <(.*)> (.*)$/) {
+			$info{'author'} = $1;
+			$info{'author_email'} = $2;
+			$info{'author_date'} = $3;
+		} elsif (m/^committer (.*) <(.*)> (.*)$/) {
+			$info{'committer'} = $1;
+			$info{'committer_email'} = $2;
+			$info{'committer_date'} = $3;
+		}
+	}
+	close(COMMIT);
+
+	return %info;
+}
-- 
1.2.2.gb342

^ permalink raw reply related

* Re: Prepend the history of one git tree to another
From: Thomas Glanzmann @ 2006-02-20 10:43 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: GIT
In-Reply-To: <43F99684.5070403@op5.se>

Hello Andreas,

> Something like this might do the trick, depending on how linear your 
> ancestry graph is:

> $ cd blastwave
> $ first=$(git rev-list HEAD | tail -n 1)
> $ git format-patch -k --stdout $first..HEAD > ../blw.mbox
> $ cd ../blastwave.old
> $ git am -k -3 ../blw.mbox

My graph is very linear. However. I have binaries checked into my tree.
I am not sure if format-patch can handle this.

        Thomas

^ permalink raw reply

* Re: [PATCH] Add a Documentation/git-tools.txt
From: Catalin Marinas @ 2006-02-20 10:31 UTC (permalink / raw)
  To: Marco Costalba; +Cc: git, junkio
In-Reply-To: <e5bfff550602190200j1ef3858as6a1564064dc81fef@mail.gmail.com>

"Marco Costalba" <mcostalba@gmail.com> wrote:
> +        - *StGit* (http://homepage.ntlworld.com/cmarinas/stgit/)

This line should be:

+        - *StGIT* (http://www.procode.org/stgit/)

The URL you put is just the download area which may change.

Thanks.

-- 
Catalin

^ permalink raw reply

* Re: Prepend the history of one git tree to another
From: Andreas Ericsson @ 2006-02-20 10:14 UTC (permalink / raw)
  To: Thomas Glanzmann; +Cc: GIT
In-Reply-To: <20060220090909.GT6558@cip.informatik.uni-erlangen.de>

Thomas Glanzmann wrote:
> Hello,
> I have two trees: blastwave and blastwave.old. blastwave.old is the
> BitKeeper -> CVS -> GIT Tree of the project and blastwave is the newer
> one that I started when I stoped using bitkeeper. What I want is to 
> append the history of blastwave to blastwave.old. The problem is that I
> need to create new commit objects for every commit I want to append to
> the old history. Is there a script which does that for me? Or do I have
> to write this script myself?
> 

Something like this might do the trick, depending on how linear your 
ancestry graph is:

$ cd blastwave
$ first=$(git rev-list HEAD | tail -n 1)
$ git format-patch -k --stdout $first..HEAD > ../blw.mbox
$ cd ../blastwave.old
$ git am -k -3 ../blw.mbox

YMMV though, so set an anchor tag at the HEAD of blastwave.old so you 
can return to it if things go awry. If the history is very non-linear I 
think you'll have to do the same for each and every branch, although 
you'd have to use "git merge-base" to figure out how long to go.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

^ permalink raw reply

* Re: What's in git.git
From: Junio C Hamano @ 2006-02-20  9:47 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: git
In-Reply-To: <43F97F0D.9080500@op5.se>

Andreas Ericsson <ae@op5.se> writes:

> Junio C Hamano wrote:
>>
>> The updated pack-object series is now in "next" branch, and
>> seems to be cooking nicely.  The "reuse from existing pack"
>> change seems to be a huge win and I haven't found problems in
>> there.
>
> Wonderful news. I'll cherry-pick them and do some further testing.

BTW, the point of "next" is that you do not have to necessarily
cherry pick.  The topic branches in there are supposed to be in
testable shape.

Having said that, you could disect them out if you wanted to:

$ git log --pretty=oneline next | grep jc/pack- | head -n 8
5be4eabf90a4f6d14d3ae16772e6b2e063d71587 Merge branch 'jc/pack-thin' into next
bb837eccf42e5e8bbd4fe0927e7fa2afcfd2b564 Merge branch 'jc/pack-thin' into next
416b3cb4303e1a13ed05413bef7a0c1b9f7fc09e Merge branch 'jc/pack-reuse'
07e8ab9be913bd50595707f21a896ac15c4f5a89 Merge branch 'jc/pack-reuse'

The tip of jc/pack-reuse (that is the "reuse data from existing
packs" topic branch) jc/pack-thin ("thin packs") are at 416b3c^2
and 5be4ea^2 respectively.

So to check out the "reuse", you would:

$ git branch -f jc/pack-reuse 416b3c^2
$ git pull . jc/pack-reuse

If you want to try out "thin packs", you would need both
pack-objects change and rev-list change (the tip of jc/rev-list
is at 8c0db2^2).

$ git branch -f jc/rev-list 8c0db2^2
$ git branch -f jc/pack-thin 5be4ea^2
$ git pull . jc/pack-thin
$ git pull . jc/rev-list

^ permalink raw reply

* Prepend the history of one git tree to another
From: Thomas Glanzmann @ 2006-02-20  9:09 UTC (permalink / raw)
  To: GIT

Hello,
I have two trees: blastwave and blastwave.old. blastwave.old is the
BitKeeper -> CVS -> GIT Tree of the project and blastwave is the newer
one that I started when I stoped using bitkeeper. What I want is to 
append the history of blastwave to blastwave.old. The problem is that I
need to create new commit objects for every commit I want to append to
the old history. Is there a script which does that for me? Or do I have
to write this script myself?

        Thomas

^ permalink raw reply

* Re: What's in git.git
From: Junio C Hamano @ 2006-02-20  9:04 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: git
In-Reply-To: <43F97F0D.9080500@op5.se>

Andreas Ericsson <ae@op5.se> writes:

> Junio C Hamano wrote:
>
>> There now is further performance improvements for git-send-pack
>> to avoid sending a huge blob or tree object in its full
>> representation when we know the other end has a suitable object
>> to use as the base; instead we can just send it out deltified.
>> The other end would expand it to a loose object and this would
>> not make abit of difference in the resulting repository -- only
>> the bandwidth requirement reduction is visible [*1*].
>
> How likely is this to increase the CPU-power needed on the
> server-side? If there is a blob on the server-side, but far from the
> deltified object I suppose we have to look at each commit, perhaps
> only to discover that the client doesn't have them and we need to
> construct the blob anyways.

Not much.  It deliberately keeps the set of blobs and trees to
consider for remote base to minimum -- just the trees contained
in the boundary commits.  That way we may miss the best base
candidate that are further back in history, but it does not
matter because even using the less optimum one as a base saves
us from sending the base object at all.

^ permalink raw reply

* Re: What's in git.git
From: Andreas Ericsson @ 2006-02-20  8:34 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v3bieea32.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:
> The updated pack-object series is now in "next" branch, and
> seems to be cooking nicely.  The "reuse from existing pack"
> change seems to be a huge win and I haven't found problems in
> there.
> 

Wonderful news. I'll cherry-pick them and do some further testing.

> There now is further performance improvements for git-send-pack
> to avoid sending a huge blob or tree object in its full
> representation when we know the other end has a suitable object
> to use as the base; instead we can just send it out deltified.
> The other end would expand it to a loose object and this would
> not make abit of difference in the resulting repository -- only
> the bandwidth requirement reduction is visible [*1*].
> 

How likely is this to increase the CPU-power needed on the server-side? 
If there is a blob on the server-side, but far from the deltified object 
I suppose we have to look at each commit, perhaps only to discover that 
the client doesn't have them and we need to construct the blob anyways.

> 
> After a bit more testing, we might want to make --thin transfer
> the default (even without an option to turn it off -- I just do
> not see a point not to use it if it is bug-free).
> 

If the answer to my question above is "minimal to none", I agree most 
vehemently. ;)

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

^ permalink raw reply

* What's in git.git
From: Junio C Hamano @ 2006-02-20  7:57 UTC (permalink / raw)
  To: git

The updated pack-object series is now in "next" branch, and
seems to be cooking nicely.  The "reuse from existing pack"
change seems to be a huge win and I haven't found problems in
there.

There now is further performance improvements for git-send-pack
to avoid sending a huge blob or tree object in its full
representation when we know the other end has a suitable object
to use as the base; instead we can just send it out deltified.
The other end would expand it to a loose object and this would
not make abit of difference in the resulting repository -- only
the bandwidth requirement reduction is visible [*1*].

In principle, this is also applicable for fetch-pack, but it
involves a bit of pack protocol change.  The protocol extension
mechanism was done nicely by Johannes a while ago, and we can
use it to implement this with full backward compatibility.

After a bit more testing, we might want to make --thin transfer
the default (even without an option to turn it off -- I just do
not see a point not to use it if it is bug-free).

* The 'master' branch has these since the last announcement.

Junio C Hamano:
      fmt-merge-msg: say which branch things were merged into unless 'master'
      Allow git-mv to accept ./ in paths.
      Documentation: fix typo in rev-parse --short option description.
      fmt-merge-msg: do not add excess newline at the end.
      Merge branch 'jc/mv'
      Merge branch 'jc/merge-msg'


* The 'next' branch, in addition, has these.

Johannes Schindelin:
      Fixes for ancient versions of GNU make
      avoid makefile override warning
      Really honour NO_PYTHON

Junio C Hamano:
      Merge branch 'jc/merge-msg' into next
      Merge branch 'js/portable' into next
      rev-list --objects-edge
      Merge branch 'jc/rev-list' into next
      Thin pack - create packfile with missing delta base.
      send-pack --thin: use "thin pack" delta transfer.
      Merge branch 'jc/pack-thin' into next


[Footnote]

*1* The version of the patch I earlier sent to the list had a
grave performance bug; please do not use it.  The one in "next"
branch has the bug fixed already.

^ permalink raw reply

* git-svnimport -- http/dav authentication notes
From: Martin Langhoff @ 2006-02-20  7:24 UTC (permalink / raw)
  To: Git Mailing List

After a lot of trial and error against a server I don't control (so I
can't log things on) I've managed to use svn-import on it and it
mostly seems to work. Kind of. It's slowly grinding through the
commits.

To make it short, I seem to be doing well with:

   git-svnimport -t tags -T trunk -b branches -o svntrunk -v
         'http://martin%40catalyst.net.nz:password@nameless.server.org/svn/someproject'

The repo has LDAP authentication, and the username is my email
address, so I guessed that url-encoding would work, and it did.

svnimport is a bit of a mistery actually. I often know if it's really
doing the import or the files are going to be there but empty. SVN is
so flexible in its "everything is a directory" way of thinking that if
I mess up -t or -b I get the commits alright... but no files.

Strange world, svn ;-)


martin

^ permalink raw reply

* Re: [PATCH] Add a Documentation/git-tools.txt
From: Marco Costalba @ 2006-02-20  6:21 UTC (permalink / raw)
  To: Jonas Fonseca; +Cc: git, junkio
In-Reply-To: <20060220020147.GB8759@diku.dk>

On 2/20/06, Jonas Fonseca <fonseca@diku.dk> wrote:
> Marco Costalba <mcostalba@gmail.com> wrote Sun, Feb 19, 2006:
> > +     - *gitview*  (contrib/)
> > +
> > +            gitview is a GTK based repository browser for git
> > +
> > +
> > +     - *gitweb* (ftp://ftp.kernel.org/pub/software/scm/gitweb/)
> > +
> > +            GITweb provides full-fledged web interface for GIT repositories.
>
> You can make it more asciidoc-friendly if you convert the list to use
> the format:
>
> *gitview* (contrib)::
>
>         gitview is a GTK based repository browser for git
>
> ftp://ftp.kernel.org/pub/software/scm/gitweb/[*gitweb*]::
>
>         GITweb provides full-fledged web interface for GIT repositories.
>
> --
> Jonas Fonseca
>

Thanks, I will change the format.

I am waiting to collect some more comments so to change git-tools.txt only once.

Marco

^ permalink raw reply

* Re: [PATCH] git-rev-list --help anywhere
From: Junio C Hamano @ 2006-02-20  5:52 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Alex Riesen, linux, git
In-Reply-To: <Pine.LNX.4.63.0602192023270.11855@wbgn013.biozentrum.uni-wuerzburg.de>

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> can someone please enlighten me why you need to see the usage, when you 
> cannot execute the command anyway?

I think Pasky gave rev-list just as an example, as I am sure
there are other lowlevel core tools, that share this same
unfriendliness.  Primarily, these tools are meant for scripting,
and not for end-user interactive use.  For this reason, it is
not high on my priority list to add --help to the lowlevel core
tools, although it would be nicer to have.

^ permalink raw reply

* Re: New shiny gitk
From: walt @ 2006-02-20  2:04 UTC (permalink / raw)
  To: git
In-Reply-To: <17400.23434.724188.649656@cargo.ozlabs.ibm.com>

Paul Mackerras wrote:
> I just created a branch called "new" in my gitk repository at
> 
> git://git.kernel.org/pub/scm/gitk/gitk.git

Thanks.  The new version seems to fix a bug I posted about
last week concerning searching on filenames.  I like it!

^ permalink raw reply

* Re: [PATCH] Add a Documentation/git-tools.txt
From: Jonas Fonseca @ 2006-02-20  2:01 UTC (permalink / raw)
  To: Marco Costalba; +Cc: git, junkio
In-Reply-To: <e5bfff550602190200j1ef3858as6a1564064dc81fef@mail.gmail.com>

Marco Costalba <mcostalba@gmail.com> wrote Sun, Feb 19, 2006:
> +	- *gitview*  (contrib/)
> +
> +            gitview is a GTK based repository browser for git
> +
> +
> +	- *gitweb* (ftp://ftp.kernel.org/pub/software/scm/gitweb/)
> +
> +            GITweb provides full-fledged web interface for GIT repositories.

You can make it more asciidoc-friendly if you convert the list to use
the format:

*gitview* (contrib)::

	gitview is a GTK based repository browser for git

ftp://ftp.kernel.org/pub/software/scm/gitweb/[*gitweb*]::

	GITweb provides full-fledged web interface for GIT repositories.

-- 
Jonas Fonseca

^ permalink raw reply

* [PATCH] Convert the git faq to asciidoc
From: Jonas Fonseca @ 2006-02-20  1:45 UTC (permalink / raw)
  To: Thomas Riboulet; +Cc: git
In-Reply-To: <22e91bb0602151636r2e70e60cpa5038f4b6caccc9c@mail.gmail.com>

Signed-off-by: Jonas Fonseca <fonseca@diku.dk>

---

Thomas Riboulet <riboulet@gmail.com> wrote Thu, Feb 16, 2006:
> Comments and suggestions are welcome (on the content, the form, format, etc ...)
> I'll try to add questions from the archives of this ml, I'm also open
> to any suggestions.

As promissed on the #git channel this patch converts the faq to asciidoc
format, with a few enhancements such as links to manpages and a TOC.

Previews at
http://www.diku.dk/hjemmesider/studerende/fonseca/git/git-faq.{html,txt,xml}.

---

 Makefile |   23 ++++++++
 faq.conf |   19 +++++++
 faq.txt  |  175 ++++++++++++++++++++++++++++++++++++++++++--------------------
 3 files changed, 161 insertions(+), 56 deletions(-)

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..09f6978
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,23 @@
+all: git-faq.html git-faq.xml git-faq.txt
+
+clean:
+	rm -f git-faq.html git-faq.xml git-faq.txt faq-toc.txt
+
+git-faq.html git-faq.xml git-faq.txt: faq.txt faq-toc.txt
+
+git-faq.xml:
+	asciidoc -f faq.conf -b docbook -d article -o $@ faq.txt
+
+git-faq.html: faq.txt faq-toc.txt
+	asciidoc -f faq.conf -b xhtml11 -d article -o $@ faq.txt
+
+git-faq.txt: git-faq.html
+	elinks --no-numbering --no-references --dump $< > $@
+
+faq-toc.txt: faq.txt
+	sed -n '/^\[\[/,/--/p' < $< | while read line; do \
+		case "$$line" in \
+		"[["*"]]") echo -n ". <<$$line, " | sed 's/\[\[\(.*\)\]\]/\1/' ;; \
+		--*)	   echo    ">>" ;; \
+		*)	   echo -n "$$line " ;; \
+		esac; done > $@
diff --git a/faq.conf b/faq.conf
new file mode 100644
index 0000000..fa16ad6
--- /dev/null
+++ b/faq.conf
@@ -0,0 +1,19 @@
+# AsciiDoc FAQ definitions
+
+[attributes]
+gitdoc-base=http://kernel.org/pub/software/scm/git/docs/
+cgdoc-base=http://kernel.org/pub/software/scm/cogito/docs/
+
+ifdef::backend-docbook[]
+[gitdoc-inlinemacro]
+<ulink url="{gitdoc-base}{target}.html">{0}</ulink>
+[cgdoc-inlinemacro]
+<ulink url="{cgdoc-base}{target}.html">{0}</ulink>
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+[gitdoc-inlinemacro]
+<a href="{gitdoc-base}{target}.html">{0}</a>
+[cgdoc-inlinemacro]
+<a href="{cgdoc-base}{target}.html">{0}</a>
+endif::backend-xhtml11[]
diff --git a/faq.txt b/faq.txt
index e719d04..9c7baa0 100644
--- a/faq.txt
+++ b/faq.txt
@@ -1,68 +1,131 @@
-Why the 'git' name ?
-
-As Linus' own words as the inventor of git : "git" can mean anything, depending on your mood.
-
-* random three-letter combination that is pronounceable, and not actually used by any common UNIX command. The fact that it is a mispronunciation of "get" may or may not be relevant.
-*  stupid. contemptible and despicable. simple. Take your pick from the dictionary of slang.
-* global information tracker": you're in a good mood, and it actually works for you. Angels sing, and a light suddenly fills the room.
-* "goddamn idiotic truckload of sh*t": when it breaks 
-
-
-Can I share a git public repository and use it in a CVS way ?
-
-Use cg-admin-setuprepo -g or do git-init-db --shared and some additional stuff. It's ok that refs aren't group writable, it's enough the directory is. See Cogito README or GIT's cvs-migration doc, "Emulating the CVS Development Model" for details.
-
-
-Git commit is dying telling me "fatal : empty ident <user@myhost> not allowed" , what's wrong ?
-
-Make sure your Full Name is not empty in chsh or the 5th field of your user line in /etc/passwd isn't empty. You can also set the GIT_AUTHOR_NAME environment variable. If you @myhost is empty make sure your hostname is correctly set.
-What's the difference between fetch and pull ?
-
-Fetch : download objects and a head from another repository.
-Pull : fetch (as defined above) and merge with the current development.
-See man git-fetch and git-pull or the tutorials for more details.
-
-
-
-Can I tell git to ignore files ?
-
-Yes. If you want to ignore files localy (only for you in your local work copy) put the files path in the repository in the .git/info/exclude file.
-
-If you want to make the ignore matters for all and everyone who checkouts the project you have to put the files path in the .gitignore in the tree itself.
-
-
-Can I import from cvs ?
-
-Yes. Use git-cvsimport. See the cvs-migration doc for more details.
-
-
-Can I import from svn ?
-
-Yes. Use git-svnimport. See the svn-import doc for more details.
+The git FAQ
+===========
+:Author:	Thomas Riboulet
+:CorpAuthor:	git mailing list
+
+//////////////////////////////////////////////////////////////////////////////
+A note about required info for FAQ entries. Please use the following template:
+
+	[[question-id]]
+	question?
+	---------
+	answer.
+
+The question-id + question will be used for generating a table of contents.
+//////////////////////////////////////////////////////////////////////////////
+
+// DocBook derived output will (hopefully) have it's own TOC
+ifdef::backend-xhtml11[]
+include::faq-toc.txt[]
+endif::backend-xhtml11[]
+
+[[git-name]]
+Why the 'git' name?
+-------------------
+In Linus' own words as the inventor of git: "git" can mean anything, depending
+on your mood:
+
+ - random three-letter combination that is pronounceable, and not actually
+   used by any common UNIX command. The fact that it is a mispronunciation of
+   "get" may or may not be relevant.
+ - stupid. contemptible and despicable. simple. Take your pick from the
+   dictionary of slang.
+ - global information tracker": you're in a good mood, and it actually works
+   for you. Angels sing, and a light suddenly fills the room.
+ - "goddamn idiotic truckload of sh*t": when it breaks 
+
+
+[[repo-sharing]]]
+Can I share a git public repository and use it in a CVS way?
+------------------------------------------------------------
+Use cg-admin-setuprepo -g or do git-init-db --shared and some additional
+stuff. It's ok that refs aren't group writable, it's enough the directory is.
+See Cogito README or GIT's cvs-migration doc, "Emulating the CVS Development
+Model" for details.
+
+
+[[empty-ident]]
+Git commit is dying telling me "fatal: empty ident <user@myhost> not allowed", what's wrong?
+--------------------------------------------------------------------------------------------
+Make sure your Full Name is not empty in chsh or the 5th field of your user
+line in `/etc/passwd` isn't empty. You can also set the `GIT_AUTHOR_NAME`
+environment variable. If your @myhost is empty make sure your hostname is
+correctly set. Use gitdoc:git-var[`git-var -l`] to make git display user
+identity variables.
+
+
+[[fetch-vs-pull]]
+What's the difference between fetch and pull?
+---------------------------------------------
+The short definition is:
+
+Fetch::	Download objects and a head from another repository.
+Pull::	Fetch (as defined above) and merge with the current development.
+
+See the gitdoc:git-fetch[git-fetch(1)] and gitdoc:git-pull[git-pull(1)]
+manpages or the tutorials for more details.
+
+
+[[gitignore]]
+Can I tell git to ignore files?
+-------------------------------
+Yes. If you want to ignore files localy (only for you in your local work copy)
+put the files path in the repository in the `.git/info/exclude` file.
+
+If you want to make the ignore matters for all and everyone who checkouts the
+project you have to put the files path in the `.gitignore` in the tree itself.
+
+
+[[import-cvs]]
+Can I import from CVS?
+----------------------
+Yes. Use git-cvsimport. See the gitdoc:git-cvsimport[git-cvsimport(1)] or
+gitdoc:cvs-migration[the CVS migration doc] for more detail.
+
+
+[[import-svn]]
+Can I import from svn?
+----------------------
+Yes. Use git-svnimport. See gitdoc:git-svnimport[git-svnimport(1)] for more
+details.
 
 
+[[import-arch]]
 Can I import from arch/baz/tla?
-
-Yes. Use git-archimport.
+-------------------------------
+Yes. Use git-svnimport. See gitdoc:git-archimport[git-archimport(1)] for more
+details.
 
 
+[[import-others]]
 Can I import from others?
+-------------------------
+Maybe -- check if http://www.darcs.net/DarcsWiki/Tailor[tailor.py] can do it.
 
-Maybe -- check if tailor.py can do it. Check http://www.darcs.net/DarcsWiki/Tailor.
-
-
-How old linus bk repos have been import to git ?
 
+[[linux-bk]]
+How was the old Linux BitKeeper repository imported into git?
+-------------------------------------------------------------
 Using the CVS gateway, via git-cvsimport.
 
 
-What can I use to setup a public repository ?
-
-A ssh server, an http server, or the git-daemon. See the tutorial for more details.
-
-
-Why won't git let me change to a different branch using "git checkout <branch>" or "git checkout -b <branch>"?
-
-Instead it just says: fatal: Entry 'foo.c' not uptodate. Cannot merge.
+[[public-repo]]
+What can I use to setup a public repository?
+--------------------------------------------
+A SSH server, an HTTP server, or the gitdoc:git-daemon[git-daemon]. See the
+tutorial for more details.
+
+
+[[change-branch]]
+Why won't git let me change to a different branch?
+--------------------------------------------------
+Using "git checkout <branch>" or "git checkout -b <branch>" it just says:
+
+	fatal: Entry 'foo.c' not uptodate. Cannot merge.
+
+You have changes to files in your working directory that will be overwritten,
+removed or otherwise lost if the checkout and change to the new branch were to
+proceed. To fix this you may either check your changes in, create a patch of
+your changes and revert your files, or use the "-m" flag like this:
 
-You have changes to files in your working directory that will be overwritten, removed or otherwise lost if the checkout and change to the new branch were to proceed. To fix this you may either check your changes in, create a patch of your changes and revert your files, or use the "-m" flag like this: git checkout -m -b my-branch 
+	git checkout -m -b my-branch

-- 
Jonas Fonseca

^ permalink raw reply related

* Re: Fixing author/email fields in commit messages
From: Jacob Kroon @ 2006-02-20  1:21 UTC (permalink / raw)
  To: Jon Nelson; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0602191729100.6352@gheavc.wnzcbav.cig>

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

After some more private discussion (I forgot to CC the mailing list) 
with Jon Nelson,
he came up with this strategy for fixing the author/email part of commit 
messages:

0. Make a backup copy of the repository, just in case.

1. Setup your GIT_AUTHOR_xxx/GIT_COMMITTER_xxx env. variables correctly.

2. Apply the attached patch to recent git sources. (patch made by Jon 
Nelson).

3. Run the patched git-convert-objects, passing HEAD as argument.

4. Run "git-update-ref HEAD 'newsha1'", where 'newsha1' is the output 
from the previous command.

5. Run "git-prune" to get rid of the old stale object files.

This worked for me, but I guess there are no warranties 8)
In case you have multiple branches you might need to repeat the 
procedure for each branch.

thanks Jon

//Jacob

[-- Attachment #2: convert-objects.diff --]
[-- Type: text/x-patch, Size: 9372 bytes --]

diff --git a/convert-objects.c b/convert-objects.c
index b49bce2..109bfb0 100644
--- a/convert-objects.c
+++ b/convert-objects.c
@@ -263,7 +263,156 @@ static void convert_date(void *buffer, u
 	newlen += size;
 
 	write_sha1_file(new, newlen, "commit", result_sha1);
-	free(new);	
+	free(new);
+}
+
+static int convert_email_line(char *dst, void **buf, unsigned long *sp, const char *name, const char *new_email)
+{
+        unsigned long size = *sp;
+        char *line = *buf;
+        char *space = strchr(line, ' ');
+	char *next = strchr(line, '\n');
+	char *email_start = strchr(line, '<');
+        char *email_end = strchr(line, '>');
+        int len, total = 0;
+
+	// "author|committer xyz <xyz> date"
+        // "committer xyz <xyz> date"
+	if (!space || !next || !email_start || !email_end)
+            die("missing or bad author/committer line %s", line);
+
+        ++space;
+        ++email_start;
+        ++next;
+
+        //fprintf(stderr, "yikes: size; %lu \"%s\"\n", size, line);
+
+        *buf = next;
+        *sp = size - (next - line);
+
+        /* copy the stuff from before the name */
+        len = space - line;
+        memcpy(dst, line, len);
+        dst += len;
+        total += len;
+        size -= len;
+
+        /* copy the new name */
+        len = strlen(name);
+        memcpy(dst, name, len);
+        dst += len;
+        total += len;
+        size -= len;
+
+        /* put a space in there */
+        *dst = ' ';
+        ++dst;
+        ++total;
+        --size;
+
+        /* put a '<' in there */
+        *dst = '<';
+        ++dst;
+        ++total;
+        --size;
+
+        /* copy the new email */
+        len = strlen(new_email);
+        memcpy(dst, new_email, len);
+        dst += len;
+        total += len;
+        size -= len;
+
+        /* copy the rest of the line */
+        len = next - email_end;
+        memcpy(dst, email_end, len);
+        dst += len;
+        total += len;
+        size -= len;
+
+        return total;
+}
+
+static void convert_authorcommitter(void *buffer, unsigned long size, unsigned char *result_sha1)
+{
+	char *new = xmalloc(size + 100);
+        unsigned long newlen = 0;
+        char *author_info = strdup(git_author_info());
+        char *committer_info = strdup(git_committer_info());
+        char *author_name, *author_email;
+        char *committer_name, *committer_email;
+        char *temp;
+
+//#define TESTING
+#ifdef TESTING
+        fprintf(stderr, "author_info: \"%s\"\n",
+                author_info);
+        fprintf(stderr, "committer_info: \"%s\"\n",
+                committer_info);
+#endif
+        author_name = author_info;
+        temp = strchr(author_name, '<');
+        if (!temp)
+            die("Unable to find valid name address.");
+        --temp;
+        *temp = '\0';
+        temp += 2;
+
+        author_email = temp;
+        temp = strrchr(author_email, '>');
+        if (!temp)
+            die("Unable to find valid email address.");
+        *temp = '\0';
+
+        committer_name = committer_info;
+        temp = strchr(committer_name, '<');
+        if (!temp)
+            die("Unable to find valid name address.");
+        --temp;
+        *temp = '\0';
+        temp += 2;
+
+        committer_email = temp;
+        temp = strrchr(committer_email, '>');
+        if (!temp)
+            die("Unable to find valid email address.");
+        *temp = '\0';
+
+#ifdef TESTING
+        fprintf(stderr, "author_name: \"%s\"\n", author_name);
+        fprintf(stderr, "author_email: \"%s\"\n", author_email);
+        fprintf(stderr, "committer_name: \"%s\"\n", committer_name);
+        fprintf(stderr, "committer_email: \"%s\"\n", committer_email);
+        exit(0);
+#endif
+
+	// "tree <sha1>\n"
+	memcpy(new + newlen, buffer, 46);
+	newlen += 46;
+	buffer += 46;
+	size -= 46;
+
+	// "parent <sha1>\n"
+	while (!memcmp(buffer, "parent ", 7)) {
+		memcpy(new + newlen, buffer, 48);
+		newlen += 48;
+		buffer += 48;
+		size -= 48;
+	}
+
+	// "author xyz <xyz> date"
+	// "committer xyz <xyz> date"
+        newlen += convert_email_line(new + newlen, &buffer, &size, author_name, author_email);
+        newlen += convert_email_line(new + newlen, &buffer, &size, committer_name, committer_email);
+
+	// Rest
+	memcpy(new + newlen, buffer, size);
+	newlen += size;
+
+	write_sha1_file(new, newlen, "commit", result_sha1);
+        free(new);
+        free(author_info);
+        free(committer_info);
 }
 
 static void convert_commit(void *buffer, unsigned long size, unsigned char *result_sha1)
@@ -279,7 +428,117 @@ static void convert_commit(void *buffer,
 		convert_ascii_sha1(buffer+7);
 		buffer += 48;
 	}
-	convert_date(orig_buffer, orig_size, result_sha1);
+	convert_authorcommitter(orig_buffer, orig_size, result_sha1);
+}
+
+static void convert_tag(void *buffer, unsigned long size, unsigned char *result_sha1)
+{
+	void *orig_buffer = buffer;
+
+	char *new = xmalloc(size + 100);
+        unsigned long newlen = 0;
+
+        char *author_info = strdup(git_author_info());
+        char *committer_info = strdup(git_committer_info());
+        char *author_name, *author_email;
+        char *committer_name, *committer_email;
+        char *temp;
+        unsigned long len = 0;
+        char *email_start;
+        char *email_end;
+        char *author_start;
+        int has_author = 1;
+
+        author_name = author_info;
+        temp = strchr(author_name, '<');
+        if (!temp)
+            die("Unable to find valid name address.");
+        --temp;
+        *temp = '\0';
+        temp += 2;
+
+        author_email = temp;
+        temp = strrchr(author_email, '>');
+        if (!temp)
+            die("Unable to find valid email address.");
+        *temp = '\0';
+
+        committer_name = committer_info;
+        temp = strchr(committer_name, '<');
+        if (!temp)
+            die("Unable to find valid name address.");
+        --temp;
+        *temp = '\0';
+        temp += 2;
+
+        committer_email = temp;
+        temp = strrchr(committer_email, '>');
+        if (!temp)
+            die("Unable to find valid email address.");
+        *temp = '\0';
+
+        //* START *//
+
+	if (memcmp(buffer, "object ", 7))
+		die("Bad tag '%s'", (char*) buffer);
+        convert_ascii_sha1(buffer+7);
+//        fprintf(stderr, "converting %s", (char *) (buffer + 7));
+        buffer += 7 + 40 + 1;    /* "object " + "hex sha1" + "\n" */
+        /* type commit
+           tag boa-0.94.14rc6
+           tagger...
+           */
+        /* with tagger, we check for tagger author_name <author_email>
+         * and if so, we convert that, too
+         */
+        temp = strchr(buffer, '\n'); /* end of commit line */
+        if (!temp) {
+            die("Bad tag '%s'", (char *) buffer);
+        }
+        ++temp;
+        temp = strchr(temp, '\n'); /* end of tag line */
+        if (!temp) {
+            die("Bad tag '%s'", (char *) buffer);
+        }
+        ++temp;
+        if (memcmp(temp, "tagger ", 7))
+            die("Bad tag '%s'", (char *) buffer);
+        temp += 7; /* just after 'tagger ' */
+
+        len = (temp - (char *) orig_buffer);
+        memcpy(new, orig_buffer, len);
+        newlen += len;
+        ++temp;
+
+        /* check to see if the next item looks like an name + email */
+        email_start = strchr(temp, '<');
+        if (email_start) {
+            email_end = strchr(email_start, '>');
+            if (email_end) {
+                author_start = strchr(temp, ' ');
+                if (author_start && author_start < email_start) {
+                    has_author = 1;
+                    newlen += sprintf(new + newlen,
+                                      "%s <%s>\n",
+                                      author_name,
+                                      author_email);
+                    len = (email_end - (char *) buffer) + 2;
+                }
+
+            }
+        }
+
+        if (len > size) {
+            memcpy(new + newlen, orig_buffer + len, size - len);
+            newlen += (size - len);
+        }
+//        fprintf(stderr, "About to write: %s", new);
+//        exit(0);
+
+        write_sha1_file(new, newlen, "tag", result_sha1);
+        free(new);
+        free(author_info);
+        free(committer_info);
 }
 
 static struct entry * convert_entry(unsigned char *sha1)
@@ -297,13 +556,15 @@ static struct entry * convert_entry(unsi
 
 	buffer = xmalloc(size);
 	memcpy(buffer, data, size);
-	
+
 	if (!strcmp(type, "blob")) {
 		write_sha1_file(buffer, size, "blob", entry->new_sha1);
-	} else if (!strcmp(type, "tree"))
-		convert_tree(buffer, size, entry->new_sha1);
-	else if (!strcmp(type, "commit"))
-		convert_commit(buffer, size, entry->new_sha1);
+        } else if (!strcmp(type, "tree"))
+            convert_tree(buffer, size, entry->new_sha1);
+        else if (!strcmp(type, "commit"))
+            convert_commit(buffer, size, entry->new_sha1);
+        else if (!strcmp(type, "tag"))
+            convert_tag(buffer, size, entry->new_sha1);
 	else
 		die("unknown object type '%s' in %s", type, sha1_to_hex(sha1));
 	entry->converted = 1;
@@ -318,6 +579,7 @@ int main(int argc, char **argv)
 	struct entry *entry;
 
 	setup_git_directory();
+	setup_ident();
 
 	if (argc != 2 || get_sha1(argv[1], sha1))
 		usage("git-convert-objects <sha1>");

^ permalink raw reply related

* Re: Fixing author/email fields in commit messages
From: Jon Nelson @ 2006-02-19 23:34 UTC (permalink / raw)
  Cc: git
In-Reply-To: <43F9005E.30901@gmail.com>

On Mon, 20 Feb 2006, Jacob Kroon wrote:

> Jon Nelson wrote:
> 
> > >I modified git-convert-objects to perform just that task.
> > >I'll see if I can dig it up (I'm not able to do so right now).
> > >    
> > >
> >
> >Attached. Notes:
> >
> >1. it's ugly
> >2. it's indented funny
> >3. it didn't seem to break anything for me, but no guarantees
> >4. it probably smells of elderberries
> >5. set your GIT_* environment up properly first or you'll wonder why it
> >doesn't work like I did.
> >
> >  
> >
> Hi Jon,
> 
> I've applied your patch to the latest git sources, and it compiles, but I'm
> not quite sure how to
> invoke the command. I've setup GIT_* env. variables, and git-convert-objects
> needs a sha1 identifier.
> I've tried passing "HEAD", and some other commit id's, but they don't seem to
> make any difference.
> Am I doing things right ? How exactly do I invoke the command to clean up the
> commit messages ?
> 
> At least I don't get any error messages.

If I recall properly, it should be sufficient to invoke it with the sha1 
of the HEAD branch.  

Thus, you could use:

git-convert-objects $(git-rev-list --max-count=1 HEAD)

To do /all/ of the branches:

for branch in $(cat .git/refs/heads/* | sort | uniq); do
  git-convert-objects ${branch}
done

It should work on tags, too, although I only tested on my own git stuff 
which was converted from cvs.

--
Jon Nelson <jnelson-git@jamponi.net>

^ permalink raw reply

* [PATCH] Thin pack - create packfile with missing delta base.
From: Junio C Hamano @ 2006-02-19 23:28 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: git

This goes together with "rev-list --object-edge" change, to feed
pack-objects list of edge commits in addition to the usual
object list.  Upon seeing such list, pack-objects loosens the
usual "self contained delta" constraints, and can produce delta
against blobs and trees contained in the edge commits without
storing the delta base objects themselves.

The resulting packfile is not usable in .git/object/packs, but
is a good way to implement "delta-only" transfer.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 * For "delta transfer"; this comes on top of "next".

 pack-objects.c |  298 +++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 218 insertions(+), 80 deletions(-)

630dcb88482d99b77f83e1ed67b24d4026183c81
diff --git a/pack-objects.c b/pack-objects.c
index 0c9f4c9..fc923c9 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -3,6 +3,7 @@
 #include "delta.h"
 #include "pack.h"
 #include "csum-file.h"
+#include "diff.h"
 #include <sys/time.h>
 
 static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
@@ -26,6 +27,13 @@ struct object_entry {
 	struct object_entry *delta_sibling; /* other deltified objects who
 					     * uses the same base as me
 					     */
+	int preferred_base;	/* we do not pack this, but is encouraged to
+				 * be used as the base objectto delta huge
+				 * objects against.
+				 */
+	int based_on_preferred;	/* current delta candidate is a preferred
+				 * one, or delta against a preferred one.
+				 */
 };
 
 /*
@@ -48,7 +56,7 @@ static int local = 0;
 static int incremental = 0;
 static struct object_entry **sorted_by_sha, **sorted_by_type;
 static struct object_entry *objects = NULL;
-static int nr_objects = 0, nr_alloc = 0;
+static int nr_objects = 0, nr_alloc = 0, nr_result = 0;
 static const char *base_name;
 static unsigned char pack_file_sha1[20];
 static int progress = 1;
@@ -229,7 +237,8 @@ static int encode_header(enum object_typ
 	return n;
 }
 
-static unsigned long write_object(struct sha1file *f, struct object_entry *entry)
+static unsigned long write_object(struct sha1file *f,
+				  struct object_entry *entry)
 {
 	unsigned long size;
 	char type[10];
@@ -239,6 +248,9 @@ static unsigned long write_object(struct
 	enum object_type obj_type;
 	int to_reuse = 0;
 
+	if (entry->preferred_base)
+		return 0;
+
 	obj_type = entry->type;
 	if (! entry->in_pack)
 		to_reuse = 0;	/* can't reuse what we don't have */
@@ -326,10 +338,11 @@ static void write_pack_file(void)
 	if (!base_name)
 		f = sha1fd(1, "<stdout>");
 	else
-		f = sha1create("%s-%s.%s", base_name, sha1_to_hex(object_list_sha1), "pack");
+		f = sha1create("%s-%s.%s", base_name,
+			       sha1_to_hex(object_list_sha1), "pack");
 	hdr.hdr_signature = htonl(PACK_SIGNATURE);
 	hdr.hdr_version = htonl(PACK_VERSION);
-	hdr.hdr_entries = htonl(nr_objects);
+	hdr.hdr_entries = htonl(nr_result);
 	sha1write(f, &hdr, sizeof(hdr));
 	offset = sizeof(hdr);
 	for (i = 0; i < nr_objects; i++)
@@ -341,9 +354,10 @@ static void write_pack_file(void)
 static void write_index_file(void)
 {
 	int i;
-	struct sha1file *f = sha1create("%s-%s.%s", base_name, sha1_to_hex(object_list_sha1), "idx");
+	struct sha1file *f = sha1create("%s-%s.%s", base_name,
+					sha1_to_hex(object_list_sha1), "idx");
 	struct object_entry **list = sorted_by_sha;
-	struct object_entry **last = list + nr_objects;
+	struct object_entry **last = list + nr_result;
 	unsigned int array[256];
 
 	/*
@@ -368,7 +382,7 @@ static void write_index_file(void)
 	 * Write the actual SHA1 entries..
 	 */
 	list = sorted_by_sha;
-	for (i = 0; i < nr_objects; i++) {
+	for (i = 0; i < nr_result; i++) {
 		struct object_entry *entry = *list++;
 		unsigned int offset = htonl(entry->offset);
 		sha1write(f, &offset, 4);
@@ -378,27 +392,87 @@ static void write_index_file(void)
 	sha1close(f, NULL, 1);
 }
 
-static int add_object_entry(unsigned char *sha1, unsigned int hash)
+static int locate_object_entry_hash(const unsigned char *sha1)
+{
+	int i;
+	unsigned int ui;
+	memcpy(&ui, sha1, sizeof(unsigned int));
+	i = ui % object_ix_hashsz;
+	while (0 < object_ix[i]) {
+		if (!memcmp(sha1, objects[object_ix[i]-1].sha1, 20))
+			return i;
+		if (++i == object_ix_hashsz)
+			i = 0;
+	}
+	return -1 - i;
+}
+
+static struct object_entry *locate_object_entry(const unsigned char *sha1)
+{
+	int i;
+
+	if (!object_ix_hashsz)
+		return NULL;
+
+	i = locate_object_entry_hash(sha1);
+	if (0 <= i)
+		return &objects[object_ix[i]-1];
+	return NULL;
+}
+
+static void rehash_objects(void)
 {
+	int i;
+	struct object_entry *oe;
+
+	object_ix_hashsz = nr_objects * 2;
+	if (object_ix_hashsz < 256)
+		object_ix_hashsz = 256;
+	object_ix = xrealloc(object_ix, sizeof(int) * object_ix_hashsz);
+	object_ix = memset(object_ix, 0, sizeof(int) * object_ix_hashsz);
+	for (i = 0, oe = objects; i < nr_objects; i++, oe++) {
+		int ix = locate_object_entry_hash(oe->sha1);
+		if (0 <= ix)
+			continue;
+		ix = -1 - ix;
+		object_ix[ix] = i + 1;
+	}
+}
+
+static int add_object_entry(const unsigned char *sha1, const char *name, int exclude)
+{
+	unsigned int hash = 0;
 	unsigned int idx = nr_objects;
 	struct object_entry *entry;
 	struct packed_git *p;
 	unsigned int found_offset = 0;
 	struct packed_git *found_pack = NULL;
+	int ix;
 
-	for (p = packed_git; p; p = p->next) {
-		struct pack_entry e;
-		if (find_pack_entry_one(sha1, &e, p)) {
-			if (incremental)
-				return 0;
-			if (local && !p->pack_local)
-				return 0;
-			if (!found_pack) {
-				found_offset = e.offset;
-				found_pack = e.p;
+	if (!exclude) {
+		for (p = packed_git; p; p = p->next) {
+			struct pack_entry e;
+			if (find_pack_entry_one(sha1, &e, p)) {
+				if (incremental)
+					return 0;
+				if (local && !p->pack_local)
+					return 0;
+				if (!found_pack) {
+					found_offset = e.offset;
+					found_pack = e.p;
+				}
 			}
 		}
 	}
+	if ((entry = locate_object_entry(sha1)) != NULL)
+		goto already_added;
+
+	while (*name) {
+		unsigned char c = *name++;
+		if (isspace(c))
+			continue;
+		hash = hash * 11 + c;
+	}
 
 	if (idx >= nr_alloc) {
 		unsigned int needed = (idx + 1024) * 3 / 2;
@@ -406,45 +480,79 @@ static int add_object_entry(unsigned cha
 		nr_alloc = needed;
 	}
 	entry = objects + idx;
+	nr_objects = idx + 1;
 	memset(entry, 0, sizeof(*entry));
 	memcpy(entry->sha1, sha1, 20);
 	entry->hash = hash;
-	if (found_pack) {
-		entry->in_pack = found_pack;
-		entry->in_pack_offset = found_offset;
+
+	if (object_ix_hashsz <= nr_objects * 2)
+		rehash_objects();
+	else {
+		ix = locate_object_entry_hash(entry->sha1);
+		if (0 <= ix)
+			die("internal error in object hashing.");
+		object_ix[-1 - ix] = idx + 1;
+	}
+
+ already_added:
+	if (exclude)
+		entry->preferred_base = 1;
+	else {
+		if (found_pack) {
+			entry->in_pack = found_pack;
+			entry->in_pack_offset = found_offset;
+		}
 	}
-	nr_objects = idx+1;
 	return 1;
 }
 
-static int locate_object_entry_hash(unsigned char *sha1)
+static void add_pbase_tree(struct tree_desc *tree)
 {
-	int i;
-	unsigned int ui;
-	memcpy(&ui, sha1, sizeof(unsigned int));
-	i = ui % object_ix_hashsz;
-	while (0 < object_ix[i]) {
-		if (!memcmp(sha1, objects[object_ix[i]-1].sha1, 20))
-			return i;
-		if (++i == object_ix_hashsz)
-			i = 0;
+	while (tree->size) {
+		const unsigned char *sha1;
+		const char *name;
+		unsigned mode;
+		unsigned long size;
+		char type[20];
+
+		sha1 = tree_entry_extract(tree, &name, &mode);
+		update_tree_entry(tree);
+		if (!has_sha1_file(sha1))
+			continue;
+		if (sha1_object_info(sha1, type, &size))
+			continue;
+		add_object_entry(sha1, name, 1);
+		if (!strcmp(type, "tree")) {
+			struct tree_desc sub;
+			void *elem;
+			elem = read_sha1_file(sha1, type, &sub.size);
+			sub.buf = elem;
+			if (sub.buf) {
+				add_pbase_tree(&sub);
+				free(elem);
+			}
+		}
 	}
-	return -1 - i;
 }
 
-static struct object_entry *locate_object_entry(unsigned char *sha1)
+static void add_preferred_base(unsigned char *sha1)
 {
-	int i = locate_object_entry_hash(sha1);
-	if (0 <= i)
-		return &objects[object_ix[i]-1];
-	return NULL;
+	struct tree_desc tree;
+	void *elem;
+	elem = read_object_with_reference(sha1, "tree", &tree.size, NULL);
+	tree.buf = elem;
+	if (!tree.buf)
+		return;
+	add_object_entry(sha1, "", 1);
+	add_pbase_tree(&tree);
+	free(elem);
 }
 
 static void check_object(struct object_entry *entry)
 {
 	char type[20];
 
-	if (entry->in_pack) {
+	if (entry->in_pack && !entry->preferred_base) {
 		unsigned char base[20];
 		unsigned long size;
 		struct object_entry *base_entry;
@@ -463,7 +571,8 @@ static void check_object(struct object_e
 		 */
 		if (!no_reuse_delta &&
 		    entry->in_pack_type == OBJ_DELTA &&
-		    (base_entry = locate_object_entry(base))) {
+		    (base_entry = locate_object_entry(base)) &&
+		    (!base_entry->preferred_base)) {
 
 			/* Depth value does not matter - find_deltas()
 			 * will never consider reused delta as the
@@ -501,25 +610,6 @@ static void check_object(struct object_e
 		    sha1_to_hex(entry->sha1), type);
 }
 
-static void hash_objects(void)
-{
-	int i;
-	struct object_entry *oe;
-
-	object_ix_hashsz = nr_objects * 2;
-	object_ix = xcalloc(sizeof(int), object_ix_hashsz);
-	for (i = 0, oe = objects; i < nr_objects; i++, oe++) {
-		int ix = locate_object_entry_hash(oe->sha1);
-		if (0 <= ix) {
-			error("the same object '%s' added twice",
-			      sha1_to_hex(oe->sha1));
-			continue;
-		}
-		ix = -1 - ix;
-		object_ix[ix] = i + 1;
-	}
-}
-
 static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)
 {
 	struct object_entry *child = me->delta_child;
@@ -538,7 +628,6 @@ static void get_object_details(void)
 	int i;
 	struct object_entry *entry;
 
-	hash_objects();
 	prepare_pack_ix();
 	for (i = 0, entry = objects; i < nr_objects; i++, entry++)
 		check_object(entry);
@@ -576,6 +665,24 @@ static int sha1_sort(const struct object
 	return memcmp(a->sha1, b->sha1, 20);
 }
 
+static struct object_entry **create_final_object_list()
+{
+	struct object_entry **list;
+	int i, j;
+
+	for (i = nr_result = 0; i < nr_objects; i++)
+		if (!objects[i].preferred_base)
+			nr_result++;
+	list = xmalloc(nr_result * sizeof(struct object_entry *));
+	for (i = j = 0; i < nr_objects; i++) {
+		if (!objects[i].preferred_base)
+			list[j++] = objects + i;
+	}
+	current_sort = sha1_sort;
+	qsort(list, nr_result, sizeof(struct object_entry *), sort_comparator);
+	return list;
+}
+
 static int type_size_sort(const struct object_entry *a, const struct object_entry *b)
 {
 	if (a->type < b->type)
@@ -586,6 +693,10 @@ static int type_size_sort(const struct o
 		return -1;
 	if (a->hash > b->hash)
 		return 1;
+	if (a->preferred_base < b->preferred_base)
+		return -1;
+	if (a->preferred_base > b->preferred_base)
+		return 1;
 	if (a->size < b->size)
 		return -1;
 	if (a->size > b->size)
@@ -610,6 +721,8 @@ static int try_delta(struct unpacked *cu
 {
 	struct object_entry *cur_entry = cur->entry;
 	struct object_entry *old_entry = old->entry;
+	int old_preferred = (old_entry->preferred_base ||
+			     old_entry->based_on_preferred);
 	unsigned long size, oldsize, delta_size, sizediff;
 	long max_size;
 	void *delta_buf;
@@ -618,9 +731,15 @@ static int try_delta(struct unpacked *cu
 	if (cur_entry->type != old_entry->type)
 		return -1;
 
-	/* If the current object is at edge, take the depth the objects
-	 * that depend on the current object into account -- otherwise
-	 * they would become too deep.
+	/* We do not compute delta to *create* objects we are not
+	 * going to pack.
+	 */
+	if (cur_entry->preferred_base)
+		return -1;
+
+	/* If the current object is at pack edge, take the depth the
+	 * objects that depend on the current object into account --
+	 * otherwise they would become too deep.
 	 */
 	if (cur_entry->delta_child) {
 		if (max_depth <= cur_entry->delta_limit)
@@ -646,8 +765,27 @@ static int try_delta(struct unpacked *cu
 	 * delete).
 	 */
 	max_size = size / 2 - 20;
-	if (cur_entry->delta)
-		max_size = cur_entry->delta_size-1;
+	if (cur_entry->delta) {
+		if (cur_entry->based_on_preferred) {
+			if (old_preferred)
+				max_size = cur_entry->delta_size-1;
+			else
+				/* trying with non-preferred one when we
+				 * already have a delta based on preferred
+				 * one is pointless.
+				 */
+				return 0;
+		}
+		else if (!old_preferred)
+			max_size = cur_entry->delta_size-1;
+		else
+			/* otherwise...  even if delta with a
+			 * preferred one produces a bigger result than
+			 * what we currently have, which is based on a
+			 * non-preferred one, it is OK.
+			 */
+			;
+	}
 	if (sizediff >= max_size)
 		return -1;
 	delta_buf = diff_delta(old->data, oldsize,
@@ -657,6 +795,7 @@ static int try_delta(struct unpacked *cu
 	cur_entry->delta = old_entry;
 	cur_entry->delta_size = delta_size;
 	cur_entry->depth = old_entry->depth + 1;
+	cur_entry->based_on_preferred = old_preferred;
 	free(delta_buf);
 	return 0;
 }
@@ -722,7 +861,7 @@ static void find_deltas(struct object_en
 static void prepare_pack(int window, int depth)
 {
 	if (progress)
-		fprintf(stderr, "Packing %d objects", nr_objects);
+		fprintf(stderr, "Packing %d objects", nr_result);
 	get_object_details();
 	if (progress)
 		fputc('.', stderr);
@@ -861,8 +1000,6 @@ int main(int argc, char **argv)
 		gettimeofday(&prev_tv, NULL);
 	}
 	while (fgets(line, sizeof(line), stdin) != NULL) {
-		unsigned int hash;
-		char *p;
 		unsigned char sha1[20];
 
 		if (progress && (eye_candy <= nr_objects)) {
@@ -881,31 +1018,32 @@ int main(int argc, char **argv)
 			}
 			eye_candy += eye_candy_incr;
 		}
+		if (line[0] == '-') {
+			if (get_sha1_hex(line+1, sha1))
+				die("expected edge sha1, got garbage:\n %s",
+				    line+1);
+			add_preferred_base(sha1);
+			continue;
+		}
 		if (get_sha1_hex(line, sha1))
 			die("expected sha1, got garbage:\n %s", line);
-		hash = 0;
-		p = line+40;
-		while (*p) {
-			unsigned char c = *p++;
-			if (isspace(c))
-				continue;
-			hash = hash * 11 + c;
-		}
-		add_object_entry(sha1, hash);
+		add_object_entry(sha1, line+40, 0);
 	}
 	if (progress)
 		fprintf(stderr, "Done counting %d objects.\n", nr_objects);
 	if (non_empty && !nr_objects)
 		return 0;
 
-	sorted_by_sha = create_sorted_list(sha1_sort);
+	sorted_by_sha = create_final_object_list();
 	SHA1_Init(&ctx);
 	list = sorted_by_sha;
-	for (i = 0; i < nr_objects; i++) {
+	for (i = 0; i < nr_result; i++) {
 		struct object_entry *entry = *list++;
 		SHA1_Update(&ctx, entry->sha1, 20);
 	}
 	SHA1_Final(object_list_sha1, &ctx);
+	if (progress && (nr_objects != nr_result))
+		fprintf(stderr, "Result has %d objects.\n", nr_result);
 
 	if (reuse_cached_pack(object_list_sha1, pack_to_stdout))
 		;
@@ -918,6 +1056,6 @@ int main(int argc, char **argv)
 	}
 	if (progress)
 		fprintf(stderr, "Total %d, written %d (delta %d), reused %d (delta %d)\n",
-			nr_objects, written, written_delta, reused, reused_delta);
+			nr_result, written, written_delta, reused, reused_delta);
 	return 0;
 }
-- 
1.2.2.g0d27

^ permalink raw reply related

* [PATCH] send-pack --thin: use "thin pack" delta transfer.
From: Junio C Hamano @ 2006-02-19 23:28 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: git

The new flag loosens the usual "self containedness" requirment
of packfiles, and sends deltified representation of objects when
we know the other side has the base objects needed to unpack
them.  This would help reducing the transfer size.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 * Together with the other two patches, this allows you to say
   "git-send-pack --thin" to implement the "delta transfer" we
   discussed earlier.

 send-pack.c |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

7830d82ec3103e3e4c099750620626b3d53530be
diff --git a/send-pack.c b/send-pack.c
index 990be3f..ad22da5 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -12,6 +12,7 @@ static const char *exec = "git-receive-p
 static int verbose = 0;
 static int send_all = 0;
 static int force_update = 0;
+static int use_thin_pack = 0;
 
 static int is_zero_sha1(const unsigned char *sha1)
 {
@@ -41,7 +42,10 @@ static void exec_rev_list(struct ref *re
 	int i = 0;
 
 	args[i++] = "rev-list";	/* 0 */
-	args[i++] = "--objects";	/* 1 */
+	if (use_thin_pack)	/* 1 */
+		args[i++] = "--objects-edge";
+	else
+		args[i++] = "--objects";
 	while (refs) {
 		char *buf = malloc(100);
 		if (i > 900)
@@ -361,6 +365,10 @@ int main(int argc, char **argv)
 				verbose = 1;
 				continue;
 			}
+			if (!strcmp(arg, "--thin")) {
+				use_thin_pack = 1;
+				continue;
+			}
 			usage(send_pack_usage);
 		}
 		if (!dest) {
-- 
1.2.2.g0d27

^ permalink raw reply related

* [PATCH] rev-list --objects-edge
From: Junio C Hamano @ 2006-02-19 23:28 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: git

This new flag is similar to --objects, but causes rev-list to
show list of "uninteresting" commits that appear on the edge
commit prefixed with '-'.

Downstream pack-objects will be changed to take these as hints
to use the trees and blobs contained with them as base objects
of resulting pack, producing an incomplete (not self-contained)
pack.

Such a pack cannot be used in .git/objects/pack (it is prevented
by git-index-pack erroring out if it is fed to git-fetch-pack -k
or git-clone-pack), but would be useful when transferring only
small changes to huge blobs.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 * Together with "thin-pack" patch I'll send next, this will
   allow you to do the "delta transfer" we discussed on the #git
   channel last night (eh, *my* last night anyway).

 rev-list.c  |   34 ++++++++++++++++++++++++++++------
 rev-parse.c |    1 +
 2 files changed, 29 insertions(+), 6 deletions(-)

52de788e6094b31be218f0f69576cbbfb310205f
diff --git a/rev-list.c b/rev-list.c
index f2d1105..373549e 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -30,7 +30,7 @@ static const char rev_list_usage[] =
 "    --date-order\n"
 "  formatting output:\n"
 "    --parents\n"
-"    --objects\n"
+"    --objects | --objects-edge\n"
 "    --unpacked\n"
 "    --header | --pretty\n"
 "    --abbrev=nr | --no-abbrev\n"
@@ -44,6 +44,7 @@ static int bisect_list = 0;
 static int tag_objects = 0;
 static int tree_objects = 0;
 static int blob_objects = 0;
+static int edge_hint = 0;
 static int verbose_header = 0;
 static int abbrev = DEFAULT_ABBREV;
 static int show_parents = 0;
@@ -430,16 +431,30 @@ static struct commit_list *find_bisectio
 	return best;
 }
 
+static void mark_edge_parents_uninteresting(struct commit *commit)
+{
+	struct commit_list *parents;
+
+	for (parents = commit->parents; parents; parents = parents->next) {
+		struct commit *parent = parents->item;
+		if (!(parent->object.flags & UNINTERESTING))
+			continue;
+		mark_tree_uninteresting(parent->tree);
+		if (edge_hint)
+			printf("-%s\n", sha1_to_hex(parent->object.sha1));
+	}
+}
+
 static void mark_edges_uninteresting(struct commit_list *list)
 {
 	for ( ; list; list = list->next) {
-		struct commit_list *parents = list->item->parents;
+		struct commit *commit = list->item;
 
-		for ( ; parents; parents = parents->next) {
-			struct commit *commit = parents->item;
-			if (commit->object.flags & UNINTERESTING)
-				mark_tree_uninteresting(commit->tree);
+		if (commit->object.flags & UNINTERESTING) {
+			mark_tree_uninteresting(commit->tree);
+			continue;
 		}
+		mark_edge_parents_uninteresting(commit);
 	}
 }
 
@@ -843,6 +858,13 @@ int main(int argc, const char **argv)
 			blob_objects = 1;
 			continue;
 		}
+		if (!strcmp(arg, "--objects-edge")) {
+			tag_objects = 1;
+			tree_objects = 1;
+			blob_objects = 1;
+			edge_hint = 1;
+			continue;
+		}
 		if (!strcmp(arg, "--unpacked")) {
 			unpacked = 1;
 			limited = 1;
diff --git a/rev-parse.c b/rev-parse.c
index a5fb93c..610eacb 100644
--- a/rev-parse.c
+++ b/rev-parse.c
@@ -43,6 +43,7 @@ static int is_rev_argument(const char *a
 		"--min-age=",
 		"--no-merges",
 		"--objects",
+		"--objects-edge",
 		"--parents",
 		"--pretty",
 		"--show-breaks",
-- 
1.2.2.g0d27

^ permalink raw reply related

* Delta-transfer using thin-pack
From: Junio C Hamano @ 2006-02-19 23:27 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: git

I'll be sending out three experimental patches that would come
on top of "next".  With them, you should be able to:

	$ git send-pack --thin other/repo/sitory

and it would send deltified representation based on things not
in the transferred data.

This is somewhat experimental, although I tried it myself and it
seems to work with my limited test.  Do not push into your
production repository with it yet, but please do try it out.

How does it work?

"git send-pack" works by:

 (1) negotiating with the other end to find out what common
     commits our repository and the other one has;

 (2) computing the list of objects to send to the other end by
     running

     "git-rev-list --objects $heads `git-rev-parse --not $commons`"

     ($heads are what we are going to send, $commons are what
     they already have).

 (3) feeding (2) to git-pack-object --stdout, sending the result
     to the other end.

 (4) invoke git-receive-pack on the other end and have it read
     the output from (3), which will feed git-unpack-objects on
     the other end.

In general, the packfile is designed to be "self contained".
This is necessary in case we need to deal with more than one
huge packfiles that we can mmap only one at a time -- we
guarantee that the base object of a deltified object is found
while unpacking that deltified object because the base object
can always be found in the same pack.

However, during send-pack/receive-pack transfer, we will unpack
the resulting packfile on the other end into loose objects, so
it is not strictly necessary to require self-containedness to
the packfile used for the transfer.

^ permalink raw reply

* Re: Fixing author/email fields in commit messages
From: Jacob Kroon @ 2006-02-19 23:33 UTC (permalink / raw)
  To: Jon Nelson; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0602191651340.6352@gheavc.wnzcbav.cig>

Jon Nelson wrote:

>>I modified git-convert-objects to perform just that task.
>>I'll see if I can dig it up (I'm not able to do so right now).
>>    
>>
>
>Attached. Notes:
>
>1. it's ugly
>2. it's indented funny
>3. it didn't seem to break anything for me, but no guarantees
>4. it probably smells of elderberries
>5. set your GIT_* environment up properly first or you'll wonder why it 
>doesn't work like I did.
>
>  
>
Hi Jon,

I've applied your patch to the latest git sources, and it compiles, but 
I'm not quite sure how to
invoke the command. I've setup GIT_* env. variables, and 
git-convert-objects needs a sha1 identifier.
I've tried passing "HEAD", and some other commit id's, but they don't 
seem to make any difference.
Am I doing things right ? How exactly do I invoke the command to clean 
up the commit messages ?

At least I don't get any error messages.

//Jacob

^ 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