1

What I want to do.

All files in my repo are in one folder, but this folder contains other files excluded by .gitignore. I want to reorganise (programmatically) those files from the repo only (and not those ignored) to different folders according to their extensions.

Example..

Let's say I have a folder /project with:
a.py,b.py, c.py, 1.png, 2.png, 3.png
where
- a.py, b.py, 1.png, 2.png are in the git repo;
- c.py, 3.png are not in the git repo, i.e. they are ignored according to the rules in .gitignore.

In the end I want to have two subfolders:
- /project/scripts containing a.py and b.py;
- /project/images containing 1.png and 2.png;
while
- /project still contains c.py and 3.png.

Some ideas.

I read the documentation of the git mv command, but I did not see that I could filter files directly from the git mv command.

One idea is to list those files from the repo using git ls-files, then pipe that to git mv. But I am suspecting that this is as bad as piping ls and mv.

As a last resort, I could use a for loop, but I am sure someone out there knows better. In fact, I am not sure that this would circumvent the issues of piping ls with mv.

Format of filenames.

The filenames are not particularly exotic: apart from their extensions (.py, .png), they only contain alphanumeric characters [a-zA-Z0-9], hyphens -, and underscores _. So piping git ls-files with git mv is perhaps not the end of the world.

Antoine
  • 600
  • 7
  • 19

1 Answers1

2

Assuming now your files are in project directory and you want to move only tracked files to different directories you can use

mkdir scripts images
find project/ -name "*.py" -exec git mv -k {} scripts/ \;
find project/ -name "*.png" -exec git mv -k {} images/ \;
git commit

You'll find all files matching a specific pattern. Then you'll move those files, but only if they are tracked by git, to specified folder. Otherwise the git mv command will skip those files (e.g. because they are ignored by .gitignore).

From git mv man page:

   -k
       Skip move or rename actions which would lead to an error condition.
       An error happens when a source is neither existing nor controlled by Git, or
       when it would overwrite an existing file unless -f is given.

Actually you could omit the -k option, since git mv command is being executed for every single file that has been found. It would simply print an error message and continue with the remaining files. On the other hand it is needed when executing git mv for more than one file at once (e.g. git mv project/* new_folder/) because in this case it would simply end with error and omit remaining files.

Manuel Schmidt
  • 2,178
  • 2
  • 15
  • 19
  • Thanks! I was aware of `find`, and now I know a use case! I guess the main point (alluded to by ElpieKay) is that git will not do anything to a file that it does not control. – Antoine Apr 24 '19 at 11:16
  • 1
    Yes, that's it. Actually you could omit the `-k` option, since the `git mv` command is being executed once for every file that has been found. Therefore it wouldn't be a problem that `git mv` command fails. It would simply print an error message and remaining files would be still processed. If you execute `git mv` command on more than one file, then you need the `-k` option because otherwise remaining files would be omitted (the command simply fails). E.g. if you do `git mv project/* tracked_files/` – Manuel Schmidt Apr 24 '19 at 11:26