Bash – Packaging a directory and its contents as a diff patch

bashdiff()patch

I have a small project folder with text files, which I'd like to post somewhere in order to ask a question on a forum. Let's take, in the simplest case, that I have something like this:

mkdir aaa
cd aaa
echo AAA > aaa.txt
mkdir bbb
echo BBB > bbb/bbb.txt

Obviously, I'd like the subfolder structure:

aaa/
├── aaa.txt
└── bbb
    └── bbb.txt

… to be preserved when I share this. So I thought first using https://gist.github.com/ and entering subdirectory names for each file; unfortunately github responds with:

Contents files can't be in subdirectories or include '/' in the name

… and I don't intend to register there, just to be able to check out and commit subdirectories to the gist via git, for something like this (one would wish they accepted openID, but… eh).

So, I thought, maybe I can somehow package the entire directory structure and the file contents as a diff patch file; then as a single file, it should be easy to upload to a gist. However, I don't know how to specify a diff between my folder and an empty folder; I tried:

$ diff -Naur /dev/null /tmp/aaa
diff: /tmp/aaa/null: No such file or directory

… but clearly, that doesn't work.

However, in principle it should be possible – here is a test case via git:

mkdir aaa
cd aaa
git init
git config user.name test
git config user.email test@test.com

echo AAA > aaa.txt
mkdir bbb
echo BBB > bbb/bbb.txt

git add .
git commit -m 'initial commit'
git format-patch -1 HEAD

At this point, a file 0001-initial-commit.patch appears, with these contents:

From 5834ae98fad9a9148648577f366af3498be6d364 Mon Sep 17 00:00:00 2001
From: test <test@test.com>
Date: Wed, 16 Dec 2015 10:25:23 +0100
Subject: [PATCH] initial commit

---
 aaa.txt     | 1 +
 bbb/bbb.txt | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 aaa.txt
 create mode 100644 bbb/bbb.txt

diff --git a/aaa.txt b/aaa.txt
new file mode 100644
index 0000000..43d5a8e
--- /dev/null
+++ b/aaa.txt
@@ -0,0 +1 @@
+AAA
diff --git a/bbb/bbb.txt b/bbb/bbb.txt
new file mode 100644
index 0000000..ba62923
--- /dev/null
+++ b/bbb/bbb.txt
@@ -0,0 +1 @@
+BBB
-- 
1.9.1

… which is approximately what I had in mind, except – I don't want any of the email headers and stat comments that git adds; and also I wouldn't want git to be required to reconstruct the folder from the patch file – I'd just want people to be able to use patch to reconstruct the folder and its contents.

So

  • Is it possible to do a patch file like this using only vanilla diff?
  • If not, is it possible to tell git to remove all git-specific comments, and format a patch as if it was produced by diff alone?
  • In case there are small binary files there (i.e. spinner.gif and such), is it possible to instruct diff (or git) to include the binary data as base64, or other text encoding that would survive posting/pasting to a public service like gist?

Best Answer

Using only diff, you need a reference (empty) directory to compare things against:

mkdir /tmp/scratch
diff -urN /tmp/scratch /tmp/aaa

Using git, git diff should give you the output you're looking for.

To handle binaries, use git diff --binary; this will produce an encoded patch which git apply will know how to handle.

Related Question