Export all commits into ZIP files or directories

2.8k Views Asked by At

How is it possible to export all commits into ZIP files (containing all files, not only patch/diff):

myproject-commit1-67d91ab.zip
myproject-commit2-9283acd.zip
myproject-commit3-c57daa6.zip
...

or into directories:

myproject-commit1-67d91ab/
myproject-commit2-9283acd/
myproject-commit3-c57daa6/

?

I was thinking about commands like:

git archive --format zip --output myproject-commit3.zip c57daa6

from How do I export a specific commit with git-archive?, but how to get all commits?

Notes:

  • the goal is to do an export of all files of each commit, so that I can have access to them even if I don't have git on the machine

  • the answer from How can I export Git change sets from one repository to another via sneaker net (external files)? creates a .bundle file, but it seems impossible to access it without git, so it's not what I'm looking for

  • this nearly works:

    for ((i = 0;; ++i)); do git checkout master~$i || break; tar czf ../myproject-commit$i.tgz .; done
    

    but it also archives all the files in the current directory which are not git added to the repo... How to avoid this problem?

3

There are 3 best solutions below

1
On BEST ANSWER

You can't, except by the methods you are already thinking about.

Specifically, to turn every commit into a zip archive (one separate archive per commit), simply iterate over every commit, turning each one into a zip archive.

Your method for iterating simply needs to walk all possible commits, rather than walking only all first-parents of the master branch, and you must use git archive on each such commit. Hence:

git rev-list --all |
    while read hash; do git archive ...options... $hash
done

The command git rev-list --all tells Git to print out every reachable commit hash ID, in some order. To change the order, use the various sorting options available to both git rev-list and git log (e.g., --author-date-order or --topo-order).

If you don't want every commit—if you want instead only first-parents of master—you can still do this with git rev-list:

git rev-list --first-parent master | ...

Here, since Git is walking only first-parents starting from whichever commit master identifies, the hash IDs will be output in what Git considers forward order, i.e., backwards across the branch's first-parents:

...--o--o--o--o--o--o------o   <-- master
      \        \          /
       \        X--X--...X   <-- somebranch
        \         /
         X--X----X--X   <-- anotherbranch

None of the X commits will appear since they are not on the first-parent lineage. (Without --first-parent, since all the commits on somebranch, and all but the last one on anotherbranch, are also on master, you would get all the X commits.)

[Basj adds the following, which appears to be bash-specific due to $((i=i+1)):] Edit: this is a ready to use command to do it as described in the question:

git rev-list --all --reverse | while read hash; do git archive --format zip --output ../myproject-commit$((i=i+1))-$hash.zip $hash; done

[torek feels the need to add :-) : Note that the above enumerates commits sequentially, even if this is not an invertible mapping.]

0
On

I slightly improved solution by @torek.
This one export commits, that are "normally visible" using git log (all commits are exported in folder zip):

mkdir zip && git log --format=%h --reverse |
    while read hash;
    do git archive --format zip --output zip/$((i=i+1))-project-$hash.zip $hash;
done

If you want also date and time (without "project"), use this one:

mkdir zip && git log --format="%h %ad" --date=format:"%d.%m.%Y-%H.%M" --reverse |
    while read hash date;
    do git archive --format zip --output zip/$((i=i+1))-$hash-$date.zip $hash;
done

Or if you want to export all commits to folders (instead to zip archives) use this one:

mkdir zip && git log --format="%h %ad" --date=format:"%d.%m.%Y-%H.%M" --reverse |
    while read hash date;
    do git archive --format zip --output zip/$((i=i+1))-$hash-$date.zip $hash;
done && find zip -name '*.zip' -exec sh -c 'unzip "$1" -d "${1%.*}"' _ {} \; && rm zip/*.zip

Anyway, if you want to also keep file mode (chmod), use this one. It uses tar archives instead zip archives:

mkdir tar && git log --format="%h %ad" --date=format:"%d.%m.%Y-%H.%M" --reverse |
    while read hash date;
    do git archive --format tar --output tar/$((i=i+1))-$hash-$date.tar $hash;
done && find tar -name '*.tar' -exec sh -c 'mkdir ${1%.*} && tar -xvf "$1" -C "${1%.*}"' _ {} \; && rm tar/*.tar
2
On

You can download the your project with specific commit in zip file using

https://host_url/{user_name}/{project_name}/archive/{commit_id}.zip

EDIT

You can do this using command line.

git archive -o commit_id.tar --remote=<repo_url> <commit_id>