3

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 [email protected]

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 <[email protected]>
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?

3 Answers 3

7

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.

2
  • Is it safe to run diff -urN on the original directories, without copying them to tmp? Or it is possible that git will delete something? Mar 25, 2021 at 16:52
  • diff and git diff don’t delete anything; this is safe anywhere. Mar 25, 2021 at 16:54
4

Is it possible to do a patch file like this using only vanilla diff?

With GNU diff, yes, if you include the -N option, and you don't care about empty directories:

$ tree a b
a
├── aaa
│   ├── aaa.txt
│   └── bbb
│       └── bbb.txt
└── ccc
b

3 directories, 2 files
$ diff -uNr b a | (cd b; patch -p1)
~/devel/b
patching file aaa/aaa.txt
patching file aaa/bbb/bbb.txt
$  tree b
b
└── aaa
    ├── aaa.txt
    └── bbb
        └── bbb.txt

2 directories, 2 files

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?

git diff could be used if there was an initial empty commit:

$ git init
$ git commit --allow-empty -m init
[empty (root-commit) d1d0a97] init
$ git add aaa
$ git commit -m 'foo'
[empty b834eba] foo
 2 files changed, 2 insertions(+)
 create mode 100644 aaa/aaa.txt
 create mode 100644 aaa/bbb/bbb.txt
$ git diff 'HEAD^'
diff --git a/aaa/aaa.txt b/aaa/aaa.txt
new file mode 100644
index 0000000..43d5a8e
--- /dev/null
+++ b/aaa/aaa.txt
@@ -0,0 +1 @@
+AAA
diff --git a/aaa/bbb/bbb.txt b/aaa/bbb/bbb.txt
new file mode 100644
index 0000000..ba62923
--- /dev/null
+++ b/aaa/bbb/bbb.txt
@@ -0,0 +1 @@
+BBB
1
  • Thanks for that, @muru - good to have the snippet examples; cheers!
    – sdaau
    Dec 16, 2015 at 10:18
0

The (somewhat) standard way to ship files and directories as text is to use shar(1). This creates a (somewhat readable) shell script that recreates the files/directories.

It is easier to just pack the stuff up with tar(1) or even zip(1), and have the recipient unpack.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .