Recommended resources
The freely available resources this lesson will direct you to.
Hello! Last time, you wrote pytest tests for api_demo.py and learned to check both expected results and error cases. You now have a small coding project worth preserving. In this final lesson of the Python-workflows module, you’ll use Git commits to record tested versions of that project and a branch to make a change without immediately changing your main line of work. Allow about 40 minutes, including the short video segments and time at your terminal.
A commit records a chosen version, not every keystroke
Git distinguishes between the files you are editing, the staging area (the content selected for the next commit), and the repository history (versions already committed). This matters when a project contains both a useful code change and an unrelated experiment: you can commit the useful change without including the experiment.

Watch the opening of Visual Studio Code’s Using Git with Visual Studio Code (Official Beginner Tutorial). It shows these states in an editor interface; we’ll perform the same operations with terminal commands.
Using Git with Visual Studio Code (Official Beginner Tutorial)
Visual Studio Code’s beginner tutorial makes the difference between an untracked file, a staged file, and a commit visible before you use the commands yourself.
Watch the first commit, from initializing a repository through staging a file and committing it. Focus on the separate action taken before the commit: selecting what will be included.
For the command-line version, read the relevant portions of Git’s official gittutorial Documentation.
Git’s official tutorial shows how a project becomes a repository and how staged content becomes a commit. Read it for the commands and the distinction between editing and recording.
In “Importing a new project,” read the initial workflow, beginning with the example project and ending at the first commit command. You do not need to create its example tarball. Then, in “Making changes,” read the change workflow, from staging edited files through recording another version. Notice how git diff --cached previews staged changes, whereas git diff previews changes not yet staged.
A commit is a snapshot of the content you staged, accompanied by a message and a place in the project’s history. It is more deliberate than saving a file in your editor: saving changes your working copy; committing records a version you can identify later.
Put the tested project under version control
Open a terminal in the directory containing api_demo.py and test_api_demo.py. First check whether it is already a Git repository:
git --version
git status
If Git is not installed, install it for your operating system before continuing. If git status reports that this is not a git repository, initialize this project directory, not a parent directory containing other projects:
git init -b main
If your Git version does not recognize -b, use git init followed by git branch -M main. If the project already is a repository, do not initialize another one. Check its current branch with git branch --show-current; if it is not named main, use that existing name wherever this lesson says main.
Before the first commit, create a .gitignore file containing:
.venv/
venv/
__pycache__/
.pytest_cache/
*.pyc
.env
This excludes common local environment files, generated Python files, and a common name for a credentials file. Adjust it if your environment has a different name. Review the files you stage: .gitignore prevents untracked matching files from being added, but it does not remove files that were already tracked. Do not commit API keys, passwords, or other secrets.
Run the tests, then stage the project files you intend to preserve:
python -m pytest -q
git add .gitignore api_demo.py test_api_demo.py
git status
git diff --staged
If you have a reviewed dependency file from the earlier environment lesson, stage that by name too. In the diff, check that the staged code is the tested version and that no sensitive values appear. If you edit a file after staging it, run git add for that file again: staging selected its content at the time you added it.
If the staged changes look right, record the baseline:
git commit -m "Record tested API summary project"
git status
git log --oneline
If Git asks for your identity, set a name and email for this repository, then retry the commit:
git config user.name "Your Name"
git config user.email "you@example.com"
Use an identity you are comfortable attaching to commits. If git commit instead says there is nothing to commit, your project may already have a committed baseline; check git log --oneline and continue. A clean git status means the tracked working files match the recorded state. It does not mean tests have passed—you checked that separately.
A branch gives a change its own history
Suppose you want extract_post_summary() to remove surrounding spaces from a post title. That is a small, testable change, but you need not put its work directly on main.
Read how Git represents branches in Branches in a Nutshell from the Git book.
The Git book explains why a branch is lightweight: it names a commit rather than making a second full project directory.
In “Branches in a Nutshell,” read commits and branches, starting with the description of what a commit stores and ending with how a branch advances. Focus on the commit’s link to its predecessor and the definition of a branch as a movable pointer; you can skim the intervening blob-and-tree storage details.
The name main is a convention, not a special kind of branch. Your current branch is the one a new commit will advance. Creating a branch gives another name to the current commit; switching to it chooses which line of development your next commit will advance.
The official Git tutorial demonstrates the related commands under “Managing branches.” Its example calls the primary branch master and creates branches and switches in separate commands. We’ll use main and a single command to create and switch.
Return to Git’s official tutorial for a concrete example of creating, switching, and merging branches.
In “Managing branches,” read the branch example, from the opening explanation through the note that a merge can encounter conflicts. Track which branch is current when a change is committed and which branch is current when a merge is requested.
Make sure git status is clean before switching. Then create and enter a feature branch:
git switch -c feature/normalize-title
git branch --show-current
Add this test to test_api_demo.py, retaining its existing tests and imports:
def test_extract_post_summary_strips_title_whitespace():
post = {
"id": 17,
"userId": 4,
"title": " Draft title ",
}
result = extract_post_summary(post)
assert result["title"] == "Draft title"
Run python -m pytest -q. The new test should fail because the function currently returns the title unchanged. In api_demo.py, change the title entry in the dictionary returned by extract_post_summary() to:
"title": post["title"].strip(),
Run the tests again. Assuming they pass, inspect and commit this change on the feature branch:
git diff
git add api_demo.py test_api_demo.py
git diff --staged
git commit -m "Normalize whitespace in post titles"
git log --oneline --decorate -3
The log should mark the new commit as belonging to your current feature branch. Meanwhile, main still identifies the earlier commit. Short messages like these make the history useful: each says what changed rather than merely announcing that changes occurred.
The tutorial’s visual branch demonstration is worth watching now. Its editor buttons correspond to the terminal operations you just performed.
Using Git with Visual Studio Code (Official Beginner Tutorial)
Return to Visual Studio Code’s beginner tutorial to see how a committed feature-branch change stays separate from the main branch until it is merged.
Watch creating a branch and committing and merging. Pay particular attention to the branch name displayed while the feature is committed, and to the switch back to the primary branch before merging.
Bring the tested change back to the main branch
Switching branches changes the project files shown in your working directory to match the branch you selected. With your feature change committed and git status clean, switch back:
git switch main
git status
Open api_demo.py or run the tests. The whitespace-normalization change is absent on main; the feature-branch commit has not been lost. To inspect both branch names and their commits, run:
git log --oneline --decorate --all --graph
Now merge the tested feature while on the branch that should receive it:
git merge feature/normalize-title
python -m pytest -q
git status
git log --oneline --decorate --all --graph
Because this walkthrough made no new commit on main after the feature branch was created, Git can normally fast-forward: main moves to the feature commit. If both branches had acquired different commits, Git would instead need to combine their histories; conflicting edits to the same area of a file could require you to resolve the conflict. If a merge stops with conflicts, use git status to identify the files and resolve them deliberately rather than committing conflict markers.
Once the merge has succeeded and the tests pass, you may delete the now-merged local branch name:
git branch -d feature/normalize-title
Deleting that name does not delete the change now included on main. Everything you did here was local: Git commits and branches do not require a GitHub account or an internet connection.
Takeaways
Use git status to see what needs attention, git add to select content, git diff --staged to review it, and git commit to record a meaningful, tested version. A branch lets you commit a change separately; switching branches lets you inspect each version, and merging brings the finished change into your main line. git log --oneline --decorate --all --graph lets you check where those commits and branch names ended up.
That completes the Python-workflows module. Next, you’ll begin working with SQL to retrieve filtered and sorted records—another way to prepare the data used in later AI-engineering projects.