@@ -81,113 +81,57 @@ type mirrorSyncResult struct {
8181 newCommitID string
8282}
8383
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 )
10397 continue
10498 }
99+ oldOID , newOID , ref := fields [0 ], fields [1 ], fields [2 ]
105100
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+ }
107109
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
116112 results = append (results , & mirrorSyncResult {
117- refName : git . RefNameFromBranch ( refName ) ,
113+ refName : refFull ,
118114 oldCommitID : gitShortEmptySha ,
115+ newCommitID : newOID ,
119116 })
120- case strings . HasPrefix ( lines [ i ], " * [new ref]" ) : // new reference
117+ case '-' : // pruned (deleted)
121118 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 ,
137121 newCommitID : gitShortEmptySha ,
138122 })
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
183124 results = append (results , & mirrorSyncResult {
184- refName : refFullName ,
185- oldCommitID : shas [ 0 ] ,
186- newCommitID : shas [ 1 ] ,
125+ refName : refFull ,
126+ oldCommitID : oldOID ,
127+ newCommitID : newOID ,
187128 })
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
189133 default :
190- log .Warn ("parseRemoteUpdateOutput: unexpected update line %q" , lines [ i ] )
134+ log .Warn ("parseFetchPorcelain: unknown flag %q on %q" , flag , line )
191135 }
192136 }
193137 return results
@@ -260,7 +204,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
260204 if m .EnablePrune {
261205 cmd .AddArguments ("--prune" )
262206 }
263- cmd .AddArguments ("--tags" ).AddDynamicArguments (m .GetRemoteName ())
207+ cmd .AddArguments ("--tags" , "--porcelain" , "--no-progress" ).AddDynamicArguments (m .GetRemoteName ())
264208
265209 remoteURL , remoteErr := gitrepo .GitRemoteGetURL (ctx , m .Repo , m .GetRemoteName ())
266210 if remoteErr != nil {
@@ -324,7 +268,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
324268 return nil , false
325269 }
326270 }
327- output := stderrBuilder .String ()
271+ output := stdoutBuilder .String ()
328272
329273 if err := git .WriteCommitGraph (ctx , repoPath ); err != nil {
330274 log .Error ("SyncMirrors [repo: %-v]: %v" , m .Repo , err )
@@ -426,7 +370,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
426370 }
427371
428372 m .UpdatedUnix = timeutil .TimeStampNow ()
429- return parseRemoteUpdateOutput (output , m . GetRemoteName () ), true
373+ return parseFetchPorcelain (output ), true
430374}
431375
432376func getRepoPullMirrorLockKey (repoID int64 ) string {
0 commit comments