automatix
automatix

Reputation: 14532

How to export the ignored files by retaining the folders structure in Git?

I have a project, where I want to separate the (not versioned / .gitignored) files (the most of them are config files) from the actual source code. I want to copy them to a directories structure identical to the project's directories structure. E.g.:

/foo
/bar/config/env.xml <-- ignored
/bar/config/env.xml.dist
/buz/keys <-- ignored
/buz/logs <-- ignored
/buz/source

$ git extract-ignored-files --exclude-from-extracting=/buz/logs (pseudocode)
Aimed result:

/bar/config/env.xml <-- ignored
/buz/keys <-- ignored

The concrete requirement behind it is to be able to transfer settings from one system to another (and set up this another one quickly by adapting only a couple of settings).

How to export the .gitignored files? In the best case I also would like (1) to keep there by the folders' structure identical to the original structure and (2) be able to exclude some paths from the extracting result.

Upvotes: 1

Views: 59

Answers (3)

automatix
automatix

Reputation: 14532

1. Define the paths, you want to transfer. It will be a subset of the set of the ignored files.

This can be done various ways, e.g. by reviewing the .gitignore and transforming its rules to paths or by using git status --ignored or git check-ignore *. I prefer this way:

a. Get all .gitignored files (git ls-files --others > ./transfer-excludes.txt) (in my case I got a file with about 22k lines).

b. Define from the result file's entries manually the patterns you don't (!) want to transfer. It can be for example your IDE settings, the folder with the external libraries, logs etc. -- everything you definitely won't need to copy to another project instance.

2. Get the paths to be transferred.

$ git ls-files --others --exclude-from=./transfer-excludes.txt > ./transfer-files.txt

The approach might need some more effort. But then all possible ignore paths (including the ones excluded by the sub-directories' .gitignores) become visible and can be checked.

3. Copy the files.

It's just a simple bash script, that scans the paths, creates the needed directories structure (by using mkdir -p), and copies the files:

#!/bin/bash
INFILE="./transfer-files.txt"
TARGETROOT="./transfer"
while read line
do
    TARGETDIR=`dirname $line`
    TARGETPATH="${TARGETROOT}/${TARGETDIR}"
    if [ ! -d "${TARGETPATH}" ]
    then
        mkdir -p "${TARGETPATH}"
    fi
    # echo ${TARGETPATH}
    cp "$line" "${TARGETPATH}"
done < ${INFILE}

The cp --parents instead of the combination of mkdir -p and cp doesn't work in this case, since it cannot crate complete path recursively, if it's not there yet.

$ ./transfer.sh

That's it.


A little check:

$ find ./transfer/ -type f -exec du -a {} +

The output should equal to the list of the files from the transfer-files.txt.

Possible improvements:

  • The steps 2 and 3 can be merged to script. (But sometimes you won't want to, in order to have a chance to check the file list first.)
  • Another improvement idea: It would be possible to create Git hook, that checks, wheter the commit affects a .gigitnore file -- in this case the transfer-excludes.txt should be updated.

Upvotes: 0

phd
phd

Reputation: 94676

rsync -R preserves relative path names:

rsync -aR `git ls-files --others` ignored_files/

Upvotes: 1

EncryptedWatermelon
EncryptedWatermelon

Reputation: 5598

The --parents flag to cp will maintain directory structure.

mkdir ignored_files
  for x in `git status --ignored .`; do
  cp -va --parents $x ignored_files/$x
done

Upvotes: 1

Related Questions