diff --git a/book/05-distributed-git/1-distributed-git.asc b/book/05-distributed-git/1-distributed-git.asc index bb2f9ded..5b27c5e2 100644 --- a/book/05-distributed-git/1-distributed-git.asc +++ b/book/05-distributed-git/1-distributed-git.asc @@ -1,11 +1,21 @@ [[_distributed_git]] +////////////////////////// == Distributed Git +////////////////////////// +== Git での分散作業 (((distributed git))) +////////////////////////// Now that you have a remote Git repository set up as a point for all the developers to share their code, and you're familiar with basic Git commands in a local workflow, you'll look at how to utilize some of the distributed workflows that Git affords you. +////////////////////////// +リモート Git リポジトリを用意し、すべての開発者がコードを共有できるようになりました。また、ローカル環境で作業をする際に使う基本的な Git コマンドについても身についたことでしょう。次に、Git を使った分散作業の流れを見ていきましょう。 +////////////////////////// In this chapter, you'll see how to work with Git in a distributed environment as a contributor and an integrator. That is, you'll learn how to contribute code successfully to a project and make it as easy on you and the project maintainer as possible, and also how to maintain a project successfully with a number of developers contributing. +////////////////////////// +本章では、Git を使った分散環境での作業の流れを説明します。 +自分のコードをプロジェクトに提供する方法、そしてプロジェクトのメンテナーと自分の両方が作業を進めやすくする方法、そして多数の開発者からの貢献を受け入れるプロジェクトを運営する方法などを扱います。 include::sections/distributed-workflows.asc[] @@ -13,8 +23,15 @@ include::sections/contributing.asc[] include::sections/maintaining.asc[] +////////////////////////// === Summary - +////////////////////////// +=== まとめ +////////////////////////// You should feel fairly comfortable contributing to a project in Git as well as maintaining your own project or integrating other users' contributions. Congratulations on being an effective Git developer! In the next chapter, you'll learn about how to use the largest and most popular Git hosting service, GitHub. +////////////////////////// +Git を使っているプロジェクトにコードを提供したり、自分のプロジェクトに他のユーザーからのコードを取り込んだりといった作業を安心してこなせるようになりましたね。 +おめでとうございます。Git を使いこなせる開発者の仲間入りです! +次の章では、世界最大で一番人気の Git ホスティングサービス、GitHub の使い方を見ていきましょう。 diff --git a/book/05-distributed-git/sections/contributing.asc b/book/05-distributed-git/sections/contributing.asc index dbd8c3e7..dfcdde9d 100644 --- a/book/05-distributed-git/sections/contributing.asc +++ b/book/05-distributed-git/sections/contributing.asc @@ -1,51 +1,107 @@ [[_contributing_project]] +////////////////////////// === Contributing to a Project +////////////////////////// +=== プロジェクトへの貢献 (((contributing))) +////////////////////////// The main difficulty with describing how to contribute to a project is that there are a huge number of variations on how it's done. Because Git is very flexible, people can and do work together in many ways, and it's problematic to describe how you should contribute – every project is a bit different. Some of the variables involved are active contributor count, chosen workflow, your commit access, and possibly the external contribution method. +////////////////////////// +どうやってプロジェクトに貢献するか、というのは非常に説明しづらい内容です。というのも、ほんとうにいろいろなパターンがあるからです。 +Git は柔軟なシステムなので、いろいろな方法で共同作業をすることができます。そのせいもあり、どのプロジェクトをとってみても微妙に他とは異なる方式を使っているのです。 +違いが出てくる原因としては、アクティブな貢献者の数やプロジェクトで使用しているワークフロー、あなたのコミット権、そして外部からの貢献を受け入れる際の方式などがあります。 +////////////////////////// The first variable is active contributor count – how many users are actively contributing code to this project, and how often? In many instances, you'll have two or three developers with a few commits a day, or possibly less for somewhat dormant projects. For larger companies or projects, the number of developers could be in the thousands, with hundreds or thousands of commits coming in each day. This is important because with more and more developers, you run into more issues with making sure your code applies cleanly or can be easily merged. Changes you submit may be rendered obsolete or severely broken by work that is merged in while you were working or while your changes were waiting to be approved or applied. How can you keep your code consistently up to date and your commits valid? - +////////////////////////// +最初の要素はアクティブな貢献者の数です。そのプロジェクトに対してアクティブにコードを提供している開発者はどれくらいいるのか、そして彼らはどれくらいの頻度で提供しているのか。 +よくあるのは、数名の開発者が一日数回のコミットを行うというものです。休眠状態のプロジェクトなら、もう少し頻度が低くなるでしょう。 +企業やプロジェクトの規模が大きくなると、開発者の数が数千人になることもあります。数百から下手したら千を超えるようなコミットが毎日やってきます。 +開発者の数が増えれば増えるほど、あなたのコードをきちんと適用したり他のコードをマージしたりするのが難しくなります。 +あなたが手元で作業をしている間に他の変更が入って、手元で変更した内容が無意味になってしまったりあるいは他の変更を壊してしまう羽目になったり。そのせいで、手元の変更を適用してもらうための待ち時間が発生したり。 +手元のコードを常に最新の状態にし、正しいコミットを作るにはどうしたらいいのでしょうか。 + +////////////////////////// The next variable is the workflow in use for the project. Is it centralized, with each developer having equal write access to the main codeline? Does the project have a maintainer or integration manager who checks all the patches? Are all the patches peer-reviewed and approved? Are you involved in that process? Is a lieutenant system in place, and do you have to submit your work to them first? - +////////////////////////// +次に考えるのは、プロジェクトが採用しているワークフローです。 +中央管理型で、すべての開発者がコードに対して同等の書き込みアクセス権を持っている状態? +特定のメンテナーや統合マネージャーがすべてのパッチをチェックしている? +パッチを適用する前にピアレビューをしている? +あなたはパッチをチェックしたりピアレビューに参加したりしている人? +若頭型のワークフローを使っており、まず彼らにコードを渡さなければならない? + +////////////////////////// The next issue is your commit access. The workflow required in order to contribute to a project is much different if you have write access to the project than if you don't. If you don't have write access, how does the project prefer to accept contributed work? Does it even have a policy? How much work are you contributing at a time? How often do you contribute? - +////////////////////////// +次の問題は、あなたのコミット権です。 +あなたがプロジェクトへの書き込みアクセス権限を持っている場合は、プロジェクトに貢献するための作業の流れが変わってきます。 +書き込み権限がない場合、そのプロジェクトではどのような形式での貢献を推奨していますか? +何かポリシーのようなものはありますか? +一度にどれくらいの作業を貢献することになりますか? +また、どれくらいの頻度で貢献することになりますか? + +////////////////////////// All these questions can affect how you contribute effectively to a project and what workflows are preferred or available to you. We'll cover aspects of each of these in a series of use cases, moving from simple to more complex; you should be able to construct the specific workflows you need in practice from these examples. +////////////////////////// +これらの点を考慮して、あなたがどんな流れでどのようにプロジェクトに貢献していくのかが決まります。 +単純なものから複雑なものまで、実際の例を見ながら考えていきましょう。これらの例を参考に、あなたなりのワークフローを見つけてください。 [[_commit_guidelines]] +////////////////////////// ==== Commit Guidelines +////////////////////////// +==== コミットの指針 +////////////////////////// Before we start looking at the specific use cases, here's a quick note about commit messages. Having a good guideline for creating commits and sticking to it makes working with Git and collaborating with others a lot easier. The Git project provides a document that lays out a number of good tips for creating commits from which to submit patches – you can read it in the Git source code in the `Documentation/SubmittingPatches` file. +////////////////////////// +個々の例を見る前に、コミットメッセージについてのちょっとした注意点をお話しておきましょう。 +コミットに関する指針をきちんと定めてそれを守るようにすると、Git での共同作業がよりうまく進むようになります。 +Git プロジェクトでは、パッチの投稿用のコミットを作成するときのヒントをまとめたドキュメントを用意しています。Git のソースの中にある `Documentation/SubmittingPatches` をごらんください。 (((git commands, diff, check))) +////////////////////////// First, you don't want to submit any whitespace errors. Git provides an easy way to check for this – before you commit, run `git diff --check`, which identifies possible whitespace errors and lists them for you. +////////////////////////// +まず、余計な空白文字を含めてしまわないように注意が必要です。 +Git には、余計な空白文字をチェックするための簡単な仕組みがあります。コミットする前に `git diff --check` を実行してみましょう。おそらく意図したものではないと思われる空白文字を探し、それを教えてくれます。 +////////////////////////// .Output of `git diff --check`. image::images/git-diff-check.png[Output of `git diff --check`.] +////////////////////////// +.`git diff --check` 実行結果 +image::images/git-diff-check.png[`git diff --check` 実行結果] +////////////////////////// If you run that command before committing, you can tell if you're about to commit whitespace issues that may annoy other developers. +////////////////////////// +コミットの前にこのコマンドを実行すれば、余計な空白文字をコミットしてしまって他の開発者に嫌がられることもなくなるでしょう。 +////////////////////////// Next, try to make each commit a logically separate changeset. If you can, try to make your changes digestible – don't code for a whole weekend on five different issues and then submit them all as one massive commit on Monday. Even if you don't commit during the weekend, use the staging area on Monday to split your work into at least one commit per issue, with a useful message per commit. @@ -53,7 +109,16 @@ If some of the changes modify the same file, try to use `git add --patch` to par The project snapshot at the tip of the branch is identical whether you do one commit or five, as long as all the changes are added at some point, so try to make things easier on your fellow developers when they have to review your changes. This approach also makes it easier to pull out or revert one of the changesets if you need to later. <<_rewriting_history>> describes a number of useful Git tricks for rewriting history and interactively staging files – use these tools to help craft a clean and understandable history before sending the work to someone else. - +////////////////////////// +次に、コミットの単位が論理的に独立した変更となるようにしましょう。 +つまり、個々の変更内容を把握しやすくするということです。週末に五つの問題点を修正した大規模な変更を、月曜日にまとめてコミットするなどということは避けましょう。 +仮に週末の間にコミットできなかったとしても、ステージングエリアを活用して月曜日にコミット内容を調整することができます。修正した問題ごとにコミットを分割し、それぞれに適切なコメントをつければいいのです。 +もし別々の問題の修正で同じファイルを変更しているのなら、`git add --patch` を使ってその一部だけをステージすることもできます (詳しくは <<_interactive_staging>> で説明します)。 +すべての変更を同時に追加しさえすれば、一度にコミットしようが五つのコミットに分割しようがブランチの先端は同じ状態になります。あとから変更内容をレビューする他のメンバーのことも考えて、できるだけレビューしやすい状態でコミットするようにしましょう。 +こうしておけば、あとからその変更の一部だけを取り消したりするのにも便利です。 +<<_rewriting_history>> では、Git を使って歴史を書き換えたり対話的にファイルをステージしたりする方法を説明します。作業内容を誰かに送る前にその方法を使えば、きれいでわかりやすい歴史を作り上げることができます。 + +////////////////////////// The last thing to keep in mind is the commit message. Getting in the habit of creating quality commit messages makes using and collaborating with Git a lot easier. As a general rule, your messages should start with a single line that's no more than about 50 characters and that describes the changeset concisely, followed by a blank line, followed by a more detailed explanation. @@ -62,8 +127,17 @@ It's also a good idea to use the imperative present tense in these messages. In other words, use commands. Instead of ``I added tests for'' or ``Adding tests for,'' use ``Add tests for.'' Here is a template originally written by Tim Pope: +////////////////////////// +最後に注意しておきたいのが、コミットメッセージです。 +よりよいコミットメッセージを書く習慣を身に着けておくと、Git を使った共同作業をより簡単に行えるようになります。 +一般的な規則として、メッセージの最初には変更の概要を一行 (50 文字以内) にまとめた説明をつけるようにします。その後に空行をひとつ置いてからより詳しい説明を続けます。 +Git プロジェクトでは、その変更の動機やこれまでの実装との違いなどのできるだけ詳しい説明をつけることを推奨しています。参考にするとよいでしょう。 +また、メッセージでは命令形、現在形を使うようにしています。 +つまり ``私は○○のテストを追加しました (I added tests for)'' とか ``○○のテストを追加します (Adding tests for,)'' ではなく ``○○のテストを追加 (Add tests for.)'' 形式にするということです。 +Tim Pope が書いたテンプレート (の日本語訳) を以下に示します。 [source,text] +////////////////////////// ----- Short (50 chars or less) summary of changes @@ -83,28 +157,69 @@ Further paragraphs come after blank lines. preceded by a single space, with blank lines in between, but conventions vary here ----- +////////////////////////// +----- +短い (50 文字以下での) 変更内容のまとめ + +必要に応じた、より詳細な説明。72文字程度で折り返します。最初の +行がメールの件名、残りの部分がメールの本文だと考えてもよいでしょ +う。最初の行と詳細な説明の間には、必ず空行を入れなければなりま +せん (詳細説明がまったくない場合は空行は不要です)。空行がないと、 +rebase などがうまく動作しません。 +空行を置いて、さらに段落を続けることもできます。 + + - 箇条書きも可能 + + - 箇条書きの記号としては、主にハイフンやアスタリスクを使います。 + 箇条書き記号の前にはひとつ空白を入れ、各項目の間には空行を入 + れます。しかし、これ以外の流儀もいろいろあります。 +----- + +////////////////////////// If all your commit messages look like this, things will be a lot easier for you and the developers you work with. The Git project has well-formatted commit messages – try running `git log --no-merges` there to see what a nicely formatted project-commit history looks like. +////////////////////////// +すべてのコミットメッセージがこのようになっていれば、他の開発者との作業が非常に進めやすくなるでしょう。 +Git プロジェクトでは、このようにきれいに整形されたコミットメッセージを使っています。`git log --no-merges` を実行すれば、きれいに整形されたプロジェクトの歴史がどのように見えるかがわかります。 +////////////////////////// In the following examples, and throughout most of this book, for the sake of brevity this book doesn't have nicely-formatted messages like this; instead, we use the `-m` option to `git commit`. Do as we say, not as we do. +////////////////////////// +これ以降の例を含めて本書では、説明を簡潔にするためにこのような整形を省略します。そのかわりに `git commit` の `-m` オプションを使います。 +本書でのこのやり方をまねするのではなく、ここで説明した方式を使いましょう。 [[_private_team]] +////////////////////////// ==== Private Small Team +////////////////////////// +==== 非公開な小規模のチーム (((contributing, private small team))) +////////////////////////// The simplest setup you're likely to encounter is a private project with one or two other developers. ``Private,'' in this context, means closed-source – not accessible to the outside world. You and the other developers all have push access to the repository. +////////////////////////// +実際に遭遇するであろう環境のうち最も小規模なのは、非公開のプロジェクトで開発者が数名といったものです。 +ここでいう「非公開」とは、クローズドソースであるということ。つまり、チームのメンバー以外は見られないということです。 +チーム内のメンバーは全員、リポジトリへのプッシュ権限を持っています。 +////////////////////////// In this environment, you can follow a workflow similar to what you might do when using Subversion or another centralized system. You still get the advantages of things like offline committing and vastly simpler branching and merging, but the workflow can be very similar; the main difference is that merges happen client-side rather than on the server at commit time. Let's see what it might look like when two developers start to work together with a shared repository. The first developer, John, clones the repository, makes a change, and commits locally. (The protocol messages have been replaced with `...` in these examples to shorten them somewhat.) +////////////////////////// +こういった環境では、今まで Subversion やその他の中央管理型システムを使っていたときとほぼ同じワークフローで作業を進めることができます。 +オフラインでコミットできたりブランチやマージが楽だったりといった Git ならではの利点はいかせますが、作業の流れ自体は今までとほぼ同じです。最大の違いは、マージが (コミット時にサーバー側で行われるのではなく) クライアント側で行われるということです。 +二人の開発者が共有リポジトリで開発を始めるときにどうなるかを見ていきましょう。 +最初の開発者 John が、リポジトリをクローンして変更を加え、それをローカルでコミットします (これ以降のメッセージでは、プロトコル関連のメッセージを `...` で省略しています)。 [source,console] +////////////////////////// ----- # John's Machine $ git clone john@githost:simplegit.git @@ -116,10 +231,26 @@ $ git commit -am 'removed invalid default value' [master 738ee87] removed invalid default value 1 files changed, 1 insertions(+), 1 deletions(-) ----- +////////////////////////// +----- +# John のマシン +$ git clone john@githost:simplegit.git +Initialized empty Git repository in /home/john/simplegit/.git/ +... +$ cd simplegit/ +$ vim lib/simplegit.rb +$ git commit -am 'removed invalid default value' +[master 738ee87] removed invalid default value + 1 files changed, 1 insertions(+), 1 deletions(-) +----- +////////////////////////// The second developer, Jessica, does the same thing – clones the repository and commits a change: +////////////////////////// +もう一人の開発者 Jessica も同様に、リポジトリをクローンして変更をコミットしました。 [source,console] +////////////////////////// ----- # Jessica's Machine $ git clone jessica@githost:simplegit.git @@ -131,10 +262,26 @@ $ git commit -am 'add reset task' [master fbff5bc] add reset task 1 files changed, 1 insertions(+), 0 deletions(-) ----- +////////////////////////// +----- +# Jessica のマシン +$ git clone jessica@githost:simplegit.git +Initialized empty Git repository in /home/jessica/simplegit/.git/ +... +$ cd simplegit/ +$ vim TODO +$ git commit -am 'add reset task' +[master fbff5bc] add reset task + 1 files changed, 1 insertions(+), 0 deletions(-) +----- +////////////////////////// Now, Jessica pushes her work up to the server: +////////////////////////// +Jessica が作業内容をサーバーにプッシュします。 [source,console] +////////////////////////// ----- # Jessica's Machine $ git push origin master @@ -142,10 +289,22 @@ $ git push origin master To jessica@githost:simplegit.git 1edee6b..fbff5bc master -> master ----- +////////////////////////// +----- +# Jessica のマシン +$ git push origin master +... +To jessica@githost:simplegit.git + 1edee6b..fbff5bc master -> master +----- +////////////////////////// John tries to push his change up, too: +////////////////////////// +John も同様にプッシュしようとしました。 [source,console] +////////////////////////// ----- # John's Machine $ git push origin master @@ -153,11 +312,25 @@ To john@githost:simplegit.git ! [rejected] master -> master (non-fast forward) error: failed to push some refs to 'john@githost:simplegit.git' ----- +////////////////////////// +----- +# John のマシン +$ git push origin master +To john@githost:simplegit.git + ! [rejected] master -> master (non-fast forward) +error: failed to push some refs to 'john@githost:simplegit.git' +----- +////////////////////////// John isn't allowed to push because Jessica has pushed in the meantime. This is especially important to understand if you're used to Subversion, because you'll notice that the two developers didn't edit the same file. Although Subversion automatically does such a merge on the server if different files are edited, in Git you must merge the commits locally. John has to fetch Jessica's changes and merge them in before he will be allowed to push: +////////////////////////// +John はプッシュできませんでした。Jessica が先にプッシュを済ませていたからです。 +Subversion になじみのある人には特に注目してほしいのですが、ここで John と Jessica が編集していたのは別々のファイルです。 +Subversion ならこのような場合はサーバー側で自動的にマージを行いますが、Git の場合はローカルでマージしなければなりません。 +John は、まず Jessica の変更内容を取得してマージしてからでないと、自分の変更をプッシュできないのです。 [source,console] ----- @@ -167,12 +340,22 @@ From john@githost:simplegit + 049d078...fbff5bc master -> origin/master ----- +////////////////////////// At this point, John's local repository looks something like this: +////////////////////////// +この時点で、John のローカルリポジトリはこのようになっています。 +////////////////////////// .John's divergent history. image::images/small-team-1.png[John's divergent history.] +////////////////////////// +.John の分岐した歴史 +image::images/small-team-1.png[John の分岐した歴史] +////////////////////////// John has a reference to the changes Jessica pushed up, but he has to merge them into his own work before he is allowed to push: +////////////////////////// +John の手元に Jessica がプッシュした内容が届きましたが、さらにそれを彼自身の作業にマージしてからでないとプッシュできません。 [source,console] ----- @@ -182,12 +365,22 @@ Merge made by recursive. 1 files changed, 1 insertions(+), 0 deletions(-) ----- +////////////////////////// The merge goes smoothly – John's commit history now looks like this: +////////////////////////// +マージがうまくいきました。John のコミット履歴は次のようになります。 +////////////////////////// .John's repository after merging `origin/master`. image::images/small-team-2.png[John's repository after merging `origin/master`.] +////////////////////////// +.`origin/master` をマージしたあとの John のリポジトリ +image::images/small-team-2.png[`origin/master` をマージしたあとの John のリポジトリ] +////////////////////////// Now, John can test his code to make sure it still works properly, and then he can push his new merged work up to the server: +////////////////////////// +自分のコードが正しく動作することを確認した John は、変更内容をサーバーにプッシュします。 [source,console] ----- @@ -197,21 +390,41 @@ To john@githost:simplegit.git fbff5bc..72bbc59 master -> master ----- +////////////////////////// Finally, John's commit history looks like this: +////////////////////////// +最終的に、John のコミット履歴は以下のようになりました。 +////////////////////////// .John's history after pushing to the `origin` server. image::images/small-team-3.png[John's history after pushing to the `origin` server.] +////////////////////////// +.origin サーバーにプッシュした後の John の履歴 +image::images/small-team-3.png[origin サーバーにプッシュした後の John の履歴] +////////////////////////// In the meantime, Jessica has been working on a topic branch. She's created a topic branch called `issue54` and done three commits on that branch. She hasn't fetched John's changes yet, so her commit history looks like this: +////////////////////////// +一方そのころ、Jessica はトピックブランチで作業を進めていました。 +`issue54` というトピックブランチを作成した彼女は、そこで 3 回コミットをしました。 +彼女はまだ John の変更を取得していません。したがって、彼女のコミット履歴はこのような状態です。 +////////////////////////// .Jessica's topic branch. image::images/small-team-4.png[Jessica's topic branch.] +////////////////////////// +.Jessica のコミット履歴 +image::images/small-team-4.png[Jessica のコミット履歴] +////////////////////////// Jessica wants to sync up with John, so she fetches: +////////////////////////// +Jessica は John の作業を取り込もうとしました。 [source,console] +////////////////////////// ----- # Jessica's Machine $ git fetch origin @@ -219,15 +432,34 @@ $ git fetch origin From jessica@githost:simplegit fbff5bc..72bbc59 master -> origin/master ----- +////////////////////////// +----- +# Jessica のマシン +$ git fetch origin +... +From jessica@githost:simplegit + fbff5bc..72bbc59 master -> origin/master +----- +////////////////////////// That pulls down the work John has pushed up in the meantime. Jessica's history now looks like this: +////////////////////////// +これで、さきほど John がプッシュした内容が取り込まれました。Jessica の履歴は次のようになります。 +////////////////////////// .Jessica's history after fetching John's changes. image::images/small-team-5.png[Jessica's history after fetching John's changes.] +////////////////////////// +.John の変更を取り込んだ後の Jessica の履歴 +image::images/small-team-5.png[John の変更を取り込んだ後の Jessica の履歴] +////////////////////////// Jessica thinks her topic branch is ready, but she wants to know what she has to merge into her work so that she can push. She runs `git log` to find out: +////////////////////////// +Jessica のトピックブランチ上での作業が完了しました。そこで、自分の作業をプッシュする前に何をマージしなければならないのかを確認するため、 +彼女は `git log` コマンドを実行しました。 [source,console] ----- @@ -239,12 +471,21 @@ Date: Fri May 29 16:01:27 2009 -0700 removed invalid default value ----- +////////////////////////// The `issue54..origin/master` syntax is a log filter that asks Git to only show the list of commits that are on the latter branch (in this case `origin/master`) that are not on the first branch (in this case `issue54`). We'll go over this syntax in detail in <<_commit_ranges>>. +////////////////////////// +`issue54..origin/master` はログのフィルター記法です。このように書くと、後者のブランチ(この例では `origin/master` )には含まれるが前者のブランチ(この例では `issue54` )には含まれないコミットのログだけを表示します。この記法の詳細は <<_commit_ranges>> で説明します。 +////////////////////////// For now, we can see from the output that there is a single commit that John has made that Jessica has not merged in. If she merges `origin/master`, that is the single commit that will modify her local work. +////////////////////////// +この例では、John が作成して Jessica がまだマージしていないコミットがひとつあることがコマンド出力から読み取れます。仮にここで Jessica が `origin/master` をマージするとしましょう。その場合、Jessica の手元のファイルを変更するのは John が作成したコミットひとつだけ、という状態になります。 +////////////////////////// Now, Jessica can merge her topic work into her master branch, merge John's work (`origin/master`) into her `master` branch, and then push back to the server again. First, she switches back to her master branch to integrate all this work: +////////////////////////// +Jessica はトピックブランチの内容を自分の master ブランチにマージし、同じく John の作業 (`origin/master`) も自分の `master` ブランチにマージして再び変更をサーバーにプッシュすることになります。まずは master ブランチに戻り、これまでの作業を統合できるようにします。 [source,console] ----- @@ -253,9 +494,14 @@ Switched to branch 'master' Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded. ----- +////////////////////////// She can merge either `origin/master` or `issue54` first – they're both upstream, so the order doesn't matter. The end snapshot should be identical no matter which order she chooses; only the history will be slightly different. She chooses to merge in `issue54` first: +////////////////////////// +`origin/master` と `issue54` のどちらからマージしてもかまいません。どちらも上流にあるので、マージする順序が変わっても結果は同じなのです。 +どちらの順でマージしても、最終的なスナップショットはまったく同じものになります。ただそこにいたる歴史が微妙に変わってくるだけです。 +彼女はまず `issue54` からマージすることにしました。 [source,console] ----- @@ -267,8 +513,12 @@ Fast forward 2 files changed, 6 insertions(+), 1 deletions(-) ----- +////////////////////////// No problems occur; as you can see it was a simple fast-forward. Now Jessica merges in John's work (`origin/master`): +////////////////////////// +何も問題は発生しません。ご覧の通り、単なる fast-forward です。 +次に Jessica は John の作業 (`origin/master`) をマージします。 [source,console] ----- @@ -279,12 +529,22 @@ Merge made by recursive. 1 files changed, 1 insertions(+), 1 deletions(-) ----- +////////////////////////// Everything merges cleanly, and Jessica's history looks like this: +////////////////////////// +こちらもうまく完了しました。Jessica の履歴はこのようになります。 +////////////////////////// .Jessica's history after merging John's changes. image::images/small-team-6.png[Jessica's history after merging John's changes.] +////////////////////////// +.John の変更をマージした後の Jessica の履歴 +image::images/small-team-6.png[John の変更をマージした後の Jessica の履歴] +////////////////////////// Now `origin/master` is reachable from Jessica's `master` branch, so she should be able to successfully push (assuming John hasn't pushed again in the meantime): +////////////////////////// +これで、Jessica の `master` ブランチから `origin/master` に到達可能となります。これで自分の変更をプッシュできるようになりました (この作業の間に John は何もプッシュしていなかったものとします)。 [source,console] ----- @@ -294,34 +554,69 @@ To jessica@githost:simplegit.git 72bbc59..8059c15 master -> master ----- +////////////////////////// Each developer has committed a few times and merged each other's work successfully. +////////////////////////// +各開発者が何度かコミットし、お互いの作業のマージも無事できました。 +////////////////////////// .Jessica's history after pushing all changes back to the server. image::images/small-team-7.png[Jessica's history after pushing all changes back to the server.] +////////////////////////// +.すべての変更をサーバーに書き戻した後の Jessica の履歴 +image::images/small-team-7.png[すべての変更をサーバーに書き戻した後の Jessica の履歴] +////////////////////////// That is one of the simplest workflows. You work for a while, generally in a topic branch, and merge into your master branch when it's ready to be integrated. When you want to share that work, you merge it into your own master branch, then fetch and merge `origin/master` if it has changed, and finally push to the `master` branch on the server. The general sequence is something like this: +////////////////////////// +これがもっとも単純なワークフローです。 +トピックブランチでしばらく作業を進め、統合できる状態になれば自分の master ブランチにマージする。 +他の開発者の作業を取り込む場合は、`origin/master` を取得してもし変更があればマージする。そして最終的にそれをサーバーの master ブランチにプッシュする。 +全体的な流れは次のようになります。 +////////////////////////// .General sequence of events for a simple multiple-developer Git workflow. image::images/small-team-flow.png[General sequence of events for a simple multiple-developer Git workflow.] +////////////////////////// +.複数開発者での Git を使ったシンプルな開発作業のイベントシーケンス +image::images/small-team-flow.png[複数開発者での Git を使ったシンプルな開発作業のイベントシーケンス] +////////////////////////// ==== Private Managed Team +////////////////////////// +==== 非公開で管理されているチーム (((contributing, private managed team))) +////////////////////////// In this next scenario, you'll look at contributor roles in a larger private group. You'll learn how to work in an environment where small groups collaborate on features and then those team-based contributions are integrated by another party. +////////////////////////// +次に扱うシナリオは、大規模な非公開のグループに貢献するものです。 +機能単位の小規模なグループで共同作業した結果を別のグループと統合するような環境での作業の進め方を学びましょう。 +////////////////////////// Let's say that John and Jessica are working together on one feature, while Jessica and Josie are working on a second. In this case, the company is using a type of integration-manager workflow where the work of the individual groups is integrated only by certain engineers, and the `master` branch of the main repo can be updated only by those engineers. In this scenario, all work is done in team-based branches and pulled together by the integrators later. +////////////////////////// +John と Jessica が共同でとある機能を実装しており、Jessica はそれとは別の件で Josie とも作業をしているものとします。 +彼らの勤務先は統合マネージャー型のワークフローを採用しており、各グループの作業を統合する担当者が決まっています。メインリポジトリの `master` ブランチを更新できるのは統合担当者だけです。 +この場合、すべての作業はチームごとのブランチで行われ、後で統合担当者がまとめることになります。 +////////////////////////// Let's follow Jessica's workflow as she works on her two features, collaborating in parallel with two different developers in this environment. Assuming she already has her repository cloned, she decides to work on `featureA` first. She creates a new branch for the feature and does some work on it there: +////////////////////////// +では、Jessica の作業の流れを追っていきましょう。彼女は二つの機能を同時に実装しており、それぞれ別の開発者と共同作業をしています。 +すでに自分用のリポジトリをクローンしている彼女は、まず `featureA` の作業を始めることにしました。 +この機能用に新しいブランチを作成し、そこで作業を進めます。 [source,console] +////////////////////////// ----- # Jessica's Machine $ git checkout -b featureA @@ -331,9 +626,23 @@ $ git commit -am 'add limit to log function' [featureA 3300904] add limit to log function 1 files changed, 1 insertions(+), 1 deletions(-) ----- +////////////////////////// +----- +# Jessica のマシン +$ git checkout -b featureA +Switched to a new branch 'featureA' +$ vim lib/simplegit.rb +$ git commit -am 'add limit to log function' +[featureA 3300904] add limit to log function + 1 files changed, 1 insertions(+), 1 deletions(-) +----- +////////////////////////// At this point, she needs to share her work with John, so she pushes her `featureA` branch commits up to the server. Jessica doesn't have push access to the `master` branch – only the integrators do – so she has to push to another branch in order to collaborate with John: +////////////////////////// +自分の作業内容を John に渡すため、彼女は `featureA` ブランチへのコミットをサーバーにプッシュしました。 +Jessica には `master` ブランチへのプッシュをする権限はありません。そこにプッシュできるのは統合担当者だけなのです。そこで、John との共同作業用の別のブランチにプッシュします。 [source,console] ----- @@ -343,19 +652,35 @@ To jessica@githost:simplegit.git * [new branch] featureA -> featureA ----- +////////////////////////// Jessica e-mails John to tell him that she's pushed some work into a branch named `featureA` and he can look at it now. While she waits for feedback from John, Jessica decides to start working on `featureB` with Josie. To begin, she starts a new feature branch, basing it off the server's `master` branch: +////////////////////////// +Jessica は John に「私の作業を `featureA` というブランチにプッシュしておいたので、見てね」というメールを送りました。 +John からの返事を待つ間、Jessica はもう一方の `featureB` の作業を Josie とはじめます。 +まず最初に、この機能用の新しいブランチをサーバーの `master` ブランチから作ります。 [source,console] +////////////////////////// ----- # Jessica's Machine $ git fetch origin $ git checkout -b featureB origin/master Switched to a new branch 'featureB' ----- +////////////////////////// +----- +# Jessicaのマシン +$ git fetch origin +$ git checkout -b featureB origin/master +Switched to a new branch 'featureB' +----- +////////////////////////// Now, Jessica makes a couple of commits on the `featureB` branch: +////////////////////////// +そして Jessica は、`featureB` ブランチに何度かコミットしました。 [source,console] ----- @@ -369,14 +694,26 @@ $ git commit -am 'add ls-files' 1 files changed, 5 insertions(+), 0 deletions(-) ----- +////////////////////////// Jessica's repository looks like this: +////////////////////////// +Jessica のリポジトリはこのようになっています。 +////////////////////////// .Jessica's initial commit history. image::images/managed-team-1.png[Jessica's initial commit history.] +////////////////////////// +.Jessica のコミット履歴 +image::images/managed-team-1.png[Jessica のコミット履歴] +////////////////////////// She's ready to push up her work, but gets an e-mail from Josie that a branch with some initial work on it was already pushed to the server as `featureBee`. Jessica first needs to merge those changes in with her own before she can push to the server. She can then fetch Josie's changes down with `git fetch`: +////////////////////////// +この変更をプッシュしようと思ったそのときに、Josie から「私の作業を `featureBee` というブランチにプッシュしておいたので、見てね」というメールがやってきました。 +Jessica はまずこの変更をマージしてからでないとサーバーにプッシュすることはできません。 +そこで、まず Josie の変更を `git fetch` で取得しました。 [source,console] ----- @@ -386,7 +723,10 @@ From jessica@githost:simplegit * [new branch] featureBee -> origin/featureBee ----- +////////////////////////// Jessica can now merge this into the work she did with `git merge`: +////////////////////////// +次に、`git merge` でこの内容を自分の作業にマージします。 [source,console] ----- @@ -397,8 +737,12 @@ Merge made by recursive. 1 files changed, 4 insertions(+), 0 deletions(-) ----- +////////////////////////// There is a bit of a problem – she needs to push the merged work in her `featureB` branch to the `featureBee` branch on the server. She can do so by specifying the local branch followed by a colon (:) followed by the remote branch to the `git push` command: +////////////////////////// +ここでちょっとした問題が発生しました。彼女は、手元の `featureB` ブランチの内容をサーバーの `featureBee` ブランチにプッシュしなければなりません。 +このような場合は、`git push` コマンドでローカルブランチ名に続けてコロン (:) を書き、その後にリモートブランチ名を指定します。 [source,console] ----- @@ -408,12 +752,21 @@ To jessica@githost:simplegit.git fba9af8..cd685d1 featureB -> featureBee ----- +////////////////////////// This is called a _refspec_. See <<_refspec>> for a more detailed discussion of Git refspecs and different things you can do with them. Also notice the `-u` flag; this is short for `--set-upstream`, which configures the branches for easier pushing and pulling later. +////////////////////////// +これは _refspec_ と呼ばれます。 +<<_refspec>> で、Git の refspec の詳細とそれで何ができるのかを説明します。 +また、 `-u` オプションが使われていることにも注意しましょう。これは `--set-upstream` オプションの省略形で、のちのちブランチのプッシュ・プルで楽をするための設定です。 +////////////////////////// Next, John e-mails Jessica to say he's pushed some changes to the `featureA` branch and ask her to verify them. She runs a `git fetch` to pull down those changes: +////////////////////////// +さて、John からメールが返ってきました。「私の変更も `featureA` ブランチにプッシュしておいたので、確認よろしく」とのことです。 +彼女は `git fetch` でその変更を取り込みます。 [source,console] ----- @@ -423,7 +776,10 @@ From jessica@githost:simplegit 3300904..aad881d featureA -> origin/featureA ----- +////////////////////////// Then, she can see what has been changed with `git log`: +////////////////////////// +そして、`git log` で何が変わったのかを確認します。 [source,console] ----- @@ -435,7 +791,10 @@ Date: Fri May 29 19:57:33 2009 -0700 changed log output to 30 from 25 ----- +////////////////////////// Finally, she merges John's work into her own `featureA` branch: +////////////////////////// +確認を終えた彼女は、John の作業を自分の `featureA` ブランチにマージしました。 [source,console] ----- @@ -448,7 +807,10 @@ Fast forward 1 files changed, 9 insertions(+), 1 deletions(-) ----- +////////////////////////// Jessica wants to tweak something, so she commits again and then pushes this back up to the server: +////////////////////////// +Jessica はもう少し手を入れたいところがあったので、再びコミットしてそれをサーバーにプッシュします。 [source,console] ----- @@ -461,36 +823,74 @@ To jessica@githost:simplegit.git 3300904..774b3ed featureA -> featureA ----- +////////////////////////// Jessica's commit history now looks something like this: +////////////////////////// +Jessica のコミット履歴は、この時点で以下のようになります。 +////////////////////////// .Jessica's history after committing on a feature branch. image::images/managed-team-2.png[Jessica's history after committing on a feature branch.] +////////////////////////// +.Jessica がブランチにコミットした後のコミット履歴 +image::images/managed-team-2.png[Jessica がブランチにコミットした後のコミット履歴] +////////////////////////// Jessica, Josie, and John inform the integrators that the `featureA` and `featureBee` branches on the server are ready for integration into the mainline. After the integrators merge these branches into the mainline, a fetch will bring down the new merge commit, making the history look like this: +////////////////////////// +Jessica、Josie そして John は、統合担当者に「`featureA` ブランチと `featureBee` ブランチは本流に統合できる状態になりました」と報告しました。 +これらのブランチを担当者が本流に統合した後でそれを取得すると、マージコミットが新たに追加されてこのような状態になります。 +////////////////////////// .Jessica's history after merging both her topic branches. image::images/managed-team-3.png[Jessica's history after merging both her topic branches.] +////////////////////////// +.Jessica が両方のトピックブランチをマージしたあとのコミット履歴 +image::images/managed-team-3.png[Jessica が両方のトピックブランチをマージしたあとのコミット履歴] +////////////////////////// Many groups switch to Git because of this ability to have multiple teams working in parallel, merging the different lines of work late in the process. The ability of smaller subgroups of a team to collaborate via remote branches without necessarily having to involve or impede the entire team is a huge benefit of Git. The sequence for the workflow you saw here is something like this: +////////////////////////// +Git へ移行するグループが続出しているのも、この「複数チームの作業を並行して進め、後で統合できる」という機能のおかげです。 +小さなグループ単位でリモートブランチを使った共同作業ができ、しかもそれがチーム全体の作業を妨げることがない。これは Git の大きな利点です。 +ここで見たワークフローをまとめると、次のようになります。 +////////////////////////// .Basic sequence of this managed-team workflow. image::images/managed-team-flow.png[Basic sequence of this managed-team workflow.] +////////////////////////// +.管理されたチームでのワークフローの基本的な流れ +image::images/managed-team-flow.png[管理されたチームでのワークフローの基本的な流れ] [[_public_project]] +////////////////////////// ==== Forked Public Project +////////////////////////// +==== フォークされた公開プロジェクト (((contributing, public small project))) +////////////////////////// Contributing to public projects is a bit different. Because you don't have the permissions to directly update branches on the project, you have to get the work to the maintainers some other way. This first example describes contributing via forking on Git hosts that support easy forking. Many hosting sites support this (including GitHub, BitBucket, Google Code, repo.or.cz, and others), and many project maintainers expect this style of contribution. The next section deals with projects that prefer to accept contributed patches via e-mail. - +////////////////////////// +公開プロジェクトに貢献するとなると、また少し話が変わってきます。 +そのプロジェクトのブランチを直接更新できる権限はないでしょうから、何か別の方法でメンテナに接触する必要があります。 +まずは、フォークをサポートしている Git ホスティングサービスでフォークを使って貢献する方法を説明します。 +多くの Git ホスティングサービス(GitHub、 BitBucket、 Google Code、 repo.or.cz など) がフォークをサポートしており、メンテナの多くはこの方式での協力を期待しています。 +そしてこの次のセクションでは、メールでパッチを送る形式での貢献について説明します。 + +////////////////////////// First, you'll probably want to clone the main repository, create a topic branch for the patch or patch series you're planning to contribute, and do your work there. The sequence looks basically like this: +////////////////////////// +まずはメインリポジトリをクローンしましょう。そしてパッチ用のトピックブランチを作り、そこで作業を進めます。 +このような流れになります。 [source,console] ----- @@ -504,22 +904,36 @@ $ git commit ----- [NOTE] +////////////////////////// ==== You may want to use `rebase -i` to squash your work down to a single commit, or rearrange the work in the commits to make the patch easier for the maintainer to review – see <<_rewriting_history>> for more information about interactive rebasing. ==== +////////////////////////// +==== +`rebase -i` を使ってすべての作業をひとつのコミットにまとめたり、メンテナがレビューしやすいようにコミット内容を整理したりといったことも行うかもしれません。対話的なリベースの方法については <<_rewriting_history>> で詳しく説明します。 +==== +////////////////////////// When your branch work is finished and you're ready to contribute it back to the maintainers, go to the original project page and click the ``Fork'' button, creating your own writable fork of the project. You then need to add in this new repository URL as a second remote, in this case named `myfork`: +////////////////////////// +ブランチでの作業を終えてメンテナに渡せる状態になったら、プロジェクトのページに行って ``Fork'' ボタンを押し、自分用に書き込み可能なフォークを作成します。 +このリポジトリの URL を追加のリモートとして設定しなければなりません。ここでは `myfork` という名前にしました。 [source,console] ----- $ git remote add myfork (url) ----- +////////////////////////// Then you need to push your work up to it. It's easiest to push the topic branch you're working on up to your repository, rather than merging into your master branch and pushing that up. The reason is that if the work isn't accepted or is cherry picked, you don't have to rewind your master branch. If the maintainers merge, rebase, or cherry-pick your work, you'll eventually get it back via pulling from their repository anyhow: +////////////////////////// +今後、自分の作業内容はここにプッシュすることになります。 +変更を master ブランチにマージしてからそれをプッシュするよりも、今作業中の内容をそのままトピックブランチにプッシュするほうが簡単でしょう。 +もしその変更が受け入れられなかったり一部だけが取り込まれたりした場合に、master ブランチを巻き戻す必要がなくなるからです。メンテナがあなたの作業をマージするかリベースするかあるいは一部だけ取り込むか、いずれにせよあなたはその結果をリポジトリから再度取り込むことになります。 [source,console] ----- @@ -527,11 +941,19 @@ $ git push -u myfork featureA ----- (((git commands, request-pull))) +////////////////////////// When your work has been pushed up to your fork, you need to notify the maintainer. This is often called a pull request, and you can either generate it via the website – GitHub has it's own Pull Request mechanism that we'll go over in <<_github>> – or you can run the `git request-pull` command and e-mail the output to the project maintainer manually. +////////////////////////// +自分用のフォークに作業内容をプッシュし終えたら、それをメンテナに伝えましょう。 +これは、よく「プルリクエスト」と呼ばれるもので、ウェブサイトから実行する (GutHub には Pull request を行う独自の仕組みがあります。詳しくは <<_github>> で説明します) こともできれば、 `git request-pull` コマンドの出力をプロジェクトのメンテナにメールで送ることもできます。 +////////////////////////// The `request-pull` command takes the base branch into which you want your topic branch pulled and the Git repository URL you want them to pull from, and outputs a summary of all the changes you're asking to be pulled in. For instance, if Jessica wants to send John a pull request, and she's done two commits on the topic branch she just pushed up, she can run this: +////////////////////////// +`request-pull` コマンドには、トピックブランチをプルしてもらいたい先のブランチとその Git リポジトリの URL を指定します。すると、プルしてもらいたい変更の概要が出力されます。 +たとえば Jessica が John にプルリクエストを送ろうとしたとしましょう。彼女はすでにトピックブランチ上で 2 回のコミットを済ませています。 [source,console] ----- @@ -552,12 +974,21 @@ Jessica Smith (2): 1 files changed, 9 insertions(+), 1 deletions(-) ----- +////////////////////////// The output can be sent to the maintainer–it tells them where the work was branched from, summarizes the commits, and tells where to pull this work from. +////////////////////////// +この出力をメンテナに送れば「どのブランチからフォークしたのか、どういったコミットをしたのか、そしてそれをどこにプルしてほしいのか」を伝えることができます。 +////////////////////////// On a project for which you're not the maintainer, it's generally easier to have a branch like `master` always track `origin/master` and to do your work in topic branches that you can easily discard if they're rejected. Having work themes isolated into topic branches also makes it easier for you to rebase your work if the tip of the main repository has moved in the meantime and your commits no longer apply cleanly. For example, if you want to submit a second topic of work to the project, don't continue working on the topic branch you just pushed up – start over from the main repository's `master` branch: +////////////////////////// +自分がメンテナになっていないプロジェクトで作業をする場合は、`master` ブランチでは常に `origin/master` を追いかけるようにし、自分の作業はトピックブランチで進めていくほうが楽です。そうすれば、パッチが拒否されたときも簡単にそれを捨てることができます。 +また、作業内容ごとにトピックブランチを分離しておけば、本流のリポジトリが更新されてパッチがうまく適用できなくなったとしても簡単にリベースできるようになります。 +たとえば、さきほどのプロジェクトに対して別の作業をすることになったとしましょう。その場合は、先ほどプッシュしたトピックブランチを使うのではなく、メインリポジトリの `master` ブランチから新たなトピックブランチを作成します。 +////////////////////////// [source,console] ----- $ git checkout -b featureB origin/master @@ -567,14 +998,35 @@ $ git push myfork featureB # (email maintainer) $ git fetch origin ----- +////////////////////////// +[source,console] +----- +$ git checkout -b featureB origin/master +# (作業) +$ git commit +$ git push myfork featureB +# (メンテナにメールを送る) +$ git fetch origin +----- +////////////////////////// Now, each of your topics is contained within a silo – similar to a patch queue – that you can rewrite, rebase, and modify without the topics interfering or interdepending on each other, like so: +////////////////////////// +これで、それぞれのトピックがサイロに入った状態になりました。お互いのトピックが邪魔しあったり依存しあったりすることなく、それぞれ個別に書き換えやリベースが可能となります。詳しくは以下を参照ください。 +////////////////////////// .Initial commit history with `featureB` work. image::images/public-small-1.png[Initial commit history with `featureB` work.] +////////////////////////// +.`featureB` に関する作業のコミット履歴 +image::images/public-small-1.png[`featureB` に関する作業のコミット履歴] +////////////////////////// Let's say the project maintainer has pulled in a bunch of other patches and tried your first branch, but it no longer cleanly merges. In this case, you can try to rebase that branch on top of `origin/master`, resolve the conflicts for the maintainer, and then resubmit your changes: +////////////////////////// +プロジェクトのメンテナが、他の大量のパッチを適用したあとであなたの最初のパッチを適用しようとしました。しかしその時点でパッチはすでにそのままでは適用できなくなっています。 +こんな場合は、そのブランチを `origin/master` の先端にリベースして衝突を解決させ、あらためて変更内容をメンテナに送ります。 [source,console] ----- @@ -583,21 +1035,38 @@ $ git rebase origin/master $ git push -f myfork featureA ----- +////////////////////////// This rewrites your history to now look like <>. +////////////////////////// +これで、あなたの歴史は <> のように書き換えられました。 [[psp_b]] +////////////////////////// .Commit history after `featureA` work. image::images/public-small-2.png[Commit history after `featureA` work.] +////////////////////////// +.`featureA` の作業を終えた後のコミット履歴 +image::images/public-small-2.png[`featureA` の作業を終えた後のコミット履歴] +////////////////////////// Because you rebased the branch, you have to specify the `-f` to your push command in order to be able to replace the `featureA` branch on the server with a commit that isn't a descendant of it. An alternative would be to push this new work to a different branch on the server (perhaps called `featureAv2`). +////////////////////////// +ブランチをリベースしたので、プッシュする際には `-f` を指定しなければなりません。これは、サーバー上の `featureA` ブランチをその直系の子孫以外のコミットで上書きするためです。 +別のやり方として、今回の作業を別のブランチ (`featureAv2` など) にプッシュすることもできます。 +////////////////////////// Let's look at one more possible scenario: the maintainer has looked at work in your second branch and likes the concept but would like you to change an implementation detail. You'll also take this opportunity to move the work to be based off the project's current `master` branch. You start a new branch based off the current `origin/master` branch, squash the `featureB` changes there, resolve any conflicts, make the implementation change, and then push that up as a new branch: +////////////////////////// +もうひとつ別のシナリオを考えてみましょう。あなたの二番目のブランチを見たメンテナが、その考え方は気に入ったものの細かい実装をちょっと変更してほしいと連絡してきました。 +この場合も、プロジェクトの `master` ブランチから作業を進めます。 +現在の `origin/master` から新たにブランチを作成し、そこに `featureB` ブランチの変更を押し込み、もし衝突があればそれを解決し、実装をちょっと変更してからそれを新しいブランチとしてプッシュします。 (((git commands, merge, squash))) [source,console] +////////////////////////// ----- $ git checkout -b featureBv2 origin/master $ git merge --no-commit --squash featureB @@ -605,28 +1074,61 @@ $ git merge --no-commit --squash featureB $ git commit $ git push myfork featureBv2 ----- +////////////////////////// +----- +$ git checkout -b featureBv2 origin/master +$ git merge --no-commit --squash featureB +# (実装をちょっと変更する) +$ git commit +$ git push myfork featureBv2 +----- +////////////////////////// The `--squash` option takes all the work on the merged branch and squashes it into one non-merge commit on top of the branch you're on. The `--no-commit` option tells Git not to automatically record a commit. This allows you to introduce all the changes from another branch and then make more changes before recording the new commit. +////////////////////////// +`--squash` オプションは、マージしたいブランチでのすべての作業をひとつのコミットにまとめ、それを現在のブランチの先頭にマージします。 +`--no-commit` オプションは、自動的にコミットを記録しないよう Git に指示しています。 +こうすれば、別のブランチのすべての変更を取り込んでさらに手元で変更を加えたものを新しいコミットとして記録できるのです。 +////////////////////////// Now you can send the maintainer a message that you've made the requested changes and they can find those changes in your `featureBv2` branch. +////////////////////////// +そして、メンテナに「言われたとおりのちょっとした変更をしたものが `featureBv2` ブランチにあるよ」と連絡します。 +////////////////////////// .Commit history after `featureBv2` work. image::images/public-small-3.png[Commit history after `featureBv2` work.] +////////////////////////// +.`featureBv2` の作業を終えた後のコミット履歴 +image::images/public-small-3.png[`featureBv2` の作業を終えた後のコミット履歴] [[_project_over_email]] +////////////////////////// ==== Public Project over E-Mail +////////////////////////// +==== メールを使った公開プロジェクトへの貢献 (((contributing, public large project))) +////////////////////////// Many projects have established procedures for accepting patches – you'll need to check the specific rules for each project, because they will differ. Since there are several older, larger projects which accept patches via a developer mailing list, we'll go over an example of that now. +////////////////////////// +多くのプロジェクトでは、パッチを受け付ける手続きが確立されています。プロジェクトによっていろいろ異なるので、まずはそのプロジェクト固有のルールがないかどうか確認しましょう。 +また、長期間続いている大規模なプロジェクトには、開発者用メーリングリストでパッチを受け付けているものがいくつかあります。そこで、ここではそういったプロジェクトを例にとって話を進めます。 +////////////////////////// The workflow is similar to the previous use case – you create topic branches for each patch series you work on. The difference is how you submit them to the project. Instead of forking the project and pushing to your own writable version, you generate e-mail versions of each commit series and e-mail them to the developer mailing list: +////////////////////////// +実際の作業の流れは先ほどとほぼ同じで、作業する内容ごとにトピックブランチを作成することになります。 +違うのは、パッチをプロジェクトに提供する方法です。 +プロジェクトをフォークし、自分用のリポジトリにプッシュするのではなく、個々のコミットについてメールを作成し、それを開発者用メーリングリストに投稿します。 [source,console] +////////////////////////// ----- $ git checkout -b topicA # (work) @@ -634,11 +1136,24 @@ $ git commit # (work) $ git commit ----- +////////////////////////// +----- +$ git checkout -b topicA +# (作業) +$ git commit +# (作業) +$ git commit +----- (((git commands, format-patch))) +////////////////////////// Now you have two commits that you want to send to the mailing list. You use `git format-patch` to generate the mbox-formatted files that you can e-mail to the list – it turns each commit into an e-mail message with the first line of the commit message as the subject and the rest of the message plus the patch that the commit introduces as the body. The nice thing about this is that applying a patch from an e-mail generated with `format-patch` preserves all the commit information properly. +////////////////////////// +これで二つのコミットができあがりました。これらをメーリングリストに投稿します。 +`git format-patch` を使うと mbox 形式のファイルが作成されるので、これをメーリングリストに送ることができます。このコマンドは、コミットメッセージの一行目を件名、残りのコミットメッセージとコミット内容のパッチを本文に書いたメールを作成します。 +これのよいところは、`format-patch` で作成したメールからパッチを適用すると、すべてのコミット情報が適切に維持されるというところです。 [source,console] ----- @@ -647,9 +1162,14 @@ $ git format-patch -M origin/master 0002-changed-log-output-to-30-from-25.patch ----- +////////////////////////// The `format-patch` command prints out the names of the patch files it creates. The `-M` switch tells Git to look for renames. The files end up looking like this: +////////////////////////// +`format-patch` コマンドは、できあがったパッチファイルの名前を出力します。 +`-M` スイッチは、名前が変わったことを検出するためのものです。 +できあがったファイルは次のようになります。 [source,console] ----- @@ -682,17 +1202,31 @@ index 76f47bc..f9815f1 100644 2.1.0 ----- +////////////////////////// You can also edit these patch files to add more information for the e-mail list that you don't want to show up in the commit message. If you add text between the `---` line and the beginning of the patch (the `diff --git` line), then developers can read it; but applying the patch excludes it. +////////////////////////// +このファイルを編集して、コミットメッセージには書けなかったような情報をメーリングリスト用に追加することもできます。 +`---` の行とパッチの開始位置 ( `diff --git` の行) の間にメッセージを書くと、メールを受信した人はそれを読むことができますが、パッチからは除外されます。 +////////////////////////// To e-mail this to a mailing list, you can either paste the file into your e-mail program or send it via a command-line program. Pasting the text often causes formatting issues, especially with ``smarter'' clients that don't preserve newlines and other whitespace appropriately. Luckily, Git provides a tool to help you send properly formatted patches via IMAP, which may be easier for you. We'll demonstrate how to send a patch via Gmail, which happens to be the e-mail agent we know best; you can read detailed instructions for a number of mail programs at the end of the aforementioned `Documentation/SubmittingPatches` file in the Git source code. +////////////////////////// +これをメーリングリストに投稿するには、メールソフトにファイルの内容を貼り付けるか、あるいはコマンドラインのプログラムを使います。 +ファイルの内容をコピーして貼り付けると「かしこい」メールソフトが勝手に改行の位置を変えてしまうなどの問題が起こりがちです。 +ありがたいことに Git には、きちんとしたフォーマットのパッチを IMAP で送ることを支援するツールが用意されています。これを使うと便利です。 +ここでは、パッチを Gmail で送る方法を説明しましょう。というのも、一番よく知っているメールソフトが Gmail だからです。さまざまなメールソフトでの詳細なメール送信方法が、Git ソースコードにある `Documentation/SubmittingPatches` の最後に載っています。 (((git commands, config)))(((email))) +////////////////////////// First, you need to set up the imap section in your `~/.gitconfig` file. You can set each value separately with a series of `git config` commands, or you can add them manually, but in the end your config file should look something like this: +////////////////////////// +まず。`~/.gitconfig` ファイルの imap セクションを設定します。 +それぞれの値を `git config` コマンドで順に設定してもかまいませんし、このファイルに手で書き加えてもかまいません。最終的に、設定ファイルは次のようになります。 [source,ini] ----- @@ -705,8 +1239,12 @@ You can set each value separately with a series of `git config` commands, or you sslverify = false ----- +////////////////////////// If your IMAP server doesn't use SSL, the last two lines probably aren't necessary, and the host value will be `imap://` instead of `imaps://`. When that is set up, you can use `git send-email` to place the patch series in the Drafts folder of the specified IMAP server: +////////////////////////// +IMAP サーバーで SSL を使っていない場合は、最後の二行はおそらく不要でしょう。そして host のところが `imaps://` ではなく `imap://` となります。 +ここまでの設定が終われば、`git send-email` を実行して IMAP サーバーの Drafts フォルダにパッチを置くことができるようになります。 [source,console] ----- @@ -719,7 +1257,10 @@ Who should the emails be sent to? jessica@example.com Message-ID to be used as In-Reply-To for the first email? y ----- +////////////////////////// Then, Git spits out a bunch of log information looking something like this for each patch you're sending: +////////////////////////// +Git はその後、各パッチについてこのようなログ情報をはき出すはずです。 [source,text] ----- @@ -739,10 +1280,21 @@ References: Result: OK ----- +////////////////////////// At this point, you should be able to go to your Drafts folder, change the To field to the mailing list you're sending the patch to, possibly CC the maintainer or person responsible for that section, and send it off. +////////////////////////// +あとは、Drafts フォルダに移動して To フィールドをメーリングリストのアドレスに変更し (おそらく CC には担当メンテなのアドレスを入れ)、送信できるようになりました。 +////////////////////////// ==== Summary +////////////////////////// +==== まとめ +////////////////////////// This section has covered a number of common workflows for dealing with several very different types of Git projects you're likely to encounter, and introduced a couple of new tools to help you manage this process. Next, you'll see how to work the other side of the coin: maintaining a Git project. You'll learn how to be a benevolent dictator or integration manager. +////////////////////////// +このセクションでは、今後みなさんが遭遇するであろうさまざまな形式の Git プロジェクトについて、関わっていくための作業手順を説明しました。そして、その際に使える新兵器もいくつか紹介しました。 +次はもう一方の側、つまり Git プロジェクトを運営する側について見ていきましょう。 +慈悲深い独裁者、あるいは統合マネージャーとしての作業手順を説明します。 diff --git a/book/05-distributed-git/sections/distributed-workflows.asc b/book/05-distributed-git/sections/distributed-workflows.asc index 560f38e2..2247ba84 100644 --- a/book/05-distributed-git/sections/distributed-workflows.asc +++ b/book/05-distributed-git/sections/distributed-workflows.asc @@ -1,26 +1,54 @@ +////////////////////////// === Distributed Workflows +////////////////////////// +=== 分散作業の流れ (((workflows))) +////////////////////////// Unlike Centralized Version Control Systems (CVCSs), the distributed nature of Git allows you to be far more flexible in how developers collaborate on projects. In centralized systems, every developer is a node working more or less equally on a central hub. In Git, however, every developer is potentially both a node and a hub – that is, every developer can both contribute code to other repositories and maintain a public repository on which others can base their work and which they can contribute to. This opens a vast range of workflow possibilities for your project and/or your team, so we'll cover a few common paradigms that take advantage of this flexibility. We'll go over the strengths and possible weaknesses of each design; you can choose a single one to use, or you can mix and match features from each. - +////////////////////////// +中央管理型のバージョン管理システム (Centralized Version Control System: CVCS) とは違い、Git は分散型だという特徴があります。この特徴を生かすと、プロジェクトの開発者間での共同作業をより柔軟に行えるようになります。 +中央管理型のシステムでは、個々の開発者は中央のハブに対するノードという位置づけとなります。 +しかし Git では、各開発者はノードであると同時にハブにもなり得ます。つまり、誰もが他のリポジトリに対してコードを提供することができ、誰もが公開リポジトリを管理して他の開発者の作業を受け入れることもできるということです。 +これは、みなさんのプロジェクトや開発チームでの作業の流れにさまざまな可能性をもたらします。本章では、この柔軟性を生かすいくつかの実例を示します。 +それぞれについて、利点だけでなく想定される弱点についても扱うので、適宜取捨選択してご利用ください。 + +////////////////////////// ==== Centralized Workflow +////////////////////////// +==== 中央集権型のワークフロー (((workflows, centralized))) +////////////////////////// In centralized systems, there is generally a single collaboration model–the centralized workflow. One central hub, or repository, can accept code, and everyone synchronizes their work to it. A number of developers are nodes – consumers of that hub – and synchronize to that one place. +////////////////////////// +中央管理型のシステムでは共同作業の方式は一つだけです。それが中央集権型のワークフローです。 +これは、中央にある一つのハブ (リポジトリ) がコードを受け入れ、他のメンバー全員がそこに作業内容を同期させるという流れです。 +多数の開発者がハブにつながるノードとなり、作業を一か所に集約します。 +////////////////////////// .Centralized workflow. image::images/centralized.png[Centralized workflow.] +////////////////////////// +.中央集権型のワークフロー +image::images/centralized.png[中央集権型のワークフロー] +////////////////////////// This means that if two developers clone from the hub and both make changes, the first developer to push their changes back up can do so with no problems. The second developer must merge in the first one's work before pushing changes up, so as not to overwrite the first developer's changes. This concept is as true in Git as it is in Subversion(((Subversion))) (or any CVCS), and this model works perfectly well in Git. +////////////////////////// +二人の開発者がハブからのクローンを作成して個々に変更をした場合、最初の開発者がそれをプッシュするのは特に問題なくできます。 +もう一人の開発者は、まず最初の開発者の変更をマージしてからサーバーへのプッシュを行い、最初の開発者の変更を消してしまわないようにします。 +この考え方は、Git 上でも Subversion (((Subversion))) (あるいはその他の CVCS) と同様に生かせます。そしてこの方式は Git でも完全に機能します。 +////////////////////////// If you are already comfortable with a centralized workflow in your company or team, you can easily continue using that workflow with Git. Simply set up a single repository, and give everyone on your team push access; Git won't let users overwrite each other. Say John and Jessica both start working at the same time. @@ -28,61 +56,133 @@ John finishes his change and pushes it to the server. Then Jessica tries to push her changes, but the server rejects them. She is told that she's trying to push non-fast-forward changes and that she won't be able to do so until she fetches and merges. This workflow is attractive to a lot of people because it's a paradigm that many are familiar and comfortable with. - +////////////////////////// +小規模なチームに所属していたり、組織内で既に中央集権型のワークフローになじんでいたりなどの場合は、Git でその方式を続けることも簡単です。 +リポジトリをひとつ立ち上げて、チームのメンバー全員がそこにプッシュできるようにすればいいのです。Git は他のユーザーの変更を上書きしてしまうことはありません。 +たとえば、John と Jessica が作業を一斉に始めたとしましょう。 +先に作業が終わった John が、変更をサーバーにプッシュします。 +次に、Jessica が変更をプッシュしようとすると、サーバー側でそのプッシュは拒否されます。 +そして Jessica は、直接プッシュすることはできないのでまずは変更内容をマージする必要があることを Git のエラーメッセージから気づきます。 +この方式は多くの人にとって魅力的なものでしょう。これまでにもなじみのある方式だし、今までそれでうまくやってきたからです。 + +////////////////////////// This is also not limited to small teams. With Git's branching model, it's possible for hundreds of developers to successfully work on a single project through dozens of branches simultaneously. +////////////////////////// +また、この例は小規模なチームに限った話ではありません。Git のブランチモデルを用いてひとつのプロジェクト上にたくさんのブランチを作れば、何百人もの開発者が同時並行で作業を進めることだってできるのです。 [[_integration_manager]] +////////////////////////// ==== Integration-Manager Workflow +////////////////////////// +==== 統合マネージャー型のワークフロー (((workflows, integration manager))) +////////////////////////// Because Git allows you to have multiple remote repositories, it's possible to have a workflow where each developer has write access to their own public repository and read access to everyone else's. This scenario often includes a canonical repository that represents the ``official'' project. To contribute to that project, you create your own public clone of the project and push your changes to it. Then, you can send a request to the maintainer of the main project to pull in your changes. The maintainer can then add your repository as a remote, test your changes locally, merge them into their branch, and push back to their repository. The process works as follows (see <>): - +////////////////////////// +Git では複数のリモートリポジトリを持つことができるので、書き込み権限を持つ公開リポジトリを各自が持ち、他のメンバーからは読み込みのみのアクセスを許可するという方式をとることもできます。 +この方式には、「公式」プロジェクトを表す公式なリポジトリも含みます。 +このプロジェクトの開発に参加するには、まずプロジェクトのクローンを自分用に作成し、変更はそこにプッシュします。 +次に、メインプロジェクトのメンテナーに「変更を取り込んでほしい」とお願いします。 +メンテナーはあなたのリポジトリをリモートに追加し、変更を取り込んでマージします。そしてその結果をリポジトリにプッシュするのです。 +この作業の流れは次のようになります ( <> を参照ください)。 + +////////////////////////// 1. The project maintainer pushes to their public repository. 2. A contributor clones that repository and makes changes. 3. The contributor pushes to their own public copy. 4. The contributor sends the maintainer an e-mail asking them to pull changes. 5. The maintainer adds the contributor's repo as a remote and merges locally. 6. The maintainer pushes merged changes to the main repository. +////////////////////////// +1. プロジェクトのメンテナーが公開リポジトリにプッシュする +2. 開発者がそのリポジトリをクローンし、変更を加える +3. 開発者が各自の公開リポジトリにプッシュする +4. 開発者がメンテナーに「変更を取り込んでほしい」というメールを送る +5. メンテナーが開発者のリポジトリをリモートに追加し、それをマージする +6. マージした結果をメンテナーがメインリポジトリにプッシュする [[wfdiag_b]] +////////////////////////// .Integration-manager workflow. image::images/integration-manager.png[Integration-manager workflow.] +////////////////////////// +.統合マネージャー型のワークフロー +image::images/integration-manager.png[統合マネージャー型のワークフロー] (((forking))) +////////////////////////// This is a very common workflow with hub-based tools like GitHub or GitLab, where it's easy to fork a project and push your changes into your fork for everyone to see. One of the main advantages of this approach is that you can continue to work, and the maintainer of the main repository can pull in your changes at any time. Contributors don't have to wait for the project to incorporate their changes – each party can work at their own pace. +////////////////////////// +これは GitHub や GitLab のようなハブ型のツールでよく使われている流れです。プロジェクトを容易にフォークでき、そこにプッシュした内容をみんなに簡単に見てもらえます。 +この方式の主な利点の一つは、あなたはそのまま開発を続行し、メインリポジトリのメンテナーはいつでも好きなタイミングで変更を取り込めるということです。 +変更を取り込んでもらえるまで作業を止めて待つ必要はありません。自分のペースで作業を進められるのです。 +////////////////////////// ==== Dictator and Lieutenants Workflow +////////////////////////// +==== 独裁者と若頭型のワークフロー (((workflows, dictator and lieutenants))) +////////////////////////// This is a variant of a multiple-repository workflow. It's generally used by huge projects with hundreds of collaborators; one famous example is the Linux kernel. Various integration managers are in charge of certain parts of the repository; they're called lieutenants. All the lieutenants have one integration manager known as the benevolent dictator. The benevolent dictator's repository serves as the reference repository from which all the collaborators need to pull. The process works like this (see <>): - +////////////////////////// +これは、複数リポジトリ型のワークフローのひとつです。 +何百人もの開発者が参加するような巨大なプロジェクトで採用されています。有名どころでは Linux カーネルがこの方式です。 +統合マネージャーを何人も用意し、それぞれにリポジトリの特定の部分を担当させます。彼らは若頭 (lieutenant) と呼ばれます。 +そしてすべての若頭をまとめる統合マネージャーが「慈悲深い独裁者 (benevalent dictator)」です。 +独裁者のリポジトリが基準リポジトリとなり、すべてのメンバーはこれをプルします。 +この作業の流れは次のようになります ( <> を参照ください)。 + +////////////////////////// 1. Regular developers work on their topic branch and rebase their work on top of `master`. The `master` branch is that of the dictator. 2. Lieutenants merge the developers' topic branches into their `master` branch. 3. The dictator merges the lieutenants' `master` branches into the dictator's `master` branch. 4. The dictator pushes their `master` to the reference repository so the other developers can rebase on it. +////////////////////////// +1. 一般の開発者はトピックブランチ上で作業を進め、`master` の先頭にリベースする。独裁者の `master` ブランチがマスターとなる +2. 若頭が各開発者のトピックブランチを自分の `master` ブランチにマージする +3. 独裁者が各若頭の `master` ブランチを自分の `master` ブランチにマージする +4. 独裁者が自分の `master` をリポジトリにプッシュし、他のメンバーがリベースできるようにする [[wfdiag_c]] +////////////////////////// .Benevolent dictator workflow. image::images/benevolent-dictator.png[Benevolent dictator workflow.] +////////////////////////// +.慈悲深い独裁者型のワークフロー +image::images/benevolent-dictator.png[慈悲深い独裁者型のワークフロー] +////////////////////////// This kind of workflow isn't common, but can be useful in very big projects, or in highly hierarchical environments. It allows the project leader (the dictator) to delegate much of the work and collect large subsets of code at multiple points before integrating them. +////////////////////////// +この手のワークフローはあまり一般的ではありませんが、大規模なプロジェクトや高度に階層化された環境では便利です。 +プロジェクトリーダー (独裁者) が大半の作業を委譲し、サブセット単位である程度まとまってからコードを統合することができるからです。 +////////////////////////// ==== Workflows Summary +////////////////////////// +==== ワークフローのまとめ +////////////////////////// These are some commonly used workflows that are possible with a distributed system like Git, but you can see that many variations are possible to suit your particular real-world workflow. Now that you can (hopefully) determine which workflow combination may work for you, we'll cover some more specific examples of how to accomplish the main roles that make up the different flows. In the next section, you'll learn about a few common patterns for contributing to a project. +////////////////////////// +Git のような分散システムでよく使われるワークフローの多くは、実社会での何らかのワークフローにあてはめて考えることができます。 +これで、どのワークフローがあなたに合うかがわかったことでしょう (ですよね?)。 +次は、より特化した例をあげて個々のフローを実現する方法を見ていきましょう。 diff --git a/book/05-distributed-git/sections/maintaining.asc b/book/05-distributed-git/sections/maintaining.asc index 2f521758..d4997ad4 100644 --- a/book/05-distributed-git/sections/maintaining.asc +++ b/book/05-distributed-git/sections/maintaining.asc @@ -1,59 +1,108 @@ +////////////////////////// === Maintaining a Project +////////////////////////// +=== プロジェクトの運営 (((maintaining a project))) +////////////////////////// In addition to knowing how to effectively contribute to a project, you'll likely need to know how to maintain one. This can consist of accepting and applying patches generated via `format-patch` and e-mailed to you, or integrating changes in remote branches for repositories you've added as remotes to your project. Whether you maintain a canonical repository or want to help by verifying or approving patches, you need to know how to accept work in a way that is clearest for other contributors and sustainable by you over the long run. +////////////////////////// +プロジェクトに貢献する方法だけでなく、プロジェクトを運営する方法についても知っておくといいでしょう。 +たとえば `format-patch` を使ってメールで送られてきたパッチを処理する方法や、別のリポジトリのリモートブランチでの変更を統合する方法などです。 +本流のリポジトリを保守するにせよパッチの検証や適用を手伝うにせよ、どうすれば貢献者たちにとってわかりやすくなるかを知っておくべきでしょう。 +////////////////////////// ==== Working in Topic Branches +////////////////////////// +==== トピックブランチでの作業 (((branches, topic))) +////////////////////////// When you're thinking of integrating new work, it's generally a good idea to try it out in a topic branch – a temporary branch specifically made to try out that new work. This way, it's easy to tweak a patch individually and leave it if it's not working until you have time to come back to it. If you create a simple branch name based on the theme of the work you're going to try, such as `ruby_client` or something similarly descriptive, you can easily remember it if you have to abandon it for a while and come back later. The maintainer of the Git project tends to namespace these branches as well – such as `sc/ruby_client`, where `sc` is short for the person who contributed the work. As you'll remember, you can create the branch based off your master branch like this: +////////////////////////// +新しい機能を組み込もうと考えている場合は、トピックブランチを作ることをおすすめします。トピックブランチとは、新しく作業を始めるときに一時的に作るブランチのことです。 +そうすれば、そのパッチだけを個別にいじることができ、もしうまくいかなかったとしてもすぐに元の状態に戻すことができます。 +ブランチの名前は、今からやろうとしている作業の内容にあわせたシンプルな名前にしておきます。たとえば `ruby_client` などといったものです。そうすれば、しばらく時間をおいた後でそれを廃棄することになったときに、内容を思い出しやすくなります。 +Git プロジェクトのメンテナは、ブランチ名に名前空間を使うことが多いようです。たとえば `sc/ruby_client` のようになり、ここでの `sc` はその作業をしてくれた人の名前を短縮したものとなります。 +自分の master ブランチをもとにしたブランチを作成する方法は、このようになります。 [source,console] ----- $ git branch sc/ruby_client master ----- +////////////////////////// Or, if you want to also switch to it immediately, you can use the `checkout -b` option: +////////////////////////// +作成してすぐそのブランチに切り替えたい場合は、`checkout -b` オプションを使います。 [source,console] ----- $ git checkout -b sc/ruby_client master ----- +////////////////////////// Now you're ready to add your contributed work into this topic branch and determine if you want to merge it into your longer-term branches. +////////////////////////// +受け取った作業はこのトピックブランチですすめ、長期ブランチに統合するかどうかを判断することになります。 [[_patches_from_email]] +////////////////////////// ==== Applying Patches from E-mail +////////////////////////// +==== メールで受け取ったパッチの適用 (((email, applying patches from))) +////////////////////////// If you receive a patch over e-mail that you need to integrate into your project, you need to apply the patch in your topic branch to evaluate it. There are two ways to apply an e-mailed patch: with `git apply` or with `git am`. +////////////////////////// +あなたのプロジェクトへのパッチをメールで受け取った場合は、まずそれをトピックブランチに適用して中身を検証します。 +メールで届いたパッチを適用するには `git apply` と `git am` の二通りの方法があります。 +////////////////////////// ===== Applying a Patch with apply +////////////////////////// +===== apply によるパッチの適用 (((git commands, apply))) +////////////////////////// If you received the patch from someone who generated it with the `git diff` or a Unix `diff` command (which is not recommended; see the next section), you can apply it with the `git apply` command. Assuming you saved the patch at `/tmp/patch-ruby-client.patch`, you can apply the patch like this: +////////////////////////// +`git diff` あるいは Unix の `diff` コマンドで作ったパッチ(パッチの作り方としては推奨できません。次節で理由を説明します)を受け取ったときは、`git apply` コマンドを使ってパッチを適用します。 +パッチが `/tmp/patch-ruby-client.patch` にあるとすると、このようにすればパッチを適用できます。 [source,console] ----- $ git apply /tmp/patch-ruby-client.patch ----- +////////////////////////// This modifies the files in your working directory. It's almost identical to running a `patch -p1` command to apply the patch, although it's more paranoid and accepts fewer fuzzy matches than patch. It also handles file adds, deletes, and renames if they're described in the `git diff` format, which `patch` won't do. Finally, `git apply` is an ``apply all or abort all'' model where either everything is applied or nothing is, whereas `patch` can partially apply patchfiles, leaving your working directory in a weird state. `git apply` is overall much more conservative than `patch`. It won't create a commit for you – after running it, you must stage and commit the changes introduced manually. - +////////////////////////// +これは、作業ディレクトリ内のファイルを変更します。 +`patch -p1` コマンドでパッチをあてるのとほぼ同じなのですが、それ以上に「これでもか」というほどのこだわりを持ってパッチを適用するので fuzzy マッチになる可能性が少なくなります。 +また、`git diff` 形式ではファイルの追加・削除やファイル名の変更も扱うことができますが、`patch` コマンドにはそれはできません。 +そして最後に、`git apply` は「全部適用するか、あるいは一切適用しないか」というモデルを採用しています。一方 `patch` コマンドの場合は、途中までパッチがあたった中途半端な状態になって困ることがあります。 +`git apply` のほうが、 `patch` よりも慎重に処理を行うのです。 +`git apply` コマンドはコミットを作成するわけではありません。実行した後で、その変更をステージしてコミットする必要があります。 + +////////////////////////// You can also use git apply to see if a patch applies cleanly before you try actually applying it – you can run `git apply --check` with the patch: +////////////////////////// +git apply を使って、そのパッチをきちんと適用できるかどうかを事前に確かめることができます。パッチをチェックするには `git apply --check` を実行します。 [source,console] ----- @@ -62,20 +111,35 @@ error: patch failed: ticgit.gemspec:1 error: ticgit.gemspec: patch does not apply ----- +////////////////////////// If there is no output, then the patch should apply cleanly. This command also exits with a non-zero status if the check fails, so you can use it in scripts if you want. +////////////////////////// +何も出力されなければ、そのパッチはうまく適用できるということです。 +このコマンドは、チェックに失敗した場合にゼロ以外の値を返して終了します。スクリプト内でチェックしたい場合などにはこの返り値を使用します。 [[_git_am]] +////////////////////////// ===== Applying a Patch with `am` +////////////////////////// +===== `am` でのパッチの適用 (((git commands, am))) +////////////////////////// If the contributor is a Git user and was good enough to use the `format-patch` command to generate their patch, then your job is easier because the patch contains author information and a commit message for you. If you can, encourage your contributors to use `format-patch` instead of `diff` to generate patches for you. You should only have to use `git apply` for legacy patches and things like that. +////////////////////////// +コードを提供してくれた人が Git のユーザーで、`format-patch` コマンドを使ってパッチを送ってくれたとしましょう。この場合、あなたの作業はより簡単になります。パッチの中に、作者の情報やコミットメッセージも含まれているからです。 +「パッチを作るときには、できるだけ `diff` ではなく `format-patch` を使ってね」とお願いしてみるのもいいでしょう。 +昔ながらの形式のパッチが届いたときだけは `git apply` を使わなければならなくなります。 +////////////////////////// To apply a patch generated by `format-patch`, you use `git am`. Technically, `git am` is built to read an mbox file, which is a simple, plain-text format for storing one or more e-mail messages in one text file. It looks something like this: +////////////////////////// +`format-patch` で作ったパッチを適用するには `git am` を使います。技術的なお話をすると、`git am` は mbox ファイルを読み込む仕組みになっています。mbox はシンプルなプレーンテキスト形式で、一通あるいは複数のメールのメッセージをひとつのテキストファイルにまとめるためのものです。中身はこのようになります。 [source,console] ----- @@ -87,12 +151,21 @@ Subject: [PATCH 1/2] add limit to log function Limit log functionality to the first 20 ----- +////////////////////////// This is the beginning of the output of the format-patch command that you saw in the previous section. This is also a valid mbox e-mail format. If someone has e-mailed you the patch properly using git send-email, and you download that into an mbox format, then you can point git am to that mbox file, and it will start applying all the patches it sees. If you run a mail client that can save several e-mails out in mbox format, you can save entire patch series into a file and then use git am to apply them one at a time. +////////////////////////// +先ほどのセクションでごらんいただいたように、format-patch コマンドの出力結果もこれと同じ形式で始まっていますね。 +これは、mbox 形式のメールフォーマットとしても正しいものです。 +git send-email を正しく使ったパッチが送られてきた場合、受け取ったメールを mbox 形式で保存して git am コマンドでそのファイルを指定すると、すべてのパッチの適用が始まります。 +複数のメールをまとめてひとつの mbox に保存できるメールソフトを使っていれば、送られてきたパッチをひとつのファイルにまとめて git am で一度に適用することもできます。 +////////////////////////// However, if someone uploaded a patch file generated via `format-patch` to a ticketing system or something similar, you can save the file locally and then pass that file saved on your disk to `git am` to apply it: +////////////////////////// +しかし、`format-patch` で作ったパッチがチケットシステム (あるいはそれに類する何か) にアップロードされたような場合は、まずそのファイルをローカルに保存して、それを `git am` に渡すことになります。 [source,console] ----- @@ -100,9 +173,12 @@ $ git am 0001-limit-log-function.patch Applying: add limit to log function ----- +////////////////////////// You can see that it applied cleanly and automatically created the new commit for you. The author information is taken from the e-mail's `From` and `Date` headers, and the message of the commit is taken from the `Subject` and body (before the patch) of the e-mail. For example, if this patch was applied from the mbox example above, the commit generated would look something like this: +////////////////////////// +どんなパッチを適用したのかが表示され、コミットも自動的に作られます。作者の情報はメールの `From` ヘッダと `Date` ヘッダから取得し、コミットメッセージは `Subject` とメールの本文 (パッチより前の部分) から取得します。たとえば、先ほどごらんいただいた mbox の例にあるパッチを適用した場合は次のようなコミットとなります。 ----- $ git log --pretty=fuller -1 @@ -117,12 +193,21 @@ CommitDate: Thu Apr 9 09:19:06 2009 -0700 Limit log functionality to the first 20 ----- +////////////////////////// The `Commit` information indicates the person who applied the patch and the time it was applied. The `Author` information is the individual who originally created the patch and when it was originally created. +////////////////////////// +`Commit` には、そのパッチを適用した人と適用した日時が表示されます。 +`Author` には、そのパッチを実際に作成した人と作成した日時が表示されます。 +////////////////////////// But it's possible that the patch won't apply cleanly. Perhaps your main branch has diverged too far from the branch the patch was built from, or the patch depends on another patch you haven't applied yet. In that case, the `git am` process will fail and ask you what you want to do: +////////////////////////// +しかし、パッチが常にうまく適用できるとは限りません。 +パッチを作成したときの状態と現在のメインブランチとが大きくかけ離れてしまっていたり、そのパッチが別の (まだ適用していない) パッチに依存していたりなどといったことがあり得るでしょう。 +そんな場合は `git am` は失敗し、次にどうするかを聞かれます。 [source,console] ----- @@ -136,20 +221,37 @@ If you would prefer to skip this patch, instead run "git am --skip". To restore the original branch and stop patching run "git am --abort". ----- +////////////////////////// This command puts conflict markers in any files it has issues with, much like a conflicted merge or rebase operation. You solve this issue much the same way – edit the file to resolve the conflict, stage the new file, and then run `git am --resolved` to continue to the next patch: +////////////////////////// +このコマンドは、何か問題が発生したファイルについて衝突マークを書き込みます。これは、マージやリベースに失敗したときに書き込まれるのとよく似たものです。 +問題を解決する方法も同じです。まずはファイルを編集して衝突を解決し、新しいファイルをステージし、`git am --resolved` を実行して次のパッチに進みます。 [source,console] +////////////////////////// ----- $ (fix the file) $ git add ticgit.gemspec $ git am --resolved Applying: seeing if this helps the gem ----- +////////////////////////// +----- +$ (ファイルを編集する) +$ git add ticgit.gemspec +$ git am --resolved +Applying: seeing if this helps the gem +----- +////////////////////////// If you want Git to try a bit more intelligently to resolve the conflict, you can pass a `-3` option to it, which makes Git attempt a three-way merge. This option isn't on by default because it doesn't work if the commit the patch says it was based on isn't in your repository. If you do have that commit – if the patch was based on a public commit – then the `-3` option is generally much smarter about applying a conflicting patch: +////////////////////////// +Git にもうちょっと賢く働いてもらって衝突を回避したい場合は、`-3` オプションを使用します。これは、Git で三方向のマージを行うオプションです。 +このオプションはデフォルトでは有効になっていません。適用するパッチの元になっているコミットがあなたのリポジトリ上のものでない場合に正しく動作しないからです。 +パッチの元になっているコミットが手元にある場合は、`-3` オプションを使うと、衝突しているパッチをうまく適用できます。 [source,console] ----- @@ -162,10 +264,17 @@ Falling back to patching base and 3-way merge... No changes -- Patch already applied. ----- +////////////////////////// In this case, this patch had already been applied. Without the `-3` option, it looks like a conflict. +////////////////////////// +ここでは、既に適用済みのパッチを適用してみました。 +`-3` オプションがなければ、衝突が発生していたことでしょう。 +////////////////////////// If you're applying a number of patches from an mbox, you can also run the `am` command in interactive mode, which stops at each patch it finds and asks if you want to apply it: +////////////////////////// +たくさんのパッチが含まれる mbox からパッチを適用するときには、`am` コマンドを対話モードで実行することもできます。パッチが見つかるたびに処理を止め、それを適用するかどうかの確認を求められます。 [source,console] ----- @@ -177,17 +286,32 @@ seeing if this helps the gem Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all ----- +////////////////////////// This is nice if you have a number of patches saved, because you can view the patch first if you don't remember what it is, or not apply the patch if you've already done so. +////////////////////////// +これは、「大量にあるパッチについて、内容をまず一通り確認したい」「既に適用済みのパッチは適用しないようにしたい」などの場合に便利です。 +////////////////////////// When all the patches for your topic are applied and committed into your branch, you can choose whether and how to integrate them into a longer-running branch. +////////////////////////// +トピックブランチ上でそのトピックに関するすべてのパッチの適用を済ませてコミットすれば、次はそれを長期ブランチに統合するかどうか (そしてどのように統合するか) を考えることになります。 [[_checking_out_remotes]] +////////////////////////// ==== Checking Out Remote Branches +////////////////////////// +==== リモートブランチのチェックアウト (((branches, remote))) +////////////////////////// If your contribution came from a Git user who set up their own repository, pushed a number of changes into it, and then sent you the URL to the repository and the name of the remote branch the changes are in, you can add them as a remote and do merges locally. +////////////////////////// +自前のリポジトリを持つ Git ユーザーが自分のリポジトリに変更をプッシュし、そのリポジトリの URL とリモートブランチ名だけをあなたにメールで連絡してきた場合のことを考えてみましょう。そのリポジトリをリモートとして登録し、それをローカルにマージすることになります。 +////////////////////////// For instance, if Jessica sends you an e-mail saying that she has a great new feature in the `ruby-client` branch of her repository, you can test it by adding the remote and checking out that branch locally: +////////////////////////// +Jessica から「すばらしい新機能を作ったので、私のリポジトリの `ruby-client` ブランチを見てください」といったメールが来たとします。これを手元でテストするには、リモートとしてこのリポジトリを追加し、ローカルにブランチをチェックアウトします。 [source,console] ----- @@ -196,18 +320,35 @@ $ git fetch jessica $ git checkout -b rubyclient jessica/ruby-client ----- +////////////////////////// If she e-mails you again later with another branch containing another great feature, you can fetch and check out because you already have the remote setup. +////////////////////////// +「この前のとは違う、別のすばらしい機能を作ったの!」と別のブランチを伝えられた場合は、すでにリモートの設定が済んでいるので単にそのブランチを取得してチェックアウトするだけで確認できます。 +////////////////////////// This is most useful if you're working with a person consistently. If someone only has a single patch to contribute once in a while, then accepting it over e-mail may be less time consuming than requiring everyone to run their own server and having to continually add and remove remotes to get a few patches. You're also unlikely to want to have hundreds of remotes, each for someone who contributes only a patch or two. However, scripts and hosted services may make this easier – it depends largely on how you develop and how your contributors develop. +////////////////////////// +この方法は、誰かと継続的に共同作業を進めていく際に便利です。 +ちょっとしたパッチをたまに提供してくれるだけの人の場合は、パッチをメールで受け取るようにしたほうが時間の節約になるでしょう。全員に自前のサーバーを用意させて、たまに送られてくるパッチを取得するためだけに定期的にリモートの追加と削除を行うなどというのは時間の無駄です。 +ほんの数件のパッチを提供してくれる人たちを含めて数百ものリモートを管理することなど、きっとあなたはお望みではないでしょう。 +しかし、スクリプトやホスティングサービスを使えばこの手の作業は楽になります。つまり、どのような方式をとるかは、あなたや他のメンバーがどのような方式で開発を進めるかによって決まります。 +////////////////////////// The other advantage of this approach is that you get the history of the commits as well. Although you may have legitimate merge issues, you know where in your history their work is based; a proper three-way merge is the default rather than having to supply a `-3` and hope the patch was generated off a public commit to which you have access. +////////////////////////// +この方式のもうひとつの利点は、コミットの履歴も同時に取得できるということです。 +マージの際に問題が起こることもあるでしょうが、そんな場合にも相手の作業が自分側のどの地点に基づくものなのかを知ることができます。適切に三方向のマージが行われるので、`-3` を指定したときに「このパッチの基点となるコミットにアクセスできればいいなぁ」と祈る必要はありません。 +////////////////////////// If you aren't working with a person consistently but still want to pull from them in this way, you can provide the URL of the remote repository to the `git pull` command. This does a one-time pull and doesn't save the URL as a remote reference: +////////////////////////// +継続的に共同作業を続けるわけではないけれど、それでもこの方式でパッチを取得したいという場合は、リモートリポジトリの URL を `git pull` コマンドで指定することもできます。 +これは一度きりのプルに使うものであり、リモートを参照する URL は保存されません。 [source,console] ----- @@ -218,17 +359,31 @@ Merge made by recursive. ----- [[_what_is_introduced]] +////////////////////////// ==== Determining What Is Introduced +////////////////////////// +==== 何が変わるのかの把握 (((branches, diffing))) +////////////////////////// Now you have a topic branch that contains contributed work. At this point, you can determine what you'd like to do with it. This section revisits a couple of commands so you can see how you can use them to review exactly what you'll be introducing if you merge this into your main branch. +////////////////////////// +トピックブランチの中に、提供してもらった作業が含まれた状態になりました。 +次に何をすればいいのか考えてみましょう。 +このセクションでは、これまでに扱ったいくつかのコマンドを復習します。それらを使って、もしこの変更をメインブランチにマージしたらいったい何が起こるのかを調べていきましょう。 +////////////////////////// It's often helpful to get a review of all the commits that are in this branch but that aren't in your master branch. You can exclude commits in the master branch by adding the `--not` option before the branch name. This does the same thing as the `master..contrib` format that we used earlier. For example, if your contributor sends you two patches and you create a branch called `contrib` and applied those patches there, you can run this: +////////////////////////// +トピックブランチのコミットのうち、master ブランチに存在しないコミットの内容をひとつひとつレビューできれば便利でしょう。 +master ブランチに含まれるコミットを除外するには、ブランチ名の前に `--not` オプションを指定します。 +これは、これまで使ってきた `master..contrib` という書式と同じ役割を果たしてくれます。 +たとえば、誰かから受け取った二つのパッチを適用するために `contrib` というブランチを作成したとすると、 [source,console] ----- @@ -246,27 +401,50 @@ Date: Mon Oct 22 19:38:36 2008 -0700 updated the gemspec to hopefully work better ----- +////////////////////////// To see what changes each commit introduces, remember that you can pass the `-p` option to `git log` and it will append the diff introduced to each commit. +////////////////////////// +このようなコマンドを実行すればそれぞれのコミットの内容を確認できます。`git log` に `-p` オプションを渡せば、コミットの後に diff を表示させることもできます。これも以前に説明しましたね。 +////////////////////////// To see a full diff of what would happen if you were to merge this topic branch with another branch, you may have to use a weird trick to get the correct results. You may think to run this: +////////////////////////// +このトピックブランチを別のブランチにマージしたときに何が起こるのかを完全な diff で知りたい場合は、ちょっとした裏技を使わないと正しい結果が得られません。 +おそらく「こんなコマンドを実行するだけじゃないの?」と考えておられることでしょう。 [source,console] ----- $ git diff master ----- +////////////////////////// This command gives you a diff, but it may be misleading. If your `master` branch has moved forward since you created the topic branch from it, then you'll get seemingly strange results. This happens because Git directly compares the snapshots of the last commit of the topic branch you're on and the snapshot of the last commit on the `master` branch. For example, if you've added a line in a file on the `master` branch, a direct comparison of the snapshots will look like the topic branch is going to remove that line. +////////////////////////// +このコマンドで表示される diff は、誤解を招きかねないものです。 +トピックブランチを切った時点からさらに `master` ブランチが先に進んでいたとすると、これは少し奇妙に見える結果を返します。 +というのも、Git は現在のトピックブランチの最新のコミットのスナップショットと `master` ブランチの最新のコミットのスナップショットを直接比較するからです。 +トピックブランチを切った後に `master` ブランチ上であるファイルに行を追加したとすると、スナップショットを比較した結果は「トピックブランチでその行を削除しようとしている」状態になります。 +////////////////////////// If `master` is a direct ancestor of your topic branch, this isn't a problem; but if the two histories have diverged, the diff will look like you're adding all the new stuff in your topic branch and removing everything unique to the `master` branch. +////////////////////////// +`master` がトピックブランチの直系の先祖である場合は、これは特に問題とはなりません。しかし二つの歴史が分岐している場合には、diff の結果は「トピックブランチで新しく追加したすべての内容を追加し、`master` ブランチにしかないものはすべて削除する」というものになります。 +////////////////////////// What you really want to see are the changes added to the topic branch – the work you'll introduce if you merge this branch with master. You do that by having Git compare the last commit on your topic branch with the first common ancestor it has with the master branch. +////////////////////////// +本当に知りたいのはトピックブランチで変更された内容、つまりこのブランチを master にマージしたときに master に加わる変更です。 +これを知るには、Git に「トピックブランチの最新のコミット」と「トピックブランチと master ブランチの直近の共通の先祖」とを比較させます。 +////////////////////////// Technically, you can do that by explicitly figuring out the common ancestor and then running your diff on it: +////////////////////////// +共通の先祖を見つけだしてそこからの diff を取得するには、このようにします。 [source,console] ----- @@ -275,105 +453,213 @@ $ git merge-base contrib master $ git diff 36c7db ----- +////////////////////////// However, that isn't convenient, so Git provides another shorthand for doing the same thing: the triple-dot syntax. In the context of the `diff` command, you can put three periods after another branch to do a `diff` between the last commit of the branch you're on and its common ancestor with another branch: +////////////////////////// +しかし、これでは不便です。そこで Git には、同じことをより手短にやるための手段としてトリプルドット構文が用意されています。 +`diff` コマンドを実行するときにピリオドを三つ打った後に別のブランチを指定すると、「現在いるブランチの最新のコミット」と「指定した二つのブランチの共通の先祖」とを比較するようになります。 [source,console] ----- $ git diff master...contrib ----- +////////////////////////// This command shows you only the work your current topic branch has introduced since its common ancestor with master. That is a very useful syntax to remember. +////////////////////////// +このコマンドは、master との共通の先祖から分岐した現在のトピックブランチで変更された内容のみを表示します。 +この構文は、覚えやすいので非常に便利です。 +////////////////////////// ==== Integrating Contributed Work +////////////////////////// +==== 提供された作業の取り込み (((integrating work))) +////////////////////////// When all the work in your topic branch is ready to be integrated into a more mainline branch, the question is how to do it. Furthermore, what overall workflow do you want to use to maintain your project? You have a number of choices, so we'll cover a few of them. +////////////////////////// +トピックブランチでの作業をメインブランチに取り込む準備ができたら、どのように取り込むかを考えることになります。 +さらに、プロジェクトを運営していくにあたっての全体的な作業の流れはどのようにしたらいいでしょうか? +さまざまな方法がありますが、ここではそのうちのいくつかを紹介します。 +////////////////////////// ===== Merging Workflows +////////////////////////// +===== マージのワークフロー (((workflows, merging))) +////////////////////////// One simple workflow merges your work into your `master` branch. In this scenario, you have a `master` branch that contains basically stable code. When you have work in a topic branch that you've done or that someone has contributed and you've verified, you merge it into your master branch, delete the topic branch, and then continue the process. If we have a repository with work in two branches named `ruby_client` and `php_client` that looks like <> and merge `ruby_client` first and then `php_client` next, then your history will end up looking like <>. +////////////////////////// +シンプルなワークフローのひとつとして、作業を自分の `master` ブランチに取り込むことを考えます。 +ここでは、`master` ブランチで安定版のコードを管理しているものとします。 +トピックブランチでの作業が一段落したら (あるいは誰かから受け取ったパッチをトピックブランチ上で検証し終えたら)、それを master ブランチにマージしてからトピックブランチを削除し、作業を進めることになります。 +`ruby_client` および `php_client` の二つのブランチを持つ <> のようなリポジトリでまず `ruby_client` をマージしてから `php_client` もマージすると、歴史は <> のようになります。 [[merwf_a]] +////////////////////////// .History with several topic branches. image::images/merging-workflows-1.png[History with several topic branches.] +////////////////////////// +.いくつかのトピックブランチを含む履歴 +image::images/merging-workflows-1.png[いくつかのトピックブランチを含む履歴] [[merwf_b]] +////////////////////////// .After a topic branch merge. image::images/merging-workflows-2.png[After a topic branch merge.] +////////////////////////// +.トピックブランチをマージした後の状態 +image::images/merging-workflows-2.png[トピックブランチをマージした後の状態] +////////////////////////// That is probably the simplest workflow, but it can possibly be problematic if you're dealing with larger or more stable projects where you want to be really careful about what you introduce. +////////////////////////// +これがおそらく一番シンプルなワークフローでしょう。ただし、それが問題になることもあります。大規模プロジェクトや安定しているプロジェクトのように、何を受け入れるかを慎重に決めなければいけない場合です。 +////////////////////////// If you have a more important project, you might want to use a two-phase merge cycle. In this scenario, you have two long-running branches, `master` and `develop`, in which you determine that `master` is updated only when a very stable release is cut and all new code is integrated into the `develop` branch. You regularly push both of these branches to the public repository. Each time you have a new topic branch to merge in (<>), you merge it into `develop` (<>); then, when you tag a release, you fast-forward `master` to wherever the now-stable `develop` branch is (<>). +////////////////////////// +より重要なプロジェクトの場合は、二段階のマージサイクルを使うこともあるでしょう。 +ここでは、長期間運用するブランチが `master` と `develop` のふたつあるものとします。`master` が更新されるのは安定版がリリースされるときだけで、新しいコードはずべて `develop` ブランチに統合されるという流れです。 +これらのブランチは、両方とも定期的に公開リポジトリにプッシュすることになります。 +新しいトピックブランチをマージする準備ができたら (<>)、それを `develop` にマージします (<>)。そしてリリースタグを打つときに、`master` を現在の `develop` ブランチが指す位置に進めます (<>)。 [[merwf_c]] +////////////////////////// .Before a topic branch merge. image::images/merging-workflows-3.png[Before a topic branch merge.] +////////////////////////// +.トピックブランチのマージ前 +image::images/merging-workflows-3.png[トピックブランチのマージ前] [[merwf_d]] +////////////////////////// .After a topic branch merge. image::images/merging-workflows-4.png[After a topic branch merge.] +////////////////////////// +.トピックブランチのマージ後 +image::images/merging-workflows-4.png[トピックブランチのマージ後] [[merwf_e]] +////////////////////////// .After a project release. image::images/merging-workflows-5.png[After a topic branch release.] +////////////////////////// +.プロジェクトのリリース後 +image::images/merging-workflows-5.png[トピックブランチのリリース後] +////////////////////////// This way, when people clone your project's repository, they can either check out master to build the latest stable version and keep up to date on that easily, or they can check out develop, which is the more cutting-edge stuff. You can also continue this concept, having an integrate branch where all the work is merged together. Then, when the codebase on that branch is stable and passes tests, you merge it into a develop branch; and when that has proven itself stable for a while, you fast-forward your master branch. +////////////////////////// +他の人があなたのプロジェクトをクローンするときには、master をチェックアウトすれば最新の安定版をビルドすることができ、その後の更新を追いかけるのも容易にできるようになります。一方 develop をチェックアウトすれば、さらに最先端の状態を取得することができます。 +この考え方を推し進めると、統合用のブランチを用意してすべての作業をいったんそこにマージするようにもできます。 +統合ブランチ上のコードが安定してテストを通過すれば、それを develop ブランチにマージします。そしてそれが安定していることが確認できたら master ブランチを先に進めるということになります。 +////////////////////////// ===== Large-Merging Workflows +////////////////////////// +===== 大規模マージのワークフロー (((workflows, "merging (large)"))) +////////////////////////// The Git project has four long-running branches: `master`, `next`, and `pu` (proposed updates) for new work, and `maint` for maintenance backports. When new work is introduced by contributors, it's collected into topic branches in the maintainer's repository in a manner similar to what we've described (see <>). At this point, the topics are evaluated to determine whether they're safe and ready for consumption or whether they need more work. If they're safe, they're merged into `next`, and that branch is pushed up so everyone can try the topics integrated together. +////////////////////////// +Git 開発プロジェクトには、常時稼働するブランチが四つあります。`master`、`next`、そして新しい作業用の `pu` (proposed updates) とメンテナンスバックポート用の `maint` です。 +新しいコードを受け取ったメンテナは、まず自分のリポジトリのトピックブランチにそれを格納します。先ほど説明したのと同じ方式です ( <> を参照ください)。 +そしてその内容を検証し、安全に取り込める状態かさらなる作業が必要かを見極めます。 +だいじょうぶだと判断したらそれを `next` にマージします。このブランチをプッシュすれば、すべてのメンバーがそれを試せるようになります。 [[merwf_f]] +////////////////////////// .Managing a complex series of parallel contributed topic branches. image::images/large-merges-1.png[Managing a complex series of parallel contributed topic branches.] +////////////////////////// +.複数のトピックブランチの並行管理 +image::images/large-merges-1.png[複数のトピックブランチの並行管理] +////////////////////////// If the topics still need work, they're merged into `pu` instead. When it's determined that they're totally stable, the topics are re-merged into `master` and are then rebuilt from the topics that were in `next` but didn't yet graduate to `master`. This means `master` almost always moves forward, `next` is rebased occasionally, and `pu` is rebased even more often: +////////////////////////// +さらに作業が必要なトピックについては、`pu` にマージします。 +完全に安定していると判断されたトピックについては改めて `master` にマージされ、`next` にあるトピックのうちまだ `master` に入っていないものを再構築します。 +つまり、`master` はほぼ常に前に進み、`next` は時々リベースされ、`pu` はそれ以上の頻度でリベースされることになります。 +////////////////////////// .Merging contributed topic branches into long-term integration branches. image::images/large-merges-2.png[Merging contributed topic branches into long-term integration branches.] +////////////////////////// +.常時稼働する統合用ブランチへのトピックブランチのマージ +image::images/large-merges-2.png[常時稼働する統合用ブランチへのトピックブランチのマージ] +////////////////////////// When a topic branch has finally been merged into `master`, it's removed from the repository. The Git project also has a `maint` branch that is forked off from the last release to provide backported patches in case a maintenance release is required. Thus, when you clone the Git repository, you have four branches that you can check out to evaluate the project in different stages of development, depending on how cutting edge you want to be or how you want to contribute; and the maintainer has a structured workflow to help them vet new contributions. +////////////////////////// +最終的に `master` にマージされたトピックブランチは、リポジトリから削除します。 +Git 開発プロジェクトでは `maint` ブランチも管理しています。これは最新のリリースからフォークしたもので、メンテナンスリリースに必要なバックポート用のパッチを管理します。 +つまり、Git のリポジトリをクローンするとあなたは四つのブランチをチェックアウトすることができるということです。これらのブランチはどれも異なる開発段階を表し、「どこまで最先端を追いかけたいか」「どのように Git プロジェクトに貢献したいか」によって使い分けることになります。メンテナ側では、新たな貢献を受け入れるためのワークフローが整っています。 [[_rebase_cherry_pick]] +////////////////////////// ===== Rebasing and Cherry Picking Workflows +////////////////////////// +===== リベースとチェリーピックのワークフロー (((workflows, rebasing and cherry-picking))) +////////////////////////// Other maintainers prefer to rebase or cherry-pick contributed work on top of their master branch, rather than merging it in, to keep a mostly linear history. When you have work in a topic branch and have determined that you want to integrate it, you move to that branch and run the rebase command to rebuild the changes on top of your current master (or `develop`, and so on) branch. If that works well, you can fast-forward your `master` branch, and you'll end up with a linear project history. +////////////////////////// +受け取った作業を master ブランチにマージするのではなく、リベースやチェリーピックを使って master ブランチの先端につなげていく方法を好むメンテナもいます。そのほうがほぼ直線的な歴史を保てるからです。 +トピックブランチでの作業を終えて統合できる状態になったと判断したら、そのブランチで rebase コマンドを実行し、その変更を現在の master (あるいは `develop` などの) ブランチの先端につなげます。 +うまくいけば、`master` ブランチをそのまま前に進めてることでプロジェクトの歴史を直線的に進めることができます。 (((git commands, cherry-pick))) +////////////////////////// The other way to move introduced work from one branch to another is to cherry-pick it. A cherry-pick in Git is like a rebase for a single commit. It takes the patch that was introduced in a commit and tries to reapply it on the branch you're currently on. This is useful if you have a number of commits on a topic branch and you want to integrate only one of them, or if you only have one commit on a topic branch and you'd prefer to cherry-pick it rather than run rebase. For example, suppose you have a project that looks like this: - +////////////////////////// +あるブランチの作業を別のブランチに移すための手段として、他にチェリーピック (つまみぐい) という方法があります。 +Git におけるチェリーピックとは、コミット単位でのリベースのようなものです。 +あるコミットによって変更された内容をパッチとして受け取り、それを現在のブランチに再適用します。 +トピックブランチでいくつかコミットしたうちのひとつだけを統合したい場合、あるいはトピックブランチで一回だけコミットしたけれどそれをリベースではなくチェリーピックで取り込みたい場合などにこの方法を使用します。 +以下のようなプロジェクトを例にとって考えましょう。 + +////////////////////////// .Example history before a cherry-pick. image::images/rebasing-1.png[Example history before a cherry-pick.] +////////////////////////// +.チェリーピック前の歴史 +image::images/rebasing-1.png[チェリーピック前の歴史] +////////////////////////// If you want to pull commit `e43a6` into your master branch, you can run +////////////////////////// +コミット `e43a6` を master ブランチに取り込むには、次のようにします。 [source,console] ----- @@ -383,43 +669,80 @@ Finished one cherry-pick. 3 files changed, 17 insertions(+), 3 deletions(-) ----- +////////////////////////// This pulls the same change introduced in `e43a6`, but you get a new commit SHA-1 value, because the date applied is different. Now your history looks like this: +////////////////////////// +これは `e43a6` と同じ内容の変更を施しますが、コミットの SHA-1 値は新しくなります。適用した日時が異なるからです。 +これで、歴史は次のように変わりました。 +////////////////////////// .History after cherry-picking a commit on a topic branch. image::images/rebasing-2.png[History after cherry-picking a commit on a topic branch.] +////////////////////////// +.トピックブランチのコミットをチェリーピックした後の歴史 +image::images/rebasing-2.png[トピックブランチのコミットをチェリーピックした後の歴史] +////////////////////////// Now you can remove your topic branch and drop the commits you didn't want to pull in. +////////////////////////// +あとは、このトピックブランチを削除すれば取り込みたくない変更を消してしまうことができます。 ===== Rerere (((git commands, rerere)))(((rerere))) +////////////////////////// If you're doing lots of merging and rebasing, or you're maintaining a long-lived topic branch, Git has a feature called ``rerere'' that can help. +////////////////////////// +マージやリベースを頻繁に行っているなら、もしくは長く続いているトピックブランチをメンテナンスしているなら、Git の ``rerere'' という機能が役に立つでしょう。 +////////////////////////// Rerere stands for ``reuse recorded resolution'' – it's a way of shortcutting manual conflict resolution. When rerere is enabled, Git will keep a set of pre- and post-images from successful merges, and if it notices that there's a conflict that looks exactly like one you've already fixed, it'll just use the fix from last time, without bothering you with it. +////////////////////////// +Rerere は ``reuse recorded resolution'' の略で、コンフリクトを手っ取り早く手動で解消するための方法です。 +////////////////////////// This feature comes in two parts: a configuration setting and a command. The configuration setting is `rerere.enabled`, and it's handy enough to put in your global config: +////////////////////////// +この機能で用いるのは、設定とコマンドの2つです。 +まず設定のほうは `rerere.enabled` という項目を用います。Git のグローバル設定に登録しておくとよいでしょう。 [source,console] ---- $ git config --global rerere.enabled true ---- +////////////////////////// Now, whenever you do a merge that resolves conflicts, the resolution will be recorded in the cache in case you need it in the future. +////////////////////////// +一度この設定をしておくと、コンフリクトを手動で解消してマージするたびにその内容がキャッシュに記録され、のちのち使えるようになります。 +////////////////////////// If you need to, you can interact with the rerere cache using the `git rerere` command. When it's invoked alone, Git checks its database of resolutions and tries to find a match with any current merge conflicts and resolve them (although this is done automatically if `rerere.enabled` is set to `true`). There are also subcommands to see what will be recorded, to erase specific resolution from the cache, and to clear the entire cache. We will cover rerere in more detail in <<_rerere>>. +////////////////////////// +必要に応じてキャッシュを操作することもできます。`git rerere` コマンドを使うのです。 +このコマンドをオプションなしで実行するとキャッシュが検索され、コンフリクトの内容に合致するものがある場合はそれを用いてコンフリクトの解消が試みられます(ただし、`rerere.enabled` が `true` に設定されている場合、一連の処理は自動で行われます)。 +また、サブコマンドも複数用意されています。それらを使うと、キャッシュされようとしている内容の確認、キャッシュされた内容を指定して削除、キャッシュをすべて削除、などができるようになります。rerere については <<_rerere>> で詳しく説明します。 [[_tagging_releases]] +////////////////////////// ==== Tagging Your Releases +////////////////////////// +==== リリース用のタグ付け (((tags)))(((tags, signing))) +////////////////////////// When you've decided to cut a release, you'll probably want to drop a tag so you can re-create that release at any point going forward. You can create a new tag as discussed in <<_git_basics_chapter>>. If you decide to sign the tag as the maintainer, the tagging may look something like this: +////////////////////////// +いよいよリリースする時がきました。おそらく、後からいつでもこのリリースを取得できるようにタグを打っておくことになるでしょう。 +新しいタグを打つ方法は <<_git_basics_chapter>> で説明しました。 +タグにメンテナの署名を入れておきたい場合は、このようにします。 [source,console] ----- @@ -429,9 +752,14 @@ user: "Scott Chacon " 1024-bit DSA key, ID F721C45A, created 2009-02-09 ----- +////////////////////////// If you do sign your tags, you may have the problem of distributing the public PGP key used to sign your tags. The maintainer of the Git project has solved this issue by including their public key as a blob in the repository and then adding a tag that points directly to that content. To do this, you can figure out which key you want by running `gpg --list-keys`: +////////////////////////// +タグに署名した場合、署名に使用した PGP 鍵ペアの公開鍵をどのようにして配布するかが問題になるかもしれません。 +Git 開発プロジェクトのメンテナ達がこの問題をどのように解決したかというと、自分たちの公開鍵を blob としてリポジトリに含め、それを直接指すタグを追加することにしました。 +この方法を使うには、まずどの鍵を使うかを決めるために `gpg --list-keys` を実行します。 [source,console] ----- @@ -443,7 +771,10 @@ uid Scott Chacon sub 2048g/45D02282 2009-02-09 [expires: 2010-02-09] ----- +////////////////////////// Then, you can directly import the key into the Git database by exporting it and piping that through `git hash-object`, which writes a new blob with those contents into Git and gives you back the SHA-1 of the blob: +////////////////////////// +鍵を直接 Git データベースにインポートするには、鍵をエクスポートしてそれをパイプで `git hash-object` に渡します。これは、鍵の中身を新しい blob として Git に書き込み、その blob の SHA-1 を返します。 [source,console] ----- @@ -451,30 +782,46 @@ $ gpg -a --export F721C45A | git hash-object -w --stdin 659ef797d181633c87ec71ac3f9ba29fe5775b92 ----- +////////////////////////// Now that you have the contents of your key in Git, you can create a tag that points directly to it by specifying the new SHA-1 value that the `hash-object` command gave you: +////////////////////////// +鍵の中身を Git に取り込めたので、この鍵を直接指定するタグを作成できるようになりました。`hash-object` コマンドで知った SHA-1 値を指定すればいいのです。 [source,console] ----- $ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92 ----- +////////////////////////// If you run `git push --tags`, the `maintainer-pgp-pub` tag will be shared with everyone. If anyone wants to verify a tag, they can directly import your PGP key by pulling the blob directly out of the database and importing it into GPG: +////////////////////////// +`git push --tags` を実行すると、`maintainer-pgp-pub` タグをみんなと共有できるようになります。誰かがタグを検証したい場合は、あなたの PGP 鍵が入った blob をデータベースから直接プルで取得し、それを PGP にインポートすればいいのです。 [source,console] ----- $ git show maintainer-pgp-pub | gpg --import ----- +////////////////////////// They can use that key to verify all your signed tags. Also, if you include instructions in the tag message, running `git show ` will let you give the end user more specific instructions about tag verification. +////////////////////////// +この鍵をインポートした人は、あなたが署名したすべてのタグを検証できるようになります。タグのメッセージに検証手順の説明を含めておけば、`git show ` でエンドユーザー向けに詳しい検証手順を示すことができます。 [[_build_number]] +////////////////////////// ==== Generating a Build Number +////////////////////////// +==== ビルド番号の生成 (((build numbers)))(((git commands, describe))) +////////////////////////// Because Git doesn't have monotonically increasing numbers like 'v123' or the equivalent to go with each commit, if you want to have a human-readable name to go with a commit, you can run `git describe` on that commit. Git gives you the name of the nearest tag with the number of commits on top of that tag and a partial SHA-1 value of the commit you're describing: +////////////////////////// +Git では、コミットごとに 'v123' のような単調な番号を振っていくことはありません。もし特定のコミットに対して人間がわかりやすい名前がほしければ、そのコミットに対して `git describe` を実行します。 +Git は、そのコミットに最も近いタグの名前とそのタグからのコミット数、そしてそのコミットの SHA-1 値の一部を使った名前を作成します。 [source,console] ----- @@ -482,21 +829,39 @@ $ git describe master v1.6.2-rc1-20-g8c5b85c ----- +////////////////////////// This way, you can export a snapshot or build and name it something understandable to people. In fact, if you build Git from source code cloned from the Git repository, `git --version` gives you something that looks like this. If you're describing a commit that you have directly tagged, it gives you the tag name. +////////////////////////// +これで、スナップショットやビルドを公開するときにわかりやすい名前をつけられるようになります。 +実際、Git そのもののソースコードを Git リポジトリからクローンしてビルドすると、`git --version` が返す結果はこの形式になります。 +タグが打たれているコミットを直接指定した場合は、タグの名前が返されます。 +////////////////////////// The `git describe` command favors annotated tags (tags created with the `-a` or `-s` flag), so release tags should be created this way if you're using `git describe`, to ensure the commit is named properly when described. You can also use this string as the target of a checkout or show command, although it relies on the abbreviated SHA-1 value at the end, so it may not be valid forever. For instance, the Linux kernel recently jumped from 8 to 10 characters to ensure SHA-1 object uniqueness, so older `git describe` output names were invalidated. +////////////////////////// +`git describe` コマンドは注釈付きのタグ (`-a` あるいは `-s` フラグをつけて作成したタグ) を使います。したがって、`git describe` を使うならリリースタグは注釈付きのタグとしなければなりません。そうすれば、describe したときにコミットの名前を適切につけることができます。 +この文字列を checkout コマンドや show コマンドでの対象の指定に使うこともできますが、これは末尾にある SHA-1 値の省略形に依存しているので将来にわたってずっと使えるとは限りません。 +たとえば Linux カーネルは、最近 SHA-1 オブジェクトの一意性を確認するための文字数を 8 文字から 10 文字に変更しました。そのため、古い `git describe` の出力での名前はもはや使えません。 [[_preparing_release]] +////////////////////////// ==== Preparing a Release +////////////////////////// +==== リリースの準備 (((releasing)))(((git commands, archive))) +////////////////////////// Now you want to release a build. One of the things you'll want to do is create an archive of the latest snapshot of your code for those poor souls who don't use Git. The command to do this is `git archive`: +////////////////////////// +実際にリリースするにあたって行うであろうことのひとつに、最新のスナップショットのアーカイブを作るという作業があります。 +Git を使っていないというかわいそうな人たちにもコードを提供するために。 +その際に使用するコマンドは `git archive` です。 [source,console] ----- @@ -505,23 +870,38 @@ $ ls *.tar.gz v1.6.2-rc1-20-g8c5b85c.tar.gz ----- +////////////////////////// If someone opens that tarball, they get the latest snapshot of your project under a project directory. You can also create a zip archive in much the same way, but by passing the `--format=zip` option to `git archive`: +////////////////////////// +tarball を開けば、プロジェクトのディレクトリの下に最新のスナップショットが得られます。まったく同じ方法で zip アーカイブを作成することもできます。 +この場合は `git archive` で `--format=zip` オプションを指定します。 [source,console] ----- $ git archive master --prefix='project/' --format=zip > `git describe master`.zip ----- +////////////////////////// You now have a nice tarball and a zip archive of your project release that you can upload to your website or e-mail to people. +////////////////////////// +これで、あなたのプロジェクトのリリース用にすてきな tarball と zip アーカイブができあがりました。これをウェブサイトにアップロードするなりメールで送ってあげるなりしましょう。 [[_the_shortlog]] +////////////////////////// ==== The Shortlog +////////////////////////// +==== 短いログ (((git commands, shortlog))) +////////////////////////// It's time to e-mail your mailing list of people who want to know what's happening in your project. A nice way of quickly getting a sort of changelog of what has been added to your project since your last release or e-mail is to use the `git shortlog` command. It summarizes all the commits in the range you give it; for example, the following gives you a summary of all the commits since your last release, if your last release was named v1.0.1: +////////////////////////// +そろそろメーリングリストにメールを送り、プロジェクトに何が起こったのかをみんなに知らせてあげましょう。 +前回のリリースから何が変わったのかの変更履歴を手軽に取得するには `git shortlog` コマンドを使います。 +これは、指定した範囲のすべてのコミットのまとめを出力します。たとえば、直近のリリースの名前が v1.0.1 だった場合は、次のようにすると前回のリリース以降のすべてのコミットの概要が得られます。 [source,console] ----- @@ -541,4 +921,7 @@ Tom Preston-Werner (4): Regenerated gemspec for version 1.0.2 ----- +////////////////////////// You get a clean summary of all the commits since v1.0.1, grouped by author, that you can e-mail to your list. +////////////////////////// +v1.0.1 以降のすべてのコミットの概要が、作者別にまとめて得られました。これをメーリングリストに投稿するといいでしょう。 diff --git a/status.json b/status.json index fc15757a..3f5f8987 100644 --- a/status.json +++ b/status.json @@ -45,10 +45,10 @@ "sections/smart-http.asc": 0 }, "05-distributed-git": { - "1-distributed-git.asc": 0, - "sections/contributing.asc": 0, - "sections/distributed-workflows.asc": 0, - "sections/maintaining.asc": 0 + "1-distributed-git.asc": 100, + "sections/contributing.asc": 100, + "sections/distributed-workflows.asc": 100, + "sections/maintaining.asc": 100 }, "06-github": { "1-github.asc": 0,