<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <title>Blog entries tagged git :: mwop.net</title>
    <description>Blog entries tagged git :: mwop.net</description>
    <pubDate>Mon, 18 Dec 2023 15:34:00 -0600</pubDate>
    <generator>Laminas_Feed_Writer 2 (https://getlaminas.org)</generator>
    <link>https://mwop.net/blog/tag/git</link>
    <atom:link rel="self" type="application/rss+xml" href="https://mwop.net/blog/tag/git/rss.xml"/>
    <item>
      <title>Advent 2023: (n)vim Plugins: vim-fugitive</title>
      <pubDate>Mon, 18 Dec 2023 15:34:00 -0600</pubDate>
      <link>https://mwop.net/blog/2023-12-18-advent-vim-fugitive.html</link>
      <guid>https://mwop.net/blog/2023-12-18-advent-vim-fugitive.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>Because I've spent most of my professional life coding, I've also spent a lot of time using source control.
I've been using specifically <a href="https://git-scm.com/">git</a> for many years (even pre-dating the Zend Framework migration from <a href="https://subversion.apache.org">Subversion</a>).
While I typically use a terminal multiplexer (for me, that's <a href="https://github.com/tmux/tmux/wiki">tmux</a>; for others, that might be <a href="https://www.gnu.org/software/screen/">screen</a>), and can move to another pane or create one quickly in order to run source control commands, doing so interrupts flow.</p>
<p>That's where <a href="https://github.com/tpope/vim-fugitive">vim-fugitive</a> comes into play.</p>


<h3>What does it solve?</h3>
<p>Fugitive integrates with git, plain and simple.
It exposes a number of commands and functions that allow you to do common operations quickly, but also has some deeper bindings to allow doing more complex things such as viewing a file from previous commits, or performing a diff between the staged and working version, or using <code>git blame</code> within vim.</p>
<h3>How do I use it?</h3>
<p>Admittedly, I use a very small subset of what Fugitive provides.</p>
<p>On a daily basis, I use <code>:Gwrite</code> to stage changes, and <code>:G</code> to view the status of the working tree.
When in the status view, I often use <code>cc</code> to <strong>c</strong>ommit <strong>c</strong>hanges, which splits open a pane for writing the commit message.
I also use <code>:GRemove</code> when I want to remove a file from the tree.</p>
<p>Something else that has come in handy when reviewing code with others: <code>:GBrowse</code> can open the file in the canonical repository, using the visual selection as the line range, allowing you to quickly share a link to specific code to review.</p>
<h3>Final Thoughts</h3>
<p>This plugin does exactly what it says on the tin.
I love the fact that it integrates with the underlying <code>git</code> command, as that follows the Unix Philosophy of doing one thing well, and piping out to other processes to perform complex behavior.
For me, the fact that I can stay directly within my editor and still get full access to git when needed is tremondously powerful.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2023-12-18-advent-vim-fugitive.html">Advent 2023: (n)vim Plugins: vim-fugitive</a> was originally
    published <time class="dt-published" datetime="2023-12-18T15:34:00-06:00">18 December 2023</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Splitting the ZF2 Components</title>
      <pubDate>Fri, 15 May 2015 19:30:00 -0500</pubDate>
      <link>https://mwop.net/blog/2015-05-15-splitting-components-with-git.html</link>
      <guid>https://mwop.net/blog/2015-05-15-splitting-components-with-git.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>Today we accomplished one of the major goals towards Zend Framework 3:
splitting the various components into their own repositories. This proved to be
a huge challenge, due to the amount of history in our repository (the git
repository has history going back to 2009, around the time ZF 1.8 was
released!), and the goals we had for what component repositories should look
like. This is the story of how we made it happen.</p>


<h2>Why split them at all?</h2>
<p>&quot;But you can already install components individually!&quot;</p>
<p>True, but if you knew how that occurs, you'd cringe. We've tried a variety of
solutions, and every single one has failed us at some point or another,
typically when we move to a new minor version of the framework, but
occasionally even on trivial bugfix releases. We've tried <code>filter-branch</code> with
<code>subdirectory-filter</code>, we've tried <code>subtree split</code>, and even
<a href="https://github.com/dflydev/git-subsplit">subsplit</a>. We've used manual scripts
that rsync the contents of each commit and create a reference commit. Our
current version is a combination of several approaches, but we've found we must
run it manually and verify the results before pushing, as we've had a number of
situations, as recently as the 2.4.0 release, where contents were not correct.</p>
<p>On top of all this, there's another concern: why do all components get bumped
in version, even when no changes are present? As an example, a number of
components have had zero new <em>features</em> since the 2.0 release; they're either
stable, or have smaller user bases. It doesn't make sense to bump their
versions, but they get bumped regardless whenever we do a new release of the
framework. When we start considering a new major version of the framework, it
doesn't necessarily make sense to bump such components, as there will be
literally zero breaking changes, and, in many cases, no new features.</p>
<p>In other cases, such as the <code>EventManager</code>, <code>ServiceManager</code>, and a handful of
other components, we know that these will require major versions due to
necessary architectural changes. However, as long as we're still developing
minor release branches of the framework, we cannot have meaningful development
on those features due to the complexities of keeping changes in sync between
branches.</p>
<p>In short, we'd like to be able to version the individual components separately,
in their own cycles.</p>
<p>On top of that, when we look at maintenance, having a monolithic repository
poses a challenge: we have to limit the number of developers with commit rights
to ensure that those who <em>can</em> commit are aware of the impact a change might
have across the framework. This means that a number of developers with time and
energy to spend on improving a single component or small subset of components
are hampered by how quickly their changes can be reviewed by the maintainers.</p>
<p>Splitting the components gives us the opportunity to expand the number of
contributors with commit access. The framework itself can pin to specific
versions of components, and maintainers with commit access to the <em>framework</em>
can review and change those versions based on integration and smoke tests. In
the meantime, a larger set of contributors can be gradually improving the
individual components, and <em>users</em> can selectively adopt those new versions
into their applications, on their own review cycles.</p>
<p>In the end:</p>
<ul>
<li>We get components that follow <a href="http://semver.org">Semantic Versioning</a> properly.</li>
<li>We get accelerated development in components that need it.</li>
<li>We expand the number of active, able maintainers.</li>
<li>We enable users to adopt new features at their own pace.</li>
<li>We retain framework stability.</li>
</ul>
<h2>The Goal</h2>
<p>Since we branched ZF2 development, our repository has looked something like the
following:</p>
<pre><code class="language-asciidoc hljs asciidoc" data-lang="asciidoc"><span class="hljs-title">.coveralls.yml</span>
<span class="hljs-title">.gitattributes</span>
<span class="hljs-title">.gitignore</span>
<span class="hljs-title">.php_cs</span>
<span class="hljs-title">.travis.yml</span>
bin/
CHANGELOG.md
composer.json
CONTRIBUTING.md
demos/
INSTALL.md
library/
<span class="hljs-code">    Zend/</span>
<span class="hljs-code">        {component directories}</span>
LICENSE.txt
README-GIT.md
README.md
resources/
tests/
<span class="hljs-code">    _autoload.php</span>
<span class="hljs-code">    Bootstrap.php</span>
<span class="hljs-code">    phpunit.xml.dist</span>
<span class="hljs-code">    run-tests.php</span>
<span class="hljs-code">    run-tests.sh</span>
<span class="hljs-code">    TestConfiguration.php.dist</span>
<span class="hljs-code">    TestConfiguration.php.travis</span>
<span class="hljs-code">    ZendTest/</span>
<span class="hljs-code">        {component directories}</span>
</code></pre>
<p>The structure follows <a href="http://www.php-fig.org/psr/psr-0/">PSR-0</a>, with each
component below the <code>library/Zend/</code> directory.</p>
<p>The goal is to have individual component repositories, each with the following
structure:</p>
<pre><code class="language-asciidoc hljs asciidoc" data-lang="asciidoc"><span class="hljs-title">.coveralls.yml</span>
<span class="hljs-title">.gitattributes</span>
<span class="hljs-title">.gitignore</span>
<span class="hljs-title">.php_cs</span>
<span class="hljs-title">.travis.yml</span>
composer.json
CONTRIBUTING.md
src/
LICENSE.txt
phpunit.xml.dist
phpunit.xml.travis
README.md
test/
<span class="hljs-code">    bootstrap.php</span>
<span class="hljs-code">    {component test cases}</span>
</code></pre>
<p>In the above structure, note the following differences:</p>
<ul>
<li>Source and unit test files now follow
<a href="http://www.php-fig.org/psr/psr-4/">PSR-4</a>, and can be found directly beneath
the new <code>src/</code> and <code>test/</code> directories (which replace <code>library/</code> and
<code>tests/</code>, respectively), without any directory nesting based on namespace
(unless any subnamespaces are present).</li>
<li>The <code>README.md</code> file will need to be specific to the component. Additionally,
it can incorporate what was in the <code>INSTALL.md</code> file originally.</li>
<li>The <code>composer.json</code> file will need to be for the component, not the
framework. Additionally, we don't currently list dev/testing dependencies in
our component repos, so those will need to be added.</li>
<li>The <code>TestConfiguration.php.*</code> files define constants referenced by the unit
tests; those can be migrated to the <code>phpunit.xml.*</code> files — which we can move
to the project root to simplify testing.</li>
<li>The <code>.travis.yml</code> file can be streamlined, as we're now only testing one
component.</li>
<li>Most testing infrastructure can be removed, as it's around simplifying
running tests for individual components within the larger framework. The
<code>Bootstrap.php</code> gets renamed to <code>bootstrap.php</code> to avoid being confused with
unit test files.</li>
<li><code>README-GIT.md</code> gets replaced with a lengthier <code>CONTRIBUTING.md</code> file.</li>
</ul>
<p>On top of all this, we had the following requirements:</p>
<ul>
<li>The components <strong>MUST</strong> have full history from 2.0.0rc7 forward. This is so
those working on the components can see the <em>why</em> and <em>who</em> behind commits.</li>
<li>Commit messages <strong>MUST</strong> reference original issues and pull requests on the
ZF2 repository; again, this is to facilitate the <em>why</em> behind changes.</li>
<li>Ideally, history should contain <em>only</em> history for the given component.</li>
<li>The directory structure in <em>each</em> commit, including (and especially!) tags,
<strong>MUST</strong> follow the proposed structure.</li>
</ul>
<h2>How we got there</h2>
<p>One of the huge benefits to using Git is the ability to rewrite history. (It's
also one of its scariest features.) It provides a number of facilities for
doing so, from <code>rebase</code> to grafts to <code>subtree</code> to <code>filter-branch</code>. In our
component split research, we evaluated several solutions.</p>
<h3>Grafts</h3>
<p><a href="https://git.wiki.kernel.org/index.php/GraftPoint">Grafts</a> provide a way to
merge two different lines of history together, but, for our purposes, also
allow us to <em>prune</em> history. Why would we do this? Because we don't really need
history prior to 2.0.0 development at this point. In large part, this is
because it's irrelevant; files were moved around and changed so much between
forking from the 1.X tree and 2.0 that tracing the history is quite difficult.</p>
<p>I eventually found a methodology for pruning that looks like this:</p>
<pre><code class="language-bash hljs bash" data-lang="bash">$ <span class="hljs-built_in">echo</span> bb50be26b24a9e0e62a8f4abecce53259d707b61 &gt; .git/info/grafts
$ git filter-branch --tag-name-filter cat -- --all
$ git reflog expire --expire=now --all
$ git gc --prune=now --aggressive
$ rm .git/info/grafts
</code></pre>
<p>It's supposed to essentially remove history before the given sha1. What I found
was that by itself, I noticed little to no change in the repository, other than
size; I could still reach earlier commits. However, when coupled with the final
techniques we used, it meant that we effectively saw no commits prior to this
point.</p>
<h3>subtree</h3>
<p><code>git subtree</code> is a &quot;contributed&quot; git command; it's not available in default
distributions of git, but often available as an add-on package; if you install
git from source, it's in the <code>contrib</code> tree, where you can compile and install
it. Subtree provides a rich set of functionality around dealing with repository
subtrees, allowing you to split them off, add subtrees from other projects, and
even push commits back and forth between them.</p>
<p>At first blush, it seems like an ideal, simple solution:</p>
<ul>
<li>Split each of the <code>library/</code> and <code>tests/</code> component subtrees into their own branches.</li>
<li>Create a new repository, and add each of the above as subtrees.</li>
</ul>
<pre><code class="language-bash hljs bash" data-lang="bash">$ git <span class="hljs-built_in">clone</span> zendframework/zf2
$ git init zend-http
$ <span class="hljs-built_in">cd</span> zf2
$ git subtree split --prefix=library/Zend/Http -b src
$ git subtree split --prefix=tests/ZendTest/Http -b <span class="hljs-built_in">test</span>
$ <span class="hljs-built_in">cd</span> ../zend-http
$ <span class="hljs-comment"># add in basic assets, and create initial commit</span>
$ git remote add zf2 ../zf2
$ git subtree add --prefix=src/ zf2 src
$ git subtree add --prefix=<span class="hljs-built_in">test</span>/ zf2 <span class="hljs-built_in">test</span>
</code></pre>
<p>Indeed, if you do the above, when done, the directory looks exactly like it
should! <strong>However</strong>, the history is all wrong; if you check out any tags, you
get the full ZF2 tree for the tag. As such, subtree fails one of the most
important criteria right off the bat: that each commit and tag represent <em>only</em>
the component.</p>
<h3>subdirectory-filter</h3>
<p><code>subdirectory-filter</code> is one of the <code>git filter-branch</code> strategies. It operates
similarly to <code>subtree</code>, but also rewrites history. We used <a href="https://gist.github.com/ralphschindler/9494556">this approach</a>
when splitting the various &quot;service&quot; (API wrapper) components from the main
repository prior to the first ZF2 stable release.</p>
<p>The basic idea is similar to that of <code>subtree</code>; the difference is that you have
to begin with separate checkouts for each of the source and tests.</p>
<pre><code class="language-bash hljs bash" data-lang="bash">$ git <span class="hljs-built_in">clone</span> zendframework/zf2 zend-http-src
$ git <span class="hljs-built_in">clone</span> zendframework/zf2 zend-http-test
$ <span class="hljs-built_in">cd</span> zend-http-src
$ git filter-branch --subdirectory-filter library/Zend/Http --tag-name-filter cat -- -all
$ <span class="hljs-built_in">cd</span> ../zend-http-test
$ git filter-branch --subdirectory-filter tests/ZendTest/Http --tag-name-filter cat -- -all
$ <span class="hljs-built_in">cd</span> ..
$ git init zend-http
$ <span class="hljs-built_in">cd</span> zend-http
<span class="hljs-comment"># add in basic assets, and create initial commit</span>
$ git remote add -f src ../zend-http-src
$ git remote add -f <span class="hljs-built_in">test</span> ../zend-http-test
$ git merge -s ours --no-commit src/master
$ git <span class="hljs-built_in">read</span>-tree -u --prefix=src/ src/master
$ git commit -m <span class="hljs-string">'Merging src tree'</span>
$ git merge -s ours --no-commit <span class="hljs-built_in">test</span>/master
$ git <span class="hljs-built_in">read</span>-tree -u --prefix=<span class="hljs-built_in">test</span>/ <span class="hljs-built_in">test</span>/master
$ git commit -m <span class="hljs-string">'Merging test tree'</span>
</code></pre>
<p>Again, this looks great at first blush; all the contents for the given
component are rewritten perfectly. But when you start looking at previous tags
and commits, you see an interesting picture: based on the commit and which
remote you added first, you'll see a completely different directory structure.
Like <code>subtree</code>, this fails our criteria that the repo be in a usable state at
any given commit.</p>
<h3>tree-filter</h3>
<p>Like <code>subdirectory-filter</code>, <code>tree-filter</code> is a <code>filter-branch</code> strategy.
<code>tree-filter</code> allows you to rewrite the tree contents <em>any way you want</em>, while
retaining the commit message and metadata. This turned out to be what we were
looking for!</p>
<p>However, there were a few more pieces we needed to address:</p>
<ul>
<li>Rewriting commit messages referencing issues and pull requests to link to the
main ZF2 repository.</li>
<li>Pruning empty commits.</li>
<li>Ensuring tags contain the expected tree.</li>
</ul>
<p>Fortunately, <code>filter-branch</code> has other strategies for just these purposes:</p>
<ul>
<li><code>msg-filter</code> allows you to rewrite commit messages.</li>
<li><code>commit-filter</code> provides tools for detecting and removing empty commits.</li>
<li><code>tag-name-filter</code> ensures that tag references are rewritten when the parent commits change or are removed.</li>
</ul>
<p>So, what we ended up with was something like the following:</p>
<pre><code class="language-bash hljs bash" data-lang="bash">git filter-branch -f \
    --tree-filter <span class="hljs-string">"php /path/to/tree-filter.php"</span> \
    --msg-filter <span class="hljs-string">"sed -re 's/(^|[^a-zA-Z])(\#[1-9][0-9]*)/zendframework\/zf2/g'"</span> \
    --commit-filter <span class="hljs-string">'git_commit_non_empty_tree "$@"'</span> \
    --tag-name-filter cat \
    -- --all
</code></pre>
<p><code>/path/to/tree-filter.php</code> is a script that contains the logic for re-arranging
the directory structure, as well as rewriting the contents of files as
necessary (e.g., rewriting the contents of <code>composer.json</code>, or filling in the
name of the component in the <code>CONTRIBUTING.md</code>). The <code>msg-filter</code> looks for
issue and pull request identifiers (a <code>#</code> character followed by one or more
digits), and rewrites them to reference the repository. The <code>commit-filter</code>
checks to see if the repository contents have changed in this commit, and, if
not, instructs <code>git</code> to ignore the commit (and, since <code>tree-filter</code> always
executes before <code>commit-filter</code>, the comparison is always between rewritten
trees). The <code>tag-name-filter</code> <strong>MUST</strong> be present, and essentially just ensures
that the tag is rewritten; if absent, tags are not rewritten, and refer to the
original contents!</p>
<h3>Stumbling blocks</h3>
<p>We had a few stumbling blocks getting the above to work. The first was that,
for purposes of testing, we had to specify a <em>commit range</em>, instead of <code>-- --all</code>.
This was necessary because of the size of the repo; at ~27k commits, running
over every single commit can take between 5 and 12 hours, depending on git
version, HDD vs ramdisk, speed of I/O, etc. For small subsets, we could get
consistent results. When we expanded the range, we started seeing strange
errors, such as some tags not getting written.</p>
<p>To compound the situation, we also made a last minute change to only do history
from the 2.0.0rc7 tag forward, and this is when things completely fell apart. A
large number of tags would not get rewritten, the set of malformed tags varied
between components, and we couldn't figure out why.</p>
<p>At a certain point, I recalled that <code>git</code> stores commits as a tree, and that's
when I realized what was happening: when we specified a commit range, we were
essentially specifying a specific path through the commits. If a tag was made
on a branch falling outside that path, it would not get rewritten.</p>
<p>This meant that the only way to get consistent results that met our criteria
was to run a test over the full history. Fortunately, sometime around that
point, a community member, <a href="http://www.renatomefi.com.br/">Renato</a>, suggested I
try a run using a <a href="http://en.wikipedia.org/wiki/Tmpfs">tmpfs filesystem</a> —
essentially a ramdisk. This sped up runs by a factor of 2, and I was able to
validate my hypothesis within an evening.</p>
<p>Another stumbling block was empty commits. We originally used <code>filter-branch</code>'s
<code>--prune-empty</code> switch, but found it was generally unreliable when used with
<code>tree-filter</code>. The solution to this problem is the <code>commit-filter</code> as listed
above; it did a stellar job.</p>
<h3>Empty merge commits</h3>
<p>There was one lingering issue, however: when inspecting the filtered
repository, we still had a large number of empty merge commits that had nothing
to do with the component. After a lot of searching, I found this gem:</p>
<pre><code class="language-bash hljs bash" data-lang="bash">$ git filter-branch -f \
&gt; --commit-filter <span class="hljs-string">'
&gt;    if [ z$1 = z`git rev-parse $3^{tree}` ];then
&gt;        skip_commit "$@";
&gt;    else
&gt;        git commit-tree "$@";
&gt; fi'</span> \
&gt; --tag-name-filter cat -- --all
$ git reflog expire --expire=now --all
$ git gc --prune=now --aggressive
</code></pre>
<p>The above uses a <code>commit-filter</code> which internally uses <code>rev-parse</code> to determine
if the commit is a merge and that both parents are present in the repository;
if not, it skips (removes) the commit. The <code>reflog expire</code> and <code>gc</code> commands
clean up and remove any objects in the repository that are now no longer
reachable.</p>
<h2>Final Solution</h2>
<p>With a working <code>graft</code>, <code>tree-filter</code>, and <code>commit-filter</code> in place, we could
finally proceed. We created a repository containing all scripts we needed, as
well as the assets necessary for rewriting the component repository trees. We
then had a tool that could be executed as simply as:</p>
<pre><code class="language-bash hljs bash" data-lang="bash">$ ./bin/split.sh -c Authentication 2&gt;&amp;1 | tee authentication.log
</code></pre>
<p>And with that, we could sit back and watch the component get split, and push
the results when done.</p>
<p>You can see the work in our
<a href="https://github.com/zendframework/component-split">component-split</a> repository.</p>
<h2>But what about the speed?</h2>
<p>&quot;But didn't you say it takes between 5 and 12 hours to run per component? And
aren't there something like 50 components? That would take weeks!&quot;</p>
<p>You're quite astute! And for that, we had a secret weapon: a community
contributor, <a href="https://github.com/gianarb">Gianluca Arbezzano</a> working for an
AWS partner, <a href="http://www.corley.it">Corley</a>, which sponsored splitting all
components in parallel at once, allowing us to complete the entire effort in a
single day. I'll let others tell that story, though!</p>
<h2>The results</h2>
<p>I'm quite pleased with the results. The ZF2 repository has ~27k commits, 67
releases, and over 700 contributors; a clean checkout is around 150MB. As a
contrast, the rewritten <code>zend-http</code> component repository ended up with ~1.7k
commits, 50 releases, ~160 contributors, and a clean checkout clocks in at
5.4MB! So the individual components are substantially leaner! Additionally,
they contain all the QA tooling necessary to start developing against for those
wanting to patch issues or create features, making development a simpler
process.</p>
<p>The lessons learned:</p>
<ul>
<li><code>tree-filter</code> is your friend, if your restructuring involves more than one
directory and/or adding or removing files.</li>
<li><code>tag-name-filter</code> <strong>MUST</strong> be used anytime you use <code>filter-branch</code>; otherwise
your tags may end up invalid!</li>
<li><code>filter-branch</code> should be used on ranges <em>sparingly</em>, and ideally only if
you're not worried about tags. In most cases, you want to run over the entire
history.</li>
<li><code>commit-filter</code> is your best option for ensuring empty commits of any type
are stripped, particularly if you're using <code>tree-filter</code>; the <code>--prune-empty</code>
flag is not terribly reliable.</li>
<li>Always do a full test run. It's tempting to use a commit range to verify that
your filters work, but the results will differ from running over the entire
history. Which leads to:</li>
<li>Schedule plenty of time, particularly if your repository is large. Those full
test runs will take time, and, if you follow the scientific process and make
one change at a time, you may need quite a few iterations to get your scripts
right.</li>
</ul>
<p>All-in-all, this was a stressful, time-consuming, thankless task. But I <em>am</em>
quite happy with the results; our components look like they are and were always
developed as first-class components, and have a rich history referencing their
original development as part of the encompassing framework.</p>
<h2>Kudos!</h2>
<p>I cannot thank Gianluca and Corley enough for their generous efforts! What
looked like a task that would take days and/or weeks happened literally
overnight, allowing us to complete a major task in Zend Framework 3
development, and setting the stage for a ton of new features. Grazie!</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2015-05-15-splitting-components-with-git.html">Splitting the ZF2 Components</a> was originally
    published <time class="dt-published" datetime="2015-05-15T19:30:00-05:00">15 May 2015</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Automatic deployment with git and gitolite</title>
      <pubDate>Sun, 24 Jun 2012 21:50:00 -0500</pubDate>
      <link>https://mwop.net/blog/2012-06-24-git-deploy.html</link>
      <guid>https://mwop.net/blog/2012-06-24-git-deploy.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I read a <a href="http://seancoates.com/blogs/deploy-on-push-from-github">post recently by Sean Coates about deploy on push</a>.
The concept is nothing new: you set up a hook that listens for commits on
specific branches or tags, and it then deploys your site from that revision.</p>
<p>Except I'd not done it myself. This is how I got there.</p>


<p>Sean's approach uses <a href="https://help.github.com/articles/post-receive-hooks">Github webhooks</a>,
which are a fantastic concept. Basically, once your commit completes, Github
will send a JSON-encoded payload to a specific URI. Sean uses this to trigger
an API call to a specific page in his website, which will then trigger a
deployment activity.</p>
<p>Awesome, this should be easy; I already have a deploy script written that I
trigger manually.</p>
<p>One small problem: my site, while in Git, is not on Github. I maintain it on my
own <a href="https://github.com/sitaramc/gitolite">Gitolite</a> repository. Which means I
needed to write my own hooks.</p>
<p>I originally went down the route of using a post-receive hook. However, I had
problems determining what branch the given commit was on, despite a variety of
advice I found on the subject on <a href="http://stackoverflow.com/">StackOverflow</a> and
git mailing lists. I ended up finding a great example using <code>post-update</code>, which
was actually perfect for my needs.</p>
<p>In order to keep the <code>post-update</code> script non-blocking when I commit, I made it
do very little: It simply determines what branch the commit was on, and if it
was the master branch, it touches a specific file on the filesystem and
finishes. The entire hook looks like this:</p>
<pre><code class="language-bash hljs bash" data-lang="bash"><span class="hljs-meta">#!/bin/bash</span>
branch=$(git rev-parse --symbolic --abbrev-ref <span class="hljs-variable">$1</span>)
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Commit was for branch <span class="hljs-variable">$branch</span>"</span>
<span class="hljs-keyword">if</span> [[ <span class="hljs-string">"<span class="hljs-variable">$branch</span>"</span> == <span class="hljs-string">"master"</span> ]];<span class="hljs-keyword">then</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Preparing to deploy"</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"1"</span> &gt; /var/<span class="hljs-built_in">local</span>/mwop.net.update
<span class="hljs-keyword">fi</span>
</code></pre>
<p>Now I needed something to detect such a push, and act on it.</p>
<p>I considered using cron for this; it'd be relatively easy to have it fire up
once a minute, and simply act on it. But I decided instead to write a simple
little daemon using perl. Perl daemons are trivially easy to write, and if you
use module such as <code>Proc::Daemon</code> and follow a few trivial defensive coding
practices, you can keep memory leaks contained (or at least minimal). Besides,
it gave me a chance to dust off my perl chops.</p>
<p>I decided I'd have it check for the file in 30 second intervals, simply
sleeping if no changes were detected. If the file was found, however, it should
attempt to deploy. Additionally, I wanted it to quit if it was unable to remove
the file (as this could lead to multiple deploy attempts), and log success and
failure status of the deploy. The full script looks like this:</p>
<pre><code class="language-perl hljs perl" data-lang="perl"><span class="hljs-comment">#!/usr/bin/perl</span>
<span class="hljs-keyword">use</span> strict;
<span class="hljs-keyword">use</span> warnings;
<span class="hljs-keyword">use</span> Proc::Daemon;

Proc::Daemon::Init;

<span class="hljs-keyword">my</span> $continue = <span class="hljs-number">1</span>;
$SIG<span class="hljs-string">{TERM}</span> = <span class="hljs-function"><span class="hljs-keyword">sub</span> </span>{ $continue = <span class="hljs-number">0</span> };

<span class="hljs-keyword">my</span> $updateFile   = <span class="hljs-string">"/var/local/mwop.net.update"</span>;
<span class="hljs-keyword">my</span> $updateScript = <span class="hljs-string">"/home/matthew/bin/deploy-mwop"</span>;
<span class="hljs-keyword">my</span> $logFile      = <span class="hljs-string">"/var/local/mwop.net-deploy.log"</span>;
<span class="hljs-keyword">while</span> ($continue) {
    <span class="hljs-comment"># 30s intervals between iterations</span>
    <span class="hljs-keyword">sleep</span> <span class="hljs-number">30</span>;

    <span class="hljs-comment"># Check for update file, and restart loop if not found</span>
    <span class="hljs-keyword">unless</span> (-e $updateFile) {
        <span class="hljs-keyword">next</span>;
    }

    <span class="hljs-comment"># Remove update file</span>
    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">unlink</span>($updateFile)) {
        <span class="hljs-comment"># If unable to unlink, we need to quit</span>
        <span class="hljs-keyword">system</span>(<span class="hljs-string">'echo "'</span> . <span class="hljs-keyword">time</span>() . <span class="hljs-string">': Failed to REMOVE '</span> . $updateFile . <span class="hljs-string">'" &gt;&gt; '</span> . $logFile);
        $continue = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">next</span>;
    }

    <span class="hljs-comment"># Deploy</span>
    <span class="hljs-keyword">system</span>($updateScript);
    <span class="hljs-keyword">if</span> ( $? == -<span class="hljs-number">1</span> ) {
        <span class="hljs-keyword">system</span>(<span class="hljs-string">'echo "'</span> . <span class="hljs-keyword">time</span>() . <span class="hljs-string">': FAILED to deploy: '</span> . $! . <span class="hljs-string">'" &gt;&gt; '</span> .  $logFile);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">system</span>(<span class="hljs-string">'echo "'</span> . <span class="hljs-keyword">time</span>() . <span class="hljs-string">': Successfully DEPLOYED" &gt;&gt; '</span> . $logFile);
    }
}
</code></pre>
<p>The <code>system()</code> calls for logging could have been done using Perl, but I didn't
want to deal with additional error handling and file pointers; simply proxying
to the system seemed reasonable and expedient.</p>
<p>When all was ready, I started the above listener, which automatically
daemonizes itself. I then installed the <code>post-update</code> hook into my bare
repository, and tested it out. And it runs! When I push to master, my site is
automatically deployed, typically within 15-20 seconds from completion.</p>
<h4>Caveats</h4>
<p>This solution, of course, relies on a daemonized process. If that process were
to terminate, I'd have no idea until I discovered my site didn't refresh after
the most recent push. Clearly, some sort of monitor checking for the status of
the daemon should be in place.</p>
<p>Also, note that I'm having this update on changes to the master branch; you may
need to adapt it for your own needs, depending on your branching strategy.</p>
<p>Finally, this approach does not address issues that might require a roll-back.
Ideally, the script should probably log what revision was current prior to the
deployment, allowing roll-back to the previous state. Alternately, the
deployment script should create a new clone of the site and swap symlinks to
allow quick roll-back when required.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2012-06-24-git-deploy.html">Automatic deployment with git and gitolite</a> was originally
    published <time class="dt-published" datetime="2012-06-24T21:50:00-05:00">24 June 2012</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>git-svn Tip: don't use core.autocrlf</title>
      <pubDate>Wed, 24 Sep 2008 12:16:27 -0500</pubDate>
      <link>https://mwop.net/blog/191-git-svn-Tip-dont-use-core.autocrlf.html</link>
      <guid>https://mwop.net/blog/191-git-svn-Tip-dont-use-core.autocrlf.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I've been playing around with <a href="http://git.or.cz/">Git</a> in the past couple
months, and have been really enjoying it. Paired with subversion, I get the
best of all worlds — distributed source control when I want it (working on new
features or trying out performance tuning), and non-distributed source control
for my public commits.</p>
<p><a href="http://github.com/guides/dealing-with-newlines-in-git">Github</a> suggests that
when working with remote repositories, you turn on the <code>autocrlf</code> option, which
ensures that changes in line endings do not get accounted for when pushing to
and pulling from the remote repo. However, when working with <code>git-svn</code>, this
actually causes issues. After turning this option on, I started getting the
error &quot;Delta source ended unexpectedly&quot; from <code>git-svn</code>. After a bunch of aimless
tinkering, I finally asked myself the questions, &quot;When did this start
happening?&quot; and, &quot;Have I changed anything with Git lately?&quot; Once I'd backed out
the config change, all started working again.</p>
<p>In summary: don't use <code>git config --global core.autocrlf true</code> when using <code>git-svn</code>.</p>




<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/191-git-svn-Tip-dont-use-core.autocrlf.html">git-svn Tip: don&#039;t use core.autocrlf</a> was originally
    published <time class="dt-published" datetime="2008-09-24T12:16:27-05:00">24 September 2008</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
  </channel>
</rss>
