rod mclaughlinThis is not an April Fools' Day Joke (01 apr 21)
How to copy nested folders, overwriting .git folders if necessary If you use the source control system called GIT, you end up with lots of folders containing .git folders. If you want to copy a new version of one of these folders onto an old version, you can't just copy the contents of the new .git into the old .git. Git won't let you, and if you did, it might get its knickers in a twist. The old version might have a file called 38e46da630c7f6abd877b800c78a7b9136b57c, and the new one has one called cf7c6ef6b2101ea8ab548fe9335662e8481617. but not 38e46da630c7f6abd877b800c78a7b9136b57c.If you just copied all from the new .git into the old one, you'd end up with both of these files, and Git wouldn't understand what that means. Unless you're Linus, the guy who created Git, there is no way you could work out which files to copy and/or rename. So I had to create a script which copies all the files and folders from new into old, but if new has a .git folder, and so does old, delete the contents of the old .git folder before overwriting its contents with the contents of the new one. It goes like this: shopt -s dotglob if [ "" == "$2" ] ; then echo "Takes two arguments, a source folder and a target folder" echo "The second argument should be simple, eg. just 'dev', not /Users/me/dev" echo "If you are in the folder directly above dev/, the first argument could" echo "be e.g. /Volumes/mydrive/dev, and the second argument could be dev" exit 1 fi if [[ ! -d $1 || ! -d $2 ]] ; then echo "Takes two arguments, a source folder and a target folder" exit 1 fi source=$1 target=$2 targetgits=`find $target -type d -name .git` sourcegits=`find $source -type d -name .git | cut -d'/' -f2-` for git in $targetgits ; do shortpath=`echo $git | cut -d'/' -f2-` if echo ${sourcegits[@]} | grep -q -w $shortpath; then echo "$shortpath is in source" echo "So - deleting everything in $git before replacing it" rm -Rf $git/* else echo "$shortpath is not in source - leaving $git alone" fi done sourcedirs=`find $source -type d -depth 1 -exec basename {} \;` for dir in $sourcedirs ; do if [ ! -d $target/$dir ] ; then echo "Creating $target/$dir" mkdir $target/$dir fi echo "Copying $source/$dir/* into $target/" cp -r $source/$dir/* $target/$dir/ done shopt -u dotglob I tested it by creating a folder called tmp, and in it, a folder called dev. I cd’d into tmp/dev, and created folders foo and bar. In them, I created the following folders, with the following characteristics. foo one - containing one file, and three git commits two - containing one file, and one git commit three - one file, no git five - empty Then I created the following bar one - containing one file, and one git commit two - containing one file, and no git three - one file, one git commit four - empty
If my script worked, copy-with-git.sh foo bar I would expect foo - no changes at all bar - the following state: one - one file, three git commits, same as foo/one two - one file, one git commit, same as foo/two three - one git commit four - empty five - empty This is what in fact happened. The only thing which went wrong was when I cd'd to /Volumes/mydrive, and tried to copy dev/* to ~/dev {/Users/rod/dev}, it didn't like the second argument beginning with a /. But when I cd'd into /Users/rod, and issued the following command, it worked. copy-with-git.sh /Volumes/mydrive/dev dev Back
|