0

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.

  • Did you squash P1-P5 into the single commit M50? You say "merged to master" and then you say "squashed". Please explain exactly what happened to P1-P5 in relation to master. – Lasse V. Karlsen Nov 12 '21 at 09:59
  • @LasseV.Karlsen I first rebased the commits P1-P5 on top of M50 and while rebasing I picked commit P5 and squashed commits P1-P4. I did push force with lease to get my branch on top of M50. There were no conflicts while doing this. I then merged the branch to master. – Trilokinath Modi Nov 12 '21 at 10:13

2 Answers2

0

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.

Andreas Louv
  • 46,145
  • 13
  • 104
  • 123
  • Rebasing P2 on M60, is it because P2 is the immediate ancestor of C1? And you assumed I am currently at C5. On other way can this be achieved by rebasing onto with 3 arguments right if I am not at C5? I am asking this because I was pointing to P5 and I have rebased P1-P5 on top of M50 and that rebase didn't include C1-C5. And now if I am pointing at C5 and do a rebase onto M60 P2 then it considers C1-C5 as well. Please correct me if I said something wrong here. – Trilokinath Modi Nov 12 '21 at 10:23
  • I can try to explain you how `git rebase --onto` works, or you could spend the ten minutes required to read the documentation, as it will always be way better than what I can manage to explain. – Andreas Louv Nov 12 '21 at 10:27
0

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.

torek
  • 448,244
  • 59
  • 642
  • 775