34

I'm using git-archive to archive a subdirectory in a git repo, like so:

git archive -o ../subarchive.zip HEAD subdir/*

However the resulting archive maintains the subdir/ directory structure, i.e. the contents are:

subdir/
   whatever.js
   morestuff.js

When I actually want whatever.js and morestuff.js at the root of the archive.

How do? Thanks.

wildabeast
  • 1,723
  • 3
  • 18
  • 31

2 Answers2

57

You can do that like this:

git archive -o ../subarchive.zip HEAD:subdir

By the way, an easy way to play with the command and see what it will generate is if you use it in this form:

git archive --format=tar HEAD:subdir | tar t
git archive --format=tar HEAD subdir | tar t
# ... and so on ...

Once you see what you're looking for, you can change the format and use the -o flag to actually create the archive.

janos
  • 120,954
  • 29
  • 226
  • 236
  • 2
    Is there any way to do this efficiently for remote repos, e.g. to fetch just one dir/one revision of a gigantic repo that's not practical to clone? I tried `--remote` but it was ridiculously slow. – R.. GitHub STOP HELPING ICE Sep 14 '15 at 16:43
  • It works, great. I was trying to understand which part of the GIT documentation talked about this, but could not. May you elaborate pls? – Meglio Dec 04 '17 at 11:57
  • @Meglio `git archive --help`, let me know if you cannot find something (and then please be as specific as possible) – janos Dec 04 '17 at 13:56
  • 1
    Note that if the current working directory is not the root of the repo, then git will archive from working directory (and descendants) only. To change this, use the `:` notation above - i.e. just `HEAD:`; `HEAD:/` and `HEAD:.` don't work. – user234461 Dec 06 '17 at 17:20
  • For some reason though, if you use this, it does ignore the `export-ignore` statements in your `.gitattributes`. Even if the file is included in the dir you export and even if you use `--worktree-attributes`. – rugk Oct 14 '18 at 15:03
  • Okay, asked a separate question for using this here together with `.gitattributes` "export-ignore", which did not really work: [How to ignore files/directories in “git archive” and only create an archive of a subdirectory?](https://stackoverflow.com/questions/52804334/how-to-ignore-files-directories-in-git-archive-and-only-create-an-archive-of-the) – rugk Oct 14 '18 at 15:45
0

If you do use git archive -o ../subarchive.zip HEAD:subdir, make sure to do it with Git 2.41 (Q2 2023):

"git archive"(man) run from a subdirectory mishandled attributes and paths outside the current directory.

See commit 92b1dd1 (24 Mar 2023) by René Scharfe (rscharfe).
(Merged by Junio C Hamano -- gitster -- in commit de73a20, 21 Apr 2023)

archive: improve support for running in subdirectory

Reported-by: Cristian Le
Reported-by: Matthias Görgens
Signed-off-by: René Scharfe

When git archive(man) is started in a subdirectory, it archives its corresponding tree and its child objects, only.
That is intended.
It does that by effectively cd'ing into that tree and setting "prefix" to the empty string.

This has unfortunate consequences, though: Attributes are anchored at the root of the repository and git archive still applies them to subtrees, causing mismatches.
And when checking pathspecs it cannot tell the difference between one that doesn't match anthing or one that matches some actual blob outside of the subdirectory, leading to a confusing error message ("current working directory is untracked").

Fix that by keeping the "prefix" value and passing it to pathspec and attribute functions, and shortening it using relative_path() for paths written to the archive and (if --verbose is given) to stdout.

Still reject attempts to archive files outside the current directory, but print a more specific error in that case ("outside the current directory").
Recognizing it requires a full traversal of the subtree for each pathspec, however.
Allowing them would be easier, but archive entry paths starting with "../" can be problematic to extract -- e.g. bsdtar skips them by default.

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