INTRODUCTION
Even if you are using Git and GitHub daily in your job, it is hard to remember all git commands and best practices. I have collected a set of best practices in this small document, so that I do not have to remember all Git commands or look them up in one of those multi hundred pages books. Maybe, this Nutshell is also helpful for your work.
Welcome to the complete guide for mastering Git and GitHub in professional software development. This curriculum assumes no prior knowledge and will take you from absolute beginner to advanced practitioner through carefully structured modules. Each section builds upon previous knowledge with real-world examples and production-ready code.
Git is a distributed version control system that tracks changes in source code during software development. GitHub is a web-based platform that hosts Git repositories and provides collaboration tools. Together, they form the backbone of modern software development workflows.
MODULE 1: FUNDAMENTAL CONCEPTS
What is Version Control?
Version control is a system that records changes to files over time so that you can recall specific versions later. Imagine writing a novel where you want to keep every draft, see what changed between drafts, and potentially revert to an earlier version if needed. Git does this for code.
The Three States of Git
Git has three main states that your files can reside in: modified, staged, and committed. Modified means you have changed the file but not committed it to your database yet. Staged means you have marked a modified file in its current version to go into your next commit snapshot. Committed means the data is safely stored in your local database.
Your First Git Repository
Let us start by creating a new project directory and initializing it as a Git repository. This is the foundation of every Git project.
# Create a new directory for our project
mkdir professional-web-app
cd professional-web-app
# Initialize a new Git repository
git init
# Check the status of our repository
git status
The output will show that we are on the master branch (or main branch in newer Git versions) with no commits yet. This is our starting point.
Configuring Git Identity
Before making any commits, we need to configure Git with our identity. This information will be attached to every commit we make.
git config --global user.name "Your Full Name"
git config --global user.email "your.email@company.com"
# Verify the configuration
git config --global user.name
git config --global user.email
MODULE 2: BASIC WORKFLOW MASTERY
Creating Meaningful Files
Let us create a simple web application structure to work with. This represents a real project that you might encounter in professional development.
# Create project structure
mkdir src
mkdir tests
mkdir docs
# Create a main application file
cat > src/app.js << 'EOF'
/**
* Professional Web Application
* Main application entry point
*
* @author Your Name
* @version 1.0.0
*/
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware setup
app.use(express.json());
app.use(express.static('public'));
// Health check endpoint
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime()
});
});
// Main route
app.get('/', (req, res) => {
res.json({
message: 'Welcome to Professional Web App',
version: '1.0.0'
});
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
// Start server
if (require.main === module) {
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
}
module.exports = app;
EOF
# Create package.json
cat > package.json << 'EOF'
{
"name": "professional-web-app",
"version": "1.0.0",
"description": "A production-ready web application demonstrating Git best practices",
"main": "src/app.js",
"scripts": {
"start": "node src/app.js",
"dev": "nodemon src/app.js",
"test": "jest",
"lint": "eslint src/**/*.js"
},
"keywords": ["web", "express", "nodejs"],
"author": "Your Name",
"license": "MIT",
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"nodemon": "^3.0.1",
"jest": "^29.7.0",
"eslint": "^8.50.0"
}
}
EOF
Understanding the Staging Area
The staging area is like a preparation zone where you compose your next commit. Think of it as a shopping cart where you collect items before checking out.
# Check what files are untracked
git status
# Add specific files to staging area
git add src/app.js
git add package.json
# Or add all files at once
git add .
# See what is staged
git diff --staged
Making Your First Commit
A commit is like taking a snapshot of your project at a specific point in time. Each commit has a unique identifier and contains the changes you have staged.
# Create a meaningful commit
git commit -m "Initial project setup with Express.js web application
- Added main application file with health check endpoint
- Configured package.json with production dependencies
- Set up basic project structure with src, tests, and docs directories
- Included error handling and proper server startup logic"
# View commit history
git log --oneline
MODULE 3: BRANCHING STRATEGIES
Understanding Branches
Branches in Git allow you to diverge from the main line of development and work on features or fixes in isolation. Think of branches as parallel universes where you can experiment without affecting the stable version of your code.
Creating and Switching Branches
Let us create a feature branch for adding user authentication to our application.
# Create and switch to a new branch
git checkout -b feature/user-authentication
# Verify current branch
git branch
# Create authentication module
cat > src/auth.js << 'EOF'
/**
* Authentication Module
* Handles user authentication and authorization
*
* @module auth
*/
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
class AuthService {
constructor() {
this.users = new Map();
this.secretKey = process.env.JWT_SECRET || 'your-secret-key-change-in-production';
}
/**
* Register a new user
* @param {string} username - The username
* @param {string} password - The plain text password
* @returns {Object} User object without password
*/
async register(username, password) {
if (this.users.has(username)) {
throw new Error('Username already exists');
}
const hashedPassword = await bcrypt.hash(password, 10);
const user = {
id: Date.now().toString(),
username,
password: hashedPassword,
createdAt: new Date().toISOString()
};
this.users.set(username, user);
// Return user without password
const { password: _, ...userWithoutPassword } = user;
return userWithoutPassword;
}
/**
* Authenticate a user
* @param {string} username - The username
* @param {string} password - The plain text password
* @returns {string} JWT token
*/
async login(username, password) {
const user = this.users.get(username);
if (!user) {
throw new Error('User not found');
}
const isValidPassword = await bcrypt.compare(password, user.password);
if (!isValidPassword) {
throw new Error('Invalid password');
}
return jwt.sign(
{ userId: user.id, username: user.username },
this.secretKey,
{ expiresIn: '24h' }
);
}
/**
* Verify a JWT token
* @param {string} token - The JWT token
* @returns {Object} Decoded token payload
*/
verifyToken(token) {
try {
return jwt.verify(token, this.secretKey);
} catch (error) {
throw new Error('Invalid token');
}
}
}
module.exports = AuthService;
EOF
# Update package.json to include new dependencies
# First, let's see the current state
git status
# Stage and commit the authentication feature
git add src/auth.js
git commit -m "Add user authentication service
- Implemented AuthService class with register, login, and verifyToken methods
- Added bcrypt for password hashing with salt rounds of 10
- Integrated JWT token generation with 24-hour expiration
- Included comprehensive JSDoc documentation
- Prepared for environment variable configuration"
Merging Branches
After completing work on a feature branch, we merge it back into the main branch. This integrates our changes into the stable codebase.
# Switch back to main branch
git checkout main
# Merge the feature branch
git merge feature/user-authentication
# Delete the feature branch (optional)
git branch -d feature/user-authentication
MODULE 4: COLLABORATIVE WORKFLOWS
Setting Up GitHub
GitHub extends Git with collaboration features. First, create a GitHub account and set up SSH keys for secure communication.
# Generate SSH key pair
ssh-keygen -t ed25519 -C "your.email@company.com"
# Start SSH agent and add key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
# Copy public key to clipboard
cat ~/.ssh/id_ed25519.pub
Add the public key to your GitHub account under Settings > SSH and GPG keys.
Connecting Local Repository to GitHub
Create a new repository on GitHub named "professional-web-app" (without README), then connect your local repository.
# Add remote repository
git remote add origin git@github.com:yourusername/professional-web-app.git
# Push code to GitHub
git push -u origin main
Pull Requests and Code Reviews
In professional development, we use pull requests to propose changes and conduct code reviews before merging.
# Create a new feature branch
git checkout -b feature/add-database
# Add database configuration
cat > src/database.js << 'EOF'
/**
* Database Configuration Module
* Handles database connections and operations
*
* @module database
*/
const sqlite3 = require('sqlite3').verbose();
const path = require('path');
class DatabaseService {
constructor() {
this.db = null;
this.dbPath = process.env.DB_PATH || path.join(__dirname, '../data/app.db');
}
/**
* Initialize database connection
* @returns {Promise} Database connection promise
*/
async connect() {
return new Promise((resolve, reject) => {
this.db = new sqlite3.Database(this.dbPath, (err) => {
if (err) {
reject(err);
} else {
console.log('Connected to SQLite database');
this.initializeTables();
resolve(this.db);
}
});
});
}
/**
* Initialize database tables
*/
initializeTables() {
const createUsersTable = `
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`;
this.db.run(createUsersTable, (err) => {
if (err) {
console.error('Error creating users table:', err);
} else {
console.log('Users table ready');
}
});
}
/**
* Close database connection
*/
close() {
if (this.db) {
this.db.close((err) => {
if (err) {
console.error('Error closing database:', err);
} else {
console.log('Database connection closed');
}
});
}
}
}
module.exports = DatabaseService;
EOF
# Create data directory
mkdir data
# Update .gitignore to exclude sensitive files
cat > .gitignore << 'EOF'
# Dependencies
node_modules/
# Environment variables
.env
# Database files
data/*.db
# Logs
*.log
logs/
# Runtime data
pids/
*.pid
*.seed
# Coverage directory used by tools like istanbul
coverage/
# IDE
.vscode/
.idea/
# OS
.DS_Store
Thumbs.db
EOF
# Stage and commit changes
git add .
git commit -m "Add SQLite database service with user table
- Implemented DatabaseService class for SQLite operations
- Added automatic table initialization for users
- Configured .gitignore to exclude sensitive files
- Prepared for environment-based configuration
- Added proper error handling and connection management"
MODULE 5: ADVANCED GIT FEATURES
Interactive Rebase
Interactive rebase allows you to rewrite commit history for a cleaner project history. This is useful before merging feature branches.
# Start interactive rebase for last 3 commits
git rebase -i HEAD~3
# The editor will open with options like:
# pick, reword, edit, squash, fixup, drop
# Save and close to apply changes
Cherry-Picking
Cherry-picking allows you to apply specific commits from one branch to another without merging entire branches.
# Find the commit hash you want to cherry-pick
git log --oneline
# Cherry-pick a specific commit
git cherry-pick abc123def456
Stashing Changes
Stashing temporarily shelves changes so you can work on something else, then return to them later.
# Stash current changes
git stash save "Work in progress on user profile feature"
# List stashes
git stash list
# Apply most recent stash
git stash pop
# Apply specific stash
git stash apply stash@{2}
MODULE 6: COLLABORATION BEST PRACTICES
Fork and Clone Workflow
When contributing to open-source projects or working with restricted repositories, you use the fork and clone workflow.
# Fork repository on GitHub web interface
# Then clone your fork
git clone git@github.com:yourusername/some-open-source-project.git
# Add upstream remote
git remote add upstream git@github.com:originalauthor/some-open-source-project.git
# Keep fork updated
git fetch upstream
git checkout main
git merge upstream/main
Issue Tracking Integration
Link commits to GitHub issues for better project management.
# Commit that fixes an issue
git commit -m "Fix user authentication bypass vulnerability
- Added input validation for all authentication endpoints
- Implemented rate limiting to prevent brute force attacks
- Added comprehensive security tests
- Fixes #42"
MODULE 7: CONTINUOUS INTEGRATION
GitHub Actions Setup
GitHub Actions automate testing and deployment workflows. Create a workflow file:
# Create GitHub Actions directory
mkdir -p .github/workflows
# Create CI/CD workflow
cat > .github/workflows/ci.yml << 'EOF'
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test
- name: Build application
run: npm run build
- name: Upload coverage reports
uses: codecov/codecov-action@v3
if: matrix.node-version == '18.x'
EOF
# Commit the workflow
git add .github/workflows/ci.yml
git commit -m "Add GitHub Actions CI/CD pipeline
- Configured automated testing for Node.js 16, 18, and 20
- Added linting and build steps
- Integrated Codecov for coverage reporting
- Runs on push to main/develop and all pull requests"
MODULE 8: RELEASE MANAGEMENT
Semantic Versioning
Use semantic versioning (SemVer) for releases: MAJOR.MINOR.PATCH.
# Create a release branch
git checkout -b release/v1.1.0
# Update version in package.json
# Then commit
git commit -am "Bump version to 1.1.0"
# Create annotated tag
git tag -a v1.1.0 -m "Release version 1.1.0
- Added user authentication system
- Implemented SQLite database support
- Enhanced security features
- Improved error handling"
# Push tag to GitHub
git push origin v1.1.0
MODULE 9: ADVANCED COLLABORATION
Code Review Guidelines
When reviewing pull requests, focus on:
1. Code quality and maintainability
2. Security considerations
3. Performance implications
4. Test coverage
5. Documentation completeness
Example review comment:
This authentication implementation looks solid! However, I recommend:
- Adding rate limiting middleware to prevent brute force attacks
- Using environment variables for JWT secret configuration
- Adding unit tests for edge cases (empty passwords, SQL injection attempts)
- Consider using async/await consistently throughout the codebase
Branch Protection Rules
Set up branch protection on GitHub to enforce quality standards:
1. Require pull request reviews before merging
2. Require status checks to pass
3. Require branches to be up to date before merging
4. Restrict pushes that create files larger than 100MB
MODULE 10: TROUBLESHOOTING COMMON ISSUES
Recovering from Mistakes
If you accidentally committed sensitive data:
# Remove sensitive file from history
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch path/to/sensitive/file" \
--prune-empty --tag-name-filter cat -- --all
# Force push to update remote
git push origin --force --all
Resolving Merge Conflicts
When Git cannot automatically merge changes:
# During merge, conflicts will be marked
# Edit files to resolve conflicts
# Then stage resolved files
git add path/to/resolved/file.js
# Complete the merge
git commit -m "Resolve merge conflicts in authentication module"
MODULE 11: PERFORMANCE OPTIMIZATION
Repository Size Management
Keep repositories lean for better performance:
# Check repository size
git count-objects -vH
# Remove large files from history
git filter-branch --tree-filter 'rm -f path/to/large/file.zip' HEAD
# Use Git LFS for large files
git lfs track "*.zip"
git lfs track "*.mp4"
git add .gitattributes
Submodule Management
For projects with dependencies:
# Add a submodule
git submodule add https://github.com/company/shared-library.git lib/shared
# Initialize submodules after clone
git submodule update --init --recursive
# Update submodule to latest commit
cd lib/shared
git pull origin main
cd ../..
git add lib/shared
git commit -m "Update shared library to latest version"
MODULE 12: SECURITY BEST PRACTICES
Secret Management
Never commit secrets to Git:
# Create .env.example for documentation
cat > .env.example << 'EOF'
# Database Configuration
DB_PATH=./data/app.db
# JWT Configuration
JWT_SECRET=your-jwt-secret-here
# Server Configuration
PORT=3000
NODE_ENV=development
EOF
# Add .env to .gitignore (already done)
# Use environment variables in code
const jwtSecret = process.env.JWT_SECRET || 'fallback-for-dev-only';
Signed Commits
Use GPG signing for verified commits:
# Generate GPG key
gpg --full-generate-key
# Configure Git to use GPG key
git config --global user.signingkey YOUR_GPG_KEY_ID
git config --global commit.gpgsign true
# Make signed commit
git commit -S -m "Add secure payment processing module"
MODULE 13: WORKFLOW OPTIMIZATION
Git Aliases
Create shortcuts for common commands:
# Set up useful aliases
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual '!gitk'
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
# Use aliases
git st
git lg
Pre-commit Hooks
Automate quality checks:
# Install pre-commit framework
npm install --save-dev husky lint-staged
# Set up husky
npx husky install
# Create pre-commit hook
cat > .husky/pre-commit << 'EOF'
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
EOF
# Configure lint-staged in package.json
# Add to package.json:
# "lint-staged": {
# "*.js": ["eslint --fix", "git add"]
# }
MODULE 14: MONOREPO MANAGEMENT
Managing Large Projects
For projects with multiple packages:
# Create monorepo structure
mkdir -p packages/{web,api,shared}
git add packages/
git commit -m "Set up monorepo structure"
# Use workspaces in package.json
cat > package.json << 'EOF'
{
"name": "professional-web-app",
"version": "1.0.0",
"private": true,
"workspaces": [
"packages/*"
],
"scripts": {
"dev": "concurrently \"npm run dev --workspace=packages/web\" \"npm run dev --workspace=packages/api\"",
"test": "npm test --workspaces"
}
}
EOF
MODULE 15: DEPLOYMENT STRATEGIES
GitHub Pages Deployment
For static sites:
# Create gh-pages branch
git checkout --orphan gh-pages
git rm -rf .
# Add deployment workflow
cat > .github/workflows/deploy.yml << 'EOF'
name: Deploy to GitHub Pages
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
EOF
git add .github/workflows/deploy.yml
git commit -m "Add GitHub Pages deployment workflow"
git push -u origin gh-pages
Heroku Deployment
For Node.js applications:
# Create Procfile for Heroku
echo "web: node src/app.js" > Procfile
# Add Heroku remote
heroku create professional-web-app-demo
git remote add heroku https://git.heroku.com/professional-web-app-demo.git
# Deploy to Heroku
git push heroku main
MODULE 16: MAINTENANCE AND HOUSEKEEPING
Regular Repository Maintenance
Keep your repository healthy:
# Prune remote-tracking branches
git remote prune origin
# Garbage collect to optimize repository
git gc --aggressive
# Verify repository integrity
git fsck --full
# Clean untracked files (use carefully)
git clean -fd
# Preview what would be deleted
git clean -fdn
Documentation Standards
Maintain comprehensive documentation:
# Create comprehensive README
cat > README.md << 'EOF'
# Professional Web Application
A production-ready web application demonstrating Git and GitHub best practices.
## Getting Started
### Prerequisites
- Node.js 16 or higher
- npm or yarn
### Installation
1. Clone the repository
git clone git@github.com:yourusername/professional-web-app.git
2. Install dependencies
npm install
3. Set up environment variables
cp .env.example .env
4. Start development server
npm run dev
### Testing
npm test
### Deployment
This project uses GitHub Actions for CI/CD. Pushes to main branch automatically deploy to production.
## Architecture
- Express.js backend
- SQLite database
- JWT authentication
- RESTful API design
EOF
git add README.md
git commit -m "Add comprehensive project documentation"
MODULE 17: TEAM COLLABORATION-----
Scenario 1: Hotfix Production Issue
When critical bugs need immediate attention:
# Create hotfix branch from main
git checkout main
git pull origin main
git checkout -b hotfix/security-patch
# Make urgent fix
# ... fix the security vulnerability ...
# Test thoroughly
npm test
# Merge quickly
git checkout main
git merge hotfix/security-patch
git tag v1.0.1
git push origin main --tags
Scenario 2: Feature Development with Multiple Developers
Coordinating work on large features:
# Developer A starts feature
git checkout -b feature/payment-system
# ... works on payment processing ...
# Developer B joins the feature
git checkout feature/payment-system
git pull origin feature/payment-system
# ... works on payment UI ...
# Regular integration
git checkout feature/payment-system
git merge main
# Resolve any conflicts
git push origin feature/payment-system
Scenario 3: Release Management
Managing stable releases:
# Create release candidate
git checkout -b release/v2.0.0-rc1
# Final testing and bug fixes
# Update version numbers
git commit -am "Prepare release candidate 2.0.0-rc1"
git tag v2.0.0-rc1
git push origin v2.0.0-rc1
# After testing, create final release
git checkout main
git merge release/v2.0.0-rc1
git tag v2.0.0
git push origin main --tags
CONCLUSION AND NEXT STEPS
You have now completed a comprehensive curriculum covering professional Git and GitHub usage. The concepts and practices covered here form the foundation for effective software development in team environments.
Key takeaways for continued learning:
- Practice these workflows regularly in real projects
- Explore advanced Git features like bisect, reflog, and worktrees
- Contribute to open-source projects to gain collaborative experience
- Stay updated with Git and GitHub's evolving features
- Consider learning Git internals for deeper understanding
Remember that mastering Git is a journey. Start with the basics, gradually incorporate advanced features, and always prioritize clear communication with your team through meaningful commit messages and well-structured branches.
Your professional development workflow is now equipped with industry-standard practices that will serve you throughout your career in software development.
No comments:
Post a Comment