question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

OK let’s break this down into tasks…

File: src/commands/merge.js pseudocode

import diff3 from 'node-diff3' // at least this exists
// find most recent common ancestor of ref a and ref b
let o = await findMergeBase(a, b)
// for each file, determine whether it is present or absent or modified (see http://gitlet.maryrosecook.com/docs/gitlet.html#section-217)
let diff = await findChangedFiles(a, o, b)
for (let file of diff) {
  // for simple cases of add, remove, or modify files
  updateMergeIndex(file);
  updateWorkTree(file);
  // for files that changed on both branches, compute the diff3.
  if (file.a !== file.o && file.b !== file.o && file.a !== file.b) {
    diff = await diff3(file.a, file.o, file.b)
    // If the diff3 merge was unsuccessful, mark the conflict
    if (diff.length > 1 || diff[0].conflict) {
      markConflictInIndex(file)
    }
    // regardless save the result to the work dir
    fs.writeFile(file.name, formatDiff3(diff))
  }
}

Tasks:

  • implement findMergeBase(a, b)
  • ~implement findChangedFiles(a, o, b)~
  • ~implement updateMergeIndex(file)~
  • ~implement updateWorkTree(file)~
  • ~implement markConflictInIndex(file)~
  • ~implement formatDiff3(diff)~
  • implement mergeTree(a, o, b)
  • implement mergeFile(a, o, b)

copied and pasted from my work document:

This is trickier, and would involve implementing more of the merge in isomorphic-git. This would undoubtedly be a good thing for everyone who uses isomorphic-git, but it is a bit of a time commitment to do well.

Simple cases involving merges that don’t involve the same files should be doable in just a couple days. The algorithm is something like:

  1. Compute the nearest common ancestor of commit A and B, call it O. (This code already exists as findMergeBase)
  2. Compute two tree patches: O -> A and O -> B. (This algorithm should be very similar to that used in statusMatrix I think) Note: this should also be used to speed up and make checkout safer.
  3. Check that the two tree patches do not contain any operations that happen to the same file.
  4. If there are no operations on the same file, apply both patches to O and create a merge commit D whose parents are A and B.
  5. Move the current branch to point to D.
  6. Attempt to checkout the current branch.

We need a datastructure for storing tree patches. I propose something like:

const patches = [
  {filepath: 'TODO.MD', op: 'rm', before: 'f4c8920', after: null},
  {filepath: 'TODO.md', op: 'write', before: null, after: 'ec63514'},
  {filepath: 'lib', op: 'mkdir', before: null, after: 'he3414c'},
  {filepath: 'lib/app.rb', op: 'write', before: null, after: '00750ed'},
]

Including before oids makes it possible to safely detect if files have changed between the time the patch is computed and the time the patch is performed. For instance, a “safe delete with rollback” might consist of:

  • create a temporary directory ‘tmp’
  • move <file> to tmp/<before> (e.g. mv ‘TODO.MD’ to ‘tmp/f4c8920…’)
  • compute the SHA of tmp/<before> and make sure it matches before.
  • if not, move the file back and trigger a rollback.
  • if so, delete tmp/<before>

The after oids should simply be written to the indicated filepath. For directories, I guess the tree oid could be computed and verified afterwards, but if all the file oids match it should be correct.

Edit: So… actually most of that is not needed. There’s no need to compute two “tree patches” for O -> A and O -> B. There’s no need to merge the patches or apply patches. In the end I just merged the commits in a single call to walkBeta1.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:4
  • Comments:13 (10 by maintainers)

github_iconTop GitHub Comments

3reactions
wmhiltoncommented, May 20, 2019

I’d love to! I just haven’t had time to work on it. 😞

3reactions
wmhiltoncommented, Mar 5, 2018

Status update

v0.9.0 features preliminary support for fast-forward merges and a “pull” command! https://isomorphic-git.github.io/docs/pull.html This should greatly simplify workflows that consist of mostly “clone” and “pull” commands.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Git - git-merge Documentation
Incorporates changes from the named commits (since the time their histories diverged from the current branch) into the current branch. This command is...
Read more >
Git Merge | Atlassian Git Tutorial
Merging is Git's way of putting a forked history back together again. The git merge command lets you take the independent lines of...
Read more >
git merge - Integrating changes from another branch
The "merge" command is used to integrate changes from another branch. ; Creates a merge commit even when a fast-forward would be possible....
Read more >
Git Branch Merge
We have the emergency fix ready, and so let's merge the master and emergency-fix branches. First, we need to change to the master...
Read more >
How To Combine Branches With Git Merge
The git merge command integrates the commit histories and moves the master branch's pointer forward to the form branch. ## Switch to the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found