What is Version Control?
Version control is a system that records changes to files over time, allowing you to recall specific versions later. Git is the most widely used distributed version control system, essential for any software development project.
Why Git Matters for Java Developers
- Track Changes - See who changed what and when
- Collaboration - Multiple developers work on the same codebase
- Branching - Work on features without affecting main code
- Backup - Code is stored in multiple locations
- CI/CD Integration - Automated builds and deployments
Git Basics
Initial Setup
# Configure your identity (required once)
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
# Configure default branch name
git config --global init.defaultBranch main
# Configure line endings (Windows)
git config --global core.autocrlf true
# Configure line endings (Mac/Linux)
git config --global core.autocrlf input
# View all configuration
git config --list
Creating a Repository
# Initialize a new repository
cd my-java-project
git init
# Clone an existing repository
git clone https://github.com/username/repository.git
# Clone with specific branch
git clone -b develop https://github.com/username/repository.git
Basic Workflow
# Check status of your working directory
git status
# Stage specific files
git add src/main/java/MyClass.java
# Stage all changes
git add .
# Commit staged changes
git commit -m "Add user authentication feature"
# Push to remote repository
git push origin main
# Pull latest changes
git pull origin main
.gitignore for Java Projects
The .gitignore file specifies which files Git should ignore. This is crucial for Java projects to avoid committing compiled classes and IDE files.
# Compiled class files
*.class
# Log files
*.log
# Package files
*.jar
*.war
*.ear
*.zip
*.tar.gz
# Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
# Gradle
.gradle/
build/
!gradle/wrapper/gradle-wrapper.jar
# IntelliJ IDEA
.idea/
*.iws
*.iml
*.ipr
out/
# Eclipse
.settings/
.classpath
.project
bin/
# VS Code
.vscode/
# OS generated files
.DS_Store
Thumbs.db
# Environment files
.env
*.env.local
application-local.properties
# Test output
/test-output/
/coverage/
Global .gitignore
Set up a global .gitignore for OS-specific files:
git config --global core.excludesfile ~/.gitignore_global
Branching Strategies
Branch Commands
# List all branches
git branch -a
# Create a new branch
git branch feature/user-login
# Switch to a branch
git checkout feature/user-login
# Create and switch in one command
git checkout -b feature/user-login
# Modern alternative (Git 2.23+)
git switch -c feature/user-login
# Delete a branch (local)
git branch -d feature/user-login
# Delete a branch (remote)
git push origin --delete feature/user-login
# Rename current branch
git branch -m new-branch-name
Git Flow
# Git Flow branch structure:
main (or master) # Production-ready code
├── develop # Integration branch for features
│ ├── feature/xyz # New features
│ └── feature/abc
├── release/1.0 # Release preparation
└── hotfix/urgent # Production bug fixes
# Feature branch workflow
git checkout develop
git checkout -b feature/user-authentication
# ... develop the feature ...
git checkout develop
git merge feature/user-authentication
git push origin develop
GitHub Flow (Simplified)
# Simpler workflow for continuous deployment
main # Always deployable
├── feature/login # Feature branches
├── fix/null-pointer # Bug fix branches
└── docs/readme-update # Documentation branches
# Workflow:
# 1. Create branch from main
git checkout -b feature/new-feature main
# 2. Make changes and commit
git add .
git commit -m "Implement new feature"
# 3. Push branch and create Pull Request
git push -u origin feature/new-feature
# 4. After review, merge to main and deploy
Merging and Rebasing
Merge
# Merge feature branch into main
git checkout main
git merge feature/user-login
# Merge with commit message
git merge feature/user-login -m "Merge user login feature"
# Abort a merge in progress
git merge --abort
Rebase
# Rebase feature branch onto main
git checkout feature/user-login
git rebase main
# Interactive rebase (squash commits)
git rebase -i HEAD~3 # Interact with last 3 commits
# Continue after resolving conflicts
git rebase --continue
# Abort rebase
git rebase --abort
Merge vs Rebase
- Merge - Preserves complete history, creates merge commit
- Rebase - Linear history, rewrites commits
Rule: Never rebase commits that have been pushed to a shared branch.
Resolving Conflicts
# When conflicts occur, files are marked:
<<<<<<< HEAD
public void processPayment(Payment payment) {
// Your changes
=======
public void processPayment(Payment payment, User user) {
// Their changes
>>>>>>> feature/payment-update
# Steps to resolve:
# 1. Edit the file to keep desired changes
# 2. Remove conflict markers
# 3. Stage the resolved file
git add src/main/java/PaymentService.java
# 4. Continue with merge/rebase
git commit # For merge
git rebase --continue # For rebase
Common Git Operations
Viewing History
# View commit history
git log
# Compact one-line format
git log --oneline
# With graph visualization
git log --oneline --graph --all
# Show changes in each commit
git log -p
# Show commits by author
git log --author="John"
# Show commits in date range
git log --since="2024-01-01" --until="2024-06-30"
# Search commit messages
git log --grep="fix bug"
Undoing Changes
# Discard changes in working directory
git checkout -- filename.java
git restore filename.java # Modern alternative
# Unstage a file
git reset HEAD filename.java
git restore --staged filename.java # Modern alternative
# Amend last commit (change message or add files)
git commit --amend -m "New commit message"
# Undo last commit (keep changes)
git reset --soft HEAD~1
# Undo last commit (discard changes)
git reset --hard HEAD~1
# Revert a commit (creates new commit)
git revert abc123
Stashing
# Save work in progress
git stash
# Stash with message
git stash save "WIP: user authentication"
# List stashes
git stash list
# Apply most recent stash
git stash pop
# Apply specific stash
git stash apply stash@{2}
# Drop a stash
git stash drop stash@{0}
# Clear all stashes
git stash clear
Tags
# Create lightweight tag
git tag v1.0.0
# Create annotated tag (recommended)
git tag -a v1.0.0 -m "Release version 1.0.0"
# Tag specific commit
git tag -a v1.0.0 abc123 -m "Release version 1.0.0"
# List tags
git tag -l
# Push tags to remote
git push origin v1.0.0
git push origin --tags # Push all tags
# Delete tag
git tag -d v1.0.0
git push origin --delete v1.0.0 # Delete remote tag
Working with Remotes
# List remotes
git remote -v
# Add remote
git remote add origin https://github.com/user/repo.git
# Add upstream (for forks)
git remote add upstream https://github.com/original/repo.git
# Change remote URL
git remote set-url origin https://github.com/user/new-repo.git
# Fetch from remote (download without merge)
git fetch origin
# Fetch all remotes
git fetch --all
# Sync fork with upstream
git fetch upstream
git checkout main
git merge upstream/main
git push origin main
Git Commit Best Practices
Commit Message Format
# Conventional Commits format
type(scope): subject
body (optional)
footer (optional)
# Types:
feat: # New feature
fix: # Bug fix
docs: # Documentation changes
style: # Formatting, missing semicolons, etc.
refactor: # Code restructuring without behavior change
test: # Adding or fixing tests
chore: # Build tasks, dependencies, configs
# Examples:
feat(auth): add JWT token refresh endpoint
fix(payment): handle null payment method gracefully
Fixes #123
refactor(user): extract validation logic to separate class
BREAKING CHANGE: UserService now requires AuthProvider
Good Commit Practices
- Commit early and often
- Make atomic commits (one logical change per commit)
- Write meaningful commit messages
- Use present tense ("Add feature" not "Added feature")
- Keep subject line under 50 characters
- Reference issue numbers when applicable
Git in Java IDEs
IntelliJ IDEA Git Integration
# Key shortcuts:
Ctrl+K # Commit dialog
Ctrl+Shift+K # Push
Ctrl+T # Update project (pull)
Alt+9 # Open Git tool window
Alt+` # VCS operations popup
# Features:
# - Visual diff viewer
# - Interactive rebase
# - Conflict resolution tool
# - Shelve (similar to stash)
# - Local history (independent of Git)
Eclipse Git (EGit)
# Access via:
# Team menu (right-click on project)
# Git Perspective
# Git Staging View
# Common operations:
# Team -> Commit (Ctrl+#)
# Team -> Push
# Team -> Pull
# Team -> Switch To -> New Branch
Advanced Git Commands
# Cherry-pick specific commit
git cherry-pick abc123
# Find which commit introduced a bug
git bisect start
git bisect bad # Current commit is bad
git bisect good v1.0.0 # v1.0.0 was good
# Git will help find the problematic commit
git bisect reset # When done
# Show who changed each line
git blame filename.java
# Search for string in all commits
git log -S "methodName" --source --all
# Clean untracked files
git clean -n # Dry run
git clean -f # Force clean
# Recover deleted branch
git reflog # Find the commit hash
git checkout -b recovered-branch abc123
GitHub/GitLab Workflow
Pull Request / Merge Request
# 1. Create feature branch
git checkout -b feature/new-api
# 2. Make changes and commit
git add .
git commit -m "feat(api): add new REST endpoint"
# 3. Push branch
git push -u origin feature/new-api
# 4. Create Pull Request via GitHub/GitLab UI
# 5. Address review comments
git add .
git commit -m "fix: address review comments"
git push
# 6. After approval, merge via UI or CLI
# GitHub CLI example:
gh pr merge --squash
Code Review Tips
- Keep pull requests small and focused
- Write clear PR descriptions
- Link related issues
- Add screenshots for UI changes
- Respond promptly to review feedback