Version Control Hacking for a Kind of Forward Compatibility

54 views Asked by At

(First paragraph is just context that may or may not be useful for the actual question(s).) I'm working on an application with a complex document format and a lot of weird legacy issues. We're interested in transitioning to a new format that's designed to play nicely with Git (and potentially other VCSs). We are developing custom diff and merge drivers for our format.

I think I've stumbled on a neat way to support a kind of forward compatibility, and I'm curious if anyone knows about this existing in the world already.

Let's say Alice is working on a project in version 73, and she wants to hire Bob, a contractor, to help with the project, but he only has version 67 of the software. I think a VCS workflow like the following sketch could make it reasonably convenient for them to collaborate.

        E---F---G---K        "downgraded" branch
       /             \
      /---------------L      "re-upgrade" commit
     /                 \
A---B----C----D----H----J-   trunk

Alice explicitly makes commit E to downgrade from 73 to 67; this probably involves removing some data and other format changes. Bob and Alice work concurrently for a while. Bob finishes with commit K and then Alice re-upgrades the downgraded branch by running a weird merge with the following inputs:

  • Ours - B
  • Theirs - K
  • Base - E

This produces commit L in the diagram, which can then be merged back in using a vanilla merge or rebase or whatever.

Does this make any sense to anyone else? What would be the cleanest way to implement it in Git? I'm imagining some kind of cherry-pick, but if Bob's branch has some complicated internal branching/history hacking, I'm not sure if that's right. What I think I'm trying to get out of Git is just a delta between Bob's last commit (K) and the original downgraded commit (E), then applying this delta to the pre-downgrade commit (B)

1

There are 1 answers

5
IMSoP On

I think the closest to what you're looking for here is a "rebase": take somebody's changes, and re-apply them in a new context.

If we take as our starting point the branch with the "downgrade commit" E at the start of it, plus another branch which doesn't have that:

        E---F---G---K  <--  "downgraded" branch
       /                
A----B----C----D----H   <--  trunk

In git, a "rebase" allows us to create a new branch with just the changes from F, G, and K on top of the new base H:

        E---F---G---K  <--  "downgraded" branch
       /                
A----B----C----D----H   <--  trunk
                     \
                      F2---G2---K2   <-- rebased changes

In git, this would be something like git rebase F K --onto H, or could be achieved with an interactive rebase by deleting the todo line for commit E.

Alternatively, you can rebase onto the base B, and then perform a normal merge:

        E---F---G---K  <--  "downgraded" branch
       /                
A----B----C----D----H---M   <--  trunk
      \                /
       F2---G2---K2---+  <-- rebased changes

The key either way is that you want commit E not to be in the final history. This is somewhat cleaner than the even simpler solution, which is simply to revert commit E (reverse the changes it made, creating a new commit "ER") at the end of the process, and then merge from there:

        E---F---G---K---ER---+
       /                      \
A----B----C----D----H----------M   <--  trunk