Logo
HomeAbout MeProjectsBlogsMemoriesContact
HomeAbout MeProjectsBlogsMemoriesContact

Whether you are an entry-level software engineer, a senior tech lead, or a DevOps specialist, mastering Git is a core requirement for modern software development. Git is more than just a tool to back up code; it is an environment for team collaboration, quality control, and automated deployment.

This document serves as an end-to-end guide and production-grade cheatsheet covering Git architecture, branch management, commit conventions, release workflows, safety mechanisms, and advanced flag options.


1. The Git Mental Model

To use Git effectively, you must understand its four primary areas:

+-------------------+       git add       +------------------+
| Working Directory | ------------------> |   Staging Area   |
| (Unstaged Files)  | <------------------ |     (Index)      |
+-------------------+     git restore     +------------------+
                                                   |
                                                   | git commit
                                                   v
+-------------------+      git push       +------------------+
| Remote Repository | <------------------ | Local Repository |
| (GitHub/GitLab)   | ------------------> |      (.git)      |
+-------------------+      git fetch      +------------------+

  1. Working Directory: Your local workspace where you create, edit, and delete files.
  2. Staging Area (Index): A draft zone where you organize changes before committing them to history.
  3. Local Repository (.git): The local database containing all committed history and branch pointers on your machine.
  4. Remote Repository: The central server (e.g., GitHub, GitLab, Bitbucket) that facilitates team collaboration.

2. Configuration & Repository Initialization

First-Time Configuration

Set your identity globally across all repositories on your system:

# Set global identity
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"

# Set default main branch name
git config --global init.defaultBranch main

# Set default push behavior to push only current branch
git config --global push.default simple

# Verify configurations
git config --list

Initializing and Cloning

# Initialize a new local Git repository in current directory
git init

# Clone a remote repository via HTTPS or SSH
git clone https://github.com/organization/repository.git
git clone git@github.com:organization/repository.git

Ignoring Files (.gitignore)

Always create a .gitignore file at the root of your project to prevent sensitive or build files from entering the repository (e.g., node_modules/, .env, dist/, .DS_Store).


3. Enterprise Branching Strategies

There is no single "best" branching strategy for every team. Different organizations adopt different workflows depending on their release cadence, deployment model, team size, and compliance requirements.

The four most common strategies are:

StrategyBest ForCharacteristics
GitHub FlowStartups, SaaS, Continuous DeploymentSimple workflow using a single production branch and short-lived feature branches.
GitLab FlowTeams with staging environmentsExtends GitHub Flow with environment branches such as staging or production.
GitflowEnterprise products with scheduled releasesUses dedicated develop, release, and hotfix branches for controlled release cycles.
Trunk-Based DevelopmentLarge engineering organizations and CI/CDDevelopers integrate into a shared trunk frequently using short-lived branches or direct commits behind feature flags.

Which one should you choose?

  • Choose GitHub Flow if you deploy frequently and maintain a simple workflow.
  • Choose GitLab Flow if your deployment pipeline includes multiple environments such as staging and production.
  • Choose Gitflow if your organization follows scheduled release cycles and requires dedicated release management.
  • Choose Trunk-Based Development if your team practices Continuous Integration and Continuous Deployment (CI/CD) with frequent integrations.

Gitflow Branch Structure

This guide primarily uses Gitflow because it is still widely adopted by enterprises that maintain scheduled releases and multiple testing environments.


main (Production)
        ▲
        │
release/*
        ▲
        │
develop
   ▲
   │
feature/*

main

The production branch containing stable, production-ready code.

  • Protected branch
  • No direct commits
  • Deployment source
  • Tagged with release versions

develop

The integration branch where completed features are merged and tested before a release.


feature/*

Short-lived branches created from develop to implement individual features or bug fixes.

Examples:

feature/user-auth
feature/payment
feature/search

release/*

Created from develop when preparing a production release.

Typical activities include:

  • Final QA
  • Bug fixes
  • Documentation updates
  • Version bumping

hotfix/*

Created directly from main to fix critical production issues.

After deployment, the hotfix should be merged back into both:

  • main
  • develop

to prevent future releases from reintroducing the bug.


4. Branch Navigation & Cleanup Operations

Git introduced git switch to replace the multi-purpose git checkout command for branch navigation, reserving git restore for file operations.

Listing Branches

git branch             # List local branches
git branch -r          # List remote branches (-r = --remotes)
git branch -a          # List both local and remote branches (-a = --all)

Branch Creation & Navigation

# Modern Approach (Recommended)
git switch dev                              # Switch to existing branch
git switch -c feature/user-auth             # Create (-c = create) and switch to new branch

# Legacy Approach
git checkout dev                            # Switch to existing branch
git checkout -b feature/user-auth           # Create (-b = branch) and switch to new branch

Deleting Branches

When work on a branch is merged and completed, clean up local and remote environments:

# Local Branch Deletion
git branch -d feature/user-auth             # Safe delete (-d): Fails if unmerged changes exist
git branch -D feature/user-auth             # Force delete (-D = -d --force): Overrides safety check

# Remote Branch Deletion
git push origin --delete feature/user-auth  # Delete branch on remote repository


5. Staging, Status, & File Inspection

Inspecting Changes

git status                                  # Display working tree and staging area state
git status -s                               # Compact status output (-s = --short)
git diff                                    # Show unstaged changes against staging area
git diff --staged                           # Show staged changes against last commit

Staging Files (git add)

git add file.js                             # Stage specific file
git add .                                   # Stage all new, modified, and deleted files in current dir
git add -A                                  # Stage all changes across entire repository (-A = --all)
git add -p                                  # Interactively stage chunks of code (-p = --patch)

Discarding Local Changes (git restore)

git restore file.js                         # Discard unstaged changes in local file
git restore .                               # Discard ALL unstaged local changes (DESTRUCTIVE)
git restore --staged file.js                # Unstage file (move back to working directory)


6. Commit Conventions & Issue Linking

Commit Flags (git commit)

  • -m "message": Inline commit message.
  • -a / --all: Automatically stage modified/deleted tracked files before committing.
  • -am "message": Combined shortcut for -a and -m.
  • --amend: Overwrite or modify the most recent commit.
# Standard Commit
git commit -m "feat(auth): add JWT token validation"

# Stage tracked files and commit in one command
git commit -am "fix(cart): correct price rounding error"

# Modify last commit message or add forgotten files
git add forgotten-file.js
git commit --amend --no-edit               # Keep original message, add new changes

Conventional Commit Specification

Follow standard commit formatting: <type>(<scope>): <short summary>

  • feat: A new feature for the user.
  • fix: A bug fix.
  • docs: Documentation only changes.
  • style: Changes that do not affect code logic (formatting, white-space).
  • refactor: Code change that neither fixes a bug nor adds a feature.
  • test: Adding or correcting existing tests.
  • chore: Maintenance tasks, updates to build tools, or dependencies.

Linking Issues (GitHub / GitLab / Jira)

Use trigger keywords in your commit message or Pull Request description to close linked issues automatically when merged into the main branch:

Keywords: Fixes #123, Closes #123, Resolves #123, Refs #123

git commit -m "fix(checkout): resolve Stripe API key exposure issue

Closes #104"


7. Syncing, Merging, and Rebasing

Synchronizing Remote Changes

git fetch origin                            # Fetch remote metadata without modifying local code
git pull origin dev                         # Fetch and automatically merge remote branch into local
git pull --rebase origin dev                # Fetch and apply local commits ON TOP of remote commits

Why git pull --rebase?

By default, git pull performs a fetch followed by a merge. If both you and the remote branch have new commits, Git creates an additional merge commit, which can clutter the commit history over time.

Using git pull --rebase instead rewrites your local commits so they are replayed on top of the latest remote commits, resulting in a cleaner and more linear history.

Example:

Before pulling:

origin/dev

A──B──C

local

A──B──D──E

Using git pull:

A──B──C────────M
      \      /
       D────E

Using git pull --rebase:

A──B──C──D'──E'

The second history is easier to read, debug, and review because it avoids unnecessary merge commits.

Enterprise Best Practice

Use git pull --rebase on your local feature branches to keep commit history clean and minimize unnecessary merge commits.

When NOT to use it

Avoid rebasing commits that have already been shared with your team on a public branch, as rebasing rewrites commit history. Once a branch is shared, prefer merging unless your team's workflow explicitly allows rebasing.

Merging Strategies

# Standard Merge (creates a explicit merge commit)
git switch dev
git merge --no-ff feature/user-auth -m "merge: feature/user-auth into dev"

# Squash Merge (combines all branch commits into a single unified commit)
git switch dev
git merge --squash feature/user-auth
git commit -m "feat(auth): complete user authentication module"

  • --no-ff (No Fast-Forward): Ensures a merge commit is recorded even if the merge could be fast-forwarded. Preserves the history of the feature branch.
  • --squash: Flattens multiple micro-commits on a feature branch into one single commit before integrating.

8. Releases & Semantic Versioning (git tag)

Deployments are tracked using Git tags using Semantic Versioning (vMAJOR.MINOR.PATCH):

  • MAJOR: Incompatible API changes.
  • MINOR: Added functionality in a backward-compatible manner.
  • PATCH: Backward-compatible bug fixes.
# Create an annotated tag (-a = annotated, -m = message)
git tag -a v1.0.0 -m "Production Release v1.0.0"

# List tags
git tag -l                                  # List all tags (-l = --list)

# Push tags to remote
git push origin v1.0.0                      # Push specific tag
git push origin --tags                      # Push all local tags to remote


9. End-to-End Enterprise Workflow Execution

Scenario A: Developing a New Feature

# 1. Update dev branch
git switch dev
git pull --rebase origin dev

# 2. Create feature branch
git switch -c feature/payment-gateway

# 3. Work, stage, and commit changes
git add .
git commit -m "feat(payment): implement Stripe payment intent handler Closes #45"

# 4. Sync with dev before pushing (to catch potential conflicts early)
git fetch origin
git rebase origin/dev

# 5. Push branch and set upstream tracking (-u = --set-upstream)
git push -u origin feature/payment-gateway

# 6. Open Pull Request (PR) on GitHub/GitLab targeting 'dev'
# 7. Once approved and merged, clean up local branch
git switch dev
git pull origin dev
git branch -d feature/payment-gateway

Scenario B: Emergency Production Hotfix

# 1. Branch directly from production main
git switch main
git pull origin main
git switch -c hotfix/auth-bypass-vulnerability

# 2. Apply fix and commit
git commit -am "fix(security): patch authentication bypass vulnerability Closes #911"

# 3. Merge hotfix into main, tag it, and push
git switch main
git merge --no-ff hotfix/auth-bypass-vulnerability -m "merge: hotfix v1.0.1"
git tag -a v1.0.1 -m "Hotfix Release v1.0.1"
git push origin main --tags

# 4. Backport hotfix into dev so changes aren't lost in future releases
git switch dev
git merge --no-ff hotfix/auth-bypass-vulnerability -m "merge: backport hotfix v1.0.1 to dev"
git push origin dev

# 5. Clean up hotfix branch
git branch -d hotfix/auth-bypass-vulnerability
git push origin --delete hotfix/auth-bypass-vulnerability


10. Emergency Room: Undoing Mistakes & Data Recovery

1. Undoing Commits (git reset)

CommandWorking DirectoryStaging AreaCommit HistoryUse Case
git reset --soft HEAD~1KeptKept (Staged)UndoneRedo commit message or group commits.
git reset --mixed HEAD~1 (Default)KeptClearedUndoneModify staged files before re-committing.
git reset --hard HEAD~1DestroyedClearedUndoneDangerous. Completely destroy last commit and all local changes.

2. Reverting Public Commits (git revert)

If a bad commit is already pushed to a shared remote branch (main or dev), do not use reset. Use git revert to create a new inverse commit safely:

# Create a new commit that safely reverses changes from specified commit
git revert <commit-hash>
git push origin main

3. Temporary Workspace Storage (git stash)

Save dirty working directory state temporarily without committing:

git stash save "Work in progress on user checkout" # Save unstaged/staged changes
git stash list                                      # List saved stashes
git stash pop                                       # Apply last stash and remove it from stash list
git stash apply                                     # Apply last stash but keep it in stash list
git stash drop                                      # Remove last stash

4. Recovery of Lost Commits (git reflog)

Git keeps a log of every HEAD position movement. Even if you perform a git reset --hard, you can recover lost commits via reflog:

git reflog                                  # Display history of HEAD moves
# Output example: HEAD@{1}: reset: moving to HEAD~1
# Output example: HEAD@{2}: commit: feat(user): add user page

# Restore lost commit using hash or reference
git reset --hard HEAD@{2}


11. Master Cheatsheet & Command Options Table

CategoryCommandEssential Flags & OptionsFunction Description
Configgit config--global<br>

<br>--list | Set global user configurations<br>

<br>Display active config settings | | Branching | git switch | -c <branch> | Create and switch to new branch | | | git branch | -a<br>

<br>-r<br>

<br>-d<br>

<br>-D | List local and remote branches<br>

<br>List remote branches only<br>

<br>Delete merged branch safely<br>

<br>Force delete branch | | Inspection | git status | -s | Short/compact status output | | | git diff | --staged | Show changes staged for commit | | | git log | --oneline<br>

<br>--graph<br>

<br>--all | Display compact commit history<br>

<br>Show ASCII branch tree structure<br>

<br>Include all branches in log | | Staging | git add | . / -A<br>

<br>-p | Stage all changes<br>

<br>Interactively select chunks to stage | | | git restore | --staged<br>

<br>. | Unstage files back to working directory<br>

<br>Discard unstaged local changes | | Commit | git commit | -m "msg"<br>

<br>-am "msg"<br>

<br>--amend | Set commit message<br>

<br>Stage tracked files & commit<br>

<br>Modify previous commit | | Syncing | git fetch | --prune / -p | Remove remote-tracking branches that no longer exist on remote | | | git pull | --rebase | Apply local commits on top of fetched branch | | | git push | -u origin <branch><br>

<br>--tags<br>

<br>--delete<br>

<br>--force-with-lease | Set upstream branch pointer<br>

<br>Push annotated tags<br>

<br>Delete remote branch<br>

<br>Safely force push without overwriting team commits | | Merging | git merge | --no-ff<br>

<br>--squash | Preserve branch history with explicit merge commit<br>

<br>Flatten branch commits into single commit | | Recovery | git reset | --soft<br>

<br>--mixed<br>

<br>--hard | Keep changes staged<br>

<br>Unstage changes<br>

<br>Permanently destroy local changes | | | git revert | <hash> | Create new inverse commit for safe remote reversal | | | git reflog | N/A | Log all local HEAD updates to recover lost work |


Core Operational Rules for Engineers

  1. **Protect main and dev**: Require Pull Requests and mandatory code reviews before merging.
  2. Pull with Rebase: Keep your local history clean using git pull --rebase origin dev.
  3. Commit Atomically: Each commit should address a single, logical change.
  4. **Use force-with-lease over force**: When pushing rebased branches, use git push --force-with-lease to avoid overwriting a teammate's remote work.
  5. Clean up Merged Branches: Keep remote and local repositories free of abandoned feature branches using git branch -d and git push origin --delete.
© 2026 thisisduykhanh. All rights reserved.