Git workflow for Java developers: how not to go crazy with pull requests

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Git workflow for Java developers: when "just commit" no longer works



Let's be honest: every Java developer has at least once been in a situation where, after a failed merge, their project stopped compiling, and colleagues in the chat wrote "Who touched pom.xml?". If you recognize yourself — this article is for you.



Git is not just a version control system. In the Java world, where projects live for years and dependencies are pulled in via Maven or Gradle, a proper Git workflow becomes a matter of survival. Today we'll break down how to organize work with Git so that code reviews go quickly and conflicts don't turn into a headache.



We won't teach you the git init or git commit commands. Instead, we'll focus on how exactly Java teams build their processes: from choosing a branching model to setting up CI/CD pipelines.



Why do Java projects require a special approach to Git?



Java is a language with a rich ecosystem. In a typical enterprise project, you will find:

  • Multi-layered architecture (controller → service → repository);
  • Builds via Maven or Gradle with dozens of dependencies;
  • Long-running tests (integration, unit, E2E);
  • Strict version compatibility requirements.


This means that a Git workflow for Java developers must account not only for code but also for the build infrastructure. An error in pom.xml can break the entire project, and a conflict in application.properties can halt deployment.



Main branching models: what to choose for a Java team



GitFlow — the enterprise Java classic



GitFlow is the de facto standard for large Java projects. It offers a strict branch structure:

  • main — only production-ready code;
  • develop — integration branch for development;
  • feature/ — for new features;
  • release/ — for release preparation;
  • hotfix/ — for urgent fixes.


Example: you are writing a new REST endpoint in Spring Boot. You create a branch feature/add-user-endpoint from develop, work on it, then merge it back. When enough features accumulate for a release, you create release/v2.1.0, where bugs are fixed without adding new functionality.



Pros: clear isolation, understandable history, suitable for versioning.
Cons: complexity, many merges, inconvenient for CI/CD.



GitHub Flow — for fast iterations



If your Java team uses microservices or works in Agile, GitHub Flow might be simpler. Here there is only one main branch — main. All changes go through pull requests.



It works like this:

  1. Create a branch from main;
  2. Write code and tests;
  3. Open a PR, go through code review;
  4. CI/CD runs the build and tests;
  5. After merge, the branch is deleted.


For a Java project, this means each PR should be small enough for CI to run all tests in a reasonable time.



Trunk-based development — for the bold



This is when all developers work in a single branch (trunk), and features are hidden behind feature flags. Suitable for mature teams with excellent test coverage. In Java, it is often used together with Spring Cloud Config for dynamically enabling/disabling features.



Merge vs Rebase: the eternal debate of Java developers



In the Java world, merge and rebase have different philosophies. Let's break it down with an example.



Merge — preserving history

If you are working on a large module with multiple developers, merge creates a merge commit that visually shows where the changes came from. This is convenient for understanding

Blogs

Book Recommendations