Git development
 help / color / mirror / Atom feed
* Re: the war on trailing whitespace
From: Linus Torvalds @ 2006-02-26 17:29 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Junio C Hamano, git
In-Reply-To: <20060225210712.29b30f59.akpm@osdl.org>



On Sat, 25 Feb 2006, Andrew Morton wrote:
> 
> I'd suggest a) git will simply refuse to apply such a patch unless given a
> special `forcing' flag, b) even when thus forced, it will still warn and c)
> with a different flag, it will strip-then-apply, without generating a
> warning.

This doesn't do the "strip-then-apply" thing, but it allows you to make 
git-apply generate a warning or error on extraneous whitespace.

Use --whitespace=warn to warn, and (surprise, surprise) --whitespace=error 
to make it a fatal error to have whitespace at the end.

Totally untested, of course. But it compiles, so it must be fine.

HOWEVER! Note that this literally will check every single patch-line with 
"+" at the beginning. Which means that if you fix a simple typo, and the 
line had a space at the end before, and you didn't remove it, that's still 
considered a "new line with whitespace at the end", even though obviously 
the line wasn't really new.

I assume this is what you wanted, and there isn't really any sane 
alternatives (you could make the warning activate only for _pure_ 
additions with no deletions at all in that hunk, but that sounds a bit 
insane).

		Linus

---
diff --git a/apply.c b/apply.c
index 244718c..e7b3dca 100644
--- a/apply.c
+++ b/apply.c
@@ -34,6 +34,12 @@ static int line_termination = '\n';
 static const char apply_usage[] =
 "git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] <patch>...";
 
+static enum whitespace_eol {
+	nowarn,
+	warn_on_whitespace,
+	error_on_whitespace
+} new_whitespace = nowarn;
+
 /*
  * For "diff-stat" like behaviour, we keep track of the biggest change
  * we've seen, and the longest filename. That allows us to do simple
@@ -815,6 +821,22 @@ static int parse_fragment(char *line, un
 			oldlines--;
 			break;
 		case '+':
+			/*
+			 * We know len is at least two, since we have a '+' and
+			 * we checked that the last character was a '\n' above
+			 */
+			if (isspace(line[len-2])) {
+				switch (new_whitespace) {
+				case nowarn:
+					break;
+				case warn_on_whitespace:
+					new_whitespace = nowarn;	/* Just once */
+					error("Added whitespace at end of line at line %d", linenr);
+					break;
+				case error_on_whitespace:
+					die("Added whitespace at end of line at line %d", linenr);
+				}
+			}
 			added++;
 			newlines--;
 			break;
@@ -1839,6 +1861,17 @@ int main(int argc, char **argv)
 			line_termination = 0;
 			continue;
 		}
+		if (!strncmp(arg, "--whitespace=", 13)) {
+			if (strcmp(arg+13, "warn")) {
+				new_whitespace = warn_on_whitespace;
+				continue;
+			}
+			if (strcmp(arg+13, "error")) {
+				new_whitespace = error_on_whitespace;
+				continue;
+			}
+			die("unrecognixed whitespace option '%s'", arg+13);
+		}
 
 		if (check_index && prefix_length < 0) {
 			prefix = setup_git_directory();

^ permalink raw reply related

* [PATCH] Use setenv(), fix warnings
From: Timo Hirvonen @ 2006-02-26 15:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


  - Use setenv() instead of putenv()
  - Fix -Wundef -Wold-style-definition warnings
  - Make pll_free() static

Signed-off-by: Timo Hirvonen <tihirvon@gmail.com>

---

 cache.h          |    2 +-
 exec_cmd.c       |    2 +-
 fetch-pack.c     |    2 +-
 fsck-objects.c   |    4 ++--
 pack-objects.c   |    2 +-
 pack-redundant.c |    4 ++--
 path.c           |    2 +-
 7 files changed, 9 insertions(+), 9 deletions(-)

4001390d41ffd2c816cead47c256e598bedff452
diff --git a/cache.h b/cache.h
index 5020f07..58eec00 100644
--- a/cache.h
+++ b/cache.h
@@ -10,7 +10,7 @@
 #define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
 #endif
 
-#if defined(DT_UNKNOWN) && !NO_D_TYPE_IN_DIRENT
+#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
 #define DTYPE(de)	((de)->d_type)
 #else
 #undef DT_UNKNOWN
diff --git a/exec_cmd.c b/exec_cmd.c
index 55af33b..b5e59a9 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -13,7 +13,7 @@ void git_set_exec_path(const char *exec_
 
 
 /* Returns the highest-priority, location to look for git programs. */
-const char *git_exec_path()
+const char *git_exec_path(void)
 {
 	const char *env;
 
diff --git a/fetch-pack.c b/fetch-pack.c
index 09738fe..535de10 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -82,7 +82,7 @@ static void mark_common(struct commit *c
   Get the next rev to send, ignoring the common.
 */
 
-static const unsigned char* get_rev()
+static const unsigned char* get_rev(void)
 {
 	struct commit *commit = NULL;
 
diff --git a/fsck-objects.c b/fsck-objects.c
index 6439d55..f9c69f5 100644
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -20,7 +20,7 @@ static int check_strict = 0;
 static int keep_cache_objects = 0; 
 static unsigned char head_sha1[20];
 
-#if NO_D_INO_IN_DIRENT
+#ifdef NO_D_INO_IN_DIRENT
 #define SORT_DIRENT 0
 #define DIRENT_SORT_HINT(de) 0
 #else
@@ -483,7 +483,7 @@ int main(int argc, char **argv)
 	if (standalone && check_full)
 		die("Only one of --standalone or --full can be used.");
 	if (standalone)
-		putenv("GIT_ALTERNATE_OBJECT_DIRECTORIES=");
+		setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", "", 1);
 
 	fsck_head_link();
 	fsck_object_dir(get_object_directory());
diff --git a/pack-objects.c b/pack-objects.c
index 0287449..21ee572 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -768,7 +768,7 @@ static int sha1_sort(const struct object
 	return memcmp(a->sha1, b->sha1, 20);
 }
 
-static struct object_entry **create_final_object_list()
+static struct object_entry **create_final_object_list(void)
 {
 	struct object_entry **list;
 	int i, j;
diff --git a/pack-redundant.c b/pack-redundant.c
index 1869b38..cd81f5a 100644
--- a/pack-redundant.c
+++ b/pack-redundant.c
@@ -45,7 +45,7 @@ static inline void llist_item_put(struct
 	free_nodes = item;
 }
 
-static inline struct llist_item *llist_item_get()
+static inline struct llist_item *llist_item_get(void)
 {
 	struct llist_item *new;
 	if ( free_nodes ) {
@@ -275,7 +275,7 @@ static void cmp_two_packs(struct pack_li
 	}
 }
 
-void pll_free(struct pll *l)
+static void pll_free(struct pll *l)
 {
 	struct pll *old;
 	struct pack_list *opl;
diff --git a/path.c b/path.c
index 334b2bd..6500a40 100644
--- a/path.c
+++ b/path.c
@@ -243,7 +243,7 @@ char *enter_repo(char *path, int strict)
 
 	if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
 	    validate_symref("HEAD") == 0) {
-		putenv("GIT_DIR=.");
+		setenv("GIT_DIR", ".", 1);
 		check_repository_format();
 		return path;
 	}
-- 
1.2.1

^ permalink raw reply related

* Re: [PATCH 4/4] Read author names and emails from a file
From: Andreas Ericsson @ 2006-02-26 11:49 UTC (permalink / raw)
  To: Karl Hasselström; +Cc: Git Mailing List
In-Reply-To: <20060226051131.24860.15804.stgit@backpacker.hemma.treskal.com>

Karl Hasselström wrote:
> Read a file with lines on the form
> 
>   username User's Full Name <email@addres.org>
> 
> and use "User's Full Name <email@addres.org>" as the GIT author and
> committer for Subversion commits made by "username". If encountering a
> commit made by a user not in the list, abort.
> 

This is a good thing, but wouldn't it be better to use the same format 
as that of cvsimport's -A flag? Also, I imagine one would like to save 
those files within the .git directory for incremental importing, also 
like cvsimport does.

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

^ permalink raw reply

* git-svn and working with tags
From: Nicolas Vilz 'niv' @ 2006-02-26 11:38 UTC (permalink / raw)
  To: git

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

Hi guys,

I am about to use a git/svn construct for a project next week to track
my work and the work of my co-workers.

Reason for this is, that all the others are working on windows-boxes and
I am the lonesome gunman, who wants to work with git on a linux box
contributing the others on svn side.

There is still a lot of work todo, preparing both backends, git and svn,
for serving almost the same content structure.

I think, i can do a little scripting to switch my git-SVN-HEAD to
another branch. But how am i intended to export tags to svn?

tags should simply go to <repos>/tags/<tagname>
branches go to <repos>/branches/<branchname>
master goes to <repos>/trunk

A svn-import should be no problem then. The re-exporting back to one
branch or svn_path is described in git-svn howto. but how about tags?

do i have to consider the tags on svn-side manually?

any ideas/hints?

Sincerly
Nicolas

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

^ permalink raw reply

* [PATCH] contrib/git-svn: optimize sequential commits to svn
From: Eric Wong @ 2006-02-26 10:22 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Eric Wong
In-Reply-To: <11409493473353-git-send-email-normalperson@yhbt.net>

Avoid running 'svn up' to a previous revision if we know the
revision we just committed is the first descendant of the
revision we came from.

This reduces the time to do a series of commits by about 25%.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/git-svn.perl |   30 +++++++++++++++++++++++++++---
 1 files changed, 27 insertions(+), 3 deletions(-)

ea810425ed7d5d16c12b3f49246ba2a03ac3d23d
diff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl
index 84d43de..29c8690 100755
--- a/contrib/git-svn/git-svn.perl
+++ b/contrib/git-svn/git-svn.perl
@@ -30,6 +30,7 @@ use File::Basename qw/dirname basename/;
 use File::Path qw/mkpath/;
 use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
 use File::Spec qw//;
+use POSIX qw/strftime/;
 my $sha1 = qr/[a-f\d]{40}/;
 my $sha1_short = qr/[a-f\d]{6,40}/;
 my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
@@ -591,6 +592,7 @@ sub handle_rmdir {
 sub svn_commit_tree {
 	my ($svn_rev, $commit) = @_;
 	my $commit_msg = "$GIT_DIR/$GIT_SVN/.svn-commit.tmp.$$";
+	my %log_msg = ( msg => '' );
 	open my $msg, '>', $commit_msg  or croak $!;
 
 	chomp(my $type = `git-cat-file -t $commit`);
@@ -606,6 +608,7 @@ sub svn_commit_tree {
 			if (!$in_msg) {
 				$in_msg = 1 if (/^\s*$/);
 			} else {
+				$log_msg{msg} .= $_;
 				print $msg $_ or croak $!;
 			}
 		}
@@ -625,9 +628,30 @@ sub svn_commit_tree {
 			join("\n",@ci_output),"\n";
 	my ($rev_committed) = ($committed =~ /^Committed revision (\d+)\./);
 
-	# resync immediately
-	my @svn_up = (qw(svn up), "-r$svn_rev");
+	my @svn_up = qw(svn up);
 	push @svn_up, '--ignore-externals' unless $_no_ignore_ext;
+	if ($rev_committed == ($svn_rev + 1)) {
+		push @svn_up, "-r$rev_committed";
+		sys(@svn_up);
+		my $info = svn_info('.');
+		my $date = $info->{'Last Changed Date'} or die "Missing date\n";
+		if ($info->{'Last Changed Rev'} != $rev_committed) {
+			croak "$info->{'Last Changed Rev'} != $rev_committed\n"
+		}
+		my ($Y,$m,$d,$H,$M,$S,$tz) = ($date =~
+					/(\d{4})\-(\d\d)\-(\d\d)\s
+					 (\d\d)\:(\d\d)\:(\d\d)\s([\-\+]\d+)/x)
+					 or croak "Failed to parse date: $date\n";
+		$log_msg{date} = "$tz $Y-$m-$d $H:$M:$S";
+		$log_msg{author} = $info->{'Last Changed Author'};
+		$log_msg{revision} = $rev_committed;
+		$log_msg{msg} .= "\n";
+		my $parent = file_to_s("$REV_DIR/$svn_rev");
+		git_commit(\%log_msg, $parent, $commit);
+		return $rev_committed;
+	}
+	# resync immediately
+	push @svn_up, "-r$svn_rev";
 	sys(@svn_up);
 	return fetch("$rev_committed=$commit")->{revision};
 }
@@ -724,7 +748,7 @@ sub svn_info {
 	# only single-lines seem to exist in svn info output
 	while (<$info_fh>) {
 		chomp $_;
-		if (m#^([^:]+)\s*:\s*(\S*)$#) {
+		if (m#^([^:]+)\s*:\s*(\S.*)$#) {
 			$ret->{$1} = $2;
 			push @{$ret->{-order}}, $1;
 		}
-- 
1.2.2.ga559

^ permalink raw reply related

* [PATCH] contrib/git-svn: add show-ignore command
From: Eric Wong @ 2006-02-26 10:22 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Eric Wong

Recursively finds and lists the svn:ignore property on
directories.  The output is suitable for appending to the
$GIT_DIR/info/exclude file.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/git-svn.perl |   25 +++++++++++++++++++++++++
 contrib/git-svn/git-svn.txt  |    7 +++++++
 2 files changed, 32 insertions(+), 0 deletions(-)

0858c770ef3e0f440c20a255baaf4792b3201813
diff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl
index a32ce15..84d43de 100755
--- a/contrib/git-svn/git-svn.perl
+++ b/contrib/git-svn/git-svn.perl
@@ -49,6 +49,7 @@ my %cmd = (
 	fetch => [ \&fetch, "Download new revisions from SVN" ],
 	init => [ \&init, "Initialize and fetch (import)"],
 	commit => [ \&commit, "Commit git revisions to SVN" ],
+	'show-ignore' => [ \&show_ignore, "Show svn:ignore listings" ],
 	rebuild => [ \&rebuild, "Rebuild git-svn metadata (after git clone)" ],
 	help => [ \&usage, "Show help" ],
 );
@@ -258,6 +259,30 @@ sub commit {
 
 }
 
+sub show_ignore {
+	require File::Find or die $!;
+	my $exclude_file = "$GIT_DIR/info/exclude";
+	open my $fh, '<', $exclude_file or croak $!;
+	chomp(my @excludes = (<$fh>));
+	close $fh or croak $!;
+	
+	$SVN_URL ||= file_to_s("$GIT_DIR/$GIT_SVN/info/url");
+	chdir $SVN_WC or croak $!;
+	my %ign;
+	File::Find::find({wanted=>sub{if(lstat $_ && -d _ && -d "$_/.svn"){
+		s#^\./##;
+		@{$ign{$_}} = safe_qx(qw(svn propget svn:ignore),$_);
+		}}, no_chdir=>1},'.');
+	
+	print "\n# /\n";
+	foreach (@{$ign{'.'}}) { print '/',$_ if /\S/ }
+	delete $ign{'.'};
+	foreach my $i (sort keys %ign) {
+		print "\n# ",$i,"\n";
+		foreach (@{$ign{$i}}) { print '/',$i,'/',$_ if /\S/ }
+	}
+}
+
 ########################### utility functions #########################
 
 sub setup_git_svn {
diff --git a/contrib/git-svn/git-svn.txt b/contrib/git-svn/git-svn.txt
index cf098d7..b4b7789 100644
--- a/contrib/git-svn/git-svn.txt
+++ b/contrib/git-svn/git-svn.txt
@@ -61,6 +61,11 @@ rebuild::
 	the directory/repository you're tracking has moved or changed
 	protocols.
 
+show-ignore::
+	Recursively finds and lists the svn:ignore property on
+	directories.  The output is suitable for appending to
+	the $GIT_DIR/info/exclude file.
+
 OPTIONS
 -------
 -r <ARG>::
@@ -152,6 +157,8 @@ Tracking and contributing to an Subversi
 	git commit git-svn-HEAD..my-branch
 # Something is committed to SVN, pull the latest into your branch::
 	git-svn fetch && git pull . git-svn-HEAD
+# Append svn:ignore settings to the default git exclude file:
+	git-svn show-ignore >> .git/info/exclude
 
 DESIGN PHILOSOPHY
 -----------------
-- 
1.2.2.ga559

^ permalink raw reply related

* [PATCH] contrib/git-svn: version 0.10.0
From: Eric Wong @ 2006-02-26 10:22 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Eric Wong
In-Reply-To: <11409493473344-git-send-email-normalperson@yhbt.net>

New features deserve an increment of the minor version.  This will very
likely become 1.0.0 unless release-critical bugs are found.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/git-svn.perl |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

8d35c4193507147a6caa8a25b0ed1e5e9c43a49c
diff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl
index 29c8690..9f12836 100755
--- a/contrib/git-svn/git-svn.perl
+++ b/contrib/git-svn/git-svn.perl
@@ -8,7 +8,7 @@ use vars qw/	$AUTHOR $VERSION
 		$GIT_SVN_INDEX $GIT_SVN
 		$GIT_DIR $REV_DIR/;
 $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
-$VERSION = '0.9.1';
+$VERSION = '0.10.0';
 $GIT_DIR = $ENV{GIT_DIR} || "$ENV{PWD}/.git";
 $GIT_SVN = $ENV{GIT_SVN_ID} || 'git-svn';
 $GIT_SVN_INDEX = "$GIT_DIR/$GIT_SVN/index";
-- 
1.2.2.ga559

^ permalink raw reply related

* Re: [PATCH] Add a Documentation/git-tools.txt
From: Marco Costalba @ 2006-02-26  8:22 UTC (permalink / raw)
  To: junkio; +Cc: git
In-Reply-To: <tnxwtfq8gok.fsf@arm.com>

A brief survey of useful git tools, including third-party
and external projects.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
---

Suggestions/corrections from the list has been collected during the
past week, so I resend
the updated patch.

Please consider for apply.

One note. The suggestion of Jonas (  -*gitview*    ->  *gitview* :: )
has not been applied because
the output had no indent on project name. I played a little with
asciidoc to get an indent but without
success, so I revert to original indented format.

  Documentation/git-tools.txt |   97 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 97 insertions(+), 0 deletions(-)
  create mode 100644 Documentation/git-tools.txt

8f41794257a6efe46f44e056710dfadcfbf362d7
diff --git a/Documentation/git-tools.txt b/Documentation/git-tools.txt
new file mode 100644
index 0000000..7854972
--- /dev/null
+++ b/Documentation/git-tools.txt
@@ -0,0 +1,97 @@
+A short git tools survey
+========================
+
+
+Introduction
+------------
+
+Apart from git contrib/ area there are some others third-party tools
+you may want to look.
+
+This document presents a brief summary of each tool and the corresponding link.
+
+
+Alternative/Augmentative Porcelains
+-----------------------------------
+
+        - *Cogito* (http://www.kernel.org/pub/software/scm/cogito/)
+
+	  Cogito is a version control system layered on top of the git tree history
+	  storage system. It aims at seamless user interface and ease of
use, providing
+	  generally smoother user experience than the "raw" Core GIT itself and indeed
+	  many other version control systems.
+
+
+        - *pg* (http://www.spearce.org/category/projects/scm/pg/)
+
+	  pg is a shell script wrapper around GIT to help the user manage a set of
+          patches to files. pg is somewhat like quilt or StGIT, but
it does have a
+          slightly different feature set.
+
+
+        - *StGit* (http://www.procode.org/stgit/)
+
+	  Stacked GIT provides a quilt-like patch management functionality in the GIT
+          environment. You can easily manage your patches in the
scope of GIT until they
+          get merged upstream.
+
+
+History Viewers
+---------------
+
+	- *gitk* (shipped with git-core)
+
+            gitk is a simple TK GUI for browsing history of GIT
repositories easily.
+
+
+	- *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.
+
+
+        - *qgit* (http://digilander.libero.it/mcostalba/)
+
+            QGit is a git/StGIT GUI viewer built on Qt/C++. QGit could be used
+            to browse history and directory tree, view annotated files, commit
+            changes cherry picking single files or applying patches.
+            Currently it is the fastest and most feature rich among
the git viewers
+            and commit tools.
+
+
+
+Foreign SCM interface
+---------------------
+
+        - *git-svn* (contrib/)
+
+            git-svn is a simple conduit for changesets between a
single Subversion
+            branch and git.
+
+
+        - *quilt2git / git2quilt* (http://home-tj.org/wiki/index.php/Misc)
+
+            These utilities convert patch series in a quilt
repository and commit
+            series in git back and forth.
+
+
+Others
+------
+
+	- *(h)gct* (http://www.cyd.liu.se/users/~freku045/gct/)
+
+            Commit Tool or (h)gct is a GUI enabled commit tool for git and
+            Mercurial (hg). It allows the user to view diffs, select
which files
+            to committed (or ignored / reverted) write commit
messages and perform
+            the commit itself.
+
+        - *pcl-cvs* (contrib/)
+
+            This is an Emacs interface for git. The user interface is
modeled on
+            pcl-cvs. It has been developed on Emacs 21 and will
probably need some
+            tweaking to work on XEmacs.
+
--
1.2.2.g8fcf1

^ permalink raw reply related

* [PATCH 3/4] Convert the svn:ignore property
From: Karl  Hasselström @ 2006-02-26  5:11 UTC (permalink / raw)
  To: Git Mailing List
In-Reply-To: <20060226050335.24860.95155.stgit@backpacker.hemma.treskal.com>

Put the value of the svn:ignore property in a regular file when
converting a Subversion repository to GIT. The Subversion and GIT
ignore syntaxes are similar enough that it often just works to set the
filename to .gitignore and do nothing else.

Signed-off-by: Karl Hasselström <kha@treskal.com>

---

 Documentation/git-svnimport.txt |    8 +++++
 git-svnimport.perl              |   60 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 64 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt
index b5c7721..c95ff84 100644
--- a/Documentation/git-svnimport.txt
+++ b/Documentation/git-svnimport.txt
@@ -13,7 +13,7 @@ SYNOPSIS
 		[ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_rev]
 		[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
 		[ -s start_chg ] [ -m ] [ -r ] [ -M regex ]
-		<SVN_repository_URL> [ <path> ]
+		[ -I <ignorefile_name> ] <SVN_repository_URL> [ <path> ]
 
 
 DESCRIPTION
@@ -65,6 +65,12 @@ When importing incrementally, you might 
 	Prepend 'rX: ' to commit messages, where X is the imported
 	subversion revision.
 
+-I <ignorefile_name>::
+	Import the svn:ignore directory property to files with this
+	name in each directory. (The Subversion and GIT ignore
+	syntaxes are similar enough that using the Subversion patterns
+	directly with "-I .gitignore" will almost always just work.)
+
 -m::
 	Attempt to detect merges based on the commit message. This option
 	will enable default regexes that try to capture the name source
diff --git a/git-svnimport.perl b/git-svnimport.perl
index 6603b96..0dd9fab 100755
--- a/git-svnimport.perl
+++ b/git-svnimport.perl
@@ -29,19 +29,21 @@ die "Need SVN:Core 1.2.1 or better" if $
 $SIG{'PIPE'}="IGNORE";
 $ENV{'TZ'}="UTC";
 
-our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b,$opt_r,$opt_s,$opt_l,$opt_d,$opt_D);
+our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,
+    $opt_b,$opt_r,$opt_I,$opt_s,$opt_l,$opt_d,$opt_D);
 
 sub usage() {
 	print STDERR <<END;
 Usage: ${\basename $0}     # fetch/update GIT from SVN
        [-o branch-for-HEAD] [-h] [-v] [-l max_rev]
        [-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname]
-       [-d|-D] [-i] [-u] [-r] [-s start_chg] [-m] [-M regex] [SVN_URL]
+       [-d|-D] [-i] [-u] [-r] [-I ignorefilename] [-s start_chg]
+       [-m] [-M regex] [SVN_URL]
 END
 	exit(1);
 }
 
-getopts("b:C:dDhil:mM:o:rs:t:T:uv") or usage();
+getopts("b:C:dDhiI:l:mM:o:rs:t:T:uv") or usage();
 usage if $opt_h;
 
 my $tag_name = $opt_t || "tags";
@@ -130,6 +132,24 @@ sub file {
 	return ($name, $mode);
 }
 
+sub ignore {
+	my($self,$path,$rev) = @_;
+
+	print "... $rev $path ...\n" if $opt_v;
+	my (undef,undef,$properties)
+	    = $self->{'svn'}->get_dir($path,$rev,undef);
+	if (exists $properties->{'svn:ignore'}) {
+		my ($fh, $name) = tempfile('gitsvn.XXXXXX',
+					   DIR => File::Spec->tmpdir(),
+					   UNLINK => 1);
+		print $fh $properties->{'svn:ignore'};
+		close($fh);
+		return $name;
+	} else {
+		return undef;
+	}
+}
+
 package main;
 use URI;
 
@@ -341,6 +361,34 @@ sub get_file($$$) {
 	return [$mode, $sha, $path];
 }
 
+sub get_ignore($$$$$) {
+	my($new,$old,$rev,$branch,$path) = @_;
+
+	return unless $opt_I;
+	my $svnpath = revert_split_path($branch,$path);
+	my $name = $svn->ignore("$svnpath",$rev);
+	if ($path eq '/') {
+		$path = $opt_I;
+	} else {
+		$path = File::Spec->catfile($path,$opt_I);
+	}
+	if (defined $name) {
+		my $pid = open(my $F, '-|');
+		die $! unless defined $pid;
+		if (!$pid) {
+			exec("git-hash-object", "-w", $name)
+			    or die "Cannot create object: $!\n";
+		}
+		my $sha = <$F>;
+		chomp $sha;
+		close $F;
+		unlink $name;
+		push(@$new,['0644',$sha,$path]);
+	} else {
+		push(@$old,$path);
+	}
+}
+
 sub split_path($$) {
 	my($rev,$path) = @_;
 	my $branch;
@@ -546,6 +594,9 @@ sub commit {
 						my $opath = $action->[3];
 						print STDERR "$revision: $branch: could not fetch '$opath'\n";
 					}
+				} elsif ($node_kind eq $SVN::Node::dir) {
+					get_ignore(\@new, \@old, $revision,
+						   $branch,$path);
 				}
 			} elsif ($action->[0] eq "D") {
 				push(@old,$path);
@@ -554,6 +605,9 @@ sub commit {
 				if ($node_kind eq $SVN::Node::file) {
 					my $f = get_file($revision,$branch,$path);
 					push(@new,$f) if $f;
+				} elsif ($node_kind eq $SVN::Node::dir) {
+					get_ignore(\@new, \@old, $revision,
+						   $branch,$path);
 				}
 			} else {
 				die "$revision: unknown action '".$action->[0]."' for $path\n";

^ permalink raw reply related

* [PATCH 4/4] Read author names and emails from a file
From: Karl  Hasselström @ 2006-02-26  5:11 UTC (permalink / raw)
  To: Git Mailing List
In-Reply-To: <20060226050335.24860.95155.stgit@backpacker.hemma.treskal.com>

Read a file with lines on the form

  username User's Full Name <email@addres.org>

and use "User's Full Name <email@addres.org>" as the GIT author and
committer for Subversion commits made by "username". If encountering a
commit made by a user not in the list, abort.

Signed-off-by: Karl Hasselström <kha@treskal.com>

---

 Documentation/git-svnimport.txt |   13 ++++++++++++-
 git-svnimport.perl              |   23 ++++++++++++++++++++---
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt
index c95ff84..e0e3a5d 100644
--- a/Documentation/git-svnimport.txt
+++ b/Documentation/git-svnimport.txt
@@ -13,7 +13,8 @@ SYNOPSIS
 		[ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_rev]
 		[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
 		[ -s start_chg ] [ -m ] [ -r ] [ -M regex ]
-		[ -I <ignorefile_name> ] <SVN_repository_URL> [ <path> ]
+		[ -I <ignorefile_name> ] [ -A <author_file> ]
+		<SVN_repository_URL> [ <path> ]
 
 
 DESCRIPTION
@@ -71,6 +72,16 @@ When importing incrementally, you might 
 	syntaxes are similar enough that using the Subversion patterns
 	directly with "-I .gitignore" will almost always just work.)
 
+-A <author_file>::
+	Read a file with lines on the form
+
+	  username User's Full Name <email@addres.org>
+
+	and use "User's Full Name <email@addres.org>" as the GIT
+	author and committer for Subversion commits made by
+	"username". If encountering a commit made by a user not in the
+	list, abort.
+
 -m::
 	Attempt to detect merges based on the commit message. This option
 	will enable default regexes that try to capture the name source
diff --git a/git-svnimport.perl b/git-svnimport.perl
index 0dd9fab..75ce8e0 100755
--- a/git-svnimport.perl
+++ b/git-svnimport.perl
@@ -30,7 +30,7 @@ $SIG{'PIPE'}="IGNORE";
 $ENV{'TZ'}="UTC";
 
 our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,
-    $opt_b,$opt_r,$opt_I,$opt_s,$opt_l,$opt_d,$opt_D);
+    $opt_b,$opt_r,$opt_I,$opt_A,$opt_s,$opt_l,$opt_d,$opt_D);
 
 sub usage() {
 	print STDERR <<END;
@@ -38,12 +38,12 @@ Usage: ${\basename $0}     # fetch/updat
        [-o branch-for-HEAD] [-h] [-v] [-l max_rev]
        [-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname]
        [-d|-D] [-i] [-u] [-r] [-I ignorefilename] [-s start_chg]
-       [-m] [-M regex] [SVN_URL]
+       [-m] [-M regex] [-A author_file] [SVN_URL]
 END
 	exit(1);
 }
 
-getopts("b:C:dDhiI:l:mM:o:rs:t:T:uv") or usage();
+getopts("A:b:C:dDhiI:l:mM:o:rs:t:T:uv") or usage();
 usage if $opt_h;
 
 my $tag_name = $opt_t || "tags";
@@ -68,6 +68,19 @@ if ($opt_M) {
 	push (@mergerx, qr/$opt_M/);
 }
 
+our %users = ();
+if ($opt_A) {
+	die "Cannot open $opt_A\n" unless -f $opt_A;
+	open(my $authors,$opt_A);
+	while(<$authors>) {
+		chomp;
+		next unless /^(\S+)\s+(.+?)\s+<(\S+)>$/;
+		(my $user,my $name,my $email) = ($1,$2,$3);
+		$users{$user} = [$name,$email];
+	}
+	close($authors);
+}
+
 select(STDERR); $|=1; select(STDOUT);
 
 
@@ -485,6 +498,10 @@ sub commit {
 
 	if (not defined $author) {
 		$author_name = $author_email = "unknown";
+	} elsif ($opt_A) {
+		die "User $author is not listed in $opt_A\n"
+		    unless exists $users{$author};
+		($author_name,$author_email) = @{$users{$author}};
 	} elsif ($author =~ /^(.*?)\s+<(.*)>$/) {
 		($author_name, $author_email) = ($1, $2);
 	} else {

^ permalink raw reply related

* [PATCH 2/4] Convert executable flag
From: Karl  Hasselström @ 2006-02-26  5:11 UTC (permalink / raw)
  To: Git Mailing List
In-Reply-To: <20060226050335.24860.95155.stgit@backpacker.hemma.treskal.com>

Convert the svn:executable property to file mode 755 when converting
an SVN repository to GIT.

Signed-off-by: Karl Hasselström <kha@treskal.com>

---

 git-svnimport.perl |   20 +++++++++++++-------
 1 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/git-svnimport.perl b/git-svnimport.perl
index ee2940f..6603b96 100755
--- a/git-svnimport.perl
+++ b/git-svnimport.perl
@@ -112,16 +112,22 @@ sub file {
 		    DIR => File::Spec->tmpdir(), UNLINK => 1);
 
 	print "... $rev $path ...\n" if $opt_v;
-	my $pool = SVN::Pool->new();
-	eval { $self->{'svn'}->get_file($path,$rev,$fh,$pool); };
-	$pool->clear;
+	my (undef, $properties);
+	eval { (undef, $properties)
+		   = $self->{'svn'}->get_file($path,$rev,$fh); };
 	if($@) {
 		return undef if $@ =~ /Attempted to get checksum/;
 		die $@;
 	}
+	my $mode;
+	if (exists $properties->{'svn:executable'}) {
+		$mode = '0755';
+	} else {
+		$mode = '0644';
+	}
 	close ($fh);
 
-	return $name;
+	return ($name, $mode);
 }
 
 package main;
@@ -296,7 +302,7 @@ sub get_file($$$) {
 	my $svnpath = revert_split_path($branch,$path);
 
 	# now get it
-	my $name;
+	my ($name,$mode);
 	if($opt_d) {
 		my($req,$res);
 
@@ -316,8 +322,9 @@ sub get_file($$$) {
 			return undef if $res->code == 301; # directory?
 			die $res->status_line." at $url\n";
 		}
+		$mode = '0644'; # can't obtain mode via direct http request?
 	} else {
-		$name = $svn->file("$svnpath",$rev);
+		($name,$mode) = $svn->file("$svnpath",$rev);
 		return undef unless defined $name;
 	}
 
@@ -331,7 +338,6 @@ sub get_file($$$) {
 	chomp $sha;
 	close $F;
 	unlink $name;
-	my $mode = "0644"; # SV does not seem to store any file modes
 	return [$mode, $sha, $path];
 }
 

^ permalink raw reply related

* [PATCH 1/4] Mention -r in usage summary
From: Karl  Hasselström @ 2006-02-26  5:11 UTC (permalink / raw)
  To: Git Mailing List
In-Reply-To: <20060226050335.24860.95155.stgit@backpacker.hemma.treskal.com>

I added the -r option to git-svnimport some time ago, but forgot to
update the usage summary in the documentation.

Signed-off-by: Karl Hasselström <kha@treskal.com>

---

 Documentation/git-svnimport.txt |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt
index 5c543d5..b5c7721 100644
--- a/Documentation/git-svnimport.txt
+++ b/Documentation/git-svnimport.txt
@@ -10,10 +10,10 @@ git-svnimport - Import a SVN repository 
 SYNOPSIS
 --------
 'git-svnimport' [ -o <branch-for-HEAD> ] [ -h ] [ -v ] [ -d | -D ]
-			[ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_rev]
-			[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
-			[ -s start_chg ] [ -m ] [ -M regex ]
-			<SVN_repository_URL> [ <path> ]
+		[ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_rev]
+		[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
+		[ -s start_chg ] [ -m ] [ -r ] [ -M regex ]
+		<SVN_repository_URL> [ <path> ]
 
 
 DESCRIPTION

^ permalink raw reply related

* [PATCH 0/4] some git-svnimport improvements
From: Karl  Hasselström @ 2006-02-26  5:03 UTC (permalink / raw)
  To: Git Mailing List

This patch series teaches git-svnimport about the svn:executable and
svn:ignore Subversion properties (try to guess from their names what
they do!), and lets the user specify a file with username -> Full Name
<email@address> mappings.

I vaguely recall some discussion some time ago about the format of
this kind of username mapping file, but I ended up just picking the
simplest format I could think of since that was the boring part.

^ permalink raw reply

* Re: the war on trailing whitespace
From: Andrew Morton @ 2006-02-26  5:07 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v1wxq7psj.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> wrote:
>
> Andrew Morton <akpm@osdl.org> writes:
> 
> > It's invariably pointless to add lines which have trailing whitespace. 
> > Nobody cares much, but my scripts spam me when it happens, so I've become
> > obsessive....
> 
> I do not call me obsessive, but I do enable pre-commit and
> pre-applypatch hooks I ship with git myself.

It's apparent that few others do this.

> > I realise that we cannot do this when doing git fetches, but when importing
> > patches and mboxes, git ought to whine loudly about input which matches the
> > above regexp, and it should offer an option to tidy it up.  Perhaps by
> > default.
> 
> I stole the policy the sample hook scripts use from you; it is
> not enabled by default, and as the tool manufacturer I am a bit
> reluctant to do so.
> 

It's not strong enough.  I mean, if you ask a developer "do you wish to add
new trialing whitespace to the kernel" then obviously their answer would be
"no".   So how do we help them in this?

I'd suggest a) git will simply refuse to apply such a patch unless given a
special `forcing' flag, b) even when thus forced, it will still warn and c)
with a different flag, it will strip-then-apply, without generating a
warning.

^ permalink raw reply

* Re: [PATCH] First cut at libifying revlist generation
From: Junio C Hamano @ 2006-02-26  3:40 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.64.0602251608160.22647@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> This really just splits things up partially, and creates the
> interface to set things up by parsign the command line.

Sorry, I'll keep this but I ended up wasting the whole day
setting up a new machine for my wife (a windows box).  The next
task would be to install Cygwin so I can have fun with git...

^ permalink raw reply

* Re: the war on trailing whitespace
From: Junio C Hamano @ 2006-02-26  3:38 UTC (permalink / raw)
  To: Andrew Morton; +Cc: git
In-Reply-To: <20060225174047.0e9a6d29.akpm@osdl.org>

Andrew Morton <akpm@osdl.org> writes:

> It's invariably pointless to add lines which have trailing whitespace. 
> Nobody cares much, but my scripts spam me when it happens, so I've become
> obsessive....

I do not call me obsessive, but I do enable pre-commit and
pre-applypatch hooks I ship with git myself.

> I realise that we cannot do this when doing git fetches, but when importing
> patches and mboxes, git ought to whine loudly about input which matches the
> above regexp, and it should offer an option to tidy it up.  Perhaps by
> default.

I stole the policy the sample hook scripts use from you; it is
not enabled by default, and as the tool manufacturer I am a bit
reluctant to do so.

However, as a kernel project maintainer high in the foodchain,
I'd imagine your plea to your fellow maintainers who apply
patches using git tools would be heard well.

^ permalink raw reply

* [PATCH] annotate: Convert all -| calls to use a helper open_pipe().
From: Ryan Anderson @ 2006-02-26  3:02 UTC (permalink / raw)
  To: junkio; +Cc: git, Ryan Anderson
In-Reply-To: <11409185133616-git-send-email-ryan@michonline.com>

When we settle on a solution for ActiveState's forking issues, all
compatibility checks can be handled inside this one function.

Also, fixed an abuse of global variables in the process of cleaning this up.

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

---

 I should have done this before I sent the other patch out, sorry about
 that.  This one will also be in my annotate-upstream branch, but I'm a
 bit less sure where we stand on this kind of fixup at the moment.  Even
 if this is the wrong place to start, this at least flags all the spots
 that need fixing in a nice way.

 git-annotate.perl |   73 ++++++++++++++++++++++++++++++++---------------------
 1 files changed, 44 insertions(+), 29 deletions(-)

3e72e9de7ece2b9c2c9447e761ee721bdd94a33f
diff --git a/git-annotate.perl b/git-annotate.perl
index 91da6d5..ee8ff15 100755
--- a/git-annotate.perl
+++ b/git-annotate.perl
@@ -98,15 +98,15 @@ while (my $bound = pop @stack) {
 push @revqueue, $head;
 init_claim( defined $starting_rev ? $starting_rev : 'dirty');
 unless (defined $starting_rev) {
-	open(DIFF,"-|","git","diff","-R", "HEAD", "--",$filename)
+	my $diff = open_pipe("git","diff","-R", "HEAD", "--",$filename)
 		or die "Failed to call git diff to check for dirty state: $!";
 
-	_git_diff_parse(*DIFF, $head, "dirty", (
+	_git_diff_parse($diff, $head, "dirty", (
 				'author' => gitvar_name("GIT_AUTHOR_IDENT"),
 				'author_date' => sprintf("%s +0000",time()),
 				)
 			);
-	close(DIFF);
+	close($diff);
 }
 handle_rev();
 
@@ -172,20 +172,21 @@ sub handle_rev {
 sub git_rev_list {
 	my ($rev, $file) = @_;
 
+	my $revlist;
 	if ($rev_file) {
-		open(P, '<' . $rev_file);
+		open($revlist, '<' . $rev_file);
 	} else {
-		open(P,"-|","git-rev-list","--parents","--remove-empty",$rev,"--",$file)
+		$revlist = open_pipe("git-rev-list","--parents","--remove-empty",$rev,"--",$file)
 			or die "Failed to exec git-rev-list: $!";
 	}
 
 	my @revs;
-	while(my $line = <P>) {
+	while(my $line = <$revlist>) {
 		chomp $line;
 		my ($rev, @parents) = split /\s+/, $line;
 		push @revs, [ $rev, @parents ];
 	}
-	close(P);
+	close($revlist);
 
 	printf("0 revs found for rev %s (%s)\n", $rev, $file) if (@revs == 0);
 	return @revs;
@@ -194,22 +195,22 @@ sub git_rev_list {
 sub find_parent_renames {
 	my ($rev, $file) = @_;
 
-	open(P,"-|","git-diff-tree", "-M50", "-r","--name-status", "-z","$rev")
+	my $patch = open_pipe("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>) {
+	my $junk = <$patch>;
+	while (my $change = <$patch>) {
 		chomp $change;
-		my $filename = <P>;
+		my $filename = <$patch>;
 		chomp $filename;
 
 		if ($change =~ m/^[AMD]$/ ) {
 			next;
 		} elsif ($change =~ m/^R/ ) {
 			my $oldfilename = $filename;
-			$filename = <P>;
+			$filename = <$patch>;
 			chomp $filename;
 			if ( $file eq $filename ) {
 				my $parent = git_find_parent($rev, $oldfilename);
@@ -218,7 +219,7 @@ sub find_parent_renames {
 			}
 		}
 	}
-	close(P);
+	close($patch);
 
 	return \%bound;
 }
@@ -227,14 +228,14 @@ sub find_parent_renames {
 sub git_find_parent {
 	my ($rev, $filename) = @_;
 
-	open(REVPARENT,"-|","git-rev-list","--remove-empty", "--parents","--max-count=1","$rev","--",$filename)
+	my $revparent = open_pipe("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>;
+	my $parentline = <$revparent>;
 	chomp $parentline;
 	my ($revfound,$parent) = split m/\s+/, $parentline;
 
-	close(REVPARENT);
+	close($revparent);
 
 	return $parent;
 }
@@ -245,13 +246,13 @@ sub git_find_parent {
 sub git_diff_parse {
 	my ($parent, $rev, %revinfo) = @_;
 
-	open(DIFF,"-|","git-diff-tree","-M","-p",$rev,$parent,"--",
+	my $diff = open_pipe("git-diff-tree","-M","-p",$rev,$parent,"--",
 			$revs{$rev}{'filename'}, $revs{$parent}{'filename'})
 		or die "Failed to call git-diff for annotation: $!";
 
-	_git_diff_parse(*DIFF, $parent, $rev, %revinfo);
+	_git_diff_parse($diff, $parent, $rev, %revinfo);
 
-	close(DIFF);
+	close($diff);
 }
 
 sub _git_diff_parse {
@@ -264,7 +265,7 @@ sub _git_diff_parse {
 	my $gotheader = 0;
 	my ($remstart);
 	my ($hunk_start, $hunk_index);
-	while(<DIFF>) {
+	while(<$diff>) {
 		chomp;
 		if (m/^@@ -(\d+),(\d+) \+(\d+),(\d+)/) {
 			$remstart = $1;
@@ -335,15 +336,15 @@ sub git_cat_file {
 
 	my $blob = git_ls_tree($rev, $filename);
 
-	open(C,"-|","git","cat-file", "blob", $blob)
+	my $catfile = open_pipe("git","cat-file", "blob", $blob)
 		or die "Failed to git-cat-file blob $blob (rev $rev, file $filename): " . $!;
 
 	my @lines;
-	while(<C>) {
+	while(<$catfile>) {
 		chomp;
 		push @lines, $_;
 	}
-	close(C);
+	close($catfile);
 
 	return @lines;
 }
@@ -351,15 +352,15 @@ sub git_cat_file {
 sub git_ls_tree {
 	my ($rev, $filename) = @_;
 
-	open(T,"-|","git","ls-tree",$rev,$filename)
+	my $lstree = open_pipe("git","ls-tree",$rev,$filename)
 		or die "Failed to call git ls-tree: $!";
 
 	my ($mode, $type, $blob, $tfilename);
-	while(<T>) {
+	while(<$lstree>) {
 		($mode, $type, $blob, $tfilename) = split(/\s+/, $_, 4);
 		last if ($tfilename eq $filename);
 	}
-	close(T);
+	close($lstree);
 
 	return $blob if $filename eq $filename;
 	die "git-ls-tree failed to find blob for $filename";
@@ -379,11 +380,11 @@ sub claim_line {
 
 sub git_commit_info {
 	my ($rev) = @_;
-	open(COMMIT, "-|","git-cat-file", "commit", $rev)
+	my $commit = open_pipe("git-cat-file", "commit", $rev)
 		or die "Failed to call git-cat-file: $!";
 
 	my %info;
-	while(<COMMIT>) {
+	while(<$commit>) {
 		chomp;
 		last if (length $_ == 0);
 
@@ -397,7 +398,7 @@ sub git_commit_info {
 			$info{'committer_date'} = $3;
 		}
 	}
-	close(COMMIT);
+	close($commit);
 
 	return %info;
 }
@@ -430,3 +431,17 @@ sub gitvar_name {
     return join(' ', @field[0...(@field-4)]);
 }
 
+
+sub open_pipe {
+	my (@execlist) = @_;
+
+	my $pid = open my $kid, "-|";
+	defined $pid or die "Cannot fork: $!";
+
+	unless ($pid) {
+		exec @execlist;
+		die "Cannot exec @execlist: $!";
+	}
+
+	return $kid;
+}
-- 
1.2.3.g9ca3

^ permalink raw reply related

* [PATCH] annotate: Handle dirty state and arbitrary revisions.
From: Ryan Anderson @ 2006-02-26  1:48 UTC (permalink / raw)
  To: junkio; +Cc: git, Ryan Anderson

Also, use Getopt::Long and only process each rev once.

(Thanks to Morten Welinder for spotting the performance problems.)

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

---

Or pull from http://h4x0r5.com/~ryan/git/ryan.git/ annotate-upstream

 git-annotate.perl |  150 ++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 113 insertions(+), 37 deletions(-)

9ca393b055b53df4eb9284b39f38c5b42b7f93b1
diff --git a/git-annotate.perl b/git-annotate.perl
index 3800c46..91da6d5 100755
--- a/git-annotate.perl
+++ b/git-annotate.perl
@@ -8,44 +8,62 @@
 
 use warnings;
 use strict;
-use Getopt::Std;
+use Getopt::Long;
 use POSIX qw(strftime gmtime);
 
 sub usage() {
-	print STDERR 'Usage: ${\basename $0} [-s] [-S revs-file] file
-
-	-l		show long rev
-	-r		follow renames
-	-S commit	use revs from revs-file instead of calling git-rev-list
+	print STDERR 'Usage: ${\basename $0} [-s] [-S revs-file] file [ revision ]
+	-l, --long
+			Show long rev (Defaults off)
+	-r, --rename
+			Follow renames (Defaults on).
+	-S, --rev-file revs-file
+			use revs from revs-file instead of calling git-rev-list
+	-h, --help
+			This message.
 ';
 
 	exit(1);
 }
 
-our ($opt_h, $opt_l, $opt_r, $opt_S);
-getopts("hlrS:") or usage();
-$opt_h && usage();
+our ($help, $longrev, $rename, $starting_rev, $rev_file) = (0, 0, 1);
+
+my $rc = GetOptions(	"long|l" => \$longrev,
+			"help|h" => \$help,
+			"rename|r" => \$rename,
+			"rev-file|S" => \$rev_file);
+if (!$rc or $help) {
+	usage();
+}
 
 my $filename = shift @ARGV;
+if (@ARGV) {
+	$starting_rev = shift @ARGV;
+}
 
 my @stack = (
 	{
-		'rev' => "HEAD",
+		'rev' => defined $starting_rev ? $starting_rev : "HEAD",
 		'filename' => $filename,
 	},
 );
 
-our (@lineoffsets, @pendinglineoffsets);
 our @filelines = ();
-open(F,"<",$filename)
-	or die "Failed to open filename: $!";
 
-while(<F>) {
-	chomp;
-	push @filelines, $_;
+if (defined $starting_rev) {
+	@filelines = git_cat_file($starting_rev, $filename);
+} else {
+	open(F,"<",$filename)
+		or die "Failed to open filename: $!";
+
+	while(<F>) {
+		chomp;
+		push @filelines, $_;
+	}
+	close(F);
+
 }
-close(F);
-our $leftover_lines = @filelines;
+
 our %revs;
 our @revqueue;
 our $head;
@@ -66,7 +84,7 @@ while (my $bound = pop @stack) {
 			next;
 		}
 
-		if (!$opt_r) {
+		if (!$rename) {
 			next;
 		}
 
@@ -78,8 +96,18 @@ while (my $bound = pop @stack) {
 	}
 }
 push @revqueue, $head;
-init_claim($head);
-$revs{$head}{'lineoffsets'} = {};
+init_claim( defined $starting_rev ? $starting_rev : 'dirty');
+unless (defined $starting_rev) {
+	open(DIFF,"-|","git","diff","-R", "HEAD", "--",$filename)
+		or die "Failed to call git diff to check for dirty state: $!";
+
+	_git_diff_parse(*DIFF, $head, "dirty", (
+				'author' => gitvar_name("GIT_AUTHOR_IDENT"),
+				'author_date' => sprintf("%s +0000",time()),
+				)
+			);
+	close(DIFF);
+}
 handle_rev();
 
 
@@ -88,7 +116,7 @@ foreach my $l (@filelines) {
 	my ($output, $rev, $committer, $date);
 	if (ref $l eq 'ARRAY') {
 		($output, $rev, $committer, $date) = @$l;
-		if (!$opt_l && length($rev) > 8) {
+		if (!$longrev && length($rev) > 8) {
 			$rev = substr($rev,0,8);
 		}
 	} else {
@@ -102,7 +130,6 @@ foreach my $l (@filelines) {
 
 sub init_claim {
 	my ($rev) = @_;
-	my %revinfo = git_commit_info($rev);
 	for (my $i = 0; $i < @filelines; $i++) {
 		$filelines[$i] = [ $filelines[$i], '', '', '', 1];
 			# line,
@@ -117,7 +144,9 @@ sub init_claim {
 
 sub handle_rev {
 	my $i = 0;
+	my %seen;
 	while (my $rev = shift @revqueue) {
+		next if $seen{$rev}++;
 
 		my %revinfo = git_commit_info($rev);
 
@@ -143,8 +172,8 @@ sub handle_rev {
 sub git_rev_list {
 	my ($rev, $file) = @_;
 
-	if ($opt_S) {
-		open(P, '<' . $opt_S);
+	if ($rev_file) {
+		open(P, '<' . $rev_file);
 	} else {
 		open(P,"-|","git-rev-list","--parents","--remove-empty",$rev,"--",$file)
 			or die "Failed to exec git-rev-list: $!";
@@ -216,24 +245,31 @@ sub git_find_parent {
 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: $!";
 
+	_git_diff_parse(*DIFF, $parent, $rev, %revinfo);
+
+	close(DIFF);
+}
+
+sub _git_diff_parse {
+	my ($diff, $parent, $rev, %revinfo) = @_;
+
+	my ($ri, $pi) = (0,0);
 	my $slines = $revs{$rev}{'lines'};
 	my @plines;
 
 	my $gotheader = 0;
-	my ($remstart, $remlength, $addstart, $addlength);
-	my ($hunk_start, $hunk_index, $hunk_adds);
+	my ($remstart);
+	my ($hunk_start, $hunk_index);
 	while(<DIFF>) {
 		chomp;
 		if (m/^@@ -(\d+),(\d+) \+(\d+),(\d+)/) {
-			($remstart, $remlength, $addstart, $addlength) = ($1, $2, $3, $4);
+			$remstart = $1;
 			# Adjust for 0-based arrays
 			$remstart--;
-			$addstart--;
 			# Reinit hunk tracking.
 			$hunk_start = $remstart;
 			$hunk_index = 0;
@@ -279,7 +315,6 @@ sub git_diff_parse {
 		}
 		$hunk_index++;
 	}
-	close(DIFF);
 	for (my $i = $ri; $i < @{$slines} ; $i++) {
 		push @plines, $slines->[$ri++];
 	}
@@ -295,13 +330,13 @@ sub get_line {
 }
 
 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);
+	my ($rev, $filename) = @_;
+	return () unless defined $rev && defined $filename;
 
-	open(C,"-|","git-cat-file", "blob", $blob)
-		or die "Failed to git-cat-file blob $blob (rev $parent, file $filename): " . $!;
+	my $blob = git_ls_tree($rev, $filename);
+
+	open(C,"-|","git","cat-file", "blob", $blob)
+		or die "Failed to git-cat-file blob $blob (rev $rev, file $filename): " . $!;
 
 	my @lines;
 	while(<C>) {
@@ -313,6 +348,25 @@ sub git_cat_file {
 	return @lines;
 }
 
+sub git_ls_tree {
+	my ($rev, $filename) = @_;
+
+	open(T,"-|","git","ls-tree",$rev,$filename)
+		or die "Failed to call git ls-tree: $!";
+
+	my ($mode, $type, $blob, $tfilename);
+	while(<T>) {
+		($mode, $type, $blob, $tfilename) = split(/\s+/, $_, 4);
+		last if ($tfilename eq $filename);
+	}
+	close(T);
+
+	return $blob if $filename eq $filename;
+	die "git-ls-tree failed to find blob for $filename";
+
+}
+
+
 
 sub claim_line {
 	my ($floffset, $rev, $lines, %revinfo) = @_;
@@ -354,3 +408,25 @@ sub format_date {
 	return strftime("%Y-%m-%d %H:%M:%S " . $timezone, gmtime($timestamp));
 }
 
+# Copied from git-send-email.perl - We need a Git.pm module..
+sub gitvar {
+    my ($var) = @_;
+    my $fh;
+    my $pid = open($fh, '-|');
+    die "$!" unless defined $pid;
+    if (!$pid) {
+	exec('git-var', $var) or die "$!";
+    }
+    my ($val) = <$fh>;
+    close $fh or die "$!";
+    chomp($val);
+    return $val;
+}
+
+sub gitvar_name {
+    my ($name) = @_;
+    my $val = gitvar($name);
+    my @field = split(/\s+/, $val);
+    return join(' ', @field[0...(@field-4)]);
+}
+
-- 
1.2.3.g9ca3

^ permalink raw reply related

* the war on trailing whitespace
From: Andrew Morton @ 2006-02-26  1:40 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


It's invariably pointless to add lines which have trailing whitespace. 
Nobody cares much, but my scripts spam me when it happens, so I've become
obsessive.    Looking at Dave Miller's current net devel tree:

bix:/usr/src/25> grep '^+.*[    ]$' patches/git-net.patch | wc -l
    170

Note that this is purely _added_ trailing whitespace.  I'm not proposing
that the revision control system should care about pre-existing trailing
whitespace.

I got the quilt guys to generate warnings when patches add trailing
whitespace, and to provide the tools to strip it.  And I believe Larry made
similar changes to bk.

I realise that we cannot do this when doing git fetches, but when importing
patches and mboxes, git ought to whine loudly about input which matches the
above regexp, and it should offer an option to tidy it up.  Perhaps by
default.

Of course, this means that the person who sent the patch will find that his
as-yet-unsent patches don't apply to the upstream tree any more.  Well,
that's tough luck - perhaps it'll motivate him to stop adding trailing
whitespace.  The patches will still apply with `patch -l'.

Thanks for listening ;)

^ permalink raw reply

* [PATCH] First cut at libifying revlist generation
From: Linus Torvalds @ 2006-02-26  0:19 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


This really just splits things up partially, and creates the
interface to set things up by parsign the command line.

No real code changes so far, although the parsing of filenames is a bit 
stricter. In particular, if there is a "--", then we do not accept any 
filenames before it, and if there isn't any "--", then we check that _all_ 
paths listed are valid, not just the first one.

The new argument parsing automatically also gives us "--default" and 
"--not" handling as in git-rev-parse.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

The path checking just makes sense. 

This also makes git-rev-list handle "--all" and "--not" correctly (before, 
it wouldn't handle "--not"), and teaches it to handle "--default". I 
didn't do "--since" and "--before", but I will eventually. The final end 
result is that we won't need git-rev-parse for most things.

But basically there should be no code changes, and this is just a mid-way 
point where a _partial_ set of routines from "git-rev-list" has been moved 
into a library files - revision.c. The half-way point has some ugly 
interfaces, but I don't want to do it all in one go.

The _plan_ is to:

 - move the actual history traversal into revision.c too

 - leave all the git-rev-list -specific stuff (the "--bisect" logic, 
   the print-out logic etc) in rev-list.c

 - make it trivial to make a small C version of "git diff" that just uses 
   the same "setup_revisions()" interface and then looks at 
   "revs->commits" to see what revisions were passed in (the library 
   interface is already at the point where that should work)

 - when the actual history _traversal_ is moved into "revision.c" too, it 
   should then be possible to make an equally small "git log" and friends 
   (whatchanged etc) into C using the revision.c code.

Comments? I think this is safe to apply, because I've done a diff of the 
old non-split rev-list.c against both the new rev-list.c and revision.c, 
and all the changes _look_ like just moving things around and taking the 
new "struct rev_info" into account.

It also passes all the tests, and in general seems straightforward enough. 
HOEVER, I'd still like to point out that I could have screwed something 
up, and this is just about the most core program in all of git, so it 
would make a lot of sense if more people double-checked my "trivial" 
split-up.

		Linus


diff --git a/Makefile b/Makefile
index 6c59cee..3575489 100644
--- a/Makefile
+++ b/Makefile
@@ -192,7 +192,7 @@ LIB_FILE=libgit.a
 LIB_H = \
 	blob.h cache.h commit.h count-delta.h csum-file.h delta.h \
 	diff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \
-	run-command.h strbuf.h tag.h tree.h git-compat-util.h
+	run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h
 
 DIFF_OBJS = \
 	diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \
@@ -205,7 +205,7 @@ LIB_OBJS = \
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
 	tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
-	fetch-clone.o \
+	fetch-clone.o revision.o \
 	$(DIFF_OBJS)
 
 LIBS = $(LIB_FILE)
diff --git a/epoch.c b/epoch.c
index 3a76748..0f37492 100644
--- a/epoch.c
+++ b/epoch.c
@@ -15,6 +15,7 @@
 
 #include "cache.h"
 #include "commit.h"
+#include "revision.h"
 #include "epoch.h"
 
 struct fraction {
diff --git a/epoch.h b/epoch.h
index 7493d5a..3756009 100644
--- a/epoch.h
+++ b/epoch.h
@@ -11,7 +11,6 @@ typedef int (*emitter_func) (struct comm
 int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter);
 
 /* Low bits are used by rev-list */
-#define UNINTERESTING   (1u<<10)
 #define BOUNDARY        (1u<<11)
 #define VISITED         (1u<<12)
 #define DISCONTINUITY   (1u<<13)
diff --git a/rev-list.c b/rev-list.c
index 67d2a48..d1c52a6 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -6,9 +6,10 @@
 #include "blob.h"
 #include "epoch.h"
 #include "diff.h"
+#include "revision.h"
+
+/* bits #0 and #1 in revision.h */
 
-#define SEEN		(1u << 0)
-#define INTERESTING	(1u << 1)
 #define COUNTED		(1u << 2)
 #define SHOWN		(1u << 3)
 #define TREECHANGE	(1u << 4)
@@ -38,60 +39,20 @@ static const char rev_list_usage[] =
 "    --bisect"
 ;
 
-static int dense = 1;
+struct rev_info revs;
+
 static int unpacked = 0;
 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;
 static int hdr_termination = 0;
 static const char *commit_prefix = "";
-static unsigned long max_age = -1;
-static unsigned long min_age = -1;
-static int max_count = -1;
 static enum cmit_fmt commit_format = CMIT_FMT_RAW;
 static int merge_order = 0;
 static int show_breaks = 0;
 static int stop_traversal = 0;
-static int topo_order = 0;
-static int lifo = 1;
 static int no_merges = 0;
-static const char **paths = NULL;
-static int remove_empty_trees = 0;
-
-struct name_path {
-	struct name_path *up;
-	int elem_len;
-	const char *elem;
-};
-
-static char *path_name(struct name_path *path, const char *name)
-{
-	struct name_path *p;
-	char *n, *m;
-	int nlen = strlen(name);
-	int len = nlen + 1;
-
-	for (p = path; p; p = p->up) {
-		if (p->elem_len)
-			len += p->elem_len + 1;
-	}
-	n = xmalloc(len);
-	m = n + len - (nlen + 1);
-	strcpy(m, name);
-	for (p = path; p; p = p->up) {
-		if (p->elem_len) {
-			m -= p->elem_len + 1;
-			memcpy(m, p->elem, p->elem_len);
-			m[p->elem_len] = '/';
-		}
-	}
-	return n;
-}
 
 static void show_commit(struct commit *commit)
 {
@@ -168,15 +129,15 @@ static int filter_commit(struct commit *
 		return STOP;
 	if (commit->object.flags & (UNINTERESTING|SHOWN))
 		return CONTINUE;
-	if (min_age != -1 && (commit->date > min_age))
+	if (revs.min_age != -1 && (commit->date > revs.min_age))
 		return CONTINUE;
-	if (max_age != -1 && (commit->date < max_age)) {
+	if (revs.max_age != -1 && (commit->date < revs.max_age)) {
 		stop_traversal=1;
 		return CONTINUE;
 	}
 	if (no_merges && (commit->parents && commit->parents->next))
 		return CONTINUE;
-	if (paths && dense) {
+	if (revs.paths && revs.dense) {
 		if (!(commit->object.flags & TREECHANGE))
 			return CONTINUE;
 		rewrite_parents(commit);
@@ -196,7 +157,7 @@ static int process_commit(struct commit 
 		return CONTINUE;
 	}
 
-	if (max_count != -1 && !max_count--)
+	if (revs.max_count != -1 && !revs.max_count--)
 		return STOP;
 
 	show_commit(commit);
@@ -204,19 +165,6 @@ static int process_commit(struct commit 
 	return CONTINUE;
 }
 
-static struct object_list **add_object(struct object *obj,
-				       struct object_list **p,
-				       struct name_path *path,
-				       const char *name)
-{
-	struct object_list *entry = xmalloc(sizeof(*entry));
-	entry->item = obj;
-	entry->next = *p;
-	entry->name = path_name(path, name);
-	*p = entry;
-	return &entry->next;
-}
-
 static struct object_list **process_blob(struct blob *blob,
 					 struct object_list **p,
 					 struct name_path *path,
@@ -224,7 +172,7 @@ static struct object_list **process_blob
 {
 	struct object *obj = &blob->object;
 
-	if (!blob_objects)
+	if (!revs.blob_objects)
 		return p;
 	if (obj->flags & (UNINTERESTING | SEEN))
 		return p;
@@ -241,7 +189,7 @@ static struct object_list **process_tree
 	struct tree_entry_list *entry;
 	struct name_path me;
 
-	if (!tree_objects)
+	if (!revs.tree_objects)
 		return p;
 	if (obj->flags & (UNINTERESTING | SEEN))
 		return p;
@@ -314,75 +262,6 @@ static void show_commit_list(struct comm
 	}
 }
 
-static void mark_blob_uninteresting(struct blob *blob)
-{
-	if (!blob_objects)
-		return;
-	if (blob->object.flags & UNINTERESTING)
-		return;
-	blob->object.flags |= UNINTERESTING;
-}
-
-static void mark_tree_uninteresting(struct tree *tree)
-{
-	struct object *obj = &tree->object;
-	struct tree_entry_list *entry;
-
-	if (!tree_objects)
-		return;
-	if (obj->flags & UNINTERESTING)
-		return;
-	obj->flags |= UNINTERESTING;
-	if (!has_sha1_file(obj->sha1))
-		return;
-	if (parse_tree(tree) < 0)
-		die("bad tree %s", sha1_to_hex(obj->sha1));
-	entry = tree->entries;
-	tree->entries = NULL;
-	while (entry) {
-		struct tree_entry_list *next = entry->next;
-		if (entry->directory)
-			mark_tree_uninteresting(entry->item.tree);
-		else
-			mark_blob_uninteresting(entry->item.blob);
-		free(entry);
-		entry = next;
-	}
-}
-
-static void mark_parents_uninteresting(struct commit *commit)
-{
-	struct commit_list *parents = commit->parents;
-
-	while (parents) {
-		struct commit *commit = parents->item;
-		commit->object.flags |= UNINTERESTING;
-
-		/*
-		 * Normally we haven't parsed the parent
-		 * yet, so we won't have a parent of a parent
-		 * here. However, it may turn out that we've
-		 * reached this commit some other way (where it
-		 * wasn't uninteresting), in which case we need
-		 * to mark its parents recursively too..
-		 */
-		if (commit->parents)
-			mark_parents_uninteresting(commit);
-
-		/*
-		 * A missing commit is ok iff its parent is marked 
-		 * uninteresting.
-		 *
-		 * We just mark such a thing parsed, so that when
-		 * it is popped next time around, we won't be trying
-		 * to parse it and get an error.
-		 */
-		if (!has_sha1_file(commit->object.sha1))
-			commit->object.parsed = 1;
-		parents = parents->next;
-	}
-}
-
 static int everybody_uninteresting(struct commit_list *orig)
 {
 	struct commit_list *list = orig;
@@ -413,7 +292,7 @@ static int count_distance(struct commit_
 
 		if (commit->object.flags & (UNINTERESTING | COUNTED))
 			break;
-		if (!paths || (commit->object.flags & TREECHANGE))
+		if (!revs.paths || (commit->object.flags & TREECHANGE))
 			nr++;
 		commit->object.flags |= COUNTED;
 		p = commit->parents;
@@ -447,7 +326,7 @@ static struct commit_list *find_bisectio
 	nr = 0;
 	p = list;
 	while (p) {
-		if (!paths || (p->item->object.flags & TREECHANGE))
+		if (!revs.paths || (p->item->object.flags & TREECHANGE))
 			nr++;
 		p = p->next;
 	}
@@ -457,7 +336,7 @@ static struct commit_list *find_bisectio
 	for (p = list; p; p = p->next) {
 		int distance;
 
-		if (paths && !(p->item->object.flags & TREECHANGE))
+		if (revs.paths && !(p->item->object.flags & TREECHANGE))
 			continue;
 
 		distance = count_distance(p);
@@ -483,7 +362,7 @@ static void mark_edge_parents_uninterest
 		if (!(parent->object.flags & UNINTERESTING))
 			continue;
 		mark_tree_uninteresting(parent->tree);
-		if (edge_hint && !(parent->object.flags & SHOWN)) {
+		if (revs.edge_hint && !(parent->object.flags & SHOWN)) {
 			parent->object.flags |= SHOWN;
 			printf("-%s\n", sha1_to_hex(parent->object.sha1));
 		}
@@ -613,7 +492,7 @@ static void try_to_simplify_commit(struc
 			return;
 
 		case TREE_NEW:
-			if (remove_empty_trees && same_tree_as_empty(p->tree)) {
+			if (revs.remove_empty_trees && same_tree_as_empty(p->tree)) {
 				*pp = parent->next;
 				continue;
 			}
@@ -664,7 +543,7 @@ static void add_parents_to_list(struct c
 	 * simplify the commit history and find the parent
 	 * that has no differences in the path set if one exists.
 	 */
-	if (paths)
+	if (revs.paths)
 		try_to_simplify_commit(commit);
 
 	parent = commit->parents;
@@ -693,7 +572,7 @@ static struct commit_list *limit_list(st
 		list = list->next;
 		free(entry);
 
-		if (max_age != -1 && (commit->date < max_age))
+		if (revs.max_age != -1 && (commit->date < revs.max_age))
 			obj->flags |= UNINTERESTING;
 		if (unpacked && has_sha1_pack(obj->sha1))
 			obj->flags |= UNINTERESTING;
@@ -704,155 +583,40 @@ static struct commit_list *limit_list(st
 				break;
 			continue;
 		}
-		if (min_age != -1 && (commit->date > min_age))
+		if (revs.min_age != -1 && (commit->date > revs.min_age))
 			continue;
 		p = &commit_list_insert(commit, p)->next;
 	}
-	if (tree_objects)
+	if (revs.tree_objects)
 		mark_edges_uninteresting(newlist);
 	if (bisect_list)
 		newlist = find_bisection(newlist);
 	return newlist;
 }
 
-static void add_pending_object(struct object *obj, const char *name)
-{
-	add_object(obj, &pending_objects, NULL, name);
-}
-
-static struct commit *get_commit_reference(const char *name, const unsigned char *sha1, unsigned int flags)
-{
-	struct object *object;
-
-	object = parse_object(sha1);
-	if (!object)
-		die("bad object %s", name);
-
-	/*
-	 * Tag object? Look what it points to..
-	 */
-	while (object->type == tag_type) {
-		struct tag *tag = (struct tag *) object;
-		object->flags |= flags;
-		if (tag_objects && !(object->flags & UNINTERESTING))
-			add_pending_object(object, tag->tag);
-		object = parse_object(tag->tagged->sha1);
-		if (!object)
-			die("bad object %s", sha1_to_hex(tag->tagged->sha1));
-	}
-
-	/*
-	 * Commit object? Just return it, we'll do all the complex
-	 * reachability crud.
-	 */
-	if (object->type == commit_type) {
-		struct commit *commit = (struct commit *)object;
-		object->flags |= flags;
-		if (parse_commit(commit) < 0)
-			die("unable to parse commit %s", name);
-		if (flags & UNINTERESTING)
-			mark_parents_uninteresting(commit);
-		return commit;
-	}
-
-	/*
-	 * Tree object? Either mark it uniniteresting, or add it
-	 * to the list of objects to look at later..
-	 */
-	if (object->type == tree_type) {
-		struct tree *tree = (struct tree *)object;
-		if (!tree_objects)
-			return NULL;
-		if (flags & UNINTERESTING) {
-			mark_tree_uninteresting(tree);
-			return NULL;
-		}
-		add_pending_object(object, "");
-		return NULL;
-	}
-
-	/*
-	 * Blob object? You know the drill by now..
-	 */
-	if (object->type == blob_type) {
-		struct blob *blob = (struct blob *)object;
-		if (!blob_objects)
-			return NULL;
-		if (flags & UNINTERESTING) {
-			mark_blob_uninteresting(blob);
-			return NULL;
-		}
-		add_pending_object(object, "");
-		return NULL;
-	}
-	die("%s is unknown object", name);
-}
-
-static void handle_one_commit(struct commit *com, struct commit_list **lst)
-{
-	if (!com || com->object.flags & SEEN)
-		return;
-	com->object.flags |= SEEN;
-	commit_list_insert(com, lst);
-}
-
-/* for_each_ref() callback does not allow user data -- Yuck. */
-static struct commit_list **global_lst;
-
-static int include_one_commit(const char *path, const unsigned char *sha1)
-{
-	struct commit *com = get_commit_reference(path, sha1, 0);
-	handle_one_commit(com, global_lst);
-	return 0;
-}
-
-static void handle_all(struct commit_list **lst)
-{
-	global_lst = lst;
-	for_each_ref(include_one_commit);
-	global_lst = NULL;
-}
-
 int main(int argc, const char **argv)
 {
-	const char *prefix = setup_git_directory();
-	struct commit_list *list = NULL;
+	struct commit_list *list;
 	int i, limited = 0;
 
+	argc = setup_revisions(argc, argv, &revs);
+
 	for (i = 1 ; i < argc; i++) {
-		int flags;
 		const char *arg = argv[i];
-		char *dotdot;
-		struct commit *commit;
-		unsigned char sha1[20];
 
 		/* accept -<digit>, like traditilnal "head" */
 		if ((*arg == '-') && isdigit(arg[1])) {
-			max_count = atoi(arg + 1);
+			revs.max_count = atoi(arg + 1);
 			continue;
 		}
 		if (!strcmp(arg, "-n")) {
 			if (++i >= argc)
 				die("-n requires an argument");
-			max_count = atoi(argv[i]);
+			revs.max_count = atoi(argv[i]);
 			continue;
 		}
 		if (!strncmp(arg,"-n",2)) {
-			max_count = atoi(arg + 2);
-			continue;
-		}
-		if (!strncmp(arg, "--max-count=", 12)) {
-			max_count = atoi(arg + 12);
-			continue;
-		}
-		if (!strncmp(arg, "--max-age=", 10)) {
-			max_age = atoi(arg + 10);
-			limited = 1;
-			continue;
-		}
-		if (!strncmp(arg, "--min-age=", 10)) {
-			min_age = atoi(arg + 10);
-			limited = 1;
+			revs.max_count = atoi(arg + 2);
 			continue;
 		}
 		if (!strcmp(arg, "--header")) {
@@ -893,23 +657,6 @@ int main(int argc, const char **argv)
 			bisect_list = 1;
 			continue;
 		}
-		if (!strcmp(arg, "--all")) {
-			handle_all(&list);
-			continue;
-		}
-		if (!strcmp(arg, "--objects")) {
-			tag_objects = 1;
-			tree_objects = 1;
-			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;
@@ -923,100 +670,42 @@ int main(int argc, const char **argv)
 			show_breaks = 1;
 			continue;
 		}
-		if (!strcmp(arg, "--topo-order")) {
-		        topo_order = 1;
-			lifo = 1;
-		        limited = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--date-order")) {
-		        topo_order = 1;
-			lifo = 0;
-		        limited = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--dense")) {
-			dense = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--sparse")) {
-			dense = 0;
-			continue;
-		}
-		if (!strcmp(arg, "--remove-empty")) {
-			remove_empty_trees = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--")) {
-			i++;
-			break;
-		}
-
-		if (show_breaks && !merge_order)
-			usage(rev_list_usage);
+		usage(rev_list_usage);
 
-		flags = 0;
-		dotdot = strstr(arg, "..");
-		if (dotdot) {
-			unsigned char from_sha1[20];
-			char *next = dotdot + 2;
-			*dotdot = 0;
-			if (!*next)
-				next = "HEAD";
-			if (!get_sha1(arg, from_sha1) && !get_sha1(next, sha1)) {
-				struct commit *exclude;
-				struct commit *include;
-				
-				exclude = get_commit_reference(arg, from_sha1, UNINTERESTING);
-				include = get_commit_reference(next, sha1, 0);
-				if (!exclude || !include)
-					die("Invalid revision range %s..%s", arg, next);
-				limited = 1;
-				handle_one_commit(exclude, &list);
-				handle_one_commit(include, &list);
-				continue;
-			}
-			*dotdot = '.';
-		}
-		if (*arg == '^') {
-			flags = UNINTERESTING;
-			arg++;
-			limited = 1;
-		}
-		if (get_sha1(arg, sha1) < 0) {
-			struct stat st;
-			if (lstat(arg, &st) < 0)
-				die("'%s': %s", arg, strerror(errno));
-			break;
-		}
-		commit = get_commit_reference(arg, sha1, flags);
-		handle_one_commit(commit, &list);
 	}
 
+	list = revs.commits;
+	if (list && list->next)
+		limited = 1;
+
+	if (revs.topo_order)
+		limited = 1;
+
 	if (!list &&
-	    (!(tag_objects||tree_objects||blob_objects) && !pending_objects))
+	    (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending_objects))
 		usage(rev_list_usage);
 
-	paths = get_pathspec(prefix, argv + i);
-	if (paths) {
+	if (revs.paths) {
 		limited = 1;
-		diff_tree_setup_paths(paths);
+		diff_tree_setup_paths(revs.paths);
 	}
+	if (revs.max_age || revs.min_age)
+		limited = 1;
 
 	save_commit_buffer = verbose_header;
 	track_object_refs = 0;
 
 	if (!merge_order) {		
 		sort_by_date(&list);
-		if (list && !limited && max_count == 1 &&
-		    !tag_objects && !tree_objects && !blob_objects) {
+		if (list && !limited && revs.max_count == 1 &&
+		    !revs.tag_objects && !revs.tree_objects && !revs.blob_objects) {
 			show_commit(list->item);
 			return 0;
 		}
 	        if (limited)
 			list = limit_list(list);
-		if (topo_order)
-			sort_in_topological_order(&list, lifo);
+		if (revs.topo_order)
+			sort_in_topological_order(&list, revs.lifo);
 		show_commit_list(list);
 	} else {
 #ifndef NO_OPENSSL
diff --git a/revision.c b/revision.c
new file mode 100644
index 0000000..17dbf9a
--- /dev/null
+++ b/revision.c
@@ -0,0 +1,370 @@
+#include "cache.h"
+#include "tag.h"
+#include "blob.h"
+#include "tree.h"
+#include "commit.h"
+#include "refs.h"
+#include "revision.h"
+
+static char *path_name(struct name_path *path, const char *name)
+{
+	struct name_path *p;
+	char *n, *m;
+	int nlen = strlen(name);
+	int len = nlen + 1;
+
+	for (p = path; p; p = p->up) {
+		if (p->elem_len)
+			len += p->elem_len + 1;
+	}
+	n = xmalloc(len);
+	m = n + len - (nlen + 1);
+	strcpy(m, name);
+	for (p = path; p; p = p->up) {
+		if (p->elem_len) {
+			m -= p->elem_len + 1;
+			memcpy(m, p->elem, p->elem_len);
+			m[p->elem_len] = '/';
+		}
+	}
+	return n;
+}
+
+struct object_list **add_object(struct object *obj,
+				       struct object_list **p,
+				       struct name_path *path,
+				       const char *name)
+{
+	struct object_list *entry = xmalloc(sizeof(*entry));
+	entry->item = obj;
+	entry->next = *p;
+	entry->name = path_name(path, name);
+	*p = entry;
+	return &entry->next;
+}
+
+static void mark_blob_uninteresting(struct blob *blob)
+{
+	if (blob->object.flags & UNINTERESTING)
+		return;
+	blob->object.flags |= UNINTERESTING;
+}
+
+void mark_tree_uninteresting(struct tree *tree)
+{
+	struct object *obj = &tree->object;
+	struct tree_entry_list *entry;
+
+	if (obj->flags & UNINTERESTING)
+		return;
+	obj->flags |= UNINTERESTING;
+	if (!has_sha1_file(obj->sha1))
+		return;
+	if (parse_tree(tree) < 0)
+		die("bad tree %s", sha1_to_hex(obj->sha1));
+	entry = tree->entries;
+	tree->entries = NULL;
+	while (entry) {
+		struct tree_entry_list *next = entry->next;
+		if (entry->directory)
+			mark_tree_uninteresting(entry->item.tree);
+		else
+			mark_blob_uninteresting(entry->item.blob);
+		free(entry);
+		entry = next;
+	}
+}
+
+void mark_parents_uninteresting(struct commit *commit)
+{
+	struct commit_list *parents = commit->parents;
+
+	while (parents) {
+		struct commit *commit = parents->item;
+		commit->object.flags |= UNINTERESTING;
+
+		/*
+		 * Normally we haven't parsed the parent
+		 * yet, so we won't have a parent of a parent
+		 * here. However, it may turn out that we've
+		 * reached this commit some other way (where it
+		 * wasn't uninteresting), in which case we need
+		 * to mark its parents recursively too..
+		 */
+		if (commit->parents)
+			mark_parents_uninteresting(commit);
+
+		/*
+		 * A missing commit is ok iff its parent is marked 
+		 * uninteresting.
+		 *
+		 * We just mark such a thing parsed, so that when
+		 * it is popped next time around, we won't be trying
+		 * to parse it and get an error.
+		 */
+		if (!has_sha1_file(commit->object.sha1))
+			commit->object.parsed = 1;
+		parents = parents->next;
+	}
+}
+
+static void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
+{
+	add_object(obj, &revs->pending_objects, NULL, name);
+}
+
+static struct commit *get_commit_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
+{
+	struct object *object;
+
+	object = parse_object(sha1);
+	if (!object)
+		die("bad object %s", name);
+
+	/*
+	 * Tag object? Look what it points to..
+	 */
+	while (object->type == tag_type) {
+		struct tag *tag = (struct tag *) object;
+		object->flags |= flags;
+		if (revs->tag_objects && !(object->flags & UNINTERESTING))
+			add_pending_object(revs, object, tag->tag);
+		object = parse_object(tag->tagged->sha1);
+		if (!object)
+			die("bad object %s", sha1_to_hex(tag->tagged->sha1));
+	}
+
+	/*
+	 * Commit object? Just return it, we'll do all the complex
+	 * reachability crud.
+	 */
+	if (object->type == commit_type) {
+		struct commit *commit = (struct commit *)object;
+		object->flags |= flags;
+		if (parse_commit(commit) < 0)
+			die("unable to parse commit %s", name);
+		if (flags & UNINTERESTING)
+			mark_parents_uninteresting(commit);
+		return commit;
+	}
+
+	/*
+	 * Tree object? Either mark it uniniteresting, or add it
+	 * to the list of objects to look at later..
+	 */
+	if (object->type == tree_type) {
+		struct tree *tree = (struct tree *)object;
+		if (!revs->tree_objects)
+			return NULL;
+		if (flags & UNINTERESTING) {
+			mark_tree_uninteresting(tree);
+			return NULL;
+		}
+		add_pending_object(revs, object, "");
+		return NULL;
+	}
+
+	/*
+	 * Blob object? You know the drill by now..
+	 */
+	if (object->type == blob_type) {
+		struct blob *blob = (struct blob *)object;
+		if (!revs->blob_objects)
+			return NULL;
+		if (flags & UNINTERESTING) {
+			mark_blob_uninteresting(blob);
+			return NULL;
+		}
+		add_pending_object(revs, object, "");
+		return NULL;
+	}
+	die("%s is unknown object", name);
+}
+
+static void add_one_commit(struct commit *commit, struct rev_info *revs)
+{
+	if (!commit || (commit->object.flags & SEEN))
+		return;
+	commit->object.flags |= SEEN;
+	commit_list_insert(commit, &revs->commits);
+}
+
+static int all_flags;
+static struct rev_info *all_revs;
+
+static int handle_one_ref(const char *path, const unsigned char *sha1)
+{
+	struct commit *commit = get_commit_reference(all_revs, path, sha1, all_flags);
+	add_one_commit(commit, all_revs);
+	return 0;
+}
+
+static void handle_all(struct rev_info *revs, unsigned flags)
+{
+	all_revs = revs;
+	all_flags = flags;
+	for_each_ref(handle_one_ref);
+}
+
+/*
+ * Parse revision information, filling in the "rev_info" structure,
+ * and removing the used arguments from the argument list.
+ *
+ * Returns the number of arguments left ("new argc").
+ */
+int setup_revisions(int argc, const char **argv, struct rev_info *revs)
+{
+	int i, flags, seen_dashdash;
+	const char *def = NULL;
+	const char **unrecognized = argv+1;
+	int left = 1;
+
+	memset(revs, 0, sizeof(*revs));
+	revs->lifo = 1;
+	revs->dense = 1;
+	revs->prefix = setup_git_directory();
+	revs->max_age = -1;
+	revs->min_age = -1;
+	revs->max_count = -1;
+
+	/* First, search for "--" */
+	seen_dashdash = 0;
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		if (strcmp(arg, "--"))
+			continue;
+		argv[i] = NULL;
+		argc = i;
+		revs->paths = get_pathspec(revs->prefix, argv + i + 1);
+		seen_dashdash = 1;
+		break;
+	}
+
+	flags = 0;
+	for (i = 1; i < argc; i++) {
+		struct commit *commit;
+		const char *arg = argv[i];
+		unsigned char sha1[20];
+		char *dotdot;
+		int local_flags;
+
+		if (*arg == '-') {
+			if (!strncmp(arg, "--max-count=", 12)) {
+				revs->max_count = atoi(arg + 12);
+				continue;
+			}
+			if (!strncmp(arg, "--max-age=", 10)) {
+				revs->max_age = atoi(arg + 10);
+				continue;
+			}
+			if (!strncmp(arg, "--min-age=", 10)) {
+				revs->min_age = atoi(arg + 10);
+				continue;
+			}
+			if (!strcmp(arg, "--all")) {
+				handle_all(revs, flags);
+				continue;
+			}
+			if (!strcmp(arg, "--not")) {
+				flags ^= UNINTERESTING;
+				continue;
+			}
+			if (!strcmp(arg, "--default")) {
+				if (++i >= argc)
+					die("bad --default argument");
+				def = argv[i];
+				continue;
+			}
+			if (!strcmp(arg, "--topo-order")) {
+				revs->topo_order = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--date-order")) {
+				revs->lifo = 0;
+				revs->topo_order = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--dense")) {
+				revs->dense = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--sparse")) {
+				revs->dense = 0;
+				continue;
+			}
+			if (!strcmp(arg, "--remove-empty")) {
+				revs->remove_empty_trees = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--objects")) {
+				revs->tag_objects = 1;
+				revs->tree_objects = 1;
+				revs->blob_objects = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--objects-edge")) {
+				revs->tag_objects = 1;
+				revs->tree_objects = 1;
+				revs->blob_objects = 1;
+				revs->edge_hint = 1;
+				continue;
+			}
+			*unrecognized++ = arg;
+			left++;
+			continue;
+		}
+		dotdot = strstr(arg, "..");
+		if (dotdot) {
+			unsigned char from_sha1[20];
+			char *next = dotdot + 2;
+			*dotdot = 0;
+			if (!*next)
+				next = "HEAD";
+			if (!get_sha1(arg, from_sha1) && !get_sha1(next, sha1)) {
+				struct commit *exclude;
+				struct commit *include;
+
+				exclude = get_commit_reference(revs, arg, from_sha1, flags ^ UNINTERESTING);
+				include = get_commit_reference(revs, next, sha1, flags);
+				if (!exclude || !include)
+					die("Invalid revision range %s..%s", arg, next);
+				add_one_commit(exclude, revs);
+				add_one_commit(include, revs);
+				continue;
+			}
+			*dotdot = '.';
+		}
+		local_flags = 0;
+		if (*arg == '^') {
+			local_flags = UNINTERESTING;
+			arg++;
+		}
+		if (get_sha1(arg, sha1) < 0) {
+			struct stat st;
+			int j;
+
+			if (seen_dashdash || local_flags)
+				die("bad revision '%s'", arg);
+
+			/* If we didn't have a "--", all filenames must exist */
+			for (j = i; j < argc; j++) {
+				if (lstat(argv[j], &st) < 0)
+					die("'%s': %s", arg, strerror(errno));
+			}
+			revs->paths = get_pathspec(revs->prefix, argv + i);
+			break;
+		}
+		commit = get_commit_reference(revs, arg, sha1, flags ^ local_flags);
+		add_one_commit(commit, revs);
+	}
+	if (def && !revs->commits) {
+		unsigned char sha1[20];
+		struct commit *commit;
+		if (get_sha1(def, sha1) < 0)
+			die("bad default revision '%s'", def);
+		commit = get_commit_reference(revs, def, sha1, 0);
+		add_one_commit(commit, revs);
+	}
+	*unrecognized = NULL;
+	return left;
+}
diff --git a/revision.h b/revision.h
new file mode 100644
index 0000000..5170ac4
--- /dev/null
+++ b/revision.h
@@ -0,0 +1,48 @@
+#ifndef REVISION_H
+#define REVISION_H
+
+#define SEEN		(1u<<0)
+#define UNINTERESTING   (1u<<1)
+
+struct rev_info {
+	/* Starting list */
+	struct commit_list *commits;
+	struct object_list *pending_objects;
+
+	/* Basic information */
+	const char *prefix;
+	const char **paths;
+
+	/* Traversal flags */
+	unsigned int	dense:1,
+			remove_empty_trees:1,
+			lifo:1,
+			topo_order:1,
+			tag_objects:1,
+			tree_objects:1,
+			blob_objects:1,
+			edge_hint:1;
+
+	/* special limits */
+	int max_count;
+	unsigned long max_age;
+	unsigned long min_age;
+};
+
+/* revision.c */
+extern int setup_revisions(int argc, const char **argv, struct rev_info *revs);
+extern void mark_parents_uninteresting(struct commit *commit);
+extern void mark_tree_uninteresting(struct tree *tree);
+
+struct name_path {
+	struct name_path *up;
+	int elem_len;
+	const char *elem;
+};
+
+extern struct object_list **add_object(struct object *obj,
+				       struct object_list **p,
+				       struct name_path *path,
+				       const char *name);
+
+#endif

^ permalink raw reply related

* Re: [PATCH] git-fetch: print the new and old ref when fast-forwarding
From: Junio C Hamano @ 2006-02-25 20:53 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Lukas Sandström, Git Mailing List
In-Reply-To: <Pine.LNX.4.63.0602252107110.17999@wbgn013.biozentrum.uni-wuerzburg.de>

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

>> This is useful when you check out new changes with gitk.
>> Just copy/paste the old ref into gitk from the terminal.
>
> Why does "gitk ORIG_HEAD..HEAD" not work? (It also does the correct thing 
> when pulling...)

For most projects and repositories with single interesting head,
that would work just fine.

If you use additional Pull: lines to track more than one remote
refs, this patch would help.

For example, if you are tracking my "next" while keeping an eye
on my "master" and "pu", your .git/remotes/origin file may have
something like this:

	URL: git://git.kernel.org/pub/scm/git/git.git
        Pull: next:origin
        Pull: master:ko-master
        Pull: pu:ko-pu

When "git pull origin" pulls my next branch into your current
branch (typically "master"), it also fast forwards your tracking
branches ko-master and ko-pu.  If you want to see what I merged
in the meantime, you would want to get the old value of
ko-master and the new value and feed them to gitk (or git log).
ORIG_HEAD in this case was the old value of _your_ current
branch head, and is not useful to see what happened to my master
branch.

^ permalink raw reply

* Re: [PATCH] git-fetch: print the new and old ref when fast-forwarding
From: Johannes Schindelin @ 2006-02-25 20:08 UTC (permalink / raw)
  To: Lukas Sandström; +Cc: Git Mailing List, Junio C Hamano
In-Reply-To: <44003D6D.2010406@etek.chalmers.se>

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

Hi,

On Sat, 25 Feb 2006, Lukas Sandström wrote:

> This is useful when you check out new changes with gitk.
> Just copy/paste the old ref into gitk from the terminal.

Why does "gitk ORIG_HEAD..HEAD" not work? (It also does the correct thing 
when pulling...)

Hth,
Dscho

^ permalink raw reply

* Re: [PATCH] diff-delta: produce optimal pack data
From: Linus Torvalds @ 2006-02-25 19:18 UTC (permalink / raw)
  To: Nicolas Pitre; +Cc: Junio C Hamano, git, Carl Baldwin
In-Reply-To: <Pine.LNX.4.64.0602242326381.31162@localhost.localdomain>



On Sat, 25 Feb 2006, Nicolas Pitre wrote:
> 
> Yes, the hash is larger.  There is a cost in memory usage but not really 
> in CPU cycles.

Note that memory usage translates almost 1:1 (or worse) to CPU cycles in 
almost all real-life behaviours. Only in carefully tuned benchmarks does 
it not.

Increased memory usage means more paging, and worse cache behaviour. Now, 
hashes aren't wonderful for caches in the first place, but imagine the 
hump you pass when the data doesn't fit in a 64kB L1 any more (or a 256kB 
L2). Huge.

> > You'll find a lot of that in any file: three or four bytes of similarity 
> > just doesn't sound worthwhile to go digging after. 
> 
> Well after having experimented a lot with multiple parameters I think 
> they are worth it after all.  Not only they provide for optimal deltas, 
> but their hash is faster to compute than larger blocks which seems to 
> counter balance for the cost of increased hash list.

Hey, numbers talk. If you've got the numbers, I'll just shut up ;)

		Linus

^ permalink raw reply

* [PATCH] git-fetch: print the new and old ref when fast-forwarding
From: Lukas Sandström @ 2006-02-25 11:20 UTC (permalink / raw)
  To: Git Mailing List, Junio C Hamano

Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>

---
This is useful when you check out new changes with gitk.
Just copy/paste the old ref into gitk from the terminal.

 git-fetch.sh |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

78f2844c17bb8627e84389e3026906d074c43363
diff --git a/git-fetch.sh b/git-fetch.sh
index fcc24f8..a3e2a34 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -164,6 +164,7 @@ fast_forward_local () {
 		;;
 	    *,$local)
 		echo >&2 "* $1: fast forward to $3"
+		echo >&2 "  from $local to $2"
 		git-update-ref "$1" "$2" "$local"
 		;;
 	    *)
-- 
1.2.3.gc412

^ permalink raw reply related

* Re: gitview: Use monospace font to draw the branch and tag name
From: Aneesh Kumar @ 2006-02-25  7:00 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vzmkg6kj7.fsf@assigned-by-dhcp.cox.net>

On 2/25/06, Junio C Hamano <junkio@cox.net> wrote:
>
> >> I have an impression that hardcoding UI policy like this is
> >> generally frowned upon.
> >
> > But with that changes branch and the tag name looks neat.
>
> The point being that it only looks neat on your display, with
> its size and resolution, and to your eye.
>
> People have different tastes and equipments.  One thing I really
> liked gitk (I do not know if gitview does this as well -- if so
> I am happy) is I can do - and + to change the text size
> depending on what display I am working on.
>
>

Point taken. Right now gitview doesn't support + and - key binding. I
will try to add that. For the time being can you can drop my font and
font size related  changes and apply rest of the patches.

-aneesh

^ 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