<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Git on weblog.masukomi.org</title>
    <link>https://weblog.masukomi.org/tags/git/</link>
    <description>Recent content in Git on weblog.masukomi.org</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <copyright>&amp;copy Kay Rhodes (masukomi.org) 2022</copyright>
    <lastBuildDate>Mon, 19 Jun 2023 00:00:00 -0400</lastBuildDate><atom:link href="https://weblog.masukomi.org/tags/git/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Github Rubocop Workflow</title>
      <link>https://weblog.masukomi.org/2023/06/19/github-rubocop-workflow/</link>
      <pubDate>Mon, 19 Jun 2023 00:00:00 -0400</pubDate>
      
      <guid>https://weblog.masukomi.org/2023/06/19/github-rubocop-workflow/</guid>
      <description>&lt;p&gt;It took me a while to figure out the correct collection of magical incantations
required to make RuboCop run in a GitHub workflow, but ONLY on the files that
were changed within the PR. This is a useful configuration if you have a
codebase that has not yet been modified to satisfy all your &amp;ldquo;Cops&amp;rdquo;.  I&amp;rsquo;ve also
included a version of the same file that you can use when you&amp;rsquo;re ready to have
RuboCop run on all non-excluded files.&lt;/p&gt;
&lt;p&gt;The result is that rubocop will only block your PR &lt;em&gt;if&lt;/em&gt; some of the files touched
in the PR don&amp;rsquo;t conform to your new standards. Once your codebase is&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;on: [pull_request]&lt;/code&gt; means that it will run when you make the pull request
&lt;em&gt;and&lt;/em&gt; any time you push to it (with or without force).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# A GitHub workflow to run rubocop, but ONLY on changed files&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# honors any exclusions specified in your .rubocop.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# store this file in .github/workflows/rubocop.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# note: the Checkout Branches step is required&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# because by default what&amp;#39;s checked out is the branch&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that represents the future merging of the PRs branch&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# with the target branch.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;RuboCop&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;pull_request]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;jobs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;rubocop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;runs-on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ubuntu-22.04&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;steps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;uses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;actions/checkout@v2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;uses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ruby/setup-ruby@v1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ruby-version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;.ruby-version&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;bundler-cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Install gems&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;          bundle config path vendor/bundle
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;          bundle config set without &amp;#39;test tools functional&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;          bundle install --jobs 4 --retry 3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Checkout Branches&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;          git fetch origin ${{ github.head_ref }}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;          git fetch origin ${{ github.base_ref }}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Run RuboCop&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;bundle exec rubocop --parallel --force-exclusion $( git diff --name-only --ignore-submodules=all --diff-filter=ACMR origin/${{ github.base_ref }}..origin/${{ github.head_ref }} )&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once your codebase has finally been cleaned up to a point that RuboCop is happy with it you can change it to the following. This is strongly recommend because it will catch when code made it through to the target branch without getting checked (merged directly, or a PR that was merged despite failing checks). The time difference is &lt;em&gt;not&lt;/em&gt; noteworthy. Spinning up the container and checking out the gems takes &lt;em&gt;much&lt;/em&gt; longer than the actual RuboCop run.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# store this file in .github/workflows/rubocop.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# this will run rubocop on ALL the files in your repo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# that have not been excluded in your main .rubocop.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# rubocop configuration file.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;RuboCop&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;pull_request]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;jobs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;rubocop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;runs-on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ubuntu-22.04&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;steps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;uses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;actions/checkout@v2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;uses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ruby/setup-ruby@v1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ruby-version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;.ruby-version&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;bundler-cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Install gems&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;          bundle config path vendor/bundle
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;          bundle config set without &amp;#39;test tools functional&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;          bundle install --jobs 4 --retry 3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Run RuboCop&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;bundle exec rubocop --parallel --force-exclusion&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>Mirroring With Gitea</title>
      <link>https://weblog.masukomi.org/2022/09/26/mirroring-with-gitea/</link>
      <pubDate>Mon, 26 Sep 2022 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2022/09/26/mirroring-with-gitea/</guid>
      <description>&lt;div class=&#34;ox-hugo-toc toc&#34;&gt;
&lt;div class=&#34;heading&#34;&gt;Table of Contents&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#overview&#34;&gt;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-goal&#34;&gt;The Goal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-process&#34;&gt;The Process&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-learnings&#34;&gt;The Learnings&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;!--endtoc--&gt;
&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;Following on the heels of my &lt;a href=&#34;https://weblog.masukomi.org/2022/09/24/do-and-dont-self-host-your-repos/&#34;&gt;last post on why you should (not) self host your
git repos&lt;/a&gt;, I went ahead and used &lt;a href=&#34;https://gitea.io&#34;&gt;Gitea&lt;/a&gt; to set up a local mirror of all my
repositories, and all the repositories I don&amp;rsquo;t want to loose access to.&lt;/p&gt;
&lt;p&gt;The results were surprising, and after reading this, you might want to do the
same. This post will be a qick overview of how I did it, some tips that&amp;rsquo;ll help,
and what I learned as a result.&lt;/p&gt;
&lt;p&gt;Installation was pretty straightforward. I grabbed my old Raspberry Pi 3B and
followed &lt;a href=&#34;https://pimylifeup.com/raspberry-pi-gitea/&#34;&gt;this spectacualar step-by-step guide for installation for installing
Gitea.&lt;/a&gt; Afterwards a friend pointed out that I could have just installed
installed it on our Synology with a Docker image.&lt;/p&gt;
&lt;h2 id=&#34;the-goal&#34;&gt;The Goal&lt;/h2&gt;
&lt;p&gt;My goal was two-fold:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I wanted a backup of all my repos. Many of them &lt;em&gt;only&lt;/em&gt; existed in GitHub.&lt;/li&gt;
&lt;li&gt;I wanted to delete every fork I&amp;rsquo;d made &lt;em&gt;just&lt;/em&gt; to guarantee I had a copy.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;the-process&#34;&gt;The Process&lt;/h2&gt;
&lt;p&gt;With that in mind I started working through my list of repositories&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. Gitea
makes it trivial to mirror a repo. You just choose &amp;ldquo;new migration&amp;rdquo; from under
the &amp;ldquo;+&amp;rdquo; menu, and then click on the service you&amp;rsquo;re migrating from. There are 3
things that can make your life easier here if you&amp;rsquo;re importing lots&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Bookmark the form that comes up after choosing a service to migrate from.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re going to be importing a lot you&amp;rsquo;ll probably want to use a &lt;a href=&#34;https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token&#34;&gt;personal
access token (GitHub docs)&lt;/a&gt;. That way you won&amp;rsquo;t get rate limited by the API,
unless you&amp;rsquo;re migrating (not mirroring) something with many thousands of
issues.&lt;/li&gt;
&lt;li&gt;Use a clipboard manager. It doesn&amp;rsquo;t remember your API key so you&amp;rsquo;ll be
pasting it into every form, along with the URL of the repo you&amp;rsquo;re importing.
I use &lt;a href=&#34;https://maccy.app/&#34;&gt;Maccy&lt;/a&gt;, and I would recommend it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For each repo in my list of repos on github, I&amp;rsquo;d make a couple quick decisions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;for things I authored
&lt;ul&gt;
&lt;li&gt;If it was something I am either maintaining or may poke in the future I&amp;rsquo;d
just grab the url and tell Gitea to mirror it.&lt;/li&gt;
&lt;li&gt;If it was something I wandered off from years ago, and am unlikely to ever
touch again, I&amp;rsquo;d mark it as archived.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;for the backups of other people&amp;rsquo;s things
&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;d click through and see if i&amp;rsquo;d added anything, or if it was just an old
copy.
&lt;ul&gt;
&lt;li&gt;If I&amp;rsquo;d added something, and the original repo hadn&amp;rsquo;t been touched, I&amp;rsquo;d
mirror my fork.&lt;/li&gt;
&lt;li&gt;If I&amp;rsquo;d added something, but the original had moved forwards some
significant amount I just abandoned my changes, and mirrored theirs.&lt;/li&gt;
&lt;li&gt;If mine was just an ancient copy of a repo that&amp;rsquo;d moved on, I&amp;rsquo;d go to the
parent repo.
&lt;ul&gt;
&lt;li&gt;If the parent repo was archived I&amp;rsquo;d just tell Gitea to import it but not
bother mirroring. There aren&amp;rsquo;t going to be updates.&lt;/li&gt;
&lt;li&gt;If the parent repo indicated that &lt;em&gt;it too&lt;/em&gt; was a mirror, I&amp;rsquo;d follow that
back to the source repo and mirror &lt;em&gt;that&lt;/em&gt; instead.&lt;/li&gt;
&lt;li&gt;After successfully mirroring I&amp;rsquo;d delete my copy.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;the-learnings&#34;&gt;The Learnings&lt;/h2&gt;
&lt;p&gt;(In no particular order)&lt;/p&gt;
&lt;p&gt;First off, &lt;a href=&#34;https://gitea.io&#34;&gt;Gitea&lt;/a&gt; is really impressive. Those devs have done a great job and
should be proud of what they&amp;rsquo;ve built.&lt;/p&gt;
&lt;p&gt;Along the way, I discovered that many of the repos that I&amp;rsquo;d forked had moved on
significantly. I had copies that were so old they probably wouldn&amp;rsquo;t run with
modern versions of things. They were also frequently missing lots of new
features and bug fixes.&lt;/p&gt;
&lt;p&gt;While this isn&amp;rsquo;t terribly surprising if you think about it, the notable learning
is that that&amp;rsquo;s never going to be a problem again, because Gitea is &lt;em&gt;mirroring&lt;/em&gt;
them and regularly polling them for updates. If they disappear I&amp;rsquo;ll have the
latest copy before they went away. Github doesn&amp;rsquo;t give me that option.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not the only one forking repos just to have a copy. Multiple times I clicked
through to the parent repo, and got curious. I&amp;rsquo;d see hundreds of forks, click
into the insights page and see that essentially no-one was hacking on it except
for the original authors. I guess lots of folks have gotten burned when they
discovered that some repo they&amp;rsquo;d starred or bookmarked was gone when they went
to check it out again.&lt;/p&gt;
&lt;p&gt;Mirroring isn&amp;rsquo;t something you can turn on later in Gitea. You &lt;em&gt;must&lt;/em&gt; set a repo up
as a mirror from the beginning.&lt;/p&gt;
&lt;p&gt;Gitea can&amp;rsquo;t mirror &lt;em&gt;everything&lt;/em&gt;. Some repos (like &lt;a href=&#34;https://github.com/oz/tz&#34;&gt;this great command line time
zone tool&lt;/a&gt;) always error out. Gitea provides no information as to &lt;em&gt;why&lt;/em&gt; it failed
to clone them down too. I think I encountered three repos like that. Also, I
can&amp;rsquo;t figure out how to clone anything from &lt;a href=&#34;https://sourcehut.org/&#34;&gt;Sourcehut&lt;/a&gt;&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;. Even when I tried
to clone repos manually their http links for cloning always error.&lt;/p&gt;
&lt;p&gt;I realized that if i don&amp;rsquo;t &lt;em&gt;just&lt;/em&gt; mirror the tools that I author, and want backups
of, but &lt;em&gt;also&lt;/em&gt; mirror the repos of tools that I need to reference the source code
of regularly then I have a single place I can search for &lt;em&gt;only&lt;/em&gt; stuff that&amp;rsquo;s
relevant to me. For example, it&amp;rsquo;s not uncommon for me to know that &lt;em&gt;one&lt;/em&gt; of the
libraries I use frequently has a piece of functionality, but not remember &lt;em&gt;which&lt;/em&gt;
library. Searching Google or Github would be frustrating, because there are just
too many responses. But now, I can just search my Gitea install.&lt;/p&gt;
&lt;p&gt;The experience of doing this was very cathartic for me. I now know that I have
&lt;em&gt;up-to-date&lt;/em&gt; copies of all the useful tools I care about. I was also able to
delete about 100 repositories from &lt;a href=&#34;https://github.com/masukomi?tab=repositories&#34;&gt;my list of repositories on Github.&lt;/a&gt; Now, if a
future employer checks them out, they&amp;rsquo;re almost &lt;em&gt;all&lt;/em&gt; things I have actively
worked on to some degree. It&amp;rsquo;s also nice to know that from now on I have a
trivially easy way to mirror any useful tool I care about. No more ancient
frozen it time forks, and no more bookmarks &amp;amp; stars that cease to exist.&lt;/p&gt;
&lt;p&gt;My next step? Going through all the repos I&amp;rsquo;ve bookmarked, but not forked, and
see which of those are worth mirroring.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Before working through your list of repositories, be sure to sort them by
name. Mine were sorted by recency and that made things a little harder towards
the end.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;For a sense of scale I ended up mirroring or migrating 169 repos into
Gitea.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;In addition to having a visual style from the 1990&amp;rsquo;s, and having UX from
hell, Sourcehut appears to also just not &lt;em&gt;fucking&lt;/em&gt; work as a git host. I don&amp;rsquo;t
understand why anyone uses them, nevermind why anyone pays for them.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Do (not) Self-Host your repos</title>
      <link>https://weblog.masukomi.org/2022/09/24/do-and-dont-self-host-your-repos/</link>
      <pubDate>Sat, 24 Sep 2022 00:00:00 -0500</pubDate>
      
      <guid>https://weblog.masukomi.org/2022/09/24/do-and-dont-self-host-your-repos/</guid>
      <description>&lt;h1 id=&#34;table-of-contents&#34;&gt;Table of Contents&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;#org5fd34c4&#34;&gt;Why You &lt;em&gt;Should&lt;/em&gt; Self-Host&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;➠&lt;a href=&#34;#org647e5e9&#34;&gt;What about GitLab and other Competitors?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#org379a435&#34;&gt;Why You Shouldn&amp;rsquo;t Self-Host&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#orge80cd4c&#34;&gt;So what&amp;rsquo;s a geek to do?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#orge2c2733&#34;&gt;What am &lt;em&gt;I&lt;/em&gt; going to do?&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once upon a time, GitHub was a successful geek enterprise. Then Microsoft bought it, and folks started arguing that you should abandon ship. You should self-host your repos they say.&lt;/p&gt;
&lt;p&gt;I 100% agree, and 100% disagree. Let me explain.&lt;/p&gt;
&lt;p&gt;GitHub&amp;rsquo;s been a benevolent host. When &lt;a href=&#34;https://github.blog/2020-03-16-npm-is-joining-github/&#34;&gt;they bought NPM&lt;/a&gt; they went from being a de facto piece of internet infrastructure to an &lt;em&gt;actual&lt;/em&gt; piece of &lt;em&gt;critical&lt;/em&gt; infrastructure.  At this point you may as well argue that we should sever our connection to the electric company.&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s a difference between &lt;em&gt;needing&lt;/em&gt; the electric company and ignoring the fact that sometimes the power goes. Usually it&amp;rsquo;s temporary. Days isn&amp;rsquo;t uncommon in wintery climes. But every now and then, it&amp;rsquo;s more. In the case of internet SAAS apps, it&amp;rsquo;s sometimes permanent.&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;org5fd34c4&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;why-you-should-self-host&#34;&gt;Why You &lt;em&gt;Should&lt;/em&gt; Self-Host&lt;/h1&gt;
&lt;p&gt;The biggest argument, of course, is backups and continuity of service. If something hapened and you lost access to your GitHub account right now, what would you loose? If you maintain a project with many users and contributors, what would it do to your community, and your work?&lt;/p&gt;
&lt;p&gt;GitHub isn&amp;rsquo;t &lt;em&gt;just&lt;/em&gt; where your Git repos are hosted, but where all the metadata that surrounds them. This means years of Issues, Pull Requests, wiki pages, and frequently the project&amp;rsquo;s web site.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve derived a ton of value from old tickets on GitHub projects. They regularly answer questions, and provid workarounds. The takedown off a popular repo could be a huge loss.&lt;/p&gt;
&lt;p&gt;GitHub suspends accounts, and deletes repositories for  a variety of reasons.  If yours targeted for seemingly &amp;ldquo;no reason&amp;rdquo; it wouldn&amp;rsquo;t be the first.&lt;/p&gt;
&lt;p&gt;Even if you believe it won&amp;rsquo;t, or can&amp;rsquo;t, happen to you, there&amp;rsquo;s another reason reason to consider self-hosting: Lock in. Right &lt;em&gt;now&lt;/em&gt; (September 2022) GitHub is very good about letting you export everything. As far as I know, there&amp;rsquo;s no data you can put into GitHub that you can&amp;rsquo;t also get out via their APIs. In theory.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Our migration has been in the process for a while, but every time we run it we find that our attempts were missing some data, so we need to re-run to fetch missing data, if we had higher limits it wouldn&amp;rsquo;t take so long to find these issues. Github doesn&amp;rsquo;t provide tokens with higher limits, so we have to work around that. We even had people with [GitHub Enterprise] subscriptions ask, and they got the same response.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://social.gitea.io/@gitea/108833229447552270&#34;&gt;Gitea on Mastodon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://gitea.io/&#34;&gt;Gitea&lt;/a&gt; is an open source GitHub alternative, whose creation started out &lt;em&gt;on&lt;/em&gt; GitHub. Eventually, the software got really robust, and they decided to host their own repo and issues. The problem is, they&amp;rsquo;ve got over 20,000 Issues &amp;amp; PRs they want to export. Thousands of those are still open, and the longer it takes them to cut over, the larger those numbers get.&lt;/p&gt;
&lt;p&gt;To be fair, 99% of GitHub users wouldn&amp;rsquo;t have this problem. We don&amp;rsquo;t have projects that are popular enough, but companies who use GitHub do, and there&amp;rsquo;s no advantage to GitHub to help large projects or customers leave. They may even consider locking that metadata down to guarantee they stay.&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;org647e5e9&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;what-about-gitlab-and-other-competitors&#34;&gt;What about GitLab and other Competitors?&lt;/h2&gt;
&lt;p&gt;You can apply the same reasoning to GitHub&amp;rsquo;s hosted alternatives. Plus, none of them are as financially successful as GitHub.  They&amp;rsquo;re far more likely to go out of business, and screw everyone who uses them.&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;org379a435&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;why-you-shouldnt-self-host&#34;&gt;Why You Shouldn&amp;rsquo;t Self-Host&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Right now&lt;/em&gt; it&amp;rsquo;s incredibly improbable that you&amp;rsquo;ll have your account suspended. The stories of suspended accounts are rare. &lt;em&gt;Most&lt;/em&gt; of them seem to be from government action,or &amp;ldquo;Terms of Service&amp;rdquo; violations that most geeks react to with &amp;ldquo;Yup. Seems fair.&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also the fact that self-hosting is work. But let&amp;rsquo;s set that aside for the moment. Let&amp;rsquo;s pretend there&amp;rsquo;s some magical free button you can click that takes care of everything. &lt;strong&gt;Boop&lt;/strong&gt;. You&amp;rsquo;re self-hosted now.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s also assume you&amp;rsquo;ve got a project that&amp;rsquo;s popular / useful enough to get Issues and the occasional Pull Request.&lt;/p&gt;
&lt;p&gt;How is that going to happen on your new site?  Well, first they&amp;rsquo;re going to need to set up an account on your server. Are they going to think it&amp;rsquo;s worth it? Worth it enough to give their email to yet another stranger? If they want to submit a fix / feature, is it also worth it to figure out how to fork it in this not-GitHub? Worth it to figure out how its PR equivalents work? These probably aren&amp;rsquo;t hard, but every little difference they have to navigate is another reason to not bother.&lt;/p&gt;
&lt;p&gt;And then there&amp;rsquo;s discovery. GitHub isn&amp;rsquo;t &lt;em&gt;only&lt;/em&gt; the default place to look for code. They&amp;rsquo;ve also got massive &amp;ldquo;website authority&amp;rdquo; in Google. It doesn&amp;rsquo;t matter if you&amp;rsquo;re the only place hosting your thing. Any project on GitHub that&amp;rsquo;s remotely similar to your search terms is likely to come up before your site.&lt;/p&gt;
&lt;p&gt;But, even if you&amp;rsquo;re ok with all of that. There&amp;rsquo;s an even bigger reason you shouldn&amp;rsquo;t self host. A reason we &lt;em&gt;shouldn&amp;rsquo;t&lt;/em&gt; encourage folks to self host. Sooner or later you&amp;rsquo;ll get sick of bothering, or you&amp;rsquo;ll die. One is guaranteed. The other has lots of historical precedence.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve bookmarked thousands of useful web sites over the years. A huge chunk of those have been useful, and insightful blog posts about development. Hundreds of them don&amp;rsquo;t exist anymore. Mostly because the person who ran them simply didn&amp;rsquo;t feel like bothering with it anymore. How many millions of others have poofed out of existence?&lt;/p&gt;
&lt;p&gt;But, a repo isn&amp;rsquo;t some just random thoughts. Almost every repo contains some useful tool or library. Sooner or later, someone&amp;rsquo;s going to need tha. There are thousands, probably millions, of little repos out there containing the only bit of code in existence, that solves that particular problem. Sometimes they&amp;rsquo;re just the only thing that solves it in that particular language. When you stop hosting it, for whatever reason, that useful tool ceases to exist. Even if it&amp;rsquo;s &amp;ldquo;just a port&amp;rdquo;. That&amp;rsquo;s a lot of work that someone will need to recreate, and debug.&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;orge80cd4c&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;so-whats-a-geek-to-do&#34;&gt;So what&amp;rsquo;s a geek to do?&lt;/h1&gt;
&lt;p&gt;Before I answer that, let me note that this bit gets into implementation strategies. If you just came for the question of &amp;ldquo;should I, or shouldn&amp;rsquo;t I?&amp;rdquo; you can stop reading. Thanks for making it this far. Good luck whatever you choose.&lt;/p&gt;
&lt;p&gt;–&lt;/p&gt;
&lt;p&gt;So, what to do…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Short short version&lt;/strong&gt;:
&lt;em&gt;If lots of people rely on your project&lt;/em&gt;, then mirror your code to a large competitor and accept that you may loose access to your issues, PRs, etc. . Stick a note in your README so that folks know where to find your mirror &lt;em&gt;before&lt;/em&gt; lightning strikes.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re like most open source developers, you&amp;rsquo;ve got some repos that are mostly ignored by the world, and receive essentially no issues or PRs. No-one&amp;rsquo;s going to be stressed if your repo disappears for a week. So, Install Gitea on your computer. Tell it to mirror your repos and forget about it. Or, just clone the all locally and set up a cron job to regularly pull down changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Longer version&lt;/strong&gt;:
I think that depends a lot on what, if any, metadata exists in your GitHub repos. Most devs have small repos that are mostly just used by them.  If this sounds like you, then simply keeping an up-to-date copy of them on your home computer could be fine.&lt;/p&gt;
&lt;p&gt;Things are different if you maintain some repo that other people actually care about enough to make issues, or even contribute code to.&lt;/p&gt;
&lt;p&gt;In that case my &lt;em&gt;personal&lt;/em&gt; advice is to host your stuff on Github, but have it mirrored to a second system. Ideally you&amp;rsquo;d want all your issues, PRs, etc. mirrored to it. But as far as I know, that&amp;rsquo;s not actually something you can do. It&amp;rsquo;s easy to keep the &lt;em&gt;code&lt;/em&gt; synced to a mirror. It&amp;rsquo;s the metadata that&amp;rsquo;s a problem. To be clear, I&amp;rsquo;m not saying it&amp;rsquo;s not &lt;em&gt;technically&lt;/em&gt; possible. I&amp;rsquo;m saying, I don&amp;rsquo;t think anyone&amp;rsquo;s actually written the code to keep those synced between GitHub and any open source alternative. It&amp;rsquo;s a hard problem because Issues, PRs, comments, and just about everything else can be edited.&lt;/p&gt;
&lt;p&gt;So, that leaves you with regularly backing up your stuff. I&amp;rsquo;m going to assume you&amp;rsquo;re not someone with ~10k open &amp;amp; closed issues, plus another ~10k PRs like Gitea. So, &lt;em&gt;exporting&lt;/em&gt; your issues is probably something that&amp;rsquo;s actually doable. Exporting. &lt;em&gt;Not&lt;/em&gt; syncing. However, the more things you have to export, and the more frequently you want to back it up, the more likely you are to hit your rate limits.&lt;/p&gt;
&lt;p&gt;If you go this route, you&amp;rsquo;ve got two options. You could use something like &lt;a href=&#34;https://gitea.com/gitea/migrator/&#34;&gt;the gitea-github-migrator&lt;/a&gt; that can export everything. Tools like that are made to create a &lt;em&gt;new&lt;/em&gt; repo in GitHub alternatives, not &lt;em&gt;sync&lt;/em&gt; to them. You&amp;rsquo;d be constantly churning, deleting old repos and setting up new ones.&lt;/p&gt;
&lt;p&gt;A better solution might be something like &lt;a href=&#34;https://github.com/matomo-org/github-issues-mirror&#34;&gt;github-issues-mirror&lt;/a&gt; which can download all your issues as JSON files. Keep that running in the background and if worst comes to worst you can write an importer for wherever you&amp;rsquo;ve been mirroring your code.&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;orge2c2733&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;what-am-i-going-to-do&#34;&gt;What am &lt;em&gt;I&lt;/em&gt; going to do?&lt;/h1&gt;
&lt;p&gt;I think I&amp;rsquo;m going to install Gitea on my Raspberry Pi. I&amp;rsquo;ll tell it to mirror all my repos, and all the repos of useful tools I want to always have a copy of. I do maintain some repos which are somewhat useful to other people if GitHub deletes them. No-one will be screwed, and I can take my time in uploading a backup somewhere else. I&amp;rsquo;ll stick it in the basement with the router and back it up to our &lt;a href=&#34;https://en.wikipedia.org/wiki/Network-attached_storage&#34;&gt;NAS&lt;/a&gt;, which backs up to &lt;a href=&#34;https://www.backblaze.com/b2/cloud-storage.html&#34;&gt;B2&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Keeping a great Changelog</title>
      <link>https://weblog.masukomi.org/2016/07/03/keeping-a-great-changelog/</link>
      <pubDate>Sun, 03 Jul 2016 13:03:55 -0400</pubDate>
      
      <guid>https://weblog.masukomi.org/2016/07/03/keeping-a-great-changelog/</guid>
      <description>&lt;p&gt;Changelogs are an invaluable, and often neglected part of &lt;em&gt;any&lt;/em&gt; software
project. So, how do you do that?&lt;/p&gt;
&lt;p&gt;A good changelog helps you users to understand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why they should care about your latest version&lt;/li&gt;
&lt;li&gt;If any of your changes affect the problems or frustrations they&amp;rsquo;ve been
having.&lt;/li&gt;
&lt;li&gt;If there are any changes that might affect how they use your app / library.&lt;/li&gt;
&lt;li&gt;Why your efforts are worth their continued support.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A &lt;em&gt;great&lt;/em&gt; changelog does all that, &lt;em&gt;and&lt;/em&gt; shows the personality of your team.&lt;/p&gt;
&lt;p&gt;Shifty Jelly&amp;rsquo;s &lt;a href=&#34;http://www.shiftyjelly.com/pocketcasts/&#34;&gt;Pocket Casts&lt;/a&gt; is
notorious for their fun, and informative changelog entries:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Equal Opportunity variable speed playback. Why should MP3s have all the fun?
Welcome AAC &amp;amp; OGG!  * Bzzz. Bzzz. You can now choose which podcasts to be
notified of.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://slack.com/&#34;&gt;Slack&amp;rsquo;s&lt;/a&gt; been doing a pretty bang-up job too:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Fixed: The app now automatically scrolls down when you begin writing a file
comment, giving your precious fingertips much needed beauty rest.  * Fixed:
Time zones were sometimes shown with incorrect deltas. Now your coworker who
is 5 hours ahead of you will no longer simultaneously be 8 hours behind you.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;I can&amp;rsquo;t overstate how valuable it is to have a Changelog with personality. As
soon as you see that one of the apps you use has a great changelog you look out
for them, and always stay on top of what they&amp;rsquo;ve fixed and added. Then you start
spreading the word, because not only did they add good stuff, or fix that really
annoying bug, they made you smile along the way.&lt;/p&gt;
&lt;p&gt;A Changelog with personality helps build evangelism for the thing you&amp;rsquo;ve spent
so much time building.&lt;/p&gt;
&lt;h2 id=&#34;the-guts-of-a-good-changelog-entry&#34;&gt;The guts of a good Changelog Entry&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;It must speak in terms users understand. Most of them won&amp;rsquo;t be intimately
familiar with your source code. Don&amp;rsquo;t use internal jargon. If a bug is fixed,
speak in terms of the actions that caused it, or the behavior it exhibited,
but not the specific classes, unless you absolutely have to.&lt;/li&gt;
&lt;li&gt;It must be knowledge that&amp;rsquo;s useful to your users. Speak to the features and
flaws that affect your customers. Users don&amp;rsquo;t care that you refactored some
unit test, or reformatted your comments.&lt;/li&gt;
&lt;li&gt;It has to be at the right level of abstraction. Even if your writing an open
source library. The Slack timezone bug above was handled perfectly. They
could have mentioned which class &amp;amp; method had the bug, or the conceptual flaw
that caused the bug, but that&amp;rsquo;s all too fine grained for a Changelog.
Instead, they spoke at a higher level of abstraction.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;changes-need-to-be-grouped-by-type&#34;&gt;Changes need to be grouped by type&lt;/h2&gt;
&lt;p&gt;Group your bug fixes. Group your features. Group &amp;ldquo;all the things!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Imagine a user who&amp;rsquo;s been particularly frustrated by a bug in your app. They&amp;rsquo;re
going to open your changelog and immediately try and find out if you&amp;rsquo;ve fixed it
in this release. Help them. Don&amp;rsquo;t frustrate them further by making them hunt for
it in a jumble of features, fixes, and changes.&lt;/p&gt;
&lt;h2 id=&#34;dates-are-important&#34;&gt;Dates are important&lt;/h2&gt;
&lt;p&gt;Versioning your software is great, but dates are important too. When did version
6.0.0 come out? Did I have that problem before then or after?&lt;/p&gt;
&lt;p&gt;Additionally, not everyone in the world keeps dates in the same format.
06-08-16. Is that August 6th or June 8th? It depends on who&amp;rsquo;s reading it. Year
Month Day is the only one that makes any &lt;em&gt;logical&lt;/em&gt; sense no matter where you
are. XKCD even had a &lt;a href=&#34;http://xkcd.com/1179/&#34;&gt;Public Service Announcement about it&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;to-summarize&#34;&gt;To summarize&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Write at a high level of abstraction&lt;/li&gt;
&lt;li&gt;Speak to things that affect users, not developers.&lt;/li&gt;
&lt;li&gt;Group things so that people can find them easily.&lt;/li&gt;
&lt;li&gt;Add some personality.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;want-an-easy-tool-to-help-manage-this&#34;&gt;Want an easy tool to help manage this?&lt;/h2&gt;
&lt;p&gt;Check out
&lt;a href=&#34;https://github.com/masukomi/changelog_manager#readme&#34;&gt;changelog_manager&lt;/a&gt;. It&amp;rsquo;s
a free and open source tool to help you easily generate high quality Changelog
entries.&lt;/p&gt;
&lt;h2 id=&#34;related-posts&#34;&gt;Related Posts:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://weblog.masukomi.org/2016/06/30/why-you-cant-auto-generate-your-changelog/&#34;&gt;Why you can&amp;rsquo;t auto-generate your Changelog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Why you can&#39;t auto-generate your Changelog</title>
      <link>https://weblog.masukomi.org/2016/06/30/why-you-cant-auto-generate-your-changelog/</link>
      <pubDate>Thu, 30 Jun 2016 08:28:07 -0400</pubDate>
      
      <guid>https://weblog.masukomi.org/2016/06/30/why-you-cant-auto-generate-your-changelog/</guid>
      <description>&lt;p&gt;Let&amp;rsquo;s start by taking it as a given that a &lt;a href=&#34;http://keepachangelog.com&#34;&gt;Changelog&lt;/a&gt; file is something &lt;em&gt;very&lt;/em&gt; valuable that &lt;em&gt;every&lt;/em&gt; product should come with. Even if your &amp;ldquo;product&amp;rdquo; is a library for other developers.&lt;/p&gt;
&lt;p&gt;With that in mind, the question rises of &amp;ldquo;How can I make it really easy to generate one&amp;rdquo;. Many developers have had exactly that thought. There are many free and some paid solutions that will &amp;ldquo;Autogenerate your changelog from your git commits/tickets&amp;rdquo;.  The simple fact is, that no matter how well they&amp;rsquo;re written, you shouldn&amp;rsquo;t use any of them.&lt;/p&gt;
&lt;h2 id=&#34;a-good-changelog-entry-has&#34;&gt;A good Changelog entry has&amp;hellip;&lt;/h2&gt;
&lt;p&gt;A good Changelog entry has three primary aspects&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It&amp;rsquo;s at the right level of abstraction. Consumers of your product don&amp;rsquo;t care what files you tweaked or how. They care about the fixes and changes you&amp;rsquo;ve made that may impact them.&lt;/li&gt;
&lt;li&gt;It needs to be knowledge that&amp;rsquo;s useful to the consumer of your product. It&amp;rsquo;s a simple judgement call, but it&amp;rsquo;s one that has to be made.&lt;/li&gt;
&lt;li&gt;It needs to be written in a way that people who either aren&amp;rsquo;t geeks, or at least aren&amp;rsquo;t intimately familiar with your codebase can understand.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;changelogs-from-commits&#34;&gt;Changelogs from commits&lt;/h2&gt;
&lt;h3 id=&#34;commits-are-at-the-wrong-level-of-abstraction&#34;&gt;Commits are at the wrong level of abstraction&lt;/h3&gt;
&lt;p&gt;A git log is filled with commits like: &amp;ldquo;ensured current_and_future_campaigns returns a relation&amp;rdquo;, or &amp;ldquo;cleaned up whitespace in User.rb&amp;rdquo;, or &amp;ldquo;fixed expected aspect name in update test for locations_controller_spec&amp;rdquo; These &lt;em&gt;are&lt;/em&gt; useful to other developers on the project, but they &lt;em&gt;aren&amp;rsquo;t&lt;/em&gt; things that are useful to the users of your product.&lt;/p&gt;
&lt;p&gt;In short, they contain too much detail, at the wrong level of abstraction.&lt;/p&gt;
&lt;h3 id=&#34;commits-are-messages-from-one-developer-on-a-team-to-another-one&#34;&gt;Commits are messages from one developer on a team to another one&lt;/h3&gt;
&lt;p&gt;They&amp;rsquo;re not messages to your users, and they shouldn&amp;rsquo;t be.&lt;/p&gt;
&lt;p&gt;Commits frequently use jargon, and references to specific elements of code. This is absolutely fine, but it&amp;rsquo;s probably meaningless or useless to most of your consumers.&lt;/p&gt;
&lt;h3 id=&#34;theres-no-point&#34;&gt;There&amp;rsquo;s no point&lt;/h3&gt;
&lt;p&gt;If I wanted a geek level listing of all the changes in your git history I could just ask git: &lt;code&gt;git log --oneline&lt;/code&gt; Plus, git will let me slice and dice that information sixteen ways from Sunday.&lt;/p&gt;
&lt;h3 id=&#34;you-cant-edit-them&#34;&gt;You can&amp;rsquo;t edit them&lt;/h3&gt;
&lt;p&gt;As &lt;a href=&#34;http://www.commitlogsfromlastnight.com/&#34;&gt;Commits From Last Night&lt;/a&gt; proves. Commit messages frequently aren&amp;rsquo;t written in a customer friendly way. Even if you&amp;rsquo;ve got very polite developers, everyone makes typos. You can&amp;rsquo;t edit the old commit. If you want a changelog that looks professional you&amp;rsquo;re going to have to manually edit it, the same mistakes every single time you generate it.&lt;/p&gt;
&lt;h2 id=&#34;tickets-are-at-the-right-level-of-abstraction&#34;&gt;Tickets &lt;em&gt;are&lt;/em&gt; at the right level of abstraction&lt;/h2&gt;
&lt;p&gt;&amp;hellip;but they rarely have titles that are appropriate for a changelog.&lt;/p&gt;
&lt;p&gt;How about &amp;ldquo;Item Finder - Page gets wonky after searching for content that doesn&amp;rsquo;t exist - plus 404&amp;rdquo;, or &amp;ldquo;Something&amp;rsquo;s eating up all the ram and taking down the servers&amp;rdquo; Not really appropriate for your changelog.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re really following agile an agile methodology you have user stories that look like &amp;ldquo;As a &lt;user type&gt; I should be able to ___ because ___&amp;rdquo; and that&amp;rsquo;s no good for your changelog.&lt;/p&gt;
&lt;p&gt;Some projects do take the time to curate their ticket titles. The results are &lt;em&gt;almost&lt;/em&gt; usable as changelog entries too, but there are always exceptions. They&amp;rsquo;re generally worded well for the people who need to work on them, but not your consumers.&lt;/p&gt;
&lt;h2 id=&#34;its-a-matter-of-human-judgement&#34;&gt;It&amp;rsquo;s a matter of human judgement&lt;/h2&gt;
&lt;p&gt;You want a changelog with the information that is useful to your consumers, and written at the right level of abstraction. This means people need to ask themselves some questions. &amp;ldquo;Do we need a changelog entry for this?&amp;rdquo;, and if so, &amp;ldquo;How do I summarize this change in a  way that&amp;rsquo;s useful to our users?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The first question sometimes eliminates information, through curation. That&amp;rsquo;s something tools can&amp;rsquo;t do. The second question changes the form of the information conveyed. It was directed internally, now it&amp;rsquo;s directed externally.&lt;/p&gt;
&lt;h2 id=&#34;want-an-easy-tool-to-help-manage-this&#34;&gt;Want an easy tool to help manage this?&lt;/h2&gt;
&lt;p&gt;Check out &lt;a href=&#34;https://github.com/masukomi/changelog_manager#readme&#34;&gt;changelog_manager&lt;/a&gt;. It&amp;rsquo;s a free and open source tool to help you easily generate high quality Changelog entries.&lt;/p&gt;
&lt;h2 id=&#34;related-posts&#34;&gt;Related Posts:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://weblog.masukomi.org/2016/07/03/keeping-a-great-changelog/&#34;&gt;Keeping a Great Changelog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Finding the Github Pull Request for a topic branch</title>
      <link>https://weblog.masukomi.org/2013/12/24/finding-the-github-pull-request-for-a-topic-branch/</link>
      <pubDate>Tue, 24 Dec 2013 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2013/12/24/finding-the-github-pull-request-for-a-topic-branch/</guid>
      <description>&lt;p&gt;Finding the Github pull request associated with a branch.&lt;/p&gt;
&lt;p&gt;Work on a large enough project, with other people and sooner or later you&amp;rsquo;re going to find some commit, or branch, and want to know what was in the pull request that merged it in.  Maybe you want to see what other commits got merged over at the same time. Maybe you want to see what the diff was at that point in time. But, how do you get from a branch name to a pull-request.&lt;/p&gt;
&lt;p&gt;The key to solving this is knowing that pull requests are actually branches. They&amp;rsquo;re just&amp;hellip; hidden branches. So, first you start tracking them&amp;hellip;&lt;/p&gt;
&lt;p&gt;Locate the section for your github remote in the &lt;code&gt;.git/config&lt;/code&gt; file. It looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[remote &amp;quot;origin&amp;quot;]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = git@github.com:joyent/node.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now add the line &lt;code&gt;fetch = +refs/pull/*/head:refs/remotes/origin/pr/*&lt;/code&gt; to this section. Obviously, change the github url to match your project&amp;rsquo;s URL. It ends up looking like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[remote &amp;quot;origin&amp;quot;]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = git@github.com:joyent/node.git
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, after a &lt;code&gt;git fetch origin&lt;/code&gt; you can say &lt;code&gt;git checkout pr/999&lt;/code&gt; to checkout pull request number 999 as a local branch and diff it, or do pretty-much anything else with it.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve got that set up, it&amp;rsquo;s just a matter of comparing your local topic branch to the other branches in your system to find other branches that point to whatever branch you&amp;rsquo;re interested in.&lt;/p&gt;
&lt;p&gt;I use a shell script called &lt;code&gt;git-find-twins&lt;/code&gt; which iterates over the known branches (including pull request branches) and finds any whose &lt;a href=&#34;https://www.kernel.org/pub/software/scm/git/docs/gitglossary.html#def_tree-ish&#34;&gt;tree-ish&lt;/a&gt; matches that of the current branch.  You can &lt;a href=&#34;https://github.com/masukomi/masuconfigs/blob/master/bin/find_in_branches&#34;&gt;find the latest source here in Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;[Note: My apologies for the disappearing code on the right side in these examples. Just grab the source from the link above.]&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;#!/bin/sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# Finds other git branches whose HEADs point to the same &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# treeish as this branch.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# thanks to mockinterface on &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# http://stackoverflow.com/a/20756047/13973&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# for showing how to do this.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Looking for branches pointing to: &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;git rev-parse HEAD&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    git &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;-each-ref --format&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;%(refname)&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        xargs -I refname   &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        sh -c &lt;span class=&#34;s1&#34;&gt;&amp;#39;[[ $(git rev-parse HEAD^{tree}) == $(git rev-parse refname^{tree}) ]] &amp;amp;&amp;amp; echo refname&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;DONE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add that to your path, and make it executable then check out the branch you want to find the pull request for, and run your new shell script with &lt;code&gt;git find-twins&lt;/code&gt; (note the space) and you&amp;rsquo;ll see output like this.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git find-twins
Looking for branches pointing to: cb3c2dcf606a0a26107131697dd37aef53d44aad
refs/heads/9284_vzw_bug_fixtures_without_fixture_types
refs/remotes/origin/9284_vzw_bug_fixtures_without_fixture_types
refs/remotes/origin/pr/530
DONE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That last one is what you want. 530 the number of the pull request, which you can put into an URL to see the pull request. Now, you&amp;rsquo;re probably saying &amp;ldquo;Yeah, but what URL?&amp;rdquo; well, one way to get the correct url is to just bring up any other pull request in the current project and change the number in the url. Or you can add this shell script, which I call url_for_pr which generates an url for the pull request number in the current repo. It&amp;rsquo;s based on the assumption that &amp;ldquo;origin&amp;rdquo; is the Github repo. If it isn&amp;rsquo;t you&amp;rsquo;ll need to tweak what remote it gets its info from. You can &lt;a href=&#34;https://github.com/masukomi/masuconfigs/blob/master/bin/url_for_pr&#34;&gt;find the latest source here on Github&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[Note: My apologies for the disappearing code on the right side in this example. Just grab the source from the link above.]&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;#!/bin/sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# when run from a git repository, and passed the number &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# for a pull request, it will generate an url for &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# where to find it on Github. This assumes that&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# &amp;#34;origin&amp;#34; is pointing to the Github repo.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# This will work with Github Enterprise too.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$#&lt;/span&gt; -eq &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;ROOT_URL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;git config --get remote.origin.url &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;            sed s/.*@// &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;sed s/&lt;span class=&#34;se&#34;&gt;\.&lt;/span&gt;git// &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sed s/&lt;span class=&#34;se&#34;&gt;\:&lt;/span&gt;/&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;//&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;PR_NUM&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ROOT_URL&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/pull/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Please pass in a Pull Request number&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Note that this should be run within a git repository&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>Rebasing A Pull Request on GitHub</title>
      <link>https://weblog.masukomi.org/2013/02/07/rebasing-a-pull-request-on-github/</link>
      <pubDate>Thu, 07 Feb 2013 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2013/02/07/rebasing-a-pull-request-on-github/</guid>
      <description>&lt;p&gt;It&amp;rsquo;s generally good practice to rebase commits on a topic branch into a single commit before merging. It results in a much cleaner commit history, and makes rollbacks easier.&lt;/p&gt;
&lt;h2 id=&#34;the-question&#34;&gt;The Question&lt;/h2&gt;
&lt;p&gt;However, the question was raised: what happens if you&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fix a bug (commit 1)&lt;/li&gt;
&lt;li&gt;create a Pull Request&lt;/li&gt;
&lt;li&gt;get feedback via the Pull Request&lt;/li&gt;
&lt;li&gt;fix the bug fix (commit 2)&lt;/li&gt;
&lt;li&gt;rebase those two commits together (new tree-ish)&lt;/li&gt;
&lt;li&gt;push that back to GitHub (requires &lt;code&gt;push -f&lt;/code&gt; )&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The answer is based on understanding that a GitHub pull request has two forms of commenting:
* comments on the pull request itself
* comments on the commits that the pull request encapsulates. These are the comments made  on specific lines in the diff.&lt;/p&gt;
&lt;h2 id=&#34;the-answer&#34;&gt;The Answer&lt;/h2&gt;
&lt;p&gt;When you rebase and then force that changed version of history up onto GitHub you are effectively throwing out the old commit (the old tree-ish no longer exists) and replacing it with a new one.&lt;/p&gt;
&lt;p&gt;As a result any comments created on the diffs (and thus tied to a specific commit) will be lost, but the comments on the pull request itself will be preserved.&lt;/p&gt;
&lt;p&gt;So, the proposed rule of thumb is to simply NOT rebase once you have made a pull request. Instead, just add commits to your topic branch. This will maintain the comment history for future people curious about this piece of code.&lt;/p&gt;
&lt;h2 id=&#34;alternate-solutions&#34;&gt;Alternate Solutions&lt;/h2&gt;
&lt;p&gt;There are alternate solutions, of course, but the consequences of them tend to not be worth it.&lt;/p&gt;
&lt;h3 id=&#34;rebase-anyway&#34;&gt;Rebase Anyway&lt;/h3&gt;
&lt;p&gt;Decide that you don&amp;rsquo;t care about maintaining the inline comments, then rebase and &lt;code&gt;push -f&lt;/code&gt; back up to the server. The downside here is that at this point someone has already started looking at your code and has likely pulled it down. They will now be forced to blow away their old branch (or at least &lt;code&gt;reset --hard&lt;/code&gt; back to a point in its history before your commit), which is a pain and not obvious unless you tell them directly.&lt;/p&gt;
&lt;h3 id=&#34;make-a-second-topic-branch&#34;&gt;Make A Second Topic Branch&lt;/h3&gt;
&lt;p&gt;You could close the first pull request after having gotten the set of commits to an approvable state, and then open a new pull request from a separate topic branch with all those commits having been rolled up into one. The problem here is that if your new pull request is merged in then git blame will point to the tree-ish of the new one and no-one will ever see the comments on the old pull request unless they search, but when they do they may find that the commits in the original request don&amp;rsquo;t exist in the codebase (they&amp;rsquo;re all under the rebased commit).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Git: pushing and pulling from multiple repos</title>
      <link>https://weblog.masukomi.org/2013/01/31/git-pushing-and-pulling-from-multiple-repos/</link>
      <pubDate>Thu, 31 Jan 2013 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2013/01/31/git-pushing-and-pulling-from-multiple-repos/</guid>
      <description>&lt;p&gt;Lets assume you&amp;rsquo;ve already cloned a remote repo and have been working with it. Now, someone has set up a second repo out there for the same codebase, and you&amp;rsquo;d like to interact with both.&lt;/p&gt;
&lt;p&gt;*Please note: The following is based on the assumption that you have write privileges to the second repo, but don&amp;rsquo;t worry, you do essentially the same thing if you don&amp;rsquo;t and I&amp;rsquo;ll cover the differences at the end. *&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;git remote add &amp;lt;local_name_for_remote_repo&amp;gt; &lt;url&gt;&lt;/li&gt;
&lt;li&gt;git checkout -b &lt;branch name&gt; &amp;lt;local_name_for_remote_repo&amp;gt;/master
&lt;ul&gt;
&lt;li&gt;could be any branch on that repo, not necessarily master&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, your new local branch is now set up to track (push and pull to/from) the remote repo&amp;rsquo;s &amp;ldquo;master&amp;rdquo; branch. All your pre-existing branches will continue to track whatever they were tracking previously&lt;/p&gt;
&lt;p&gt;A practical example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git remote add repo2  git@github.com:masukomi/kudos.git
git checkout -b repo2_kudos -t repo2/master
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;workflow&#34;&gt;Workflow&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say you&amp;rsquo;ve decided to add a new feature in the &lt;code&gt;kudos&lt;/code&gt; repo we just connected to.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Checkout the &lt;code&gt;repo2_kudos&lt;/code&gt; branch&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git pull&lt;/code&gt; to get the latest code from repo2/master&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git checkout -b adding_feature_x&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;this new topic branch is not &lt;em&gt;yet&lt;/em&gt; tracking anything so if you attempt to &lt;code&gt;push&lt;/code&gt; or &lt;code&gt;pull&lt;/code&gt; it won&amp;rsquo;t work, because it won&amp;rsquo;t know what endpoint you want to interact with.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Make your changes on this topic branch.&lt;/li&gt;
&lt;li&gt;When you&amp;rsquo;re ready run &lt;code&gt;git push -u repo2 adding_feature_x&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;This will do three things:
&lt;ol&gt;
&lt;li&gt;It will create a new branch in the repo2 repository named &amp;ldquo;adding_feature_x&amp;rdquo;&lt;/li&gt;
&lt;li&gt;It will push the contents of your &lt;code&gt;adding_feature_x&lt;/code&gt; branch into the corresponding one on repo2.&lt;/li&gt;
&lt;li&gt;It will configure things so that your local &lt;code&gt;adding_feature_x&lt;/code&gt; branch is now tracking the remote &lt;code&gt;adding_feature_x&lt;/code&gt; branch so &lt;code&gt;push&lt;/code&gt; and &lt;code&gt;pull&lt;/code&gt; will work without additional arguments. &lt;strong&gt;You &lt;em&gt;must&lt;/em&gt; pass the &lt;code&gt;-u&lt;/code&gt; parameter for tracking to be set up here.&lt;/strong&gt; If you fail to pass the &lt;code&gt;-u&lt;/code&gt; parameter at this point then &lt;code&gt;push&lt;/code&gt; and &lt;code&gt;pull&lt;/code&gt; won&amp;rsquo;t work without additional parameters. You can, however, set up tracking after the fact with &lt;code&gt;git branch -u repo2/adding_feature_x&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now that you&amp;rsquo;ve pushed your changes to the new branch on the remote repo you can initiate pull requests from your topic branch into the main branches (if you&amp;rsquo;re using github) or you can simple tell others about it so that they can interact with it.&lt;/p&gt;
&lt;p&gt;Keep in mind that it&amp;rsquo;s best practice to regularly pull from your main branch into your topic branch (&lt;code&gt;repo2_kudos&lt;/code&gt; into &lt;code&gt;adding_feature_x&lt;/code&gt; in this case) so as to avoid large merge conflicts. Alternately you could pull from the corresponding main branch on the second repo (&lt;code&gt;repo2/master&lt;/code&gt; in this case) since they should be equivalent.&lt;/p&gt;
&lt;h2 id=&#34;when-you-dont-have-write-privileges&#34;&gt;When you don&amp;rsquo;t have write privileges&lt;/h2&gt;
&lt;p&gt;If you don&amp;rsquo;t have write privileges to the second repo things change slightly. The difference is in where you push your new topic branch (&lt;code&gt;adding_feature_x&lt;/code&gt;) to. You can either push as a new branch on whatever repo your local repo was cloned from (if you&amp;rsquo;ve got write privileges to that) &lt;em&gt;or&lt;/em&gt; you can create a third remote repo that you control, and push the branch to that. The third repo would be configured in the same way as the second, and you should be able to push to it in the same way we pushed to the second. Git makes it easy to flow code from one repo to another, or through multiple repos.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Using Git Bisect to Crush Your Enemies</title>
      <link>https://weblog.masukomi.org/2012/04/10/using-git-bisect-to-crush-your-enemies/</link>
      <pubDate>Tue, 10 Apr 2012 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2012/04/10/using-git-bisect-to-crush-your-enemies/</guid>
      <description>&lt;h2 id=&#34;using-git-bisect&#34;&gt;Using Git Bisect&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&amp;hellip;to crush your enemies and/or bugs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Or, how to save countless hours and find out where things broke&lt;/p&gt;
&lt;p&gt;Git bisect is the most awesome, and most poorly publicized feature of git. It allows git to walk through your branch and quickly find out which commit broke things.&lt;/p&gt;
&lt;p&gt;The usage is simple. You point git to a bad commit ( usually the most recent one ) and you point it to a good commit (the most recent one you know of when things were working).  So, if, for example, things were working on Tuesday morning, you bring up git log and scroll until you find one from Tuesday morning or maybe late Monday and copy its hash.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git bisect start
$ git bisect bad
	# that tells it that the current commit is bad
	# but you could say git bisect bad 48476f7b15022526393e6c4f44f610f552736fdc
$ git bisect good 71f45f2a0302b5fb2331c268ee2bfb3cfde452ab
	# that&#39;s the hash of some commit you know to have been good
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;git will then find the commit mid-way through and wait for you to tell it if it&amp;rsquo;s good or bad (&lt;code&gt;git bisect good&lt;/code&gt; or &lt;code&gt;git bisect bad&lt;/code&gt;). If it&amp;rsquo;s bad it knows the offending commit was earlier. If it&amp;rsquo;s good it knows the offending commit was later. It continues on in that vein, bisecting the commits with each step until it eventually says something like &lt;code&gt;54cb86bd35c226dc0df83dc2e2d4c8702fcf2c04 is the first bad commit&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;re done you run the following to reset your branch to its original state&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git bisect reset
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;full-automation&#34;&gt;Full Automation&lt;/h2&gt;
&lt;p&gt;But it&amp;rsquo;s even better than that. You can fully automate git bisect. Just kick it off and have it test each branch. All you have to do is write a script that can be executed from the shell and exits with 0 if the commit is good, and a number from 1-124 if it is bad.&lt;/p&gt;
&lt;p&gt;You only have to do one thing differently. Once you&amp;rsquo;ve told it a good and a bad commit it will bisect the commits as usual and give you a system prompt and wait for you to tell it if it is a good or bad commit, but instead of telling it if it&amp;rsquo;s good or bad, you tell it what it needs to run to test it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git bisect run my_test_script.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example: I&amp;rsquo;m working on a rails project at the moment and just used this simple rake task which would blow up if the .fixtures method wasn&amp;rsquo;t loaded correctly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# lib/tasks/location_test.rake
namespace :location_test do

	desc &amp;quot;tests location.fixtures classload issue&amp;quot;
	task :run =&amp;gt; :environment do
		begin 
				Location.first.fixtures
				$stderr.puts &amp;quot;it worked&amp;quot;
		rescue Exception=&amp;gt;e
				$stderr.puts &amp;quot;it died: #{e}&amp;quot;
				exit(1)
		end
		exit(0)
	end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, my run looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git bisect start 
$ git bisect good bebcc378d16d8fe74736c763c144753b2a382933
$ git bisect bad
$ git bisect run bundle exec rake location_test:run 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And git bisect proceeded about its merry way until it found the offending commit. Then I ran &lt;code&gt;git bisect reset&lt;/code&gt; and went about fixing the bug.&lt;/p&gt;
&lt;h2 id=&#34;pro-tip&#34;&gt;Pro-Tip&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;http://book.git-scm.com/5_finding_issues_-_git_bisect.html&#34;&gt;The Git Book adds this great note&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that the version which git-bisect checks out for you at each point is just a suggestion, and you&amp;rsquo;re free to try a different version if you think it would be a good idea. For example, occasionally you may land on a commit that broke something unrelated; run&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;$ git bisect visualize
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;which will run gitk and label the commit it chose with a marker that says &amp;ldquo;bisect&amp;rdquo;. Choose a safe-looking commit nearby, note its commit id, and check it out with:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;$ git reset --hard fb47ddb2db...
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;then test, run &amp;ldquo;bisect good&amp;rdquo; or &amp;ldquo;bisect bad&amp;rdquo; as appropriate, and continue.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Obviously this won&amp;rsquo;t work if you&amp;rsquo;re running a fully automated bisect, and it points to the one gotcha of git bisect. If there are multiple bugs that inhibit your ability to test it ( either manually or via a more automated means) it can leave you with no obvious candidate. Most of the time, this isn&amp;rsquo;t a problem, especially when you have done your best to chose the most recent &amp;ldquo;good&amp;rdquo; commit that you are confident in.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>git status-report</title>
      <link>https://weblog.masukomi.org/2010/07/16/git-status-report/</link>
      <pubDate>Fri, 16 Jul 2010 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2010/07/16/git-status-report/</guid>
      <description>&lt;p&gt;Every week I, and millions of developers like me, have to put together a
status report for our bosses, letting them know what we&amp;rsquo;ve been up to
for the previous week. Like most of the developers I&amp;rsquo;ve encountered I&amp;rsquo;m
always a little unsure of what *exactly* I was working on, and
typically I just open up git to see what commits I made, and try to
remember any non-code stuff I&amp;rsquo;ve Thinking it was silly to keep wading
through everyone&amp;rsquo;s commits for the past week to see what I worked on
I&amp;rsquo;ve put it all together in a script (in Ruby) called git status-report,
which you can &lt;a href=&#34;http://github.com/masukomi/git_accessories/blob/master/git-status-report&#34;&gt;grab from github
here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It outputs a bullet list of all your commits for the past n days, or the
commits of one of your fellow contributors. I think I&amp;rsquo;ll find the latter
a great way to keep up on what other folks on my team are working on at
the moment.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Usage: git status-report [-e &amp;lt;email&amp;gt;][-d &amp;lt;days&amp;gt;]
Generates a status report for what you worked on for the past n days.
    -a, --all                        Displays output for all contributers sorted by person
    -b, --branches &amp;lt;branch name&amp;gt;     Limit results to work found in the specified branch(es). 
                                         Multiple branches can be comma separated
    -c, --current                    Generates status report for the current repo only
    -d, --days &amp;lt;num days&amp;gt;            The number of days to generate the report for. Defaults to past 6 days (one week)
    -e, --email &amp;lt;email address&amp;gt;      The email address of the committer to generate a report for. 
                                         Defaults to your &amp;quot;git config user.email&amp;quot; address. 
                                         Multiple email addresses can be comma separated.
    -f, --files                      Display a list of files involved in the commit(s)
    -h, --help                       Displays this message
    -r, --reverse                    Displays output in reverse chronological order
    -s, --simple                     Simpler output. Doesn&#39;t include the dates
    -v, --verbose                    Verbose output includes details on each commit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please don&amp;rsquo;t hesitate to fork the repo on github and make improvements.
I&amp;rsquo;ll happily merge them in to the main one. git-status-report supports
will check for commits in all the branches and supports multiple
repositories. Check the README for full details.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Git Rebase: why, and when, you&#39;d use it.</title>
      <link>https://weblog.masukomi.org/2010/05/08/git-rebase-why-and-when-youd-use-it/</link>
      <pubDate>Sat, 08 May 2010 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2010/05/08/git-rebase-why-and-when-youd-use-it/</guid>
      <description>&lt;p&gt;Rebase is one of the most powerful tools in Git&amp;rsquo;s arsenal, but it can
trip up people coming from centralized version control systems. This is
just a quick example of why, and when, you&amp;rsquo;d want to use it.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say
we&amp;rsquo;ve got a team of three developers. Monday morning they all come in,
Bob makes a quick commit, and shares it with everyone. They all do a git
pull and suck it into their repos.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2010/05/rebasing_monday.png&#34;&gt;&lt;img src=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2010/05/rebasing_monday.png&#34; alt=&#34;image&#34; title=&#34;rebasing_monday&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Tuesday Mary does some work, but Bob and Tom are taking the day off and
don&amp;rsquo;t pull in her changes yet.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2010/05/rebasing_tuesday.png&#34;&gt;&lt;img src=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2010/05/rebasing_tuesday.png&#34; alt=&#34;image&#34; title=&#34;rebasing_tuesday&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wednesday Tom makes a change and everyone pulls it into their repos.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2010/05/rebasing_wednesday.png&#34;&gt;&lt;img src=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2010/05/rebasing_wednesday.png&#34; alt=&#34;image&#34; title=&#34;rebasing_wednesday&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now depending on what changes Mary has made Bob and Tom may be able to pull
them in without problem. Then again it &lt;em&gt;could&lt;/em&gt; result in a conflict. But
Mary&amp;rsquo;s a pro who thinks of her teammates, so she&amp;rsquo;s going to rebase her
repository and reorder the commits so that her change is on top of
Tom&amp;rsquo;s. Now, &lt;em&gt;if&lt;/em&gt; Mary&amp;rsquo;s changes were such that they&amp;rsquo;d cause a conflict
when Bob and Tom pulled them in then they&amp;rsquo;ll cause a conflict for Mary
when she rebases, but they&amp;rsquo;re Mary&amp;rsquo;s changes so she&amp;rsquo;s the one most
capable of resolving those quickly. Also, if Mary takes care of it in
the rebasing then no-one else is going to have to deal with the
conflict. It&amp;rsquo;s much better to have the person who wrote the change
resolve it than have everyone else on the team have to deal with it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2010/05/rebasing_mary_rebase.png&#34;&gt;&lt;img src=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2010/05/rebasing_mary_rebase.png&#34; alt=&#34;image&#34; title=&#34;rebasing_mary_rebase&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So, Mary reorders her commits with git rebase, and &lt;em&gt;if&lt;/em&gt; there were any
conflicts she resolves them. When the others pull down her changes it&amp;rsquo;ll
look like she wrote them on top of the changes they already had.&lt;/p&gt;
&lt;p&gt;Another reason Mary might want to rebase is if she made a bunch of partial
commits along the way. She might do this to give herself multiple
roll-back points, or maybe she committed every time she finished working
on one of the files related to the current feature she&amp;rsquo;s implementing,
just so she wouldn&amp;rsquo;t have to worry about loosing anything. Now, she
wouldn&amp;rsquo;t want to share those partial commits because they&amp;rsquo;d probably
break something in other people&amp;rsquo;s system. So, when she finishes with her
work, she uses rebase to squash the partial commits into one nice clean
commit and then tells people to pull that, or maybe pushes it to some
common repo they all push changes to.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2010/05/rebasing_mary_rebase_2.png&#34;&gt;&lt;img src=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2010/05/rebasing_mary_rebase_2.png&#34; alt=&#34;image&#34; title=&#34;rebasing_mary_rebase_2&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Rebase is an incredibly powerful tool, but there&amp;rsquo;s one thing you must remember
to never do and that&amp;rsquo;s rebase commits that have already been shared with
others. For example: Git wouldn&amp;rsquo;t prevent Mary from rebasing the &amp;ldquo;Bob -
Monday&amp;rdquo; commit up after all the other commits, or merge it into the
commit she made on Tuesday, but doing so is guaranteed to cause problems
for anyone who tries to pull from her. So rebase your own work before
you set it free, but once others have it you can&amp;rsquo;t touch it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://creativecommons.org/licenses/by-nc-sa/3.0/us/&#34;&gt;&lt;img src=&#34;http://i.creativecommons.org/l/by-nc-sa/3.0/us/88x31.png&#34; alt=&#34;Creative Commons License&#34;&gt;&lt;/a&gt;
This work is licensed under a &lt;a href=&#34;http://creativecommons.org/licenses/by-nc-sa/3.0/us/&#34;&gt;Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you found this useful you might be interested in &lt;a href=&#34;http://localhost:4000/blog/categories/git/&#34;&gt;some of the other git posts here&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Handling and Avoiding Conflicts in Git</title>
      <link>https://weblog.masukomi.org/2008/07/12/handling-and-avoiding-conflicts-in-git/</link>
      <pubDate>Sat, 12 Jul 2008 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2008/07/12/handling-and-avoiding-conflicts-in-git/</guid>
      <description>&lt;p&gt;John Kelvie said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[To] me the fundamental challenge with existing version control
systems is the difficulty of merging change sets from multiple
developers across the same set of code. To me, this issue comes down
to the diffing/merging functionality provided by the software, and I
haven&amp;rsquo;t seen or heard of anything that really improves the state of
the art. How does GIT address this? How does it make it easier to do?
Are there specific branching and merging tools it provides? Is through
the use of more atomic commits (which I could see helping to an
extent, but only so far as it allows for changes to be small enough
that there is no overlap, thus sidestepping the problem).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are two concepts that you must understand to really take advantage
of git. The first is the index / staging area. A full description would
require its own post but for this discussion you can think of it as a
temporary branch where you put everything before committing it. You can
diff between it and the last commit, between it and the working
directory, etc. The second is that a git repo can have (and usually
does) have multiple branches in the same location on disk.&lt;/p&gt;
&lt;p&gt;The idea of
multiple branches in the same folder, is critical to understand when
trying to address conflicts. In most version control systems you have
one checkout for every branch, each in a different location on your
disk, and while this is an option in git, you can also have multiple
branches in the same folder, just like the server side of most version
control systems.&lt;/p&gt;
&lt;p&gt;So, we&amp;rsquo;re going to need an example. Let&amp;rsquo;s assume I&amp;rsquo;ve
got a git repo with foo.rb. &lt;strong&gt;In the master branch&lt;/strong&gt; foo.rb looks like
this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (value == &amp;quot;test&amp;quot;) puts &amp;quot;I&#39;m in!&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On &lt;strong&gt;branch_one&lt;/strong&gt; we&amp;rsquo;ll change that test to&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (value == TEST\_CONSTANT) 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and on &lt;strong&gt;branch_two&lt;/strong&gt; we&amp;rsquo;ll make it&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (value ==&amp;quot;test&amp;quot; || value == &amp;quot;test2&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if master, branch_one,
and branch_two are all in the same repo we could stay in the same
directory and &amp;ldquo;checkout&amp;rdquo; whichever branch we wanted to be working on.
All the would change in place without you ever leaving the directory.
So, if you checkout master and cat foo.rb you&amp;rsquo;ll get the first example.
Checkout branch_two and cat foo.rb (without changing directories) and
you&amp;rsquo;ll see the last example. I&amp;rsquo;m sorry if that was obvious, but it&amp;rsquo;s
critical that you understand that, and some newbs just aren&amp;rsquo;t aware of
it yet.&lt;/p&gt;
&lt;p&gt;So, back to John&amp;rsquo;s questions. How does git make branching and
merging easier to do, and does it provide any specific tools for
managing it? Well, first off the commands are freaking simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;to create a branch in the same repo git branch branch_name or, more
commonly git checkout -b branch_name The latter creates the branch
then checks it out so you can immediately start working on it.&lt;/li&gt;
&lt;li&gt;to merge in a branch in the same repo git merge branch_name&lt;/li&gt;
&lt;li&gt;to merge in a branch from a remote repo you&amp;rsquo;ve got git fetch and git
pull More on these two in a minute, because they do dramatically
change how you manage conflicts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As for specific tools for managing it. Yes and no. &amp;ldquo;&amp;hellip;if you rather use
GUI tools to merge files instead of editing file with conflict markers
(like shown in example), you can use git-mergetool, which would call GUI
tool of your choice; currently supported out of the box are: kdiff3,
tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff.&amp;rdquo;
BUT, regardless of GUI tools, the ability to have multiple branches in
the same local repo changes everything.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example. Same files as
above, except I&amp;rsquo;m using a different repo for each instead of different
branches in the same repo, because that&amp;rsquo;s the way it would be when
pulling from other people, and since we&amp;rsquo;re dealing with people, we&amp;rsquo;ll
say branch_one is Mary&amp;rsquo;s branch and branch_two is Bob&amp;rsquo;s (pretend that
the. The first thing you&amp;rsquo;d do if you were pulling from these guys
regularly is to add them to your repos list of remote directories&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git remote add marys\_branch ../branch\_one/
$ git remote add bobs\_branch ../branch\_two/ 
$ git remote show bobs\_branch marys\_branch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here&amp;rsquo;s where the difference
between pull and fetch come in to play. fetch tells git &amp;ldquo;hey, go get
this remote data, and shove it into a &amp;ldquo;remote&amp;rdquo; branch &lt;em&gt;in my repo&lt;/em&gt;. pull
says, &amp;ldquo;fetch it, and &lt;em&gt;also&lt;/em&gt; merge it with my current branch.&amp;rdquo; Using
fetch we can suck in data from two sources, knowing full well it would
conflict if we tried to merge it, but still have no problems.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git remote update
Updating marys_branch
remote: Counting objects: 5, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From ../branch_one
* [new branch] master -&amp;gt; marys_branch/master
Updating bobs_branch
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), remote: reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From ../branch_two
* [new branch] master -&amp;gt; bobs_branch/master

$ cat foo.rb
if (value == &amp;quot;test&amp;quot;)
puts &amp;quot;I&#39;m in!&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, now, we&amp;rsquo;ve pulled in two people&amp;rsquo;s
conflicting changes, but not applied either. So, lets assume I don&amp;rsquo;t
suspect a conflict (hopefully they&amp;rsquo;re not normal occourrances for you).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git merge marys_branch/master
Updating 7d6f564..5713885
Fast forward
foo.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

$ git merge bobs_branch/master
Auto-merged foo.rb
CONFLICT (content): Merge conflict in foo.rb
Automatic merge failed; fix conflicts and then commit the result.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Damn, a conflict! Who would have guessed? Now, I do
what git suggests, fix the problem and commit it, but I&amp;rsquo;m neither the
one who broke it nor the one who knows most about it. So, I&amp;rsquo;m going to
kick this back to Bob or Mary, but, I may want to see what&amp;rsquo;s going on,
to help choose who to kick this to.&lt;/p&gt;
&lt;p&gt;One thing I can do is see
specifically which commits are conflicting:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git log --merge
commit f068f89e88e9174b50a0bc5622875dd4d8e21bc8
Author: Kay Rhodes
Date: Sat Jul 12 09:26:44 2008 -0400

switched to testing for test or test2 in branch_two

commit 5713885c9adc5689b6d8222b2650d4b3ad0dbc42
Author: Kay Rhodes
Date: Sat Jul 12 09:25:52 2008 -0400

switch test to TEST_CONSTANT on branch_one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the commit messages aren&amp;rsquo;t enough info I can
actually diff the two branches that conflicted totally separately from
anything in MY branch.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git diff marys_branch/master bobs_branch/master
diff --git a/foo.rb b/foo.rb
index dac3b0f..220011b 100644
--- a/foo.rb
+++ b/foo.rb
@@ -1,3 +1,3 @@
-if (value == TEST_CONSTANT)
+if (value == &amp;quot;test&amp;quot; || value == &amp;quot;test2&amp;quot;)
puts &amp;quot;I&#39;m in!&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I could have also diffed the specific
commits in conflict if I&amp;rsquo;d wanted, instead of the entire branches. In
this case it would give the same result. But, not knowing what
TEST_CONSTANT is (maybe it&amp;rsquo;s a closure, maybe it&amp;rsquo;s a predefined
variable) I can either make an educated guess that whatever
TEST_CONSTANT is it&amp;rsquo;s probably a better choice from a maintenance
perspective and tell Bob to go fix his stuff. Or, I could just send an
e-mail to both of them and let them figure it out.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also important
to point out that the &amp;ldquo;index in git contains on conflict *all*
versions of a file: &amp;lsquo;ours&amp;rsquo; i.e. the version in the branch you merge
into, &amp;rsquo;theirs&amp;rsquo; i.e. the version in the branch you are merging, and
&amp;lsquo;base&amp;rsquo; i.e. the version in the common ancestor ot the branches, and also
version with conflict markers.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Another option is to just fix it myself.
The conflicting file currently looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD:foo.rb

if (value == TEST_CONSTANT)
=======
if (value == &amp;quot;test&amp;quot; || value == &amp;quot;test2&amp;quot;)
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; bobs_branch/master:foo.rb
puts &amp;quot;I&#39;m in!&amp;quot;
end 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;HEAD is git
slang for &amp;ldquo;the branch you&amp;rsquo;re currently working on&amp;rdquo; which, in this case,
has Mary&amp;rsquo;s changes successfully merged in (actually, by default it&amp;rsquo;s
pointing to the last commit on the current branch). So, I decide that
all three tests need to be there and make the edit, and then update the
index. You need to update the index because git has already added Bob&amp;rsquo;s
changes to the index but knows that there was a conflict that needs
resolving.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git status
foo.rb: needs merge
# On branch master
# Changed but not updated:
# (use &amp;quot;git add ...&amp;quot; to update what will be committed)
#
# unmerged: foo.rb
#
no changes added to commit (use &amp;quot;git add&amp;quot; and/or &amp;quot;git commit -a&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Updating the index is simply a matter of getting the file how you want
it and saying:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; $ git add foo.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;at which point committing would get you a commit message template that
started like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; Merge commit &#39;bobs\_branch/master&#39; Conflicts: foo.rb \# \# It looks
&amp;gt; like you may be committing a MERGE. \# If this is not correct, please
&amp;gt; remove the file \# /Users/krhodes/temp/trunk/.git/MERGE\_HEAD \# and
&amp;gt; try again. \#
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The basic take-away from all this fetch / pull stuff is that it&amp;rsquo;s
generally a good idea to fetch first when dealing with other people&amp;rsquo;s
work, because having a local copy of their branch in your repo gives you
a number of additional options if things go wrong.&lt;/p&gt;
&lt;p&gt;And yes, atomic
commits go a huge way towards avoiding the problem of conflicts, and
handling them when they crop up. Obviously this applies to centralized
systems too. They avoid them by keeping your commits on topic. If one
commit is for bug X you generally don&amp;rsquo;t have to worry about it
conflicting with a commit for bug Y. And, when you discover that two
people you&amp;rsquo;re pulling from both have patches for bug X that conflict you
have many more options.&lt;/p&gt;
&lt;p&gt;Another key technique for avoiding conflicts is
to merge constantly. Every single day you should be pulling any work
that&amp;rsquo;s been committed upstream. That way, when things do conflict, you
only have to resolve a little tiny thing (if the commits are atomic then
it&amp;rsquo;s even tinier), and, if you choose to kick the issue back to someone
else it&amp;rsquo;s still fresh in their heads. This, of course, applies to
centralized systems to.&lt;/p&gt;
&lt;p&gt;Another way that git (and every other
distributed system) helps to avoid conflicts is a social change that
comes out of the distributed nature of the repos. Because you&amp;rsquo;re
constantly pulling in from multiple sources, having atomic commits
becomes a requirement to participation. If Bob is a twit and only makes
massive sprawling commits you&amp;rsquo;re simply not going to pull from him. It&amp;rsquo;s
not like a centralized system where you&amp;rsquo;re forced to take all the
changes out there. Whoever is in charge of the main trunk would be
stupid to accept Bob&amp;rsquo;s changes because if there was a problem in one of
them it&amp;rsquo;d be a pain in the butt to extract the bits that fixed bug A
from the bits that didn&amp;rsquo;t really fix bug B. No, they&amp;rsquo;d kick it back to
Bob, telling him to clean up his stuff and make two separate patches.&lt;/p&gt;
&lt;p&gt;This becomes even more important when you&amp;rsquo;re working on a project that
manages patches via e-mail. Just check out the git mailing list.
People&amp;rsquo;s patches are incredibly focused, enabling other git developers
to take just the bits and pieces they choose. Because the patches are
uniquely identifiable in git, it doesn&amp;rsquo;t matter if some people take a
change and some don&amp;rsquo;t and you, as the maintainer, pull from all of them.
Git won&amp;rsquo;t think they&amp;rsquo;re two different but identical changes. It&amp;rsquo;ll know,
&amp;ldquo;Oh, that&amp;rsquo;s change x. I&amp;rsquo;ve got that already.&amp;rdquo; Git also doesn&amp;rsquo;t care how
a patch got there. It could be from a commit you pulled over the lan, or
something someone e-mailed. Because it&amp;rsquo;s guaranteed cryptographically
unique, it&amp;rsquo;s the same thing.&lt;/p&gt;
&lt;p&gt;[Update 2] Some additional tips from Jakub
Narebski&lt;/p&gt;
&lt;p&gt;If you want to see what some file looks like on other branch
(or for example at specified point of time, for example at tagged
revision, marking some released version), you don’t need to use “git
checkout ‘branch’ &amp;amp;&amp;amp; cat ‘file’”; you can use “git show ‘branch’:&amp;lsquo;file’”
(see “Examples” section in git-show(1) manpage, and “Specifying
revisions” section in git-rev-parse(1) manpage).&lt;/p&gt;
&lt;p&gt;Below there is example
how index looks like during conflicted merge. The example uses yet
another way of specifying object names, i.e. “:’stage’:&amp;lsquo;file’” (we could
alternatively use SHA-1 or shortened SHA-1 of object shown in
git-ls-files output, e.g. “git show 2f096cc”).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git ls-files –abbrev –unmerged
100644 2f096cc 1 foo.rb
100644 89f36fe 2 foo.rb
100644 d3ea75d 3 foo.rb
$ git show :1:foo.rb
if (value == “test”)
puts “I’m in!”
end
$ git show :2:foo.rb
if (value == TEST_CONSTANT)
puts “I’m in!”
end
$ git show :3:foo.rb
if (value == “test” || value == “test2″)
puts “I’m in!”
end 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Try it yourself!&lt;/strong&gt;&lt;br&gt;
I find that reading how to do things like this is much enhanced by actually
having something to test it on, especially when there are so many
variables. So, I&amp;rsquo;ve uploaded &lt;a href=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2008/07/temp.tgz&#34; title=&#34;a temp dir with the three repos&#34;&gt;the temp dir with the three
repos&lt;/a&gt;
I used in writing this. If you go into the trunk repo you&amp;rsquo;ll see that
the other ones have already been configured as remote repos. And, if you
go into branch_one or branch_two you&amp;rsquo;ll see that they&amp;rsquo;re clones of
trunk and thus both already know that their upstream is trunk and how to
fetch from it without having to configure anything. You can also see
what the difference would be in pulling and fetching from one of them.&lt;/p&gt;
&lt;p&gt;Please let me know if there&amp;rsquo;s still something that&amp;rsquo;s a little unclear
about dealing with conflicts in git and I&amp;rsquo;ll add it in.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you found this useful you might be interested in &lt;a href=&#34;http://localhost:4000/blog/categories/git/&#34;&gt;some of the other git posts here&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why you should use a distributed version control system</title>
      <link>https://weblog.masukomi.org/2008/06/27/why-you-should-use-a-distributed-version-control-system/</link>
      <pubDate>Sat, 28 Jun 2008 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2008/06/27/why-you-should-use-a-distributed-version-control-system/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;ve ever:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;made a commit and then realized you forgot &amp;ldquo;one little change&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;made a commit and regretted it.&lt;/li&gt;
&lt;li&gt;wished you could combine some the past couple days worth of commits
into one nice combined commit in the main branch.&lt;/li&gt;
&lt;li&gt;wished you could commit just part of a file.&lt;/li&gt;
&lt;li&gt;needed to drop work on one task and switch tracks to another one
without having to make commits with unfinished changes, or commits
with changes for one issue and a little of another.&lt;/li&gt;
&lt;li&gt;wanted to make a test spike with version control and without
polluting the public repo.&lt;/li&gt;
&lt;li&gt;managed an open source project.&lt;/li&gt;
&lt;li&gt;wanted the security of knowing that there was a valid backup of your
revisions on many other peoples boxes, or even just your own.&lt;/li&gt;
&lt;li&gt;been frustrated with branch namespacing issues&lt;/li&gt;
&lt;li&gt;been frustrated with how difficult branching and merging is in most
centralized version control systems.&lt;/li&gt;
&lt;li&gt;wished you could just create branches to work on a feature or a bug
without worrying about the consequences to the main repo.&lt;/li&gt;
&lt;li&gt;wondered which branch a bug applied to.&lt;/li&gt;
&lt;li&gt;wanted to use version control when you were offline.&lt;/li&gt;
&lt;li&gt;wished you could quickly compare versions of entire trees.&lt;/li&gt;
&lt;li&gt;wished you could easily release everything in the current branch
&amp;ldquo;except that&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;been concerned about how to scale a system to support hundreds, or
thousands, of users.&lt;/li&gt;
&lt;li&gt;been concerned about what would happen if your main repo box died.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip;then distributed version control is worth your consideration.&lt;/p&gt;
&lt;p&gt;Now, there are a variety of DVCS to choose from, Git and Mercurial (Hg) are main
contenders, and both are really good. My experience is primarily with
Git so I&amp;rsquo;ll be speaking as a Git user, but Mercurial can do most
everything Git can, and a lot of this is general to all Distributed
Version Control systems.&lt;/p&gt;
&lt;p&gt;Quite possibly the most powerful, world
altering thing about DVCSs is how they handle branches. Because of their
distributed nature branching and merging absolutely must be simple
effective, and avoid conflicts whenever possible. As a result people
who&amp;rsquo;ve gotten the DVCS religion tend to make a branch for practically
every bug or feature. We call these &amp;ldquo;&lt;a href=&#34;https://weblog.masukomi.org/2007/09/10/branching-for-atomic-patches-and-cherry-picking&#34;&gt;topic
branches&lt;/a&gt;&amp;rdquo;.
If you&amp;rsquo;ve been working on one task for a while and a bug comes in that
has to be address NOW it&amp;rsquo;s not an issue. Commit your changes in the
current branch (or &amp;ldquo;stash&amp;rdquo; them away) and make a new branch for the bug
that just came in. I doesn&amp;rsquo;t matter if you commit unfinished work in one
of these branches, or if the work totally breaks the build, because it&amp;rsquo;s
&lt;em&gt;your&lt;/em&gt; branch. When you&amp;rsquo;ve finished working on a feature or bug you can
&amp;ldquo;rebase&amp;rdquo; all your interim commits on that task into one nice clean one,
or maybe generate a patch to apply to the main branch.&lt;/p&gt;
&lt;p&gt;The fact that you
can as many of &lt;em&gt;your&lt;/em&gt; branches as you want solves a huge number of
problems. Combine that with the ability to &amp;ldquo;rebase&amp;rdquo; you changes, by
bringing up a list of past commits to merge, reorder, or exclude, as you
see fit, and &amp;hellip;well it&amp;rsquo;s like heaven. The only caveat is that you can&amp;rsquo;t
rebase commits that others have already pulled. But that&amp;rsquo;s not a big
deal if you simply do your work in personal branches that others aren&amp;rsquo;t
going to be pulling from.&lt;/p&gt;
&lt;p&gt;Because most DVCSs allow you to cherry-pick
exactly which commits you want to be in a branch you can easily build a
release branch with just the parts that you want. There&amp;rsquo;s one caveat to
cherry-picking in most distributed and centralized systems : to do it
well you must have commits that are a self contained and atomic as
possible. If you make a commit with multiple features/fixes in it and
later on you decide not to include one of them there&amp;rsquo;s no simple way to
exclude just the bit you don&amp;rsquo;t want, because it&amp;rsquo;s mixed in with all the
others. And this, brings us back to the idea of &amp;ldquo;topic branches.&amp;rdquo; If
you&amp;rsquo;re already working with topic branches then you can easily merge the
changes in one topic branch into the main branch as one atomic commit
that can be excluded or included individually. However, as
&lt;a href=&#34;http://plasmasturm.org/&#34;&gt;Aristotle&lt;/a&gt; pointed out in the comments&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;the power of [Git&amp;rsquo;s] rebasing allows you to go back, split the commit
sensibly into several, and then transplant the rest of your history on
top of that. I guess whether this is simple depends on your definition
of simplicity, but git has enough tooling to support this procedure
directly. In other DVCSs you have to painstakingly monkey around with
far less powerful tools, and in centralised VCSs it is for all intents
and purposes impossible to do it at all.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, there will always be some changes that are dependent upon some
prior commit, but by having nice little atomic commits you can limit the
tree of dependencies to a bare minimum.&lt;/p&gt;
&lt;p&gt;One of the best features of
DVCSs is speed, but unfortunately it&amp;rsquo;s a lot like the Matrix. No-one can
be told how much of a difference it makes. You have to experience it for
yourself. I never complained about the speed of the centralized systems
I worked with until I switched to Distributed Version Control. I found
it hard to believe that &amp;ldquo;instant&amp;rdquo; commits would make a difference. Or
that the time it took to diff against past versions was an issue. But I
swear to you that the effect on how you work is almost as radical as the
improved branching, and it flows over into the branching too. Now
branching and merging is not only painless, it&amp;rsquo;s instant. I create,
merge, and destroy branches throughout the day without hesitation
because no matter what operation I do it comes back so fast that I
frequently am incapable of telling that any time passed. That&amp;rsquo;s means
that many (most?) of my operations are happening in the sub 100ms range.
Imagine being able to diff versions of entire trees in tenths of
seconds.&lt;/p&gt;
&lt;p&gt;Scaling to thousands of users is not an issue with Distributed
Version Control Systems because one box doesn&amp;rsquo;t have to support all the
simultaneous operations that would normally be going on. Commits,
checkouts, reverts, branches, diffs&amp;hellip;. all of it happens on peoples
local machines. They rarely need interact with &lt;a href=&#34;https://weblog.masukomi.org/2008/03/11/wheres-the-main-repo-when-using-git&#34;&gt;the canonical / central
repo&lt;/a&gt;.
This means that large companies like Google wouldn&amp;rsquo;t need to invest in
massive boxes with huge processors and piles of ram just to keep their
version control system usable.&lt;/p&gt;
&lt;p&gt;Speaking of the canonical repo&amp;hellip;
workflow doesn&amp;rsquo;t have to change at all. If you&amp;rsquo;ve got an established
workflow with a centralized system there&amp;rsquo;s absolutely no reason it can&amp;rsquo;t
continue on after a switch to Distributed Version Control. But, it does
open up some &lt;a href=&#34;http://bazaar-vcs.org/Workflows&#34;&gt;other ways of working&lt;/a&gt;
that you may want to explore.&lt;/p&gt;
&lt;p&gt;In a centralized system if the box your
main repo lives on goes down you&amp;rsquo;re pretty much screwed. If your IT
people are &lt;em&gt;really&lt;/em&gt; on the ball you&amp;rsquo;ve got it syncing to another box
every few minutes (or more) and everything will fail over&amp;hellip; bringing
the primary box back up and resycing it may cause them to pull out their
hair but at least no-one would be affected. Unfortunately it is a very
rare company that&amp;rsquo;s that well prepared. And if you&amp;rsquo;re hosting an open
source project you just have to hope that the people you&amp;rsquo;re hosting with
have good backups and don&amp;rsquo;t go down.&lt;/p&gt;
&lt;p&gt;Most software companies, and open
source projects, simply grind to a halt when the version control system
goes down. Changes can&amp;rsquo;t be shared, branches can&amp;rsquo;t be made, bugs can&amp;rsquo;t
be patched, releases can&amp;rsquo;t be made, developers start building up a
backlog of changes that will end up mooshed together into one commit
when things do come back up, etc., etc., etc. But teams using DVCSs
simply don&amp;rsquo;t care. It&amp;rsquo;s a non issue. &amp;ldquo;The heads crashed on the drives of
the main repo, and a fuel truck plowed into our offsite backups&amp;rdquo;. It
simply doesn&amp;rsquo;t matter. Sure your IT guys are going to have to deal with
fixing that, but the impact to development is essentially zero. Someone
stands up, or sends out an e-mail, and says &amp;ldquo;the main repo is down, just
use my box instead&amp;rdquo;, and people do, and that&amp;rsquo;s the end of it. When the
main box is repaired IT simply pulls from the box everyone&amp;rsquo;s been using
in the interim and once again stands up, or sends out an email saying
&amp;ldquo;the main box is back up&amp;rdquo;. Automatically syncing a remote box for
fail-over becomes trivially simple with DVCS. Just set up a cron job to
pull from the main box every minute and you&amp;rsquo;re done.&lt;/p&gt;
&lt;p&gt;When it comes to
open source projects there is one factor that absolutely sucks and
that&amp;rsquo;s giving out write permissions. You don&amp;rsquo;t want to give them out to
just anyone, but if you don&amp;rsquo;t then people who you don&amp;rsquo;t trust yet either
have to work on your code without any revision control, or as is
frequently the case, they just fork it into a version control repo they
&lt;em&gt;do&lt;/em&gt; have control over and loose the ability to easily merge their
changes back into the main repo. You could just give them out to anyone
but that&amp;rsquo;s not a choice that many project managers are comfortable with.
With DVCSs it simply isn&amp;rsquo;t an issue. Everyone&amp;rsquo;s got their own repo(s)
everyone can commit, branch, etc.. And when they&amp;rsquo;ve got something
worthwhile they can ask you to pull from them, or send you a patch that
they know will work with your repo because that&amp;rsquo;s where their repo
originated and they&amp;rsquo;ve been pulling down your changes and merging it in
to their work.&lt;/p&gt;
&lt;p&gt;One problem that&amp;rsquo;s been an annoyance for me for years is
that most bug trackers have no concept of branches. When you go into
your bug tracker it shows you all your bugs but there&amp;rsquo;s no way to tell
what branches they exist in, and what happens when you fix a bug, and
get QA to sign off on it, in one branch but it hasn&amp;rsquo;t been patched in
another one? Is the bug fixed or isn&amp;rsquo;t it? And what about the people who
don&amp;rsquo;t have an intimate knowledge of that bug? How are they supposed to
know where it does and doesn&amp;rsquo;t exist?&lt;/p&gt;
&lt;p&gt;Distributed Issue Trackers solve
this problem. You file a ticket in the branch the bug exists in. Then
that ticket follows along with and branches of that branch until someone
closes the ticket. As they merge the fixes back into parent branches the
closed ticket merges in too. As a result you can always tell if a bug is
or isn&amp;rsquo;t fixed in the current branch. If you commit your closed ticket
with your patch then even more possibilities open up. If, for example,
it was decided that your cure was worse than the cause and excluded that
commit from a release then the ticket would re-open itself in the
release too (because you got rid of the fix).&lt;/p&gt;
&lt;p&gt;To date the best Distributed Issue Tracker, without question is
&lt;a href=&#34;http://ditz.rubyforge.org/&#34;&gt;Ditz&lt;/a&gt;, but the field is still very young.
I&amp;rsquo;ve personally been working on a fork of Ditz that makes some dramatic
changes and tightly integrates itself with Git, and I&amp;rsquo;ll update this
page and make an announcement as soon as it&amp;rsquo;s released (a week or two).
Personally I wouldn&amp;rsquo;t recommend anything other that Ditz right now. The
projects are either too immature or abandoned and buggy. Ditz doesn&amp;rsquo;t
have a lot of features yet but it&amp;rsquo;s reliable and gets the job done.&lt;/p&gt;
&lt;p&gt;Another cool thing about Distributed Version Control Systems is that you
don&amp;rsquo;t need anyone&amp;rsquo;s permission, or cooperation, to start using them. I
work at a company that uses Perforce, and I think that &lt;a href=&#34;https://weblog.masukomi.org/2007/08/31/dear-perforce-fuck-you&#34;&gt;Perforce is the
devil&lt;/a&gt;,
but it doesn&amp;rsquo;t matter, because I have Git. I do all my work in Git;
constantly branching and merging and mooshing commits, and when I&amp;rsquo;m
ready I just submit the completed changes back to Perforce. And this is
actually better for everyone. Sysadmins don&amp;rsquo;t have to deal with the
consequences of me making topic branches all over the place, the commits
I make for coworkers are generally cleaner, and I can commit as often as
I want, even break the build, without having to worry about the impact
on others. Now, it happens that Git has a number of tools for working
with the major centralized version control systems (it&amp;rsquo;s even got a CVS
proxy so that CVS people too resistant to change can keep working the
way they&amp;rsquo;re used to). But, if your DVCS of choice doesn&amp;rsquo;t have a tool to
bridge the gap to whatever centralized system you&amp;rsquo;re forced to deal
with, you can always use &lt;a href=&#34;http://progetti.arstecnica.it/tailor&#34;&gt;Tailor&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It sounds &lt;em&gt;too&lt;/em&gt; good&amp;hellip;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Some of you are probably thinking this
sounds too good to be true, or maybe that I&amp;rsquo;m DVCS zealot. But really,
it isn&amp;rsquo;t, and I&amp;rsquo;m not. I&amp;rsquo;m a huge fan of DVCS, it&amp;rsquo;s true, but I&amp;rsquo;m not
about to claim that they will solve all your problems. To really get the
full benefits of them you&amp;rsquo;ve got to start making atomic commits. This is
actually true of centralized systems too, but since centralized systems
tend to be such a pain to use, and frequently can&amp;rsquo;t do cool things like
cherry-picking, people don&amp;rsquo;t even bother to do anything advanced with
them. With a distributed system the advanced stuff becomes trivial
every-day stuff, and it becomes more annoying to have to deal with those
developers who won&amp;rsquo;t stop making ginormous commits with changes to
multiple bugs as well as a new feature or twelve. Fortunately, you don&amp;rsquo;t
have to accept their patches of you don&amp;rsquo;t want to. ;)&lt;/p&gt;
&lt;p&gt;Guis have come a long way since this was first posted, especially for
Git and Mercurial with quality that rivals the best tools for centralized
systems.&lt;/p&gt;
&lt;p&gt;On the command line some DVCSs like Darcs shine with totally intuitive commands, others
have a bit more of a learning curve. Git definitely does because of how
it stages things before commits. It &lt;em&gt;appears&lt;/em&gt; similar enough to the way
centralized systems work that many newbs expect it to work the same, and
get frustrated when their expectations collide with its significantly
different paradigm. Not only does Git stage things before commits but it
doesn&amp;rsquo;t even think in terms of files, although, unless you&amp;rsquo;re paying
attention, it may seem that it does.&lt;/p&gt;
&lt;p&gt;Scaling to handle extremely large
repos with years of history is something that Git handles very well
(Mercurial probably does too), but some systems, like Darcs, have
serious problems with.&lt;/p&gt;
&lt;p&gt;In short, Distributed Version Control systems are
totally bad-ass, and can really help with a lot of common development
problems, but they&amp;rsquo;re still fairly new, and while the big ones are good,
and reliable, they may not have all the polish and GUI widgets that
you&amp;rsquo;re used to with your centralized system. My advice is to go get Git,
unless the majority of your developers are on Windows, in which case
Mercurial may be a better choice&amp;hellip; for the moment.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Getting just the tip of a Git repo</title>
      <link>https://weblog.masukomi.org/2008/03/13/getting-just-the-tip-of-a-git-repo/</link>
      <pubDate>Thu, 13 Mar 2008 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2008/03/13/getting-just-the-tip-of-a-git-repo/</guid>
      <description>&lt;p&gt;Sometimes you just want to distribute the source code without its history, and that&amp;rsquo;s where git-archive comes in. git-archive will create an archive of the files at any point in the history and wrap them all up for you in a tar or zip (defaults to tar). You can even make an archive from a remote repo by using the&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;—remote=&amp;lt;repo&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;option in the administrator has enabled it.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll typically use git-archive like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git archive &amp;lt;tree-ish&amp;gt; &amp;gt; my_new_archive.tar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that will create an archive of everything in your repo. If you just want an archive of some specific files you can simply pass in the path(s) to the
file(s) you want in the archive after your tree-ish. If you wanted to create a zip file instead of a tar you&amp;rsquo;d simply pass it the &amp;ldquo;—format=zip&amp;rdquo; option.&lt;/p&gt;
&lt;p&gt;Many people wonder if there is a way to check out just the tip of the repo so that they don&amp;rsquo;t have to download the entire revision history. This is called a &amp;ldquo;shallow&amp;rdquo; clone and is possible by passing the &amp;ldquo;&lt;code&gt;--depth &amp;lt;some\_number\&amp;gt;&lt;/code&gt;&amp;rdquo; but it has a number of limitations: you can&amp;rsquo;t clone, or fetch from it and you can&amp;rsquo;t push from or into it, but it&amp;rsquo;s useful if you only want to look at, or near, the tip of a large project with a long revision history and would want to send in your fixes or features as patches.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Sharing a public Git repo over HTTP [flow chart]</title>
      <link>https://weblog.masukomi.org/2008/03/11/sharing-a-public-git-repo-over-http-flow-chart/</link>
      <pubDate>Tue, 11 Mar 2008 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2008/03/11/sharing-a-public-git-repo-over-http-flow-chart/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2008/03/config_remote_repo.jpg&#34; alt=&#34;Configuring a public HTTP Git
repository&#34;&gt;&lt;/p&gt;
&lt;p&gt;There is also &lt;a href=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2008/03/config_remote_repo.svg&#34;&gt;an SVG version of this flow&lt;/a&gt;, which is more readable (but poor IE folks will have issues). Notes: This is a simplest possible configuration. Be sure to check out the docs for git-remote to see how to, optionally, designate specific local or remote branches. Many of the initial commands could be performed locally and then just uploaded to the server. This particular sequence guarantees that all the connection pieces are in place and working correctly.&lt;/p&gt;
&lt;p&gt;Much thanks to Tim Toolman for getting this info into two easy to follow posts: &lt;a href=&#34;http://toolmantim.com/article/2007/12/5/sharing_git_repositories_via_os_xs_built_in_web_sharing&#34;&gt;Sharing git repositories via OS X&amp;rsquo;s built-in web sharing&lt;/a&gt;
and &lt;a href=&#34;http://toolmantim.com/article/2007/12/5/setting_up_a_new_remote_git_repository&#34;&gt;Setting up a new remote git repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, this doesn&amp;rsquo;t feel elegant to me. If anyone can come up with a
simpler / more elegant way to do this please add a comment.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Some thoughts about Git</title>
      <link>https://weblog.masukomi.org/2008/02/04/some-thoughts-about-git/</link>
      <pubDate>Tue, 05 Feb 2008 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2008/02/04/some-thoughts-about-git/</guid>
      <description>&lt;p&gt;Not too long ago I decided to start writing a book about distributed
version control. I was originally going to focus on
&lt;a href=&#34;http://www.selenic.com/mercurial/wiki/&#34; title=&#34;Mercurial&#34;&gt;Mercurial&lt;/a&gt; (Hg)
because it&amp;rsquo;s quite good and of the two leading systems it was the only
one that ran on every OS (because it was written in Python). The fact
that it could also run under Windows meant that I could help spread the
word about distributed version control to more people, and it slightly
increased the chance that I might actually make some money in the
process.&lt;/p&gt;
&lt;p&gt;There was just one problem: Linus was right.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Hg is pretty good, but &lt;a href=&#34;http://git.or.cz/&#34; title=&#34;Git&#34;&gt;Git&lt;/a&gt; is better.&amp;rdquo; -
Linus Torvalds&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I heard him utter those words in his talk to the folks at Google I
took them with a grain of salt. Almost every project owner believes that
their software is &amp;ldquo;better&amp;rdquo; than the competition, especially when they&amp;rsquo;re
so similar, but it turns out that it wasn&amp;rsquo;t hubris on his part. When you
sit down and compare the functionality Git simply lets you do more.&lt;/p&gt;
&lt;p&gt;I had actually started writing the book about Hg but time and again I
found myself confronted with something that was either easier to do in
Git, or simply not possible in Hg. It happened enough that I decided
that I didn&amp;rsquo;t want to keep writing about, and arguably helping, out a
product that I not only wouldn&amp;rsquo;t choose to use myself but also felt was
dramatically inferior from a usage standpoint.&lt;/p&gt;
&lt;p&gt;And then I joined the Git mailing list. Linus mentioned that it had a
high signal to noise ratio but&amp;hellip; holy shit. I have been on a lot of
mailing lists for open source projects over the years and I have never
seen anything like this. Almost every e-mail is a patch, or a good
discussion of a patch, or a good discussion of some new feature and how
to go about implementing it. Currently, one of the topics they&amp;rsquo;re
discussing is how to allow people to push to a Git repo based on GPG
keys stored in, or accessible by, Git. What&amp;rsquo;s amazing is that it isn&amp;rsquo;t
just one or two people going back and forth or someone trying to
proclaim the &amp;ldquo;one true way&amp;rdquo; to do things. It&amp;rsquo;s exactly what you would
expect if you took a bunch of smart geeks, stuck them in a room, and
watched them all work together to solve some common problem. That alone
is impressive, but when you combine that with the fact that it&amp;rsquo;s a
pretty high traffic list and you&amp;rsquo;ve got a lot of really smart people
pushing a tool forwards at an incredible pace.&lt;/p&gt;
&lt;p&gt;Now, all is not sunshine and roses in Git land:&lt;/p&gt;
&lt;p&gt;The documentation is actually pretty good, but when you want to do a
specific task and don&amp;rsquo;t know the Git specific terminology for it it can
be a little difficult to find what you need, and sometimes the commands
take a dizzying array of options and could really do with more examples.
That works out well for me, because it&amp;rsquo;ll be all the more reason for
people to buy my book, but it&amp;rsquo;s obviously not great for attracting new
users. I still think that, for most use cases, Darcs does a better job
than anyone at making it easy to ferret out what command you need to
accomplish a task.&lt;/p&gt;
&lt;p&gt;Git is a lot like C. It&amp;rsquo;s incredibly flexible and powerful but it is
also incredible flexible and powerful. If you want to shoot yourself in
the foot Git will point you to the gun rack and show you how to load the
bullets.&lt;/p&gt;
&lt;p&gt;Under the covers Git is a collection of small C apps surrounded by
shell scripts, Perl scripts, Python scripts&amp;hellip;. whatever the author
chose to get the job done. From a usability standpoint this is
irrelevant. Calling &amp;ldquo;git foo&amp;rdquo; is going to work just as well regardless
of what foo was written in and will have no impact on the user, but I&amp;rsquo;d
personally prefer to hack on a project that was all written in one
language.&lt;/p&gt;
&lt;p&gt;It also means that the &lt;a href=&#34;http://code.google.com/p/msysgit/&#34;&gt;msysgit&lt;/a&gt; team has a lot of work
ahead of them in trying make it install easily under Windows. If you&amp;rsquo;d
like to see git working under Windows, and are familiar with coding for
Windows please check these guys out and see if there&amp;rsquo;s anywhere you can
help out. Even just taking on a little task here and there is something
that would be greatly appreciated. Part of me wonders if it wouldn&amp;rsquo;t be
better to just port everything in Git to C.&lt;/p&gt;
&lt;p&gt;I think that if the Git book goes over well I may go back and retool it
for Mercurial, but in the meantime I have to agree with &lt;a href=&#34;http://tytso.livejournal.com/294672.html&#34;&gt;Ted Tso&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;&amp;hellip;the main reason why I&amp;rsquo;ve come out in favor if Git is that I see
its potential as being greater than [that of] Hg, and&amp;hellip; in the long
run I think it has &amp;lsquo;more legs&amp;rsquo; than Hg&amp;hellip;&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just to be totally up front. Ted did have some complaints about ease
of use and documentation, but I think that since his post came out Git
has made some really significant improvements in those areas.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Branching for atomic patches and cherry-picking</title>
      <link>https://weblog.masukomi.org/2007/09/10/branching-for-atomic-patches-and-cherry-picking/</link>
      <pubDate>Mon, 10 Sep 2007 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2007/09/10/branching-for-atomic-patches-and-cherry-picking/</guid>
      <description>&lt;p&gt;The best thing about Distributed Source Control Managers (
&lt;a href=&#34;http://www.urbandictionary.com/define.php?term=imnsho&#34; title=&#34;In My Not So Humble Opinion&#34;&gt;IMNSHO&lt;/a&gt;
) is how quick and easy it is to branch and merge. The problem is that
most of us cut our teeth on centralized systems that couldn&amp;rsquo;t even hope to
take advantage of cherry picking, which is, in short the ability to take
a single patch out of the middle of a sequence of patches, or every
patch but one from a sequence. Just imagine knowing that there was a bug
introduced in a specific patch and being able to prune it from your
repository but not any of the patches around it. Or, plucking one little
feature out of a mass of others that should wait until the next release.
You can, but if you don&amp;rsquo;t make the effort to keep your patches as atomic
as possible you&amp;rsquo;ll find that that patch you want to remove or extract is
dependant upon another one, or more, that you may not want to involve.&lt;/p&gt;
&lt;p&gt;Which brings me to my hierarchy of branches. Now, I&amp;rsquo;m still working
with this concept so if you can improve upon it please let me know.
The idea is that most of the time you&amp;rsquo;re not
adding one little atomic feature, you&amp;rsquo;re adding a number of features
that can be conceptually clustered. So, you make a branch for the
cluster, but do no actual development directly in it. Then you branch
from there for each atomic feature (be sure to scroll down to the graph
below the fold here).&lt;/p&gt;
&lt;p&gt;While you are working on a feature feel free to commit as often as you
want. Check in broken or unfinished code. Pollute that branch&amp;rsquo;s revision
history with as much crap as you want. Do whatever it takes in there to
make sure you can roll back to any point you want, and never loose work.
Have a cron job check in any uncommitted changes to this micro-branch
every night in case you forget to. It doesn&amp;rsquo;t matter because you&amp;rsquo;re not
going to push the revision history back up to the branch for the feature
cluster. Instead you diff from the branch point and patch the cluster
branch and commit it. This way you&amp;rsquo;ve got one atomic revision with the
combined changes for that one small feature and if you need to prune it
for any reason (maybe it&amp;rsquo;s broken, or decided you should wait on adding
it) you can easily do so without worry of dependencies. Your micro
branch has all the details of the feature evolution if you really feel
you need it, but most of the time you&amp;rsquo;ll just delete it after creating
the patch and applying it to the cluster. Eventually the cluster will
have all the related features completed and checked in and it&amp;rsquo;s revision
history will consist of a series of atomic commits. The cluster&amp;rsquo;s
revision history is then pushed upstream to your personal development
branch. Occasionally you&amp;rsquo;ll have a small feature to work on with no
related ones to cluster. Just branch from your personal development
trunk and then patch back into it as you would have into a feature
cluster.&lt;/p&gt;
&lt;p&gt;Bugs should be treated in exactly the same way as features, although
you&amp;rsquo;ll find yourself with many more small bugs that don&amp;rsquo;t need a parent
cluster and can just be worked on in their branch and then used to patch
your personal development branch.&lt;/p&gt;
&lt;p&gt;People working farther upstream now have the option of cherry picking
features, feature clusters, bugs, and bug clusters, and will be able to
do so with much less worry of getting caught up with patches that depend
on other patches.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;http://s3.amazonaws.com/mobtvse_masukomi/assets/2007/9/10/heirarchy_of_branches.png&#34; alt=&#34;a heirarchy of
branches&#34;&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why you should be using a distributed source control system</title>
      <link>https://weblog.masukomi.org/2006/12/29/why-you-should-be-using-a-distributed-source-control-system/</link>
      <pubDate>Fri, 29 Dec 2006 00:00:00 +0000</pubDate>
      
      <guid>https://weblog.masukomi.org/2006/12/29/why-you-should-be-using-a-distributed-source-control-system/</guid>
      <description>&lt;p&gt;I was reading some articles yesterday that finally made the light bulb
go off about distributed source control management (scm) and why we
should be using them. First off, a distributed scm, unlike CVS or
Subversion, has no central repository that all others pull from. It&amp;rsquo;s
possible to set one up and say that it&amp;rsquo;s the master and tell people to
pull from and push to it but that&amp;rsquo;s more a matter of convention. What&amp;rsquo;s
truly unique about these systems is that each checkout is it&amp;rsquo;s own
self-contained ecosystem. And there are many reasons this is a good
thing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can make as many changes as you want, check in unfinished code,
and explore new functionality without ever affecting other
developers. It only impacts other users when you sync your current
working environment with others.&lt;/li&gt;
&lt;li&gt;You don&amp;rsquo;t have to have net access, or be connected to any other box
to get work done while still taking advantage of version control.
Working on your laptop? Stuck in the boonies with just dial-up?
Commit changes, roll-back to previous versions, make branches, none
of it is dependent upon some central server. When you do get back
online you can sync your changes with others.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;You don’t need to set up and manage a central SCM host with
sufﬁcient disk space, compute power, bandwidth, and backup to
support the concurrent SCM operations of your entire development
community.&amp;rdquo; *&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;real-world-uses&#34;&gt;Real world uses:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The open source project:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If Mozilla has taught us anything it&amp;rsquo;s that you&amp;rsquo;re NOT going to get
thousands of developers working on your project. So, while huge
numbers of developers is something that distributed scm handle
exceedingly well I think the point is moot. But, in my experience, a
developer interested in some OSS (Open Source Software) project will
download the source from a traditional scm, poke around to
understand it, and if they&amp;rsquo;re smitten with the idea will start
customizing it for their needs. But, the are forced to either work
without the benefits of version control or they have to check it
into their own personal scm. If they check it into their own you can
pretty much forget about ever getting patches from them because
they&amp;rsquo;re no longer able to sync with your tree and it would be way
more work than they generally want to do to get synced and give you
a patch that was useful. If they work without scm (because they
don&amp;rsquo;t have commit rights to your scm) you may get a patch from them
but for them it&amp;rsquo;s like climbing a rock face without lines and
harnesses.&lt;/p&gt;
&lt;p&gt;If you were to use a distributed scm each developer would be working
off of their own personal copy of the scm that could be synced at
any point in time no matter how many changes, revisions, or commits
they have made. They&amp;rsquo;re generally not going to check it into their
own scm system because that&amp;rsquo;s work that doesn&amp;rsquo;t get them any real
benefit. They already have version control via their checkout and
the fact that it&amp;rsquo;s a distributed system. End result, they don&amp;rsquo;t need
to work without the safety and security of an scm and they will
generally always be working on a system they can easily send you
changes from when they&amp;rsquo;re ready.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Web developers with sites others depend on:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re really working like a pro, you&amp;rsquo;re constantly branching and
merging your code. You&amp;rsquo;ve got a live site branch. You&amp;rsquo;ve got a
branch for each new functionality exploration. You&amp;rsquo;ve got a trunk
branch that everyone merges into their other branches regularly. In
the real world you probably have a live site branch and the trunk
and cross your fingers that each developers functional exploration
doesn&amp;rsquo;t screw over any other developer&amp;rsquo;s pokings. Or, in far too
many cases, you just have the trunk. The problem comes (for those of
us who hate dealing with the pain in the ass that is the current
state of merging on most traditional SCMs and have minimal branches)
when you decide you want to integrate one developers functional
exploration into the live branch. How do you extract that code from
the other code in the trunk (or any other common branch)?&lt;/p&gt;
&lt;p&gt;If you were using a distributed scm it would go something like this:
Everything starts with the live site repo (wherever you happen to
keep that). Everyone&amp;rsquo;s local repo(s) started as a copy of that. It&amp;rsquo;s
not uncommon to check out another copy to go explore some new
feature set in. Maybe you sync it with the live. Maybe you trash it.
It doesn&amp;rsquo;t matter no other repo was affected by your fiddling. You
don&amp;rsquo;t have to make a new branch in some central repo that gets
stored forever even if your fiddlings proved insignificant or were
just abandoned. If everyone decides that the features you worked out
in a particular repo are worth keeping they just sync with it. If
you decide to wait to put it into a later release that&amp;rsquo;s fine too
because there&amp;rsquo;s no need to untangle it from other work you, or
others, have been doing. This is because to &amp;ldquo;branch&amp;rdquo; you just do a
simple checkout from any other repo. When it comes to merging you
benefit from the fact that any decent distributed scm is designed to
work with syncing sweeping changes to entire code-bases not just
individual files. They all handle this a bit differently of course,
and some better than others, but the point is that while you&amp;rsquo;re
almost always going to have conflicts you&amp;rsquo;re working with tools that
&lt;em&gt;have&lt;/em&gt; to be better equipped to avoid them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Projects with reeeeally large code-bases or many many
developers:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t really speak to those because I just haven&amp;rsquo;t worked on them
but utilizing distributed scms does mean that you don&amp;rsquo;t have the
huge demands on the server hosting your scm. Plus all the
aforementioned benefits.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So what are your options? Well the main contenders appear to be
&lt;a href=&#34;http://www.darcs.net/&#34;&gt;darcs&lt;/a&gt; (written in Haskell),
&lt;a href=&#34;http://www.selenic.com/mercurial/wiki/index.cgi&#34;&gt;Mercurial&lt;/a&gt; (written in
Python), and &lt;a href=&#34;http://git.or.cz/&#34;&gt;Git&lt;/a&gt; (written in c plus hooks into a
bunch of other things I think). darcs seems to be the easiest to use,
with some decidedly funky features, but isn&amp;rsquo;t great for projects with
huge numbers of files (it can be ram intensive at times). Mercurial is
going to be used by the newly open-sourced JDK, and Git is being used to
manage the Linux kernel.&lt;/p&gt;
&lt;p&gt;* My light bulb moment, and some of the quotes here are thanks in no
small part to &lt;a href=&#34;http://blogs.sun.com/mr/entry/openjdk_scm&#34;&gt;this blog
post&lt;/a&gt; about the JDK moving to
Mercurial by Mark Reinhold. Thanks Mark.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
