Skip to content

Instantly share code, notes, and snippets.

@AndrewAltimit
Last active July 7, 2025 09:34
Show Gist options
  • Save AndrewAltimit/2ffad7aaf881ba14f4bd0f6aedbfe49b to your computer and use it in GitHub Desktop.
Save AndrewAltimit/2ffad7aaf881ba14f4bd0f6aedbfe49b to your computer and use it in GitHub Desktop.

Git Workflow Guide

Git Workflow Diagram

Diagram credit: nikkiandchris.io (@nikki.and.chris, @NikkiSiapno, @ChrisStaud)

A visual guide to understanding Git's core workflow and the relationship between your working directory, staging area, local repository, and remote repository.

GitFourAreas

Initial Git Setup

Before using Git, you need to configure it properly:

Required Configuration

# Set your identity (required for commits)
git config --global user.name "Your Full Name"
git config --global user.email "[email protected]"

# Verify your configuration
git config --global --list

SSH Key Setup (Recommended)

SSH keys provide secure authentication without entering passwords:

# Generate SSH key pair
ssh-keygen -t ed25519 -C "[email protected]"
# Press Enter for default location (~/.ssh/id_ed25519)
# Optionally set a passphrase

# Add key to SSH agent
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

# Copy public key to clipboard (macOS)
pbcopy < ~/.ssh/id_ed25519.pub

# Copy public key to clipboard (Linux)
cat ~/.ssh/id_ed25519.pub | xclip -selection clipboard

# Copy public key to clipboard (Windows)
type %USERPROFILE%\.ssh\id_ed25519.pub | clip

Add the public key to your Git platform:

  • GitHub: Settings → SSH and GPG keys → New SSH key
  • GitLab: Preferences → SSH Keys → Add key
  • Bitbucket: Personal settings → SSH keys → Add key

Test your SSH connection:

# Test GitHub connection
ssh -T [email protected]

# Test GitLab connection  
ssh -T [email protected]

Git Ignore: Excluding Files from Version Control

Git tracks all files in your repository by default, but some files shouldn't be committed (temporary files, secrets, build artifacts, etc.). The .gitignore file tells Git which files to ignore.

GitIgnoreDemo

Creating a .gitignore File

# Create .gitignore in your repository root
touch .gitignore

# Edit with your preferred editor
code .gitignore
vim .gitignore

Common .gitignore Patterns

Basic syntax:

# This is a comment

# Ignore specific file
secret.txt

# Ignore all files with extension
*.log
*.tmp
*.cache

# Ignore entire directory
node_modules/
build/
.env/

# Ignore files in any directory
**/temp.txt

# Ignore files only in root directory
/config.local

# Negate a rule (don't ignore this file)
!important.log

Real-world examples:

Node.js project:

# Dependencies
node_modules/
npm-debug.log*

# Environment variables
.env
.env.local

# Build output
dist/
build/

# IDE files
.vscode/
.idea/

# OS files
.DS_Store
Thumbs.db

Python project:

# Python cache
__pycache__/
*.pyc
*.pyo

# Virtual environment
venv/
env/
.env

# IDE
.vscode/
.idea/

# Jupyter notebooks checkpoints
.ipynb_checkpoints/

Java project:

# Compiled class files
*.class

# Build directories
target/
build/

# IDE files
.idea/
.eclipse/
*.iml

# OS files
.DS_Store

Important .gitignore Rules

Files you should typically ignore:

  • Secrets: API keys, passwords, certificates
  • Dependencies: node_modules/, vendor/, package files
  • Build artifacts: dist/, build/, compiled files
  • IDE files: .vscode/, .idea/, workspace files
  • OS files: .DS_Store, Thumbs.db, desktop.ini
  • Logs: *.log, debug files
  • Temporary files: *.tmp, *.cache, backup files

Working with .gitignore

Check what's being ignored:

# See which files are ignored
git status --ignored

# Check if specific file is ignored
git check-ignore -v filename.txt

Already committed files:

# If you accidentally committed a file that should be ignored
git rm --cached filename.txt
git commit -m "Remove file from tracking"

# For directories
git rm -r --cached directory/
git commit -m "Remove directory from tracking"

Global .gitignore:

# Create global gitignore for your machine
git config --global core.excludesfile ~/.gitignore_global

# Add common files you never want to commit
echo ".DS_Store" >> ~/.gitignore_global
echo "*.tmp" >> ~/.gitignore_global

.gitignore Best Practices

Do ignore:

  • Environment-specific files (.env, config files with secrets)
  • Build artifacts and compiled files
  • Package manager directories (node_modules/, vendor/)
  • IDE and editor files
  • OS-generated files
  • Log files and temporary files

Don't ignore:

  • Source code files
  • Configuration templates (.env.example)
  • Documentation files
  • Package manager lock files (package-lock.json, Gemfile.lock)

Pro tips:

  • Add .gitignore early in your project
  • Use templates from gitignore.io for your tech stack
  • Commit your .gitignore file so the whole team uses the same rules
  • Be specific rather than overly broad with patterns

Template Resources

Quick setup:

# Generate .gitignore for your tech stack
curl -o .gitignore https://www.toptal.com/developers/gitignore/api/node,python,java,visualstudiocode

# Or visit gitignore.io and search for your languages/tools

GitHub templates: GitHub provides .gitignore templates when creating repositories for popular languages and frameworks.

Git LFS (Large File Storage)

For repositories with large files (images, videos, datasets, binaries):

# Install Git LFS (if not already installed)
# macOS: brew install git-lfs
# Ubuntu: sudo apt install git-lfs
# Windows: Download from git-lfs.github.io

# Initialize LFS in your user account
git lfs install

# Track large file types in your repository
git lfs track "*.jpg"
git lfs track "*.png" 
git lfs track "*.mp4"
git lfs track "*.zip"
git lfs track "*.pdf"

# The above commands create/update .gitattributes file
git add .gitattributes
git commit -m "Track large files with LFS"

# Check what's being tracked
git lfs track

# View LFS file info
git lfs ls-files

When to use Git LFS:

  • Files larger than 100MB (GitHub's limit)
  • Binary files that change frequently
  • Media files (images, videos, audio)
  • Compiled binaries or archives
  • Large datasets

Additional Useful Configuration

# Set default branch name
git config --global init.defaultBranch main

# Set default editor (optional)
git config --global core.editor "code --wait"  # VS Code
git config --global core.editor "vim"          # Vim

# Enable colored output
git config --global color.ui auto

# Set up credential helper (HTTPS only)
git config --global credential.helper store    # Stores credentials in plain text
git config --global credential.helper cache    # Caches for 15 minutes

# Configure line endings (important for cross-platform teams)
git config --global core.autocrlf input        # macOS/Linux
git config --global core.autocrlf true         # Windows

Verify Your Setup

# Check all global configuration
git config --global --list

# Test with a new repository
mkdir test-repo
cd test-repo
git init
echo "Hello Git" > README.md
git add README.md
git commit -m "Initial commit"

# Should show your name and email in the commit
git log --oneline

The Four Areas of Git

1. Working Directory

Your project files as they exist on your file system. This is where you make changes, edit files, and create new content.

2. Staging Area (Index)

A holding area for changes that are ready to be committed. Think of it as a "draft" of your next commit.

3. Local Repository

Your local Git database containing all commits, branches, and history stored in the .git folder.

4. Remote Repository

The shared repository (e.g., on GitHub, GitLab, Bitbucket) where your team collaborates.

Core Git Commands Flow

Moving Changes Forward

# Stage changes from working directory to staging area
git add <file>          # Add specific file
git add .               # Add all changes

# Commit staged changes to local repository
git commit -m "message" # Create commit with message

# Send commits to remote repository
git push                # Push to remote

Getting Changes from Remote

# Download changes without merging
git fetch               # Updates local repo with remote changes

# Download and merge changes
git pull                # Equivalent to git fetch + git merge

Working with Stash

The stash is a temporary storage area for uncommitted changes:

GitStashDemo

# Save current changes to stash
git stash               # Stash with auto-generated message
git stash save "WIP: working on login feature"  # Stash with custom message

# Apply stashed changes back
git stash apply         # Apply most recent stash
git stash pop           # Apply and remove most recent stash

# List all stashes (shows like this)
git stash list
# Output example:
# stash@{0}: WIP on feature-branch: 1a2b3c4 Add user validation
# stash@{1}: On main: 5d6e7f8 Fix header styling
# stash@{2}: WIP: working on login feature

# Apply specific stash by index
git stash apply stash@{1}
git stash pop stash@{0}

# See what's in a stash without applying
git stash show stash@{0}        # Summary of changes
git stash show -p stash@{0}     # Full diff

# Delete specific stash
git stash drop stash@{1}

# Clear all stashes
git stash clear

Stash identification tips:

  • Most recent stash is always stash@{0}
  • Stashes include branch name and last commit message
  • Use descriptive messages: git stash save "fixing CSS before switching to bug branch"
  • git stash show lets you preview before applying

Common Workflow Patterns

Basic Development Flow

  1. Make changes in working directory
  2. git add to stage changes
  3. git commit to save to local repository
  4. git push to share with team

Before Starting Work

git pull                # Get latest changes from remote
# Make your changes
git add .
git commit -m "Your changes"
git push

Using Stash for Context Switching

# You're working on feature A, but need to switch to fix a bug
git stash               # Save current work
git checkout main       # Switch to main branch
# Fix the bug, commit, push
git checkout feature-a  # Back to your feature
git stash pop           # Restore your work

Best Practices

  • Commit often: Make small, logical commits with clear messages
  • Pull before push: Always git pull before pushing to avoid conflicts
  • Use stash wisely: Great for temporarily saving work when switching contexts
  • Stage selectively: Use git add <file> to stage only related changes together

Visual Reference

The diagram shows how each command moves your code between the different areas:

  • Rightward arrows: Moving code toward the remote (add → commit → push)
  • Leftward arrows: Getting code from remote (pull, fetch)
  • Stash operations: Temporary storage for work-in-progress

Git Branching Strategies

Beyond the basic workflow, teams use different branching strategies to organize their development process:

GitBranchingStrategies

1. Gitflow without environment branches

main ← feature-branch-1
     ← feature-branch-2
     ← feature-branch-3

Simple and effective for continuous deployment:

# Start new feature
git checkout main
git pull
git checkout -b feature/user-authentication

# Develop feature
# ... make changes, add, commit ...

# Push and create pull request
git push -u origin feature/user-authentication
# Create PR to merge into main
# After review, merge to main

Best for: Small teams, continuous deployment, rapid iterations

2. Gitflow with environment branches

main ← test ← develop ← feature-branch-1
                     ← feature-branch-2
                     ← feature-branch-3

Structured approach with quality gates:

# Start feature from develop
git checkout develop
git pull
git checkout -b feature/payment-system

# Develop feature
# ... make changes, add, commit ...

# Merge to develop
git checkout develop
git merge feature/payment-system

# When ready for testing
git checkout test
git merge develop

# After QA approval
git checkout main
git merge test
git tag v1.2.0  # Tag the release

Branch purposes:

  • main: Production-ready code only
  • test: Pre-production testing and QA
  • develop: Integration of all features
  • feature/*: Individual feature development

Best for: Larger teams, formal QA process, scheduled releases

3. Classic Gitflow

main ← release ← develop ← feature branches
     ← hotfix branches

Full Gitflow with release branches:

  • main: Production releases
  • develop: Integration branch
  • feature/*: New features
  • release/*: Preparing releases (bug fixes only)
  • hotfix/*: Emergency production fixes

Best for: Complex projects with formal release cycles

4. Trunk-based Development

main (trunk) ← very short-lived feature branches

High-velocity approach:

  • Everyone commits to main frequently (multiple times daily)
  • Feature branches live for hours/1-2 days maximum
  • Heavy use of feature flags to hide incomplete features
  • Requires excellent CI/CD and automated testing

Best for: High-velocity teams with strong automation

5. GitLab Flow

main ← feature branches
     ↓
staging ← (deploy by merging)
        ↓
production

Environment-based deployments:

  • Deploy by merging between environment branches
  • Can have multiple environment branches
  • Combines simplicity with deployment control

Choosing the Right Strategy

Consider these factors:

Team Size & Experience:

  • Small team (2-5): Feature Branch Workflow
  • Medium team (5-15): Gitflow with Testing Branch
  • Large team (15+): Classic Gitflow or Trunk-based

Release Frequency:

  • Continuous deployment: Feature Branch or Trunk-based
  • Weekly/monthly releases: Gitflow variations
  • Scheduled releases: Classic Gitflow

Quality Requirements:

  • High-risk applications: Gitflow with testing stages
  • Rapid prototyping: Feature Branch Workflow
  • Enterprise software: Classic Gitflow

Automation Level:

  • High automation: Trunk-based Development
  • Manual testing: Gitflow variations
  • Mixed: Feature Branch with CI/CD

Branch Naming Conventions

# Feature branches
feature/user-authentication
feature/payment-integration
feat/dashboard-redesign

# Bug fixes
bugfix/login-validation
fix/memory-leak

# Hotfixes
hotfix/security-patch
hotfix/v1.2.1

# Release branches (if using Gitflow)
release/v1.3.0
release/2024-q1

Git Rebase: Rewriting History

Rebase is a powerful tool that allows you to rewrite commit history for a cleaner project timeline.

Merge vs Rebase

Scenario: You're working on a feature branch, but main has moved forward with new commits.

Before (your situation):

main:     A---B---C---F---G  (main moved forward while you worked)
               \
feature:        D---E        (your feature commits)

Option 1 - Merge main into feature:

main:     A---B---C---F---G
               \         \
feature:        D---E---M  (merge commit M combines both)

Option 2 - Rebase your feature branch to catch up:

feature:  A---B---C---F---G---D'---E'  (your commits moved to new base)
main:     A---B---C---F---G            (main unchanged)

What rebase does: Takes your commits (D, E) and replays them on top of the latest main (after G), creating new commits (D', E') with the same changes but different commit hashes. Your feature branch is now up-to-date with main.

Common Rebase Operations

Rebase Feature Branch

Update your feature branch with latest main (this is probably what you've done):

# You're on your feature branch, main has moved forward
git checkout feature-branch
git fetch origin                    # Get latest changes
git rebase origin/main             # Replay your commits on top of latest main

# Or if you have local main up to date
git rebase main feature-branch

Common scenario: You made commits on your feature branch, but someone else pushed to main (or you made changes in GitHub UI). Rebasing puts your feature commits on top of the latest main.

Interactive Rebase on Same Branch

Clean up your own commits before pushing:

# Clean up your last 3 commits on current branch
git rebase -i HEAD~3

# This is useful when you have commits like:
# - "Add user login"
# - "Fix typo"  
# - "Actually fix the typo"
# - "Add validation"

# You can squash the typo fixes into the main commits

Rebase vs Merge Decision

Use Rebase when:

  • Cleaning up local commits before pushing
  • Creating linear history for features
  • You haven't shared the commits yet (local only)

Use Merge when:

  • Preserving the true history of development
  • Working with shared/public branches
  • Merging completed features

Golden Rule: Never rebase commits that have been pushed to shared repositories unless your team explicitly agrees to it.

Handling Merge Conflicts

Conflicts occur when Git can't automatically merge changes. Here's how to resolve them:

GitMergeConflict

When Conflicts Happen

# During merge
git merge feature-branch
# Auto-merging failed; fix conflicts and then commit

# During rebase
git rebase main
# CONFLICT: Merge conflict in file.txt

Conflict Resolution Process

1. Identify conflicted files:

git status
# Shows files with conflicts in red

2. Open conflicted files and look for markers:

<<<<<<< HEAD
Your current branch content
=======
The incoming change content
>>>>>>> feature-branch

3. Resolve conflicts by editing the file:

# Remove conflict markers and choose/combine content
Final resolved content here

4. Mark conflicts as resolved:

git add <resolved-file>

5. Complete the merge/rebase:

# For merge
git commit

# For rebase
git rebase --continue

Advanced Conflict Resolution

Use merge tools:

# Configure a merge tool (like VS Code)
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'

# Use the tool during conflicts
git mergetool

Abort if needed:

# Abort merge
git merge --abort

# Abort rebase
git rebase --abort

View conflict details:

# See what caused the conflict
git diff

# See both sides of the conflict
git log --merge --oneline

Best Practices for Avoiding Conflicts

Prevention strategies:

  • Pull frequently from main branch
  • Keep feature branches small and short-lived
  • Communicate with team about file changes
  • Use consistent code formatting

During conflicts:

  • Don't panic - conflicts are normal
  • Take time to understand both changes
  • Test your resolution before committing
  • Ask for help if you're unsure about the intent of conflicting changes

Example conflict resolution workflow:

# Working on feature branch
git checkout feature/new-header
git rebase main
# CONFLICT in header.html

# 1. Check what's conflicted
git status

# 2. Open header.html, see:
# <<<<<<< HEAD
# <h1>Welcome to Our Site</h1>
# =======
# <h1>Welcome to My Amazing Site</h1>
# >>>>>>> feature/new-header

# 3. Decide on resolution:
# <h1>Welcome to Our Amazing Site</h1>

# 4. Mark as resolved
git add header.html

# 5. Continue rebase
git rebase --continue
#!/usr/bin/env python3
"""
Git Workflow Animations for the Git Guide
Creates visual animations explaining key Git concepts
"""
from manim import *
class GitFourAreas(Scene):
"""Animation showing the four areas of Git and command flow"""
def construct(self):
# Set camera frame height to reduce vertical space
self.camera.frame_height = 6
# Title
title = Text("The Four Areas of Git", font_size=36, color=BLUE)
self.play(Write(title))
self.wait(1)
self.play(FadeOut(title))
# Create the four areas (reduced height)
working_dir = RoundedRectangle(
width=2.5, height=1.5,
color=GREEN,
fill_opacity=0.3
).shift(LEFT * 4 + UP * 0.5)
wd_label = Text("Working\nDirectory", font_size=18).move_to(working_dir)
staging = RoundedRectangle(
width=2.5, height=1.5,
color=YELLOW,
fill_opacity=0.3
).shift(LEFT * 1.3 + UP * 0.5)
staging_label = Text("Staging\nArea", font_size=18).move_to(staging)
local_repo = RoundedRectangle(
width=2.5, height=1.5,
color=ORANGE,
fill_opacity=0.3
).shift(RIGHT * 1.3 + UP * 0.5)
local_label = Text("Local\nRepository", font_size=18).move_to(local_repo)
remote_repo = RoundedRectangle(
width=2.5, height=1.5,
color=RED,
fill_opacity=0.3
).shift(RIGHT * 4 + UP * 0.5)
remote_label = Text("Remote\nRepository", font_size=18).move_to(remote_repo)
# Animate areas appearing
self.play(
Create(working_dir), Write(wd_label),
Create(staging), Write(staging_label),
Create(local_repo), Write(local_label),
Create(remote_repo), Write(remote_label),
run_time=2
)
self.wait(1)
# Add commands between areas - all arrows go to the right
add_arrow = Arrow(
working_dir.get_right(),
staging.get_left(),
color=WHITE,
stroke_width=3,
buff=0.1
)
add_text = Text("git add", font_size=16, color=WHITE).next_to(add_arrow, UP, buff=0.1)
commit_arrow = Arrow(
staging.get_right(),
local_repo.get_left(),
color=WHITE,
stroke_width=3,
buff=0.1
)
commit_text = Text("git commit", font_size=16, color=WHITE).next_to(commit_arrow, UP, buff=0.1)
push_arrow = Arrow(
local_repo.get_right(),
remote_repo.get_left(),
color=WHITE,
stroke_width=3,
buff=0.1
)
push_text = Text("git push", font_size=16, color=WHITE).next_to(push_arrow, UP, buff=0.1)
# Pull/fetch arrows (bottom) - goes from remote all the way to working directory
pull_arrow = Arrow(
remote_repo.get_left(),
working_dir.get_right(),
color=BLUE_C,
stroke_width=3,
buff=0.1
).shift(DOWN * 1.2)
pull_text = Text("git pull/fetch", font_size=16, color=BLUE_C).next_to(pull_arrow, DOWN, buff=0.1)
# Show commands
self.play(
Create(add_arrow), Write(add_text),
Create(commit_arrow), Write(commit_text),
Create(push_arrow), Write(push_text),
Create(pull_arrow), Write(pull_text),
run_time=2
)
# Demonstrate file movement - position lower and label to the right
file_icon = Circle(radius=0.15, color=WHITE, fill_opacity=1)
file_icon.move_to(working_dir.get_center() + DOWN * 0.3)
file_label = Text("file.txt", font_size=12, color=YELLOW)
file_label.next_to(file_icon, RIGHT, buff=0.1)
file_group = VGroup(file_icon, file_label)
self.play(Create(file_group))
self.wait(1)
# Move through the workflow - keep file at same vertical level
file_y_level = working_dir.get_center()[1] + DOWN * 0.3 # Remember the vertical position
# git add
self.play(
file_group.animate.move_to(staging.get_center() + DOWN * 0.3),
add_arrow.animate.set_color(GREEN),
add_text.animate.set_color(GREEN),
run_time=1.5
)
self.wait(0.5)
self.play(
add_arrow.animate.set_color(WHITE),
add_text.animate.set_color(WHITE)
)
# git commit
self.play(
file_group.animate.move_to(local_repo.get_center() + DOWN * 0.3),
commit_arrow.animate.set_color(YELLOW),
commit_text.animate.set_color(YELLOW),
run_time=1.5
)
self.wait(0.5)
self.play(
commit_arrow.animate.set_color(WHITE),
commit_text.animate.set_color(WHITE)
)
# git push
self.play(
file_group.animate.move_to(remote_repo.get_center() + DOWN * 0.3),
push_arrow.animate.set_color(ORANGE),
push_text.animate.set_color(ORANGE),
run_time=1.5
)
self.wait(0.5)
self.play(
push_arrow.animate.set_color(WHITE),
push_text.animate.set_color(WHITE)
)
self.wait(2)
class GitStashDemo(Scene):
"""Animation demonstrating git stash workflow"""
def construct(self):
# Set camera frame height to reduce vertical space even more
self.camera.frame_height = 5
# Title
title = Text("Git Stash: Saving Work Temporarily", font_size=32, color=BLUE)
self.play(Write(title))
self.wait(1)
self.play(FadeOut(title))
# Create areas
working_dir = RoundedRectangle(
width=3, height=2,
color=GREEN,
fill_opacity=0.3
).shift(LEFT * 3 + UP * 0.3)
wd_label = Text("Working Directory", font_size=18).next_to(working_dir, UP, buff=0.15)
stash_area = RoundedRectangle(
width=3, height=2,
color=PURPLE,
fill_opacity=0.3
).shift(RIGHT * 3 + UP * 0.3)
stash_label = Text("Stash", font_size=18).next_to(stash_area, UP, buff=0.15)
self.play(
Create(working_dir), Write(wd_label),
Create(stash_area), Write(stash_label)
)
# Create work in progress
wip_file = Rectangle(width=1.8, height=0.5, color=YELLOW, fill_opacity=0.7)
wip_label = Text("WIP: login.js", font_size=14, color=BLACK)
wip_label.move_to(wip_file)
wip_group = VGroup(wip_file, wip_label).move_to(working_dir)
self.play(FadeIn(wip_group))
self.wait(1)
# Show interruption - raise text higher
interrupt = Text("! URGENT: Bug fix needed!", font_size=20, color=RED)
interrupt.to_edge(DOWN).shift(UP * 1.7)
self.play(Write(interrupt))
self.wait(1)
# Stash the work
stash_arrow = Arrow(
working_dir.get_right(),
stash_area.get_left(),
color=PURPLE,
stroke_width=3
)
stash_cmd = Text("git stash", font_size=16, color=PURPLE).next_to(stash_arrow, UP, buff=0.2)
self.play(Create(stash_arrow), Write(stash_cmd))
self.play(
wip_group.animate.move_to(stash_area),
run_time=1.5
)
self.play(FadeOut(stash_arrow), FadeOut(stash_cmd))
# Work on bug fix
self.play(FadeOut(interrupt))
bug_file = Rectangle(width=1.8, height=0.5, color=RED, fill_opacity=0.7)
bug_label = Text("bugfix.js", font_size=14, color=WHITE)
bug_label.move_to(bug_file)
bug_group = VGroup(bug_file, bug_label).move_to(working_dir)
fix_text = Text("Fix bug → commit → push", font_size=18, color=WHITE)
fix_text.to_edge(DOWN).shift(UP * 1.7)
self.play(FadeIn(bug_group), Write(fix_text))
self.wait(1)
self.play(FadeOut(bug_group), FadeOut(fix_text))
# Restore stashed work
pop_arrow = Arrow(
stash_area.get_left(),
working_dir.get_right(),
color=GREEN,
stroke_width=3
)
pop_cmd = Text("git stash pop", font_size=16, color=GREEN).next_to(pop_arrow, UP, buff=0.2)
self.play(Create(pop_arrow), Write(pop_cmd))
self.play(
wip_group.animate.move_to(working_dir),
run_time=1.5
)
restore_text = Text("✓ Back to working on login feature", font_size=18, color=GREEN)
restore_text.to_edge(DOWN).shift(UP * 1.7)
self.play(Write(restore_text))
self.wait(2)
class GitBranchingStrategies(Scene):
"""Animation showing different branching strategies"""
def construct(self):
# Use default camera height for this animation to show all content
# self.camera.frame_height = 8 # Default height
# Title
title = Text("Git Branching Strategies", font_size=36, color=BLUE)
self.play(Write(title))
self.wait(1)
self.play(FadeOut(title))
# Feature Branch Workflow
subtitle1 = Text("Gitflow without Environment Branches", font_size=28, color=YELLOW)
subtitle1.to_edge(UP)
self.play(Write(subtitle1))
# Main branch
main_line = Line(LEFT * 5, RIGHT * 5, color=WHITE, stroke_width=3)
main_label = Text("main", font_size=18).next_to(main_line, LEFT)
self.play(Create(main_line), Write(main_label))
# Feature branches being squashed into main
for i, (name, color) in enumerate([
("feature/auth", GREEN),
("feature/ui", BLUE),
("feature/api", ORANGE)
]):
start_point = LEFT * 3 + RIGHT * i * 2
# Feature branch below main
branch = Line(
start_point,
start_point + DOWN * 1 + RIGHT * 1.5,
color=color,
stroke_width=2
)
# Squash merge back to main
merge_line = Arrow(
start_point + DOWN * 1 + RIGHT * 1.5,
start_point + RIGHT * 2.5,
color=color,
stroke_width=2,
max_tip_length_to_length_ratio=0.15
)
label = Text(name, font_size=14, color=color)
label.next_to(branch.get_center() + DOWN * 0.3, DOWN)
squash_text = Text("squash", font_size=10, color=color)
squash_text.next_to(merge_line.get_center(), RIGHT, buff=0.1)
self.play(Create(branch), Write(label))
self.wait(0.5)
self.play(Create(merge_line), Write(squash_text))
self.wait(2)
self.play(FadeOut(Group(*self.mobjects)))
# Gitflow with Test Branch
subtitle2 = Text("Gitflow with Environment Branches", font_size=28, color=YELLOW)
subtitle2.to_edge(UP)
self.play(Write(subtitle2))
# Branch levels
main_y = 0.5
test_y = -0.5
develop_y = -1.5
# Create branches with environment labels
for y, name, env_label, color in [
(main_y, "main", "PROD", RED),
(test_y, "test", "TEST", YELLOW),
(develop_y, "develop", "DEV", GREEN)
]:
line = Line(LEFT * 5, RIGHT * 5, color=color, stroke_width=3)
line.shift(UP * y)
label = Text(name, font_size=18, color=color)
label.next_to(line, LEFT)
env_text = Text(f"({env_label})", font_size=14, color=color)
env_text.next_to(label, DOWN, buff=0.1)
self.play(Create(line), Write(label), Write(env_text))
# Show feature branches merging upward
feature_y = develop_y - 1.2 # Feature branches below develop
for i in range(3):
x = LEFT * 3 + RIGHT * i * 2.5
# Create feature branch
feature_name = ["feat/login", "feat/api", "feat/ui"][i]
feature_color = [BLUE_C, PURPLE, TEAL][i]
# Feature branch line
feature_line = Line(
x + UP * feature_y,
x + UP * feature_y + RIGHT * 1,
color=feature_color,
stroke_width=2
)
feature_label = Text(feature_name, font_size=12, color=feature_color)
feature_label.next_to(feature_line, DOWN, buff=0.1)
# Feature to develop (squash merge)
squash_arrow = Arrow(
x + UP * feature_y + RIGHT * 1,
x + UP * develop_y + RIGHT * 1,
color=feature_color,
stroke_width=2,
max_tip_length_to_length_ratio=0.15
)
squash_label = Text("squash", font_size=10, color=feature_color)
squash_label.next_to(squash_arrow, RIGHT, buff=0.1)
# Develop to test (merge commit) - unique color
merge_arrow1 = Arrow(
x + UP * develop_y + RIGHT * 1.2,
x + UP * test_y + RIGHT * 1.2,
color=BLUE_D,
stroke_width=3,
max_tip_length_to_length_ratio=0.15
)
merge_label1 = Text("merge", font_size=10, color=BLUE_D)
merge_label1.next_to(merge_arrow1.get_center(), LEFT, buff=0.1)
# Test to main (merge commit) - unique color
merge_arrow2 = Arrow(
x + UP * test_y + RIGHT * 1.4,
x + UP * main_y + RIGHT * 1.4,
color=PURPLE_B,
stroke_width=3,
max_tip_length_to_length_ratio=0.15
)
merge_label2 = Text("merge", font_size=10, color=PURPLE_B)
merge_label2.next_to(merge_arrow2.get_center(), LEFT, buff=0.1)
# Animate the flow
self.play(
Create(feature_line),
Write(feature_label),
run_time=0.5
)
self.play(
Create(squash_arrow),
Write(squash_label),
run_time=0.5
)
self.play(
Create(merge_arrow1),
Write(merge_label1),
Create(merge_arrow2),
Write(merge_label2),
run_time=0.5
)
self.wait(2)
class GitMergeConflict(Scene):
"""Animation showing merge conflict resolution"""
def construct(self):
# Set camera frame height to reduce vertical space
self.camera.frame_height = 6
# Title
title = Text("Resolving Merge Conflicts", font_size=36, color=BLUE)
self.play(Write(title))
self.wait(1)
self.play(FadeOut(title))
# Create two developers
dev1 = VGroup(
Circle(radius=0.4, color=BLUE, fill_opacity=0.8),
Text("Dev 1", font_size=14, color=WHITE)
).arrange(DOWN, buff=0.05).shift(LEFT * 4.5 + UP * 1.5)
dev2 = VGroup(
Circle(radius=0.4, color=GREEN, fill_opacity=0.8),
Text("Dev 2", font_size=14, color=WHITE)
).arrange(DOWN, buff=0.05).shift(RIGHT * 4.5 + UP * 1.5)
self.play(FadeIn(dev1), FadeIn(dev2))
# Show file (make it bigger to fit code)
file_rect = Rectangle(width=5, height=2.5, color=WHITE)
file_label = Text("header.html", font_size=18).next_to(file_rect, UP, buff=0.2)
self.play(Create(file_rect), Write(file_label))
# Show original content
original = Text('<h1>Welcome</h1>', font_size=16, font="monospace")
original.move_to(file_rect)
self.play(Write(original))
self.wait(1)
# Both developers make changes
change1 = Text('<h1>Welcome to Our Site</h1>',
font_size=14, font="monospace", color=BLUE)
change1.shift(LEFT * 3 + DOWN * 1.5)
change2 = Text('<h1>Welcome to My Site</h1>',
font_size=14, font="monospace", color=GREEN)
change2.shift(RIGHT * 3 + DOWN * 1.5)
arrow1 = Arrow(dev1.get_bottom(), change1.get_top(), color=BLUE, stroke_width=2)
arrow2 = Arrow(dev2.get_bottom(), change2.get_top(), color=GREEN, stroke_width=2)
self.play(
Create(arrow1), Create(arrow2),
Write(change1), Write(change2)
)
self.wait(1)
# Show conflict
self.play(FadeOut(original))
conflict_text = VGroup(
Text('<<<<<<< HEAD', font_size=12, font="monospace", color=RED),
Text('<h1>Welcome to Our Site</h1>', font_size=12, font="monospace", color=BLUE),
Text('=======', font_size=12, font="monospace", color=RED),
Text('<h1>Welcome to My Site</h1>', font_size=12, font="monospace", color=GREEN),
Text('>>>>>>> feature', font_size=12, font="monospace", color=RED)
).arrange(DOWN, buff=0.05).move_to(file_rect)
self.play(Write(conflict_text))
conflict_label = Text("CONFLICT!", font_size=24, color=RED)
conflict_label.next_to(file_rect, DOWN, buff=0.2)
self.play(Write(conflict_label))
self.wait(2)
# Show resolution
self.play(
FadeOut(conflict_text),
FadeOut(conflict_label),
FadeOut(arrow1),
FadeOut(arrow2),
FadeOut(change1),
FadeOut(change2)
)
resolved = Text('<h1>Welcome to Our Amazing Site</h1>',
font_size=14, font="monospace", color=PURPLE)
resolved.move_to(file_rect)
resolve_label = Text("✓ Resolved!", font_size=20, color=GREEN)
resolve_label.next_to(file_rect, DOWN, buff=0.2)
self.play(Write(resolved), Write(resolve_label))
# Show git commands
commands = VGroup(
Text("git add header.html", font_size=14, font="monospace"),
Text("git commit", font_size=14, font="monospace")
).arrange(DOWN, aligned_edge=LEFT).to_edge(DOWN).shift(UP * 0.3)
self.play(Write(commands))
self.wait(2)
if __name__ == "__main__":
# Run these animations to generate output files
print("Git Workflow Animations")
print("======================")
print("Run with: manim -pql git_workflow_animations.py ClassName")
print("\nAvailable animations:")
print("- GitFourAreas: Shows the four areas of Git")
print("- GitStashDemo: Demonstrates git stash workflow")
print("- GitBranchingStrategies: Shows different branching approaches")
print("- GitMergeConflict: Shows conflict resolution")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment