Gitでコメントを無視して差分を見る

古いRubyのコードのコメントを独自のRDoc形式からYARD形式に変換して、さらにその後にプログラムを変更したんですが、その後に差分を見ると大量のコメントの差分が表示されて、実際のコードの差分が何かわからなくなったりしたので、コメントを無視して差分を取る方法を調べてみました。

普通にgit diffするとこんな感じ:

diff --git a/hoge.rb b/hoge.rb
index 8fa6659..0561977 100644
--- a/hoge.rb
+++ b/hoge.rb
@@ -1,8 +1,8 @@
-# == ほげクラス
+# ほげクラス
 class Hoge
-  # === ほげ
-  # +str+ 何か
+  # ほげ
+  # @param str [String] 何か
   def hoge(str)
-    123
+    456
   end
 end

プログラムとしての変更部分は1行だけなのですが、コメントの差分がたくさん出てきて見にくいです。 Git の attribute を使ってコメントの変更を無視するようにしてみます。参考: Git のカスタマイズ - Git の属性

まず引数で指定されたファイルのコメント行を削除して出力するコマンドを作成します:

#!/bin/sh
sed -e '/^ *#/d' "$@"

git config で上のコマンドを登録:

git config diff.ignore-comment.textconv /tmp/delete-comment

.gitattributes ファイルにファイル名パターンと差分にignore-commentを使用するように登録:

*.rb diff=ignore-comment

以上を設定した状態で差分を取ってみます:

diff --git a/hoge.rb b/hoge.rb
index 8fa6659..0561977 100644
--- a/hoge.rb
+++ b/hoge.rb
@@ -1,5 +1,5 @@
 class Hoge
   def hoge(str)
-    123
+    456
   end
 end

コメント行の差分が無視されました。パチパチ。🎉

一時的に確認するためだけに設定しただけなので、確認したら .gitattributes を元に戻しておきます。

もっといい方法があるかもしれませんが、一応目的は達成できたので良しということで。

Git に対する Subversion の利点

気がついたら Git を初めて触ってからもう5年近くになってました。

それまで使ってた Subversion はもう全然使ってなくて、もう svn のサブコマンドは ls, log, co くらいしか使えません。Subversion のリポジトリを見ないといけないときは、とりあえず git svn で Git リポジトリに変換してから見たりしてます。 SCCS, RCS, CVS はもう全然わからないので、Subversion はまだ覚えてる方ですけど…。

Subversion に対する Git の利点はあちこちで述べられているので今更何も書くことはありませんが、Git よりも Subversion の方が良いこともあるので、忘れないうちに書いときます。

リポジトリ全体をコピーしなくても編集できる

リポジトリの歴史が長い場合や、頻繁に更新されるバイナリデータがあるとリポジトリが大きくなります。それは Subversion でも同様なのですが、Subversion はリポジトリ全体をローカルにコピーする必要はないので、ローカル用のディスクは作業ディレクトリ分だけで良いです。

Git は編集するためにはリポジトリ全体をコピーする必要があるので、ローカルディスクもそれだけ必要となります。git clone --depth で最新n件分のコミットだけ clone することができますが、そのようにして得られたリポジトリから元のリポジトリに対して push することはできません。

…と思っていたのですが、どうやらバージョン 1.9 からできるようになったようです。

コミットに認証が必要

Git はローカルにリポジトリがあるので、リポジトリに対して何でもできます。リモートリポジトリにプッシュ権があれば、人の名前を騙ったコミットをプッシュすることもできます。

Subversion サーバーを立てる場合は、普通はコミット時に認証を必要とするように設定するので、他人を騙ってコミットすることはできません。

[追記] Git でコミットに署名をつけることができるようです。

リポジトリ内のファイルを HTTP で簡単に得られる

Apache で Subversion サーバーを立ててる場合、専用プログラムを使わなくても、ブラウザだけですべてのブランチとタグのファイルを HTTP で取得できます。 最新のリビジョンだけで、古いリビジョンのファイルは見えませんが…。

[追記] URLのパラメータでリビジョンの指定もできるようです。

WebDAV でファイル共有できる

これも Apache でサーバーを立ててる場合ですが、Subversion 用プログラムを使わなくても、WebDAV でファイル共有できます。 Windows を使っている場合はエクスプローラーを使ってアクセスすることができます。 コミットメッセージは書けませんが、非エンジニアの人に共有ディスクと同じ感覚でファイルを置いてもらうだけでバージョン管理できるのはお手軽です。

Subversion実践入門:達人プログラマに学ぶバージョン管理(第2版)

Subversion実践入門:達人プログラマに学ぶバージョン管理(第2版)

実用 Subversion 第2版

実用 Subversion 第2版

  • 作者: C. Michael Pilato,Ben Collins-Sussman,Brian W. Fitzpatrick,宮本久仁男(監訳),朝枝雅子,浜本階生
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2009/07/27
  • メディア: 大型本
  • 購入: 6人 クリック: 45回
  • この商品を含むブログ (19件) を見る

Gitで最初のコミットをどうにかする

最初のコミットの内容を変更したい

Gitで最初のコミットの内容を変更したいと思って git rebase -i <最初のコミット> とやっても、最初のコミットは出てきません。

% git log --oneline
4f4f42c 二番目のコミット
9d4876c 最初のコミット

% git rebase -i 9d4876c
pick 4f4f42c 二番目のコミット

このような場合は git rebase -i --root を指定すると良いようです。

% git rebase -i --root
pick 9d4876c 最初のコミット
pick 4f4f42c 二番目のコミット

最初のコミットの前に別のコミットを入れたい

さっきと同様に git rebase -i --root で開いて、最初のコミットを edit にします。

% git rebase -i --root
edit 9d4876c 最初のコミット
pick 4f4f42c 二番目のコミット

ここで何か変更して、git commitgit rebase --continue すると、最初のコミットの次に入ります。

% git log --oneline
94d6512 二番目のコミット
1b424b1 何か変更
14ad5e8 最初のコミット

そしてもう一度 git rebase -i --root で、コミットの順番を並び替えると、最初のコミットの前に移動できます。

% git log --oneline
c6e0a13 二番目のコミット
71e774a 最初のコミット
828ea78 なにか

または親を持たないブランチを作成して、それに rebase するという方法もあります。

% git checkout --orphan hoge            # 親を持たないブランチ
% git reset                             # ファイルが stage 状態になってるので reset
% git commit --allow-empty -m 'なにか'  # 空コミット
% git clean -fdx                        # master にあるファイルが残っているのでクリア
% git checkout master
% git rebase hoge                       # master を hoge から派生するように rebase
% git log --oneline
5cc41ab 二番目のコミット
b87ca1f 最初のコミット
0544410 なにか

ほかにもいい方法があるかもしれません。

Gitでリモートリポジトリを巻き戻す

Gitで間違ったコミットをリモートリポジトリに push してしまった後に、それを無かったことにするには、リモート側での作業が必要だと思っていたのですが、ローカルからの操作でもできることがわかったので備忘録的に書いておきます。

次の状態にあるとします。アルファベットはコミットだと思ってください。

リモート: A-B-C       master
ローカル: A-B-C-D     master

ローカルで変更を加えてDの状態になっています。

git push すると次のようになるのですが、

リモート: A-B-C-D     master
ローカル: A-B-C-D     master

ここで、D は間違いだったと気づきました。

リモートリポジトリの master のバックアップ用のブランチを作ります。これは必須ではありませんが、念のため。

% git push origin master:master_bak

これで次の状態になります。

リモート: A-B-C-D     master
          A-B-C-D     master_bak
ローカル: A-B-C-D     master

リモートの master ブランチを削除します。

% git push origin :master
リモート: A-B-C-D     master_bak
ローカル: A-B-C-D     master

ローカルを一つ戻します。

% git reset HEAD^
リモート: A-B-C-D     master_bak
ローカル: A-B-C       master

リモートに push します。

% git push origin master
リモート: A-B-C       master
          A-B-C-D     master_bak
ローカル: A-B-C       master

すべてが順調にいって master_bak が要らなくなったら削除します。

% git push origin :master_bak
リモート: A-B-C       master
ローカル: A-B-C       master

最後のコミットを消す前にリモートリポジトリが誰かに pull されてたりしたら、その人が混乱するので一声かけるか、素直にあきらめましょう。

なんかもっと簡単にできるような気もするのですけどわかりませんでした。もっと良い方法を知っている人がいたら教えてください。

追記

コメントで id:akitsukada さんに教えてもらいました。

上記の

% git push origin :master
% git reset HEAD^
% git push origin master 

の手順は

% git push -f origin HEAD^:master

…と簡単にできるみたいです。

この場合はローカルのコミット状態は変わらないので、必要に応じて git reset などをやりましょう。

Git勉強会

NSEG Git勉強会 #3 を開催しました。動画

今回は二人の方に発表してもらいました。

MagitでGit/本杉圭吾 さん

Emacs 上で Git を使うツール Magit についての説明でした。

私も最近使うようになったのですが Emacs から Git のほとんどの機能が使えてとても便利です。

自分が理解するためにマニュアルも翻訳してみました。 http://redmine.tmtms.net/projects/misc/repository/revisions/master/entry/magit.md

Gitorious を Ubuntu 10.04 LTS にインストールしてみんなで幸せになろうよ/佐藤潔 さん

スライド

github クローンの gitorious のインストールの苦労話でした。

なかなか一筋縄ではいかなそうですが、github みたいに利用者の操作で簡単にリポジトリを作れるようになるとリポジトリ管理者の手間が省けて良いですね。簡単に導入できるようになって欲しいです。

その他

発表後、1時間ほど Git について参加者で色々話しました。

  • git gui
  • gitk は Tk のバージョンをあげるとフォントが綺麗になる
  • github のサービスの gist の話
  • github は Web でファイルの編集ができる
  • ブランチとかマージとか
  • Emacs の vc-annotate
  • git bisect の話
  • Subversion と違って Git は共有リポジトリ内のコミットメッセージを簡単に変更しちゃいけない

次回

もしかしたら来年に第4回やるかもしれません。やらないかもしれません。

NSEG Git勉強会

NSEG平日夜の部勉強会でGitの勉強会の2回目やりました。

動画はこちら

私の他に id:stealthinu さんにも発表していただきました。
http://www.slideshare.net/stealthinu/tortoise-gitgit

前回やった時は2回目やるとは思ってなかったんですけど、自分の理解のために資料にまとめたので、やってみました。

なので次回があるかどうかもやっぱり未定です。
もし次にやるんだったらハンズオン形式もいいんじゃないかと思ってたりしてます。