@@ -987,6 +987,7 @@ pub struct Repository {
987
987
pub default_branch : String ,
988
988
#[ serde( default ) ]
989
989
pub fork : bool ,
990
+ pub parent : Option < Box < Repository > > ,
990
991
}
991
992
992
993
#[ derive( Copy , Clone ) ]
@@ -1485,16 +1486,66 @@ impl Repository {
1485
1486
}
1486
1487
1487
1488
/// Synchronize a branch (in a forked repository) by pulling in its upstream contents.
1489
+ ///
1490
+ /// **Warning**: This will to a force update if there are conflicts.
1488
1491
pub async fn merge_upstream ( & self , client : & GithubClient , branch : & str ) -> anyhow:: Result < ( ) > {
1489
1492
let url = format ! ( "{}/merge-upstream" , self . url( ) ) ;
1490
- client
1493
+ let merge_error = match client
1491
1494
. send_req ( client. post ( & url) . json ( & serde_json:: json!( {
1492
1495
"branch" : branch,
1493
1496
} ) ) )
1494
1497
. await
1498
+ {
1499
+ Ok ( _) => return Ok ( ( ) ) ,
1500
+ Err ( e) => {
1501
+ if e. downcast_ref :: < reqwest:: Error > ( ) . map_or ( false , |e| {
1502
+ matches ! (
1503
+ e. status( ) ,
1504
+ Some ( StatusCode :: UNPROCESSABLE_ENTITY | StatusCode :: CONFLICT )
1505
+ )
1506
+ } ) {
1507
+ e
1508
+ } else {
1509
+ return Err ( e) ;
1510
+ }
1511
+ }
1512
+ } ;
1513
+ // 409 is a clear error that there is a merge conflict.
1514
+ // However, I don't understand how/why 422 might happen. The docs don't really say.
1515
+ // The gh cli falls back to trying to force a sync, so let's try that.
1516
+ log:: info!(
1517
+ "{} failed to merge upstream branch {branch}, trying force sync: {merge_error:?}" ,
1518
+ self . full_name
1519
+ ) ;
1520
+ let parent = self . parent . as_ref ( ) . ok_or_else ( || {
1521
+ anyhow:: anyhow!(
1522
+ "{} failed to merge upstream branch {branch}, \
1523
+ force sync could not determine parent",
1524
+ self . full_name
1525
+ )
1526
+ } ) ?;
1527
+ // Note: I'm not sure how to handle the case where the branch name
1528
+ // differs to the upstream. For example, if I create a branch off
1529
+ // master in my fork, somehow GitHub knows that my branch should push
1530
+ // to upstream/master (not upstream/my-branch-name). I can't find a
1531
+ // way to find that branch name. Perhaps GitHub assumes it is the
1532
+ // default branch if there is no matching branch name?
1533
+ let branch_ref = format ! ( "heads/{branch}" ) ;
1534
+ let latest_parent_commit = parent
1535
+ . get_reference ( client, & branch_ref)
1536
+ . await
1537
+ . with_context ( || {
1538
+ format ! (
1539
+ "failed to get head branch {branch} when merging upstream to {}" ,
1540
+ self . full_name
1541
+ )
1542
+ } ) ?;
1543
+ let sha = latest_parent_commit. object . sha ;
1544
+ self . update_reference ( client, & branch_ref, & sha)
1545
+ . await
1495
1546
. with_context ( || {
1496
1547
format ! (
1497
- "{} failed to merge upstream branch {branch }" ,
1548
+ "failed to force update { branch} to {sha} for { }" ,
1498
1549
self . full_name
1499
1550
)
1500
1551
} ) ?;
0 commit comments