Work with version control in a team
Outcome
Section titled “Outcome”You will place the Vite workflow lab in a private shared GitHub repository, develop one small change on a feature branch, exchange specific review feedback through a pull request, integrate the accepted work into main, and finish with synchronized clean repositories.
Why this matters
Section titled “Why this matters”A team needs more than a remote backup. Contributors need a shared baseline, isolated work, reviewable changes, an agreed integration point, and a recovery route when histories or files conflict.
Git records the project history. GitHub coordinates access, branch publication, discussion, review, and integration. The workflow in this lesson keeps those responsibilities visible.
What you will practice
- Prepare a source-focused repository that excludes dependencies, generated builds, secrets, and unrelated files.
- Synchronize main before creating a short-lived feature branch.
- Inspect, stage, commit, and push one focused change without writing directly to shared main.
- Create a pull request that states the outcome, verification evidence, and requested review focus.
- Give and receive constructive feedback about observable code behavior.
- Update a reviewed branch, resolve or safely abort an integration conflict, and verify the complete result.
- Finish with local main, remote main, and the working tree in a known synchronized state.
What is new and what is reused
Section titled “What is new and what is reused”- New: Repository ownership and collaborator access, cloned working copies, remote-tracking branches, feature branches, upstream branches, pull requests, reviews, branch integration, merge conflicts, conflict markers, and post-merge cleanup.
- Reused: The Level 1 working tree, staging area, commits,
main,origin, push workflow, private repositories, Git identity, terminal context, Vite project checks, focused debugging, and the completedm3-workflow-labsource.
Starting point
Before you start
- The completed m3-workflow-lab folder from the Vite lesson. npm run typecheck, npm run lint, and npm run build must pass before Git setup.
- Git and the intended commit identity from Level 1.
- A GitHub account with permission to create a private repository.
- One authorized reviewer. Use a teammate when available or ask the teacher to review. Do not create a second account to imitate a reviewer.
- Each contributor uses a separate working copy. A shared Windows account requires an agreed identity setup before anyone commits.
- Current state
- The Vite workflow lab works locally, but it has no shared repository, branch review, or integration history.
- First action
- Open m3-workflow-lab as the VS Code workspace root, open a terminal, and run git status.
- First checkpoint
- Git reports that the folder is not yet a repository, or it reports an existing repository whose root, branch, remote, and files all belong to m3-workflow-lab.
- Help trigger
- Ask for help before you stage, commit, pull, merge, or push if the repository root is wrong, another project appears in git status, the commit identity belongs to another person, a credential prompt is unexpected, a secret appears in a diff, main has local commits that are not on GitHub, or a conflict cannot be resolved from the intended final behavior.
Required result
Section titled “Required result”You have completed the lesson when:
m3-workflow-labis a Git repository whose default branch ismain;- the initial commit contains source, configuration,
package.json, andpackage-lock.json, but notnode_modules,dist, credentials, or unrelated work; - a private GitHub repository named
m3-workflow-labcontains the initialmainbranch; - the reviewer has authorized access to the private repository;
- the change is developed on
feature/item-metadata, not directly onmain; - the branch contains a focused first commit that displays the number of labels;
- a pull request states the outcome, checks, and review focus;
- the reviewer leaves one specific comment about singular and plural output;
- the author responds through a second focused commit and records one-label and two-label evidence;
- the accepted branch is integrated through the pull request;
- every contributor updates local
mainwithgit pull --ff-only; and - final
git status, branch, remote, and log checks show a clean synchronized result.
Agree on roles and the integration rule
Section titled “Agree on roles and the integration rule”Use these roles for the lesson:
| Role | Required responsibility |
|---|---|
| Repository owner | Creates the private remote, grants access, and confirms the final repository settings |
| Branch author | Owns feature/item-metadata, implements the change, runs checks, and responds to review |
| Reviewer | Reads the pull-request diff, tests the stated behavior, gives specific feedback, and approves only verified work |
| Integration owner | Merges the accepted pull request and confirms remote main afterward |
One person can hold the repository-owner and integration-owner roles. The branch author and reviewer must be different people so the review is a real exchange.
For this lesson, use one integration rule:
Shared
mainchanges through an accepted pull request. Feature work begins from synchronizedmainand remains on one named branch until integration.
The rule creates a stable location for completed work. A branch name does not create a second folder. It makes the repository’s working tree and new commits follow another named history.
Coordinate before editing
Section titled “Coordinate before editing”Before the branch author changes code, agree on:
- the visible outcome: show the work item’s label count;
- the owner of the feature branch;
- the file expected to change:
src/App.tsx; - the required checks: typecheck, lint, build, and browser behavior;
- the reviewer; and
- the point at which the pull request is ready for review.
This small agreement reduces overlapping changes. It does not replace implementation.
Prepare the local repository boundary
Section titled “Prepare the local repository boundary”In the terminal, confirm the workspace and Git context:
Get-Locationgit --versiongit statusIf git status reports that this is not a repository, continue with initialization. If it reports an existing repository, run:
git rev-parse --show-toplevelgit branch --show-currentgit remote -vContinue only if the top-level path is exactly the intended m3-workflow-lab folder and any existing history belongs to this lab. Ask for help before changing a parent or unrelated repository.
Initialize main when required
Section titled “Initialize main when required”Run this only when m3-workflow-lab is not already a repository:
git init -b maingit statusOpen .gitignore. Confirm that it excludes at least:
node_modulesdist*.localThe current Vite template can include more rules. Keep relevant generated-file and editor rules. Do not replace the complete file with the three-line example.
Ask Git which rule excludes the generated folders:
git check-ignore -v node_modules/git check-ignore -v dist/Each command must identify a .gitignore rule. If a folder does not exist, create it only through its normal command: npm install creates node_modules, and npm run build creates dist.
Inspect every staged file before the initial commit
Section titled “Inspect every staged file before the initial commit”Run the complete project verification first:
npm run typechecknpm run lintnpm run buildThen inspect and stage the controlled workspace:
git status --shortgit add --allgit diff --cached --statgit diff --cachedBefore you commit, confirm:
- source and configuration files are present;
package.jsonandpackage-lock.jsonare present;.gitignoreis present;node_modulesanddistare absent;- no
.envcredential file is present; - no unrelated folder or personal file is present; and
- the staged source is the version that passed all three commands.
If the staged boundary is wrong, unstage one path without deleting the working file:
git restore --staged PATH-TO-FILEReplace the placeholder with the exact path. Then correct .gitignore or move the unrelated file out of the project before you stage again.
Create the baseline commit:
git commit -m "chore: create Vite TypeScript workspace"git statusThe final status must report On branch main and a clean working tree.
Checkpoint: Git records a safe verified baseline
- What now works
- The main branch contains one initial commit with the intended source, lockfile, and configuration, while generated dependencies, build output, secrets, and unrelated work remain outside Git.
- Files changed
.gitignore, package.json, package-lock.json, src/App.tsx, src/main.tsx, src/styles.scss, TypeScript and Vite configuration- What remains
- Create the private shared remote, grant reviewer access, and confirm that each working copy starts from the same main commit.
- Next action
- On GitHub, create an empty private repository named m3-workflow-lab.
- If it does not work
- Inspect git rev-parse --show-toplevel, git status, and git diff --cached again. Do not publish until the repository boundary and staged content are correct.
Create the shared private repository
Section titled “Create the shared private repository”The repository owner creates the remote on GitHub:
- Create a repository named
m3-workflow-lab. - Set its visibility to Private.
- Do not add a README,
.gitignore, or license on GitHub. The local repository already contains its initial history. - Create the repository and copy its HTTPS URL.
In the project terminal, add the remote and push the verified baseline:
git remote add origin https://github.com/YOUR-USERNAME/m3-workflow-lab.gitgit remote -vgit push -u origin mainReplace YOUR-USERNAME with the repository owner’s GitHub username. Authenticate through the approved Git Credential Manager or browser flow. Do not paste an access token into source, chat, a screenshot, or the remote URL.
Open the GitHub repository and confirm that main shows the baseline commit and expected files.
Grant access to the reviewer
Section titled “Grant access to the reviewer”The repository owner opens the repository settings and uses the access or collaborators section to invite the branch author and reviewer by their GitHub usernames. Each invited person accepts the invitation through their own account.
A collaborator on a repository owned by a personal account can normally read and write repository content. Grant access only to the people who need it for the project.
If the school uses a GitHub organization, follow its repository-role policy instead of changing organization settings yourself.
Prepare the second working copy
Section titled “Prepare the second working copy”A contributor who does not own the existing local folder clones the shared repository into their own work area:
git clone https://github.com/OWNER-USERNAME/m3-workflow-lab.gitcd m3-workflow-labnpm cinpm run typechecknpm run lintnpm run buildgit statusReplace OWNER-USERNAME. The contributor must finish on main with a clean working tree and the same baseline commit visible on GitHub.
npm ci installs the dependency tree recorded in package-lock.json without rewriting the lockfile. It removes an existing node_modules folder first, so use it for a clean cloned workspace rather than during an active uncommitted dependency change.
Do not copy the owner’s project folder with its hidden .git directory. A clone creates the contributor’s own working copy with the correct remote relationship.
If it does not work
Section titled “If it does not work”- If GitHub rejects the push because the remote contains another initial commit, stop and ask for help. Do not force-push over unknown history.
- If the remote name already exists, run
git remote -vand compare its URL before you change it. - If a contributor receives a not-found or permission error, confirm the exact account, invitation acceptance, repository visibility, and URL.
- If a cloned project cannot build, run
npm installin the cloned folder and fix the first source or dependency error before branch work. - If commits show the wrong person’s identity on a shared computer, stop before creating another commit and correct the repository or account setup with the teacher.
Checkpoint: The team shares one verified main branch
- What now works
- The private GitHub repository contains the baseline, authorized contributors can access it, and each working copy has the same clean main source and passing project checks.
- Files changed
Git repository configuration outside tracked source, GitHub collaborator settings- What remains
- Create the feature branch, implement one focused change, and publish it for review.
- Next action
- Choose the branch author, then synchronize that contributor's local main before branch creation.
- If it does not work
- Compare the remote URL, access invitation, current branch, latest commit, and npm verification results in that order.
Develop the change on a feature branch
Section titled “Develop the change on a feature branch”The branch author begins from their own clean working copy.
Synchronize main and create the branch:
git switch maingit pull --ff-onlygit statusgit switch -c feature/item-metadatagit branch --show-currentgit pull --ff-only fetches the remote result and updates local main only when Git can move the local branch pointer forward without reconciling divergent local commits. If it fails, do not choose another pull mode at random. Inspect the local and remote history with the teacher.
The final branch command must print:
feature/item-metadataAdd the first visible behavior
Section titled “Add the first visible behavior”In src/App.tsx, add this paragraph after the status paragraph and before the final connection paragraph:
<p>{firstItem.labels.length} labels</p>Save the file. With the development server running, confirm that the current two-label data displays 2 labels.
Run the required source checks:
npm run typechecknpm run lintnpm run buildInspect and commit only the changed source file:
git status --shortgit diff -- src/App.tsxgit add src/App.tsxgit diff --cachedgit commit -m "feat: show work item label count"git statusThe working tree must be clean after the commit. Push the branch and set its upstream relationship:
git push -u origin feature/item-metadataThe push creates or updates the remote feature branch. It does not change remote main.
If it does not work
Section titled “If it does not work”- If
git switch mainwould overwrite local changes, return to the current branch and decide whether those changes need a commit or removal. Do not discard them without identifying their owner. - If the new branch already exists, run
git branch --listand ask whether to resume it or choose a new agreed name. - If
git diffincludes unrelated changes, keep those files unstaged and return them to their owner or separate branch. - If a check fails, do not commit the failing state. Restore the lesson code and fix the first failed command.
- If the push is rejected because the remote branch changed, coordinate with the person who changed it. Do not use force push in this course workflow.
Checkpoint: The feature branch contains one verified change
- What now works
- feature/item-metadata adds the visible two-label count, passes typecheck, lint, and build, contains one focused commit, and exists on GitHub without changing main.
- Files changed
src/App.tsx- What remains
- Open a pull request, test the singular case through review, and update the same branch.
- Next action
- Open the pushed feature branch on GitHub and create a pull request into main.
- If it does not work
- Confirm the current branch, source diff, three check results, local commit, and remote branch before you open review.
Review the change through a pull request
Section titled “Review the change through a pull request”A pull request asks the repository to compare a source branch with a target branch and discuss whether the change should be integrated.
On GitHub, create a pull request with:
- base:
main; - compare:
feature/item-metadata; and - title:
Show work item label count.
Use this description:
## Outcome
- Show the current work item's label count below its status.
## Verification
- [x] `npm run typecheck`- [x] `npm run lint`- [x] `npm run build`- [x] Browser shows `2 labels` for the current two-label item
## Review focus
- Confirm that the displayed count comes from `firstItem.labels`.- Check whether the wording remains correct for other valid label counts.The description separates the intended behavior from the evidence already collected and the question that still needs review.
Give feedback about observable behavior
Section titled “Give feedback about observable behavior”The reviewer reads the changed-files diff and checks out or opens the branch when local testing is needed. The reviewer then leaves this inline comment on the count paragraph:
A work item can have one label. This code would display
1 labels. Please make the singular and plural output correct, then record the one-label and two-label browser results.
This feedback has four useful parts:
- Observation: The code always uses the plural word.
- Consequence: One valid data state produces incorrect interface text.
- Requested change: Handle singular and plural output.
- Verification: Test both one and two labels.
The comment addresses the code and behavior. It does not make a claim about the author.
Receive and evaluate feedback
Section titled “Receive and evaluate feedback”The author does not need to accept every suggestion without analysis. For this comment, the product model permits one label and the consequence is reproducible, so the author accepts it.
On the existing feature branch, add this function after firstItem and before App:
function formatLabelCount(count: number): string { return `${count} ${count === 1 ? "label" : "labels"}`;}Replace the first count paragraph with:
<p>{formatLabelCount(firstItem.labels.length)}</p>Test the browser behavior:
- Keep the original two labels and confirm 2 labels.
- Temporarily leave one string in the
labelsarray and confirm 1 label. - Restore both original labels and confirm 2 labels again.
- Confirm that the browser Console has no application error.
Run the complete source checks again:
npm run typechecknpm run lintnpm run buildInspect and commit the review response:
git diff -- src/App.tsxgit add src/App.tsxgit diff --cachedgit commit -m "fix: format singular label count"git pushgit statusThe pull request updates automatically because both commits belong to the same published branch.
Reply to the review comment with the observed result:
Updated in the latest commit. One label renders as “1 label,” and the restored two-label data renders as “2 labels.” Typecheck, lint, and build pass.The reviewer inspects the new diff and evidence, tests when needed, and approves the pull request when the required result is correct.
Checkpoint: Review feedback changes the verified result
- What now works
- The pull request records a specific behavior issue, the author responds with a focused commit, one and two labels use correct wording, all source checks pass, and the reviewer approves the updated diff.
- Files changed
src/App.tsx, Pull-request review history on GitHub- What remains
- Integrate the approved branch, synchronize every working copy, and clean up the completed branch.
- Next action
- Before merging, compare the pull request with the latest remote main and resolve any integration issue.
- If it does not work
- Reproduce the one-label state, inspect the function input and returned string, restore the two-label data, and rerun all three source checks before requesting another review.
Integrate current main before the merge
Section titled “Integrate current main before the merge”Other accepted work can reach main while a feature is under review. Update the feature branch before integration when GitHub reports that it is behind or has a conflict.
On the feature branch, fetch the latest remote state:
git statusgit branch --show-currentgit fetch origingit log --oneline HEAD..origin/mainContinue only when the working tree is clean and the branch is feature/item-metadata.
- If the log command prints nothing and GitHub reports no conflict, the branch already contains the required base history.
- If the log command prints commits, integrate remote
maininto the feature branch:
git merge --no-edit origin/mainGit can complete the merge automatically or stop with a conflict.
Resolve a conflict from intended behavior
Section titled “Resolve a conflict from intended behavior”A merge conflict means Git cannot choose one final file automatically. It does not mean that either contributor did something wrong.
If a conflict occurs:
- Run
git statusand list every unmerged path. - Open one conflicted file.
- Read the current branch section, the separator, and the incoming section.
- Decide the final source from the required product behavior.
- Remove all
<<<<<<<,=======, and>>>>>>>markers. - Save the file and run the relevant behavior check.
- Run
npm run typecheck,npm run lint, andnpm run build. - Stage only the resolved files.
- Inspect the staged resolution.
- Commit and push the integration result.
Example conflict structure:
current marker: <<<<<<< HEADfeature branch versionseparator marker: =======incoming main versionincoming marker: >>>>>>> origin/mainDo not keep all text automatically. The final source can use one side, the other side, or a deliberate combination. The required behavior decides.
After a verified resolution, use the exact affected paths:
git add PATH-TO-RESOLVED-FILEgit diff --cachedgit commit -m "chore: resolve main integration conflict"git pushIf you cannot determine a safe final result and have not committed the merge, abort it:
git merge --abortgit statusAn abort is a recovery action. Ask the relevant contributor what the incoming code must preserve, then retry with that information.
Merge and synchronize the accepted result
Section titled “Merge and synchronize the accepted result”After approval and any required integration update, the integration owner merges the pull request on GitHub. Use the repository’s agreed merge option. For this lesson, preserve the branch commits with Create a merge commit when that option is available.
Confirm on GitHub that:
- the pull request is marked merged;
- remote
maincontains the label-count behavior; - the review conversation remains available; and
- the remote feature branch can be deleted after integration.
After the integrated main result is confirmed, select GitHub’s Delete branch action for feature/item-metadata. Delete only the merged feature branch, not main.
Every contributor then updates their local repository:
git switch maingit pull --ff-onlygit statusnpm installnpm run typechecknpm run lintnpm run buildnpm install synchronizes installed dependencies with the committed lockfile. It is required after another branch changes dependencies and harmless when the lockfile is already satisfied.
Verify the browser result from updated main: one label must display 1 label, restored two-label data must display 2 labels, and the Console must remain free of application errors.
Delete the local completed branch only after local main contains the merged commits:
git branch -d feature/item-metadatagit fetch --prunegit branch --allThe branch deletion removes a completed branch name. The commits remain reachable through main and the pull-request history.
Inspect the final history and relationships:
git statusgit branch --show-currentgit remote -vgit log --oneline --decorate --graph -6The required final state is:
- current branch:
main; - working tree: clean;
- local
main: updated from remotemain; origin: the intended private GitHub repository;- source checks: passing;
- browser behavior: correct for one and two labels; and
- pull request: merged with review evidence.
Self-check
Complete these checks against the required result.
- Confirm that git rev-parse --show-toplevel identifies only m3-workflow-lab.
- Confirm that the initial commit contains source, configuration, package.json, and package-lock.json but excludes node_modules, dist, credentials, and unrelated files.
- Open the private GitHub repository and confirm that only authorized accounts can access it.
- Point to the command that synchronized main before feature/item-metadata was created.
- Confirm that both feature commits were created on feature/item-metadata and not directly on main.
- Confirm that the pull-request description states the outcome, completed checks, and review focus.
- Read the review comment and identify its observation, consequence, requested change, and verification step.
- Test one label and two labels on updated main and confirm the singular and plural outputs.
- Run typecheck, lint, and build from updated main and confirm that all three commands pass.
- Confirm that the pull request is merged and its review conversation remains available.
- Confirm that git status is clean, git branch --show-current reports main, and origin points to the intended private repository.
- Confirm that every contributor pulled the integrated main result into their own working copy.
Checkpoint: The team workflow ends in one synchronized verified main
- What now works
- A focused branch passed review, feedback improved observable behavior, the accepted commits reached remote main, and every contributor verified a clean updated local main.
- Files changed
src/App.tsx, Local Git history, Private GitHub repository and pull-request history- What remains
- Apply the same workflow to the first assessed project stage with an agreed product brief and team contract.
- Next action
- Keep the synchronized repository available and open Project stage 1: Prepare the application workspace.
- If it does not work
- Compare the current branch, working-tree status, origin URL, local and remote main commits, project checks, and browser result before making another change.
Reference documentation
Section titled “Reference documentation”- Git switch documents switching branches and creating a branch with
-c. - Git pull documents fetch-and-integrate behavior and the
--ff-onlyoption. - GitHub repository access documents inviting and managing authorized contributors.
- GitHub pull requests documents branch comparison, review, updates, and integration.
- Resolve a merge conflict with Git documents conflict markers, staging, and resolution commits.
Next step or safe stopping point
Section titled “Next step or safe stopping point”The required lesson is complete when the pull request is merged, every contributor has pulled the accepted main, the one-label and two-label behavior passes, all project checks pass, and each working tree is clean.
Continue to Project stage 1: Prepare the application workspace to apply the TypeScript, Vite, Sass, and team Git workflow to the continuing assessed application.
If you stop here, leave this resume note: The reviewed item-metadata change is on remote and local main, every check passes, and the working tree is clean. Next, agree on the Stage 1 product brief and repository contract before feature work begins.