Automatische Versionierung bei Dateiänderung (Ändern / Erstellen / Löschen)


16

Ich suche eine Implementierung (unter Linux) eines Mechanismus, der Änderungen in einem Verzeichnis (rekursiv) automatisch und transparent versioniert. Dies soll eine Ergänzung (möglicherweise ein Ersatz, wenn alle angeforderten Funktionen verfügbar sind) zur Standardversionierung (SVN, Git, ...) sein.

Ein Produkt unter MS Windows, das dies tut, ist AutoVer (um eine bessere Vorstellung von den Anforderungen zu haben). Ich würde gerne so etwas haben, aber auf Linux in einer nicht-grafischen Umgebung abzielen.

Ich habe gesehen, dass es einige Versuche gibt, diese Funktionalität unter Linux zu haben. Die nächste, die ich gefunden habe, ist die automatische Versionierung unter Subversion, aber es ist nicht offensichtlich, sie in vorhandenen Umgebungen zu implementieren (Server, auf denen zum Beispiel Konfigurationsdateien lokal sind).

Vielleicht etwas, mit dem ich arbeite inotify?

Vielen Dank im Voraus für alle Hinweise! WoJ


verwandt: Flashbake
Dan D.


Gibt es eine spezielle Anforderung bezüglich der von Ihnen verwendeten Software? Wenn Sie Änderungen nur manuell nachverfolgen möchten (durch Bearbeiten von Dateien), ist in Eclipse diese Funktion integriert, die als "lokaler Verlauf" bezeichnet wird.
Stefan Seidel

@StefanSeidel Ich bin nicht der Themenstarter, aber ich würde keine IDE-Lösung vorziehen.
Michael Pankov

Antworten:


5

1. Allzweckmethode mit Basar & Inotify

Dies ist von mir nicht getestet, aber ich habe diese Beschreibung gefunden , die bzr(bazaar) & inotifywaitzur Überwachung eines Verzeichnisses und zur Versionskontrolle der darin enthaltenen Dateien mithilfe von bazaar verwendet.

Dieses Skript überwacht das Verzeichnis auf Änderungen:

#!/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. Verwalten von / etc

Für den speziellen Fall Ihres Systems verwalten /etcVerzeichnis, können Sie die App verwenden etckeeper .

etckeeper ist eine Sammlung von Werkzeugen, mit denen / etc in einem git-, mercurial-, darcs- oder bzr-Repository gespeichert werden kann. Es ist mit apt (und anderen Paketmanagern, einschließlich yum und pacman-g2) verbunden, um Änderungen an / etc während Paket-Upgrades automatisch festzuschreiben. Es werden Dateimetadaten nachverfolgt, die Revison-Steuerungssysteme normalerweise nicht unterstützen. Dies ist jedoch wichtig für / etc, z. B. für die Berechtigungen von / etc / shadow. Es ist ziemlich modular und konfigurierbar, aber auch einfach zu bedienen, wenn Sie die Grundlagen der Arbeit mit der Versionskontrolle verstehen.

Hier ist ein gutes Tutorial , um Ihnen den Einstieg zu erleichtern.

3. Mit Git und Incron

Diese Technik nutzt gitund incron. Für diese Methode müssen Sie Folgendes tun:

A. Mach ein Repo

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

B. Erstellen Sie ein $HOME/bin/git-autocommitSkript

#!/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. Fügen Sie einen Eintrag zu incrontab hinzu

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

4. Flashbake verwenden

Eine andere Möglichkeit ist die Verwendung eines Tools wie Flashbake . Flashbake ist das Versionskontrollsystem, mit dem Cory Doctorow (von BoingBoing) seine Bücher schreibt.

Flashbake verwendet git under the hood, um Änderungen nachzuverfolgen, liegt jedoch zwischen automatisierten Sicherungen und der Verwendung eines einfachen Versionskontrollsystems.

Cory wollte, dass die Version Eingabeaufforderungen enthielt, Momentaufnahmen davon, wo er sich zu dem Zeitpunkt befand, als ein automatischer Commit stattfand, und was er dachte. Ich entwarf schnell ein Python-Skript, um die gewünschten Kontextinformationen abzurufen, und begann, ein Shell-Skript zu hacken, um git zu steuern. Dabei verwendete ich die Ausgabe des Python-Skripts für den Festschreibungskommentar, wenn ein Cron-Job den Shell-Wrapper aufrief.

Ressourcen


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


3

Ich denke, Sie sind auf dem richtigen Weg inotify. Dieser Artikel beschreibt die grundlegende Verwendung in einem ähnlichen Fall wie Sie. Ich würde vorschlagen, es entweder direkt zu verwenden oder ein Dienstprogramm auf Kernel-Ebene wie fschange zu kompilieren . Dies ist etwas umständlich, aber Sie können dann die Erkennung von Änderungen an eine git commitoder eine ähnliche Funktion binden .

Diese Lösungen haben beide das Problem, sich auf etwas unvollkommene Lösungen von Drittanbietern zu verlassen. Wenn Sie nichts dagegen nicht die Hände schmutzig zu machen, NodeJS bietet eine hervorragende, plattformübergreifende Einrichtung ( fs.watch ) für diesen genauen Zweck. Ein grundlegendes Tutorial zum Überwachen von Dateien auf Änderungen in NodeJS finden Sie hier . In ein paar Dutzend Zeilen oder weniger könnten Sie etwas schreiben, das ein Verzeichnis nach Dateien überwacht , dann (über child_process ) aussortiert und einen git commitoder einen ähnlichen Index ausführt (oder sogar manuell inkrementiert, wenn Sie den Roll-Your-Your-Process-Index mögen). eigener Ansatz).

fs.watchwird von inotifyLinux unterstützt, ist aber viel intuitiver zu bedienen. Es gibt andere NodeJS-Projekte, die diese Dateiüberwachungsfunktionalität in verschiedenen Komfortstufen wie dieser oder dieser umschließen .


Immer noch keine fertige Lösung, und ich würde wahrscheinlich mit Python gehen inotify. Aber danke.
Michael Pankov

3

Inotify (2) unter Linux kann einen großen Baum nicht überwachen, Fuse-Dateisysteme (an einem separaten Speicherort bereitgestellt) können dies jedoch möglicherweise tun, indem Dateisystemanforderungen in svn- oder git-Aufrufe übersetzt oder svn / git-Metadaten direkt geändert werden.

Dies ist eine sehr interessante Idee, aber ich hatte noch keine vorhandenen Implementierungen gehört.


Nehmen wir an, ich habe nur ein paar Dateien.
Michael Pankov

0

Ein solches Skript ist nicht schwer zu schreiben.

Meine Lieblingsversionskontrolle ist Git.

Folgendes Skript sollte es tun:

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

Lassen Sie dies entweder regelmäßig Ihr Verzeichnis überprüfen - oder rufen Sie Ihren Editor nach dem Speichern über ein Skript auf.

Wenn Sie dies jedoch tun, ist es möglicherweise sinnvoll, große Dateien und möglicherweise einige "nutzlose" wie Autosaves auszuschließen.


Ja, ich weiß, dass eine Cron-basierte Lösung einfach zu implementieren ist. Ich bin jedoch auf der Suche nach etwas, das beim Speichern versionieren würde, unabhängig vom Speichermechanismus. Aus diesem Grund habe ich in meiner Frage auch autoversionninf auf svn und inotify erwähnt.
WoJ

0

SparkleShare ( http://sparkleshare.org ) basiert auf git und implementiert eine Dropbox- ähnliche Funktionalität mit Versionskontrolle, Sie müssen jedoch einen ssh-Server einrichten (kann localhost sein).


Dieses Ding ist ungeschickt und erfordert viel Setup. Außerdem wird die Dropbox-Funktionalität nicht benötigt.
Michael Pankov

0

Ich würde dir empfehlen, NILFS auszuprobieren. Siehe die über Seite und Sie werden Quicky Lage zu entscheiden , whther das ist die eine , was Sie für oder nicht suchen.

HTH


0

Es gibt auch einen "armen Mann", der nur Rsync und einen Cron-Job verwendet. Grundsätzlich verlassen Sie sich auf die Backup-Funktion von rsync und verwenden zwei separate Pfade sowie ein Präfix / Suffix, um die Übersicht über Ihre Dateien zu behalten.

Es sieht mehr oder weniger so aus: / usr / bin / rsync -a -A -X --backup --suffix = date +".%Y-%m-%d_%H-%M-%S"$ source_path $ backup_path

Endergebnis: Wenn Sie nach der ersten Ausführung eine Datei mit dem Namen test_rsync im Quellpfad ändern, wird im Sicherungspfad eine Datei mit dem Namen test_rsync.2017-02-09_11-00-01 erstellt.

Es gibt eine Reihe von Problemen damit (es funktioniert nur, wenn Sie eine anständige Menge an Dateien haben und schlägt fehl, wenn Änderungen zwischen zwei aufeinander folgenden Rsync-Durchläufen vorgenommen werden (in meinem Fall 1 Minute)), aber es reicht möglicherweise für Ihre Anforderungen aus.

Wenn wir hier über Samba-Freigaben sprechen, könnte eine Ausschlussliste in Ordnung sein, habe ich leider noch nicht verstanden.

Lassen Sie mich wissen, wenn Sie dies verbessern.


0

Hier ist ein Python3-Skript, mit dem VMS die automatische Dateiversionierung mithilfe eines Zeitstempels ausführt, der beim Speichern an den ursprünglichen Dateinamen angehängt wird.

Ich habe eine Reihe von Kommentaren in das Skript eingefügt und ein halbes Dutzend solcher Skripte auf meinem Ubuntu-Computer ausgeführt, wobei nur die Verzeichnisse in den verschiedenen Versionen des Skripts unterschiedlich sind, sodass ich mehrere Verzeichnisse gleichzeitig versioniere. Keine wirkliche Beeinträchtigung der Maschinenleistung.

! / usr / bin / env python3

print ("PROJECT FILES VERSIONING STARTED") print ("version_creation.py") #Legen Sie den gesamten Code in das Skript dieses Namens. print ("run as .. 'python3 version_creation.py' from command line") print ("ctrl ' c 'to stop ") print (" ") print (" Um das Programm im Hintergrund auszuführen, geben Sie unten den Befehl ein und schließen Sie das Fenster. ") print (" nohup python3 version_creation.py ") print (" .... to Prozess stoppen, Menü / Administration / Systemüberwachung starten ... und python3 beenden ") print (" ") print (" Dateien immer im Verzeichnis 'ProjectFiles' und in den Versionsdateien speichern ") print (" wird ebenfalls in diesem Verzeichnis erstellt . ") print (" ") print (" ") print (" ") print (" ")

importiere bis importiere und importiere Zeit

--- Stellen Sie das Zeitintervall ein, nach dem nach neuen Dateien gesucht werden soll (in Sekunden)

- Dieses Intervall sollte kürzer sein als das Intervall, in dem neue Dateien angezeigt werden!

t = 10

--- Setzt das Quellverzeichnis (dr1) und das Zielverzeichnis (dr2)

dr1 = "/ path / to / source_directory"

dr2 = "/ path / to / target_directory"

import glob import os

dr1 = "/ home / michael / ProjectFiles" # Beide Originale und Versionen werden in diesem Verzeichnis gespeichert

dr2 = "/ home / michael / ProjectFileVersions"

während wahr:

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

drucken ("leer")

    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 =", Dateierstellung)

    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)

Teilen

das untenstehende wurde früher eingefügt und funktioniert, aber ich mag das obige Python-Skript viel besser ...... (benutze Python seit ca. 3 Stunden)

#!/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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.