Share
Embed
Transcript
37 slides
-
3 37 $ git add test.txt $ git commit -m
“updaets test.txt” スペルミスしたことにコミット後に気づいた 既に歴史に誤りが刻まれてしまった $ git log --oneline 8f7d4f8 (HEAD -> main) updaets test.txt 78efaf0 initial commit -
4 37 $ git commit --amend カレントブランチの最新コミットのコミット メッセージを修正する $ git
commit --amend -m "updates test.txt" -mと一緒に使うことが多い 歴史が修正された $ git log --oneline 52304ef (HEAD -> main) updates test.txt 78efaf0 initial commit -
5 37 initial commit 78efaf0 8f7d4f8 updaets test.txt initial commit
78efaf0 52304ef updates test.txt git commit --amendによりコミットハッシュが変わる →歴史が書き換わる プッシュしたブランチをリベースしてはならないのと同じ 理由で、プッシュしたブランチをamendしてはならない -
6 37 $ git restore ファイル名 いろいろ修正したが、よくわからなくなったので 修正をなかったことにしたい 指定したファイルを、最新のコミットの状態まで戻す 注:git
restoreはgit 2.23から導入された比較的新しいコマンド で、それまではgit checkoutやgit resetを使っていた。それぞれ 操作に失敗すると危険なので、git restoreを使うと良い(後述)。 -
7 37 間違えてステージングしてしまったファイルを取 り消したい $ git restore --staged ファイル名 インデックスに登録されたファイルを取り消す。インデック
スは最新のコミットの状態に戻る。 git addで余計なファイルをステージングした時などに使う。 --stagedは-Sでも良い ワーキングツリーの修正を取り消すには--worktreeもしくは-W デフォルトでは-Wが暗黙に指定される -
8 37 チェックアウトとは リポジトリからファイルを 取り出すこと リポジトリから指定したブランチのコミットを取り出して ワーキングツリーに展開する = ブランチを切り替える $
git checkout ブランチ名 $ git checkout ファイル名 インデックスから指定したファイルを取り出してワーキング ツリーに展開する = ステージングされていない修正を取りけす -
9 37 git checkoutはコミットを指定してチェックアウトできる $ git checkout コミットハッシュ main HEAD
9b662ef $ git checkout 9b662ef main 9b662ef HEAD いわゆる「頭が取れた(Detached HEAD)」状態になる -
10 37 git checkoutが担う役割が多すぎる問題 →Git 2.23.0からswitchとrestoreが追加 ブランチ切り替え機能 → git switch
修正取り消し機能 → git restore 原則としてgit checkoutは使わない git switchもコミットハッシュを指定できるが、ブランチ名を つけることが強制される→より「安全」に $ git switch -c branchname 9b662ef ※ 古い情報にgit checkoutの用法が載っていることがあるので注意 -
11 37 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 [email protected]:appi-github/somerepository.git error: remote origin already exists. 改めてSSHで登録しようとしても…… 「既にoriginという名前のリモートリポジトリが存在 するよ」と言われて追加を拒否される -
12 37 $ git remote remove origin 指定したリモートリポジトリを削除する 多くの場合originを指定するはず $
git remote add origin [email protected]:appi-github/somerepository.git 削除後に改めてSSHで登録すればOK -
14 37 $ git stash 修正を保存し、ワーキングツリーを最新の コミットの状態に戻す 修正したファイル $ git
stash 修正が退避 最新のコミットのスナッ プショットに戻る -
15 37 main HEAD ブランチを切り替える $ git switch -c feature
main HEAD feature 修正を適用する $ git stash pop ブランチを切り替えてから修正した状態になる -
16 37 作業のまとめ 1. git stash で修正内容を退避 2. git switch
-c branchname でブランチを作成して切り替え 3. git stash pop で修正内容をワーキングツリーに適用 git stashについて 複数の状態を退避可能(スタックになっている) 退避した状態はgit stash listで表示できる 指定した状態を適用するにはgit apply ただし、複数退避すると混乱しやすい 「退避は一つだけ」「退避したらすぐ適用」 -
17 37 $ 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. 家で作業して、ある程度まとまったので、プッシュしよう としたら拒否された あ、大学でプッシュした内容をフェッチし忘れた! ここに拒否の理由が書いてある -
19 37 main リモートリポジトリ main origin/main ローカルリポジトリ main origin/main $
git fetch origin/mainがリモートと同じ状態に まずフェッチする -
20 37 main origin/main main origin/main ローカルリポジトリ $ git merge
次にマージする ローカルに「リモートの歴史」が取り込まれた -
21 37 main リモートリポジトリ main main origin/main main origin/main $
git push 歴史を共有したのでプッシュできる -
22 37 作業のまとめ 1. git fetchで最新の情報をローカルに持ってくる 2. git mergeで修正を取り込む(ここで歴史を共有) 3.
git pushで修正をリモートに送る メッセージを読む プッシュに失敗すると、赤字でrejectedと言われ、いろいろ メッセージが出てきて焦るが、ヒントに「リモートにロー カルに存在しないコミットがあるからリジェクトされた よ」「まずリモートの修正を取り込んでからプッシュし ろ」と書いてある。 -
23 37 main HEAD Detached HEAD状態 HEADがブランチではなく、直接 コミットを指した状態 どんな状況でなるか? git
checkoutで直接コミットを指定した←普通やらない git rebaseの最中に衝突した←対応後述 git bisectの実行中←git bisect resetで抜ける 上記以外で「よくわからないけど頭が取れた」時の対処 -
24 37 main HEAD なぜかわからないけど頭が取れた main HEAD $ git switch
main ここでmainに戻ってしまうと、後でアクセス できなくなるコミットができてしまう -
25 37 main HEAD $ git branch 20210918_detached_head 20210918_detached_head いまHEADが指しているコミットに
適当な名前のブランチをつけておく $ git switch main main 20210918_detached_head mainブランチに戻る -
26 37 作業のまとめ 1. git branchで適当な名前のブランチをつけておく 2. git switch mainでメインブランチに戻る
3. 必要があればマージ、しばらく待って不要だと思えば ブランチを削除 普通にやっていればgit rebaseとgit bisect以外で 頭は取れないはず。上記はあくまで緊急回避。 -
27 37 $ 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 37 main branch m1 m2 m3 f1 f2 f3
root main branch m1 m2 m3 f1’ f2’ f3’ root $ git rebase main HEAD HEAD まだこのブランチは ここにきていない ここで衝突 -
29 37 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 37 作業のまとめ 1. git add により「次に作るべきコミット」をインデッ クスに登録する 2. git
commitでコミット(merge実行時のマージコミット にあたるもの)を作る 3. git rebase --continueでリベース続行 4. 衝突するたびに1-3を繰り返す リベース中に衝突すると頭が取れるので焦りがち 「次に作るべきコミットはどういうものか」を考え、 それを作っていく -
31 37 $ git blame ファイル名 指定したファイルの、どの行をいつ、誰が修正したかを表示する def func1(): print("Hello
func1") def func2(): print("Hello func2") if __name__ == '__main__': print("Hello") func1() func2() 例えばこのPythonスクリプトの、それぞれ の関数をいつ、だれが書いたか知りたい -
32 37 $ 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() 個人開発では著者は全て自分だが「あれ?これ書 いたのいつだっけ?」と思うことがあるのでたま に便利(特にデバッグ時に)。 -
34 37 $ git bisect start 問題のある場所 問題のない場所 二分探索開始。Gitが候補となるコミットを次々に持っ てくるので、そのたびに問題があるかないかを教える。
? git bisect good git bisect bad -
35 37 ここでバグ発見 ここは確実に大丈夫 e6348e408b57fdb42eb1281cb77b5c331cd400e7 is the first bad commit
e6348e4 $ git branch bug e6348e4 $ git bisect reset main bug 見つけたコミットにブランチをつけてbisectを抜ける -
36 37 作業のまとめ 1. 間違いなくバグっていないコミットを探す 2. git bisect startで二分探索開始 3.
git bisect good/badで良いか悪いかGitに教える 4. Gitが見つけた「最初にバグが入ったコミット」にブ ランチを付けてgit bisectを抜ける 5. 「最初にバグが入ったコミット」とその前の差分を調 べる 補足 歴史に「中途半端なコミット」があると二分探索できない 合否判定を自動化できる(演習でやります)