Extract both file versions from a diff

Paste a unified diff — git diff, git show, git format-patch, diff -u, or a .patch file — and get the original text and the patched text back, with the parts the diff never carried marked instead of quietly closed up.

Try:
Reconstructed text

About this tool

Sometimes the patch is all you were sent. A .patch attachment on a mailing list, a diff pasted into a chat thread, a code-review snippet, a fragment in a bug report, a hunk in a CI log — and no copy of the file it came from. Every other diff tool asks you to supply the original file first and then applies the patch to it. This one works the other way round: it reads the diff by itself and rebuilds the two file versions the diff describes, using the context lines the diff already carries.

Paste the output of git diff, git show, git format-patch, diff -u, or svn diff. Mail preambles, index and file-mode lines, similarity index headers and git format-patch signature blocks are ignored, so you can paste a whole patch email without trimming it first.

Worked example

Input diff:

--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
 fn main() {
     let x = 1;
+    let y = 2;
     println!("{x}");
 }

Output with Both versions, labelled:

===== BEFORE: src/main.rs =====
fn main() {
    let x = 1;
    println!("{x}");
}
===== AFTER: src/main.rs =====
fn main() {
    let x = 1;
    let y = 2;
    println!("{x}");
}

Choose Original (before) text only to get just the first block with no banner — copy-paste-ready, byte for byte, including tabs and CRLF line endings.

What a diff cannot tell you

A diff records the neighbourhood of each change, not the file. With the usual three lines of context, everything between two hunks and everything after the last hunk is simply absent from the patch, and no tool can invent it. Rather than silently joining unrelated regions together, this one accounts for what is missing:

   | [... 8 lines not in the diff (lines 1-8) ...]
 9 | nine
10 | ten

Switch the gap handling to Omit when you only want the recoverable fragments spliced together, or to Refuse a partial reconstruction when a half-file result would be worse than an error. If you control how the diff is produced, git diff -U100000 embeds the whole file as context and the reconstruction becomes exact.

Options and limits

FAQ

Do I need the original file?

No — that is the whole point of this tool. It reconstructs both versions from the patch alone. If you do have the original file and want the patched result, that is applying a patch, and a dedicated apply-patch tool is the better fit.

Why does my output start with a "lines not in the diff" marker?

Because the first hunk does not begin at line 1. A diff carries only the context around each change, so the lines before the first hunk were never in the text you pasted. The marker counts exactly how many lines are missing and which line numbers they occupied, so you can splice the result back into a real file with confidence.

Can I get the whole file back instead of fragments?

Only if the diff carries the whole file. Re-generate it with full context — git diff -U100000 — and the reconstruction covers everything up to the last line the diff mentions. Nothing after the final hunk is knowable from any diff, because a diff never records how long the file is.

What does the JSON output contain?

One entry per file: both paths, the status (modified, added, deleted, renamed, binary), the hunk count, added and removed line counts, a complete flag, the exact missing line ranges for each side, whether the header counts had to be corrected, the trailing-newline state, and the two reconstructed texts. It is the machine-readable version of the same result.

My diff came from an email and it will not parse.

Mail clients word-wrap long lines, which destroys the leading +/-/space marker that every hunk line must start with. The error message names the exact line so you can unwrap it. Lines that merely lost a single trailing space (a common transformation for blank context lines) are repaired automatically, since that fix is unambiguous.

Which diff dialects are supported?

Unified diff in its common spellings: git diff / git show (with diff --git, index, mode, rename and new file headers), git format-patch mail patches, POSIX diff -u with timestamped ---/+++ headers, and svn diff with its Index: headers. The a/ and b/ prefixes are stripped for display.

Developer & Automation Access

Run it from the terminal

Same engine as this page, headless — via the gizza CLI:

gizza tool diff-extract-versions '--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
 fn main() {
     let x = 1;
+    let y = 2;
     println!("{x}");
 }'

New to the CLI? Get gizza →

Open it by URL

Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:

https://gizza.ai/tools/diff-extract-versions/?diff=---%20a%2Fsrc%2Fmain.rs%0A%2B%2B%2B%20b%2Fsrc%2Fmain.rs%0A%40%40%20-1%2C4%20%2B1%2C5%20%40%40%0A%20fn%20main%28%29%20%7B%0A%20%20%20%20%20let%20x%20%3D%201%3B%0A%2B%20%20%20%20let%20y%20%3D%202%3B%0A%20%20%20%20%20println%21%28%22%7Bx%7D%22%29%3B%0A%20%7D&output=both&file=src%2Fmain.rs%20%20%C2%B7%20%20%2A.rs%20%20%C2%B7%20%20leave%20empty%20for%20all&gaps=marker&line_numbers=true

Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.