Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

3 coconala / Time Ticket / ストアカで Git / GitHubに関する相談・レクチャーを受付中❗ 本⽇の内容以外についても 聞きたいことや悩みがあればお気軽にどうぞ 宣伝

Slide 4

Slide 4 text

4 TOPIC • (復習) git branchについて • (前半) branchを⾃由に操えるようになろう • branchを付け替えてみよう • 付け替え前のcommit IDを忘れたら • remoteとの乖離が発⽣したら • (復習) git rebase -iについて • (後半) rebase -iでcommitとPull Requestを整理 • ⼤きなPull Requestを分割するために • git branchの分岐元を変える • Pull Requestを⼩さくできない時は?

Slide 5

Slide 5 text

5 補⾜: commit logを⾒やすくするために 今回commit logがたくさん出てきます。 ブランチの状態を⾒やすくするために... • ターミナル上で "git log --graph --all --oneline" • Sublime MergeのようなGUIツールを使う Sublime Mergeの画⾯

Slide 6

Slide 6 text

6 (復習) git branchについて

Slide 7

Slide 7 text

7 git branchとは • 複数の変更履歴を切り替えるための⽬印 • 並列・⾮同期での開発に役⽴つ > git branch feature // feature ブランチを作成 > git checkout feature // feature ブランチに切り替え > git branch -d old // old ブランチを削除 ブランチの作成・切り替え・削除

Slide 8

Slide 8 text

001 002 master 003 dev 004 005 branch is コレ よくあるブランチの説明 ※「detached HEADを理解して脱Git初⼼者を⽬指す⽅のためのGit⼊⾨勉強会」より (古い) (新しい)

Slide 9

Slide 9 text

002 master 001 ※「detached HEADを理解して脱Git初⼼者を⽬指す⽅のためのGit⼊⾨勉強会」より git branchとは?? > The command’s second form creates a new branch head named which points to the current HEAD branch = commitへのポインタ Gitの公式マニュアルでも "points to" と表現

Slide 10

Slide 10 text

⭐ さらにざっくり言えば 「branch = commitの別名」 (⾠全く同じではない) よくある勘違いの原因 「branch ≠ コミット群」
 左の例では • master は004を指すポインタ • devは 005を指すポインタ 001 002 master 003 dev 004 005 ※「detached HEADを理解して脱Git初⼼者を⽬指す⽅のためのGit⼊⾨勉強会」より

Slide 11

Slide 11 text

⭐ 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⼊⾨勉強会」より

Slide 12

Slide 12 text

12 (前半) branchを⾃由に操えるようになろう

Slide 13

Slide 13 text

13 branchを付け替えてみよう ➡ branchは付け替え可能 feature A B feature A B • branch = commitへのポインタ • ポインタは付け替えが可能 BEFORE AFTER

Slide 14

Slide 14 text

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を指すブランチが無い

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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を覚えて付け替え

Slide 17

Slide 17 text

> git reflog HEADの移動履歴をreflogで確認 17 git reflog : HEADの移動履歴を参照する 付け替え前のcommit IDを忘れたらgit reflogで探す master A B feature HEAD ここでgit reflog

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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"

Slide 20

Slide 20 text

20 diverged branch : リモートとの乖離 ブランチの履歴がリモートと変わると同期できなくなる master A B feature master A B feature push/pull可能 push/pull不可 feature A B master ❌ ⭕

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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を指す

Slide 23

Slide 23 text

23 実際の開発現場の運⽤では... • force pushは原則的に望ましくない • リモートの履歴はマスターデータ • 確実に安全 or 責任が取れる範囲でのみ • push前にローカルリポジトリでやっておく master A B feature master B A feature O O O どちらの状態でも push可能

Slide 24

Slide 24 text

24 演習: git branch -f imaizume/2020-01-07_SupporterZ_branch-f git clone またはZIPダウンロードして移動をお願いします リセットするにはgit branch -fで移動させるだけ! (なのでbackup上ではcommit等はしないでください) (ちなみに...) "backup/xxx" は初期状態のxxxと同じcommitを指します

Slide 25

Slide 25 text

25 (復習) git rebase -iについて

Slide 26

Slide 26 text

rebase -i で commit log を再編集 =結合/分割/書き換え/順序⼊れ替えが可能 001 002 003 004 001* 002* 005 > Fix bugs > Remove methods 001* 002A 002B 005* 書き換え 結合 分割 順序⼊れ替え ※「きれいなcommit,pull requestを知りたい/作りたい⽅のためのgit勉強会」より

Slide 27

Slide 27 text

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勉強会」より

Slide 28

Slide 28 text

28 (後半) rebase -iでcommitとPull Requestを整理

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

31 ⼤きなPull Requestを複数に分割 途中のcommitでbranchを作成し複数のPull Requestに master feature1 feature2 feature commit履歴を 事前に整理する必要あり 意味単位でまとまったbranchにしたい

Slide 32

Slide 32 text

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'

Slide 33

Slide 33 text

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関連

Slide 34

Slide 34 text

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)

Slide 35

Slide 35 text

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をまとめる

Slide 36

Slide 36 text

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)に変えて保存

Slide 37

Slide 37 text

37 (再) ⼤きなPull Requestを複数に分割 A" Top Page更新 Header作成 Top 画像追加 C" B" master feature/header feature/top feature/top_image 意味単位でまとまった⼩さなPull Requestへ

Slide 38

Slide 38 text

38 rebase -iするための前提条件 各commit間に依存関係がないこと ≒差分が⼩さいcommitであること (⼤きなcommitほど他のcommitが依存する可能性⼤) ※詳しくは「きれいなcommit,pull requestを知りたい/作りたい⽅のためのgit勉強会」を参照

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

40 より⾼度なテクニック: 分岐元を変える ある作業中に別ブランチにしたい差分が発⽣ (例: 投稿画⾯を作成中にアプリ全体で共有する関数を実装) A1 master shared/func An 投稿画⾯ / UI Test B1 Bn グローバル関数 / Unit Test masterから分岐させたい feature/post 依存関係なし ※コミット前なら "git stash save" が使える

Slide 41

Slide 41 text

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 分岐元を付け替え

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

44 force push による更新 リモートの状態を強制的に更新する B A' B' C' feature feature A B A > git checkout feature > git rebase -i HEAD~2 履歴を書き換え

Slide 45

Slide 45 text

45 force push時の注意点 間違えた&他のローカルに元の状態がない場合に復旧困難 B A' B' C' feature A B A' B' C' feature > git push -f origin feature 強制的に更新 A ⚠戻すのが困難

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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とブランチを付け替える

Slide 48

Slide 48 text

48 Pull Requestを⼩さくできないときは? • commit/Pull Requestの単位を⾒直す • 作成と編集、定義と実装で分ける • スコープやファイル単位で分ける • 実装やcommitの仕⽅を変えてみる • git add -pの活⽤ • 実装前にインターフェースやテストを書く • アプリ設計の⾒直しも必要かも (SOLID原則等) • 同じPull Requestにする必要性は? • commit間に依存がないなら分けられるはず

Slide 49

Slide 49 text

49 まとめ

Slide 50

Slide 50 text

50 まとめ ✓ git branchは付け替え可能 ✓ただし元のブランチを⾒失わないように ✓ rebase -i で履歴をいい感じに整理してからPRに ✓rebaseしやすくするため⼩さいcommitを意識しよう ✓ リモートと履歴が異なる場合はforce pushも可能 ✓ ただし復旧困難にならないよう慎重に 前半 後半

Slide 51

Slide 51 text

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