Force Overwrite¶
Sometimes the simplest solution is the best: just overwrite it.
The Pattern¶
Force overwrite skips existence checks entirely. The operation succeeds whether the target exists or not, and the final state is always the desired state.
flowchart LR
A[Source] --> B[Overwrite]
B --> C[Target = Source]
%% Ghostty Hardcore Theme
style A fill:#65d9ef,color:#1b1d1e
style B fill:#fd971e,color:#1b1d1e
style C fill:#a7e22e,color:#1b1d1e
Zero Decisions
Force overwrite has no branches in its logic. The target becomes the source, period. Previous state is irrelevant.
When to Use¶
Good Fit
- Writing configuration files (same content = same result)
- Syncing files where source is authoritative
- Branch resets where local state should match remote
- Cache population where stale data should be replaced
- Artifact uploads where latest version wins
Poor Fit
- Resources with history you want to preserve
- Collaborative content (user edits would be lost)
- Operations where overwrites have side effects
- When you need to know if content actually changed
Examples¶
File Synchronization¶
Git Branch Reset¶
The -B flag creates the branch if it doesn't exist, or resets it if it does.
Git Push with Lease¶
--force-with-lease overwrites the remote but fails if someone else pushed changes you haven't seen. It's force overwrite with a safety net.
Configuration Files¶
GitHub Actions Artifacts¶
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
overwrite: true # Explicitly overwrite if exists
Safe Force Overwrite Patterns¶
Force with Lease (Git)¶
# Overwrites remote branch, but fails if remote changed unexpectedly
git push --force-with-lease origin feature-branch
This prevents accidentally overwriting someone else's commits while still enabling idempotent branch updates.
Atomic Write (Files)¶
# Write to temp file, then atomically move
cat > "$TARGET.tmp" << 'EOF'
content here
EOF
mv -f "$TARGET.tmp" "$TARGET"
Atomic write prevents partial content if the process is interrupted.
The Temp-Then-Move Pattern
Always use write-to-temp + atomic move for critical files. A mv on the same filesystem is atomic; a multi-megabyte write is not.
Backup Before Overwrite¶
# Preserve previous version just in case
cp "$TARGET" "$TARGET.bak" 2>/dev/null || true
cp -f "$SOURCE" "$TARGET"
Conditional Force Based on Content¶
# Only force overwrite if content differs
if ! diff -q "$SOURCE" "$TARGET" &>/dev/null; then
cp -f "$SOURCE" "$TARGET"
echo "Updated $TARGET"
else
echo "No changes needed"
fi
This hybrid approach avoids unnecessary writes while still being idempotent.
GitHub Actions Examples¶
Cache Overwrite¶
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ hashFiles('package-lock.json') }}
# Cache is overwritten on key match (save always runs)
Artifact Replacement¶
- name: Upload coverage report
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
overwrite: true
retention-days: 5
Environment Variable Override¶
- name: Set deployment version
run: |
# Always overwrites previous value
echo "DEPLOY_VERSION=${{ github.sha }}" >> "$GITHUB_ENV"
Kubernetes Examples¶
ConfigMap Replacement¶
# Delete and recreate (force overwrite pattern)
kubectl delete configmap app-config --ignore-not-found
kubectl create configmap app-config --from-file=config/
Or use the declarative approach:
Secret Rotation¶
# Force-replace secret
kubectl create secret generic db-creds \
--from-literal=password="$NEW_PASSWORD" \
--dry-run=client -o yaml | kubectl apply -f -
Edge Cases and Gotchas¶
Loss of History¶
Force overwrite destroys previous state:
Mitigation: Use version control or backups for important files.
Unexpected Content Changes¶
If source content changes between runs, target changes too:
# Run 1: writes v1.0
cp -f release.tar.gz /deploy/
# Run 2: writes v1.1 (source changed)
cp -f release.tar.gz /deploy/
Consideration: This might be desired (latest wins) or problematic (version mismatch).
Force Push Dangers¶
Never Force Push to Shared Branches
git push --force to main or master can destroy your team's work. Commits they pushed will vanish. Always use --force-with-lease at minimum.
Partial Writes¶
Non-atomic overwrites can leave corrupt state:
Mitigation: Write to temp file, then atomic move.
Anti-Patterns¶
Force Push to Shared Branches¶
# Bad: destroys others' work without warning
git push --force origin main
# Better: use force-with-lease
git push --force-with-lease origin main
# Best: don't force push to main at all
Silent Overwrites of User Data¶
# Bad: user's customizations lost without warning
cp -f default.config ~/.myapp/config
# Better: merge or prompt
if [ -f ~/.myapp/config ]; then
echo "Config exists. Overwrite? (y/n)"
fi
Overwrite Without Verification¶
# Bad: no way to know if overwrite was needed
cp -f source target
# Better: log whether content changed
if ! diff -q source target &>/dev/null; then
cp -f source target
echo "Updated target"
fi
Comparison with Other Patterns¶
| Aspect | Check-Before-Act | Upsert | Force Overwrite |
|---|---|---|---|
| Preserves history | Yes | Depends | No |
| Requires existence check | Yes | No | No |
| Shows if content changed | Yes | Sometimes | No (unless you add diff) |
| Simplicity | Medium | High | Highest |
Summary¶
Force overwrite is the simplest idempotency pattern.
Key Takeaways
- Use for authoritative sources - when your source is always correct
- Add safety nets -
--force-with-lease, atomic writes, backups - Consider history - don't destroy data you might need
- Log changes - add diff checks if you need visibility into what changed