Fare git auto-commit


155

Vorrei usare git per registrare tutte le modifiche a un file.

C'è un modo in cui posso attivare git 'commit' in modo che avvenga automaticamente ogni volta che un file viene aggiornato - quindi c'è un nuovo commit per ogni modifica a un file?

Idealmente, vorrei che i miei utenti non sapessero nemmeno che git è in esecuzione dietro le quinte. Un utente potrebbe quindi potenzialmente "annullare" le modifiche a un file e ciò potrebbe essere ottenuto estraendo una versione precedente da git.


9
Sarebbe più facile usare un filesystem con versioning: en.wikipedia.org/wiki/Versioning_file_system
William Pursell

1
SparkleShare è stato abbastanza impressionante.
teodo

SparkleShare sembra un'ottima opzione ma distrugge qualsiasi cartella .git all'interno del git principale
firma il

Puoi usare github.com/jw0k/gwatch . Funziona su Windows e Linux.
rubix_addict

@rubix_addict Perché non l'hai pubblicato come risposta?
Tobias Kienzler,

Risposte:


127

Su Linux puoi usare inotifywait per eseguire automaticamente un comando ogni volta che il contenuto di un file viene modificato.

Modifica: il seguente comando commette file.txt non appena viene salvato:

inotifywait -q -m -e CLOSE_WRITE --format="git commit -m 'autocommit on change' %w" file.txt | sh

2
Come puoi farlo per un'intera cartella (non solo un singolo file?)
Anderson Green,

2
Usa il -rflag per inotifywait, ma nota che il kernel ha un limite al numero di orologi inotifywait che può impostare. man inotifywaitti dirò di più.
JesperE,

14
c'è qualche opzione in Windows ..?
Chandan Pasunoori,

50

La prima risposta inotifywait è ottima, ma non è una soluzione abbastanza completa. Come scritto, si tratta di un commit one-shot per una modifica di una volta in un file. Non funziona nel caso comune in cui la modifica di un file crea un nuovo inode con il nome originale. inotifywait -m apparentemente segue i file per inode, non per nome. Inoltre, dopo che il file è stato modificato, non viene messo in scena per git commit senza git add o git commit -a . Apportando alcune modifiche, ecco cosa sto usando su Debian per tenere traccia di tutte le modifiche al mio file di calendario:

/etc/rc.local:


su -c /home/<username>/bin/gitwait -l <username>

/ Home / <nomeutente> / bin / gitwait:


#!/bin/bash
#
# gitwait - watch file and git commit all changes as they happen
#

while true; do

  inotifywait -qq -e CLOSE_WRITE ~/.calendar/calendar

  cd ~/.calendar; git commit -a -m 'autocommit on change'

done

Questo può essere generalizzato per attendere su un elenco di file e / o directory e sui processi inotifywait corrispondenti e riavviare ogni inotifywait quando un file viene modificato.


8
Lester, per favore, potresti espandere come generalizzare questo in una directory?
Diego,

29

Le risposte precedenti che raccomandavano inotifywait per questo lavoro mi hanno lasciato nella giusta direzione quando ho avuto questo problema da solo, quindi ho scritto una piccola sceneggiatura. All'inizio questo poteva solo guardare ricorsivamente intere cartelle (l'opposto dell'esempio di Lester Buck), ma poi volevo anche guardare un file da qualche altra parte, quindi l'ho espanso.

Il risultato è uno script attualmente chiamato gitwatch, in quanto è quello che fa: controlla un file o una cartella per le modifiche (usando inotifywait) e le trasferisce in un repository git.

Puoi trovare lo script, maggiori informazioni e istruzioni su github: https://github.com/nevik/gitwatch


4
utile piccola sceneggiatura lì. Ne prenderò nota.
iwein,

interessante potrebbe essere utile per i siti magento. Lo sto testando, ma non riesco a farlo spingere anche automaticamente
NoSixties,

16

git-wip è un'ottima soluzione che funziona bene per me. "WIP" sta per "lavori in corso". Ogni volta che esegui 'git wip', le modifiche vengono memorizzate in un ramo separato. Può essere eseguito dalla riga di comando, ma ci sono estensioni per vim ed emacs per eseguire automaticamente git-wip ogni volta che viene scritto un file.


12

Volevo farlo in Windows e ho scoperto che il modo migliore era usare Directory Monitor per verificare la presenza di modifiche, quindi quando ha rilevato una modifica è stato eseguito:

Programma: cmd.exe

Params: /CC:\pathToBatchFile.bat

Quel file batch conteneva:

c:
cd c:\gitRepoDirectory\
(if exist "%PROGRAMFILES(X86)%" (
"%PROGRAMFILES(X86)%\git\bin\sh.exe" --login -i -c "git commit -am AutoCommitMessage"
) else (
"%PROGRAMFILES%\git\bin\sh.exe" --login -i -c "git commit -am AutoCommitMessage"
))

Ho anche provato ad avere un altro comando lì per aggiungere file ( "%PROGRAMFILES(X86)%\git\bin\sh.exe" --login -i -c "git add *.*"), ma non credo di averlo fatto funzionare correttamente.

Ho anche creato un hook post-commit contenente:

#!/bin/sh
git.exe pull -v --progress  "origin"
git.exe push    --progress  "origin" master:master
curl.exe -s https://webserverdomain.com/updateFromGitHook.x?r=repoName

(Se ci fossero stati dei conflitti, questo avrebbe interrotto la spinta e interrotto la spinta, ma non c'era alcun modo chiaro per dire che era successo - alla fine abbiamo abbandonato l'intera idea a causa di questo difetto.)

Quel comando curl disse al mio server che doveva fare un pull sul codice. Tutto ciò che era necessario per gestirlo in php era:

<?
$r = $_GET['r'];
if (!empty($c)) {
    //use system instead of exec if you want the output to go back to the git client
    exec("cd /path/to/repo/parent/$r; sudo git reset --hard HEAD; sudo git pull;");
    echo "\n\nServer: Updated\n\n";
} else {
    echo "\n\nServer: UPDATE FAILED\n\n";
}
?>

L'unico problema era che doveva essere eseguito dall'utente root anziché dall'utente apache, quindi dovevo anche creare un file /etc/sudoers.d/contenente:

www-data ALL = NOPASSWD: /usr/bin/git

Per me, penso che abbia funzionato abbastanza bene. Directory Monitor può essere configurato per essere eseguito all'avvio e iniziare a essere ridotto a icona e può guardare diverse cartelle


Anche su Windows, non riesco a far funzionare git in LocalSystem, quindi se crei il tuo servizio di monitoraggio dovrai eseguirlo con un utente che può effettivamente eseguire Git. Forse mi mancano solo alcune impostazioni / config, ma probabilmente è meglio creare un nuovo account git commit comunque
Whelkaholism

8
#!/bin/bash
git commit -a -m "autoupdate `date +%F-%T`"
git push

autopushing con data e ora correnti.


8

Inotify suona davvero come lo strumento giusto per il lavoro.

C'è uno strumento chiamato incron che potrebbe essere esattamente quello che stai cercando. Puoi specificare file o cartelle (e tipi di eventi, come "cambia", "crea", "scollega") in qualcosa come un crontab e un comando da eseguire quando si verifica un evento del genere.

Contrariamente a inotifywait (che sarebbe l'analogo del cron del povero sleep 10;do stuff), questo catturerà ogni evento, non solo il primo.

Non l'ho usato da solo, ma dalla documentazione non sembra troppo complicato da configurare.


7

Ho scritto un programma, GitPrime , per fornire il salvataggio automatico per i tuoi repository Git locali. Ora è facile tornare indietro prima di averlo eliminato! Repository Bitbucket .

Questo dovrebbe funzionare su qualsiasi piattaforma che supporti una shell bash tra cui Windows + Cygwin.


+1 Sto usando questo su Windows (CygWin) per salvare automaticamente le modifiche che apporto a un repository git-tf ogni 10 minuti usando un'attività pianificata
Darbio,

6

Nel caso in cui qualcuno provi a farlo da Powershell ho avuto successo usando il seguente:

& "C:\Program Files (x86)\Git\bin\sh.exe" -c "cd D:\PATH\TO\REPO && git add --all  &&  git commit -m 'Automatic Commit Message Goes Here' && git push origin master"

5
E come viene attivato automaticamente?
Jerik,

2
operazione pianificata?
ozzy432836,


2

Se conosci il nome del file e vuoi monitorare solo uno (o pochi file), puoi semplicemente chiamare "git commit" ogni pochi minuti per raggiungere questo obiettivo. Se il file non è cambiato, git si lamenterà e dovrai ignorare questo errore, ma a parte questo, non ci sarà corruzione.

Inoltre, ti consigliamo di contrassegnare questi file come "commit automatico" per poter eseguire il commit anche manualmente. In questo modo, l'utente può vedere le modifiche automatiche e anche le modifiche "logiche" più grandi che sono accompagnate da commenti di commit per spiegare che è cambiato dall'ultimo commit manuale.

Ad esempio, utilizzare "AUTOCOMMIT" come messaggio di commit. Successivamente, puoi scrivere uno strumento per eliminare questi commit usando git log (per scoprire le revisioni da uccidere) oppure puoi provare a creare un ramo AUTOCOMMIT usando una strategia di risoluzione delle collisioni della forza bruta da martellare nei "commit manuali".

Un'altra opzione è quella di utilizzare i comandi di basso livello git per creare il proprio repository specializzato.

Infine, è possibile copiare il file con un nuovo nome ("$ nomefile.ac") mentre si eseguono commit automatici per distinguere tra la versione manuale e quella automatica.


1

Sono abbastanza sicuro che avresti bisogno di collegarlo a qualunque editor i tuoi utenti stiano usando. È possibile scrivere qualcosa nel polling per le modifiche, ma a seconda dei modelli di utilizzo, la frequenza di polling potrebbe dover essere incredibilmente alta per assicurarsi che stesse rilevando singole modifiche anziché più modifiche.


Inoltre, il sondaggio per le modifiche creerà condizioni di gara.
Bombe

1
Non con editor come emacs e yi, che scrivono file "in modo transazionale" per cercare di garantire che i dati non vadano persi dopo un arresto anomalo.
Robin Green,

1

Sembra che tu stia cercando qualcosa di simile a etckeeper , che è progettato per controllare automaticamente tutti i tuoi chances su / etc / * in git (o qualunque VCS tu voglia), ma non vedo alcun motivo per cui non possa essere usato con i file diversi da quelli in / etc.

Se vuoi gestire solo un singolo file, forse non sarebbe perfetto, ma se vuoi tenere traccia di tutto in una determinata directory, penso che valga la pena di controllarlo.


1

Questo script non viene eseguito quando un utente modifica il file, ma potrebbe essere eseguito come cron job (rilasciandolo in una directory /etc/cron.*), che è anche una soluzione ragionevole.

Questo script eseguirà l'iterazione nella directory / srv / www (modificandola in tutti i siti memorizzati), aggiungerà, eseguirà il commit e invierà tutti i file e registrerà tutto su /var/log/gitlog.txt

now=$(date +"%m.%d.%Y_%T")
logfile='/var/log/gitlog.txt'

for dir in /srv/www/*/
do
echo -e '\n' >> $logfile
echo "autocommit $dir $now" >> $logfile
echo "--------------------------" >> $logfile

cd $dir
git add . >> $logfile
git commit -am "autocommit $now" >> $logfile
git push origin master >> $logfile
done



0

Questo non soddisfa la parte "Idealmente" della domanda, ma questa è stata la domanda più vicina che ho visto alla risposta che volevo, quindi ho pensato che potesse andare qui. Il mio primo post su StackOverflow però, quindi mi scuso se mi sbaglio.

Lo script seguente assicura commit automatici modifiche salvate, ma non richiedono all'utente di commit ingresso. (Mi rendo conto che il mio scenario è un po 'diverso da quello di Git-Noob).


# While running, monitors the specified directory, and when a file therein 
# is created or edited and saved, this prompts the user for a commit message.
# The --exclude is to avoid extra prompts for the changes made to 
# version control directories.

# requires inotify-tools

inotifywait --exclude '/\..+' -m  path/to/directory -e modify -e create |
        while read path action file; do
                gnome-terminal -e 'bash -c "cd path/to/directory; 
                                            git add *; 
                                            echo What did you just do??; 
                                            read varname; 
                                            git commit -m \"$varname\""'
        done

0

Per Windows

Secondo questo articolo su autocommit , devi creare un .batfile con contenuto:

git add -u
git commit -m "your commit message"
git push origin master 

ed eseguire con Task Scheduler. Se non sai come fare passo per passo, consulta l'articolo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.