A free, open-source distributed version-control system that tracks changes in any collection of files.
Table of Contents#
- Overview
- Installation
- Configuration
- Essential Commands
- Branching and Merging
- Synchronizing With Remote
- Stashing
- Interactive Rebase
- Cherry-pick
- Reflog
- GPG Commit Signing
- Git Hooks
- .gitignore
- .gitattributes
- Git LFS
- Aliases
- Troubleshooting
- See Also
- Sources
1. Overview#
Git is a distributed version-control system originally authored by Linus Torvalds in 2005 for Linux kernel development. Every Git working directory contains the full history and version-tracking capabilities, independent of network access or a central server. Git tracks content by storing snapshots, not diffs, which makes branching and merging extremely fast.
Key concepts:
| Concept | Description |
|---|---|
| Working tree | The files you see and edit on disk |
| Staging area (index) | A buffer between the working tree and the repository; holds the next commit |
| Repository (.git) | The full history stored in the .git directory |
| Commit | An immutable snapshot of the staging area with metadata (author, date, message, parent) |
| Branch | A movable pointer to a commit |
| HEAD | A pointer to the current branch tip (or a detached commit) |
| Remote | A reference to another copy of the repository (e.g., origin) |
2. Installation#
Linux#
# Debian/Ubuntu
sudo apt install git
# Arch Linux
sudo pacman -S git
# RHEL/Fedora
sudo dnf install gitmacOS#
brew install gitWindows#
winget install gitFor alternative packages and binary installers see https://git-scm.com/downloads.
3. Configuration#
User Identity#
git config --global user.name "Your Name"
git config --global user.email "you@example.com"Credential Storage#
| Helper | Description | Example |
|---|---|---|
store | Saves credentials unencrypted to ~/.git-credentials | git config --local credential.helper store |
cache | Holds credentials in memory for N seconds (default 900) | git config --global credential.helper 'cache --timeout=3600' |
osxkeychain | Uses macOS Keychain | git config --global credential.helper osxkeychain |
manager / manager-core | Cross-platform GUI helper supporting PATs, OAuth | git config --global credential.helper manager-core |
Personal Access Tokens#
Modern Git hosting services deprecate password authentication over HTTPS. Options:
Generate a PAT: GitHub (Settings, Developer settings, Personal access tokens), GitLab (User settings, Access tokens), Bitbucket (Personal settings, App passwords). Grant only required scopes (e.g.,
repo,write:packages).Use the token when cloning/pushing:
git clone https://<token>@github.com/<user>/<repo>.gitOr input the token when prompted by your credential helper.
Store the token with one of the helpers above, or keep it ephemeral with
cache.Alternative: switch to SSH keys (
ssh-keygen -t ed25519) and add the public key in your host profile.
4. Essential Commands#
| Command | Purpose |
|---|---|
git init | Create a repository in the current directory |
git clone <url> | Copy a remote repository locally |
git status | Show unstaged and staged changes |
git add <file> | Stage file for next commit |
git rm <file> | Delete file and stage removal |
git mv <old> <new> | Rename/move file and stage the change |
git commit -m "msg" | Record staged snapshot |
git commit | Open editor for detailed message |
git diff | Show unstaged changes |
git diff --staged | Show staged changes (what will be committed) |
git log | Show commit history |
git log --oneline --graph | Compact history with branch visualization |
git show <commit> | Show a specific commit's diff and metadata |
5. Branching and Merging#
# List branches (* marks current)
git branch
# Create and switch to a new branch
git switch -c <branch>
# Switch to an existing branch
git switch <branch>
# Fast-forward merge
git merge --ff-only <branch>
# Merge with a merge commit (no fast-forward)
git merge --no-ff <branch>
# Rebase current branch on top of another
git rebase <branch>
# Rebase instead of merge on pull
git pull --rebase origin main
# Delete a local branch (safe, refuses if unmerged)
git branch -d <branch>
# Delete a remote branch
git push origin --delete <branch>
# Rename current branch
git branch -m <new-name>Merge Conflict Resolution#
# After a conflict, edit the files, then:
git add <resolved-file>
git merge --continue
# Or abort the merge entirely
git merge --abort6. Synchronizing With Remote#
# Track a newly created branch
git push -u origin <branch>
# Fetch without merging
git fetch --all --prune
# Push all local branches
git push --all origin
# Push tags
git push --tags
# Set upstream for current branch
git branch --set-upstream-to=origin/<branch>
# Show remote URLs
git remote -v
# Add a new remote
git remote add <name> <url>7. Stashing#
Stash saves uncommitted changes (both staged and unstaged) and reverts the working tree to HEAD:
# Stash current changes
git stash
# Stash with a descriptive message
git stash push -m "work in progress on feature X"
# Stash including untracked files
git stash push --include-untracked
# Stash only staged changes
git stash push --staged
# List all stashes
git stash list
# Apply the most recent stash (keep stash in list)
git stash apply
# Apply and remove the most recent stash
git stash pop
# Apply a specific stash by index
git stash apply stash@{2}
# Show what a stash contains
git stash show -p stash@{0}
# Drop a specific stash
git stash drop stash@{1}
# Clear all stashes
git stash clear
# Create a branch from a stash
git stash branch <new-branch> stash@{0}8. Interactive Rebase#
Interactive rebase rewrites history by reordering, editing, squashing, or dropping commits:
# Rebase the last 5 commits interactively
git rebase -i HEAD~5
# Rebase onto a branch interactively
git rebase -i mainThe editor opens with a list of commits. Each line starts with a command:
| Command | Short | Description |
|---|---|---|
pick | p | Keep the commit as-is |
reword | r | Keep the commit but edit its message |
edit | e | Pause at this commit for amending |
squash | s | Meld into the previous commit, combine messages |
fixup | f | Meld into the previous commit, discard this message |
drop | d | Remove the commit entirely |
exec | x | Run a shell command after this commit |
Example workflow for squashing:
# Start interactive rebase for last 3 commits
git rebase -i HEAD~3
# In the editor, change "pick" to "squash" on commits to combine:
# pick abc1234 Add feature
# squash def5678 Fix typo in feature
# squash ghi9012 Another fix
# Save and close, then edit the combined commit messageWarning: never rebase commits that have been pushed to a shared branch. This rewrites history and will cause problems for collaborators.
9. Cherry-pick#
Cherry-pick applies a specific commit from one branch onto the current branch:
# Apply a single commit
git cherry-pick <commit-hash>
# Apply multiple commits
git cherry-pick <hash1> <hash2> <hash3>
# Apply a range of commits (exclusive start, inclusive end)
git cherry-pick <start-hash>..<end-hash>
# Cherry-pick without committing (stage changes only)
git cherry-pick --no-commit <commit-hash>
# Abort a cherry-pick in progress
git cherry-pick --abort
# Continue after resolving conflicts
git cherry-pick --continue10. Reflog#
The reflog records every change to HEAD, including commits, rebases, resets, and checkouts. It is the safety net for recovering "lost" commits:
# Show reflog for HEAD
git reflog
# Show reflog for a specific branch
git reflog show <branch>
# Recover a commit after a bad reset
git reflog
# Find the commit hash, then:
git reset --hard <commit-hash>
# Recover a deleted branch
git reflog
# Find the last commit of the branch, then:
git branch <branch-name> <commit-hash>
# Show reflog with timestamps
git reflog --date=relativeReflog entries expire after 90 days (30 days for unreachable commits) by default. Adjust with:
git config gc.reflogExpire 180.days
git config gc.reflogExpireUnreachable 90.days11. GPG Commit Signing#
Signed commits provide cryptographic proof of authorship:
# List your GPG keys
gpg --list-secret-keys --keyid-format=long
# Configure Git to use your key
git config --global user.signingkey <key-id>
# Sign a single commit
git commit -S -m "signed commit"
# Sign all commits by default
git config --global commit.gpgsign true
# Sign tags
git tag -s v1.0 -m "signed release"
# Verify a commit signature
git verify-commit <commit-hash>
# Verify a tag signature
git verify-tag v1.0
# Show signatures in log
git log --show-signatureFor SSH signing (Git 2.34+):
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub12. Git Hooks#
Hooks are scripts that run automatically at specific points in the Git workflow. They live in .git/hooks/ (local) or can be shared via a configured hooks directory.
Common Hooks#
| Hook | Trigger | Use case |
|---|---|---|
pre-commit | Before commit is created | Linting, formatting, running tests |
prepare-commit-msg | After default message, before editor opens | Auto-populate commit message templates |
commit-msg | After message is entered | Enforce commit message format |
post-commit | After commit completes | Notifications, CI triggers |
pre-push | Before push to remote | Run full test suite, prevent force-push |
pre-rebase | Before rebase starts | Prevent rebasing published branches |
post-merge | After merge completes | Reinstall dependencies, rebuild |
post-checkout | After checkout/switch | Update submodules, regenerate files |
Creating a Hook#
# Create a pre-commit hook that runs a linter
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
echo "Running linter..."
npm run lint
if [ $? -ne 0 ]; then
echo "Lint failed. Commit aborted."
exit 1
fi
EOF
chmod +x .git/hooks/pre-commitSharing Hooks#
# Store hooks in the repository and configure the path
mkdir -p .githooks
# Move hooks into .githooks/
git config core.hooksPath .githooks13. .gitignore#
Create a .gitignore file to exclude generated and ephemeral files:
# Node
node_modules/
dist/
# Python
__pycache__/
*.py[cod]
.venv/
# IDE
.idea/
.vscode/
*.swp
# OS
.DS_Store
Thumbs.db
# Secrets (never commit these)
.env
*.pemUseful patterns:
| Pattern | Meaning |
|---|---|
*.log | Ignore all .log files |
!important.log | Exception: track this specific file |
build/ | Ignore entire directory |
**/temp | Ignore "temp" directory at any depth |
doc/*.txt | Ignore .txt in doc/ only (not subdirectories) |
doc/**/*.txt | Ignore .txt in doc/ and all its subdirectories |
# Check why a file is ignored
git check-ignore -v <file>
# List all ignored files
git status --ignored14. .gitattributes#
.gitattributes controls per-path settings for line endings, diff behavior, merge strategies, and LFS tracking:
# Normalize line endings (LF in repo, native on checkout)
* text=auto
# Force LF for shell scripts
*.sh text eol=lf
# Force CRLF for Windows batch files
*.bat text eol=crlf
# Binary files (no diff, no merge)
*.png binary
*.jpg binary
*.pdf binary
# Custom diff driver for specific files
*.csv diff=csv
# LFS tracking
*.psd filter=lfs diff=lfs merge=lfs -text
# Linguist overrides (for GitHub language stats)
docs/** linguist-documentation
vendor/** linguist-vendoredCommon use cases:
# Apply .gitattributes retroactively to normalize line endings
git add --renormalize .
git commit -m "Normalize line endings"15. Git LFS#
Git LFS (Large File Storage) handles large assets outside the main repository:
# Install LFS (once per machine)
git lfs install
# Track file types
git lfs track "*.psd"
git lfs track "*.zip"
# Verify tracking (shows tracked files)
git lfs ls-files
# Show LFS configuration
cat .gitattributes
# Fetch LFS objects for current branch
git lfs pull
# Migrate existing files to LFS
git lfs migrate import --include="*.psd" --everythingCommit and push as usual; large files upload via the LFS endpoint.
16. Aliases#
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 "reset HEAD --"
git config --global alias.amend "commit --amend --no-edit"Troubleshooting#
| Issue | Cause | Solution |
|---|---|---|
"Permission denied" on git push | Invalid PAT scopes or SSH key not loaded | Verify PAT scopes or run ssh-add; clear credential cache with git credential-cache exit |
| Wrong user in commits | Global config overrides local identity | Set per-repo: git config user.email "correct@email.com", or amend: git commit --amend --author="Name <mail>" |
| Merge conflicts | Divergent changes to the same lines | Edit conflicted files, git add, then git merge --continue |
| "detached HEAD" state | Checked out a tag or specific commit | Create a branch: git switch -c <branch-name> |
| Accidentally committed to wrong branch | Commits on wrong branch | git stash, git switch <correct-branch>, git stash pop or use cherry-pick |
| Need to undo last commit (keep changes) | Premature commit | git reset --soft HEAD~1 (keeps changes staged) |
| Large repo clone is slow | Full history is large | Use git clone --depth 1 for shallow clone, git clone --filter=blob:none for blobless |
.gitignore not working for tracked files | File was tracked before the ignore rule was added | git rm --cached <file>, commit, then the ignore rule applies |
| Reflog is empty | Freshly cloned repo has no local history | Reflog only records local operations; it will populate as you work |
See Also#
Sources#
- Git Documentation
- Pro Git Book
man git,man git-rebase,man git-stash,man gitattributes