quyennv.com

Senior DevOps Engineer · Healthcare, Singapore

Git (SCM) Best Practices

#git#scm#version-control#best-practices#devops#collaboration

Git is the dominant source control management (SCM) tool. Using it well keeps history readable, merges smooth, and CI/CD reliable. This post outlines best practices for commits, branches, and workflows that scale from solo work to large teams.

Commit messages

  • One logical change per commit — Easier to review, revert, and bisect. Avoid “fix stuff” or dumping a whole feature in one commit.
  • Write for humans — Future you and your team will search and read these. Good messages explain why as well as what.
  • Conventional format — A common pattern:
<type>(<scope>): <short summary>

[optional body: details, rationale, breaking changes]
[optional footer: Refs #123, BREAKING CHANGE: ...]
TypeUse for
featNew feature
fixBug fix
docsDocumentation only
refactorCode change, no fix/feat
testAdding or updating tests
choreBuild, tooling, dependencies

Examples: feat(auth): add SSO login, fix(api): handle null pagination. Many teams enforce this with commitlint or branch protection.

Branching strategy

Choose a model that fits your release cadence and team size.

StrategyBest forMain idea
Trunk-basedSmall teams, frequent deploysShort-lived branches off main; merge often.
Git FlowVersioned releases, hotfixesLong-lived develop + release/*, hotfix/*.
GitHub FlowSingle production branchmain is deployable; feature branches only.

Practical tips:

  • Short-lived branches — Integrate with main (or develop) at least daily to avoid painful merges.
  • Descriptive namesfeat/order-checkout, fix/login-timeout, docs/api-readme; avoid john-branch or test2.
  • Delete merged branches — Keeps the branch list meaningful; the history is already in main.

Before you commit

  • Review your diffgit status, git diff, and git diff --staged. Don’t commit commented-out code, debug prints, or unrelated files.
  • Run checks locally — Linters, tests, and formatters. Fix failures before pushing so CI stays green.
  • Keep secrets out — Never commit passwords, API keys, or tokens. Use .gitignore and secret scanners; if leaked, rotate immediately and use git filter-repo or BFG to remove from history if policy requires it.

.gitignore and hygiene

  • Ignore by default — IDE config (e.g. .idea/), OS files (.DS_Store), build outputs (dist/, node_modules/), env files with secrets (.env, .env.local).
  • One repo, one .gitignore — Prefer a root-level .gitignore (and maybe a few in subdirs for large monorepos). Document any “ignore by convention” in the README.
  • Don’t commit generated artifacts — Binaries, compiled assets, and logs should be produced by build or run, not stored in Git (unless you have a clear policy, e.g. release binaries in a separate repo).

Pull requests (merge requests)

  • Small, focused PRs — Few hundred lines and a clear purpose. Easier review and fewer merge conflicts.
  • Describe context — What problem it solves, how to test, and any follow-ups. Link issues/tickets.
  • Respond to review — Address comments or discuss; re-request review after updates so the reviewer knows to look again.
  • Squash or no squash — Either keep a clean linear history with “Squash and merge” or preserve full history with “Merge commit”; pick one and stick to it in the project.

Rebase vs merge

ApproachWhen to useTrade-off
MergeIntegrating feature branchesPreserves history; can be noisy.
RebaseUpdating your branch onto mainLinear history; never rebase shared branches.

Rule of thumb: Rebase your own branch onto main before opening a PR so the diff is up to date. Do not rebase branches others are using (e.g. shared develop); use merge there to avoid rewriting published history.

Tags and releases

  • Semantic versioning — Tag releases as v1.2.3. Use annotated tags: git tag -a v1.2.3 -m "Release 1.2.3".
  • Tags in CI/CD — Many pipelines build or deploy only when a tag is pushed (e.g. v*). Keep tag names consistent so automation is simple.

Summary

AreaBest practice
CommitsOne logical change; conventional message format.
BranchesShort-lived; descriptive names; delete after merge.
Before commitReview diff; run tests/lint; no secrets.
.gitignoreIgnore build output, IDE, OS files, and secret files.
PRsSmall and focused; good description; respond to review.
RebaseRebase your branch onto main; never rebase shared branches.
ReleasesAnnotated tags (e.g. v1.2.3) and consistent naming.

Adopting these practices keeps your Git history clear and your SCM a solid base for collaboration and automation.

← All posts

Comments