Versioning automatique lors du changement de fichier (modifier / créer / supprimer)


16

Je cherche une implémentation (sous Linux) d'un mécanisme qui versionnerait automatiquement et de manière transparente toutes les modifications dans un répertoire (récursivement). Il s'agit d'un ajout (éventuellement de remplacement si toutes les fonctionnalités demandées sont disponibles) au versioning standard (SVN, git, ...)

Un produit sur MS Windows qui fait cela est AutoVer (pour avoir une meilleure idée des exigences). J'adorerais avoir quelque chose comme ça mais destiné à Linux dans un environnement non graphique.

J'ai vu qu'il y a quelques tentatives pour avoir cette fonctionnalité sur Linux, la plus proche que j'ai trouvée est la conversion automatique sur Subversion mais il n'est pas évident de l'implémenter sur des environnements existants (serveurs où, par exemple, les fichiers de configuration sont locaux).

Peut-être que quelque chose fonctionne avec inotify?

Merci d'avance pour tout conseil! WoJ


en relation: flashbake
Dan D.


Existe-t-il une exigence particulière concernant le logiciel que vous utilisez? Parce que si vous cherchez uniquement à suivre les modifications que vous effectuez manuellement (en modifiant des fichiers), Eclipse a cette fonctionnalité intégrée, elle s'appelle "l'historique local".
Stefan Seidel

@StefanSeidel Je ne suis pas le sujet de départ, mais je préférerais une solution sans IDE.
Michael Pankov

Réponses:


6

1. Méthode à usage général utilisant bazar et inotify

Ceci n'est pas testé par moi mais j'ai trouvé cette écriture qui utilise bzr(bazaar) et inotifywaitpour surveiller un répertoire et contrôler la version des fichiers qu'il contient en utilisant bazaar.

Ce script fait tout le travail de surveillance du répertoire pour les changements:

#!/bin/bash

# go to checkout repository folder you want to watch
cd path/to/www/parent/www
# start watching the directory for changes recusively, ignoring .bzr dir
# comment is made out of dir/filename
# no output is shown from this, but wrinting a filename instead of /dev/null 
# would allow logging
inotifywait –exclude \.bzr -r -q -m -e CLOSE_WRITE \
    –format=”bzr commit -m ‘autocommit for %w/%f’” ./ | \
    sh  2>/dev/null 1>&2 &
# disown the pid, so the inotify thread will get free from parent process
# and will not be terminated with it
PID=`ps aux | grep inotify | grep CLOSE_WRITE | grep -v grep | awk ‘{print $2}’`
disown $PID

# this is for new files, not modifications, optional
inotifywait –exclude \.bzr -r -q -m -e CREATE \
    –format=”bzr add *; bzr commit -m ‘new file added %w/%f’” ./ | \
    sh  2>/dev/null 1>&2 &
PID=`ps aux | grep inotify | grep CREATE | grep -v grep | awk ‘{print $2}’`
disown $PID

exit 0;

2. Gestion / etc

Pour le cas particulier de la gestion du /etcrépertoire de votre système , vous pouvez utiliser l'application etckeeper .

etckeeper est une collection d'outils pour laisser / etc être stocké dans un dépôt git, mercurial, darcs ou bzr. Il se connecte à apt (et à d'autres gestionnaires de packages, yum et pacman-g2) pour valider automatiquement les modifications apportées à / etc lors des mises à niveau des packages. Il suit les métadonnées des fichiers que les systèmes de contrôle de révision ne prennent généralement pas en charge, mais cela est important pour / etc, comme les autorisations de / etc / shadow. Il est assez modulaire et configurable, tout en étant simple à utiliser si vous comprenez les bases du travail avec le contrôle de révision.

Voici un bon tutoriel pour vous aider à démarrer.

3. Utiliser git et incron

Cette technique utilise gitet incron. Pour cette méthode, vous devez effectuer les opérations suivantes:

A. Faire un repo

% mkdir $HOME/git
% cd $HOME/git
% git init

B. Créez un $HOME/bin/git-autocommitscript

#!/bin/bash

REP_DIR="$HOME/git"       # repository directory
NOTIFY_DIR="$HOME/srv"    # directory to version

cd $REP_DIR
GIT_WORK_TREE=$NOTIFY_DIR /usr/bin/git add .
GIT_WORK_TREE=$NOTIFY_DIR /usr/bin/git commit -a -m "auto"

C. Ajouter une entrée à incrontab

% sudo incrontab -e $HOME/srv IN_MODIFY,IN_CREATE,IN_MOVED_FROM,IN_MOVED_TO $HOME/bin/git-autocommit

4. Utilisation de Flashbake

Une autre option consiste à utiliser un outil comme Flashbake . Flashbake est le système de contrôle de version que Cory Doctorow (de la renommée BoingBoing) utilise pour écrire ses livres.

Flashbake utilise git sous le capot pour suivre les modifications, mais se situe entre la réalisation de sauvegardes automatisées et l'utilisation d'un système de contrôle de version simple vous-même.

Cory voulait que la version contienne des invites, des instantanés de l'endroit où il se trouvait au moment de la validation automatique et de ce qu'il pensait. J'ai rapidement esquissé un script Python pour extraire les informations contextuelles qu'il voulait et j'ai commencé à pirater un script shell pour piloter git, en utilisant la sortie du script Python pour le commentaire de validation lorsqu'un travail cron a appelé le wrapper shell.

Ressources


3
inotifywait + "git local" = gitwatch.sh, regardez ici: github.com/nevik/gitwatch/blob/master/gitwatch.sh
diyism


3

Je pense que vous êtes sur la bonne voie avec inotify. Cet article détaille son utilisation de base dans un boîtier similaire au vôtre. Je suggère de l'utiliser soit directement, soit de compiler un utilitaire au niveau du noyau comme fschange . C'est quelque chose de compliqué, mais vous pouvez alors lier la détection des changements à un git commitou similaire.

Ces solutions ont toutes deux pour problème de s'appuyer sur des solutions tierces quelque peu imparfaites. Si cela ne vous dérange pas de vous salir les mains, NodeJS fournit une excellente installation multiplateforme ( fs.watch ) à cet effet précis. Un tutoriel de base sur la surveillance des fichiers pour les changements dans NodeJS peut être trouvé ici . En quelques dizaines de lignes ou moins, vous pouvez écrire quelque chose qui surveille un répertoire pour les fichiers, puis s'exécute (via child_process ) et exécute un git commitou similaire (ou même incrémente manuellement un index de fichier de version, si vous aimez le roll-your- propre approche).

fs.watchest soutenu par inotifyLinux, mais est beaucoup plus intuitif à utiliser. Il existe d'autres projets NodeJS qui enveloppent cette fonctionnalité d'observation des fichiers à différents niveaux de commodité, comme celui-ci ou celui-ci .


Pas encore une solution prête, et, eh bien, je serais probablement aller avec Python inotify. Mais merci.
Michael Pankov

3

inotify (2) sur Linux ne pourra pas regarder une grande arborescence, mais le système de fichiers fusionné (monté dans un emplacement séparé) pourrait probablement le gérer, en traduisant les demandes de système de fichiers en appels svn ou git, ou en changeant directement les métadonnées svn / git.

C'est une idée très intéressante, mais je n'avais entendu parler d'aucune implémentation existante.


Disons que je n'ai que quelques fichiers.
Michael Pankov

0

Un tel script n'est pas difficile à écrire.

Mon contrôle de version préféré est git.

le script suivant devrait le faire:

#!/bin/sh
git add .
git commit -am "my automatic commit"

soit faire vérifier périodiquement votre répertoire - ou si votre éditeur est appelable par script après avoir enregistré.

Mais si vous le faites comme ça, il peut être judicieux d'exclure les gros fichiers et peut-être certains "inutiles" comme les sauvegardes automatiques.


Oui, je sais qu'une solution basée sur cron est simple à implémenter. Je suis cependant à la recherche de quelque chose qui serait une version de sauvegarde, quel que soit le mécanisme de sauvegarde. C'est aussi pourquoi j'ai mentionné autoversionninf sur svn ainsi que inotify dans ma question.
WoJ

0

SparkleShare ( http://sparkleshare.org ) est basé sur git et implémente une fonctionnalité de type Dropbox avec contrôle de version, mais vous devez configurer un serveur ssh (peut être localhost).


Cette chose est maladroite et nécessite beaucoup de configuration. En outre, la fonctionnalité Dropbox n'est pas nécessaire.
Michael Pankov

0

Je vous recommande d'essayer NILFS. Référez-vous à la page À propos et vous pourrez rapidement décider si c'est celle-ci que vous recherchez ou non.

HTH


0

Il y a aussi une manière de faire cela pour le pauvre en utilisant seulement rsync et un travail cron. Vous vous basez essentiellement sur la fonction de sauvegarde de rsync et utilisez deux chemins séparés plus un préfixe / suffixe pour garder une trace de vos fichiers.

Il ressemble plus ou moins à ceci: / usr / bin / rsync -a -A -X --backup --suffix = date +".%Y-%m-%d_%H-%M-%S"$ source_path $ backup_path

Résultat final: la modification d'un fichier appelé test_rsync dans le chemin source après l'exécution initiale entraînera la création d'un fichier appelé test_rsync.2017-02-09_11-00-01 dans le chemin de sauvegarde.

Il y a un tas de problèmes avec cela (cela fonctionne si vous avez seulement une quantité décente de fichiers et échouera pour les changements qui se produisent entre deux exécutions consécutives de rsync (1 minute dans mon cas)) mais cela peut être suffisant pour vos besoins.

Si nous parlons ici de partages de samba, une liste d'exclusion pourrait être en ordre, je n'y ai pas encore eu peur, j'ai peur.

Faites-moi savoir si vous améliorez cela.


0

Voici un script Python3 qui utilise VMS comme le versionnage automatique des fichiers en utilisant un horodatage ajouté au nom du fichier d'origine lors de l'enregistrement.

J'ai mis un tas de commentaires dans le script et exécuté une demi-douzaine de tels scripts sur ma machine ubuntu, seuls les répertoires étant différents dans chaque version différente du script, de sorte que je versionne simultanément plusieurs répertoires. Aucune réelle pénalité sur les performances des machines.

! / usr / bin / env python3

print ("PROJECT FILES VERSIONING STARTED") print ("version_creation.py") #placer tout ce code dans le script de ce nom print ("run as .. 'python3 version_creation.py' from line command") print ("ctrl ' c 'pour arrêter ") print (" ") print (" Pour exécuter le programme en arrière-plan, tapez ci-dessous sur la ligne de commande, puis fermez la fenêtre. ") print (" nohup python3 version_creation.py ") print (" .... to arrêter le processus aller menu / administration / moniteur système ... et tuer python3 ") print (" ") print (" Toujours enregistrer les fichiers dans le répertoire 'ProjectFiles' et les fichiers de version ") print (" sera également créé dans ce répertoire . ") imprimer (" ") imprimer (" ") imprimer (" ") imprimer (" ")

importation shutil import os os import time

--- définissez l'intervalle de temps pour vérifier les nouveaux fichiers (en secondes) ci-dessous

- cet intervalle doit être plus petit que l'intervalle où les nouveaux fichiers apparaissent!

t = 10

--- définir le répertoire source (dr1) et le répertoire cible (dr2)

dr1 = "/ chemin / vers / répertoire_source"

dr2 = "/ chemin / vers / répertoire_cible"

import glob import os

dr1 = "/ home / michael / ProjectFiles" #les deux originaux et versions seront enregistrés dans ce répertoire

dr2 = "/ home / michael / ProjectFileVersions"

tandis que True:

if os.listdir(dr1) == []:

imprimer ("Vide")

    n = 100
else:
    list_of_files = glob.glob(dr1+'/*')   # * means all if need specific format then *.csv
    latest_file_path = max(list_of_files, key=os.path.getctime)

print ("1 Latest_file_path =", latest_file_path)

    originalname = latest_file_path.split('/')[-1]

print ("2 originalname =", originalname)

    filecreation = (os.path.getmtime(latest_file_path))

print ("filecreation =", filecreation)

    now = time.time()
    fivesec_ago = now - 5 # Number of seconds

print ("fivesec_ago =", fivesec_ago)

    timedif = fivesec_ago - filecreation #time between file creation

print ("timedif =", timedif)

    if timedif <= 5: #if file created less than 5 seconds ago

        nameroot = originalname.split(".")[-0]
        print ("3 nameroot= ", nameroot)

        extension = os.path.splitext(originalname)[1][1:]
        print ("4 extension = ", extension)

        curdatetime = time.strftime('%Y%m%d-%H%M%S')
        print ("5 curdatetime = ", curdatetime)

        newassembledname = (nameroot + "_" + curdatetime + "." + extension)
        print ("6 newassembledname = ", newassembledname)



        source = dr1+"/"+originalname
        print ("7 source = ", source)

        target = dr1+"/"+newassembledname
        print ("8 target = ", target)

        shutil.copy(source, target)


    time.sleep(t)

partager

le ci-dessous a été mis en place plus tôt et fonctionne mais j'aime beaucoup mieux le script python ci-dessus ...... (utilise python depuis environ 3 heures)

#!/usr/bin/env python3

print ("PROJECT FILES VERSIONING STARTED")
print ("projectfileversioning.py")
print ("run as..  'python3 projectfileversioning.py'       from command line")
print ("ctrl 'c'      to stop")
print (" ")
print ("To run program in background type below to command line and then close the window. ")
print ("nohup python3 projectfileversioning.py")
print ("....to stop process go menu/administration/system monitor... and kill python")
print (" ")
print ("Always save files to the 'ProjectFiles' directory and the file ")
print ("   will be redirected to the ProjectFileVersions where")
print ("   time stamped versions will also be created.")
print (" ")
print ("If you like you may then copy/move the versioned and original file from 'ProjectFileVersions' to ")
print ("any other directory you like.")

import shutil
import os
import time

#--- set the time interval to check for new files (in seconds) below 
#-   this interval should be smaller than the interval new files appear!
t = 10

#--- set the source directory (dr1) and target directory (dr2)
#dr1 = "/path/to/source_directory"
#dr2 = "/path/to/target_directory"

import glob
import os

dr1 = "/home/michael/ProjectFiles"
dr2 = "/home/michael/ProjectFileVersions"


while True:

    if os.listdir(dr1) == []:
        n = 100
    else:
        list_of_files = glob.glob(dr1+'/*')   # * means all if need specific format then *.csv
        latest_file_path = max(list_of_files, key=os.path.getctime)
        print ("1 Latest_file_path = ", latest_file_path)

        originalname = latest_file_path.split('/')[-1]
        print ("2 originalname = ", originalname)

        nameroot = originalname.split(".")[-0]
        print ("3 nameroot= ", nameroot)

        extension = os.path.splitext(originalname)[1][1:]
        print ("4 extension = ", extension)

        curdatetime = time.strftime('%Y%m%d-%H%M%S')
        print ("5 curdatetime = ", curdatetime)

        newassembledname = (nameroot + "_" + curdatetime + "." + extension)
        print ("6 newassembledname = ", newassembledname)




        source = dr1+"/"+originalname
        print ("7 source = ", source)

        target = dr2+"/"+originalname
        print ("8 target = ", target)

        shutil.copy(source, target)



        source = dr1+"/"+originalname
        print ("9 source = ", source)

        target = dr2+"/"+newassembledname
        print ("10 target = ", target)

        shutil.move(source, target)
        time.sleep(t)


#share
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.