Git Advanced Topics — Complete Power User Guide
Once you’ve mastered the basic Git workflow, advanced features like tags, hooks, submodules, and signed commits help you automate workflows, manage large files, collaborate on complex projects, and integrate with CI/CD pipelines.
What You’ll Learn
By the end of this tutorial, you’ll tag releases with semantic versioning, set up Git hooks for automated linting and testing, embed submodules for shared libraries, manage large files with Git LFS, sign commits cryptographically, and configure CI/CD pipelines.
Why Advanced Git Matters
Professional development requires more than commit-push-pull. Tags ensure reproducible releases. Hooks prevent bad code from ever being committed. Submodules let you share libraries across projects. Signed commits prove authenticity — critical for open source and enterprise security. DodaTech uses all of these: signed releases for Durga Antivirus Pro, hooks for Doda Browser builds, and submodules for shared components across products.
Advanced Git Learning Path
flowchart LR
A[Git Basics] --> B[Branching & Merging]
B --> C[Remote Repositories]
C --> D[Undoing Changes]
D --> E[Advanced Git]
style E fill:#3b82f6,stroke:#fff,color:#fff
Advanced Topics Overview
flowchart TD
A[Git Advanced] --> B[Tagging<br/>Releases & versions]
A --> C[Hooks<br/>Run scripts on events]
A --> D[Submodules<br/>Nested repos]
A --> E[LFS<br/>Large files]
A --> F[Signing<br/>Verify identity]
A --> G[CI/CD<br/>Automated pipelines]
Tagging — Marking Releases
Tags label specific commits as important — typically for releases. Think of them like sticky notes on a timeline: “v1.0.0 — shipped to production here.”
# Lightweight tag (just a pointer — no metadata)
git tag v1.0.0
# Annotated tag (recommended — includes message, author, date)
git tag -a v1.0.0 -m "Release version 1.0.0"
# Tag a specific commit (not just HEAD)
git tag -a v0.9.0 a1b2c3d -m "Beta release"
# List tags
git tag
git tag -l "v1.*" # filter by pattern
# View tag details
git show v1.0.0
# Push tags to remote
git push origin v1.0.0 # single tag
git push --tags # all tags
# Delete tags
git tag -d v1.0.0 # local
git push origin --delete v1.0.0 # remote
# Checkout a tag (detached HEAD)
git checkout v1.0.0
# Create a branch from a tag
git checkout -b release-v1 v1.0.0Why annotated tags? Lightweight tags are just pointers — like a bookmark with no label. Annotated tags store the tagger name, date, message, and can be GPG-signed. For releases, always use annotated tags.
Semantic Versioning
v1.2.3
| | └── Patch (bug fixes, backward compatible)
| └──── Minor (new features, backward compatible)
└────── Major (breaking changes)Analogy: Think of version numbers like hotel room numbers: v1 is the floor (major), v2 is the room (minor), v3 is the bed (patch). Breaking changes = moving to a new floor.
Git Hooks — Automation Triggers
Hooks are scripts that run automatically on Git events. They live in .git/hooks/:
ls .git/hooks/
# applypatch-msg.sample pre-applypatch.sample pre-commit.sample
# commit-msg.sample pre-push.sample prepare-commit-msg.sampleCommon Hooks
| Hook | When it runs | Use case |
|---|---|---|
pre-commit | Before commit message | Lint code, run tests |
prepare-commit-msg | Before commit editor opens | Auto-fill message |
commit-msg | After message is written | Validate message format |
pre-push | Before pushing | Run full test suite |
post-merge | After merge | Install dependencies |
Example: Pre-commit Hook
#!/bin/sh
# .git/hooks/pre-commit — make executable with chmod +x
# Prevent committing to main or develop
branch=$(git rev-parse --abbrev-ref HEAD)
if [ "$branch" = "main" ] || [ "$branch" = "develop" ]; then
echo "Direct commits to $branch are not allowed"
exit 1
fi
# Check for debug statements
if git diff --cached | grep -q "debugger\|console.log"; then
echo "Remove debug statements before committing"
exit 1
fiLine-by-line explanation:
#!/bin/sh— tells the system to run this as a shell scriptgit rev-parse --abbrev-ref HEAD— gets the current branch namegit diff --cached— checks the staged changes (what’s about to be committed)exit 1— aborts the commit with an error
.git/hooks/ are not tracked by Git. To share hooks with your team, store them in a .githooks/ directory and run git config core.hooksPath .githooks.Git Submodules — Repos Within Repos
Submodules embed one Git repo inside another at a specific commit:
# Add a submodule
git submodule add https://github.com/user/shared-lib.git libs/shared
# Clone a repo WITH its submodules
git clone --recurse-submodules https://github.com/user/project.git
# Or after cloning without --recurse-submodules:
git submodule init
git submodule update
# Update all submodules to latest
git submodule update --remoteAnalogy: Submodules are like a bookshelf in your house. The shelf holds separate books (repos). Your house repo knows which books are on the shelf and which editions, but the books have their own authors and history.
Typical Submodule Workflow
# When pulling changes that include a submodule update:
git pull
git submodule update --init --recursive
# When you update a submodule:
cd libs/shared
git checkout main
git pull
cd ../..
git add libs/shared
git commit -m "Update shared-lib to latest"Git LFS — Large File Storage
Git stores every version of every file. Binary files (images, videos, ZIPs) bloat the repository quickly. LFS replaces them with text pointers:
# Install LFS
git lfs install
# Track file types
git lfs track "*.psd"
git lfs track "*.mp4"
git lfs track "*.zip"
# The configuration is stored in .gitattributes
cat .gitattributes
# *.psd filter=lfs diff=lfs merge=lfs -text
# Add and commit as normal
git add .gitattributes
git add large-file.psd
git commit -m "Add large file with LFS"
# List tracked patterns
git lfs track
# Pull LFS files
git lfs pullWhat happens behind the scenes: Your repo stores a small pointer file (like “file.psd is actually at URL X”). The real binary goes to LFS storage on GitHub. When you clone, you get pointers instantly; the actual files download on demand.
Signing Commits & Tags
Cryptographically sign your commits to prove they came from you:
# Generate GPG key
gpg --full-generate-key
# List keys
gpg --list-secret-keys --keyid-format LONG
# Configure Git to use it
git config --global user.signingkey KEY_ID
git config --global commit.gpgSign true # sign all commits
# Sign a specific commit
git commit -S -m "Signed commit"
# Sign a tag
git tag -s v1.0.0 -m "Signed release"
# Verify
git verify-commit HEAD
git verify-tag v1.0.0
# Add public key to GitHub
gpg --armor --export KEY_IDWhy sign commits? Anyone can commit with your name and email. A GPG signature cryptographically proves the commit came from you. Open source projects like Linux kernel require signed commits.
Git Configuration & Aliases
Create shortcuts for common commands:
# Useful aliases
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.ci "commit"
git config --global alias.co "checkout"
git config --global alias.br "branch"
git config --global alias.st "status -sb"
git config --global alias.unstage "reset HEAD --"
git config --global alias.last "log -1 HEAD"
# Usage
git lg # pretty log graph
git unstage file # unstage a file
git last # show last commitUseful Config Options
# Case-insensitive filenames
git config --global core.ignorecase true
# Auto-convert line endings
git config --global core.autocrlf input # Linux/macOS
git config --global core.autocrlf true # Windows
# Colored output
git config --global color.ui auto
# Rebase when pulling (instead of merge)
git config --global pull.rebase trueCI/CD with Git
Continuous Integration / Continuous Deployment automates testing and deployment:
# .github/workflows/ci.yml — GitHub Actions example
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm test
- run: npm run buildHow it works: Every time you push, GitHub Actions checks out your repo, sets up Node.js, installs dependencies, and runs tests. If tests fail, the PR is blocked.
Git Bundle — Offline Transfer
Bundle your repo as a single file for air-gapped environments:
# Create a bundle
git bundle create repo.bundle --all
# Restore from bundle
git clone repo.bundle my-repo
# Create incremental bundle (last 5 commits)
git bundle create incremental.bundle HEAD~5..HEADCommon Mistakes
1. Committing large files without LFS
Binary files like images and videos bloat the repository forever. Even if deleted later, they remain in history. Use git lfs track before adding them.
2. Not sharing hooks with the team
Hooks in .git/hooks/ are local and not committed. Store hooks in a version-controlled .githooks/ directory and configure core.hooksPath for team-wide enforcement.
3. Forgetting --recurse-submodules when cloning
Without this flag, submodule directories are empty. Run git submodule update --init --recursive after cloning to populate them.
4. Tagging without pushing
Tags are local until explicitly pushed. git push does not push tags by default. Use git push --tags or git push origin v1.0.0.
5. Overriding hooks with --no-verify
git commit --no-verify skips pre-commit hooks. While useful for emergencies, habitual use defeats the purpose.
6. Using git config --global when project config is needed
--global applies to all repos. Use project-level config (without --global) for settings that should differ per project — like user.email for work vs personal.
Practice Questions
1. What is the difference between lightweight and annotated tags?
Answer: Lightweight tags are just pointers to a commit — no metadata. Annotated tags store the tagger name, date, message, and can be GPG-signed. Always use annotated tags for releases.
2. How do you share Git hooks with your team?
Answer: Store hooks in a .githooks/ directory (tracked by Git) and run git config core.hooksPath .githooks so team members automatically get the hooks.
3. What is Git LFS and when should you use it?
Answer: Large File Storage replaces binary files with text pointers. Use it for files > 1MB that change often: images, audio, video, design assets.
4. Why should you sign your commits?
Answer: Signing cryptographically proves the commit came from you, preventing impersonation. It’s required by many open source projects and enterprise security policies.
Challenge
Set up a pre-commit hook that checks for TODO comments and prevents committing them. Share the hook with your team via a .githooks directory.
FAQ
Try It Yourself
# 1. Create a hooks directory
mkdir .githooks
# 2. Create a pre-commit hook
cat > .githooks/pre-commit << 'EOF'
#!/bin/sh
echo "Running pre-commit checks..."
# Check for merge markers
if git diff --cached | grep -E "^\+<<<<<<<|^\+=======|^\+>>>>>>>"; then
echo "Merge conflict markers found!"
exit 1
fi
echo "Checks passed"
EOF
chmod +x .githooks/pre-commit
# 3. Configure Git to use it
git config core.hooksPath .githooks
git add .githooks/pre-commit
git commit -m "Add pre-commit hook for merge conflict detection"
# 4. Set up useful aliases
git config alias.lg "log --oneline --graph --all --decorate"
git config alias.unstage "reset HEAD --"
# 5. Create an annotated tag
git tag -a v0.1.0 -m "First development release"
git log --onelineWhat’s Next
Keep this reference handy:
| Topic | Description |
|---|---|
| https://tutorials.dodatech.com/devops/git/git-reference/ | Complete Git command cheatsheet |
| https://tutorials.dodatech.com/devops/cloud/aws/reference/ | AWS services reference |
Related topics to explore:
What’s Next
Congratulations on completing this Git Advanced tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro