My Dev's Guide to Git: From Basics to Pro Workflows
Written on: June, 2025
•13 min readGit isn't just version control. It's the backbone of how modern development teams think, collaborate, and ship code. For the first two years of my career, I treated it like a glorified backup system: commit, push, pray nothing breaks. Then I joined a team where Git wasn't just a tool, it was their entire development philosophy. That's when everything clicked. Git shapes how you structure features, how you communicate with teammates, and how you deploy to production. It's the difference between chaos and orchestrated teamwork, between "works on my machine" and bulletproof releases. In this guide, I'll walk you through the journey I wish I'd taken from day one. We'll start with the fundamentals that every developer needs, then build up to the advanced workflows that separate junior developers from senior ones. You'll learn not just the commands, but the thinking behind them, when to rebase versus merge, how to craft commits that tell a story, and how to structure branches that make your team's life easier. Whether you're just getting started or looking to level up your Git game, this is the comprehensive guide I wish someone had given me when I first typed git init. Let's dive into the world of Git.
Steps
- The Git Essentials: Creating the repository
- Your First Real Commands: Building a Feature
- Creating Your Feature Branch
- Staging and Committing Changes
- Pushing Your Changes
- Collaborating with Your Team
- Handling Merge Conflicts
- Power Tools for Developers
- Cleaning Up Your Commits
- Advanced Power Tools: Cherry-Pick and Bisect
- Setting Up Git Hooks with Husky
- Securing Your Commits with GPG
- Integrating with CI/CD
- Automating Code Reviews
A repository is a directory that contains a project and its history. It uses Git to track changes to the project. You can create a repository by running the following command in your terminal or by using github app.
1git init
Let's walk through a real scenario from your first week on the job. You've been assigned to build a login feature, and you'll need to download the project to your machine. The first step is cloning the repository, which downloads the entire project history to your local system. Once you have the project locally, you can start working on your assigned feature.
1git clone https://github.com/your-company/project.git
1cd project
Before diving into the code, you'll want to create a new branch for your feature. This is a crucial practice that keeps your changes isolated from the main codebase and makes it easy to switch between different tasks. Think of branches as parallel universes where you can experiment freely without affecting the main timeline of your project.
1git checkout -b feature/login-page
As you build the login feature, you'll want to save your progress in logical chunks. Think of commits as checkpoints in a video game. Before creating a checkpoint, you'll want to check which files you've modified using git status. This shows you everything that's changed since your last commit. Then you can stage specific files that are ready to be committed. When creating a commit, think of it as documenting a clear, specific change to the project. Your commit message should tell other developers exactly what this change accomplishes.
1git status
2git add src/components/LoginForm.tsx
3git commit -m "feat(auth): implement login form with validation"
Once you've made progress on your feature and committed your changes locally, it's time to share your work with the team. Pushing your feature branch uploads your commits to the remote repository where other team members can see them. After pushing, you'll typically create a Pull Request, which signals to your team that your code is ready for review. This is where the collaboration really begins.
1git push origin feature/login-page
Now comes an important part of team development: keeping your code in sync with others. Before starting new work each day, you'll want to make sure you have the latest changes from the main branch. This helps prevent conflicts and keeps you aligned with the team's progress. The process involves switching to the main branch, pulling the latest changes, and then merging those updates into your feature branch.
1git checkout main
2git pull origin main
3git checkout feature/login-page
4git merge main
Sooner or later, you'll encounter a merge conflict. This happens when you and another developer have changed the same part of a file. While it might seem scary at first, resolving conflicts is a normal part of collaboration. When a conflict occurs, Git will mark the file with special markers showing both versions of the code. Your job is to decide which changes to keep, or how to combine them. After editing the file to resolve the conflict, you'll stage it and create a new commit to complete the merge.
1# After fixing conflicts in the files
2git add .
3git commit -m "fix: resolve merge conflicts in login form"
As you grow more comfortable with Git, you'll discover powerful commands that can help you work more efficiently. One such tool is git stash, which lets you temporarily save your work-in-progress changes when you need to switch tasks quickly. Think of it as a clipboard for your code changes, letting you paste them back when you're ready to continue working.
1git stash save "login form validation WIP"
2git stash list
3git stash pop
Before submitting your work for review, you might want to clean up your commit history. Git provides powerful tools for this. Interactive rebase lets you modify your commit history, combining multiple small commits into more logical units, or rewording commit messages to be more clear. This is like editing a document before publication – you want your changes to tell a clear, coherent story.
1git rebase -i HEAD~3 # Rebase last 3 commits
2git reset --soft HEAD~3 && git commit -m "feat(auth): complete login feature"
Sometimes you need surgical precision in Git, and that's where cherry-pick comes in. Imagine you're working on a feature when your team lead messages you about an urgent authentication fix you made last week that needs to go to production immediately. Instead of merging your entire branch, you can pluck just that one commit and apply it where needed. Another powerful tool is git bisect, which becomes invaluable when tracking down bugs. Picture this: your team discovers a bug in production, but no one knows when it was introduced. Instead of checking every commit manually, git bisect performs a binary search through your history, helping you pinpoint exactly when the bug appeared. You simply tell Git whether each commit it checks has the bug or not, and it narrows down the search until it finds the culprit.
1# Cherry-picking a specific commit
2git log --oneline --grep="auth fix"
3git checkout production
4git cherry-pick abc123
5
6# Using git bisect to find a bug
7git bisect start
8git bisect bad # current commit has the bug
9git bisect good v2.0.0 # this version worked
10# Git will checkout commits for you to test
11# After testing, mark each commit:
12git bisect good # if the bug isn't present
13git bisect bad # if the bug is present
14git bisect reset # when finished
Git hooks are like automated guardians for your codebase, running checks and tasks at specific points in your Git workflow. Using Husky, we can easily set up these hooks to ensure code quality. For example, we can automatically run tests before each commit, or ensure commit messages follow team conventions. This automation helps maintain consistency and catches issues before they make it into the codebase.
1npm install husky --save-dev
2npx husky install
3npm pkg set scripts.prepare="husky install"
4
5# Add hooks for tests and commit message format
6npx husky add .husky/pre-commit "npm test"
7npx husky add .husky/commit-msg "npx --no -- commitlint --edit ${1}"
In professional environments, it's crucial to verify that code changes genuinely come from the right developers. This is where GPG signed commits come in. By generating a unique GPG key and configuring Git to use it, you can cryptographically sign your commits. This adds an extra layer of security and verification to your development workflow, ensuring that commits attributed to you actually came from you.
1# Generate a GPG key
2gpg --full-generate-key
3# List your keys and copy the ID
4gpg --list-secret-keys --keyid-format=long
5# Configure Git to use the key
6git config --global user.signingkey YOUR_KEY_ID
7git config --global commit.gpgsign true
Modern Git workflows are incomplete without continuous integration and deployment. By integrating your Git repository with CI/CD pipelines, you can automatically test and validate every change. A common setup using GitHub Actions automatically runs your test suite and linting checks on every pull request. This ensures that only quality code makes it into your main branch, catching issues before they affect other team members or reach production.
1# .github/workflows/main.yml
2name: CI
3on:
4 pull_request:
5 branches: [ main ]
6
7jobs:
8 test:
9 runs-on: ubuntu-latest
10 steps:
11 - uses: actions/checkout@v2
12 - name: Setup Node.js
13 uses: actions/setup-node@v2
14 with:
15 node-version: '18'
16 - run: npm ci
17 - run: npm test
18 - run: npm run lint
Code reviews are essential for maintaining code quality, but they can be time-consuming. Git provides tools to make this process more efficient. By setting up helpful aliases and automated checks, you can streamline the review process. Custom Git commands can help you quickly see changes in a more readable format, while pre-push hooks ensure basic quality checks pass before code is shared with the team.
1# Add useful aliases to .gitconfig
2git config --global alias.review "log --patch --reverse"
3git config --global alias.files "diff-tree --no-commit-id --name-only -r"
4
5# Create a pre-push hook
6cat > .husky/pre-push << 'EOF'
7#!/bin/sh
8npm run lint && npm test
9EOF
10chmod +x .husky/pre-push