DEV Community

Cover image for The Complete Git Command Reference: Mastering Version Control from Basics to Advanced
TheBitForge
TheBitForge

Posted on

The Complete Git Command Reference: Mastering Version Control from Basics to Advanced

1. Introduction to Git and Version Control {#introduction}

Version control systems are the backbone of modern software development, and Git stands as the most widely adopted distributed version control system in the world. Created by Linus Torvalds in 2005 to manage the Linux kernel's source code, Git has evolved into an indispensable tool that transcends programming—writers, designers, data scientists, and countless other professionals rely on it daily.

What Makes Git Special?

Unlike centralized version control systems like SVN or CVS, Git is fundamentally distributed. Every developer's working copy is a complete repository with full history and version-tracking capabilities, independent of network access or a central server. This architecture provides several profound advantages:

Speed: Nearly all operations are local, making Git blazingly fast compared to systems that need constant server communication.

Redundancy: Every clone is a full backup of the entire project history.

Branching: Git's branching model is exceptionally lightweight and fast, encouraging experimental workflows.

Data Integrity: Git uses SHA-1 hashing to ensure data integrity—every file and commit is checksummed, making silent corruption nearly impossible.

Non-linear Development: Multiple parallel branches of development can proceed simultaneously without interfering with each other.

The Philosophy Behind Git

Git was designed with specific goals that shape how it works:

  1. Content-addressable filesystem: Git is fundamentally a simple key-value data store where the content itself determines the key (via SHA-1 hashing).

  2. Snapshots, not differences: Unlike systems that store file changes, Git takes snapshots of your entire project at each commit.

  3. Branch-centric workflow: Branches are cheap and merging is encouraged.

  4. Distributed is better: No single point of failure; everyone has the full history.

Understanding Git's Learning Curve

Git has a reputation for complexity, and this reputation isn't entirely undeserved. However, the complexity stems not from arbitrary design choices but from Git's powerful, flexible model. Once you understand Git's internal model—how it stores data, what commits really are, how branches work—the commands begin to make intuitive sense.

This guide will take you from absolute beginner to Git expert, explaining not just what commands do, but why they work the way they do, and when you should use them. We'll cover every significant Git command with unprecedented depth, including real-world examples, internal mechanics, and expert-level variations.


2. Git's Architecture and Internal Model {#architecture}

Before diving into commands, understanding Git's internal architecture is crucial. This knowledge transforms Git from a collection of mysterious commands into a logical, predictable system.

The Object Database

At its core, Git is a content-addressable filesystem with a version control interface built on top. Everything in Git—files, directories, commits—is stored as an object in the .git/objects directory.

There are four types of objects:

1. Blob (Binary Large Object)

  • Stores file contents
  • Contains no metadata—not even the filename
  • Identified by SHA-1 hash of contents
  • Immutable once created

2. Tree

  • Represents a directory
  • Contains pointers to blobs (files) and other trees (subdirectories)
  • Stores filenames and permissions
  • Like a snapshot of directory structure

3. Commit

  • Points to a tree object (the project snapshot)
  • Contains metadata: author, committer, timestamp, message
  • Points to parent commit(s)
  • Creates the history chain

4. Tag

  • Points to a commit (usually)
  • Contains annotation metadata
  • Used for marking releases

How Git Stores Data

When you commit changes, Git:

  1. Creates blob objects for each modified file
  2. Creates tree objects representing directory structure
  3. Creates a commit object pointing to the root tree
  4. Updates the branch reference to point to the new commit

This creates an immutable, content-addressed history. Because objects are identified by content hash, identical files are stored only once (deduplication), and any corruption is immediately detectable.

References (Refs)

While objects are immutable and content-addressed, Git needs mutable pointers to track branches, tags, and other important commits. These are called references or refs, stored in .git/refs/.

Types of references:

  • refs/heads/*: Local branches
  • refs/remotes/*: Remote-tracking branches
  • refs/tags/*: Tags
  • HEAD: Special reference pointing to current branch

The Index (Staging Area)

Git uniquely features a staging area (also called the index), sitting between your working directory and the repository. This intermediate step allows you to carefully craft commits, including only the changes you want.

The index is stored in .git/index as a binary file containing:

  • List of files to be committed
  • Their blob object hashes
  • File metadata (permissions, timestamps)

The Three States

Every file in Git exists in one of three states:

  1. Modified: Changed in working directory but not staged
  2. Staged: Marked for inclusion in next commit
  3. Committed: Safely stored in repository

Understanding these states is fundamental to mastering Git's workflow.


3. Installation and Initial Configuration {#installation}

Installing Git

Git is available for all major platforms:

Linux:

# Debian/Ubuntu sudo apt-get update sudo apt-get install git # Fedora/RHEL sudo dnf install git # Arch Linux sudo pacman -S git 
Enter fullscreen mode Exit fullscreen mode

macOS:

# Using Homebrew brew install git # Or download from git-scm.com # Xcode Command Line Tools also includes Git xcode-select --install 
Enter fullscreen mode Exit fullscreen mode

Windows:

  • Download Git for Windows from git-scm.com
  • Includes Git BASH, a terminal emulator
  • Integrates with Windows Terminal

Verify Installation:

git --version 
Enter fullscreen mode Exit fullscreen mode

This displays the installed Git version, confirming successful installation.


4. git config - Configuration Management

Purpose

git config manages Git configuration at three hierarchical levels, controlling everything from user identity to default behaviors, aliases, and external tool integration.

Configuration Levels

Git configuration operates at three scopes, each overriding the previous:

1. System-level (--system)

  • Location: /etc/gitconfig (Linux/macOS) or C:\Program Files\Git\etc\gitconfig (Windows)
  • Applies to all users and repositories on the system
  • Requires administrator privileges to modify
  • Rarely used except in corporate environments

2. Global/User-level (--global)

  • Location: ~/.gitconfig or ~/.config/git/config
  • Applies to all repositories for the current user
  • Most common configuration level
  • Your identity and preferences go here

3. Repository-level (--local)

  • Location: .git/config in the repository
  • Applies only to the specific repository
  • Overrides global and system settings
  • Default when no scope specified

Essential Initial Configuration

After installing Git, you must configure your identity:

git config --global user.name "Your Full Name" git config --global user.email "your.email@example.com" 
Enter fullscreen mode Exit fullscreen mode

Why this matters: Every commit includes author information. Without configuration, Git will guess (poorly) or refuse to commit. This identity is embedded in every commit you create and cannot be easily changed later without rewriting history.

Advanced Identity Configuration:

# Set different identity for a specific repository cd /path/to/work-project git config user.name "Your Name" git config user.email "work.email@company.com" # Use conditional includes for automatic identity switching # In ~/.gitconfig: [includeIf "gitdir:~/work/"] path = ~/.gitconfig-work [includeIf "gitdir:~/personal/"] path = ~/.gitconfig-personal 
Enter fullscreen mode Exit fullscreen mode

This powerful feature automatically applies different configurations based on directory location.

Default Branch Name

Modern Git allows customizing the default branch name:

git config --global init.defaultBranch main 
Enter fullscreen mode Exit fullscreen mode

This sets "main" as the default branch for new repositories instead of "master". Many projects and platforms have adopted this convention.

Editor Configuration

Git opens an editor for commit messages, interactive rebases, and other tasks:

# Use your preferred editor git config --global core.editor "vim" git config --global core.editor "nano" git config --global core.editor "code --wait" # VS Code git config --global core.editor "subl -n -w" # Sublime Text git config --global core.editor "emacs" 
Enter fullscreen mode Exit fullscreen mode

The --wait flag (VS Code) tells Git to wait for you to close the file before continuing.

Viewing Configuration

# Show all configuration and their sources git config --list --show-origin # Show specific configuration value git config user.name # List all global configuration git config --global --list # List all local (repository) configuration git config --local --list 
Enter fullscreen mode Exit fullscreen mode

Removing Configuration

# Remove specific setting git config --global --unset user.name # Remove entire section git config --global --remove-section user 
Enter fullscreen mode Exit fullscreen mode

Advanced Configuration Options

Line Ending Configuration:

Different operating systems use different line ending conventions (CRLF on Windows, LF on Unix). Git can normalize these:

# Windows: Convert LF to CRLF on checkout, CRLF to LF on commit git config --global core.autocrlf true # macOS/Linux: Convert CRLF to LF on commit, no conversion on checkout git config --global core.autocrlf input # Disable line ending conversion entirely git config --global core.autocrlf false 
Enter fullscreen mode Exit fullscreen mode

Whitespace Handling:

# Warn about whitespace errors (trailing whitespace, etc.) git config --global core.whitespace trailing-space,space-before-tab # Make Git diff highlight whitespace errors git config --global color.diff.whitespace "red reverse" 
Enter fullscreen mode Exit fullscreen mode

Color Configuration:

# Enable colored output git config --global color.ui auto # Customize specific colors git config --global color.branch.current "yellow reverse" git config --global color.branch.local yellow git config --global color.branch.remote green git config --global color.status.added green git config --global color.status.changed yellow git config --global color.status.untracked red 
Enter fullscreen mode Exit fullscreen mode

Diff and Merge Tools:

# Configure external diff tool git config --global diff.tool meld git config --global difftool.meld.path "/usr/bin/meld" git config --global difftool.prompt false # Configure external merge tool git config --global merge.tool kdiff3 git config --global mergetool.kdiff3.path "/usr/bin/kdiff3" git config --global mergetool.prompt false git config --global mergetool.keepBackup false 
Enter fullscreen mode Exit fullscreen mode

Aliases for Efficiency:

Aliases are custom shortcuts for Git commands:

# Basic aliases git config --global alias.co checkout git config --global alias.br branch git config --global alias.ci commit git config --global alias.st status # Advanced aliases git config --global alias.unstage 'reset HEAD --' git config --global alias.last 'log -1 HEAD' git config --global alias.visual 'log --oneline --graph --decorate --all' git config --global alias.amend 'commit --amend --no-edit' # Aliases with arguments git config --global alias.show-branches '!git for-each-ref --sort=-committerdate --format="%(committerdate:short) %(refname:short)" refs/heads/' 
Enter fullscreen mode Exit fullscreen mode

The ! prefix executes the command in the shell, allowing complex operations.

Credential Storage:

Avoid repeatedly entering passwords:

# Cache credentials in memory for 15 minutes (900 seconds) git config --global credential.helper cache git config --global credential.helper 'cache --timeout=3600' # Store credentials permanently (less secure) git config --global credential.helper store # Use OS-specific credential managers # macOS Keychain git config --global credential.helper osxkeychain # Windows Credential Manager git config --global credential.helper manager-core # Linux Secret Service git config --global credential.helper libsecret 
Enter fullscreen mode Exit fullscreen mode

Push Behavior:

# Only push current branch to its upstream git config --global push.default simple # Push all matching branches git config --global push.default matching # Push current branch to branch of same name git config --global push.default current # Refuse to push if upstream differs git config --global push.default nothing 
Enter fullscreen mode Exit fullscreen mode

Pull Behavior:

# Use rebase instead of merge when pulling git config --global pull.rebase true # Only allow fast-forward merges when pulling git config --global pull.ff only 
Enter fullscreen mode Exit fullscreen mode

Performance Settings:

# Enable parallel index preload for faster operations git config --global core.preloadindex true # Enable filesystem monitor for large repositories git config --global core.fsmonitor true # Increase HTTP buffer size for large repositories git config --global http.postBuffer 524288000 
Enter fullscreen mode Exit fullscreen mode

Configuration File Format

Git configuration files use INI-style format:

[user] name = Your Name email = your.email@example.com [core] editor = vim autocrlf = input [alias] st = status co = checkout [color] ui = auto [push] default = simple 
Enter fullscreen mode Exit fullscreen mode

You can edit these files directly with a text editor, though using git config is safer.

Real-World Configuration Example

Here's a comprehensive .gitconfig for professional development:

[user] name = Jane Developer email = jane@example.com signingkey = ABC123DEF456 [core] editor = code --wait autocrlf = input whitespace = trailing-space,space-before-tab pager = delta [init] defaultBranch = main [pull] rebase = true [push] default = simple autoSetupRemote = true [fetch] prune = true [rebase] autoStash = true [merge] conflictstyle = diff3 tool = vscode [diff] colorMoved = zebra tool = vscode [alias] st = status -sb co = checkout br = branch ci = commit unstage = reset HEAD -- last = log -1 HEAD lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit amend = commit --amend --no-edit undo = reset --soft HEAD^ stash-all = stash save --include-untracked [color] ui = auto [credential] helper = osxkeychain 
Enter fullscreen mode Exit fullscreen mode

5. Repository Initialization and Cloning {#repository-basics}

git init - Initialize a New Repository

Purpose: Creates a new Git repository, transforming an ordinary directory into a version-controlled project.

Basic Usage:

# Initialize in current directory git init # Initialize in a new directory git init my-project # Initialize with specific initial branch name git init --initial-branch=main my-project # Or shorter: git init -b main my-project 
Enter fullscreen mode Exit fullscreen mode

What Actually Happens:

When you run git init, Git creates a .git subdirectory containing the entire repository structure:

.git/ ├── HEAD # Points to current branch ├── config # Repository configuration ├── description # Repository description (for GitWeb) ├── hooks/ # Hook scripts ├── info/ # Additional repository information │ └── exclude # Local .gitignore equivalent ├── objects/ # Object database │ ├── info/ │ └── pack/ └── refs/ # References (branches, tags) ├── heads/ # Local branches └── tags/ # Tags 
Enter fullscreen mode Exit fullscreen mode

Bare Repositories:

A bare repository contains only Git data (no working directory) and is used as a central sharing point:

# Create bare repository git init --bare project.git # Convention: bare repositories end with .git 
Enter fullscreen mode Exit fullscreen mode

Bare repositories are used for:

  • Central servers (like GitHub's storage)
  • Shared network repositories
  • Backup repositories

When to Use git init:

  • Starting a new project from scratch
  • Converting existing project to Git
  • Creating a local repository for experimentation
  • Setting up a central bare repository

Real-World Example:

# Start a new web project mkdir awesome-website cd awesome-website git init -b main # Create initial structure mkdir src css js touch README.md src/index.html css/style.css js/app.js # Make first commit git add . git commit -m "Initial project structure" 
Enter fullscreen mode Exit fullscreen mode

git clone - Clone a Repository

Purpose: Creates a complete local copy of a remote repository, including all history, branches, and tags.

Basic Usage:

# Clone a repository git clone https://github.com/user/repository.git # Clone into specific directory git clone https://github.com/user/repository.git my-local-name # Clone specific branch git clone -b develop https://github.com/user/repository.git # Shallow clone (limited history) git clone --depth 1 https://github.com/user/repository.git 
Enter fullscreen mode Exit fullscreen mode

Protocol Options:

Git supports several protocols for cloning:

1. HTTPS:

git clone https://github.com/user/repo.git 
Enter fullscreen mode Exit fullscreen mode
  • Most common and universally supported
  • Works through firewalls
  • Requires authentication for private repos
  • Can cache credentials

2. SSH:

git clone git@github.com:user/repo.git 
Enter fullscreen mode Exit fullscreen mode
  • Requires SSH key setup
  • More secure than HTTPS with passwords
  • No credential prompting once keys configured
  • Preferred for frequent access

3. Git Protocol:

git clone git://github.com/user/repo.git 
Enter fullscreen mode Exit fullscreen mode
  • Fastest protocol
  • No authentication (read-only for public repos)
  • Often blocked by firewalls
  • Rarely used today

4. Local Filesystem:

git clone /path/to/repository git clone file:///path/to/repository 
Enter fullscreen mode Exit fullscreen mode
  • Clone from local directories
  • Useful for network shares
  • Can hardlink objects for efficiency

What git clone Does:

  1. Creates a new directory with the repository name
  2. Initializes a .git directory inside it
  3. Fetches all repository data from remote
  4. Checks out the default branch into working directory
  5. Sets up origin remote pointing to source
  6. Creates remote-tracking branches for all remote branches

Advanced Cloning Options:

Shallow Clones:

For large repositories where you only need recent history:

# Clone only latest commit git clone --depth 1 https://github.com/user/large-repo.git # Clone with last 50 commits git clone --depth 50 https://github.com/user/repo.git # Shallow clone single branch git clone --depth 1 --single-branch --branch main https://github.com/user/repo.git 
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Faster cloning
  • Less disk space
  • Faster operations on huge repositories

Limitations:

  • Cannot push to shallow clones
  • Limited history access
  • Cannot clone from shallow clones

Deepen Shallow Clones:

# Fetch more history git fetch --depth=100 # Convert to full clone git fetch --unshallow 
Enter fullscreen mode Exit fullscreen mode

Partial Clones (Sparse Checkout):

Clone without immediately downloading all files:

# Clone with blob filtering (no file contents initially) git clone --filter=blob:none https://github.com/user/repo.git # Clone with tree filtering (fetch trees on-demand) git clone --filter=tree:0 https://github.com/user/repo.git 
Enter fullscreen mode Exit fullscreen mode

Files are downloaded on-demand when checked out. Perfect for monorepos where you only work on specific areas.

Mirror Clones:

Create an exact mirror of the repository:

# Mirror clone (includes all refs and history) git clone --mirror https://github.com/user/repo.git # Useful for backups or creating exact replicas 
Enter fullscreen mode Exit fullscreen mode

Submodule Handling:

# Clone repository and initialize submodules git clone --recursive https://github.com/user/repo.git # Or equivalently: git clone --recurse-submodules https://github.com/user/repo.git 
Enter fullscreen mode Exit fullscreen mode

Configuration During Clone:

# Set configuration during clone git clone -c http.proxy=http://proxy.example.com:8080 https://github.com/user/repo.git # Set branch name git clone -c init.defaultBranch=main https://github.com/user/repo.git 
Enter fullscreen mode Exit fullscreen mode

Clone and Checkout Specific Commit:

# Clone then checkout specific commit git clone https://github.com/user/repo.git cd repo git checkout abc123def456 
Enter fullscreen mode Exit fullscreen mode

Real-World Scenarios:

Scenario 1: Contributing to Open Source

# Clone the project git clone https://github.com/original/project.git cd project # Add your fork as remote git remote add myfork git@github.com:yourname/project.git # Create feature branch git checkout -b feature/awesome-addition # Work, commit, push to your fork git push -u myfork feature/awesome-addition 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Large Repository (e.g., Linux Kernel)

# Shallow clone for quick start git clone --depth 1 --single-branch --branch master https://github.com/torvalds/linux.git # Later, if you need more history cd linux git fetch --unshallow 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Backup Creation

# Create exact mirror for backup git clone --mirror https://github.com/company/critical-project.git backup.git # Update backup regularly cd backup.git git remote update 
Enter fullscreen mode Exit fullscreen mode

6. The Three Trees: Working Directory, Staging Area, and Repository {#three-trees}

Understanding Git's three-tree architecture is essential for mastering its workflow. These "trees" represent three different states of your project:

The Three Trees Explained

1. Working Directory (Working Tree)

  • Your actual project files
  • What you see in your file explorer
  • Where you make changes
  • Can contain untracked, modified, or clean files

2. Staging Area (Index)

  • Proposed next commit
  • Intermediate storage between working directory and repository
  • Allows selective committing
  • Stored in .git/index

3. Repository (HEAD)

  • Committed history
  • Permanent storage of snapshots
  • Immutable object database
  • Organized as commits, trees, and blobs

The Git Workflow Cycle

Working Directory → (git add) → Staging Area → (git commit) → Repository ← (git checkout) ← ← (git reset) ← 
Enter fullscreen mode Exit fullscreen mode

Visual Representation

┌─────────────────────┐ │ Working Directory │ ← Your files as you edit them │ - file1.txt │ │ - file2.txt │ └─────────────────────┘ │ │ git add ▼ ┌─────────────────────┐ │ Staging Area │ ← Files staged for commit │ - file1.txt │ └─────────────────────┘ │ │ git commit ▼ ┌─────────────────────┐ │ Repository (HEAD) │ ← Committed history │ - commit abc123 │ │ - commit def456 │ └─────────────────────┘ 
Enter fullscreen mode Exit fullscreen mode

7. Basic Git Workflow Commands {#basic-workflow}

git status - Check Repository Status

Purpose: Shows the state of the working directory and staging area. This is your primary diagnostic command.

Basic Usage:

# Full status git status # Short format git status -s git status --short # Show branch and tracking info git status -sb git status --short --branch 
Enter fullscreen mode Exit fullscreen mode

Understanding Output:

Full Status Output:

$ git status On branch main Your branch is up to date with 'origin/main'. Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: file1.txt new file: file2.txt Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: file3.txt Untracked files: (use "git add <file>..." to include in what will be committed) file4.txt 
Enter fullscreen mode Exit fullscreen mode

Section Breakdown:

  1. Current Branch: Which branch you're on
  2. Branch Status: Relationship to remote tracking branch
  3. Changes to be committed: Staged changes (green in color terminals)
  4. Changes not staged: Modified but not staged (red in color terminals)
  5. Untracked files: New files Git doesn't know about

Short Status Format:

$ git status -s M file1.txt # Modified and staged M file3.txt # Modified but not staged A file2.txt # Added (new file staged) ?? file4.txt # Untracked MM file5.txt # Modified, staged, then modified again 
Enter fullscreen mode Exit fullscreen mode

Status Codes:

  • ?? - Untracked
  • A - Added (staged)
  • M - Modified
  • D - Deleted
  • R - Renamed
  • C - Copied
  • U - Updated but unmerged (conflict)

Advanced Usage:

# Show ignored files git status --ignored # Show untracked files in detail git status -u git status --untracked-files=all # Machine-readable format (for scripts) git status --porcelain # Show status with file stats git status -v git status --verbose 
Enter fullscreen mode Exit fullscreen mode

Why Use git status Frequently:

Running git status before and after operations helps you:

  • Understand current repository state
  • Prevent accidental commits
  • Verify operations completed successfully
  • Catch uncommitted changes before switching branches
  • Identify merge conflicts

Best Practice: Run git status constantly. It's fast, safe, and informative.


git add - Stage Changes

Purpose: Adds file contents to the staging area, preparing them for commit. This is how you tell Git which changes to include in the next commit.

Basic Usage:

# Stage specific file git add filename.txt # Stage multiple files git add file1.txt file2.txt file3.txt # Stage all changes in current directory and subdirectories git add . # Stage all changes in repository git add -A git add --all # Stage all modified and deleted files (not new files) git add -u git add --update 
Enter fullscreen mode Exit fullscreen mode

Understanding the Differences:

Command New Files Modified Files Deleted Files Scope
git add . Current directory and below
git add -A Entire repository
git add -u Entire repository

Interactive Staging:

The most powerful git add feature is interactive mode, allowing surgical precision in staging changes:

# Enter interactive mode git add -i git add --interactive 
Enter fullscreen mode Exit fullscreen mode

Interactive Mode Menu:

*** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help 
Enter fullscreen mode Exit fullscreen mode

Patch Mode (Most Useful):

# Stage parts of files interactively git add -p filename.txt git add --patch filename.txt # Patch mode for all files git add -p 
Enter fullscreen mode Exit fullscreen mode

Patch Mode Commands:

When in patch mode, Git shows each change hunk and asks what to do:

  • y - Stage this hunk
  • n - Don't stage this hunk
  • q - Quit; don't stage this or remaining hunks
  • a - Stage this and all remaining hunks in file
  • d - Don't stage this or any remaining hunks in file
  • s - Split the hunk into smaller hunks
  • e - Manually edit the hunk
  • ? - Print help

Example Patch Mode Session:

$ git add -p example.py diff --git a/example.py b/example.py index 1234567..abcdefg 100644 --- a/example.py +++ b/example.py @@ -10,6 +10,7 @@ def process_data(data): result = [] for item in data: processed = transform(item) + validated = validate(processed) result.append(processed) return result Stage this hunk [y,n,q,a,d,s,e,?]? y 
Enter fullscreen mode Exit fullscreen mode

Staging by File Type:

# Stage all Python files git add *.py # Stage all files in directory git add src/ # Stage all .txt files recursively git add '*.txt' 
Enter fullscreen mode Exit fullscreen mode

Note: Quote wildcards to prevent shell expansion.

Force Adding Ignored Files:

# Add file even if in .gitignore git add -f ignored-file.txt git add --force ignored-file.txt 
Enter fullscreen mode Exit fullscreen mode

Intent to Add:

# Register untracked file without staging content git add -N newfile.txt git add --intent-to-add newfile.txt 
Enter fullscreen mode Exit fullscreen mode

This makes the file visible to git diff without staging it.

Dry Run:

# Show what would be added git add --dry-run . git add -n . 
Enter fullscreen mode Exit fullscreen mode

Verbose Mode:

# Show added files git add -v file.txt git add --verbose file.txt 
Enter fullscreen mode Exit fullscreen mode

Real-World Scenarios:

Scenario 1: Commit Related Changes Separately

You've fixed a bug and also refactored unrelated code. Commit them separately:

# Stage only bug fix git add src/buggy_module.py git commit -m "Fix: Resolve null pointer exception" # Stage refactoring git add src/refactored_module.py git commit -m "Refactor: Improve code readability" 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Stage Part of a File

You've made multiple independent changes in one file. Stage them separately:

git add -p complex_file.py # Stage first logical change: y # Skip unrelated change: n git commit -m "Add validation function" # Now stage the second change git add -p complex_file.py # Stage second logical change: y git commit -m "Add logging" 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Stage Everything Except One File

# Stage all changes git add -A # Unstage one file git restore --staged unwanted.txt 
Enter fullscreen mode Exit fullscreen mode

Common Mistakes:

Mistake 1: Using git add . in wrong directory

# You're in src/ but meant to stage root files pwd # /home/user/project/src git add . # Only stages src/ contents! # Solution: Navigate to repository root or use -A cd .. git add -A 
Enter fullscreen mode Exit fullscreen mode

Mistake 2: Forgetting to stage after modifications

git add file.txt # Edit file.txt more git commit -m "Update file" # Doesn't include latest edits! # Solution: Always check status before committing git status git add file.txt # Stage latest changes git commit -m "Update file" 
Enter fullscreen mode Exit fullscreen mode

Mistake 3: Accidentally staging sensitive data

# Accidentally added secrets file git add config/secrets.yml # Solution: Unstage immediately git restore --staged config/secrets.yml # Add to .gitignore echo "config/secrets.yml" >> .gitignore 
Enter fullscreen mode Exit fullscreen mode

git commit - Record Changes to Repository

Purpose: Creates a snapshot of staged changes in the repository, permanently recording them in project history with metadata (author, timestamp, message).

Basic Usage:

# Commit with inline message git commit -m "Add user authentication feature" # Open editor for commit message git commit # Commit with detailed message git commit -m "Add user authentication" -m "- Implement JWT tokens" -m "- Add login endpoint" -m "- Add tests" 
Enter fullscreen mode Exit fullscreen mode

Commit Message Best Practices:

A good commit message has structure:

Short summary (50 characters or less) More detailed explanatory text, if necessary. Wrap it to about 72 characters. The blank line separating the summary from the body is critical; tools like git log --oneline will only show the summary. Explain the problem that this commit is solving. Focus on why you are making this change as opposed to how (the code explains that). Are there side effects or other unintuitive consequences of this change? Here's the place to explain them. - Bullet points are okay - Use a hyphen or asterisk for bullets If you use an issue tracker, put references to them at the bottom: Resolves: #123 See also: #456, #789 
Enter fullscreen mode Exit fullscreen mode

Conventional Commits Format:

Many teams use structured commit messages:

git commit -m "feat: add user authentication with JWT" git commit -m "fix: resolve null pointer in payment processing" git commit -m "docs: update API documentation" git commit -m "refactor: simplify database query logic" git commit -m "test: add unit tests for auth module" git commit -m "chore: update dependencies" 
Enter fullscreen mode Exit fullscreen mode

Types:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • style: Code style changes (formatting, semicolons, etc.)
  • refactor: Code refactoring
  • perf: Performance improvements
  • test: Adding or updating tests
  • chore: Maintenance tasks
  • ci: CI/CD changes
  • build: Build system changes

Advanced Commit Options:

Skip Staging Area:

# Stage and commit modified tracked files in one step git commit -a -m "Update all tracked files" git commit -am "Update all tracked files" 
Enter fullscreen mode Exit fullscreen mode

⚠️ Warning: This doesn't include untracked files, only modified tracked files.

Amend Previous Commit:

# Modify the last commit git commit --amend # Amend without changing message git commit --amend --no-edit # Amend and change message git commit --amend -m "Corrected commit message" 
Enter fullscreen mode Exit fullscreen mode

What --amend does:

  • Replaces the last commit entirely
  • Includes currently staged changes
  • Allows message modification
  • Changes commit SHA (rewrites history)

⚠️ Critical Warning: Never amend commits that have been pushed to shared branches. This rewrites history and causes problems for collaborators.

Use case for amend:

# Made a commit git commit -m "Add feature X" # Oops, forgot to include a file git add forgotten-file.txt git commit --amend --no-edit # Or fix typo in commit message git commit --amend -m "Add feature X (corrected)" 
Enter fullscreen mode Exit fullscreen mode

Empty Commits:

# Create commit without changes (useful for triggering CI/CD) git commit --allow-empty -m "Trigger CI pipeline" 
Enter fullscreen mode Exit fullscreen mode

Commit with Specific Date:

# Set custom commit date git commit --date="2024-01-15 10:30:00" -m "Backdated commit" # Use author date instead of commit date GIT_AUTHOR_DATE="2024-01-15 10:30:00" git commit -m "Message" 
Enter fullscreen mode Exit fullscreen mode

Commit as Different Author:

# Commit with different author git commit --author="Jane Doe <jane@example.com>" -m "Fix bug" 
Enter fullscreen mode Exit fullscreen mode

Useful when:

  • Applying patches from others
  • Committing on behalf of someone
  • Maintaining proper attribution

Sign Commits (GPG):

# Sign commit with GPG key git commit -S -m "Signed commit" git commit --gpg-sign -m "Signed commit" # Configure automatic signing git config --global commit.gpgsign true 
Enter fullscreen mode Exit fullscreen mode

Signed commits prove authenticity and are required by many organizations.

Verbose Mode:

# Show diff in commit message editor git commit -v git commit --verbose 
Enter fullscreen mode Exit fullscreen mode

This displays the diff below the commit message template, helping you write accurate messages.

Template Messages:

# Use commit message template git config --global commit.template ~/.gitmessage.txt 
Enter fullscreen mode Exit fullscreen mode

Example template (~/.gitmessage.txt):

# [Type] Short description (max 50 chars) # Detailed description (wrap at 72 chars) # Explain WHY this change is being made # Related issues # Resolves: # # See also: # 
Enter fullscreen mode Exit fullscreen mode

Partial Commits with Interactive Staging:

# Stage specific changes, then commit git add -p file.txt git commit -m "Add first feature" git add -p file.txt git commit -m "Add second feature" 
Enter fullscreen mode Exit fullscreen mode

Commit Only Specific Files:

# Commit specific files, bypassing staging area git commit file1.txt file2.txt -m "Update specific files" 
Enter fullscreen mode Exit fullscreen mode

Reuse Previous Message:

# Reuse message from previous commit git commit -C HEAD -m "Same message as before" # Edit the reused message git commit -c HEAD 
Enter fullscreen mode Exit fullscreen mode

Real-World Commit Strategies:

Atomic Commits:

Each commit should be a single logical unit:

# Bad: Everything in one commit git add . git commit -m "Various updates" # Good: Separate logical commits git add src/auth.js git commit -m "feat: add JWT authentication" git add src/validation.js git commit -m "feat: add input validation" git add tests/auth.test.js git commit -m "test: add authentication tests" git add README.md git commit -m "docs: update authentication section" 
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Easier code review
  • Simpler to revert specific changes
  • Clearer history
  • Better bisecting for bugs

Commit Frequency:

# Too infrequent (bad) # Work all day, commit once with "Day's work" # Too frequent (bad) # Commit after every line change # Just right (good) # Commit after each logical, working change git commit -m "feat: add login form" git commit -m "feat: add form validation" git commit -m "feat: connect form to API" git commit -m "test: add login form tests" 
Enter fullscreen mode Exit fullscreen mode

Work-in-Progress Commits:

For checkpoint commits you'll squash later:

# Quick checkpoint git commit -m "WIP: working on feature X" # More checkpoints git commit -m "WIP: partial implementation" # Before pushing, squash WIP commits git rebase -i HEAD~3 # Mark WIP commits with 'squash' or 'fixup' 
Enter fullscreen mode Exit fullscreen mode

Commit Verification:

Before committing, verify:

# Check what's staged git diff --staged git diff --cached # Check status git status # Run tests npm test # or your test command # Then commit git commit -m "feat: add feature X" 
Enter fullscreen mode Exit fullscreen mode

Commit Message Examples by Type:

Feature Addition:

git commit -m "feat: add password reset functionality Implement password reset workflow: - Add /forgot-password endpoint - Send email with reset token - Add token validation - Allow password update with valid token Closes #234" 
Enter fullscreen mode Exit fullscreen mode

Bug Fix:

git commit -m "fix: resolve race condition in payment processing The payment confirmation was sometimes sent before database commit, causing confusion when users refreshed and saw 'pending' status. Now we ensure database commit completes before sending confirmation. Fixes #567" 
Enter fullscreen mode Exit fullscreen mode

Refactoring:

git commit -m "refactor: extract user validation into separate module No functional changes. Improves code organization and makes validation logic reusable across auth and profile modules." 
Enter fullscreen mode Exit fullscreen mode

Documentation:

git commit -m "docs: add API authentication guide Add comprehensive guide covering: - JWT token generation - Token refresh flow - Error handling - Code examples in multiple languages" 
Enter fullscreen mode Exit fullscreen mode

git diff - Show Changes

Purpose: Shows differences between various Git states: working directory, staging area, commits, branches, and more. Essential for understanding what changed.

Basic Usage:

# Show unstaged changes (working directory vs staging area) git diff # Show staged changes (staging area vs last commit) git diff --staged git diff --cached # Show all changes (working directory vs last commit) git diff HEAD 
Enter fullscreen mode Exit fullscreen mode

Understanding Diff Output:

$ git diff example.txt diff --git a/example.txt b/example.txt index 1234567..abcdefg 100644 --- a/example.txt +++ b/example.txt @@ -1,5 +1,6 @@ Line 1 Line 2 -Line 3 +Line 3 modified +Line 4 added Line 5 
Enter fullscreen mode Exit fullscreen mode

Output breakdown:

  1. diff --git a/example.txt b/example.txt: Compared files
  2. index 1234567..abcdefg: Object hashes
  3. --- a/example.txt: Original file
  4. +++ b/example.txt: Modified file
  5. @@ -1,5 +1,6 @@: Hunk header (old range, new range)
  6. Lines with -: Removed
  7. Lines with +: Added
  8. Lines with no prefix: Context (unchanged)

Comparing Commits:

# Compare two commits git diff commit1 commit2 # Compare with specific commit git diff abc123 # Compare with HEAD git diff HEAD git diff HEAD~1 # One commit before HEAD git diff HEAD~5 # Five commits before HEAD # Compare with branch git diff main git diff origin/main 
Enter fullscreen mode Exit fullscreen mode

Comparing Branches:

# Show differences between branches git diff main..feature-branch # Show what's in feature-branch but not in main git diff main...feature-branch # Compare current branch with main git diff main 
Enter fullscreen mode Exit fullscreen mode

Difference between .. and ...:

  • git diff main..feature: Changes between the tips of both branches
  • git diff main...feature: Changes in feature since it diverged from main (more useful)

Specific File Diff:

# Diff specific file git diff filename.txt # Diff specific file between commits git diff commit1 commit2 filename.txt # Diff specific file on different branch git diff main:file.txt feature:file.txt 
Enter fullscreen mode Exit fullscreen mode

Diff Statistics:

# Show summary statistics git diff --stat # Show statistics and brief diff git diff --shortstat # Show file name and statistics git diff --numstat # Show summary of changes git diff --summary 
Enter fullscreen mode Exit fullscreen mode

Example output:

$ git diff --stat file1.txt | 10 +++++----- file2.txt | 5 +++++ file3.txt | 15 --------------- 3 files changed, 15 insertions(+), 20 deletions(-) 
Enter fullscreen mode Exit fullscreen mode

Word-Level Diff:

# Show word-by-word differences (better for prose) git diff --word-diff # Color word diff git diff --word-diff=color # Show only changed words git diff --word-diff=plain 
Enter fullscreen mode Exit fullscreen mode

Ignoring Whitespace:

# Ignore whitespace changes git diff -w git diff --ignore-all-space # Ignore whitespace at line end git diff --ignore-space-at-eol # Ignore whitespace amount changes git diff -b git diff --ignore-space-change 
Enter fullscreen mode Exit fullscreen mode

Context Lines:

# Show 10 lines of context instead of default 3 git diff -U10 git diff --unified=10 # Show entire file git diff --unified=999999 # Show only changes, no context git diff -U0 
Enter fullscreen mode Exit fullscreen mode

Color and Highlighting:

# Force color output (useful for piping) git diff --color # Highlight moved code git diff --color-moved # Show whitespace errors git diff --check 
Enter fullscreen mode Exit fullscreen mode

Diff Tools:

# Use external diff tool git difftool # Use specific tool git difftool --tool=meld # Compare directory git difftool --dir-diff 
Enter fullscreen mode Exit fullscreen mode

Advanced Diff Options:

Function Context:

# Show function name in hunk headers git diff -p git diff --show-function # For Python/Java/C, shows which function changed 
Enter fullscreen mode Exit fullscreen mode

Rename Detection:

# Detect renames (default) git diff -M git diff --find-renames # Detect renames with threshold (50% similarity) git diff -M50% # Detect copies as well git diff -C git diff --find-copies 
Enter fullscreen mode Exit fullscreen mode

Binary Files:

# Show binary files changed git diff --binary # Don't show binary file differences git diff --no-binary 
Enter fullscreen mode Exit fullscreen mode

Diff Algorithms:

# Use different diff algorithm git diff --minimal # Spend extra time to find smaller diff git diff --patience # Patience algorithm (better for complex changes) git diff --histogram # Histogram algorithm (fast and good) # Configure default algorithm git config --global diff.algorithm histogram 
Enter fullscreen mode Exit fullscreen mode

Diff Filters:

# Show only added files git diff --diff-filter=A # Show only deleted files git diff --diff-filter=D # Show only modified files git diff --diff-filter=M # Show renamed files git diff --diff-filter=R # Combine filters (added or modified) git diff --diff-filter=AM 
Enter fullscreen mode Exit fullscreen mode

Real-World Diff Scenarios:

Scenario 1: Pre-Commit Review

# Review what you're about to commit git diff --staged # If using multiple stages, review each step git diff # Unstaged changes git diff --staged # Staged changes git diff HEAD # All changes since last commit 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Code Review

# Review all changes in feature branch git diff main...feature-branch # Review specific file changes git diff main...feature-branch -- src/ # Get statistics for pull request git diff main...feature-branch --stat 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Finding When Bug Was Introduced

# Compare current broken state with last known good commit git diff known-good-commit current-broken-commit # Focus on specific problematic file git diff known-good-commit current-broken-commit -- src/buggy-file.js 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Reviewing Others' Changes

# See what changed in latest pull git fetch git diff HEAD origin/main # Review changes before merging git diff main origin/feature-branch 
Enter fullscreen mode Exit fullscreen mode

Scenario 5: Checking Whitespace Issues

# Find whitespace errors before committing git diff --check # See exactly what whitespace changed git diff --ws-error-highlight=all 
Enter fullscreen mode Exit fullscreen mode

Creating Patches:

# Create patch file git diff > changes.patch # Create patch for specific commits git diff commit1 commit2 > feature.patch # Apply patch git apply changes.patch # Apply patch and stage changes git apply --index changes.patch 
Enter fullscreen mode Exit fullscreen mode

Diff Output Formats:

# Default unified format git diff # Context format (old-style) git diff --context # Raw format (for scripts) git diff --raw # Name only git diff --name-only # Name and status git diff --name-status 
Enter fullscreen mode Exit fullscreen mode

Performance Optimization:

# For large repositories, limit diff git diff --patience # More accurate but slower git diff --minimal # Spend extra time finding minimal diff git diff -U0 # No context (faster) # Skip binary files git diff --no-binary 
Enter fullscreen mode Exit fullscreen mode

git restore - Restore Working Tree Files

Purpose: Modern command (Git 2.23+) for discarding changes in working directory or unstaging files. Replaces old git checkout and git reset usage for these purposes.

Basic Usage:

# Discard changes in working directory (restore from staging area or HEAD) git restore filename.txt # Discard all changes git restore . # Unstage file (restore staging area from HEAD) git restore --staged filename.txt # Unstage all files git restore --staged . 
Enter fullscreen mode Exit fullscreen mode

Understanding git restore:

git restore operates on two main areas:

  1. Working directory: Discard local modifications
  2. Staging area: Unstage changes

Restore from Different Sources:

# Restore from HEAD (last commit) git restore --source=HEAD filename.txt # Restore from specific commit git restore --source=abc123 filename.txt # Restore from different branch git restore --source=main filename.txt # Restore from previous commit git restore --source=HEAD~1 filename.txt 
Enter fullscreen mode Exit fullscreen mode

Restore Both Working Directory and Staging Area:

# Restore file in both working directory and staging area git restore --staged --worktree filename.txt # Short version git restore -SW filename.txt 
Enter fullscreen mode Exit fullscreen mode

Interactive Restore:

# Interactively choose changes to discard git restore -p filename.txt git restore --patch filename.txt 
Enter fullscreen mode Exit fullscreen mode

Similar to git add -p, this lets you selectively discard hunks of changes.

Restore Specific Paths:

# Restore entire directory git restore src/ # Restore by pattern git restore '*.txt' # Restore from specific source and path git restore --source=main -- src/ 
Enter fullscreen mode Exit fullscreen mode

Advanced Options:

# Show what would be restored (dry run) git restore --dry-run filename.txt # Merge restored content (when conflicts) git restore --merge filename.txt # Keep unmerged entries (during conflict resolution) git restore --ours filename.txt git restore --theirs filename.txt 
Enter fullscreen mode Exit fullscreen mode

Overlay vs No-Overlay Mode:

# Overlay mode (default): only restore specified files git restore --overlay filename.txt # No-overlay: remove files in target that aren't in source git restore --no-overlay --source=main src/ 
Enter fullscreen mode Exit fullscreen mode

Real-World Scenarios:

Scenario 1: Undo Accidental Changes

# Oops, made unwanted changes to file git status # modified: important-file.txt # Discard changes git restore important-file.txt # Verify git status # nothing to commit, working tree clean 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Unstage Accidentally Added File

# Added wrong file git add secrets.txt git status # Changes to be committed: secrets.txt # Unstage it git restore --staged secrets.txt git status # Untracked files: secrets.txt # Add to .gitignore echo "secrets.txt" >> .gitignore 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Partially Discard Changes

# File has multiple changes, keep some, discard others git restore -p complex-file.js # Interactively choose: # y - discard this hunk # n - keep this hunk # q - quit # s - split into smaller hunks 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Restore File from Different Branch

# Need version of file from main branch git restore --source=main -- config/settings.json # This brings main's version to working directory without switching branches 
Enter fullscreen mode Exit fullscreen mode

Scenario 5: Completely Reset File

# Staged changes AND working directory changes git restore -SW buggy-file.py # File now matches HEAD exactly 
Enter fullscreen mode Exit fullscreen mode

Comparison with Old Commands:

Before Git 2.23, you'd use:

# OLD WAY (still works but discouraged) git checkout -- filename.txt # Discard changes git reset HEAD filename.txt # Unstage # NEW WAY (clearer) git restore filename.txt # Discard changes git restore --staged filename.txt # Unstage 
Enter fullscreen mode Exit fullscreen mode

The new git restore is clearer in intent and safer.

Safety Warnings:

⚠️ Critical: git restore permanently discards changes in working directory. There's no undo (unless you have editor backups or IDE history).

# DANGEROUS: Discards ALL local changes git restore . # SAFER: Check what you're about to discard git diff # See unstaged changes git status # See overall state git stash # Consider stashing instead # Then decide git restore filename.txt # Discard specific file 
Enter fullscreen mode Exit fullscreen mode

git rm - Remove Files

Purpose: Remove files from working directory AND stage the removal for commit. Combines file system deletion with Git staging.

Basic Usage:

# Remove file from working directory and stage deletion git rm filename.txt # Remove multiple files git rm file1.txt file2.txt file3.txt # Remove all .log files git rm *.log # Remove directory recursively git rm -r directory/ 
Enter fullscreen mode Exit fullscreen mode

What git rm Does:

  1. Deletes file from working directory
  2. Stages the deletion (ready for commit)
  3. After commit, file is removed from repository history going forward

Remove from Git Only (Keep File Locally):

# Stop tracking file but keep in working directory git rm --cached filename.txt # Remove from Git, keep locally (common for .env files) git rm --cached .env echo ".env" >> .gitignore git commit -m "Stop tracking .env file" 
Enter fullscreen mode Exit fullscreen mode

This is crucial when you accidentally committed sensitive files.

Force Removal:

# Force remove (even if file has uncommitted changes) git rm -f filename.txt git rm --force filename.txt 
Enter fullscreen mode Exit fullscreen mode

⚠️ Warning: This discards uncommitted changes. Use cautiously.

Dry Run:

# See what would be removed git rm --dry-run -r directory/ git rm -n *.txt 
Enter fullscreen mode Exit fullscreen mode

Remove Files Matching Pattern:

# Remove all .txt files in directory git rm directory/*.txt # Remove all .log files recursively git rm -r '*.log' 
Enter fullscreen mode Exit fullscreen mode

Note: Quote wildcards to prevent shell expansion.

Handling Modified Files:

If file has uncommitted changes:

$ git rm modified-file.txt error: the following file has changes staged in the index: modified-file.txt # Options: # 1. Commit changes first git commit -am "Save changes before removing" git rm modified-file.txt # 2. Force remove (loses changes) git rm -f modified-file.txt # 3. Unstage and remove git restore --staged modified-file.txt git rm modified-file.txt 
Enter fullscreen mode Exit fullscreen mode

Real-World Scenarios:

Scenario 1: Remove Accidentally Committed Secrets

# OH NO! Committed API keys git rm --cached config/secrets.yml echo "config/secrets.yml" >> .gitignore git commit -m "Remove secrets file from tracking" # Note: This doesn't remove from history! # File still exists in previous commits # For complete removal, need git filter-branch or BFG Repo-Cleaner 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Cleanup Obsolete Files

# Remove entire deprecated module git rm -r src/old-module/ git commit -m "Remove deprecated authentication module" 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Convert to Ignored Files

# Stop tracking node_modules but keep locally git rm -r --cached node_modules/ echo "node_modules/" >> .gitignore git commit -m "Stop tracking node_modules" 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Mass File Removal

# Remove all temporary files git rm '*.tmp' '*.cache' '*.swp' git commit -m "Remove temporary files" 
Enter fullscreen mode Exit fullscreen mode

Comparison with Regular File Deletion:

Method 1: Regular deletion (BAD for Git)

rm filename.txt # Delete file git add filename.txt # Stage deletion git commit -m "Remove file" 
Enter fullscreen mode Exit fullscreen mode

Method 2: Git rm (GOOD)

git rm filename.txt # Delete AND stage in one step git commit -m "Remove file" 
Enter fullscreen mode Exit fullscreen mode

git rm is cleaner and prevents forgotten staging.

Method 3: Delete then commit -a

rm filename.txt git commit -am "Remove file" # Works but less explicit 
Enter fullscreen mode Exit fullscreen mode

Recovery from git rm:

If you haven't committed yet:

# Undo git rm before commit git restore --staged filename.txt # Unstage git restore filename.txt # Restore file # Or in one step (old command) git checkout HEAD filename.txt 
Enter fullscreen mode Exit fullscreen mode

If you've committed:

# Restore file from previous commit git restore --source=HEAD~1 filename.txt # Or checkout from history git checkout HEAD~1 -- filename.txt 
Enter fullscreen mode Exit fullscreen mode

git mv - Move or Rename Files

Purpose: Move or rename files while maintaining Git history tracking. Git automatically detects renames, but git mv makes it explicit and efficient.

Basic Usage:

# Rename file git mv oldname.txt newname.txt # Move file to directory git mv file.txt directory/ # Move and rename git mv old-name.txt new-directory/new-name.txt # Move directory git mv old-directory/ new-directory/ 
Enter fullscreen mode Exit fullscreen mode

What git mv Does:

  1. Renames/moves file in working directory
  2. Stages the change (ready for commit)
  3. Git tracks it as a rename (not delete + add)

Internally, git mv is equivalent to:

mv oldname.txt newname.txt git rm oldname.txt git add newname.txt 
Enter fullscreen mode Exit fullscreen mode

But git mv is cleaner and more explicit.

Git's Rename Detection:

Git doesn't actually store renames—it detects them by content similarity:

# These are equivalent: git mv file.txt renamed.txt # Same as: mv file.txt renamed.txt git add renamed.txt git rm file.txt 
Enter fullscreen mode Exit fullscreen mode

Git sees the content is similar and marks it as a rename.

Checking Rename Detection:

# Status shows rename $ git mv readme.txt README.md $ git status Changes to be committed: renamed: readme.txt -> README.md # In log git log --follow README.md # Shows history through renames 
Enter fullscreen mode Exit fullscreen mode

Force Move/Rename:

# Overwrite existing file (dangerous!) git mv -f source.txt destination.txt git mv --force source.txt destination.txt 
Enter fullscreen mode Exit fullscreen mode

Dry Run:

# See what would happen git mv -n oldname.txt newname.txt git mv --dry-run oldname.txt newname.txt 
Enter fullscreen mode Exit fullscreen mode

Handling Case-Sensitive Renames:

On case-insensitive filesystems (Windows, macOS), renaming file.txt to File.txt is tricky:

# This might not work on case-insensitive systems: git mv file.txt File.txt # Solution: use intermediate name git mv file.txt temp.txt git mv temp.txt File.txt git commit -m "Fix file name casing" 
Enter fullscreen mode Exit fullscreen mode

Real-World Scenarios:

Scenario 1: Reorganize Project Structure

# Move related files into subdirectory mkdir utils git mv helper1.py utils/ git mv helper2.py utils/ git mv validator.py utils/ git commit -m "Organize utility functions into utils/ directory" 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Rename for Conventions

# Rename to follow naming convention git mv myComponent.js MyComponent.js # React component git mv database_helper.py db_helper.py # Python convention git commit -m "Rename files to follow project conventions" 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Mass Renaming

# Rename multiple files (using shell script) for file in *.html; do git mv "$file" "${file%.html}.htm" done git commit -m "Change file extension from .html to .htm" 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Rename with History Preservation

# Rename file git mv old-implementation.js new-implementation.js git commit -m "Rename old-implementation to new-implementation" # View history following renames git log --follow new-implementation.js # Shows full history including when it was "old-implementation.js" 
Enter fullscreen mode Exit fullscreen mode

Rename Detection Threshold:

Git detects renames based on content similarity:

# Configure similarity threshold (default 50%) git config diff.renameLimit 1000 git config diff.renames copies # Also detect copies # View renames in log with similarity percentage git log --stat -M # Show renames git log --stat -C # Show renames and copies 
Enter fullscreen mode Exit fullscreen mode

Advanced Rename Options:

# Detect renames even if only 30% similar git log --find-renames=30% # Show exact rename percentage git log --stat -M --summary 
Enter fullscreen mode Exit fullscreen mode

When Manual Rename Detection Fails:

If Git doesn't detect a rename automatically:

# After manual move mv oldname.txt newname.txt # Git shows as delete + add $ git status deleted: oldname.txt untracked: newname.txt # Fix it git rm oldname.txt git add newname.txt # Commit with both staged git commit -m "Rename oldname to newname" # Git will detect rename if content is similar enough 
Enter fullscreen mode Exit fullscreen mode

8. Branching and Branch Management {#branching}

Branches are one of Git's most powerful features, allowing parallel lines of development without affecting the main codebase. Understanding branching is essential for effective Git use.

What Is a Branch?

A branch is simply a movable pointer to a commit. Git's default branch is typically main or master. When you create a branch, you're creating a new pointer—nothing more. This makes branching incredibly lightweight and fast.

Branch Representation:

main → commit C feature → commit E A ← B ← C (main) ↖ D ← E (feature) 
Enter fullscreen mode Exit fullscreen mode

git branch - List, Create, and Delete Branches

Purpose: Manage branches—list existing branches, create new ones, delete old ones, rename branches.

Basic Usage:

# List local branches git branch # List all branches (including remote) git branch -a git branch --all # List remote branches only git branch -r git branch --remotes # Create new branch (doesn't switch to it) git branch feature-x # Create branch from specific commit git branch feature-x abc123 # Create branch from another branch git branch feature-x develop 
Enter fullscreen mode Exit fullscreen mode

Branch Listing with Details:

# Show last commit on each branch git branch -v git branch --verbose # Show tracking information git branch -vv # Show merged branches git branch --merged # Show unmerged branches git branch --no-merged 
Enter fullscreen mode Exit fullscreen mode

Example output:

$ git branch -vv * main abc123 [origin/main] Latest commit message develop def456 [origin/develop: ahead 2] Work in progress feature ghi789 Feature implementation 
Enter fullscreen mode Exit fullscreen mode
  • * indicates current branch
  • [origin/main] shows tracking branch
  • ahead 2 means 2 commits not pushed yet

Deleting Branches:

# Delete branch (safe: prevents deleting unmerged branches) git branch -d feature-x git branch --delete feature-x # Force delete (even if unmerged) git branch -D feature-x git branch --delete --force feature-x # Delete remote branch git push origin --delete feature-x git push origin :feature-x # Old syntax 
Enter fullscreen mode Exit fullscreen mode

Renaming Branches:

# Rename current branch git branch -m new-name git branch --move new-name # Rename different branch git branch -m old-name new-name # Force rename (overwrite existing) git branch -M old-name new-name 
Enter fullscreen mode Exit fullscreen mode

Renaming and Updating Remote:

# Rename local branch git branch -m old-name new-name # Delete old remote branch git push origin --delete old-name # Push new branch and set upstream git push origin -u new-name 
Enter fullscreen mode Exit fullscreen mode

Creating Branch and Switching:

While git branch creates branches, it doesn't switch to them:

# Create and switch (two commands) git branch feature-x git checkout feature-x # Better: create and switch in one command git checkout -b feature-x # Modern way (Git 2.23+) git switch -c feature-x 
Enter fullscreen mode Exit fullscreen mode

Advanced Branch Options:

Copy Branches:

# Copy branch to new name git branch -c existing-branch new-branch git branch --copy existing-branch new-branch # Force copy (overwrite if exists) git branch -C existing-branch new-branch 
Enter fullscreen mode Exit fullscreen mode

Set Upstream Tracking:

# Set upstream for existing branch git branch -u origin/feature-x git branch --set-upstream-to=origin/feature-x # Remove upstream tracking git branch --unset-upstream 
Enter fullscreen mode Exit fullscreen mode

Branch with Specific Start Point:

# Create branch from tag git branch hotfix v1.2.3 # Create branch from remote branch git branch local-feature origin/remote-feature # Create branch from specific commit git branch bugfix abc123def 
Enter fullscreen mode Exit fullscreen mode

List Branches by Pattern:

# List branches matching pattern git branch --list 'feature/*' git branch --list '*fix*' # Case-insensitive matching git branch -i --list 'FEATURE/*' 
Enter fullscreen mode Exit fullscreen mode

Branch Sorting:

# Sort by commit date git branch --sort=-committerdate # Sort by author date git branch --sort=-authordate # Sort alphabetically (default) git branch --sort=refname 
Enter fullscreen mode Exit fullscreen mode

Branch Coloring:

# Always use colors git branch --color=always # Never use colors git branch --color=never # Auto (default) git branch --color=auto 
Enter fullscreen mode Exit fullscreen mode

Real-World Branch Strategies:

Feature Branch Workflow:

# Create feature branch from main git checkout main git pull git checkout -b feature/user-authentication # Work on feature git add . git commit -m "Implement login endpoint" # Push to remote git push -u origin feature/user-authentication # After review and merge, delete git checkout main git branch -d feature/user-authentication git push origin --delete feature/user-authentication 
Enter fullscreen mode Exit fullscreen mode

Release Branch Workflow:

# Create release branch from develop git checkout develop git checkout -b release/v2.0 # Finalize release (bug fixes only) git commit -m "Bump version to 2.0" # Merge to main git checkout main git merge release/v2.0 git tag v2.0 # Merge back to develop git checkout develop git merge release/v2.0 # Delete release branch git branch -d release/v2.0 
Enter fullscreen mode Exit fullscreen mode

Hotfix Branch Workflow:

# Critical bug in production! git checkout main git checkout -b hotfix/critical-security-fix # Fix and test git commit -m "Fix SQL injection vulnerability" # Merge to main git checkout main git merge hotfix/critical-security-fix git tag v1.2.1 # Merge to develop git checkout develop git merge hotfix/critical-security-fix # Delete hotfix branch git branch -d hotfix/critical-security-fix 
Enter fullscreen mode Exit fullscreen mode

git checkout - Switch Branches and Restore Files

Purpose: Historically did two things: switch branches and restore files. In Git 2.23+, split into git switch (branches) and git restore (files) for clarity, but git checkout still works.

Branch Switching:

# Switch to existing branch git checkout existing-branch # Create and switch to new branch git checkout -b new-branch # Create branch from specific commit and switch git checkout -b hotfix abc123 # Switch to previous branch git checkout - # Switch to remote branch (creates tracking branch) git checkout remote-branch 
Enter fullscreen mode Exit fullscreen mode

What Happens During Checkout:

  1. Updates HEAD to point to the branch
  2. Updates staging area to match branch's commit
  3. Updates working directory to match branch's commit
  4. Fails if you have uncommitted changes that conflict

Handling Uncommitted Changes:

# If you have uncommitted changes $ git checkout other-branch error: Your local changes would be overwritten by checkout # Options: # 1. Commit changes git commit -am "WIP" # 2. Stash changes git stash git checkout other-branch git stash pop # 3. Force checkout (DANGEROUS - loses changes) git checkout -f other-branch 
Enter fullscreen mode Exit fullscreen mode

Detached HEAD State:

Checking out a commit (not a branch) creates "detached HEAD":

# Checkout specific commit git checkout abc123 # You're now in detached HEAD state $ git status HEAD detached at abc123 # Any commits made here are orphaned unless you create a branch git checkout -b save-my-work 
Enter fullscreen mode Exit fullscreen mode

Use Cases for Detached HEAD:

  • Inspecting historical code
  • Testing specific versions
  • Building release artifacts
  • Bisecting to find bugs

Checkout with Path:

# Restore file from HEAD git checkout -- filename.txt # Restore file from specific commit git checkout abc123 -- filename.txt # Restore file from different branch git checkout main -- config.yml # Restore entire directory git checkout main -- src/ 
Enter fullscreen mode Exit fullscreen mode

Advanced Checkout Options:

Merge During Checkout:

# Attempt three-way merge when switching branches git checkout -m branch-name # If conflicts, resolves what it can and marks conflicts 
Enter fullscreen mode Exit fullscreen mode

Orphan Branches:

# Create branch with no history (useful for gh-pages) git checkout --orphan gh-pages git rm -rf . # Add new content git add . git commit -m "Initial GitHub Pages commit" 
Enter fullscreen mode Exit fullscreen mode

Track Remote Branches:

# Create tracking branch git checkout -t origin/feature-x git checkout --track origin/feature-x # Create with different name git checkout -b local-name origin/remote-name 
Enter fullscreen mode Exit fullscreen mode

Checkout and Reset:

# Checkout and discard all local changes git checkout -f branch-name git checkout --force branch-name 
Enter fullscreen mode Exit fullscreen mode

git switch - Switch Branches (Modern)

Purpose: Modern command (Git 2.23+) specifically for switching branches, clearer than git checkout.

Basic Usage:

# Switch to existing branch git switch branch-name # Create and switch to new branch git switch -c new-branch git switch --create new-branch # Switch to previous branch git switch - # Force switch (discard local changes) git switch -f branch-name git switch --force branch-name # Discard local changes with confirmation git switch --discard-changes branch-name 
Enter fullscreen mode Exit fullscreen mode

Create Branch from Commit:

# Create branch from specific commit and switch git switch -c bugfix abc123 # Create from remote branch git switch -c local-feature origin/remote-feature 
Enter fullscreen mode Exit fullscreen mode

Guess and Create Tracking Branch:

# If "feature" doesn't exist locally but "origin/feature" does git switch feature # Automatically creates local tracking branch 
Enter fullscreen mode Exit fullscreen mode

Detached HEAD:

# Switch to specific commit (detached HEAD) git switch --detach abc123 # Create branch from detached HEAD git switch -c save-detached-work 
Enter fullscreen mode Exit fullscreen mode

Advantages of git switch over git checkout:

  1. Clarity: Only switches branches, doesn't restore files
  2. Safety: Won't accidentally overwrite files
  3. Simplicity: Fewer options, easier to understand
  4. Modern: Part of Git's effort to improve user experience

Comparison:

# OLD WAY (still works) git checkout branch-name git checkout -b new-branch # NEW WAY (clearer) git switch branch-name git switch -c new-branch 
Enter fullscreen mode Exit fullscreen mode

Branch Management Best Practices

Branch Naming Conventions:

# Feature branches feature/user-authentication feature/payment-integration feat/shopping-cart # Bug fix branches bugfix/login-error fix/memory-leak hotfix/security-vulnerability # Release branches release/v1.2.0 release/2024-q1 # Experimental branches experiment/new-architecture poc/graphql-migration 
Enter fullscreen mode Exit fullscreen mode

Benefits of conventions:

  • Easy to identify branch purpose
  • Helps with filtering and organization
  • Supports automated workflows
  • Improves team communication

Branch Lifecycle:

# 1. Create from up-to-date main git checkout main git pull git checkout -b feature/new-feature # 2. Regular commits git commit -m "Progress on feature" # 3. Keep updated with main git checkout main git pull git checkout feature/new-feature git merge main # or rebase # 4. Push to remote git push -u origin feature/new-feature # 5. Create pull request (on GitHub/GitLab/etc.) # 6. After merge, clean up git checkout main git pull git branch -d feature/new-feature git push origin --delete feature/new-feature 
Enter fullscreen mode Exit fullscreen mode

Cleaning Up Old Branches:

# List merged branches git branch --merged main # Delete all merged branches (except main) git branch --merged main | grep -v "\* main" | xargs -n 1 git branch -d # Delete remote-tracking branches that no longer exist git fetch --prune git fetch -p # Remove stale remote-tracking references git remote prune origin 
Enter fullscreen mode Exit fullscreen mode

Branch Protection:

On remote repositories (GitHub, GitLab), protect important branches:

  • Require pull request reviews
  • Require status checks to pass
  • Require signed commits
  • Restrict who can push
  • Prevent force pushes
  • Prevent deletion

Long-Lived vs Short-Lived Branches:

Long-lived branches:

  • main/master: Production code
  • develop: Integration branch
  • staging: Pre-production testing

Short-lived branches:

  • Feature branches: Deleted after merge
  • Bug fix branches: Deleted after merge
  • Hotfix branches: Deleted after merge

Recommended: Keep short-lived branches actually short (days to weeks, not months).


9. Merging Strategies and Conflict Resolution {#merging}

Merging combines independent lines of development. Understanding merge strategies is crucial for maintaining clean history and resolving conflicts.

git merge - Join Development Histories

Purpose: Integrate changes from one branch into another, creating a merge commit if necessary.

Basic Usage:

# Merge branch into current branch git merge feature-branch # Merge with commit message git merge feature-branch -m "Merge feature X implementation" # Merge without committing (stage changes) git merge --no-commit feature-branch # Abort merge git merge --abort 
Enter fullscreen mode Exit fullscreen mode

How Merging Works:

Git finds the common ancestor (merge base) of the two branches and performs a three-way merge:

 C---D (feature) / A---B---E---F (main) After merge: C---D / \ A---B---E---F---G (main, merge commit G) 
Enter fullscreen mode Exit fullscreen mode

Types of Merges:

1. Fast-Forward Merge:

When the target branch hasn't diverged, Git simply moves the pointer forward:

# Before: A---B---C (main) \ D---E (feature) # After fast-forward merge: A---B---C---D---E (main, feature) 
Enter fullscreen mode Exit fullscreen mode
# Fast-forward merge happens automatically git checkout main git merge feature # Fast-forward # Force merge commit even for fast-forward git merge --no-ff feature 
Enter fullscreen mode Exit fullscreen mode

2. Three-Way Merge:

When branches have diverged, Git creates a merge commit:

# Before: C---D (feature) / A---B---E (main) # After three-way merge: C---D / \ A---B---E---F (main, merge commit) 
Enter fullscreen mode Exit fullscreen mode

3. Squash Merge:

Combines all commits from feature branch into one commit on target:

git merge --squash feature-branch git commit -m "Implement feature X (squashed)" 
Enter fullscreen mode Exit fullscreen mode

This creates clean history but loses individual commit information.

Merge Strategies:

Git supports different merge strategies for complex scenarios:

Recursive (Default):

# Explicit recursive strategy git merge -s recursive feature-branch git merge --strategy=recursive feature-branch # With strategy options git merge -s recursive -X ours feature-branch # Prefer our changes git merge -s recursive -X theirs feature-branch # Prefer their changes 
Enter fullscreen mode Exit fullscreen mode

Ours (Take Our Version):

# Use our version entirely, discard theirs git merge -s ours obsolete-feature 
Enter fullscreen mode Exit fullscreen mode

Use case: Record that a branch was merged, but don't actually include its changes.

Octopus (Multiple Branches):

# Merge multiple branches at once git merge feature1 feature2 feature3 
Enter fullscreen mode Exit fullscreen mode

Used for merging multiple branches simultaneously (rarely needed manually).

Subtree:

# Merge as subdirectory git merge -s subtree sub-project-branch 
Enter fullscreen mode Exit fullscreen mode

Useful when one project is part of another.

Merge Strategy Options:

# Ignore whitespace changes git merge -Xignore-space-change feature # Ignore all whitespace git merge -Xignore-all-space feature # Be more patient (better conflict resolution) git merge -Xpatience feature # Use diff3 conflict style (shows common ancestor) git merge -Xdiff3 feature # Rename threshold (for rename detection) git merge -Xrename-threshold=50% feature 
Enter fullscreen mode Exit fullscreen mode

Merge Verification:

# Verify merge would succeed before doing it git merge --no-commit --no-ff feature git diff --staged # Review changes git merge --abort # Back out if not happy # Or just check if branches can merge git merge-base main feature # Shows common ancestor 
Enter fullscreen mode Exit fullscreen mode

Fast-Forward Control:

# Only allow fast-forward merges git merge --ff-only feature # Fails if fast-forward not possible # Always create merge commit (no fast-forward) git merge --no-ff feature # Allow fast-forward (default) git merge --ff feature 
Enter fullscreen mode Exit fullscreen mode

When to use --no-ff:

  • Preserve feature branch history
  • Make it clear when feature was integrated
  • Easier to revert entire feature later

Merge with Specific File Handling:

# Use theirs version for specific file git checkout --theirs conflicted-file.txt git add conflicted-file.txt # Use ours version git checkout --ours conflicted-file.txt git add conflicted-file.txt 
Enter fullscreen mode Exit fullscreen mode

Conflict Resolution

What Is a Merge Conflict?

Occurs when Git can't automatically reconcile differences between commits. Requires manual intervention.

Conflict Markers:

def calculate_total(items): <<<<<<< HEAD (Current Change) total = sum(item.price for item in items) return total * 1.1 # Add 10% tax ======= total = sum(item.cost for item in items) return total * 1.15 # Add 15% tax >>>>>>> feature-branch (Incoming Change) 
Enter fullscreen mode Exit fullscreen mode

Marker Explanation:

  • <<<<<<< HEAD: Start of your current branch's version
  • =======: Separator
  • >>>>>>> feature-branch: End of incoming branch's version

Step-by-Step Conflict Resolution:

1. Identify conflicts:

$ git merge feature-branch Auto-merging src/calculator.py CONFLICT (content): Merge conflict in src/calculator.py Automatic merge failed; fix conflicts and then commit the result. # Check status $ git status Unmerged paths: (use "git add <file>..." to mark resolution) both modified: src/calculator.py 
Enter fullscreen mode Exit fullscreen mode

2. Open conflicted file:

# Use your editor vim src/calculator.py code src/calculator.py nano src/calculator.py 
Enter fullscreen mode Exit fullscreen mode

3. Resolve conflict:

Choose which version to keep, or combine both:

# Option 1: Keep ours def calculate_total(items): total = sum(item.price for item in items) return total * 1.1 # Option 2: Keep theirs def calculate_total(items): total = sum(item.cost for item in items) return total * 1.15 # Option 3: Combine (often best) def calculate_total(items): # Use 'price' attribute (from HEAD)  total = sum(item.price for item in items) # Use 15% tax rate (from feature-branch)  return total * 1.15 
Enter fullscreen mode Exit fullscreen mode

Remove conflict markers completely.

4. Mark as resolved:

# Stage resolved file git add src/calculator.py # Check status git status # All conflicts fixed: run "git commit" 
Enter fullscreen mode Exit fullscreen mode

5. Complete merge:

# Commit merge git commit # Opens editor with merge commit message # Or provide message directly git commit -m "Merge feature-branch, resolve calculation conflicts" 
Enter fullscreen mode Exit fullscreen mode

Tools for Conflict Resolution:

Using Diff Tools:

# Launch configured merge tool git mergetool # Use specific tool git mergetool --tool=meld git mergetool --tool=kdiff3 git mergetool --tool=vimdiff 
Enter fullscreen mode Exit fullscreen mode

Popular merge tools:

  • Meld: Visual diff and merge (Linux, macOS, Windows)
  • KDiff3: Three-way merge tool
  • P4Merge: Perforce's merge tool (free)
  • Beyond Compare: Commercial but powerful
  • VS Code: Built-in merge conflict UI

Configure Merge Tool:

# Set default merge tool git config --global merge.tool meld # Don't save backup files (.orig) git config --global mergetool.keepBackup false # Don't prompt before launching git config --global mergetool.prompt false 
Enter fullscreen mode Exit fullscreen mode

Using Built-in Merge Conflict Resolution:

# Accept all "ours" changes git checkout --ours . # Accept all "theirs" changes git checkout --theirs . # For specific files git checkout --ours path/to/file git checkout --theirs path/to/file 
Enter fullscreen mode Exit fullscreen mode

⚠️ Warning: These commands automatically resolve ALL conflicts in favor of one side. Use cautiously.

Conflict Resolution Strategies:

Strategy 1: Diff3 Style (Recommended)

Shows common ancestor for better context:

# Configure diff3 style git config --global merge.conflictstyle diff3 # Conflict now shows: <<<<<<< HEAD current version ||||||| merged common ancestor original version ======= incoming version >>>>>>> branch 
Enter fullscreen mode Exit fullscreen mode

The middle section shows the original (common ancestor), helping understand what each side changed.

Strategy 2: Always Use Specific Strategy:

# Configure default merge strategy git config --global pull.rebase false # merge (default) git config --global pull.rebase true # rebase # Always use ours for specific file types git config --global merge.ours.driver true # Then in .gitattributes: # *.config merge=ours 
Enter fullscreen mode Exit fullscreen mode

Advanced Conflict Handling:

Restart Merge:

# Made a mistake? Abort and restart git merge --abort # Or reset to before merge git reset --hard HEAD 
Enter fullscreen mode Exit fullscreen mode

Continue After Resolving:

# If merge was stopped (e.g., by pre-commit hook) git merge --continue 
Enter fullscreen mode Exit fullscreen mode

Skip Specific Commits:

# During rebase, skip commit causing conflicts git rebase --skip # Or cherry-pick git cherry-pick --skip 
Enter fullscreen mode Exit fullscreen mode

View Conflicts:

# List conflicted files git diff --name-only --diff-filter=U # Show conflicts for specific file git diff file.txt # Show changes from both sides git diff HEAD...MERGE_HEAD 
Enter fullscreen mode Exit fullscreen mode

Real-World Conflict Scenarios:

Scenario 1: Simple Conflict Resolution

# Merge causes conflict $ git merge feature CONFLICT (content): Merge conflict in app.js # Edit app.js, resolve conflicts, remove markers # Stage resolved file git add app.js # Complete merge git commit 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Multiple File Conflicts

# Multiple conflicts $ git merge feature CONFLICT in file1.js CONFLICT in file2.js CONFLICT in file3.js # Resolve each file vim file1.js # resolve git add file1.js vim file2.js # resolve git add file2.js vim file3.js # resolve git add file3.js # Commit when all resolved git commit 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Using Merge Tool

# Launch merge tool for all conflicts git mergetool # Resolve in GUI # Tool stages files automatically # Clean up backup files rm *.orig # Commit git commit 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Accept One Side Entirely

# Feature branch is definitely correct git checkout --theirs . git add . git commit -m "Merge feature, accepting all their changes" # Or main is definitely correct git checkout --ours . git add . git commit -m "Merge feature, keeping our changes" 
Enter fullscreen mode Exit fullscreen mode

Scenario 5: Complex Three-Way Conflict

# Use diff3 to see ancestor git config merge.conflictstyle diff3 git merge feature # In file: <<<<<<< HEAD new implementation ||||||| merged common ancestor old implementation ======= alternative new implementation >>>>>>> feature # Now you understand: # - Old had X # - We changed X to Y # - They changed X to Z # - Need to combine Y and Z approaches 
Enter fullscreen mode Exit fullscreen mode

Preventing Conflicts:

1. Frequent Integration:

# Regularly merge main into feature branch git checkout feature git merge main 
Enter fullscreen mode Exit fullscreen mode

2. Small, Focused Changes:

  • Keep feature branches small
  • Merge frequently
  • Avoid long-lived branches

3. Communication:

  • Coordinate with team on overlapping work
  • Use feature flags for incomplete features
  • Split work to minimize conflicts

4. Code Reviews:

  • Review before merging
  • Discuss potential conflicts
  • Plan integration strategy

10. Rebasing: Rewriting History {#rebasing}

Rebasing is a powerful but potentially dangerous operation that rewrites commit history. It's an alternative to merging that creates a linear history.

git rebase - Reapply Commits on Top of Another Base

Purpose: Move or combine a sequence of commits to a new base commit, creating a linear history.

Basic Usage:

# Rebase current branch onto main git rebase main # Rebase feature branch onto main (while on feature) git checkout feature git rebase main # Rebase specific branch onto another git rebase main feature-branch # Interactive rebase git rebase -i HEAD~5 git rebase --interactive HEAD~5 
Enter fullscreen mode Exit fullscreen mode

How Rebase Works:

Before rebase: C---D (feature) / A---B---E---F (main) After git checkout feature; git rebase main: C'---D' (feature) / A---B---E---F (main) 
Enter fullscreen mode Exit fullscreen mode

Git:

  1. Finds common ancestor (B)
  2. Saves commits C and D as patches
  3. Resets feature to main
  4. Applies patches C and D on top

Note: C' and D' are new commits with different SHAs (history rewritten).

Rebase vs Merge:

Merge:

  • Preserves complete history
  • Shows when branches were integrated
  • Creates merge commits
  • Safe for public branches

Rebase:

  • Creates linear history
  • Cleaner, easier to follow
  • No merge commits
  • Dangerous for public branches

The Golden Rule of Rebasing:

🚨 NEVER rebase commits that have been pushed to a shared/public branch 🚨

Why? Rebasing rewrites history. If others have based work on your original commits, rebasing causes massive conflicts and confusion.

Safe rebasing:

# Safe: Rebasing local, unpushed commits git checkout feature git rebase main 
Enter fullscreen mode Exit fullscreen mode

Dangerous rebasing:

# DANGEROUS: Rebasing shared branch git checkout main # Public branch! git rebase some-branch # DON'T DO THIS 
Enter fullscreen mode Exit fullscreen mode

Interactive Rebase

Interactive rebase (-i) is incredibly powerful for cleaning up commit history before sharing.

Basic Interactive Rebase:

# Rebase last 5 commits interactively git rebase -i HEAD~5 # Rebase all commits since main git rebase -i main # Rebase from specific commit git rebase -i abc123 
Enter fullscreen mode Exit fullscreen mode

Interactive Rebase Editor:

pick abc123 Add user authentication pick def456 Fix typo in authentication pick ghi789 Add password validation pick jkl012 Update documentation pick mno345 Fix bug in validation # Rebase abc123..mno345 onto previous commit # # Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, meld into previous commit # f, fixup <commit> = like squash, discard commit message # x, exec <command> = run command # b, break = stop here (continue with 'git rebase --continue') # d, drop <commit> = remove commit # l, label <label> = label current HEAD # t, reset <label> = reset HEAD to label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] 
Enter fullscreen mode Exit fullscreen mode

Interactive Rebase Commands:

1. pick (p): Use commit as-is

pick abc123 Add feature 
Enter fullscreen mode Exit fullscreen mode

2. reword (r): Change commit message

reword def456 Fix typo # Will prompt for new message 
Enter fullscreen mode Exit fullscreen mode

3. edit (e): Stop at commit to make changes

edit ghi789 Add validation # Git stops here, you can: # - Amend commit: git commit --amend # - Split commit: git reset HEAD^, then make multiple commits # - Continue: git rebase --continue 
Enter fullscreen mode Exit fullscreen mode

4. squash (s): Combine with previous commit, edit message

pick abc123 Add feature squash def456 Add tests for feature # Git combines both, lets you edit combined message 
Enter fullscreen mode Exit fullscreen mode

5. fixup (f): Combine with previous, discard this message

pick abc123 Add feature fixup def456 Fix typo # Git combines, keeps only first message 
Enter fullscreen mode Exit fullscreen mode

6. drop (d): Remove commit entirely

drop ghi789 Experimental code 
Enter fullscreen mode Exit fullscreen mode

7. exec (x): Run shell command

pick abc123 Add feature exec npm test pick def456 Add another feature exec npm test # Runs tests after each commit 
Enter fullscreen mode Exit fullscreen mode

Real-World Interactive Rebase Examples:

Example 1: Clean Up Messy History

# You have: abc123 WIP: start feature def456 WIP: continue ghi789 WIP: almost done jkl012 Feature complete mno345 Fix typo pqr678 Actually fix typo # Clean it up: git rebase -i HEAD~6 # Change to: pick abc123 WIP: start feature fixup def456 WIP: continue fixup ghi789 WIP: almost done reword jkl012 Feature complete fixup mno345 Fix typo fixup pqr678 Actually fix typo # Result: Two clean commits 
Enter fullscreen mode Exit fullscreen mode

Example 2: Reorder Commits

# You have: abc123 Add feature A def456 Add feature B ghi789 Fix bug in feature A jkl012 Add tests for feature B # Reorder logically: git rebase -i HEAD~4 # Change to: pick abc123 Add feature A pick ghi789 Fix bug in feature A pick def456 Add feature B pick jkl012 Add tests for feature B 
Enter fullscreen mode Exit fullscreen mode

Example 3: Split a Commit

# One commit does too much git rebase -i HEAD~3 # Mark commit with 'edit': edit abc123 Add many features pick def456 Other commit # When Git stops: git reset HEAD^ # Now make separate commits: git add feature1.js git commit -m "Add feature 1" git add feature2.js git commit -m "Add feature 2" # Continue rebase: git rebase --continue 
Enter fullscreen mode Exit fullscreen mode

Example 4: Remove Sensitive Data

# Oops, committed secrets git rebase -i HEAD~10 # Find commit with secrets: drop ghi789 Add configuration (contains secrets!) # Or edit to remove just the sensitive file: edit ghi789 Add configuration git rm --cached secrets.yml git commit --amend git rebase --continue 
Enter fullscreen mode Exit fullscreen mode

⚠️ Note: This only removes from future history. Old commits still contain secrets. For complete removal, use git filter-branch or BFG Repo-Cleaner.


Handling Rebase Conflicts

Conflicts during rebase are common:

$ git rebase main ... CONFLICT (content): Merge conflict in file.txt error: could not apply abc123... Commit message hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". 
Enter fullscreen mode Exit fullscreen mode

Resolution Steps:

# 1. Fix conflicts in files vim file.txt # Resolve conflicts # 2. Stage resolved files git add file.txt # 3. Continue rebase git rebase --continue # If you want to skip this commit: git rebase --skip # If you want to abort entirely: git rebase --abort 
Enter fullscreen mode Exit fullscreen mode

Common Rebase Scenarios:

Scenario 1: Update Feature Branch

# Keep feature branch up-to-date with main git checkout feature git rebase main # If conflicts, resolve and continue git add resolved-file.txt git rebase --continue # Force push (since history changed) git push --force-with-lease origin feature 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Squash All Commits Before Merging

# Squash all feature commits into one git checkout feature git rebase -i main # Mark all except first as 'squash' or 'fixup' pick abc123 First commit squash def456 Second commit squash ghi789 Third commit # Edit combined message, then: git push --force-with-lease 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Clean History Before Pull Request

# Fix commit messages, combine WIP commits git rebase -i HEAD~10 # Reword unclear messages # Fixup WIP commits # Reorder for logical flow # Force push git push --force-with-lease 
Enter fullscreen mode Exit fullscreen mode

Advanced Rebase Options

Preserve Merges:

# Preserve merge commits during rebase git rebase --preserve-merges main git rebase -p main # Note: --preserve-merges is deprecated, use --rebase-merges git rebase --rebase-merges main 
Enter fullscreen mode Exit fullscreen mode

Rebase Onto:

# Rebase onto different branch than fork point git rebase --onto new-base old-base branch # Example: Move feature from main to develop # Before: # main: A---B---C # feature: D---E # develop: A---B---F---G # # After git rebase --onto develop main feature: # main: A---B---C # develop: A---B---F---G # feature: D'---E' 
Enter fullscreen mode Exit fullscreen mode

Autosquash:

# Create fixup commits git commit --fixup=abc123 git commit --squash=def456 # Rebase with autosquash git rebase -i --autosquash main # Configure as default git config --global rebase.autosquash true 
Enter fullscreen mode Exit fullscreen mode

This automatically organizes fixup/squash commits in interactive rebase.

Autostash:

# Automatically stash and reapply during rebase git rebase --autostash main # Configure as default git config --global rebase.autostash true 
Enter fullscreen mode Exit fullscreen mode

Force Push Safely:

# After rebase, force push required (history changed) git push --force-with-lease # This fails if someone else pushed to branch # Safer than --force which overwrites unconditionally 
Enter fullscreen mode Exit fullscreen mode

When to Use Rebase

Good Use Cases:

  1. Update feature branch with latest main:
git checkout feature git rebase main 
Enter fullscreen mode Exit fullscreen mode
  1. Clean up local commits before pushing:
git rebase -i HEAD~5 
Enter fullscreen mode Exit fullscreen mode
  1. Maintain linear history:
# Instead of merging main into feature repeatedly git rebase main # Creates linear history 
Enter fullscreen mode Exit fullscreen mode
  1. Fix recent commits:
# Fix last commit git commit --amend # Fix earlier commits git rebase -i HEAD~3 
Enter fullscreen mode Exit fullscreen mode

Bad Use Cases:

  1. Public/shared branches:
# NEVER do this: git checkout main git rebase feature # Rewrites public history! 
Enter fullscreen mode Exit fullscreen mode
  1. Commits already pushed and used by others:
# DANGEROUS: git rebase main # If others branched from your commits git push --force 
Enter fullscreen mode Exit fullscreen mode
  1. When merge commits provide valuable context:
# Sometimes merge commits are informative git merge feature # Shows when feature was integrated 
Enter fullscreen mode Exit fullscreen mode

Rebase Best Practices

1. Only Rebase Local Commits:

# Safe: Rebase commits not yet pushed git rebase main # Check if commits are pushed: git log origin/feature..feature # Shows unpushed commits 
Enter fullscreen mode Exit fullscreen mode

2. Use --force-with-lease Instead of --force:

# Safer force push git push --force-with-lease origin feature # This fails if remote has commits you don't have locally # Prevents accidentally overwriting others' work 
Enter fullscreen mode Exit fullscreen mode

3. Communicate with Team:

If you must rebase shared branches:

  • Warn team members
  • Coordinate timing
  • Provide instructions for updating their local copies

4. Test After Rebase:

# After rebase, verify everything works git rebase main npm test # or your test command git push --force-with-lease 
Enter fullscreen mode Exit fullscreen mode

5. Keep Rebase Sessions Short:

# Don't rebase too many commits at once git rebase -i HEAD~5 # Manageable # Instead of: git rebase -i HEAD~50 # Too many, error-prone 
Enter fullscreen mode Exit fullscreen mode

6. Use Descriptive Messages During Interactive Rebase:

When rewording commits, make messages clear:

# Bad: "Fix stuff" # Good: "Fix null pointer exception in payment processing" 
Enter fullscreen mode Exit fullscreen mode

Recovery from Rebase Disasters

If Rebase Goes Wrong:

1. Abort Ongoing Rebase:

# During rebase, if things are messy git rebase --abort # Returns to state before rebase started 
Enter fullscreen mode Exit fullscreen mode

2. Use Reflog to Recover:

The reflog tracks all HEAD movements, even rebase operations:

# View reflog git reflog # Output: abc123 HEAD@{0}: rebase: Add feature def456 HEAD@{1}: rebase: Fix bug ghi789 HEAD@{2}: rebase: Start jkl012 HEAD@{3}: commit: Original state (before rebase) # Reset to before rebase git reset --hard HEAD@{3} # or git reset --hard jkl012 
Enter fullscreen mode Exit fullscreen mode

3. Recover Specific Commits:

# Find lost commit in reflog git reflog | grep "lost commit message" # Cherry-pick it back git cherry-pick abc123 
Enter fullscreen mode Exit fullscreen mode

4. If Force Push Caused Problems:

# If you force pushed and broke things for others: # Option 1: Revert the force push (if possible) git reset --hard origin/feature@{1} # Previous state git push --force-with-lease # Option 2: Create revert commits git revert abc123..def456 git push 
Enter fullscreen mode Exit fullscreen mode

11. Remote Repositories and Collaboration {#remotes}

Remote repositories enable collaboration. Understanding remote operations is essential for team workflows.

git remote - Manage Remote Repositories

Purpose: Add, view, rename, and remove remote repository connections.

Basic Usage:

# List remotes git remote # List with URLs git remote -v git remote --verbose # Add remote git remote add origin https://github.com/user/repo.git # Add remote with different name git remote add upstream https://github.com/original/repo.git # Remove remote git remote remove origin git remote rm origin # Rename remote git remote rename old-name new-name # Change remote URL git remote set-url origin https://github.com/user/new-repo.git 
Enter fullscreen mode Exit fullscreen mode

Viewing Remote Details:

# Show detailed information about remote git remote show origin # Output includes: # - Fetch/push URLs # - Remote branches # - Local branches configured for push/pull # - Stale branches 
Enter fullscreen mode Exit fullscreen mode

Example output:

$ git remote show origin * remote origin Fetch URL: https://github.com/user/repo.git Push URL: https://github.com/user/repo.git HEAD branch: main Remote branches: main tracked develop tracked feature/new-feature tracked refs/remotes/origin/old-branch stale (use 'git remote prune' to remove) Local branch configured for 'git pull': main merges with remote main Local ref configured for 'git push': main pushes to main (up to date) 
Enter fullscreen mode Exit fullscreen mode

Managing Multiple Remotes:

Common pattern: fork workflow

# Add original repository as 'upstream' git remote add upstream https://github.com/original/repo.git # Add your fork as 'origin' git remote add origin https://github.com/yourusername/repo.git # List remotes $ git remote -v origin https://github.com/yourusername/repo.git (fetch) origin https://github.com/yourusername/repo.git (push) upstream https://github.com/original/repo.git (fetch) upstream https://github.com/original/repo.git (push) # Fetch from upstream git fetch upstream # Merge upstream changes git merge upstream/main 
Enter fullscreen mode Exit fullscreen mode

Pruning Stale Remote Branches:

# Remove stale remote-tracking branches git remote prune origin # Show what would be pruned git remote prune origin --dry-run # Prune during fetch git fetch --prune git fetch -p 
Enter fullscreen mode Exit fullscreen mode

Changing Remote URLs:

# Switch from HTTPS to SSH git remote set-url origin git@github.com:user/repo.git # Add push URL different from fetch URL git remote set-url --add --push origin git@github.com:user/repo.git # View remote URLs git remote get-url origin git remote get-url --all origin 
Enter fullscreen mode Exit fullscreen mode

git fetch - Download Objects and Refs from Remote

Purpose: Download commits, files, and refs from remote repository without merging. Updates remote-tracking branches.

Basic Usage:

# Fetch from default remote (origin) git fetch # Fetch from specific remote git fetch upstream # Fetch specific branch git fetch origin main # Fetch all remotes git fetch --all # Fetch and prune stale branches git fetch --prune git fetch -p 
Enter fullscreen mode Exit fullscreen mode

What git fetch Does:

Remote repository: origin/main: A---B---C---D---E Local repository before fetch: origin/main: A---B---C main: A---B---C After git fetch: origin/main: A---B---C---D---E (updated) main: A---B---C (unchanged) 
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • Downloads new commits from remote
  • Updates remote-tracking branches (origin/main, etc.)
  • Does NOT modify your working directory
  • Does NOT merge anything
  • Safe to run anytime

Fetch Specific Refs:

# Fetch specific branch git fetch origin feature-branch # Fetch specific tag git fetch origin tag v1.0.0 # Fetch all tags git fetch --tags # Fetch and create local branch git fetch origin feature-branch:feature-branch 
Enter fullscreen mode Exit fullscreen mode

Fetch Depth:

# Shallow fetch (last N commits only) git fetch --depth=10 # Deepen existing shallow clone git fetch --deepen=50 # Convert shallow to complete git fetch --unshallow # Shallow fetch single branch git fetch --depth=1 origin main 
Enter fullscreen mode Exit fullscreen mode

Fetch with Pruning:

# Remove remote-tracking branches that no longer exist on remote git fetch --prune # Aggressive pruning (also remove tags) git fetch --prune --prune-tags # Configure automatic pruning git config --global fetch.prune true 
Enter fullscreen mode Exit fullscreen mode

Dry Run:

# See what would be fetched without actually fetching git fetch --dry-run git fetch -n 
Enter fullscreen mode Exit fullscreen mode

Fetch and Display:

# Fetch and show what was fetched git fetch --verbose git fetch -v # Show what changed after fetch git fetch git log HEAD..origin/main # Commits on remote not on local git diff HEAD origin/main # Changes between local and remote 
Enter fullscreen mode Exit fullscreen mode

Real-World Fetch Scenarios:

Scenario 1: Check for Updates Before Starting Work

# Start of day routine git fetch --all --prune # See what's new git log HEAD..origin/main --oneline # Update your branch git merge origin/main # or git rebase origin/main 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Review Changes Before Merging

# Fetch updates git fetch origin # Review what's new without merging git log origin/main --not main --oneline git diff main origin/main # If satisfied, merge git merge origin/main 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Update Multiple Remotes

# Fetch from all configured remotes git fetch --all # See status across remotes git branch -vv # Merge from upstream git merge upstream/main 
Enter fullscreen mode Exit fullscreen mode

git pull - Fetch and Merge

Purpose: Fetch from remote and immediately merge into current branch. Combination of git fetch + git merge.

Basic Usage:

# Pull from tracking branch git pull # Pull from specific remote and branch git pull origin main # Pull with rebase instead of merge git pull --rebase git pull -r # Pull from specific remote git pull upstream 
Enter fullscreen mode Exit fullscreen mode

How git pull Works:

# git pull is equivalent to: git fetch origin git merge origin/main # git pull --rebase is equivalent to: git fetch origin git rebase origin/main 
Enter fullscreen mode Exit fullscreen mode

Pull Strategies:

1. Merge (Default):

git pull # Creates merge commit if branches diverged 
Enter fullscreen mode Exit fullscreen mode

2. Rebase:

git pull --rebase # Rebases your commits on top of remote commits # Creates linear history 
Enter fullscreen mode Exit fullscreen mode

3. Fast-forward Only:

git pull --ff-only # Only succeeds if fast-forward possible # Fails if branches diverged (safety measure) 
Enter fullscreen mode Exit fullscreen mode

Configure Default Pull Behavior:

# Use merge (default) git config --global pull.rebase false # Use rebase git config --global pull.rebase true # Use fast-forward only git config --global pull.ff only 
Enter fullscreen mode Exit fullscreen mode

Pull Specific Branch:

# Pull specific branch into current branch git pull origin feature-branch # Pull and create/update local branch git pull origin feature-branch:feature-branch 
Enter fullscreen mode Exit fullscreen mode

Pull with Options:

# Pull without commit (stage changes) git pull --no-commit # Pull with verbose output git pull --verbose git pull -v # Pull all remotes git pull --all # Pull and prune git pull --prune 
Enter fullscreen mode Exit fullscreen mode

Handling Pull Conflicts:

$ git pull Auto-merging file.txt CONFLICT (content): Merge conflict in file.txt Automatic merge failed; fix conflicts and then commit the result. # Resolve conflicts vim file.txt # Stage resolved files git add file.txt # Complete merge git commit # Or abort pull git merge --abort 
Enter fullscreen mode Exit fullscreen mode

Pull vs Fetch:

Use git fetch when:

  • Checking for updates without applying them
  • Reviewing changes before integrating
  • Need to inspect remote branches
  • Working on multiple features

Use git pull when:

  • Ready to integrate remote changes immediately
  • Branch is up-to-date and simple fast-forward expected
  • Quick synchronization needed

Best Practice: Many developers prefer git fetch + manual git merge/git rebase for more control:

# Explicit workflow (recommended) git fetch origin git log HEAD..origin/main # Review changes git merge origin/main # Merge when ready # Quick workflow (convenient but less control) git pull 
Enter fullscreen mode Exit fullscreen mode

git push - Update Remote Refs

Purpose: Upload local commits to remote repository, updating remote branches.

Basic Usage:

# Push to tracking branch git push # Push to specific remote and branch git push origin main # Push and set upstream tracking git push -u origin feature-branch git push --set-upstream origin feature-branch # Push all branches git push --all # Push tags git push --tags git push --follow-tags # Push tags reachable from pushed commits 
Enter fullscreen mode Exit fullscreen mode

How git push Works:

Local repository: main: A---B---C---D---E Remote repository before push: origin/main: A---B---C After git push origin main: origin/main: A---B---C---D---E (updated) 
Enter fullscreen mode Exit fullscreen mode

Setting Upstream:

# First push of new branch, set tracking git push -u origin feature-branch # Future pushes just need: git push # Configure automatic upstream setup git config --global push.autoSetupRemote true 
Enter fullscreen mode Exit fullscreen mode

Force Push:

# Force push (DANGEROUS - overwrites remote) git push --force # Safer force push (fails if remote has changes you don't have) git push --force-with-lease # Force push specific branch git push --force-with-lease origin feature-branch 
Enter fullscreen mode Exit fullscreen mode

⚠️ Critical Warning: Never force push to shared branches like main or develop. Only force push to your personal feature branches after rebasing.

Push Options:

Delete Remote Branch:

# Delete remote branch git push origin --delete feature-branch # Old syntax (still works) git push origin :feature-branch 
Enter fullscreen mode Exit fullscreen mode

Push Specific Refs:

# Push local branch to different remote branch git push origin local-branch:remote-branch # Push tag git push origin v1.0.0 # Push all tags git push origin --tags # Delete remote tag git push origin --delete tag v1.0.0 
Enter fullscreen mode Exit fullscreen mode

Push with Options:

# Dry run (see what would be pushed) git push --dry-run git push -n # Verbose output git push --verbose git push -v # Verify before push (run pre-push hook) git push --verify # Skip pre-push hook git push --no-verify 
Enter fullscreen mode Exit fullscreen mode

Push Behavior Configuration:

# Configure default push behavior # Simple: Push current branch to its upstream (default) git config --global push.default simple # Current: Push current branch to branch of same name git config --global push.default current # Upstream: Push current branch to its upstream branch git config --global push.default upstream # Matching: Push all matching branches git config --global push.default matching # Nothing: Don't push anything unless explicitly specified git config --global push.default nothing 
Enter fullscreen mode Exit fullscreen mode

Recommended: Use simple (default) or current.

Handling Push Rejection:

$ git push To https://github.com/user/repo.git ! [rejected] main -> main (fetch first) error: failed to push some refs to 'https://github.com/user/repo.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., 'git pull ...') before pushing again. # Solution 1: Pull first (merge) git pull git push # Solution 2: Pull with rebase git pull --rebase git push # Solution 3: Force push (DANGEROUS - only for personal branches) git push --force-with-lease 
Enter fullscreen mode Exit fullscreen mode

Real-World Push Scenarios:

Scenario 1: First Push of New Branch

# Create and switch to new branch git checkout -b feature/new-feature # Make commits git commit -am "Implement feature" # Push and set upstream git push -u origin feature/new-feature # Future pushes git push # Just works 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Update Feature Branch After Rebase

# Rebase feature on latest main git fetch origin git rebase origin/main # Force push (history changed) git push --force-with-lease 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Push Multiple Branches

# Push all branches git push --all origin # Push specific branches git push origin main develop feature-x 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Cleaning Up Remote Branches

# Delete merged feature branch git branch -d feature-old git push origin --delete feature-old # Or in one command git push origin --delete feature-old 
Enter fullscreen mode Exit fullscreen mode

Scenario 5: Push with CI/CD Trigger

# Push specific commit message to trigger deployment git commit -m "Deploy to production [deploy]" git push # Or use tags for releases git tag -a v1.2.0 -m "Release version 1.2.0" git push origin v1.2.0 
Enter fullscreen mode Exit fullscreen mode

Remote Branch Tracking

Understanding Remote-Tracking Branches:

Remote-tracking branches are references to the state of branches on remote repositories. They're named <remote>/<branch> (e.g., origin/main).

Viewing Tracking Information:

# Show all branches with tracking info git branch -vv # Output: * main abc123 [origin/main] Latest commit feature def456 [origin/feature: ahead 2, behind 1] Work in progress local ghi789 No tracking information # Ahead 2: You have 2 commits not pushed # Behind 1: Remote has 1 commit you don't have 
Enter fullscreen mode Exit fullscreen mode

Setting Up Tracking:

# Set upstream for current branch git branch -u origin/main git branch --set-upstream-to=origin/main # Set upstream when pushing git push -u origin feature-branch # Create branch tracking remote branch git checkout -b local-branch origin/remote-branch # Or with git switch git switch -c local-branch origin/remote-branch # Automatic tracking (Git 2.37+) git config --global push.autoSetupRemote true 
Enter fullscreen mode Exit fullscreen mode

Removing Tracking:

# Remove upstream tracking git branch --unset-upstream # Branch no longer tracks remote 
Enter fullscreen mode Exit fullscreen mode

Synchronizing with Remote:

# Fetch updates git fetch origin # See differences git log HEAD..origin/main # What's on remote you don't have git log origin/main..HEAD # What you have that's not on remote # Pull updates git pull # Push updates git push 
Enter fullscreen mode Exit fullscreen mode

Collaboration Workflows

Centralized Workflow:

Single central repository, everyone pushes to main:

# Clone repository git clone https://github.com/team/project.git cd project # Make changes git add . git commit -m "Add feature" # Pull latest changes git pull # Push changes git push 
Enter fullscreen mode Exit fullscreen mode

Feature Branch Workflow:

Each feature developed in dedicated branch:

# Create feature branch git checkout -b feature/awesome-feature # Make commits git commit -am "Implement feature" # Push feature branch git push -u origin feature/awesome-feature # Create pull request on GitHub/GitLab # After review and approval, merge # Delete branch git branch -d feature/awesome-feature git push origin --delete feature/awesome-feature 
Enter fullscreen mode Exit fullscreen mode

Gitflow Workflow:

Structured branching model with dedicated branches:

# Main branches: # - main: Production-ready code # - develop: Integration branch # Create feature branch from develop git checkout develop git checkout -b feature/new-feature # Develop feature git commit -am "Add feature" # Merge back to develop git checkout develop git merge feature/new-feature git branch -d feature/new-feature # Create release branch git checkout -b release/1.0 develop # Final testing and bug fixes # Merge to main and develop git checkout main git merge release/1.0 git tag v1.0 git checkout develop git merge release/1.0 git branch -d release/1.0 # Hotfix for production git checkout -b hotfix/critical-bug main # Fix bug git checkout main git merge hotfix/critical-bug git tag v1.0.1 git checkout develop git merge hotfix/critical-bug git branch -d hotfix/critical-bug 
Enter fullscreen mode Exit fullscreen mode

Fork and Pull Request Workflow:

Common in open source:

# Fork repository on GitHub/GitLab # Clone your fork git clone https://github.com/yourname/project.git cd project # Add upstream remote git remote add upstream https://github.com/original/project.git # Create feature branch git checkout -b feature/contribution # Make changes and commit git commit -am "Add contribution" # Keep updated with upstream git fetch upstream git rebase upstream/main # Push to your fork git push -u origin feature/contribution # Create pull request from your fork to upstream # After merge, sync your fork git checkout main git fetch upstream git merge upstream/main git push origin main 
Enter fullscreen mode Exit fullscreen mode

12. Inspection, Logging, and History Navigation {#inspection}

Understanding your repository's history is crucial. Git provides powerful tools for inspecting commits, changes, and project evolution.

git log - Show Commit Logs

Purpose: Display commit history with various formatting and filtering options.

Basic Usage:

# Show commit history git log # One commit per line git log --oneline # Show last N commits git log -n 5 git log -5 # Show commits with diffs git log -p git log --patch # Show commit stats git log --stat # Show graph of branches git log --graph --oneline --all 
Enter fullscreen mode Exit fullscreen mode

Understanding Log Output:

$ git log commit abc123def456... (HEAD -> main, origin/main) Author: John Doe <john@example.com> Date: Mon Dec 2 10:30:00 2024 -0800 Add user authentication feature Implemented JWT-based authentication with login and logout endpoints. Added middleware for protected routes. commit 789ghi012jkl... Author: Jane Smith <jane@example.com> Date: Sun Dec 1 15:20:00 2024 -0800 Fix bug in payment processing 
Enter fullscreen mode Exit fullscreen mode

Formatting Options:

# Oneline format git log --oneline # Output: abc123 Commit message # Short format git log --pretty=short # Full format (includes committer) git log --pretty=full # Fuller format (includes dates) git log --pretty=fuller # Custom format git log --pretty=format:"%h - %an, %ar : %s" # Output: abc123 - John Doe, 2 days ago : Commit message 
Enter fullscreen mode Exit fullscreen mode

Custom Format Placeholders:

Placeholder Description
%H Commit hash (full)
%h Commit hash (abbreviated)
%T Tree hash
%t Tree hash (abbreviated)
%P Parent hashes
%p Parent hashes (abbreviated)
%an Author name
%ae Author email
%ad Author date
%ar Author date, relative
%cn Committer name
%ce Committer email
%cd Committer date
%cr Committer date, relative
%s Subject (commit message)
%b Body (commit message)
%Cred Switch color to red
%Cgreen Switch color to green
%Cblue Switch color to blue
%Creset Reset color

Beautiful Custom Format:

git log --pretty=format:"%C(yellow)%h%Creset %C(blue)%ad%Creset %C(green)%an%Creset %s" --date=short # Or create alias: git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative" # Use: git lg 
Enter fullscreen mode Exit fullscreen mode

Graph Visualization:

# Show branch structure git log --graph # Compact graph git log --graph --oneline # All branches git log --graph --all --oneline # Decorated (show branch/tag names) git log --graph --decorate --oneline 
Enter fullscreen mode Exit fullscreen mode

Example output:

* abc123 (HEAD -> main) Latest commit * def456 Previous commit | * ghi789 (feature) Feature commit | * jkl012 Another feature commit |/ * mno345 Common ancestor 
Enter fullscreen mode Exit fullscreen mode

Filtering Commits:

By Author:

# Commits by specific author git log --author="John Doe" # Multiple authors (regex) git log --author="John\|Jane" # Case-insensitive git log --author="john" -i 
Enter fullscreen mode Exit fullscreen mode

By Date:

# Commits after date git log --since="2024-01-01" git log --after="2 weeks ago" # Commits before date git log --until="2024-12-31" git log --before="1 month ago" # Date range git log --since="2024-01-01" --until="2024-12-31" # Relative dates git log --since="2 weeks ago" git log --since="yesterday" git log --until="3 days ago" 
Enter fullscreen mode Exit fullscreen mode

By Message:

# Commits with message containing text git log --grep="bug fix" # Case-insensitive git log --grep="BUG" -i # Multiple patterns (OR) git log --grep="fix" --grep="bug" # Multiple patterns (AND) git log --grep="fix" --grep="bug" --all-match # Invert match (exclude) git log --grep="WIP" --invert-grep 
Enter fullscreen mode Exit fullscreen mode

By File:

# Commits affecting specific file git log -- path/to/file.txt # Multiple files git log -- file1.txt file2.txt # Files in directory git log -- src/ # Follow file renames git log --follow -- file.txt 
Enter fullscreen mode Exit fullscreen mode

By Content Changes:

# Commits adding or removing specific string git log -S "function_name" # With regex git log -G "regex_pattern" # Show patches with changes git log -S "function_name" -p 
Enter fullscreen mode Exit fullscreen mode

This is incredibly powerful for finding when specific code was introduced or removed.

By Commit Range:

# Commits between two commits git log commit1..commit2 # Commits reachable from commit2 but not commit1 git log commit1...commit2 # Commits on branch not on main git log main..feature-branch # Commits on main not on feature git log feature-branch..main # Not yet merged to main git log --no-merges main..feature 
Enter fullscreen mode Exit fullscreen mode

Limiting Output:

# First N commits git log -n 10 git log -10 # Skip first N commits git log --skip=5 # Maximum count git log --max-count=20 
Enter fullscreen mode Exit fullscreen mode

Merge and Non-Merge Commits:

# Only merge commits git log --merges # Exclude merge commits git log --no-merges # First parent only (simplifies merge history) git log --first-parent 
Enter fullscreen mode Exit fullscreen mode

Statistics and Patches:

# Show files changed and stats git log --stat # Show shorter stat git log --shortstat # Show name and status only git log --name-status # Show filenames only git log --name-only # Show patches (diffs) git log -p # Show word diff in patches git log -p --word-diff 
Enter fullscreen mode Exit fullscreen mode

Advanced Log Options:

# Show commits that changed number of lines git log --diff-filter=M --stat # Show only added files git log --diff-filter=A --name-only # Show only deleted files git log --diff-filter=D --name-only # Show renamed files git log --diff-filter=R --name-status # Complex filter (Added or Modified) git log --diff-filter=AM # Show commits touching specific function git log -L :function_name:path/to/file.c # Show commits changing lines 10-20 git log -L 10,20:path/to/file.txt 
Enter fullscreen mode Exit fullscreen mode

Real-World Log Examples:

Example 1: Daily Standup Report

# What did I do yesterday? git log --author="Your Name" --since="yesterday" --oneline # What did the team do this week? git log --since="1 week ago" --pretty=format:"%an: %s" --no-merges 
Enter fullscreen mode Exit fullscreen mode

Example 2: Release Notes

# Changes since last release git log v1.0.0..HEAD --oneline --no-merges # With categories git log v1.0.0..HEAD --pretty=format:"%s" --no-merges | grep "^feat:" git log v1.0.0..HEAD --pretty=format:"%s" --no-merges | grep "^fix:" 
Enter fullscreen mode Exit fullscreen mode

Example 3: Find Bug Introduction

# When was this function added? git log -S "problematic_function" --oneline # Show the actual changes git log -S "problematic_function" -p # Who introduced this bug? git log -S "buggy_code" --pretty=format:"%an - %s" 
Enter fullscreen mode Exit fullscreen mode

Example 4: Code Review Preparation

# All commits in feature branch git log main..feature-branch --oneline # With file changes git log main..feature-branch --name-status # With full diffs git log main..feature-branch -p 
Enter fullscreen mode Exit fullscreen mode

git show - Show Various Types of Objects

Purpose: Display information about Git objects (commits, tags, trees, blobs).

Basic Usage:

# Show latest commit git show # Show specific commit git show abc123 # Show commit with specific formatting git show --oneline abc123 # Show specific file at specific commit git show abc123:path/to/file.txt # Show tag git show v1.0.0 
Enter fullscreen mode Exit fullscreen mode

Showing Commits:

# Show commit with diff git show HEAD # Show previous commit git show HEAD^ git show HEAD~1 # Show grandparent commit git show HEAD~2 # Show specific commit git show abc123def # Show abbreviated commit git show --abbrev-commit abc123 
Enter fullscreen mode Exit fullscreen mode

Showing Specific Files:

# Show file at specific commit git show HEAD:README.md # Show file from different branch git show main:src/app.js # Show file as it was 5 commits ago git show HEAD~5:config.yml 
Enter fullscreen mode Exit fullscreen mode

Showing Tags:

# Show tag (displays tag object and commit) git show v1.0.0 # Show lightweight tag (just the commit) git show v1.0.1 
Enter fullscreen mode Exit fullscreen mode

Formatting Options:

# Show with stats git show --stat abc123 # Show with patch git show -p abc123 # Show abbreviated git show --oneline abc123 # Show with specific format git show --pretty=format:"%h - %s" abc123 
Enter fullscreen mode Exit fullscreen mode

Showing Trees:

# Show tree object (directory listing) git show abc123^{tree} # Show specific directory git show abc123:src/ 
Enter fullscreen mode Exit fullscreen mode

Real-World Show Examples:

Example 1: Inspect Merge Commit

# Show what was merged git show merge-commit-hash # Show files changed in merge git show --stat merge-commit-hash 
Enter fullscreen mode Exit fullscreen mode

Example 2: Compare File Versions

# Current version cat README.md # Version from 5 commits ago git show HEAD~5:README.md # Side-by-side comparison diff <(git show HEAD~5:README.md) README.md 
Enter fullscreen mode Exit fullscreen mode

Example 3: Extract File from History

# Get old version of file git show abc123:old-file.txt > recovered-file.txt 
Enter fullscreen mode Exit fullscreen mode

git diff - Show Differences (Covered Earlier)

We covered git diff extensively in the Basic Workflow section. Quick refresher on history-related diff usage:

# Diff between commits git diff commit1 commit2 # Diff with ancestor git diff HEAD~3 HEAD # Diff between branches git diff main feature-branch # Diff specific file between commits git diff abc123 def456 -- file.txt # Diff with three dots (since branches diverged) git diff main...feature-branch 
Enter fullscreen mode Exit fullscreen mode

git reflog - Reference Logs

Purpose: Shows history of HEAD and branch references, even after commits are "lost" from normal history. Essential for recovery.

Basic Usage:

# Show reflog for HEAD git reflog # Show reflog for specific branch git reflog show main # Show with dates git reflog --date=iso # Show relative dates git reflog --date=relative 
Enter fullscreen mode Exit fullscreen mode

Understanding Reflog Output:

$ git reflog abc123 HEAD@{0}: commit: Add feature X def456 HEAD@{1}: commit: Fix bug Y ghi789 HEAD@{2}: checkout: moving from main to feature jkl012 HEAD@{3}: commit: Update documentation mno345 HEAD@{4}: merge feature: Fast-forward pqr678 HEAD@{5}: commit: Initial commit 
Enter fullscreen mode Exit fullscreen mode

Each entry shows:

  • Commit hash
  • HEAD position reference (HEAD@{N})
  • Action performed
  • Message

Using Reflog References:

# Checkout previous HEAD position git checkout HEAD@{1} # Reset to where HEAD was 3 moves ago git reset --hard HEAD@{3} # Show commit from reflog git show HEAD@{5} # Diff with previous position git diff HEAD HEAD@{1} 
Enter fullscreen mode Exit fullscreen mode

Reflog with Time:

# HEAD position 1 hour ago git show HEAD@{1.hour.ago} # HEAD position yesterday git show HEAD@{yesterday} # HEAD position last week git show HEAD@{1.week.ago} # Branch position 2 days ago git show main@{2.days.ago} 
Enter fullscreen mode Exit fullscreen mode

Filtering Reflog:

# Show only specific action git reflog --grep="commit" git reflog --grep="rebase" git reflog --grep="checkout" # Show reflog for specific file git reflog -- path/to/file.txt # Limit output git reflog -n 20 git reflog -10 
Enter fullscreen mode Exit fullscreen mode

Reflog for All References:

# Show reflog for all refs (branches, tags, etc.) git reflog show --all # Specific branch reflog git reflog show feature-branch # Remote branch reflog git reflog show origin/main 
Enter fullscreen mode Exit fullscreen mode

Reflog Expiration:

Reflog entries expire after a certain time:

# Show reflog expiration configuration git config --get gc.reflogExpire # Default: 90 days git config --get gc.reflogExpireUnreachable # Default: 30 days # Change expiration git config gc.reflogExpire 180 # Keep for 180 days # Expire reflog manually git reflog expire --expire=30.days --all # Never expire (dangerous, can bloat repository) git config gc.reflogExpire never 
Enter fullscreen mode Exit fullscreen mode

Real-World Reflog Usage:

Scenario 1: Recover from Bad Reset

# Oops, accidentally reset too far git reset --hard HEAD~10 # Check reflog git reflog # abc123 HEAD@{0}: reset: moving to HEAD~10 # def456 HEAD@{1}: commit: Important work # Recover git reset --hard HEAD@{1} # or git reset --hard def456 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Recover Deleted Branch

# Accidentally deleted branch git branch -D important-feature # Deleted branch important-feature (was abc123). # Find it in reflog git reflog show important-feature # or search all reflog git reflog | grep "important-feature" # Recreate branch git branch important-feature abc123 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Undo Rebase Disaster

# Rebase went wrong git rebase main # ... conflicts, mess ... git rebase --abort # If still in progress # Or if rebase completed but broke things git reflog # Find commit before rebase git reset --hard HEAD@{5} 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Find Lost Commit

# Made commit, then somehow lost it git reflog --all | grep "commit message fragment" # Found it: abc123 git cherry-pick abc123 # or create branch git branch recovered-work abc123 
Enter fullscreen mode Exit fullscreen mode

git blame - Show What Revision Modified Each Line

Purpose: Show who last modified each line of a file and when. Essential for understanding code history and accountability.

Basic Usage:

# Blame entire file git blame filename.txt # Blame specific line range git blame -L 10,20 filename.txt # Blame with commit details git blame -c filename.txt # Show email instead of name git blame -e filename.txt 
Enter fullscreen mode Exit fullscreen mode

Understanding Blame Output:

$ git blame example.py abc123de (John Doe 2024-11-15 10:30:00 -0800 1) def calculate_total(items): abc123de (John Doe 2024-11-15 10:30:00 -0800 2) total = 0 def456gh (Jane Smith 2024-11-20 14:15:00 -0800 3) for item in items: def456gh (Jane Smith 2024-11-20 14:15:00 -0800 4) total += item.price ghi789jk (Bob Lee 2024-12-01 09:00:00 -0800 5) return total * 1.1 # Add tax 
Enter fullscreen mode Exit fullscreen mode

Columns:

  1. Commit hash
  2. Author name
  3. Date and time
  4. Line number
  5. Line content

Formatting Options:

# Show long format (full commit hash) git blame -l filename.txt # Show short format (abbreviated hash) git blame -s filename.txt # Suppress author name git blame -n filename.txt # Show line number git blame -n filename.txt # Show email addresses git blame -e filename.txt # Show relative dates git blame --date=relative filename.txt # Show custom date format git blame --date=short filename.txt git blame --date=iso filename.txt 
Enter fullscreen mode Exit fullscreen mode

Line Range:

# Blame lines 10 to 20 git blame -L 10,20 filename.txt # Blame from line 10 to end git blame -L 10, filename.txt # Blame first 50 lines git blame -L 1,50 filename.txt # Blame function (if Git can detect) git blame -L :function_name: filename.c 
Enter fullscreen mode Exit fullscreen mode

Following File Renames:

# Follow file renames git blame -C filename.txt # Follow with copy detection git blame -C -C filename.txt # Aggressive copy detection git blame -C -C -C filename.txt 
Enter fullscreen mode Exit fullscreen mode

Ignoring Whitespace:

# Ignore whitespace changes git blame -w filename.txt # Ignore whitespace changes at line ends git blame --ignore-space-at-eol filename.txt # Ignore all space changes git blame --ignore-space-change filename.txt 
Enter fullscreen mode Exit fullscreen mode

Blame Specific Revision:

# Blame as of specific commit git blame abc123 filename.txt # Blame as of tag git blame v1.0.0 filename.txt # Blame as of date git blame HEAD@{2.weeks.ago} filename.txt 
Enter fullscreen mode Exit fullscreen mode

Ignoring Revisions:

Useful for ignoring bulk formatting commits:

# Create .git-blame-ignore-revs echo "abc123def456" >> .git-blame-ignore-revs # Formatting commit # Configure Git to use it git config blame.ignoreRevsFile .git-blame-ignore-revs # Now blame ignores that commit git blame filename.txt 
Enter fullscreen mode Exit fullscreen mode

Interactive Blame:

# Use tig (if installed) for interactive blame tig blame filename.txt # Use Git GUI git gui blame filename.txt 
Enter fullscreen mode Exit fullscreen mode

Real-World Blame Examples:

Example 1: Find Who Introduced Bug

# Find problematic line grep -n "buggy_code" src/app.js # Line 42 matches # Blame that line git blame -L 42,42 src/app.js # abc123 (John Doe 2024-11-15) buggy_code # Show full commit git show abc123 # Contact John about the bug 
Enter fullscreen mode Exit fullscreen mode

Example 2: Understand Code History

# Why does this code exist? git blame -L 100,150 complex_file.py # See commits that modified these lines git log -p abc123 def456 ghi789 # Read commit messages for context 
Enter fullscreen mode Exit fullscreen mode

Example 3: Code Review Context

# Reviewing someone's changes git blame new_file.py # See who wrote each part # Check if recent changes are from PR author # Review their overall contribution patterns 
Enter fullscreen mode Exit fullscreen mode

Example 4: Track Feature Development

# When was this feature added? git blame -L :feature_function: src/features.js # See evolution git log -p abc123 # Initial commit git log -p def456 # Later modification 
Enter fullscreen mode Exit fullscreen mode

git shortlog - Summarize Git Log

Purpose: Summarize commit history by author, useful for generating release notes and contributor lists.

Basic Usage:

# Summarize by author git shortlog # Count commits per author git shortlog -sn git shortlog --summary --numbered # Show email addresses git shortlog -sne git shortlog --summary --numbered --email 
Enter fullscreen mode Exit fullscreen mode

Understanding Output:

$ git shortlog Jane Doe (10): Add user authentication Fix login bug Update documentation ... John Smith (5): Implement payment processing Add tests ... 
Enter fullscreen mode Exit fullscreen mode

With -sn (summary, numbered):

$ git shortlog -sn 10 Jane Doe 5 John Smith 3 Bob Lee 1 Alice Johnson 
Enter fullscreen mode Exit fullscreen mode

Filtering:

# Specific date range git shortlog --since="2024-01-01" --until="2024-12-31" # Specific author git shortlog --author="John" # Specific branch git shortlog main # Between commits/branches git shortlog v1.0..v2.0 # No merge commits git shortlog --no-merges 
Enter fullscreen mode Exit fullscreen mode

Formatting:

# Group by committer instead of author git shortlog -c # Show email addresses git shortlog -e # Custom format git shortlog --format="%h %s" 
Enter fullscreen mode Exit fullscreen mode

Real-World Shortlog Examples:

Example 1: Generate Release Notes

# Commits since last release git shortlog v1.0.0..HEAD --no-merges # Summarize contributions git shortlog v1.0.0..HEAD --no-merges -sn 
Enter fullscreen mode Exit fullscreen mode

Example 2: Contributor Recognition

# All-time contributors git shortlog -sn # Contributors this year git shortlog --since="2024-01-01" -sn # New contributors this release git shortlog v1.0..HEAD -sn 
Enter fullscreen mode Exit fullscreen mode

Example 3: Team Activity Report

# Activity last month git shortlog --since="1 month ago" -sn # Detailed activity git shortlog --since="1 week ago" 
Enter fullscreen mode Exit fullscreen mode

git describe - Describe Commit Using Tags

Purpose: Give human-readable name to commit based on available tags.

Basic Usage:

# Describe current commit git describe # Describe specific commit git describe abc123 # Describe with tags git describe --tags # Always show long format git describe --long 
Enter fullscreen mode Exit fullscreen mode

Understanding Output:

$ git describe v1.2.0-5-gabc123d # Breakdown: # v1.2.0: Most recent tag # 5: Number of commits since tag # g: Prefix indicating Git # abc123d: Abbreviated commit hash 
Enter fullscreen mode Exit fullscreen mode

If on exact tag:

$ git describe v1.2.0 # Just the tag name 
Enter fullscreen mode Exit fullscreen mode

Options:

# Abbreviated commit hash length git describe --abbrev=10 # Only show tag (no commit count) git describe --exact-match # Fails if not on tag # Always show tag-commits-hash git describe --long # Use all refs, not just tags git describe --all # Use any tag (annotated or lightweight) git describe --tags # Add dirty indicator for modified working directory git describe --dirty git describe --dirty=-modified # Output: v1.2.0-5-gabc123d-modified 
Enter fullscreen mode Exit fullscreen mode

Real-World Describe Usage:

Example 1: Version Numbering

# Get version for build VERSION=$(git describe --tags --always --dirty) echo "Building version: $VERSION" # Use in code echo "#define VERSION \"$VERSION\"" > version.h 
Enter fullscreen mode Exit fullscreen mode

Example 2: Release Identification

# What release is this commit from? git describe abc123 # Output: v1.2.0-3-gabc123 # It's 3 commits after v1.2.0 
Enter fullscreen mode Exit fullscreen mode

Example 3: CI/CD Versioning

# In CI/CD pipeline GIT_VERSION=$(git describe --tags --always --dirty) docker build -t myapp:$GIT_VERSION . 
Enter fullscreen mode Exit fullscreen mode

Navigating History

Relative References:

Git provides convenient syntax for referring to commits relative to others:

Parent References:

# Parent of HEAD HEAD^ HEAD~1 # Grandparent HEAD^^ HEAD~2 # Great-grandparent HEAD^^^ HEAD~3 # Show specific parent commit git show HEAD^ git show HEAD~2 
Enter fullscreen mode Exit fullscreen mode

For Merge Commits (Multiple Parents):

# First parent (main branch) HEAD^1 HEAD^ # Second parent (merged branch) HEAD^2 # Grandparent through first parent HEAD^^1 HEAD~2 # Grandparent through second parent HEAD^2^ 
Enter fullscreen mode Exit fullscreen mode

Combining References:

# Third commit before HEAD HEAD~3 # First parent of second parent of HEAD HEAD^2^1 # Show range HEAD~5..HEAD~2 
Enter fullscreen mode Exit fullscreen mode

Branch References:

# Latest commit on branch main origin/main feature/auth # Previous commit on branch main^ main~1 # Branch as of yesterday main@{yesterday} # Branch as of specific date main@{2024-11-15} 
Enter fullscreen mode Exit fullscreen mode

Real-World Navigation:

# View previous commit git show HEAD^ # Compare current with 5 commits ago git diff HEAD~5 HEAD # Checkout previous version git checkout HEAD~3 # Cherry-pick parent's parent git cherry-pick HEAD~2 # Reset to 3 commits ago git reset --soft HEAD~3 
Enter fullscreen mode Exit fullscreen mode

13. Stashing: Temporary Storage {#stashing}

Stashing saves your work temporarily without committing, allowing you to switch contexts cleanly.

git stash - Stash Changes

Purpose: Temporarily save modified tracked files and staged changes, reverting working directory to clean state.

Basic Usage:

# Stash current changes git stash # Stash with message git stash push -m "Work in progress on feature X" # Stash including untracked files git stash -u git stash --include-untracked # Stash everything (including ignored files) git stash -a git stash --all # List stashes git stash list # Apply most recent stash git stash apply # Apply and remove most recent stash git stash pop # Remove stash git stash drop # Clear all stashes git stash clear 
Enter fullscreen mode Exit fullscreen mode

How Stashing Works:

Before stash: Working Directory: Modified files Staging Area: Staged files Repository: Clean After git stash: Working Directory: Clean (matches HEAD) Staging Area: Clean Stash: Saved changes (both working directory and staging area) 
Enter fullscreen mode Exit fullscreen mode

Stash List:

$ git stash list stash@{0}: WIP on main: abc123 Latest commit stash@{1}: On feature: Work in progress stash@{2}: WIP on develop: def456 Previous work 
Enter fullscreen mode Exit fullscreen mode

Stashes are numbered: stash@{0} is most recent, stash@{1} is older, etc.

Stashing Options:

Stash with Message:

# Better than default "WIP on branch" git stash push -m "Implementing user authentication" # Or (older syntax, still works) git stash save "Implementing user authentication" 
Enter fullscreen mode Exit fullscreen mode

Partial Stashing:

# Stash specific files git stash push path/to/file1.txt path/to/file2.txt # Stash with pattern git stash push -m "Config changes" -- '*.config' # Interactive stashing git stash push -p git stash push --patch # Choose which hunks to stash (like git add -p) 
Enter fullscreen mode Exit fullscreen mode

Stash Untracked Files:

# Include untracked files git stash -u git stash --include-untracked # Include ignored files too git stash -a git stash --all 
Enter fullscreen mode Exit fullscreen mode

Stash Keeping Index:

# Stash working directory changes but keep staging area git stash --keep-index # Use case: You staged changes for one commit, # but need to quickly switch branches 
Enter fullscreen mode Exit fullscreen mode

Applying Stashes:

# Apply most recent stash (keeps stash in list) git stash apply # Apply specific stash git stash apply stash@{2} # Apply and remove (pop) git stash pop git stash pop stash@{1} # Apply only file changes, not staging information git stash apply --index 
Enter fullscreen mode Exit fullscreen mode

Viewing Stashes:

# List stashes git stash list # Show stash contents git stash show # Show detailed diff git stash show -p git stash show --patch # Show specific stash git stash show stash@{1} -p 
Enter fullscreen mode Exit fullscreen mode

Managing Stashes:

# Drop specific stash git stash drop stash@{1} # Clear all stashes (CAUTION: irreversible) git stash clear # Create branch from stash git stash branch new-branch-name git stash branch new-branch stash@{1} 
Enter fullscreen mode Exit fullscreen mode

Creating a branch from stash applies the stash and drops it if successful.

Real-World Stash Scenarios:

Scenario 1: Quick Context Switch

# Working on feature, urgent bug reported git stash push -m "WIP: feature X implementation" # Switch to main, fix bug git checkout main git checkout -b hotfix/critical-bug # Fix bug, commit, push # Return to feature work git checkout feature-branch git stash pop 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Clean Working Directory for Pull

# Have local changes, need to pull git stash -u # Pull updates git pull # Reapply changes git stash pop # If conflicts, resolve and drop manually git stash drop 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Experiment Without Committing

# Current work is not ready to commit git stash # Try experimental approach # ... make changes ... # Doesn't work, discard git reset --hard # Restore original work git stash pop 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Partial Stashing

# Have changes for two different features git stash push -p -m "Feature A changes" # Select only Feature A hunks # Commit Feature B git commit -am "Implement Feature B" # Restore Feature A work git stash pop 
Enter fullscreen mode Exit fullscreen mode

Scenario 5: Transfer Work Between Branches

# Started work on wrong branch git stash # Switch to correct branch git checkout correct-branch # Apply work git stash pop 
Enter fullscreen mode Exit fullscreen mode

Advanced Stash Techniques:

Stash and Create Branch:

# Stash causes conflicts when popping git stash pop # CONFLICT... # Instead, create branch from stash git stash branch fix-conflicts # Git creates branch, applies stash, drops it if successful # You're now on new branch with changes applied 
Enter fullscreen mode Exit fullscreen mode

Recover Dropped Stash:

# Accidentally dropped important stash git stash drop stash@{0} # Oops! # Find it in reflog git fsck --unreachable | grep commit | cut -d ' ' -f3 | xargs git log --merges --no-walk --grep=WIP # Or search reflog git log --graph --oneline --decorate $(git fsck --no-reflog | awk '/dangling commit/ {print $3}') # Apply recovered stash git stash apply <commit-hash> 
Enter fullscreen mode Exit fullscreen mode

Stash Part of Staging Area:

# Some files staged, some not git status # Changes to be committed: file1.txt # Changes not staged: file2.txt # Stash only unstaged changes git stash --keep-index # Now only staged changes remain 
Enter fullscreen mode Exit fullscreen mode

Create Stash Without Changing Working Directory:

# Create stash but don't clean working directory git stash create # Returns stash commit hash # Useful for scripting 
Enter fullscreen mode Exit fullscreen mode

Comparing Stashes:

# Diff between stash and current state git diff stash@{0} # Diff between two stashes git diff stash@{0} stash@{1} # Diff stash with specific commit git diff stash@{0} main 
Enter fullscreen mode Exit fullscreen mode

14. Tagging: Marking Important Points {#tagging}

Tags mark specific points in history as important, typically for releases.

git tag - Create, List, Delete Tags

Purpose: Create named references to specific commits, typically for marking releases.

Types of Tags:

1. Lightweight Tags:

  • Simple pointer to commit
  • Just a name
  • Like a branch that doesn't move

2. Annotated Tags:

  • Full Git objects
  • Contain tagger name, email, date
  • Can be signed and verified
  • Can have message
  • Recommended for releases

Basic Usage:

# List tags git tag # List tags with pattern git tag -l "v1.*" git tag --list "v1.*" # Create lightweight tag git tag v1.0.0 # Create annotated tag git tag -a v1.0.0 -m "Release version 1.0.0" git tag --annotate v1.0.0 -m "Release version 1.0.0" # Tag specific commit git tag v1.0.0 abc123 # Delete tag git tag -d v1.0.0 git tag --delete v1.0.0 # Show tag info git show v1.0.0 
Enter fullscreen mode Exit fullscreen mode

Creating Tags:

Lightweight Tag:

# Create lightweight tag on HEAD git tag v1.0.0 # Create on specific commit git tag v1.0.0 abc123 
Enter fullscreen mode Exit fullscreen mode

Annotated Tag (Recommended):

# Create annotated tag with message git tag -a v1.0.0 -m "Release version 1.0.0" # Create annotated tag and open editor for message git tag -a v1.0.0 # Tag specific commit git tag -a v1.0.0 abc123 -m "Release 1.0.0" 
Enter fullscreen mode Exit fullscreen mode

Signed Tags:

# Create signed tag (requires GPG) git tag -s v1.0.0 -m "Signed release 1.0.0" git tag --sign v1.0.0 -m "Signed release 1.0.0" # Verify signed tag git tag -v v1.0.0 git tag --verify v1.0.0 
Enter fullscreen mode Exit fullscreen mode

Listing Tags:

# List all tags git tag # List with pattern git tag -l "v1.8.*" git tag -l "v2.*" # List annotated tags with messages git tag -n git tag -n9 # Show up to 9 lines of message # Sort tags git tag --sort=-version:refname # Descending version sort git tag --sort=version:refname # Ascending version sort git tag --sort=-committerdate # By date 
Enter fullscreen mode Exit fullscreen mode

Showing Tag Information:

# Show tag and commit info git show v1.0.0 # Show only tag object git cat-file -p v1.0.0 # List tags with commit info git show-ref --tags 
Enter fullscreen mode Exit fullscreen mode

Deleting Tags:

# Delete local tag git tag -d v1.0.0 # Delete remote tag git push origin --delete v1.0.0 git push origin :refs/tags/v1.0.0 # Old syntax 
Enter fullscreen mode Exit fullscreen mode

Pushing Tags:

# Push specific tag git push origin v1.0.0 # Push all tags git push origin --tags # Push only annotated tags git push --follow-tags # Configure to always push annotated tags git config --global push.followTags true 
Enter fullscreen mode Exit fullscreen mode

Checking Out Tags:

# Checkout tag (detached HEAD) git checkout v1.0.0 # Create branch from tag git checkout -b version-1.0 v1.0.0 # Switch to tag (Git 2.23+) git switch --detach v1.0.0 
Enter fullscreen mode Exit fullscreen mode

Real-World Tagging Scenarios:

Scenario 1: Release Workflow

# Finalize release commit git commit -m "Bump version to 1.0.0" # Create annotated tag git tag -a v1.0.0 -m "Release 1.0.0 Major features: - User authentication - Payment processing - Admin dashboard Breaking changes: - API endpoint /v1/users renamed to /v2/users" # Push commit and tag git push origin main git push origin v1.0.0 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Semantic Versioning

# Major release (breaking changes) git tag -a v2.0.0 -m "Major release with breaking changes" # Minor release (new features) git tag -a v2.1.0 -m "Add new features" # Patch release (bug fixes) git tag -a v2.1.1 -m "Fix critical bug" # Pre-release git tag -a v2.2.0-beta.1 -m "Beta release" 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Hotfix Tagging

# Critical bug in production (v1.2.0) git checkout v1.2.0 git checkout -b hotfix/security-fix # Fix bug git commit -m "Fix security vulnerability" # Tag hotfix git tag -a v1.2.1 -m "Security hotfix" # Push git push origin hotfix/security-fix git push origin v1.2.1 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Build Versioning

# Tag nightly build DATE=$(date +%Y%m%d) git tag -a nightly-$DATE -m "Nightly build $DATE" # Tag release candidate git tag -a v1.0.0-rc.1 -m "Release candidate 1" git tag -a v1.0.0-rc.2 -m "Release candidate 2" 
Enter fullscreen mode Exit fullscreen mode

Scenario 5: Comparing Releases

# Changes between releases git log v1.0.0..v2.0.0 --oneline # Diff between releases git diff v1.0.0 v2.0.0 # Files changed git diff --name-status v1.0.0 v2.0.0 # Generate changelog git log v1.0.0..v2.0.0 --no-merges --pretty=format:"- %s" 
Enter fullscreen mode Exit fullscreen mode

Tag Naming Conventions:

Semantic Versioning:

v1.0.0 (or 1.0.0) vMAJOR.MINOR.PATCH Examples: v1.0.0 - Initial release v1.1.0 - New features v1.1.1 - Bug fixes v2.0.0 - Breaking changes Pre-releases: v1.0.0-alpha v1.0.0-beta.1 v1.0.0-rc.1 
Enter fullscreen mode Exit fullscreen mode

Date-Based:

release-2024.12.02 v2024.12 
Enter fullscreen mode Exit fullscreen mode

Build Numbers:

build-12345 v1.0.0-build.456 
Enter fullscreen mode Exit fullscreen mode

Best Practices:

  1. Use annotated tags for releases:
# Good git tag -a v1.0.0 -m "Release 1.0.0" # Avoid for releases git tag v1.0.0 
Enter fullscreen mode Exit fullscreen mode
  1. Be consistent with naming:
# Choose one format and stick to it v1.0.0, v1.1.0, v2.0.0 # Good v1.0.0, 1.1.0, version-2.0 # Inconsistent 
Enter fullscreen mode Exit fullscreen mode
  1. Don't move tags:
# DON'T do this: git tag -d v1.0.0 git tag v1.0.0 different-commit # Tags should be permanent markers 
Enter fullscreen mode Exit fullscreen mode
  1. Sign release tags:
# For important releases git tag -s v1.0.0 -m "Signed release" 
Enter fullscreen mode Exit fullscreen mode
  1. Document releases in tag messages:
git tag -a v1.0.0 -m "Release 1.0.0 Features: - Feature A - Feature B Bug fixes: - Fix issue #123 Breaking changes: - API change in module X" 
Enter fullscreen mode Exit fullscreen mode

15. Advanced History Modification {#history-modification}

⚠️ Warning: These commands rewrite history. Never use on public/shared branches unless you understand the consequences.

git commit --amend (Covered Earlier)

Quick refresher:

# Modify last commit git commit --amend # Amend without changing message git commit --amend --no-edit # Amend and change author git commit --amend --author="New Author <email@example.com>" 
Enter fullscreen mode Exit fullscreen mode

git reset - Reset Current HEAD

Purpose: Move HEAD (and optionally branch) to specified commit, with various effects on staging area and working directory.

Three Modes:

1. Soft Reset:

  • Moves HEAD and branch pointer
  • Keeps staging area unchanged
  • Keeps working directory unchanged
  • Commits become "uncommitted changes"

2. Mixed Reset (Default):

  • Moves HEAD and branch pointer
  • Resets staging area to match commit
  • Keeps working directory unchanged
  • Commits become "unstaged changes"

3. Hard Reset:

  • Moves HEAD and branch pointer
  • Resets staging area to match commit
  • Resets working directory to match commit
  • Destroys uncommitted changes

Basic Usage:

# Soft reset (uncommit, keep changes staged) git reset --soft HEAD~1 # Mixed reset (unstage changes) git reset HEAD~1 git reset --mixed HEAD~1 # Hard reset (discard everything) git reset --hard HEAD~1 # Reset to specific commit git reset --hard abc123 # Reset specific file git reset HEAD file.txt 
Enter fullscreen mode Exit fullscreen mode

Visual Representation:

Initial state: A---B---C---D (HEAD, main) After git reset --soft HEAD~2: A---B---C---D ↑ (HEAD, main) Changes from C and D are staged After git reset --mixed HEAD~2: A---B---C---D ↑ (HEAD, main) Changes from C and D are unstaged After git reset --hard HEAD~2: A---B (HEAD, main) Commits C and D are "gone" (but recoverable via reflog) 
Enter fullscreen mode Exit fullscreen mode

Reset Modes Comparison:

Mode HEAD Staging Area Working Directory
--soft Reset Unchanged Unchanged
--mixed Reset Reset Unchanged
--hard Reset Reset Reset

Common Reset Scenarios:

Scenario 1: Undo Last Commit (Keep Changes)

# Undo commit, keep changes staged git reset --soft HEAD~1 # Now you can re-commit with different message or add more changes git commit -m "Better commit message" 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Unstage Files

# 1Accidentally staged wrong file git add wrong-file.txt # Unstage it git reset HEAD wrong-file.txt # or (Git 2.23+) git restore --staged wrong-file.txt 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Completely Undo Commits

# Discard last 3 commits entirely git reset --hard HEAD~3 # WARNING: This destroys commits and changes # Only do this on unpushed commits 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Squash Commits Before Pushing

# You have 5 messy commits git log --oneline # e5 Fix typo # e4 Fix another typo # e3 Implement feature # e2 WIP # e1 Start feature # Reset to before commits (keep changes) git reset --soft HEAD~5 # Now create one clean commit git commit -m "Implement feature X" 
Enter fullscreen mode Exit fullscreen mode

Scenario 5: Discard Local Changes

# Made a mess, want to start over git reset --hard HEAD # Or go back to specific commit git reset --hard origin/main 
Enter fullscreen mode Exit fullscreen mode

Reset Specific Paths:

# Reset specific file to specific commit git reset abc123 -- path/to/file.txt # Reset multiple files git reset HEAD -- file1.txt file2.txt # Reset directory git reset HEAD -- src/ 
Enter fullscreen mode Exit fullscreen mode

Recovery from Reset:

If you reset by mistake:

# View reflog git reflog # Find commit before reset # abc123 HEAD@{1}: commit: Important work # Reset back git reset --hard abc123 # or git reset --hard HEAD@{1} 
Enter fullscreen mode Exit fullscreen mode

git revert - Revert Commits

Purpose: Create new commit that undoes changes from previous commit(s). Safe for public branches because it doesn't rewrite history.

Basic Usage:

# Revert last commit git revert HEAD # Revert specific commit git revert abc123 # Revert multiple commits git revert abc123 def456 ghi789 # Revert range git revert HEAD~3..HEAD # Revert without committing (stage changes) git revert -n abc123 git revert --no-commit abc123 
Enter fullscreen mode Exit fullscreen mode

How Revert Works:

Original: A---B---C---D (HEAD, main) After git revert C: A---B---C---D---E (HEAD, main) ↑ Revert C (undoes changes from C) 
Enter fullscreen mode Exit fullscreen mode

Commit E contains the inverse of changes in commit C.

Revert vs Reset:

Feature git revert git reset
History Creates new commit Moves HEAD pointer
Public branches ✅ Safe ❌ Dangerous
Undo method Add inverse changes Remove commits
History rewrite No Yes

Revert Options:

Edit Commit Message:

# Revert and open editor for message git revert abc123 # Use default message git revert abc123 --no-edit # Custom message git revert abc123 -m "Revert problematic feature" 
Enter fullscreen mode Exit fullscreen mode

Revert Merge Commits:

Merge commits have multiple parents, must specify which to revert to:

# Revert merge commit, keeping main history git revert -m 1 merge-commit-hash # -m 1: Keep changes from first parent (main) # -m 2: Keep changes from second parent (merged branch) 
Enter fullscreen mode Exit fullscreen mode

Multiple Reverts:

# Revert multiple commits separately git revert abc123 def456 # Revert range (oldest..newest) git revert abc123..def456 # Revert without auto-commit (for manual adjustments) git revert -n abc123 def456 ghi789 git commit -m "Revert multiple changes" 
Enter fullscreen mode Exit fullscreen mode

Abort Revert:

# If revert causes conflicts git revert --abort # Or if using -n flag git revert --quit 
Enter fullscreen mode Exit fullscreen mode

Continue Revert:

# After resolving conflicts git add resolved-file.txt git revert --continue 
Enter fullscreen mode Exit fullscreen mode

Real-World Revert Scenarios:

Scenario 1: Revert Bad Commit on Main

# Bad commit pushed to main git log --oneline # abc123 (HEAD -> main, origin/main) Bad feature # def456 Previous commit # Revert it (safe for public branch) git revert abc123 # Push revert git push origin main 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Revert Merge

# Merged feature branch, but it broke production git log --oneline --graph # * abc123 (HEAD -> main) Merge branch 'feature' # |\ # | * def456 Feature commit # * | ghi789 Main commit # Revert merge git revert -m 1 abc123 # Push git push origin main 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Revert Series of Commits

# Last 5 commits introduced bugs git revert --no-commit HEAD~4..HEAD # Review changes git diff --staged # Commit all reverts together git commit -m "Revert commits that introduced bugs" 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Partial Revert

# Revert commit but stage only (no commit) git revert -n abc123 # Unstage specific files you want to keep git restore --staged file-to-keep.txt # Commit partial revert git commit -m "Partially revert abc123" 
Enter fullscreen mode Exit fullscreen mode

git cherry-pick (Covered in Next Section)

Cherry-picking applies specific commits from one branch to another.


16. Cherry-Picking and Patching {#cherry-picking}

git cherry-pick - Apply Changes from Existing Commits

Purpose: Apply changes from specific commits onto current branch, creating new commits.

Basic Usage:

# Cherry-pick single commit git cherry-pick abc123 # Cherry-pick multiple commits git cherry-pick abc123 def456 ghi789 # Cherry-pick range git cherry-pick abc123..def456 # Cherry-pick without committing git cherry-pick -n abc123 git cherry-pick --no-commit abc123 
Enter fullscreen mode Exit fullscreen mode

How Cherry-Pick Works:

Source branch: A---B---C---D (feature) Target branch before: A---B---E---F (main, HEAD) After git cherry-pick C: A---B---E---F---C' (main, HEAD) C' is new commit with same changes as C but different hash 
Enter fullscreen mode Exit fullscreen mode

Cherry-Pick Options:

Edit Commit Message:

# Cherry-pick and edit message git cherry-pick -e abc123 git cherry-pick --edit abc123 # Use original message git cherry-pick -x abc123 # Adds "cherry picked from" note 
Enter fullscreen mode Exit fullscreen mode

Mainline Parent (for Merges):

# Cherry-pick merge commit git cherry-pick -m 1 merge-commit # -m 1: Use first parent # -m 2: Use second parent 
Enter fullscreen mode Exit fullscreen mode

Sign Off:

# Add Signed-off-by line git cherry-pick -s abc123 git cherry-pick --signoff abc123 
Enter fullscreen mode Exit fullscreen mode

Continue, Abort, Quit:

# If conflicts occur git cherry-pick abc123 # CONFLICT... # Resolve conflicts git add resolved-file.txt # Continue git cherry-pick --continue # Or abort git cherry-pick --abort # Or quit (leave in current state) git cherry-pick --quit 
Enter fullscreen mode Exit fullscreen mode

Multiple Cherry-Picks:

# Cherry-pick range (exclusive start, inclusive end) git cherry-pick abc123..def456 # Cherry-pick all commits from branch git cherry-pick feature-branch # Cherry-pick with strategy git cherry-pick -X theirs abc123 git cherry-pick -X ours abc123 
Enter fullscreen mode Exit fullscreen mode

Real-World Cherry-Pick Scenarios:

Scenario 1: Apply Hotfix to Multiple Branches

# Hotfix committed to main git checkout main git commit -m "Fix critical security bug" # Commit: abc123 # Apply to release branch git checkout release-2.0 git cherry-pick abc123 # Apply to release branch 1.0 git checkout release-1.0 git cherry-pick abc123 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Extract Commits from Feature Branch

# Feature branch has 10 commits # Only commits 3 and 7 are ready git checkout main git cherry-pick <commit-3-hash> git cherry-pick <commit-7-hash> # Leave rest of feature for later 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Move Commit to Different Branch

# Accidentally committed to main instead of feature git log --oneline # abc123 (HEAD -> main) Feature work # Create feature branch git branch feature abc123 # Remove from main (if not pushed) git reset --hard HEAD~1 # Or revert if already pushed git revert abc123 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Apply Commits Between Forks

# Add fork as remote git remote add other-fork https://github.com/other/repo.git git fetch other-fork # Cherry-pick their commit git cherry-pick other-fork/main~2 
Enter fullscreen mode Exit fullscreen mode

Scenario 5: Selective Backporting

# Backport specific fixes to older version git checkout stable-1.0 git cherry-pick bug-fix-hash-1 git cherry-pick bug-fix-hash-2 git cherry-pick feature-hash # Skip if not compatible # Test and push git push origin stable-1.0 
Enter fullscreen mode Exit fullscreen mode

git apply - Apply Patch Files

Purpose: Apply changes from patch files (created with git diff or git format-patch).

Basic Usage:

# Apply patch git apply patch-file.patch # Apply and stage changes git apply --index patch-file.patch # Check if patch can be applied git apply --check patch-file.patch # Apply with statistics git apply --stat patch-file.patch # Reject conflicts to separate files git apply --reject patch-file.patch 
Enter fullscreen mode Exit fullscreen mode

Creating Patches:

Method 1: Using git diff:

# Create patch from uncommitted changes git diff > changes.patch # Create patch from specific commits git diff abc123 def456 > feature.patch # Create patch for specific files git diff -- file1.txt file2.txt > files.patch 
Enter fullscreen mode Exit fullscreen mode

Method 2: Using git format-patch:

# Create patch for last commit git format-patch -1 HEAD # Create patches for last 3 commits git format-patch -3 # Create patches since specific commit git format-patch abc123..HEAD # Create patch for specific commit git format-patch -1 abc123 # Output to specific directory git format-patch -o patches/ abc123..HEAD 
Enter fullscreen mode Exit fullscreen mode

Applying Patches:

# Apply patch file git apply changes.patch # Apply and stage git apply --index changes.patch # Apply with three-way merge git apply -3 changes.patch # Apply formatted patches (preserves author, message) git am patches/0001-feature.patch # Apply multiple formatted patches git am patches/*.patch 
Enter fullscreen mode Exit fullscreen mode

Patch Options:

Check Before Applying:

# Dry run git apply --check patch.patch # Show what would change git apply --stat patch.patch # Show actual changes git apply --summary patch.patch 
Enter fullscreen mode Exit fullscreen mode

Handle Whitespace:

# Ignore whitespace changes git apply --ignore-whitespace patch.patch # Warn about whitespace errors git apply --whitespace=warn patch.patch # Fix whitespace automatically git apply --whitespace=fix patch.patch 
Enter fullscreen mode Exit fullscreen mode

Reverse Apply:

# Unapply patch git apply --reverse patch.patch git apply -R patch.patch 
Enter fullscreen mode Exit fullscreen mode

Partial Application:

# Apply specific files from patch git apply --include='*.txt' patch.patch # Exclude specific files git apply --exclude='test/*' patch.patch 
Enter fullscreen mode Exit fullscreen mode

Real-World Patching Scenarios:

Scenario 1: Email-Based Workflow

# Create patches to email git format-patch -2 HEAD --stdout > feature.patch # Email feature.patch # Recipient applies git am feature.patch 
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Quick Fix Sharing

# Create quick fix git diff > quickfix.patch # Send to colleague # Colleague applies git apply quickfix.patch git commit -am "Apply quick fix" 
Enter fullscreen mode Exit fullscreen mode

Scenario 3: Code Review via Patches

# Generate patches for review git format-patch origin/main # Output: 0001-commit1.patch, 0002-commit2.patch # Reviewer applies and tests git am 0001-commit1.patch # Test git am 0002-commit2.patch # Test 
Enter fullscreen mode Exit fullscreen mode

Scenario 4: Resolve Conflicts in Patches

# Apply patch with conflicts git apply changes.patch # error: patch failed... # Apply with reject files git apply --reject changes.patch # Creates .rej files for failed hunks # Manually apply .rej files # Then stage git add . git commit 
Enter fullscreen mode Exit fullscreen mode

git format-patch - Prepare Patches for Email

Purpose: Create properly formatted patch files suitable for email submission, preserving commit metadata.

Basic Usage:

# Create patch for last commit git format-patch -1 # Create patches for last N commits git format-patch -5 # Create patches since commit git format-patch abc123 # Create patches for range git format-patch abc123..def456 # Output to directory git format-patch -o output-dir/ abc123..HEAD 
Enter fullscreen mode Exit fullscreen mode

Format-Patch Options:

# Include cover letter git format-patch --cover-letter -3 # Add threading headers for email git format-patch --thread -3 # Include signature git format-patch --signature="My Signature" -1 # Suppress diff output git format-patch --stdout abc123 > patch.txt # Include binary files git format-patch --binary -1 
Enter fullscreen mode Exit fullscreen mode

Real-World Format-Patch Usage:

Linux Kernel Style Submission:

# Create patch series with cover letter git format-patch --cover-letter -3 --thread -o patches/ # Edit cover letter vim patches/0000-cover-letter.patch # Send via email git send-email patches/* 
Enter fullscreen mode Exit fullscreen mode

git am - Apply Mailbox Format Patches

Purpose: Apply patches from email (created with git format-patch), preserving commit information.

Basic Usage:

# Apply single patch git am 0001-feature.patch # Apply multiple patches git am patches/*.patch # Apply from stdin cat feature.patch | git am # Apply interactively git am -i patches/*.patch 
Enter fullscreen mode Exit fullscreen mode

Handling Conflicts:

# Apply patch git am feature.patch # Conflict occurs # Resolve conflicts vim conflicted-file.txt git add conflicted-file.txt # Continue git am --continue # Skip this patch git am --skip # Abort git am --abort 
Enter fullscreen mode Exit fullscreen mode

AM Options:

# Apply with three-way merge git am -3 patch.patch # Sign off patches git am -s patches/*.patch # Keep non-patch content in commit message git am -k patches/*.patch # Ignore whitespace git am --ignore-whitespace patches/*.patch 
Enter fullscreen mode Exit fullscreen mode

This completes the comprehensive sections on Git fundamentals, branching, merging, rebasing, remotes, inspection, stashing, tagging, history modification, and cherry-picking/patching.

Top comments (0)