Skip to content

๐Ÿš€ Advanced Techniques โ€‹

git stash โ€” Temporarily Save Your Work โ€‹

Scenario: You're developing a new feature when your boss suddenly says "There's an urgent bug in production, fix it now!" Your code is half-done and you don't want to commit an unfinished change. What do you do? git stash to the rescue!

bash
# "Hide" your current changes
git stash
Saved working directory and index state WIP on main: f4e5d6c feat: add welcome message

# Working directory is now clean
git status
On branch main
nothing to commit, working tree clean

# Now you can fix the bug with peace of mind...
# After fixing and committing the bug, restore your work
git stash pop
On branch main
Changes not staged for commit:
        modified:   index.html

# View all stash records
git stash list
stash@{0}: WIP on main: f4e5d6c feat: add welcome message

# Stash with a description (recommended!)
git stash push -m "working on user avatar feature"
git stash list
stash@{0}: On main: working on user avatar feature

# Restore a specific stash (don't delete the stash record)
git stash apply stash@{0}

# Restore and delete the stash record
git stash pop stash@{0}

# Delete all stashes
git stash clear

git cherry-pick โ€” Precisely "Transplant" a Commit โ€‹

Sometimes you want to "move" just one specific commit to another branch, rather than merging the entire branch. This is where cherry-pick comes in as a powerful tool.

bash
# Scenario: The feature/experiment branch has an urgent fix, you want to move just that to main

# First find the commit hash
git log --oneline feature/experiment
d4e5f6a feat: experimental feature A
c3d4e5f fix: fixed a critical bug
b2c3d4e feat: experimental feature B
a1b2c3d feat: initialize experiment branch

# Switch to main and cherry-pick that fix
git switch main
git cherry-pick c3d4e5f
[main e5f6a7b] fix: fixed a critical bug
 Date: Thu Jun 20 15:30:00 2025 +0800
 1 file changed, 2 insertions(+), 1 deletion(-)

# You can also cherry-pick multiple commits at once
git cherry-pick a1b2c3d..c3d4e5f

# Cherry-pick without auto-committing (lets you review first)
git cherry-pick --no-commit c3d4e5f

git bisect โ€” Binary Search for Bug Hunting โ€‹

This command is amazing! If you know the code was working 100 commits ago and there's a bug now, bisect uses binary search to quickly pinpoint which commit introduced the bug.

bash
# Start binary search
git bisect start

# Mark the current version as buggy
git bisect bad

# Mark an older version as good
git bisect good a1b2c3d
Bisecting: 50 revisions left to test after this (roughly 6 steps)
[f5a6b7c...] feat: add search feature

# Git automatically checks out the middle commit
# Test this version...
# If it's good:
git bisect good
Bisecting: 25 revisions left to test after this (roughly 5 steps)

# If it's buggy:
git bisect bad
Bisecting: 12 revisions left to test after this (roughly 4 steps)

# After a few rounds, Git will tell you:
a7b8c9d is the first bad commit
commit a7b8c9d
Author: Bob <bob@example.com>
Date:   Thu Jun 20 14:00:00 2025 +0800

    feat: add shopping cart feature

 :040000 040000 abc123 def456 M        cart.js

# Found the "culprit"! End bisect
git bisect reset

git blame โ€” Who Wrote This Line of Code? โ€‹

bash
# View the last modifier of each line in a file
git blame index.html
a1b2c3d4 (Alice  2025-06-20 10:00:00 +0800  1) <!DOCTYPE html>
a1b2c3d4 (Alice  2025-06-20 10:00:00 +0800  2) <html>
a1b2c3d4 (Alice  2025-06-20 10:00:00 +0800  3) <head>
f4e5d6c7 (Alice  2025-06-20 10:30:00 +0800  4)   <title>My First Website</title>
a1b2c3d4 (Alice  2025-06-20 10:00:00 +0800  5) </head>
a1b2c3d4 (Alice  2025-06-20 10:00:00 +0800  6) <body>
d4e5f6a7 (Bob    2025-06-20 11:00:00 +0800  7)   <h1>Welcome to our website!</h1>
f4e5d6c7 (Alice  2025-06-20 10:30:00 +0800  8)   <p>Hello, Git!</p>
a1b2c3d4 (Alice  2025-06-20 10:00:00 +0800  9) </body>
a1b2c3d4 (Alice  2025-06-20 10:00:00 +0800 10) </html>

# View a specific line range
git blame -L 5,8 index.html

git grep โ€” Search Within Code โ€‹

bash
# Search code content (faster than grep because it uses Git's index)
git grep "Hello"
index.html:7:  <h1>Hello, Git!</h1>

# Search and count matches per file
git grep -c "class"
index.html:2
style.css:5

# Search content in a specific commit
git grep "Hello" a1b2c3d

Git Aliases โ€” Nicknames for Commands โ€‹

Some Git commands are too long and tedious to type. Setting up aliases doubles your efficiency:

bash
# Common alias settings
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.last "log -1 HEAD"
git config --global alias.unstage "restore --staged"
git config --global alias.aliases "config --get-regexp alias"

# Using aliases
git st      # = git status
git co main # = git checkout main
git lg      # = nice commit history

Git Hooks โ€” Automation Scripts โ€‹

Git Hooks are scripts that automatically execute when specific events occur. For example, automatically checking code format before each commit, or running tests before each push.

bash
# View available hooks
ls .git/hooks/
applypatch-msg.sample  pre-commit.sample     pre-rebase.sample
commit-msg.sample      pre-merge-commit.sample prepare-commit-msg.sample
fsmonitor-watchman.sample pre-push.sample      update.sample

# Create a pre-commit hook (run checks before committing)
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
# Check for unresolved conflict markers
if git diff --cached --diff-filter=ACM | grep -q '<<<<<<'; then
    echo "Error: Found unresolved conflict markers! Please resolve conflicts first."
    exit 1
fi

# Check for debug statements
if git diff --cached --diff-filter=ACM | grep -qE 'console\.log|debugger|print\('; then
    echo "Warning: Code may contain debug statements."
    echo "If intentional, use git commit --no-verify to skip checks."
    exit 1
fi
EOF

# Make it executable
chmod +x .git/hooks/pre-commit

๐Ÿ“ Note: Scripts in .git/hooks/ won't be committed to the repository. If you want to share hooks with your team, you can use the pre-commit tool, or place hook scripts in the project directory and use symlinks.

Git Submodules โ€” A Repository Within a Repository โ€‹

Sometimes your project depends on another Git repository (like a shared utility library). submodule lets you nest one repository inside another.

bash
# Add a submodule
git submodule add git@github.com:yourname/shared-utils.git libs/utils
Cloning into '/home/yourname/my-first-website/libs/utils'...
remote: Enumerating objects: 42, done.
...
Adding existing repo at 'libs/utils' to the index

# View submodule status
git submodule status
 a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 libs/utils (heads/main)

# Clone a repository with submodules
git clone --recurse-submodules git@github.com:yourname/my-first-website.git

# If you already cloned but forgot --recurse-submodules
git submodule update --init --recursive