Fazendo auto-commit do git

155

Eu gostaria de usar o git para registrar todas as alterações em um arquivo.

Existe uma maneira de ativar o 'commit' do git para que ocorra automaticamente toda vez que um arquivo é atualizado - para que haja um novo commit para cada alteração em um arquivo?

Idealmente, eu gostaria que meus usuários nem soubessem que o git está sendo executado nos bastidores. Um usuário pode então potencialmente "desfazer" as alterações em um arquivo - e isso pode ser conseguido retirando uma versão anterior do git.

git-noob
fonte
9
Seria mais fácil de usar um sistema de arquivos de versões: en.wikipedia.org/wiki/Versioning_file_system
William Pursell
1
O SparkleShare foi bastante impressionante nisso.
theode 23/03
O SparkleShare parece uma ótima opção, mas destrói qualquer pasta .git dentro do git principal
insira 28/08
Você pode usar o github.com/jw0k/gwatch . Funciona no Windows e Linux.
rubix_addict
@rubix_addict Por que você não postou isso como resposta?
Tobias Kienzler

Respostas:

127

No Linux, você pode usar o inotifywait para executar automaticamente um comando toda vez que o conteúdo de um arquivo for alterado.

Editar: o seguinte comando confirma o arquivo.txt assim que é salvo:

inotifywait -q -m -e CLOSE_WRITE --format="git commit -m 'autocommit on change' %w" file.txt | sh
JesperE
fonte
2
Como você pode torná-lo fazer isso para uma pasta inteira (e não apenas um único arquivo?)
Anderson Verde
2
Use o -rsinalizador para inotifywait, mas observe que o kernel tem um limite no número de relógios inotifywait que ele pode configurar. man inotifywaitvou lhe contar mais.
JesperE
14
existe alguma opção no windows ..?
Chandan Pasunoori
50

A resposta inotifywait anterior é ótima, mas não é uma solução completa. Como está escrito, é um commit único para uma alteração única em um arquivo. Não funciona no caso comum em que a edição de um arquivo cria um novo inode com o nome original. inotifywait -m aparentemente segue arquivos por inode, não por nome. Além disso, após a alteração do arquivo, ele não é preparado para o git commit sem o git add ou o git commit -a . Fazendo alguns ajustes, eis o que estou usando no Debian para rastrear todas as alterações no meu arquivo de calendário:

/etc/rc.local:


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

/ home / <nome do usuário> / 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

Isso pode ser generalizado para aguardar uma lista de arquivos e / ou diretórios e os processos inotifywait correspondentes e reiniciar cada inotifywait à medida que um arquivo é alterado.

Lester Buck
fonte
8
Lester, você poderia expandir como generalizar isso para um diretório?
Diego
29

As respostas anteriores, recomendando inotifywait para este trabalho, levaram- me na direção certa quando eu tive esse problema, então escrevi um pequeno script. Primeiro, isso só podia assistir pastas inteiras recursivamente (o oposto do exemplo de Lester Buck), mas depois eu também queria assistir um arquivo em outro lugar, então o expandi.

O resultado é um script atualmente chamado gitwatch, como é o que faz: ele observa um arquivo ou pasta em busca de alterações (usando inotifywait) e os confirma em um repositório git.

Você pode encontrar o script, mais informações e instruções no github: https://github.com/nevik/gitwatch

Nevik Rehnel
fonte
4
pequeno script útil lá. Eu vou tomar nota disso.
Iwein
interessante pode ser útil para sites magento. Estou testando-lo, mas parece que não consegue obtê-lo para empurrar automaticamente assim
NoSixties
16

O git-wip é uma ótima solução que funciona bem para mim. "WIP" significa "trabalho em andamento". Toda vez que você executa o 'git wip', as alterações são confirmadas em um ramo separado. Pode ser executado na linha de comando, mas existem extensões para o vim e o emacs executarem automaticamente o git-wip toda vez que um arquivo é gravado.

rafak
fonte
12

Eu queria fazer isso no Windows, e achei a melhor maneira de usar o Directory Monitor para verificar se havia alterações e, quando detectou uma alteração, execute:

Programa: cmd.exe

Parâmetros: /CC:\pathToBatchFile.bat

Esse arquivo em lotes continha:

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"
))

Também tentei ter outro comando lá para adicionar arquivos ( "%PROGRAMFILES(X86)%\git\bin\sh.exe" --login -i -c "git add *.*"), mas acho que não funcionou corretamente.

Também criei um gancho pós-confirmação contendo:

#!/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 houvesse algum conflito, isso abortaria o impulso e o empurrão, mas não havia uma maneira clara de saber o que havia acontecido - no final, abandonamos toda a ideia por causa dessa falha.)

Esse comando curl disse ao meu servidor que ele precisava fazer um puxão no código. Tudo o que era necessário para lidar com isso no 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";
}
?>

O único problema com isso era que ele precisava ser executado pelo usuário raiz em vez do usuário apache, então eu também tive que criar um arquivo /etc/sudoers.d/contendo:

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

Para mim, acho que funcionou muito bem. O Directory Monitor pode ser configurado para executar na inicialização e iniciar minimizado, além de assistir a várias pastas diferentes

Redzarf
fonte
Também no Windows, não consigo executar o git no LocalSystem; portanto, se você criar seu próprio serviço de monitoramento, precisará executá-lo em um usuário que possa executar o Git. Possível estou faltando apenas alguns ajustes / config, mas é provavelmente mais agradável para configurar um novo git commit conta de qualquer maneira
Whelkaholism
8
#!/bin/bash
git commit -a -m "autoupdate `date +%F-%T`"
git push

autopushing com data e hora atuais.

web-rider
fonte
8

Inotify realmente soa como a ferramenta certa para o trabalho.

Existe uma ferramenta chamada incron que pode ser exatamente o que você está procurando. Você pode especificar arquivos ou pastas (e tipos de eventos, como "alterar", "criar", "desvincular") em algo como um crontab e um comando para executar quando esse evento ocorrer.

Em contraste com inotifywait (que seria o análogo do cron do pobre homem) sleep 10;do stuff ), isso captura todos os eventos, não apenas o primeiro.

Eu não o usei, mas a partir da documentação não parece muito complexo de configurar.

pixelbrei
fonte
7

Eu escrevi um programa, GitPrime , para fornecer salvamento automático para seus repositórios Git locais. Agora é fácil reverter antes de ser eliminado! Repositório Bitbucket .

Isso deve funcionar em qualquer plataforma que suporte um shell bash, incluindo Windows + Cygwin.

Brendan
fonte
+1 Eu estou usando isso no Windows (Cygwin) para autosave alterações que fizer a um repositório git-tf cada 10 minutos usando uma tarefa agendada
Darbio
6

Caso alguém tente fazer isso no Powershell, obtive sucesso usando o seguinte:

& "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"
mekuls
fonte
5
E como isso é acionado automaticamente?
jerik
2
tarefa agendada?
ozzy432836
2

Se você conhece o nome do arquivo e deseja monitorar apenas um (ou alguns arquivos), basta chamar "git commit" a cada poucos minutos para conseguir isso. Se o arquivo não foi alterado, o git apenas reclamará e você terá que ignorar esse erro, mas, além disso, não haverá corrupção.

Além disso, você desejará marcar esses arquivos como "confirmação automática" para poder confirmar manualmente também. Dessa forma, o usuário pode ver as alterações automáticas e também as alterações "lógicas" maiores, que são acompanhadas de comentários de confirmação para explicar que isso mudou desde a última confirmação manual.

Por exemplo, use "AUTOCOMMIT" como a mensagem de confirmação. Posteriormente, você pode escrever uma ferramenta para eliminar essas confirmações usando o git log (para descobrir as revisões a serem eliminadas) ou pode tentar criar um ramo AUTOCOMMIT usando uma estratégia de resolução de colisão de força bruta para martelar nas "confirmações manuais".

Outra opção é usar os comandos de baixo nível git para criar seu próprio repositório especializado.

Por fim, você pode copiar o arquivo para um novo nome ("$ filename.ac") enquanto realiza as confirmações automáticas para distinguir entre as versões manual e automática.

Aaron Digulla
fonte
1

Tenho certeza de que você precisaria conectar isso a qualquer editor que seus usuários estejam usando. Você pode escrever algo para pesquisar mudanças, mas, dependendo dos padrões de uso, a frequência da pesquisa talvez precise ser incrivelmente alta para garantir que ela esteja captando alterações individuais em vez de várias alterações.

Hank Gay
fonte
Além disso, a pesquisa de mudanças criará condições de corrida.
7609 Bombe
1
Não com editores como o emacs e o yi, que gravam arquivos "de maneira transacional" para tentar garantir que os dados não sejam perdidos após uma falha.
Robin Green
1

Parece que você está procurando algo semelhante ao etckeeper , que é projetado para verificar automaticamente todas as suas alterações em / etc / * no git (ou em qualquer VCS que você quiser), mas não vejo razão para que ele não possa ser usado com arquivos diferente daqueles em / etc.

Se você deseja apenas lidar com um único arquivo, talvez isso não seja perfeito, mas se você deseja acompanhar tudo em um determinado diretório, acho que vale a pena conferir.

iconoclasta
fonte
1

Este script não é executado quando um usuário altera o arquivo, mas pode ser executado como um trabalho cron (colocando-o em um diretório /etc/cron.*), o que também é uma solução razoável.

Esse script irá percorrer seu diretório / srv / www (altere-o para onde todos os seus sites estiverem armazenados), adicione, confirme e envie todos os arquivos, e registre tudo em /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
runningonplants
fonte
0

Eu tive o mesmo problema e no mac launchd fornece uma ótima solução. ele assistirá a um arquivo ou diretório e, se houver alterações, você poderá executar um aplicativo ou qualquer outra coisa ...


fonte
Consulte "Monitorando um diretório" aqui: developer.apple.com/library/mac/#documentation/MacOSX/…
Kris
0

Isso não satisfaz a parte "Idealmente" da pergunta, mas essa foi a pergunta mais próxima que eu vi da resposta que queria, então imaginei que poderia ir aqui. Minha primeira postagem no stackoverflow, desculpe-me se eu estiver enganado.

O script a seguir garante submissões automáticas sobre alterações salvas, mas faz alerta o usuário para comprometer entrada. (Eu percebo que meu cenário é um pouco diferente do do 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
Fintan
fonte
0

Para Windows

De acordo com este artigo sobre confirmação automática , você deve criar um .batarquivo com o conteúdo:

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

e execute com Task Scheduler. Se você não sabe fazer passo a passo, consulte esse artigo.

T.Todua
fonte