Estimated Time: 90 minutes
Difficulty: Beginner to Intermediate
Prerequisites: Git installed, GitHub account created
By completing this lab, you will:
- Create and manage GitHub Issues
- Use branch-based workflow for feature development
- Submit and review pull requests
- Resolve merge conflicts
- Experience a realistic team collaboration scenario
Before starting, verify your environment:
# Check Git installation
git --version
# Should output: git version 2.x or higher
# Check Git configuration
git config --global user.name
git config --global user.email
# If not configured, run:
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"✅ Have a GitHub account? If not, create one at github.com
We've created a practice repository for this lab:
- Go to:
https://github.com/tfdevs/git-workflow-practice - Click: "Fork" button (top right)
- Select: Your GitHub account as the destination
You now have your own copy of the repository!
# Replace YOUR_USERNAME with your actual GitHub username
git clone https://github.com/YOUR_USERNAME/git-workflow-practice.git
# Navigate into the repository
cd git-workflow-practice
# Verify the remote
git remote -v
# Should show your fork as 'origin'# List files
ls -la
# You should see:
# - README.md (project description)
# - index.html (simple web page)
# - styles.css (stylessheet)
# - script.js (JavaScript file)
# - .gitignorePractice creating well-structured GitHub Issues for project management.
You're joining a team working on a simple todo application. You need to create issues for upcoming work.
- Navigate to your fork on GitHub
- Go to the "Issues" tab
- Click "New Issue"
- Create a feature issue with this information:
Title: Add dark mode toggle button
## Description
Add a dark mode feature that allows users to switch between light and dark themes.
## Acceptance Criteria
- [ ] Add toggle button in navigation bar
- [ ] Implement dark color scheme
- [ ] Save user preference in localStorage
- [ ] Apply theme on page load based on saved preference
## Design Notes
- Toggle should show moon icon for dark mode, sun icon for light mode
- Dark mode colors:
- Background: #1a1a1a
- Text: #f0f0f0
- Accent: #4a9eff
## Estimated Effort
Medium (3-4 hours)- Add labels:
enhancement,frontend - Assign it to yourself
- Click "Submit New Issue"
✅ Checkpoint: You now have Issue #1 (or similar number)
Create another issue for a bug:
Title: Submit button not responsive on mobile devices
## Description
The submit button on the todo form doesn't respond to taps on iOS Safari
and Chrome mobile browsers.
## Steps to Reproduce
1. Open the application on iPhone (iOS 15+) or Android device
2. Navigate to the todo input form
3. Enter a todo item
4. Tap the "Add Task" button
5. Nothing happens - button doesn't register the tap
## Expected Behavior
Button should add the task to the list and clear the input field
## Actual Behavior
Button visual feedback appears but no action is taken
## Environment
- Device: iPhone 12, Samsung Galaxy S21
- OS: iOS 15.6, Android 12
- Browsers: Safari, Chrome Mobile
## Priority
High - affects mobile users (estimated 40% of user base)
## Possible Cause
May be related to z-index or touch event handlingAdd labels: bug, mobile, high-priority
✅ Checkpoint: You now have two distinct issues
Create a third issue that references the others:
Title: Mobile optimization sprint
## Description
Collection of mobile-related improvements and bug fixes
## Tasks
- [ ] Fix submit button responsiveness (#2)
- [ ] Test dark mode on mobile devices
- [ ] Optimize touch targets (minimum 44x44px)
- [ ] Test on various screen sizes
## Related Issues
- Fixes #2
- Related to #1 (need to test dark mode on mobile)
## Sprint Goal
Improve mobile user experience and fix critical mobile bugsAdd label: mobile, epic
✅ Checkpoint: Three issues created with proper cross-referencing
Learn to use feature branches for isolated development.
You're implementing the dark mode feature from Issue #1.
# Ensure you're on main and up to date
git checkout main
git pull origin main
# Create and switch to a new feature branch
git checkout -b feature/dark-mode-toggle
# Verify you're on the new branch
git branch
# Output should show * next to feature/dark-mode-toggleCreate a new file for the dark mode functionality:
# Create a new CSS file for dark mode styles
cat > dark-mode.css << 'EOF'
/* Dark Mode Styles */
body.dark-mode {
background-color: #1a1a1a;
color: #f0f0f0;
transition: background-color 0.3s ease, color 0.3s ease;
}
body.dark-mode .navbar {
background-color: #2a2a2a;
border-bottom: 1px solid #4a4a4a;
}
body.dark-mode .card {
background-color: #2a2a2a;
border-color: #4a4a4a;
}
body.dark-mode .btn-primary {
background-color: #4a9eff;
border-color: #4a9eff;
}
.theme-toggle {
cursor: pointer;
padding: 8px 12px;
border: none;
background: transparent;
font-size: 1.2rem;
}
.theme-toggle:hover {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 4px;
}
EOFUpdate index.html to include the toggle button:
# Add dark mode script to the HTML (this is a simplified version)
cat > dark-mode.js << 'EOF'
// Dark Mode Toggle Functionality
document.addEventListener('DOMContentLoaded', function() {
// Create toggle button
const toggleButton = document.createElement('button');
toggleButton.className = 'theme-toggle';
toggleButton.innerHTML = '🌙';
toggleButton.setAttribute('aria-label', 'Toggle dark mode');
// Add to navbar (assuming navbar exists)
const navbar = document.querySelector('.navbar') || document.body;
navbar.appendChild(toggleButton);
// Check for saved theme preference
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark') {
document.body.classList.add('dark-mode');
toggleButton.innerHTML = '☀️';
}
// Toggle theme on button click
toggleButton.addEventListener('click', function() {
document.body.classList.toggle('dark-mode');
// Update button icon and save preference
if (document.body.classList.contains('dark-mode')) {
toggleButton.innerHTML = '☀️';
localStorage.setItem('theme', 'dark');
} else {
toggleButton.innerHTML = '🌙';
localStorage.setItem('theme', 'light');
}
});
});
EOF# Check what files changed
git status
# Add the new files
git add dark-mode.css dark-mode.js
# Commit with a descriptive message referencing the issue
git commit -m "feat: add dark mode toggle button
- Created dark-mode.css with dark theme styles
- Implemented toggle functionality in dark-mode.js
- Saves user preference in localStorage
- Auto-applies theme on page load
Implements #1"
# Check your commit
git log -1Make another commit to show incremental development:
# Improve the dark mode styles
cat >> dark-mode.css << 'EOF'
/* Additional dark mode improvements */
body.dark-mode input,
body.dark-mode textarea {
background-color: #3a3a3a;
color: #f0f0f0;
border-color: #4a4a4a;
}
body.dark-mode a {
color: #4a9eff;
}
body.dark-mode a:hover {
color: #6ab0ff;
}
EOF
# Commit the improvement
git add dark-mode.css
git commit -m "style: enhance dark mode contrast for form inputs
Improved readability of input fields in dark mode"# Push the feature branch to GitHub
git push -u origin feature/dark-mode-toggle
# The -u flag sets upstream tracking
# Future pushes can just use: git push✅ Checkpoint: Your feature branch is now on GitHub!
Create a professional pull request and practice code review.
Your feature is ready for team review. Time to create a pull request!
- Go to your GitHub repository in browser
- You'll see a banner: "feature/dark-mode-toggle had recent pushes"
- Click: "Compare & pull request"
- Fill out the PR template:
Title: Add dark mode toggle feature
## What does this PR do?
Implements a dark mode toggle that allows users to switch between light
and dark themes. The preference is saved and persists across sessions.
## Why is this needed?
Resolves #1 - Adds requested dark mode functionality for better user
experience in low-light environments.
## What changed?
- Created `dark-mode.css` with comprehensive dark theme styles
- Implemented toggle button in `dark-mode.js`
- Added localStorage support for theme persistence
- Included smooth transitions between themes
- Enhanced contrast for form inputs in dark mode
## How to test
1. Open `index.html` in a browser
2. Look for the 🌙 icon in the navigation
3. Click to toggle to dark mode (icon changes to ☀️)
4. Refresh the page - dark mode should persist
5. Click again to return to light mode
## Screenshots
[You would add screenshots here in a real PR]
## Checklist
- [x] Code follows project style guidelines
- [x] Feature works as expected
- [x] Theme preference persists on reload
- [x] Smooth transition between themes
- [x] Accessible (keyboard navigation works)
- [x] Tested in Chrome, Firefox, Safari- Request yourself as a reviewer (for practice)
- Add label:
enhancement - Link to issue: The PR description should automatically link with "Resolves #1"
- Click: "Create pull request"
✅ Checkpoint: PR is created and visible on GitHub
This is practice for when you review others' code:
- Go to the "Files changed" tab in your PR
- Click the "+" next to a line to add a comment
- Add at least 3 comments:
# Example 1: Question
💡 Could we add a preference for "auto" mode that respects system theme?
# Example 2: Suggestion
Consider adding a transition to the toggle button itself for smoother UX
# Example 3: Approval
✅ Great implementation of localStorage! This will work well.- Click "Start a review" and add comments
- Submit review with "Comment" (since you're practicing)
Now practice responding to review feedback:
# Make an improvement based on feedback
cat >> dark-mode.css << 'EOF'
/* Smooth transition for toggle button */
.theme-toggle {
transition: transform 0.2s ease, background-color 0.2s ease;
}
.theme-toggle:active {
transform: scale(0.95);
}
EOF
# Commit and push
git add dark-mode.css
git commit -m "style: add transition to toggle button
Improved UX with smooth button animation"
git pushOn GitHub:
- Reply to your own comments: "Great idea! Added in commit abc123"
- The PR automatically updates with new commits
✅ Checkpoint: PR updated with feedback addressed
- In your PR, click "Merge pull request"
- Select "Squash and merge" for clean history
- Edit the commit message if needed:
feat: add dark mode toggle (#1)
- Implements theme toggle with localStorage persistence
- Includes smooth transitions and enhanced form input contrast
- Click "Confirm squash and merge"
- Delete the branch when prompted
✅ Checkpoint: Feature merged into main!
# Switch back to main
git checkout main
# Pull the merged changes
git pull origin main
# Delete local feature branch
git branch -d feature/dark-mode-toggle
# Verify it's gone
git branch
# Should only show: * main
# Check that your commit is there
git log --oneline -3Learn to confidently handle merge conflicts.
Two team members edited the same file. You need to resolve the conflict.
# Ensure you're on main and up to date
git checkout main
git pull origin main
# Create first branch and make changes
git checkout -b feature/update-header
echo "<h1>Welcome to the Todo App</h1>" > header.html
git add header.html
git commit -m "feat: update header with welcome message"
git push -u origin feature/update-header
# Go back to main and create another branch
git checkout main
git checkout -b feature/add-logo
echo "<h1><img src='logo.png'> Todo App</h1>" > header.html
git add header.html
git commit -m "feat: add logo to header"
git push -u origin feature/add-logo# Merge the first feature
git checkout main
git merge feature/update-header
git push origin main# Try to merge the second branch
git merge feature/add-logo
# You'll see:
# Auto-merging header.html
# CONFLICT (content): Merge conflict in header.html
# Automatic merge failed; fix conflicts and then commit the result.
# Check the conflict
cat header.html
# Output will show conflict markers:
# <<<<<<< HEAD
# <h1>Welcome to the Todo App</h1>
# =======
# <h1><img src='logo.png'> Todo App</h1>
# >>>>>>> feature/add-logo# Option 1: Manual resolution
# Open header.html in your editor and change to:
cat > header.html << 'EOF'
<h1><img src="logo.png" alt="Logo"> Welcome to the Todo App</h1>
EOF
# Check the file
cat header.html
# Should have no conflict markers!
# Mark as resolved
git add header.html
# Check status
git status
# Should say: "All conflicts fixed but you are still merging"
# Complete the merge
git commit -m "merge: combine welcome message with logo
Resolved conflict in header.html by including both logo and welcome text"
# Push the resolution
git push origin main# Delete merged branches
git branch -d feature/update-header
git branch -d feature/add-logo
# Delete on GitHub (optional)
git push origin --delete feature/update-header
git push origin --delete feature/add-logo✅ Checkpoint: Conflict resolved successfully!
Experience a realistic team workflow with multiple features being developed simultaneously.
You're part of a 3-person team. Each person is working on a different feature. Simulate all three roles.
Create three issues for three features:
Issue A: "Add task counter"
Issue B: "Add task search functionality"
Issue C: "Add task categories"
# Create these on GitHub Issues tab
# We'll skip the detailed creation for brevity# Developer A starts working
git checkout main
git pull origin main
git checkout -b feature/task-counter
# Add counter functionality
cat > counter.js << 'EOF'
// Task Counter
function updateTaskCounter() {
const tasks = document.querySelectorAll('.task-item');
const counter = document.getElementById('task-counter');
if (counter) {
counter.textContent = `Total tasks: ${tasks.length}`;
}
}
// Initialize counter on page load
document.addEventListener('DOMContentLoaded', updateTaskCounter);
EOF
git add counter.js
git commit -m "feat: add task counter display
Shows total number of tasks in the list"
git push -u origin feature/task-counter
# Create PR on GitHub (you can do this via browser)# Meanwhile, Developer B starts (from main)
git checkout main
git checkout -b feature/task-search
# Add search functionality
cat > search.js << 'EOF'
// Task Search
function setupSearch() {
const searchInput = document.getElementById('task-search');
if (!searchInput) return;
searchInput.addEventListener('input', function(e) {
const searchTerm = e.target.value.toLowerCase();
const tasks = document.querySelectorAll('.task-item');
tasks.forEach(task => {
const text = task.textContent.toLowerCase();
if (text.includes(searchTerm)) {
task.style.display = 'block';
} else {
task.style.display = 'none';
}
});
});
}
document.addEventListener('DOMContentLoaded', setupSearch);
EOF
git add search.js
git commit -m "feat: add task search functionality
Users can now filter tasks by searching"
git push -u origin feature/task-search
# Create PR on GitHub# Developer C also starts from main
git checkout main
git checkout -b feature/task-categories
# Add category functionality
cat > categories.js << 'EOF'
// Task Categories
const CATEGORIES = ['Work', 'Personal', 'Shopping', 'Other'];
function addCategoryDropdown() {
const form = document.querySelector('.task-form');
if (!form) return;
const select = document.createElement('select');
select.id = 'task-category';
select.className = 'category-select';
CATEGORIES.forEach(category => {
const option = document.createElement('option');
option.value = category.toLowerCase();
option.textContent = category;
select.appendChild(option);
});
form.appendChild(select);
}
document.addEventListener('DOMContentLoaded', addCategoryDropdown);
EOF
git add categories.js
git commit -m "feat: add task categories
Users can categorize tasks as Work, Personal, Shopping, or Other"
git push -u origin feature/task-categories
# Create PR on GitHubAs Team Lead (or team consensus):
-
Review PR from Developer A (task-counter)
- Leave a comment: "LGTM! Simple and effective."
- Approve and merge
-
Review PR from Developer B (task-search)
- Leave feedback: "Could we add a 'clear search' button?"
- Request changes
-
Developer B addresses feedback:
git checkout feature/task-search
# Add clear button
cat >> search.js << 'EOF'
// Add clear search button
function addClearButton() {
const searchInput = document.getElementById('task-search');
const clearBtn = document.createElement('button');
clearBtn.textContent = '×';
clearBtn.className = 'clear-search';
clearBtn.onclick = () => {
searchInput.value = '';
searchInput.dispatchEvent(new Event('input'));
};
searchInput.parentNode.appendChild(clearBtn);
}
document.addEventListener('DOMContentLoaded', addClearButton);
EOF
git add search.js
git commit -m "feat: add clear search button"
git push-
Re-review and approve PR from Developer B
- "Great addition! Merging now."
- Merge
-
Review PR from Developer C (task-categories)
- This might now have conflicts with the merged changes!
git checkout feature/task-categories
# Merge main to get latest changes
git merge main
# If conflicts:
# - Resolve them
# - Test that everything works together
# - Commit the resolution
git add .
git commit -m "merge: sync with main and resolve conflicts"
git push
# PR gets updated and can now be merged✅ Checkpoint: All three features integrated successfully!
Create a simple GitHub Actions workflow:
# .github/workflows/greet.yml
name: Greet Contributors
on:
pull_request:
types: [opened]
jobs:
greet:
runs-on: ubuntu-latest
steps:
- name: Greet
run: echo "Thanks for your contribution!"Commit and push this file, then create a new PR to see it in action!
Create an issue template:
# .github/ISSUE_TEMPLATE/feature_request.md
---
name: Feature Request
about: Suggest a new feature
title: '[FEATURE] '
labels: 'enhancement'
assignees: ''
---
## Feature Description
[Describe the feature you'd like to see]
## Use Case
[Why would this be useful?]
## Proposed Solution
[How do you envision this working?]# Create a branch
git checkout -b feature/rebase-practice
# Make multiple small commits
echo "line 1" > file.txt && git add . && git commit -m "Add line 1"
echo "line 2" >> file.txt && git add . && git commit -m "Add line 2"
echo "line 3" >> file.txt && git add . && git commit -m "Add line 3"
# Interactive rebase to squash commits
git rebase -i HEAD~3
# In the editor, change 'pick' to 'squash' for last 2 commitsConfirm you've completed:
- Created 3+ GitHub Issues with proper descriptions
- Used feature branches for all development
- Created and merged at least one Pull Request
- Practiced code review (even if self-review)
- Resolved a merge conflict successfully
- Simulated team collaboration workflow
- Cleaned up merged branches
- Understand the complete Git/GitHub workflow
GitHub Issues:
- Writing clear, actionable issues
- Using labels and assignments
- Linking issues to PRs
Branch Workflow:
- Creating feature branches
- Making atomic commits
- Pushing branches to GitHub
Pull Requests:
- Writing comprehensive PR descriptions
- Conducting code reviews
- Addressing feedback constructively
Merge Conflicts:
- Understanding conflict markers
- Resolving conflicts manually
- Testing after resolution
Team Collaboration:
- Coordinating multiple developers
- Integrating concurrent features
- Professional communication patterns
Want more practice? Try these:
-
Fork a real open-source project
- Find a "good first issue"
- Follow their contribution guidelines
- Submit a real PR!
-
Collaborate with a friend
- Both fork the same repository
- Make conflicting changes
- Practice resolving together
-
Explore advanced Git
git cherry-pick- Apply specific commitsgit bisect- Find where bugs were introducedgit stash- Temporarily save work
-
Set up a team project
- Create a real project with friends
- Use GitHub Projects board
- Practice the full workflow
Can't push to GitHub:
# Make sure you're pushing to your fork
git remote -v
# Should show YOUR_USERNAME, not tfdevs
# If wrong, update:
git remote set-url origin https://github.com/YOUR_USERNAME/repo.gitMerge conflict too complex:
# Abort the merge and try again
git merge --abort
# Or get help:
git status # See what's conflicted
# Open files in VS Code for visual merge toolsLost work:
# Git rarely loses anything
git reflog # See all your actions
# Find your commit and restore:
git checkout <commit-hash>
git checkout -b recovery-branchStuck? Here's how to get help:
- Check Git status:
git statusoften tells you what to do - Read error messages: They usually explain the problem
- Use Git docs:
git help <command> - Ask in workshops: Use the discussion forum
- Google the error: Likely someone else had the same issue
You've completed the Git & GitHub Team Workflow hands-on lab! You now have practical experience with:
- Professional Git workflows
- GitHub collaboration features
- Team development practices
Keep practicing these workflows in your projects!
Previous: Workshop Content | Back to: Workshop README