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


16

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

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

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

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

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


связанные: flashbake
Дэн Д.


Есть ли особые требования относительно того, какое программное обеспечение вы используете? Потому что, если вы хотите отслеживать изменения, которые вы делаете вручную (путем редактирования файлов), Eclipse имеет эту встроенную функцию, которая называется «локальная история».
Стефан Зайдель

@StefanSeidel Я не начинающий, но я бы предпочел решение без IDE.
Михаил Панков

Ответы:


6

1. Метод общего назначения с использованием базара и inotify

Это не проверено мной, но я нашел эту запись, которая использует bzr(базар) & inotifywaitдля мониторинга каталога и контроля версий файлов в нем, используя базар.

Этот скрипт выполняет всю работу по просмотру каталога на предмет изменений:

#!/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. Управление / и т. Д.

Для особого случая управления системным /etcкаталогом вы можете использовать приложение etckeeper .

etckeeper - это набор инструментов, позволяющих хранить / etc в репозитории git, mercurial, darcs или bzr. Он подключается к apt (и другим менеджерам пакетов, включая yum и pacman-g2) для автоматической фиксации изменений, внесенных в / etc во время обновления пакетов. Он отслеживает метаданные файла, которые обычно не поддерживаются системами контроля версий, но это важно для / etc, например, разрешения для / etc / shadow. Он достаточно модульный и настраиваемый, а также простой в использовании, если вы понимаете основы работы с контролем версий.

Вот хороший учебник, с которого можно начать.

3. Использование git и incron

Эта техника использует gitи incron. Для этого метода вам нужно сделать следующее:

А. Сделайте репо

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

Б. Создать $HOME/bin/git-autocommitскрипт

#!/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. Добавить запись в incrontab

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

4. Использование Flashbake

Другой вариант - использовать такой инструмент, как Flashbake . Flashbake - это система контроля версий, которую Кори Доктороу (из знаменитости BoingBoing) использует для написания своих книг.

Flashbake использует git для отслеживания изменений, но находится где-то между автоматическим резервным копированием и использованием простой системы контроля версий.

Кори хотел, чтобы версия содержала подсказки, снимки того, где он был в то время, когда происходил автоматический коммит, и что он думал. Я быстро набросал сценарий Python для извлечения нужной ему контекстной информации и начал собирать сценарий оболочки для управления git, используя вывод сценария Python для комментария коммита, когда задание cron вызывало оболочку оболочки.

Ресурсы


3
inotifywait + "git local" = gitwatch.sh, посмотрите здесь: github.com/nevik/gitwatch/blob/master/gitwatch.sh
diyism

4

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


Я читал о ZFS, но похоже, что это нестабильное решение для базовых файловых систем (по крайней мере, в Linux)
WoJ

Мне бы очень хотелось, чтобы решение было привязано к существующему FS.
Михаил Панков

Возможно это? ext3cow.com
Зак Б

3

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

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

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


Все еще не готовое решение, и, ну, я бы, наверное, выбрал Python inotify. Но спасибо.
Михаил Панков

3

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

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


Допустим, у меня есть только несколько файлов.
Михаил Панков

0

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

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

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

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

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

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


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

0

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


Эта вещь неуклюжа и требует много настроек. Кроме того, функциональность Dropbox не нужна.
Михаил Панков


0

Существует также способ «бедняков» сделать это, используя только 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

Вот скрипт 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.