├── .gitmodules ├── 01_what_is_git.md ├── 02_first_commit.md ├── 03_second_commit.md ├── 04_more_commits.md ├── 05_branch.md ├── 06_merge.md ├── 07_more_merges.md ├── 08_rebase.md ├── 09_clone.md ├── 10_push_pull.md ├── 11_appendix.md ├── README.md └── images └── 09_00.png /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "03_second_commit/my_first_workspace"] 2 | path = 03_second_commit/my_first_workspace 3 | url = https://github.com/takanabe/introduction-to-git_03_second_commit.git 4 | [submodule "04_more_commits/my_first_workspace"] 5 | path = 04_more_commits/my_first_workspace 6 | url = https://github.com/takanabe/introduction-to-git_04_more_commits.git 7 | [submodule "05_branch/my_first_workspace"] 8 | path = 05_branch/my_first_workspace 9 | url = https://github.com/takanabe/introduction-to-git_05_branch.git 10 | -------------------------------------------------------------------------------- /01_what_is_git.md: -------------------------------------------------------------------------------- 1 | # Git とはなんぞや 2 | 3 | Git は、数ある VCS のうちのひとつです。では VCS とはなんでしょうか。VCS とは、「ヴァージョン管理システム/Version Control System」のことです。VCSがなにかということは、高野将さんが [VCS入門](https://Github.com/masaru-b-cl/introduction-to-vcs) というすばらしい資料を書いてくれています。少なくともこの資料の4章までは読んでおいてください(良い資料なので、情報系のお仕事をやっているひとは全部読んだ方がいいです)。 4 | 5 | VCS がどのようなものなのかわかりましたか? Git はこのような役割をしてくれる VCS のうちのひとつである、と理解してください。 6 | 7 | ## Git は分散 VCS 8 | 9 | では、数ある VCS の中で、Git はどのような特徴を持った VCS なのでしょうか。"マージ" が賢いとか "ブランチ" (いまはこれらの言葉の意味はわからなくていいです)が軽量であるという特徴もあるのですが、何よりも特徴的なのは、「分散VCS」であるということでしょう。 10 | 11 | 分散 VCS と言われると「なんのことじゃ」という感じですけれど、簡単に言えば「みんなが手元にそれぞれリポジトリを持っている」ということです。上記の [VCS入門](https://Github.com/masaru-b-cl/introduction-to-vcs) では、「みんなが触るリポジトリ」がひとつあって、個々人はその「みんながさわるリポジトリ」に対して作業コピーの内容を反映させたりしていましたね。でも、Git の場合は、そういう「みんながたったひとつのリポジトリを触る」みたいな感じではなくて、みんながそれぞれ自分の手元に「自分のリポジトリ」を持つことになります。作業コピーに対して行った変更を、「たったひとつのリポジトリ」に反映させるのではなくて、「分散してるリポジトリ」(=手元のリポジトリ)に対して反映させるので、「分散 VCS」です 12 | 13 | でも、せっかく「みんなで編集する」のにも便利な VCS なのに、それぞれが自分のリポジトリに対して変更を反映させたりするだけでは、意味がありませんね。自分が行った変更を誰かと共有したり、だれがか行った変更を自分のところに持ってきたりできないと VCS の嬉しさ半減です。 14 | 15 | そこで、Git には「このリポジトリにある変更を、そっちのリポジトリに反映してくれない?」とか「そのリポジトリの変更、こっちのリポジトリに取り込ませてよ」みたいな感じで、リポジトリ同士で変更内容を取り込んだりする機能があります。これによって、複数のメンバーで同じコードを触ることができるようになるわけですね。もちろん、このときに競合が起こったりした場合は「あー競合おこっちゃってるからその変更取り込めないわ、ちょっと手元で競合直してから取り込んでもらっていいかい」みたいな感じで Git が教えてくれます。 16 | 17 | まとめです。 18 | 19 | * Git を使う場合は(ふつうは)みんながそれぞれ手元に自分用のリポジトリを持つ 20 | * みんなはそれぞれ自分で行った変更を自分のリポジトリに反映させる 21 | * 誰かが行った変更を誰かのリポジトリから自分のリポジトリに取り込んだり、逆に自分のリポジトリに行った変更を誰かのリポジトリに取り込んでもらうことで複数人での作業を行う 22 | 23 | とりあえず、具体的なことがわからなくても、「ふーん、そんなイメージなんだな」と、そんなふうに理解してください。 24 | 25 | [next - ひとりでつかう - はじめてのコミット](02_first_commit.md) 26 | -------------------------------------------------------------------------------- /02_first_commit.md: -------------------------------------------------------------------------------- 1 | # ひとりでつかう - はじめてのコミット 2 | 3 | さて、Git がどんなものなのか、だいたいわかったでしょうか。というわけで、まずは、ひとりで Git を使ってみましょう。 4 | 5 | ## まずはリポジトリを作ろう 6 | 7 | なにはともあれ、まずはリポジトリを作らなくては話ははじまりません。リポジトリを作りましょう。 8 | 9 | と、その前に!! Git のインストールはお済みですか?まずはインストールしてください。そのあと、初期設定みたいな感じで自分の名前とメールアドレスを設定しないとだめなので、それをやってみましょう。 10 | 11 | $ git config --global user.name 'YOUR NAME' 12 | $ git config --global user.email 'yourmail@example.com' 13 | 14 | `YOUR NAME` と `yourmail@example.com` はあなたの名前と email アドレスに置き換えて下さい。既にこの設定が済んでいる方はこの設定は飛ばしてかまいません。 15 | 16 | 済ませましたか?でははじめましょう。空っぽのリポジトリを作ってみます。 17 | 18 | $ mkdir my_first_workspace 19 | $ cd my_first_workspace 20 | $ git init 21 | 22 | `mkdir my_first_workspace` で、 my_first_workspace という「作業ディレクトリ」を作っています。`cd my_first_workspace` で、そのディレクトリに入っています。そこで、`git init` をすることで、この作業ディレクトリに対応するリポジトリを作成しています。 23 | 24 | 「作業ディレクトリ」と「リポジトリ」の関係は頭に入ってますか? 頭に入ってないひとは [VCS入門](https://github.com/masaru-b-cl/introduction-to-vcs/blob/master/readme.md) をおさらいしましょう。 25 | 26 | さて、これで、「作業ディレクトリ」と「リポジトリ」が出来上がりました。が、リポジトリは一体どこにつくられたのでしょうか?my_first_workspace ディレクトリにいる状態で、 27 | 28 | $ ls -a 29 | 30 | としてみましょう。`ls` は、そのディレクトリにあるファイル一覧を確認するコマンドで、`-a` は、「特殊なファイルも全て表示する」という意味です。さて、コマンドは打ちましたか? すると、下記のように、".git" というディレクトリが存在しているのが見て取れると思います。 31 | 32 | . .. .git 33 | 34 | この ".git" というディレクトリが、「リポジトリ」の正体です。workspace という「作業ディレクトリ」があるとき、その作業ディレクトリに対応する「リポジトリ」は、 workspace/.git である、ということですね。 35 | 36 | 今はコマンドラインから見てみましたが、ファイラーから見てみましょう(Mac 環境であることを前提として説明しますが、他の環境の場合はそれぞれのファイラーに置き換えてみてください)。Finder で、my_first_workspace ディレクトリを開いてみましょう。 37 | 38 | あれっ!? ".git" が無いように見えますね!? じつは、 "." から始まるファイルやディレクトリは「隠しファイル」と呼ばれ、Finder からは見えないようになっています。大切な設定情報などが書き込まれているファイルは、誤操作で消してしまったりしないように、「隠しファイル」とされることが多いのです。リポジトリも、とても大切なものですよね。誤操作でリポジトリがふっとんじゃった!なんてことになったら、目もあてられないので、リポジトリは ".git" という "." で始まる隠しファイルとなっているわけです。ちなみに、Finder から隠しファイルを見れるようにする方法もあるのですが、ここでは脇道にそれてしまうため触れません。 39 | 40 | とにかく、これで、「作業ディレクトリ」である "my_first_workspace" と、それに対応する「リポジトリ」である ".git" が出来上がりました。この「作業ディレクトリ」の中で編集されるファイル群が、「作業コピー」となります。 41 | 42 | ちなみに、作業コピーでの変更内容をリポジトリに登録することを、「コミット」と言いますので、ついでにここで覚えておきましょう。 43 | 44 | ## 作業ディレクトリで作業をしよう 45 | 46 | まずは、作業ディレクトリの中になにかファイルを作って見ましょう。どのようなやり方でもかまいません。いまはとりあえず 47 | 48 | nyan 49 | 50 | と書かれた nyan.txt というファイルを作業ディレクトリ内に作ってください。 51 | 52 | 作りましたか? 53 | 54 | これで、作業ディレクトリ内に変化が起こりました。「なにもない」という状態から、「nyan.txtというファイルがある」という状態に変化したわけですね。では、この作業ディレクトリ内の変化を Git さんはどのように認識しているのでしょうか。その様子を見てみましょう。ターミナルで作業ディレクトリに入って、`git status` と打つことで、「現在のリポジトリと作業コピーの状態を Git さんがどう認識しているか」が見れます。 55 | 56 | $ cd path/to/my_first_workspace 57 | $ git status 58 | 59 | `path/to/my_first_workspace` はおのおの自分が my_first_workspace を作ったパスに読み替えてください。 60 | 61 | さて、上記のようにコマンドを打ってみると、 62 | 63 | # On branch master 64 | # 65 | # Initial commit 66 | # 67 | # Untracked files: 68 | # (use "git add ..." to include in what will be committed) 69 | # 70 | # nyan.txt 71 | nothing added to commit but untracked files present (use "git add" to track) 72 | 73 | というような表示が出てきたかと思います。「ウワァ英語だ!助けて!」みたいにならないでください。少なくとも中学で3年間、多くのひとはそのあと高校で3年間はみっちり英語習ってきたでしょう。これくらいは読みましょう。 74 | 75 | まず上から見ていきましょう。「On branch master」 とありますね。「ブランチ master 上だよ」と言っています。ブランチについて説明していないので、いまはこれは無視してかまいません。 76 | 77 | そのあとに 「Initial commit」 と書かれていますね。「最初のコミットだよ」と書かれています。まだ一度もコミットしていないので、「この作業コピーをコミットするとこれが最初のコミットになるよ」って意味です。 78 | 79 | そのあと、「Untracked files:」 と書かれていて、括弧のなかにごちゃごちゃ書かれてて、その下に nyan.txt と書かれています。つまり、「トラックされていないファイルは以下のとおりだよ:nyan.txt」といったところでしょうか。この場合の "トラック" は、「追跡する」の意味ですね。つまり、「追跡されてないファイルだよ」という意味です。「追跡されていない」とはどういうことでしょうか。だれがなにを追跡していないのでしょうか。 80 | 81 | 正解は、「Git はこのファイルを追跡してないよ」という意味です。つまり、Gitさんが、「なんか知らんファイルあるんだけど、おれこれどうしたらいいか知らんよ」って言ってるわけですね。「これどうしたらいいか知らんよ」と言っているので、この状態で「コミット」をしても、リポジトリはこのファイルを無視してしまいます。 82 | 83 | では、さきほど無視した括弧の中を見てみましょう。 「use "git add \ ..." to include in what will be committed」 と書かれています。「コミットされるものに含めたければ "git add \..." 使えば良いよ」ってことですね。親切な Git さんが、「これを追跡するためにはどうすればいいか」を教えてくれてるわけです。 84 | 85 | 最後に、「nothing added to commit but untracked files present (use "git add" to track)」 と書かれていますね。「コミットするものがなにもないよ、でも追跡されてないファイルがあるよ(追跡したければ "git add" するといいよ)」ともう一度説明してくれています。 86 | 87 | 英語、ちゃんと読めば、これだけ丁寧に情報が書かれているんです。たまに「なんか表示されたけど英語だから読まなかったです」みたいなひといるけど、読んでください。ググるまでもなく、ひとに聞くまでもなく、ちゃんと読めばちゃんと情報が出ているんです。 88 | 89 | さて、上記をまとめると、今は「nyan.txtっていうファイルが作業コピー内にあるけど、リポジトリはそのファイルのこと追跡してないよ、だからまだコミットできないよ」という状態であることがわかりました。 90 | 91 | ## 作業ディレクトリで作業をしよう、の落ち穂拾い 92 | 93 | さて、さきほど `git status` を打ったときの出力ですが、もしかしたら、 94 | 95 | # On branch master 96 | # 97 | # Initial commit 98 | # 99 | # Untracked files: 100 | # (use "git add ..." to include in what will be committed) 101 | # 102 | # .DS_Store 103 | # nyan.txt 104 | nothing added to commit but untracked files present (use "git add" to track) 105 | 106 | という感じで、身に覚えない .DS_Store というファイルが「Untracked files」として表示されてしまったひともいるかもしれません。この .DS_Store というファイルは、Mac OS が勝手に作る、「このフォルダのアイコンの並び順はこんな感じで表示サイズはこのくらい」みたいな情報が入ったファイルです。このファイルは、リポジトリで管理する必要のないファイルですね。むしろ、このファイルはそれぞれの環境によって内容が異なるので、リポジトリで管理すると無用なトラブルのもとになります。こういうときには、「.DS_Storeっていうファイル、無視してね」と Git に教えてあげましょう。その方法はふたつあります。 107 | 108 | 1. .gitignore というファイルをリポジトリに作成する。すると、リポジトリは .gitignore の中に名前が書かれているファイルは無視する 109 | 2. どのリポジトリでも .DS_Store という名前のファイルを無視するように Git を設定する 110 | 111 | 「このリポジトリの中では無視したいファイルなんだけど、他のリポジトリの中では無視したいわけではない」みたいなファイルは .gitignore に書く方法がいいでしょうし、どんな場合にも無視してほしいようなファイルに関してはグローバルに無視する設定をしたほうがいいでしょう。今回の .DS_Store は、どんなリポジトリにも追加したくない類いのものだと思いますので、今回はその方法を取りましょう。ターミナルを開いて、以下のコマンドを打ってください。 112 | 113 | $ git config --global core.excludesfile ~/.gitignore_global 114 | $ echo ".DS_Store" >> ~/.gitignore_global 115 | 116 | 一行目で、「グローバルに無視するファイル名を書いたファイルは ~/.gitignore_global というファイルだよ」と Git に教えてあげています。二行目で、そのファイルに ".DS_Store" を書き込み、Git に「.DS_Storeは無視してね」と教えています。 117 | 118 | .gitignore ファイルの書き方には触れないので、グーグル先生に聞いてください。 119 | 120 | さて、ここで再度 121 | 122 | $ git status 123 | 124 | してみましょう。今度は、.DS_Store が 「Untracking files:」 から消えて、Git が完全にその存在を無視していることが見て取れるでしょう。 125 | 126 | ## 作業コピーの内容を track してもらう 127 | 128 | さて、作業ディレクトリの中で新しいファイルを作っただけでは、そのファイルは untracked な状態なのでした。では、この untracked な状態のファイルを、リポジトリに track してもらいましょう。git status したときに Git さんが丁寧に教えてくれたので、その方法をあなたはもう知っているはずです。そうです。 `git add` ですね。ではやってみましょう。 129 | 130 | $ git add nyan.txt 131 | 132 | これで、「nyan.txtを track してね」と Git さんに伝える事ができました。ではここで再度 `git status` してみましょう。 133 | 134 | $ git status 135 | # On branch master 136 | # 137 | # Initial commit 138 | # 139 | # Changes to be committed: 140 | # (use "git rm --cached ..." to unstage) 141 | # 142 | # new file: nyan.txt 143 | # 144 | 145 | このような出力が得られたかと思います。ちょっと内容が変わってますね。英語だけど頑張って読んでみましょう。 146 | 147 | 「Initial commit」のところまではいいでしょう。その下、「Changes to be committed:」と書かれていて、括弧のなかにごにょごにょ書かれていて、その下に「new file: nyan.txt」とあります。日本語にすれば、「コミットされる変更は以下の通りです。・新しいファイル: nyan.txt」といったところでしょうか。つまり、この状態でコミットをすると、nyan.txt に対して行った変更がコミットされるよ、ということですね。いい感じです! 148 | 149 | では、括弧のなかにはなんて書いてあるでしょうか。 「use "git rm --cached \..." to unstage」 だそうです。「unstage するには、 "git rm --cached \..." ってすればいいよ」ってことですね。ん? 新しい単語が出てきましたね。unstage とはなんでしょうか。というわけで、 stage と unstage について説明しましょう。 150 | 151 | ## stage とは unstage とは 152 | 153 | Git では、コミットの前に、「作業ディレクトリ内のこのファイルの内容はリポジトリに反映してほしいけど、このファイルの内容は反映してほしくない」みたいなことを Git に教えておく必要があります。そうしないと、Git さんはコミットのときに「えっこれどのファイルのどの変更をリポジトリに反映すればいいの!?」となってしまいます。このとき、「次にコミットするときにリポジトリに反映される内容の置き場」のことを、"staging area" と呼んでいます。 154 | 155 | つまり、さっき `git add nyan.txt` としたことで、nyan.txt はその時点でのそのファイルの内容が「staging area に上げられた」ことになります。これを、 「stage する」と言います。この状態で commit を行うと、Git は stage に上がっている内容をリポジトリに登録します。では unstage とは? もうお分かりでしょう。「stage」が「staging areaにファイルを置く」なので、「unstage」はその逆、「staging area からファイルの内容を取り下げる」です。では、実際にやってみましょう。「use "git rm --cached ..." to unstage」でしたね。今回は nyan.txt を unstage するので、以下のようになります。 156 | 157 | $ git rm --cached nyan.txt 158 | 159 | はい、ではここでもう一度 `git status` で状態を見てみましょう 160 | 161 | $ git status 162 | # On branch master 163 | # 164 | # Initial commit 165 | # 166 | # Untracked files: 167 | # (use "git add ..." to include in what will be committed) 168 | # 169 | # nyan.txt 170 | nothing added to commit but untracked files present (use "git add" to track) 171 | 172 | おおー。nyna.txt が Untracked files に戻っていますね。 173 | 174 | こんな感じで、「作業ディレクトリで行った変更のうち、リポジトリに反映してほしいもの」を stage したり、「リポジトリに反映してほしくない変更」を unstage することで、どういう変更をリポジトリに反映させたいのかを Git さんに教えてあげましょう。 175 | 176 | とりあえず今回は nyan.txt に行った変更を反映させたいので、再度 nyan.txt を stage しておきましょう。 177 | 178 | $ git add nyan.txt 179 | 180 | $ git status 181 | # On branch master 182 | # 183 | # Initial commit 184 | # 185 | # Changes to be committed: 186 | # (use "git rm --cached ..." to unstage) 187 | # 188 | # new file: nyan.txt 189 | # 190 | 191 | ## ついにcommitしてみよう 192 | 193 | さて、それでは、ついに commit をしてみましょう。コミットをするには、 194 | 195 | $ git commit 196 | 197 | です。 `git commit` とすると、エディタが立ち上がります。おそらく vi というターミナル内で動くエディタが立ち上がったのではないでしょうか($EDITORを設定してるような中級者以上の読者は想定してないのでそういうひとは自分で読み替えてください)。vi の使いかたについてはここでは触れないので、Google 先生に聞いてください。慣れると使いやすいですよ。 198 | 199 | 「えっなにこれは」「怖い」ってなったひとは、かなりの荒技ではありますが、Mac での標準のエディタを使うのもひとつの手かもしれません。とりあえず今はこの怖い画面を "[Esc]:q!"と打って([Esc]はエスケープキー) 抜け出してしまいましょう。そのあと、 200 | 201 | $ git config --global core.editor 'open -t -W' 202 | 203 | と打ってください。すると、次回のコミットからは Mac のテキストエディタが開きます。これで怖くないエディターを利用できますね! 204 | 205 | Linuxを普段から使ってる場合はどうすればいいのかって? そういうひとは vi くらい使えるでしょ! 206 | 207 | Windowsを使ってるひとはどうすればいいのかって? わたしもわかりません…… 208 | 209 | さて、エディタが立ち上がった画面には、先ほど `git status` で確認したのと似たような、でもちょっとだけ違うものが出力されているかとおもいます。では、また英語を読みましょう。何度も言うけど、出力された英語をちゃんと読めば必要な情報はそこに書いてあります。四の五の言わずに読んでください。 210 | 211 | # Please enter the commit message for your changes. Lines starting 212 | # with '#' will be ignored, and an empty message aborts the commit. 213 | # On branch master 214 | # 215 | # Initial commit 216 | # 217 | # Changes to be committed: 218 | # (use "git rm --cached ..." to unstage) 219 | # 220 | # new file: nyan.txt 221 | # 222 | 223 | 「On branch masater」 以下の表示については前みた通りなので説明しなくていいですね。さて、では最初の段落になんと書いてありますか? 224 | 225 | 「君がやった変更についてのコミットメッセージを書いてくれよな! '#'で始まる行は無視するぜ!空のメッセージ書きやがったらこのコミットを中止するからな!」と書いてあります。Git さんのキャラがぶれてきている気がしますがまあ気にせず進めましょう。 226 | 227 | ところで、では「コミットメッセージ」とはなんでしょうか。コミットを進める前に、コミットメッセージについて少し話をしておきましょう。 228 | 229 | ## コミットメッセージとは? 230 | 231 | 何度も参照している [VCS入門](https://github.com/masaru-b-cl/introduction-to-vcs/blob/master/readme.md) を紐解いてみましょう。 232 | 233 | > ## VCSの力 234 | > VCSの能力は、主に次の2つです。 235 | > 236 | > 1. 履歴を残す 237 | > 1. 作業の競合を防ぐ 238 | > 239 | > [VCS入門](https://github.com/masaru-b-cl/introduction-to-vcs/blob/master/2.power-of-vcs.md#vcs)より 240 | 241 | この、「履歴を残す」というのは、「誰が」「いつ」「何を」したかを残すということでしたね。「誰が」「いつ」の履歴を残すところまでは Git さんが面倒を見てくれますが、「何を」したかまでは、機械にはわかりません。なので、「何をしたか」を、コミットメッセージとして残しておく必要があるのです。 242 | 243 | ただ、「何をしたか」は機械にはわからないと言っても、もちろん、「どのファイルを編集した」まではわかります。ここで言う「何をしたか」というのは、もっと現実世界の話、つまり、「ほげほげがふがふがしてしまうバグを直した」だとか、「ほげほげ画面にふがふが機能を追加した」とか、そういう話です。 244 | 245 | こういうメッセージを残しておくことで、あとで履歴を見るときに「なるほどなるほど〜」と言いながら見ることができるわけですね。ちなみに、良いコミットメッセージとはどんなメッセージなのかということも、さきほどの VCS 入門に書かれています。熟読しておきましょう。 246 | 247 | ## 今度こそ commit してみよう 248 | 249 | さて、コミットメッセージとはなにかがわかったところで、コミットメッセージを書いてみましょう。今回だと「猫の鳴き声を管理するファイルを作成」という感じでしょうか。 250 | 251 | '#'から始まる行は無視される、とあるので、#から始めずに、「猫の鳴き声を管理するファイルを作成」というメッセージを書いて、保存、エディタを終了してみましょう。Macのエディタを開いてるひとは、ウィンドウを消すのではなくて、終了まで行う必要があります。言い方を変えれば、⌘+W ではなくて ⌘+Q です。 252 | 253 | $ git commit 254 | [master (root-commit) 33028c1] 猫の鳴き声を管理するファイルを作成 255 | 1 file changed, 1 insertion(+) 256 | create mode 100644 nyan.txt 257 | 258 | 終了したらこんな感じになりました。なんかいろいろ出てきましたね。おめでとうございます!これで、初めてのコミットができました! 259 | 260 | ## じゃあ履歴を見てみましょう 261 | 262 | VCS の能力として、「履歴を残す」というのがあると言いました。では履歴を見てみましょう。`git log` で見れます 263 | 264 | $ git log 265 | commit 33028c115cc19cf6122fc2004fc6393a22712d23 266 | Author: Shinpei Maruyama 267 | Date: Fri May 3 22:32:52 2013 +0900 268 | 269 | 猫の鳴き声を管理するファイルを作成 270 | 271 | お、ちゃんと履歴が残っていますね。一行目になんかおそろしげな文字列がありますが、次に説明するのでとりあえず無視しましょう。その下のAuthorのに「だれが」が、さらにその下の Date に「いつ」が、その下に「何を」行ったかがきちんとリポジトリに登録されています。yippie! 272 | 273 | おっと、もしかしたら、履歴がターミナルの全画面に表示され、もとにもどれなくて困っていますか?そんなときには、キーボードの「q」を推してみてください。これでもとに戻れます。「quit」の q ですね。 274 | 275 | ## コミットされると何が起こるのか 276 | 277 | さあ、はじめてのコミットは成功しましたが、まだまだこの章は終わりません。コミットしたとき、リポジトリに一体なにが起こっているのでしょうか。それを見てみましょう。 278 | 279 | コミットされたとき、リポジトリには新しい「コミットオブジェクト」というものが生まれます。では「コミットオブジェクト」とは一体なんなのでしょうか。 280 | 281 | 簡単に言うと、コミットオブジェクトは、「staging されていたファイルの内容 + コミットメッセージ」みたいなものです。git commit したことにより、stage されていた内容が、コミットメッセージとともに「コミットオブジェクト」となり、リポジトリに大切にしまわれた、という感じです。こうして「そのときの内容」をオミットオブジェクトに詰め込んで保存しておけば、いつでもこのときの状態を復元できることができますね。 282 | 283 | そして、次にまたなにかファイルを変更してそれをコミットすると、また新しいコミットオブジェクトが作られ、リポジトリにしまわれます。それぞれのコミットオブジェクトには一意の id がついていて、それがさっきみた謎の文字列です。 284 | 285 | commit 33028c115cc19cf6122fc2004fc6393a22712d23 286 | 287 | これは、このコミットオブジェクトの id が "33028c115cc19cf6122fc2004fc6393a22712d23" だよ、ということを表しているのですね。 288 | 289 | ひとまず今はそんなふうに思っておいてください。 290 | 291 | ## まとめ 292 | 293 | リポジトリを作るところから、最初のコミットまで、ていねいに見てみました。ポイントをおさらいしておきましょう。 294 | 295 | * workspaceという作業ディレクトリに対応するリポジトリは、 workspace/.git に作られる 296 | * 作業ディレクトリで作業しただけでは、コミットしたときに Git はその変更内容をリポジトリに登録していいのかどうかわからない 297 | * なので、`git add` などのコマンド(その他のコマンドも後で出てきます)をつかって、変更したファイルをstageする(「staging area」に置く) 298 | * 一度 stage されたファイルは、 `git rm --cached` などのコマンドを使って unstage する(「staging area」から取り下げる)ことができる 299 | * `git commit` を行うと、エディタが立ち上がるのでコミットメッセージを書いて保存、終了する。すると、staging areaに上がっていた変更内容がコミットメッセージとともにリポジトリに反映される。このとき、stage されていたファイルの内容とコミットメッセージは「コミットオブジェクト」としてリポジトリ内に保存されている。 300 | 301 | 今回のポイントは以上です。次回は「二回目のコミット」をしますよ!わくわく! 302 | 303 | [next - ひとりでつかう - にどめのコミット](03_second_commit.md) -------------------------------------------------------------------------------- /03_second_commit.md: -------------------------------------------------------------------------------- 1 | # ひとりでつかう - にどめのコミット 2 | 3 | さて、前回、作業ディレクトリで変更した内容を stage し、コミットするところまで見てみました。では、今からで 2 度目のコミットを行ってみましょう。 4 | 5 | なにはともあれ、まずは状態の確認から行いましょう。 6 | 7 | $ cd path/to/my_first_workspace 8 | $ git status 9 | # On branch master 10 | nothing to commit, working directory clean 11 | 12 | はい、nothing to commit, woking directory clean だそうです。「コミットするものはなにもないし、作業ディレクトリもキレイなままだよ」と教えてくれてますね。リポジトリに登録されてる内容と、作業ディレクトリの間に変更がないよ、ということです。 13 | 14 | ## 作業ディレクトリで作業 15 | 16 | では、作業ディレクトリで作業をしてみましょう。ディレクターから「猫の鳴き声さー、"にゃん"じゃなくてさ、"ミュウ"にしようよー」と言われたので、その変更を行いましょう。お好きなエディタで、nyan.txt を編集しましょう 17 | 18 | nyan 19 | 20 | だったものを 21 | 22 | mew 23 | 24 | と書き換えてください。書き換えましたか? 25 | 26 | ではここで、おもむろに `git status` です 27 | 28 | $ git status 29 | # On branch master 30 | # Changes not staged for commit: 31 | # (use "git add ..." to update what will be committed) 32 | # (use "git checkout -- ..." to discard changes in working directory) 33 | # 34 | # modified: nyan.txt 35 | # 36 | no changes added to commit (use "git add" and/or "git commit -a") 37 | 38 | はい、いろいろ出てきましたね。上から読んで行きましょう。 39 | 40 | 「Changes not staged for commit:」のあとに括弧でごにょごにょ言って、その下に 「modified: nyan.txt」です。 41 | 42 | 日本語にすれば、「コミット用に stage されてない変更は以下の通りです。変更されたファイル:nyan.txt」くらいの感じでしょうか。もう意味わかりますね。作業ディレクトリの内容を変更したけど、そのファイルのその内容が staging area に上がってないわけですね。括弧の中身も見てみましょう。ふたつあります。 43 | 44 | 「use "git add \..." to update what will be committed」。「"git add \ ..." すると コミットされるようになるよ」とのこと。untracked なファイルを track するときと一緒ですね。こんな感じで、 編集したり新しくできたりしたファイルを `git add` で staging area に登録することができます。 45 | 46 | もうひとつのほうの括弧の中も見てみましょう。「use "git checkout -- \..." to discard changes in working directory」だそうです。「"git checkout -- \ ..." すると、作業ディレクトリ内での変更をなかったことにできるよ!」だそうです。 47 | 48 | へえー。 49 | 50 | じゃあやってみましょう。 51 | 52 | $ git checkout -- nyan.txt 53 | 54 | としたあとに、nyan.txt の中身を見てみてください。 55 | 56 | nyan 57 | 58 | に戻っていると思います。おおー。 59 | 60 | 当然ですが、この状態で git status をすれば「working directory は clean だよ」って言われます。 61 | 62 | $ git status 63 | # On branch master 64 | nothing to commit, working directory clean 65 | 66 | おっと!寄り道をしてしまいました。せっかく編集したファイルをもとにもどしてしまったので、もう一度 nyan を mew に書き換えて、コミットしてみましょう。 67 | 68 | まずは nyan.txt の中身を書き換えてください。 69 | 70 | 書き換えましたか? では `git status` で状態を確認。 71 | 72 | $ git status 73 | # On branch master 74 | # Changes not staged for commit: 75 | # (use "git add ..." to update what will be committed) 76 | # (use "git checkout -- ..." to discard changes in working directory) 77 | # 78 | # modified: nyan.txt 79 | # 80 | no changes added to commit (use "git add" and/or "git commit -a") 81 | 82 | `git add` で stage 83 | 84 | $ git add nyan.txt 85 | 86 | `git status` で確認 87 | 88 | $ git status 89 | # On branch master 90 | # Changes to be committed: 91 | # (use "git reset HEAD ..." to unstage) 92 | # 93 | # modified: nyan.txt 94 | # 95 | 96 | はい、新しい表示が出てきました 97 | 98 | 「Changes to be committed、括弧でごにょごにょ、 modified: nyan.txt」だそうです。「コミットされる変更は以下の通りだよ。変更されたファイル:nyan.txt」でいいですね。括弧の中は「use "git reset HEAD \..." to unstage」とあります。「"git reset HEAD \ ..." ってやるとunstageできるよ」ってことですね。 99 | 100 | へー。 101 | 102 | 試しにやってみましょう。 103 | 104 | $ git reset HEAD nyan.txt 105 | Unstaged changes after reset: 106 | M nyan.txt 107 | 108 | なんか出ましたね。「Unstaged changes after reset: M nyan.txt」だそうです。「unstageされた変更は以下の通りだよ。M nyan.txt」ってことですね。M nyan.txt はなんとなく察しがついてるかと思いますが、「Modified」の M です。nyan.txtが変更されてるけど、その変更が `git reset` によって unstage されたよって言ってくれてますね。 109 | 110 | じゃあ `git status` で確認だ! 111 | 112 | $ git status 113 | # On branch master 114 | # Changes not staged for commit: 115 | # (use "git add ..." to update what will be committed) 116 | # (use "git checkout -- ..." to discard changes in working directory) 117 | # 118 | # modified: nyan.txt 119 | # 120 | no changes added to commit (use "git add" and/or "git commit -a") 121 | 122 | はい、`git add` で nyan.txt を stage する前の状態に戻っている(= unstageされた)ことが確認できました。 123 | 124 | おっと、また寄り道してしまい、せっかく stage した変更を unstage してしまいました。ここからはノンストップで commit までやってしまいましょう。 125 | 126 | $ git add nyan.txt 127 | 128 | で nyan.txt に対しておこなった変更を stage して、 129 | 130 | $ git commit 131 | 132 | でエディタが立ち上がるので、「猫の鳴き声を nyan から mew に変更」みたいな感じのコミットメッセージを書いて変更、保存です。 133 | 134 | [master 66346b5] 猫の鳴き声を nyan から mew に変更 135 | 1 file changed, 1 insertion(+), 1 deletion(-) 136 | 137 | と表示されました。「1 file changed, 1 insertion(+), 1 deletion(-)」だってさ。つまり、「一つのファイルが変更されててー、一行挿入されててー、一行消えてる!」とのことです、一行編集するってのは言い換えれば一行消して一行挿入するってことなので、なるほどね!って感じですね。 138 | 139 | ## コミットオブジェクトふたたび 140 | 141 | さて、2 回コミットを行ったので、これでリポジトリに存在するコミットオブジェクトはふたつになりました。ところで、この二つのコミットオブジェクトはどういう関係なのでしょうか? じつは、特殊なコミットオブジェクトを除き、コミットオブジェクトは必ずひとつの「親となるコミットオブジェクト」を持っています。最初に行ったコミットはその特殊なコミットオブジェクトのうちのひとつで、これを「ルートコミット(オブジェクト)」と呼びます、最初にコミットを行うときには「親」となれるような他のコミットオブジェクトがないので、仕方なく「親なし」のコミットオブジェクトができあがるのですね。そして、今行った 2 度目のコミットにとっては、この最初のコミットが親となります。基本的に、「前やったコミット」が「今やったコミット」の親となります。 142 | 143 | では、この親子関係は実際には何を表しているのでしょうか? それを見てみましょう。 144 | 145 | まず、「コミットする」という言葉が何を言っているのか、再度考えてみましょう、コミットするというのは、「変更内容をリポジトリに反映する」ということでしたね。では、ここで、「変更」という言葉に含まれる意味をちょっと考えてみましょう、「変更」と言うからには、必ず「以前の状態」があるはずです。そして、「以前の状態に対して行われる変更」があって、その変更の結果として「現在の状態」が生まれるわけですね。 146 | 147 | そして、コミットオブジェクトには、「変更後の状態」が入っています。「以前の状態」は入っていないし、「どのような変更を行ったのか」も入っていません。入っているのは、「変更後の状態」だけ、ということだけです。 148 | 149 | さて、では、そのような断片的な情報から、どうやってリポジトリは「そのコミットでどのような変更が行われたのか」を知ることができるのでしょうか。ここで先ほどの「親子関係」の話が生きています。 150 | 151 | まずは、最初のコミット、「ルートコミット」が生まれたときのことを考えてみましょう、ルートコミットには親がいないのでした。ルートコミットにとっての「以前の状態」というのは「なにもない状態」ですから、これはまあいいでしょう。そして、ルートコミットが生まれたことにより、ルートコミットを参照することで「現在の状態」を確認できるようになりました。 152 | 153 | さて、これで、ルートコミットはふたつの情報を手に入れました。 154 | 155 | * ルートコミットの中に記されている状態 156 | * 以前はなにもない状態であったということ 157 | 158 | このふたつの情報があれば、Git さんは「ルートコミットに記されている状態」と「なにもなかったときの状態」のを比べることで、「ルートコミットでどのような変更が行われたのか」を知ることができます。 159 | 160 | では、次は 2 度目のコミットが生まれたときのことを考えてみましょう。 2 度目のコミットの親コミットはルートコミットです。「親コミットがルートコミットである」というのはどういう意味なのでしょうか? 実はこれは、 2 度目のコミットのコミットオブジェクトの「以前の状態」が、「ルートコミットが保持している内容」である、ということを意味しているのです。 161 | 162 | さて、これで2度目のコミットはふたつの情報を手に入れました。 163 | 164 | * 2 度目のコミットの中に記されている状態 165 | * 2 度目のコミットが行われる以前の状態は、ルートコミットが知っているということ 166 | 167 | このふたつの情報をさらに使えば、Git さんはいつでも「ルートコミットから 2 度目のコミットの間に起こった変更」を知ることができます。簡単ですね、ルートコミットの持っている内容と 2 度目のコミットの持っている内容を比べれば、その差分がまさに「変更された内容」です。 168 | 169 | 同様に、3 度目、4 度目とコミットされたとしても、Git さんは「そのコミットオブジェクトに保存されている状態」と、「親コミットオブジェクトが保持していた内容」を比べることで、「どんな変更が行われたか」を知ることができるのです。 170 | 171 | 賢い!!!! 172 | 173 | ## 履歴の確認 174 | 175 | さて、これで 2 度目のコミットが行われました。ログを確認しておきましょう。 176 | 177 | $ git log 178 | commit 66346b53f10bbe68efb14d72a56eea836dd7e0f2 179 | Author: Shinpei Maruyama 180 | Date: Sat May 4 03:20:59 2013 +0900 181 | 182 | 猫の鳴き声を nyan から mew に変更 183 | 184 | commit 33028c115cc19cf6122fc2004fc6393a22712d23 185 | Author: Shinpei Maruyama 186 | Date: Fri May 3 22:32:52 2013 +0900 187 | 188 | 猫の鳴き声を管理するファイルを作成 189 | 190 | twitterのタイムラインと一緒で、あたらしいものほど上に来ています。ふたつのコミットがあるのが確認できますね。--graph というオプションをつけて実行すると、コミットの親子関係を視覚化することもできます。 191 | 192 | $ git log --graph 193 | * commit 66346b53f10bbe68efb14d72a56eea836dd7e0f2 194 | | Author: Shinpei Maruyama 195 | | Date: Sat May 4 03:20:59 2013 +0900 196 | | 197 | | 猫の鳴き声を nyan から mew に変更 198 | | 199 | * commit 33028c115cc19cf6122fc2004fc6393a22712d23 200 | Author: Shinpei Maruyama 201 | Date: Fri May 3 22:32:52 2013 +0900 202 | 203 | 猫の鳴き声を管理するファイルを作成 204 | 205 | \* と \* を | でつなぐことによって、このふたつのコミットが親子関係にあることが示されています。`git log` の表示フォーマットはいろいろいじれるので、気になるひとは調べてみて、自分の好きなフォーマットで見てみるといいと思います。 206 | 207 | ## まとめ 208 | 209 | 今回は 2 度目のコミットを行ってみました。それにより、 210 | 211 | * コミットには親子関係がある 212 | * コミットオブジェクトには「親コミットはどれか」という情報と、「この瞬間のファイルの状態」という情報が入っている 213 | * これらのふたつの情報を比べることによって、Git さんはいつでも「その 2 つのコミットの間にどのような変更が行われたか」を知ることができる 214 | 215 | ということが学べました。 216 | 217 | 次回はもっといろんなコミットを行ってみましょう。 218 | 219 | [next - ひとりでつかう - どんどんコミット](04_more_commits.md) 220 | -------------------------------------------------------------------------------- /04_more_commits.md: -------------------------------------------------------------------------------- 1 | # ひとりでつかう - どんどんコミット 2 | 3 | さて、前回までで、staging area についてと、コミットオブジェクトについてなんとなくわかってもらえたのではないかと思います。再度まとめておきましょう。 4 | 5 | * 作業ディレクトリでなんらかの変更を行う 6 | * 行った変更のうち、コミット時にリポジトリに反映したい内容を「staging area」に登録する 7 | * commit を行いコミットメッセージを記入する 8 | * コミットオブジェクトが作成される。 9 | * コミットオブジェクトは、「以前の状態が入ったコミットはどれなのか」を親コミットオブジェクトを持つことで表現する。 10 | * コミットオブジェクトの中には、staging areaに登録されていたファイルの内容が保存されている。 11 | * これにより、Git さんは「あのときのコミットの状態を復元!」みたいなことができるようになる。 12 | * また、複数のコミットを比べることで、「その間に起こった変更」を知ることもできる。 13 | 14 | ところで、今まで見てきた「作業ディレクトリ内で起こった変更」は、「ファイルの追加」と「ファイルの内容の編集」の2種類でしたね? しかし、作業を行っていく上でのディレクトリ内の変化は、もちろんそれだけではないはずです。「ファイルの削除」や、「ファイルのリネーム」「ファイルの移動」というような変化が起こることもあるでしょう。というわけで、今回は「ファイルの削除やリネーム、移動」について見て行きましょう。 15 | 16 | ## ファイルの削除 - その準備 17 | 18 | 今までと同じ作業ディレクトリにて作業を行います。とはいえ、いまは nyan.txt しかリポジトリに存在しないので、とりあえずいくつか新しいファイルをコミットしておきましょう。 19 | 20 | wan 21 | 22 | と書かれた wan.txt と、 23 | 24 | boo 25 | 26 | と書かれた、boo.txt を作業ディレクトリに作成し、この二つのファイルを追加したよ、という内容のコミットを作成しましょう。 27 | 28 | まずは wan.txt と boo.txt を作成してください。できましたか? では、`git add` でこの二つのファイルを stage しましょう。 29 | 30 | $ git add . 31 | 32 | ん!? `git add wan.txt boo.txt` ではなくて、`git add .` としていますね。なんだこれは!? 33 | 34 | じつは、 "." というのは、「現在いるディレクトリ」のことを指します。そして、`git add` などでは、ディレクトリを指定すると、「その中身のファイルを全部」と指定したのと同じになります。つまり、今回で言えば、`git add .` は `git add boo.txt nyan.txt wan.txt` と指定したのと同じことなのです。このとき、nyan.txt にはなんの変更も行われていないため、git は変更があった wan.txt と boo.txt だけを staging area に登録するのです。賢い! 35 | 36 | というわけで、今は新規に作成された wan.txt と boo.txt が staging area に上がっているはずです。それを見てみましょう。 37 | 38 | $ git status 39 | # On branch master 40 | # Changes to be committed: 41 | # (use "git reset HEAD ..." to unstage) 42 | # 43 | # new file: boo.txt 44 | # new file: wan.txt 45 | # 46 | 47 | よし、意図通りの結果になっていますね! 48 | 49 | ではコミットしてしまいましょう。 50 | 51 | $ git commit 52 | 53 | エディタが立ち上がるので「犬と豚の鳴き声を追加」とコミットメッセージを書いて保存、終了。 54 | 55 | [master 66c681b] 犬と豚の鳴き声を追加 56 | 2 files changed, 2 insertions(+) 57 | create mode 100644 boo.txt 58 | create mode 100644 wan.txt 59 | 60 | と出力されました。2ファイルに変更があって、2行追加されているよ、だそうです。1行のファイルを2つ作ったので、計算は合ってますね。 61 | 62 | create mode 100644 boo.txt 63 | create mode 100644 wan.txt 64 | 65 | に関しては、mode 100644 でboo.txtとwan.txtを作ったという変更だよ、ってことですね。「このmode 100644ってのはなんじゃ」って感じですが、Unix系システムの「パーミッション」という概念を知らないと意味不明なので、無視しておいていいです。とりあえず、「boo.txt と wan.txt が追加されたよ」という情報が出ていることを確認してください。 66 | 67 | 一応 `git log` も確認しておきましょうか。 68 | 69 | $ git log --graph 70 | * commit 66c681b9596f28c93bc396320b934cd3cdde46d4 71 | | Author: Shinpei Maruyama 72 | | Date: Sat May 4 22:05:12 2013 +0900 73 | | 74 | | 犬と豚の鳴き声を追加 75 | | 76 | * commit 66346b53f10bbe68efb14d72a56eea836dd7e0f2 77 | | Author: Shinpei Maruyama 78 | | Date: Sat May 4 03:20:59 2013 +0900 79 | | 80 | | 猫の鳴き声を nyan から mew に変更 81 | | 82 | * commit 33028c115cc19cf6122fc2004fc6393a22712d23 83 | Author: Shinpei Maruyama 84 | Date: Fri May 3 22:32:52 2013 +0900 85 | 86 | 猫の鳴き声を管理するファイルを作成 87 | 88 | うん、いいですね。 89 | 90 | と、ここで、唐突に git が怖くなくなる tips をひとつお伝えしましょう。21世紀で、もうあなたのパソコンはいろんな色を表示できるというのに、こんなモノクロの出力ばかり眺めていると気がめいります。あと、やっぱり色がないとわかりづらい。なので、表示に色を付けちゃいましょう。 91 | 92 | $ git config --global color.ui true 93 | 94 | はい。これで次回から Git さんが表示する内容に色がつきます。 95 | 96 | ## ファイルの削除 97 | 98 | さて、これでようやく「ファイルの削除」の準備が整いました。ディレクターが「俺豚嫌いなんだよね、なくさない?」と言っています。しょうがないので boo.txt を削除してしまいましょう。お好きな手段で作業ディレクトリ内から boo.txt を削除してください。 99 | 100 | 削除しましたか? 101 | 102 | さて、これで、作業ディレクトリ内には、「boo.txtが削除された」という変化がおこりました。`git status` でそれを確認してみましょう。 103 | 104 | $ git status 105 | # On branch master 106 | # Changes not staged for commit: 107 | # (use "git add/rm ..." to update what will be committed) 108 | # (use "git checkout -- ..." to discard changes in working directory) 109 | # 110 | # deleted: boo.txt 111 | # 112 | no changes added to commit (use "git add" and/or "git commit -a") 113 | 114 | はい、「Changes not staged for commit:」のなかに 「deleted: boo.txt」 が記載されています。いいですね。ではこの変更を stage しましょう。 115 | 116 | $ git add boo.txt 117 | 118 | 確認 119 | 120 | $ git status 121 | # On branch master 122 | # Changes not staged for commit: 123 | # (use "git add/rm ..." to update what will be committed) 124 | # (use "git checkout -- ..." to discard changes in working directory) 125 | # 126 | # deleted: boo.txt 127 | # 128 | no changes added to commit (use "git add" and/or "git commit -a") 129 | 130 | アレッ!?「Changes not staged for commit:」のままですね!? これはおかしい。 131 | 132 | よく `git status` の出力内容を見てみてください。いままでと少し違う部分がありますね。そうです。括弧の中身が、変わっています。「use "git add/rm \..." to update what will be committed」となって、「stage するためには git add/rm を使ってね」と書かれています。 133 | 134 | じつは、ファイルの削除という変更を stage するためには、`git add` ではなく、`git rm` を使わないとダメなのです。ちょっとめんどうですね。やってみましょう。 135 | 136 | $ git rm boo.txt 137 | rm 'boo.txt' 138 | 139 | $ git status 140 | # On branch master 141 | # Changes to be committed: 142 | # (use "git reset HEAD ..." to unstage) 143 | # 144 | # deleted: boo.txt 145 | # 146 | 147 | うん、きちんと「Changes to be committed」になっています。stage されましたね。 148 | 149 | ちなみに、今回は作業ディレクトリの中からファイルを削除してからその変更を stage しましたが、これを一気に行う方法もあります。それを見てみましょう。 150 | 151 | そのために、まずは、stage された変更を unstage して、さらに作業ディレクトリで行った変更をなかったことにしましょう。 152 | 153 | `git status` で出てきた内容に、「use "git reset HEAD \..." to unstage」とありますから、従いましょう 154 | 155 | $ git reset HEAD boo.txt 156 | D boo.txt 157 | 158 | $ git status 159 | # On branch master 160 | # Changes not staged for commit: 161 | # (use "git add/rm ..." to update what will be committed) 162 | # (use "git checkout -- ..." to discard changes in working directory) 163 | # 164 | # deleted: boo.txt 165 | # 166 | no changes added to commit (use "git add" and/or "git commit -a") 167 | 168 | はい、not staged な状態に戻りました。さらに、作業ディレクトリの変更を「なかったこと」にしましょう。`git status` に出てきている「use "git checkout -- ..." to discard changes in working directory」に従えばいいですね。 169 | 170 | $ git checkout -- boo.txt 171 | 172 | $ git status 173 | # On branch master 174 | nothing to commit, working directory clean 175 | 176 | はい、「以前のコミットから作業ディレクトリの中に変更点はないよ」という状態になっていますね。ディレクトリの中を覗いてみると boo.txt が復活しているのが見て取れると思います。 177 | 178 | では、ここから、「作業ディレクトリの中からファイルを削除して、さらにその "削除したよ" という情報を stage する」というのを一気にやってみましょう。そのために使うコマンドは、おなじく `git rm` です、言い方を変えると、`git rm` は、 179 | 180 | * 作業ディレクトリにファイルが存在するときにはそのファイルを削除する(すでに無い場合はなにもしない) 181 | * その後「ファイルを削除したよ」という情報を stage する 182 | 183 | というコマンドなのです。ではやってみましょう。 184 | 185 | $ git rm boo.txt 186 | rm 'boo.txt' 187 | 188 | $ git status 189 | # On branch master 190 | # Changes to be committed: 191 | # (use "git reset HEAD ..." to unstage) 192 | # 193 | # deleted: boo.txt 194 | # 195 | 196 | お、一気に「Changes to be committed:」になりました。staging area に「削除したよ」という情報を登録するところまで一気にできていますね。念のため、ディレクトリの中を覗いてみてください。boo.txtが無くなっているのが見て取れると思います。 197 | 198 | ではこの変更をコミットしましょう。コミットメッセージは「豚の鳴き声は要らないので削除」くらいにしておきましょうか。 199 | 200 | $ git commit 201 | [master 8faaa1f] 豚の鳴き声は要らないので削除 202 | 1 file changed, 1 deletion(-) 203 | delete mode 100644 boo.txt 204 | 205 | ログを見ます。 206 | 207 | $ git log --graph 208 | * commit 8faaa1f91278ff3763b44dd79aa884e30b630e62 209 | | Author: Shinpei Maruyama 210 | | Date: Sat May 4 22:37:54 2013 +0900 211 | | 212 | | 豚の鳴き声は要らないので削除 213 | | 214 | * commit 66c681b9596f28c93bc396320b934cd3cdde46d4 215 | | Author: Shinpei Maruyama 216 | | Date: Sat May 4 22:05:12 2013 +0900 217 | | 218 | | 犬と豚の鳴き声を追加 219 | | 220 | * commit 66346b53f10bbe68efb14d72a56eea836dd7e0f2 221 | | Author: Shinpei Maruyama 222 | | Date: Sat May 4 03:20:59 2013 +0900 223 | | 224 | | 猫の鳴き声を nyan から mew に変更 225 | | 226 | * commit 33028c115cc19cf6122fc2004fc6393a22712d23 227 | Author: Shinpei Maruyama 228 | Date: Fri May 3 22:32:52 2013 +0900 229 | 230 | 猫の鳴き声を管理するファイルを作成 231 | 232 | うん、良いですね。 233 | 234 | まとめです。 235 | 236 | * 作業ディレクトリ内で「ファイルの削除」という変更がおこったとき、その変更を stage するためには `git add` ではなくて `git rm` を使う。 237 | * 手動で作業ディレクトリ内からファイルを削除しなくても、`git rm` をいきなり使うと、指定したファイルを作業ディレクトリから削除して、さらにその変更を stage するところまで一気にやってくれる。 238 | 239 | といったところです。あっ、ところで、`git rm` の「rm」ってなんのことでしょうね? 「add」というのは普通に「加える」でいいのですが。実は、「rm」は remove の略です。これで覚えやすくなりましたね! 240 | 241 | ## ファイルのリネーム 242 | 243 | ディレクターから、「ファイル名さ、wan.txt とか nyan.txt じゃなくて、もっと英語っぽくならないの」と言われてしまいました。では次はファイルのリネームを行いましょう。どんな手段でもいいので、wan.txt を bow.txtに、nyan.txt を mew.txt に作業ディレクトリ内でリネームしてみてください。 244 | 245 | さて、これで「ファイルのリネーム」という変化が作業ディレクトリに起こりましたね。じゃあ `git status` で確認です。 246 | 247 | $ git status 248 | # On branch master 249 | # Changes not staged for commit: 250 | # (use "git add/rm ..." to update what will be committed) 251 | # (use "git checkout -- ..." to discard changes in working directory) 252 | # 253 | # deleted: nyan.txt 254 | # deleted: wan.txt 255 | # 256 | # Untracked files: 257 | # (use "git add ..." to include in what will be committed) 258 | # 259 | # bow.txt 260 | # mew.txt 261 | no changes added to commit (use "git add" and/or "git commit -a") 262 | 263 | 「!?」なんか出た!怖い!はい、怖くないです。いっこずつ見て行けばなるほどって感じです。 264 | 265 | まずは上から見て行きましょうか。 266 | 267 | 「Changes not staged for commit:」に、deleted として nyan.txt とwan.txt が表示されていますね。つまり、「作業ディレクトリから nyan.txt と wan.txt がなくなってるけど、stage されてないよ」ですね。nyan.txtはどこへ行ってしまったのでしょうか……? 268 | 269 | nyan.txt は名前がかわり、mew.txt になりました。これは、別の言い方をすると、「nyan.txt」という名前のファイルは無くなって、同じ内容の「mew.txt」という名前のファイルが出来た、という風にみることができますね。 270 | 271 | この前半部分 "「nyan.txt」という名前のファイルはなくなって" というのが、この "deleted: nyan.txt" が示していることです。そして、後半の「同じ内容の mew.txt という名前のファイルができた」というのも、「Untracked files:」に bow.txt と mew.txt が表示されている、つまり、「新しく作業コピーに bow.txt と nyan.txt があるけど、このファイル知らないファイルだよ」と Git さんが言っていることで確認できますね。 272 | 273 | と言う感じで、「リネーム」というのが「新しい名前で同じ内容のファイルを作って、古いファイルは消す」という動作と同じであるということを理解すれば、「あーなるほどね」という感じで見れるのではないでしょうか。 274 | 275 | ではこの変化を stage しましょう。もういいですね。消えたファイルは `git rm` で stage、増えたファイルは `git add` で stage です。 276 | 277 | $ git add bow.txt mew.txt 278 | 279 | $ git rm nyan.txt wan.txt 280 | rm 'nyan.txt' 281 | rm 'wan.txt' 282 | 283 | $ git status 284 | # On branch master 285 | # Changes to be committed: 286 | # (use "git reset HEAD ..." to unstage) 287 | # 288 | # renamed: wan.txt -> bow.txt 289 | # renamed: nyan.txt -> mew.txt 290 | # 291 | 292 | おー。staging areaに、renamed: として「wan.txt -> bow.txt」「nayn.txt -> mew.txt」が登録されました。Hooray! 293 | 294 | ちなみに、`git rm` では作業ディレクトリからのファイルを削除と、その変更内容の staging を一気に行うことができましたが、リネームのときにはできないのでしょうか? 実は、リネームのときには、`git mv <リネーム前のファイルの名前> <リネーム後のファイルの名前>` とすることでこれを一気に行えます。今回ならば、 295 | 296 | $ git mv nyan.txt mew.txt 297 | $ git mv wan.txt bow.txt 298 | 299 | とすればOKです。 300 | 301 | ではこれを commit しておきましょう。コミットメッセージは「ファイル名を英語に変更」とかでしょうか。 302 | 303 | $ git commit 304 | [master bb8f610] ファイル名を英語に変更 305 | 2 files changed, 0 insertions(+), 0 deletions(-) 306 | rename wan.txt => bow.txt (100%) 307 | rename nyan.txt => mew.txt (100%) 308 | 309 | 出ている情報も問題ないですね。最後に `git log` で確認。 310 | 311 | ``` 312 | * commit bb8f61009a30190c1bda537ae7f9c40ab22f2e62 313 | | Author: Shinpei Maruyama 314 | | Date: Sat May 4 23:00:48 2013 +0900 315 | | 316 | | ファイル名を英語に変更 317 | | 318 | * commit 8faaa1f91278ff3763b44dd79aa884e30b630e62 319 | | Author: Shinpei Maruyama 320 | | Date: Sat May 4 22:37:54 2013 +0900 321 | | 322 | | 豚の鳴き声は要らないので削除 323 | | 324 | * commit 66c681b9596f28c93bc396320b934cd3cdde46d4 325 | | Author: Shinpei Maruyama 326 | | Date: Sat May 4 22:05:12 2013 +0900 327 | | 328 | | 犬と豚の鳴き声を追加 329 | | 330 | * commit 66346b53f10bbe68efb14d72a56eea836dd7e0f2 331 | | Author: Shinpei Maruyama 332 | | Date: Sat May 4 03:20:59 2013 +0900 333 | | 334 | | 猫の鳴き声を nyan から mew に変更 335 | | 336 | * commit 33028c115cc19cf6122fc2004fc6393a22712d23 337 | Author: Shinpei Maruyama 338 | Date: Fri May 3 22:32:52 2013 +0900 339 | 340 | 猫の鳴き声を管理するファイルを作成 341 | ``` 342 | 343 | うん、OKです。 344 | 345 | ## ファイルの移動 346 | 347 | さて、そうこうしている間に、ディレクターが「動物のファイル、animals ディレクトリにまとめたいね」という話を持ちかけてきました。animals ディレクトリを作って、ファイルをそこに移動させましょう。例によって手段はなんでもいいのでやってみてください。 348 | 349 | 移動させましたか?では `git status`。 350 | 351 | # On branch master 352 | # Changes not staged for commit: 353 | # (use "git add/rm ..." to update what will be committed) 354 | # (use "git checkout -- ..." to discard changes in working directory) 355 | # 356 | # deleted: bow.txt 357 | # deleted: mew.txt 358 | # 359 | # Untracked files: 360 | # (use "git add ..." to include in what will be committed) 361 | # 362 | # animals/ 363 | no changes added to commit (use "git add" and/or "git commit -a") 364 | 365 | はい、もう怖くないですね。ファイルの移動というのはファイルのリネームと同じく、「新しい場所に同じ内容のファイルを作成して、古いファイルは消す」のと一緒です。なので bow.txt と mew.txt が「削除されてるけどその変更は stage されてないよ」と表示され、新しく作られた "animals/" ディレクトリが「あたらしくディレクトリできてるけどこれ知らないディレクトリだよ」と言われています。 366 | 367 | では新しいディレクトリを `git add` で stage して、ファイルの削除を `git rm` で stage しましょう。`git add` にディレクトリを指定すると「その中のファイル全部」を意味することを思い出してください。 368 | 369 | $ git add animals 370 | 371 | $ git rm bow.txt mew.txt 372 | rm 'bow.txt' 373 | rm 'mew.txt' 374 | 375 | $ git status 376 | # On branch master 377 | # Changes to be committed: 378 | # (use "git reset HEAD ..." to unstage) 379 | # 380 | # renamed: bow.txt -> animals/bow.txt 381 | # renamed: mew.txt -> animals/mew.txt 382 | # 383 | 384 | おっと? Changes to be committed つまり stage された変更の中に、"renamed" と表示されました。でもこれも少し考えれば納得ですね。さきほど、"ファイルの移動というのはファイルのリネームと同じく、「新しい場所に同じ内容のファイルを作成して、古いファイルは消す」のと一緒です" と言ったのを思い出してください。リネームも移動も、どちらもコンピューターから見れば、「新しい場所に同じ内容のファイルを作成して、古いやつは消す」という操作になっているのです。なので、リネームと移動を区別する必要はないのですね。 385 | 386 | ということは? そうです。とうぜん、`git mv` を使えば、ファイルの移動とその変更内容を stage するのを一気にやってしまえます。 387 | 今回で言えば、 388 | 389 | $ mkdir animals 390 | $ git mv bow.txt animals/bow.txt 391 | $ git mv mew.txt animals/mew.txt 392 | 393 | で良いですね。最初に animals ディレクトリを作成しないとそもそもファイルの移動ができないので、最初に animals ディレクトリを作っているところに注意してください。 394 | 395 | ではコミット。コミットメッセージは「動物ファイルを animals ディレクトリに移動」くらいでしょうか 396 | 397 | $ git commit 398 | [master 5fe17c7] 動物ファイルを animals ディレクトリに移動 399 | 2 files changed, 0 insertions(+), 0 deletions(-) 400 | rename bow.txt => animals/bow.txt (100%) 401 | rename mew.txt => animals/mew.txt (100%) 402 | 403 | ログを確認 404 | 405 | * commit 5fe17c7e3f0b2252b4081d08778fdfcbd232e7d9 406 | | Author: Shinpei Maruyama 407 | | Date: Sat May 4 23:20:06 2013 +0900 408 | | 409 | | 動物ファイルを animals ディレクトリに移動 410 | | 411 | * commit bb8f61009a30190c1bda537ae7f9c40ab22f2e62 412 | | Author: Shinpei Maruyama 413 | | Date: Sat May 4 23:00:48 2013 +0900 414 | | 415 | | ファイル名を英語に変更 416 | | 417 | * commit 8faaa1f91278ff3763b44dd79aa884e30b630e62 418 | | Author: Shinpei Maruyama 419 | | Date: Sat May 4 22:37:54 2013 +0900 420 | | 421 | | 豚の鳴き声は要らないので削除 422 | | 423 | * commit 66c681b9596f28c93bc396320b934cd3cdde46d4 424 | | Author: Shinpei Maruyama 425 | | Date: Sat May 4 22:05:12 2013 +0900 426 | | 427 | | 犬と豚の鳴き声を追加 428 | | 429 | * commit 66346b53f10bbe68efb14d72a56eea836dd7e0f2 430 | | Author: Shinpei Maruyama 431 | | Date: Sat May 4 03:20:59 2013 +0900 432 | | 433 | | 猫の鳴き声を nyan から mew に変更 434 | | 435 | * commit 33028c115cc19cf6122fc2004fc6393a22712d23 436 | Author: Shinpei Maruyama 437 | Date: Fri May 3 22:32:52 2013 +0900 438 | 439 | 猫の鳴き声を管理するファイルを作成 440 | 441 | はい、OKです。 442 | 443 | まとめましょう。 444 | 445 | * 「ファイルのリネーム、移動」は、実質は「新しい場所(名前)に同じ内容のファイルを作って、古い場所にあるファイルを消す」という動作である。 446 | * なので、ファイルをリネーム/移動 した場合は、「新しくファイルができたよ」という情報を `git add` で stage、「古いファイルは消えたよ」という情報を `git rm` で stage することでリネーム/削除が表現できる。 447 | * `git mv` を使うと、「作業ディレクトリ内のファイルのリネーム/移動」と、「その変更を stage」を一気にやってくれる 448 | 449 | ちなみに、`git mv` の mv は move の略です。 450 | 451 | 次回はブランチについて見て行きましょう。 452 | 453 | [next - ひとりでつかう - ブランチを知る](05_branch.md) 454 | -------------------------------------------------------------------------------- /05_branch.md: -------------------------------------------------------------------------------- 1 | # ひとりでつかう - ブランチを知る 2 | 3 | さて、今までの内容で、あなたはもう作業ディレクトリの変更内容を自由自在に stage, unsatage したり commit したりできるようになりましたね?「なってない」というひとは先に進む前に前回までの内容を復習してください。 4 | 5 | さて、ここで、再度 [VCS入門](https://github.com/masaru-b-cl/introduction-to-vcs/blob/master/2.power-of-vcs.md) を紐解いてみましょう。 6 | 7 | > 1. 履歴を残す 8 | 9 | > VCSでできることの一番大きなものは「作業履歴を残すこと」です。これは、言い換えると「誰が」「いつ」「何を」したかが残るということになります。 10 | > 11 | > (中略) 12 | > 13 | > 履歴が残ると何ができるのか。大まかには次の3つができるようになります。 14 | > 15 | > * 参照 16 | > * 再現 17 | > * 分岐 18 | > 19 | > (中略) 20 | > 21 | > (2) 再現 22 | > 23 | > VCSを使うと、履歴を参照するだけでなく、その時点の状態を再現することも可能です。つまり、動かなくなったとしても正常に動作していた状態に巻き戻せる、ということです。 24 | > 25 | > この特徴を利用して、動作しなくなる一つ手前に戻り作業をやり直すといったことや、バグが発生する時点の成果物を、他のメンバーに確認してもらう、といったことが可能になります。 26 | > 27 | > (3) 分岐 28 | > 29 | > 過去の状態を再現した上で、そこから別の変更を加えることで、履歴を分岐することもできます。つまり、複数のアプローチにより、作業を行うことができるということです。 30 | > 31 | > このことから、動作しなくなる手前の状態を元に別の変更を加えていき、それぞれのパターンをメンバーに評価してもらう、といったこともできるようになります。 32 | 33 | なるほど。で、この「再現」と「分岐」をするのに使えるのが、「ブランチ」です。ブランチっていってもブレックファストとランチの中間の brunch のほうではなくて、branch、つまり枝とか分枝とかを意味するほうのことです。分岐を管理するのに branch が使えるというのは直感的ですね。 34 | 35 | とはいえ、イメージはわかったけどじゃあ実際の「再現」とか「分岐」ってなに?って感じもあります。このあたりは、習うよりも慣れろな感じがあるので、実際に手を動かしてみましょう。まずは Git におけるブランチとは何者なのか、というのから見ていきましょう。 36 | 37 | ## Git におけるブランチはただの「ポインタ」である 38 | 39 | あっ! ブラウザを閉じないでください! この「ポインタ」は C 言語とかのポインタとはまっっっっっったく関係のない言葉です! 怖くないですよ! 「ポインタ」を和訳してみてください。「指し示すもの」ですね。では、なにがなにを指し示しているのでしょうか。 40 | 41 | それは、「あるブランチ」が、「あるコミットオブジェクト」を指し示しているのです。まずは実際を見てみましょう。 42 | 43 | 現在リポジトリに存在しているブランチの一覧を表示するには、`git branch` でできます。 44 | 45 | $ git branch 46 | * master 47 | 48 | はい、master というブランチが表示されました。つまり、今このリポジトリには「master」というブランチが存在していることが見れたわけです。以前からちょくちょく出てきている「On master branch」のことですね。master というブランチは、Git さんがリポジトリを作ったときに勝手に作るブランチです。ブランチというのはコミットオブジェクトを指し示すものなのでしたね。ではこの master というブランチも、なんらかのコミットオブジェクトを指し示しているはずです。ではそれを見てみましょう。あるブランチがどこを指し示しているか知るのに、以下のコマンドを打ってみましょう。 49 | 50 | $ git log --graph --pretty=format:'%s %d' 51 | 52 | はい、`git log --graph` に `--pretty=format:'%s %d'` というオプションを渡してみました。これは、コミットの履歴を `'%s %d'` というフォーマットで表示してね、という意味です。`'%s'` はコミットメッセージ、`'%d'` がブランチを意味します。 53 | 54 | * 動物ファイルを animals ディレクトリに移動 (HEAD, master) 55 | * ファイル名を英語に変更 56 | * 豚の鳴き声は要らないので削除 57 | * 犬と豚の鳴き声を追加 58 | * 猫の鳴き声を nyan から mew に変更 59 | * 猫の鳴き声を管理するファイルを作成 60 | 61 | こんなログが表示されたのではないでしょうか。これを見てみると、「HEAD」と「master」というのがありますね。HEAD はとりあえず今は置いておいて、「動物ファイルを animals ディレクトリに移動」というコミットの横に master と表示されています。これは、master ブランチがこのコミットを指している、という意味です。 62 | 63 | うーん、なんか、「で?それがなんなん?」って感じですね。でも、今はよくわかんなくていいです。とにかく今は、「master というブランチが存在していて、その master ブランチが "動物ファイルを animals ディレクトリに移動" というコミットオブジェクトを指している」と理解してくれれば良いです。 64 | 65 | ではここで恒例の、唐突な Git tips です。 66 | 67 | $ git config --global alias.graph "log --graph --date-order --all --pretty=format:'%h %Cred%d %Cgreen%ad %Cblue%cn %Creset%s' --date=short" 68 | 69 | と打ち込んでおきましょう。すると、次回から 70 | 71 | $ git graph 72 | 73 | とするときれいにフォーマットされたログが見れるようになります。この文章では、今後はこの alias が設定されていることを前提として話を進めます。 74 | 75 | ## ブランチを新しく作ってみよう 76 | 77 | さて、今は master が最新のコミットを指していることがわかりました。では、新しくブランチを作ってみましょう。 78 | 79 | $ git branch my_first_branch 80 | 81 | はい、これで、「my_first_branch」というブランチが作られました。ちゃんと作られているかどうか、確認してみましょう。 82 | 83 | $ git branch 84 | * master 85 | my_first_branch 86 | 87 | さっきは存在しなかった my_first_branch が出来上がってますね。 88 | 89 | ところで、`git branch` でブランチ一覧を表示したとき、 master のよこに \* がついているのに気づいたでしょうか。これは、今自分が選択しているブランチが master であることを示しています。選択しているブランチ? よくわからないですね。今はよくわからないままでいいです。 90 | 91 | `git graph` の表示も確認しておきましょう。 92 | 93 | ``` 94 | * 5fe17c7 (HEAD, my_first_branch, master) 2013-05-04 Shinpei Maruyama 動物ファイルを animals ディレクトリに移動 95 | * bb8f610 2013-05-04 Shinpei Maruyama ファイル名を英語に変更 96 | * 8faaa1f 2013-05-04 Shinpei Maruyama 豚の鳴き声は要らないので削除 97 | * 66c681b 2013-05-04 Shinpei Maruyama 犬と豚の鳴き声を追加 98 | * 66346b5 2013-05-04 Shinpei Maruyama 猫の鳴き声を nyan から mew に変更 99 | * 33028c1 2013-05-03 Shinpei Maruyama 猫の鳴き声を管理するファイルを作成 100 | ``` 101 | 102 | my_first_branch というブランチが出来ていて、masterと同じく最新のコミットオブジェクトを指しているのが見て取れるとおもいます。 103 | 104 | さて、よくわからない感じのことが増えてきましたが、もう少しでその謎が解けます。頑張ってやっていきましょう。 105 | 106 | ## コミットしてみよう 107 | 108 | よくわらかないことをわかるために、とにかく、なにかコミットしてみましょう。bow.txt の中身が "wan" のままなので、これを "bow" に書き換えてみましょうか。 109 | 110 | 書き換えて、stage して、コミット。コミットメッセージは「犬ファイルの中身も英語に合わせた」あたりにしておきましょうか。 111 | 112 | できましたか? 113 | 114 | それでは、この状態で、コミットログがどうなっているか確認してみましょう。 115 | 116 | ``` 117 | $ git graph 118 | * c3ef974 (HEAD, master) 2013-05-05 Shinpei Maruyama 犬ファイルの中身も英語に合わせた 119 | * 5fe17c7 (my_first_branch) 2013-05-04 Shinpei Maruyama 動物ファイルを animals ディレクトリに移動 120 | * bb8f610 2013-05-04 Shinpei Maruyama ファイル名を英語に変更 121 | * 8faaa1f 2013-05-04 Shinpei Maruyama 豚の鳴き声は要らないので削除 122 | * 66c681b 2013-05-04 Shinpei Maruyama 犬と豚の鳴き声を追加 123 | * 66346b5 2013-05-04 Shinpei Maruyama 猫の鳴き声を nyan から mew に変更 124 | * 33028c1 2013-05-03 Shinpei Maruyama 猫の鳴き声を管理するファイルを作成 125 | ``` 126 | 127 | おっ。変化がありましたね。さっきまでは、my_first_branch も master も「動物ファイルを animals ディレクトリに移動」というコミットを指し示していましたが、master ブランチを選択した状態で新しく commit を行ったら、新しいコミットオブジェクトが生まれて、masterはその新しいコミットオブジェクトを指すようになりました。しかし、my_first_branch のほうは依然として「動物ファイルを animals ディレクトリに移動」を指し示したままです。 128 | 129 | これはどういうことでしょうか? それを知るために、コミットが行われたときにリポジトリに何が起こっているのか、もう一度確認してみましょう。 130 | 131 | ## コミットオブジェクト、みたび 132 | 133 | さて、コミットが行われると、コミットオブジェクトが作成されるのでしたね。そして、そのコミットオブジェクトは、「親コミットオブジェクトはどれなのか」という情報と、「その瞬間のファイルの状態」という情報を持っているのでした。ここまではいいですか? 134 | 135 | そして、「そのコミットの瞬間のファイルの状態」というのは、そのとき staging area に置いてあったものでしたね。では、「親コミットオブジェクトがどれなのか」という情報はどこから引っ張ってくるのでしょうか? 以前は、「直前のコミット」とぼかした言い方をしていましたね。 136 | 137 | 察しの良いひとは薄々感付いているかもしれませんね。そうです。実は、「親コミットオブジェクト」になるのは、「コミットするときに選択されていたブランチが指し示しているコミットオブジェクト」なのです。 138 | 139 | コミットが行われると、Git さんは「選択されているブランチが指し示しているコミットオブジェクト」を親として、新しいコミットオブジェクトを作成します。その後、Git さんは「選択されているブランチ」がこの新しくできたコミットオブジェクトを指し示すように更新します。 140 | 141 | そのような動きを頭にいれたあと、再度さきほどの `git graph` の結果を眺めてください。以前 master が指し示していたコミットを親コミットオブジェクトに持つ新しいコミットオブジェクトが生まれ、選択していた master ブランチがその新しいコミットオブジェクトを指し示していることが見て取れると思います。 142 | 143 | そして、このタイミングで HEAD という存在のなぞにも答えておきましょう。実はこの HEAD というのは特殊なブランチ(ポインタ)で、「今選択しているブランチがどれなのか」という情報を保持しているのです。今、HEAD は master と同じところにありますね。つまり、今は master が選択されている、ということです。 144 | 145 | ## 選択中のブランチを切り替えてみる 146 | 147 | では、選択されているブランチを切り替えてみましょう。ブランチを切り替えるには `git checkout` です。 148 | 149 | $ git checkout my_first_branch 150 | Switched to branch 'my_first_branch' 151 | 152 | うん、「my_first_branch っていうブランチに切り替えたよ」と言われましたね。 git graph で確認してみます。 153 | 154 | ``` 155 | $ git graph 156 | * c3ef974 (master) 2013-05-05 Shinpei Maruyama 犬ファイルの中身も英語に合わせた 157 | * 5fe17c7 (HEAD, my_first_branch) 2013-05-04 Shinpei Maruyama 動物ファイルを animals ディレクトリに移動 158 | * bb8f610 2013-05-04 Shinpei Maruyama ファイル名を英語に変更 159 | * 8faaa1f 2013-05-04 Shinpei Maruyama 豚の鳴き声は要らないので削除 160 | * 66c681b 2013-05-04 Shinpei Maruyama 犬と豚の鳴き声を追加 161 | * 66346b5 2013-05-04 Shinpei Maruyama 猫の鳴き声を nyan から mew に変更 162 | * 33028c1 2013-05-03 Shinpei Maruyama 猫の鳴き声を管理するファイルを作成 163 | ``` 164 | 165 | 見事に HEAD が移動して my_first_branch と同じところを指すようになりました。 166 | 167 | さて、今、選択したブランチを切り替えましたね? そして、「ブランチ」は「コミットオブジェクトを指し示している」のでした。ということは、選択しているブランチが変われば、「指し示されているコミットオブジェクト」も変わっているはずです。 168 | 169 | これはどういうことでしょうか? ここで、以前「コミットオブジェクトさえあれば、Git さんはコミットがされたときの状態を復元できる」と言ったのが生きてきます。 170 | 171 | あるブランチを checkout すると、Git さんはふたつのことを行います。 172 | 173 | 1. HEADを指定したブランチに切り替える 174 | 2. 作業ディレクトリの内容を、そのブランチが指し示すコミットのときの状態に復元する 175 | 176 | です。1 のほうはもう見たので、2 のほうを見てみましょう。my_first_branch が指しているコミットしたときというのは、どんな状態なんでしたっけ? ログを見ると、「ファイルを animals ディレクトリに移動したけど、bow.txt の中身は英語になっていない」状態なんだな、というのがわかります。では作業ディレクトリの中身を見てみてください。実際、bow.txt の中身が「wan」に戻っているのが確認できると思います。 177 | 178 | さあ、これで [VCS 入門](https://github.com/masaru-b-cl/introduction-to-vcs) に書かれていた、VCSの履歴を残す能力によりできるみっつのことのうち、「参照」と「復元」を実際に行ってみました。残るは「分岐」です。 179 | 180 | ## my_first_branch でもコミットを行う 181 | 182 | 現在選択しているブランチは my_first_branch、そしてそのブランチが指し示しているのは「動物ファイルを animals ディレクトリに移動」のコミットでした。 183 | 184 | では、ここから、なにか変更をしてみましょう。そうですね、気まぐれディレクターが、「牛の鳴き声も追加したいなー」などと言っています。じゃあ、ここから牛の鳴き声を追加してみましょう。 185 | 186 | "mow" と書かれた mow.txt を animals ディレクトリの中に作成し、`git add` で stage、「牛の鳴き声を追加」というコミットメッセージでコミットしてみてください。 187 | 188 | OKですか? 189 | 190 | では、`git graph` でコミット後の様子を見てみましょう。 191 | 192 | ``` 193 | * bab8d49 (HEAD, my_first_branch) 2013-05-05 Shinpei Maruyama 牛の鳴き声を追加 194 | | * c3ef974 (master) 2013-05-05 Shinpei Maruyama 犬ファイルの中身も英語に合わせた 195 | |/ 196 | * 5fe17c7 2013-05-04 Shinpei Maruyama 動物ファイルを animals ディレクトリに移動 197 | * bb8f610 2013-05-04 Shinpei Maruyama ファイル名を英語に変更 198 | * 8faaa1f 2013-05-04 Shinpei Maruyama 豚の鳴き声は要らないので削除 199 | * 66c681b 2013-05-04 Shinpei Maruyama 犬と豚の鳴き声を追加 200 | * 66346b5 2013-05-04 Shinpei Maruyama 猫の鳴き声を nyan から mew に変更 201 | * 33028c1 2013-05-03 Shinpei Maruyama 猫の鳴き声を管理するファイルを作成 202 | ``` 203 | 204 | オッなんかちょっとかっこよくなってる。 205 | 206 | * 「牛の鳴き声を追加」というコミットが作成されていること 207 | * そのコミットオブジェクトが、コミット時にmy_first_branch が指し示していた「動物ファイルを animals ディレクトリに移動」を親コミットオブジェクトに持っていること 208 | * my_first_branchが指し示すコミットが、新しく作成されたコミットになっていること 209 | 210 | を確認してください。 211 | 212 | さて、これで、「動物ファイルを animals ディレクトリに移動」のコミットを親に持つ、ふたつの異なったコミットが生まれたことになります。これが、「分岐」です。さて、しつこいようですが、今どういう状態になっているか、整理しますよ。 213 | 214 | まず、起点として、「動物ファイルを animals ディレクトリに移動」というコミットがあります。そして、そこからふたつの異なるコミットが生まれています。 215 | 216 | その片方、master ブランチが指し示しているコミットには、「bow.txtの中身を書き換えた状態のファイルたち」が詰まっていますが、「牛の鳴き声を追加した状態のファイルたち」は詰まっていません。 217 | 218 | もう一方、my_first_branch が指し示しているコミットには、「animals/mow.txtを追加した状態のファイルたち」が詰まっていますが、「犬ファイルの中身を書き換えたファイルたち」は詰まっていません。 219 | 220 | 実際にその様子を見てみましょう。 221 | 222 | $ git checkout master 223 | 224 | として、master ブランチを checkout します。これにより、 225 | 226 | 1. 選択しているブランチが master になり 227 | 2. masterが指し示しているコミットの状態が作業ディレクトリに復元される 228 | 229 | のでしたね。では、作業ディレクトリの中身を覗いてみてください。このコミットには「犬の鳴き声を書き換えた」という情報は詰まっているけれど、「牛の鳴き声を追加した」という情報は詰まっていないので、「bow.txt」の中身は "bow" に書き変わっているけれど、作業ディレクトリに「mow.txt」は存在しないはずです。 230 | 231 | 次に、 232 | 233 | $ git checkout my_first_branch 234 | 235 | として、my_first_branch を checkout してみましょう。これで、 236 | 237 | 1. 選択しているブランチが my_first_branch になり 238 | 2. my_first_branch が指し示しているコミットのときの状態が作業ディレクトリに復元される 239 | 240 | のでした。このコミットには「牛の鳴き声を追加した状態のファイルたち」は詰まっているけれど、「犬の鳴き声を書き換えた状態のファイルたち」は詰まっていません。作業ディレクトリの中を覗いてみると、mow.txt は追加されているけれど、bow.txt の中身は "wan" のままなのが見て取れると思います。 241 | 242 | こんな感じで、ブランチを活用することで、「ある時点のコミット」を共通の親にもつ、複数の異なるコミットを作り出すことができました。履歴(言い換えれば歴史)が「分岐」したのです。 243 | 244 | この例だと、こんな分岐の何がうれしいのか、って感じがないではないですね。それは次回「マージ」について見てみてから、嬉しい例をいくつか紹介しようと思います。 245 | 246 | では、今回のまとめです。 247 | 248 | * Git のブランチは「コミットオブジェクトを指し示すポインター」である 249 | * リポジトリには最初から「master」というブランチが存在している。 250 | * HEAD という特殊なブランチも存在していて、このブランチは「現在選択しているブランチ」を指している。 251 | * `git branch new_branch_name` とすることで、新しいブランチを new_bnrach_name という名前で作成することができる 252 | * この新しいブランチは、現在選択しているブランチが指しているのと同じコミットオブジェクトを指している。 253 | * `git checkout some_branch_name` とすると、 254 | * "some_branch_name" という名前のが指しているコミットオブジェクトの状態が作業ディレクトリ内に復元される 255 | * "some_branch_name" が選択された状態になり、HEAD が some_branch_nameを指すようになる 256 | * 新しくコミットを行うと 257 | * 新しいコミットオブジェクトが作られる。このコミットオブジェクトは、選択しているブランチが指し示していたコミットオブジェクトを親に持つ。 258 | * 選択しているブランチは、新しくできたコミットオブジェクトを指し示すようになる 259 | 260 | ということですね。このようなブランチを活用することで、上にみたように「あるときの状態の復元」や「そこから分岐したコミット」を作り出すことができるのです。 261 | 262 | 少しずつ内容が高度になってきましたね。でも、最初から丁寧に読めば、きっと理解できると思います。がんばってください。 263 | 264 | 次回はマージについて見て行く予定です。 265 | 266 | [next - ひとりでつかう - はじめてのマージ](06_merge.md) 267 | -------------------------------------------------------------------------------- /06_merge.md: -------------------------------------------------------------------------------- 1 | # ひとりでつかう - はじめてのマージ 2 | 3 | さて、前回は、ブランチを使って状態の「復元」と「分岐」を行うことができるのを見てみましたね。そして、今回はマージについて見てみましょう。 4 | 5 | ## マージとはなにか 6 | 7 | merge というのは「複数のものをがっちゃんこする」という意味ですね。では、ここで言う「複数のもの」とはなんでしょうか? これは簡単で、複数のコミットをがっちゃんこするのです。 8 | 9 | 前回、master と my_first_branch が、共通の親を持ち、異なる変更履歴を持つコミットオブジェクトを指していたことを思い出してください。このふたつのコミットを merge することで、これらを「がっちゃんこ」します。 10 | 11 | 何はともあれ、例を見てみましょう。 12 | 13 | ## マージしてみる 14 | 15 | では、やってみましょう。まずは master ブランチを checkout します。 16 | 17 | $ git checkout master 18 | 19 | そして、master ブランチから、my_first_branch を merge します。 20 | 21 | $ git merge my_first_branch 22 | 23 | とすると、コミットのときとおなじくエディタが立ち上がります。 24 | 25 | Merge branch 'my_first_branch' 26 | 27 | と書かれているとおもうので、まあそのままエディタを保存、終了してみましょう。 28 | 29 | Merge made by the 'recursive' strategy. 30 | animals/mow.txt | 1 + 31 | 1 file changed, 1 insertion(+) 32 | create mode 100644 animals/mow.txt 33 | 34 | という表示が出てきたかと思います。読んで行きましょう。 35 | 36 | 「Merge made by the 'recursive' strategy.」 とありますね。「'recursive' strategy で merge されたよ」だそうです。'recursive' starategy ってなに……って感じですが、ひとまず今はそれは置いておきます。「なんらかの方法でマージされたんだな」と今は思っておいてください。 37 | 38 | その次の行、「animals/mow.txt | 1 +」と表示されています。なんとなくわかるでしょうか。「animals/mow.txtというファイルに1行増えてるよ」くらいの感じですね。その下に表示されている内容も、もうわかりますね。「1ファイル変更があって、1行追加されてるよ」と、「animals/mow.txt ってファイルを作ったよ」ですね。たしかに、my_first_branch にはあるけれど master にはないファイルは、「"mow" と 1 行書かれた書かれた animals/mow.txt」というファイルでした。そのファイルを取り込むのだから、このような結果になるのは納得ですね。 39 | 40 | ではここで、履歴がどうなっているのか見てみましょう。 41 | 42 | ``` 43 | $ git graph 44 | * e175c44 (HEAD, master) 2013-05-05 Shinpei Maruyama Merge branch 'my_first_branch' 45 | |\ 46 | | * bab8d49 (my_first_branch) 2013-05-05 Shinpei Maruyama 牛の鳴き声を追加 47 | * | c3ef974 2013-05-05 Shinpei Maruyama 犬ファイルの中身も英語に合わせた 48 | |/ 49 | * 5fe17c7 2013-05-04 Shinpei Maruyama 動物ファイルを animals ディレクトリに移動 50 | * bb8f610 2013-05-04 Shinpei Maruyama ファイル名を英語に変更 51 | * 8faaa1f 2013-05-04 Shinpei Maruyama 豚の鳴き声は要らないので削除 52 | * 66c681b 2013-05-04 Shinpei Maruyama 犬と豚の鳴き声を追加 53 | * 66346b5 2013-05-04 Shinpei Maruyama 猫の鳴き声を nyan から mew に変更 54 | * 33028c1 2013-05-03 Shinpei Maruyama 猫の鳴き声を管理するファイルを作成 55 | ``` 56 | 57 | おお、なんかかっこよくなってる! ひとつひとつ確認して行きましょう。 58 | 59 | まず、一番上の行に、あたらしいコミットが増えているのがわかりますね。「Merge branch 'my_first_branch'」というコミットです。これは、マージを行ったときに生まれる特殊なコミット、「マージコミット」と呼ばれるものです。今「特殊なコミット」と言いましたが、なにが特殊なのでしょうか? 再度コミットオブジェクトについて復習してみましょう。 60 | 61 | ## マージコミット 62 | 63 | コミットオブジェクトが保持している情報のことを覚えていますか? 64 | 65 | * 「"このコミットの前の状態を表す親コミットオブジェクト" はどれか」という情報 66 | * 「そのコミットがされた瞬間のファイルの状態」の情報 67 | 68 | を持っているのでした。 69 | 70 | それを頭に入れた上で、さきほどの `git graph` の結果を再度眺めてみましょう。コミットの親子関係を示す線に注目してください。新しく出来たマージコミットが、親コミットをふたつ持っているのに気づきましたか? 71 | 72 | ふつうは、コミットオブジェクトは親をひとつしかもちません。親コミットというのは、「以前どのような状態であったか」を示すものなので、当然ですね。親コミットがふたつあるというのは「以前の状態がふたつある」ということになってしまい、意味がわかりません。しかし、このマージコミットは、親をふたつ持っています。これが、「マージコミット」の特徴です。 73 | 74 | では、「親をふたつもっている」というのがどういう状態なのか、考えてみましょう。 75 | 76 | コミットには、「以前の状態を表すコミットはどれか」と、「変更を行ったあとの現在の状態」という情報が含まれているのでした。そして、新しいコミットオブジェクトを作ると、現在選択しているブランチの指しているコミットがこの「以前の状態」となるのでしたね。 さきほどわたしたちは、master ブランチを選択していました。そのため、今回のマージコミットにおける「以前の状態」というのは、 master ブランチが指していた状態のこととなります。これが、親コミットその 1 になります。これはいいですね。 77 | 78 | さて、わたしたちはさきほど、mater ブランチから my_first_branch をマージしました。このときの「この瞬間のファイルの内容」というのはどのようなものでしょうか。普通のコミットならば、「作業ディレクトリで行った作業の結果を stage したもの」になりますが、今回はなにも stage していませんね。そのかわり、今回はmy_first_branch が保持しているファイルの内容を取り込んでいます。これを言い換えると、「今回のマージコミットで作り出されるファイルの状態」は、master が指していたコミットが持っていた状態と、my_first_branch が指しているコミットが持っていた状態の間の子みたいなもんですね。だから、このコミットはもうひとつ、 my_first_branch が指していたコミットを「親コミットその 2」として持つことになるわけです。 79 | 80 | マージコミットは、このようにして、ふたつの親コミットの状態をがっちゃんした状態もつ存在として生まれることになるのです。 81 | 82 | さて、これで「分岐」していたブランチが指すコミットが、マージされて「統合」されたことになります。たしかに分岐していた親子関係の線がひとつに統合されていますね。 83 | 84 | ## ブランチはどうなった? 85 | 86 | こんな具合で、マージにより master ブランチに my_firstbranch で行われた変更を取り込むことができ、新しいコミット(マージコミット)が生まれました。ではブランチがどうなっているか見てみましょう。 `git graph` の結果を再掲します。 87 | 88 | ``` 89 | $ git graph 90 | * e175c44 (HEAD, master) 2013-05-05 Shinpei Maruyama Merge branch 'my_first_branch' 91 | |\ 92 | | * bab8d49 (my_first_branch) 2013-05-05 Shinpei Maruyama 牛の鳴き声を追加 93 | * | c3ef974 2013-05-05 Shinpei Maruyama 犬ファイルの中身も英語に合わせた 94 | |/ 95 | * 5fe17c7 2013-05-04 Shinpei Maruyama 動物ファイルを animals ディレクトリに移動 96 | * bb8f610 2013-05-04 Shinpei Maruyama ファイル名を英語に変更 97 | * 8faaa1f 2013-05-04 Shinpei Maruyama 豚の鳴き声は要らないので削除 98 | * 66c681b 2013-05-04 Shinpei Maruyama 犬と豚の鳴き声を追加 99 | * 66346b5 2013-05-04 Shinpei Maruyama 猫の鳴き声を nyan から mew に変更 100 | * 33028c1 2013-05-03 Shinpei Maruyama 猫の鳴き声を管理するファイルを作成 101 | ``` 102 | 103 | ふむ、master ブランチは新しいコミットを指すようになっています。一方、my_first_branch は依然として古いコミットを指したままです。 104 | 105 | コミットを行うと、 106 | 107 | * 選択されているブランチの指していたコミットを親にもつ新しいコミットが作られ 108 | * ブランチはその新しいコミットを指すようになる 109 | 110 | のでしたね、その通りの動きをしています。 111 | 112 | ## いらないブランチはしまっちゃおうねぇ 113 | 114 | さて、無事に my_first_branch が持っていた変更履歴の内容が master ブランチに統合されたため、もう my_first_branch は用済みです。要らないブランチは消しちゃいましょう。 115 | 116 | $ git branch -d my_first_branch 117 | 118 | こんな感じで消せます。 -d は delete の d です。ブランチ一覧を確認してみましょう。 119 | 120 | $ git branch 121 | * master 122 | 123 | うん、消えてますね。念のため `git graph` も確認。 124 | 125 | ``` 126 | $ git graph 127 | * e175c44 (HEAD, master) 2013-05-05 Shinpei Maruyama Merge branch 'my_first_branch' 128 | |\ 129 | | * bab8d49 2013-05-05 Shinpei Maruyama 牛の鳴き声を追加 130 | * | c3ef974 2013-05-05 Shinpei Maruyama 犬ファイルの中身も英語に合わせた 131 | |/ 132 | * 5fe17c7 2013-05-04 Shinpei Maruyama 動物ファイルを animals ディレクトリに移動 133 | * bb8f610 2013-05-04 Shinpei Maruyama ファイル名を英語に変更 134 | * 8faaa1f 2013-05-04 Shinpei Maruyama 豚の鳴き声は要らないので削除 135 | * 66c681b 2013-05-04 Shinpei Maruyama 犬と豚の鳴き声を追加 136 | * 66346b5 2013-05-04 Shinpei Maruyama 猫の鳴き声を nyan から mew に変更 137 | * 33028c1 2013-05-03 Shinpei Maruyama 猫の鳴き声を管理するファイルを作成 138 | ``` 139 | 140 | うん、消えています。 141 | 142 | こんな感じで、マージを行うことで分岐したコミット(変更の履歴)を、ひとつのコミットにまとめることが可能です。では今回のまとめ 143 | 144 | * `git merge branch_name` で、今選択されているブランチに branch_name という名前のブランチのコミット内容を取り込むことができる 145 | * マージするときには「マージコミット」という特殊なコミットが行われ、マージコミットのコミットオブジェクトは親をふたつ持つ 146 | * そのマージコミットが持つ「この瞬間のファイルの状態」は、ふたつの親が持っていた内容を合わせたものになる 147 | * `git branch -d branch_name` とすることで、branch_name という名前のブランチを消すことができる 148 | 149 | こんなところでしょうか。次回はもう少し実践的なマージを行ってみましょう! 150 | 151 | [ひとりでつかう - もっとマージ](07_more_merges.md) 152 | -------------------------------------------------------------------------------- /07_more_merges.md: -------------------------------------------------------------------------------- 1 | # ひとりでつかう - もっとマージ 2 | 3 | さて、前回までで、ブランチを使いこなしてはじめてのマージを行うところまでやってみましたね。では今回は、もっと実践的なマージを行ってみましょう。 4 | 5 | ## まずは準備から 6 | 7 | 今回は、前回まで使っていた「my_first_workspace」とはまたべつの作業ディレクトリとリポジトリを作成して、そこで作業をおこないましょう。まずは、my_second_workspace というディレクトリを作成し、そこにリポジトリを作成してください。 8 | 9 | $ mkdir my_second_workspace 10 | $ cd my_second_workspace 11 | $ git init 12 | 13 | はい、よいですね。 14 | 15 | では、まずはここに以下のようなふたつのファイルを作成しましょう。 16 | 17 | * cat_lover_said.txt 18 | 19 | ``` 20 | 猫は動物の一種である。 21 | 22 | 犬とならび、ペットとして飼われることの多い動物である。 23 | 24 | 猫は人間のことを下僕かなにかだと思っており、また人間も 25 | 人間で猫に使役されることを至上の喜びと思う傾向にある。 26 | 27 | 猫の魅力に取り付かれた人間は二度と猫の魅力から離れることが 28 | できないとも言われており、猫ってほんとうにかわいいですね。 29 | 30 | もうほんとうに可愛い、猫。 31 | 猫。 32 | 猫が本当にかわいい。 33 | 34 | 猫好きじゃない人間とか頭がおかしいとしか思えない。 35 | ``` 36 | 37 | * cat_hater_said.txt 38 | 39 | ``` 40 | 猫は動物の一種である。 41 | 42 | 犬とならび、ペットとして飼われることの多い動物である。 43 | 44 | 猫は人間のことを下僕かなにかだと思っているが、冗談じゃない。 45 | 人間が猫を飼ってやっているのである。そこを勘違いする猫は 46 | 本当にダメである。 47 | 48 | その点犬は良い。犬は人間のことを「ご主人様」だとおもって 49 | なついてくれる。それならばこそかわいがる気も起きるというものである。 50 | 51 | 犬は賢い。犬がいい。犬かわいい。散歩に行って息が上がった 52 | あの「ヘッヘッヘッヘッへ」がもう私をおかしくしちゃうほんとにかわいい。 53 | 54 | 犬大好き。犬最高。 55 | 56 | 猫好きな人間とか頭がおかしいとしか思えない。 57 | ``` 58 | 59 | いろいろひどいですが、ひとまずこれをコミットしましょう。 60 | 61 | $ git add . 62 | $ git commit 63 | 64 | コミットメッセージは「猫好きの話と犬好きの話を作成」くらいでいいでしょう。 65 | 66 | これで準備は完了です。 67 | 68 | ## 編集作業はブランチで 69 | 70 | さて、ディレクターさんから変更の指示が入ってきました。「興奮しすぎて文体が途中で変わっちゃってるじゃん、これじゃだめだよ、直して。」だそうです。 71 | 72 | Git 運用のコツとして、なにか変更を行うときにはブランチを作ってそちらのブランチで作業するとよい、というのがあります。それがなぜかは、後で見てみることとして、まずはじゃあ作業用のブランチを切りましょう。ブランチを作成することを、ギョーカイ用語(?)で「ブランチを切る」と言ったりします。文体を統一するためのブランチなので、「unify_styles」という名前のブランチにしましょうか。ブランチを切ってそのブランチを checkout します。 73 | 74 | $ git branch unify_styles 75 | $ git checkout unify_styles 76 | 77 | でいいですね。 78 | 79 | 念のため今の状態を確認しておきましょう。 80 | 81 | $ git graph 82 | * 8efecbd (HEAD, unify_styles, master) 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 83 | 84 | $ git branch 85 | master 86 | * unify_styles 87 | 88 | はい。最初のコミットがあって、unify_styles ブランチも master ブランチもそのコミットを指していますね。 `git branch` の結果を見ると、きちんと unify_styles が選択されています。 89 | 90 | では、ここで文体を直して行きましょう。直した結果は下のようになりました。 91 | 92 | * cat_lover_said.txt 93 | 94 | ``` 95 | 猫は動物の一種である。 96 | 97 | 犬とならび、ペットとして飼われることの多い動物である。 98 | 99 | 猫は人間のことを下僕かなにかだと思っており、また人間も 100 | 人間で猫に使役されることを至上の喜びと思う傾向にある。 101 | 102 | 猫の魅力に取り付かれた人間は二度と猫の魅力から離れることが 103 | できないとも言われている。 104 | 105 | 猫というのはかように本当にかわいいものである。 106 | 107 | 猫好きではない人間は、頭がおかしいのではないだろうか。 108 | ``` 109 | 110 | * cat_hater_said.txt 111 | 112 | ``` 113 | 猫は動物の一種である。 114 | 115 | 犬とならび、ペットとして飼われることの多い動物である。 116 | 117 | 猫は人間のことを下僕かなにかだと思っているが、冗談じゃない。 118 | 人間が猫を飼ってやっているのである。そこを勘違いする猫は 119 | 本当にダメである。 120 | 121 | その点犬は良い。犬は人間のことを「ご主人様」だとおもって 122 | なついてくれる。それならばこそかわいがる気も起きるというものである。 123 | 124 | 犬は賢い。やはり犬がよい。犬はかわいい。 125 | 126 | 散歩に行ったあとに息が上がっている様など、ほんとうに良いものである。 127 | 128 | 猫が好きな人間は、頭がおかしいのではないだろうか。 129 | ``` 130 | 131 | はい、修正しました。これをコミットしましょう。 132 | 133 | $ git add . 134 | $ git commit 135 | 136 | コミットメッセージは「文体を統一」でいいでしょう。 137 | 138 | ではここで状態を確認です。 139 | 140 | ``` 141 | $ git graph 142 | * ff00bb6 (HEAD, unify_styles) 2013-05-06 Shinpei Maruyama 文体を統一 143 | * 8efecbd (master) 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 144 | ``` 145 | 146 | うん、いいですね。新しいコミットが作られ、unify_styles ブランチはその新しいコミットを指しています。 147 | 148 | さて、ひとまずこれで、あなたはディレクターにこの修正を見せました。すると、ディレクターは「今忙しいからチェックするまで 2 週間かかるわ」と返事をして、別の仕事にとりかかってしまいました。えー、せっかく急いでやったのに……。 149 | 150 | # hotfix もブランチで 151 | 152 | さて、そんな折、ディレクターが血相を変えてやってきました。「"頭がおかしい" って表現まずいよ! 怒られちゃったよ! すぐ直して! 文体直したやつはまだチェックしてないから、そのバージョン出すにはあと2週間かかるけど、以前の状態から「頭おかしい」って表現だけ直したやつでいいからすぐ出して! ていうかなんでこんな表現使ってんだお前頭おかしいのか!」返す言葉もないですね。 153 | 154 | VCS を使っていなければ「えー前の状態に戻してからまた別の編集するの……まじで……だるい……」という感じですが、あなたには Git さんがついています。Git の力を借りて、「復元」して、そこから「分岐」した編集を作り出しましょう。 155 | 156 | なにはともあれログを確認 157 | 158 | ``` 159 | $ git graph 160 | * ff00bb6 (HEAD, unify_styles) 2013-05-06 Shinpei Maruyama 文体を統一 161 | * 8efecbd (master) 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 162 | ``` 163 | 164 | masterのところを復元して、そこから編集をすればよさそうですね。やりましょう。 165 | 166 | ``` 167 | $ git checkout master 168 | ``` 169 | 170 | これで master が指すコミットの状態が作業ディレクトリ内に復元され、HEAD が 指すブランチが master になったはずです。確認しましょう。まずはファイルを開いて、ファイルの中身が復元されていることを確認してください。 171 | 172 | 確認しましたか? きちんと復元されていますね。では今度は graph の確認です。 173 | 174 | ``` 175 | $ git graph 176 | * ff00bb6 (unify_styles) 2013-05-06 Shinpei Maruyama 文体を統一 177 | * 8efecbd (HEAD, master) 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 178 | ``` 179 | 180 | HEAD が masterを指している(= masterブランチが選択されている)のが確認できました。 181 | 182 | ではここから、緊急の作業のためのブランチを切ってそこに移動しましょう。名前は hotfix にしましょうか。今までは 183 | 184 | ``` 185 | $ git branch ブランチ名 186 | $ git checkout ブランチ名 187 | ``` 188 | 189 | とふたつのコマンドを打っていましたが、「ブランチを切ってそこに移動する」というのはじつは一発でできるコマンドがあります。今回はそちらを使いましょう。 190 | 191 | ``` 192 | $ git checkout -b hotfix 193 | ``` 194 | 195 | これで、 hotfix という名前のブランチを作成し、そのブランチを選択したことになります。確認してみましょう。 196 | 197 | ``` 198 | $ git branch 199 | * hotfix 200 | master 201 | unify_styles 202 | ``` 203 | 204 | hotfixができていて、選択されていますね。graph も確認します。 205 | 206 | ``` 207 | $ git graph 208 | * ff00bb6 (unify_styles) 2013-05-06 Shinpei Maruyama 文体を統一 209 | * 8efecbd (HEAD, master, hotfix) 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 210 | ``` 211 | 212 | hotfix は master と同じコミットを指していますね。 213 | 214 | では、この hotfix 上で緊急の編集を行いましょう。 215 | 216 | 「猫好きじゃない人間とか頭がおかしいとしか思えない。」を「猫好きじゃない人間がいるのが不思議。」に書き換え、「猫好きな人間とか頭がおかしいとしか思えない。」を「猫好きな人間がいるのが不思議。」に書き換えましょう。 217 | 218 | 書き換えましたか? 219 | 220 | ではそれをコミットしてください。コミットメッセージは「頭がおかしいという表現はまずいので修正」あたりでいいでしょう。 221 | 222 | ではここで graph 確認。 223 | 224 | ``` 225 | * 5f26eb2 (HEAD, hotfix) 2013-05-06 Shinpei Maruyama 頭がおかしいという表現はまずいので修正 226 | | * ff00bb6 (unify_styles) 2013-05-06 Shinpei Maruyama 文体を統一 227 | |/ 228 | * 8efecbd (master) 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 229 | ``` 230 | 231 | はい、いいですね。文体を統一するための変更とは別のルートに、緊急対応で "頭がおかしい" という表現を直した状態のファイルがコミットできました。 232 | 233 | さて、できあがったので、あなたはこのブランチでの変更内容をディレクターに見せに行きました。「OK!それでリリースしちゃって!」との言葉をもらったので、この hotfix ブランチで行った変更をリリースするために、master ブランチに取り込みましょう。 234 | 235 | ## hotfixをマージしよう 236 | 237 | あるブランチで行った変更を別のブランチに取り込むためには、 merge でしたね。今回は、master ブランチに hotfix ブランチの内容を取り込みたいので、 master ブランチから merge を行いましょう。 238 | 239 | ``` 240 | $ git checkout master 241 | $ git merge hotfix 242 | Updating 8efecbd..5f26eb2 243 | Fast-forward 244 | cat_hater_said.txt | 2 +- 245 | cat_lover_said.txt | 2 +- 246 | 2 files changed, 2 insertions(+), 2 deletions(-) 247 | ``` 248 | 249 | アレっ!? おかしいですね。 git merge をすると、マージコミットのためのコミットメッセージを書くためにエディタが立ち上がるはずなのに、何も立ち上がらずマージが行われてしまいました。そして、この前 'recursive' strategy がどうこうと表示されていたところに「Fast-forward」と書かれています。なんだこれは? とりあえず、ログを確認しましょう。 250 | 251 | ``` 252 | $ git graph 253 | * 5f26eb2 (HEAD, master, hotfix) 2013-05-06 Shinpei Maruyama 頭がおかしいという表現はまずいので修正 254 | | * ff00bb6 (unify_styles) 2013-05-06 Shinpei Maruyama 文体を統一 255 | |/ 256 | * 8efecbd 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 257 | ``` 258 | 259 | !? マージコミットが作成されていません。なんだこれは!? 260 | 261 | でも、よく見てみてください。master ブランチが指すコミットが、先ほどまでと変わっているのがわかりますか? 262 | 263 | merge する前は、「猫好きの話と犬好きの話を作成」のコミットを指していた master ブランチが、今は hotfix と同じコミットを指しています。なぜこんなことがおこったのでしょうか。 264 | 265 | それを理解するために、今はマージの登場人物である hotfix ブランチと master ブランチだけに注目して見てみましょう。 266 | 267 | merge を行う前のグラフを再度見てみましょう。 268 | 269 | ``` 270 | * 5f26eb2 (HEAD, hotfix) 2013-05-06 Shinpei Maruyama 頭がおかしいという表現はまずいので修正 271 | | * ff00bb6 (unify_styles) 2013-05-06 Shinpei Maruyama 文体を統一 272 | |/ 273 | * 8efecbd (master) 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 274 | ``` 275 | 276 | でしたね。今回のマージには関係のない unify_styles を無視してこのグラフを見てみましょう。 277 | 278 | ``` 279 | * 5f26eb2 (HEAD, hotfix) 2013-05-06 Shinpei Maruyama 頭がおかしいという表現はまずいので修正 280 | | 281 | * 8efecbd (master) 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 282 | ``` 283 | 284 | となっています。このグラフ、一本道で、「分岐」してませんね。さて、このとき、master ブランチが hotfix ブランチの変更内容を取り込もうと思った場合、一番楽な方法はなんでしょうか。単純に master ブランチを hotfix と同じところを指すようにしてしまえば、それで master ブランチに hotfix ブランチの変更内容を反映したのと同じことになりますね。そういうとき、賢い Git さんは「じゃあそれでええやん」という感じで単純に master のブランチを hotfix と同じところまで進めるのです。で、こういう merge の仕方を「Fast-forward」と呼んでいるのです。 285 | 286 | へー。 287 | 288 | これはこれで便利なのですが、わたしはこの挙動があまり気に入りません。だって、このログからは「このタイミングで hotfix ブランチをマージしたよ」という情報が消えてしまっています。マージ作業だって立派な「変更履歴」なのに、それがログに残らないのは気分が悪いです。Fast-forward なんてよけいなお世話だ!というわけで、Fast-forward できるときにも Fast-forward せず、いつもどおりマージコミットを作成することはできないのでしょうか?じつはできるのです。実際にやってみましょう。 289 | 290 | おっと、でも、そのためには、さっきの merge で hotfix と同じところまで進んでしまった master ブランチを、元の位置に戻さないとだめですね。 `git reset --hard <戻りたいコミットのid>` というコマンドで、今選択しているブランチをそこまで戻し、作業ディレクトリ内にそのときの状態が復元することができます。今回なら、"8efecbd" のコミットに戻りたいので、それを指定しましょう。 291 | 292 | $ git reset --hard 8efecbd 293 | HEAD is now at 8efecbd 猫好きの話と犬好きの話を作成 294 | 295 | お、HEAD が "8efecbd 猫好きの話と犬好きの話を作成" になったよ、と言われましたね。グラフを確認します。 296 | 297 | ``` 298 | $ git graph 299 | * 5f26eb2 (hotfix) 2013-05-06 Shinpei Maruyama 頭がおかしいという表現はまずいので修正 300 | | * ff00bb6 (unify_styles) 2013-05-06 Shinpei Maruyama 文体を統一 301 | |/ 302 | * 8efecbd (HEAD, master) 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 303 | ``` 304 | 305 | うん、いいですね。master の位置がもとに戻っています。念のため、ファイルの内容ももどに戻っていることを確認してください。いいですね? 306 | 307 | では、今度はここから「Fast-forward」にならないようにマージをしてみましょう。そのためには `git merge` に `--no-ff` というオプションを指定します。 308 | 309 | ``` 310 | $ git merge --no-ff hotfix 311 | ``` 312 | 313 | はい、これでエディタが立ち上がるマージになりました。コミットメッセージはデフォルトのままでいいのでテキストエディタを保存、終了しましょう。さて、ターミナルはどんな表示になっていますか? 314 | 315 | ``` 316 | Merge made by the 'recursive' strategy. 317 | cat_hater_said.txt | 2 +- 318 | cat_lover_said.txt | 2 +- 319 | 2 files changed, 2 insertions(+), 2 deletions(-) 320 | ``` 321 | 322 | うん、'recursive' stragy でマージされてますね。グラフも確認しましょう。 323 | 324 | ``` 325 | * 7090c03 (HEAD, master) 2013-05-06 Shinpei Maruyama Merge branch 'hotfix' 326 | |\ 327 | | * 5f26eb2 (hotfix) 2013-05-06 Shinpei Maruyama 頭がおかしいという表現はまずいので修正 328 | |/ 329 | | * ff00bb6 (unify_styles) 2013-05-06 Shinpei Maruyama 文体を統一 330 | |/ 331 | * 8efecbd 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 332 | ``` 333 | 334 | うん、マージコミットも作られています。良いですね。 335 | 336 | hotfix ブランチはもう用無しなので消しちゃいましょう。 337 | 338 | ``` 339 | $ git branch -d hotfix 340 | ``` 341 | 342 | さて、これで master ブランチの内容をリリースしてしまいましょう。一安心ですね。 343 | 344 | ところで、今回は Fast-fowarding せずにマージコミットを作る方式でマージを行いましたが、Fast-foward できるときは Fast-foward してしまうほうが好みであるというひともいます。このあたりは現在でも活発に宗教戦争が起こっているので、あなたの所属する組織やプロジェクトのやり方に合わせるといいでしょう。 345 | 346 | ## 文体統一のためのブランチにリテイクが発生 347 | 348 | さて、2週間たち、ディレクターから文体統一のほうの作業にダメだしされました。「あの犬好きのひとが "ヘッヘッヘッヘッ" って言ってたくだり無くしちゃったの? 俺あれ好きだったんだけど。あれ残してよ」だそうです。じゃあ unify_styles ブランチにもどって、そのための作業を行いましょう。 349 | 350 | $ git checkout unify_styles 351 | 352 | で unify_styles ブランチをチェックアウトします。 353 | 354 | そしたら、ファイルを編集しましょう。結果こうなりました。 355 | 356 | ``` 357 | 猫は動物の一種である。 358 | 359 | 犬とならび、ペットとして飼われることの多い動物である。 360 | 361 | 猫は人間のことを下僕かなにかだと思っているが、冗談じゃない。 362 | 人間が猫を飼ってやっているのである。そこを勘違いする猫は 363 | 本当にダメである。 364 | 365 | その点犬は良い。犬は人間のことを「ご主人様」だとおもって 366 | なついてくれる。それならばこそかわいがる気も起きるというものである。 367 | 368 | 犬は賢い。やはり犬がよい。犬はかわいい。 369 | 370 | 散歩に行ったあとに息が上がって "ヘッヘッヘッヘッ" と 371 | なっている様など、ほんとうに良いものである。 372 | 373 | 猫が好きな人間は、頭がおかしいのではないだろうか。 374 | ``` 375 | 376 | 変更をコミットしましょう。コミットメッセージは「"ヘッヘッヘッヘッ" という表現は残すようにした」でいいでしょう。 377 | 378 | コミットしましたか? ではグラフを確認。 379 | 380 | ``` 381 | $ git graph 382 | * ddfdb5f (HEAD, unify_styles) 2013-05-06 Shinpei Maruyama "ヘッヘッヘッヘッ" という表現は残すようにした 383 | | * 7090c03 (master) 2013-05-06 Shinpei Maruyama Merge branch 'hotfix' 384 | | |\ 385 | | | * 5f26eb2 2013-05-06 Shinpei Maruyama 頭がおかしいという表現はまずいので修正 386 | | |/ 387 | * | ff00bb6 2013-05-06 Shinpei Maruyama 文体を統一 388 | |/ 389 | * 8efecbd 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 390 | ``` 391 | 392 | 問題ないですね? 393 | 394 | ではこのコミットの内容をディレクターに見てもらいましょう。見てもらったら、「OK」と言われました。ではこのブランチの編集内容をリリースするために、 master に反映させましょう! 395 | 396 | ## 文体統一のためのブランチをマージしよう 397 | 398 | ブランチA の内容をブランチ B に反映させるには、ブランチ B を選択して、ブランチ A を merge ですね。今回は unify_styles を master に merge なので、「masterを選択して、unify_styles をマージ」です。 399 | 400 | ``` 401 | $ git checkout master 402 | $ git merge unify_styles 403 | Auto-merging cat_lover_said.txt 404 | CONFLICT (content): Merge conflict in cat_lover_said.txt 405 | Auto-merging cat_hater_said.txt 406 | CONFLICT (content): Merge conflict in cat_hater_said.txt 407 | Automatic merge failed; fix conflicts and then commit the result. 408 | ``` 409 | 410 | やってみたらなんか出た!怖い!!!! 411 | 412 | 怖くないです。英語の内容を見てみましょう。 413 | 414 | 「Auto-merging cat_lover_said.txt」は「cat_lover_said.txt を 自動マージしてるよ」でいいですね。そのあと、「CONFLICT (content): Merge conflict in cat_lover_said.txt」と言われています。オッ、これは「競合」ですね。よく考えてみると、hotfix でも cat_lover_said.txt の一番最後の行を編集していますし、unify_styles でも一番最後の行を編集してしまっています。このため、Git さんは「お、これどっちの状態を真とすればいいんだ?」と混乱してしまって、自動でマージが行えなかったわけですね。 415 | 416 | その下の表示を見てみると、どうやら cat_hater_said.txt でも同様のことが起こっているようです。 417 | 418 | そして最後に、「Automatic merge failed; fix conflicts and then commit the result.」と書かれていますね。「自動マージに失敗しちゃった>< 競合を直して、その結果をコミットしてね!」と言われています。言われたとおりにしましょう。 419 | 420 | と、そのまえに、なにはともあれ status を確認。 421 | 422 | ``` 423 | $ git status 424 | # On branch master 425 | # You have unmerged paths. 426 | # (fix conflicts and run "git commit") 427 | # 428 | # Unmerged paths: 429 | # (use "git add ..." to mark resolution) 430 | # 431 | # both modified: cat_hater_said.txt 432 | # both modified: cat_lover_said.txt 433 | # 434 | no changes added to commit (use "git add" and/or "git commit -a") 435 | ``` 436 | 437 | 見た事無い表示ですね。 438 | 439 | 「マージされてないパスがあるよ(コンフリクトを修正して git commit してね)。」だそうです。この「パス」ってのは「ファイルパス」のことですね。ファイルのことだと思ってくれてかまいません。 440 | 441 | その下には「マージされてないパスは以下の通りだよ(修正したよってマーク付けるためには git add \ ...してね)。 ・両方で変更されているファイル:cat_hater_said.txt ・両方で変更されているファイル cat_lover_said.txt」とありますね。 442 | 443 | では、そのファイルの内容を見てみましょう。 444 | 445 | * cat_hater_said.txt 446 | 447 | ``` 448 | 猫は動物の一種である。 449 | 450 | 犬とならび、ペットとして飼われることの多い動物である。 451 | 452 | 猫は人間のことを下僕かなにかだと思っているが、冗談じゃない。 453 | 人間が猫を飼ってやっているのである。そこを勘違いする猫は 454 | 本当にダメである。 455 | 456 | その点犬は良い。犬は人間のことを「ご主人様」だとおもって 457 | なついてくれる。それならばこそかわいがる気も起きるというものである。 458 | 459 | 犬は賢い。やはり犬がよい。犬はかわいい。 460 | 461 | 散歩に行ったあとに息が上がって "ヘッヘッヘッヘッ" と 462 | なっている様など、ほんとうに良いものである。 463 | 464 | 猫が好きな人間は、頭がおかしいのではないだろうか。 465 | 466 | <<<<<<< HEAD 467 | 猫好きな人間がいるのが不思議。 468 | ======= 469 | >>>>>>> unify_styles 470 | ``` 471 | 472 | なにこれファイルが壊れてる怖い! 473 | 474 | 怖くないです。これは、「どこが自動でマージできなかったか」を Git さんが教えてくれたのです。 475 | 476 | <<<<<<< HEAD 477 | 478 | から 479 | 480 | ======= 481 | 482 | までは、「HEAD」で編集された内容です。今回は HEAD は master でしたね。master は hotfix の 内容を取り込んでいたので、hotfix のほうにあった内容「猫好きな人間がいるのが不思議。」がここに書かれています。 483 | 484 | 一方、 485 | 486 | ======= 487 | 488 | から 489 | 490 | >>>>>>> unify_styles 491 | 492 | までには、unify_styles で編集された内容が書かれています。 493 | 494 | ん? 何も書かれていませんね。と思ったら、上のほうに「猫が好きな人間は、頭がおかしいのではないだろうか。」とありました。これが unify_styles に存在した内容ですね。どうやら Git さんはここまでは自動でマージしてくれたけど、「猫好きな人間がいるのが不思議。」という行はどうしたらいいのかわからなかったみたいですね。 495 | 496 | では、この競合を、手動で解決しましょう。ふつうにファイルを編集してください。 497 | 498 | ``` 499 | 猫は動物の一種である。 500 | 501 | 犬とならび、ペットとして飼われることの多い動物である。 502 | 503 | 猫は人間のことを下僕かなにかだと思っているが、冗談じゃない。 504 | 人間が猫を飼ってやっているのである。そこを勘違いする猫は 505 | 本当にダメである。 506 | 507 | その点犬は良い。犬は人間のことを「ご主人様」だとおもって 508 | なついてくれる。それならばこそかわいがる気も起きるというものである。 509 | 510 | 犬は賢い。やはり犬がよい。犬はかわいい。 511 | 512 | 散歩に行ったあとに息が上がって "ヘッヘッヘッヘッ" と 513 | なっている様など、ほんとうに良いものである。 514 | 515 | 猫が好きな人間が存在するというのが、私には不思議に思える。 516 | ``` 517 | 518 | うん、これでいいでしょう。競合を手動で解決したので、Git さんにこのファイルの競合は解決したよ、と教えて上げましょう。`git status` の表示によると、「use "git add \..." to mark resolution」でしたね。 519 | 520 | $ git add cat_hater_said.txt 521 | 522 | はい、これで Git さんに「解決したよ」と教えて上げられました。`git status` で確認しましょう 523 | 524 | ``` 525 | $ git status 526 | # On branch master 527 | # You have unmerged paths. 528 | # (fix conflicts and run "git commit") 529 | # 530 | # Changes to be committed: 531 | # 532 | # modified: cat_hater_said.txt 533 | # 534 | # Unmerged paths: 535 | # (use "git add ..." to mark resolution) 536 | # 537 | # both modified: cat_lover_said.txt 538 | # 539 | ``` 540 | 541 | 良いですね。では残りの cat_lover_said.txt も同様に手動で編集します 542 | 543 | ``` 544 | 猫は動物の一種である。 545 | 546 | 犬とならび、ペットとして飼われることの多い動物である。 547 | 548 | 猫は人間のことを下僕かなにかだと思っており、また人間も 549 | 人間で猫に使役されることを至上の喜びと思う傾向にある。 550 | 551 | 猫の魅力に取り付かれた人間は二度と猫の魅力から離れることが 552 | できないとも言われている。 553 | 554 | 猫というのはかように本当にかわいいものである。 555 | 556 | 猫好きではない人間が存在するのが、私には不思議に思える。 557 | ``` 558 | 559 | これで競合が解決したので、`git add` しましょう。 560 | 561 | ``` 562 | $ git add cat_lover_said.txt 563 | ``` 564 | 565 | `git status` で確認します。 566 | 567 | ``` 568 | $ git status 569 | # On branch master 570 | # All conflicts fixed but you are still merging. 571 | # (use "git commit" to conclude merge) 572 | # 573 | # Changes to be committed: 574 | # 575 | # modified: cat_hater_said.txt 576 | # modified: cat_lover_said.txt 577 | # 578 | ``` 579 | 580 | お、表示が変わりましたね。 581 | 582 | 「All conflicts fixed but you are still merging.(use "git commit" to conclude merge)」とありますね。日本語にすれば「競合は全部解決したけど、まだマージ中だよ。(マージを完成させるには、git commit してね)」です。 583 | 584 | じゃあ言う通りにしましょう。 585 | 586 | $ git commit 587 | 588 | はい、エディタが立ち上がりました。 589 | 590 | ``` 591 | Merge branch 'unify_styles' 592 | 593 | Conflicts: 594 | cat_hater_said.txt 595 | cat_lover_said.txt 596 | # 597 | # It looks like you may be committing a merge. 598 | # If this is not correct, please remove the file 599 | # .git/MERGE_HEAD 600 | # and try again. 601 | 602 | 603 | # Please enter the commit message for your changes. Lines starting 604 | # with '#' will be ignored, and an empty message aborts the commit. 605 | # On branch master 606 | # All conflicts fixed but you are still merging. 607 | # (use "git commit" to conclude merge) 608 | # 609 | # Changes to be committed: 610 | # 611 | # modified: cat_hater_said.txt 612 | # modified: cat_lover_said.txt 613 | # 614 | ``` 615 | 616 | と書かれていますね。一応上から読みましょう。なになに? 617 | 618 | ``` 619 | unify_stylesをマージします。 620 | 621 | 競合していたファイル: 622 | cat_hater_said.txt 623 | cat_lover_said.txt 624 | ``` 625 | 626 | はい、そのとおりでしたね。次。 627 | 628 | ``` 629 | # マージコミットをしようとしているようですね。 630 | # もしそうでないなら、以下のファイルを消してください。 631 | # .git/MERGE_HEAD 632 | # で、そのあと、もう一度やってみてください。 633 | ``` 634 | 635 | マージコミットしてるので、これは無視でいいですね。 636 | 637 | その下に書かれている内容はいつもと同じですので、割愛します。 638 | 639 | うん、いいですね。じゃあこのままテキストエディタを保存して終了させましょう。 640 | 641 | ## マージの結果は? 642 | 643 | はい、これでマージができました。結果を graph で確認しましょう。 644 | 645 | ``` 646 | $ git graph 647 | * 16fa3b3 (HEAD, master) 2013-05-06 Shinpei Maruyama Merge branch 'unify_styles' 648 | |\ 649 | | * ddfdb5f (unify_styles) 2013-05-06 Shinpei Maruyama "ヘッヘッヘッヘッ" という表現は残すようにした 650 | * | 7090c03 2013-05-06 Shinpei Maruyama Merge branch 'hotfix' 651 | |\ \ 652 | | * | 5f26eb2 2013-05-06 Shinpei Maruyama 頭がおかしいという表現はまずいので修正 653 | |/ / 654 | | * ff00bb6 2013-05-06 Shinpei Maruyama 文体を統一 655 | |/ 656 | * 8efecbd 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 657 | ``` 658 | 659 | 無事にマージコミットが作成されていますね!!いい感じです! 660 | 661 | これで無事 unify_styles ブランチで行った変更も master ブランチに取り込まれたので、unify_stylesブランチは消してしまいましょう。 662 | 663 | $ git branch -d unify_styles 664 | 665 | そして、すべての変更が反映されている master ブランチを、このままリリースしてしまいましょう。おつかれさまでした!! 666 | 667 | 今回のまとめです。 668 | 669 | * なにか作業を行うときはブランチを切ってから行うと、いつでも「その作業を行う前の状態」に戻れるので便利 670 | * 「分岐」してないブランチをマージするときには Fast-foward という手法が取られる 671 | * Fast-foward だと、マージコミットは作られず、たんにブランチが進められる 672 | * Fast-foward したくないときには `--no-ff` というオプションを付ける 673 | * マージしたときに競合が発生した場合には、手動でマージする 674 | * ファイルを手動で修正 675 | * `git add <修正したファイル>`として「競合を直したよ」と Git に伝える 676 | * 全部直したら `git commit` でマージコミットを完成させる 677 | 678 | 良いでしょうか? 679 | 680 | 次回は、コミットの歴史を修正してしまう黒魔術「rebase」について見て行きましょう。 681 | 682 | [ひとりでつかう - 過去を改変](08_rebase.md) -------------------------------------------------------------------------------- /08_rebase.md: -------------------------------------------------------------------------------- 1 | # ひとりでつかう - 過去を改変 2 | 3 | さて、前回までで、ひととおりブランチの運用とマージができるようになりましたね。だいぶ Git が怖くなくなってきたのではないでしょうか。むしろ「あーこれは便利かもしれない」となってきたのではないですか? それでは今回は過去を改変する機能について、少しだけ見て行きましょう。 4 | 5 | ## まずは準備 6 | 7 | さて、準備からはじめましょうか。今回も前回と同じシナリオでやっていきます。my_third_workspace を作って、そこにリポジトリを用意してください、よいですか? そしたら前回と同じくそこに以下のようなファイルを用意しましょう。 8 | 9 | * cat_lover_said.txt 10 | 11 | ``` 12 | 猫は動物の一種である。 13 | 14 | 犬とならび、ペットとして飼われることの多い動物である。 15 | 16 | 猫は人間のことを下僕かなにかだと思っており、また人間も 17 | 人間で猫に使役されることを至上の喜びと思う傾向にある。 18 | 19 | 猫の魅力に取り付かれた人間は二度と猫の魅力から離れることが 20 | できないとも言われており、猫ってほんとうにかわいいですね。 21 | 22 | もうほんとうに可愛い、猫。 23 | 猫。 24 | 猫が本当にかわいい。 25 | 26 | 猫好きじゃない人間とか頭がおかしいとしか思えない。 27 | ``` 28 | 29 | * cat_hater_said.txt 30 | 31 | ``` 32 | 猫は動物の一種である。 33 | 34 | 犬とならび、ペットとして飼われることの多い動物である。 35 | 36 | 猫は人間のことを下僕かなにかだと思っているが、冗談じゃない。 37 | 人間が猫を飼ってやっているのである。そこを勘違いする猫は 38 | 本当にダメである。 39 | 40 | その点犬は良い。犬は人間のことを「ご主人様」だとおもって 41 | なついてくれる。それならばこそかわいがる気も起きるというものである。 42 | 43 | 犬は賢い。犬がいい。犬かわいい。散歩に行って息が上がった 44 | あの「ヘッヘッヘッヘッへ」がもう私をおかしくしちゃうほんとにかわいい。 45 | 46 | 犬大好き。犬最高。 47 | 48 | 猫好きな人間とか頭がおかしいとしか思えない。 49 | ``` 50 | 51 | で、これをコミット。コミットメッセージも前回とおなじく「猫好きの話と犬好きの話を作成」です。これで準備は完了です。 52 | 53 | # 作業をトピックブランチで 54 | 55 | さて、今回も前回と同じく「文体統一してくれ」という作業依頼が来たとしましょう。unify_styles ブランチを切って作業しますよ。ちなみに、こういう「特定の目的の作業を行うためのブランチ」のことを、「トピックブランチ」とか「フィーチャーブランチ」と呼ぶことが多いです。あるトピックやある機能に特化したブランチ、くらいの意味ですね。 56 | 57 | はい、トピックブランチ(今回で言えば unify_styles)を切って checkout しましたか? もうコマンドはここには書かないので自分でやってみてください。 58 | 59 | さて、あなたは作業を進めて行きます。ひとまず、こんな感じで途中まで文体を統一しました。 60 | 61 | * cat_lover_said.txt 62 | 63 | ``` 64 | 猫は動物の一種である。 65 | 66 | 犬とならび、ペットとして飼われることの多い動物である。 67 | 68 | 猫は人間のことを下僕かなにかだと思っており、また人間も 69 | 人間で猫に使役されることを至上の喜びと思う傾向にある。 70 | 71 | 猫の魅力に取り付かれた人間は二度と猫の魅力から離れることが 72 | できないとも言われている。 73 | 74 | もうほんとうに可愛い、猫。 75 | 猫。 76 | 猫が本当にかわいい。 77 | 78 | 猫好きじゃない人間とか頭がおかしいとしか思えない。 79 | ``` 80 | 81 | * cat_hater_said.txt 82 | 83 | ``` 84 | 猫は動物の一種である。 85 | 86 | 犬とならび、ペットとして飼われることの多い動物である。 87 | 88 | 猫は人間のことを下僕かなにかだと思っているが、冗談じゃない。 89 | 人間が猫を飼ってやっているのである。そこを勘違いする猫は 90 | 本当にダメである。 91 | 92 | その点犬は良い。犬は人間のことを「ご主人様」だとおもって 93 | なついてくれる。それならばこそかわいがる気も起きるというものである。 94 | 95 | 犬は賢い。やはり犬がよい。犬はかわいい。 96 | 97 | 散歩に行ったあとに息が上がっている様など、ほんとうに良いものである。 98 | 99 | 犬大好き。犬最高。 100 | 101 | 猫好きな人間とか頭がおかしいとしか思えない。 102 | ``` 103 | 104 | うん、まだ中途半端な状態ですね。 105 | 106 | でも、ここでディレクターから「おい頭おかしいってなんだよこれすぐ直して!」と言われてしまいました。 master を checkout してそこから hotfix ブランチを作らないと! 107 | 108 | でもちょっと待ってください。あなたの作業ディレクトリには、まだコミットされてない変更があります。しかもこの中途半端な状態の変更をコミットしたくはありません。困りましたね! でも、今はとりあえず気にせず、ひとまずコミットしてしまいましょう。コミットさえしておけばいつでもこの状態に戻れるのですからね! 109 | 110 | まだ作業途中なんで、コミットメッセージは「作業途中だがとりあえずコミットしておく」くらいにしておきましょうか。こんなコミットしたら怒られるって? いいですいいです、それはあとでなんとかしましょう。今はとっとと「頭おかしい」を直さないと! 111 | 112 | はい、コミットしましたか? 113 | 114 | ではグラフを確認。 115 | 116 | ``` 117 | $ git gprah 118 | * 1321d1b (HEAD, unify_styles) 2013-05-06 Shinpei Maruyama 作業途中だがとりあえずコミットしておく 119 | * 15248b3 (master) 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 120 | ``` 121 | はい、いいですね。 122 | 123 | じゃあ今度は hotfix をやっちゃいましょう。 124 | 125 | ## hotfix しよう 126 | 127 | まずは master を checkout して文体統一のための作業を行う前の状態を復元して、そこから hotfix ブランチを切って選択しましょう。 128 | 129 | やりかたはわかりますね? わからないひとは前回、前々回を復習してください。 130 | 131 | はい、ではそこから緊急対応を行います。 132 | 133 | 「猫好きじゃない人間とか頭がおかしいとしか思えない。」を「猫好きじゃない人間がいるのが不思議。」に書き換え、「猫好きな人間とか頭がおかしいとしか思えない。」を「猫好きな人間がいるのが不思議。」に書き換えます。いいですね。 134 | 135 | そしたらコミットしましょう。メッセージは「頭おかしいという表現はまずいので修正」でいいでしょう。 136 | 137 | はい、今のグラフを確認しましょう。 138 | 139 | ``` 140 | $ git graph 141 | * 18fca6b (HEAD, hotfix) 2013-05-06 Shinpei Maruyama 頭おかしいという表現はまずいので修正 142 | | * 1321d1b (unify_styles) 2013-05-06 Shinpei Maruyama 作業途中だがとりあえずコミットしておく 143 | |/ 144 | * 15248b3 (master) 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 145 | ``` 146 | 147 | ふむ、良いですね。ディレクターから OK が出たので、master にマージしてリリースしちゃいましょう。 148 | 149 | ``` 150 | $ git checkout master 151 | $ git merge hotfix --no-ff 152 | ``` 153 | 154 | コミットメッセージは「Merge branch 'hotfix'」のままでいいですね。 155 | 156 | いらなくなった hotfix ブランチを削除。 157 | 158 | ``` 159 | $ git branch -d hotfix 160 | ``` 161 | 162 | グラフを確認します 163 | 164 | ``` 165 | $ git graph 166 | * 662776b (HEAD, master) 2013-05-06 Shinpei Maruyama Merge branch 'hotfix' 167 | |\ 168 | | * 18fca6b 2013-05-06 Shinpei Maruyama 頭おかしいという表現はまずいので修正 169 | |/ 170 | | * 1321d1b (unify_styles) 2013-05-06 Shinpei Maruyama 作業途中だがとりあえずコミットしておく 171 | |/ 172 | * 15248b3 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 173 | ``` 174 | 175 | うん、いいですね。 176 | 177 | ではここで途中だった作業に戻りましょう。 178 | 179 | ## トピックブランチで作業を再開、したいんだけど…… 180 | 181 | unify_styles ブランチを checkout して、作業を進めたいところですね。でもちょっとまってください。ここで、仮定の話をしましょう。 182 | 183 | 今はこの unify_styles ブランチでの作業を始めたのが hotfix が行われる前でしたが、仮に、もしこれが、hotfix が行われたあとに発生したタスクだったら、話はずいぶんシンプルになるのにな、と思いませんか? 184 | 185 | 言い方を変えましょう。 186 | 187 | * 15248b3 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 188 | 189 | から分岐している 190 | 191 | * 1321d1b (unify_styles) 2013-05-06 Shinpei Maruyama 作業途中だがとりあえずコミットしておく 192 | 193 | が、もしも 194 | 195 | * 662776b (HEAD, master) 2013-05-06 Shinpei Maruyama Merge branch 'hotfix' 196 | 197 | から分岐していてくれれば、なんだかシンプルなのになー、と思いませんか? 198 | 199 | じゃあ、そういうふうに歴史を改変しちゃえばいいんです。改変しちゃいましょう。 200 | 201 | ## いざリベース!!! 202 | 203 | さあ、改変を行いますよ! 204 | 205 | $ git checkout unify_styles 206 | 207 | で、unify_styles を選択しましょう。その状態で、 208 | 209 | $ git rebase master 210 | 211 | としてみましょう。お、なんか出ましたね。 212 | 213 | ``` 214 | First, rewinding head to replay your work on top of it... 215 | Applying: 作業途中だがとりあえずコミットしておく 216 | ``` 217 | 218 | だそうです。これなんでしょうね? ひとまず置いておいて、現在のグラフを確認しましょう。 219 | 220 | ``` 221 | $ git graph 222 | * 03f91be (HEAD, unify_styles) 2013-05-06 Shinpei Maruyama 作業途中だがとりあえずコミットしておく 223 | * 87fe5eb (master) 2013-05-06 Shinpei Maruyama Merge branch 'hotfix' 224 | |\ 225 | | * 0bd5673 2013-05-06 Shinpei Maruyama 頭おかしいという表現はまずいので修正 226 | |/ 227 | * 3b9ccc5 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 228 | ``` 229 | 230 | おおお! グラフがシンプルになってる!「作業途中だがとりあえずコミットしておく」の親コミットが、「Merge branch 'hotfix'」になりました! では、現在ファイルの中身がどうなっているかも見てみましょう。 231 | 232 | * cat_lover_said.txt 233 | 234 | ``` 235 | 猫は動物の一種である。 236 | 237 | 犬とならび、ペットとして飼われることの多い動物である。 238 | 239 | 猫は人間のことを下僕かなにかだと思っており、また人間も 240 | 人間で猫に使役されることを至上の喜びと思う傾向にある。 241 | 242 | 猫の魅力に取り付かれた人間は二度と猫の魅力から離れることが 243 | できないとも言われている。 244 | 245 | もうほんとうに可愛い、猫。 246 | 猫。 247 | 猫が本当にかわいい。 248 | 249 | 猫好きじゃない人間がいるのが不思議。 250 | ``` 251 | 252 | * cat_hater_said.txt 253 | 254 | ``` 255 | 猫は動物の一種である。 256 | 257 | 犬とならび、ペットとして飼われることの多い動物である。 258 | 259 | 猫は人間のことを下僕かなにかだと思っているが、冗談じゃない。 260 | 人間が猫を飼ってやっているのである。そこを勘違いする猫は 261 | 本当にダメである。 262 | 263 | その点犬は良い。犬は人間のことを「ご主人様」だとおもって 264 | なついてくれる。それならばこそかわいがる気も起きるというものである。 265 | 266 | 犬は賢い。やはり犬がよい。犬はかわいい。 267 | 268 | 散歩に行ったあとに息が上がっている様など、ほんとうに良いものである。 269 | 270 | 犬大好き。犬最高。 271 | 272 | 猫好きな人間がいるのが不思議。 273 | ``` 274 | 275 | おお、hotfix で行った変更が取り込まれている!!これで、グラフも、コミットに含まれているファイルの内容も、「hotfixが終わったところから編集した」のと同じことになりましたね! ここまでは良いですか? 276 | 277 | では、rebase を行ったときに何が起こっていたのかを詳しくみて行きましょう。 278 | 279 | ## 過去へさかのぼりやりなおす 280 | 281 | rebase したときに出てきた表示を再度見てみましょう。なんて書いてありますか? 282 | 283 | ``` 284 | First, rewinding head to replay your work on top of it... 285 | Applying: 作業途中だがとりあえずコミットしておく 286 | ``` 287 | 288 | 「まず、head を巻き戻すよ。これは、君がやったことを最初からリプレイするためだよ!」と言ってますね。そして、そのあとに、「適用中:作業途中だがとりあえずコミットしておく」とあります。 289 | 290 | つまりこれはどういうことでしょうか? 291 | 292 | それを理解する補助線として、まずは「もしもあなたが手動で rebase と同じことをするとしたらどうする?」という話を考えましょう。以下の手順で、同じことができますね。 293 | 294 | 1. unify_styles の各コミットで「どのような変更を行ったのか」を覚えておく 295 | 1. master (hotfix を merge したあとの状態) を checkoutする 296 | 1. そこから新しくまた unify_stylesブランチを切る 297 | 1. 覚えておいた「どのような変更を行ったのか」をイチから適用し直して行く。 298 | 299 | じつは、rebase で行われていることもこれとかわりがありません。 300 | 301 | まずは、unify_styles を「巻き戻し」して、master からあたらしくブランチを切り直します。そこから、unify_styles の各コミットで行った変更を、master が指しているコミットに対して適用しなおしているわけです。つまり、「適用中:作業途中だがとりあえずコミットしておく」が意味しているのは、そのコミットで行った変更内容を、再度 master から適用しなおしているよ、という意味だったのですね! 302 | 303 | ということはですよ? 304 | 305 | rebase 前の、「作業途中だがとりあえずコミットしておく」のコミットと、rebase 後の「作業途中だがとりあえずコミットしておく」というのは、似て非なるコミットとなっているはずです。実際、ファイルの内容は hotfix で行った変更を取り込んだものに変化していましたね?そして、rebase 前のコミットオブジェクトの id と rebase 後のコミットオブジェクトの id が変化しています! 306 | 307 | なるほどー。 308 | 309 | つまり rebase というのは、「過去に戻って別のところから変更をやりなおして、コミットをやり直すことで過去を改変しているもの」なのですね。 310 | 311 | ## そんなになにもかもうまくはいかない 312 | 313 | でも、ちょっと待ってください。今回はたまたま「変更のやり直し」が機械的に可能だったけれど、もしも Git さんが「やり直し」をしている間に、「機械的に変更の適用」ができない事態に陥ったらどうなるのでしょう? 言い方を変えれば、リベース中にコンフリクトが起こったら? ということです。 314 | 315 | そのときは、rebase 作業が途中で止まってしまい、「このコミットやり直してるときにコンフリクトが起こったよ!」と Git さんが教えてくれます。 316 | 317 | 実際にわたしの手元で意図的にコンフリクトを起こしたときの表示は以下のように表示されました。 318 | 319 | ``` 320 | First, rewinding head to replay your work on top of it... 321 | Applying: <やりなおしているコミットの名前> 322 | Using index info to reconstruct a base tree... 323 | M <コンフリクトを起こしたファイルの名前> 324 | Falling back to patching base and 3-way merge... 325 | Auto-merging <コンフリクトを起こしたファイルの名前> 326 | CONFLICT (content): Merge conflict in <コンフリクトを起こしたファイルの名前> 327 | Failed to merge in the changes. 328 | Patch failed at <コンフリクトを起こした行> <コンフリクトの内容> 329 | The copy of the patch that failed is found in: 330 | /Users/shinpeim/hoge/.git/rebase-apply/patch 331 | 332 | When you have resolved this problem, run "git rebase --continue". 333 | If you prefer to skip this patch, run "git rebase --skip" instead. 334 | To check out the original branch and stop rebasing, run "git rebase --abort". 335 | ``` 336 | 337 | ふむふむ、いろいろと情報が出てきて、最後の三行に、 338 | 339 | ``` 340 | 問題を解決したら、"git rebase --continue".をしてね。 341 | この変更をスキップしちゃいたいなら、"git rebase --skip" instead.だよ。 342 | もとのブランチを checkout してリベースをやめてしまいたいなら、"git rebase --abortしてね" 343 | ``` 344 | 345 | だそうです。コンフリクトを起こしたファイルを開いてみると、mregeでコンフリクトを起こしたときとおなじように、どのようなコンフリクトがおこったかの情報が書かれていますので、手動で修正しましょう。修正したら、マージのときと同じように、 `git add` で「修正したよ」と Git に教えてあげましょう。これで問題は解決したので、Git さんの言う通り`git rebase --continue`をすれば、Git さんは rebase の続きを行ってくれます。 346 | 347 | ## では今度こそ作業の続き 348 | 349 | さて、とにかく、rebase で歴史を改変して、「hotfix が終わったあとに文体の統一の作業を始めた」世界線に辿りつくことができました。作業の続きを行いましょう。といいたい所なのですが、直前のコミットが「とりあえずのコミット」だったのを覚えていますか? こんな中途半端なコミット、捨て置けないですね。なので、今度は「直前のコミットをやりなおす」という歴史改変方法を伝授しましょう。 350 | 351 | これは簡単で、`git add` で「やりなおした後の状態のファイル」を stage してから、 352 | 353 | $ git commit --amend 354 | 355 | することで、直前のコミットをやり直すことができます。やってみましょう。 356 | 357 | まずはファイルを編集します。 358 | 359 | * cat_lover_said.txt 360 | 361 | ``` 362 | 猫は動物の一種である。 363 | 364 | 犬とならび、ペットとして飼われることの多い動物である。 365 | 366 | 猫は人間のことを下僕かなにかだと思っており、また人間も 367 | 人間で猫に使役されることを至上の喜びと思う傾向にある。 368 | 369 | 猫の魅力に取り付かれた人間は二度と猫の魅力から離れることが 370 | できないとも言われている。 371 | 372 | 猫というのはかように本当にかわいいものである。 373 | 374 | 猫好きではない人間が存在するのが、私には不思議に思える。 375 | ``` 376 | 377 | * cat_hater_said.txt 378 | 379 | ``` 380 | cat cat_hater_said.txt 381 | 猫は動物の一種である。 382 | 383 | 犬とならび、ペットとして飼われることの多い動物である。 384 | 385 | 猫は人間のことを下僕かなにかだと思っているが、冗談じゃない。 386 | 人間が猫を飼ってやっているのである。そこを勘違いする猫は 387 | 本当にダメである。 388 | 389 | その点犬は良い。犬は人間のことを「ご主人様」だとおもって 390 | なついてくれる。それならばこそかわいがる気も起きるというものである。 391 | 392 | 犬は賢い。やはり犬がよい。犬はかわいい。 393 | 394 | 散歩に行ったあとに息が上がって ヘッヘッヘッヘッ と 395 | なっている様など、ほんとうに良いものである。 396 | 397 | 猫が好きな人間が存在するというのが、私には不思議に思える。 398 | ``` 399 | 400 | このように編集しました。さて、ではこの内容で直前のコミットを「やりなおし」しましょう。 401 | 402 | $ git add . 403 | $ git commit --amend 404 | 405 | です。前回のコミットメッセージ「作業途中だがとりあえずコミットしておく」が表示されたテキストエディタが立ち上がったでしょう。もう作業は終わったので、このメッセージを「文体を統一」に書き換えて、保存して終了しましょう。 406 | 407 | はい、コミットができましたね。ではグラフを確認しましょう。 408 | 409 | ``` 410 | $ git graph 411 | * 519a167 (HEAD, unify_styles) 2013-05-06 Shinpei Maruyama 文体を統一 412 | * 87fe5eb (master) 2013-05-06 Shinpei Maruyama Merge branch 'hotfix' 413 | |\ 414 | | * 0bd5673 2013-05-06 Shinpei Maruyama 頭おかしいという表現はまずいので修正 415 | |/ 416 | * 3b9ccc5 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 417 | ``` 418 | 419 | 「作業途中だがとりあえずコミットしておく」というコミットが、「文体を統一」でやりなおされているのがわかると思います。 420 | 421 | ちょう便利! 422 | 423 | ## あとはリリース 424 | 425 | さて、「文体の統一」の作業の結果をディレクターにチェックしてもらい、OK が出ました。あとは master に merge してリリースしてしまいましょう。 426 | 427 | $ git checkout master 428 | $ git merge --no-ff unify_styles 429 | $ git branch -d unify_styles 430 | 431 | はい、最後にグラフを確認しておきましょう。 432 | 433 | ``` 434 | $ git graph 435 | * fe4090c (HEAD, master) 2013-05-06 Shinpei Maruyama Merge branch 'unify_styles' 436 | |\ 437 | | * 519a167 2013-05-06 Shinpei Maruyama 文体を統一 438 | |/ 439 | * 87fe5eb 2013-05-06 Shinpei Maruyama Merge branch 'hotfix' 440 | |\ 441 | | * 0bd5673 2013-05-06 Shinpei Maruyama 頭おかしいという表現はまずいので修正 442 | |/ 443 | * 3b9ccc5 2013-05-06 Shinpei Maruyama 猫好きの話と犬好きの話を作成 444 | ``` 445 | 446 | なんだかすっきりしたグラフになりました。いいですね! 447 | 448 | ## merge を使うべきなのか rebase を使うべきなのか 449 | 450 | さて、rebase を使うとグラフや履歴がすっきりするのはわかりました。では、こういうケースではいつでも rebase を使うべきなのでしょうか? これも結構現在でも宗教戦争が活発に行われているトピックなので、あなたの所属する組織やプロジェクトのやり方に合わせるのが良いでしょう。 451 | 452 | ちなみに、筆者は最近では rebase のような大掛かりな過去改変は「ダークサイド」であるという見解に与するものです。rebaseすると、Git さんが勝手に過去のコミットを書き換えてしまいます。これによって、「ちゃんと問題なく動いていたコミット」が「動かないコミット」になってしまう可能性がある、というのがその理由です。 453 | 454 | もちろん、マージコミットでもそのようなことは起こるのですが、マージコミットの場合はその後のテストでかならずすぐに「動かないコミット」を作ってしまったことを確認できますが、リベースで出来上がったコミットをいちいち再度テストするのは現実的ではないですよね? 455 | 456 | それでは今回のまとめです。 457 | 458 | * 今いるブランチが「履歴上のどこから分岐したのか」という過去を改変するためには、`git rebase` を使う。 459 | * rebase をすると、分岐元から今までに行ったコミットの変更内容を、新しい分岐元からひとつずつイチから適用しなおしてくれる。 460 | * 直前のコミットという過去を改変するためには、`git commit --amend` を使う 461 | 462 | こんなところでしょうか。次回はついに「複数人で一緒に Git を使う」の話に入りますよ! 463 | 464 | [next - みんなでつかう - ベアリポジトリとクローン,リモートリポジトリ](09_clone.md) -------------------------------------------------------------------------------- /09_clone.md: -------------------------------------------------------------------------------- 1 | # みんなでつかう - ベアリポジトリとクローン,リモートリポジトリ 2 | 3 | さて、前回までで、ひとりで使うぶんには基本的な使い方ができるようになりましたね。では、これからはみんなで Git を使って行きましょう。ここからは学習のためにひとり何役もこなしてもらいますよ! 4 | 5 | # まずは準備 6 | 7 | まずは毎度恒例、準備から行いましょう。そして、今からあなたが演じるのは「たかし」です。 8 | 9 | たかしは、今からあるプロジェクトを始めます。まずはそのためのディレクトリとリポジトリを作成しましょう。ディレクトリの名前は「takashis_workspace」にしましょうか。ではそこにリポジトリを作ってください。 10 | 11 | できましたか? 12 | 13 | そして、あなたはこのディレクトリ内にいるときはたかしくんです。なので、たかしくんとして振る舞うための設定をしておきましょう。 14 | 15 | $ cd path/to/takashis_workspace 16 | $ git config user.name TAKASHI 17 | $ git config user.email takashi@example.com 18 | 19 | これで、このディレクトリ内ではあなたの名前は TAKASHI になりますし、メールアドレスも takashi@example.com となります。 20 | 21 | まずは、なにかコミットしましょう。いつものやつにしますか。 22 | 23 | * cat_lover_said.txt 24 | 25 | ``` 26 | 猫は動物の一種である。 27 | 28 | 犬とならび、ペットとして飼われることの多い動物である。 29 | 30 | 猫は人間のことを下僕かなにかだと思っており、また人間も 31 | 人間で猫に使役されることを至上の喜びと思う傾向にある。 32 | 33 | 猫の魅力に取り付かれた人間は二度と猫の魅力から離れることが 34 | できないとも言われており、猫ってほんとうにかわいいですね。 35 | 36 | もうほんとうに可愛い、猫。 37 | 猫。 38 | 猫が本当にかわいい。 39 | 40 | 猫好きじゃない人間とか頭がおかしいとしか思えない。 41 | ``` 42 | 43 | 上のような内容のテキストを作成し、コミットしてください。コミットメッセージは「猫好きの話を追加」でいいですね。 44 | 45 | さて、準備はいいですね。では、まずは今回のブランチの運用のポリシーを決めましょう。 46 | 47 | まず、masterブランチですが、master ブランチにコミットするものは「リリースするもの」だけ、ということにしましょう。開発途中のものをコミットするのは、「development」というブランチにします。そして、作業は development からトピックブランチを切って行います。 48 | 49 | 言い方を変えると、なにか作業をするときには development ブランチから topic ブランチを切って行います。そして、その作業が終わったら、develop ブランチでそのトピックブランチを merge します。これを繰り返して、development ブランチの状態が「リリースできるもの」になったら、master ブランチから development ブランチを merge します。 50 | 51 | こうすることによって、 52 | 53 | * master が指してるコミットは、必ず 「最新のリリース」 である 54 | * development が指しているコミットは、「最新の開発版」である 55 | * 各トピックブランチが指しているコミットは、「作業途中の状態」である 56 | 57 | ということが保証されます。なんか便利な気がしますね。ディレクターから「今の最新版チェックしたいから見せて」と言われたら、「自分で development ブランチ見ろや」って言えますし、ユーザーから不具合報告が来たら、master ブランチの内容を精査すればいいのです。 58 | 59 | それともうひとつ、すでにリリースしてしまったものに不具合が見つかったときにそれを緊急で修正しなければならないときには、master ブランチから hotfix ブランチを切って、ここで修正した内容を master ブランチに merge することにしましょう。これで、開発中のものを急いでリリースせずに、緊急の対応だけは先にリリース版に組み込みことができますね。 60 | 61 | そして、この緊急対応が無事にリリースされたなら、hotfix が取り込まれた master ブランチを development にマージすることにしましょう。このように運用することで、開発版にも、リリース版での修正を反映することができます。 62 | 63 | では、このような開発を進めるために、たかしくんであるあなたは、まずは development ブランチを作っておきましょう。 64 | 65 | $ git branch development 66 | 67 | はい、いいですね。 68 | 69 | ## ゆうすけがプロジェクトに参戦! 70 | 71 | さて、ここで、このプロジェクトにあたらしくゆうすけが参戦することになりました。嬉しいですね!今回は簡単のため、たかしもゆうすけも同じマシン上で開発を行っているという設定にしましょう。ほんらいならば、おそらくネットワーク越しに協調作業を行うことになるのでしょうが、その場合もやることはほとんど変わりません。 72 | 73 | さて、たかしであるあなたは、「ゆうすけとどうやって作業を一緒にやろうかな」と考えています。"ゆうすけのリポジトリ" と "たかしのリポジトリ" の間で変更内容をやりとりしてもいいのですが、このあと、さらに三人目のメンバーがプロジェクトに参戦した場合、三人で互いに変更内容をやりとりするのは想像するだけで大変ですね。 74 | 75 | なので、ふたりが共通でさわるリポジトリを作ってしまいましょう。それぞれ、自分のリポジトリで行った変更をこの共通のリポジトリに反映させたり、相手が行った変更をこの共通のリポジトリから取ってきたりする、という運用でいきます。 76 | 77 | みんなで触るリポジトリーのイメージ 78 | 79 | では、なにはともあれ「みんなで触るリポジトリ」が必要ですね。この「みんなで触るリポジトリ」は、「たかしのリポジトリ」から複製してしまいましょう。リポジトリの複製は、`git clone <複製元> <複製される先>` です。 takashis_workspace ディレクトリから出て、 80 | 81 | $ git clone --bare path/to/takashis_workspace path/to/shared_repo.git 82 | 83 | と打ってみましょう。 `--bare` というオプションがついてますが、今は気にしないでおいてください。 path/to/shared_repo.git はそれぞれ自分の環境に読み替えてください。 84 | 85 | さて、実際にコマンドを打ってみると、こんな表示が出てくるはずです。 86 | 87 | ``` 88 | Cloning into bare repository 'shared_repo.git'... 89 | done. 90 | ``` 91 | 92 | 「bare repository 'shared_repo.git' を作ったよ」だそうです。bare repository? なんだそれは? 93 | 94 | それを知るために、作られたリポジトリの正体を見てみましょう。ファイラーでもなんでもいいです。作られたリポジトリはどんなファイルですか? そう、ディレクトリですね。そして、その中になんかいろいろごちゃごちゃとファイルが入っているのがわかるでしょう。 95 | 96 | ここで、本書の最初で見た「リポジトリの実体」がなんだったか、思い出してみましょう。そうです、作業ディレクトリの中に作られた、「.git」というディレクトリでしたね。リポジトリは、ただのディレクトリです。そして、今回の「bare repository」もディレクトリでした。 97 | 98 | 勘のいいひとはもうわかったかもしれませんね。実は、 99 | 100 | $ git clone --bare 複製元 複製される先 101 | 102 | という感じで `--bare` を付けてリポジトリを複製すると、作業ディレクトリなしで、リポジトリだけを複製することができるのです。 103 | 104 | 「みんなで触るリポジトリ」で直接作業を行うことはないので、このリポジトリには作業ディレクトリは要らないですよね。なので、みんなで触るリポジトリを作るときには `--bare` 付きで複製しましょう。みんなで触るリポジトリをこういう「bare repository」で作るのには、実はもうひとつ理由があるのですが、それはまた改めて説明しましょう。ちなみに、bareリポジトリの名前は、最後に「.git」を付けるのが慣習となってます。 105 | 106 | さて、これで無事に「みんなで触るリポジトリ」が出来上がりました。 107 | 108 | では、今からあなたは「ゆうすけ」です。ゆうすけはこのプロジェクトに参戦するために、このプロジェクトのリポジトリを手元に複製する必要ですがありますね。 109 | 110 | というわけで、ゆうすけはこの「みんなで触るリポジトリ」から、自分の手元にリポジトリを複製してきましょう。 111 | 112 | $ git clone path/to/shared_repo.git path/to/yuusukes_workspace 113 | 114 | はい、`--bare` なしでcloneしてみました。これで、path/to/yuusukes_workspace に、作業ディレクトリ付きでリポジトリが複製されました。 115 | 116 | では、ゆうすけの作業ディレクトリではゆうすけとして振る舞う設定をしておきましょう。 117 | 118 | $ cd path/to/yuusukes_workspace 119 | $ git config user.name YUUSUKE 120 | $ git config user.email yuusuke@example.com 121 | 122 | ## ゆうすけ、混乱する 123 | 124 | さて、ここで、ディレクターは、ゆうすけに例の「文体変更」のお仕事をお願いしました。ゆうすけであるあなたは、この作業を行おうとしています。 125 | 126 | 作業を行うには、development ブランチからトピックブランチを切るのでしたね。ちゃんと手元に development ブランチが複製されてきてるか、`git branch` で確認しましょう。 127 | 128 | $ git branch 129 | * master 130 | 131 | !? developmentブランチがないぞ!? グラフも確認しましょう。 132 | 133 | $ git graph 134 | * 253585d (HEAD, origin/master, origin/development, origin/HEAD, master) 2013-05-07 TAKASHI 猫好きの話を追加 135 | 136 | なんか知らないのたくさんある!怖い!! 137 | 138 | 怖いですね。説明しましょう。 139 | 140 | ## リモートリポジトリとはなにか 141 | 142 | さて、この状態を説明するためには、「リモートリポジトリ」というものを説明しないといけません。「リモートリポジトリ」とはなんでしょうか。その説明のために、今回の登場人物(登場リポジトリ?)の整理から始めましょう。今回の共同作業で登場したリポジトリは、みっつです。 143 | 144 | * たかしのリポジトリ 145 | * ゆうすけのリポジトリ 146 | * みんなで触るリポジトリ 147 | 148 | そして、ゆうすけは、ゆうすけのリポジトリで変更した内容を「みんなで触るリポジトリ」に反映させなければなりません。あるいは、たかしが行った内容を、「みんなで触るリポジトリ」から取得しなければなりません。 149 | 150 | こういう、「あのリポジトリにコミット内容を反映させたい」とか「あのリポジトリの変更内容を取得してきたい」というようなことをするためには、「あのリポジトリ」にあたるリポジトリを、「リモートリポジトリ」として登録しておかなければなりません。なので、今回で言えば、「みんなで触るリポジトリ」を「ゆうすけのリポジトリから見たリモートリポジトリ」として登録する必要がある訳ですね。 151 | 152 | 逆の言い方をすると、手元のリポジトリのコミット内容を別のリポジトリに反映させたり、別のリポジトリのコミット内容を手元のリポジトリに反映したい場合には、「リモートリポジトリ」として、そのリポジトリを登録しておく必要がある、ということです。 153 | 154 | ちなみに、`git clone` でリポジトリを手元に複製してきた場合、Git さんが勝手に clone 元のリポジトリを、「origin」という名前のリモートリポジトリとして登録してくれるのです。これで、cloneしてきたリポジトリからコミット内容を手元に取り込んだり、手元のリポジトリのコミット内容をcloneしてきたリポジトリに反映できますね!Git さんってば気が利く! 155 | 156 | では、現在のゆうすけのリモートリポジトリの様子を見てみましょう。あなたはゆうすけです。今ゆうすけの作業ディレクトリにいますね?では、そこで、 `git remote` と打ってみましょう。 157 | 158 | $ git remote 159 | origin 160 | 161 | はい、origin が表示されました。これはつまり、「リモートリポジトリとして origin というリポジトリが登録されているよ」ということです。 162 | 163 | ふむふむなるほど。 164 | 165 | それでは、それを念頭においてから、先ほどの graph の結果を眺めてみましょう。 166 | 167 | $ git graph 168 | * 253585d (HEAD, origin/master, origin/development, origin/HEAD, master) 2013-05-07 TAKASHI 猫好きの話を追加 169 | 170 | origin/master, origin/development, origin/HEAD というみっつのブランチがありますね。これらはそれぞれ、「origin リモートリポジトリ(つまり clone 元)の master ブランチ」「origin リモートリポジトリの development ブランチ」「origin リモートリポジトリのHEAD」を表しています。`git clone` をすると、クローン元に存在するコミットとブランチを、手元に複製してきます。このとき、ブランチは「リモートブランチ」としてコピーされてきます。リモートリポジトリからコピーされてきたブランチなので、「リモートブランチ」です。 171 | 172 | 今は、手元に master ブランチと、clone 元から複製されてきた三つの「リモートブランチ」が存在している状態です。 173 | 174 | これらのリモートブランチは、もともと「自分の物」ではありません。「みんなのもの」です。なので、このリモートブランチを選択して作業をすることはできません。では、リモートリポジトリに内容を反映させたいような変更を手元で行うためには、どうすればいいのでしょうか? 175 | 176 | 手順は以下の通りです。 177 | 178 | * リモートリポジトリの、反映したいブランチを「追跡」するためのブランチを手元のリポジトリに作成する 179 | * そのブランチ上で変更を行い、コミットする 180 | * このコミットを、「追跡」しているリモートブランチとリモートリポジトリに反映する 181 | 182 | 言い方を変えると、手元に「リモートを追跡するブランチ」を作ることで、そこで行った変更をその追跡元であるリモートブランチに反映したり、逆にリモートブランチに行われている変更は追跡しているブランチに取り込むことができる、ということです。 183 | 184 | ちょっと複雑な話になっているので、ここまでをまとめておきましょうか。 185 | 186 | * `git clone` すると、複製元のコミットとブランチがすべて手元のリポジトリに複製される 187 | * このとき、複製元のブランチは「リモートブランチ」として複製される 188 | * リモートリポジトリに対して手元で行った変更を反映するためには、このリモートブランチを「追跡」するブランチを手元に作成する必要がある。 189 | * このブランチに対するコミットは、対応するリモートリポジトリのブランチに反映することができる 190 | * 対応するリモートリポジトリのブランチで行われているコミットは、このブランチに取り込むことができる 191 | 192 | さて、ゆうすけは今から作業を行うために、development ブランチからトピックブランチを切らなければなりません。なので、なにはともあれ手元に development ブランチが必要です。 193 | 194 | というわけで、「origin/development」を追跡する development ブランチを、手元に作成しましょう。リモートブランチを追跡するブランチを作成するためには、 `git branch <手元のブランチの名前> <追跡したいリモートブランチの名前>`です。やってみましょう。 195 | 196 | $ git branch development origin/development 197 | Branch development set up to track remote branch development from origin. 198 | 199 | 「development ブランチは、 origin から来た development リモートブランチを追跡するように設定されたよ」と言われましたね。いい感じです。 200 | 201 | これで、ゆうすけは手元の development ブランチで行った反映を origin の development ブランチに反映したり、その逆に origin の development ブランチで行われた変更を自分の development ブランチに適用することができるようになりました。 202 | 203 | ところで、さきほど `git clone` してきたときに、すでに手元に master ブランチが存在していましたね? これはどういうことでしょうか。 204 | 205 | git clone を行ったとき、まずはクローン元のリポジトリに存在するコミットとブランチが手元に複製されるのは上で見た通りです。じつは、Git さんはそのあと、origin/master ブランチを追跡する master ブランチを勝手に手元に作成してくれて、さらに作業ディレクトリ内にこの master ブランチを checkout するところまで自動でやってくれていたのです。 206 | 207 | なるほどねー。 208 | 209 | ## 一方たかしは? 210 | 211 | では、たかしのほうはどうでしょうか。今度はたかしになって、たかしの作業ディレクトリに移動してみてください。 212 | 213 | ``` 214 | $ cd path/to/takashis_workspace 215 | $ git remote 216 | ``` 217 | 218 | なにも表示されませんね。 219 | 220 | これは当然で、たかしのリポジトリは、clone で作ったリポジトリではないので、Git さんが勝手にリモートリポジトリを登録してくれたりはしていないのです。じゃあ、たかしのほうからも「みんなで触るリポジトリ」に対して変更を反映できたりそこから変更を取得してきたりできるように、remote リポジトリを設定しておきましょう。remoteリポジトリを追加するためには、`git remote add <リモートリポジトリの名前> <リモートリポジトリの場所>` です。 221 | 222 | ``` 223 | $ git remote add origin path/to/shared_repo.git 224 | ``` 225 | 226 | さて、これでリモートリポジトリが設定されました。確認してみましょう。 227 | 228 | ``` 229 | $ git remote 230 | origin 231 | ``` 232 | 233 | うん、よさそうですね。では、graph も確認しましょう。 234 | 235 | ``` 236 | $ git graph 237 | * a10bcb5 (HEAD, master, development) 2013-05-07 Shinpei Maruyama 猫好きの話を追加 238 | ``` 239 | 240 | アレッ!? origin/* ブランチがないですね!? 241 | 242 | それもそのはず、今は「リモートリポジトリはここにあるよ」という設定はしましたが、そのリモートリポジトリに存在しているコミットやブランチを手元のリポジトリにコピーしてくるところまではやっていません。ゆうすけの場合、git clone を行うことでリモートリポジトリのコミットやブランチが手元にコピーされてきましたが、たかしはリモートリポジトリをクローンしたわけではないですからね。 243 | 244 | では、リモートリポジトリに存在するコミットやブランチを手元に持ってきましょう。そのために使うコマンドが、 `git fetch` です。`git fetch <リモートリポジトリの名前>` で、リモートリポジトリの中身を手元に持って来れます。やってみましょう。 245 | 246 | ``` 247 | $ git fetch origin 248 | From path/to/shared_repo 249 | * [new branch] development -> origin/development 250 | * [new branch] master -> origin/master 251 | ``` 252 | 253 | ふたつの新しいブランチが生まれていますね。矢印の左側が「リモートリポジトリでのブランチの名前」、矢印の右側が「手元にコピーされたリモートブランチ」です。 254 | 255 | さて、これで準備は OK でしょうか? 256 | 257 | じつは、まだ準備は万端ではありません。今、たかしの手元には development ブランチと master ブランチが存在していますが、このブランチがそれぞれ origin/development と origin/master を追跡するようにしないと、手元で行った変更が origin/development や origin/master に反映されませんね。なので、次は手元の master, development がそれぞれ origin/master, origin/development を追跡するように設定しましょう。 258 | 259 | そのためには、"git branch --set-upstream-to=<追跡したいリモートブランチ> <手元のブランチ>" というコマンドを利用します。 260 | 261 | ではやってみましょう。 262 | 263 | $ git branch --set-upstream-to=origin/master master 264 | Branch master set up to track remote branch master from origin. 265 | 266 | $ git branch --set-upstream-to=origin/development development 267 | Branch development set up to track remote branch development from origin. 268 | 269 | うん、いい感じに設定できましたね。 270 | 271 | ようやくこれで、みんなで Git を使う準備が整いました!今回はリポジトリを用意するところから初めて、しかも二人分の環境をひとりで設定したのでなんだか大変でしたが、実際のプロジェクトでは多くの場合「ゆうすけ」のポジションで開発を行うことになるでしょうから、そんなに大変なことはありません。「みんなで触るリポジトリ」を `git clone` してきて、必要に応じて手元で追跡ブランチを作成すればいいだけですね。 272 | 273 | では、今回のまとめです。 274 | 275 | * 手元のリポジトリでの変更内容を他のリポジトリに反映したり、逆に他のリポジトリでの変更内容を自分のリポジトリに反映するためには、そのリポジトリを「リモートリポジトリ」として登録しておかなくてはいけない 276 | * `git clone` でリポジトリを複製した場合、Git が勝手にこの複製もとを「origin」という名前でリモートリポジトリに登録してくれる 277 | * そうでない場合は、 `git remote add <名前> <場所>` でリモートリポジトリを登録できる 278 | * リモートリポジトリに存在するブランチやコミットを手元に複製するためには、 `git fetch <リモートブランチの名前>` を使う 279 | * `git clone` でリポジトリを複製した場合は、clone の段階ですでに手元のリポジトリに複製されている。 280 | * リモートリポジトリに存在するブランチは、手元のブランチにコピーしてくるときには「リモートブランチ」という形でコピーされる。 281 | * リモートブランチに直接コミットすることはできないので、このリモートブランチを追跡するためのブランチを手元のリポジトリに作成する必要がある。 282 | * あるリモートブランチを追跡する新しいブランチを作成したい場合は、`git branch <新しいブランチ名> <リモートブランチ名>` 283 | * すでに手元に存在するブランチであるリモートブランチを追跡したい場合は `git branch --set-upstream-to=<追跡したいリモートブランチ> <手元のブランチ>` 284 | 285 | では、次回は、手元で行ったコミットを「みんなで触るリポジトリ」に反映する方法、「みんなで触るリポジトリ」に反映されたコミットから手元にコミットを持ってくる方法を紹介して、実際にたかしとゆうすけの共同作業をやってみましょう。 286 | 287 | [next - みんなでつかう - push pull](10_push_pull.md) 288 | -------------------------------------------------------------------------------- /10_push_pull.md: -------------------------------------------------------------------------------- 1 | # みんなでつかう - push pull 2 | 3 | さて、前回までで、「たかしのリポジトリと作業ディレクトリ」「ゆうすけのリポジトリと作業ディレクトリ」「みんなで触るリポジトリ」の準備ができました。今回はここから協調作業をおこなっていきましょう。 4 | 5 | ## ゆうすけ、頑張る 6 | 7 | あなたはゆうすけです。ゆうすけは、ディレクターから例の「文体変更」の作業を頼まれていましたね。ではゆうすけの作業ディレクトリでその作業を行って生きましょう。 8 | 9 | $ cd path/to/yuusukes_workspace 10 | $ git checkout -b feature/unify_styles development 11 | 12 | おや、いくつか新しい感じのものが出てきました。 `git checkout -b` は「ブランチを切ってそれをチェックアウト」ですね。今回は「feature/unify_styles」という名前のブランチを切っていますね。これは、「このブランチはフィーチャーブランチだよ」ということをわかりやすくするために、こういう名前を付けただけです。しかし、そのあとに development という指定をさらにしてあります。 13 | 14 | これはどういうことかと言うと、新しいブランチを「どこから」切るのかを指定したのです。 15 | 16 | おそらく、いまゆうすけであるあなたは master ブランチを選択していたでしょう。この状態で`git branch -b <新しく作るブランチの名前>`とすると、master ブランチから分岐するブランチが切られます。しかし、`git branch -b <新しく作るブランチの名前> <分岐元>`とすることで、明示的に「どこからブランチを分岐させるのか」を指定することができるのです。 17 | 18 | さて、これで新しいフィーチャーブランチを切ってチェックアウトしたので、ここで作業を行いましょう。 19 | 20 | * cat_lover_said.txt 21 | 22 | ``` 23 | 猫は動物の一種である。 24 | 25 | 犬とならび、ペットとして飼われることの多い動物である。 26 | 27 | 猫は人間のことを下僕かなにかだと思っており、また人間も 28 | 人間で猫に使役されることを至上の喜びと思う傾向にある。 29 | 30 | 猫の魅力に取り付かれた人間は二度と猫の魅力から離れることが 31 | できないとも言われている。 32 | 33 | 猫というのはかように本当にかわいいものである。 34 | 35 | 猫好きではない人間は、頭がおかしいのではないだろうか。 36 | ``` 37 | 38 | さて、これで文体を統一しました。ではこの変更をコミットしましょう。コミットメッセージは「文体を統一」でいいでしょう。 39 | 40 | ## たかし、頑張る 41 | 42 | さて、ゆうすけが文体の統一という作業を行っている間に、たかしにはディレクターから「頭おかしい」を急いで直せという指示が飛んでいました。 43 | 44 | あなたは今からたかしです。たかし、がんばりましょう。 45 | 46 | たかしの作業ディレクトリに移動し、マスターブランチから hotfix ブランチを切り、チェックアウトします。 47 | 48 | $ cd path/to/takashis_workspace 49 | $ git checkout -b hotfix master 50 | 51 | そして緊急で「頭おかしい」を直しましょう。 52 | 53 | * cat_lover_said.txt 54 | 55 | ``` 56 | 猫は動物の一種である。 57 | 58 | 犬とならび、ペットとして飼われることの多い動物である。 59 | 60 | 猫は人間のことを下僕かなにかだと思っており、また人間も 61 | 人間で猫に使役されることを至上の喜びと思う傾向にある。 62 | 63 | 猫の魅力に取り付かれた人間は二度と猫の魅力から離れることが 64 | できないとも言われており、猫ってほんとうにかわいいですね。 65 | 66 | もうほんとうに可愛い、猫。 67 | 猫。 68 | 猫が本当にかわいい。 69 | 70 | 猫好きじゃない人間がいるのが不思議 71 | ``` 72 | 73 | はい、書き換えましたね。ではこれをコミット。メッセージは「頭おかしいという表現はまずいので修正」です。 74 | 75 | そして、この修正で OK かどうかをディレクターに見てもらうために、この「hotfix」というブランチを「みんなで触るリポジトリ」に反映させましょう! 76 | 77 | ## たかし、固まる 78 | 79 | さて、手元のリポジトリの変更をリモートリポジトリに反映させるためにはどうするのでしたっけ? そうです、追跡ブランチですね。今回ならば、origin/hotfix を追跡するブランチを作れば…………、とここまで考えて、たかしは「アレっ」となりました。そもそも origin/hotfix というリモートブランチが存在しない……。 80 | 81 | こういうときには、「リモートリポジトリに新しいブランチを複製」してしましましょう。方法は、`git push <リモートリポジトリの名前> <手元のブランチ>:<リモートに作りたいブランチ>` です。 82 | 83 | $ git push origin hotfix:hotfix 84 | Counting objects: 5, done. 85 | Delta compression using up to 8 threads. 86 | Compressing objects: 100% (2/2), done. 87 | Writing objects: 100% (3/3), 371 bytes, done. 88 | Total 3 (delta 1), reused 0 (delta 0) 89 | To ../shared_repo.git 90 | * [new branch] hotfix -> hotfix 91 | 92 | いろいろ出てきました。なんかいろいろ出ましたが、重要なのは最後の 2 行です。「shred_repo.git に対して: ・新しいブランチ hotfix -> hotfix」という感じですね。うん。みんなで触るリポジトリにhotfixを作成することができました。 93 | 94 | ちなみに、今回のように、手元のリポジトリでのブランチの名前とリモートリポジトリのブランチの名前が同一の場合は、 95 | 96 | $ git push <リモートリポジトリの名前> <ブランチの名前> 97 | 98 | でも OK です。 99 | 100 | さて、これで「みんなで触るリポジトリ」にhotfixブランチを作成することができました。じゃあ、手元の hotfix ブランチがこのリモートブランチを追跡するように設定しておきましょう。 101 | 102 | $ git branch --set-upstream-to=origin/hotfix hotfix 103 | 104 | はい、いいですね。 105 | 106 | ## たかし、マージする 107 | 108 | さて、「みんなで触るリポジトリ」に hotfix ブランチを push したたかしは、ディレクターに「みんなで触るリポジトリのhotfixブランチの内容をチェックしてください。OK ならばマスターに merge して修正リリースとします」と説明しました。ディレクターはそれを聞いて内容をチェックして、「よし、OK」と OK を出しました。OK を出されたので、これを共有リポジトリの master にマージしたいですね。 109 | 110 | しかし、共有リポジトリを直接いじることはできません。そういうときにはどうするのでしたか? そうです、「追跡ブランチ」を変更すればいいのでしたね。今、共有リポジトリの master ブランチを追跡しているのは、手元の master ブランチです。 111 | 112 | では、hotfix の内容を手元の master ブランチに merge しましょう。これは簡単ですね。 113 | 114 | $ git checkout master 115 | $ gir git merge --no-ff hotfix 116 | 117 | です。では現在のグラフを確認しましょう。 118 | 119 | ``` 120 | $ git graph 121 | * 38f43dc (HEAD, master) 2013-05-07 Shinpei Maruyama Merge branch 'hotfix' 122 | |\ 123 | | * 1d83043 (origin/hotfix, hotfix) 2013-05-07 Shinpei Maruyama 頭おかしいという表現はまずいので修正 124 | |/ 125 | * a10bcb5 (origin/master, origin/development, development) 2013-05-07 Shinpei Maruyama 猫好きの話を追加 126 | ``` 127 | 128 | 手元の master ブランチは、できたてのマージコミットを指しています。しかし、origin/master はまだこのマージコミットを指していませんね。それもそのはず、そもそもまだこのコミットはたかしの手元のリポジトリにしか存在しません。 129 | 130 | では、ここで `git status` を確認してみましょう。 131 | 132 | ``` 133 | $ git status 134 | # On branch master 135 | # Your branch is ahead of 'origin/master' by 2 commits. 136 | # (use "git push" to publish your local commits) 137 | # 138 | nothing to commit, working directory clean 139 | ``` 140 | 141 | お、初めて見る表示が出てきました。なになに? 142 | 143 | 「君のブランチは origin/master よりも 2 コミット進んでいるぜ!(もし君の手元のコミットを公開してしまいたければ、 git push するといいぜ!)」だそうです。また Git さんのキャラがブレていますが、Git さんのキャラがぶれてるときは筆者が疲れている証拠です。暖かく見守って下さい。 144 | 145 | ## たかし、push する 146 | 147 | では、Gitさんに言われたとおり、ここで `git push` で共有リポジトリにこの変更を公開しましょう! 148 | 149 | ``` 150 | $ git push 151 | warning: push.default is unset; its implicit value is changing in 152 | Git 2.0 from 'matching' to 'simple'. To squelch this message 153 | and maintain the current behavior after the default changes, use: 154 | 155 | git config --global push.default matching 156 | 157 | To squelch this message and adopt the new behavior now, use: 158 | 159 | git config --global push.default simple 160 | 161 | See 'git help config' and search for 'push.default' for further information. 162 | (the 'simple' mode was introduced in Git 1.7.11. Use the similar mode 163 | 'current' instead of 'simple' if you sometimes use older versions of Git) 164 | 165 | Counting objects: 1, done. 166 | Writing objects: 100% (1/1), 226 bytes, done. 167 | Total 1 (delta 0), reused 0 (delta 0) 168 | To ../shared_repo.git 169 | a10bcb5..38f43dc master -> master 170 | ``` 171 | 172 | ヒャー!なんか warning が出た! 173 | 174 | 出なかったひとは Git のヴァージョンを上げましょう。あなたの使っている Git はすでに古いです。 175 | 176 | では、warning の内容を読んでみましょう。 177 | 178 | ``` 179 | 警告: push.default が設定されてないよ。push.defaultが設定されていないとき 180 | の値は、Git 2.0 で「matching から simple」に変更されるよ。 181 | 以下のようなコマンドを打つと、今後このメッセージは出なくなるし、 182 | 変更されてからも今までと同じ動きをするよ 183 | 184 | git config --global push.default matching 185 | 186 | 以下のようなコマンドを打つと、今後このメッセージは出なくなるし 187 | 2.0以降の新しい動きをするようになるよ。 188 | 189 | git config --global push.default simple 190 | 191 | もっと詳しい説明が聞きたければ、'git help config' と打って、 192 | 'push .default'の部分を探してくれよな。 193 | (ちなみに'simple'モードは Git 1.7.11 から使えるんだ。もし古い Git の 194 | ヴァージョンを使うようなら、似たような 'current' ってモードを使ってくれ) 195 | ``` 196 | 197 | だそうです。 198 | 199 | 'simple'? 'matching'? 'push.default'? よくわからないですね。説明します。 200 | 201 | この push.default というのは、`git push` 何も後ろに付けずに push を実行したときに、Git さんがどのような動きをするのかを設定する設定項目です。'matching' モードだと、今選択されているブランチがどのブランチかには関係なく、「手元にあるすべての追跡ブランチの変更をリモートに反映する」という動きになります。'simple'モードは、「今選択されているブランチが追跡ブランチであれば、手元のブランチの変更内容をリモートに反映する」という動きになります。 202 | 203 | では、その下の表示も見てみましょう。 204 | 205 | 3 行ログが表示されて、その下に、 shared_repo.git に対して master -> master したよ、と書かれています。うん、手元の master からリモートの master に変更が反映されたみたいですね! 206 | 207 | ん?ちょっとまってください。現在は、git push は「matching」モードになっているはずです。ならば、development ブランチや hotfix ブランチもリモートに反映されないとおかしいのでは? 208 | 209 | そのとおりです。でも、よく考えてみると、development ブランチも hotfix ブランチも、手元とリモートの間に差異がありませんね。なので、Gitさんは、「じゃあ反映させるのは master ブランチだけでいいか」と判断して、masterブランチだけが反映されたのです。 210 | 211 | と、今回 `git push` で行われた内容を一通り確認したところで、push.default の値をどちらに設定するか、決めておきましょう。まあ、ここは素直に新しいほうに合わせて simple に設定しておきましょう。こっちのほうが「あっやべ! push しちゃいけないやつ push しちゃった!」みたいな事故にあわずに済みそうです。 212 | 213 | さて、それでは現在のグラフを確認しましょう。 214 | 215 | ``` 216 | $ git graph 217 | * 38f43dc (HEAD, origin/master, master) 2013-05-07 Shinpei Maruyama Merge branch 'hotfix' 218 | |\ 219 | | * 1d83043 (origin/hotfix, hotfix) 2013-05-07 Shinpei Maruyama 頭おかしいという表現はまずいので修正 220 | |/ 221 | * a10bcb5 (origin/development, development) 2013-05-07 Shinpei Maruyama 猫好きの話を追加 222 | ``` 223 | 224 | うん、origin/master もマージコミットを指すようになりましたね。 225 | 226 | ## たかし、あと始末をする 227 | 228 | さて、これで無事に共有リポジトリの master ブランチに緊急リリースのためのコミットが生まれました。さっさとリリースしてしまいましょう。 229 | 230 | 無事にリリースされたそうです。では、あと始末をしましょう。今からやらなければならないのは大まかに以下の二つです。 231 | 232 | * hotfix ブランチはもう用無しなので、手元からもリモートからも消してしまう 233 | * 緊急リリースによる変更内容を、開発ブランチにも反映させる 234 | 235 | さあ、ではやっていきましょう。手元の hotfix ブランチを消すのは簡単ですね 236 | 237 | $ git branch -d hotfix 238 | 239 | ではリモートのhotfixブランチも消しましょう。ええと、origin/hotfix を消すという変更だから、そのための追跡ブランチは…………あれ、今手元で消しちゃった。消したっていう内容を反映するために追跡ブランチが必要なんだけど消したっていう内容を生むためには消す必要があって push できない……。という感じですね。そんなわけなんで、リモートのブランチを消すためにはそのためのコマンドを別に打つ必要があります。 240 | 241 | $ git push origin :hotfix 242 | 243 | です。「はぁ〜〜〜〜!?なにこのコマンド、このコマンドのどこに「消す」っていう情報が含まれてるの、なんなのこの直感的でないコマンド、ふざけてんのか。」……と思う気持ちもわかります。これ、わかりにくいですね。でも、リモートにブランチを作ったときの `git push` の構文をもう一度思い出してください。 244 | 245 | $ git push <リモートリポジトリの名前> <手元のブランチ>:<リモートに作るブランチ> 246 | 247 | でしたね。これと上のコマンドを見比べてみると、 248 | 249 | $ git push <リモートリポジトリの名前> (ここになにも書いてない):<リモートのブランチ> 250 | 251 | となっています。つまり、「なにもなし」で<リモートのブランチ>を上書きしてるみたいな感じですね。なんかプーさんの「なにもしないをしてるんだよ」に似た納得できなさも感じますが、まあそういうものだと思えば、少しは覚えやすいのではないでしょうか。 252 | 253 | なにはともあれ、これで hotfix ブランチを手元でもリモートでも削除することに成功しました。 254 | 255 | では、次は、 hotfix で対応された内容が反映されている master を、 development に取り込みましょう。 256 | 257 | $ git checkout development 258 | $ git mrege --no-ff master 259 | 260 | コミットメッセージは、なんのために master をマージしたのかわかりやすいように「緊急対応で行った修正をmaster から取り込む」くらいにしておきましょうか。 261 | 262 | はい、これで手元の development の準備ができましたね。それではここでリモートにこれを反映しましょう。 263 | 264 | $ git push 265 | 266 | たかしくん、おつかれさまでした。 267 | 268 | ## 一方ゆうすけは 269 | 270 | さて、ではあなたはゆうすけの役に戻りましょう。ゆうすけ、今どんな状態でしたっけ? ゆうすけの作業ディレクトリに行って、状態を確認しましょう。 271 | 272 | ``` 273 | $ cd path/to/yuusukes_workspace 274 | $ git graph 275 | * 3422d74 (HEAD, feature/unify_styles) 2013-05-07 Shinpei Maruyama 文体を統一 276 | * a10bcb5 (origin/master, origin/development, origin/HEAD, master, development) 2013-05-07 Shinpei Maruyama 猫好きの話を追加 277 | ``` 278 | 279 | ああ、そうでした。文体を統一する作業を終えて、手元のリポジトリにコミットしたところでしたね。では、この内容をディレクターにチェックしてもらうために、共有リポジトリに push しましょう。 280 | 281 | 共有リポジトリにはまだ feature/unify_styles が存在しないので、共有リポジトリにこのブランチを push しないとだめですね。 282 | 283 | ``` 284 | $ git push origin feature/unify_styles 285 | Counting objects: 6, done. 286 | Delta compression using up to 8 threads. 287 | Compressing objects: 100% (4/4), done. 288 | Writing objects: 100% (6/6), 922 bytes, done. 289 | Total 6 (delta 1), reused 0 (delta 0) 290 | To /Users/shinpeim/shared_repo.git 291 | * [new branch] feature/unify_styles -> feature/unify_styles 292 | ``` 293 | 294 | うん、いいでしょう。これでディレクターにチェックしてもらいましょう。 295 | 296 | はい、ディレクターから OK が出ました。では、最新の開発版にこれを反映させるために、development ブランチにマージしましょう。 297 | 298 | でもちょっとまって!共有リポジトリの development ブランチには、すでにたかしが変更を加えています。なので、さきにそのたかしが行った変更をゆうすけは手元に持ってきておきたいですね。 299 | 300 | リモートリポジトリのコミットやブランチを手元にコピーしてくるコマンドは覚えていますか?そうです。 git fetch です。 301 | 302 | ``` 303 | $ git fetch origin 304 | remote: Counting objects: 7, done. 305 | remote: Compressing objects: 100% (4/4), done. 306 | remote: Total 5 (delta 3), reused 0 (delta 0) 307 | Unpacking objects: 100% (5/5), done. 308 | From /Users/shinpeim/shared_repo 309 | a10bcb5..c5e394e development -> origin/development 310 | a10bcb5..38f43dc master -> origin/master 311 | ``` 312 | 313 | はい、これでリモートリポジトリの内容がコピーされてきました。リモートリポジトリのブランチは「リモートブランチ」としてコピーされてくるのでしたね。いいですか? 314 | 315 | ではここでグラフを確認してみましょう。 316 | 317 | ``` 318 | $ git graph 319 | * c5e394e (origin/development) 2013-05-07 Shinpei Maruyama 緊急対応で行った修正をmasterから取り込む 320 | |\ 321 | | * 38f43dc (origin/master, origin/HEAD) 2013-05-07 Shinpei Maruyama Merge branch 'hotfix' 322 | | |\ 323 | |/ / 324 | | * 1d83043 2013-05-07 Shinpei Maruyama 頭おかしいという表現はまずいので修正 325 | |/ 326 | | * 3422d74 (HEAD, origin/feature/unify_styles, feature/unify_styles) 2013-05-07 Shinpei Maruyama 文体を統一 327 | |/ 328 | * a10bcb5 (master, development) 2013-05-07 Shinpei Maruyama 猫好きの話を追加 329 | ``` 330 | 331 | 見事にリモートリポジトリのコミットとブランチが取り込まれています。 332 | 333 | さて、ここでリモートブランチと手元のブランチを比べてみてください。手元のブランチはリモートリポジトリよりもだいぶ「昔のコミット」を指しています。リモートで行われた変更を手元に反映させるために、手元のブランチもリモートブランチのところまで「進めて」しまいたいですね。そうです、「Fast-forward」したいのです。じゃあそうしましょう。 334 | 335 | ``` 336 | $ git checkout master 337 | $ git mrege origin/master 338 | $ git checkout development 339 | $ git merge origin/development 340 | ``` 341 | 342 | はい、これで Fast-forward されて手元のブランチがリモートリポジトリに「追いつき」ました。グラフを確認しましょう。 343 | 344 | ``` 345 | $ git graph 346 | * c5e394e (HEAD, origin/development, development) 2013-05-07 Shinpei Maruyama 緊急対応で行った修正をmasterから取り込む 347 | |\ 348 | | * 38f43dc (origin/master, origin/HEAD, master) 2013-05-07 Shinpei Maruyama Merge branch 'hotfix' 349 | | |\ 350 | |/ / 351 | | * 1d83043 2013-05-07 Shinpei Maruyama 頭おかしいという表現はまずいので修正 352 | |/ 353 | | * 3422d74 (origin/feature/unify_styles, feature/unify_styles) 2013-05-07 Shinpei Maruyama 文体を統一 354 | |/ 355 | * a10bcb5 2013-05-07 Shinpei Maruyama 猫好きの話を追加 356 | ``` 357 | 358 | うん、きちんと追いついています。 359 | 360 | さて、いちいちこうやってリモートリポジトリの内容を取得してきて、手動で merge するのは正直だるいですね。だるすぎです。そのために用意されているの `git pull` です。 361 | 362 | `git pull` は、「fetch してマージ」という一連の動作を自動でやってくれます。普段はこちらを使うと良いでしょう。ただし、気をつけてください。さきほど "`git pull` は「fetch してマージ」をという一連の動作を自動でやってくれる" といいました。そうです、「マージ」を行うのです。そのため、`git pull` を行うと「コンフリクト」が起こる可能性もあります。でも、もうあなたはコンフリクトがおこったおきにどうすればいいか、知っていますね。なら怖がらなくても大丈夫。落ち着いて競合を直し手動でマージコミットを作ればいいのです。 363 | 364 | 当然、このマージコミットは「手元」にしかないマージコミットなので、適切に共有リポジトリに push する必要も出てくるでしょう。でも、もうあなたはリモートリポジトリと手元のリポジトリの関係を適切にハンドルすることができるようになっています。これもなにも怖くないですね。 365 | 366 | ## ゆうすけ、development にマージする 367 | 368 | さて、これでゆうすけのリポジトリは「みんなで触るリポジトリ」に「追いつき」ました。再度グラフを確認しましょう。 369 | 370 | ``` 371 | $ git graph 372 | * c5e394e (HEAD, origin/development, development) 2013-05-07 Shinpei Maruyama 緊急対応で行った修正をmasterから取り込む 373 | |\ 374 | | * 38f43dc (origin/master, origin/HEAD, master) 2013-05-07 Shinpei Maruyama Merge branch 'hotfix' 375 | | |\ 376 | |/ / 377 | | * 1d83043 2013-05-07 Shinpei Maruyama 頭おかしいという表現はまずいので修正 378 | |/ 379 | | * 3422d74 (origin/feature/unify_styles, feature/unify_styles) 2013-05-07 Shinpei Maruyama 文体を統一 380 | |/ 381 | * a10bcb5 2013-05-07 Shinpei Maruyama 猫好きの話を追加 382 | ``` 383 | 384 | さて、今から何を行うのでしたっけ? ああ、そうでした、feature/unify_styles の変更を development に反映したいのでした。ではやってしまいましょう。 385 | 386 | ``` 387 | $ git checkout development 388 | $ git merge feature/unify_styles 389 | Auto-merging cat_lover_said.txt 390 | CONFLICT (content): Merge conflict in cat_lover_said.txt 391 | Automatic merge failed; fix conflicts and then commit the result. 392 | ``` 393 | 394 | Oops!コンフリクトです。そういえば、hotfix でも unify_styles でも、一番最後の「頭おかしい」の行を修正しているのでした。コンフリクトを解決しましょう。コンフリクトしたファイルを手動で修正して、`git add`、 `git commit` でしたね。 395 | 396 | 今回はコミットメッセージに「なぜコンフリクトが起こったのか、どうコンフリクトを解決したのか」も書いておきましょう。「コンフリクトの修正<改行><改行>文体を修正するための修正と、"頭おかしい" の修正で同じ行を修正していたので、どちらの修正も生かすような対応を行った」くらいですかね。コミットの内容を詳しく書きたいときには、こんな感じでコミットメッセージの一行目にコミットの概要を書き、ふたつ改行を行ったあとに詳細を書くと、いろんなツールでコミットログを見たときにいい感じに表示してくれるので、こういう書き方をするといいでしょう。 397 | 398 | はい、これで無事にマージが行われました。ではこれを共有リポジトリにpushしましょう。 399 | 400 | $ git push 401 | 402 | はい、無事に push できました。おつかれさまでした! 403 | 404 | あとはレビューしてもらって、OK ならば master に反映して「新規リリースバージョン」をリリースすればいいですね! 405 | 406 | ## git push 落ち穂ひろい 407 | 408 | さて、今回は何事もなくスムースにことが運びましたが、`git push` が成功するためには、条件があります。 409 | 410 | * リモートリポジトリが、bare リポジトリである 411 | * 覚えてますか? bare リポジトリ。作業ディレクトリを伴わないリポジトリでしたね。自分が作業してるところにどっかから push されてきたら混乱しちゃいますよね。そのため、作業ディレクトリを持たない bare リポジトリへじゃないと、push は受け入れてもらえません。 412 | * リモートリポジトリへの書き込み権限を持っている 413 | * 今回は同じファイルシステム上の書き込み権のあるリポジトリだったから push 可能だったけれど、たとえば Github の他人のリポジトリだとか、そういう「書き込み権」のないリポジトリに対して push しても書き込みはできません。まあ、当然ですね。 414 | * 手元のリモートブランチがリモートリポジトリに「追いついて」いる 415 | * 自分の手元にあるコミットよりもリモートのコミットのほうが「先に」進んでいたら、そのコミットは「あれ。親コミットが違う……」これどうすればいいんだろう……となってしまいます。このような場合には、適宜 `git fetch` からの merge や `git pull` を行って(その際の merge ではコンフリクトが発生する可能性があります)、手元のリモートブランチをリモートリポジトリに追いつかせてから push してください。 416 | * すでにリモートリポジトリに push 済みのコミットが、手元のリポジトリで改変されていない 417 | * push 済みのコミットが `git rebase` や `git commit --amend` で改変されてしまうと、リモートリポジトリと手元のリポジトリの間で不整合が起こってしまいます。 418 | 419 | さて、では今回のまとめです。 420 | 421 | * リモートリポジトリに手元の変更を反映したいなら、`git push` 422 | * 追跡ブランチに対しての変更はそのまま `git push` 423 | * 新しいブランチを作りたいなら `git push <リモートリポジトリの名前> <手元のブランチ>:<リモートのブランチの名前>` 424 | * ブランチを削除したいなら `git push <リモートリポジトリの名前> :<リモートのブランチの名前>` 425 | * リモートリポジトリから手元に変更を持ってきたいなら `git fetch` 426 | * リモートリポジトリのコミットとブランチを持ってくる 427 | * リモートリポジトリのブランチはリモートブランチとして作られる 428 | * fetch のついでに merge も一緒にやりたいなら、`git pull` 429 | 430 | これで、ひととおりこのドキュメントはおしましです。たいへんおつかれさまでした。ここまで丁寧に読んでくれたあなたが、今日から快適なヴァージョン管理ライフを過ごせることを祈っています。 431 | 432 | ## 最後に 433 | 434 | さて、このドキュメント自体も git リポジトリで管理されています。が、このリポジトリにはなんと master ブランチしか存在しません。ひどいですね。ただ、すこし言い訳をしておくと、あくまで Git は道具です。わたしは今回このドキュメントを書くにあたり、「ブランチは一本でいいや、なにか大きな改修を行うときになったらブランチを切ろう」というポリシーで書くことに決めました。今回、このドキュメントの中では、けっこうきちんとしたブランチ運用を見てみましたが、もちろん、全てのプロジェクトでこのような運用をする必要はありません。あるいは、もっときちんとした運用をするべきプロジェクトもあるでしょう。 435 | 436 | 大切なのは、ベストプラクティスを知っていて、必要な場所で必要なときにいつでも使えるようになることです。あるひとつのやり方に固執する必要はありません。そのときに一番良いやりかたを選択していきましょう(もちろん、ベストプラクティスは「ベスト」だからベストプラクティスと呼ばれるわけで、基本的にはベストプラクティスに従うのが良いでしょう)。 437 | 438 | そのために、いろいろなブランチの運用方法を知っておくことは大切なことです。本書は、そのためのポインターをふたつだけ最後に書いて、おしまいとしましょう。 439 | 440 | * [見えないチカラ: A successful Git branching model を翻訳しました](http://keijinsonyaban.blogspot.jp/2010/10/successful-git-branching-model.html) 441 | * [GitHub Flow (Japanese translation)](https://gist.github.com/Gab-km/3705015) 442 | 443 | ## もうちょっとだけ続くんじゃ 444 | 445 | あ、そうそう、これで本編はおしまいですが、この文章で出てきたコマンドを逆引きできる逆引きコマンド集を付録として付けます。もしよかったら、慣れるまではそちらを手元に置いて作業をするといいかもしれないですね。 446 | 447 | では、今度こそ。おつかれさまでした! -------------------------------------------------------------------------------- /11_appendix.md: -------------------------------------------------------------------------------- 1 | # 付録 ー 逆引き Git コマンド 2 | 3 | ## リポジトリの作成 4 | 5 | ### 現在のディレクトリを作業ディレクトリとしてリポジトリをはじめから作成したい 6 | 7 | $ git init 8 | 9 | ### 既存のリポジトリを複製したい 10 | 11 | $ git clone <複製元> <複製先> 12 | 13 | * `--bare` オプションを付けると、作業ディレクトリは複製されず、リポジトリだけが複製される。 14 | * clone してきた場合、 15 | * 複製もとのリポジトリが自動的に origin という名前でリモートリポジトリに登録される 16 | * 複製もとのブランチはすべて「リモートブランチ」として複製される 17 | * origin/master 追跡する master というブランチが作成される 18 | * master の内容が作業ディレクトリにチェックアウトされ、復元される。 19 | 20 | ## 作業ディレクトリの内容をコミット 21 | ### 作業ディレクトリの変更内容をstage, unstageしたい 22 | 23 | $ git status 24 | 25 | するとたいてい「こういうときはどうしてね」と書いてあるのでそれに従うと良い。 26 | 27 | 28 | ### コミットしたい 29 | 30 | $ git commit 31 | 32 | * `-m <コミットメッセージ>` を付けて実行するとエディタを立ち上げずにコミットメッセージを入力できる 33 | 34 | ## 歴史を改変 35 | 36 | ### 直前のコミットをやり直したい 37 | 38 | $ git commit --amend 39 | 40 | ### あるブランチで行われた変更を別のところからやり直したことにしたい 41 | 42 | $ git rebase <ここからやったよということにしたいコミット> 43 | 44 | 45 | ## リモートリポジトリ 46 | 47 | ### リモートリポジトリの一覧を表示したい 48 | 49 | $ git remote 50 | 51 | ### リモートリポジトリを追加したい 52 | 53 | $ git remote add <そのリモートリポジトリにつける名前> <リモートリポジトリの場所> 54 | 55 | ### リモートリポジトリのコミット内容とブランチを手元のリポジトリに取り込みたい 56 | 57 | $ git fetch <リモートリポジトリの名前> 58 | 59 | * リモートリポジトリのブランチは「リモートブランチ」として手元に取り込まれる 60 | 61 | ## リモートブランチと追跡ブランチ 62 | 63 | ### あるリモートブランチを追跡する新しいブランチを作りたい 64 | 65 | $ git branch <新しいブランチ> <リモートブランチ> 66 | 67 | ついでに新しくできたブランチを checkout したいならば、 68 | 69 | $ git checkout -b <新しいブランチ> <リモートブランチ> 70 | 71 | 72 | ### 手元のブランチの変更をリモートブランチを通じてリモートリポジトリに反映したい 73 | 74 | $ git push 75 | 76 | * push.default の値が 'simple' ならば、今選択しているブランチのみ push される 77 | * push.default の値が 'matching' ならば、追跡しているブランチすべてが push される 78 | * 手元のリモートブランチが「リモートリポジトリ」に追いついていないと push できない 79 | * リモートリポジトリに対する書き込み権限をあなたがもっていないと push できない 80 | 81 | ### リモートリポジトリの変更を手元に取り込みたい 82 | 83 | $ git fetch 84 | $ git checkout <取り込みたいブランチ> 85 | $ git merge <リモートブランチ> (あるいはリベースのほうが都合がよければ git rebase <リモートブランチ>でもよい) 86 | 87 | あるいは 88 | 89 | $ git pull 90 | 91 | とすると、追跡ブランチにリモートブランチの内容を merge するところまで一気にやってくれる -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Git をはじめからていねいに 2 | 3 | by shinpei maruyama 4 | 5 | ## はじめに 6 | 7 | 本文書は Git の基本的な概念と使い方を、なるべくわかりやすく説明する意図で書かれています。本書を読む事で 8 | 9 | * かんたんな Git の使い方ができる 10 | * ブランチを使える 11 | * 複数人での協調作業ができる 12 | * わからないことがあったときに google で「どんな単語で調べればいいのか」 がわかる 13 | 14 | ようになるのが目的です。 15 | 16 | 対象読者は、「Git を使ってみたいと思ってるけどなんか怖い」「業務で Git 使ってるけどよく詰む」「なんかいろいろ英語でてくるけどよくわかんないから読んでない」「なんとなく使ってるけどよくわかってない」というひとが対象読者です。逆に、「べつに Git で困ってない」「git flow おいしいです」「普通に毎日使ってる」「もうGitなしには生きられない」「彼氏が VCS 使ってなかった、別れたい」というようなひとは対象読者ではありません。 17 | 18 | なお、一部 Mac OS X 向けの記述になっていますが、基本的にはコマンドラインで Git が使える環境ならば問題なく読み進めることができるようになっています。 19 | 20 | ## 使い方 21 | 以下のコマンドを実施してください。 22 | ダウンロードしたディレクトリには各章に対応したgitレポジトリが用意されています。 23 | 苦手な章を何度も練習する場合などにお使いください 24 | 25 | ``` 26 | $ git clone --recursive https://github.com/takanabe/introduction-to-git.git 27 | $ cd introduction-to-git 28 | $ git submodule foreach git checkout master 29 | ``` 30 | ## 目次 31 | 32 | 1. [gitとはなんぞや](01_what_is_git.md) 33 | 1. [ひとりでつかう - はじめてのコミット](02_first_commit.md) 34 | 1. [ひとりでつかう - にどめのコミット](03_second_commit.md) 35 | 1. [ひとりでつかう - どんどんコミット](04_more_commits.md) 36 | 1. [ひとりでつかう - ブランチを知る](05_branch.md) 37 | 1. [ひとりでつかう - はじめてのマージ](06_merge.md) 38 | 1. [ひとりでつかう - もっとマージ](07_more_merges.md) 39 | 1. [ひとりでつかう - 過去を改変](08_rebase.md) 40 | 1. [みんなでつかう - ベアリポジトリとクローン,リモートリポジトリ](09_clone.md) 41 | 1. [みんなでつかう - push pull](10_push_pull.md) 42 | 1. [付録 - 逆引きコマンド集](11_appendix.md) 43 | 44 | ## ライセンス 45 | クリエイティブ・コモンズ・ライセンス 46 | 47 | この 作品 は クリエイティブ・コモンズ 表示 - 継承 3.0 非移植 ライセンスの下に提供されています。 48 | 49 | 50 | -------------------------------------------------------------------------------- /images/09_00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takanabe/introduction-to-git/da57090825d72590118860f214c6d6c14f2e03f0/images/09_00.png --------------------------------------------------------------------------------