-
-
Notifications
You must be signed in to change notification settings - Fork 19
/
Update-Gits.ps1
177 lines (151 loc) · 4.51 KB
/
Update-Gits.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
<#
.SYNOPSIS
Scan all sub-folders looking for Git repos and fetch/pull each of them to
get latest code.
.PARAMETER Branch
Speciies the branch name, default is read from the .git\config file
.PARAMETER Merge
Merges main into the feature branch if the current branch is not main
.PARAMETER Project
Specifies the project (subfolder) to update. If not specified then it will
scan all subfolders and update every one that contains a .git folder.
.PARAMETER Reset
Perform a hard reset to the tip of the specified Branch
for each repo before fetch and pull. This is to discard all local changes.
#>
# CmdletBinding adds -Verbose functionality, SupportsShouldProcess adds -WhatIf
[CmdletBinding(SupportsShouldProcess = $true)]
param (
[Parameter(Position = 0)] [string] $Project,
[Parameter(Position = 1)] [string] $Branch,
[switch] $Merge,
[switch] $Reset
)
Begin
{
$script:divider = New-Object String('-', 80)
function Update
{
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[string] $Project
)
if ($Project -match '-skip')
{
Write-Host $divider
Write-Host "... skipping $Project" -ForegroundColor DarkGray
return
}
Push-Location $Project
GetBranches
$updated = (git log -1 --date=format:"%b %d, %Y" --format="%ad")
Write-Verbose '$updated = (git log -1 --date=format:"%b %d, %Y" --format="%ad")'
Write-Verbose "`$updated > $updated"
if ($detached -and !$Branch -and !$Reset)
{
Write-Host $divider
Write-Host "... detached HEAD at $active, last updated $updated" -ForegroundColor DarkGray
return
}
$br = $Branch
if (!$Branch)
{
if ($Reset -and $detached) { $br = $mainBr }
else { $br = $active }
}
if ($br.StartsWith('origin/')) { $br = $br.Substring(7) }
Write-Verbose "`$br > $br"
Write-Host $divider
$expected = $mainBr
if ($expected.StartsWith('origin/')) { $expected = $mainBr.Substring(7) }
if ($br -eq $expected)
{
Write-Host "... updating $Project from $br, last updated $updated" -ForegroundColor Blue
}
else
{
Write-Host "... updating $Project from " -ForegroundColor Blue -NoNewline
Write-Host $br -ForegroundColor DarkYellow -NoNewline
Write-Host ", last updated $updated" -ForegroundColor Blue
}
if ($Reset)
{
if ($detached)
{
Write-Verbose "git checkout $br"
git checkout $br
}
# revert uncommitted changes that have been added to the index
Write-Verbose "git reset --hard origin/$br"
git reset --hard origin/$br
# revert uncommitted, unindexed changes (f=force, d=recurse, x=uncontrolled)
Write-Verbose 'git clean -dxf'
git clean -dxf
}
($br -match '(?:origin/)?(.*)') | out-null ; $shortBr = $matches[1]
($mainBr -match '(?:origin/)?(.*)') | out-null ; $shortMain = $matches[1]
if ($Merge -and ($shortBr -ne $shortMain))
{
Write-Host "... merging $mainBr into $br" -ForegroundColor DarkCyan
Write-Verbose "git fetch origin $shortMain"
git fetch origin $shortMain
Write-Verbose "git merge $mainBr"
git merge $mainBr
}
Write-Verbose 'git fetch'
git fetch #origin
Write-Verbose 'git pull'
git pull #origin $br
if ($LASTEXITCODE -ne 0)
{
Write-Host
Write-Host "*** failed git pull origin $br" -ForegroundColor Red
Write-Host
}
else
{
$head = (git rev-parse --abbrev-ref HEAD)
if ($head -ne 'main' -and $head -ne 'master')
{
$ahead = (git rev-list --count origin/$br..$head)
$behind = (git rev-list --count $head..origin/$br)
Write-Host "... branch is ahead $ahead commits and behind $behind commits" -ForegroundColor DarkGray
}
}
Pop-Location
}
function GetBranches
{
$branches = (git branch)
$script:active = $branches | ? { $_.startswith('*') } | % { $_.substring(2) }
Write-Verbose '$active = git branch'
Write-Verbose "`$active > $active"
# get name of "main" branch from origin/HEAD
$script:mainBr = (git branch -a | ? { $_ -match 'origin/HEAD -> (.*)' } | % { $Matches[1] })
Write-Verbose '$mainBr = (git branch -a | ? { $_ -match ''origin/HEAD -> (.*)'' } | % { $Matches[1] })'
Write-Verbose "`$mainBr > $mainBr"
$script:detached = ($active -match '\(HEAD detached at ([a-f0-9]+)\)')
if ($detached)
{
# $active will contain the commit hash
$script:active = $matches[1]
return
}
}
}
Process
{
if ($Project)
{
$Host.PrivateData.VerboseForegroundColor = 'DarkGray'
Update $Project
$Host.PrivateData.VerboseForegroundColor = 'Yellow'
}
else
{
Get-ChildItem | `
? { Test-Path (Join-Path $_.FullName '.git') } | `
Select -ExpandProperty Name | `
% { Update $_ }
}
}