Module 2: Git from Scratch for Automators
8. Project: a workflow under version control
Description
By the end of this lesson you will have built and running the deliverable that summarizes the entire module: Cumbre's order-triage workflow under version control end to end. You will have put the workflow into Git, iterated on it across three different branches, reviewed every change with its diff, merged all three into main, cleanly reverted a specific change, and connected everything to a remote on GitHub. The result is a repository with a readable history and one traceably reverted change —exactly what the market asks for when it says "version-controlled JSON," and proof, defensible in an interview, that you crossed the border from workflow builder to system owner.
This matters because it's the difference between having read about Git and knowing how to use it on a real workflow. The previous seven lessons gave you each piece separately: install, commit, diff, branch, back up, revert. None of that sticks until you chain it into a complete flow, watch the history grow with your decisions, and at the end can look at your git log and read the whole story of your work in it. That readable git log is your portfolio artifact: the concrete object you put on the table in a technical interview.
Connection to the module: this lesson doesn't introduce any new concept. It assembles the previous seven. Lesson 2's repository is where you work; lesson 3's commits are each photo; lesson 4's diffs are how you review; lesson 5's branches are the three iterations; lesson 6's remote is where you back it up; and lesson 7's revert is the clean close. If anything below isn't familiar, that's the lesson number worth going back to before continuing.
What you're going to deliver
A cumbre-automations repository, hosted on GitHub, with a history telling this story from start to finish. By the end, your git log --oneline should look a lot like this —the same block we opened lesson 1 with, now built by you:
f1a2b3c (HEAD -> main) Revert "Point CRM lookup at the staging URL"
e9d8c7b Point CRM lookup at the staging URL
d4e5f6a Add priority routing after classification
b2c4d6e Widen CRM lookup timeout to 15 seconds
a91c3f8 Add wholesale category to the order classifier
c08b4a2 Add order-triage workflow
That history isn't decorative: every line is a decision you made, made with judgment. Three of the middle commits arrived through different feature branches you merged. The top one is a clean rollback of a change that broke the workflow. And it's all backed up on a remote.
Alongside the repository, two deliverables that aren't commands and matter just as much:
- A portfolio defense of about five sentences: why every decision in your history was the right one (phase 8). It's what you'd answer in an interview looking at your own
git log. - Your repository on GitHub, private, with the complete history pushed.
On time: the whole project takes about an hour if you follow along. Phase 6 —the rollback— is the one not worth skipping, because it's where the whole module justifies itself.
A note on IDs. In all the examples you're going to see commit IDs like c08b4a2 or f1a2b3c. Yours are going to be different —Git calculates them from the content, the date, and your author info, so they can't possibly match mine. When a step asks you to use an ID, take it from your git log, don't copy it from the guide. It's the same principle as always: verify against your own machine.
Why this order of phases. It isn't arbitrary, and it's worth seeing why. First you prepare the ground (phase 0) and initialize with a base commit (phase 1), because you can't branch off of nothing. Then the three branches (phases 2 through 4) before merging, so you have several experiments alive at once and practice their independence from each other. Then you review and merge (phase 5), which is where diffs earn their keep. Only then the rollback (phase 6), because you need a history with several commits for reverting one specific one to make sense. And at the end, GitHub (phase 7) and the defense (phase 8), because backing up and explaining come after building. It's, in miniature, the complete lifecycle of a change to a workflow: it gets saved, experimented on, integrated, corrected, shared, defended.
Phase 0 — Preparing the ground
You need two things: the order-triage workflow exported as JSON, and a machine with Git configured (lesson 2).
Step 0.1. Confirm Git is ready:
git --version
git config --list
You should see a 2.x version and your user.name and user.email. If something's missing, go back to lesson 2.
Step 0.2. Create the project folder and put your order-triage.json inside it (Cumbre's workflow that receives orders with a Webhook, classifies them with an AI Agent, and queries the CRM with an HTTP Request). If you've been working on the workflow since the previous lessons, you already have it; if you're starting fresh here, export it from n8n with the download option, which produces multi-line JSON —friendlier for diffs, as you saw in lesson 4.
mkdir cumbre-automations
# (put order-triage.json inside the folder)
cd cumbre-automations
Step 0.3. Protect the secrets from the very start. Create a .gitignore (lesson 3) so no credential enters the history by accident:
# .gitignore
.DS_Store
.env
credentials.json
*.key
A moment to notice something. You haven't run git init yet. You're getting the ground in order before starting to version: the file you're about to version and the list of what never gets versioned. That order —prepare before initializing— avoids the most common first-commit mistake, photographing a secret without noticing.
Phase 1 — Initialize and the base commit
Step 1.1. Turn the folder into a repository:
git init
What to expect: Initialized empty Git repository in .../cumbre-automations/.git/. Confirm with git status that order-triage.json shows up as "Untracked files" and that your .gitignore is there too (the .gitignore does get versioned; it's what it ignores that doesn't go in).
Step 1.2. Make the base commit —the first photo, the workflow's honest starting point:
git add order-triage.json .gitignore
git commit -m "Add order-triage workflow"
What to expect:
[main (root-commit) c08b4a2] Add order-triage workflow
2 files changed, 129 insertions(+)
create mode 100644 .gitignore
create mode 100644 order-triage.json
That (root-commit) marks it as your history's root. From here, everything grows upward. Verify with git log --oneline that you have your first commit with HEAD -> main next to it.
Phase 2 — Branch 1: adding the wholesale category
Now the three iterations, each on its own branch. The first: adding the wholesale category to the classifier, because Cumbre started distinguishing its wholesale customers.
Step 2.1. Create the branch and switch to it:
git switch -c add-wholesale-category
What to expect: Switched to a new branch 'add-wholesale-category'.
Step 2.2. In n8n, open order-triage, go into the Classify Order node (the AI Agent), and add wholesale to its category list (standard, priority → standard, priority, wholesale). Save, export, and replace your order-triage.json.
Step 2.3. Review the change before saving it, applying the four "read through the noise" rules (lesson 4):
git diff
Skip the versionId and the positions; stop at the Classify Order node's parameters. You should see the added category. Confirm it's the change you wanted and only that.
Step 2.4. Save it:
git add order-triage.json
git commit -m "Add wholesale category to the order classifier"
The commit got saved on the add-wholesale-category branch, not on main. Your feature bookmark advanced; main's stayed at the base commit.
Phase 3 — Branch 2: widening the CRM's timeout
Second iteration, second branch, always starting from main so the branches stay independent.
Step 3.1. Go back to main and create the second branch from there:
git switch main
git switch -c widen-crm-timeout
Notice the detail: you went back to main before creating the second branch. That way widen-crm-timeout comes off the base commit, not the previous branch. They're three parallel, independent experiments, not a chain.
Step 3.2. In n8n, go into the Lookup Customer in CRM node (the HTTP Request) and raise its timeout from 5 to 15 seconds, because the CRM sometimes takes a while under load. Save, export, replace the file.
Step 3.3. Review with git diff (look for the timeout inside the CRM node's options) and save:
git add order-triage.json
git commit -m "Widen CRM lookup timeout to 15 seconds"
Phase 4 — Branch 3: routing priority orders
Third iteration: adding a step that routes priority orders after classifying them.
Step 4.1. Again, start from main:
git switch main
git switch -c add-priority-routing
Step 4.2. In n8n, add the routing node (for example a Switch routing based on the order's category), connect it after the classifier, save, export, and replace the file.
Step 4.3. Review with git diff —this change adds an entire node, so the diff will be bigger; locate the new node and its connections— and save:
git add order-triage.json
git commit -m "Add priority routing after classification"
Now you have three feature branches, each with one change, none merged yet. Look at it with lesson 5's branch map:
git switch main
git log --oneline --all --graph
What to expect: the forked tree, with the three branches coming off the base commit, each with its commit. It's the photo of three experiments alive in parallel, on top of a main that stays intact.
Phase 5 — Review and merge into main
Here you decide what goes in. In a real flow you'd review each branch carefully —maybe in a GitHub Pull Request (lesson 6)— before merging. Let's review with diffs and merge all three.
Step 5.1. From main, review what each branch brings before merging it, comparing the branch against main:
git diff main add-wholesale-category
This shows you exactly what the merge would add. Repeat it for the other two branches. Reviewing before merging is the professional habit: you never bring something into main you haven't reviewed.
Step 5.2. Merge the first branch:
git merge add-wholesale-category
What to expect: a Fast-forward, because main hadn't moved. Now main has the wholesale category.
Step 5.3. Merge the second one:
git merge widen-crm-timeout
What to expect: here it might not be a Fast-forward anymore. Since main advanced when merging the first branch, this second branch and main diverged a bit, and Git will create a merge commit joining the two lines —or, if the changes touched different parts of the file, it'll combine them on its own. If by chance both changes touched the same zone of the JSON, a conflict will show up: resolve it as in lesson 5 (identify the two sides, keep the correct one, delete the markers, or replace with a clean export from n8n).
Step 5.4. Merge the third one:
git merge add-priority-routing
Step 5.5. Clean up the already-merged branches and look at the result:
git branch -d add-wholesale-category widen-crm-timeout add-priority-routing
git log --oneline
Your main now contains all three changes. The exact history can vary depending on whether or not there were merge commits, but you should recognize your three features integrated on top of the base commit.
What to check before continuing. Confirm three things before moving on to the rollback. First, that git status says working tree clean —everything merged is saved. Second, that git branch shows only main —the three feature branches already did their job and you deleted them. Third, that your order-triage.json, imported back into n8n, has all three things at once: the wholesale category, the 15-second timeout, and the routing node. This last check is the one that really matters: it proves the three independent branches got integrated into one coherent workflow, which is the whole point of merging. If a feature got lost along the way —because of a badly resolved conflict, for example— this is where you catch it, not in production.
Phase 6 — The rollback: reverting a change that broke the workflow
This is the phase that justifies the whole module. We're going to reproduce Cumbre's "bad Tuesday": introduce a change that breaks the workflow and then cleanly revert it.
Step 6.1. On main, make the bad change: in n8n, point the Lookup Customer in CRM node's url at the staging server (https://crm.cumbre.example/... → https://crm-staging.cumbre.example/...). Save, export, replace the file. Save it:
git add order-triage.json
git commit -m "Point CRM lookup at the staging URL"
Step 6.2. Imagine wholesale orders now stop routing: staging doesn't have those customers. Diagnose before acting, with the diff that confirms the cause:
git diff HEAD~1 HEAD
You should see, among the noise, that the only thing that changed is the CRM's url, from production to staging. Cause confirmed.
Step 6.3. Revert the bad commit, the safe way (lesson 7):
git revert HEAD --no-edit
(The --no-edit accepts the automatic message Revert "Point CRM lookup at the staging URL" without opening the editor.)
What to expect:
[main f1a2b3c] Revert "Point CRM lookup at the staging URL"
1 file changed, 1 insertion(+), 1 deletion(-)
Step 6.4. Read the final history:
git log --oneline
You should see, at the very top, the revert commit, and right below it the bad commit that is still in the history —you didn't delete it, you corrected it. Your order-triage.json points the CRM at production again. The incident got closed with traceability: anyone reading the history sees a mistake was made and got fixed, with a date and an author.
Phase 7 — Connecting and pushing to GitHub
Step 7.1. On GitHub, create an empty and private repository called cumbre-automations (no README, no box checked, lesson 6). Copy its URL.
Step 7.2. Connect and push:
git remote add origin https://github.com/YOUR-USERNAME/cumbre-automations.git
git push -u origin main
Resolve the authentication when it shows up (browser wizard, or PAT/SSH depending on your system).
Step 7.3. Open the URL in the browser and verify: you should see your order-triage.json, your .gitignore, and the complete list of commits with their notes and your name. There's your deliverable, backed up and shareable.
Phase 8 — The portfolio defense
Last deliverable, and it isn't a command. Write five sentences answering the question an interviewer would ask you looking at your git log: "Walk me through the decisions behind this history."
It's exactly the conversation this module prepared you for. The answer "I just made changes" won't do; a good one names the concepts by their name. A reference version, so you see the expected level:
"Every feature lives in its own commit with an imperative message saying what changed and on which node, so the history reads without opening the JSON. I worked every change on a separate feature branch, always starting from
main, somainstayed always ready for production and no experiment put it at risk. I reviewed every branch with a diff before merging it, reading through n8n's JSON noise to separate the real logic from the platform's metadata. When a change pointed the CRM at staging and broke the routing, I diagnosed it withgit diffand undid it withgit revert—notreset— because the commit was already in the shared history, so the rollback stayed recorded and auditable instead of erased. And it's all in a private GitHub repository, which gives the team a backup and a common working point that n8n's Community edition doesn't provide natively."
Notice what that answer does: it doesn't describe commands, it describes judgment. It names why each decision was the right one and what would have broken with the alternative. That's what separates someone who "knows Git" from someone who understands what it's for. And it's, word for word, the kind of conversation lesson 1 promised would open up for you.
Some advice on how to present this in an interview, because the artifact by itself doesn't speak. Share your screen, open your git log --oneline, and walk through it bottom to top like someone telling a story: "here's the base workflow; these three I worked on separate branches so as not to risk production; here someone pointed the CRM at staging and broke it; and here I reverted it auditably instead of deleting it." In thirty seconds you proved, on a real object, that you understand a change's complete lifecycle. Almost nobody applying to an automation role shows up with this; most show up with screenshots of pretty workflows. A git log that reads like a story is a signal of professional maturity that's hard to miss.
Delivery criteria
Review them before considering the project closed:
- The
cumbre-automationsrepository exists, hasgit initdone, and a.gitignoreexcluding credentials. - The base commit
Add order-triage workflowis the history's root. - You made three changes on three different branches, each starting from
main, and merged them. - Every commit has an English message, in the imperative, specific about which node or parameter it touched.
- You reviewed at least one branch with
git diffbefore merging it, and can say what really changed and what was noise. - There's one change reverted with
git revert, and the bad commit still shows up in the history below its revert. -
git log --onelinereads smoothly and tells the workflow's story without ambiguity. - The repository is pushed to GitHub, private, with the entire history visible on the web.
- You have the five-sentence portfolio defense written.
Optional extensions
If you want to keep practicing before starting Module 3, here are three ideas of increasing difficulty. None requires anything you haven't seen:
Easy. Recover the base commit's version of order-triage.json with git checkout <base-ID> -- order-triage.json, look at it, then discard it with git restore order-triage.json to go back to the current one. You practice recovering and discarding without cluttering the history.
Medium. Simulate a coworker: in another folder, git clone your GitHub repository, make a change on the clone, push it with git push, and from your original folder bring it in with git pull. Verify the change traveled from one copy to the other through the remote.
Hard. Create a try-urgent-category branch that adds an urgent category to the classifier, make a commit on it, and then decide not to merge it: delete it with git branch -D from main and verify with git log --oneline that main is exactly as if the experiment had never happened. You practice throwing away an experiment with no scar left behind.
Common mistakes
Chaining the branches instead of all coming off main (practical). What happens: the second branch gets created without going back to main first, leaving widen-crm-timeout hanging off add-wholesale-category instead of the base commit; when merging, the second branch drags along the first one's changes and the history gets tangled. Why it happens: it's easy to forget to go back to main between branches. How to spot it: the git log --oneline --all --graph map shows it —if the branches come off each other in a chain instead of fanning out from the base commit, they're chained. How to fix it: adopt the rhythm of git switch main before every git switch -c new-branch. For independent experiments, every branch comes off the same point.
Merging without reviewing the diff (conceptual). What happens: every branch gets merged blindly with git merge without looking first at what it brings, and something unwanted —an extra moved node, a half-finished change— goes into main without anyone seeing it. Why it happens: merging is a one-line command and reviewing feels optional. How to spot it: if you can't say what each merge changed, you didn't review. How to fix it: run git diff main <branch> before every git merge, and read the result with lesson 4's four rules. On a team, this review is the Pull Request; solo, it's your own discipline. main only receives what's been reviewed.
Using reset instead of revert for phase 6's rollback (conceptual). What happens: to undo the bad change, git reset --hard HEAD~1 gets used instead of git revert, deleting the bad commit from the history. Why it happens: reset feels "cleaner" because the bad commit disappears. How to spot it: if after the rollback the Point CRM lookup at the staging URL commit no longer shows up in git log, you used reset. How to fix it: for this project —and for almost anything going to a shared remote— the correct path is revert, which keeps the bad commit and adds its correction. The deliverable asks precisely for an auditable rollback: the value is in the mistake staying visible next to its amendment. reset would erase that audit trail.
Pushing the repository as public, or with a secret inside (practical and serious). What happens: the GitHub repo gets created as public, or gets pushed without having set up the .gitignore, exposing business logic or a credential. Why it happens: the public option is sometimes preselected, and without a .gitignore a nearby secret sneaks in easily. How to spot it: before the push, review with git log and git status what's versioned; on GitHub, confirm the repo says "Private." How to fix it: private repo by default, and .gitignore from the base commit (phase 0). If you already pushed a secret, switching to private isn't enough: the secret has to be rotated and cleaned from the history, a Module 3 topic. Think about visibility and secrets before pushing.
Exercises
Exercise 1 — Audit your own history. Open your finished git log --oneline and, putting yourself in an outside reviewer's shoes who didn't watch you build it, answer: can you understand what each commit does just from its message, without opening the JSON? Is there a vague message you'd rewrite? Does the rollback read as such? Note what you'd improve.
See solution
There's no single answer; the value is in looking at your own work with someone else's eyes. The concrete test is this: cover the codes and read only the message column. If the story reads smoothly —"the workflow got added, then the wholesale category, then the timeout got widened, then priority routing, then someone pointed the CRM at staging and it got reverted"— your history passes the test. If any message forces you to open the commit to know what it did, that's the one you'd rewrite.
Why it works: auditing your own history is the skill that really matters, because the history is going to be read by others (or your future self) without the context you have fresh today. A git log that's understood without opening a single commit is the mark of a professional repository, and it's the first thing whoever evaluates your portfolio looks at.
Exercise 2 — Explain the rollback to someone who doesn't know Git. Imagine a Cumbre colleague who's never used Git asks you: "why is the bad commit still there? wouldn't it be cleaner to delete it?" Answer in three or four sentences, without jargon, explaining why keeping the bad commit next to its revert is better than deleting it.
See solution
A good answer goes like this: deleting the bad commit would hide that the mistake happened, and on a team that's worse than leaving it visible —nobody would learn from it, and if someone else had a copy with that commit, the two histories would stop matching and it'd cause a mess. Keeping it alongside its correction is like an adjustment line in a ledger book: the mistake stays visible and so does its amendment, so anyone can audit what happened, who did it, and how it got fixed. The history tells the whole truth, which is exactly what you want when something went wrong.
Why it works: being able to explain a technical concept without jargon, to someone who doesn't know it, is the most honest proof that you understood it yourself. And this particular explanation —traceability over deletion— is the heart of why professional version control prefers revert over reset for shared work. If you can defend it to a colleague, you can defend it in an interview.
Exercise 3 — Design the next iteration. Cumbre asks you for a new change: add a node that logs every classified order to a spreadsheet, for audit purposes. Without writing the code, describe the complete Git flow you'd follow to make this change professionally, from before touching n8n to the change being on main on GitHub. Name every command.
See solution
A complete professional flow:
git switch mainandgit pull— start from a cleanmain, updated with whatever's on the remote.git switch -c add-order-logging— create the feature branch for this change.- You make the change in n8n (add the logging node), save and export, replacing
order-triage.json. git diff— review that the change is what you wanted and only that, reading through the noise.git add order-triage.jsonandgit commit -m "Log classified orders to the audit sheet"— save with a clear message.git switch mainandgit diff main add-order-logging— go back tomainand review what the merge would bring.git merge add-order-logging— merge (resolving a conflict if one shows up).git branch -d add-order-logging— clean up the merged branch.git push— push the updatedmainto the remote.
Why it works: this exercise asks you to orchestrate the entire module as a single fluid motion, which is exactly what you'll do in real work every time you touch a workflow. When this flow comes to you from memory —without thinking about each command separately— you stopped "knowing Git commands" and started having a process, which is what makes an automation system owner.
Summary and next step
With this project you close Module 2. You took Cumbre's order-triage and put it under version control end to end: you initialized it with a .gitignore protecting the secrets, made the base commit, iterated on it across three different branches —wholesale category, CRM timeout, priority routing— reviewed each one with its diff before merging it into main, reproduced Cumbre's "bad Tuesday" and closed it with a clean, auditable git revert, and pushed it all to a private GitHub repository. And you wrote the portfolio defense: the conversation, backed by judgment and not by commands, that you're going to be asked for in an interview looking at your git log.
You can now: install and configure Git; create a repository; make clean commits with good messages; read diffs through n8n's JSON noise; experiment on branches without risking the good version; back up and share on GitHub; and go back when something breaks, with precision, traceability, and confidence. Not bad for not having known, eight lessons ago, what a commit was.
And that's exactly Module 3's starting point. In this module we lived with an annoyance we deliberately put off, over and over: n8n's JSON noise —the versionIds, the canvas positions, the pinData— cluttering every diff and enlarging every conflict. You learned to read through that noise, which was the right skill for working today. Module 3 eliminates it at the root: you're going to export workflows with n8n's CLI, separate credentials from the repository once and for all, normalize the JSON so your diffs come out as clean as the "ideal world" you saw in lesson 4, and structure and document the repository for handoff —the "documented" part of "version-controlled, documented JSON." You have the lifecycle under control; now let's leave the repository spotless.
Resources
- Git Basics — Git Docs — the chapter walking through the complete cycle you assembled in this project, from
inittopush. A good comprehensive review. - git merge — Git Docs — the merge reference, useful for phase 5's three merges and for understanding when a merge commit shows up instead of a fast-forward.
- git revert — Git Docs — the reference for phase 6's auditable rollback, with the
--no-editoption. - Source control and environments — n8n Docs — the background on how n8n conceives version control, which Module 3 and Module 6 develop further; useful for placing what you did by hand against what the platform offers.
- Export and import workflows — n8n Docs — how to export the workflow you versioned; Module 3 takes it further with CLI export for clean diffs.