The actual workflow every working programmer uses every day. Branches, remotes, pull requests, code review. The lab submits Lab 9 as a PR for instructor review.
Theme
FND-101 covered git init, git add, git commit, git push. That is the solo workflow: you and your repo on your laptop. The team workflow has more shape: you work on a branch named for your change, push the branch to a shared remote, open a pull request (PR) that says "please merge this branch into main," another person reviews it, you respond to feedback, the PR is merged.
Most professional Python (and most open-source Python) is built this way. Every commit on the main branch of a serious project has been through a PR. Code review is where bugs are caught, design discussions happen, and junior developers learn from senior ones.
This week's lab is your first real PR: you take Lab 9's disk-usage reporter, push it to a remote (GitHub or GitLab; the academy uses GitLab self-hosted at git.sandhillscto.com but GitHub works equally well for the lab), open a PR with the instructor as reviewer, respond to one round of feedback, and get the PR merged.
By the end of week 10 you can: create and switch branches; push a branch to a remote; open a pull request via the web UI or the gh / glab CLI; respond to a code review comment; merge a PR after approval; resolve a simple merge conflict.
Reading list (~1 hour)
- Scott Chacon, Pro Git 2nd ed., Ch 3.1-3.5 ("Git Branching") at
https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell. Free online. The canonical reference. Read 3.1 through 3.5; the rebasing material (3.6) is forward-stretch. - GitHub Docs: "Creating an issue or pull request" at
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request. ~10 min. Read the "Creating the pull request" section; skim the rest. - GitLab Docs: "Merge requests" at
https://docs.gitlab.com/ee/user/project/merge_requests/. ~10 min. The same concept as GitHub PRs; GitLab calls them merge requests. - Real Python: "Git Tutorial" at
https://realpython.com/python-git-github-intro/. ~20 min. Worked examples of the branch / push / PR workflow.
Lecture outline (~1.5 hours, 2 sessions of ~50 min)
Session 1: Branches and remotes
Section 1.1: What a branch is
- A branch is a pointer to a commit. That is the whole concept.
mainis a branch. Every other branch starts as a pointer to whatever commitmainwas at when you branched.- Each commit has a parent (the previous commit on the branch). Branches diverge when they have different commits after the branch point; they reunite when one is merged into the other.
Section 1.2: Creating and switching branches
- Create and switch in one step:
git checkout -b feature/disk-usage
- Or in two steps (modern):
git branch feature/disk-usage git switch feature/disk-usage
- The branch name
feature/disk-usageis a convention:<type>/<short-description>. Common types:feature,bugfix,refactor,docs. Your team's convention may vary; consistency matters more than which one you pick.
Section 1.3: Working on a branch
- Make changes;
git add;git commit(just like main). - Multiple commits on a branch are normal: one commit per logical step.
git log --all --oneline --graphshows the branch structure.git statusshows which branch you are on and any uncommitted changes.
Section 1.4: Pushing a branch to a remote
- The first push of a new branch:
git push -u origin feature/disk-usage
- The
-u(--set-upstream) tells Git to remember that this local branch tracks the same-named remote branch. Subsequent pushes are justgit push. - A remote is a name (
originis the conventional default) for a Git URL.git remote -vlists all remotes.
Section 1.5: Remotes
git clonesets up a remote calledoriginautomatically.- To start from scratch with a new remote:
git remote add origin git@github.com:yourusername/repo.git
- The URL form
git@github.com:...is SSH (requires an SSH key set up with GitHub/GitLab). The HTTPS formhttps://github.com/...works without SSH but requires a token for write access. - For FND-102, the lab uses either GitHub or GitLab; you may need to set up an SSH key. GitHub's guide is at
https://docs.github.com/en/authentication/connecting-to-github-with-ssh.
Session 2: Pull requests, code review, merge conflicts
Section 2.1: Opening a PR
- After
git push -u origin feature/..., the remote (GitHub or GitLab) displays a "Compare and pull request" link. Click it. - The PR form has a title and a description:
- Title: one sentence describing what the PR does (imperative voice, like a commit message: "Add disk-usage reporter with subprocess wrapper")
- Description: what changed, why, and how to test it. ~3-5 paragraphs. Link to any issue or spec.
- Pick the target branch (
main); pick the source branch (feature/...). - Click "Create pull request."
- The PR has a unique number (#42); other developers reference it as
#42.
Section 2.2: Receiving code review
- The reviewer reads your diff. They may:
- Approve (the PR is ready to merge).
- Request changes (the PR has issues you must address).
- Leave non-blocking comments (suggestions; not required to address).
- Common review comments:
- "This function is doing two things; can you split it?"
- "The error message could be clearer."
- "Missing test for the edge case where X."
- "Why not use the stdlib for this instead of rolling your own?"
- The discipline of receiving review: ASSUME GOOD FAITH. The reviewer's job is to make the code better, not to attack you. Disagree if you have a good reason; agree gracefully when you do not.
Section 2.3: Responding to feedback
- For each comment, either:
- Make the change in a new commit; push to the same branch; the PR updates automatically
- Reply with why you disagree (rare; pick your battles)
- Multi-commit response is fine. The PR can be squash-merged at the end so the merged commit is clean.
- Mark each comment as "resolved" after addressing it (GitHub) or click the checkbox (GitLab) so the reviewer knows you handled it.
Section 2.4: Merging the PR
- After approval, click "Merge pull request" (GitHub) or "Merge" (GitLab).
- Three merge strategies:
- Merge commit (default): preserves all commits on the branch plus a merge commit. Most history; least squashed.
- Squash and merge: combines all branch commits into one new commit on main. Cleanest main history; loses the per-step history on the branch.
- Rebase and merge: replays branch commits onto main without a merge commit. Linear history; harder for beginners.
- For FND-102: squash-and-merge is the default. Clean main history; the branch's intermediate commits live in the PR but not on main.
- After merge, delete the branch (the web UI offers a button).
Section 2.5: Merge conflicts
- A merge conflict happens when your branch and
mainboth modified the same lines of the same file in incompatible ways. - Git pauses the merge and marks the conflicting region in the file:
<<<<<<< HEAD your changes ======= the other side's changes >>>>>>> main
- To resolve: edit the file to the version you want (often a combination), remove the marker lines, save.
git add file.pymarks it as resolved;git commit(orgit merge --continue) finishes the merge.- Conflicts are normal on long-lived branches. The defense: keep branches short (a few days max); merge / rebase main into your branch frequently.
Labs (~90 minutes)
Lab 10: PR Submission (labs/lab-10-pr-submission.md)
- Goal: take Lab 9's disk-usage reporter; push it to a remote on a branch; open a PR with the instructor as reviewer; respond to one round of feedback; merge
- Time: ~90 minutes
- Artifact: a merged PR + transcript (saved as
lab-10-transcript.mdin~/fnd-102/lab-10/)
Independent practice (~4 hours)
- Branch hygiene drill (30 min). In any of your existing FND-102 lab repositories: create a branch
feature/cleanup, make a small change (rename a variable; add a comment; reformat), commit, push, delete the branch (without merging). Notice that the deleted branch's commit is now unreachable (you can recover viagit reflog; useful safety net). - Merge conflict resolution (45 min). Set up a deliberate conflict:
Resolve the conflict; commit; verify withgit switch -c branch-a # edit file.py; change line 1 git commit -am "branch-a change" git switch main git switch -c branch-b # edit file.py; change line 1 differently git commit -am "branch-b change" git switch main git merge branch-a # this works git merge branch-b # this conflicts
git log --all --graph. - PR template (30 min). Most repos use a
.github/pull_request_template.mdor.gitlab/merge_request_templates/. Write one for your FND-102 repo with five sections: Summary, What changed, Why, Testing notes, Reviewer asks. Commit it. Future PRs auto-populate from this template. - Read a real PR (30 min). On GitHub, find any Python project you care about (CPython itself:
https://github.com/python/cpython/pulls). Read three merged PRs. Notice: how long are the discussions? How many commits? How is the merge done? - Write a good commit message (30 min). Take the last 5 commits in your FND-102 repo. Rewrite each commit message to follow the convention: imperative voice; ~50 character first line; blank line; multi-paragraph body. Use
git rebase -i HEAD~5and pickrewordfor each. (Forward-stretch: interactive rebase is advanced; only attempt on a private branch with no other team members.) git diffmastery (15 min). In the REPL of git:git diff(unstaged changes);git diff --cached(staged changes);git diff HEAD~1(diff from one commit ago);git diff main feature/x(between branches). These four are 90% of the diff invocations you will use.- Optional stretch (60 min). Set up a personal CI: a
.github/workflows/test.ymlfile that runspyteston every push to your FND-102 repo. Free for public repos. The yaml looks like:
Forward-pointer to week 13.on: [push] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: '3.11' - run: pip install pytest - run: pytest
Reflection prompts (~30 minutes)
- The branch-and-PR workflow is more setup than the solo
git add; git commit; git pushworkflow you knew before. What is the payoff that justifies the setup? - Code review is uncomfortable the first time. What is the worst case if your reviewer finds a real bug in your PR? What is the worst case if they don't?
- Squash-and-merge vs merge-commit: which does your Lab 10 PR use? Why? When might the other be better?
- Merge conflicts feel scary the first time. After practice 2, do they still feel scary? What did you learn that you would tell a future student?
- One thing from this week you want to know more about?
Tool journal (week 10)
git switch,git switch -c BRANCH: create and change branches (modern)git checkout -b BRANCH: same in legacy formgit push -u origin BRANCH: first push of a new branchgit pullvsgit fetch: pull = fetch + merge; fetch alone if you want to inspect before merging- Pull Request / Merge Request: the team workflow
ghCLI (GitHub) orglabCLI (GitLab): PR operations from the terminal- Merge strategies: merge commit, squash, rebase
git rebase -i HEAD~N: interactive rebase (advanced; private branches only)git reflog: safety net for "where did my branch go?"
What comes next
Week 11 introduces hashing and integrity. Lab 11 is a directory-integrity checker that computes SHA-256 for every file in a tree and detects later modifications. The first place in the course you use cryptographic primitives (the hashing kind, not encryption).