Skip to main content
Published / updated

Team Repository Simulation

Before you start

You need: all of Articles 01–07, a GitHub account, and two clones of the same repository to act as two developers.

Time: 5–8 hours.

Goal

Run a complete team workflow on your own, using two clones as two developers, and produce a repository whose history a stranger could read.

Assignment

Simulate a two-developer team on the School Management System through one full cycle: features, a conflict, review, a release, a hotfix and a recovery from a mistake.

Use two clones of the same remote. This is what makes the exercise real — you cannot experience a rejected push, a stale origin/main or a genuine conflict with one working copy.

git clone git@github.com:<you>/school-portal.git dev-ravi
git clone git@github.com:<you>/school-portal.git dev-priya

Work in dev-ravi as Ravi Kumar and dev-priya as Priya Sharma, setting a different user.name in each so the history shows two authors.

Setup

cd dev-ravi
git config user.name "Ravi Kumar"
git config user.email "ravi.kumar@nexcoding.in"
cd ../dev-priya
git config user.name "Priya Sharma"
git config user.email "priya.sharma@nexcoding.in"

Configure the repository on GitHub:

  • Protect main: require a pull request, require one approval, block force pushes
  • Add CONTRIBUTING.md stating the workflow, the branch naming convention and the commit message format
  • Add a .gitignore covering bin/, obj/, node_modules/, .env, appsettings.Development.json

Part 1: Two features in parallel

Ravi builds student search:

git switch -c feature/142-student-search

Three commits, each doing one thing:

Add SearchStudents query to StudentRepository
Add GET /api/students/search endpoint
Add tests for student search including empty results

Priya builds the fee summary, touching FeeService.cs:

git switch -c feature/145-fee-summary
Add GetFeeSummary to FeeRepository
Add fee summary endpoint
Add tests for fee summary with partial payments

Both open pull requests with the five-section description. Both review the other's.

Requirement: every review must include one blocking comment, one question and one nit, each labelled. Address them with new commits, and reply to every thread.

Merge Ravi's first.

Part 2: The rejected push

Before merging Priya's, have Priya try to push a new commit directly to main:

git switch main
git commit -am "Quick fix"
git push

Record the rejection. Then:

git pull --rebase
git push

Record what happened to the commit's hash.

Then repeat with branch protection on and record how the server refuses even a valid push to main. This is the difference between Git rejecting a push and a policy rejecting it — two different messages, two different fixes.

Part 3: The conflict

Both developers change CalculateTotalFees in FeeService.cs:

Ravi adds a discount:

public decimal CalculateTotalFees(int studentId)
{
decimal total = _feeRepository.GetTotalFees(studentId);
decimal discount = _discountService.GetDiscount(studentId);
return total - discount;
}

Priya adds a late fee:

public decimal CalculateTotalFees(int studentId)
{
decimal total = _feeRepository.GetTotalFees(studentId);
decimal lateFee = _lateFeeService.CalculateLateFee(studentId);
return total + lateFee;
}

Merge one, then the other. Resolve the conflict.

Do it wrong first, deliberately. Take --theirs wholesale, commit, and then write down what the application now does to a student who has both a discount and a late fee. Note that nothing failed and no test necessarily broke.

Then reset and resolve correctly, keeping both:

public decimal CalculateTotalFees(int studentId)
{
decimal total = _feeRepository.GetTotalFees(studentId);
decimal discount = _discountService.GetDiscount(studentId);
decimal lateFee = _lateFeeService.CalculateLateFee(studentId);
return total - discount + lateFee;
}

Verify with three cases — discount only, late fee only, both — then run grep -rn "<<<<<<<" src/ before committing.

Enable merge.conflictstyle zdiff3, recreate the conflict, and record whether the base section made the intent clearer.

Part 4: Release

git switch main
git pull
git tag -a v1.0.0 -m "Release 1.0.0 — student search and fee summary"
git push origin v1.0.0

Confirm the tag appears on GitHub. Then check what happens if you push without --tags.

Part 5: The hotfix

A bug in production: CalculateTotalFees throws for a student with no fee account.

git switch -c hotfix/no-fee-account main

Fix it, test it, open a PR, merge, tag v1.0.1, and record the deploy.

Then do the wrong version deliberately: branch a second hotfix from develop (or from an unmerged feature branch) and record exactly what unreleased work it drags in.

If you are running a develop branch, merge the hotfix back into it and record why skipping that step reintroduces the bug.

Part 6: Recovery

Cause each of these, then recover:

MistakeRecovery
git reset --hard HEAD~3 on committed workgit reflog
Deleted a branch with -Dgit reflog, git branch <name> <hash>
Committed to main instead of a feature branchreset --soft, stash, switch, commit
Committed a fake connection stringRevert, then confirm it is still in history
reset --hard with an uncommitted changeCannot recover — record this

The last row is the point of the exercise. Everything committed is recoverable; nothing uncommitted is.

For the connection string, run git log -p | grep -i "server=;" after reverting and confirm it is still there. Write down what the real fix would be.

Part 7: Find the bug

Introduce a subtle bug ten commits back — absent exam results counted as zero rather than excluded — then find it:

git bisect start
git bisect bad
git bisect good v1.0.0

Then repeat with automation:

git bisect run dotnet test --filter FullyQualifiedName~ExamResultTests

Record how many steps each took, and what the offending commit's message told you.

Submission template

Repository URL:
Branch protection settings applied:
CONTRIBUTING.md workflow chosen and why:

Part 1 — Features
Branch names:
Commit messages (paste git log --oneline):
Review comments given (blocking / question / nit):
How each was addressed:

Part 2 — Rejected push
Error text:
Hash before and after the rebase:
Difference between Git's rejection and the protection rule's:

Part 3 — Conflict
Marker block, pasted:
What the wrong resolution did to a student with both:
Correct resolution:
Verification performed:
zdiff3 — did it help?

Part 4 — Release
Tag command and what push --tags changed:

Part 5 — Hotfix
Correct hotfix, branched from:
Wrong hotfix, what it pulled in:
Consequence of not merging back:

Part 6 — Recovery
Each mistake, the recovery command, and whether it worked:
What was unrecoverable, and why:
Connection string still in history — evidence and the real fix:

Part 7 — Bisect
Manual steps taken:
Automated command:
Commit found, and what its message explained:

Final
git log --oneline --graph --all (paste):
What a stranger could tell about this project from the history alone:

Verification

The history reads. git log --oneline --graph --all should show branches, merges and tags in a shape someone else could follow. A flat list of "update" commits fails this.

Every commit message says why. Pick three at random and check that the body explains something the diff cannot.

No secret in history. git log -p | grep -i "password\|connectionstring\|apikey" returns nothing except your deliberate exercise, which you documented.

No build artefacts committed. git log --stat | grep -E "bin/|obj/|node_modules/" returns nothing.

Both features work after the conflict. A student with a discount, a student with a late fee, and a student with both.

Tags exist on the remote. git ls-remote --tags origin lists v1.0.0 and v1.0.1.

The hotfix is on main and, if you used one, on develop. git branch --contains <hotfix-hash> proves it.

Every recovery is recorded, including the one that failed.

AI practice

Three AI exercises from this track's syllabus. Do each after the simulation is complete, and apply Track 18's discipline — every answer is a hypothesis until you have run it.

  1. Ask AI to explain a diff. Paste the diff from your conflict resolution in Part 3 and ask what changed and what the risk is. Check whether it notices that taking one side wholesale removed a working feature. That is the failure this track exists to prevent, and it is invisible in a diff that compiles.
  2. Generate a commit-message suggestion, then improve it. Ask for a message for your fee-calculation fix. Generated messages describe what changed, which the diff already shows. Rewrite it to explain why — what was broken, for which student, and what you decided.
  3. Verify every AI-suggested recovery command before running it. Ask how to undo a bad commit that has already been pushed. If the answer suggests git reset plus a force push, stop — that discards a colleague's work. git revert is the correct answer after pushing. Never run a suggested Git command you cannot explain.

Exercise 3 is not optional. reset --hard, clean -fdx and push --force are all irreversible, and all three appear in confident, wrong answers.

Track 18 — Reviewing AI-generated code — has the full checklist.

Self-assessment

Your submission is complete when the repository shows a full cycle and your notes show you understand why each step behaved as it did.

Five specific tests:

  • Can you explain what the wrong conflict resolution broke, and why no test caught it? This is the most important lesson in the track.
  • Do you know which recovery is impossible? Uncommitted work discarded by reset --hard has no recovery path. Everything else does.
  • Can you say why a hotfix branches from main? If your answer is "because the guide said so", redo Part 5 and read what the wrong version pulled in.
  • Did bisect find the commit faster than reading the diffs would have? If not, your commits are too large.
  • Would a new developer, given only this repository, know how to contribute? That is what CONTRIBUTING.md and the branch names are for.

Track completion criteria

You can use Git confidently in a team — branching, merging, resolving conflicts, reviewing, releasing and recovering.

Specifically, you can:

  • Create a repository with a .gitignore written before the first commit
  • Stage deliberately with git add -p and read git diff --staged before committing
  • Write commit messages that explain why
  • Push, pull, and read a rejected push correctly
  • Explain what origin/main is and when it updates
  • Branch, merge, and delete branches safely
  • Resolve a conflict keeping both changes, and verify it
  • Raise a pull request someone can review in ten minutes
  • Give review feedback that is specific and labelled
  • Identify a team's workflow from its branches
  • Run a release, tag it, and ship a hotfix without breaking the next release
  • Recover from reset --hard, a deleted branch and a commit on the wrong branch
  • Find a regression with git bisect
  • Say what Git cannot recover

The syllabus recommends Track 18 — Claude & Codex AI-Assisted Development or Track 01 — Microsoft .NET Full Stack Guided Path next. Track 17 — Debugging Skills pairs naturally with this one.