Git Topic
Undoing Changes and Fixing Mistakes
What You'll Learn:
-
How to safely undo changes at different stages
-
Fixing commit mistakes without losing work
-
Recovering "lost" commits and changes
Detailed Explanation:
Understanding the Different Levels of Undo
1. Discard Unstaged Changes
# Discard changes in specific file
git checkout -- filename.txt
# Discard all unstaged changes
git checkout -- .
# Using restore (newer command)
git restore filename.txt
git restore .
2. Unstage Files (Keep Changes)
# Unstage specific file
git reset HEAD filename.txt
# Unstage all files
git reset HEAD
# Using restore to unstage
git restore --staged filename.txt
Reset Commands - The Three Modes
Soft Reset (--soft)
# Moves HEAD but keeps changes staged
git reset --soft HEAD~1
# Use case: Recommit with different message or additional changes
Mixed Reset (--mixed) - DEFAULT
# Moves HEAD, unstages changes but keeps in working directory
git reset HEAD~1
git reset --mixed HEAD~1
# Use case: Split a large commit into smaller ones
Hard Reset (--hard)
# COMPLETELY discards changes - USE CAREFULLY!
git reset --hard HEAD~1
git reset --hard commit-hash
# Use case: Completely remove recent commits
Revert vs Reset
Revert (Safe for shared history)
# Creates new commit that undoes changes
git revert commit-hash
git revert HEAD~3..HEAD # Revert range of commits
# Example workflow:
git log --oneline
# a1b2c3d (HEAD -> main) Bad commit
# e4f5g6h Good commit
git revert a1b2c3d # Creates new commit undoing a1b2c3d
Reset (Dangerous for shared history)
# Only for local branches - rewrites history
git reset --hard a1b2c3d
Amending Commits
Fix Last Commit Message
git commit --amend -m "New commit message"
Add Files to Last Commit
git add forgotten-file.txt
git commit --amend --no-edit
Change Last Commit Content
# Make changes to files
git add .
git commit --amend
# Opens editor to modify commit message if desired
Reflog - Your Safety Net
View Reflog
git reflog
git reflog show --all
# Shows all HEAD movements - even "lost" commits
Recovery Examples
# Scenario 1: Accidentally reset hard
git reset --hard HEAD~3 # Oops!
git reflog
# Find the commit hash before reset
git reset --hard a1b2c3d # Restore
# Scenario 2: Deleted branch
git branch -D feature-branch # Oops!
git reflog
# Find last commit on deleted branch
git checkout -b feature-branch a1b2c3d
# Scenario 3: Lost commit after rebase
git reflog
git cherry-pick a1b2c3d # Reapply specific commit
Practical Recovery Workflow
# 1. Check what happened
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: Important feature
# 2. Restore to desired state
git reset --hard e4f5g6h
# 3. Verify recovery
git log --oneline
Merge Conflicts Resolution
What You'll Learn:
-
What causes merge conflicts and how to prevent them
-
Step-by-step conflict resolution
-
Tools and strategies for efficient resolution
Detailed Explanation:
Understanding Conflict Causes
Common Conflict Scenarios:
-
Same file, same lines modified by different branches
-
File deleted in one branch, modified in another
-
Divergent histories after force pushes
Conflict Resolution Process
1. Identify Conflicted Files
# During merge/pull/rebase, Git will stop and show:
# CONFLICT (content): Merge conflict in filename.txt
# Automatic merge failed; fix conflicts and then commit the result.
git status
# Shows: "Unmerged paths: both modified: filename.txt"
2. Understand Conflict Markers
# In conflicted file:
<<<<<<< HEAD
# Your changes (current branch)
print("Hello from main branch")
=======
# Their changes (incoming branch)
print("Hello from feature branch")
>>>>>>> feature-branch
3. Resolve Conflicts Manually
Option 1: Choose One Version
# Delete conflict markers and keep desired code
print("Hello from main branch") # Keep your changes
# OR
print("Hello from feature branch") # Keep their changes
Option 2: Combine Changes
# Create a hybrid solution
print("Hello from main and feature branches")
4. Complete the Resolution
# Mark file as resolved
git add filename.txt
# Complete the operation
git commit # For merge conflicts
git rebase --continue # For rebase conflicts
Resolution Strategies
Abort Operations
# Change your mind? Abort the operation:
git merge --abort
git rebase --abort
git cherry-pick --abort
Using Merge Tools
# Configure and use visual merge tools
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
# Use the tool
git mergetool
Advanced Resolution Techniques
Accept All Incoming/Current Changes
# Accept all their changes
git checkout --theirs -- path/to/file
git add path/to/file
# Accept all our changes
git checkout --ours -- path/to/file
git add path/to/file
Partial File Resolution
# Use patch mode for complex files
git add -p filename.txt
# Interactively choose which hunks to stage
Prevention Strategies
1. Frequent Integration
# Keep feature branches short-lived
git fetch origin
git merge origin/main # Regularly merge main into feature
2. Communication
-
Coordinate with team on file ownership
-
Use pull requests for code review
3. Configuration
# Set up diff3 style for better conflict markers
git config --global merge.conflictstyle diff3
Complete Resolution Example
# Start merge
git merge feature-branch
# CONFLICT occurs
# Identify conflicts
git status
# Edit conflicted files
code conflicted-file.js
# After resolving, mark as resolved
git add conflicted-file.js
# Complete merge
git commit -m "Merge feature-branch, resolve conflicts"
GitHub/GitLab Specific Features
What You'll Learn:
-
Platform-specific collaboration features
-
Managing projects through web interfaces
-
CI/CD integration basics
Detailed Explanation:
Pull/Merge Requests
Creating Effective PRs/MRs:
1. Pre-requisites:
# Local preparation
git checkout -b feature/awesome-feature
# Make changes...
git add .
git commit -m "Implement awesome feature"
git push -u origin feature/awesome-feature
2. PR/MR Best Practices:
-
Title: Clear, descriptive (e.g., "Add user authentication")
-
Description: What, why, how, testing done
-
Linked Issues: Closes #123, Fixes #456
-
Reviewers: Tag relevant team members
3. Template Example:
## Description
What does this PR accomplish?
## Changes
- Change 1
- Change 2
## Testing
- [ ] Unit tests added
- [ ] Manual testing performed
## Screenshots (if UI changes)
Issues and Projects
Effective Issue Management:
Issue Templates:
### Bug Report
**Description**: [What happened]
**Steps to Reproduce**: [Detailed steps]
**Expected Behavior**: [What should happen]
**Actual Behavior**: [What actually happened]
### Feature Request
**Problem**: [What problem this solves]
**Solution**: [Proposed solution]
**Alternatives**: [Other options considered]
Project Boards:
-
Columns: Backlog, In Progress, Review, Done
-
Automation: Auto-move issues based on PRs
-
Milestones: Group related issues for releases
CI/CD Integration
Basic GitHub Actions Workflow (.github/workflows/ci.yml):
name: CI Pipeline
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build project
run: npm run build
GitLab CI (.gitlab-ci.yml):
stages:
- test
- build
- deploy
test:
stage: test
script:
- npm install
- npm test
build:
stage: build
script:
- npm run build
artifacts:
paths:
- dist/
Advanced Platform Features
1. Protected Branches:
-
Require PR reviews
-
Require status checks
-
Prevent force pushes to main
2. Webhooks and Automation:
-
Auto-close issues with PR merges
-
Notifications to Slack/Discord
-
Deployment triggers
3. Code Review Tools:
-
Inline comments
-
Suggested changes
-
Review approvals
Complete Collaboration Workflow
# 1. Create feature branch
git checkout -b feature/new-login
# 2. Develop and commit
git add .
git commit -m "Add new login component"
git push origin feature/new-login
# 3. Create PR/MR on GitHub/GitLab
# - Add description
# - Request reviews
# - Link issues
# 4. Address review feedback
git commit --amend # Incorporate feedback
git push --force-with-lease
# 5. After approval and merge
git checkout main
git pull origin main
git branch -d feature/new-login
Advanced Git Techniques
What You'll Learn:
-
When to use rebase vs merge
-
Advanced history rewriting
-
Managing complex project dependencies
Detailed Explanation:
Rebasing vs Merging
Merge - Preserves History
# Creates merge commit showing branch integration
git checkout main
git merge feature-branch
# Result:
# * Merge branch 'feature-branch'
# |\
# | * Feature commit 2
# | * Feature commit 1
# |/
# * Main commit
Rebase - Linear History
# Replays commits on top of base branch
git checkout feature-branch
git rebase main
# Result:
# * Feature commit 2
# * Feature commit 1
# * Main commit
When to Use Each:
| Scenario | Use Merge | Use Rebase |
|---|---|---|
| Public/shared branches | ✅ | ❌ |
| Feature branches | ✅ | ✅ |
| Cleaning up local history | ❌ | ✅ |
| Team prefers clear merge points | ✅ | ❌ |
Interactive Rebase
Basic Usage:
# Rebase last 3 commits
git rebase -i HEAD~3
# Rebase onto different branch
git rebase -i main
Interactive Rebase Actions:
pick a1b2c3d Add feature A
reword e4f5g6h Fix typo
edit f7g8h9i Add tests
squash j1k2l3m More tests
drop m4n5o6p Debug code
Common Scenarios:
1. Squash Multiple Commits:
git rebase -i HEAD~4
# Change "pick" to "squash" for commits to combine
2. Reorder Commits:
git rebase -i HEAD~5
# Reorder lines to change commit sequence
3. Split Large Commit:
git rebase -i HEAD~2
# Mark commit as "edit"
# During rebase:
git reset HEAD~1
# Stage changes in separate commits
git add -p
git commit -m "Part 1"
git commit -m "Part 2"
git rebase --continue
Submodules and Worktrees
Git Submodules - Nested Repositories
# Add submodule
git submodule add https://github.com/user/repo.git lib/repo
# Clone repository with submodules
git clone --recurse-submodules https://github.com/user/main-repo.git
# Update submodules
git submodule update --init --recursive
# Work in submodule
cd lib/repo
git checkout -b feature
# Make changes...
cd ../..
git add lib/repo
git commit -m "Update submodule"
Git Worktrees - Multiple Working Directories
# Create new worktree for feature branch
git worktree add ../my-project-feature feature-branch
# Work in parallel
cd ../my-project-feature
# Make changes...
git commit -m "Feature work"
# List worktrees
git worktree list
# Remove worktree
git worktree remove ../my-project-feature
Advanced Cherry-picking
Selective Commit Application:
# Cherry-pick specific commit
git cherry-pick a1b2c3d
# Cherry-pick range
git cherry-pick main..feature-branch
# Cherry-pick with conflicts
git cherry-pick --continue
git cherry-pick --abort
# Cherry-pick without committing
git cherry-pick --no-commit a1b2c3d
Bisect for Bug Hunting
Find Introducing Commit:
# Start bisect session
git bisect start
git bisect bad HEAD # Current commit is bad
git bisect good v1.0.0 # This commit was good
# Test current commit, then:
git bisect good # If current commit is good
git bisect bad # If current commit is bad
# Finish bisect
git bisect reset
Git in Team Environments
What You'll Learn:
-
Establishing effective team workflows
-
Code review best practices
-
Release and deployment management
Detailed Explanation:
Code Review Workflows
1. Fork & Pull Request Workflow:
# Contributor workflow:
# 1. Fork on GitHub/GitLab
# 2. Clone fork
git clone https://github.com/yourname/repo.git
# 3. Add upstream
git remote add upstream https://github.com/original/repo.git
# 4. Create feature branch
git checkout -b feature-branch
# 5. Push to fork
git push -u origin feature-branch
# 6. Create PR from fork to upstream
2. Shared Repository Workflow:
# Team member workflow:
# 1. Clone main repo
git clone https://github.com/team/repo.git
# 2. Create feature branch
git checkout -b feature/description
# 3. Push to origin
git push -u origin feature/description
# 4. Create PR within same repo
Code Review Best Practices:
Before Review:
-
Self-review your code
-
Ensure tests pass
-
Update documentation
-
Keep PRs focused and small
During Review:
-
Use inline comments
-
Suggest changes (GitHub)
-
Request specific reviewers
-
Discuss, don't dictate
Review Checklist:
-
Code follows team standards
-
Tests added/updated
-
Documentation updated
-
Security considerations
-
Performance impact assessed
Branch Protection Rules
Essential Protections for Main Branch:
-
Require pull requests
-
Require approvals (1-2 reviewers)
-
Require status checks (CI passing)
-
Prevent force pushes
-
Require linear history
GitHub Example:
# .github/branch-protection.yml
main:
required_status_checks:
strict: true
contexts: [ci/tests, ci/build]
required_pull_request_reviews:
required_approving_review_count: 2
dismiss_stale_reviews: true
enforce_admins: false
restrictions: null
Release Management
Semantic Versioning Strategy:
# Create release branches
git checkout -b release/v1.2.0
# Final testing, bug fixes
git tag v1.2.0
git push origin v1.2.0
# Hotfix workflow
git checkout -b hotfix/v1.2.1 main
# Fix critical issue
git tag v1.2.1
git push origin v1.2.1
Automated Versioning:
# Using semantic-release or similar
npm version patch # 1.2.3 → 1.2.4
npm version minor # 1.2.3 → 1.3.0
npm version major # 1.2.3 → 2.0.0
git push --follow-tags
Team Coordination Strategies
1. Regular Syncs:
# Daily: Fetch latest changes
git fetch --all
# Weekly: Clean up merged branches
git fetch -p # Prune deleted remote branches
git branch --merged main | grep -v "main" | xargs git branch -d
2. Communication Protocols:
-
Use conventional commits
-
Document breaking changes
-
Announce large refactors
-
Coordinate database changes
3. Conflict Prevention:
# Pre-merge checks
git fetch origin
git merge-base --fork-point origin/main feature-branch
# Ensure feature branch isn't too far behind
Large Team Scale Strategies
Monorepo Management:
# Sparse checkout for large repos
git sparse-checkout init
git sparse-checkout set app/frontend
# Partial clones
git clone --filter=blob:none https://github.com/large/repo.git
Team-specific Branches:
# Team feature flags
git checkout -b team/frontend/feature-name
git checkout -b team/backend/feature-name
Git Hooks and Automation
What You'll Learn:
-
Automating workflows with Git hooks
-
Integrating with CI/CD systems
-
Creating custom Git commands
Detailed Explanation:
Pre-commit Hooks
Location and Setup:
# Hooks live in .git/hooks/
# But better: store in project and use a hook manager
# Using Husky (Node.js projects)
npm install husky --save-dev
npx husky init
# Add pre-commit hook
npx husky add .husky/pre-commit "npm test"
Common Pre-commit Validations:
1. Code Quality:
#!/bin/bash
# .husky/pre-commit
# Run linter
npm run lint
# Run tests
npm test
# Check commit message format
commit_msg=$(cat $1)
if ! echo "$commit_msg" | grep -qE "^(feat|fix|docs|style|refactor|test|chore): "; then
echo "Invalid commit message format!"
exit 1
fi
2. Security Checks:
#!/bin/bash
# Check for secrets in code
if git diff --cached --name-only | xargs grep -n "password\|secret\|key"; then
echo "Potential secret found in code!"
exit 1
fi
CI Integration Hooks
Post-receive Hook for Auto-deploy:
#!/bin/bash
# .git/hooks/post-receive
while read oldrev newrev refname
do
branch=$(git rev-parse --symbolic --abbrev-ref $refname)
if [ "main" == "$branch" ]; then
# Deploy to production
git --work-tree=/var/www/html --git-dir=/path/to/repo checkout -f
systemctl reload nginx
fi
done
Pre-push Hook for Validation:
#!/bin/bash
# .husky/pre-push
# Ensure tests pass before push
npm run test:ci
# Check branch naming convention
current_branch=$(git symbolic-ref --short HEAD)
if ! echo "$current_branch" | grep -qE "^(feature|fix|hotfix)/[a-z0-9-]+$"; then
echo "Invalid branch name: $current_branch"
exit 1
fi
Custom Git Commands
Creating Git Aliases:
# Add to ~/.gitconfig or project .git/config
[alias]
# Shortcuts
co = checkout
br = branch
ci = commit
st = status
# Useful custom commands
last = log -1 HEAD
unstage = reset HEAD --
recent = log --oneline -10
graph = log --graph --oneline --all
# Team-specific aliases
cleanup = "!git fetch -p && git branch --merged main | grep -v main | xargs git branch -d"
wip = "!git add -A && git commit -m 'WIP'"
unwip = "!git reset --soft HEAD~1"
Advanced Custom Commands:
1. Branch Cleanup Script:
#!/bin/bash
# Save as git-cleanup-branches
# Delete merged branches except main and develop
git fetch --prune
git branch --merged main | grep -vE "^(main|develop|\*)" | xargs -r git branch -d
git branch --merged develop | grep -vE "^(main|develop|\*)" | xargs -r git branch -d
echo "Cleanup complete!"
2. Smart Commit:
#!/bin/bash
# git-smart-commit
if [ -z "$1" ]; then
echo "Usage: git smart-commit \"message\""
exit 1
fi
# Run tests first
npm test
if [ $? -eq 0 ]; then
git add -A
git commit -m "$1"
echo "Commit successful!"
else
echo "Tests failed! Commit aborted."
exit 1
fi
Hook Management Tools
1. Husky (Node.js):
// package.json
{
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"lint-staged": {
"*.js": "eslint --fix",
"*.{js,css,md}": "prettier --write"
}
}
2. pre-commit (Python):
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
Complete Automation Example
Project Setup with Full Automation:
#!/bin/bash
# setup-project.sh
# Initialize project
npm init -y
npm install husky lint-staged @commitlint/cli @commitlint/config-conventional
# Configure Git hooks
npx husky init
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
npx husky add .husky/pre-commit 'npx lint-staged'
# Create configuration files
cat > .commitlintrc.json << EOF
{
"extends": ["@commitlint/config-conventional"]
}
EOF
cat > .lintstagedrc.json << EOF
{
"*.js": ["eslint --fix", "prettier --write"],
"*.json": ["prettier --write"],
"*.md": ["prettier --write"]
}
EOF
echo "Project automation setup complete!"
This completes the extensive Git tutorial covering from basic to advanced topics. Each subtopic builds upon the previous ones, creating a logical learning path for mastering Git.
Comments (0)
No comments yet. Be the first to comment!