Skip to content

Work with version control in a team

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.

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.
  • 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 completed m3-workflow-lab source.

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.

You have completed the lesson when:

  • m3-workflow-lab is a Git repository whose default branch is main;
  • the initial commit contains source, configuration, package.json, and package-lock.json, but not node_modules, dist, credentials, or unrelated work;
  • a private GitHub repository named m3-workflow-lab contains the initial main branch;
  • the reviewer has authorized access to the private repository;
  • the change is developed on feature/item-metadata, not directly on main;
  • 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 main with git pull --ff-only; and
  • final git status, branch, remote, and log checks show a clean synchronized result.

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 main changes through an accepted pull request. Feature work begins from synchronized main and 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.

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.

In the terminal, confirm the workspace and Git context:

Check the project and repository context
Get-Location
git --version
git status

If git status reports that this is not a repository, continue with initialization. If it reports an existing repository, run:

Inspect an existing repository before continuing
git rev-parse --show-toplevel
git branch --show-current
git remote -v

Continue 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.

Run this only when m3-workflow-lab is not already a repository:

Initialize the project repository
git init -b main
git status

Open .gitignore. Confirm that it excludes at least:

.gitignore — required generated-file exclusions
node_modules
dist
*.local

The 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:

Verify generated-folder exclusions
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:

Verify the source baseline
npm run typecheck
npm run lint
npm run build

Then inspect and stage the controlled workspace:

Stage the initial controlled workspace
git status --short
git add --all
git diff --cached --stat
git diff --cached

Before you commit, confirm:

  • source and configuration files are present;
  • package.json and package-lock.json are present;
  • .gitignore is present;
  • node_modules and dist are absent;
  • no .env credential 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:

Unstage one unintended path
git restore --staged PATH-TO-FILE

Replace 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:

Create the verified baseline commit
git commit -m "chore: create Vite TypeScript workspace"
git status

The 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.

The repository owner creates the remote on GitHub:

  1. Create a repository named m3-workflow-lab.
  2. Set its visibility to Private.
  3. Do not add a README, .gitignore, or license on GitHub. The local repository already contains its initial history.
  4. Create the repository and copy its HTTPS URL.

In the project terminal, add the remote and push the verified baseline:

Connect and publish main
git remote add origin https://github.com/YOUR-USERNAME/m3-workflow-lab.git
git remote -v
git push -u origin main

Replace 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.

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.

A contributor who does not own the existing local folder clones the shared repository into their own work area:

Clone and verify a contributor working copy
git clone https://github.com/OWNER-USERNAME/m3-workflow-lab.git
cd m3-workflow-lab
npm ci
npm run typecheck
npm run lint
npm run build
git status

Replace 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 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 -v and 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 install in 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.

The branch author begins from their own clean working copy.

Synchronize main and create the branch:

Start a branch from synchronized main
git switch main
git pull --ff-only
git status
git switch -c feature/item-metadata
git branch --show-current

git 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-metadata

In src/App.tsx, add this paragraph after the status paragraph and before the final connection paragraph:

src/App.tsx — first review version
<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:

Verify the first feature version
npm run typecheck
npm run lint
npm run build

Inspect and commit only the changed source file:

Commit the focused feature change
git status --short
git diff -- src/App.tsx
git add src/App.tsx
git diff --cached
git commit -m "feat: show work item label count"
git status

The working tree must be clean after the commit. Push the branch and set its upstream relationship:

Publish the feature branch
git push -u origin feature/item-metadata

The push creates or updates the remote feature branch. It does not change remote main.

  • If git switch main would 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 --list and ask whether to resume it or choose a new agreed name.
  • If git diff includes 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.

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:

Pull-request 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.

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.

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:

src/App.tsx — add before App
function formatLabelCount(count: number): string {
return `${count} ${count === 1 ? "label" : "labels"}`;
}

Replace the first count paragraph with:

src/App.tsx — reviewed output
<p>{formatLabelCount(firstItem.labels.length)}</p>

Test the browser behavior:

  1. Keep the original two labels and confirm 2 labels.
  2. Temporarily leave one string in the labels array and confirm 1 label.
  3. Restore both original labels and confirm 2 labels again.
  4. Confirm that the browser Console has no application error.

Run the complete source checks again:

Verify the reviewed revision
npm run typecheck
npm run lint
npm run build

Inspect and commit the review response:

Commit and publish the review response
git diff -- src/App.tsx
git add src/App.tsx
git diff --cached
git commit -m "fix: format singular label count"
git push
git status

The pull request updates automatically because both commits belong to the same published branch.

Reply to the review comment with the observed result:

Review reply
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.

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:

Compare the feature branch with remote main
git status
git branch --show-current
git fetch origin
git log --oneline HEAD..origin/main

Continue 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 main into the feature branch:
Integrate current main into the feature branch
git merge --no-edit origin/main

Git can complete the merge automatically or stop with a conflict.

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:

  1. Run git status and list every unmerged path.
  2. Open one conflicted file.
  3. Read the current branch section, the separator, and the incoming section.
  4. Decide the final source from the required product behavior.
  5. Remove all <<<<<<<, =======, and >>>>>>> markers.
  6. Save the file and run the relevant behavior check.
  7. Run npm run typecheck, npm run lint, and npm run build.
  8. Stage only the resolved files.
  9. Inspect the staged resolution.
  10. Commit and push the integration result.

Example conflict structure:

Conflict markers are evidence, not final source
current marker: <<<<<<< HEAD
feature branch version
separator marker: =======
incoming main version
incoming marker: >>>>>>> origin/main

Do 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:

Record a verified conflict resolution
git add PATH-TO-RESOLVED-FILE
git diff --cached
git commit -m "chore: resolve main integration conflict"
git push

If you cannot determine a safe final result and have not committed the merge, abort it:

Return to the pre-merge feature state
git merge --abort
git status

An abort is a recovery action. Ask the relevant contributor what the incoming code must preserve, then retry with that information.

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 main contains 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:

Synchronize local main after integration
git switch main
git pull --ff-only
git status
npm install
npm run typecheck
npm run lint
npm run build

npm 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:

Remove the integrated local branch
git branch -d feature/item-metadata
git fetch --prune
git branch --all

The branch deletion removes a completed branch name. The commits remain reachable through main and the pull-request history.

Inspect the final history and relationships:

Verify the final repository state
git status
git branch --show-current
git remote -v
git log --oneline --decorate --graph -6

The required final state is:

  • current branch: main;
  • working tree: clean;
  • local main: updated from remote main;
  • 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.

  1. Confirm that git rev-parse --show-toplevel identifies only m3-workflow-lab.
  2. Confirm that the initial commit contains source, configuration, package.json, and package-lock.json but excludes node_modules, dist, credentials, and unrelated files.
  3. Open the private GitHub repository and confirm that only authorized accounts can access it.
  4. Point to the command that synchronized main before feature/item-metadata was created.
  5. Confirm that both feature commits were created on feature/item-metadata and not directly on main.
  6. Confirm that the pull-request description states the outcome, completed checks, and review focus.
  7. Read the review comment and identify its observation, consequence, requested change, and verification step.
  8. Test one label and two labels on updated main and confirm the singular and plural outputs.
  9. Run typecheck, lint, and build from updated main and confirm that all three commands pass.
  10. Confirm that the pull request is merged and its review conversation remains available.
  11. Confirm that git status is clean, git branch --show-current reports main, and origin points to the intended private repository.
  12. 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.

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.