mhagger / git-imerge

Incremental merge for git
GNU General Public License v2.0
2.68k stars 126 forks source link

Automate ability to extend merge when source branches are updated #198

Closed jrosenberger closed 1 year ago

jrosenberger commented 1 year ago

I've just completed my first merge with imerge, and it was awesome. However, the merge took a while because of needing conflict resolutions from coworkers in other timezones. One of the two branches has had 27 commits added in the intervening time. I'd like to be able to re-use the already completed merges in creating a new merge.

In other words, looking at the existing merge in 'git imerge diagram' output, extend the x axis 27 more commits to the right, and run 'git imerge continue' Is there a way to do this that I missed? I may attempt to do it manually first by hacking on the refs, and then dive in to the code.

mhagger commented 1 year ago

@jrosenberger: if the first merge had instead used full, rebase-with-history, or border-with-history then I think one could just start a second imerge and it would work incrementally. But the finish step of an incremental merge throws away a bunch of the information that would be helpful for continuing incrementally.

You could still do an incremental merge of the last 27 commits onto the merge commit resulting from the previous imerge, but that will only be incremental along the x-axis, not along the y-axis (roughly equivalent to a git rebase).

If you haven't done the finish yet, you could still run git imerge finish with a --goal option, then you could probably do the second merge incrementally, as described above. Then you'd probably have to create the desired merge commit by hand (e.g., using git imerge reparent) if that's the result that you want. If you decide to try this, I recommend making a copy of your repository before running git imerge finish so that you can experiment with variations.

It would be nice if git imerge had support for extending or truncating incremental merges after they've been started, but I never built that.

Good luck and let us know how it works out!

jrosenberger commented 1 year ago

It would be nice if git imerge had support for extending or truncating incremental merges after they've been started, but I never built that.

That's exactly what I'm proposing with this issue.

I have a copy of the merge in progress, because I pushed the refs to a remote in order for a coworker to provide a conflict resolution. I tried simply filling in the new merge by copying the refs in auto from the old merge to the new, but it didn't work, so there was some understanding missing.

It seems like, as long as the imerge refs haven't been deleted, refs/MERGE/auto/ and refs/MERGE/manual/ should have everything needed to auto-fill a new merge, and pick up from there. Is there a reason that, given MERGE is done, but finish / remove hasn't yet been called that starting a new merge of the same branches and then doing:

cp .git/refs/MERGE/auto/* .git/refs/NEWMERGE/auto
cp .git/refs/MERGE/manual/* .git/refs/NEWMERGE/manual
git imerge continue

Do you have a reason this shouldn't work?

Where I'd like to get to is a command like:

git imerge extend [--source [BRANCH]] [--target BRANCH]
options:
--source [BRANCH]: extend the in progress merge to include commits subsequently added to the original source branch, or commits on BRANCH, which must be a fast forward of the original source branch.
--target [BRANCH]: extend the in-progress merge to include commits subsequently added to the original target branch, or change the target to BRANCH (which must be a FF of the original target) and add its subsequent commits.

Is there any kind of documentation aimed at someone wanting to learn the code of imerge and how to modify/extend it anywhere, like a conference talk about the internals or something? I'm an embedded C guy, so just diving in to a python program by reading the code is non-trivial.

jrosenberger commented 1 year ago

So, I just did a manual experiment which was successful.
Starting from a state where a merge was complete, but none of simplify/finish/delete had yet been called. I did a git imerge init with the same branches but a new name Then I simply did:

cp .git/refs/imerge/NEWNAME/manual/* .git/refs/imerge/OLDNAME/manual
git imerge continue --name OLDNAME

This picked up where I left off in OLDNAME and let me finish the merge.

Writing this in to imerge itself and only creating the new manual commits seems pretty straightforward. I hope to open a PR next week.