@@ -987,6 +987,7 @@ pub struct Repository {
987987 pub default_branch : String ,
988988 #[ serde( default ) ]
989989 pub fork : bool ,
990+ pub parent : Option < Box < Repository > > ,
990991}
991992
992993#[ derive( Copy , Clone ) ]
@@ -1485,16 +1486,66 @@ impl Repository {
14851486 }
14861487
14871488 /// 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.
14881491 pub async fn merge_upstream ( & self , client : & GithubClient , branch : & str ) -> anyhow:: Result < ( ) > {
14891492 let url = format ! ( "{}/merge-upstream" , self . url( ) ) ;
1490- client
1493+ let merge_error = match client
14911494 . send_req ( client. post ( & url) . json ( & serde_json:: json!( {
14921495 "branch" : branch,
14931496 } ) ) )
14941497 . 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
14951546 . with_context ( || {
14961547 format ! (
1497- "{} failed to merge upstream branch {branch }" ,
1548+ "failed to force update { branch} to {sha} for { }" ,
14981549 self . full_name
14991550 )
15001551 } ) ?;
0 commit comments