Introduction
Git is the de‑facto version control system for modern software development. Whether you're a solo coder or part of a massive open‑source community, mastering Git can dramatically improve your workflow, collaboration, and code quality. In this post we'll walk through the essentials—cloning, branching, merging, rebasing, and some pro‑level tricks—while keeping the examples short and practical.
1. Getting Started: The First Commit
# Initialize a new repository
mkdir my‑project && cd my‑project
git init
# Create a README and commit it
printf "# My Project\n\nA brief description." > README.md
git add README.md
git commit -m "Initial commit"
Why git add?
- Stages files for the next commit.
- Allows you to commit a subset of changes (useful for partial work).
2. Cloning & Remote Workflows
# Clone an existing repo
git clone https://github.com/your‑org/awesome‑app.git
cd awesome‑app
# List configured remotes
git remote -v
Typical remote names:
-
origin– the default remote created byclone. -
upstream– a second remote pointing to the original upstream repository (common for forks).
Adding a New Remote
git remote add upstream https://github.com/original/awesome‑app.git
Now you can fetch upstream changes without affecting your origin branches.
3. Branching: The Core of Parallel Development
# Create and switch to a new feature branch
git checkout -b feature/login
# Do some work, then commit
git add src/login.js
git commit -m "Add login component"
Branch Naming Conventions
-
feature/*– new functionality. -
bugfix/*– bug repairs. -
hotfix/*– urgent production patches. -
release/*– preparation for a release.
Keeping branches short‑lived reduces merge conflicts and simplifies history.
4. Merging vs. Rebasing
Merging (preserves history)
git checkout main
git merge feature/login # Creates a merge commit
Rebasing (linear history)
git checkout feature/login
git rebase main # Replay commits on top of main
When to rebase?
- Before opening a Pull Request (PR) to keep the PR tidy.
- Never rebase shared branches that teammates have already pulled.
When to merge?
- For long‑running branches where you want to retain the original context.
5. Interactive Rebase: Cleaning Up Commits
Suppose you have three messy commits and want to squash them into a single coherent one.
git log --oneline # Identify the commit hash before the three
# Assume the hash is abc123
git rebase -i abc123
An editor opens:
pick e1a2b3 Add login UI
pick f4c5d6 Fix login typo
pick a7b8c9 Add unit tests
Change pick to squash (or s) for the second and third lines, save, and edit the combined commit message.
6. Stashing: Save Work in Progress
When you need to switch branches but aren't ready to commit:
git stash push -m "WIP: login UI"
# Switch branches, work, then restore
git stash list
git stash apply stash@{0}
You can also git stash pop to apply and drop the stash in one step.
7. Resolving Conflicts
A conflict occurs when Git can't automatically merge changes. After a merge or rebase that hits a conflict:
# Open the conflicted file; you'll see markers like:
<<<<<<< HEAD
// code from current branch
=======
// code from incoming branch
>>>>>>> feature/login
# Edit to keep the correct version, then:
git add conflicted-file.js
# Continue the operation
git merge --continue # or git rebase --continue
Tip: Use git diff --conflict to see a side‑by‑side view.
8. Tagging Releases
# Annotated tag (recommended for releases)
git tag -a v1.0.0 -m "First stable release"
# Push tags to remote
git push origin v1.0.0
Annotated tags store the tagger name, email, date, and a message—perfect for release notes.
9. Pro Tips & Lesser‑Known Commands
| Command | What It Does |
|---|---|
git log --graph --oneline --decorate |
Visualize branch structure in the terminal |
git reflog |
Recover lost commits by viewing the reference log |
git cherry-pick <hash> |
Apply a single commit from another branch |
git bisect start … git bisect bad/good
|
Binary search to locate a bug introduction |
git filter-branch (or git filter-repo) |
Rewrite history (e.g., remove large files) |
Example: Using git bisect to Find a Bug
# Start bisect on the range where bug appeared
git bisect start
git bisect bad # Current HEAD is bad
git bisect good v1.2.3 # Tag known good version
# Git checks out a mid‑point; test, then tell Git:
# If bad:
git bisect bad
# If good:
git bisect good
# Repeat until Git pinpoints the offending commit
10. Automating with Hooks
Git hooks let you run scripts at key points. For example, enforce commit messages:
# .git/hooks/commit-msg (make it executable)
#!/usr/bin/env bash
msg=$(cat "$1")
if ! grep -qE "^JIRA-[0-9]+:" <<< "$msg"; then
echo "Commit message must start with a JIRA ticket (e.g., JIRA-123: ...)" >&2
exit 1
fi
Now any git commit that doesn't start with a ticket ID aborts.
Conclusion
Git is a powerful toolbox, not just a single command. By mastering the basics—cloning, branching, merging/rebasing—and sprinkling in advanced techniques like interactive rebasing, bisect, and hooks, you can keep your repository clean, your history readable, and your team productive.
Start applying these patterns today, and watch your development workflow become faster, safer, and far more enjoyable.
Happy coding!
Top comments (0)