3 min read

On Rsync

I found myself writing a Makefile for several tasks to manage this website, which uses Hugo. Of course, I use rsync, a truly tremendous tool, to deploy the files to my remote server.

This will be a short article about it.

Definition

rsync stands for remote sync and is used to transfer files from a source location to a destination location. The destination can be either local or remote, and it uses ssh as its remote shell by default, although it can use others such as rsh.

Its algorithm ensures that only the files that have changed since the last sync will be copied over, which it determines by looking at a file’s modification time.

Examples

Here are the flags used in these examples:

-a - Archive mode; equals -rlptgoD (no -H,-A,-X).

-z - Compress file data during the transfer.

-P - Same as --partial --progress.

-v - Increase verbosity.

–delete - Delete files from the destination directory if they are removed from the source.

Let’s create our workspace:

$ mkdir -p tmp/{foo,bar}
$ cd tmp
$ touch bar/file_{0..4}

This creates a directory structure like the following:

$ tree tmp
tmp
├── bar
│   ├── file_0
│   ├── file_1
│   ├── file_2
│   ├── file_3
│   ├── file_4
└── foo

2 directories, 5 files

Copying

Now, let’s copy all of the files from bar to foo:

~/tmp:$ rsync -az bar/ foo
~:$ tree ../tmp
../tmp
├── bar
│   ├── file_0
│   ├── file_1
│   ├── file_2
│   ├── file_3
│   ├── file_4
└── foo
    ├── file_0
    ├── file_1
    ├── file_2
    ├── file_3
    ├── file_4

2 directories, 10 files

The forward slash (/) after the source location tells rsync to copy only the contents of bar. If the slash is omitted, it will copy the directory, too.

~/tmp:$ tree ../tmp
../tmp
├── bar
│   ├── file_0
│   ├── file_1
│   ├── file_2
│   ├── file_3
│   ├── file_4
└── foo
    └── bar
        ├── file_0
        ├── file_1
        ├── file_2
        ├── file_3
        ├── file_4

3 directories, 10 files

Verbosity

There’s verbose mode:

~/tmp:$ rsync -avz bar/ foo
sending incremental file list
./
file_0
file_1
file_2
file_3
file_4

sent 314 bytes  received 114 bytes  856.00 bytes/sec
total size is 0  speedup is 0.00

And running again without having modified any of the files won’t transfer anything:

~/tmp:$ rsync -avz bar/ foo
sending incremental file list

sent 127 bytes  received 12 bytes  278.00 bytes/sec
total size is 0  speedup is 0.00

Now, let’s modify a file:

~/tmp:$ touch bar/file_2
~/tmp:$ rsync -avz bar/ foo
sending incremental file list
file_2

sent 175 bytes  received 35 bytes  420.00 bytes/sec
total size is 0  speedup is 0.00

Weeeeeeeeeeeeeeeeeeeeeeeeeeeee

Syncing

Adding the --delete switch will keep the directories truly in sync:

~/tmp:$ rm bar/file_3
~/tmp:$ rsync -avz --delete bar/ foo
sending incremental file list
deleting file_3

sent 125 bytes  received 22 bytes  294.00 bytes/sec
total size is 0  speedup is 0.00
~/tmp:$ tree ../tmp
../tmp
├── bar
│   ├── file_0
│   ├── file_1
│   ├── file_2
│   └── file_4
└── foo
    ├── file_0
    ├── file_1
    ├── file_2
    └── file_4

2 directories, 8 files

Remote Transfer

rsync -azP --delete bar/ kilgoretrout@vonnegut:/var/www/foo/

Makefile

Here be a simple Makefile:

CC              = hugo
FLAGS           = -D

DEST            = /path/to/document_root/
SYSTEM          = kilgoretrout@vonnegut
TARGET          = public

.PHONY: build clean deploy serve

build:
        $(CC)

clean:
        rm -rf $(TARGET)

deploy: $(TARGET)
        rsync -azP --delete $(TARGET)/ $(SYSTEM):$(DEST)

serve:
        $(CC) $(FLAGS) serve