@babajide234/git-merge-workflow 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/GitMergeWorkflow.psd1 +42 -18
- package/GitMergeWorkflow.psm1 +365 -343
- package/LICENSE +21 -21
- package/README.md +1 -1
- package/package.json +39 -39
package/GitMergeWorkflow.psd1
CHANGED
|
@@ -1,18 +1,42 @@
|
|
|
1
|
-
@{
|
|
2
|
-
RootModule
|
|
3
|
-
ModuleVersion
|
|
4
|
-
GUID
|
|
5
|
-
Author
|
|
6
|
-
CompanyName
|
|
7
|
-
Copyright
|
|
8
|
-
Description
|
|
9
|
-
PowerShellVersion = '5.1'
|
|
10
|
-
FunctionsToExport = @('Invoke-GitMergeWorkflow', 'New-GitWorkflowConfig', 'Get-GitWorkflowConfig')
|
|
11
|
-
AliasesToExport
|
|
12
|
-
PrivateData
|
|
13
|
-
PSData = @{
|
|
14
|
-
Tags
|
|
15
|
-
ProjectUri
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
@{
|
|
2
|
+
RootModule = 'GitMergeWorkflow.psm1'
|
|
3
|
+
ModuleVersion = '1.0.6'
|
|
4
|
+
GUID = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
|
|
5
|
+
Author = 'babajide Tomoshegbo'
|
|
6
|
+
CompanyName = 'babajide234'
|
|
7
|
+
Copyright = '(c) 2025 Expedier. All rights reserved.'
|
|
8
|
+
Description = 'Automated Git workflow for merging feature branches through staging to develop'
|
|
9
|
+
PowerShellVersion = '5.1'
|
|
10
|
+
FunctionsToExport = @('Invoke-GitMergeWorkflow', 'New-GitWorkflowConfig', 'Get-GitWorkflowConfig')
|
|
11
|
+
AliasesToExport = @('git-merge-workflow', 'gmw')
|
|
12
|
+
PrivateData = @{
|
|
13
|
+
PSData = @{
|
|
14
|
+
Tags = @('Git', 'Workflow', 'Automation', 'Merge', 'DevOps')
|
|
15
|
+
ProjectUri = 'https://github.com/babajide234/GitMergeWorkflow'
|
|
16
|
+
ReleaseNotes = @"
|
|
17
|
+
## 1.0.6
|
|
18
|
+
- Fix: Resolve false positive remote branch detection caused by git credential-manager stderr warnings polluting ls-remote output.
|
|
19
|
+
- Fix: Use full refs/heads/ refspec prefix in fetch command to prevent remote ref resolution failures.
|
|
20
|
+
- Improvement: Added fallback to create local branch if remote fetch fails unexpectedly.
|
|
21
|
+
|
|
22
|
+
## 1.0.5
|
|
23
|
+
- Fix: Ensure correct remote branch referencing and fetching by using full refspecs in ls-remote and fetch commands.
|
|
24
|
+
|
|
25
|
+
## 1.0.4
|
|
26
|
+
- Version bump for NPM publication.
|
|
27
|
+
|
|
28
|
+
## 1.0.3
|
|
29
|
+
- Prepare for NPM publication.
|
|
30
|
+
|
|
31
|
+
## 1.0.1
|
|
32
|
+
- chore: Bump module version, update branding and ownership details, and remove the developer guide.
|
|
33
|
+
|
|
34
|
+
## 1.0.0
|
|
35
|
+
- Initial release with automated merge workflow (feature -> staging -> target).
|
|
36
|
+
- Safety checks, conflict handling, and automatic cleanup.
|
|
37
|
+
- Configurable via .git-merge-workflow.json.
|
|
38
|
+
- Dry run support with -WhatIf.
|
|
39
|
+
"@
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
package/GitMergeWorkflow.psm1
CHANGED
|
@@ -1,343 +1,365 @@
|
|
|
1
|
-
|
|
2
|
-
function Get-GitWorkflowConfig {
|
|
3
|
-
<#
|
|
4
|
-
.SYNOPSIS
|
|
5
|
-
Retrieves the Git Merge Workflow configuration from the current repository
|
|
6
|
-
.DESCRIPTION
|
|
7
|
-
Looks for a .git-merge-workflow.json file in the root of the git repository.
|
|
8
|
-
If found, parses and returns the configuration.
|
|
9
|
-
If not found, returns null.
|
|
10
|
-
#>
|
|
11
|
-
[CmdletBinding()]
|
|
12
|
-
param()
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
# Get git root
|
|
16
|
-
$gitRoot = git rev-parse --show-toplevel 2>$null
|
|
17
|
-
if ($LASTEXITCODE -eq 0 -and $gitRoot) {
|
|
18
|
-
$configPath = Join-Path $gitRoot ".git-merge-workflow.json"
|
|
19
|
-
if (Test-Path $configPath) {
|
|
20
|
-
return Get-Content $configPath -Raw | ConvertFrom-Json
|
|
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
|
-
[string]$
|
|
48
|
-
[string]$
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
Write-Host "
|
|
72
|
-
Write-Host
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
$
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
Write-Host "
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
Write-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
#
|
|
329
|
-
$
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
1
|
+
|
|
2
|
+
function Get-GitWorkflowConfig {
|
|
3
|
+
<#
|
|
4
|
+
.SYNOPSIS
|
|
5
|
+
Retrieves the Git Merge Workflow configuration from the current repository
|
|
6
|
+
.DESCRIPTION
|
|
7
|
+
Looks for a .git-merge-workflow.json file in the root of the git repository.
|
|
8
|
+
If found, parses and returns the configuration.
|
|
9
|
+
If not found, returns null.
|
|
10
|
+
#>
|
|
11
|
+
[CmdletBinding()]
|
|
12
|
+
param()
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
# Get git root
|
|
16
|
+
$gitRoot = git rev-parse --show-toplevel 2>$null
|
|
17
|
+
if ($LASTEXITCODE -eq 0 -and $gitRoot) {
|
|
18
|
+
$configPath = Join-Path $gitRoot ".git-merge-workflow.json"
|
|
19
|
+
if (Test-Path $configPath) {
|
|
20
|
+
return Get-Content $configPath -Raw | ConvertFrom-Json
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
Write-Verbose "Error reading config: $_"
|
|
26
|
+
}
|
|
27
|
+
return $null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function New-GitWorkflowConfig {
|
|
31
|
+
<#
|
|
32
|
+
.SYNOPSIS
|
|
33
|
+
Creates a new configuration file for the Git Merge Workflow
|
|
34
|
+
.DESCRIPTION
|
|
35
|
+
Creates a .git-merge-workflow.json file in the root of the current git repository.
|
|
36
|
+
.PARAMETER TargetBranch
|
|
37
|
+
The default target branch (default: develop)
|
|
38
|
+
.PARAMETER StagingSuffix
|
|
39
|
+
The suffix for staging branches (default: -staging)
|
|
40
|
+
.PARAMETER Remote
|
|
41
|
+
The default remote name (default: origin)
|
|
42
|
+
.EXAMPLE
|
|
43
|
+
New-GitWorkflowConfig -TargetBranch "main" -StagingSuffix "-test"
|
|
44
|
+
#>
|
|
45
|
+
[CmdletBinding(SupportsShouldProcess = $true)]
|
|
46
|
+
param(
|
|
47
|
+
[string]$TargetBranch = "develop",
|
|
48
|
+
[string]$StagingSuffix = "-staging",
|
|
49
|
+
[string]$Remote = "origin"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Check if in git repo
|
|
53
|
+
$gitRoot = git rev-parse --show-toplevel 2>$null
|
|
54
|
+
if ($LASTEXITCODE -ne 0 -or -not $gitRoot) {
|
|
55
|
+
Write-Error "Not in a git repository. Please run inside a git repository."
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
$configPath = Join-Path $gitRoot ".git-merge-workflow.json"
|
|
60
|
+
|
|
61
|
+
$config = @{
|
|
62
|
+
TargetBranch = $TargetBranch
|
|
63
|
+
StagingSuffix = $StagingSuffix
|
|
64
|
+
Remote = $Remote
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
$json = $config | ConvertTo-Json -Depth 2
|
|
68
|
+
|
|
69
|
+
if ($PSCmdlet.ShouldProcess($configPath, "Create configuration file")) {
|
|
70
|
+
$json | Set-Content $configPath
|
|
71
|
+
Write-Host "Configuration file created at: $configPath" -ForegroundColor Green
|
|
72
|
+
Write-Host "Content:" -ForegroundColor Cyan
|
|
73
|
+
Write-Host $json
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function Invoke-GitMergeWorkflow {
|
|
78
|
+
<#
|
|
79
|
+
.SYNOPSIS
|
|
80
|
+
Automated Git workflow to merge current branch to staging and then to develop
|
|
81
|
+
.DESCRIPTION
|
|
82
|
+
This function automates the process of:
|
|
83
|
+
1. Getting the current branch name
|
|
84
|
+
2. Merging current branch to {branch}-staging
|
|
85
|
+
3. Merging {branch}-staging to develop
|
|
86
|
+
4. Pushing all changes
|
|
87
|
+
|
|
88
|
+
Configuration can be stored in .git-merge-workflow.json in the repository root.
|
|
89
|
+
.PARAMETER CommitMessage
|
|
90
|
+
Optional commit message if there are uncommitted changes
|
|
91
|
+
.PARAMETER StagingBranch
|
|
92
|
+
Optional custom staging branch name.
|
|
93
|
+
Defaults to {current-branch}{staging-suffix} (configured in JSON or defaults to -staging)
|
|
94
|
+
.PARAMETER TargetBranch
|
|
95
|
+
Optional target branch name.
|
|
96
|
+
Defaults to 'develop' or value in configuration file.
|
|
97
|
+
.PARAMETER Remote
|
|
98
|
+
Optional remote name.
|
|
99
|
+
Defaults to 'origin' or value in configuration file.
|
|
100
|
+
.EXAMPLE
|
|
101
|
+
Invoke-GitMergeWorkflow
|
|
102
|
+
.EXAMPLE
|
|
103
|
+
Invoke-GitMergeWorkflow -CommitMessage "Fix: Updated business contact form"
|
|
104
|
+
.EXAMPLE
|
|
105
|
+
git-merge-workflow -CommitMessage "Feature: Added new component" -WhatIf
|
|
106
|
+
#>
|
|
107
|
+
|
|
108
|
+
[CmdletBinding(SupportsShouldProcess = $true)]
|
|
109
|
+
param(
|
|
110
|
+
[Parameter(Mandatory = $false)]
|
|
111
|
+
[string]$CommitMessage = "",
|
|
112
|
+
|
|
113
|
+
[Parameter(Mandatory = $false)]
|
|
114
|
+
[string]$StagingBranch = "",
|
|
115
|
+
|
|
116
|
+
[Parameter(Mandatory = $false)]
|
|
117
|
+
[string]$TargetBranch = "",
|
|
118
|
+
|
|
119
|
+
[Parameter(Mandatory = $false)]
|
|
120
|
+
[string]$Remote = ""
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Load configuration
|
|
124
|
+
$config = Get-GitWorkflowConfig
|
|
125
|
+
|
|
126
|
+
# Set defaults (Priority: Parameter > Config > Hardcoded Default)
|
|
127
|
+
if (-not $TargetBranch) {
|
|
128
|
+
$TargetBranch = if ($config.TargetBranch) { $config.TargetBranch } else { "develop" }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (-not $Remote) {
|
|
132
|
+
$Remote = if ($config.Remote) { $config.Remote } else { "origin" }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
$stagingSuffix = if ($config.StagingSuffix) { $config.StagingSuffix } else { "-staging" }
|
|
136
|
+
|
|
137
|
+
# Internal helper to execute git commands with error handling
|
|
138
|
+
function Exec-Git {
|
|
139
|
+
[CmdletBinding()]
|
|
140
|
+
param(
|
|
141
|
+
[Parameter(Mandatory = $true, Position = 0)]
|
|
142
|
+
[string]$Command,
|
|
143
|
+
|
|
144
|
+
[Parameter(Mandatory = $false)]
|
|
145
|
+
[string]$ErrorMessage,
|
|
146
|
+
|
|
147
|
+
[Parameter(Mandatory = $false)]
|
|
148
|
+
[switch]$IgnoreError,
|
|
149
|
+
|
|
150
|
+
[Parameter(Mandatory = $false)]
|
|
151
|
+
[switch]$ReturnOutput,
|
|
152
|
+
|
|
153
|
+
[Parameter(ValueFromRemainingArguments = $true)]
|
|
154
|
+
[string[]]$Arguments
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
$cmdDesc = "git $Command $Arguments"
|
|
158
|
+
|
|
159
|
+
if ($PSCmdlet.ShouldProcess("Git Repository", "Execute: $cmdDesc")) {
|
|
160
|
+
# Construct the command to run
|
|
161
|
+
# Note: We use & operator to run git with arguments
|
|
162
|
+
$output = & git $Command $Arguments 2>&1
|
|
163
|
+
$exitCode = $LASTEXITCODE
|
|
164
|
+
|
|
165
|
+
if ($ReturnOutput) {
|
|
166
|
+
return $output
|
|
167
|
+
}
|
|
168
|
+
elseif ($output) {
|
|
169
|
+
# If not capturing output, write it to the stream (except errors which we handle below)
|
|
170
|
+
$output | ForEach-Object { Write-Verbose $_ }
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (-not $IgnoreError -and $exitCode -ne 0) {
|
|
174
|
+
$msg = if ($ErrorMessage) { $ErrorMessage } else { "Git command failed: $cmdDesc" }
|
|
175
|
+
throw "$msg`nDetails: $output"
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
Write-Host "`n=== Git Merge Workflow ===" -ForegroundColor Cyan
|
|
181
|
+
Write-Host "Starting automated merge process...`n" -ForegroundColor Cyan
|
|
182
|
+
|
|
183
|
+
# Check if we're in a git repository
|
|
184
|
+
try {
|
|
185
|
+
Exec-Git "rev-parse" "--is-inside-work-tree" -ErrorMessage "Not a git repository" -ReturnOutput | Out-Null
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
Write-Error $_.Exception.Message
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
# Get current branch
|
|
193
|
+
$currentBranch = (git branch --show-current).Trim()
|
|
194
|
+
Write-Host "Current branch: $currentBranch" -ForegroundColor Yellow
|
|
195
|
+
|
|
196
|
+
if ([string]::IsNullOrWhiteSpace($currentBranch)) {
|
|
197
|
+
Write-Error "Could not determine current branch."
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
# Validate we are not on target or explicitly named staging
|
|
202
|
+
if ($currentBranch -eq $TargetBranch) {
|
|
203
|
+
Write-Error "You are currently on the target branch '$TargetBranch'. Please checkout your feature branch first."
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
# Define staging branch
|
|
208
|
+
if (-not $StagingBranch) {
|
|
209
|
+
$StagingBranch = "$currentBranch$stagingSuffix"
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if ($currentBranch -eq $StagingBranch) {
|
|
213
|
+
Write-Error "You are currently on the staging branch '$StagingBranch'. Please checkout your feature branch first."
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
Write-Host "`nStaging branch: $StagingBranch" -ForegroundColor Yellow
|
|
218
|
+
Write-Host "Target branch: $TargetBranch" -ForegroundColor Yellow
|
|
219
|
+
Write-Host "Remote: $Remote" -ForegroundColor Yellow
|
|
220
|
+
|
|
221
|
+
# Store starting branch to return to it later
|
|
222
|
+
$originalBranch = $currentBranch
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
# Verify remote connection before proceeding
|
|
226
|
+
Write-Host "`nVerifying connection to $Remote..." -ForegroundColor Yellow
|
|
227
|
+
Exec-Git -Command "ls-remote" -Arguments $Remote, "HEAD" -ErrorMessage "Could not connect to remote '$Remote'. Please check your internet connection and git credentials." -ReturnOutput | Out-Null
|
|
228
|
+
Write-Host "Connection successful!" -ForegroundColor Green
|
|
229
|
+
|
|
230
|
+
# Check for uncommitted changes
|
|
231
|
+
$status = git status --porcelain
|
|
232
|
+
if ($status) {
|
|
233
|
+
if ($CommitMessage) {
|
|
234
|
+
Write-Host "`nCommitting changes..." -ForegroundColor Yellow
|
|
235
|
+
if ($PSCmdlet.ShouldProcess("Current Branch", "Add all changes and commit with message '$CommitMessage'")) {
|
|
236
|
+
Exec-Git "add" "." -ErrorMessage "Failed to add changes"
|
|
237
|
+
Exec-Git "commit" "-m" "$CommitMessage" -ErrorMessage "Failed to commit changes"
|
|
238
|
+
Write-Host "Changes committed!" -ForegroundColor Green
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
Write-Error "You have uncommitted changes! Please commit them first or use -CommitMessage parameter"
|
|
243
|
+
git status
|
|
244
|
+
return
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
# --- Handle Staging Branch ---
|
|
249
|
+
|
|
250
|
+
# Check if staging branch exists locally
|
|
251
|
+
$branchExists = git branch --list $StagingBranch
|
|
252
|
+
if (-not $branchExists) {
|
|
253
|
+
Write-Host "`nStaging branch doesn't exist locally. Checking remote..." -ForegroundColor Yellow
|
|
254
|
+
# Check if exists on remote using a direct git command to avoid
|
|
255
|
+
# false positives from stderr warnings (e.g. credential-manager)
|
|
256
|
+
$remoteBranchExists = $false
|
|
257
|
+
try {
|
|
258
|
+
# Use & git directly so stderr warnings don't pollute the result.
|
|
259
|
+
# ls-remote --heads returns lines like "<hash>\trefs/heads/<branch>" for matches.
|
|
260
|
+
$lsOutput = & git ls-remote --heads $Remote "refs/heads/$StagingBranch" 2>$null
|
|
261
|
+
if ($lsOutput -and $lsOutput -match "refs/heads/$([regex]::Escape($StagingBranch))") {
|
|
262
|
+
$remoteBranchExists = $true
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
Write-Warning "Could not check remote branch: $_"
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if ($remoteBranchExists) {
|
|
270
|
+
Write-Host "Fetching remote staging branch..." -ForegroundColor Yellow
|
|
271
|
+
try {
|
|
272
|
+
Exec-Git -Command "fetch" -Arguments $Remote, "refs/heads/${StagingBranch}:refs/remotes/$Remote/$StagingBranch"
|
|
273
|
+
Exec-Git -Command "checkout" -Arguments "-b", $StagingBranch, "$Remote/$StagingBranch"
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
Write-Warning "Failed to fetch remote staging branch. Creating new local branch instead."
|
|
277
|
+
Exec-Git -Command "checkout" -Arguments "-b", $StagingBranch
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
Write-Host "Creating new staging branch..." -ForegroundColor Yellow
|
|
282
|
+
Exec-Git -Command "checkout" -Arguments "-b", $StagingBranch
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
Write-Host "Checking out staging branch..." -ForegroundColor Yellow
|
|
287
|
+
Exec-Git -Command "checkout" -Arguments $StagingBranch
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
# Pull latest from staging (if tracked)
|
|
291
|
+
Write-Host "`nPulling latest changes from staging..." -ForegroundColor Yellow
|
|
292
|
+
# We use IgnoreError because it might fail if there's no tracking info yet, which is acceptable here
|
|
293
|
+
Exec-Git -Command "pull" -Arguments $Remote, $StagingBranch -IgnoreError
|
|
294
|
+
|
|
295
|
+
# Merge current branch into staging
|
|
296
|
+
Write-Host "`nMerging $currentBranch into $StagingBranch..." -ForegroundColor Yellow
|
|
297
|
+
Exec-Git -Command "merge" -Arguments $currentBranch, "--no-ff", "-m", "Merge $currentBranch into $StagingBranch" -ErrorMessage "Merge conflict detected in staging! Please resolve conflicts manually."
|
|
298
|
+
|
|
299
|
+
Write-Host "Successfully merged to staging!" -ForegroundColor Green
|
|
300
|
+
|
|
301
|
+
# Push staging
|
|
302
|
+
Write-Host "`nPushing $StagingBranch to remote..." -ForegroundColor Yellow
|
|
303
|
+
try {
|
|
304
|
+
Exec-Git -Command "push" -Arguments "-u", $Remote, $StagingBranch -ErrorMessage "Failed to push staging branch"
|
|
305
|
+
Write-Host "Staging branch pushed!" -ForegroundColor Green
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
Write-Warning "Failed to push staging branch to remote."
|
|
309
|
+
Write-Warning "Error: $_"
|
|
310
|
+
if ($PSCmdlet.ShouldContinue("Do you want to skip pushing the staging branch and continue to merge into $TargetBranch?", "Skip Staging Push")) {
|
|
311
|
+
Write-Host "Skipping staging push..." -ForegroundColor Yellow
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
throw $_
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
# --- Handle Target Branch ---
|
|
319
|
+
|
|
320
|
+
# Checkout target branch
|
|
321
|
+
Write-Host "`nChecking out $TargetBranch branch..." -ForegroundColor Yellow
|
|
322
|
+
Exec-Git "checkout" $TargetBranch -ErrorMessage "Failed to checkout $TargetBranch"
|
|
323
|
+
|
|
324
|
+
# Pull latest from target
|
|
325
|
+
Write-Host "Pulling latest changes from $TargetBranch..." -ForegroundColor Yellow
|
|
326
|
+
Exec-Git "pull" $Remote $TargetBranch -ErrorMessage "Failed to pull $TargetBranch"
|
|
327
|
+
|
|
328
|
+
# Merge staging into target
|
|
329
|
+
Write-Host "`nMerging $StagingBranch into $TargetBranch..." -ForegroundColor Yellow
|
|
330
|
+
Exec-Git "merge" $StagingBranch "--no-ff" "-m" "Merge $StagingBranch into $TargetBranch" -ErrorMessage "Merge conflict detected in target! Please resolve conflicts manually."
|
|
331
|
+
|
|
332
|
+
Write-Host "Successfully merged to target!" -ForegroundColor Green
|
|
333
|
+
|
|
334
|
+
# Push target
|
|
335
|
+
Write-Host "`nPushing $TargetBranch to remote..." -ForegroundColor Yellow
|
|
336
|
+
Exec-Git "push" $Remote $TargetBranch -ErrorMessage "Failed to push $TargetBranch branch"
|
|
337
|
+
Write-Host "$TargetBranch branch pushed!" -ForegroundColor Green
|
|
338
|
+
|
|
339
|
+
Write-Host "`n=== Workflow Complete! ===" -ForegroundColor Green
|
|
340
|
+
Write-Host "Summary:" -ForegroundColor Cyan
|
|
341
|
+
Write-Host " ✓ Merged: $originalBranch → $StagingBranch → $TargetBranch" -ForegroundColor White
|
|
342
|
+
Write-Host " ✓ All changes pushed to remote`n" -ForegroundColor White
|
|
343
|
+
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
Write-Error $_.Exception.Message
|
|
347
|
+
Write-Host "`nWorkflow failed. Attempting to return to original branch..." -ForegroundColor Red
|
|
348
|
+
}
|
|
349
|
+
finally {
|
|
350
|
+
# Return to original branch
|
|
351
|
+
$finalBranch = (git branch --show-current).Trim()
|
|
352
|
+
if ($originalBranch -and $finalBranch -ne $originalBranch) {
|
|
353
|
+
Write-Host "`nReturning to $originalBranch..." -ForegroundColor Yellow
|
|
354
|
+
if ($PSCmdlet.ShouldProcess("Cleanup", "Checkout $originalBranch")) {
|
|
355
|
+
git checkout $originalBranch 2>$null | Out-Null
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
# Create aliases for easier usage
|
|
362
|
+
New-Alias -Name git-merge-workflow -Value Invoke-GitMergeWorkflow -Force
|
|
363
|
+
New-Alias -Name gmw -Value Invoke-GitMergeWorkflow -Force
|
|
364
|
+
|
|
365
|
+
Export-ModuleMember -Function Invoke-GitMergeWorkflow, New-GitWorkflowConfig, Get-GitWorkflowConfig -Alias git-merge-workflow, gmw
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 babajide Tomoshegbo
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 babajide Tomoshegbo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Automate your git merge workflow with safety and ease. This module helps you mer
|
|
|
17
17
|
You can install this tool globally using npm:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npm install -g @
|
|
20
|
+
npm install -g @babajide234/git-merge-workflow
|
|
21
21
|
```
|
|
22
22
|
This will make the `gmw` and `git-merge-workflow` commands available in your terminal.
|
|
23
23
|
|
package/package.json
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@babajide234/git-merge-workflow",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"private": false,
|
|
5
|
-
"publishConfig": {
|
|
6
|
-
"access": "public"
|
|
7
|
-
},
|
|
8
|
-
"description": "Automated Git workflow for merging feature branches through staging to develop",
|
|
9
|
-
"bin": {
|
|
10
|
-
"git-merge-workflow": "./bin/cli.js",
|
|
11
|
-
"gmw": "./bin/cli.js"
|
|
12
|
-
},
|
|
13
|
-
"files": [
|
|
14
|
-
"bin/",
|
|
15
|
-
"GitMergeWorkflow.psd1",
|
|
16
|
-
"GitMergeWorkflow.psm1",
|
|
17
|
-
"Install.ps1",
|
|
18
|
-
"README.md"
|
|
19
|
-
],
|
|
20
|
-
"scripts": {
|
|
21
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
22
|
-
},
|
|
23
|
-
"keywords": [
|
|
24
|
-
"git",
|
|
25
|
-
"workflow",
|
|
26
|
-
"powershell",
|
|
27
|
-
"automation",
|
|
28
|
-
"devops"
|
|
29
|
-
],
|
|
30
|
-
"author": "babajide Tomoshegbo",
|
|
31
|
-
"license": "MIT",
|
|
32
|
-
"repository": {
|
|
33
|
-
"type": "git",
|
|
34
|
-
"url": "https://github.com/babajide234/GitMergeWorkflow.git"
|
|
35
|
-
},
|
|
36
|
-
"engines": {
|
|
37
|
-
"node": ">=14"
|
|
38
|
-
}
|
|
39
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@babajide234/git-merge-workflow",
|
|
3
|
+
"version": "1.0.6",
|
|
4
|
+
"private": false,
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"description": "Automated Git workflow for merging feature branches through staging to develop",
|
|
9
|
+
"bin": {
|
|
10
|
+
"git-merge-workflow": "./bin/cli.js",
|
|
11
|
+
"gmw": "./bin/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"bin/",
|
|
15
|
+
"GitMergeWorkflow.psd1",
|
|
16
|
+
"GitMergeWorkflow.psm1",
|
|
17
|
+
"Install.ps1",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"git",
|
|
25
|
+
"workflow",
|
|
26
|
+
"powershell",
|
|
27
|
+
"automation",
|
|
28
|
+
"devops"
|
|
29
|
+
],
|
|
30
|
+
"author": "babajide Tomoshegbo",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/babajide234/GitMergeWorkflow.git"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=14"
|
|
38
|
+
}
|
|
39
|
+
}
|