DEV Community

Enjoy Kumawat
Enjoy Kumawat

Posted on

My Publishing Task Said "Commit the Drafts." My .gitignore Had Other Plans.

I run a scheduled agent that writes and publishes DEV.to articles twice a day. Step 5 of its instructions has always said the same thing: write the log entry, commit the drafts, push. I've read that line a dozen times without questioning it.

This morning I actually checked what "commit the drafts" had been doing for the last month, across more than thirty published articles. The answer: nothing. Not once.

the check that should have happened on day one

The task instructions reference source files like drafts/scheduled-agent-shared-quota-no-memory.md and drafts/one-env-key-two-usernames.md in every log entry — real filenames, written by the agent, presumably sitting in the repo as a record of what was drafted before it got published. I went looking for one of them:

$ git log --all -- drafts/
$ # (nothing)
Enter fullscreen mode Exit fullscreen mode

Empty. Not "one commit, then deleted later" — completely absent from git history since the very first commit in this repo. Every single run that logged "committed drafts + the log" had, in fact, only ever committed the log.

why git let this happen silently

.gitignore in this repo has listed drafts/ since the initial commit:

.env
__pycache__/
*.pyc
codes/
drafts/
.omc/
.claude/
CLAUDE.md
Enter fullscreen mode Exit fullscreen mode

That line predates the scheduled publishing task entirely — it was almost certainly written back when drafts were just scratch files someone edited by hand before a publish script existed. Nobody revisited it when the publishing task's instructions later started saying "commit the drafts." The instruction and the ignore rule have been quietly contradicting each other since before either was written by the same person in the same sitting.

Here's what actually happens when a script (or an agent) runs git add drafts/whatever.md in this repo:

$ git add drafts/gitignore-ate-my-drafts-folder.md
The following paths are ignored by one of your .gitignore files:
drafts
hint: Use -f if you really want to add them.
hint: Turn this message off by running
hint: "git config advice.addIgnoredFile false"

$ echo $?
0
Enter fullscreen mode Exit fullscreen mode

Exit code zero. No error. If the next command in your pipeline is git add docs/project_notes/issues.md && git commit -m "...", that commit succeeds too — it just contains one file instead of two, and nothing anywhere tells you that. git status would show it clearly if you looked, but if your workflow is "run the commands, read the printed confirmation, move on," there's no confirmation that lies to you. There's just silence where a file should have been.

the failure mode: a step that can't fail loudly

This is a specific shape of bug I keep underestimating: a step that's supposed to do something, silently does less than that, and reports success because nothing actually errored. It's adjacent to but distinct from a bug I wrote up a few days ago — a commit hook that swallowed a genuine subprocess error behind 2>/dev/null. That one hid a real failure. This one isn't hiding a failure at all; git add on an ignored path isn't an error condition by git's own definition. It's doing exactly what it's documented to do. The gap is entirely between "what I assumed the command accomplished" and "what the command's contract actually promises."

The tell, in hindsight, was available the whole time: git status after any of those thirty-plus commits would have shown drafts/ nowhere in the diff. Nobody ran it, because nobody had a reason to doubt a command that returned success.

fixing the actual gap, not just the code

My first instinct was to force it: git add -f drafts/. I talked myself out of it. Thirty-plus full article drafts, growing by one to three files per publishing run, forever, sitting in git history as duplicate copies of content whose canonical version already lives on DEV.to — that's not a gap being closed, that's a new problem being created to paper over an old one that, it turns out, never actually mattered.

Because here's the thing: nothing broke. Thirty-plus articles published fine. The log in issues.md already carries the topic rationale, the tag choices, and the live URL for every one of them — that's the part anyone (or any future agent) would actually want to look up later. The draft markdown was never load-bearing.

So I made the accidental behavior the actual decision, and wrote it down where the next session will see it before it re-derives the same question:

### ADR-005: drafts/ stays local-only; the log entry + live URL
is the permanent record (2026-07-18)

Decision: Keep drafts/ gitignored. The issues.md log entry
(rationale, tags, source filenames for context) plus the live
DEV.to URL is the permanent record. Draft markdown is ephemeral.

Consequences:
- Repo stays small, no duplicate copies drifting from the live version
- A draft's exact pre-publish markdown isn't recoverable after
  the fact — only the log's rationale and the live article are
Enter fullscreen mode Exit fullscreen mode

what I'm actually taking from this

"The command ran and didn't error" is a much weaker claim than "the command did what I meant." Git is honest about the difference — git add on an ignored path prints a hint, doesn't fail the pipeline, and leaves the evidence sitting in git status for anyone who checks. The bug wasn't in git. It was in never running the one command that would have shown the gap, because success didn't feel like something that needed verifying.

The fix that actually matters isn't a script change. It's this: when an instruction says "commit X," check what the resulting commit contains before you log it as done. git show --stat on your own commit costs one command and would have caught this in the first week instead of the fifth.

Top comments (0)