| name | git |
| description | Use when working with Git version control — branching strategies, common workflows, conflict resolution, history manipulation, hooks, and configuration. Covers everyday commands through advanced operations like rebase, cherry-pick, bisect, and worktrees.
USE FOR: git, version control, branching, merging, rebasing, git hooks, git workflows, Gitflow, trunk-based development, cherry-pick, bisect, stash, worktrees, git configuration, .gitignore, git aliases
DO NOT USE FOR: GitHub/GitLab platform features (use platform-specific skills), CI/CD pipeline configuration, Git LFS administration
|
| license | MIT |
| metadata | {"displayName":"Git","author":"Tyler-R-Kendrick"} |
| compatibility | claude, copilot, cursor |
| references | [{"title":"Git Documentation","url":"https://git-scm.com/doc"},{"title":"Pro Git Book (Official)","url":"https://git-scm.com/book/en/v2"},{"title":"Git GitHub Repository","url":"https://github.com/git/git"}] |
Git
Overview
Git is the universal version control system. Mastering it means understanding not just the commands but the model -- commits are snapshots (not diffs), branches are lightweight pointers to commits, and the staging area (index) separates what you have changed from what you intend to commit. Every operation in Git manipulates this underlying graph of commits, and once you internalize that model, even advanced operations become intuitive.
Configuration
Set up Git globally after installation. These settings live in ~/.gitconfig:
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global core.autocrlf input
git config --global core.autocrlf true
git config --global init.defaultBranch main
git config --global pull.rebase true
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.unstage "reset HEAD --"
Verify your configuration:
git config --list --show-origin
Everyday Commands
Starting a Repository
git init my-project
cd my-project
git clone https://github.com/user/repo.git
git clone git@github.com:user/repo.git
git clone --depth 1 https://github.com/user/repo.git
Working with Changes
git status
git status -s
git diff
git diff --staged
git diff HEAD
git add file.txt
git add src/
git add -p
git commit -m "feat: add user authentication"
git commit -am "fix: correct null check"
git restore file.txt
git restore --staged file.txt
git stash
git stash push -m "WIP: auth feature"
git stash list
git stash pop
git stash apply stash@{2}
git stash drop stash@{0}
git stash clear
Branching
git branch
git branch -r
git branch -a
git branch feature/auth
git switch feature/auth
git switch -c feature/auth
git checkout -b feature/auth
git branch -d feature/auth
git branch -D feature/auth
git switch main
git merge feature/auth
git merge --no-ff feature/auth
git switch feature/auth
git rebase main
Working with Remotes
git remote -v
git fetch origin
git fetch --all
git pull
git pull --rebase
git push origin main
git push -u origin feature/auth
git push --force-with-lease
git remote add upstream https://github.com/original/repo.git
Inspecting History
git log
git log --oneline
git log --oneline --graph --all
git log --since="2 weeks ago"
git log --author="Alice"
git log -- path/to/file.txt
git show abc1234
git blame src/app.py
git blame -L 10,20 src/app.py
git diff main..feature/auth
git diff main...feature/auth
Branching Strategies
| Strategy | Description | Best For |
|---|
| Trunk-Based Development | Short-lived feature branches (hours to a few days), merge to main frequently. Often paired with feature flags. | Teams practicing CI/CD, high-velocity delivery |
| Gitflow | Long-lived develop branch plus feature/*, release/*, and hotfix/* branches. Structured and formal. | Teams with scheduled releases, enterprise projects |
| GitHub Flow | Feature branches off main, open a PR, code review, merge. Simple and effective. | Small to mid-size teams, continuous deployment |
| GitLab Flow | Environment branches (main -> staging -> production). Merges promote code through environments. | Teams needing environment tracking and approvals |
Modern default: Trunk-based development is the recommended approach for most teams today. It reduces merge conflicts, encourages small incremental changes, and aligns with continuous integration and delivery practices.
Merge vs Rebase
| Aspect | Merge | Rebase |
|---|
| History | Preserves branch topology with a merge commit | Linear, clean history — as if work happened sequentially |
| Safety | Safe for shared branches | Dangerous on shared branches — rewrites commit hashes |
| Conflict resolution | Resolve once at merge time | Potentially resolve at each replayed commit |
| When to use | Merging feature branches into main (public) | Cleaning up local feature branch before merging |
| Command | git merge feature | git rebase main (from feature branch) |
Golden Rule: Never rebase commits that have been pushed to a shared branch. Rebasing rewrites commit history, and if others have based work on the original commits, you will create divergent histories and cause significant confusion. Rebase is for local cleanup only.
git switch feature/auth
git fetch origin
git rebase origin/main
git switch main
git merge feature/auth
Advanced Operations
Cherry-Pick
Apply specific commits from one branch to another without merging the entire branch:
git cherry-pick abc1234
git cherry-pick abc1234 def5678
git cherry-pick abc1234 --no-commit
Bisect
Binary search to find the commit that introduced a bug:
git bisect start
git bisect bad
git bisect good v1.0.0
git bisect good
git bisect bad
git bisect reset
Automate bisect with a test script:
git bisect start HEAD v1.0.0
git bisect run ./test-script.sh
Worktrees
Work on multiple branches simultaneously without stashing or switching:
git worktree add ../hotfix-branch hotfix/urgent-fix
git worktree list
git worktree remove ../hotfix-branch
Reflog
The reflog records every change to HEAD. It is your safety net for recovering "lost" commits:
git reflog
git reflog
git reset --hard abc1234
git reflog
git branch recovered-branch abc1234
The reflog keeps entries for approximately 90 days by default. If you made a mistake, you almost certainly can recover from it.
Interactive Rebase (Local Only)
Squash, reorder, edit, or drop commits before pushing:
git rebase -i HEAD~4
In the editor, change pick to:
squash (or s) — combine with previous commit
reword (or r) — change commit message
edit (or e) — pause to amend the commit
drop (or d) — remove the commit entirely
Only use interactive rebase on commits that have not been pushed to a shared branch.
Conflict Resolution
When Git cannot automatically merge changes, it marks conflicts in the affected files:
Step-by-Step
-
Identify conflicted files:
git status
-
Open the file and understand the conflict markers:
<<<<<<< HEAD
// Your changes on the current branch
const timeout = 5000;
=======
// Their changes from the incoming branch
const timeout = 10000;
>>>>>>> feature/update-timeout
-
Decide which changes to keep (yours, theirs, or a combination). Edit the file to the correct final state and remove all conflict markers (<<<<<<<, =======, >>>>>>>).
-
Stage the resolved file and continue:
git add src/config.js
git commit
git rebase --continue
Merge tools can simplify visual conflict resolution:
git mergetool
git config --global merge.tool vscode
Git Hooks
Git hooks are scripts that run automatically at specific points in the Git workflow. They live in .git/hooks/.
| Hook | Trigger | Common Use |
|---|
pre-commit | Before a commit is created | Linting, formatting, running quick tests |
commit-msg | After commit message is written | Validate conventional commit format |
pre-push | Before push to remote | Run full test suite, check for secrets |
prepare-commit-msg | Before editor opens for message | Insert template, branch name, or ticket number |
post-merge | After a merge completes | Install dependencies, rebuild |
pre-rebase | Before rebase starts | Warn if rebasing published branch |
Example: pre-commit Hook
#!/bin/sh
npm run lint
if [ $? -ne 0 ]; then
echo "Linting failed. Fix errors before committing."
exit 1
fi
if grep -rn "console.log\|debugger\|binding.pry" --include="*.js" --include="*.ts" --include="*.rb" src/; then
echo "Debug statements found. Remove them before committing."
exit 1
fi
Husky is the standard tool for managing Git hooks in Node.js projects. It lets you define hooks in package.json or .husky/ and ensures all team members run the same hooks.
.gitignore
The .gitignore file tells Git which files and directories to exclude from tracking.
Pattern Syntax
# Comments start with #
*.log # Ignore all .log files
!important.log # But DO track this specific one
/build/ # Ignore build directory at repo root only
**/temp/ # Ignore temp directory at any depth
doc/**/*.pdf # Ignore PDFs inside doc/ recursively
Common Entries by Platform
# Dependencies
node_modules/
vendor/
.venv/
__pycache__/
# Build output
dist/
build/
bin/
obj/
*.dll
*.exe
*.o
# Environment and secrets
.env
.env.local
*.pem
credentials.json
# OS files
.DS_Store
Thumbs.db
Desktop.ini
# IDE files
.vscode/settings.json
.idea/
*.suo
*.user
*.swp
*~
Global Gitignore
Set a global ignore file for files that should never be tracked on any repo on your machine:
git config --global core.excludesFile ~/.gitignore_global
Add OS-specific junk (.DS_Store, Thumbs.db) and editor temp files to the global file.
Conventional Commits
A lightweight convention for writing structured commit messages that can be parsed by tooling:
Format
type(scope): description
[optional body]
[optional footer(s)]
Types
| Type | Purpose |
|---|
feat | A new feature |
fix | A bug fix |
docs | Documentation only changes |
style | Formatting, white-space, semicolons (no logic change) |
refactor | Code change that neither fixes a bug nor adds a feature |
perf | Performance improvement |
test | Adding or correcting tests |
build | Changes to build system or external dependencies |
ci | Changes to CI configuration files and scripts |
chore | Maintenance tasks, dependency bumps, tooling |
Examples
feat(auth): add OAuth2 login with Google provider
fix(api): handle null response from payment gateway
docs(readme): add setup instructions for local development
refactor(db): extract connection pooling into separate module
test(auth): add integration tests for token refresh flow
build(deps): bump lodash from 4.17.20 to 4.17.21
ci(github): add CodeQL security scanning workflow
chore: update .gitignore for Python virtual environments
Adding ! after the type (e.g., feat!: ...) or including BREAKING CHANGE: in the footer signals a breaking change, which tools like semantic-release use to trigger major version bumps.
Best Practices
- Commit early and often. Small, focused commits are easier to review, revert, and bisect than large monolithic ones. Each commit should represent a single logical change.
- Write meaningful commit messages. The subject line should explain what changed and why in imperative mood ("Add auth module", not "Added auth module" or "Adding auth module"). Use the body for context when needed.
- Never force push to shared branches. Force pushing rewrites history and can destroy teammates' work. Use
--force-with-lease if you must, and only on your own feature branches.
- Use .gitignore from day one. Add it as the first file in any new repository. Include dependencies, build output, secrets, and OS artifacts. Use templates from gitignore.io or GitHub's collection.
- Learn reflog for recovery. Reflog is your undo history. Before panicking about a bad rebase or reset, check
git reflog — the original commits are almost certainly still there.
- Rebase local branches before merging. Rebase your feature branch onto the latest
main before creating a merge or pull request. This results in a clean, linear history and avoids unnecessary merge commits.
- Sign commits in sensitive repositories. Use GPG or SSH signing (
git config --global commit.gpgsign true) for repositories where commit authorship integrity matters.
- Review diffs before committing. Always run
git diff --staged before committing to verify you are committing exactly what you intend. Catching stray debug statements or unrelated changes at this stage saves time.