@@ -235,7 +235,7 @@ func (c *Client) CommitAndPush(workspace *models.Workspace, result *models.Execu
235
235
return nil
236
236
}
237
237
238
- // PullLatestChanges 拉取远端最新代码
238
+ // PullLatestChanges 拉取远端最新代码(优先使用rebase策略)
239
239
func (c * Client ) PullLatestChanges (workspace * models.Workspace , pr * github.PullRequest ) error {
240
240
log .Infof ("Pulling latest changes for workspace: %s (PR #%d)" , workspace .Path , pr .GetNumber ())
241
241
@@ -255,90 +255,98 @@ func (c *Client) PullLatestChanges(workspace *models.Workspace, pr *github.PullR
255
255
256
256
log .Infof ("PR #%d: %s -> %s" , pr .GetNumber (), headBranch , baseBranch )
257
257
258
- // 1. 先尝试直接获取 PR 内容
259
- prNumber := pr .GetNumber ()
260
- log .Infof ("Attempting to fetch PR #%d content directly" , prNumber )
261
-
262
- cmd := exec .Command ("git" , "fetch" , "origin" , fmt .Sprintf ("pull/%d/head" , prNumber ))
258
+ // 1. 获取所有远程引用
259
+ cmd := exec .Command ("git" , "fetch" , "--all" , "--prune" )
263
260
cmd .Dir = workspace .Path
264
- prFetchOutput , err := cmd .CombinedOutput ()
261
+ fetchOutput , err := cmd .CombinedOutput ()
265
262
if err != nil {
266
- log .Warnf ("Failed to fetch PR #%d directly: %v, output: %s" , prNumber , err , string (prFetchOutput ))
263
+ return fmt .Errorf ("failed to fetch latest changes: %w\n Command output: %s" , err , string (fetchOutput ))
264
+ }
265
+ log .Infof ("Fetched all remote references for PR #%d" , pr .GetNumber ())
267
266
268
- // 2. 如果直接获取失败,fallback 到 rebase 方式
269
- log .Infof ("Falling back to rebase approach for PR #%d" , prNumber )
267
+ // 2. 检查当前是否有未提交的变更
268
+ cmd = exec .Command ("git" , "status" , "--porcelain" )
269
+ cmd .Dir = workspace .Path
270
+ statusOutput , err := cmd .Output ()
271
+ if err != nil {
272
+ return fmt .Errorf ("failed to check git status: %w" , err )
273
+ }
270
274
271
- // 获取所有远程仓库的最新代码
272
- cmd = exec .Command ("git" , "fetch" , "--all" )
275
+ hasChanges := strings .TrimSpace (string (statusOutput )) != ""
276
+ if hasChanges {
277
+ // 有未提交的变更,先 stash
278
+ log .Infof ("Found uncommitted changes in worktree, stashing them" )
279
+ cmd = exec .Command ("git" , "stash" , "push" , "-m" , fmt .Sprintf ("Auto stash before syncing PR #%d" , pr .GetNumber ()))
273
280
cmd .Dir = workspace .Path
274
- fetchOutput , err := cmd .CombinedOutput ()
281
+ stashOutput , err := cmd .CombinedOutput ()
275
282
if err != nil {
276
- return fmt . Errorf ( "failed to fetch latest changes: %w \n Command output: %s" , err , string (fetchOutput ))
283
+ log . Warnf ( "Failed to stash changes: %v, output: %s" , err , string (stashOutput ))
277
284
}
285
+ }
278
286
279
- // 尝试 rebase 到目标分支的最新代码
280
- cmd = exec .Command ("git" , "rebase" , fmt .Sprintf ("origin/%s" , baseBranch ))
287
+ // 3. 尝试直接获取 PR 内容
288
+ prNumber := pr .GetNumber ()
289
+ log .Infof ("Attempting to fetch PR #%d content directly" , prNumber )
290
+ cmd = exec .Command ("git" , "fetch" , "origin" , fmt .Sprintf ("pull/%d/head" , prNumber ))
291
+ cmd .Dir = workspace .Path
292
+ _ , err = cmd .CombinedOutput ()
293
+ if err == nil {
294
+ // 直接获取成功,使用rebase合并更新
295
+ log .Infof ("Successfully fetched PR #%d content, attempting rebase" , prNumber )
296
+ cmd = exec .Command ("git" , "rebase" , "FETCH_HEAD" )
281
297
cmd .Dir = workspace .Path
282
298
rebaseOutput , err := cmd .CombinedOutput ()
283
299
if err != nil {
284
- log .Errorf ("Rebase failed: %v, output: %s" , err , string (rebaseOutput ))
285
- return fmt .Errorf ("both direct fetch and rebase failed for PR #%d" , prNumber )
286
- }
287
-
288
- log .Infof ("Successfully rebased PR #%d onto %s" , pr .GetNumber (), baseBranch )
289
- } else {
290
- // 3. 直接获取成功,尝试合并 PR 内容
291
- log .Infof ("Successfully fetched PR #%d content, attempting to merge" , prNumber )
292
-
293
- // 检查当前是否有未提交的变更
294
- cmd = exec .Command ("git" , "status" , "--porcelain" )
295
- cmd .Dir = workspace .Path
296
- statusOutput , err := cmd .Output ()
297
- if err != nil {
298
- log .Warnf ("Failed to check git status: %v" , err )
299
- }
300
-
301
- if strings .TrimSpace (string (statusOutput )) != "" {
302
- // 有未提交的变更,先 stash
303
- log .Infof ("Found uncommitted changes, stashing them" )
304
- cmd = exec .Command ("git" , "stash" , "push" , "-m" , fmt .Sprintf ("Auto stash before syncing PR #%d" , prNumber ))
300
+ log .Warnf ("Rebase failed, trying reset: %v, output: %s" , err , string (rebaseOutput ))
301
+ // rebase失败,强制切换到PR内容
302
+ cmd = exec .Command ("git" , "reset" , "--hard" , "FETCH_HEAD" )
305
303
cmd .Dir = workspace .Path
306
- stashOutput , err := cmd .CombinedOutput ()
304
+ resetOutput , err := cmd .CombinedOutput ()
307
305
if err != nil {
308
- log . Warnf ( "Failed to stash changes : %v, output: %s" , err , string (stashOutput ))
306
+ return fmt . Errorf ( "failed to reset to PR #%d : %w \n Command output: %s" , prNumber , err , string (resetOutput ))
309
307
}
308
+ log .Infof ("Hard reset worktree to PR #%d content" , prNumber )
309
+ } else {
310
+ log .Infof ("Successfully rebased worktree to PR #%d content" , prNumber )
310
311
}
311
-
312
- // 尝试合并 PR 内容,而不是强制覆盖
313
- cmd = exec .Command ("git" , "merge" , "FETCH_HEAD" , "--no-edit" )
312
+ } else {
313
+ // 直接获取失败,使用传统rebase方式
314
+ log .Warnf ("Failed to fetch PR #%d directly: %v, falling back to traditional rebase" , prNumber , err )
315
+
316
+ // 尝试rebase到目标分支的最新代码
317
+ cmd = exec .Command ("git" , "rebase" , fmt .Sprintf ("origin/%s" , baseBranch ))
314
318
cmd .Dir = workspace .Path
315
- mergeOutput , err := cmd .CombinedOutput ()
319
+ rebaseOutput , err := cmd .CombinedOutput ()
316
320
if err != nil {
317
- log .Warnf ("Merge failed, trying reset: %v, output: %s" , err , string (mergeOutput ))
318
-
319
- // 合并失败,回退到强制切换(但先备份)
320
- cmd = exec .Command ("git" , "reset" , "--hard" , "HEAD" )
321
+ log .Warnf ("Rebase to base branch failed: %v, output: %s" , err , string (rebaseOutput ))
322
+ // rebase失败,尝试强制同步到基础分支
323
+ cmd = exec .Command ("git" , "reset" , "--hard" , fmt .Sprintf ("origin/%s" , baseBranch ))
321
324
cmd .Dir = workspace .Path
322
325
resetOutput , err := cmd .CombinedOutput ()
323
326
if err != nil {
324
- log .Warnf ("Failed to reset: %v, output: %s" , err , string (resetOutput ))
325
- }
326
-
327
- // 强制切换到 PR 内容
328
- cmd = exec .Command ("git" , "checkout" , "-B" , headBranch , "FETCH_HEAD" , "--force" )
329
- cmd .Dir = workspace .Path
330
- checkoutOutput , err := cmd .CombinedOutput ()
331
- if err != nil {
332
- return fmt .Errorf ("failed to checkout PR #%d: %w\n Command output: %s" , prNumber , err , string (checkoutOutput ))
327
+ return fmt .Errorf ("failed to reset to base branch %s: %w\n Command output: %s" , baseBranch , err , string (resetOutput ))
333
328
}
329
+ log .Infof ("Hard reset worktree to base branch %s" , baseBranch )
330
+ } else {
331
+ log .Infof ("Successfully rebased worktree to base branch %s" , baseBranch )
332
+ }
333
+ }
334
334
335
- log .Infof ("Successfully force synced to PR #%d content (after merge failure)" , prNumber )
335
+ // 4. 如果之前有stash,尝试恢复
336
+ if hasChanges {
337
+ log .Infof ("Attempting to restore stashed changes for PR #%d" , prNumber )
338
+ cmd = exec .Command ("git" , "stash" , "pop" )
339
+ cmd .Dir = workspace .Path
340
+ stashPopOutput , err := cmd .CombinedOutput ()
341
+ if err != nil {
342
+ log .Warnf ("Failed to restore stashed changes: %v, output: %s" , err , string (stashPopOutput ))
343
+ log .Infof ("You may need to manually resolve the stashed changes later" )
336
344
} else {
337
- log .Infof ("Successfully merged PR #%d content" , prNumber )
345
+ log .Infof ("Successfully restored stashed changes" )
338
346
}
339
347
}
340
348
341
- log .Infof ("Successfully pulled latest changes for PR #%d from remote repo: %s " , pr .GetNumber (), workspace . Repository )
349
+ log .Infof ("Successfully pulled latest changes for PR #%d using rebase strategy " , pr .GetNumber ())
342
350
return nil
343
351
}
344
352
0 commit comments