<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>dagolden &#187; git</title>
	<atom:link href="http://www.dagolden.com/index.php/category/git/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dagolden.com</link>
	<description>Whatever comes to mind</description>
	<lastBuildDate>Mon, 23 Jan 2012 03:43:33 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>How to script git with perl and Git::Wrapper</title>
		<link>http://www.dagolden.com/index.php/998/how-to-script-git-with-perl-and-gitwrapper/</link>
		<comments>http://www.dagolden.com/index.php/998/how-to-script-git-with-perl-and-gitwrapper/#comments</comments>
		<pubDate>Tue, 31 Aug 2010 03:17:41 +0000</pubDate>
		<dc:creator>dagolden</dc:creator>
				<category><![CDATA[git]]></category>
		<category><![CDATA[perl programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ironman]]></category>

		<guid isPermaLink="false">http://www.dagolden.com/?p=998</guid>
		<description><![CDATA[If you work with git, eventually you will want to script something that git doesn't do already and can't be accomplished with an alias. If you use Perl, the Git::Wrapper module makes scripting git easy. The big advantage of Git::Wrapper is that it wraps the binary version of git, which keeps your perl and git [...]]]></description>
			<content:encoded><![CDATA[<p>If you work with <a href="http://git-scm.com/">git</a>, eventually you will want to script something that git doesn't do already and can't be accomplished with an alias.  If you use <a href="http://perl.org/">Perl</a>, the <a href="http://p3rl.org/Git::Wrapper">Git::Wrapper</a> module makes scripting git easy.</p>
<p>The big advantage of Git::Wrapper is that it wraps the binary version of git, which keeps your perl and git independent.  Upgrade perl and not git?  Add Git::Wrapper and you're done.  Upgrade git while keeping your existing perl?  No problem.  If you get your git from an OS distribution package, but <a href="http://p3rl.org/App::perlbrew">roll your own perl</a>, then Git::Wrapper is for you!</p>
<p>Git::Wrapper just makes it really easy to pass git commands and get back useful data.  It really shines on "git log" commands, as it parses each commit message into Git::Wrapper::Log objects with accessors for id, author, date, and message.  For everything else, it's not much more than a wrapper around qx(), but it returns arrays of lines and throws exceptions when things go wrong, which just saves a little time and code.</p>
<p>Here is a short example that I whipped up recently to automate the process of adding a <a href="http://github.com/">github</a> repository remote for someone when they send me a pull request.  (It also uses my <a href="http://p3rl.org/Getopt::Lucid">Getopt::Lucid</a> module, but as the name suggests, it should be clear what that does.)</p>
<pre class="brush: perl; title: ; notranslate">
#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use autodie;
use Git::Wrapper;
use Getopt::Lucid qw/:all/;

# USAGE: github-remote [-r REPO] [NAME]
#     NAME -- a github user name (or defaults to 'dagolden')
#     REPO -- a github repository path (or is parsed out of my private origin repo)

my $opts = Getopt::Lucid-&gt;getopt([
  Param('repo|r'),
]);

my $who = shift @ARGV;

# Get a wrapper for the current directory
my $git = Git::Wrapper-&gt;new(&quot;.&quot;);

# Locate the origin repository URL
my ($origin) = grep { /origin/ } $git-&gt;remote(&quot;-v&quot;);
die &quot;Couldn't determine origin\n&quot; unless $origin;
$origin =~ s/^origin\s+//;
$origin =~ s/\s+\(.*$//;

# Parse out the repository path
my $repo = $opts-&gt;get_repo;
unless ( $repo ) {
  # me@git.example.com:my-repo-name.git
  ($repo) = $origin =~ m/^[^:]+:(.+)$/;
}

# Set up someone else's github repo
if ( $who ) {
  $git-&gt;remote(&quot;add&quot;, $who, &quot;git://github.com/${who}/${repo}&quot;);
}
# Or set up my own github mirror
else {
  $git-&gt;remote(&quot;add&quot;, &quot;github&quot;, &quot;git\@github.com:dagolden/${repo}&quot;);
}
</pre>
<p>That's it.  I admit the program is a little crufty because of how I manage my repositories with a private origin that I mirror to a github repository, but there's almost no cruft around interactions with git.  Consider this:</p>
<pre class="brush: perl; title: ; notranslate">
  $git-&gt;remote(&quot;add&quot;, $who, &quot;git://github.com/${who}/${repo}&quot;);
</pre>
<p>If the command fails (if there's already $who as a remote name), an exception will be thrown. That means I don't have to write any error handling myself, which is perfect for a simple automation program like this one.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dagolden.com/index.php/998/how-to-script-git-with-perl-and-gitwrapper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Module::Build repository migrated to git</title>
		<link>http://www.dagolden.com/index.php/739/modulebuild-repository-migrated-to-git/</link>
		<comments>http://www.dagolden.com/index.php/739/modulebuild-repository-migrated-to-git/#comments</comments>
		<pubDate>Thu, 01 Apr 2010 16:56:34 +0000</pubDate>
		<dc:creator>dagolden</dc:creator>
				<category><![CDATA[git]]></category>
		<category><![CDATA[perl programming]]></category>
		<category><![CDATA[toolchain]]></category>
		<category><![CDATA[ironman]]></category>

		<guid isPermaLink="false">http://www.dagolden.com/?p=739</guid>
		<description><![CDATA[I have completed a migration of the Module::Build repository from Subversion to git. The new repository is available publicly on github.com: Browse the repository Clone it: git://github.com/dagolden/module-build.git I have done my best to clean up the merge/branch/tag history, but have not bothered to clean up empty commits left over from the original cvs2svn conversion. If [...]]]></description>
			<content:encoded><![CDATA[<p>I have completed a migration of the <a href="http://search.cpan.org/dist/Module-Build/">Module::Build</a> repository from <a href="http://subversion.tigris.org/">Subversion</a> to <a href="http://git-scm.com/">git</a>.</p>
<p>The new repository is available publicly on <a href="http://github.com/">github.com</a>:</p>
<ul>
<li><a href="http://github.com/dagolden/module-build/">Browse the repository</a></li>
<li>Clone it: git://github.com/dagolden/module-build.git</li>
</ul>
<p>I have done my best to clean up the merge/branch/tag history, but have not bothered to clean up empty commits left over from the original cvs2svn conversion.  If anyone sees any glaring errors please let me know.</p>
<p>I hope this migration makes it easy for people to contribute to Module-Build.  I was pleasantly surprised to find that within 12 hours of it being publishing on github, it's already being watched by several people.  </p>
<p>At the very least, it will make working on feature branches much easier to manage, which will make it easier to experiment with new ideas without affecting the main line of development.</p>
<p><strong>If anyone would like to start applying patches from the <a href="http://rt.cpan.org/Public/Dist/Display.html?Name=Module-Build">Module::Build bug queue</a>, or creating patches for other open tickets, that would be huge help.</strong></p>
<p>I will be "closing out" the old Subversion repository with a pointer to the new location shortly.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dagolden.com/index.php/739/modulebuild-repository-migrated-to-git/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Applying git patch emails to subversion</title>
		<link>http://www.dagolden.com/index.php/492/applying-git-patch-emails-to-subversion/</link>
		<comments>http://www.dagolden.com/index.php/492/applying-git-patch-emails-to-subversion/#comments</comments>
		<pubDate>Thu, 17 Sep 2009 19:29:14 +0000</pubDate>
		<dc:creator>dagolden</dc:creator>
				<category><![CDATA[git]]></category>
		<category><![CDATA[perl programming]]></category>
		<category><![CDATA[ironman]]></category>
		<category><![CDATA[subversion]]></category>

		<guid isPermaLink="false">http://www.dagolden.com/?p=492</guid>
		<description><![CDATA[I prefer git, but have been spending a lot with subversion working on Module::Build. To give myself local version control when offline (I was on an airplane), I layered a local git repository on top of the subversion checkout. (Yes, there might be better ways to do this with "git svn" but not as easily [...]]]></description>
			<content:encoded><![CDATA[<p>I prefer <a href="http://git-scm.org/">git</a>, but have been spending a lot with <a href="http://subversion.tigris.org/">subversion</a> working on <a href="http://search.cpan.org/dist/Module-Build/">Module::Build</a>.  To give myself local version control when offline (I was on an airplane), I layered a local git repository on top of the subversion checkout.  (Yes, there might be better ways to do this with "git svn" but not as easily once <strong>already</strong> offline!)</p>
<p>Once I had taught git to ignore .svn directories and taught svn to ignore .git and .gitignore, I imported the whole project to git and proceeded with my normal workflow, creating separate branches for different things I was working on.</p>
<p>Once I was back online, I wanted to merge my work back to the subversion tree, while still preserving the commit history from when I was offline.  A short bit of Perl programming later and I was done.  For each of the git branches I had created, I generated a series of patch emails with "git format-patch".   Then, after having subversion revert all files back to the latest commit, I passed the patches on the command line to this program:</p>
<pre class="brush: perl; title: ; notranslate">
#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use Email::Simple;
use Path::Class;
use File::Temp;

die &quot;$0: This is not an svn repo\n&quot;
  unless -d '.svn';

for my $f (sort @ARGV) {
  say &quot;*** $f ***&quot;;
  # try to apply patch
  system(&quot;patch -p1 &lt; $f&quot;);
  die &quot;Patch failed!  Aborting!\n&quot; if $?;

  # extract commit info
  my $email = Email::Simple-&gt;new( scalar file($f)-&gt;slurp );
  my $subject = $email-&gt;header(&quot;Subject&quot;);
  $subject =~ s{^\[PATCH[^\]]*\]\s+}{};
  my $body = $email-&gt;body;
  $body =~ s{\A(.*?)---.*$}{$1}ms;

  # write commit info to tempfile and commit it
  my $temp = File::Temp-&gt;new;
  say {$temp} $subject;
  print {$temp} &quot;\n$body&quot; if $body;

  system(&quot;svn commit -F $temp&quot;);
  die &quot;Commit failed!  Aborting!\n&quot; if $?;
}
</pre>
<p>I wouldn't want this kind of hybrid VCS to be part of my regular workflow, but in a pinch when I wanted offline version control, it worked remarkably well.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dagolden.com/index.php/492/applying-git-patch-emails-to-subversion/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>More git conversions</title>
		<link>http://www.dagolden.com/index.php/445/more-git-conversions/</link>
		<comments>http://www.dagolden.com/index.php/445/more-git-conversions/#comments</comments>
		<pubDate>Mon, 10 Aug 2009 19:41:05 +0000</pubDate>
		<dc:creator>dagolden</dc:creator>
				<category><![CDATA[cpan]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[perl programming]]></category>
		<category><![CDATA[ironman]]></category>

		<guid isPermaLink="false">http://www.dagolden.com/?p=445</guid>
		<description><![CDATA[My version number article exhausted me, so this will be a short post. My work to convert some more Perl module repositories from Subversion to git continues with two more things hosted on github: ExtUtils::CBuilder -- This is the complement to ExtUtils::ParseXS, which I described converting last week. Anyone interested in working on it, please [...]]]></description>
			<content:encoded><![CDATA[<p>My version number article exhausted me, so this will be a short post.  My work to convert some more Perl module repositories from Subversion to git continues with two more things hosted on github:</p>
<ul>
<li><a href="http://github.com/dagolden/extutils-cbuilder/">ExtUtils::CBuilder</a> -- This is the complement to <a href="http://github.com/dagolden/extutils-parsexs/">ExtUtils::ParseXS</a>, which I described converting last week.  Anyone interested in working on it, please see the <a href="http://rt.cpan.org/Public/Dist/Display.html?Name=ExtUtils-CBuilder">bug queue</a>.</li>
<li>
The <a href="http://github.com/dagolden/cpan-meta">CPAN META.yml spec</a> -- this isn't exactly a module, but extracting it from the Module::Build repository is a first step towards some needed improvements.  I have some things in development on that front that I hope to announce in  a week or so.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.dagolden.com/index.php/445/more-git-conversions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Convert to git and get more patches?</title>
		<link>http://www.dagolden.com/index.php/361/convert-to-git-and-get-more-patches/</link>
		<comments>http://www.dagolden.com/index.php/361/convert-to-git-and-get-more-patches/#comments</comments>
		<pubDate>Wed, 05 Aug 2009 03:31:24 +0000</pubDate>
		<dc:creator>dagolden</dc:creator>
				<category><![CDATA[cpan]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[ironman]]></category>

		<guid isPermaLink="false">http://www.dagolden.com/?p=361</guid>
		<description><![CDATA[Today, I converted the ExtUtils::ParseXS repository from subversion to git, published it on github.com and announced it on the perl5-porters and module-build perl mailing lists. Within hours, it was cloned and I got my first pull request. I don't know if that's the start of a trend or not, but it's food for thought for [...]]]></description>
			<content:encoded><![CDATA[<p>Today, <strong>I converted the <a href="http://search.cpan.org/perldoc?ExtUtils::ParseXS">ExtUtils::ParseXS</a> repository from subversion to git</strong>, <a href="https://github.com/dagolden/extutils-parsexs/tree">published it on github.com</a> and <a href="http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2009-08/msg00101.html">announced it</a> on the perl5-porters and module-build perl mailing lists.<strong> Within hours, it was cloned and I got my first pull request.</strong></p>
<p>I don't know if that's the start of a trend or not, but it's food for thought for anyone who questions whether git makes contributing easier.  As a publisher, git means no need to centrally administer repository access.  As a contributor, it means no need to request repository access (and wait for it to be granted).  And for both, it means no need to manage patches outside the VCS.  <strong>I'm convinced that making it easier for people to contribute means greater odds of getting contributions.</strong></p>
<p>On the technical side, this was not the easiest conversion and I learned a lot about git history rewriting during the cleanup.  Some of the highlights:</p>
<ul>
<li>I used a <a href="http://github.com/dagolden/svn2git/tree/master">modified clone</a> of <a href="http://github.com/schwern/svn2git/tree/master">Schwern's svn2git.pl</a> port of the ruby svn2git program</li>
<li>I manually fixed up "tag branches" where the history was confused, but I could identify the release point.  (Confirmed by identifying where there was no diff between tag branch and a point on the trunk branch)</li>
<li>I rewrote historical commits to fix empty commit messages</li>
</ul>
<p>This latter one was a multi-part fix.  Some commit entries said "*** empty log message ***'.  Others were literally empty.   Worse, the very first commit was the "*** empty ..." one.  git rebase is the normal tool for fixing up history, but rebase can't change the root commit.  I worked around it following <a href="http://stackoverflow.com/questions/645450/git-how-to-insert-a-commit-as-the-first-shifting-all-the-others">these instructions</a>:</p>
<ul>
<li>I created an empty commit on a new branch as a rebase target</li>
<li>I cherry-picked the first commit from the trunk onto the new branch</li>
<li>I interactively rebased the trunk onto the new branch (picking up everything <em>after</em> the cherry picked commit)</li>
</ul>
<p>The interactive rebase gave me a list of commits and message synopses.  I changed all the "*** empty ..." ones from "pick" to "edit".  For the entirely empty ones, they showed up strangely in the rebase list, where ce86d39 was the empty commit and parent to f4a7235  with the log message shown:</p>
<pre class="brush: plain; title: ; notranslate">
pick ce86d39 &amp;gt;f4a7235 blah blah blah
</pre>
<p>It turns out the way to rebase this is to just break them apart:</p>
<pre class="brush: plain; title: ; notranslate">
edit ce86d39
pick f4a7235 blah blah blah&amp;lt;/pre&amp;gt;
</pre>
<p>Then, during the rebase run, when it would stop on "*** empty ..." commits, I would amend the commit message with a list of files changed (a lazy fix, I'll admit) and continue:</p>
<pre class="brush: plain; title: ; notranslate">
$ git diff --name-only HEAD^ | \
  perl -E 'say &quot;Updated &quot; . join(q{, }, map { chomp; $_} &lt;&gt;)' | \
  git commit --amend --file=- &amp;&amp; git rebase --continue
</pre>
<p>Voila -- very lazy empty log editing.  In the blank message cases, the rebase commit itself fails due to the empty message, but I could do a direct  "git commit" (not amend because the rebase cherry-pick commit failed), give an appropriate log message, and then "git rebase --continue".</p>
<p>After that was done, the history was great, but the tags were still on the old messy branch.  But that was easy to fix with a little Perl programming:</p>
<ul>
<li>I wrote <a href="http://gist.github.com/162480">a program</a> to take a list of commits and tags and migrate the tags to the new branch where a commit in the new branch matches a previously tagged commit (i.e. in the old branch)</li>
</ul>
<p>This would have been more complex if there had been merges to consider and I'm glad there weren't.  But the end result was a nice clean, well-tagged git history.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dagolden.com/index.php/361/convert-to-git-and-get-more-patches/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

