Pro Yearly is on sale from $80 to $50! »

git branchを自由に操れるようになろう / Let's Play with Git branch!

git branchを自由に操れるようになろう / Let's Play with Git branch!

2020/01/07にSupporterZ CoLabでのオンライン勉強会「git branchを自由に操れるようになろう」での発表資料です。

https://supporterzcolab.com/event/1033/

演習用リポジトリ

* branch -f 用 : https://github.com/imaizume/2020-01-07_SupporterZ_branch-f
* rebase -i 用 : https://github.com/imaizume/2020-01-07_SupporterZ_rebase-i
* rebase --onto 用: https://github.com/imaizume/2020-01-07_SupporterZ_rebase--onto

参考リンク

* Sublime Merge - Git Client, done Sublime : https://www.sublimemerge.com/
* Git - git-branch Documentation : https://git-scm.com/docs/git-branch
* Git - git-rebase Documentation : https://git-scm.com/docs/git-rebase
* (再演) detached HEADを理解して脱Git初心者を目指す方のためのGit入門勉強会 @サポーターズCoLab - Speaker Deck : http://bit.ly/2DpZwga
* (再演)きれいなcommit, pull requestを知りたい/作りたい方のためのgit勉強会 - Speaker Deck : http://bit.ly/2SD90uT
* Githubで間違えてgit push -f origin masterしてしまった時の対応 - Qiita : https://qiita.com/awakia/items/52b5900e801c3bfbab04

宣伝リンク

* テキスト版:Gitの困り事何でも解決いたします 勉強会講師の経験有り ❗使い方から運用まで何でもどうぞ ❗ | ココナラ : https://coconala.com/services/642499
* ビデオ版:Gitの困り事解決いたします 勉強会講師の経験有り 使い方から運用まで何でもどうぞ! | ココナラ : https://coconala.com/services/839341
* 勉強会講師も担当 ❗ 親切丁寧にGitの使い方教えます 💻 | タイムチケット : https://www.timeticket.jp/items/58703
* Git・GitHubに関する相談・レクチャー - ストアカ : https://www.street-academy.com/myclass/73592

1a74617b91d2757b839b9cf3614648ce?s=128

Tomohiro Imaizumi

January 07, 2020
Tweet

Transcript

  1. git branchを ⾃由に操れるようになろう SupporterZ CoLab @YouTube Live 1

  2. 2 Tomohiro Imaizumi @imaizume Retty株式会社 / 株式会社UZUMAKI Androidユーザー歴8年のiOSプログラマ SupporterZ ヘビー(?)ユーザー

    ⾃⼰紹介
  3. 3 coconala / Time Ticket / ストアカで Git / GitHubに関する相談・レクチャーを受付中❗

    本⽇の内容以外についても 聞きたいことや悩みがあればお気軽にどうぞ 宣伝
  4. 4 TOPIC • (復習) git branchについて • (前半) branchを⾃由に操えるようになろう •

    branchを付け替えてみよう • 付け替え前のcommit IDを忘れたら • remoteとの乖離が発⽣したら • (復習) git rebase -iについて • (後半) rebase -iでcommitとPull Requestを整理 • ⼤きなPull Requestを分割するために • git branchの分岐元を変える • Pull Requestを⼩さくできない時は?
  5. 5 補⾜: commit logを⾒やすくするために 今回commit logがたくさん出てきます。 ブランチの状態を⾒やすくするために... • ターミナル上で "git

    log --graph --all --oneline" • Sublime MergeのようなGUIツールを使う Sublime Mergeの画⾯
  6. 6 (復習) git branchについて

  7. 7 git branchとは • 複数の変更履歴を切り替えるための⽬印 • 並列・⾮同期での開発に役⽴つ > git branch

    feature // feature ブランチを作成 > git checkout feature // feature ブランチに切り替え > git branch -d old // old ブランチを削除 ブランチの作成・切り替え・削除
  8. 001 002 master 003 dev 004 005 branch is コレ

    よくあるブランチの説明 ※「detached HEADを理解して脱Git初⼼者を⽬指す⽅のためのGit⼊⾨勉強会」より (古い) (新しい)
  9. 002 master 001 ※「detached HEADを理解して脱Git初⼼者を⽬指す⽅のためのGit⼊⾨勉強会」より git branchとは?? > The command’s

    second form creates a new branch head named <branchname> which points to the current HEAD branch = commitへのポインタ Gitの公式マニュアルでも "points to" と表現
  10. ⭐ さらにざっくり言えば 「branch = commitの別名」 (⾠全く同じではない) よくある勘違いの原因 「branch ≠ コミット群」


    左の例では • master は004を指すポインタ • devは 005を指すポインタ 001 002 master 003 dev 004 005 ※「detached HEADを理解して脱Git初⼼者を⽬指す⽅のためのGit⼊⾨勉強会」より
  11. ⭐ HEAD=「自分が今見ている commit/branchを指すポインタ」 ⭐ gitでは特殊な存在 左の例では • HEADはmasterを指す • masterはcommit

    004を指す • devはcommit 005を指す 001 002 master 003 dev 004 005 (HEADのN commit前を ”HEAD~N” のように表現) HEAD HEADとは?? ※「detached HEADを理解して脱Git初⼼者を⽬指す⽅のためのGit⼊⾨勉強会」より
  12. 12 (前半) branchを⾃由に操えるようになろう

  13. 13 branchを付け替えてみよう ➡ branchは付け替え可能 feature A B feature A B

    • branch = commitへのポインタ • ポインタは付け替えが可能 BEFORE AFTER
  14. 14 git branch -f : 強制的なブランチ移動 > git checkout master

    (HEADをmasterへ切り替え) > git branch -f feature (masterと同じcommitにfeatureを移動) ブランチの強制的な付け替え master A B feature master A B feature Bを指すブランチが無い
  15. 15 ⼀時ブランチを使った付け替え > git checkout feature (featureへ移動) > git branch

    tmp (一時的なブランチtmpを作成) > git checkout master (masterへ移動) > git branch -f feature (featureをmasterへ移動) > git checkout tmp (tmpへ移動) > git branch -f master (masterをtmpへ移動) > git checkout master (masterへ移動) ⼀時ブランチを使った付け替え master A B feature master A B feature tmp master A B feature tmp
  16. 16 commit IDを覚えて付け替え master A B feature ポイント先=B master A

    B feature HEAD HEAD featureを付け替え後Bをcheckout master A B feature HEAD > git checkout master (masterへ移動) > git branch -f feature (featureをmasterへ移動) > git checkout B (Bへ移動) > git branch -f master (masterをBへ移動) > git checkout master (Bへ移動) commit IDを覚えて付け替え
  17. > git reflog HEADの移動履歴をreflogで確認 17 git reflog : HEADの移動履歴を参照する 付け替え前のcommit

    IDを忘れたらgit reflogで探す master A B feature HEAD ここでgit reflog
  18. 18 git reflog : HEADの移動履歴を参照する > git reflog A (HEAD

    -> master, feature) HEAD@{0}: checkout: moving from feature to master B HEAD@{1}: commit: commit on feature ... HEADの移動履歴をreflogで確認 付け替え前のcommit IDを忘れたらgit reflogで探す master A B feature HEAD master A B feature HEAD master A B feature HEAD
  19. 19 git reflog : HEADの移動履歴を参照する > git reflog A (HEAD

    -> master, feature) HEAD@{0}: checkout: moving from feature to master B HEAD@{1}: commit: commit on feature ... HEADの移動履歴をreflogで確認 付け替え前のcommit IDを忘れたらgit reflogで探す master A B feature HEAD master A B feature HEAD master A B feature HEAD HEADが移動してないので reflog には残らない featureでの最後のcommitは "B"
  20. 20 diverged branch : リモートとの乖離 ブランチの履歴がリモートと変わると同期できなくなる master A B feature

    master A B feature push/pull可能 push/pull不可 feature A B master ❌ ⭕
  21. 21 git push -f : 強制的にリモートへpush master A B feature

    master A B feature master B A feature
  22. 22 git push -f : 強制的にリモートへpush master A B feature

    > git checkout feature (featureへ移動) > git push -f origin feature (強制的にリモートのfeatureを更新) 強制的にリモートへpush master A B feature master B A feature master A B feature featureのみリモートに反映 masterもforce pushでBを指す
  23. 23 実際の開発現場の運⽤では... • force pushは原則的に望ましくない • リモートの履歴はマスターデータ • 確実に安全 or

    責任が取れる範囲でのみ • push前にローカルリポジトリでやっておく master A B feature master B A feature O O O どちらの状態でも push可能
  24. 24 演習: git branch -f imaizume/2020-01-07_SupporterZ_branch-f git clone またはZIPダウンロードして移動をお願いします リセットするにはgit

    branch -fで移動させるだけ! (なのでbackup上ではcommit等はしないでください) (ちなみに...) "backup/xxx" は初期状態のxxxと同じcommitを指します
  25. 25 (復習) git rebase -iについて

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

    004 001* 002* 005 > Fix bugs > Remove methods 001* 002A 002B 005* 書き換え 結合 分割 順序⼊れ替え ※「きれいなcommit,pull requestを知りたい/作りたい⽅のためのgit勉強会」より
  27. 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 ※「きれいなcommit,pull requestを知りたい/作りたい⽅のためのgit勉強会」より
  28. 28 (後半) rebase -iでcommitとPull Requestを整理

  29. 29 ⼤きなPull Requestを複数に分割 途中のcommitでbranchを作成し複数のPull Requestに master feature たくさんのcommit→ master feature1

    feature feature2 1つの大きなPull Request 複数の小さなPull Request
  30. 30 ⼤きなPull Requestを複数に分割 途中のcommitでbranchを作成し複数のPull Requestに master feature1 feature2 レビュー時だけ feature2のmerge先を分岐元に

    feature1をmaster merge後に feature2をマージ feature
  31. 31 ⼤きなPull Requestを複数に分割 途中のcommitでbranchを作成し複数のPull Requestに master feature1 feature2 feature commit履歴を

    事前に整理する必要あり 意味単位でまとまったbranchにしたい
  32. 32 事前にやること: commitの順序を整理 関連commitごとになるようgit rebase -iで履歴を整理 A Top Page更新 Header作成

    Header内容追加 Header⼀部削除 Top 画像追加 Top 画像更新 footer追加 footer削除 B C D E F G H A' Top Page更新 Top 画像追加 Header作成 Header内容追加 Top 画像更新 footer追加 Header⼀部削除 footer削除 C' G' B' D' E' F' H'
  33. 33 事前にやること: commitの順序を整理 関連commitごとになるようgit rebase -iで履歴を整理 A' Top Page更新 Top

    画像追加 Header作成 Header内容追加 Top 画像更新 Footer追加 Header⼀部削除 Footer削除 C' G' B' D' E' F' H' Footer関連 Header関連 Top関連
  34. 34 事前にやること: rebase -i でcommit順序を変更 > git rebase -i HEAD~8

    // editor(vim)が起動 rebase -i でcommitの順序を整理 pick A Top Page更新 pick B Header作成 pick C Top 画像追加 pick D Header内容追加 pick E Header一部削除 pick F Footer追加 pick G Top 画像更新 pick H Footer削除 BEFORE pick A Top Page更新 pick C Top 画像追加 pick G Top 画像更新 pick B Header作成 pick D Header内容追加 pick E Header一部削除 pick F Footer追加 pick H Footer削除 :wq AFTER NORMAL NORMAL ※Vimの詳しい使い⽅については本⽇割愛 ⾏を⼊れ替えて保存後エディタを閉じる (失敗して進まなくなったら rebase --abort)
  35. 35 事前にやること: commitを統合/削除する 細かすぎるcommitは1つに、不必要なcommitは削除 A' Top Page更新 Top 画像追加 Header作成

    Header内容追加 Top 画像更新 Footer追加 Header⼀部削除 Footer削除 C' G' B' D' E' F' H' A" Top Page更新 Header作成 Top 画像追加 C" B" 差分が±0なのでcommitにしない 適切な粒度でcommitをまとめる
  36. 36 事前にやること: rebase -i でcommitを統合/削除 > git rebase -i HEAD~8

    // editor(vim)が起動 rebase -i でcommitの順序を整理 pick A' Top Page更新 pick C' Top 画像追加 pick G' Top 画像更新 pick B' Header作成 pick D' Header内容追加 pick E' Header一部削除 pick F' Footer追加 pick H' Footer削除 BEFORE pick A' Top Page更新 pick C' Top 画像追加 s G' Top 画像更新 pick B' Header作成 s D' Header内容追加 s E' Header一部削除 d F' Footer追加 d H' Footer削除 :wq AFTER NORMAL NORMAL ⾏頭をsquash(s)またはdrop(d)に変えて保存
  37. 37 (再) ⼤きなPull Requestを複数に分割 A" Top Page更新 Header作成 Top 画像追加

    C" B" master feature/header feature/top feature/top_image 意味単位でまとまった⼩さなPull Requestへ
  38. 38 rebase -iするための前提条件 各commit間に依存関係がないこと ≒差分が⼩さいcommitであること (⼤きなcommitほど他のcommitが依存する可能性⼤) ※詳しくは「きれいなcommit,pull requestを知りたい/作りたい⽅のためのgit勉強会」を参照

  39. 39 演習: git rebase -i imaizume/2020-01-07_SupporterZ_rebase-i git clone またはZIP DL後にターミナルでcdをお願いします

  40. 40 より⾼度なテクニック: 分岐元を変える ある作業中に別ブランチにしたい差分が発⽣ (例: 投稿画⾯を作成中にアプリ全体で共有する関数を実装) A1 master shared/func An

    投稿画⾯ / UI Test B1 Bn グローバル関数 / Unit Test masterから分岐させたい feature/post 依存関係なし ※コミット前なら "git stash save" が使える
  41. 41 rebase --onto: 分岐元を付け替える 依存関係がなければ分岐元を他のブランチに付け替え可能 A1 master shared/func An 投稿画⾯

    / UI Test B1' Bn' グローバル関数 / Unit Test feature/post > git checkout feature/array > git rebase --onto master feature/post shared/func 分岐元を付け替え
  42. 42 演習: git rebase --onto imaizume/2020-01-07_SupporterZ_rebase--onto git clone またはZIP DL後にターミナルでcdをお願いします

  43. 43 リモートと乖離してpushできなくなる rebaseではcommit idが変わるため (順序変更以外でも) A B C A' B'

    C' feature feature A B feature ⭕push可能 ❌push不可
  44. 44 force push による更新 リモートの状態を強制的に更新する B A' B' C' feature

    feature A B A > git checkout feature > git rebase -i HEAD~2 履歴を書き換え
  45. 45 force push時の注意点 間違えた&他のローカルに元の状態がない場合に復旧困難 B A' B' C' feature A

    B A' B' C' feature > git push -f origin feature 強制的に更新 A ⚠戻すのが困難
  46. 46 rebaseした履歴を安全にpushするには rebase前の履歴を別のブランチでリモートにpushしておく B feature A B A old_feature old_feature

    feature > git checkout feature > git branch old_feature > git push origin old_feature rebase前の履歴をpush
  47. 47 rebaseした履歴を安全にpushするには その後rebaseした履歴をforce pushする B A' B' C' feature A

    B A' B' C' feature A old_feature old_feature > git rebase -i HEAD~3 > git push -f origin feature rebase後の履歴をpush feature 元に戻したい場合はold_featureとブランチを付け替える
  48. 48 Pull Requestを⼩さくできないときは? • commit/Pull Requestの単位を⾒直す • 作成と編集、定義と実装で分ける • スコープやファイル単位で分ける

    • 実装やcommitの仕⽅を変えてみる • git add -pの活⽤ • 実装前にインターフェースやテストを書く • アプリ設計の⾒直しも必要かも (SOLID原則等) • 同じPull Requestにする必要性は? • commit間に依存がないなら分けられるはず
  49. 49 まとめ

  50. 50 まとめ ✓ git branchは付け替え可能 ✓ただし元のブランチを⾒失わないように ✓ rebase -i で履歴をいい感じに整理してからPRに

    ✓rebaseしやすくするため⼩さいcommitを意識しよう ✓ リモートと履歴が異なる場合はforce pushも可能 ✓ ただし復旧困難にならないよう慎重に 前半 後半
  51. 51 参考リンク Sublime Merge - Git Client, done Sublime :

    https://www.sublimemerge.com/ Git - git-branch Documentation : https://git-scm.com/docs/git-branch Git - git-rebase Documentation : https://git-scm.com/docs/git-rebase (再演) detached HEADを理解して脱Git初⼼者を⽬指す⽅のためのGit⼊⾨勉強会 @サポー ターズCoLab - Speaker Deck : http://bit.ly/2DpZwga (再演)きれいなcommit, pull requestを知りたい/作りたい⽅のためのgit勉強会 - Speaker Deck : http://bit.ly/2SD90uT Githubで間違えてgit push -f origin masterしてしまった時の対応 - Qiita : https:// qiita.com/awakia/items/52b5900e801c3bfbab04 テキスト版:Gitの困り事何でも解決いたします 勉強会講師の経験有り ❗ 使い⽅から運⽤ まで何でもどうぞ ❗ | ココナラ : https://coconala.com/services/642499 ビデオ版:Gitの困り事解決いたします 勉強会講師の経験有り 使い⽅から運⽤まで何でもど うぞ! | ココナラ : https://coconala.com/services/839341 勉強会講師も担当 ❗ 親切丁寧にGitの使い⽅教えます | タイムチケット : https:// www.timeticket.jp/items/58703 Git・GitHubに関する相談・レクチャー - ストアカ : https://www.street-academy.com/ myclass/73592