( 2010-09-28 LinuxCon Japan にて、口頭ですが、Greg K-H から翻訳・公開の許可をもらいました。Thanks! )
カーネルをハックするのに、コンピュータサイエンスの博士号や下積み期間は必要ないよ。もちろんそういうことは役には立つ。でもLinux開発の重要な点は、誰にでもオープンだってことだ。とにかく取り組むことが必要。あなたは毎日何らかの形でLinuxカーネルを使ってるでしょ? どんな小さいことでもいいから、カーネル開発を少しでも手伝えば、それを誇りに思えるはずだ。
多くの貢献をしていて (そして Linux Format の読者でもある) Greg Kroah-Hartman に聞いてみた。初心者が Linux カーネルのパッチを作るにあたって気をつけることは何かって。彼が語ったことは以下のとおりだ。
(PS: 以前の記事 How the Linux kernel works は、このチュートリアルの導入によいかもしれない)
あなたのPCでカーネルが問題なく動いていて、直したいと思える点がまるで無かったらどうしよう? がっかりすることはない。Linux カーネル開発者はどんなヘルプでも必要としてるし、クリーンアップが必要なコードはソースツリーに山ほど残ってる。例えば、drivers/staging/ ツリーのコードなんてどうだろう? これは通常の Linux カーネルコーディング規約を満たしていないコードたちだ。Linux カーネルツリーのメイン部分にマージするには、誰かがコードをきれいにしなくちゃいけない。
drivers/stagingにあるドライバには、コードをカーネルツリーの適切な場所に移動する前に必要な作業が、ToDoという形でまとめられている。ほとんどのドライバの TODO ファイルにはこんな記述がある。
- fix checkpatch.pl issues
これが何で、どうすれば良いのかを見てみよう。
コードベースが大きいプロジェクトには、コーディングスタイルがなくちゃいけない。コーディングスタイルがあることでたくさんの開発者が協力できて、プロジェクトが発展することに繋がる。Linuxカーネル開発者の目標は、他の開発者にコードの問題を見つけてもらうこと、そして、全てのコードのフォーマットを揃えることで、誰もがバグを見つけたり、修正したり、バグを報告しやすくしている。カーネルコードの一行一行が少なくとも二人の開発者にレビューされ、受理される。だから、共通のコーディングスタイル規約はとても重要だ。
Linuxカーネルのコーディングスタイルは、カーネルソースツリーの Documentation/CodingStyle にまとまっている。ただし重要なことは、このスタイルで統一されているということであって、これが他のスタイルより優れているってことじゃない。開発者がコーディングスタイルの問題をすぐに見つけられるように、scripts/checkpatch.pl というスクリプトが開発された。このスクリプトは問題を簡単に見つけてくれるし、開発者は自分が変更した部分に対してこのスクリプトを走らせないといけない。そうしないと、後々レビューワがスタイルの問題を指摘する、という無駄な作業が発生してしまう。
drivers/staging/ ディレクトリにあるドライバには、大抵コーディングスタイルの問題がある。というのは、Linuxカーネルガイドラインに詳しくない人たちによって書かれたからだ。まずやらなきゃいけないのは、正しいルールに沿ってコードを直すことだ。ここでカーネルハック初心者の出番だ。checkpatch.plを走らせれば修正すべき点が山ほどでてくる。
Gitを使ってコードを操る
Git の最高のチュートリアルは Git に付いてくる。Gitをインストールして、このコマンドを入力すればチュートリアルを読むことができる:
$ man gittutorial
お気に入りのパッケージマネージャを使って Git をさくっとインストールして、Linuxカーネルのメインリポジトリをクローンしてみよう:
$ mkdir ~/linux $ cd ~/linux $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
このコマンドを入力すると、linux/ ディレクトリの中に linux-2.6 ディレクトリが作られる。ここからの作業はこの中で行うことになるので、まずはこの中に移動しよう:
$ cd ~/linux/linux-2.6
これで生のソースコードが手に入った。次はビルドとインストールだけど、これは大仕事だし、この記事の範疇を超える。ビルドとインストールについて一冊にまとまっている本がある。「Linux Kernel in a Nutshell」だ。ここで無料で読むこともできる: www.kroah.com/lkn.
Git を使って作業するときに気をつけないといけないことは、あなたの作業を Linus と同じブランチ ('master' と呼ばれている) で行わない、ということだろう。あなたはあなた自身のブランチを作って、そこで作業しなくちゃいけない。こうすることで、あなたによる変更が Linus のブランチに問題なくコミットできるようになる。'tutorial' という名前のブランチを作ってチェックアウトするにはこうすればいい:
$ git branch tutorial $ git checkout tutorial
これだけだ。これであなたのカーネルリポジトリの 'tutorial' ブランチに移動したことになる。次のコマンドで確認してみよう:
$ git branch master * tutorial
'tutorial' の前についている * が、あなたが正しいブランチにいることを表している。これでカーネルコードを変更できるよ!
もし Git について詳しく知りたければ、このチュートリアル version control with Git を読んでみて。
特殊なルール
カーネルガイドラインの共通ルールを見てみよう。スペース
みんなが守らないといけない最初のルールは、コードのインデントにスペースじゃなくてタブを使うことだ。それから、タブはスペース8個分じゃないといけない。スペース8個分のタブにした上で、一行が80文字より長くなってはいけない。(訳注: タブ1つを8文字文として数える。)この80文字制限については、数えきれないほどの開発者が文句を言っているし、最近はこの制限を破ることが許されるところもいくつかある。もし 80文字ルールに従うためだけにおかしな行分割をしなきゃいけないと感じたら、そもそもそんなことが起こらないようにロジックを見なおしてリファクタリングしたほうが良い。
80文字という制約を強制することで、ロジックが小さく、理解しやすい大きさに分割されるようになる。そうするとレビューしたりコードを追ったりするのも簡単だ。そんなわけで、80文字ルールという気違いじみた制約にもそれなりの意味はあるんだ。
ブレース
カーネルにおけるブレースの使い方のルールはちょっと厄介だ。開きカッコは、以下に示す一つの例外を除いて、それが使われるステートメントと同じ行に置かなくてはいけない。閉じカッコは元々のインデントと同じ深さに戻さなくてはいけない。次の例を見てみよう:
if (error != -ENODEV) {
foo();
bar();
}
ifステートメントにelseステートメントを追加する場合は、次の例のように、elseを閉じカッコと同じ行に置くこと:
if (error != -ENODEV) {
foo();
bar();
} else {
report_error();
goto exit;
}
ステートメントが一つでブレースが必要ない場合は、不要なブレースはつけないこと:
if (error != -ENODEV)
foo();
else
goto exit;
開きカッコに関するただ一つの例外は、関数宣言 (訳注: 正しくは「関数定義」) に関する使い方だ。この場合は開きカッコは新しい行に置かれる。次の通り:
int function(int *baz)
{
do_something(baz);
return 0;
}
checkpatch.pl
スペースとブレースについての簡単なルールが分かったところで、checkpatch.pl を適当なスクリプトに対して走らせてみて、どうなるか見てみよう:$ ./scripts/checkpatch.pl --help
Usage: checkpatch.pl [OPTION]... [FILE]...
Version: 0.30
Options:
-q, --quiet quiet
--no-tree run without a kernel tree
--no-signoff do not check for 'Signed-off-by' line
--patch treat FILE as patchfile (default)
--emacs emacs compile window format
--terse one line per report
-f, --file treat FILE as regular source file
--subjective, --strict enable more subjective tests
--root=PATH PATH to the kernel tree root
--no-summary suppress the per-file summary
--mailback only produce a report in case of warnings/errors
--summary-file include the filename in summary
--debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of 'values', 'possible', 'type',
and 'attr' (default is all off)
--test-only=WORD report only warnings/errors containing WORD literally
-h, --help, --version display this help and exit When FILE is - read standard input.
以下で使うことになる共通オプションは、--terse と --file だ。このオプションを設定すると、とても簡潔なレポートが生成してくれるし、パッチではなくて完全なファイルをチェックしてくれる。
ということで、カーネルからファイルを選んで、checkpatch.plが何を教えてくれるのか見てみよう。:
$ ./scripts/checkpatch.pl --file --terse drivers/staging/comedi/drivers/ni_labpc.c
drivers/staging/comedi/drivers/ni_labpc.c:4: WARNING: line over 80 characters
...
drivers/staging/comedi/drivers/ni_labpc.c:486: WARNING: braces {} are not necessary for single
statement blocks
...
drivers/staging/comedi/drivers/ni_labpc.c:489: WARNING: braces {} are not necessary for single
statement blocks
...
drivers/staging/comedi/drivers/ni_labpc.c:587: WARNING: suspect code indent for conditional
statements (8, 0)
...
drivers/staging/comedi/drivers/ni_labpc.c:743: WARNING: printk() should include KERN_ facility level
drivers/staging/comedi/drivers/ni_labpc.c:750: WARNING: kfree(NULL) is safe this check is probably
not required
...
drivers/staging/comedi/drivers/ni_labpc.c:2028: WARNING: EXPORT_SYMBOL(foo); should immediately follow
its function/variable
total: 0 errors, 76 warnings, 2028 lines checked
実際の出力から多くのワーニングを取り除いた結果を載せている。実際には76個ものワーニングがあったし、ほとんど同じものだからだ。
見ての通り、checkpatch.pl は、コードのどこが80文字制限をオーバーしているのか、どのブレースが不要なのか、そしてクリーンアップすべきその他のことを指摘してくれる。
どこを直せばいいのかわかったから、お気に入りのエディタを立ち上げて、早速ちょっと直してみよう。ブレースに関する警告なんてどうだろう。これを直すのは簡単なはずだ。オリジナルコードを見てみると、486 - 490 行はこんな感じだ:
if (irq) {
printk(", irq %u", irq);
}
if (dma_chan) {
printk(", dma %u", dma_chan);
}
余分なブレースを取り除くと次のようになる:
if (irq)
printk(", irq %u", irq);
if (dma_chan)
printk(", dma %u", dma_chan);
修正したファイルを保存してから、checkpatchをもう一度走らせてみて警告が消えたことを確認しよう:
$ ./scripts/checkpatch.pl --file --terse drivers/staging/comedi/drivers/ni_labpc.c | grep 486 $
もちろん、ファイルをビルドして、あなたが何も壊してないことも確認しないとだめだ:
$ make drivers/staging/comedi/drivers/ni_labpc.o CHK include/linux/version.h CHK include/generated/utsrelease.h CALL scripts/checksyscalls.sh CC [M] drivers/staging/comedi/drivers/ni_labpc.o
やった! これであなたの最初のカーネルコード修正は完了だ。でも、この変更をまとめて、カーネル開発者にわたして、そして彼らが修正を適用できるようにするにはどうすればいいんだろうか?
gitの更なる使い方
このファイルは Git リポジトリの中で編集されているので、あなたの変更を Git は追跡している。git statusを実行するとこれが確認できる:$ git status # On branch tutorial # Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: drivers/staging/comedi/drivers/ni_labpc.c # no changes added to commit (use git add and/or git commit -a).
この出力を見ると、私たちは 'tutorial' と呼ばれるブランチにいて、ni_labpc.c という一つのファイルに変更を加えたことがわかる。何を変更したのかを Git に聞けば、実際の行を確認できる:
$ git diff
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index dc3f398..a01e35d 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -483,12 +483,10 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
printk("comedi%d: ni_labpc: %s, io 0x%lx", dev->minor, thisboard->name,
iobase);
- if (irq) {
+ if (irq)
printk(", irq %u", irq);
- }
- if (dma_chan) {
+ if (dma_chan)
printk(", dma %u", dma_chan);
- }
printk("\n");
if (iobase == 0) {
この出力は、patchツールがコード本体に適用できる形に整形されている。いくつかの行の先頭にある - や + は、どの行が削除されて、どの行が追加されたのかを示している。こういう diff 形式の出力は、すぐに自然に読めるようになる。カーネルメンテナにあなたの変更を受理してもらうためには、この形式で送らないといけない。
説明、説明、そして説明
diff 形式の出力自体は、コードがどのように変更されたのかを表している。しかしカーネルパッチを受理してもらうためには、もっと多くの情報を提供しないといけない。このメタデータは、コードの変更と同じくらい重要だ。誰がこの変更を行い、なぜこの変更が必要で、だれがこの変更をレビューしたかを示すからだ。
これが、数年前にLinuxカーネルツリーに受理されたサンプルだ:
USB: otg: Fix bug on remove path without transceiver
In the case where a gadget driver is removed while no transceiver was found at probe time,
a bug in otg_put_transceiver() will trigger.
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- a/drivers/usb/otg/otg.c
+++ b/drivers/usb/otg/otg.c
@@ -43,7 +43,8 @@ EXPORT_SYMBOL(otg_get_transceiver);
void otg_put_transceiver(struct otg_transceiver *x)
{
- put_device(x->dev);
+ if (x)
+ put_device(x->dev);
}
最初の一行で、これがカーネルのどの部分の変更なのか、そしてこの変更が何なのかを非常に簡潔に説明している:
USB: otg: Fix bug on remove path without tranceiver
その次に、この変更がなぜ必要なのかをしっかり説明する文章が続く:
In the case where a gadget driver is removed while no transceiver was found at probe time,
a bug in otg_put_transceiver() will trigger.
そのあとの何行かで、誰がこのパッチを作り、誰がレビューしたのかを表している:
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr> Acked-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
'Signed-off-by:' という用語は、開発者に次のことを行う権利があることを示すために使われる。まず、この変更を行うことを許可されていること、そして、Linuxカーネルソースツリーに追加するために、この変更を適切なライセンスに基づいて提供することが許可されていることだ。この合意は、Developer's Certificate of Origin (開発者によるコード由来の証明) と呼ばれていて、Linuxカーネルソースツリーに含まれる Documentation/SubmittingPatches ファイルの中に詳しく書かれている。
簡単にいうと、Developer's Certificate of Origin は次のようなことを意味している:
- 私がこの変更を行ないました。または、
- 互換性のあるライセンスに基づいて提供されている既存のコードを元にしています。または、
- (1), (2), (3) に該当する人から私に提供され、私は変更加えていません。(訳注: 「(3)に該当する人から私に提供され」というのは、実際のコード修正者からコードを受け取った人から受け取った人から・・・、というような再帰的な構造を意味しています。)
- この変更は公開します。
これはとても簡単な合意によって、この変更が法的に受理可能なことを関係者全てが知ることができる。パッチが開発者やメンテナに流されていく間に、このパッチを確認した全ての開発者が 'Signed-off-by:' を追加し、最終的にLinuxカーネルソースツリーに受理される。この仕組みによって、Linuxカーネルの一行一行について、コードを書いた開発者やコードをレビューした開発者を追跡することができる。
これで、パッチの構成がわかったので、私たちのパッチを作ることができる。まず、私たちの変更をチェックインするように Git に伝えよう:
$ git commit drivers/staging/comedi/drivers/ni_labpc.c
Git はあなたのお気に入りエディタを起動し、以下の情報を表示し、あなたの入力を要求する:
# Please enter the commit message for your changes. Lines starting with '#' will be ignored, and an
empty message aborts the commit.
# Explicit paths specified without -i nor -o; assuming --only paths...
# On branch tutorial
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: drivers/staging/comedi/drivers/ni_labpc.c
パッチの概要を一行で記述しよう:
Staging: comedi: fix brace coding style issue in ni_labpc.c
次に、より詳細な説明を追加する:
This is a patch to the ni_labpc.c file that fixes up a brace warning found by the checkpatch.pl tool
そしてあなたの 'Signed-off-by:' 行を追加する:
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
このファイルを保存したら、Git が commit を行い、次の内容を表示する:
[tutorial 60de825] Staging: comedi: fix brace coding style issue in ni_labpc.c 1 files changed, 2 insertions(+), 4 deletions(-)
git show HEAD コマンドを使えば、直前の変更を確認することができる。今回は、あなたのコミット内容を全て表示してくれる:
$ git show HEAD
commit 60de825964d99dee56108ce4c985a7cfc984e402
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date: Sat Jan 9 12:07:40 2010 -0800
Staging: comedi: fix brace coding style issue in ni_labpc.c
This is a patch to the ni_labpc.c file that fixes up a brace warning found by the checkpatch.pl tool
Signed-off-by: My Name <my_name@my_email_domain>
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index dc3f398..a01e35d 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -483,12 +483,10 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
printk("comedi%d: ni_labpc: %s, io 0x%lx", dev->minor, thisboard->name,
iobase);
- if (irq) {
+ if (irq)
printk(", irq %u", irq);
- }
- if (dma_chan) {
+ if (dma_chan)
printk(", dma %u", dma_chan);
- }
printk("\n");
if (iobase == 0) {
初めてのカーネルパッチ作成はこれで完了だ!
あなたの変更をカーネルツリーに取り込む
さて、パッチはできたが、カーネルツリーにはどうやって取り込めばいい? Linux カーネル開発は、いまだに主にメールベースで行われれている。パッチ提供もレビューもメールだ。まず最初に、私たちのパッチを受理する担当のメンテナに送付できるように、パッチをエクスポートしよう。このために、またもや Git のコマンド format-patch を使うことができる:
$ git format-patch master..tutorial 0001-Staging-comedi-fix-brace-coding-style-issue-in-ni_la.patch
このコマンドを使うと、'master' ブランチ (というのは Linus のブランチのことだ。最初の方で説明したけど覚えてる?) と私たちの専用ブランチ 'tutorial' とのあいだの全ての差分のパッチを作ることができる。
今回の変更は、私たちのパッチひとつだけだ。それが 0001-Staging-comedi-fix-brace-coding-style-issue-in-ni_la.patch というファイル名で、そのまま送れるフォーマットで保存される。
このパッチを送る前に、パッチが正しいフォーマットになっていて、コーディングスタイルの問題を修正しただけで、カーネルツリーにエラーを追加していないことを確認するべきだ。ここでも checkpatch.pl をもう一度使うことができる:
$ ./scripts/checkpatch.pl 0001-Staging-comedi-fix-brace-coding-style-issue-in-ni_la.patch
total: 0 errors, 0 warnings, 14 lines checked
0001-Staging-comedi-fix-brace-coding-style-issue-in-ni_la.patch has no obvious style problems and is
ready for submission.
すべて順調...だけど
でも誰に送ればいいんだろう? カーネル開発者たちは、この作業が簡単になるように、ここでもちょっとしたスクリプトを用意していて、あなたがこの変更を誰に知らせるべきかを教えてくれる。get_mainteiner.pl と呼ばれるこのスクリプトは、カーネルソースツリーの scripts/ ディレクトリに含まれている。これはあなたが変更したファイルをチェックして、カーネルソースツリーの MAINTAINERS ファイル (誰がどの部分を管理しているかをまとめたファイル) と照合してくれし、変更されたファイルの変更履歴もチェックしてくれる。こういった情報から、この変更を知らせるべき人たちのリストを魔法のように生成し、メールアドレスまで準備してくれる。
よし、あとはお気に入りのメールクライアントを起動して、get_maintainer.pl が教えてくれた人たちにパッチを送るだけ、だよね? ちょっとまった! よく使われている多くのメールクライアントはパッチファイルをぐちゃぐちゃにしちゃうんだ。改行すべきじゃないところで改行してくれたり、タブをスペースに変換してくれたり、除去すべきじゃないスペースを除去してくれたり、と、できる限りぐちゃぐちゃにしてしまう。
こういったよくある問題と、メールクライアントの適切な設定方法については、カーネルソースツリーの Documentation/email-clients.txt を見てみて。普段使ってるメールクライアントを使ってパッチを送りたいなら、このドキュメントが役立つかもしれない。でも他のやり方もあるんだ・・・。
Git には、git format-patch で作ったパッチを必要な開発者にメールで送る機能もある。git send-email コマンドがそれだ:
$ git send-email --to gregkh@suse.de --to wfp5p@virginia.edu \ --cc devel@driverdev.osuosl.org \ --cc linux-kernel@vger.kernel.org \ 0001-Staging-comedi-fix-brace-coding-style-issue-in-ni_la.patch
・・・とすることで、私たちが作ったパッチを適切な開発者に送り、適切なメーリングリストに CC してくれる。
さて次は?
ようやくパッチを作って送ることができた。今度は、あなたのパッチを受け取った開発者が数日中にメールで返事をくれるだろう。それは「ありがとう。パッチあてたよ。」という素敵な内容かもしれないし、もしかしたら、そのパッチを受理するにはもう少しこういう変更が必要だよ、というコメントかもしれない。一週間たっても返事がなければ、もう一回送ってみよう。ウザがられてるかも、なんて心配はいらない。忙しいカーネルサブシステムメンテナの注意をひくには、粘り強くやることが重要なんだ。
というわけで、Linux カーネルパッチの作成、コミット、そして送付をざっと見てきた。この記事を読んだ人が、カーネルパッチを送ってくれることを願ってるよ。パッチを作ることが楽しくなったら、ぜひコンピュータ史上最大のソフトウェアプロジェクトに貢献しつづけてね。
補記
Greg がこの記事を書いたあと、私たちは、このパッチ手続きに関するたくさんの質問を Linux Format 読者からもらいました。下の二つは特によくきかれるので、みなさんがトラブらないようにここで答えます:
こういう小さいパッチを大量に送ると、カーネル開発者は逆に困るんじゃないの?
そんなことは全然ありません。確かに彼らは大きなプロジェクトで忙しいんですが、それはつまり、彼らにとってそんなに興味のない修正をあなたがやってくれることが重要だということなんです。こういった小さいちょっとしたことを解決することで、Linux カーネルがそのドライバを使えるようになりますし、あなたがどう思うとそれは素晴らしいことです。Greg はこうも言ってます。「大きなパッチを 1 個送ってもいいし、10個のパッチを送ってもいい。どっちでもいいと思う。でも、10 個のパッチを送るってことは、あなたの名前が changelog にたくさん載るってことだからね!」
80文字を超える行があるんですが、ここに改行を入れるのはおかしいと思うんです。どうしたらいいでしょう? (その他スタイルに関する質問)
Linux カーネルメーリングリストにメールしましょう。彼らはいい人たちだし誠実だから、あなたの質問に答えてくれると思いますよ。そしてメーリングリストで回答を得るというのが重要なんです。公開メーリングリストからはみんなが学ぶことができます。世界中に公開される形でメールを送るのが嫌なら、Greg に直接送ることもできますよ。
更新: さらにいくつかのコツ...
カーネルコントリビュータの Dan Carpenter が次のようなアドバイスをくれました:
- 開発者に送る前に、まず自分にメールを送ってみるというのは良い方法です。多くのメールは少し文字化けしてるです。メールを生テキストの状態で保存して、自分でパッチを適用してみてください:
cd /patch/to/kernel/src/ cat email.file | patch -p1
- 文字列リテラルを 2 行以上に分割しないこと。カーネルのエラーメッセージを見つけると、ユーザーはその文字列でカーネルソース全体を grep しようとします。文字列リテラルを分割してしまうと、こういったユーザーが困ります。
- 重要なクリーンアップでなければ、drivers/staging以外は触らないほうがいいだろう。開発者はバグを見つけると、"git blame" を使って、誰がなぜ変更したのかを調べる。空白の修正をしてしまうと、「XYZというハードウェアをサポートした」というコメントの代わりに「スペースをタブに変更した」と表示されてしまう。(訳注:だから変更履歴を調べるのが少し難しくなる)でも deivers/staging/ のコードはそもそもクソなので、だれも "git blame" を気にしてない。 (訳注: 2012-02-15 に翻訳を追加)
- LKML は Greg が言うほど良い奴らじゃないよ。kernel-janitors@vger.kernel.org はもっと初心者に優しいね。
0 件のコメント:
コメントを投稿