31

cp -l hard links files instead of copying them, saving filesystem space. I need to use rsync instead of cp because of its --exclude capabilities.

So my question is, how do I get rsync to hard link files instead of copying them? Obviously, this is a local filesystem copy. I've read the docs for rsync's -H option, but it's unclear to me if this behaves the same way as cp -l.

nnyby
  • 1,509

3 Answers3

30

The answer has turned out to be yes, with rsync's --link-dest option. It's just not obvious because it's not a simple on/off flag like cp -l, because it takes a path argument.

So, cp -l a/ b/ can also be done like this:

rsync  -a  --link-dest=../a  a/  b/

Note that the destination needs to be ../a, because the path is relative to the relative to the target directory.
(So if you were syncing to b/c/, it would be ../../a.)

mwfearnley
  • 7,889
nnyby
  • 1,509
3

I've been using https://github.com/rsnapshot/rsnapshot for a long time. It does exactly what you are describing.

ericpe
  • 31
2

@nnyby has the correct answer, but for the life of me I couldn't get it to work until I recognized that the --link-dest be set to the source directory.

This appears to be a point of confusion in other questions and answers (here, and here).

For the sake of clarity, to create hard links on the destination, the --link-dest needs to be set to a relative path to the source directory.

Here is an example of using rsync to copy a source directory to a destination directory using correct and incorrect parameters, and also an example showing how the --hard-links(-H) option will work.

$ ls -lt source/
total 0
-rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file1
-rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file2
-rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file3
-rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file4
-rw-rw-r-- 2 smfrg smfrg 0 Aug 20 10:01 file5
-rw-rw-r-- 2 smfrg smfrg 0 Aug 20 10:01 file_hd

$ rsync -a --link-dest=../dest source/ dest/ $ ls -lt dest/ total 0 -rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file1 -rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file2 -rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file3 -rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file4 -rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file5 -rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file_hd

$ rsync -a --link-dest=../source source/ dest/ $ ls -lt dest/ total 0 -rw-rw-r-- 2 smfrg smfrg 0 Aug 20 10:01 file1 -rw-rw-r-- 2 smfrg smfrg 0 Aug 20 10:01 file2 -rw-rw-r-- 2 smfrg smfrg 0 Aug 20 10:01 file3 -rw-rw-r-- 2 smfrg smfrg 0 Aug 20 10:01 file4 -rw-rw-r-- 4 smfrg smfrg 0 Aug 20 10:01 file5 -rw-rw-r-- 4 smfrg smfrg 0 Aug 20 10:01 file_hd

$ rm -rf dest $ rsync -aH source/ dest/ $ ls -lt dest/ total 0 -rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file1 -rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file2 -rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file3 -rw-rw-r-- 1 smfrg smfrg 0 Aug 20 10:01 file4 -rw-rw-r-- 2 smfrg smfrg 0 Aug 20 10:01 file5 -rw-rw-r-- 2 smfrg smfrg 0 Aug 20 10:01 file_hd