Git Tutorial: Project Management and Version Control Fundamentals
Git is the de facto standard for version control in modern software development. It tracks every change to your codebase, enables seamless team collaboration, and provides safety nets for experimentation. Whether you are a solo developer maintaining a personal project or part of a large engineering team, mastering Git is essential. This guide covers Git from first principles through advanced workflows, with practical commands and real-world scenarios.
Introduction: Key Concepts
Before diving into commands, it helps to understand Git’s mental model. Unlike centralized version control systems, Git is distributed — every developer has a full copy of the repository history.
- Repository: The database of all files and their revision history. Every Git project lives inside a repository.
- Commit: A snapshot of the project at a specific point in time. Each commit has a unique hash, an author, a timestamp, and a message describing the change.
- Branch: A movable pointer to a specific commit. Branches let you develop features in isolation.
- Staging Area (Index): An intermediate area where you prepare changes before committing. This gives you fine-grained control over what goes into each commit.
- Remote: A copy of the repository hosted on another machine (e.g., GitHub, GitLab, Bitbucket).
Installing Git
Windows
Download the installer from git-scm.com and run it. The default options work well for most users. Once installed, open Git Bash or PowerShell and verify the installation:
git --version
macOS
Git may already be installed. Check with git --version. If missing, install via Homebrew:
brew install git
Linux
Most distributions include Git. Install it with your package manager:
# Debian/Ubuntu
sudo apt install git
# Fedora/RHEL
sudo dnf install git
Repository Setup and First Commit
Creating a repository is the first step in any Git workflow.
# Initialize a new repository
mkdir my-project
cd my-project
git init
# Add files to the staging area
echo "# My Project" > README.md
git add README.md
# Commit the staged files
git commit -m "Initial commit"
The git init command creates a hidden .git directory that stores all version control metadata. The git add command stages specific files, and git commit creates a permanent snapshot. Think of staging as the preparation area — you can stage files incrementally and commit when ready.
Connecting to a Remote Repository
Local repositories are useful, but the real power of Git emerges when you collaborate through a remote. After creating a repository on GitHub or GitLab, link it to your local project:
git remote add origin https://github.com/yourusername/my-project.git
git push -u origin main
The -u flag sets the upstream tracking reference, so future pushes can use git push without arguments. Verify your remote configuration with:
git remote -v
Branching: Isolated Development
Branches are Git’s mechanism for parallel development. You create a branch, make changes, and merge them back when ready — all without disturbing the main codebase.
# Create and switch to a new branch
git branch feature/user-auth
git checkout feature/user-auth
# Or do both in one command
git checkout -b feature/user-auth
A common branching strategy is Git Flow, which uses main for production-ready code, develop for integration, and feature branches for individual work. A simpler alternative is Trunk-Based Development, where developers work on short-lived feature branches and merge frequently into main.
| Strategy | Branches | Merge Frequency | Best For |
|---|---|---|---|
| Git Flow | main, develop, feature, release, hotfix | Lower | Complex releases |
| GitHub Flow | main, feature | High | Continuous deployment |
| Trunk-Based | main only (short feature branches) | Very high | CI/CD teams |
Pull Requests and Code Review
A pull request (PR) is a formal proposal to merge changes from one branch into another. PRs are the cornerstone of collaborative code review.
- Push your feature branch to the remote:
git push origin feature/user-auth - On GitHub/GitLab, open a new pull request against
main - Write a clear title and description explaining the change
git push origin feature/user-auth
# Then open the PR via the remote platform's UI
Reviewers leave comments, request changes, or approve. Once approved, merge the PR via the platform UI — this typically creates a merge commit or performs a fast-forward merge.
Syncing: Pull, Fetch, and Merge
Keeping your local repository up to date is essential, especially when working on a team.
# Fetch changes without merging
git fetch origin
# Fetch and merge in one step
git pull origin main
# The above is equivalent to:
git fetch origin main
git merge origin/main
Conflicts arise when two people modify the same lines of a file. Git marks the conflicting area in the file:
<<<<<<< HEAD
console.log("version A");
=======
console.log("version B");
>>>>>>> feature/branch
Edit the file to resolve the conflict, stage it, then commit:
git add conflicted-file.js
git commit -m "Resolve merge conflict in conflicted-file.js"
Rebasing: A Cleaner History
While merging preserves the exact chronology of commits, rebasing rewrites history to create a linear sequence. This results in a cleaner log but should be used carefully — never rebase commits that have been pushed to a shared branch.
# Rebase current branch onto main
git checkout feature/my-feature
git rebase main
# Interactive rebase to squash, reword, or reorder commits
git rebase -i HEAD~5
The interactive rebase opens an editor where you can:
- pick: Keep the commit as-is
- squash: Combine the commit with the previous one
- reword: Change the commit message
- drop: Remove the commit
Viewing History
Git’s history inspection tools are invaluable for understanding how a project evolved.
# Full commit log
git log
# Condensed one-line log with graph
git log --oneline --graph --all
# Show changes in a specific commit
git show abc123
# Diff between working directory and last commit
git diff
# Diff between two branches
git diff main..feature/user-auth
# Search commits by message
git log --grep="fix"
Git Configuration and Housekeeping
Set your identity — every commit uses this information:
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
The .gitignore File
Not every file belongs in version control. The .gitignore file tells Git which files to ignore — dependency directories, build outputs, environment files, and OS artifacts.
# Dependencies
node_modules/
vendor/
# Build output
dist/
build/
.out/
# Environment files
.env
.env.local
# OS files
.DS_Store
Thumbs.db
Advanced: Remote Branch Management
Over time, remote repositories accumulate stale branches. Clean them up regularly:
# Delete a remote branch
git push origin --delete feature/old-branch
# Prune local tracking of deleted remote branches
git fetch --prune
Conclusion
Git is a deep tool — this guide covers the commands and workflows you will use daily, but there is always more to learn. Focus on mastering the fundamentals: committing thoughtfully, branching intentionally, and syncing frequently. Once those habits are solid, explore advanced topics like bisect for binary searching bugs, stash for temporarily shelving work, and reflog for recovering lost commits. Version control is not just about saving code — it is about building a reliable history that empowers you and your team to move fast without breaking things.
