4

Creating a git repository for testing.

~ $ mkdir somefolder
~ $ cd somefolder/
~/somefolder $ git init
Initialized empty Git repository in /home/user/somefolder/.git/
  ~/somefolder $ echo test > xyz
  ~/somefolder $ mkdir somefolder2
  ~/somefolder $ echo test2 > ./somefolder2/zzz
  ~/somefolder $ git add *
  ~/somefolder $ git commit -a -m .
[master (root-commit) 591fda9] .
 2 files changed, 2 insertions(+)
 create mode 100644 somefolder2/zzz
 create mode 100644 xyz

When turning the whole repository into a tar.gz, it results in a determinstic file. Example.

  ~/somefolder $ git archive \
>    --format=tar \
>    --prefix="test/" \
>    HEAD \
>    | gzip -n > "test.orig.tar.gz"
  ~/somefolder $ sha512sum "test.orig.tar.gz"
e34244aa7c02ba17a1d19c819d3a60c895b90c1898a0e1c6dfa9bd33c892757e08ec3b7205d734ffef82a93fb2726496fa16e7f6881c56986424ac4b10fc0045  test.orig.tar.gz

Again.

  ~/somefolder $ git archive \
>    --format=tar \
>    --prefix="test/" \
>    HEAD \
>    | gzip -n > "test.orig.tar.gz"
  ~/somefolder $ sha512sum "test.orig.tar.gz"
e34244aa7c02ba17a1d19c819d3a60c895b90c1898a0e1c6dfa9bd33c892757e08ec3b7205d734ffef82a93fb2726496fa16e7f6881c56986424ac4b10fc0045  test.orig.tar.gz

Works.

But when changing a minor detail, when only compressing a sub folder, it does not end up with a deterministic file. Example.

  ~/somefolder $ git archive \
>    --format=tar \
>    --prefix="test/" \
>    HEAD:somefolder2 \
>    | gzip -n > "test2.orig.tar.gz"
  ~/somefolder $ sha512sum "test2.orig.tar.gz"
b523e9e48dc860ae1a4d25872705aa9ba449b78b32a7b5aa9bf0ad3d7e1be282c697285499394b6db4fe1d4f48ba6922d6b809ea07b279cb685fb8580b6b5800  test2.orig.tar.gz

Again.

  ~/somefolder $ git archive \
>    --format=tar \
>    --prefix="test/" \
>    HEAD:somefolder2 \
>    | gzip -n > "test2.orig.tar.gz"
  ~/somefolder $ sha512sum "test2.orig.tar.gz"
06ebd4efca0576f5df50b0177d54971a0ffb6d10760e60b0a2b7585e9297eef56b161f50d19190cd3f590126a910c0201616bf082fe1d69a3788055c9ae8a1e4  test2.orig.tar.gz

No deterministic tar.gz this time for some reason.

How to create a deterministic tar.gz using git-archive when just wanting to compress a single folder?

3

When you do a simple export with HEAD, an internal timestamp is initialized based on the commit's timestamp. When you use more advanced filtering options, the timestamp is set to the current time. To change the behavior, you need to fork/patch git and change the second scenario, eg proof of concept:

diff --git a/archive.c b/archive.c
index 94a9981..0ab2264 100644
--- a/archive.c
+++ b/archive.c
@@ -368,7 +368,7 @@ static void parse_treeish_arg(const char **argv,
                archive_time = commit->date;
        } else {
                commit_sha1 = NULL;
-               archive_time = time(NULL);
+               archive_time = 0;
        }

        tree = parse_tree_indirect(sha1);
  • Is there any way to set this timestamp without patching git? Using touch or so? – adrelanos Oct 25 '14 at 14:16
  • 1
    @adrelanos Given this source code, not, but you could run git under faketime. – Gilles Oct 25 '14 at 14:41
  • Agree: touch isn't enough (the timestamp is written into the tar's data stream), but faketime might do it. If you operate at high volumes, then you'd probably need to use 'absolute' times (simulating a 'stopped system clock') to mitigate raciness. – Tim Otten Oct 25 '14 at 17:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.