How To

Git Feature Branch Workflow – Develop Without Affecting Main

Feature branches are the backbone of collaborative Git workflows. They let you develop new functionality, fix bugs, or experiment – all without touching the main branch. Every change stays isolated until it is reviewed, tested, and merged.

Original content from computingforgeeks.com - post 71496

This guide covers the full feature branch workflow from creation to merge and cleanup. Whether your team follows GitHub Flow, Git Flow, or trunk-based development, the core branching mechanics are the same. We also compare merge strategies (merge commit vs rebase vs squash) and walk through conflict resolution. For a deeper look at Git terminology like PRs, MRs, tags, and branches, check our reference guide.

Prerequisites

Before starting, make sure you have the following in place:

  • Git 2.x installed on your workstation – see our guide on installing Git on RHEL / Rocky Linux / AlmaLinux
  • A remote repository on GitHub, GitLab, or Bitbucket (or any Git hosting platform)
  • Basic familiarity with Git commands (clone, commit, push)
  • SSH key or HTTPS credentials configured for pushing to the remote

Step 1: Create a Feature Branch

Every new piece of work starts with a fresh branch off the main branch. This keeps your changes isolated and makes code review straightforward. First, make sure your local main branch is up to date with the remote.

git checkout main
git pull origin main

Now create and switch to a new feature branch. Use a descriptive name that makes the purpose clear at a glance.

git checkout -b feature/add-user-authentication

This creates the branch and switches to it in one step. You can verify which branch you are on with:

git branch

The active branch is marked with an asterisk:

  main
* feature/add-user-authentication

Branch naming conventions – pick a pattern your team agrees on and stick with it:

  • feature/ – new functionality (feature/add-oauth-login)
  • bugfix/ – bug fixes (bugfix/fix-null-pointer-on-submit)
  • hotfix/ – urgent production fixes (hotfix/patch-sql-injection)
  • chore/ – maintenance tasks (chore/update-dependencies)

Step 2: Make Changes and Commit

With the feature branch active, make your code changes as usual. The key difference is that all commits stay on this branch and do not affect main. Stage your modified files and commit with a clear message.

git add src/auth/login.py src/auth/middleware.py
git commit -m "Add JWT-based login endpoint and auth middleware"

Write commits that describe what changed and why, not just “fixed stuff.” Small, focused commits are easier to review and revert if something breaks. A good practice is to commit early and often rather than accumulating a massive diff.

Continue making changes, staging, and committing as needed. You can check your commit history on the feature branch at any time:

git log --oneline main..HEAD

This shows only the commits on your feature branch that are not on main:

a3f7c2d Add JWT-based login endpoint and auth middleware
b1e9f4a Add user model with password hashing
c8d2a1b Create auth module structure

Step 3: Push Feature Branch to Remote

Once you have one or more commits on the feature branch, push it to the remote repository. This backs up your work and makes the branch visible to teammates.

git push -u origin feature/add-user-authentication

The -u flag sets the upstream tracking branch so future pushes from this branch only need git push without specifying the remote and branch name. After the first push, subsequent pushes are just:

git push

If your team uses a CI/CD pipeline, pushing the branch typically triggers automated tests. Most teams configure pipelines to run on every push to feature branches so issues surface early. If you are running Jenkins, you can set up multi-branch pipelines that automatically detect and build new branches.

Step 4: Create a Pull Request (GitHub / GitLab)

A pull request (PR on GitHub/Bitbucket) or merge request (MR on GitLab) is the formal way to propose merging your feature branch into main. It provides a centralized place for code review, discussion, and CI status checks. For a comprehensive explanation of pull requests and their lifecycle, see the official GitHub documentation.

On GitHub, create a PR from the command line using the GitHub CLI:

gh pr create --base main --head feature/add-user-authentication \
  --title "Add user authentication with JWT" \
  --body "Implements login endpoint, auth middleware, and user model with password hashing."

Or navigate to your repository on GitHub and click “Compare & pull request” after pushing the branch.

On GitLab, create a merge request via the CLI:

glab mr create --source-branch feature/add-user-authentication \
  --target-branch main \
  --title "Add user authentication with JWT"

When writing PR descriptions, include the context a reviewer needs – what problem it solves, what approach you took, how to test it, and any areas where you want specific feedback.

Step 5: Code Review Workflow

Code review is where feature branches deliver their real value. The main branch stays protected while the team reviews changes in isolation. A solid review process catches bugs, enforces standards, and spreads knowledge across the team.

For reviewers – check out and test the branch locally before approving:

git fetch origin
git checkout feature/add-user-authentication

Run the test suite and verify the changes work as described in the PR. Leave constructive comments on specific lines in the PR interface.

For authors – respond to review comments by making additional commits on the same branch:

git add src/auth/login.py
git commit -m "Address review: add input validation to login endpoint"
git push

The PR updates automatically with the new commits. Most teams require at least one approval before merging. Branch protection rules on GitHub and GitLab let you enforce this – along with requirements like passing CI checks, no merge conflicts, and signed commits.

Step 6: Merge the Feature Branch

After approval, it is time to merge the feature branch into main. Git offers three main merge strategies, each with different trade-offs for your commit history.

Merge Commit (Default)

Creates a merge commit that preserves the full branch history. All individual commits from the feature branch appear in main along with the merge commit itself.

git checkout main
git merge feature/add-user-authentication

Best for: teams that want a complete audit trail of every commit on every branch.

Rebase and Merge

Replays each feature branch commit on top of main, creating a linear history with no merge commits. This produces the cleanest git log output.

git checkout feature/add-user-authentication
git rebase main
git checkout main
git merge feature/add-user-authentication

Best for: teams that prefer a clean, linear commit history. Avoid rebasing branches that others are actively working on – it rewrites commit hashes and causes conflicts for collaborators.

Squash and Merge

Combines all feature branch commits into a single commit on main. The branch history is collapsed into one clean commit.

git checkout main
git merge --squash feature/add-user-authentication
git commit -m "Add user authentication with JWT (#42)"

Best for: teams that want each feature represented as a single commit on main. Works well when feature branches have messy “WIP” commits that do not add value to the main branch history.

Step 7: Delete Merged Branches

Once a feature branch is merged, delete it to keep your repository clean. Stale branches accumulate fast and make it hard to find active work.

Delete the local branch:

git branch -d feature/add-user-authentication

The -d flag only deletes the branch if it has been fully merged. Use -D to force-delete an unmerged branch (use with caution).

Delete the remote branch:

git push origin --delete feature/add-user-authentication

To clean up stale remote tracking references on your local machine:

git fetch --prune

Most hosting platforms (GitHub, GitLab) have an option to automatically delete branches after merge. Enable it in your repository settings to reduce manual cleanup.

Step 8: Handle Merge Conflicts

Merge conflicts happen when two branches modify the same lines in the same file. Git cannot automatically decide which version to keep, so you resolve it manually. This is a normal part of working with feature branches.

When a merge or rebase hits a conflict, Git marks the affected files. Check which files need attention:

git status

Files with conflicts appear under “Unmerged paths.” Open each conflicted file and look for the conflict markers:

<<<<<<< HEAD
def authenticate(token):
    return verify_jwt(token, secret=settings.JWT_SECRET)
=======
def authenticate(token):
    return verify_jwt(token, algorithm="HS256")
>>>>>>> feature/add-user-authentication

The section between <<<<<<< HEAD and ======= is the main branch version. The section between ======= and >>>>>>> is the feature branch version. Edit the file to keep the correct code and remove the conflict markers.

After resolving all conflicts, stage the files and complete the merge:

git add src/auth/login.py
git commit -m "Resolve merge conflict in authentication function"

Reducing conflict frequency – regularly pull updates from main into your feature branch to stay in sync:

git checkout feature/add-user-authentication
git merge main

This catches conflicts early when they are small, rather than discovering a massive conflict at merge time.

Step 9: Git Flow vs GitHub Flow vs Trunk-Based Development

Feature branches are used in every major Git workflow, but the rules around them differ. Choosing the right workflow depends on your team size, release cadence, and deployment process.

Git Flow

Uses long-lived branches: main, develop, feature/*, release/*, and hotfix/*. Features branch off develop, not main. Releases get their own branch for stabilization. Good for software with versioned releases (desktop apps, libraries). Overkill for web apps with continuous deployment.

GitHub Flow

Simpler model with just main and feature branches. Every feature branch merges directly into main via a PR. Main is always deployable. Good for web apps and services with continuous deployment. Most teams find this workflow strikes the right balance between simplicity and safety.

Trunk-Based Development

Developers commit directly to main (the “trunk”) in small, frequent increments. Feature branches exist but are extremely short-lived – usually merged within hours, not days. Feature flags control whether incomplete code is active in production. Demands strong CI/CD, automated testing, and disciplined team practices. Used by Google, Meta, and other large engineering organizations. If your team follows GitOps practices, trunk-based development pairs naturally with automated deployment pipelines.

Git Branch Command Reference

This table covers the most common Git commands for working with feature branches. Keep it handy as a quick reference.

CommandDescription
git branchList local branches
git branch -aList local and remote branches
git checkout -b branch-nameCreate and switch to a new branch
git switch -c branch-nameCreate and switch (modern syntax, Git 2.23+)
git checkout branch-nameSwitch to an existing branch
git push -u origin branch-namePush branch and set upstream tracking
git merge branch-nameMerge branch into current branch
git merge --squash branch-nameSquash all commits into one before merging
git rebase mainRebase current branch onto main
git branch -d branch-nameDelete merged local branch
git branch -D branch-nameForce-delete local branch (even if unmerged)
git push origin --delete branch-nameDelete remote branch
git fetch --pruneRemove stale remote tracking references
git log --oneline main..HEADShow commits on current branch not in main
git stashTemporarily save uncommitted changes
git stash popRestore stashed changes

Conclusion

Feature branches keep your main branch stable while giving developers freedom to build, experiment, and iterate. The workflow is the same regardless of platform – create a branch, commit your work, push, open a PR, get it reviewed, and merge. For production environments, combine branch protection rules with automated CI/CD to ensure nothing hits main without passing tests and peer review.

Related Articles

Databases How To Install LEMP Stack on Manjaro Linux Programming How to Cut Software Development Costs by Using Linux Programming Why Data Scientists use Jupyter Notebooks so Much CentOS How To Install Python 3.9 on CentOS 8 / CentOS 7

Leave a Comment

Press ESC to close