Advanced Git Concepts: Mastering Rebase, Hooks, Workflows, and Submodules

Git Rebasing: Reorganizing History

Imagine you're writing a story in a notebook, and you realize that Chapter 3 should actually come before Chapter 2. In a regular notebook, this would mean messy cutting and pasting. Git rebase is like having a magical notebook where you can effortlessly reorganize your chapters while keeping everything coherent.

Understanding Rebase

# Create a feature branch
git checkout -b feature_user_profile

# Make some changes and commits
echo "function getUserProfile() {}" > profile.js
git add profile.js
git commit -m "Add user profile function"

# Meanwhile, main branch has been updated
git checkout main
git pull

# Instead of merging, we can rebase
git checkout feature_user_profile
git rebase main

When you rebase, Git essentially:

1. Takes your changes off the branch temporarily (like lifting your chapters out of the book)

2. Applies all the updates from main (like adding new pages to your book)

3. Puts your changes back on top (like inserting your chapters in the right place)

Interactive Rebasing

# Rewrite the last 3 commits
git rebase -i HEAD~3

Interactive rebasing is like having an editor who helps you polish your story. You can:

- Combine multiple commits (squash)

- Reword commit messages

- Delete commits

- Reorder commits

Git Hooks: Your Automated Assistant

Think of Git hooks as helpful robots that automatically perform tasks when certain events occur. Like a smart home system that turns on the lights when you open the door, Git hooks can run scripts when you commit, push, or perform other Git actions.

Common Hook Types

# Create a pre-commit hook
cd .git/hooks
touch pre-commit
chmod +x pre-commit

# Add content to pre-commit hook
#!/bin/sh
# Run tests before allowing commit
npm test

# If tests fail, prevent commit
if [ $? -ne 0 ]; then
    echo "Tests failed, cannot commit!"
    exit 1
fi

Practical Hook Examples

Pre-commit hooks can:

- Run code linting

- Check for sensitive data

- Enforce commit message format

- Run unit tests

# Example commit-msg hook to enforce conventional commits
#!/bin/sh
commit_msg=$(cat "$1")
pattern="^(feat|fix|docs|style|refactor|test|chore)(\([a-z]+\))?: .{1,50}$"

if ! echo "$commit_msg" | grep -iqE "$pattern"; then
    echo "Error: Commit message must follow conventional commits format"
    exit 1
fi

Git Workflows: Orchestrating Team Collaboration

Git workflows are like traffic systems for code. Just as cities have different traffic patterns (one-way streets, roundabouts, highways), teams can adopt different Git workflows to manage their code efficiently.

Gitflow Workflow

Think of Gitflow like a publishing system:

- main branch is like your published book

- develop branch is your working manuscript

- feature branches are like draft chapters

- release branches are like proof copies

- hotfix branches are like emergency errata

# Initialize Gitflow
git flow init

# Start a new feature
git flow feature start user_authentication

# Work on the feature
echo "function login() {}" > auth.js
git add auth.js
git commit -m "Add login function"

# Finish the feature
git flow feature finish user_authentication

Trunk-Based Development

Trunk-based development is like a newspaper office where everyone works on the next day's edition together:

# Create short-lived feature branch
git checkout -b quick-fix-header
# Make changes
git commit -am "Fix header alignment"
# Integrate quickly
git checkout main
git pull
git merge quick-fix-header
git push

Git Submodules: Managing Project Dependencies

Think of submodules like books that reference other books. Just as a textbook might include chapters from other sources, your project might need to include other Git repositories.

Adding and Managing Submodules

# Add a submodule
git submodule add https://github.com/example/lib.git libs/example

# Initialize submodules after cloning
git submodule init
git submodule update

# Update all submodules to their latest versions
git submodule update --remote

Practical Submodule Example

Let's create a project that uses a shared component library:

# Create main project
mkdir my_project
cd my_project
git init

# Add shared component library as submodule
git submodule add https://github.com/company/components.git src/components

# Create main application file
echo "import { Button } from './components/Button';" > src/app.js
git add .
git commit -m "Initialize project with component library"

Real-World Integration Example

Let's put all these concepts together in a practical scenario. Imagine you're building a web application with a team:

# Set up project with Gitflow and submodules
git flow init

# Add shared UI library as submodule
git submodule add https://github.com/company/ui-lib.git lib/ui

# Create pre-commit hook for linting
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
npm run lint
if [ $? -ne 0 ]; then
    echo "Linting failed!"
    exit 1
fi
EOF
chmod +x .git/hooks/pre-commit

# Start new feature
git flow feature start user_dashboard

# Work on feature
echo "import { Dashboard } from '../lib/ui/Dashboard';" > src/pages/dashboard.js
git add src/pages/dashboard.js
git commit -m "feat(dashboard): implement user dashboard"

# Update UI library
git submodule update --remote lib/ui
git add lib/ui
git commit -m "chore: update UI library"

# Finish feature and rebase if needed
git checkout develop
git pull
git checkout feature/user_dashboard
git rebase develop
git flow feature finish user_dashboard

Troubleshooting and Best Practices

Common Rebase Issues

When rebasing goes wrong, remember:

# Save your current state
git branch backup-branch

# Abort rebase
git rebase --abort

# Start over
git rebase main

Hook Management Tips

Store hooks in your repository:

# Create hooks directory in project
mkdir .hooks

# Configure Git to use custom hooks directory
git config core.hooksPath .hooks

# Share hooks with team
git add .hooks
git commit -m "chore: add shared Git hooks"

Submodule Maintenance

# Remove a submodule
git submodule deinit vendor/unwanted-module
git rm vendor/unwanted-module
git commit -m "remove unwanted module"