0

In brief TLDR

To rsync a folder that has .git/ excluded but still keeping the .git/config file, how to do that?

My google search is not helpful so I asked here.

Full details

I want to take snapshot of all of my projects' code into another machine - later on I may not have the git repo access.

Each project code folder is a git-cloned one so they have .git folder.

I don't need those .git so will exclude them.

But I need to know what git repo the projects coming from so need to keep .git/config.

What I tried and didn't work run it

rsync -chazvP --dry-run --exclude=".git" --include=".git/config"  $FROM/ $TO/
#             .         .                .                        .      .

If you know the correct way to do so, please share.

4
  • That sounds like a task for... well, for git. I think we're dealing with an XY problem. What problem are you trying to solve with rsync here?
    – gronostaj
    Sep 10, 2020 at 14:00
  • The problem is "rsync a folder that has .git/ excluded but still keeping the .git/config file" a.k.a. when we do exclude .git/ the whole folder excluded and now we want to keep .git/config, how to? @gronostaj
    – Nam G VU
    Sep 11, 2020 at 2:19
  • Have you read the XY problem link I've posted above? You've described Y. Running rsync is not your ultimate goal, it's your solution for problem X. What's the X that you want to solve?
    – gronostaj
    Sep 11, 2020 at 6:52
  • Yes I read though not get the X there; got it now after you explained @gronostaj, thank you! My X is "take snapshot of all of my projects' code into another machine"
    – Nam G VU
    Sep 11, 2020 at 23:53

2 Answers 2

2

Include the file you want to keep, and then exclude the ones you don't want. You can't exclude the .git/ directory itself, though, because then there would be no match for .git/config.

rsync --dry-run -av --include '.git/config' --exclude '.git/*' "$FROM/" "$TO/"

As always, test it first and then remove --dry-run when you're comfortable. Remember to double-quote your variables, to protect them from the shell's word expansions.

For reference, this is described in the documentation (man rsync), but I'll be one of the first to say it's hard to understand unless you already understand it...

For instance, to include "/foo/bar/baz", the directories "/foo" and "/foo/bar" must not be excluded. Excluding one of those parent directories prevents the examination of its content, cutting off rsync’s recursion into those paths and rendering the include for "/foo/bar/baz" ineffectual (since rsync can’t match something it never sees in the cut-off section of the directory hierarchy).

The concept path exclusion is particularly important when using a trailing ’*’ rule. For instance, this won’t work:

+ /some/path/this-file-will-not-be-found
+ /file-is-included
- *

This fails because the parent directory "some" is excluded by the ’*’ rule, so rsync never visits any of the files in the "some" or "some/path" directories. [...] Another solution is to add specific include rules for all the parent dirs that need to be visited.

2
  • Great thanks @roaima for your detailed and very-careful answer! I'll try and back to you soon with trying --include '.git/config' --exclude '.git/*' .
    – Nam G VU
    Sep 11, 2020 at 23:55
  • It works like a charm. Thank you @roaima!
    – Nam G VU
    Sep 12, 2020 at 0:15
1

Based on your comment:

My X is "take snapshot of all of my projects' code into another machine"

I'd suggest just using git. It internally tracks code as directory snapshots, so you get everything rsync does + git goodies.

Git can access other repos over SSH, HTTP and even from mounted filesystems. Since rsync was your tool of choice, I assume you already have SSH set up. In case you need to update something in particular for git to work, here's a guide.

Once you have your repo cloned on 2nd machine, git fetch --all will efficiently update local clone of your repo only with files that were updated since last fetch.

Alternatively you can git init --bare a new repo on 2nd machine and add it as a remote on the 1st one. In that case you can execute git push --all on machine 1 to update machine 2.

Or you can make both repos remotes of each other, so you're able to initiate the update on both ends.

Why git is the perfect solution?

  • You're already working with git, so you don't have to introduce another tool you're not familiar with
  • Avoids reinventing the wheel
  • You don't have to parse .git/config in your head, git remote get-url origin will tell you repo's origin
  • Git compresses and deduplicates your files
  • Branches and commit history are preserved
  • Only changes are transferred, rather than entire snapshot
3
  • Thanks for your solution with git-base. My scenario is that some git repo after migrated, I may stop having the access later on.
    – Nam G VU
    Sep 12, 2020 at 8:57
  • Added "later on I may not have the git repo access" to my question to clarify. Thanks any wat.
    – Nam G VU
    Sep 12, 2020 at 8:58
  • 1
    @NamGVU My solution is still valid. Git repos are completely independent from each other. Even if you lose access to the origin, clones will remain untouched.
    – gronostaj
    Sep 12, 2020 at 19:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .