Luke Anderson Git-Github

Git for Teams: Complete Guide to Push, Pull, Revert, Merge & Team Workflows (with Commands)

Working on a solo project with Git is easy. Working on the same codebase with five other developers, all pushing to the same branches, is where things get messy fast. Merge conflicts, accidental force-pushes, broken main branches, lost commits — every team has horror stories.

This guide is the comprehensive Git reference I wish I’d had when I first joined a team. You’ll learn the essential commands, the team workflows that actually work in production, how to safely undo any mistake, and which tools make collaboration easier. Every command has a real example, and there’s a quick-reference cheat sheet at the end you can bookmark.

Why Git Workflow Matters in Teams

A solo developer can get away with git add ., git commit -m "stuff", and git push forever. A team can’t. Without a workflow:

  • Two developers overwrite each other’s work
  • The main branch breaks because someone pushed broken code
  • Features get tangled together and can’t be released independently
  • Reviewing changes becomes impossible
  • Rollbacks turn into all-night incidents

A good Git workflow solves all of this through branching, pull requests, and clear conventions that the whole team follows.

The Essential Git Commands Every Developer Must Know

Before getting into team workflows, here are the foundational commands. Master these and 90% of your daily Git work is covered.

1. Cloning and Configuring

bash
# Clone a repository (downloads the project to your machine)
git clone https://github.com/yourcompany/project.git

# Set your identity (only needs to be done once per machine, or per repo)
git config --global user.name "Jane Doe"
git config --global user.email "[email protected]"

# See your current config
git config --list

# Use VS Code as your default Git editor
git config --global core.editor "code --wait"

2. Checking Status and History

bash
# What files have I changed? (run this constantly)
git status

# Show commit history
git log

# Compact one-line history
git log --oneline --graph --all

# Show what changed in your unstaged files
git diff

# Show what's staged for commit
git diff --staged

3. Staging and Committing

bash
# Stage a specific file
git add src/components/Button.jsx

# Stage everything that changed
git add .

# Unstage a file (move back out of staging)
git restore --staged src/components/Button.jsx

# Commit with a message
git commit -m "Add primary variant to Button component"

# Stage and commit all tracked files in one command
git commit -am "Fix typo in user profile page"

# Amend the last commit (add forgotten files, fix message)
# WARNING: Only do this if you haven't pushed yet
git commit --amend -m "Better commit message"

4. Pushing and Pulling

bash
# Push your local commits to the remote
git push

# Push a new branch and set it to track the remote
git push -u origin feature/login-page

# Download remote changes WITHOUT merging them into your branch
git fetch

# Download remote changes AND merge them into your current branch
git pull

# Safer alternative: pull with rebase (keeps history linear)
git pull --rebase

Pro tip: git fetch followed by reviewing the changes is safer than git pull blindly. Pull is just “fetch + merge”.

5. Branching (The Heart of Team Workflows)

bash
# List all local branches (current branch marked with *)
git branch

# List local + remote branches
git branch -a

# Create a new branch
git branch feature/user-dashboard

# Switch to a branch
git switch feature/user-dashboard
# (Older syntax, still works:) git checkout feature/user-dashboard

# Create AND switch in one command
git switch -c feature/user-dashboard
# (Older:) git checkout -b feature/user-dashboard

# Delete a local branch (after it's merged)
git branch -d feature/user-dashboard

# Force-delete a branch (even if not merged — be careful)
git branch -D feature/user-dashboard

# Delete a remote branch
git push origin --delete feature/user-dashboard

# Rename current branch
git branch -m new-branch-name

6. Merging and Rebasing

bash
# Merge another branch INTO your current branch
git switch main
git merge feature/login-page

# Rebase your branch on top of another (cleaner history)
git switch feature/login-page
git rebase main

# Abort a merge or rebase if it goes wrong
git merge --abort
git rebase --abort

Merge vs rebase in one sentence: Merge preserves history exactly as it happened (with a merge commit); rebase rewrites your commits on top of the target branch as if you started from there (cleaner, but rewrites history).

How to Work with Multiple Developers on Git (Team Workflows)

Here are the three most common branching strategies. Pick one as a team and stick with it.

Workflow 1: GitHub Flow (Simplest — Recommended for Most Teams)

Used by GitHub itself and most modern startups. Just two rules:

  1. main is always deployable
  2. Everything else happens on feature branches that get merged via Pull Request

Daily flow:

bash
# Start every new feature from latest main
git switch main
git pull

# Create your feature branch
git switch -c feature/add-search-bar

# Work, commit, push regularly
git add .
git commit -m "Add search input UI"
git push -u origin feature/add-search-bar

# Open a Pull Request on GitHub/GitLab/Bitbucket
# Get reviewed, address feedback, merge
# Delete branch after merge

Best for: SaaS apps, small-to-medium teams, continuous deployment.

Workflow 2: Git Flow (For Versioned Releases)

More structured, uses multiple long-lived branches:

  • main — production code only
  • develop — integration branch for next release
  • feature/* — new features (branched off develop)
  • release/* — preparing a release (branched off develop)
  • hotfix/* — emergency production fixes (branched off main)

Best for: Mobile apps, desktop software, anything with versioned releases. Overkill for most web apps in 2026 — most teams have moved to GitHub Flow.

Workflow 3: Trunk-Based Development

Everyone commits directly to main (or to very short-lived branches that merge within hours). Requires strong CI, feature flags, and discipline.

Best for: High-performing teams at scale (Google, Meta, Netflix). Risky without good automation.

The Pull Request (PR) Workflow Step by Step

This is how 90% of professional teams collaborate. Every change goes through a PR before merging.

1. Start from the latest main:

bash
git switch main
git pull

2. Create a feature branch with a descriptive name:

bash
git switch -c feature/JIRA-1234-add-payment-method

Common naming conventions: feature/, bugfix/, hotfix/, chore/ — prefix + ticket number + short description.

3. Make commits with clear messages:

bash
git add .
git commit -m "feat(payments): add Stripe payment method form"

(See Conventional Commits for a popular standard.)

4. Keep your branch up to date with main:

bash
# Option A: merge main into your branch (preserves your commit history)
git switch feature/JIRA-1234-add-payment-method
git fetch
git merge origin/main

# Option B: rebase (cleaner, but rewrites your commits)
git fetch
git rebase origin/main

5. Push and open a PR:

bash
git push -u origin feature/JIRA-1234-add-payment-method

Then go to GitHub/GitLab and open a Pull/Merge Request. Add a clear description of what changed and why, link the ticket, request reviewers.

6. Address review feedback:

bash
git add .
git commit -m "Address review: extract validation to helper"
git push

7. After approval and merge, clean up:

bash
git switch main
git pull
git branch -d feature/JIRA-1234-add-payment-method

How to Resolve Merge Conflicts

Conflicts happen when two people change the same lines. Git can’t decide which version wins, so it asks you.

bash
git merge feature/login-page
# CONFLICT (content): Merge conflict in src/auth.js

Open the conflicted file. You’ll see:

javascript
<<<<<<< HEAD
const apiUrl = 'https://api.production.com';
=======
const apiUrl = 'https://api.staging.com';
>>>>>>> feature/login-page
  • Everything between <<<<<<< HEAD and ======= is YOUR version
  • Everything between ======= and >>>>>>> feature/login-page is THE OTHER version

Decide which to keep (or combine both), delete the conflict markers, save the file. Then:

bash
git add src/auth.js
git commit  # Git auto-fills a merge commit message

If the conflict is overwhelming and you want to start over:

bash
git merge --abort

VS Code, GitKraken, and similar tools have visual merge editors that show both versions side by side with “Accept Current / Accept Incoming / Accept Both” buttons. Much easier than editing manually.

How to Undo and Revert Changes in Git (Every Scenario)

This is the section that saves careers. Bookmark it.

Undo uncommitted changes (working directory)

bash
# Discard changes to one file (CAREFUL — can't be undone)
git restore src/app.js

# Discard ALL uncommitted changes
git restore .

# Unstage a file (keeps your changes, just removes from staging area)
git restore --staged src/app.js

Undo the last commit (but keep the changes)

bash
# Undo last commit, keep changes in staging
git reset --soft HEAD~1

# Undo last commit, keep changes in working dir (unstaged)
git reset HEAD~1

Completely delete the last commit and its changes

bash
# DESTRUCTIVE — changes are GONE
git reset --hard HEAD~1

Revert a commit that’s already been pushed

Never use git reset --hard on pushed commits. Use git revert instead — it creates a NEW commit that undoes the changes, preserving history.

bash
# Find the commit you want to undo
git log --oneline

# Revert it (creates a new commit)
git revert abc1234

# Push the revert commit
git push

Undo a merge that’s already been pushed

bash
git revert -m 1 <merge-commit-hash>
git push

The -m 1 flag tells Git to revert back to the first parent (the branch you merged into).

Recover a deleted branch or lost commit (Git’s safety net)

bash
# Reflog shows EVERYTHING you've done in Git, including deletes
git reflog

# Find the lost commit/branch (e.g., shows: abc1234 HEAD@{5}: commit: lost work)
# Recover it
git checkout -b recovered-branch abc1234

The reflog has saved more careers than any other Git feature. It keeps a local record of every move HEAD made for 90 days by default, even after you delete a branch.

Undo a force push

If a teammate force-pushed and overwrote your work:

bash
# Look in the reflog for the commit hash before the force-push happened
git reflog

# Restore the branch to that point
git push origin <commit-hash>:branch-name --force-with-lease

Always use --force-with-lease instead of --force — it refuses to push if someone else has pushed in the meantime, preventing you from overwriting their work.

Stashing: Save Work Without Committing

When you need to switch branches but aren’t ready to commit:

bash
# Save your current changes (and clean the working directory)
git stash

# Save with a description
git stash push -m "WIP: refactoring auth middleware"

# See your stashes
git stash list

# Restore the most recent stash (and remove it from the stash list)
git stash pop

# Apply a stash but keep it in the list
git stash apply

# Apply a specific stash
git stash apply stash@{2}

# Delete a stash
git stash drop stash@{0}

# Clear ALL stashes (careful)
git stash clear

Cherry-Picking: Apply One Commit From Another Branch

Useful when you want a single fix from a feature branch without merging everything:

bash
# Find the commit you want
git log feature/login-page --oneline

# Apply it to your current branch
git cherry-pick abc1234

Essential Tools That Make Git in Teams Easier

Hosting platforms

Tool Best for
GitHub Open source, most popular, best ecosystem
GitLab Built-in CI/CD, self-hosted option, full DevOps
Bitbucket Teams already using Atlassian (Jira, Confluence)
Azure DevOps Microsoft shops, enterprise

Visual Git clients (GUI)

Tool Notes
GitKraken Beautiful UI, paid for commercial use
Sourcetree Free, by Atlassian, solid for beginners
GitHub Desktop Free, simple, GitHub-focused
Fork Fast, native macOS/Windows, one-time fee
Tower Polished, paid subscription

Terminal tools

Tool What it does
Lazygit Terminal UI for Git — incredibly fast once you learn it
tig Text-mode interface for browsing history
gh GitHub’s official CLI (gh pr create, gh pr review)
glab GitLab equivalent of gh
delta Better-looking git diffs

IDE integration

  • VS Code has excellent built-in Git support plus the GitLens extension (a must-install)
  • JetBrains IDEs (PHPStorm, IntelliJ, WebStorm) have the best built-in Git UI of any IDE
  • Vim/Neovim users: vim-fugitive is the gold standard

Workflow automation

  • Husky — runs scripts on Git hooks (e.g., run linter before every commit)
  • lint-staged — only lint files that are staged (faster than linting everything)
  • Commitizen — interactive prompt for writing conventional commit messages
  • commitlint — rejects commits that don’t follow your team’s message format
  • pre-commit — Python-based hook framework, language-agnostic

Code review and PR tools

  • Reviewable — better PR review UI than GitHub native
  • Graphite — stacked PR workflow for larger teams
  • CodeRabbit / Codium AI — AI-assisted PR reviews

Best Practices for Git in Teams

  1. Pull before you push. Always start a session with git pull to avoid avoidable conflicts.
  2. Commit early and often. Small commits are easier to review and revert than huge ones.
  3. Write clear commit messages. “Fix bug” is useless six months from now. Try: fix(auth): prevent token refresh loop when offline.
  4. Never force-push to shared branches. main, develop, and any branch with an open PR should be untouchable.
  5. Use --force-with-lease instead of --force when you must force-push your own branch.
  6. Don’t commit secrets. Use .gitignore and tools like git-secrets or truffleHog to scan for accidental leaks.
  7. Keep branches short-lived. Long-running branches accumulate conflicts. Merge within days, not weeks.
  8. Review your own PR first. Read the diff before requesting reviewers. You’ll catch half your own bugs.
  9. Protect your main branch. Enable branch protection in GitHub/GitLab: require PR reviews, require CI to pass, block direct pushes.
  10. Use the reflog. When something goes wrong, git reflog is your friend.

Git Commands Cheat Sheet (Bookmark This)

Daily essentials

Command What it does
git status What’s changed
git diff Show unstaged changes
git add . Stage everything
git commit -m "msg" Commit with message
git push Upload commits
git pull Download + merge
git fetch Download without merging
git log --oneline --graph Pretty history

Branching

Command What it does
git branch List branches
git switch -c name Create + switch to branch
git switch main Switch to main
git merge branch Merge branch into current
git rebase main Rebase onto main
git branch -d name Delete merged branch

Undoing things

Command What it does
git restore file Discard file changes
git restore --staged file Unstage file
git reset --soft HEAD~1 Undo last commit, keep changes
git reset --hard HEAD~1 DELETE last commit (local)
git revert abc1234 Undo a pushed commit safely
git revert -m 1 hash Undo a merge commit
git reflog See everything (recover lost work)

Stashing

Command What it does
git stash Save work-in-progress
git stash pop Restore latest stash
git stash list See all stashes
git stash apply stash@{2} Apply specific stash

Remote management

Command What it does
git remote -v List remotes
git remote add name url Add a remote
git push -u origin branch Push + track remote
git push origin --delete branch Delete remote branch

Investigation

Command What it does
git blame file Who changed each line
git log -p file History of a specific file
git log --author="name" Commits by author
git bisect start Binary search for a bad commit

Wrapping Up

Git is hard not because the commands are complex but because the consequences of mistakes feel scary — until you realize almost everything is recoverable through git reflog. Master the daily commands, agree on a workflow with your team, use a visual tool like GitKraken or VS Code’s built-in Git when conflicts get hairy, and never force-push to shared branches.

The single biggest jump in productivity comes from agreeing on a workflow as a team and writing it down. Whether it’s GitHub Flow, Git Flow, or trunk-based, the worst Git setup is one where every developer does something different.

When something goes catastrophically wrong: stop, breathe, run git reflog, and you’ll almost always find your work waiting for you.

Discussion

Be the first to comment

Leave a comment

Get a quote