Git Practice Exercises
Section 1: Basic Git Operations
Exercise 1.1: Local Repository Initialization
Objective: Initialize a fresh Git repository, create a standardized markdown readme, configure local identity settings, and record the root commit.
Procedure:
- Create a workspace directory named
core-calculator. - Initialize it as a Git repository.
- Configure local repository user name and email attributes.
- Create a
README.mdfile describing the project. - Stage the newly created file and execute the initial commit.
Commands:
## 1. Create and navigate into workspace mkdir core-calculator cd core-calculator ## 2. Initialize Git tracking database git init ## 3. Configure local repository identification git config user.name "Technical Engineer" git config user.email "engineer@enterprise.domain" ## 4. Create README file echo "# Core Calculator Project" > README.md echo "This repository contains a modular Python calculator." >> README.md ## 5. Stage and record initial snapshot git add README.md git commit -m "chore: initialize repository with project README"
Expected Console Output:
Initialized empty Git repository in /path/to/core-calculator/.git/ [main (root-commit) 4f88b2c] chore: initialize repository with project README 1 file changed, 2 insertions(+) create mode 100644 README.md
Exercise 1.2: Staging Index Mechanics
Objective: Build a multi-file Python script, make selective modifications, and practice staging specific changes while leaving other changes in the working directory.
Procedure:
- Create a
calculator.pyfile containing basic addition and subtraction functions. - Stage and commit the file.
- Append multiplication and division functions.
- Verify modified status using the status command.
- Stage the updated script, verify it is staged, and commit the changes.
Commands:
## 1. Create file with initial source code cat > calculator.py << 'EOF' def add(a: float, b: float) -> float: return a + b def subtract(a: float, b: float) -> float: return a - b EOF ## 2. Stage and commit the base file git add calculator.py git commit -m "feat: implement basic addition and subtraction functions" ## 3. Modify the file to add new functions cat >> calculator.py << 'EOF' def multiply(a: float, b: float) -> float: return a * b def divide(a: float, b: float) -> float: if b == 0: raise ZeroDivisionError("Cannot divide by zero.") return a / b EOF ## 4. Inspect working directory state git status -s ## 5. Stage and record modifications git add calculator.py git commit -m "feat: implement multiplication and division functions"
Expected Console Output:
M calculator.py [main 7a89f92] feat: implement multiplication and division functions 1 file changed, 7 insertions(+)
Exercise 1.3: Ignoring Assets via .gitignore
Objective: Configure the repository to ignore compiler artifacts, python caches, environment vaults, and user-specific configurations.
Procedure:
- Create a Python byte-cache folder
__pycache__and a private.envfile containing fake api keys. - Observe that Git flags these items as untracked.
- Create a
.gitignorefile mapping patterns to ignore these items. - Verify that Git now ignores these untracked directories and files.
- Commit the
.gitignorefile.
Commands:
## 1. Simulate byte-cache and environment vault files mkdir __pycache__ echo "compiled bytes payload" > __pycache__/calculator.pyc echo "API_KEY=super_secure_vault_value" > .env ## 2. Inspect untracked items git status -s ## 3. Create .gitignore configuration cat > .gitignore << 'EOF' __pycache__/ *.pyc .env EOF ## 4. Re-inspect status to verify ignoring logic git status -s ## 5. Track and commit the gitignore configuration itself git add .gitignore git commit -m "chore: add standard Python ignore patterns"
Expected Console Output:
?? .gitignore [main 2b34a5d] chore: add standard Python ignore patterns 1 file changed, 4 insertions(+) create mode 100644 .gitignore
Exercise 1.4: Chronological History Logging
Objective: Format, query, and search the repository history using logarithmic flags.
Procedure:
- View a compact log representation showing hashes and messages.
- Print commits along with their line statistics.
- Search for commits containing the keyword
"feat"in their messages. - Inspect who modified specific lines inside
calculator.pyusing blame annotations.
Commands:
## 1. Compact log query git log --oneline ## 2. View log with statistics git log --stat -n 2 ## 3. Filter commits by keyword git log --grep="feat" --oneline ## 4. Annotate calculator.py file changes git blame calculator.py
Exercise 1.5: Undoing Local Mistakes
Objective: Practice reverting modifications in the working directory and un-staging files in the index safely.
Procedure:
- Modify
calculator.pyto insert broken code. - Discard these unstaged modifications to restore the file to the last committed state.
- Modify the file again, stage the changes, and then unstage them back to the working directory without losing modifications.
Commands:
## 1. Introduce broken syntax code echo "def broken_code_syntax_error():" >> calculator.py git status -s ## 2. Discard unstaged changes in working directory git restore calculator.py ## 3. Introduce modifications and stage them echo "# Updated module metadata" >> calculator.py git add calculator.py git status -s ## 4. Unstage changes back to working directory git restore --staged calculator.py git status -s ## 5. Discard changes to restore clean state git restore calculator.py
Expected Console Output:
M calculator.py M calculator.py M calculator.py
Section 2: Branching and Merging
Exercise 2.1: Independent Feature Branches
Objective: Create and switch branches, making isolated updates that do not impact the stable master branch history.
Procedure:
- Create and switch to a branch named
feature/modulus. - Add a
modulus(a, b)function tocalculator.py. - Commit this change to the feature branch.
- Switch back to the
mainbranch and verify that the modulus code is not present onmain.
Commands:
## 1. Create and checkout feature branch git checkout -b feature/modulus ## 2. Append modulus code cat >> calculator.py << 'EOF' def modulus(a: int, b: int) -> int: return a % b EOF ## 3. Stage and commit feature code git add calculator.py git commit -m "feat: implement modulo division function" ## 4. Switch back to main branch git checkout main ## 5. Verify file remains unmodified in main grep -q "modulus" calculator.py || echo "Modulus code absent in main."
Expected Console Output:
Switched to a new branch 'feature/modulus' [feature/modulus f829d10] feat: implement modulo division function 1 file changed, 3 insertions(+) Switched to branch 'main' Modulus code absent in main.
Exercise 2.2: Fast-Forward Merges
Objective: Perform a fast-forward merge to integrate the isolated feature branch into the base branch without creating an extra merge commit.
Procedure:
- Ensure you are on the
mainbranch. - Verify that
mainhas not diverged since the feature branch was created. - Merge
feature/modulusintomain. - Inspect the commit history to verify a linear timeline.
Commands:
## 1. Merge feature/modulus into main git merge feature/modulus ## 2. Inspect log to verify linear history git log --oneline --graph -n 3
Expected Console Output:
Updating 7a89f92..f829d10 Fast-forward calculator.py | 3 +++ 1 file changed, 3 insertions(+) * f829d10 feat: implement modulo division function * 7a89f92 feat: implement multiplication and division functions * 4f88b2c chore: initialize repository with project README
Exercise 2.3: Diverged History & 3-Way Merges
Objective: Simulate a diverged commit history by making modifications to both branches concurrently, resulting in a three-way merge commit upon integration.
Procedure:
- Create a new branch named
feature/comments. - Modify
calculator.pyon thefeature/commentsbranch to add comments, then commit the change. - Switch back to the
mainbranch. - Modify
calculator.pyon themainbranch to add a different comment in the same file (but on a different line), then commit the change. - Merge the feature branch into
mainand examine the commit log.
Commands:
## 1. Create and switch to comments branch git checkout -b feature/comments ## 2. Modify top line on feature branch sed -i '1s/^/# Core calculator implementation\n/' calculator.py git add calculator.py git commit -m "docs: add top file comments to calculator script" ## 3. Switch back to main branch git checkout main ## 4. Modify bottom line on main branch echo "# End of calculations module" >> calculator.py git add calculator.py git commit -m "docs: add trailing comment mark to calculator" ## 5. Merge feature branch (triggers three-way merge commit) git merge feature/comments --no-edit ## 6. Inspect history graph git log --oneline --graph --all -n 5
Expected Console Output:
[feature/comments a829b3c] docs: add top file comments to calculator script [main b923d4e] docs: add trailing comment mark to calculator Merge made by the 'ort' strategy. * e92b34a Merge branch 'feature/comments' |\ | * a829b3c docs: add top file comments to calculator script * | b923d4e docs: add trailing comment mark to calculator |/ * f829d10 feat: implement modulo division function
Exercise 2.4: Merge Conflict Resolution
Objective: Resolve a merge conflict step-by-step when changes overlap on the same lines.
Procedure:
- Create a branch named
feature/conflict. - Modify a specific line in
calculator.pyand commit the change. - Switch back to the
mainbranch. - Modify that same line differently on
mainand commit the change. - Attempt to merge
feature/conflictintomain, then resolve the conflict markers manually. - Stage the resolved files and complete the commit.
Commands:
## 1. Create conflict branch git checkout -b feature/conflict ## 2. Modify addition function on conflict branch sed -i 's/return a + b/return a + b # feature modification/' calculator.py git add calculator.py git commit -m "style: modify addition return comments on feature" ## 3. Switch back to main branch git checkout main ## 4. Modify addition function differently on main sed -i 's/return a + b/return a + b # main modification/' calculator.py git add calculator.py git commit -m "style: modify addition return comments on main" ## 5. Attempt merge (triggers conflict) git merge feature/conflict ## 6. Manually edit file to resolve conflict markers, keeping combined comments: ## return a + b # main and feature modification cat > calculator.py << 'EOF' ## Core calculator implementation def add(a: float, b: float) -> float: return a + b # resolved modification def subtract(a: float, b: float) -> float: return a - b def multiply(a: float, b: float) -> float: return a * b def divide(a: float, b: float) -> float: if b == 0: raise ZeroDivisionError("Cannot divide by zero.") return a / b def modulus(a: int, b: int) -> int: return a % b ## End of calculations module EOF ## 7. Stage and complete merge commit git add calculator.py git commit -m "chore: resolve merge conflict on addition function comments"
Expected Console Output:
Auto-merging calculator.py CONFLICT (content): Merge conflict in calculator.py Automatic merge failed; fix conflicts and then commit the result. [main d829d3c] chore: resolve merge conflict on addition function comments
Exercise 2.5: Branch Housekeeping
Objective: Clean up local branches and manage branch lifecycles.
Procedure:
- List all active local branches.
- Delete branches that have already been merged.
- Rename an existing branch.
Commands:
## 1. List branches git branch ## 2. Delete merged branches git branch -d feature/modulus git branch -d feature/comments ## 3. Attempt deleting an unmerged branch (will fail safely) git branch -d feature/conflict ## 4. Rename current branch main to master (if desired, then rename back) git branch -m main master git branch -m master main
Section 3: Remote Synchronization & Collaboration
Exercise 3.1: Remote Setup & Configuration
Objective: Connect a local repository to a remote repository configuration.
Procedure:
- Configure a mock remote repository named
origin. - Inspect remote configurations and tracking addresses.
- Rename remote repositories.
Commands:
## 1. Add mock remote URL git remote add origin https://github.com/engineer/core-calculator.git ## 2. Verify remotes list git remote -v ## 3. Rename remote configuration git remote rename origin upstream git remote -v ## 4. Restore original name git remote rename upstream origin
Exercise 3.2: Pushing Branches and Upstream Tracking
Objective: Upload local branches to remote servers, establishing tracking paths.
Procedure:
- Push the local
mainbranch to the remote repository. - Set up upstream tracking so that future pushes do not require explicit remote branch parameters.
Commands:
## Push and set upstream tracking (mock verification dry-run) git push -u origin main --dry-run
Exercise 3.3: Fetching and Rebasing
Objective: Retrieve remote commit metadata without modifying the local workspace, and replay local commits on top of updated upstream branches.
Procedure:
- Fetch remote tracking branch definitions.
- Rebase the current local branch on top of
origin/mainto maintain a linear commit history.
Commands:
## 1. Download metadata updates git fetch origin ## 2. Rebase current local branch onto remote tracking branch git rebase origin/main
Exercise 3.4: Stashing Working Directory States
Objective: Save work-in-progress modifications to the stash index, switch context, and then restore modifications.
Procedure:
- Modify
calculator.pyto add incomplete code. - Save these changes to the stash, returning the working directory to a clean state.
- List the saved stashes.
- Pop the stashed changes back into the working directory.
Commands:
## 1. Make incomplete modification echo "# Incomplete feature code WIP" >> calculator.py git status -s ## 2. Save changes to stash git stash save "WIP: mathematical optimization" git status -s ## 3. List active stashes git stash list ## 4. Restore stashed changes git stash pop
Expected Console Output:
M calculator.py Saved working directory and index state WIP: mathematical optimization On branch main nothing to commit, working tree clean stash@{0}: On main: WIP: mathematical optimization On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: calculator.py Dropped stash@{0} (6b7b2f0a1c)
Exercise 3.5: Tagging Release Milestones
Objective: Create annotated tags to mark key stable milestones in the repository history.
Procedure:
- Create an annotated tag named
v1.0.0at the current commit. - Show detailed metadata linked to the tag.
- List all tags in the repository.
Commands:
## 1. Create annotated tag git tag -a v1.0.0 -m "Release stable production version 1.0.0" ## 2. Inspect tag details git show v1.0.0 ## 3. List registered tags git tag
Expected Console Output:
tag v1.0.0 Tagger: Technical Engineer <engineer@enterprise.domain> Date: Mon May 18 12:00:00 2026 -0500 Release stable production version 1.0.0 v1.0.0
Finished this lesson?
Mark it complete to advance your curriculum progress.