GitHubでPull Requestを練習した

GitHubにPull Requestしたことがなかったので、これが初GitHubです。

なんだかんだでリモートリポジトリホスティングサービス的な使い方しかしてなかったのと、「プルリクエストってなに?難しそう・・・なんでみんな当たり前のように話してるの・・・怖い」とか謎の苦手意識を持っていたので、まずは手を動かして感覚をつかもうと思った。

ただ、今月の「WEB+DB PRESS Vol.81」にGitHubとPullRequestを使った開発の記事が書いてあるのでそちらを見たほうが良いと思いますです。

前提

Windows + msysGitでやってます。

Linuxでも多分Gitクライアントがあればできるかもしれません。

GitBucketで事前練習したときはEclipse+EGitでやっていたのでそっちでもできるかもしれません。操作手順は全く違いますが。

GitHubリポジトリを作る

まずはGitHubリポジトリを作ります。


HelloWorldという適当なリポジトリを作ります。

下のチェックを入れることでリポジトリを作る時にREADME.mdを置いて最初のコミットを含めて初期化することもできますが、今回は何もないまっさらな状態で作ります。こっちのほうが多分楽です。



git@github〜で始まるURLのような情報は後で使いますので暗記しておきます。

SSH接続用の鍵を作る

GitHubと自分のPC間の処理を安全に行うために、SSH接続に使う鍵を作って、GitHubに登録します。

ssh-keygenで鍵を作ります。秘密鍵ファイル(id_rsa)と、対になる公開鍵ファイル(id_rsa.pub)が作られます。

ssh-keygen -b 2048 -t rsa -N "" -f ~/.ssh/id_rsa

# Linuxなら以下も必要かもしれない
chmod 0600 ~/.ssh
chmod 0600 ~/.ssh/id_rsa ~/.ssh/id_rsa.pub



catコマンドで公開鍵ファイルの中を表示します。

cat ~/.ssh/id_rsa.pub

この中身は後で使いますので覚えておいてください。

右上のAccount Settingから左のSSH keysを選択して開きます。

「Add SSH Key」ボタンを押して、鍵の名前(適当)と、公開鍵の情報(先ほどcatコマンドで公開鍵ファイルで表示された文字列)を入力します。

このとき、鍵ファイルは「ssh-rsa」で始まり、1行で入力する必要があります。コマンドプロンプトだと、勝手に改行される場合があるので、適当に改行を削除してください。




うまく登録できると、こんな風になります。鍵の入力を誤ると怒られます。



SSH鍵の登録は異常です。

Gitの設定

初回の設定として自分の情報をGitに教えておく必要があります。この情報はコミット時に使われる情報で、設定しないとコミットできない(はず)。

git config --global user.name "あなたの名前"
git config --global user.email "あなたのメールアドレス"



ローカル環境にGitリポジトリを作り、GitHubリポジトリに反映する

そもそもGitHubで管理するものを用意していませんでした。


まず適当にファイルを用意して、ローカルにGitリポジトリを作って、適当に作ったファイルをGitで管理します。

touch README.md
git init
git add README.md
git commit -m "first commit"

git initした段階で(master)とか表示されるようになりました。これが今作業しているブランチの名前になります。
git addで管理対象にします。git commitでローカルリポジトリにコミットします。

次はGitリポジトリ毎に1度だけのみ行う必要があります。

GitHubをリモートリポジトリとして使うように教える通過儀礼です。リモートリポジトリの名前としてoriginを与えておきます。
最後のアドレスのような何かは、最初にGitHubリポジトリを作った時のアレです。

git remote add origin (githubで表示されていたgitリポジトリのURL)

問題なく終了したら、GitHubにpushします。

git push -u origin master

pushは上の操作で言えば、ローカルで作業している現在のブランチ(master)をリモートリポジトリ(origin)のブランチ(master)に反映してくれる操作です。

また、push時に初めてGitHubと通信する事になるので「お前こいつと通信しようとしてるけど知ってるヤツ?」と聞いてきますので、yesを回答しておきます。
(本当はフィンガープリントの値が Redirecting... にあるフィンガープリントと一致する事を確認してからyesを回答すべきです。)




うまくいくと、ローカルのmasterブランチがoriginのmasterブランチに反映できたよ、とログが流れます。ブラウザで確認します。




先ほど適当に作ったファイルがGitHub上で確認できますね!

pushってなんぞ?Subversion(SVN)にはそんなもんなかったぞ!という人は、SVNリポジトリにコミットする操作を、GitではPushみたいなイメージで良いと思います。

ただ、SVNも今後のバージョンでgitのcommitに相当するcheckpointsという操作が出来るようにするみたいです。

そうなると「SVNのcheckpointsはgit commit, SVNのcommitはgit pushになります!」と砕けた説明が出来て楽ですね。(SVN使い続ける人はcheckpoints実装されてもつかわなそうだけど。)

Pull Requestを送るためにコードを書く

一番書きたかった内容はここからです。

Pull RequestはGitHubの機能の一つです。「良いプロダクトだね!そこで新たにこんな機能実装してみたんだけど、取り込んでくれないかな?」と言った感じのことができます。

作法が合っているかともかく、とても簡単に出来るので、ぜひ試してみましょう。
どうせ自分しか使ってないHelloWorldリポジトリに対してPull Requestを送るだけです。

今回は適当に作った空のReadmeファイルに何か書いてあげることにします。

作業用ブランチを作る

Gitの流儀的には、何か機能を実装するたびにブランチを切るそうです。

私は色々目移りして数十ファイル修正して1個のcommitにまとめるクセがあるのですが、それは良くないみたいです。

readmeファイルを書くんだし、write-readmeでいいかな・・・(適当)

write-readmeブランチを作って、作ったブランチをチェックアウトします。。

git branch write-readme
git checkout write-readme

この操作を1行で実行することもできますが、これは宿題にしておきましょう。


ファイルを修正していく

ブランチmasterからwrite-readmeも切り替わりました。中身を書いてあげましょう。

面倒なのでcatで書き出してます。エディタを使うと良いでしょう。

cat << __EOF__ >> README.md
Hello World
===========
__EOF__



git add .

"git add ." はカレントのファイル全てを管理対象にします。数百ファイルもあったら面倒なのでこれで一発でできちゃうわけです。その中でも無視したいものも.gitignoreファイルで定義できますが、それはまた別のお話。

(ただ、ここでgit add .を使うのは適切じゃなかったです。使うとすれば変更されたファイルのみ対象にする git add -u でした。でも新規ファイルは作ってないので結果はどちらも一緒になる。)

しかしgit addしようとしたら、改行文字をLFからCRLFに変換するよ、という警告が出ています。それは困るので、無効にしておきます。

git config --global core.autocrlf false

git add .
git commit -m "write a heading"

まずは見出し(title)を書いて一旦コミットしておきます。

うちの職場だと「どうせまた後で追記するくせにゴミみたいなコミットしてんじゃねえよカス」って言われるところですが、大丈夫。gitならうまい事どうにかできるのです。後で説明します。



気をとりなおして、次に見出しに対する詳細を書いてあげましょう。

echo "Hatu GitHub desu." >> README.md
git add .
git commit -m "add description"

あ、"git add ."するのが面倒の場合、管理している(1度git addしている)ものだけ対象にするのであれば、git commit -aと-aオプションをつけると1行で出来ます。

そんなこんなでReadmeファイルが書けました!この修正されたクッソ情けないReadmeファイルをPull Requestしましょう!

コミットを整理する

Pull Requestをしたいところですが、少し考えます。上記で2回コミットしましたが、そのままマージしてもらってしまうと、全てのコミットが履歴に残ります。

このままだと、うちの仕事場の都合で言うと「しょうも無いコミット重ねてんじゃねえよハゲ」と言われます。間違いなく言われます。

それに、これぐらいの修正であれば1回のコミットであるかのように見せたほうが、Pull Requestを貰う側も良いはずです。

なので、コミットを改ざんしましょう。rebaseを使うとチョチョいとできます。

ただこのあたりは私はよくわかっていません。Git - 歴史の書き換えを参考にしました。


まず、いつのコミットを対象にするか決める必要があります。

今回は現在から2つ前のコミット("write a heading"とメッセージをつけたコミット)が対象になるので"HEAD~2"と表現できます。git logからcommitのハッシュ番号(ID?)を引っ張ってきても良いです。

git rebase -i HEAD~2



しばらくすると、編集画面が開かれます。今回はviですが、多分、EDITOR変数で変化します。

pick 〜とか書いてありますが、さっぱり分からないです。



"add description"なコミットをpickからsquashに変えます。

squashは前のコミットと合体させてコミットのメッセージを修正できます。ここで言う前のコミットは"write a heading"になります。

この状態で保存します。



次にコミットのメッセージを修正する画面になります。

ここで決定したコミットのメッセージがPull Requestしたときのメッセージになります。

なお、先頭が"#"で始まる行は無視されて削除されます。

メッセージを修正したら保存します。



うまくいくとSuccessfullyとお祝いされます。歴史が変わった瞬間です。


git logで確認してみると、確かにcommitが2個から1個になっています。


Pull Requestを送る

何のことはない。リポジトリにPushしてPull Request申請するだけです。

本当は修正対象のリポジトリを自分のリポジトリにフォークし、自分のリポジトリに対してpushするべきですが、
今回は自分のリポジトリですので、フォークする必要はないです。
他の人にPullRequestを送る時はこの辺を思い出してください。

git push origin write-readme

現在のwrite-readmeブランチを、リモートリポジトリのwrite-readmeブランチにpushします。



ブラウザでGitHubを開き、
右の「Pull Request」をクリック



「New Pull Request」ボタンをクリック



ベースとなるブランチ(デフォルト)と、先ほどPull Requestをしたいブランチを選択します。

今回は、masterブランチからwrite-readmeブランチを作ったので、baseにmaster, compareに先ほどpushしたwrite-readmeブランチを選択します。



差分が出てきますので、Pull Requestしたい内容であることを確認し、「Compare & Pull Request」ボタンをクリック


Pull Requestのタイトルとその詳細を書き、「Create Pull request」ボタンをクリック



Pull Requestすることができました!後は相手の反応を待ちましょう!

・・・自分自身に対するPull Requestなので、自分で処理します。

「Merge Pull Request」ボタンをクリックします



マージする際のメッセージを入力し、「Confirm merge」ボタンをクリックします。

もし、Issue(問題)に対するpull requestであれば、close #(Issue番号)をメッセージに含めてあげると、メッセージに連動してcloseしてくれます。



無事masterへwrite-readmeの変更をマージできました。

マージされたwrite-readmeブランチはもはや不要なブランチです。「Delete branch」ボタンを押すとpushしたwrite-readmeブランチを削除できます。ゴミはゴミ箱へ。



お疲れ様でした!

後必要なのは?

Pull Requestを送る勇気とヤル気

おしまい

Gitの理解がそこまで深くないので、へんなこと書いてたり、色々表現が間違ってたらごめんなさい。

画像付きは結構大変だった。

それにしても1個の事を理解するのにどんだけ時間かけてるんだ、という話やな・・・