4

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?

Basj
  • 41,386
  • 99
  • 383
  • 673
  • Try `git bundle`. It creates a bundle working like a read-only repository. See https://www.git-scm.com/docs/git-bundle – ElpieKay Jul 02 '18 at 08:34
  • @phd the answer from https://stackoverflow.com/questions/49101425/how-can-i-export-git-change-sets-from-one-repository-to-another-via-sneaker-net creates a `.bundle` file, but it seems impossible to access it without `git`, so it's not exactly what I'm looking for. – Basj Jul 02 '18 at 08:59
  • You hadn't explained what you want. You should do that from the start. Well, `git archive` seems to be the answer, and no, there is no single command. – phd Jul 02 '18 at 09:01
  • @phd Thank you for your remark, I thought saying I wanted to export each commit into zip files `myproject-commit3-67d91ab.zip` was explicit enough, but now I edited to add more details. – Basj Jul 02 '18 at 10:14

3 Answers3

5

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.]

torek
  • 448,244
  • 59
  • 642
  • 775
  • Thank you for your detailed answer @torek. I just appended the ready to use command at the end. – Basj Jul 02 '18 at 20:03
2

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
BelKed
  • 87
  • 7
0

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>
Shravan40
  • 8,922
  • 6
  • 28
  • 48
  • I don't use github or anything like this in this specific case. I only have a single local repo, I don't hink a web solution will work here. – Basj Jul 02 '18 at 11:04
  • Thank you @Shravan40, but you can see I already mentioned this in the question itself, the question is more: how to get an archive of *all commits*? – Basj Jul 02 '18 at 14:01