パーソルキャリア株式会社 テクノロジー本部 エンジニアリング統括部 サービス開発部 ※本資料は2023年3月時点の情報であり、当該部門における2023年新卒の研修教材です。
Git 研修1パーソルキャリア株式会社 テクノロジー本部 エンジニアリング統括部 サービス開発部※本資料は2023年3月時点の情報であり、2023年新卒の研修教材です。
View Slide
この研修について● みなさんが業務で GitHub を使う際に必要な最低限の情報を入れ込んでいます● 既に知っているところ、知らないところそれぞれあると思います● 長いのでマメに休憩を入れます気になることがあったときは 🤔● わからない、気になるところはメッセージや口頭で教えてください!● 知らないことや苦手なことを共有するのは信頼関係構築でも重要です ● 知らないから見下す、という認識の人はサビ開にいません● 知らないことを知らないと言える人がいちばん偉い
もくじ前半 Git を使ったチーム開発に関する Tips● 概念やサービス開発部での開発作法に関するもの中心後半 Git 自体の概念や仕組み理解● branch とは? HEAD って? commit って何?● rebase とは? merge / rebase の違いは?● conflict したときどうする?● その他コマンドについて
そもそも…
Gitってなに?● 分散型バージョン管理システム ( DVCS ) の一つ● Linux カーネルの開発において使用するために、Linus Torvalds によって2005年に開発された分散型各開発者がリポジトリの完全なコピーをローカルに持つ ↔ 中央集中型バージョン管理システムファイルの変更履歴を追跡し、異なるバージョン間の差分や統合を管理するソフトウェア
Git 以外のバージョン管理システム● Subversion (中央集中型)● Mercurial (分散型)● CVS (中央集中型)● Perforce (中央集中型) などGit 以外を使う理由● 長期でシステムを運用している場合、移行のリスクやコストを避けるため● ゲーム開発や映像制作など、バイナリファイルを多用するプロジェクトでは、Perforce が適しているため
図tetoblog.「【Git】インデックスとは?【図解でわかり易く解説】」. https://tetoblog.org/2021/06/git-index/,(参照2023-04-10)
GitHub ってなに?● 分散型バージョン管理システム Git を中核とした Web 開発プラットフォーム● リモートリポジトリの提供によるソースコード管理、CI / CD などの拡張的機能を備えている● 類似に GitLab や BitBucket などがある
GitHub を利用した開発の流れ
GitHub を利用した開発の流れ1. アサインされたイシューに対して作業ブランチを作成2. 作業ブランチに commit、push3. PR 作成、レビュー、マージdevfeatブランチPull Request
1. アサインされたイシューに対して作業ブランチを作成● 基本的には 1つのイシューに 1つのブランチイシューの File Changed が多くなってしまいそうな時は 2回に分けることも● ブランチ名について○ HiPro Direct の場合...○ 新機能の場合は feat/{issue番号}/{機能に関するワード}(ex : feat/1324/create_user)○ 修正タスクの場合は fix/{issue番号}/{機能に関するワード}○ プロジェクトによるので、プロジェクト配属後に確認しましょう!
2. 作業ブランチに commit、push● 何か 1つが動作する状態で commit すると良い● commit 数が多い/ Git の草の色が濃い ≠ 偉い● commit 数が評価対象になることはありません!
2. 作業ブランチに commit、push● commit メッセージはわかりやすいものにGood 👍「feat : ユーザー登録機能実装」「fix : ログイン時のバグ修正」Bad 😞「asdf」、「hogehoge」、「test」 など● Prefixを付けることが多い新機能なら feat、修正なら fix など参考 : https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#typeプロジェクトによっては絵文字を付けたりする
2. 作業ブランチに commit、push● push は慎重に○ push 先が間違っていないか確認しましょう○ force push は基本的にしない ○ が、例外もある○ コンフリクト解消する時や rebase した時
3. PR 作成、レビュー、マージ● PR は、基本的には issue の要件が完成したら作成します● 内容共有などのために他の人に見せたい時は Draft 機能を使いましょう● PR Open = 完成して見てもらえる状態である と考えましょう追加変更が必要になったら?● 追加の変更が必要になった場合は別 PR にするのがいいかも○ 変更が大きすぎてレビューコストが増えることを避けるため○ PR の対応範囲(スコープ)を明確にするため
3. PR 作成、レビュー、マージPR 作成時にやること1. ルールに沿ったタイトルをつける2. merge 先ブランチを指定する3. 詳細を記入する○ 対応する issue は何か?○ 具体的にどのような変更をしたのか?○ 動作確認はどのようにしたのか?4. (あれば)レビュアーに対してコメントを書くPR のルールはプロジェクトごとに異なるので配属時に確認しましょう!
3. PR 作成、レビュー、マージレビューで ChangeRequest がきた!● 落ち着いて指摘内容を確認し、修正していきましょう● 相手の指摘自体が間違っていることもあるため、言われたまま修正するのではなく、自分で考えて直しましょう● レビュアーが偉い or 絶対正しいなどはないので自信を持って確認しましょう
3. PR 作成、レビュー、マージレビューで ChangeRequest がきた!● 修正が終わったら変更した旨をレビュアーに返信+ Reviewers の🔁をクリックしましょう● 「修正しました!+ commit の URL 」としておくと親切です● 文字でのやり取りだと冷たく感じることがあります。コメントする際の言葉遣いは気をつけましょう● たくさんコメントがつくことは恥ずかしくないどんどん CR 受けましょう!
Approveされた!● merge するには 2人の Approve が必要な場合が多い● merge は Auto-merge /レビュアーがマージ/ Author がマージ…( PJ による)● merge の種類はいくつかあります○ Create a merge commit○ Squash and merge○ Rebase and merge● プロジェクトによってどの merge にするかは異なる場合があるため先輩に確認しましょう!
作業していて困った時は積極的に質問しましょう!
質問する際に気をつけること● どの issue に関する質問なのか(ex. issue301 のXXの API 追加について)● 何を解決しようしたのか(ex. XXができるような処理を書こうとした)● 何で詰まったのか(ex. ZZというエラーが出てうまくいかない)● 自分で既に試したことは何か?(ex. このサイトにある方法を試してみた)● どう助けて欲しいのか?(ex. エラー見て欲しい、いい実装例を知りたい)● 必要に応じて画面共有すると伝わりやすいです
レビュアーになったときは
コードと動作の両方の確認を● comment をつける時はコード引用形式で書きましょう● Change Request なのかそこまでではない意見 (in my opinion) なのか明確に「must」「imo」「nits」「Q」など● 指摘の際は「なぜ」「どのように」を明確に書きましょう● コメントは受け手にはきつい言葉のように捉えられやすいので言葉選びには気をつけましょう
コードと動作の両方の確認を● 良い実装があれば褒め、修正指摘も丁寧な言葉遣いを心がけましょうGood 👍「xxの箇所はyyとなってしまうのでzzのように修正をお願いします(参考文献あればリンク)」「ここの実装良いですね」Bad 😞「xxだとyyしちゃいますけど大丈夫ですかね?(嫌味ぽい)」「全然ダメ、書き直して」「絶対zzしたほうがいいと思うので修正して (ソースなし)」● 「自分の方が詳しいアピール」をする場ではないことを忘れずに…
後半たのしい Git ハンズオン!🎉
ハンズオンの目的● よく使う Git 操作を、Git の基本的な仕組みとともに学ぶ● なんとなく Git を使っている状態から抜ける● GUI と CLI を使いこなせるようにする
ハンズオン準備
repository を fork しよう前提条件● GitHub で SSO が完了している● 使用している PC から Git に SSH できる状態にあるGit SSH について● ここをみてねGitHub に SSH で接続する - GitHub Docs
repository を fork しよう1. https://github.com/pcae/2023-git-training を開く2. 右上の [ fork ] をクリックし、自分の名前を追加して fork する
repository を fork しよう1. GitHub から SSH を選択して URL をコピー2. 適当なディレクトリに git clone <コピーしたURL>
ツール準備GUI + CLI を併用しながらハンズオンを進めていきます。● GUI:VSCode 拡張機能 Git Graph - Visual Studio Marketplace● CLI:ターミナル or VSCode内ターミナル
ハンズオンの流れGit の概念や仕組み理解1. branch とは2. HEAD とは3. commit とは4. merge とは5. conflict したときどうする?6. rebase とは7. その他コマンド
1. branch とは
さて問題です
branch はいくつでしょう?masterQiita.「図解! Gitのブランチ・ツリーをちゃんと読む」. https://qiita.com/jesus_isao/items/2a0495c973a4c911c2cc,(参照2023-04-10)
branch はいくつでしょう?masterQiita.「図解! Gitのブランチ・ツリーをちゃんと読む」. https://qiita.com/jesus_isao/items/2a0495c973a4c911c2cc,(参照2023-04-10)答え:1 つ
branch はいくつでしょう?mastersato_devtanaka_devQiita.「図解! Gitのブランチ・ツリーをちゃんと読む」. https://qiita.com/jesus_isao/items/2a0495c973a4c911c2cc,(参照2023-04-10)
branch はいくつでしょう?mastersato_devtanaka_dev答え:3 つQiita.「図解! Gitのブランチ・ツリーをちゃんと読む」. https://qiita.com/jesus_isao/items/2a0495c973a4c911c2cc,(参照2023-04-10)
branch とは commit を指し示すポインタである
確かめるための準備として、まずはbranch を確認、作成してみましょう
現在の branch を確認してみよう1. git branch or GUI で確認する(●が白抜きになっている)2. CLI でグラフィカルに見たい方は以下のコマンドgit log --oneline --decorate --graph --all
branch を作ってみよう1. git branch test1 を実行し、test1 ブランチを作成2. git log --oneline --decorate or GUI でブランチの状態を確認する3. 同一コミットの横に branch名が増えている (が、枝分かれはしていない)
● main, origin/main, origin/HEAD, test1 は全て 8d50a5c の横にあるこれだけではまだ branch がポインタであることがわかりづらいと思うので、.git/refs/heads ディレクトリを確認していきます。● .git/refs/heads ディレクトリって?リポジトリ内のすべてのローカル ブランチを定義しているフォルダ。heads ディレクトリ直下に各ブランチ名のファイルが格納されており、各ファイル内にはコミットハッシュがあります。branch とは commit を指し示すポインタである...?
1. .git/refs/heads/mainフォルダを catコマンドで開いてみるcat .git/refs/heads/main2. 出力された文字列が commit 番号と同じになっていることを確認する3. test1 も同様に catコマンドで開いてみるcat .git/refs/heads/test1.git/refs/heads/ を確認しよう
test1 に checkout して commit しよう1. git checkout test1 を実行2. test1 に commit してみる○ test/test.md と README.md に適当な文字を追加してください○ 変更を保存したら、fix: README.mdとtest.md修正 というcommit メッセージで commit してください3. git log --oneline --decorate or GUI で変化を確認4. test1 の位置が移動している
もう一度 .git/refs/heads/ を確認しよう1. test1 をもう一度 catコマンドで開いてみるcat .git/refs/heads/test1test1 ファイルの commit ハッシュも変わっているbranch とは commit を指し示すポインタである!
● branch とは commit を指し示すポインタである○ branch は枝という意味だけれど実態はポインタ○ branch を作ると、どのコミットを指し示すかのポインタが作られる● .git/refs/heads ディレクトリで定義されている「 branch とは」まとめ
Git-flow って?Git におけるリポジトリの分岐モデルであり、ルールのこと。各ブランチを定義することで、複数人での開発時に好き勝手にブランチが作成され混乱することを防ぐ。master (main) : 本番用ブランチdevelop : 開発用ブランチfeature : issue単位 (develop にマージ)release : リリース単位 (develop から切る)hotfix : 緊急修正 (master から切る)Developers IO.「Git-flowをざっと整理してみた」.https://dev.classmethod.jp/articles/introduce-git-flow/,(参照2023-04-10)
v1.0.0
2. HEAD とは
HEAD とは 現在作業中の commit を指し示すポインタである
どこかで聞いたような...branch は複数ある ↔ HEAD は常に 1つ
確認してみよう!
.git/HEAD を確認してみよう1. .git/HEAD が実態なので見てみる2. test1ブランチで cat .git/HEAD…commit ハッシュじゃない🤔branch ファイルを ref (参照)しているHEAD → branch → commit
checkout して .git/HEAD を確認してみよう1. main に checkout してみましょう2. git checkout main3. cat .git/HEAD中身が変わりました 😲つまり、checkout は HEAD を任意の commit に動かすことである
1. この状態で git branch してみるHEAD detached at 😲このまま commit すると checkout した瞬間その commit は宙に浮いてしまうので、commit に checkout した場合、そこから branch を切ってから作業しましょう。HEAD は branch を ref して commit を指している状態にしておく2. git checkout main で main ブランチに移動しておきましょうですが…注意
commit を指しているところを見てみよう1. checkout は HEAD を任意の commit に動かすことである→ commit 自体にも checkout できる!2. git checkout d03acbae (initial commit のハッシュ)3. cat .git/HEAD で HEAD ファイルを確認するcommitを指していますね 😌
「 HEAD とは」まとめ1. HEAD とは現在作業中の commit を指すポインタである2. checkout は任意の commit に HEAD を動かすこと3. HEAD は branchファイルを介して commit を指し示すことで作業ブランチを認識するitstaffing エンジニアスタイル「第19話 detached HEAD 状態って何?ブランチがない状態を解決する方法」.https://dev.classmethod.jp/articles/introduce-git-flow/,(参照2023-04-10)
3. commit とは
commit ってなんなんだろう
commit とは● ファイルの変更を記録したもの● commit オブジェクトに tree オブジェクトを保持している● スナップショット(※)を tree オブジェクトを介して参照している※ 差分ではない
とりあえず見てみる1. GUI でコミットをクリックして見てみる
commit の中身を見てみよう1. .git ディレクトリには Git オブジェクト(.git/objects)が入っており、それらが commit の実体2. .git/objectsを見てみる3. cd .git/objects を実行 → ls -R を実行commit 番号名のファイルを格納したフォルダが複数ある
1. git cat-file -t <フォルダ名 + commitハッシュ頭2桁 (c6a1)>でファイルの type を確認できるcommit / tree / blob のどれかが表示されますcommit の中身を見てみよう
commit / tree / blob● commit : tree オブジェクト番号、親 commit、author などの情報を持つ● tree : ディレクトリのようなもの。blob ファイルが格納されている● blob : Git 管理対象のスナップショット
commit と出力されるものを開いてみる● git cat-file -p c6a1 で開いてみる ( -p は pretty-print のこと)VSCode で見たものと似ていますね 😲● tree オブジェクト、parent (親コミット)、author、commit メッセージが含まれている
tree オブジェクトを見てみよう1. git cat-file -p < tree ハッシュ上4桁 (92a8) >2. blob も開くgit cat-file -p ファイルの中身が見えます 👀
commit は差分ではなくスナップショット1. git log --oneline --decorate --graph --all or GUI でfeat: test.md作成 の commit ハッシュを確認します2. git cat-file -p <1で確認したハッシュ> を実行
commit は差分ではなくスナップショット1. git cat-file -p < tree ハッシュ > で中を見てみますREADME.mdはこの commit では変更していないはず 😐commit は差分ではなくスナップショットであるため、commit した時のファイルの状態を丸ごと持っていますもっと詳しく知りたい方はこちらを参考にしてください 👇https://github.blog/jp/2021-01-06-commits-are-snapshots-not-diffs/
「parent (親 commit) 」について1. commit は常に親を指すポインタを持つ (first-commit は例外)2. git log やGUIで確認してみる親を持つことにより、差分管理を可能にし、さらに改ざんも難しくしている
「commit とは 」まとめ● commit はスナップショットを tree を介して参照している● tree はディレクトリ、blobはファイルの内容● commit は「差分」ではなく「スナップショット」● 初回 commit を除いて、全ての commit は親を持つ
ここまでをまとめた図
4. mergeとは
● branch の変更を統合する操作のこと● 2つの branch の最新コミットを親とする merge commit が作成されるmerge とは
下準備1. git checkout main を実行し、cd ../../ でgit-training-[自分の名前]ディレクトリ直下に移動しましょう2. test フォルダ直下に test2.md ファイルを作ってコミットしておきましょう3. このような状態になっていれば OK 👌
merge してみよう1. …の前に、現時点での commit の状態をスクショしておきましょうmain ブランチと test1 ブランチの commit 番号が確認できれば良いのでGUI でもCLI git log --oneline --decorate --graph --all でも OK です!2. main ブランチにいることを確認して、git merge test1 を実行し、test1 を main ブランチに merge しましょう
branch の状態を確認する1. 先ほどのスクショを確認し、test1 ブランチと main ブランチそれぞれのcommit 番号が変わっていないことを確認しましょう2. main ブランチには親ブランチが 2つあることを確認しましょう3. merge とは、取り込み先のブランチに新しい commit を作ること
5. conflict した時どうする?
conflict って?● 異なるブランチで行われた変更が同じ箇所に重なる場合に発生する問題● Git がどちらを優先して良いかわからなくなり起こる● ユーザーが手動で競合を解決してあげないといけない
conflict してみよう1. sample_branch1 ブランチに checkout git checkout sample_branch12. main ブランチに checkout git checkout main3. git merge sample_branch1
VSCode を使って解消していきます1. source control タブをみながら編集していく2. current (HEAD) と Incomming それぞれを見比べながら修正する
見方addされていない変更(conflictした変更) commitされる予定の変更
conflict 解消方法1. ❕はコードの競合を表している2. コード上の競合はどちらの変更を取り込むか選ぶ or 手動で修正3. ファイルの削除の変更は、削除する or 追加するかを決める4. 変更内容を add して commit現branchの変更 取込ブランチの変更
merge コミットが作られた
わからなくなった時は1. どう変更すればいいのかよくわからなくなることがある2. そんな時は素直に merge を取り消し、やり直そう3. conflict 解消中は git merge --abortmerge しちゃった後は git reset --hard HEAD で merge 前に戻ることができますよくわからないけど merge!しないようにしましょう 😓落ち着いてよく変更を見比べましょう 😉
「conflict した時どうする?」まとめ● conflict とは、異なる branch で行われた変更が同じ箇所に重なる場合に発生する問題● conflict を解消した場合はその変更を含んだ commit ができる● わからなくなった時はconflict 解消中は git merge --abortmerge 後は git reset --hard HEAD で merge 前に戻れる● できるだけ conflict は起こさないようにしましょう 😮
gitコマンド解説● fetch : リモートブランチの履歴だけ取り込むこと● pull : リモートブランチを追跡ブランチに取り込むこと● stash : コミットしていない変更を退避させること● squash : 複数のコミットをまとめ、新しいコミットにすること● log : コミットログを確認すること● reflog : Git 操作全てのログを確認すること● reset : 任意の HEAD@XX まで branch の状態を巻き戻すこと
6. rebase とは
● ある branch の変更履歴を別のブランチの上に移動する操作のこと● merge と同様にブランチ間で変更内容を統合する方法の一つではあるが、違いがいくつかあるrebase とは?
merge● 2つの branch の最新コミットを親とする merge commit が作成される● 統合した commit のハッシュ値は変更されない (非破壊的変更)● コミット履歴が複雑になりがちmerge と rebase の違いrebase● ある branch の変更履歴を別ブランチの上に移動し、直線的なコミット履歴を作成● 新しい commit が作成され、commitのハッシュ値が変更される(破壊的変更)● コミット履歴が整理され、わかりやすくなる
git pullgit fetch + git mergegit pull と git pull --rebase の違いgit pull --rebasegit fetch + git rebase
rebase で注意すること● 現在の branch には破壊的変更が加えられ、commit も新しくなる→ remote に push する際には force push が必要になる● 自分の作業ブランチ以外では行わない = public ブランチでは行わない● レビュー開始後は force push しないforce push する前にそのブランチに checkout している人がいる場合、その人は git pullで差分を取り込むことができず、 git reset をする必要が出てくるためgit resetコミットした内容を取り消すためのコマンド。soft、mixed、hardなどのオプションがある。指定しなかった場合はデフォルトで mixed になる。soft = HEAD、mixed = HEAD + インデックス、hard = HEAD + インデックス + ディレクトリ
下準備1. main を push しておきましょう2. sample_branch2 に checkout しましょう
rebase の実行1. commit 番号がわかるようにスクリーンショットを撮っておく2. git pull --rebase origin main3. branch の状態をみる
何が起きていたのか?1. git reflog で操作履歴をみる2. main に checkout した後、sample_branch2 ブランチの commit を一つずつ追加 (pick) している
流れ1. main にチェックアウト (rebase start)2. sample_branch2 の commit を一つずつ追加 (pick)commit され直すことになるので commit 番号が変わる3. sample_branch2 のポインタの向き先は最後に pick された commit になり完了sample_branch2のcommit mainのcommit
「rebase とは」まとめ● merge と同じく変更内容を統合するためのもの● 直線的なコミット履歴を作成できる● commit のハッシュ値が変更される (破壊的変更)● 自分の作業ブランチ以外では行わない● レビュー開始後は force push しない● git pull = fetch + merge、git pull –-rebase = fetch + rebase
7. その他コマンド
revert とは● 特定の commit の逆のコミットをする行為● reset と違い新しく commit が増える● 修正したことが記録に残る
cherry-pick とは● 他ブランチの任意のcommitを自ブランチに取り込む行為● 英語の慣用表現で「都合のいいものだけ取る」という意味
お疲れ様でした 🎉