Git as Legal Evidence — Policy Versioning & Proof System
Purpose: This guide documents how to use git to prove — with timestamps you cannot fake — what your policies said on any given date. Use this for enterprise client disputes, regulatory audits, or any situation where you need to demonstrate the state of a policy at contract signing.
Everything here works with your existing git repository. No extra tools required for the basics. Automation options are covered for higher-stakes engagements.
Why Git Is Legally Strong Evidence
A git commit produces a SHA-1 hash — a 40-character fingerprint of the file content + the author + the timestamp + the previous commit hash. Change any one of those, and the hash changes completely.
commit d784454a3f91b2c8e0f1a2b3c4d5e6f7a8b9c0d1
Author: Jean-Philippe Kraft <jp@webility.local>
Date: Wed Feb 19 14:32:07 2026 -0500
Publish Refund Policy v1.0 — initial release
What this means in a dispute:
- The timestamp is recorded by your local machine and by GitHub's servers — two independent clocks
- The hash is mathematically impossible to forge without changing the content
- GitHub keeps immutable records of every push — even if you delete a branch, GitHub's logs retain it
- You cannot insert a commit into history without every subsequent hash changing (making tampering obvious)
A lawyer or a judge who asks a forensic expert will be told: "The git history has not been tampered with."
Part 1 — Basic Commands: Extracting Proof on Demand
These are the commands you run when a dispute arises. No setup needed — they work on any git repo right now.
1.1 Show the Full History of a Policy File
git log --follow --format="%H | %ai | %s" -- docs/legal/policies/refund-cancellation-policy.md
Output:
a1b2c3d4... | 2026-03-01 09:14:22 +0000 | Update Refund Policy v1.0→v1.1: added maintenance cancellation clause
d784454a... | 2026-02-19 14:32:07 -0500 | Publish Refund Policy v1.0 — initial release
This tells you: on February 19, 2026, the policy was first published. On March 1, it was updated.
If a client signed on February 22, they signed under v1.0. If they signed on March 5, they signed under v1.1.
1.2 Show the Exact Content of a Policy on Any Date
Method A — by date:
git show $(git rev-list -1 --before="2026-02-22 23:59:59" HEAD -- docs/legal/policies/refund-cancellation-policy.md):docs/legal/policies/refund-cancellation-policy.md
This prints the exact text of the refund policy as it existed at the end of February 22, 2026. Copy-paste this into a document as your evidence.
Method B — by commit hash (more precise):
git show d784454a:docs/legal/policies/refund-cancellation-policy.md
Replace d784454a with the commit hash from the git log output above.
1.3 Generate a Signed Evidence Report for a Client or Dispute
Run this to produce a timestamped report of all policy files, their last change date, and their current commit hash:
git log --format="%H | %ai | %an | %s" -- docs/legal/policies/ | head -20
To get an evidence report for all policies at once, listing each file's last commit:
for f in docs/legal/policies/*.md; do
echo "--- $f ---"
git log -1 --format="Commit: %H%nDate: %ai%nAuthor: %an%nChange: %s%n" -- "$f"
done
Save this output to a PDF (copy into a document, print to PDF, date-stamp the filename) and store it in the client's project folder at signing.
1.4 Get a Shareable Permalink to Any Policy Version
Every commit on GitHub has a permanent URL that never changes, even if you later update the file:
https://github.com/[your-org]/launchko-frontend/blob/[COMMIT-HASH]/docs/legal/policies/refund-cancellation-policy.md
Example:
https://github.com/launchko/launchko-frontend/blob/d784454a/docs/legal/policies/refund-cancellation-policy.md
This URL shows the exact content of that file at that commit — forever. You can share it in a legal response email and the other party can verify it themselves.
To get this URL quickly:
# Get the commit hash for the policy at the time of signing
git rev-list -1 --before="2026-02-22" HEAD -- docs/legal/policies/refund-cancellation-policy.md
# Output: d784454a3f91b2c8e0f1a2b3c4d5e6f7a8b9c0d1
# Permalink: https://github.com/[org]/launchko-frontend/blob/d784454a/docs/legal/policies/refund-cancellation-policy.md
Part 2 — Git Tags: Pinning Policy Versions Permanently
Tags are named bookmarks on a specific commit. Unlike branches, tags never move. A tag called policy/refund-v1.0 will always point to the same commit forever.
2.1 Tag a Policy When You Publish or Update It
# When publishing the initial Refund Policy
git tag -a "policy/refund-v1.0" -m "Refund & Cancellation Policy — initial release (WBL-POL-RCP-v1.0)"
# When you update it
git tag -a "policy/refund-v1.1" -m "Refund Policy v1.1 — added maintenance plan cancellation terms (2026-03-01)"
# Push tags to GitHub (they don't push automatically)
git push origin --tags
2.2 Reference Tags in Contracts
Now your contract clause becomes:
"...subject to Webility's policies as published at webility.local/legal. The versions in effect at the date of this Agreement are archived at:
github.com/[org]/launchko-frontend/releases/tag/policy/refund-v1.0(and corresponding policy tags). These tagged releases constitute Webility's official policy archive."
The client's lawyer can follow that URL and see the exact policy text, signed by the commit timestamp and GitHub's servers.
2.3 View All Policy Tags
git tag -l "policy/*"
Output:
policy/aup-v1.0
policy/ip-v1.0
policy/privacy-v1.0
policy/refund-v1.0
policy/refund-v1.1
policy/tos-v1.0
Part 3 — GPG-Signed Commits (Enterprise / High-Stakes)
For enterprise clients or regulated industries (healthcare, finance), you can cryptographically sign every commit with your personal GPG key. This adds a layer of non-repudiation — the commit is mathematically tied to your identity, not just your git username.
GitHub shows a green "Verified" badge on signed commits.
3.1 Set Up GPG Signing (One-Time)
# Generate a GPG key (if you don't have one)
gpg --full-generate-key
# Choose RSA 4096-bit, your name, your agency email
# Get your key ID
gpg --list-secret-keys --keyid-format=long
# Output: sec rsa4096/[YOUR-KEY-ID] 2026-02-19 [SC]
# Tell git to use it
git config --global user.signingkey [YOUR-KEY-ID]
git config --global commit.gpgsign true # Auto-sign all commits
git config --global tag.gpgsign true # Auto-sign all tags
# Add your public key to GitHub
# Settings → SSH and GPG keys → New GPG key
gpg --armor --export [YOUR-KEY-ID]
3.2 Sign a Specific Commit or Tag
# Sign a commit
git commit -S -m "Publish Privacy Policy v1.0 — GDPR/PIPEDA/Law25 compliant"
# Sign a tag
git tag -s "policy/privacy-v1.0" -m "Privacy Policy v1.0 — initial release"
# Verify a signed commit
git verify-commit d784454a
# Verify a signed tag
git verify-tag policy/privacy-v1.0
In a dispute: you can demonstrate that:
- The commit is cryptographically signed with your GPG key
- Your GPG key was registered with GitHub at a known date
- Therefore the commit is authentic and the timestamp is genuine
Part 4 — GitHub Releases: Enterprise Policy Archive
For enterprise clients, create a GitHub Release for each policy version. A release bundles a tag with release notes and optionally attached files (PDFs, changelogs). It is publicly accessible and permanently linked.
4.1 Create a Policy Release Manually
On GitHub: Releases → Draft a new release → Choose tag (e.g., policy/refund-v1.1)
Release title: Refund & Cancellation Policy — v1.1 (2026-03-01)
Release notes:
## Webility Refund & Cancellation Policy — v1.1
**Effective date**: 2026-03-01
**Previous version**: v1.0 (2026-02-19)
### Changes from v1.0
- Added Section 3.4: Monthly maintenance plan cancellation terms
- Clarified Section 2.1: Deposit non-refundability applies to all service types
### Full policy
See `docs/legal/policies/refund-cancellation-policy.md` in this release.
Attach a PDF of the policy (print-to-PDF from the website on that date).
Result: A permanent URL like:
https://github.com/[org]/launchko-frontend/releases/tag/policy%2Frefund-v1.1
This URL includes the release notes, the commit hash, the date, attached PDF, and the complete git diff showing exactly what changed from the previous version.
Part 5 — Automated Policy Archiving with GitHub Actions
For enterprise-level rigor, automate the entire process. This GitHub Action runs automatically whenever you update any policy file — it tags the version, generates a changelog, and submits the URL to the Internet Archive.
5.1 Create the Workflow File
# .github/workflows/policy-archive.yml
name: Policy Archive
on:
push:
paths:
- 'docs/legal/policies/**'
branches:
- master
jobs:
archive-policies:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect changed policy files
id: changes
run: |
CHANGED=$(git diff --name-only HEAD~1 HEAD -- docs/legal/policies/)
echo "changed_files=$CHANGED" >> $GITHUB_OUTPUT
echo "Changed policies: $CHANGED"
- name: Log policy change with timestamp
run: |
echo "=== POLICY CHANGE LOG ===" >> policy-change.log
echo "Timestamp: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> policy-change.log
echo "Commit: ${{ github.sha }}" >> policy-change.log
echo "Author: ${{ github.actor }}" >> policy-change.log
echo "Message: ${{ github.event.head_commit.message }}" >> policy-change.log
echo "Files changed:" >> policy-change.log
echo "${{ steps.changes.outputs.changed_files }}" >> policy-change.log
cat policy-change.log
- name: Submit policy pages to Internet Archive
run: |
# Submit each policy URL to the Wayback Machine
URLS=(
"https://webility.local/terms"
"https://webility.local/privacy"
"https://webility.local/refunds"
"https://webility.local/ip-policy"
"https://webility.local/aup"
"https://webility.local/ai-policy"
"https://webility.local/sla"
"https://webility.local/cookies"
)
for URL in "${URLS[@]}"; do
echo "Archiving: $URL"
curl -s "https://web.archive.org/save/$URL" -o /dev/null || echo "Archive failed for $URL (non-critical)"
sleep 2 # Be respectful of the Archive's rate limits
done
- name: Post summary to commit status
run: |
echo "## Policy Archive Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Commit**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
echo "**Date**: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Changed files:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "${{ steps.changes.outputs.changed_files }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Permalink to this policy state:**" >> $GITHUB_STEP_SUMMARY
echo "https://github.com/${{ github.repository }}/tree/${{ github.sha }}/docs/legal/policies" >> $GITHUB_STEP_SUMMARY
What this does automatically on every policy push:
- Detects which policy files changed
- Logs the change with an immutable timestamp tied to the commit SHA
- Submits all policy URLs to the Internet Archive
- Generates a GitHub Actions summary with the permanent permalink
You can view this log in GitHub under Actions → Policy Archive → [run].
Part 6 — The Contract Clause That Uses All of This
Upgrade the policy incorporation clause in your contracts to reference the git archive explicitly:
For SMB Contracts (concise)
Incorporated Policies: Client agrees to Webility's published policies at webility.local/legal (Terms of Service, Privacy Policy, Refund Policy, IP Policy, AUP, and AI Use Policy). The versions in effect at the date of this Agreement are preserved in Webility's version-controlled policy repository. Policies may be updated with 30 days' written notice; prior versions remain binding for work commenced under this Agreement.
For Enterprise Contracts / MSA (explicit)
Incorporated Policies and Version Control: Client agrees to Webility's published policies available at webility.local/legal. The specific versions in effect at the Effective Date of this Agreement are:
Policy Version Git Tag Effective Date Terms of Service v1.0 policy/tos-v1.02026-02-19 Privacy Policy v1.0 policy/privacy-v1.02026-02-19 Refund & Cancellation Policy v1.0 policy/refund-v1.02026-02-19 Intellectual Property Policy v1.0 policy/ip-v1.02026-02-19 Acceptable Use Policy v1.0 policy/aup-v1.02026-02-19 AI Use Policy v1.0 policy/ai-v1.02026-02-19 The above tagged versions are permanently accessible at:
https://github.com/[org]/launchko-frontend/releasesWebility maintains a cryptographically signed, version-controlled archive of all policy changes. This archive constitutes the authoritative record of policy content for any dispute resolution under this Agreement.
Part 7 — Dispute Response Template
When a client disputes what your policy said, send this:
Subject: Policy Version Evidence — [CLIENT NAME] — [PROJECT]
[Client Name],
You have raised a question about the content of our [Refund / IP / Terms] Policy
at the time you signed your contract on [DATE].
I am providing the following evidence:
1. SIGNED CONTRACT
Your contract dated [DATE] references [Policy Name] v[X.X].
[Attach signed PDF from DocuSign]
2. GIT COMMIT RECORD
The policy was in the following state on [DATE]:
Commit: [FULL SHA HASH]
Timestamp: [DATE TIME TIMEZONE]
GitHub permalink: https://github.com/[org]/launchko-frontend/blob/[SHA]/docs/legal/policies/[file].md
3. INTERNET ARCHIVE SNAPSHOT
Independent third-party archive of the live page on [DATE]:
https://web.archive.org/web/[TIMESTAMP]/webility.local/[policy-page]
4. POLICY PDF SNAPSHOT
Attached is the PDF snapshot of the policy page stored in our records
at the time of contract signing.
[Attach PDF from client project folder]
These four independent sources confirm the policy text in effect on [DATE].
The policy has [not changed / changed on [DATE] as follows: ...].
Please let me know if you have further questions.
[NAME]
Webility
Part 8 — Quick Reference Cheat Sheet
TASK COMMAND
──────────────────────────────────────────────────────────────────────
Show history of a policy file git log --follow --format="%H | %ai | %s" -- [file]
Show policy content at a date git show $(git rev-list -1 --before="YYYY-MM-DD" HEAD -- [file]):[file]
Show policy content at a commit git show [COMMIT-HASH]:[file]
Tag a new policy version git tag -a "policy/[name]-v[X.X]" -m "[message]"
Push tags to GitHub git push origin --tags
List all policy tags git tag -l "policy/*"
Verify a signed commit git verify-commit [COMMIT-HASH]
Get permalink for a commit https://github.com/[org]/[repo]/blob/[HASH]/[path]
Show what changed between versions git diff policy/refund-v1.0 policy/refund-v1.1 -- docs/legal/policies/refund-cancellation-policy.md
Generate policy state report git log --format="%H | %ai | %an | %s" -- docs/legal/policies/
Archive a URL to Wayback Machine curl -s "https://web.archive.org/save/https://webility.local/terms"
Part 9 — Maintenance Schedule
| When | Action |
|---|---|
| First policy publish | Create git tag policy/[name]-v1.0, push to GitHub, submit URL to web.archive.org |
| Every policy update | Bump version in doc, update changelog section in doc, commit with descriptive message, create new git tag, push tags |
| Every enterprise contract signed | Note the commit hash in contract, store policy snapshot PDFs in client project folder |
| Quarterly | Run git tag -l "policy/*" to verify all policies are tagged; check archive.org for recent snapshots |
| Policy dispute arises | Run commands in Part 1 to extract evidence; use dispute response template in Part 7 |
Webility — GIT-LEGAL-EVIDENCE-v1.0 Internal reference — legal operations and evidence management. Keep this repo hosted on GitHub. The remote timestamps are what make this evidence credible.