git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 2/2] cvsimport: cleanup commit function

From
Jeff King <peff@peff.net>
Date
May 23, 2006, 07:00 UTC
Message-ID
<20060523070007.GC6180@coredump.intra.peff.net>
In-Reply-To
<20060523065232.GA6180@coredump.intra.peff.net>
This change attempts to clean up the commit function to make it a bit
easier to read (or at least the first half of it). It also improves
robustness and performance. Specifically:
  - report get_headref errors on opening ref unless the error is ENOENT
  - use regex to check for sha1 instead of length
  - use lexically scoped filehandles which get cleaned up automagically
  - check for error on both 'print' and 'close' (since output is buffered)
  - avoid "fork, do some perl, then exec" in commit(). It's not necessary,
    and we probably end up COW'ing parts of the perl process. Plus the code
    is much smaller because we can use open2()
  - avoid calling strftime over and over (mainly a readability cleanup)
---

I know this patch is quite large. I can try to split it if you want, but I suspect it's not worth the effort (either you like refactoring or you don't :) ).

9dc9f05ab5e1cbd8765238e7b1da0addd6f4296a
 git-cvsimport.perl |  150 ++++++++++++++++++++++------------------------------
 1 files changed, 64 insertions(+), 86 deletions(-)
9dc9f05ab5e1cbd8765238e7b1da0addd6f4296a
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 4efb0a5..f8feb52 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -23,7 +23,7 @@ use File::Basename qw(basename dirname);
 use Time::Local;
 use IO::Socket;
 use IO::Pipe;
-use POSIX qw(strftime dup2);
+use POSIX qw(strftime dup2 :errno_h);
 use IPC::Open2;
 
 $SIG{'PIPE'}="IGNORE";
@@ -429,22 +429,25 @@ sub getwd() {
 	return $pwd;
 }
 
+sub is_sha1 {
+	my $s = shift;
+	return $s =~ /^[a-zA-Z0-9]{40}$/;
+}
 
-sub get_headref($$) {
+sub get_headref ($$) {
     my $name    = shift;
     my $git_dir = shift; 
-    my $sha;
     
-    if (open(C,"$git_dir/refs/heads/$name")) {
-	chomp($sha = <C>);
-	close(C);
-	length($sha) == 40
-	    or die "Cannot get head id for $name ($sha): $!\n";
+    my $f = "$git_dir/refs/heads/$name";
+    if(open(my $fh, $f)) {
+      	    chomp(my $r = <$fh>);
+	    is_sha1($r) or die "Cannot get head id for $name ($r): $!";
+	    return $r;
     }
-    return $sha;
+    die "unable to open $f: $!" unless $! == POSIX::ENOENT;
+    return undef;
 }
 
-
 -d $git_tree
 	or mkdir($git_tree,0777)
 	or die "Could not create $git_tree: $!";
@@ -561,90 +564,67 @@ #---------------------
 
 my $state = 0;
 
-my($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg);
-my(@old,@new,@skipped);
-sub commit {
-	my $pid;
-
+sub update_index (\@\@) {
+	my $old = shift;
+	my $new = shift;
       	open(my $fh, '|-', qw(git-update-index --index-info))
 		or die "unable to open git-update-index: $!";
 	print $fh 
 		(map { "0 0000000000000000000000000000000000000000\t$_\n" }
-			@old),
+			@$old),
 		(map { '100' . sprintf('%o', $_->[0]) . " $_->[1]\t$_->[2]\n" }
-			@new)
+			@$new)
 		or die "unable to write to git-update-index: $!";
 	close $fh
 		or die "unable to write to git-update-index: $!";
 	$? and die "git-update-index reported error: $?";
-	@old = @new = ();
+}
 
-	$pid = open(C,"-|");
-	die "Cannot fork: $!" unless defined $pid;
-	unless($pid) {
-		exec("git-write-tree");
-		die "Cannot exec git-write-tree: $!\n";
-	}
-	chomp(my $tree = <C>);
-	length($tree) == 40
-		or die "Cannot get tree id ($tree): $!\n";
-	close(C)
+sub write_tree () {
+	open(my $fh, '-|', qw(git-write-tree))
+		or die "unable to open git-write-tree: $!";
+	chomp(my $tree = <$fh>);
+	is_sha1($tree)
+		or die "Cannot get tree id ($tree): $!";
+	close($fh)
 		or die "Error running git-write-tree: $?\n";
 	print "Tree ID $tree\n" if $opt_v;
+	return $tree;
+}
 
-	my $parent = "";
-	if(open(C,"$git_dir/refs/heads/$last_branch")) {
-		chomp($parent = <C>);
-		close(C);
-		length($parent) == 40
-			or die "Cannot get parent id ($parent): $!\n";
-		print "Parent ID $parent\n" if $opt_v;
-	}
-
-	my $pr = IO::Pipe->new() or die "Cannot open pipe: $!\n";
-	my $pw = IO::Pipe->new() or die "Cannot open pipe: $!\n";
-	$pid = fork();
-	die "Fork: $!\n" unless defined $pid;
-	unless($pid) {
-		$pr->writer();
-		$pw->reader();
-		open(OUT,">&STDOUT");
-		dup2($pw->fileno(),0);
-		dup2($pr->fileno(),1);
-		$pr->close();
-		$pw->close();
-
-		my @par = ();
-		@par = ("-p",$parent) if $parent;
-
-		# loose detection of merges
-		# based on the commit msg
-		foreach my $rx (@mergerx) {
-			if ($logmsg =~ $rx) {
-				my $mparent = $1;
-				if ($mparent eq 'HEAD') { $mparent = $opt_o };
-				if ( -e "$git_dir/refs/heads/$mparent") {
-					$mparent = get_headref($mparent, $git_dir);
-					push @par, '-p', $mparent;
-					print OUT "Merge parent branch: $mparent\n" if $opt_v;
-				}
-			}
+my($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg);
+my(@old,@new,@skipped);
+sub commit {
+	update_index(@old, @new);
+	@old = @new = ();
+	my $tree = write_tree();
+	my $parent = get_headref($last_branch, $git_dir);
+	print "Parent ID " . ($parent ? $parent : "(empty)") . "\n" if $opt_v;
+
+	my @commit_args;
+	push @commit_args, ("-p", $parent) if $parent;
+
+	# loose detection of merges
+	# based on the commit msg
+	foreach my $rx (@mergerx) {
+		next unless $logmsg =~ $rx && $1;
+		my $mparent = $1 eq 'HEAD' ? $opt_o : $1;
+		if(my $sha1 = get_headref($mparent, $git_dir)) {
+			push @commit_args, '-p', $mparent;
+			print "Merge parent branch: $mparent\n" if $opt_v;
 		}
-
-		exec("env",
-			"GIT_AUTHOR_NAME=$author_name",
-			"GIT_AUTHOR_EMAIL=$author_email",
-			"GIT_AUTHOR_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)),
-			"GIT_COMMITTER_NAME=$author_name",
-			"GIT_COMMITTER_EMAIL=$author_email",
-			"GIT_COMMITTER_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)),
-			"git-commit-tree", $tree,@par);
-		die "Cannot exec git-commit-tree: $!\n";
-
-		close OUT;
 	}
-	$pw->writer();
-	$pr->reader();
+
+	my $commit_date = strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date));
+	my $pid = open2(my $commit_read, my $commit_write,
+		'env',
+		"GIT_AUTHOR_NAME=$author_name",
+		"GIT_AUTHOR_EMAIL=$author_email",
+		"GIT_AUTHOR_DATE=$commit_date",
+		"GIT_COMMITTER_NAME=$author_name",
+		"GIT_COMMITTER_EMAIL=$author_email",
+		"GIT_COMMITTER_DATE=$commit_date",
+		'git-commit-tree', $tree, @commit_args);
 
 	# compatibility with git2cvs
 	substr($logmsg,32767) = "" if length($logmsg) > 32767;
@@ -656,16 +636,14 @@ sub commit {
 	    @skipped = ();
 	}
 
-	print $pw "$logmsg\n"
+	print($commit_write "$logmsg\n") && close($commit_write)
 		or die "Error writing to git-commit-tree: $!\n";
-	$pw->close();
 
-	print "Committed patch $patchset ($branch ".strftime("%Y-%m-%d %H:%M:%S",gmtime($date)).")\n" if $opt_v;
-	chomp(my $cid = <$pr>);
-	length($cid) == 40
-		or die "Cannot get commit id ($cid): $!\n";
+	print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
+	chomp(my $cid = <$commit_read>);
+	is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
 	print "Commit ID $cid\n" if $opt_v;
-	$pr->close();
+	close($commit_read);
 
 	waitpid($pid,0);
 	die "Error running git-commit-tree: $?\n" if $?;
-- 
1.3.3.gcb64-dirty
Previous: Jeff KingNext: Jeff King
Message 63 of 82 in “irc usage..”
  1. Linus TorvaldsMay 20, 2006
  2. Junio C HamanoMay 20, 2006
  3. Jakub NarebskiMay 20, 2006
  4. Yann DirsonMay 20, 2006
  5. Donnie BerkholzMay 20, 2006
  6. Linus TorvaldsMay 20, 2006
  7. Donnie BerkholzMay 20, 2006
  8. Linus TorvaldsMay 21, 2006
  9. Linus TorvaldsMay 22, 2006
  10. Donnie BerkholzMay 22, 2006
  11. Linus TorvaldsMay 22, 2006
  12. Martin LanghoffMay 22, 2006
  13. Donnie BerkholzMay 22, 2006
  14. Martin LanghoffMay 22, 2006
  15. Linus TorvaldsMay 22, 2006
  16. Martin LanghoffMay 22, 2006
  17. Linus TorvaldsMay 22, 2006
  18. Jakub NarebskiMay 22, 2006
  19. Linus TorvaldsMay 22, 2006
  20. Matthias LederhoferMay 22, 2006
  21. Junio C HamanoMay 22, 2006
  22. Jakub NarebskiMay 23, 2006
  23. Martin LanghoffMay 22, 2006
  24. Donnie BerkholzMay 22, 2006
  25. Linus TorvaldsMay 22, 2006
  26. Donnie BerkholzMay 22, 2006
  27. Linus TorvaldsMay 22, 2006
  28. Donnie BerkholzMay 22, 2006
  29. Donnie BerkholzMay 29, 2006
  30. Martin LanghoffMay 29, 2006
  31. Donnie BerkholzMay 29, 2006
  32. Martin LanghoffMay 30, 2006
  33. Donnie BerkholzMay 30, 2006
  34. Martin LanghoffMay 30, 2006
  35. Linus TorvaldsMay 30, 2006
  36. Martin LanghoffMay 30, 2006
  37. Linus TorvaldsMay 30, 2006
  38. Martin LanghoffMay 31, 2006
  39. Donnie BerkholzMay 31, 2006
  40. Martin LanghoffMay 31, 2006
  41. Alec WarnerMay 31, 2006
  42. Martin LanghoffMay 31, 2006
  43. Alec WarnerJun 1, 2006
  44. Martin LanghoffJun 1, 2006
  45. Alec WarnerJun 5, 2006
  46. Martin LanghoffJun 5, 2006
  47. Alec WarnerJun 5, 2006
  48. Martin LanghoffJun 5, 2006
  49. SeanJun 5, 2006
  50. Martin LanghoffMay 22, 2006
  51. Linus TorvaldsMay 22, 2006
  52. Linus TorvaldsMay 22, 2006
  53. Matthias UrlichsMay 22, 2006
  54. Linus TorvaldsMay 22, 2006
  55. Martin LanghoffMay 22, 2006
  56. Martin LanghoffMay 22, 2006
  57. Linus TorvaldsMay 22, 2006
  58. Junio C HamanoMay 22, 2006
  59. Martin LanghoffMay 22, 2006
  60. Jeff KingMay 23, 2006
  61. Jeff KingMay 23, 2006
  62. 1/2 cvsimport: use git-update-index --index-infoJeff King, May 23, 2006
  63. 2/2 cvsimport: cleanup commit functionJeff King, May 23, 2006
  64. 1/2 cvsimport: use git-update-index --index-infoJeff King, May 23, 2006
  65. Martin LanghoffMay 23, 2006
  66. Junio C HamanoMay 23, 2006
  67. Martin LanghoffMay 23, 2006
  68. Linus TorvaldsMay 23, 2006
  69. Linus TorvaldsMay 23, 2006
  70. Junio C HamanoMay 23, 2006
  71. Martin LanghoffMay 23, 2006
  72. Jeff KingMay 23, 2006
  73. Martin LanghoffMay 23, 2006
  74. Morten WelinderMay 23, 2006
  75. Jeff KingMay 23, 2006
  76. Junio C HamanoMay 23, 2006
  77. Jeff KingMay 24, 2006
  78. Donnie BerkholzMay 22, 2006
  79. Thomas GlanzmannMay 21, 2006
  80. Donnie BerkholzMay 21, 2006
  81. Linus TorvaldsMay 22, 2006
  82. Jeff KingMay 23, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.