- parent = kwargs['parent']
- if not isinstance(parent, Change):
- parent = Change.objects.get(pk=kwargs['parent'])
-
- if 'patch' not in kwargs:
- if 'text' not in kwargs:
- raise ValueError("You must provide either patch or target document.")
- patch = Change.make_patch(self.materialize(change=parent), kwargs['text'])
+ return parent_ca
+
+ if parent_ca is None or parent_ca.created_at < merge_parent_ca.created_at:
+ return merge_parent_ca
+
+ return parent_ca
+
+ def get_ancestors(self):
+ revs = set()
+ if self.parent is not None:
+ revs.add(self.parent)
+ revs.update(self.parent.get_ancestors())
+ if self.merge_parent is not None:
+ revs.add(self.merge_parent)
+ revs.update(self.merge_parent.get_ancestors())
+ return revs
+
+
+@python_2_unicode_compatible
+class Ref(models.Model):
+ """A reference pointing to a specific revision."""
+
+ revision = models.ForeignKey(
+ Revision, null=True, blank=True, default=None, verbose_name=_('revision'),
+ help_text=_("The document's revision."), editable=False)
+
+ def __str__(self):
+ return "ref:{0}->rev:{1}".format(self.id, self.revision_id)
+
+ def merge_text(self, base, local, remote):
+ """Override in subclass to have different kinds of merges."""
+ files = []
+ for f in local, base, remote:
+ temp = NamedTemporaryFile(delete=False)
+ temp.write(f)
+ temp.close()
+ files.append(temp.name)
+ p = Popen(['/usr/bin/diff3', '-mE', '-L', 'old', '-L', '', '-L', 'new'] + files, stdout=PIPE)
+ result, errs = p.communicate()
+
+ for f in files:
+ os.unlink(f)
+ return result.decode('utf-8')
+
+ def merge_with(self, revision, author=None, author_name=None, author_email=None, description="Automatic merge."):
+ """Merges a given revision into the ref."""
+ if self.revision is None:
+ fast_forward = True
+ self.revision = revision
+ elif self.revision.pk == revision.pk or self.revision.is_descendant_of(revision):
+ # Already merged.
+ return
+ elif revision.is_descendant_of(self.revision):
+ # Fast forward.
+ fast_forward = True
+ self.revision = revision