Home > Enterprise >  Which commit should I pick to resolve merge conflicts when I rebase a branch to the latest commit in
Which commit should I pick to resolve merge conflicts when I rebase a branch to the latest commit in

Time:11-13

I am using beyond compare to resolve merge conflicts and git extensions to execute git commands. My scenario is something like this. The annotation used is M for Master commits, P for parent branch commits and C for child branch commits.

M1 -- M2 -- M3 -- M4 -- ......... -- M50 ...... M60
       \                            /          /
        \                          /          /
         P1 -- P2 -- P3 -- P4 -- P5          /
                \                           /
                 \                         /
                  C1 -- C2 -- C3 -- C4 -- C5

Parent branch P5 has been merged to master, all commits in parent branch were squashed except one commit and after merge the parent branch was deleted too. I believe this hasn't affected the child branch. My development in child branch is complete and I want to rebase the child branch with current commit at master(M60). There are merge conflicts because commits in branch P and commits in branch C were developed on same files(DaVinci, C, C#, xml's).

On rebasing C branch on top of M60, I believe I am doing something like this.

M1 -- ... -- M50 -- ..... M60
                             \
                              \
                               C1 -- C2 -- C3 -- C4 -- C5

The problem with my scenario is solving merge conflicts. The C, xml and C# files are not a problem but DaVinci updates many key(some unique value at multiple spots) everytime I save the workspace in DaVinci, so such changes are present in multiple commits in C branch. I am using beyond compare to solve merge conflicts and it appears as if I am spending more time to solve merge conflicts as compared to creating a new branch at M60 and redo the work in DaVinci(as I know what needs to be done now).

Is it possible to resolve merge conflicts on just the final version of the file in the branch instead of resolving conflict commit by commit? (P.S. I donot need commit history)

Please suggest if you have any better idea.

CodePudding user response:

Take a look at git rebase --onto (git help rebase):

Something like this might work for you:

git rebase --onto M60 P2

Assuming you are currently on the C5 commit.

This will essentially apply the commits C1 trough C5 on M60 on at the time, and let you resolve any conflicts along the way.

When you have done this, then you can merge the new C5 into master, either by fast forwarding or not.

CodePudding user response:

Is it possible to resolve merge conflicts on just the final version of the file in the branch instead of resolving conflict commit by commit?

No—but there is a shortcut. In fact, there are multiple possible shortcuts; which one to use depends on what you really need.

Let me copy your original diagrams (with one small change), and assume that you are correctly doing what you want using git rebase --onto:

M1 -- M2 -- M3 -- M4 -- ......... -- M50 ...... M60   <-- master
       \                            /
        \                          /
         P1 -- P2 -- P3 -- P4 -- P5
                \
                 \
                  C1 -- C2 -- C3 -- C4 -- C5   <-- branch

[is to become]

M1 -- ... -- M50 -- ..... M60   <-- master
                             \
                              \
                               C1 -- C2 -- C3 -- C4 -- C5   <-- branch

(the real change here is to note that commit C5 is not already merged to master at commit M60—if it were, we'd need to remove commit M60!).

Now, the actual error in this drawing is that C1 through C5 literally cannot be changed. So they will remain in the repository for some time, but will go unused. The new commits will have some new and different hash ID:

M1 -- ... -- M50 -- ..... M60   <-- master
                             \
                              \
                               C1'--C2'--C3'--C4'--C5'  <-- branch

Your job as you run git rebase --onto master P2 or similar here is to produce each of these new commits.

Each commit, in Git, contains:

  • a full snapshot of every file, plus
  • metadata.

That full snapshot is whatever you choose it to be. That includes these autogenerated keys:

... The C, xml and C# files are not a problem but DaVinci updates many key (some unique value at multiple spots) every time I save the workspace in DaVinci, ...

If these generated keys are required—if they have to be in the commits—then you must generate them.

If you can just use the final keys in each of the intermediate commits, that's one shortcut: generate the keys once, and then copy-paste them into place with some sort of automatic device. It's up to you to come up with the appropriate automatic device; once you do, you have a shortcut: generate the final keys and use this device (probably a simple program, maybe a sed script for instance).

If you can commit the files shorn of the keys, that's an even better solution. Don't allow these autogenerated keys to enter the Git-ized copies of any file ever, and then they will never conflict during rebases, merges, or any other Git operations.

Presumably, though, these keys have some purpose, and you need them when you actually go to build. This is what Git's clean and smudge filters are for.

These filters are something you impose between your working tree and Git. You must write them, but perhaps your existing key-generating software is already suitable and therefore your "smudge" filter will consist of "invoke the key-generating software".

The task for the clean filter is to remove autogenerated junk. It simply needs to replace any autogenerated text with nothing (if possible) or a suitable, but constant, placeholder (if appropriate). This way Git sees only the placeholder, or even nothing at all.

The task for the smudge filter is to take a cleaned file—one shorn of cruft, perhaps having placeholders—and put in the necessary cruft, perhaps by replacing the placeholders.

Since the various file-extraction commands—git checkout, git switch, git reset --hard, git restore, and the like—will run your smudge filter automatically, this will put the cruft into the files as you work on/with them. Since git add will run you clean filter automatically, this will remove the cruft from the files that Git sees. Git therefore never sees any of the autogenerated text, which means it never interferes with using Git.

This does not work for every system, but might work for yours. To see how to write clean and smudge filters, read the gitattributes documentation.

  • Related