33

How can I create an archive of the current repository including local uncommitted changes using git archive?

Ton van den Heuvel
  • 10,157
  • 6
  • 43
  • 82

9 Answers9

55

I know this is old, but I think I found a solution.

Run:

stashName=`git stash create`;
git archive <options> $stashName

Since git wants a solid commit to make an archive, we can make a 'one off' commit using git stash. The create command just creates the stash commit (doesn't reset your working directory or push it to the stash stack) and returns the hash for it.

If you are worried about the space from the dangling commit, you can clean it up with a git gc --prune=now. Otherwise, just wait 2 weeks and it'll disappear.

nevsan
  • 1,385
  • 9
  • 8
  • 2
    now it's 7 years older and still useful, thanks @nevasn . I'm using it as a one liner in a Makefile: `git archive \`git stash create\` ` – daonb Oct 31 '19 at 13:50
15

Improving nevsan's answer for my purpose - to archive latest code in any case (committed or not):

uploadStash=`git stash create`; git archive -o code_outgoing.zip ${uploadStash:-HEAD}
Edward Anderson
  • 13,591
  • 4
  • 52
  • 48
lahjaton_j
  • 805
  • 7
  • 13
  • 5
    Fixed an error: git stash create [now] always returns successfully, and prints nothing when there are no files to stash. Use bash ${var:-default} syntax instead of relying on the exit code. – Edward Anderson Oct 20 '14 at 15:02
  • IIRC there is an issue with this, it does not take out git-removed files from the archive. – lahjaton_j Aug 29 '16 at 05:57
  • Beautiful. Or separate the latest-or-head logic before using the commit: ```LATEST=`git stash create`; LATEST=${LATEST:-HEAD} # use HEAD if no changes``` – Brent Faust Jun 15 '18 at 18:36
11

Another solution with git ls-files :

git ls-files -z | xargs -0 tar -czvf archive.tar.gz
Vianney Bajart
  • 7,490
  • 2
  • 13
  • 10
  • 2
    This is, in my opinion, the best answer. However, I would recommend using the -z option of ls-files and the -0 (zero) option of xargs such that filenames with spaces are handled correctly: git ls-files -z | xargs -0 tar -czvf archive.tar.gz . – S2108887 Feb 25 '18 at 18:56
  • You're absolutely right! Thanks. I've added these options to the command line. – Vianney Bajart Mar 05 '18 at 13:27
  • 6
    `git ls-files | tar Tczf - archive.tar.gz` doesn't have system-imposed limits on the size of a single command's args. xargs isn't good for any command you really need to run only once for everything. – jthill Mar 05 '18 at 16:19
5

You don't have to use git stash anymore to create one artificial commit which would include your tracked change, for git archive to operate on.

With Git 2.29 (Q4 2020), "git archive"(man) learns the "--add-file" option to include untracked files into a snapshot from a tree-ish.

See commit df368fa, commit 2947a79, commit 200589a (19 Sep 2020) by René Scharfe (rscharfe).
(Merged by Junio C Hamano -- gitster -- in commit f6b06b4, 05 Oct 2020)

archive: add --add-file

Signed-off-by: René Scharfe

Allow users to append non-tracked files.
This simplifies the generation of source packages with a few extra files, e.g. containing version information.
They get the same access times and user information as tracked files.

git archive now includes in its man page:

--add-file=<file>

Add a non-tracked file to the archive.
Can be repeated to add multiple files.
The path of the file in the archive is built by concatenating the value for --prefix (if any) and the basename of <file>.


I also like the Git 2.30 alternative to tar.


Before Git 2.37 (Q3 2022), "git archive --add-file=<path>"(man) picked up the raw permission bits from the path and propagated to zip output in some cases, without normalization, which has been corrected (tar output did not have this issue).

See commit 6a61661 (12 May 2022) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit 6cd6906, 23 May 2022)

archive: do not let on-disk mode leak to zip archives

When the "--add-file" option is used to add the contents from an untracked file to the archive, the permission mode bits for these files are sent to the archive-backend specific "write_entry()" method as-is.
We normalize the mode bits for tracked files way before we pass them to the write_entry() method; we should do the same here.

This is not strictly needed for "tar" archive-backend, as it has its own code to further clean them up, but "zip" archive-backend is not so well prepared.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
3

This creates a zip archive containing all working tree files except those that are ignored by git:

git ls-files --others --exclude-standard --cached  | zip --names-stdin archive.zip
fhucho
  • 34,062
  • 40
  • 136
  • 186
2

If you haven't committed the changes, then git archive won't help you. If you just want a snapshot of your working area, tar is probably your best bet.

Mike Seplowitz
  • 9,785
  • 1
  • 24
  • 23
0

I'm using this command to export specify version to now (including uncommit changes file) changes by one line

git archive -o /path/to/save/temp.zip $(git stash create) $(git diff --name-only xxx_version_to_start)
Frank He
  • 637
  • 4
  • 9
0

git ls-files is preferred cause it doesn't need to create any commit object.

git ls-files --recurse-submodules -z | tar --null -T - -czvf output.tar.gz
# git ls-files
#   --recurse-submocules
#   -z, split output lines with null
# tar
#  -T -, read files from stdin
Simba
  • 23,537
  • 7
  • 64
  • 76
0

a small bash script based on @fhucho's answer:

#backup.sh
#remove final "/"
repo=${1%"/"} 
#create $repo-backup.zip
cd $repo
git ls-files --others --exclude-standard --cached  | zip --names-stdin ../$repo-backup.zip
cd ..
ls -l $repo-backup.zip

usage:

. backup.sh myrepo
Lucio M. Tato
  • 5,639
  • 2
  • 31
  • 30