良いGitコミットとは – コミットのベストプラクティス

English follows Japanese. 英語の文章は後半にあります。

こんにちは。エンジニアのファットです。

チームで開発する場合、Gitのようなバージョン管理システムはコードベースの変更を管理するために不可欠です。

弊社のGitワークフローはなかなか良い感じだと思っています。
多くのステップがありますが、いくつかの自動化ツールを使用することで、快適に使用できています。

良いGitワークフローを設定した後は、良いコミットと良いプルリクエストが何であるかを定義する必要があります。

良いプルリクエストの詳細については、今後どこかの記事で詳しく説明したいと思っていますが、一般的にプルリクエストについては、あまり多くの変更を含まない方が良いです。数百行の変更は多すぎです。理想的には、プルリクエストには1つのコミットだけが含まれるべきです。

この記事では、残ったもう1つの方。
良いコミットの特徴について説明します。

なぜ良いコミットが重要なのか?

エンジニアリングチームにとって、良いコミットの実践は、コラボレーションの向上、デバッグの容易化、そしてコードの保守性の向上につながります。
良いコミットは、過去の遺産の理解を大いに助け、コードレビューをスムーズなものにしてくれます。

良いコミットの特徴

アトミックな変更

良いコミットはアトミックであるべきです。つまり、単一の論理的な変更を表すべきです。
理解しやすく、必要に応じて元に戻すことが容易になります。

明確で記述的なメッセージ

コミットメッセージは、コミットが何を行うかを明確に記述するべきです。これにより、チームメンバーがコードを読まずに変更内容を理解できます。

ShareWisプロジェクトでは、コミットメッセージの最初の行(コミットタイトルとして扱われる)にプロジェクト管理ツールとして使っているJiraのチケットIDを含めることにしています。これにより、コミットの追跡やチェリーピッキングが容易になります。

良いコミットの例:

  • SWWB-6685 – Refactor PaymentService: Course Subscription by Stripe Part
  • SWWB-6685 – Add new StripeService::CourseSubscriptionPurchase
    • この新しいサービスは、PaymentIntentを使用してコースサブスクリプションの購入を処理し、失敗した場合にトランザクションの「ロールバック」を可能にします(SWWB-xxxx の箇所はJiraのチケットIDです)。
  • SWWB-6685 – Add RSpec Tests to StripeService::CourseSubscriptionPurchase

適切なスコープの変更

コミット内の変更は適切なスコープであり、大きすぎないようにするべきです。無関係な変更を1つのコミットに混在させるのは避けましょう。

効果的なコミットメッセージの書き方

コミットメッセージの構造

よく構造化されたコミットメッセージは、通常、短い要約(50文字以内)と必要に応じて詳細な説明を含みます。

例:

JiraのチケットID - アプリケーションにユーザー認証を追加
- ログイン機能を実装
- ユーザー登録を追加
- 既存のユーザーモデルと統合

良いコミットメッセージと悪いコミットメッセージの例

  • 良い例:JiraのチケットID – ユーザー認証のバグを修正
  • 悪い例:Fixed stuff

明確なメッセージを書くためにチームで心がけていること

  • 命令形を使用する(例:”Added feature”ではなく”Add feature”)。
  • 簡潔でありながら記述的であること。
  • 変更の理由が明確でない場合は、「なぜ」を説明すること。

良いコミットを行うためのベストプラクティス

コミットするタイミング

論理的な作業が完了したときにコミットする。各コミット後にコードが正常に動作することを確認する。コミットがテストを壊した場合は、問題を修正しコミットを修正する。

コミットの頻度

小さく頻繁にコミットする。これにより、変更を追跡しやすくなり、プロジェクト履歴で特定の変更を見つけやすくなります。

大きな変更の扱い

大きな変更を小さく管理しやすいコミットに分割する。これにより、プロジェクト履歴がクリーンで理解しやすくなります。

Git GUIツールを用いたGitワークフローの改善

クリーンで効果的なGit履歴を維持するためには、規律あるワークフローに従うことが重要です。すべての変更を一度にステージングに配備するgit commit -Aを使用する代わりに、各変更を個別にレビューする時間を取ります。実装や修正が完了した後、変更を慎重に確認し、各チャンクが正しく動作することを確認します。このレビュープロセスは、早期にミスを発見し、各コミットが意味のあるものであることを保証します。

GitKraken、SourceTree、VS Codeの組み込みツール、または私の場合はSublime MergeなどのGit GUIツールを使用することで、このプロセスを容易にできます。これらのGit GUIツールは、変更を視覚的に確認し、選択的にステージングに配備し、詳細なコミットメッセージを書くためのインターフェースを提供します。小さく論理的なチャンクで変更をステージングに配備することで、他の人が理解しやすくレビューしやすいクリーンな履歴を作成できます。この実践は、各コミットが単一の論理的な変更を表すという原則にも合致しています。

この慎重なステージング配備とコミットのアプローチを採用することで、コードの品質が向上し、チームのコラボレーションが強化されます。これにより、各コミットが意味のあるものにでき、プロジェクトの履歴がクリーンで情報豊富なものになります。

まとめ

良いコミットのためのプラクティスを守ることは、コードベースをクリーンで効率的に保つために重要です。小さく明確な変更を行い、良いコミットメッセージを書くことで、チームの作業がよりスムーズになります。
各コミットはコードを正常に動作させるべきであり、後で問題が発生しないようにするべきです。これらのプラクティスは、コードレビューやデバッグを容易にし、コードの全体的な品質を向上させます。

ShareWisでは、これらのベストプラクティスをGitワークフローに取り入れることで、チームとしてより効果的に作業し、高い基準のコードを維持できます。良いコミットは、健全なコードベースと生産的な開発環境の基盤です。各コミットを大切にし、プロジェクトをスムーズに進行させましょう。

(ファット)


What is a Good (Git) Commit?

In software development, version control systems like Git are essential for managing changes to the codebase. At ShareWis, we have a good Git workflow. It has many steps, but with some automation tools, it is still comfortable to use. After setting up a good Git workflow, we need to define what makes a good commit and a good pull request.

For pull requests, it’s best if they don’t include too many changes. Avoid having too many files with hundreds of lines of changes. Ideally, a pull request should have only one commit. We will discuss more details about good pull requests in a future post. So, what is left to work effectively when collaborating as a team is to have a good commit. In this article, we will talk about the characteristics of a good commit.

But why is a good commit important?

  • For engineering team, good commit practices lead to better collaboration, easier debugging, and more maintainable code. Additionally, well-crafted commits can greatly enhance the understanding of the project’s history and facilitate smoother code reviews.

Characteristics of a good commit

  • Atomic Changes
    • A good commit should be atomic, meaning it should represent a single logical change. This makes it easier to understand and revert if necessary.
    • Atomic changes contain only one feature, refactor, fix, etc.
  • Clear and Descriptive Messages
    • The commit message should clearly describe what the commit does. This helps team members understand the changes without having to read the code.
    • For ShareWis projects, the commit message—specifically, the first line (treated as the commit title)—should contain the JIRA ticket ID, such as SWWB-XXX or FDT-YYY. This practice aids in easy tracking and cherry-picking of commits.

Good commits with Title:

Commit 1:
SWWB-6685 – Refactor PaymentService: Course Subscription by Stripe Part

Commit 2:
SWWB-6685 – Add new StripeService::CourseSubscriptionPurchase

This new service handles the Course Subscription Purchase using PaymentIntent, allowing for transaction “rollback” if a failure occurs.

Commit 3:
SWWB-6685 – Add RSpec Tests to StripeService::CourseSubscriptionPurchase

  • Properly Scoped Changes
    • Changes in a commit should be properly scoped and not too large. Avoid mixing unrelated changes in a single commit.

Writing Effective Commit Messages

  • Structure of a Commit Message
    • A well-structured commit message typically includes a short summary (50 characters or less), followed by a more detailed description if necessary.

    Example:

    SWWB-XXX – Add user authentication to the application

    • Implemented login functionality
    • Added user registration
    • Integrated with the existing user model
  • Examples of Good and Bad Commit Messages
    • Good: FDT-XXX - Fix bug in user authentication
    • Bad: Fixed stuff
  • Tips for Writing Clear Messages
    • Use imperative mood (e.g., “Add feature” instead of “Added feature”).
    • Be concise but descriptive.
    • Explain the “why” if the reason for the change isn’t obvious.

Best Practices for Making Commits

  • When to Commit
    • Commit frequently but only when a logical piece of work is complete.
    • Ensure that your code still works after every commit. If a commit breaks some tests, fix the issues and amend the commit.
    • Also ensure your commit passed the Rubocop checks (or any other Linters for JS, Python, …), if violated some Rubocop rules, fix them and amend the commit. In the future, alongside Rubocop, we may add some other useful plugins to enhance our code quality and reliability such as Brakeman (security vulnerabilities checks), bundler-audit (Checks for vulnerable versions of gems), bullet (N+1 queries, …), Reek (detect code smells), rails_best_practices, …
  • How Often to Commit
    • Make small, frequent commits. This makes it easier to track changes and find specific modifications in the project history.
  • Handling Large Changes
    • Break down large changes into smaller, manageable commits. This keeps the project history clean and understandable.

Recommended Git Workflow

  • To maintain a clean and effective Git history, it’s crucial to follow a disciplined workflow. Instead of using git commit -A, which stages all changes at once, take the time to review each change individually. After finishing your implementation or fix, go through the changes carefully, checking each chunk to ensure it is correct and necessary. This review process helps catch mistakes early and ensures that each commit is meaningful and well-structured.
  • Using Git GUI tools like GitKraken, SourceTree, the built-in tools of VS Code, or in my case, I’m using Sublime Merge. Using these Git GUI tools can make this process easier. They provide a visual interface for reviewing changes, staging them selectively, and writing detailed commit messages. By staging changes in small, logical chunks, you create a clearer history that is easier for others to understand and review. This practice also aligns with the principle of making atomic commits, where each commit represents a single logical change.
  • Adopting this careful approach to staging and committing not only improves code quality but also enhances team collaboration. It ensures that every commit is deliberate and that the project’s history remains clean and informative.

Conclusion

Following good commit practices is important for keeping our codebase clean and efficient. By making small, clear changes and writing good commit messages, we help our team work better together. Each commit should keep the code working to avoid problems later. These habits make code reviews and debugging easier and improve the overall quality of our code. At ShareWis, using these best practices in our Git workflow will help us work more effectively as a team and keep our code at a high standard. Good commits are the foundation of a healthy codebase and a productive development environment. Let’s make every commit count and keep our projects running smoothly.