🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Git Workflows

by @gitgoodordietrying

Advanced git operations beyond add/commit/push. Use when rebasing, bisecting bugs, using worktrees for parallel development, recovering with reflog, managing subtrees/submodules, resolving merge conflicts, cherry-picking across branches, or working with monorepos.

Versionv1.0.0
Downloads13,560
Stars⭐ 5
TERMINAL
clawhub install git-workflows

πŸ“– About This Skill


name: git-workflows description: Advanced git operations beyond add/commit/push. Use when rebasing, bisecting bugs, using worktrees for parallel development, recovering with reflog, managing subtrees/submodules, resolving merge conflicts, cherry-picking across branches, or working with monorepos. metadata: {"clawdbot":{"emoji":"🌿","requires":{"bins":["git"]},"os":["linux","darwin","win32"]}}

Git Workflows

Advanced git operations for real-world development. Covers interactive rebase, bisect, worktree, reflog recovery, subtrees, submodules, sparse checkout, conflict resolution, and monorepo patterns.

When to Use

  • Cleaning up commit history before merging (interactive rebase)
  • Finding which commit introduced a bug (bisect)
  • Working on multiple branches simultaneously (worktree)
  • Recovering lost commits or undoing mistakes (reflog)
  • Managing shared code across repos (subtree/submodule)
  • Resolving complex merge conflicts
  • Cherry-picking commits across branches or forks
  • Working with large monorepos (sparse checkout)
  • Interactive Rebase

    Squash, reorder, edit commits

    # Rebase last 5 commits interactively
    git rebase -i HEAD~5

    Rebase onto main (all commits since diverging)

    git rebase -i main

    The editor opens with a pick list:

    pick a1b2c3d Add user model
    pick e4f5g6h Fix typo in user model
    pick i7j8k9l Add user controller
    pick m0n1o2p Add user routes
    pick q3r4s5t Fix import in controller
    

    Commands available:

    pick   = use commit as-is
    reword = use commit but edit the message
    edit   = stop after this commit to amend it
    squash = merge into previous commit (keep both messages)
    fixup  = merge into previous commit (discard this message)
    drop   = remove the commit entirely
    

    Common patterns

    # Squash fix commits into their parent
    

    Change "pick" to "fixup" for the fix commits:

    pick a1b2c3d Add user model fixup e4f5g6h Fix typo in user model pick i7j8k9l Add user controller fixup q3r4s5t Fix import in controller pick m0n1o2p Add user routes

    Reorder commits (just move lines)

    pick i7j8k9l Add user controller pick m0n1o2p Add user routes pick a1b2c3d Add user model

    Split a commit into two

    Mark as "edit", then when it stops:

    git reset HEAD~ git add src/model.ts git commit -m "Add user model" git add src/controller.ts git commit -m "Add user controller" git rebase --continue

    Autosquash (commit messages that auto-arrange)

    # When committing a fix, reference the commit to squash into
    git commit --fixup=a1b2c3d -m "Fix typo"
    

    or

    git commit --squash=a1b2c3d -m "Additional changes"

    Later, rebase with autosquash

    git rebase -i --autosquash main

    fixup/squash commits are automatically placed after their targets

    Abort or continue

    git rebase --abort      # Cancel and restore original state
    git rebase --continue   # Continue after resolving conflicts or editing
    git rebase --skip       # Skip the current commit and continue
    

    Bisect (Find the Bug)

    Binary search through commits

    # Start bisect
    git bisect start

    Mark current commit as bad (has the bug)

    git bisect bad

    Mark a known-good commit (before the bug existed)

    git bisect good v1.2.0

    or: git bisect good abc123

    Git checks out a middle commit. Test it, then:

    git bisect good # if this commit doesn't have the bug git bisect bad # if this commit has the bug

    Repeat until git identifies the exact commit

    "abc123 is the first bad commit"

    Done β€” return to original branch

    git bisect reset

    Automated bisect (with a test script)

    # Fully automatic: git runs the script on each commit
    

    Script must exit 0 for good, 1 for bad

    git bisect start HEAD v1.2.0 git bisect run ./test-for-bug.sh

    Example test script

    cat > /tmp/test-for-bug.sh << 'EOF' #!/bin/bash

    Return 0 if bug is NOT present, 1 if it IS

    npm test -- --grep "login should redirect" 2>/dev/null EOF chmod +x /tmp/test-for-bug.sh git bisect run /tmp/test-for-bug.sh

    Bisect with build failures

    # If a commit doesn't compile, skip it
    git bisect skip

    Skip a range of known-broken commits

    git bisect skip v1.3.0..v1.3.5

    Worktree (Parallel Branches)

    Work on multiple branches simultaneously

    # Add a worktree for a different branch
    git worktree add ../myproject-hotfix hotfix/urgent-fix
    

    Creates a new directory with that branch checked out

    Add a worktree with a new branch

    git worktree add ../myproject-feature -b feature/new-thing

    List worktrees

    git worktree list

    Remove a worktree when done

    git worktree remove ../myproject-hotfix

    Prune stale worktree references

    git worktree prune

    Use cases

    # Review a PR while keeping your current work untouched
    git worktree add ../review-pr-123 origin/pr-123

    Run tests on main while developing on feature branch

    git worktree add ../main-tests main cd ../main-tests && npm test

    Compare behavior between branches side by side

    git worktree add ../compare-old release/v1.0 git worktree add ../compare-new release/v2.0

    Reflog (Recovery)

    See everything git remembers

    # Show reflog (all HEAD movements)
    git reflog
    

    Output:

    abc123 HEAD@{0}: commit: Add feature

    def456 HEAD@{1}: rebase: moving to main

    ghi789 HEAD@{2}: checkout: moving from feature to main

    Show reflog for a specific branch

    git reflog show feature/my-branch

    Show with timestamps

    git reflog --date=relative

    Recover from mistakes

    # Undo a bad rebase (find the commit before rebase in reflog)
    git reflog
    

    Find: "ghi789 HEAD@{5}: checkout: moving from feature to main" (pre-rebase)

    git reset --hard ghi789

    Recover a deleted branch

    git reflog

    Find the last commit on that branch

    git branch recovered-branch abc123

    Recover after reset --hard

    git reflog git reset --hard HEAD@{2} # Go back 2 reflog entries

    Recover a dropped stash

    git fsck --unreachable | grep commit

    or

    git stash list # if it's still there git log --walk-reflogs --all -- stash # find dropped stash commits

    Cherry-Pick

    Copy specific commits to another branch

    # Pick a single commit
    git cherry-pick abc123

    Pick multiple commits

    git cherry-pick abc123 def456 ghi789

    Pick a range (exclusive start, inclusive end)

    git cherry-pick abc123..ghi789

    Pick without committing (stage changes only)

    git cherry-pick --no-commit abc123

    Cherry-pick from another remote/fork

    git remote add upstream https://github.com/other/repo.git git fetch upstream git cherry-pick upstream/main~3 # 3rd commit from upstream's main

    Handle conflicts during cherry-pick

    # If conflicts arise:
    

    1. Resolve conflicts in the files

    2. Stage resolved files

    git add resolved-file.ts

    3. Continue

    git cherry-pick --continue

    Or abort

    git cherry-pick --abort

    Subtree and Submodule

    Subtree (simpler β€” copies code into your repo)

    # Add a subtree
    git subtree add --prefix=lib/shared https://github.com/org/shared-lib.git main --squash

    Pull updates from upstream

    git subtree pull --prefix=lib/shared https://github.com/org/shared-lib.git main --squash

    Push local changes back to upstream

    git subtree push --prefix=lib/shared https://github.com/org/shared-lib.git main

    Split subtree into its own branch (for extraction)

    git subtree split --prefix=lib/shared -b shared-lib-standalone

    Submodule (pointer to another repo at a specific commit)

    # Add a submodule
    git submodule add https://github.com/org/shared-lib.git lib/shared

    Clone a repo with submodules

    git clone --recurse-submodules https://github.com/org/main-repo.git

    Initialize submodules after clone (if forgot --recurse)

    git submodule update --init --recursive

    Update submodules to latest

    git submodule update --remote

    Remove a submodule

    git rm lib/shared rm -rf .git/modules/lib/shared

    Remove entry from .gitmodules if it persists

    When to use which

    Subtree: Simpler, no special commands for cloners, code lives in your repo.
             Use when: shared library, vendor code, infrequent upstream changes.

    Submodule: Pointer to exact commit, smaller repo, clear separation. Use when: large dependency, independent release cycle, many contributors.

    Sparse Checkout (Monorepo)

    Check out only the directories you need

    # Enable sparse checkout
    git sparse-checkout init --cone

    Select directories

    git sparse-checkout set packages/my-app packages/shared-lib

    Add another directory

    git sparse-checkout add packages/another-lib

    List what's checked out

    git sparse-checkout list

    Disable (check out everything again)

    git sparse-checkout disable

    Clone with sparse checkout (large monorepos)

    # Partial clone + sparse checkout (fastest for huge repos)
    git clone --filter=blob:none --sparse https://github.com/org/monorepo.git
    cd monorepo
    git sparse-checkout set packages/my-service

    No-checkout clone (just metadata)

    git clone --no-checkout https://github.com/org/monorepo.git cd monorepo git sparse-checkout set packages/my-service git checkout main

    Conflict Resolution

    Understand the conflict markers

    <<<<<<< HEAD (or "ours")
    Your changes on the current branch
    =======
    Their changes from the incoming branch
    >>>>>>> feature-branch (or "theirs")
    

    Resolution strategies

    # Accept all of ours (current branch wins)
    git checkout --ours path/to/file.ts
    git add path/to/file.ts

    Accept all of theirs (incoming branch wins)

    git checkout --theirs path/to/file.ts git add path/to/file.ts

    Accept ours for ALL files

    git checkout --ours . git add .

    Use a merge tool

    git mergetool

    See the three-way diff (base, ours, theirs)

    git diff --cc path/to/file.ts

    Show common ancestor version

    git show :1:path/to/file.ts # base (common ancestor) git show :2:path/to/file.ts # ours git show :3:path/to/file.ts # theirs

    Rebase conflict workflow

    # During rebase, conflicts appear one commit at a time
    

    1. Fix the conflict in the file

    2. Stage the fix

    git add fixed-file.ts

    3. Continue to next commit

    git rebase --continue

    4. Repeat until done

    If a commit is now empty after resolution

    git rebase --skip

    Rerere (reuse recorded resolutions)

    # Enable rerere globally
    git config --global rerere.enabled true

    Git remembers how you resolved conflicts

    Next time the same conflict appears, it auto-resolves

    See recorded resolutions

    ls .git/rr-cache/

    Forget a bad resolution

    git rerere forget path/to/file.ts

    Stash Patterns

    # Stash with a message
    git stash push -m "WIP: refactoring auth flow"

    Stash specific files

    git stash push -m "partial stash" -- src/auth.ts src/login.ts

    Stash including untracked files

    git stash push -u -m "with untracked"

    List stashes

    git stash list

    Apply most recent stash (keep in stash list)

    git stash apply

    Apply and remove from stash list

    git stash pop

    Apply a specific stash

    git stash apply stash@{2}

    Show what's in a stash

    git stash show -p stash@{0}

    Create a branch from a stash

    git stash branch new-feature stash@{0}

    Drop a specific stash

    git stash drop stash@{1}

    Clear all stashes

    git stash clear

    Blame and Log Archaeology

    # Who changed each line (with date)
    git blame src/auth.ts

    Blame a specific line range

    git blame -L 50,70 src/auth.ts

    Ignore whitespace changes in blame

    git blame -w src/auth.ts

    Find when a line was deleted (search all history)

    git log -S "function oldName" --oneline

    Find when a regex pattern was added/removed

    git log -G "TODO.*hack" --oneline

    Follow a file through renames

    git log --follow --oneline -- src/new-name.ts

    Show the commit that last touched each line, ignoring moves

    git blame -M src/auth.ts

    Show log with file changes

    git log --stat --oneline -20

    Show all commits affecting a specific file

    git log --oneline -- src/auth.ts

    Show diff of a specific commit

    git show abc123

    Tags and Releases

    # Create annotated tag (preferred for releases)
    git tag -a v1.2.0 -m "Release 1.2.0: Added auth module"

    Create lightweight tag

    git tag v1.2.0

    Tag a past commit

    git tag -a v1.1.0 abc123 -m "Retroactive tag for release 1.1.0"

    List tags

    git tag -l git tag -l "v1.*"

    Push tags

    git push origin v1.2.0 # Single tag git push origin --tags # All tags

    Delete a tag

    git tag -d v1.2.0 # Local git push origin --delete v1.2.0 # Remote

    Tips

  • git rebase -i is the single most useful advanced git command. Learn it first.
  • Never rebase commits that have been pushed to a shared branch. Rebase your local/feature work only.
  • git reflog is your safety net. If you lose commits, they're almost always recoverable within 90 days.
  • git bisect run with an automated test is faster than manual binary search and eliminates human error.
  • Worktrees are cheaper than multiple clones β€” they share .git storage.
  • Prefer git subtree over git submodule unless you have a specific reason. Subtrees are simpler for collaborators.
  • Enable rerere globally. It remembers conflict resolutions so you never solve the same conflict twice.
  • git stash push -m "description" is much better than bare git stash. You'll thank yourself when you have 5 stashes.
  • git log -S "string" (pickaxe) is the fastest way to find when a function or variable was added or removed.
  • ⚑ When to Use

    TriggerAction
    - Finding which commit introduced a bug (bisect)
    - Working on multiple branches simultaneously (worktree)
    - Recovering lost commits or undoing mistakes (reflog)
    - Managing shared code across repos (subtree/submodule)
    - Resolving complex merge conflicts
    - Cherry-picking commits across branches or forks
    - Working with large monorepos (sparse checkout)

    πŸ“‹ Tips & Best Practices

  • git rebase -i is the single most useful advanced git command. Learn it first.
  • Never rebase commits that have been pushed to a shared branch. Rebase your local/feature work only.
  • git reflog is your safety net. If you lose commits, they're almost always recoverable within 90 days.
  • git bisect run with an automated test is faster than manual binary search and eliminates human error.
  • Worktrees are cheaper than multiple clones β€” they share .git storage.
  • Prefer git subtree over git submodule unless you have a specific reason. Subtrees are simpler for collaborators.
  • Enable rerere globally. It remembers conflict resolutions so you never solve the same conflict twice.
  • git stash push -m "description" is much better than bare git stash. You'll thank yourself when you have 5 stashes.
  • git log -S "string" (pickaxe) is the fastest way to find when a function or variable was added or removed.