Git 2.13.0が公開されましたね。GitHubが最近つぶやいた記事を、本当にサクッと翻訳してみたので、編集リクエストをよろしくお願いします。
「は」と「が」とか、不自然に感じてしまったら申し訳ないですが、もしGitについての新しい情報が伝わればと思います。
Git 2.13.0は公開されました
オープンソースであるGitプロジェクトはGit 2.13.0を公開し、65人以上が機能を追加したりバグを直したりしました。その機能をもっと詳しく説明する前に、セキュリティに関する短い報告があります。
自分のGitホスティング・サーバーを使用していれば、git shell
プログラムでは、信用できないGitのユーザがリモートホストでシェルコマンドを実行できてしまうという脆弱性をGit 2.13が直してくれます。これはホスティング・サーバーを使用し、特にgit shell
を設定した場合のみです。「よう意味が分からん」人には気にしなくていいはずです。一応、詳細はこちらです。Github.comもGitHub Enterpriseもgit shell
を使用していないので、影響を受けません。
ハァ...報告が終わったということで、楽しい部分を紹介しましょう!
SHA-1衝突判定
あっ、楽しいって言ったっけ?ごめん、それはまだでして...
聞いたことがあるかもしれませんが、最近はある研究者たちがSHA-1(Gitが使っているオブジェクトを認識するためのハッシュ機能)の初めての衝突を発見しました。このテクニックを使用し、Gitのユーザに対する衝突攻撃が行われたことでしょう。運よく、その同じ研究者たちがこのテクニックを駆使して攻撃しようとしている内容を検出できる方法を提供してくれました。3月に、GitHub.comはそういう衝突攻撃を防ぐために、その方法を使いはじめました。
Git 2.13にも同じような変更があり、衝突攻撃の恐れのあるオブジェクトを検出し拒否します。衝撃を判定するSHA-1はもうデフォルトとなっています。そのコードはGitに入っていますので、他のプログラムをインストールする必要はありません。この実装は他の方法と比較的に遅いですが、大体のGitの運用においては、全体的にわずかな影響しか受けません(なぜかというと、GitはSHA-1のハッシュを計算する時間はそもそも短いからです)。
他の衝突判定ニュースなんですが、Gitでより強力なハッシュアルゴリズムが使えるように、ハッシュの新しい関数を扱うコードベースの遷移の準備の計画がなお進んでいます。
より便利なpathspec
Gitでこうやってパスの引数を渡したことがあるかもしれません:
$ git log foo.c
$ git grep my_pattern program.rb
でも、Gitにとってはfoo.c
とprogram.rb
という引数の正体はpathspecs、パスのマッチを行う、特にGitのパターンであることを知っていましたか?絶対パスでも、接頭詞でもワイルドカードでもPathspecsとして使えます:
$ git log Documentation/ # Documentation/ ディレクトリの下にある全てのもの
$ git log '*.c' # ツリーの中にある全てのCのファイル
まして、強力な拡張シンタクスがあります。:(magic)
で始まるpathspecsは特別のマッチ機能を有効にします。それらのリストがgit help glossaryのpathspecのところに記載してありますが、ここでその中の何個かを見ていきましょう。
例えば、grepでファイルを除外したいという時は、:(exclude)
を使います:
$ git grep this.is.a src
src/foo.c:this is a C file
src/foo.rb:this is a ruby file
$ git grep this.is.a -- src ':(exclude)*.c'
src/foo.rb:this is a ruby file
この例ではいくつかの気づくべきことがあります。1つ目は、分離するために --
(ダブル・ダッシュ)をpathspecの後に置く必要がありました。多くのGitのコマンドは改訂(revisions)とpathspecの組み合わせを引数として受けるからです。完全なシンタクスはこうです:[<revisions>] - [<pathspecs>]
。ダブル・ダッシュが抜いていると、Gitは全ての引数が、ファイルシステムの中にある有効なオブジェクト名かファイルかをチェックします。でも、このexcludeのバターンはどちらでもないです。そのために、ダブル・ダッシュがないとGitは諦めて文句ばかりを言う(将来のGitのバージョンではこれが変わる可能性があります。*.c
みたいなワイルドカードもこのような問題があったけど、そのワイルドカードをpathspecとして扱うためにルールが緩くされました)。詳細はgit help cli
(リンク)で確認できます。
気づくべき2つ目のことは、:(exclude)
を書くのが面倒ですし、シェルでクオートに囲む必要があります。でも、解決方法があります:pathspecの短文式魔法。exclude
の短文式は!
(ビックリマーク)です。.gitignore
のファイルみたいにGitの他の部分と似ているから覚えやすいです。
$ git grep this.is.a --src ':!*.c'
src/foo.rb:this is a ruby file
これはexclude
より短いですけど、多くのシェルではビックリマークが履歴拡張を発生させますから、シングルクオートを書く必要はまだ残ってます。Git 2.13では^
(カレット)がビックリマークの類語になっていますので、クオートで囲まずに同じことができます:
$ git grep this.is.a --src :^*.c
src/foo.rb:this is a ruby file
ふゎ〜、すっきりしましたね。普段はワイルドカードの*.c
をシェルで書く時にクオートで囲む必要がありますけど、プラクティスとしては上記の方法が使えます。:^
で始まって.c
で終わるファイルがない限り、シェルはワイルドカードがどんなファイルにもマッチしないことを判定し、そのままGitに渡します。
だが、それだけではない!Git 2.13はgitattributesの値によってファイルを選択できるattr
トークンを追加しています。例えば、Git LFSを使っていたら、それを設定するファイルのリストを表示したい時:
$ git ls-files
.gitattributes
README
video.mp4
$ git ls-files ':(attr:filter=lfs)'
video.mp4
というのができます。
ファイルを1つのグループにまとめるためにattributeを定義することもできます。attributeを定義し、そのattributeでファイルを選択できます:
$ echo 'libfoo/ vendored' >>.gitattributes
$ echo 'imported-tool/ vendored' >>.gitattributes
$ git grep -i license -- ':(attr:vendored)'
実はattr
とexclude
のトークンを組み合わせられます:
$ git grep foobar -- ':(exclude,attr:vendored)'
トークンであるattr
はまだ全てのコードにおいてサポートされていないことに注意してください。いくつかのコマンドは「attr
が使えない」と報告しますけど、これは将来のGitのバージョンで拡張される見込みです。
[negative pathspecs, attribute pathspecs]
条件付きの設定
Gitの設定システムは優先する階層があります:システムの段階、ユーザの段階、レポジトリの段階、それとも個人的なコマンド呼び出し(git -c
を使う(リンク))オプションを設定できます。一般的に、より厳密な場所で見つかったオプションは比較的に厳密でないオプションをオーバーライドします。レポジトリの.git/config
にuser.email
を設定したら、ユーザの段階で設定された~/.gitconfig
をオーバーライドするかもしれません。
でも、レポジトリの集まりに対して1つのオプションを設定し、また別の集まりに対して別のオプションを設定する必要がある場合はないですか?例えば、普通の仕事で自分の名前とメールを使ってコミットするけど、オープンソースでは別の名前とメールを使う場合。ホームディレクトリにあるconfigではオープンソースの資格をユーザの段階ので設定してから、仕事のレポジトリでオーバーライドできます。でもそれを一々アップデートするのは面倒だし、もし新しいレポジトリの設定をするのを忘れた場合、違う資格でコミットしてしまうこのになります!
Git 2.13は条件付き設定インクルードを提供しています。今はレポジトリのファイルシステムパスの認識しかサポートされていないけど、それで充分です。ホームディレクトリの~/.gitconfig
で2つの条件付きインクルードを設定できます。
[includeIf "gitdir:~/work/"]
path = .gitconfig-work
[includeIf "gitdir:~/play/"]
path = .gitconfig-play
これで、そのファイルに適切なオプションを設定できます:
$ cat ~/.gitconfig-work
[user]
name = Serious Q. Programmer
email = serious.programmer@business.example.com
$ cat ~/.gitconfig-play
[user]
name = Random J. Hacker
email = rmsfan1979@example.com
work
かplay
のディレクトリの中にあるレポジトリでは、適切な設定のオプションが自動的に適用されます。
その他
・--decorate=auto
はgit log
のデフォルトとなりました。ユーザのターミナルに出力が送られてくる時、ブランチかタグに指定されたコミットはそのブランチの名前で修飾されます。(ソース)
・git branch
の出力ルーチンはgit for-each-ref
やgit tag
が共有しているref-filter
に移りました。ということは、カスタムな出力を実現するためにgit branch --format=
を使うことができます。代入のリストを閲覧するにはgit help for-each-ref
(リンク)を参照してください。ところで、このパッチを作ったのは、2015年にGitのGoogle Summer of Codeの学生だったKarthik Nayakさんです。2年前に、GSoCでのプロジェクトとして紹介したref-filter
はほぼ完成していた状態だったにもかかわらず、彼はまだ貢献しつづけています。Great work!(ソース)
・git branch
, git tag
, そしてgit for-each-ref
全てがもう既にあった--contains
オプションと更に、--no-contains
オプションが使えるようになりました。バグ(それともbugfix)がないタグかブランチを調べられる機能です。
・git stash
はpathspecsを受け取れるようになりました。作業のツリーの一部としてこのstashを作成できます。コミットをきれいにするために変更をいじる時には便利です。(ソース)
・@{upstream}
、@{u}
、と@{push}
という特別のブランチ名は小文字と大文字を区別しないようになりました。これの便利な点といえば、多くのキーボードでは@
と{
を入力するためにshiftを押す必要があるから、大文字のU
を入力してしまいます。このアップデートではshiftキーを押し続けまくってもいいぞ(ソース)
・過去のGitのバージョンでは、checkout
、grep
、とls-files
みたいなコマンドがサブモジュールにおいて再起を使うことができるようになっています。git status --short
もサブモジュールについて情報を報告できるようになりました。[ソース、ソース、ソース、ソース]
・最近のGitのバージョンはレポジトリの発見と初期化においてのコーナーケースを直しています。その作業の最後のステップとしては、Git 2.13は見逃されたケースをキャッチするアサーションを取り入れています。数ヶ月の間に渡って開発版でこれをテストしてきたので、出てくるはずはないです。でも、BUG: setup_git_env called without repository
は出てくるかもしれません。もし出たら、バグレポートを送るように、ご協力をよろしくお願いします。(ソース)
諸事万端
700コミット以上からなるGit 2.13で追加・変更した項目は、上記にいくつかしか書いてないです。リスト全体を閲覧するには、完全リリースノートを参照してください。