105

As my question says, after changing files and adding new files in my repository, I normally commit files with git, but sometimes I need all the modified / changed files copied to a folder for organizing-myself reasons.

Any option?

Mr Question
  • 1,185
  • 3
  • 9
  • 8
  • If you tell us what you're actually trying to accomplish, our answers might be a little bit more helpful. – Cascabel Nov 08 '10 at 17:37
  • It depends, sometimes just to ftp them – Mr Question Nov 08 '10 at 17:54
  • But "to ftp them" is not a goal by itself. What is the rationale of doing this? I never wanted to create a zip of just the changed files, so I'm wondering about the use case. – Sven Marnach Nov 08 '10 at 17:58
  • In this case it's more about copying them to a folder, and not zipping – Mr Question Nov 08 '10 at 18:01
  • Ah, the old "why would you ever want to do something that I never do?". Use case is completely irrelevant to the question. The question is succinct enough. – John May 10 '23 at 18:54
  • @Cascabel: perhaps OP wants a backup of the files in case git or their git GUI fucks up and wipes them out, and is reluctant to deal with [git's crappy experience](https://ohshitgit.com/) trying to restore them. – Dan Dascalescu May 17 '23 at 09:54

12 Answers12

147

Assuming you mean you haven't yet committed, and want to package up all of the files that currently have local modifications (but not completely new files), you can get the list of modified files with git ls-files --modified. If you want the files which were changed by the last commit, you could use git diff --name-only HEAD^. Where you go from there is up to you. Examples:

zip modified-files.zip $(git ls-files --modified)
cp --parents $(git ls-files --modified) ../modified-files # Linux
rsync -R $(git ls-files --modified) ../modified-files # macOS

Note that this is using the versions of files in the working tree currently.

If you have spaces in filenames, you'll have to go to a little more trouble.

(Of course, depending on what you're really trying to do, you might be looking for git stash, which stashes away all modified files and leaves you with a clean working tree, or you could simply want to make a temporary branch to commit to.)

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
Cascabel
  • 479,068
  • 72
  • 370
  • 318
79

To do exactly what you requested (assuming you already committed and want to create an archive of the files changed by the last commit), you could do:

git archive --format=zip HEAD `git diff HEAD^ HEAD --name-only` > a.zip

If you have removed files in a commit, to prevent a pathspec error use --diff-filter=d:

git archive --format=zip HEAD `git diff --diff-filter=d HEAD^ HEAD --name-only` > a.zip

But maybe you actually want to create a patch using:

git diff HEAD^ HEAD > a.patch

and apply this patch where you need it using:

patch -p1 < a.patch

Of course, applying a patch only works if your target directory already contains the old version of your repository.

David Oliver
  • 2,424
  • 1
  • 24
  • 37
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • 2
    i recommend using `git format-patch` instead of piping `git diff` to a file – knittl Nov 08 '10 at 17:55
  • 1
    this is after commiting, how can I get the new files too. – Mr Question Nov 08 '10 at 17:58
  • By new files you mean untracked files in your working directory? Well, just tell us what you actually want to accomplish. – Sven Marnach Nov 08 '10 at 18:04
  • Sorry for my imprecision, I upvote you, I save your answer because it is also very interesting if I want the last commited files – Mr Question Nov 08 '10 at 18:06
  • Pls, look at my new question I am sure this is a child's game for you: http://stackoverflow.com/questions/4126732/git-how-to-exclude-a-subfolder-in-a-repository – Mr Question Nov 08 '10 at 18:22
  • 3
    One problem is, when you deleted something, you will get error: "fatal: path not found: XYZ" – Krzysztof Romanowski May 29 '13 at 14:53
  • 1
    git archive worked perfect for me. I had to get the last 2 commits, so I did one of these: `git archive --format=zip HEAD \`git diff HEAD~2 HEAD --name-only\` > a.zip` – j.snyder Jul 22 '13 at 15:21
  • 1
    The first command in this answer didn't work for me on Windows (7). For some reason it complained that the --name-only option was unknown. I think it's probably just an escaping issue? So to be lazy I installed Cygwin and was able to run it correctly from the Cygwin prompt. – John B Feb 26 '14 at 15:51
  • 1
    @JohnBubriski: No, it's not just an escaping issue. The syntax used in the first command is POSIX shell syntax. Unfortunately, Windows doesn't come with a POSIX shell (or any usable shell, for that matter), so installing Cygwin is a good idea in any case. – Sven Marnach Feb 26 '14 at 17:22
  • What if I want to do the same as in this solution but including, for example, last two revisions? – cincplug Oct 01 '15 at 08:37
  • 1
    I've also found that if one of the commits was for a file removal, the archive breaks with a 'pathspec [file-path] did not match' - error. – Corgalore Sep 19 '17 at 13:44
  • 1
    Okay, solved the pathspec error. If you have deleted files in your commits, use --diff-filter=d – Corgalore Sep 19 '17 at 14:03
  • 1
    You should also probably use the `--relative` flag on the `git diff` subcommand, since `git archive` archives files relative to the current working directory. That allows the command to work inside subdirectories of your tree (archiving the diff for that subdirectory). – Kit Grose Aug 17 '18 at 05:38
  • I have .zip file at repo I have modify only 1 file under that now what should i do to push my changes do i need to push whole .zip or i can push only 1 file under that any suggestion please ..? – Gaurav Joshi Feb 13 '21 at 23:13
20

If you use TortoiseGIt, it provides this too.
Choose the folder, in explorer
Right click,Choose menu, TortoiseGit-> Show Log.

Select working directory and the last commiitted version.
Right click. Compare revisions. Select files you want to save/export.
Right Click. Export to folder. Done.

Aftershock
  • 5,205
  • 4
  • 51
  • 64
9

Zip the modified and newly created files in the git repository

zip mychanges.zip $({ (git ls-files --others --exclude-standard) ; (git ls-files --modified)})
Saifullah khan
  • 686
  • 11
  • 19
2

Assuming you don't have deleted or renamed files, this should do the trick

Copy:

cp --parents $(git status -s | egrep "M|A|AM" | rev | cut -d" " -f1 | rev) destination_folder

Zip:

zip modified.zip $(git status -s | egrep "M|A|AM" | rev | cut -d" " -f1 | rev)
BRT
  • 52
  • 1
  • 6
  • the cp --parents seem to copy/create directories along with file, is there way to copy on the files and not create directory. I guess removing the --parents argument works just fine :) . – rainu Mar 01 '20 at 08:19
  • --parents use full source file name under DIRECTORY The --parents argument places the files into the same folders structure on destination that they were on origin. For example, if you have modified files on include and source folders, the --parents argument places them into include and source on destination. [orig/folder_a/file_1, orig/folder_b/file_2] -> [dest/folder_a/file_1, dest/folder_b/file_2] This is very useful if you have modified files on different folders on the same project (for example include and source folders) – BRT May 13 '20 at 12:52
  • If you add '??' to egrep "M|A|AM" like egrep "M|A|AM|??", you will also copy files that are not under version-control. This is useful for new files that are not added or commited yet – BRT May 13 '20 at 13:01
  • When I add "M|A|AM|??" I get: `egrep: repetition-operator operand invalid`. – Chance Smith Oct 30 '20 at 00:44
  • I'm using GNU grep 3.3 (2018-05-11) – BRT Nov 04 '20 at 12:11
  • why do you need rev? I just used -f3 instead of -f1 and it appears to get the correct column – gonzobrains May 05 '23 at 14:34
  • 1
    @gonzobrains: `-f3` won't work for `AM` files (it will return an empty string). Anyway, the `egrep "M|A|AM"` will falsely match files that contain `M` or `A` in their name. See [my answer](https://stackoverflow.com/a/76386165/1269037) for a correct solution. – Dan Dascalescu Jun 01 '23 at 22:50
1
mkdir -p /c/temp/blah && cp $(git diff <your commit hash> --name-only) /c/temp/blah

I'm using Git Bash on windows.

user3448451
  • 21
  • 1
  • 2
1

If you have TortoiseGit, even before committing also you can export all the changed files to folder (which contains files under proper directory structure). Just perform following steps.

  1. Right click on folder which you want to see changes
  2. Select Commit to
  3. Once files are visible in box, select all files
  4. Right click - > Export selection to...
  5. Select folder where you want to put these files.
  6. Done.
Rajaram Shelar
  • 7,537
  • 24
  • 66
  • 107
1

Had the same requirement. Got the input from the first answer and created a tool (Windows Only) for myself. Which copies all the added/ modified files to a backup folder.

Tool Overview

Git-Uncommited-Files-Backup-Tool-Windows

Just wrote this quick for fun. Just posted incase it'd help someone. (Highly welcomed for modifications).

Also, you can schedule backups using the Task Scheduler.

Shazni Shiraz
  • 111
  • 1
  • 6
1

Gathered from different solutions, here's what I used:

git archive --format=zip HEAD `git diff --name-only [from-commit-hash]` > changes.zip

It'll zip changes from any particular commit.

like:

git archive --format=zip HEAD `git diff --name-only 4a944407aec42222761cdc23c3e0b89a0c1e26a1` > changes.zip
Inam Ul Huq
  • 732
  • 7
  • 8
1

Note that the git ls-files --modified command listed in other answers doesn't include new files.

I've been using the command below to back new and modified files in case my IDE screwed up when syncing from remote branches and its "Smart checkout" feature wasn't that smart:

cp --parents $(git status -s | egrep "^A|^ M" | cut -c 4-) ../modified-files # Linux
rsync -R $(git status -s | egrep "^A|^ M" | cut -c 4-) ../modified-files # macOS

Let's look at how we obtain the list of new and modified files:

git status -s | grep "^A\|^ M" | cut -c 4-
  • -s stands for --short and it will produce an output like this:

     M .gitignore
    A  _includes/code/howto/manage-data.create.py
    A  _includes/code/howto/manage-data.create.ts
     M _includes/code/howto/search.generative.ts
     M _includes/code/howto/search.hybrid.ts
    AM developers/weaviate/manage-data/create.mdx
    ?? _includes/code/howto/jeopardy_1k.csv
    
  • grep "^A\|^ M" filters for Added or Modified files

  • cut -c 4- cuts those first 3 characters and returns the filename starting from the 4th character

The other options are:

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
0

Here is a script which can make this process a lot easier, it will copy all changed file to used defined directory and also maintain the directory structure of code base.

run: sh scr.sh

================================================

#!/bin/sh
FILES=`git ls-files --modified`
for x in $FILES
do
        prev_dir=$PWD
        echo "MY Dir = $prev_dir"
        mkdir -p $1/$x
        cd $1/$x
        cd ../
        rm -r *
        cp $prev_dir/$x ./.
        cd $prev_dir
done

================================================

ChauhanTs
  • 439
  • 3
  • 6
  • how do I check FILES is empty and show message to terminal screen and set destination folder? – May'Habit Sep 18 '19 at 01:49
  • I change file in root folder and run your command, it'll create a folder with same name. Why it doesnt copy file to another folder instead create folder? – May'Habit Sep 18 '19 at 01:58
0

You can export your last modified files via git ls-files --modified Just create a .sh file with the following code And execute it.

#!/bin/sh
FILES=`git ls-files --modified`
export_dir="place your export dir"
for x in $FILES
do
   prev_dir=$PWD
   folder=$(dirname $x)
   echo "Exporting to..." $export_dir/$x
   cp $prev_dir/$x $export_dir/$x
done
ahmed
  • 1
  • 3