@@ -81,113 +81,57 @@ type mirrorSyncResult struct {
81
81
newCommitID string
82
82
}
83
83
84
- // parseRemoteUpdateOutput detects create, update and delete operations of references from upstream.
85
- // possible output example:
86
- /*
87
- // * [new tag] v0.1.8 -> v0.1.8
88
- // * [new branch] master -> origin/master
89
- // * [new ref] refs/pull/2/head -> refs/pull/2/head"
90
- // - [deleted] (none) -> origin/test // delete a branch
91
- // - [deleted] (none) -> 1 // delete a tag
92
- // 957a993..a87ba5f test -> origin/test
93
- // + f895a1e...957a993 test -> origin/test (forced update)
94
- */
95
- // TODO: return whether it's a force update
96
- func parseRemoteUpdateOutput (output , remoteName string ) []* mirrorSyncResult {
97
- results := make ([]* mirrorSyncResult , 0 , 3 )
98
- lines := strings .Split (output , "\n " )
99
- for i := range lines {
100
- // Make sure reference name is presented before continue
101
- idx := strings .Index (lines [i ], "-> " )
102
- if idx == - 1 {
84
+ // parseFetchPorcelain parses `git fetch --porcelain` lines into mirrorSyncResult.
85
+ // Lines look like: "<flag> <old> <new> <local-ref>"
86
+ func parseFetchPorcelain (output string ) []* mirrorSyncResult {
87
+ results := make ([]* mirrorSyncResult , 0 , 8 )
88
+
89
+ for _ , line := range strings .Split (output , "\n " ) {
90
+ if line == "" {
91
+ continue
92
+ }
93
+ flag := line [0 ]
94
+ fields := strings .Fields (line [1 :]) // trim flag, split rest
95
+ if len (fields ) < 3 {
96
+ log .Warn ("parseFetchPorcelain: unexpected line %q" , line )
103
97
continue
104
98
}
99
+ oldOID , newOID , ref := fields [0 ], fields [1 ], fields [2 ]
105
100
106
- refName := strings .TrimSpace (lines [i ][idx + 3 :])
101
+ // Normalize ref name
102
+ var refFull git.RefName
103
+ if strings .HasPrefix (ref , "refs/" ) {
104
+ refFull = git .RefName (ref )
105
+ } else {
106
+ // fetch porcelain prints local tracking ref; treat non-refs/* as branches
107
+ refFull = git .RefNameFromBranch (ref )
108
+ }
107
109
108
- switch {
109
- case strings .HasPrefix (lines [i ], " * [new tag]" ): // new tag
110
- results = append (results , & mirrorSyncResult {
111
- refName : git .RefNameFromTag (refName ),
112
- oldCommitID : gitShortEmptySha ,
113
- })
114
- case strings .HasPrefix (lines [i ], " * [new branch]" ): // new branch
115
- refName = strings .TrimPrefix (refName , remoteName + "/" )
110
+ switch flag {
111
+ case '*' : // new ref
116
112
results = append (results , & mirrorSyncResult {
117
- refName : git . RefNameFromBranch ( refName ) ,
113
+ refName : refFull ,
118
114
oldCommitID : gitShortEmptySha ,
115
+ newCommitID : newOID ,
119
116
})
120
- case strings . HasPrefix ( lines [ i ], " * [new ref]" ) : // new reference
117
+ case '-' : // pruned (deleted)
121
118
results = append (results , & mirrorSyncResult {
122
- refName : git .RefName (refName ),
123
- oldCommitID : gitShortEmptySha ,
124
- })
125
- case strings .HasPrefix (lines [i ], " - " ): // Delete reference
126
- isTag := ! strings .HasPrefix (refName , remoteName + "/" )
127
- var refFullName git.RefName
128
- if strings .HasPrefix (refName , "refs/" ) {
129
- refFullName = git .RefName (refName )
130
- } else if isTag {
131
- refFullName = git .RefNameFromTag (refName )
132
- } else {
133
- refFullName = git .RefNameFromBranch (strings .TrimPrefix (refName , remoteName + "/" ))
134
- }
135
- results = append (results , & mirrorSyncResult {
136
- refName : refFullName ,
119
+ refName : refFull ,
120
+ oldCommitID : oldOID ,
137
121
newCommitID : gitShortEmptySha ,
138
122
})
139
- case strings .HasPrefix (lines [i ], " + " ): // Force update
140
- if idx := strings .Index (refName , " " ); idx > - 1 {
141
- refName = refName [:idx ]
142
- }
143
- delimIdx := strings .Index (lines [i ][3 :], " " )
144
- if delimIdx == - 1 {
145
- log .Error ("SHA delimiter not found: %q" , lines [i ])
146
- continue
147
- }
148
- shas := strings .Split (lines [i ][3 :delimIdx + 3 ], "..." )
149
- if len (shas ) != 2 {
150
- log .Error ("Expect two SHAs but not what found: %q" , lines [i ])
151
- continue
152
- }
153
- var refFullName git.RefName
154
- if strings .HasPrefix (refName , "refs/" ) {
155
- refFullName = git .RefName (refName )
156
- } else {
157
- refFullName = git .RefNameFromBranch (strings .TrimPrefix (refName , remoteName + "/" ))
158
- }
159
-
160
- results = append (results , & mirrorSyncResult {
161
- refName : refFullName ,
162
- oldCommitID : shas [0 ],
163
- newCommitID : shas [1 ],
164
- })
165
- case strings .HasPrefix (lines [i ], " " ): // New commits of a reference
166
- delimIdx := strings .Index (lines [i ][3 :], " " )
167
- if delimIdx == - 1 {
168
- log .Error ("SHA delimiter not found: %q" , lines [i ])
169
- continue
170
- }
171
- shas := strings .Split (lines [i ][3 :delimIdx + 3 ], ".." )
172
- if len (shas ) != 2 {
173
- log .Error ("Expect two SHAs but not what found: %q" , lines [i ])
174
- continue
175
- }
176
- var refFullName git.RefName
177
- if strings .HasPrefix (refName , "refs/" ) {
178
- refFullName = git .RefName (refName )
179
- } else {
180
- refFullName = git .RefNameFromBranch (strings .TrimPrefix (refName , remoteName + "/" ))
181
- }
182
-
123
+ case '+' , ' ' , 't' : // force, fast-forward, tag update
183
124
results = append (results , & mirrorSyncResult {
184
- refName : refFullName ,
185
- oldCommitID : shas [ 0 ] ,
186
- newCommitID : shas [ 1 ] ,
125
+ refName : refFull ,
126
+ oldCommitID : oldOID ,
127
+ newCommitID : newOID ,
187
128
})
188
-
129
+ case '!' : // failed fetch for this ref
130
+ log .Error ("fetch failed for %s (%s -> %s)" , ref , oldOID , newOID )
131
+ case '=' : // up-to-date (only if --verbose); ignore
132
+ continue
189
133
default :
190
- log .Warn ("parseRemoteUpdateOutput: unexpected update line %q" , lines [ i ] )
134
+ log .Warn ("parseFetchPorcelain: unknown flag %q on %q" , flag , line )
191
135
}
192
136
}
193
137
return results
@@ -260,7 +204,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
260
204
if m .EnablePrune {
261
205
cmd .AddArguments ("--prune" )
262
206
}
263
- cmd .AddArguments ("--tags" ).AddDynamicArguments (m .GetRemoteName ())
207
+ cmd .AddArguments ("--tags" , "--porcelain" , "--no-progress" ).AddDynamicArguments (m .GetRemoteName ())
264
208
265
209
remoteURL , remoteErr := gitrepo .GitRemoteGetURL (ctx , m .Repo , m .GetRemoteName ())
266
210
if remoteErr != nil {
@@ -324,7 +268,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
324
268
return nil , false
325
269
}
326
270
}
327
- output := stderrBuilder .String ()
271
+ output := stdoutBuilder .String ()
328
272
329
273
if err := git .WriteCommitGraph (ctx , repoPath ); err != nil {
330
274
log .Error ("SyncMirrors [repo: %-v]: %v" , m .Repo , err )
@@ -426,7 +370,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
426
370
}
427
371
428
372
m .UpdatedUnix = timeutil .TimeStampNow ()
429
- return parseRemoteUpdateOutput (output , m . GetRemoteName () ), true
373
+ return parseFetchPorcelain (output ), true
430
374
}
431
375
432
376
func getRepoPullMirrorLockKey (repoID int64 ) string {
0 commit comments