Powershell 自动提交代码到 Github
Powershell 自动提交代码到 Github
前提
-
本地已安装 powershell,且配置 ps1 文件可执行
-
本地已安装 git,且你监控的文件夹已经跟远程 Github 仓库建立联系,在次目录下执行
git remote -v
结果不为空
当前 Powershell 版本:

当前 Git 版本:
远程仓库:

监听特定的文件夹下的文件修改,并写入日志
参考博客:Monitoring Folders for File Changes - powershell.one
以下为我的脚本,替换 >>>
开头的注释所在的变量,然后保存为 .ps1
文件即可使用
# >>> 指定监控路径
$BlogRepoPath = 'path2monitoredFolder'
# >>> 指定日志文件夹
$basicLogPath = 'path2logFolder'
# >>> 指定监控路径对应的远程仓库名
$remoteReposity = 'remoteRepositoryName'
# specify which files you want to monitor
$FileFilter = '*'
# specify whether you want to monitor subfolders as well:
$IncludeSubfolders = $true
# specify the file or folder properties you want to monitor:
$AttributeFilter = [IO.NotifyFilters]::FileName, [IO.NotifyFilters]::LastWrite
try {
$watcher = New-Object -TypeName System.IO.FileSystemWatcher -Property @{
Path = $BlogRepoPath
Filter = $FileFilter
IncludeSubdirectories = $IncludeSubfolders
NotifyFilter = $AttributeFilter
}
# define the code that should execute when a change occurs:
$action = {
# the code is receiving this to work with:
# change type information:
$details = $event.SourceEventArgs
$Name = $details.Name
$OldName = $details.OldName
$FullPath = $details.FullPath
$OldFullPath = $details.OldFullPath
if ($FullPath.StartsWith("$BlogRepoPath\.git") -and -not($FullPath.Contains(".github")) ){
<# Action to perform if the condition is true #>
return
}
# node_modules/
# if ($FullPath.StartsWith("$BlogRepoPath\node_modules")){
# <# Action to perform if the condition is true #>
# return
# }
# public/
if ($FullPath.StartsWith("$BlogRepoPath\public")){
<# Action to perform if the condition is true #>
return
}
# db.json
if ($FullPath.StartsWith("$BlogRepoPath\db.json")){
<# Action to perform if the condition is true #>
return
}
# 准备日志
if (-not (Get-Item -Path $basicLogPath)) {
return
}
$year = (get-date).Year
$mouth = (get-date).Month
$day = (get-date).Day
$filePath = "$basicLogPath\$year-$mouth"
if (-not (Get-Item -Path $filePath)) {
New-Item -ItemType Directory -Path $filePath
}
$logFile = "$filePath\$year-$mouth-$day.log"
if (-not (Get-Item -Path $logFile)) {
New-Item -ItemType File -Path $logFile
}
# type of change:
$ChangeType = $details.ChangeType
# when the change occured:
$Timestamp = $event.TimeGenerated
# save information to a global variable for testing purposes
# so you can examine it later
# MAKE SURE YOU REMOVE THIS IN PRODUCTION!
$global:all = $details
# now you can define some action to take based on the
# details about the change event:
# let's compose a message:
$text = "{0} was {1} at {2}" -f $FullPath, $ChangeType, $Timestamp
# Write-Host ""
# Write-Host $text -ForegroundColor DarkYellow
# Out-File -Append -FilePath $logFile -InputObject ""
Out-File -Append -FilePath $logFile -InputObject $text
# you can also execute code based on change type here:
switch ($ChangeType) {
'Changed' {
"CHANGE"
# 修改的时候提交也要等 5 秒
Start-Sleep -Seconds 1
}
'Created' { "CREATED" }
'Deleted' {
"DELETED"
# to illustrate that ALL changes are picked up even if
# handling an event takes a lot of time, we artifically
# extend the time the handler needs whenever a file is deleted
# Write-Host "Deletion Handler Start" -ForegroundColor Gray
Out-File -Append -FilePath $logFile -InputObject "Deletion Handler Start"
Start-Sleep -Seconds 1
# Write-Host "Deletion Handler End" -ForegroundColor Gray
Out-File -Append -FilePath $logFile -InputObject "Deletion Handler End"
}
'Renamed' {
# this executes only when a file was renamed
$text = "File {0} was renamed to {1}" -f $OldName, $Name
# Write-Host $text -ForegroundColor Yellow
Out-File -Append -FilePath $logFile -InputObject $text
}
# any unhandled change types surface here:
default {
# Write-Host $_ -ForegroundColor Red -BackgroundColor White
Out-File -Append -FilePath $logFile -InputObject $_
}
}
# git 先更新 再提交
# 日志添加时间,
# 目录添加忽略条件。不监听 .git目录下的文件
# 添加一个延时,不要提交太频繁
git -C $BlogRepoPath pull $remoteReposity master
git -C $BlogRepoPath add -A
git -C $BlogRepoPath commit -m 'auto commit'
git -C $BlogRepoPath push $remoteReposity
Out-File -Append -FilePath $logFile -InputObject "push to github $remoteReposity"
}
# subscribe your event handler to all event types that are
# important to you. Do this as a scriptblock so all returned
# event handlers can be easily stored in $handlers:
$handlers = . {
Register-ObjectEvent -InputObject $watcher -EventName Changed -Action $action
Register-ObjectEvent -InputObject $watcher -EventName Created -Action $action
Register-ObjectEvent -InputObject $watcher -EventName Deleted -Action $action
Register-ObjectEvent -InputObject $watcher -EventName Renamed -Action $action
}
# monitoring starts now:
$watcher.EnableRaisingEvents = $true
# Write-Host "Watching for changes to $BlogRepoPath"
# Out-File -Append -FilePath $logFile -InputObject '------------------------------------------------------------------------------------------------------------------------'
# Out-File -Append -FilePath $logFile -InputObject "Watching for changes to $BlogRepoPath"
# since the FileSystemWatcher is no longer blocking PowerShell
# we need a way to pause PowerShell while being responsive to
# incoming events. Use an endless loop to keep PowerShell busy:
do {
# Wait-Event waits for a second and stays responsive to events
# Start-Sleep in contrast would NOT work and ignore incoming events
Wait-Event -Timeout 60
# write a dot to indicate we are still monitoring:
# Write-Host "." -NoNewline
# Out-File -Append -FilePath $logFile -InputObject "."
} while ($true)
}
finally {
# this gets executed when user presses CTRL+C:
# stop monitoring
$watcher.EnableRaisingEvents = $false
# remove the event handlers
$handlers | ForEach-Object {
Unregister-Event -SourceIdentifier $_.Name
}
# event handlers are technically implemented as a special kind
# of background job, so remove the jobs now:
$handlers | Remove-Job
# properly dispose the FileSystemWatcher:
$watcher.Dispose()
# Write-Warning "Event Handler disabled, monitoring ends."
Out-File -Append -FilePath $logFile -InputObject "Event Handler disabled, monitoring ends."
}
对此,相比于参考博客中的源码,这里做出了几点改进:
-
将 Write-Host 打印日志改为通过 Out-File 将日志写入文件,且日志文件按天区分,自动创建。
-
在.git 文件夹、public 文件夹和 db.json 文件出现修改的时候不提交到 GitHub,避免出现提交循环,同时节约内存。
将此 ps1 脚本设置为开机自启
设置 powershell 脚本开机启动有点麻烦,需要在外面套一层 .bat
文件,同时还会有闪屏的问题,即打开一个 cmd 窗口执行完语句之后又快速关闭。为了解决这个问题,在 .bat
文件的外面再套一层 .vbs
即可解决,最终文件如下:
-
创建
script.vbs
Dim WinScriptHost Set WinScriptHost = CreateObject("WScript.Shell") WinScriptHost.Run Chr(34) & "path2batfile\script.bat" & Chr(34), 0 Set WinScriptHost = Nothing
-
创建
script.bat
pwsh.exe -file path2powershellScript\script.ps1
-
将上一小节的脚本保存为
script.ps1
,放到 path2powershellScript 指定的位置即可。 -
将
script.vbs
创建快捷方式,然后放到C:\Users\<user_name>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
文件夹,系统开机的时候,会自动执行此文件夹下的脚本或者软件。