<?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>AdamFranco.com &#187; source-control</title>
	<atom:link href="http://www.adamfranco.com/tag/source-control/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.adamfranco.com</link>
	<description>Musings, projects, software, and photography.</description>
	<lastBuildDate>Fri, 07 Dec 2012 18:11:39 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Git Tip: Grouping feature-branch commits when merging.</title>
		<link>http://www.adamfranco.com/2010/12/12/git-tip-grouping-feature-branch-commits-when-merging/</link>
		<comments>http://www.adamfranco.com/2010/12/12/git-tip-grouping-feature-branch-commits-when-merging/#comments</comments>
		<pubDate>Sun, 12 Dec 2010 18:32:02 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Computers and Technology]]></category>
		<category><![CDATA[Work/Professional]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[source-control]]></category>

		<guid isPermaLink="false">http://www.adamfranco.com/?p=478</guid>
		<description><![CDATA[Let&#8217;s say you are working on a large feature or update that requires a bunch of commits to complete. You finish up with your work and are then ready to merge it onto your master branch. For example, here is the history of my drupal repository after some work updating the cas module to the [...]]]></description>
				<content:encoded><![CDATA[<p>Let&#8217;s say you are working on a large feature or update that requires a bunch of commits to complete. You finish up with your work and are then ready to merge it onto your master branch.</p>
<p>For example, here is the history of my drupal repository after some work updating the cas module to the latest version (and to support the new version of <a href="https://wiki.jasig.org/display/CASC/phpCAS">phpCAS</a>):<br />
<a href="http://www.adamfranco.com/files/2010/12/git-merge-0.png" rel="lightbox[478]" title="git-merge-0"><img class="aligncenter size-full wp-image-479" title="git-merge-0" src="http://www.adamfranco.com/files/2010/12/git-merge-0.png" alt="" width="100%" /></a></p>
<p>As you can see, I have a number of commits, followed by a merge in with the new module code, followed by some more commits.</p>
<p>Now, if I merge my feature branch (<code>master-cas3-simple</code>) into the <code>master</code> via</p>
<pre>git merge  master-cas3-simple</pre>
<p>then the history will look like this:<br />
<a href="http://www.adamfranco.com/files/2010/12/git-merge-ff.png" rel="lightbox[478]" title="git-merge-ff"><img class="aligncenter size-full wp-image-482" title="git-merge-ff" src="http://www.adamfranco.com/files/2010/12/git-merge-ff.png" alt="" width="100%" /></a></p>
<p>While the history is all there, it isn&#8217;t obvious that all of the commits beyond &#8220;Convert MS Word quote&#8230;&#8221; are a single unit of work. They all kind of blend together because git performed a &#8220;fast-forward&#8221; commit. Usually fast-forward commits are helpful since they keep the history from being cluttered with hundreds of unnecessary merge commits, but in this case we are loosing the context of these commits being a unit of work.</p>
<p>To preserve the grouping of these commits together I can instead force the merge operation to create a merge commit (and even append a message) by using the <code>--no-ff</code> option to <code>git merge</code>:</p>
<pre>git merge --no-ff -m "Upgraded CAS support to to cas-6.x-3.x-dev and phpCAS 1.2.0 RC2.5" master-cas3-simple</pre>
<p>This results in the history below:<br />
<a href="http://www.adamfranco.com/files/2010/12/git-merge-no-ff.png" rel="lightbox[478]" title="git-merge-no-ff"><img class="aligncenter size-full wp-image-484" title="git-merge-no-ff" src="http://www.adamfranco.com/files/2010/12/git-merge-no-ff.png" alt="" width="100%" /></a></p>
<p>As you can see, merging with the <code>--no-ff</code> option creates a merge commit which very obviously delineates work on this feature. If we decided that we wanted to roll back this feature it would be much easier to sort out where the starting point before the feature was.</p>
<div class='attribution'>
Thanks to Vincent Driessen for turning me onto the utility of the the <code>--no-ff</code> merge option via his post &#8220;<a href="http://nvie.com/posts/a-successful-git-branching-model/">A successful Git branching model</a>&#8220;.</div>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfranco.com/2010/12/12/git-tip-grouping-feature-branch-commits-when-merging/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mirroring a Subversion repository on Github</title>
		<link>http://www.adamfranco.com/2010/12/05/mirroring-a-subversion-repository-on-github/</link>
		<comments>http://www.adamfranco.com/2010/12/05/mirroring-a-subversion-repository-on-github/#comments</comments>
		<pubDate>Sun, 05 Dec 2010 05:30:12 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Computers and Technology]]></category>
		<category><![CDATA[Work/Professional]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[git-svn]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[source-control]]></category>
		<category><![CDATA[Subversion]]></category>

		<guid isPermaLink="false">http://www.adamfranco.com/?p=445</guid>
		<description><![CDATA[For the past few months I have been doing a lot of work on the phpCAS library, mostly to improve the community trunk of phpCAS so that I wouldn&#8217;t have to maintain our own custom fork with support for the CAS attribute format we use at Middlebury College. The phpCAS project lead, Joachim Fritschi, has [...]]]></description>
				<content:encoded><![CDATA[<p>For the past few months I have been doing a lot of <a href="http://www.ohloh.net/p/phpcas/contributors/290013371731193">work</a> on the <a href="https://wiki.jasig.org/display/CASC/phpCAS">phpCAS library</a>, mostly to improve the community trunk of phpCAS so that I wouldn&#8217;t have to maintain our own custom fork with support for the <a href="https://issues.jasig.org/browse/PHPCAS-88">CAS attribute</a> format we use at Middlebury College. The phpCAS project lead, Joachim Fritschi, has been great to work with and I&#8217;ve had a blast helping out with the project.</p>
<p>The tooling has involved a few challenges however, since <a href="http://www.jasig.org/">Jasig</a> (the organization that hosts the <a href="http://www.jasig.org/cas">CAS</a> and phpCAS projects) uses <a href="http://subversion.apache.org/">Subversion</a> for its source-code repositories and we use <a href="http://git-scm.com/">Git</a> for all of our projects. Now, I could just suck it up and use Subversion when doing phpCAS development, but there are a few reasons I don&#8217;t:</p>
<ol>
<li>We make use of <a href="http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#submodules">Git submodules</a> to include phpCAS along with the source-code of our applications, necessitating the use of a public Git repository that includes phpCAS.</li>
<li>The <a href="http://www.kernel.org/pub/software/scm/git/docs/git-svn.html">git-svn</a> tools allow me to use git on my end to work with a Subversion repository, which is great because&#8230;</li>
<li>I find that Git&#8217;s fast history browsing and searching make troubleshooting and bug fixing much easier than any other tools I&#8217;ve used.</li>
</ol>
<p>For the past two years I have been using git-svn to work with the phpCAS repository and every so often pushing changes up to a <a href="https://github.com/adamfranco/phpcas/">public Git repository on GitHub</a>. Our applications reference this repository as a submodule when they need to make use of phpCAS. Now that I&#8217;ve been doing more work on phpCAS (and am more interested in keeping our applications using up-to-date versions), I&#8217;ve decided to automate the process of mirroring the Subversion repository on GitHub. Read on for details of how I&#8217;ve set this up and the scripts for keeping the mirror in sync.</p>
<p><span id="more-445"></span></p>
<p>On my development server I have a git repository I&#8217;ve cloned from the Jasig Subversion repository via:</p>
<pre>git svn clone --stdlayout https://source.jasig.org/cas-clients/phpcas/</pre>
<p>I use this repository for my phpCAS development and am continually using <code>git svn rebase</code> and <code>git svn dcommit</code> to update my branches from Subversion and commit changes back to the Subversion repository.</p>
<p>My goal was to fetch from Subversion and push all of the branches and tags from the Subversion repository to GitHub while ignoring any private branches or un-dcommited changes I might have kicking about my development repository.</p>
<p><strong>Step 1: Add the GitHub repository as a remote</strong></p>
<pre>git remote add github git@github.com:adamfranco/phpcas.git</pre>
<p><strong>Step 2: Fetch the latest changes from the svn repository</strong><br />
To do this, I just needed to run <code>git svn fetch</code> to import commits from the Subversion repository into my Git repository.</p>
<p><strong>Step 3: Make Git tags for Subversion tag-branches</strong><br />
I may be doing something wrong, but it seems that Subversion tags come through <code>git svn</code> as git branches rather than as git &#8220;tag&#8221; objects. Basically they are a branch with a single commit that just adds the tag message, but no content change. Using <code>git show</code> I found I could grab the parent id, message, and other metadata from the &#8220;tag-branch&#8221;, then feed that into <code>git tag</code> to create actual tag objects in the git repository.</p>
<p style="text-align: center;"><a href="http://www.adamfranco.com/files/2010/12/git-svn_tags.png" rel="lightbox[445]" title="git-svn_tags"><img class="aligncenter" title="git-svn_tags" src="http://www.adamfranco.com/files/2010/12/git-svn_tags.png" alt="" width="100%" /></a></p>
<p><strong>Step 4: Push subversion branches and newly created tags to GitHub</strong><br />
When called with no parameters <code>git push</code> will push all branches that have matching names in both the source and the destination repository. This wasn&#8217;t going to work for me since I want to only automatically push the branch-state that exists in subversion (not any un-dcommitted changes in my Git repository) and want to create mirrors of any new branches that appear in the Subversion repository. To accomplish this I needed to specify every branch individually. I determined the list of branches via:</p>
<pre>git branch -r | grep -v '/' | grep -v trunk</pre>
<p>then looped through them and appended them to the hard-coded mapping between the svn &#8220;trunk&#8221; and the GitHub &#8220;master&#8221;:</p>
<pre>$cmd = 'git push --tags github refs/remotes/trunk:refs/heads/master ';
foreach ($svnBranches as $branch) {
	$cmd .= 'refs/remotes/'.$branch.':refs/heads/'.$branch.' ';
}</pre>
<p><strong>All together: <code>update_github_phpcas</code></strong><br />
Below is a script which performs the tasks above. I&#8217;ve added it to my crontab so that it runs every half-hour and keeps my GitHub repository in-sync with the Jasig Subversion repository.</p>
<div style="display: block; border: 1px dotted; padding: 5px;"><code><span style="color: #000000;"><br />
#!/usr/local/bin/php<br />
<span style="color: #0000bb;">&lt;?php<br />
</span><span style="color: #ff8000;">/**<br />
* Script to mirror a Subversion repository on GitHub or another public Git repository.<br />
*<br />
* Author: Adam Franco (afranco@middlebury.edu)<br />
* Date: 2010-12-04<br />
* License: GNU General Public License (GPL) version 2 or later.<br />
*/&nbsp;</p>
<p><span style="color: #0000bb;">chdir</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'/home/afranco/private_html/phpcas/'</span><span style="color: #007700;">);</span></p>
<p><span style="color: #ff8000;">// Fetch from svn.<br />
</span><span style="color: #007700;">`</span><span style="color: #0000bb;">git svn fetch</span><span style="color: #007700;">`;</span></p>
<p><span style="color: #ff8000;">// Lookup all of the svn branches<br />
</span><span style="color: #0000bb;">$svnBranches </span><span style="color: #007700;">= </span><span style="color: #0000bb;">explode</span><span style="color: #007700;">(</span><span style="color: #dd0000;">"\n"</span><span style="color: #007700;">, </span><span style="color: #0000bb;">trim</span><span style="color: #007700;">(`</span><span style="color: #0000bb;">git branch -r | grep -v '/' | grep -v trunk</span><span style="color: #007700;">`));<br />
</span><span style="color: #0000bb;">$svnBranches </span><span style="color: #007700;">= </span><span style="color: #0000bb;">array_map</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'trim'</span><span style="color: #007700;">, </span><span style="color: #0000bb;">$svnBranches</span><span style="color: #007700;">);</span></p>
<p><span style="color: #ff8000;">// Add all of our branches to the list of those to push<br />
</span><span style="color: #0000bb;">$cmd </span><span style="color: #007700;">= </span><span style="color: #dd0000;">'git push --tags github refs/remotes/trunk:refs/heads/master '</span><span style="color: #007700;">;<br />
foreach (</span><span style="color: #0000bb;">$svnBranches </span><span style="color: #007700;">as </span><span style="color: #0000bb;">$branch</span><span style="color: #007700;">) {<br />
</span><span style="color: #0000bb;">$cmd </span><span style="color: #007700;">.= </span><span style="color: #dd0000;">'refs/remotes/'</span><span style="color: #007700;">.</span><span style="color: #0000bb;">$branch</span><span style="color: #007700;">.</span><span style="color: #dd0000;">':refs/heads/'</span><span style="color: #007700;">.</span><span style="color: #0000bb;">$branch</span><span style="color: #007700;">.</span><span style="color: #dd0000;">' '</span><span style="color: #007700;">;<br />
}</span></p>
<p><span style="color: #ff8000;">// Ensure that Git tags are created for every SVN tag branch.<br />
</span><span style="color: #0000bb;">$svnBranches </span><span style="color: #007700;">= </span><span style="color: #0000bb;">explode</span><span style="color: #007700;">(</span><span style="color: #dd0000;">"\n"</span><span style="color: #007700;">, </span><span style="color: #0000bb;">trim</span><span style="color: #007700;">(`</span><span style="color: #0000bb;">git branch -r | grep 'tags/'</span><span style="color: #007700;">`));<br />
</span><span style="color: #0000bb;">$svnBranches </span><span style="color: #007700;">= </span><span style="color: #0000bb;">array_map</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'trim'</span><span style="color: #007700;">, </span><span style="color: #0000bb;">$svnBranches</span><span style="color: #007700;">);<br />
foreach (</span><span style="color: #0000bb;">$svnBranches </span><span style="color: #007700;">as </span><span style="color: #0000bb;">$svnTag</span><span style="color: #007700;">) {<br />
</span><span style="color: #0000bb;">$ref </span><span style="color: #007700;">= </span><span style="color: #dd0000;">"refs/remotes/$svnTag"</span><span style="color: #007700;">;<br />
</span><span style="color: #0000bb;">$parent </span><span style="color: #007700;">= </span><span style="color: #0000bb;">shell_exec</span><span style="color: #007700;">(</span><span style="color: #dd0000;">"git show --format=\"format:%P\" $ref"</span><span style="color: #007700;">);</span></p>
<p><span style="color: #ff8000;">// If there are no tags on the parent of the tag branch, add one.<br />
</span><span style="color: #007700;">if (!</span><span style="color: #0000bb;">strlen</span><span style="color: #007700;">(</span><span style="color: #0000bb;">trim</span><span style="color: #007700;">(`</span><span style="color: #0000bb;">git tag --contains $parent</span><span style="color: #007700;">`))) {<br />
</span><span style="color: #0000bb;">$message </span><span style="color: #007700;">= </span><span style="color: #0000bb;">shell_exec</span><span style="color: #007700;">(</span><span style="color: #dd0000;">"git show --format=\"format:%s%ntagged by %aN on %aD\" $ref"</span><span style="color: #007700;">);<br />
</span><span style="color: #0000bb;">$date </span><span style="color: #007700;">= </span><span style="color: #0000bb;">shell_exec</span><span style="color: #007700;">(</span><span style="color: #dd0000;">"git show --format=\"format:%ai\" $ref"</span><span style="color: #007700;">);<br />
</span><span style="color: #0000bb;">$tagName </span><span style="color: #007700;">= </span><span style="color: #0000bb;">str_replace</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'tags/'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">''</span><span style="color: #007700;">, </span><span style="color: #0000bb;">$svnTag</span><span style="color: #007700;">);</span></p>
<p><span style="color: #0000bb;">$tagCmd </span><span style="color: #007700;">= </span><span style="color: #dd0000;">'GIT_COMMITTER_DATE="'</span><span style="color: #007700;">.</span><span style="color: #0000bb;">$date</span><span style="color: #007700;">.</span><span style="color: #dd0000;">'" git tag -a -m "'</span><span style="color: #007700;">.</span><span style="color: #0000bb;">$message</span><span style="color: #007700;">.</span><span style="color: #dd0000;">'" '</span><span style="color: #007700;">.</span><span style="color: #0000bb;">$tagName</span><span style="color: #007700;">.</span><span style="color: #dd0000;">' '</span><span style="color: #007700;">.</span><span style="color: #0000bb;">$parent</span><span style="color: #007700;">;<br />
</span><span style="color: #ff8000;">#        print $tagCmd ."\n";<br />
#        print "Creating tag $tagName\n";<br />
</span><span style="color: #007700;">`</span><span style="color: #0000bb;">$tagCmd</span><span style="color: #007700;">`;<br />
}<br />
}</span></p>
<p><span style="color: #ff8000;">#print $cmd;<br />
#print "\n";</span></p>
<p><span style="color: #0000bb;">$output </span><span style="color: #007700;">= `</span><span style="color: #0000bb;">$cmd 2&gt;&amp;1</span><span style="color: #007700;">`;</span></p>
<p>if (<span style="color: #0000bb;">trim</span><span style="color: #007700;">(</span><span style="color: #0000bb;">$output</span><span style="color: #007700;">) != </span><span style="color: #dd0000;">'Everything up-to-date'</span><span style="color: #007700;">)<br />
print </span><span style="color: #0000bb;">$output</span><span style="color: #007700;">.</span><span style="color: #dd0000;">"\n"</span><span style="color: #007700;">;</span></p>
<p></span></span></code>&nbsp;</p>
<p><code> </code>&nbsp;</p>
</div>
<p>I think that this script should work with very few changes for mirroring any Subversion repository as a Git repository.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfranco.com/2010/12/05/mirroring-a-subversion-repository-on-github/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Git Tip of the Day: Stage Hunks</title>
		<link>http://www.adamfranco.com/2009/01/13/git-tip-of-the-day-stage-hunks/</link>
		<comments>http://www.adamfranco.com/2009/01/13/git-tip-of-the-day-stage-hunks/#comments</comments>
		<pubDate>Tue, 13 Jan 2009 16:19:43 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Computers and Technology]]></category>
		<category><![CDATA[Work/Professional]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[source-control]]></category>

		<guid isPermaLink="false">http://www.adamfranco.com/?p=91</guid>
		<description><![CDATA[One of the great things about the Git version-control system is the ability to incrementally commit your changes on a private branch to keep a step-by-step record of your thought and writing process on a fix or a feature, and then merge the completed work onto your main [or public] branch after your feature or [...]]]></description>
				<content:encoded><![CDATA[<p>One of the great things about the <a href="http://git-scm.com/">Git</a> version-control system is the ability to incrementally commit your changes on a <a href="http://amarok.kde.org/wiki/Development/Git#Branching">private branch</a> to keep a step-by-step record of your thought and writing process on a fix or a feature, and then merge the completed work onto your main [or public] branch after your feature or fix is all done and tested. By keeping an incremental log of your changes &#8212; rather than just committing one giant set of code with changes to 30 files &#8212; it becomes much easier to know why a certain line was changed in the future when bugs are discovered with it.</p>
<p>One thing that often happens to me though, is that I work for about a half hour to an hour trying to get a new piece of code working and in the process make several sets of changes to one file that are only loosely related.</p>
<p>Let&#8217;s say that I am fixing a bug in my &#8216;MediaLibrary&#8217; class and while doing so notice some some spelling mistakes in some comments that I fix. Now my one file has two changes my bug fix, and the spelling fix. Rather than committing both changes together with one comment describing both changes, I can highlight one of the changes in <a href="http://www.kernel.org/pub/software/scm/git/docs/git-gui.html">git-gui</a> and select the &#8220;Stage Hunk for Commit&#8221; option.</p>
<p><a href='http://www.adamfranco.com/files/2009/01/stagehunk1.jpg' rel="lightbox[91]" title="Git-GUI: Stage Hunk"><img src="http://www.adamfranco.com/files/2009/01/stagehunk1.jpg" alt="Screen-shot of Staging a Hunk of code" title="Git-GUI: Stage Hunk" width="500" height="361" class="alignnone size-full wp-image-93" /></a></p>
<p>With that one hunk staged I can now commit with a message applicable to that change. Other changes can then be staged and committed with their own messages resulting in a very understandable history of changes.</p>
<p>&#8220;Stage Hunk for Commit&#8221; can also be used to commit important changes while not including debugging lines inserted in your code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfranco.com/2009/01/13/git-tip-of-the-day-stage-hunks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
