AndreasAugustin / actions-template-sync

:octocat: Github action for syncing other repositories (templates) with current repository. Any git provider like GitHub (enterprise), GitLab, Gittea,.. are supported for the source repository
https://andreasaugustin.github.io/actions-template-sync/
MIT License
219 stars 36 forks source link

[Feat]: Use three way merge #583

Open egulatee opened 6 hours ago

egulatee commented 6 hours ago

Describe the feature

Consider using a three way merge to update derived projects from a template.

Use Case

Context: A derived project that has modified files imported from a template. PRs opened to sync the template will suggest reverting changes back to the template's version.

This is particularly annoying if you are using the template to dictate flow (build, GitHub workflows) with derived projects making changes to suit their needs.
A sync with ANY change to the template will identify common files changed in the derived child as needing to be reverted.

Proposed Solution

Use a three way merge to identify whether the change was done in the derived project (Thus shouldn't be part of a PR) or in the template (Should be part of a PR).

Acknowledgements

AndreasAugustin commented 5 hours ago

Hi @egulatee and thanks for the feature request. There is actually the feature of ignoring changes with a .templatesyncignore file. This is working like a .gitignore file. Is this a way to handle your issue?

egulatee commented 5 hours ago

Hi @AndreasAugustin

Unfortunately not, I'm not looking to ignore files.

I've used three way merges in the past. I really don't know if you can identify the common ancestor between. (The template project at the time when it was initially spawned off or when the last merge happened I guess)

Basically I have files I am inheriting from my template project and intentionally making changes in my derived projects. I can edit the merge to remove them, but the more changes I have within a derived project to shared files, the more annoying it will become.

This would allow the sync to determine whether the changes originate from the template or the derived project.
If they are coming from the template then they should be included in the PR. (New changes in the template project) If they are coming from the derived project then they should not be included in the PR. (Someone made the change since the template and likely wants to keep the change from the derived project)

AndreasAugustin commented 4 hours ago

Hmm 🤔 possibly a change for the git remote pull params is a possible way to go? I can imaging using -X yours instead of using the default could work (if I got your description right).

At the moment I see the issue with merge conflicts. So somehow it needs to be decided which version to use in all cases. Do you have possibly an example or an idea of commands to use for your use case?

egulatee commented 4 hours ago

Yes, if someone makes changes to the same lines on both the template project and child project, there would be a conflict and the user would need to pick which set of changes to keep. (That's expected).

However if there's a change in the same file in different sections, it should be able to handle that and only include the template's changes in the PR.

RE: Example: I can create an example (It's as simple as changing a shared file in the child project, changing another unrelated file in the template project and then doing a sync with the template project)

RE: Commands to use: Let me have a look.

egulatee commented 4 hours ago

Git performs a three-way merge automatically when you use the git merge command and a fast-forward merge is not possible. Here's how it works: Basic Merge Command:

git checkout <target-branch> 
git merge <source-branch> 
target-branch: The branch you want to merge into.
source-branch: The branch you want to merge from.

Understanding Three-Way Merge: Git identifies the merge base, which is the most recent common ancestor of the two branches. It compares the merge base with the current branch (target) and the branch you're merging (source). Git combines changes from both branches into the target branch, resolving conflicts if necessary.

Screenshot 2024-11-01 at 7 49 52 PM
egulatee commented 4 hours ago

Given that there are two repositories. I'm not sure if there's a way to do a three way merge that way. Not sure if there's some way to identify which template project commit the derived project came from.

Screenshot 2024-11-01 at 7 57 27 PM
AndreasAugustin commented 4 hours ago

The issue I see here are how to handle merge conflicts within the automation. Imagine a conflict. How to solve it and commit and keep the conflict marker and show within the PR? Currently not sure if there is a way. Possibly an idea?

egulatee commented 4 hours ago

I've seen merge conflicts as having both changes in the file and the end user needs to manually edit/intervene. Not sure if that works with the automation. Perhaps a "setting" for three way merge for those two prefer the current behavior. Assuming this is even possible...

When you create a project from a template, does it keep track of the template project's commit it was spawned off of?

https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line

$ cat merge.txt
<<<<<<< HEAD
this is some content to mess with
content to append
=======
totally different content to merge later
>>>>>>> new_branch_to_merge_later