Git

Git研修【MIXI 23新卒技術研修】 - YouTube

バージョン管理システム、VCS
履歴辿れる、容量抑える、改竄に強い

時系列とブランチでバージョン管理できる
別時系列がbranch、合わせるのがmerge

git config —global init.defaultBranch でinit時に作られるbranchを変更できる
masterからmainにしたりとか

git merge-base branch1 branch2 で分岐コミットを調べられる

git log hash branch filenameでどんな修正を加えたかを調べられる

rebaseとmerge

ブランチ分岐変更

以下ブランチをmainとdevelopとし、mainにdevelopをmergeするとする

fast-forward mergeはコンフリクトを起こさないmerge
merge元のコミットがHEADの時、fast-forwardになる
mergeというか、diffも何もなく先っちょにくっつけるだけ

rebaseはdevelopのbaseをHEADに書き換え、強制的にfast-forward mergeを行う
コンフリクトをremoteではなく手元で起こせるため、簡単に修正できる
特にgithubのpublicリポジトリとかでやりたくなる

しかし、手元でコンフリさせるならmainをdevelopにマージすればいい
rebaseの利点はcommitsにマージコミットが混ざらないことだが、強制pushが必要になってしまう
なのでmergeが主流

レビュー待ちブランチからブランチを切った時

レビュー待ちブランチ(branch1)からブランチ切る(branch2)
レビューが終わりbranch1をmainにマージ
すると既にマージ済みのコミットがPRのコミットに出てきてしまう(レビュー済みの情報が出るためレビュー面倒)

そういう時はrebase
マージ済みのmainのコミットをbaseにすることにより、コミットを自分の分だけにする

コミット履歴の修正

  • 並べ替え
  • 合体(squash)
  • メッセージ変更
  • 過去のコミットを修正

全部-iでできる
終わったら--continueで確定する

-i HEAD~3とするとHEADから3つを扱える
その後何をするかはエディター上で決める(pick、squash、dropなど)

強制Push

pushはファイルへの追加などしか許されない
rebaseは履歴が書き換わるため、強制pushで書き換える必要がある

強制pushで有名なのはgit push -Fだが、これはローカル状態をリモートに完全上書きする。
ここでremote上に他の人が既にpushしたコミットがあった場合でもそれを消す危険なコマンド。

なので代わりにgit push --force-with-lease --force-if-includesを使う。

Git - git-push Documentation

--force-with-leaseは、リベース済みを明示できる。
リモートが更新されていない→refがコミットを指している時のみpushできる。
ロックではなくリースする(借りる)という意味。

--force-if-includesは、リモートの先端がローカルに統合されている→ローカルのreflogからリモート先端に到達できる場合→リモートの更新が全てローカルに含まれる時にpush。

bisect

こっからここまでのどこかのコミットでバグったが、どれか分からない。
というときに二分木探索で手動で調べられる。
テストスクリプトを組んで一緒に使うのが早い。

resetとrevert

resetはコミットを消す、つまり履歴に関わるため強制pushが必要。
revertは逆のコミットを付けるので問題なくpushできる。

log

--graphで綺麗に出せる。
--onelineだと変更部分だけになる?

stash

変更の一時退避。
stash listで一覧。
stash apply 番号で復元。
stash popで復元しつつ削除。

実質コミットみたいなものなのでstash@{n}で参照できる。

-

一つ前にいたブランチ。
git checkout - で戻ったり、
git merge -で一つ前を現在にマージしたりできる。

分散型

「リポジトリの全履歴を含めた完全なコピーがローカルにある」という意味。

集中型は全部サーバーにあるため、ローカル編集中はファイルがロックされる。
分散型は誰がどんな修正をしていても編集できる。

ブランチ運用

自由度が高いせいですぐごちゃつく
なのでいくつかやり方がある

Git Flow

リモートリポジトリは一個というやり方。
remoteに複数を設定しない。

forkしたリポジトリの元の追従とかでたまに複数になる。

main, develop

mainブランチはリリース用(ユーザー用)にし、変更時はタグをつける。
普段の変更は全部developに投げるやり方。

feature

develop内で一つの機能の編集ごとにfeatureブランチを作る。
これは複数できて当然。終わったらdevelopにmerge。

一つの機能で分けないと

  • 機能ごとのデバッグが出来ない
  • 差分が大きくなりコンフリしがち
  • 機能ごとのrevertも難しい

場合によってはfeatureから機能をさらに切り出し別のfeatureへ、ということも。
その時はworkという名前にMixiはしている。

他、概念実証もここ

release(staging)

リリースの準備をするところ。
チームによってはstagingという名前も。

bugfix、version表記やタイムスタンプ更新、アプリの審査など
最終確認
大体自動化されるところ

新機能を追加してはいけない

hotfix

本番環境のバグのうち、緊急性の高いものを修正するためのブランチ。
develop以外で唯一mainから切られる。

完了したらdevelopか、直でmainか、場合によってはreleaseに送られる。

developがreleaseを挟む都合上、遅くなるためこのブランチが切られる。
でも普通releaseは自動化されるのでこのブランチが出ることは少ない。

Github Flow、トランクベース開発

GitHub

リポジトリホスティングサービス。

Issue

気になったことをマークダウンで書き留める。
相談程度でもよく使われる。
問題解決はProjectでもできるので。

ラベルで分類、マイルストーンで期限、assignなど。

Pull Request

作業を取り込んでほしいときのやつ
元はfork元のリポジトリに頼むものなので、Merge Requestではない。(GitHub以外だとMerge Requestと呼ぶことも)

駄目だったら指摘する(レビュー)

  • プルリクは細かく
    • 巨大だと時間がかかり、他のPRが増えコンフリする
  • 大きくなりがちなら、途中レビュー
    • さらにfeatureを切る、WIPつける、draft PR出すなど
  • コミットログはキレイに
    • こまめにコミット、出来れば最後にgit rebase -iで整え
    • 厳しい時はfast-forwardできないと却下される

[! attention]

  • できるだけCIに任す
    • テストは書く、フォーマットでスペース差分を減らす
  • 仕様の穴、セキュリティ、法などにまず注力
    • 次に負債、設計、計算量・レイテンシを見る
  • ついでに自分のPRもレビューしろ
  • レビューは5W1H、どこがどういう理由でよくないかを書く
    • 合わせて、どういう方法ならいいかを書くと議論しやすい
    • あるなら定量的な指標を活用する
  • テキストはきつくなりがちなので、絵文字とかで1.5倍優しく

Actions

CI/CD
.githubにyaml置く

Projects

kanban型タスク管理
機能が少ないので、ZenHubで機能追加して使うといいらしい

Wiki

wiki
機能が貧弱、docbaseでよくない

Security

  • Security Policy
  • Security Advisories
  • Dependabot

この三つの機能の編集
主にOSS用
Dependabotくらいしか実際は使わない

Security Policy

脆弱性報告の手順。マークダウンで書いとく。

Security Advisories

非公開Issue的な。主に脆弱性について議論を交わす。
対応パッチリリース後に公開できる。

Dependabot

コードからの依存パッケージバージョン解析。
脆弱性があればアラートを飛ばす。

Insights

リポジトリの活発具合について
自分のリポジトリだと使わない
新しいライブラリとかのメンテ頻度を調べられる

Settings

設定
Branch Protection rulesでbranchについてpush規定などの設定が出来る。
branchは正規表現で指定可能。

前に書いたmainやdevelopのルールを書いておく。

git 後半