Bien que tar
dispose d'un mode incrémentiel, il existe quelques outils plus complets pour faire le travail :
- Duplicité
- Duplicata
Non seulement ils prennent en charge les sauvegardes incrémentielles, mais il est facile de configurer un calendrier sur lequel une sauvegarde complète doit être effectuée. Par exemple en duplicity
:duplicity --full-if-older-than 1M
s'assurera qu'une sauvegarde complète a été exécutée. Ils prennent également en charge le retour dans le temps vers un fichier spécifique, avec le tar ordinaire, vous devrez parcourir tous les fichiers incrémentiels jusqu'à ce que vous en trouviez un qui contient le bon fichier.
De plus, ils prennent en charge le cryptage et le téléchargement vers une variété de backends (comme sftp, le stockage blob, etc.). Evidemment si vous cryptez, n'oubliez pas de faire une bonne sauvegarde de vos clés sur une sauvegarde secondaire !
Un autre aspect important est que vous pouvez vérifier l'intégrité de vos sauvegardes, en vous assurant que vous pouvez restaurer, par exemple en utilisant duplicity verify
.
Je conseillerais négativement une stratégie de sauvegarde basée sur git. Les grandes restaurations prennent beaucoup de temps.
J'ai essayé rsync, mais il ne semble pas pouvoir faire ce que je veux, ou plus probablement, je ne sais pas comment faire pour qu'il le fasse.
Je sais que je pourrais probablement créer un script qui exécute un diff, puis sélectionne les fichiers à sauvegarder en fonction du résultat (ou plus efficacement, obtenez simplement une somme de contrôle et comparez), mais je veux savoir s'il existe un utilitaire qui peut le faire un un peu plus facile :)
rsync
est précisément ce programme qui copie sur la base d'un diff. Par défaut, il ne copie que lorsqu'il y a une différence dans l'heure ou la taille de la dernière modification, mais il peut même comparer par somme de contrôle avec -c
.
Le problème ici est que vous avez tar
'ing les sauvegardes. Cela devient plus facile si vous ne le faites pas. Je ne sais même pas pourquoi tu fais ça. Cela peut avoir du sens si vous les compressez, mais vous ne le faites même pas.
L'article de Wikipédia sur les sauvegardes incrémentielles contient un exemple rsync
commande qui va à peu près :
rsync -va \
--link-dest="$dst/2020-02-16--05-10-45--testdir/" \
"$src/testdir/" \
"$dst/2020-02-17--03-24-16--testdir/"
Ce qu'il fait est de lier les fichiers de la sauvegarde précédente lorsqu'ils sont inchangés par rapport à la source. Il y a aussi --copy-dest
si vous voulez qu'il copie à la place (c'est encore plus rapide quand $dst
est une télécommande ou sur un lecteur plus rapide).
Si vous utilisez un système de fichiers avec des sous-volumes comme btrfs, vous pouvez également prendre un instantané de la sauvegarde précédente avant la synchronisation. Les instantanés sont instantanés et ne prennent pas d'espace supplémentaire[1].
btrfs subvolume snapshot \
"$dst/2020-02-16--05-10-45--testdir" \
"$dst/2020-02-17--03-24-16--testdir"
Ou si vous utilisez un système de fichiers qui prend en charge les reflinks, comme ext4, vous pouvez également le faire. Les reflinks sont effectués en créant un nouvel inode mais en se référant aux mêmes blocs que le fichier source, implémentant le support COW. C'est toujours plus rapide que la copie normale car il ne lit ni n'écrit les données, et il ne prend pas non plus d'espace supplémentaire[1].
cp --reflink -av \
"$dst/2020-02-16--05-10-45--testdir" \
"$dst/2020-02-17--03-24-16--testdir"
Quoi qu'il en soit, une fois que vous avez fait quelque chose comme ça, vous pouvez simplement faire un rsync
normal pour copier les différences :
rsync -va \
"$src/testdir/" \
"$dst/2020-02-17--03-24-16--testdir/"
Cependant, vous voudrez peut-être ajouter --delete
, ce qui entraînerait la suppression par rsync des fichiers de la destination qui ne sont plus présents dans la source.
Une autre option utile est -i
ou --itemize-changes
. Il produit une sortie succincte et lisible par machine qui décrit les modifications apportées par rsync. J'ajoute normalement cette option et un tuyau comme :
rsync -Pai --delete \
"$src/testdir/" \
"$dst/2020-02-17--03-24-16--testdir/" \
|& tee -a "$dst/2020-02-17--03-24-16--testdir.log"
pour garder une trace des changements via facilement grep
fichiers capables. Le |&
est de diriger à la fois stdout et stderr.
Le -P
est l'abréviation de --partial
et --progress
. --partial
conserve les fichiers partiellement transférés, mais surtout --progress
rapporte la progression de chaque fichier.
Comment cela se compare à l'archivage des modifications avec tar
Les solutions ci-dessus se traduisent par des répertoires qui semblent tout contenir. Même si c'est le cas, au total pour n'importe quelle quantité/fréquence de sauvegardes, elles occuperaient à peu près la même quantité d'espace que d'avoir des archives tar simples avec seulement des changements. C'est à cause du fonctionnement des liens physiques, des liens de référence et des instantanés. L'utilisation de la bande passante lors de la création des sauvegardes serait également la même.
Les avantages sont :
- les sauvegardes sont faciles à restaurer avec rsync et plus rapides, puisque rsync ne transfère que les différences de la sauvegarde.
- ils sont plus simples à parcourir et à modifier si nécessaire.
- les suppressions de fichiers peuvent être encodées naturellement comme l'absence du fichier dans les nouvelles sauvegardes. Lors de l'utilisation d'archives tar, il faudrait recourir à des hacks, comme supprimer un fichier
foo
, marquez-lefoo.DELETED
ou faire quelque chose de compliqué. Je n'ai jamais utilisé la duplicité par exemple, mais en regardant sa documentation, il semble qu'il encode les suppressions en ajoutant un fichier vide du même nom dans le nouveau tar et en conservant la signature originale du fichier dans un fichier .sigtar séparé. J'imagine qu'il compare la signature d'origine avec celle d'un fichier vide pour faire la différence entre une suppression de fichier et une modification vers un fichier vide réel.
Si l'on veut toujours configurer chaque sauvegarde comme ne contenant que les fichiers différents (ajoutés ou modifiés), alors on peut utiliser le --link-dest
solution décrite ci-dessus, puis supprimez les liens physiques en utilisant quelque chose comme ceci :
find $new_backup -type f ! -links 1 -delete
[1] À proprement parler, ils utilisent de l'espace supplémentaire sous la forme de métadonnées en double, comme le nom de fichier et autres. Cependant, je pense que n'importe qui considérerait cela comme insignifiant.
Et pourquoi n'envisagez-vous pas git
lui-même ?
La stratégie que vous décrivez, après une sauvegarde complète et deux sauvegardes incrémentielles, a ses complications lorsque vous continuez. Il est facile de faire des erreurs, et cela peut deviennent très inefficaces, en fonction des changements. Il faudrait qu'il y ait une sorte de rotation, c'est-à-dire que de temps en temps vous faites une nouvelle sauvegarde complète - et ensuite voulez-vous garder l'ancienne ou non ?
Étant donné un fonctionnement dir "testdir" contenant un projet (fichiers et sous-répertoires), git
fait par défaut un .git
masqué sous-répertoire pour les données. Ce serait pour le contrôle de version local supplémentaire Caractéristiques. Pour la sauvegarde, vous pouvez l'archiver/le copier sur un support ou le cloner via le réseau.
Le contrôle de révision vous obtenez (sans demander) est un effet secondaire du stockage différentiel de git.
Vous pouvez omettre toutes les bifurcations/branches et ainsi de suite. Cela signifie que vous avez une branche appelée "master".
Avant de pouvoir valider (en fait écrire dans l'archive/le dépôt git), vous devez configurer un utilisateur minimal pour le fichier de configuration. Ensuite, vous devez d'abord apprendre et tester dans un sous-répertoire (peut-être tmpfs). Git est parfois aussi compliqué que tar.
Quoi qu'il en soit, comme le dit un commentaire :la sauvegarde est facile, la partie la plus difficile est la restauration.
Les inconvénients de git ne seraient que le petit surcoût / surpuissance.
Les avantages sont :git tracks contenu et noms de fichiers. Il n'enregistre que ce qui est nécessaire, basé sur un diff (pour les fichiers texte au moins).
Exemple
J'ai 3 fichiers dans un répertoire. Après git init
, git add .
et git commit
J'ai un .git
260K dir.
Puis j'ai cp -r .git /tmp/abpic.git
(un bon endroit pour enregistrer une sauvegarde :). Je rm
le jpg 154K, et aussi modifier un fichier texte. Moi aussi rm -r .git
.
]# ls
atext btext
]# git --git-dir=/tmp/abpic.git/ ls-files
atext
btext
pic154k.jpg
Avant de restaurer les fichiers, je peux obtenir les différences précises :
]# git --git-dir=/tmp/abpic.git/ status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: atext
deleted: pic154k.jpg
no changes added to commit (use "git add" and/or "git commit -a")
Ici, je veux suivre le git restore
indice.
Après git --git-dir=/tmp/abpic.git/ restore \*
:
]# ls -st
total 164
4 atext 156 pic154k.jpg 4 btext
Le jpeg est de retour, et le fichier texte btext
n'a pas été mis à jour (conserve l'horodatage). Les modifications en atext
sont écrasés.
Pour réunir le référentiel et le répertoire (de travail), vous pouvez simplement le recopier.
]# cp -r /tmp/abpic.git/ .git
]# git status
On branch master
nothing to commit, working tree clean
Les fichiers du répertoire courant sont identiques au .git
archive (après le restore
). Les nouvelles modifications seront affichées et pourront être ajoutées et validées, sans aucune planification. Vous n'avez qu'à le stocker sur un autre support, à des fins de sauvegarde.
Après la modification d'un fichier, vous pouvez utiliser status
ou diff
:
]# echo more >>btext
]# git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: btext
no changes added to commit (use "git add" and/or "git commit -a")
]# git diff
diff --git a/btext b/btext
index 96b5d76..a4a6c5b 100644
--- a/btext
+++ b/btext
@@ -1,2 +1,3 @@
This is file b
second line
+more
#]
Et tout comme git
connaît "+more" dans le fichier "btext", il ne stockera également cette ligne que de manière incrémentielle.
Après git add .
(ou git add btext
) le status
la commande passe du rouge au vert et le commit
vous donne les infos.
]# git add .
]# git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: btext
]# git commit -m 'btext: more'
[master fad0453] btext: more
1 file changed, 1 insertion(+)
Et vous pouvez vraiment accéder au contenu, d'une manière ou d'une autre :
]# git ls-tree @
100644 blob 321e55a5dc61e25fe34e7c79f388101bd1ae4bbf atext
100644 blob a4a6c5bd3359d84705e5fd01884caa8abd1736d0 btext
100644 blob 2d550ffe96aa4347e465109831ac52b7897b9f0d pic154k.jpg
Et puis les 4 premiers chiffres de hachage hexadécimaux
]# git cat-file blob a4a6
This is file b
second line
more
Pour voyager dans le temps d'un commit, c'est :
]# git ls-tree @^
100644 blob 321e55a5dc61e25fe34e7c79f388101bd1ae4bbf atext
100644 blob 96b5d76c5ee3ccb7e02be421e21c4fb8b96ca2f0 btext
100644 blob 2d550ffe96aa4347e465109831ac52b7897b9f0d pic154k.jpg
]# git cat-file blob 96b5
This is file b
second line
Le blob de btext a un hachage différent avant le dernier commit, les autres ont le même.
Un aperçu serait :
]# git log
commit fad04538f7f8ddae1f630b648d1fe85c1fafa1b4 (HEAD -> master)
Author: Your Name <[email protected]>
Date: Sun Feb 16 10:51:51 2020 +0000
btext: more
commit 0bfc1837e20988f1b80f8b7070c5cdd2de346dc7
Author: Your Name <[email protected]>
Date: Sun Feb 16 08:45:16 2020 +0000
added 3 files with 'add .'
Au lieu de fichiers tar horodatés manuellement, vous avez des commits avec un message et une date (et un auteur). Les listes de fichiers et leur contenu sont logiquement attachés à ces commits.
git
simple est 20 % plus compliqué que tar
, mais vous obtenez 50 % de fonctionnalités en plus.
Je voulais faire le troisième changement d'OP:changer un fichier plus deux nouveaux fichiers "image". Je l'ai fait, mais maintenant j'ai :
]# git log
commit deca7be7de8571a222d9fb9c0d1287e1d4d3160c (HEAD -> master)
Author: Your Name <[email protected]>
Date: Sun Feb 16 17:56:18 2020 +0000
didn't add the pics before :(
commit b0355a07476c8d8103ce937ddc372575f0fb8ebf
Author: Your Name <[email protected]>
Date: Sun Feb 16 17:54:03 2020 +0000
Two new picture files
Had to change btext...
commit fad04538f7f8ddae1f630b648d1fe85c1fafa1b4
Author: Your Name <[email protected]>
Date: Sun Feb 16 10:51:51 2020 +0000
btext: more
commit 0bfc1837e20988f1b80f8b7070c5cdd2de346dc7
Author: Your Name <[email protected]>
Date: Sun Feb 16 08:45:16 2020 +0000
added 3 files with 'add .'
]#
Alors qu'est-ce que Your Name Guy a fait exactement, dans ses deux commits, peu avant 18h ?
Les détails du dernier commit sont :
]# git show
commit deca7be7de8571a222d9fb9c0d1287e1d4d3160c (HEAD -> master)
Author: Your Name <[email protected]>
Date: Sun Feb 16 17:56:18 2020 +0000
didn't add the pics before :(
diff --git a/picture2 b/picture2
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/picture2
@@ -0,0 +1 @@
+1
diff --git a/picture3 b/picture3
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/picture3
@@ -0,0 +1 @@
+2
]#
Et pour vérifier l'avant-dernier commit, dont le message annonce deux images :
]# git show @^
commit b0355a07476c8d8103ce937ddc372575f0fb8ebf
Author: Your Name <[email protected]>
Date: Sun Feb 16 17:54:03 2020 +0000
Two new picture files
Had to change btext...
diff --git a/btext b/btext
index a4a6c5b..de7291e 100644
--- a/btext
+++ b/btext
@@ -1,3 +1 @@
-This is file b
-second line
-more
+Completely changed file b
]#
Cela s'est produit parce que j'ai essayé git commit -a
au raccourci git add .
, et les deux fichiers étaient nouveaux (non suivi). Il s'affichait en rouge avec git status
, mais comme je l'ai dit, git n'est pas moins délicat que tar ou unix.
"Votre débutante sait juste ce dont vous avez besoin, mais je sais ce que vous voulez" (ou l'inverse. Le fait est que ce n'est pas toujours pareil)