• 
      

    Update Mercurial to support multi-commit patches via the new Patcher API.

    Review Request #14239 — Created Nov. 10, 2024 and submitted

    Information

    RBTools
    release-5.x

    Reviewers

    Mercurial has some restrictions on how patches may be applied. Unlike
    Git, Subversion, etc., hg import will not apply a patch if there are
    changes in the working directory. This means that a group of patches
    must be applied in one go, and not one-by-one. Our old patching model
    didn't allow for this level of control, and this was the reason the new
    Patcher API was created.

    The Patcher API is now used to apply patches without commits, and with
    commits. It supports Git-style and Mercurial-style diffs.

    When applying patches without committing, we open all the patches and
    then pass their filenames directly to hg import, allowing it to apply
    them all without hitting the working directory changes error.

    When applying with committing, we use the standard Patcher logic to
    manage the patches, and then patch each patch using hg import
    individually. While hg import does support committing as part of the
    patch operation, we instead use our existing commit-creation
    functionality in order to utilize common logic and checks.

    Conflicts are tracked, as Mercurial uses the standard patch tool's
    output for conflict information. We apply using hg diff --partial,
    which will apply what changes it can while leaving the user responsible
    for applying the rest, keeping with the behavior in most other SCMs.

    Some notable limitations are that we can't revert or squash commits in
    Mercurial, and we generally don't have commit message or author
    information in the patches (requiring defaults to be used based on the
    review request). If applying Hg-style diffs, empty files won't be
    represented, so Git-style diffs are recommended.

    Squashing may be able to be resolved through further updates to RBTools
    (by applying and amending each commit in succession), but would require
    additional changes to the API for creating commits. We're leaving it off
    for now.

    There may be some other peculiarities of Mercurial's patching, and this
    will likely need some changes based on usage in production.

    Unit tests passed.

    Summary ID
    Update Mercurial to support multi-commit patches via the new Patcher API.
    Mercurial has some restrictions on how patches may be applied. Unlike Git, Subversion, etc., `hg import` will not apply a patch if there are changes in the working directory. This means that a group of patches must be applied in one go, and not one-by-one. Our old patching model didn't allow for this level of control, and this was the reason the new Patcher API was created. The Patcher API is now used to apply patches without commits, and with commits. It supports Git-style and Mercurial-style diffs. When applying patches without committing, we open all the patches and then pass their filenames directly to `hg import`, allowing it to apply them all without hitting the working directory changes error. When applying with committing, we use the standard Patcher logic to manage the patches, and then patch each patch using `hg import` individually. While `hg import` does support committing as part of the patch operation, we instead use our existing commit-creation functionality in order to utilize common logic and checks. Conflicts are tracked, as Mercurial uses the standard patch tool's output for conflict information. We apply using `hg diff --partial`, which will apply what changes it can while leaving the user responsible for applying the rest, keeping with the behavior in most other SCMs. Some notable limitations are that we can't revert or squash commits in Mercurial, and we generally don't have commit message or author information in the patches (requiring defaults to be used based on the review request). If applying Hg-style diffs, empty files won't be represented, so Git-style diffs are recommended. Squashing may be able to be resolved through further updates to RBTools (by applying and amending each commit in succession), but would require additional changes to the API for creating commits. We're leaving it off for now. There may be some other peculiarities of Mercurial's patching, and this will likely need some changes based on usage in production.
    6d3b736fefac72c4f5d8a0ee166f97ea780a46ff
    Description From Last Updated

    svn patch -> hg patch

    daviddavid

    if -> If

    daviddavid

    hg import is the real command, patch is just an alias. Help: import

    brenniebrennie

    Missing docs.

    maubinmaubin
    david
    1. 
        
    2. rbtools/clients/mercurial.py (Diff revision 1)
       
       
      Show all issues

      svn patch -> hg patch

    3. rbtools/clients/mercurial.py (Diff revision 1)
       
       
      Show all issues

      if -> If

    4. 
        
    brennie
    1. 
        
    2. You technically can squash hg commits. The rebase extension ships with Mercurial, but it is not enabled by default. However, you can enable it during a single hg invocation by doing hg --config extensions.rebase=.

      So you can squash the range a::b into a single commit based on c with hg --config extensions.rebase= rebase -r a::b -d c --collapse

      Rebase extension docs

      1. Is this safe for us to hard-code this support in there?

        So we'd need to apply individual commits and then rebase that range of commits, correct?

      2. Yes you would have to apply individual commits and then rebase at the end.

        Alternatively and probably more safe is to use commit --amend to apply subsequent commits, e.g.,

        hg import --no-commit /tmp/patch1.diff
        hg commit -m "message"
        hg import --no-commit /tmp/patch2.diff
        hg commit --amend
        hg import --no-commit /tmp/patch3.diff
        hg commit --amend
        

        Although it looks like hg import also supports supplying multiple patch files on the command line so you should be able to do

        hg import --no-commit /tmp/patch1.diff /tmp/patch2.diff /tmp/patch3.diff ...
        hg commit -m "message"
        
      3. Ah yeah that'd work. Worth considering, though it may skip 5.1 just due to scheduling and other work.

    3. 
        
    brennie
    1. 
        
    2. rbtools/clients/tests/test_mercurial.py (Diff revision 1)
       
       
      Show all issues

      hg import is the real command, patch is just an alias. Help: import

    3. 
        
    chipx86
    maubin
    1. 
        
    2. rbtools/clients/tests/test_mercurial.py (Diff revision 2)
       
       
      Show all issues

      Missing docs.

    3. 
        
    chipx86
    david
    1. Ship It!
    2. 
        
    maubin
    1. Ship It!
    2. 
        
    chipx86
    Review request changed
    Status:
    Completed
    Change Summary:
    Pushed to release-5.x (d5200e8)