How do I preserve timestamps with git archive

729 Views Asked by At

I use a post-commit script to 'git archive' to a temp directory, then I use Rsync to move just the changed files to my dev working directory. I am preserving timestamps with rsync, but the git archive command updates all the timestamps to current date and time, so everything is getting pushed. According to the documentation (quoted below), It is only supposed to do that if I pass it a tree ID rather than a commit ID. I am not passing anything.

My git archive command to copy to temp:

git archive $branch | (cd $tempdir; tar x)

Here is what the documentation says:

"git archive behaves differently when given a tree ID versus when given a commit ID or tag ID. In the first case the current time is used as the modification time of each file in the archive. In the latter case the commit time as recorded in the referenced commit object is used instead. Additionally the commit ID is stored in a global extended pax header if the tar format is used; it can be extracted using git get-tar-commit-id. In ZIP files it is stored as a file comment."

Does this mean I need to get the commit ID and pass that to git archive? How do I do that?

I am a little confused? How do I archive to my temp directory without changing timestamps?

Thanks.

EDIT: I also tried these to no avail:

git archive get-tar-commit-id $branch | (cd $tempdir; tar x)

and

git archive $(git get-tar-commit-id) $branch | (cd $tempdir; tar x)

I am not sure what the proper syntax is. Maybe it is easier than I thought?

2

There are 2 best solutions below

1
On BEST ANSWER

One workflow I’ve used is to make a non-bare remote, and also

git config --local receive.denycurrentbranch true

Then the server can have a true working directory, which you can push to.

3
On

If $branch is a branch name, it's resolved to a commit hash first, and then git archive archives the tree associated with that commit. Your existing git archive command is therefore doing what you wanted it to.

The problem is that the time stamps on all the files will be the date stamp on that commit. Every commit is, after all, a full snapshot of every file. So every file in the archive has the same time stamp: the time stamp from that commit. What you wanted git archive to do is not what you wanted to want git archive to do. :-)

If you have a fairly modern Git, set up the server with a non-bare repository in which you have set receive.denyCurrentBranch to updateInstead. (Then make sure no one ever does any work on the server! The point of a --bare repository is to enforce a lack of work-being-done.) Your work-tree on the server will then do what you really wanted.