Git & Workflow — Java-Specific Git Discipline

Git is universal; this file covers only the Java-specific bits and the workflow choices that matter in 2026. You already know git commit -m. What you need is the .gitignore that stops you from ever committing target/, the commit convention that makes your PRs credible, and the trunk-based-vs-GitFlow verdict.

The Java .gitignore — Copy This

Save as .gitignore in every new Java repo you create. This is the union of what IntelliJ, Eclipse, VS Code, Maven, and Gradle all leak:

# Compiled output
target/
build/
out/
bin/
*.class
*.jar
*.war
*.ear
*.nar

# Maven
.mvn/wrapper/maven-wrapper.jar
!.mvn/wrapper/maven-wrapper.properties

# Gradle
.gradle/
gradle-app.setting
!gradle-wrapper.jar
!gradle-wrapper.properties

# IntelliJ IDEA
.idea/
*.iml
*.iws
*.ipr

# Eclipse
.settings/
.project
.classpath
.factorypath
.apt_generated/

# VS Code
.vscode/
*.code-workspace

# NetBeans
nb-configuration.xml
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/

# macOS
.DS_Store

# Windows
Thumbs.db
Desktop.ini

# JVM crash logs
hs_err_pid*.log
replay_pid*.log

# Local env
.env
.env.local
application-local.yml
application-local.properties

# Logs
logs/
*.log

# Test output
test-output/
surefire-reports/
allure-results/

# JDK-managed
.sdkmanrc

# OS temp
*~
*.swp
*.swo

One rule: if you commit target/ once, junior devs on your team will copy your repo and think it’s fine. Enforce the .gitignore from Day 1.

Committing IntelliJ config safely

Some teams commit .idea/runConfigurations/ and .idea/copyright/ (both useful for team consistency) while ignoring everything else. If you need this:

.idea/*
!.idea/runConfigurations/
!.idea/copyright/

Global ~/.gitignore_global

Set up once per machine for personal noise:

git config --global core.excludesfile ~/.gitignore_global

Contents:

.DS_Store
.vscode/
.idea/
*.swp
*.swo
Thumbs.db

Keep repo .gitignore for project-specific noise; use global for OS/editor noise.

Commit Message Convention — Conventional Commits

Adopt Conventional Commits. Not because you’ll auto-generate changelogs (you probably won’t), but because it forces you to think about what you actually changed.

Format:

<type>(<optional scope>): <short summary>

<optional body — what / why, not how>

<optional footer — breaking changes, issue refs>

Types:

  • feat: — new feature

  • fix: — bug fix

  • refactor: — code change without behavior change

  • perf: — performance improvement

  • test: — adding/fixing tests only

  • docs: — documentation only

  • chore: — build config, deps, tooling

  • ci: — CI config

  • style: — formatting, whitespace

  • build: — build system

Examples:

feat(user-api): add pagination to GET /users

Previous endpoint returned unbounded list, causing OOM on production
tenant with 300k users. Adds page + size query params with 100 default.
Closes #142.
fix(auth): reject expired refresh tokens

RefreshTokenService was checking issuedAt instead of expiresAt.
Regression from #98. Added parameterized test.
refactor(order-service): extract PricingCalculator

No behavior change. Separates pricing rules from Order aggregate to
prepare for #201 (tax-per-region).

One line, imperative mood, present tense. “Add feature” not “Added” not “Adds”.

Commit hygiene rules

  1. One logical change per commit. If you git status and see 12 unrelated files, split.

  2. Never commit WIP or fix stuff. Use git commit --amend or git rebase -i.

  3. Commit tests with the code they test. Not a separate commit.

  4. Squash before merging PR. History should read like a book of features, not a diary.

Branching Strategy — The 2026 Verdict

Trunk-based development won. In 2026, most modern Java shops (including most Indian product companies — Zoho, Freshworks, Razorpay, PhonePe, Swiggy, CRED) use short-lived feature branches merged to main daily or several times a day.

GitFlow (with develop, release/, hotfix/ branches) is now considered overkill for ~90% of projects. It survives in:

  • Regulated enterprises (banking, healthcare) where release cadence is monthly+

  • Some Infosys/TCS/Wipro legacy programs

  • Products with true version-parallel releases (rare)

Trunk-based rules

  1. main is always releasable. Never merge broken code.

  2. Feature branches live < 2 days. Longer = merge hell.

  3. Behind feature flags for incomplete work. Ship code, hide feature.

  4. Merge via PR with 1+ reviewer. No direct pushes.

  5. CI runs on every push. Broken CI = highest-priority team incident.

  6. Rebase before merge. Squash-merge preferred over merge-commit for clean history.

PR discipline

A good Java PR:

  • < 400 lines diff

  • One logical change

  • All tests pass

  • Description explains: problem → approach → risks → how tested

  • Screenshots/logs if UI or observable output changed

  • Reviewer merges within 24 hrs, author responds to comments within 24 hrs

PR title = the merge commit message. Use Conventional Commits format.

The Zoho / Indian-context note

Some Zoho / Freshworks / Infosys teams still use SVN or Perforce for legacy monoliths. Learn Git for personal work regardless — it’s the study standard and the industry standard. If your day job is SVN, keep personal projects in Git for portfolio velocity.

Tools Worth Installing

Tool

Purpose

How to install

gh (GitHub CLI)

Create PRs from terminal

brew install gh / sudo apt install gh

lazygit

TUI Git client

brew install lazygit

delta

Better git diff

brew install git-delta, add to ~/.gitconfig

pre-commit

Git hooks framework

pip install pre-commit

Sourcetree / Fork / Tower

GUI clients

Optional; terminal is enough

~/.gitconfig starter

[user]
    name = Raghul R
    email = your-email@zohomail.com
[core]
    editor = code --wait
    excludesfile = ~/.gitignore_global
    autocrlf = input
[init]
    defaultBranch = main
[pull]
    rebase = true
[push]
    default = current
    autoSetupRemote = true
[rebase]
    autoStash = true
[fetch]
    prune = true
[alias]
    st = status -sb
    co = checkout
    br = branch
    ci = commit
    cim = commit -m
    lg = log --graph --pretty=format:'%C(yellow)%h%C(reset) %C(cyan)%an%C(reset) %s %C(green)(%cr)%C(reset)%C(bold red)%d%C(reset)' --abbrev-commit
    unstage = reset HEAD --

Pre-commit Hooks for Java

Install pre-commit, then add .pre-commit-config.yaml:

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
        args: ['--maxkb=1000']
  - repo: local
    hooks:
      - id: mvn-fmt
        name: Maven fmt (Spotless)
        entry: ./mvnw spotless:apply
        language: system
        pass_filenames: false
        files: \.java$

Enable: pre-commit install.

The Anti-Patterns

  • git push --force to shared branches. Rewrites history for everyone. Only use --force-with-lease on your own feature branches.

  • Committing secrets. Set up gitleaks or git-secrets as a pre-commit hook.

  • Long-lived feature branches. Merge hell 2 weeks later. Break work into small commits/PRs.

  • git pull on unclean working tree without rebase. Creates merge commits for nothing.

  • Copy-pasting from Stack Overflow into a huge commit. Small commits, one intent each.

Return to README.md · Next: 05_docker_and_containers.md