序
この記事は
の続きである。
今回は一般ユーザー向けではなく、主に業務としてプログラミングを行う者にとってのGitの話をする。
なので、これまでの記事で日常使いのために読んできた人には無用な話だ。
そして、この話には黄金律はない。
知識は純然たる知識だが、文化はそれぞれ異なる、ということを念頭に置いてほしい。
チーム作業としてのGit
GitはそもそもがLinuxの開発のために生まれたものである。
Gitは非常に大きなコミュニティであり、多くの開発者が参加している。
ただし、その開発手順は基本的にメーリングリストである。
LinuxはGitHubを使っているが、それは結果的な話であって、GitHubありきでGitが作られたわけでも、最初からGitHubを使っていたわけでもない。
GitはLinuxの開発におけるワークフローを念頭に置いて作られたが、GitHubはそうではない。
Gitは分散型ではあるが、大規模な共同開発におけるGitはSubversionとあまり変わらない使い方になる。
つまり、どこかにオリジンとなるGitリポジトリをホストし、書き込み権限を持つ人がそのリポジトリを更新する。
通常、その書き込み権限を持つ人をcommitterと言う(オリジンリポジトリにcommitするから)。
実際そのように運用する場合は、contributerはリポジトリをクローンして更新し、diffからpatchを作る。
そして、patchをcommiterに渡して、acceptされたらcomitterがそのpatchを取り込む。そして、その取り込んだ結果をpushする、という流れになる。
これは古からある格調高い手順だが、だいぶめんどくさい。主にcommitterの負担が大きい。
だから、分散型の特徴を活かして別のスタイルを取り入れよう、というのがGitHubのやり方だ。
別に選択肢はGitHubには限らないのだが、チーム開発で生Gitを使う選択肢は滅多にとられない。
GitホスティングソフトウェアはGitに備わる一部のモデルを無効にし、Gitホスティングソフトウェア経由でGitリポジトリを操作させることで拡張的なモデルを機能させる。
Gitホスティング
サービス
サービス名 | サービス主体 | 備考 |
---|---|---|
GitHub | Microsoft | 圧倒的に有名なGitホスティングサービス |
GitLab | GitLab | GitLabがGitLabを使って展開する。かなり有名 |
BitBucket | Atlassian | Atlassianのサービスを使っているなら有力選択肢となりやすい |
SourceForge | 开源中国 | 古参。Subversion, Mercurialもホスト。OSS向け |
Codeberg | Codeberg | Forgejoを使用したコミュニティベースのホスティングサービス。public/OSSリポジトリ向け |
Azure DevOps | Microsoft | Microsoft Azureのソリューションの一環 |
techpath | OpenGroove | Subversionにも対応 |
Gitea | CommitGo | Giteaを使った公式のホスティングサービス |
AWS CodeCommit | Amazon | あまり知られていないAWSサービスのひとつ。プライベートリポジトリ向け |
Cloud Source Repositories | GCPのソリューションのひとつ。プライベートリポジトリ向け |
ソフトウェア
サービス名 | 言語 | 備考 |
---|---|---|
GitLab | Ruby | GitHubライクな大型のGitホスティング実装 |
Gogs | Go | Goで書かれた軽量なGitホスティング実装 |
Gitea | Go | Gogsのフォーク |
Forgejo | Go | Giteaのフォーク |
GitBucket | Java | 多言語対応に強み |
Gitness | Go | 新しい実装。軽量志向 |
実際に触る可能性が高いもの
基本的に
GitHub > BitBucket > その他
である。
GitHubは圧倒的知名度を持っている。
知名度が高いが故に「GitHubを使っている」ということをアピールポイントとして使用する企業もある。
また、「GitHubでのチーム開発経験」を採用要件として挙げてくる企業も結構ある。
ユーザーが多いために連携機能などいろいろと充実しているメリットもある。
BitBucketはAtlassian製品であることが多い。
JiraやConfluenceを採用している企業は多いため、それらとの統合の観点から採用されやすい。
その他の中ではGitLabが人気。
中小企業やスタートアップでの採用例が多いらしい。
一方で大規模開発では(gitlab.comではなく)セルフホストのGitLabが採用されることもある。
それ以外はよっぽどでない限り、仕事として触る機会は稀。
基本的なフローと企業の文化
基本的なチーム開発フローはこのようになっていることが多い
- master(main)から作業ブランチを切る (だいたい命名規則は決まっている)
- 作業ブランチでの作業を終えたらブランチをpush
- 開発ブランチに対してプルリクエスト(マージリクエスト)を出す
- レビューを依頼する
- レビュワーによるレビューが通過したら、マージを行う
よくある差異:
- デフォルトブランチの名称。だいたいCTOが時流に従ってmain派か、古来の流儀に従ってmaster派かで決まる
- ブランチを切る元がmasterでないケースも結構ある。だいたい指定ブランチから切る
- レビュー依頼方法はかなりまちまち
- レビュー依頼の対象者はもちろん、最低限必要な承認の数も違うし、レビュー精度も違う
- レビューが正義・責任はレビュワーにありというところもあれば、レビュワーは最低限確認するだけだから責任を持って書けというところもある
- レビュー通過時に誰がマージするかもそれぞれある。場合によってはマージは責任者がやるからそこで差戻しになるというところも
この差異を含めて、一般的によくあるのレベルでしかない。
このあたりは、本当に企業によって全然違う。
プルリクエスト
これはGitホスティング固有の機能の中で最も大きい部分。
GitLabだけはマージリクエストと呼んでいる。
Gitそのものを使う場合、comitterにパッチを投げていたが、GitホスティングではGitホスティングソフトウェアがGitに対する書き込み権限を持っている。
その上でブランチの更新を許すかどうかはGitホスティングソフトウェアが制御しているわけである。
これにより、同一のブランチに対して開発者全員がpushできるようになっている。
一方で、ブランチに対してユーザーごと(ロールごと)に書き込み権限を設定し、正とされるブランチへの変更は権限を持っている人にしかできない(または手順として直接の更新を許さない)ということが可能である。
そこで、あるブランチから別のブランチに対するマージの依頼がプルリクエストである。
マージすること自体は普通にgit merge
でできることなので、これは「承認のための手順」である。
このため、プルリクエストは通常誰かしらによるレビューを求めるものである。
レビュワーはGitホスティングのシステム上のユーザーアカウントで指定する。
プルリクエストは生Gitのcommitterのように、「権限のある人に依頼する」という意味よりは、レビューを依頼するという意味のほうが大きい。
ちなみに、GitHubはGitHub上で直接マージができないため、GitHub上でマージしたいならプルリクエストを経由する必要がある。
BitBucketは権限さえあれば直接マージが可能だ。
このプルリクエストは全体で見れば他にも意味がある。
例えばissueやJiraのチケットと関連付ける1ことが可能であるということであったりだ。
しかも、これらはある程度自動化できる。
このため、開発そのものよりも管理の意味でプルリクエストが必要とされる側面もある。
ちなみに、GitLabはこのあたりのチケット管理なんかはGitLabの中でやるようになっている。
このため、GitLabはプロジェクトの中にリポジトリがある構造をしている。
CI/CD
ブランチへのpushやプルリクエストをトリガーしてテスト等を実行する。
本当はビルド、テスト、マージ、リリース、デプロイまでを一貫して自動化するのがCI/CDだが、実際はテストだけを自動で行うようになっていたりする場合が多い。
本当はテストはCI/CDは自動化のための1プロセスなので、デプロイするわけでもないのにテストだけ自動実行するというのはだいぶ本末転倒だけど、それが現実である。
テストするだけなら手元でテストした上でプルリクを出すべきであるはずなのだが、なぜかテストに通過できることを証明するためにテストが自動化されているのが現実なのだ……
まぁ、単にコードを書いて提出するだけの立場であれば、ブランチへのpushやプルリクエスト、マージなどは追加で何かしらのトリガーになっている場合がある、程度に覚えておけば良い。
よくある操作
- ブランチの切り替え -
git checkout your_branch_name
- 現在のブランチからブランチを切って切り替え -
git checkout -b your_branch_name
- 上流の変更を取り込み -
git pull
,git pull origin current_brnch_name
- 上流へ変更をアップロード -
git push origin current_working_branch_name
- 現在のブランチに別のブランチを取り込み -
git merge merging_branch_name
- 主に作業ブランチからさらに別の作業ブランチを切った場合に使う
- 作業中にmasterが更新されたときにmasterを取り込むことがあるけれど、これは競合解消がいる場合が多い
- プルリクエストの通ったブランチを捨てる -
git brnach -d done_branch_name
- プルリクエストのマージ時にブランチを削除する機能があったりするが、ホスティング側で消えるだけで手元は消えない
- 作業内容ごとブランチを捨てる -
git branch -D removing_branch_name
- プルリクエストを出す - ホスティング上で操作
- プルリクエストにコメントする - ホスティング上で操作
- プルリクエストをマージする - ホスティング上で操作
- ホスティング上のブランチを削除する - ホスティング上で操作 (おすすめ)
-
git push origin :removing_remote_branch_name
でもできる
-
- ホスティング上のブランチ削除をローカルに反映 -
git fetch -p
- masterからの変更を確認する -
git diff master
- 変更量を確認する -
git diff --stat
- コミットしていない変更を破棄してファイルを戻す -
git restore path/to/file
コミットコメントにWIP:
と入れると作業中だと認識される機能があったりする。人間的にも「これはまだ動かないコミットだ」と認識できるのでおすすめ。
巻き戻しを伴うやり方は関連知識も色々あったりするので、本記事では触れない。
A or B? を見てもらう
作業ブランチからA変更のブランチとB変更のブランチを切ってそれぞれで変更を加えてpushして見てもらうのが良い。
基本的にはプルリクエストしなくても差分は見えるので、ブランチのリンクを貼れば事足りる。
手元にあるファイルを無視させる
リポジトリのルールとしてグローバルに無視すべきファイルは.gitignore
に書くのだが、開発システム上自分の手元で発生するゴミを無視したい場合などは、.git/info/exclude
に書く。
書式は同じ。
*.orig
*.bak
.vendor/
node_modules/
チーム作業での注意
オートフォーマッター系はチームの規約として指定された設定に従う場合を除きオフにすること。
差分がすごいことになって読めなくなるし、自分のルールを適用してしまうとチームのルールに合致しないインデントのコードへの破壊的変更を行うことになってしまう。
タスク管理
単純なファイル共有よりはマシとはいえ、Gitは無軌道で野放図なファイル変更をサポートするわけではない。
作業内容が衝突しないように誰が何の作業・変更をしているのかということは管理されていなければならない。
Git視点で言うとこれは「外部で管理されていること」が必要とされているだけで、その方法をGit側で限定することはない。
一般的にはGitホスティングとの連携も踏まえた上でJiraやRedmineなどのチケット管理、もしくはGitホスティングのissue管理などと組み合わせて運用されることが多い。
この場合、必然的にブランチ運用もチケット、もしくはissueの単位を前提とした形に落ち着く。
Appendix: OSSへのコントリビュート
大前提: Contibuteの項目に従う。
よくあるのはこう:
- issueを立て、問題点と改善策を説明し、自身に実装する意思があることを表明する
- 承認され、assignされるのを待つ、またはコメントでコミュニケーションを取る
- リポジトリをforkし、開発ブランチをもとに実装を行う
- forkした開発ブランチからoriginの開発ブランチにプルリクエストを出す
- コミュニケーションを取り、必要なら修正し、マージされるのを待つ
解説記事
Qiitaに掲載したGit記事の裏話と、ちゃんとした説明 @Chienomi
-
Jiraと連携していればブランチ名に課題キーを入れるだけでトラッキングされる。大変便利。 ↩