Автоматическое управление версиями при изменении файла (изменение / создание / удаление)

11370
WoJ

Я ищу реализацию (в Linux) механизма, который бы автоматически и прозрачно версировал любые изменения в каталоге (рекурсивно). Предполагается, что это дополнение (возможно, замена, если все требуемые функции доступны) к стандартному версионированию (SVN, git, ...)

Продукт на MS Windows, который делает это, AutoVer (чтобы лучше понять требования). Я хотел бы иметь что-то подобное, но нацеленное на Linux в неграфической среде.

Я видел, что есть некоторые попытки использовать эту функциональность в Linux, самая близкая из них, которую я нашел, - это автоверсионирование в Subversion, но это не очевидно для реализации в существующих средах (серверах, где, например, файлы конфигурации являются локальными).

Может быть, что-то работает с inotify?

Заранее спасибо за любые указатели! WOJ

15
связанные: [flashbake] (http://bitbucketlabs.net/flashbake/) Dan D. 12 лет назад 0
http://sourceforge.net/apps/mediawiki/fuse/index.php?title=VersioningFileSystems SleighBoy 12 лет назад 0
Есть ли особые требования относительно того, какое программное обеспечение вы используете? Потому что, если вы хотите отслеживать изменения, которые вы делаете вручную (путем редактирования файлов), Eclipse имеет эту встроенную функцию, которая называется «локальная история». Stefan Seidel 11 лет назад 0
@StefanSeidel Я не начинающий тему, но я бы предпочел решение без IDE. Michael Pankov 11 лет назад 0

9 ответов на вопрос

5
slm

1. General purpose method using bazaar & inotify

This is untested by me but I found this write up that makes use of bzr (bazaar) & inotifywait to monitor a directory and version control the files in it using bazaar.

This script does all the work of watching the directory for changes:

#!/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 ‘’` 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 ‘’` disown $PID exit 0; 

2. Managing /etc

For the special case of managing your system's /etc directory, you can use the app etckeeper.

etckeeper is a collection of tools to let /etc be stored in a git, mercurial, darcs, or bzr repository. It hooks into apt (and other package managers including yum and pacman-g2) to automatically commit changes made to /etc during package upgrades. It tracks file metadata that revison control systems do not normally support, but that is important for /etc, such as the permissions of /etc/shadow. It's quite modular and configurable, while also being simple to use if you understand the basics of working with revision control.

Here's a good tutorial to get you started with it.

3. Using git and incron

This technique makes use of git and incron. For this method you need to do the following:

A. Make a repo

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

B. Create a $HOME/bin/git-autocommit script

#!/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. Add an entry to incrontab

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

4. Using Flashbake

Another option is to use a tool like Flashbake. Flashbake is the version control system that Cory Doctorow (of BoingBoing fame) uses to write his books.

Flashbake uses git under the hood to track changes but is somewhere between doing automated backups and using a plain version control system yourself.

Cory wanted the version to carry prompts, snapshots of where he was at the time an automated commit occurred and what he was thinking. I quickly sketched out a Python script to pull the contextual information he wanted and started hacking together a shell script to drive git, using the Python script’s output for the commit comment when a cron job invoked the shell wrapper.

Resources

inotifywait + "git local" = gitwatch.sh, посмотрите здесь: https://github.com/nevik/gitwatch/blob/master/gitwatch.sh diyism 9 лет назад 2
4
bdecaf

Тут же на ум приходит ZFS . Он может создавать снимки - и есть несколько проектов для автоматического создания снимков .

Я читал о ZFS, но похоже, что это не стабильное решение для базовых файловых систем (по крайней мере, в Linux) WoJ 12 лет назад 0
Мне бы очень хотелось, чтобы решение было привязано к существующему FS. Michael Pankov 11 лет назад 0
Возможно это? http://www.ext3cow.com Zac B 11 лет назад 0
3
Zac B

Я думаю, что вы на правильном пути inotify. Эта статья подробно описывает его основное использование в случае, похожем на ваш. Я бы предложил использовать его напрямую или скомпилировать утилиту уровня ядра, такую как fschange . Это что-то вроде хлопот, но вы можете связать обнаружение изменений с git commitили аналогичным.

Оба эти решения имеют проблему использования несовершенных решений сторонних производителей. Если вы не возражаете запачкать руки, NodeJS предоставляет отличное кроссплатформенное средство ( fs.watch ) для этой конкретной цели. Базовое руководство по просмотру файлов на предмет изменений в NodeJS можно найти здесь . В несколько десятков строк или меньше вы могли бы написать что-то, что просматривает каталог для файлов, а затем выдает (через child_process ) и запускает git commitили подобное (или даже вручную увеличивает индекс файла версии, если вам нравится roll-your- собственный подход).

fs.watchподдерживается inotifyLinux, но более интуитивно понятен в использовании. Существуют другие проекты NodeJS, которые оборачивают эту функцию просмотра файлов с различными уровнями удобства, как этот или этот .

Все еще не готовое решение, и, ну, я бы, наверное, выбрал Python для inotify. Но спасибо. Michael Pankov 11 лет назад 0
3
Mikhail Kupchik

inotify (2) в Linux не сможет наблюдать большое дерево, но файловая система fuse (смонтированная в отдельном месте), вероятно, могла бы справиться с этим, переводя запросы файловой системы в вызовы svn или git или напрямую изменяя метаданные svn / git.

Это очень интересная идея, но я не слышал ни о каких существующих реализациях.

Допустим, у меня есть только несколько файлов. Michael Pankov 11 лет назад 0
0
bdecaf

Такой сценарий не сложно написать.

Мой любимый контроль версий - это git.

следующий скрипт должен это сделать:

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

либо периодически проверяйте вашу директорию, либо, если ваш редактор вызывает сценарий после сохранения.

Но если вы делаете это таким образом, возможно, имеет смысл исключить большие файлы и, возможно, некоторые «бесполезные», такие как автосохранения.

Да, я знаю, что решение на основе cron легко реализовать. Тем не менее, я ищу что-то, что сохранит версию независимо от механизма сохранения. Именно поэтому я упомянул autoversionninf на svn, а также inotify в моем вопросе. WoJ 12 лет назад 0
0
FSMaxB

SparkleShare ( http://sparkleshare.org ) основан на git и реализует функциональность Dropbox-Like с контролем версий, но вы должны настроить ssh-сервер (может быть localhost).

Эта вещь неуклюжа и требует много настроек. Кроме того, функциональность Dropbox не нужна. Michael Pankov 11 лет назад 0
0
Nehal Dattani

I'd recommend you to try NILFS. Refer the about page and you will be quicky able to decide whther is this the one what you are looking for or not.

HTH

0
Florin COJOCARU

Существует также способ «бедняков» сделать это, используя только rsync и работу cron. Вы в основном полагаетесь на средство резервного копирования rsync и используете два отдельных пути плюс префикс / суффикс для отслеживания ваших файлов.

Более менее это выглядит так: / usr / bin / rsync -a -A -X --backup --suffix = date +".%Y-%m-%d_%H-%M-%S"$ source_path $ backup_path

Конечный результат: изменение файла с именем test_rsync в исходном пути после первоначального выполнения приведет к созданию файла с именем test_rsync.2017-02-09_11-00-01 в пути резервного копирования.

С этим связано множество проблем (это работает, если у вас только приличное количество файлов, и сбой при изменениях, которые происходят между двумя последовательными запусками rsync (1 минута в моем случае)), но этого может быть достаточно для ваших нужд.

Если мы говорим здесь об общих ресурсах samba, то список исключений мог бы быть в порядке, я не боюсь этого, я боюсь.

Дайте мне знать, если вы улучшите это.

0
michael

Вот скрипт Python3, который делает VMS как автоматическое управление версиями файлов, используя отметку времени, добавленную к исходному имени файла при сохранении.

Я добавил в сценарий кучу комментариев и запустил полдюжины таких сценариев на своем компьютере с Ubuntu, причем в каждой версии скрипта различались только каталоги, так что я одновременно управлял версиями нескольких каталогов. Нет реального штрафа в производительности машины.

! / usr / bin / env python3

print ("НАЧАТЬ ВЕРСИИ ФАЙЛОВ ПРОЕКТА") print ("version_creation.py") # поместить весь этот код в скрипт с таким именем print ("запустить как .. 'python3 version_creation.py' из командной строки") print ("ctrl ') c 'to stop ") print (" ") print (" Чтобы запустить программу в фоновом режиме ниже для командной строки, а затем закрыть окно. ") print (" nohup python3 version_creation.py ") print (" .... to остановить процесс перейти в меню / администрирование / системный монитор ... и уничтожить python3 ") print (" ") print (" Всегда сохранять файлы в каталог 'ProjectFiles' и файлы версий ") print (" также будет создан в этом каталоге . ") print (" ") print (" ") print (" ") print (" ")

импорт shutil импорт os время импорта

--- установите временной интервал для проверки новых файлов (в секундах) ниже

- этот интервал должен быть меньше интервала появления новых файлов!

т = 10

--- установить исходный каталог (dr1) и целевой каталог (dr2)

dr1 = "/ path / to / source_directory"

dr2 = "/ path / to / target_directory"

импорт глобус импорт ос

dr1 = "/ home / michael / ProjectFiles" # оба оригинала и версии будут сохранены в этом каталоге

dr2 = "/ home / michael / ProjectFileVersions"

пока верно:

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)

 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) 

доля

ниже был введен ранее и работает, но мне нравится вышеупомянутый скрипт на python намного лучше ...... (использую python около 3 часов)

#!/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 

Похожие вопросы