Process
Git Workflow
Git is version control software that tracks every change to your code. It's how multiple developers work on the same project without overwriting each other's work. It's also how you can go back in time if something breaks. Every professional development team uses Git. Understanding the workflow—how code moves from a developer's machine into production—is essential.
What Git Is and Why It Matters
Git is a version control system. It records snapshots of your code at different points in time, who made changes, and why. If you deploy code and it breaks, you can revert to the last working version in seconds. If you want to know who changed a function and when, Git tells you. If two developers edit the same file, Git helps merge their changes without losing work.
Without version control, software development is chaos. People email code files back and forth. Someone overwrites someone else's work. The history of who changed what disappears. You deploy a broken version and can't recover it.
Git is the industry standard because it's fast, secure, and distributed. Every developer has a full copy of the entire history on their machine. You can work offline. You can collaborate across continents without a central server.
Repositories and Branches
A Git repository (or "repo") is a folder containing your project and its entire history. It lives on a server (like GitHub) so multiple people can access it.
A branch is a parallel version of the code. Imagine your codebase as a tree trunk (the main branch, usually called "main" or "master"). Branches split off like limbs, allowing developers to work independently. When the work is done and tested, the branch gets merged back into the trunk.
Example workflow:
- Create a branch called "feature/user-login" from main
- Developer builds the login feature on that branch
- Other developers keep working on main, unaffected
- When login is complete and tested, merge it back into main
Branches keep teams from stepping on each other. Developer A can be building the payment system. Developer B can be building the user dashboard. They work in parallel, then merge when both are done.
Branching Strategies
Different teams organize branches differently. Three popular strategies:
| Strategy | How It Works | Best For |
|---|---|---|
| Feature Branching | Each feature gets its own branch. Developers commit to the branch, then open a pull request to merge into main when done. | Most teams. Clear, simple, good for code review. |
| Gitflow | Multiple long-lived branches: main (production), develop (staging), feature branches off develop, release branches for final testing. | Larger teams, complex releases, when staging needs to be kept separate from main. |
| Trunk-Based Dev | Everyone commits to main (or a very short-lived branch). Small commits, frequent deploys. Requires high test coverage and discipline. | High-velocity teams, continuous deployment, startups moving fast. |
Most custom software projects use Feature Branching: one branch per feature, reviewed and merged into main when complete. It's simple and gives you a clear gate (the code review) before code enters production.
Pull Requests: The Code Review Gate
A pull request (PR) is a proposal to merge code from one branch into another. It's the moment where other developers review the code before it goes into main.
The workflow looks like:
- Developer creates a feature branch and writes code
- When ready, they push the branch to GitHub and open a pull request
- Other developers review the code, ask questions, suggest improvements
- Developer makes requested changes and pushes them to the branch
- Once approved, the PR is merged into main
Pull requests are asynchronous code review. One developer doesn't need to interrupt another for approval—the reviewer checks when they have time, leaves comments, and the original developer responds.
Good pull requests are focused: one feature, not five. They're reviewed within hours, not days. They have a clear description so reviewers understand the context. They pass automated tests before being reviewed (more on that later).
Commit Messages: Why They Matter
A commit message documents why a change was made. Months later, when you're debugging an issue and need to understand why a line of code exists, a good commit message saves you hours.
Bad commit message: "fix stuff"
Good commit message: "Fix race condition in user session cleanup. The cleanup task was running concurrently with the session validation, causing intermittent timeouts for users with many open tabs. Added a mutex lock to ensure serial access."
Most teams follow a simple commit message format:
- First line (50 chars): A short summary of the change. "Add password reset flow" or "Fix bug in discount calculation"
- Blank line
- Body (wrap at 72 chars): More detail about what changed and why. What problem does this solve? What approach did you take?
Good commit messages are for your future self and your teammates. Take 30 seconds to write one that will save someone an hour of debugging later.
Branch Naming Conventions
Most teams name branches in a consistent way so you can glance at the branch name and understand what it's for:
feature/user-authentication— a new featurebugfix/login-redirect-issue— fixing a bugdocs/api-endpoints— documentation changesrefactor/payment-module— code cleanup without behavior changechore/upgrade-dependencies— maintenance tasks
Consistent names make it easier to find branches, understand what's being worked on, and automate workflows (e.g., "all feature/* branches require reviews before merging").
Merge vs Rebase: The Eternal Debate
When you're ready to combine two branches (say, feature/login and main), Git offers two approaches: merge and rebase. Both end up with the same code, but they handle the history differently.
Merge creates a new commit that combines two branches. The history shows both branches and where they came together. It's safe—if something goes wrong, it's obvious what happened.
Rebase replays one branch's commits on top of the other. The history is a straight line. It looks clean, but if you don't understand what you're doing, you can accidentally rewrite shared history.
In plain terms: Merge is safer. Use it. Rebase is for teams that really know Git. The debate goes on endlessly among developers, but most teams default to merge for safety.
Protecting the Main Branch
Main is where production-ready code lives. You can't just push anything to main. Most teams set up rules:
- Code must be reviewed by at least 2 developers before merging
- Automated tests must pass before merging
- No one can force-push to main
- All conversations in the PR must be resolved
- Branches must be up-to-date with main before merging (no old code sneaking in)
These rules prevent bad code from reaching production. They slow down merges slightly, but they save enormous pain from deployments that break production. A few hours of delay in a merge is worth avoiding a 3am wake-up call to fix a critical bug.
Handling Merge Conflicts
A merge conflict happens when two developers edit the same lines of code. Git doesn't know which version is correct, so it asks the developer to decide.
Example: Developer A changes line 42 of auth.js to add error logging. Developer B changes the same line to add a new parameter. When you try to merge, Git says "I don't know which is right—you pick."
Merge conflicts are manual work. The developer resolves them by:
- Opening the conflicted file (Git marks the conflicts with <<< and >>>)
- Deciding which code to keep or combining both
- Removing the conflict markers
- Testing to make sure the merge works
Conflicts are annoying but rare if teams coordinate well. Keep pull requests small and review them quickly so branches don't diverge too far.
Git Tags for Releases
When you deploy code to production, it's useful to mark that point in history so you can find it later. That's what tags are for.
Example: You deploy version 1.2.0 to production on March 15. You create a tag "v1.2.0" at that commit. Later, if you need to debug what was deployed on March 15, you look at the tag.
Most teams use semantic versioning: MAJOR.MINOR.PATCH. 1.2.0 means major version 1 (the product), minor version 2 (new features added), patch version 0 (no bug fixes yet). When you add a feature, increment minor. When you fix a bug, increment patch. When you make a breaking change, increment major.
Monorepo vs Polyrepo
As projects grow, you need to decide: one big repository or multiple smaller ones?
| Approach | How It Works | Pros | Cons |
|---|---|---|---|
| Polyrepo | Separate repos for frontend, backend, mobile | Teams can work independently, easier to onboard | Coordinating changes is harder, duplicate tooling |
| Monorepo | Everything in one repo: frontend, backend, shared code | Coordinated changes, shared code is obvious, atomic commits | Huge clones, tooling is more complex, harder to scale |
For small teams, polyrepo is simpler. For teams that need tight coordination or share a lot of code, monorepo works. There's no universal right answer.
Git Workflow and CI/CD
Git integrates with CI/CD (continuous integration/continuous deployment) systems. When you push code to a branch or open a pull request, automated tests run. When code is merged to main, it's automatically deployed to staging or production.
This is where Git becomes powerful. You don't manually run tests and deploy—the system does it. A developer pushes code, tests run automatically, code is deployed. If tests fail, the PR is blocked. If they pass, the code flows to production with no manual steps.
For Non-Developers: What to Expect
If you're a business owner or product manager, here's what Git workflow means for you:
- Pull requests take time to review. Code doesn't merge instantly. It sits in review for hours or a day. This is good—it prevents bugs. Don't push for faster merges without code review.
- Features go into staging before production. The Git workflow usually has a staging branch where code is tested before it reaches main. This catches issues before users see them.
- You can see who changed what and when. If there's a bug, you can ask Git "who changed this code?" It tells you the person and the date. Accountability is built in.
- Rollbacks are fast. If you deploy code and it breaks, you can revert to the last known good version in minutes, not hours.
The Flow
A healthy Git workflow looks like this:
- Developer checks out a feature branch from main
- They write code, commit frequently with clear messages
- They push to GitHub and open a pull request with a description
- Automated tests run; other developers review
- Feedback is incorporated; code is updated
- Pull request is approved and merged to main
- Tests run again on main; code is deployed to staging
- QA or the Product Owner verifies on staging
- When ready, it's deployed to production
The next section covers Documentation—how to ensure that future developers (and future you) understand the code.