Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Gitの使い方(応用編) / GitHub Advanced

A10e41b0a61d59f2258d7f6172c33479?s=47 kaityo256
October 11, 2021

Gitの使い方(応用編) / GitHub Advanced

物理情報工学ソフトウェア開発演習

A10e41b0a61d59f2258d7f6172c33479?s=128

kaityo256

October 11, 2021
Tweet

Transcript

  1. 1 Gitの使い方(応用編) 慶應義塾大学理工学部物理情報工学科 渡辺 物理情報工学ソフトウェア開発演習

  2. 2 Gitのトラブルシューティング Gitの便利機能 「しまった!」「あれ?」をなんとかする 毎日使うわけではないが、知っていると 便利な機能の紹介

  3. 3 $ git add test.txt $ git commit -m “updaets

    test.txt” スペルミスしたことにコミット後に気づいた 既に歴史に誤りが刻まれてしまった $ git log --oneline 8f7d4f8 (HEAD -> main) updaets test.txt 78efaf0 initial commit
  4. 4 $ git commit --amend カレントブランチの最新コミットのコミット メッセージを修正する $ git commit

    --amend -m "updates test.txt" -mと一緒に使うことが多い 歴史が修正された $ git log --oneline 52304ef (HEAD -> main) updates test.txt 78efaf0 initial commit
  5. 5 initial commit 78efaf0 8f7d4f8 updaets test.txt initial commit 78efaf0

    52304ef updates test.txt git commit --amendによりコミットハッシュが変わる →歴史が書き換わる プッシュしたブランチをリベースしてはならないのと同じ 理由で、プッシュしたブランチをamendしてはならない
  6. 6 $ git restore ファイル名 いろいろ修正したが、よくわからなくなったので 修正をなかったことにしたい 指定したファイルを、最新のコミットの状態まで戻す 注:git restoreはgit

    2.23から導入された比較的新しいコマンド で、それまではgit checkoutやgit resetを使っていた。それぞれ 操作に失敗すると危険なので、git restoreを使うと良い(後述)。
  7. 7 間違えてステージングしてしまったファイルを取 り消したい $ git restore --staged ファイル名 インデックスに登録されたファイルを取り消す。インデック スは最新のコミットの状態に戻る。

    git addで余計なファイルをステージングした時などに使う。 --stagedは-Sでも良い ワーキングツリーの修正を取り消すには--worktreeもしくは-W デフォルトでは-Wが暗黙に指定される
  8. 8 チェックアウトとは リポジトリからファイルを 取り出すこと リポジトリから指定したブランチのコミットを取り出して ワーキングツリーに展開する = ブランチを切り替える $ git

    checkout ブランチ名 $ git checkout ファイル名 インデックスから指定したファイルを取り出してワーキング ツリーに展開する = ステージングされていない修正を取りけす
  9. 9 git checkoutはコミットを指定してチェックアウトできる $ git checkout コミットハッシュ main HEAD 9b662ef

    $ git checkout 9b662ef main 9b662ef HEAD いわゆる「頭が取れた(Detached HEAD)」状態になる
  10. 10 git checkoutが担う役割が多すぎる問題 →Git 2.23.0からswitchとrestoreが追加 ブランチ切り替え機能 → git switch 修正取り消し機能

    → git restore 原則としてgit checkoutは使わない git switchもコミットハッシュを指定できるが、ブランチ名を つけることが強制される→より「安全」に $ git switch -c branchname 9b662ef ※ 古い情報にgit checkoutの用法が載っていることがあるので注意
  11. 11 GitHubを使っていて、SSHのつもりがHTTPSで リモートを登録してしまった git remote add origin https://github.com/appi-github/somerepository.git git branch

    -M main git push -u origin main $ git remote add origin git@github.com:appi-github/somerepository.git error: remote origin already exists. 改めてSSHで登録しようとしても…… 「既にoriginという名前のリモートリポジトリが存在 するよ」と言われて追加を拒否される
  12. 12 $ git remote remove origin 指定したリモートリポジトリを削除する 多くの場合originを指定するはず $ git

    remote add origin git@github.com:appi-github/somerepository.git 削除後に改めてSSHで登録すればOK
  13. 13 Gitでは原則としてmainブランチでは作業せず、 新しいブランチを作成してからそこで作業する カレントブランチがmainのまま、いろんなファ イルを修正して保存しちゃった。 にもかかわらず・・・ まだコミットしてなければ 対応可能

  14. 14 $ git stash 修正を保存し、ワーキングツリーを最新の コミットの状態に戻す 修正したファイル $ git stash

    修正が退避 最新のコミットのスナッ プショットに戻る
  15. 15 main HEAD ブランチを切り替える $ git switch -c feature main

    HEAD feature 修正を適用する $ git stash pop ブランチを切り替えてから修正した状態になる
  16. 16 作業のまとめ 1. git stash で修正内容を退避 2. git switch -c

    branchname でブランチを作成して切り替え 3. git stash pop で修正内容をワーキングツリーに適用 git stashについて 複数の状態を退避可能(スタックになっている) 退避した状態はgit stash listで表示できる 指定した状態を適用するにはgit apply ただし、複数退避すると混乱しやすい 「退避は一つだけ」「退避したらすぐ適用」
  17. 17 $ git push To /URL/to/repository.git ! [rejected] main ->

    main (fetch first) error: failed to push some refs to '/URL/to/test.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details. 家で作業して、ある程度まとまったので、プッシュしよう としたら拒否された あ、大学でプッシュした内容をフェッチし忘れた! ここに拒否の理由が書いてある
  18. 18 main リモートリポジトリ main origin/main ローカルリポジトリ 歴史を共有していないので プッシュできない

  19. 19 main リモートリポジトリ main origin/main ローカルリポジトリ main origin/main $ git

    fetch origin/mainがリモートと同じ状態に まずフェッチする
  20. 20 main origin/main main origin/main ローカルリポジトリ $ git merge 次にマージする

    ローカルに「リモートの歴史」が取り込まれた
  21. 21 main リモートリポジトリ main main origin/main main origin/main $ git

    push 歴史を共有したのでプッシュできる
  22. 22 作業のまとめ 1. git fetchで最新の情報をローカルに持ってくる 2. git mergeで修正を取り込む(ここで歴史を共有) 3. git

    pushで修正をリモートに送る メッセージを読む プッシュに失敗すると、赤字でrejectedと言われ、いろいろ メッセージが出てきて焦るが、ヒントに「リモートにロー カルに存在しないコミットがあるからリジェクトされた よ」「まずリモートの修正を取り込んでからプッシュし ろ」と書いてある。
  23. 23 main HEAD Detached HEAD状態 HEADがブランチではなく、直接 コミットを指した状態 どんな状況でなるか? git checkoutで直接コミットを指定した←普通やらない

    git rebaseの最中に衝突した←対応後述 git bisectの実行中←git bisect resetで抜ける 上記以外で「よくわからないけど頭が取れた」時の対処
  24. 24 main HEAD なぜかわからないけど頭が取れた main HEAD $ git switch main

    ここでmainに戻ってしまうと、後でアクセス できなくなるコミットができてしまう
  25. 25 main HEAD $ git branch 20210918_detached_head 20210918_detached_head いまHEADが指しているコミットに 適当な名前のブランチをつけておく

    $ git switch main main 20210918_detached_head mainブランチに戻る
  26. 26 作業のまとめ 1. git branchで適当な名前のブランチをつけておく 2. git switch mainでメインブランチに戻る 3.

    必要があればマージ、しばらく待って不要だと思えば ブランチを削除 普通にやっていればgit rebaseとgit bisect以外で 頭は取れないはず。上記はあくまで緊急回避。
  27. 27 $ git rebase main Auto-merging test.txt CONFLICT (content): Merge

    conflict in test.txt error: 99a8712を適用できませんでした... f2 Resolve all conflicts manually, mark them as resolved with "git add/rm <conflicted_files>", then run "git rebase --continue". You can instead skip this commit: run "git rebase --skip". To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply 99a8712... f2 リベースしようとしたら衝突が発生した test.txtで衝突が起きた 衝突を解消してからgit addしてgit rebase --continueしろ リベースを中止するなら git rebase --abortしろ
  28. 28 main branch m1 m2 m3 f1 f2 f3 root

    main branch m1 m2 m3 f1’ f2’ f3’ root $ git rebase main HEAD HEAD まだこのブランチは ここにきていない ここで衝突
  29. 29 main branch m1 m2 m3 f1’ f2’ f3’ root

    HEAD 次に作りたいコミットはここ このコミットの「あるべき姿」をインデックスに登録してコミット $ git add test.txt $ git commit -m “resolved conflict of test.txt” リベースを続行 $ git rebase --continue
  30. 30 作業のまとめ 1. git add により「次に作るべきコミット」をインデッ クスに登録する 2. git commitでコミット(merge実行時のマージコミット

    にあたるもの)を作る 3. git rebase --continueでリベース続行 4. 衝突するたびに1-3を繰り返す リベース中に衝突すると頭が取れるので焦りがち 「次に作るべきコミットはどういうものか」を考え、 それを作っていく
  31. 31 $ git blame ファイル名 指定したファイルの、どの行をいつ、誰が修正したかを表示する def func1(): print("Hello func1")

    def func2(): print("Hello func2") if __name__ == '__main__': print("Hello") func1() func2() 例えばこのPythonスクリプトの、それぞれ の関数をいつ、だれが書いたか知りたい
  32. 32 $ git blame test.py 56127fbb (H. Watanabe 2021-09-17 21:22:49

    +0900 1) def func1(): 56127fbb (H. Watanabe 2021-09-17 21:22:49 +0900 2) print("Hello func1") 56127fbb (H. Watanabe 2021-09-17 21:22:49 +0900 3) 56127fbb (H. Watanabe 2021-09-17 21:22:49 +0900 4) 26bdec20 (H. Watanabe 2021-09-17 21:23:31 +0900 5) def func2(): 26bdec20 (H. Watanabe 2021-09-17 21:23:31 +0900 6) print("Hello func2") 26bdec20 (H. Watanabe 2021-09-17 21:23:31 +0900 7) 26bdec20 (H. Watanabe 2021-09-17 21:23:31 +0900 8) ^fea5775 (H. Watanabe 2021-09-17 21:22:08 +0900 9) if __name__ == '__main__': ^fea5775 (H. Watanabe 2021-09-17 21:22:08 +0900 10) print("Hello") 26bdec20 (H. Watanabe 2021-09-17 21:23:31 +0900 11) func1() 26bdec20 (H. Watanabe 2021-09-17 21:23:31 +0900 12) func2() 個人開発では著者は全て自分だが「あれ?これ書 いたのいつだっけ?」と思うことがあるのでたま に便利(特にデバッグ時に)。
  33. 33 ここでバグ発見 ここは確実に大丈夫 このどこかに「初めてバグが入ったコミット」があるはず

  34. 34 $ git bisect start 問題のある場所 問題のない場所 二分探索開始。Gitが候補となるコミットを次々に持っ てくるので、そのたびに問題があるかないかを教える。 ?

    git bisect good git bisect bad
  35. 35 ここでバグ発見 ここは確実に大丈夫 e6348e408b57fdb42eb1281cb77b5c331cd400e7 is the first bad commit e6348e4

    $ git branch bug e6348e4 $ git bisect reset main bug 見つけたコミットにブランチをつけてbisectを抜ける
  36. 36 作業のまとめ 1. 間違いなくバグっていないコミットを探す 2. git bisect startで二分探索開始 3. git

    bisect good/badで良いか悪いかGitに教える 4. Gitが見つけた「最初にバグが入ったコミット」にブ ランチを付けてgit bisectを抜ける 5. 「最初にバグが入ったコミット」とその前の差分を調 べる 補足 歴史に「中途半端なコミット」があると二分探索できない 合否判定を自動化できる(演習でやります)
  37. 37 Gitのトラブルシューティング 慣れていないと、トラブルが起きた時に焦りがち トラブルの解消のためには、ある程度Gitの知識が必要 Gitが出すメッセージをきちんと読む Gitの便利機能 Gitには「知ってると便利」な機能が多数ある コマンド名を覚えておく必要はないが、「そういう ことができる」ということだけ知っておくと良い