きれいなcommit, pull requestを知りたい/作りたい方のためのgit勉強会

きれいなcommit, pull requestを知りたい/作りたい方のためのgit勉強会

2018年3月27日にSupporterZ CoLabで行われたgit勉強会の資料です。

1a74617b91d2757b839b9cf3614648ce?s=128

Tomohiro Imaizumi

March 27, 2018
Tweet

Transcript

  1. きれいなcommit, pull requestを 知りたい/作りたい⽅のための git勉強会 @サポーターズCoLab ミクシィグループ 株式会社Diverse 新規サービス事業部 Poiboyグループ

    今泉智博 (2018/03/27)
  2. INDEX ⾃⼰紹介(3min) なぜ「きれい」なcommitを積むべきなのか(10min) きれいなcommitの原則(10min) きれいなcommitを作るテクニック (20min) きれいなPull Requestを作るテクニック(3min) 実際に⼿を動かして演習(10min) まとめとQ&A(4min)

  3. 自己紹介 ‣今泉智博: @imaizume ‣株式会社 in ‣ iOS版の開発を担当 ‣学⽣時代はWebフロント/Railsが主でした⏰ ‣昨年ラーメン120杯完⾷からの5kg減量達成 ‣2018年はCOMP⽣活と銭湯お遍路に挑戦中♨

  4. INDEX ⾃⼰紹介(3min) なぜ「きれい」なcommitを積むべきなのか(10min) きれいなcommitの原則(10min) きれいなcommitを作るテクニック (20min) きれいなPull Requestを作るテクニック(3min) 実際に⼿を動かして演習(10min) まとめとQ&A(4min)

  5. 突然ですが ❗

  6. 「きれい」って良いですよね

  7. git のcommit logも 「きれい」が良い✌ ということは

  8. でも なぜ「きれい」であるべき❓ (なぜ「汚い」のはダメ❓) ❓

  9. そもそもcommit logとは ❓ commit: 変更の塊 の log: 履歴 002 001

    003 + .green { + color: green; + } * 001: Committed at Jan 1st, 2018 | message: green classを追加 * 002: Committed at Feb 2nd, 2018…
  10. 変更には必ず「意図」がある ‣ Aという理由でプロパティBを追加 ‣ Cという不具合を直すためDを変更 ‣ 仕様EがFになったので不要なGを削除 commit: 変更の塊 commit

    に含まれる変更の 「意図」が⾒えるべき
  11. 履歴は後から他⼈が⾒るもの ‣ 経緯不明の実装の犯⼈理由を探る時 ‣ 昔の実装を参考にしたい時 ‣ コードレビュー/PR作成時 log: 履歴 変更の「意図」を

    正しく容易に伝えるべき
  12. commit logの存在理由 変更概要と意図を 第三者に伝えるため きれいであるべき理由 変更概要と意図を 容易にかつ正確に 第三者に伝えるため

  13. ♪ 個⼈のプロジェクトなら きれいかどうかなんて関係ない❓

  14. (試しに⾃分のcommit logを⾒返して 何をしたか思い出してみよう) 「数ヶ⽉後のあなた」も「第三者」⚡ なんで⾃分 はこんな実装したんだ… コメントは適当に “fix bugs”でいいか♪ 数ヶ⽉後

  15. INDEX ⾃⼰紹介(3min) なぜ「きれい」なcommitを積むべきなのか(10min) きれいなcommitの原則(10min) きれいなcommitを作るテクニック (20min) きれいなPull Requestを作るテクニック(3min) 実際に⼿を動かして演習(10min) まとめとQ&A(4min)

  16. ところで 「commitがきれい」とは❓ 「きれい」の価値観・判断基準は 個⼈1⼈1⼈によって違う そこで今回は imaizume 独⾃の定義を使⽤

  17. 可読性 (readability) commit message の読みやすさ 論理性 (logicality) 変更内容が 意味的に まとまっているか

    「きれいなcommit」を構成する3要素 commitの 粒度の⼩ささ 原⼦性 (atomicity)
  18. 論理性(logicality) 原⼦性(atomicity) commit (ϝοηʔδ) commitྻ Pull Request ߦࠩ෼ ộ 可読性(readability)

    それぞれレイヤーが異なる Pull Requestの 構成要素 下の層での出来は 上の層での出来に影響 ʴ (มߋ܈)
  19. ✨ 可読性 readability commit messageの読みやすさ

  20. このcommit log を⾒て 変更内容がイメージできますか❓ Project A Project B 2つのcommit logの差は何か❓

  21. > fix width and height Project A の commit message

    ‣ 何のwidth/heightだろう❓(差分を⾒て分かれば良いが…) ‣ fixとは「固定」という意味❓それとも「修正」の意味❓ ‣ 何がどうダメだったんだろう❓(PRコメントもない…) > add / Update ‣ 何をadd/Updateしたんだろう❓ ‣ どうしてそうしたのだろう❓ ‣ػೳݟͨ໨తʹ͸Կ͕มΘͬͨͷͩΖ͏❓ commit messageからは変更概要が⾒えづらい
  22. > Facebook登録時に学校情報がない時に デフォルト値を送信しない Project B の commit message ‣ おそらくAPIを叩く時のパラメータを変えたんだな

    ‣ でもなぜそんな仕様に❓                 →PRコメントに仕様と関連issueへのリンクが記載 > 実際の職業を表示するセルの テキスト色を濃くする ‣ おそらく職業表⽰画⾯のUIの変更だな ‣ 理由は❓→PRコメントにデザインへのリンク commit messageから変更概要が⾒える
  23. 具体性のある内容を 相⼿が理解できる⾔葉で書く 読みやすいcommit messageを書くには

  24. ⚖ 原⼦性 atomicity commitの粒度の⼩ささ

  25. ある⽇あなたは終業10分前に PRのコードレビューを依頼されました 「よし、変更は1commitだけか すぐやっちゃえば定時で帰れそうだ✌」

  26. ☠ > File changed 1625 + 10671 - 9642 そして差分を⾒たあなた…

  27. 「うわあああああ」 YOU

  28. 「⽬が、⽬がーーー!!!」 YOU

  29. ☺ もし1commitの差分が これくらいだったら❓

  30. 1つのcommit粒度を できるだけ⼩さくする ⼩さな変更は⼀⾔で表現しやすい = 具体的なcommit messageも書きやすくなる 注⽬箇所を集中、変更把握を容易にするには

  31. ⚙ 論理性 logicality 変更内容が意味的にまとまっているか

  32. (あるWebフロントエンドプロジェクトにて) 「以前変更したヘッダーの メニューアイテムの並び順を 変更前の順序に戻したいなぁ」 そこでgit revert しようと commit logを調べてみると…

  33. imaizume@mac ~/works/project (master) $ git log —oneline —graph -1 *

    001 - (HEAD -> master) Update order and theme of header nav アイテムの順序変更と テーマ更新が 同じcommitに含まれている commitをrevertすると アイテムの順序だけなく テーマまで戻ってしまう ではどうすればよかったか❓
  34. 原⼦性を上げてみる imaizume@mac ~/works/project (master) $ git log —oneline —graph -4

    * 004 - (HEAD -> master) Reorder header nav item in HTML * 003 - Add class switch with jQuery for header navigation to JavaScript * 002 - Add class for header navigation to CSS * 001 - Add section for header navigation to HTML 各ファイルでの変更を それぞれ別のcommitに 当初の⽬的は達成されたようだが… テーマを戻したくなったら 3 commit分のrevertが必要 「不適切に」原⼦性が⾼い
  35. ✨ 意味的にまとまる範囲で原⼦性を向上 imaizume@mac ~/works/project (master) $ git log —oneline —graph

    -4 * 004 - (HEAD -> master) Reorder header nav item in HTML * 003 - Update header navigation themes * 002 - Enable SP header button appending new selector to HTML and JS * 001 - Use background-image on div instead of img element 意味的にまとまる範囲で commitへまとめた ⼩さなcommitを意識しつつ、 意味的にまとまっていると 戻す時もまとめて戻せる 「ファイルの粒度」ではなく 「意味の粒度」にまとめる
  36. commitの粒度は 意味的にまとまる範囲で⼩さくする 「これを戻したらあれも戻ってしまう」 「これを戻すにはあれも戻さないと」 は悪いcommitの可能性あり

  37. ‣可読性: 変更概要を簡単に把握できるようにする ‣原⼦性: 変更の粒度を不必要に上げない ‣論理性: 変更は意味的にまとめてcommitにする ⼩まとめ: 「きれい」の定義と⽬的 ⽬的: 変更の内容と意図を

    他⼈=未来の⾃分に伝えるため
  38. INDEX ⾃⼰紹介(3min) なぜ「きれい」なcommitを積むべきなのか(10min) きれいなcommitの原則(10min) きれいなcommitを作るテクニック (20min) きれいなPull Requestを作るテクニック(3min) 実際に⼿を動かして演習(10min) まとめとQ&A(4min)

  39. 可読性 (readability) commit message の読みやすさ 論理性 (logicality) 変更内容が 意味的に まとまっているか

    再掲:「きれいなcommit」の構成要素 commitの 粒度の⼩ささ 原⼦性 (atomicity)
  40. 可読性 readability 変更概要を伝えやすい commit messageの書き⽅

  41. commit =パッケージ化された変更 ➕ commit message = パッケージについたラベル パッケージの中⾝が ひと⽬で把握でき 想像できるメッセージに

  42. どうすればひと⽬で変更を把握しやすいか❓ 1. 具体性 再びimaizumeの独⾃定義 2. ⼈間的意味

  43. 具体性がないメッセージ例 ‣ Fix bugs ‣ Add new class ‣ 直した

    ⭕具体性があるメッセージ例 ‣ ヘッダーナビゲーションのボタンタップが正しく反 応するようjQueryのセレクタ名を修正 ‣ WebViewへのリンクを可変にするため HogeViewControllerのコンストラクタにURLパラメー タを追加 5W1Hで指⽰語や曖昧な⾔葉を使わない
  44. ⼈間的意味のないメッセージ例 ‣ addParamsメソッドの引数を0からに1変更 ‣ OLD_CONST1, OLD_CONST2を削除 ‣ MemberModelにsuccessフィールドを追加 ⭕⼈間的意味のあるメッセージ例 ‣

    addParamsに間違った引数(0)が渡されていたので正 しい状態値(1)を渡すように修正 ‣ ver2.0で廃止した登録関連の古い定数を削除 ‣ API取得が正常に完了したかを保持できるよう MemberModelに新規のフィールドを追加 変更の詳細は差分を⾒れば分かるので ⼈間的な意味を書くようにする
  45. + let tmp = Foo.bar(baz: Qux.quux) + let httpReq =

    + APIManger.getRequest(of: Endpoint.member) →コメントで補⾜が必要 差分を⾒れば⼗分意図が伝わる 過度にmessageの具体性を上げる必要なし 補⾜1 ⼩さい差分で叙述的なコードなら コードがcommit message として機能する場合も (参考: リーダブルコード)
  46. 補⾜2 チーム内での共通認識があれば コンテキストは省略可能 例:「アプリの設計はMVP」という⽅針 ⭕ XXXViewControllerの状態変数をPresenterに移設 例: メンバ変数呼出しではselfやthisを明⽰的に付ける ⭕ YYYPresenter内のメンバ変数をself付きで呼び出し

    例: プロジェクト固有の概念や⾔葉がある ⭕ SuperMatchのspecial parameterを2倍にする
  47. その他気をつけると良い点 ‣ 詳細な伝達事項がある場合 (ほとんどない) ‣ imaizumeは、基本的に1 line messageで派 GitHubやRedmineなどのIssue番号を⼊れる ‣

    GitHub上でissueからもコミットが参照できる ‣ 「詳細はISSUEを⾒て」というメッセージに ‣ closeなどのキーワードでISSUEを操作可能 ✍必要なら複数⾏書く
  48. ✨ 原⼦性 atomicity 適切な変更量のcommitを作る⽅法

  49. 前述の例のようにならないよう 1commitの変更量を⼩さくする

  50. みなさんはgit addする時 どんなコマンドを叩いていますか imaizume@mac ~/works/pretty-git (master) $ git status On

    branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: index.html modified: script.js modified: style.css no changes added to commit (use "git add" and/or "git commit -a") imaizume@mac ~/works/pretty-git (master) $ git add index.html git addの最小単位はファイルだと思っていませんか??
  51. 原⼦性の⾼いcommitを 作るテクニック git add -p (—patch)

  52. git addの最⼩単位は1⾏ ファイル内の変更を⾏単位でstagingへ static var f… +func xyz() {… …

    -class Abc() {… - } +class Xyz() {… +} … -static let PQ =… git add -p git add 001 002 003 全差分をstagingへ 差分を区間(hunk)毎に stagingへ 001
  53. imaizume@mac ~/dots (master) $ git add -p diff --git a/notfy/Cell/NotificationsTableViewCell.swift

    b/notfy/Cell/ NotificationsTableViewCell.swift index 813e59f..b50e7ef 100644 --- a/notfy/Cell/NotificationsTableViewCell.swift +++ b/notfy/Cell/NotificationsTableViewCell.swift @@ -49,6 +49,7 @@ struct Notification { var memo: String } +protocol TriggerContract { + func toString() -> String +} extension Notification: TriggerContract { Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? git add -p 後の画⾯ 各hunkでの操作を聞かれるれるので それぞれで必要なコマンドを実⾏ ( ? でヘルプを表⽰)
  54. add -p の各コマンド説明 (y/n) +hunk1 … +hunk2 … -hunk3 y:

    hunkをstageする y n: hunkをstageしない +hunk1 … +hunk2 … -hunk3 n ‣hunk1のstage確定 ‣h2へ移動 ‣hunk1の⾮stage確定 ‣h2へ移動 commit対象 に含む commit対象 に含まない
  55. add -p の各コマンド説明 (q/a) +hunk1 … +hunk2 … -hunk3 q:

    以降のhunkへの 操作をキャンセル q a: 以降の全hunkを ステージングにadd +hunk1 … +hunk2 … -hunk3 a ‣hunk1以降の全hunk の⾮stageが確定 ‣コマンド終了 ‣hunk1以降の全hunk のstageが確定 ‣コマンド終了
  56. add -p の各コマンド説明 (j/J/k/K) +hunk1 … +hunk2 … -hunk3 k:

    現在のhunkをSKIP 前の未確定hunkへ K: 現在のhunkをSKIP 前の⾮stage hunkへ +hunk1 … +hunk2 … -hunk3 ‣hunk3は保留 ‣hunk2はSKIP ‣hunk1に移動 ‣hunk3は保留 ‣hunk2に移動 (再度stageを選択可) hunk2は 非stage確定済 hunk2は 非stage確定済 k K
  57. s: 現在のhunkをさらに⼩さく分割 (できる場合) <body> <div id="main" class="main"> <h1>きれいなcommit logを積む</h1> +

    <h2>可読性</h2> <div class="circle"></div> + <h2>原子性</h2> </div> + <h2>論理性</h2> <script src="./jquery-3.3.1.min.js"/> <script src="./script.js"> </body> Stage this hunk [y,n,q,a,d,/,s,e,?]? s Split into 3 hunks. @@ -8,4 +8,5 @@ <body> <div id="main" class="main"> <h1>きれいなcommit logを積む</h1> + <h2>可読性</h2> <div class="circle"></div> Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? 自動判定されたhunkは1個 3個の小hunkへ add -p の各コマンド説明 (s) ※hunkと⾃動判定されるには ⼀定の⾏数以上の空き(未変更⾏)が必要
  58. e: ⼿動でhunkを編集する <body> <div id="main" class="main"> <h1>きれいなcommit logを積む</h1> + <h2>可読性</h2>

    + <h2>原子性</h2> + <h2>論理性</h2> <div class="circle"></div> </div> <script src="./jquery-3.3.1.min.js"/> Stage this hunk [y,n,q,a,d,/,e,?]? e 連続した行に 差分がある add -p の各コマンド説明 (e) 1 # Manual hunk edit mode -- see bottom for a quick guide. 2 @@ -8,6 +8,9 @@ 3 <body> 4 <div id="main" class="main"> 5 <h1>きれいなcommit logを積む</h1> 6 + <h2>可読性</h2> 7 <div class="circle"></div> 8 </div> 9 <script src="./jquery-3.3.1.min.js"/> 10 # --- 不要な追加差分は削除 不要な削除差分は行頭を空白に viが起動
  59. 素のgitでhunkを操作するのは 正直⾯倒くさい… (でもGUIツールではできない…)

  60. tig で簡単にgit add -p addとcommitが j/k/u/1/Enter のみで完結

  61. ✨ 論理性 logicality 意味がまとまった commitを作る⽅法

  62. ✨ 意味的にまとまった変更をcommitにしよう imaizume@mac ~/works/project (master) $ git log —oneline —graph

    -4 * 004 - (HEAD -> master) Reorder header nav item in HTML * 003 - Update header navigation themes * 002 - Enable SP header button appending new selector to HTML and JS * 001 - Use background-image on div instead of img element ❌複数の意味を持つ変更を1commitに 1⾏/ファイル毎に変更を1commitに ⭕ 意味の最⼩粒度で1commitに 頑張りましょう
  63. ‣とりあえずcommitしておきたい… ‣試⾏錯誤でTRY&DELETEを繰り返した… ‣commit messageを後で書き換えたい… というわけにはいかない commit logを再編集できれば… HTML <> CSS

    .{} JS $() 001 HTML <> CSS .{} JS $() 001 002 003
  64. 論理性の⾼いcommitを 作るテクニック git rebase -i (—interactive)

  65. rebase -i で commit log を再編集 =結合/分割/書き換え/順序⼊れ替えが可能 001 002 003

    004 001* 002* 005 > Fix bugs > Remove methods 001* 002A 002B 005* 書き換え 結合 分割 順序⼊れ替え
  66. 補⾜: rebase コマンドとは❓ →分岐元からの差分をfast-fowardでマージ master 002 dev 004 003 001

    これを「対話的」に⾏うのが -i オプション 002 dev 004 003 001 master > git rebase master
  67. imaizume@mac ~/dots (master) $ git rebase -i HEAD~2 pick e263636

    vimにJqコマンドを追加 pick 2b9c492 write !pbcopyとsortコマンドのキーマップを追加 # Rebase 59d63fc..2b9c492 onto 59d63fc (2 commands) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # d, drop = remove commit # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out git rebase -i での画面説明 どのcommitまで遡るか vimが起動するので ⾏頭の単語と順序を編集後 保存して閉じる 各サブコマンド
  68. rebase -i の各コマンド説明 (pick/reword/drop/順序入れ替え) pick: 何もしない (commitを残す) reword: commit messageを書き換え

    001 001 001* > Fix bugs > Remove methods drop: commitを削除 001 (commitの順序⼊れ替え) 001 002 001* 002*
  69. rebase -i の各コマンド説明 (squash/edit) squash: 直前のcommitと結合 edit: HEADを移動した状態で rebaseを⼀時停⽌ 001

    002 003 001 002 003 HEAD 001 002 003 HEAD master master (detached HEAD状態)
  70. editコマンドでのcommitの分割方法 001 002 003 HEAD 001 002 003 HEAD master

    master 分割したい 001 002 003 HEAD master 002の差分が 未commit状態に 001 002B 003* HEAD master 002A rebase -i 001 && (edit 002) reset HEAD~1 add -p && rebase —continue addとcommitを やり直し可能!
  71. 補⾜ 変更されたcommitはhashが変わる⚠ =リモートリポジトリにPush済みのcommitを rebase -i した場合Conflictが起きます 001 002 003 master

    origin/master rebase 前 001 002 003 001 002 003 master origin/master rebase 後 001 002* 003* (⾃⼰責任でforce push OR 別ブランチでPUSH)
  72. 補足: git alias (ショートカット) rbi3みたいなaliasを設定しておくと便利

  73. まとめ: imaizumeオススメのcommit作成⼿順 ProfileVC.swift 極⼒その場でadd -p&commit messageは最低限の質で Old Service Update VC/Service

    Update Add new property New Service Update Update TestClass プロフィール画面を作成 〜ができるようYYYServiceを〜に変更 〜ができるようYYYVCを〜に変更 OldServiceの一部をNewServiceに分離 ZZZAPIを管理するNewServiceを作成 〜ができるようXXXClassの〜を変更 あとでまとめてrebase -i 整理整頓後リモートPUSH ProfileVC.storyboard
  74. INDEX ⾃⼰紹介(3min) なぜ「きれい」なcommitを積むべきなのか(10min) きれいなcommitの原則(10min) きれいなcommitを作るテクニック (20min) きれいなPull Requestを作るテクニック(3min) 実際に⼿を動かして演習(10min) まとめとQ&A(4min)

  75. きれいな Pull Request を作るには❓ 各commitだけではなく Pull Request全体も俯瞰する ‣ commit log

    を読み返してやったことを思い出せるか ‣ 順序やcommit粒度は適切か ‣ トータルのcommit数や差分が⼤きすぎないか ‣ Pull Requestのコメントは適切か
  76. 良いcommitやPRの先にあるもの commitྻ Pull Request ߦࠩ෼ ộ commit (มߋ܈+ίϝϯτ) ίʔυ Issue

    খλεΫ େλεΫ ϓϩδΣΫτ Ϗδϣϯ αʔϏε 良いコードが書ける 良いcommitが積める 良いPRが作れる 良いISSUEが⽴てられる 良いタスクの分割ができる 良い仕事ができる‼
  77. INDEX ⾃⼰紹介(3min) なぜ「きれい」なcommitを積むべきなのか(10min) きれいなcommitの原則(10min) きれいなcommitを作るテクニック (20min) きれいなPull Requestを作るテクニック(3min) 実際に⼿を動かして演習(10min) まとめとQ&A(4min)

  78. (時間があれば) 演習コーナー

  79. INDEX ⾃⼰紹介(3min) なぜ「きれい」なcommitを積むべきなのか(10min) きれいなcommitの原則(10min) きれいなcommitを作るテクニック (20min) きれいなPull Requestを作るテクニック(3min) 実際に⼿を動かして演習(10min) まとめとQ&A(4min)

  80. git commitは「習慣」です ⼼ が変われば 態度が変わる。 態度 が変われば ⾏動 が変わる。 ⾏動

    が変われば 習慣 が変わる。 習慣 が変われば ⼈格 が変わる。 ⼈格 が変われば 運命 が変わる。 運命 が変われば ⼈⽣ が変わる。 (ヒンズー教の教えより) 良いcommitを習慣にしましょう (悪い習慣は変えましょう)
  81. ‣可読性: 変更概要を簡単に把握できるようにする ‣原⼦性: 変更の粒度を不必要に上げない ‣論理性: 変更は意味的にまとめてcommitにする まとめ きれいにする⽬的: 他⼈=未来の⾃分に 変更の内容と意図を正しく容易に伝えるため

    imaizumeオススメのcommit作成⼿順 極⼒その場でadd -p&commit、messageは最低限の質で あとでまとめてrebase -i して整理整頓
  82. Q&Aコーナー(とありそうな質問) Q. 今⽇のやり⽅を常⽇頃から守らないとですよね❓ A. これはimaizume⼀個⼈の考え⽅・やり⽅、⽬的を⾒失なわぬように。 ⾒返す必要のないcommitを無駄にきれいにする必要はありません。 Q. 正直commit messageを考える余裕がありません… A.

    ローンチ時やリリース優先時等はやむを得ないでしょう。しかしメッ セージを考える余裕もない状態が⽇常的に続くなら転職をお薦めします。 Q. commit messageは英語にすべきですか❓ A. 基本的には⽇本語の⽅が正確に意図の伝達ができ把握もしやすいので、 ⽀障がなければ⽇本語を推奨します。commit messageを読むの誰で、何 のために書くのかを考えて選びましょう。
  83. 参考記事/リンク ‣ 横着で神経質な私とあなたに贈るgit add -p:
 https://qiita.com/crifff/items/1abf08bca4ce51db4775 ‣ gitのコミットの歴史を改変する(git rebase) 1

    / 2 · けんごのお屋敷:
 http://tkengo.github.io/blog/2013/05/16/git-rebase-reference/ ‣ detached HEADを理解して脱Git初⼼者を⽬指す⽅のためのGit⼊⾨勉強会:
 https://supporterzcolab.com/event/264/ ‣ Git - リベース:
 https://git-scm.com/book/ja/v1/Git-のブランチ機能-リベース ‣ jonas/tig: https://github.com/jonas/tig ‣ peco と alias -g で git に便利⾰命おきた:
 https://qiita.com/Kuniwak/items/b711d6c3e402dfd9356b ‣ Pro Git: https://git-scm.com/book/ja/v2
  84. None