diff --git a/pygit2/index.py b/pygit2/index.py
index b1096056..8f7bb0a9 100644
--- a/pygit2/index.py
+++ b/pygit2/index.py
@@ -23,8 +23,10 @@
 # the Free Software Foundation, 51 Franklin Street, Fifth Floor,
 # Boston, MA 02110-1301, USA.
 
+import typing
 import warnings
 import weakref
+from dataclasses import dataclass
 
 # Import from pygit2
 from ._pygit2 import Oid, Tree, Diff
@@ -349,6 +351,46 @@ def conflicts(self):
         return self._conflicts()
 
 
+@dataclass
+class MergeFileResult:
+    automergeable: bool
+    'True if the output was automerged, false if the output contains conflict markers'
+
+    path: typing.Union[str, None]
+    'The path that the resultant merge file should use, or None if a filename conflict would occur'
+
+    mode: FileMode
+    'The mode that the resultant merge file should use'
+
+    contents: str
+    'Contents of the file, which might include conflict markers'
+
+    def __repr__(self):
+        t = type(self)
+        contents = (
+            self.contents if len(self.contents) <= 20 else f'{self.contents[:20]}...'
+        )
+        return (
+            f'<{t.__module__}.{t.__qualname__} "'
+            f'automergeable={self.automergeable} "'
+            f'path={self.path} '
+            f'mode={self.mode} '
+            f'contents={contents}>'
+        )
+
+    @classmethod
+    def _from_c(cls, centry):
+        if centry == ffi.NULL:
+            return None
+
+        automergeable = centry.automergeable != 0
+        path = to_str(ffi.string(centry.path)) if centry.path else None
+        mode = FileMode(centry.mode)
+        contents = ffi.string(centry.ptr, centry.len).decode('utf-8')
+
+        return MergeFileResult(automergeable, path, mode, contents)
+
+
 class IndexEntry:
     path: str
     'The path of this entry'
diff --git a/pygit2/repository.py b/pygit2/repository.py
index 34712bb3..37a6d2c5 100644
--- a/pygit2/repository.py
+++ b/pygit2/repository.py
@@ -56,7 +56,7 @@
 )
 from .errors import check_error
 from .ffi import ffi, C
-from .index import Index, IndexEntry
+from .index import Index, IndexEntry, MergeFileResult
 from .packbuilder import PackBuilder
 from .references import References
 from .remotes import RemoteCollection
@@ -682,9 +682,13 @@ def merge_file_from_index(
         ancestor: typing.Union[None, IndexEntry],
         ours: typing.Union[None, IndexEntry],
         theirs: typing.Union[None, IndexEntry],
-    ) -> str:
-        """Merge files from index. Return a string with the merge result
-        containing possible conflicts.
+        use_deprecated: bool = True,
+    ) -> typing.Union[str, typing.Union[MergeFileResult, None]]:
+        """Merge files from index.
+
+        Returns: A string with the content of the file containing
+        possible conflicts if use_deprecated==True.
+        If use_deprecated==False then it returns an instance of MergeFileResult.
 
         ancestor
             The index entry which will be used as a common
@@ -693,6 +697,10 @@ def merge_file_from_index(
             The index entry to take as "ours" or base.
         theirs
             The index entry which will be merged into "ours"
+        use_deprecated
+            This controls what will be returned. If use_deprecated==True (default),
+            a string with the contents of the file will be returned.
+            An instance of MergeFileResult will be returned otherwise.
         """
         cmergeresult = ffi.new('git_merge_file_result *')
 
@@ -709,10 +717,19 @@ def merge_file_from_index(
         )
         check_error(err)
 
-        ret = ffi.string(cmergeresult.ptr, cmergeresult.len).decode('utf-8')
+        mergeFileResult = MergeFileResult._from_c(cmergeresult)
         C.git_merge_file_result_free(cmergeresult)
 
-        return ret
+        if use_deprecated:
+            warnings.warn(
+                'Getting an str from Repository.merge_file_from_index is deprecated. '
+                'The method will later return an instance of MergeFileResult by default, instead. '
+                'Check parameter use_deprecated.',
+                DeprecationWarning,
+            )
+            return mergeFileResult.contents if mergeFileResult else ''
+
+        return mergeFileResult
 
     def merge_commits(
         self,
diff --git a/test/test_repository.py b/test/test_repository.py
index d8c8efa1..d48aa7ac 100644
--- a/test/test_repository.py
+++ b/test/test_repository.py
@@ -31,7 +31,7 @@
 
 # pygit2
 import pygit2
-from pygit2 import init_repository, clone_repository, discover_repository
+from pygit2 import init_repository, clone_repository, discover_repository, IndexEntry
 from pygit2 import Oid
 from pygit2.enums import (
     CheckoutNotify,
@@ -42,7 +42,9 @@
     RepositoryState,
     ResetMode,
     StashApplyProgress,
+    FileMode,
 )
+from pygit2.index import MergeFileResult
 from . import utils
 
 
@@ -985,3 +987,144 @@ def test_repository_hashfile_filter(testrepo):
     testrepo.config['core.safecrlf'] = 'fail'
     with pytest.raises(pygit2.GitError):
         h = testrepo.hashfile('hello.txt')
+
+
+def test_merge_file_from_index_deprecated(testrepo):
+    hello_txt = testrepo.index['hello.txt']
+    hello_txt_executable = IndexEntry(
+        hello_txt.path, hello_txt.id, FileMode.BLOB_EXECUTABLE
+    )
+    hello_world = IndexEntry('hello_world.txt', hello_txt.id, hello_txt.mode)
+
+    # no change
+    res = testrepo.merge_file_from_index(hello_txt, hello_txt, hello_txt)
+    assert res == testrepo.get(hello_txt.id).data.decode()
+
+    # executable switch on ours
+    res = testrepo.merge_file_from_index(hello_txt, hello_txt_executable, hello_txt)
+    assert res == testrepo.get(hello_txt.id).data.decode()
+
+    # executable switch on theirs
+    res = testrepo.merge_file_from_index(hello_txt, hello_txt, hello_txt_executable)
+    assert res == testrepo.get(hello_txt.id).data.decode()
+
+    # executable switch on both
+    res = testrepo.merge_file_from_index(
+        hello_txt, hello_txt_executable, hello_txt_executable
+    )
+    assert res == testrepo.get(hello_txt.id).data.decode()
+
+    # path switch on ours
+    res = testrepo.merge_file_from_index(hello_txt, hello_world, hello_txt)
+    assert res == testrepo.get(hello_txt.id).data.decode()
+
+    # path switch on theirs
+    res = testrepo.merge_file_from_index(hello_txt, hello_txt, hello_world)
+    assert res == testrepo.get(hello_txt.id).data.decode()
+
+    # path switch on both
+    res = testrepo.merge_file_from_index(hello_txt, hello_world, hello_world)
+    assert res == testrepo.get(hello_txt.id).data.decode()
+
+    # path switch on ours, executable flag switch on theirs
+    res = testrepo.merge_file_from_index(hello_txt, hello_world, hello_txt_executable)
+    assert res == testrepo.get(hello_txt.id).data.decode()
+
+    # path switch on theirs, executable flag switch on ours
+    res = testrepo.merge_file_from_index(hello_txt, hello_txt_executable, hello_world)
+    assert res == testrepo.get(hello_txt.id).data.decode()
+
+
+def test_merge_file_from_index_non_deprecated(testrepo):
+    hello_txt = testrepo.index['hello.txt']
+    hello_txt_executable = IndexEntry(
+        hello_txt.path, hello_txt.id, FileMode.BLOB_EXECUTABLE
+    )
+    hello_world = IndexEntry('hello_world.txt', hello_txt.id, hello_txt.mode)
+
+    # no change
+    res = testrepo.merge_file_from_index(
+        hello_txt, hello_txt, hello_txt, use_deprecated=False
+    )
+    assert res == MergeFileResult(
+        True, hello_txt.path, hello_txt.mode, testrepo.get(hello_txt.id).data.decode()
+    )
+
+    # executable switch on ours
+    res = testrepo.merge_file_from_index(
+        hello_txt, hello_txt_executable, hello_txt, use_deprecated=False
+    )
+    assert res == MergeFileResult(
+        True,
+        hello_txt.path,
+        hello_txt_executable.mode,
+        testrepo.get(hello_txt.id).data.decode(),
+    )
+
+    # executable switch on theirs
+    res = testrepo.merge_file_from_index(
+        hello_txt, hello_txt, hello_txt_executable, use_deprecated=False
+    )
+    assert res == MergeFileResult(
+        True,
+        hello_txt.path,
+        hello_txt_executable.mode,
+        testrepo.get(hello_txt.id).data.decode(),
+    )
+
+    # executable switch on both
+    res = testrepo.merge_file_from_index(
+        hello_txt, hello_txt_executable, hello_txt_executable, use_deprecated=False
+    )
+    assert res == MergeFileResult(
+        True,
+        hello_txt.path,
+        hello_txt_executable.mode,
+        testrepo.get(hello_txt.id).data.decode(),
+    )
+
+    # path switch on ours
+    res = testrepo.merge_file_from_index(
+        hello_txt, hello_world, hello_txt, use_deprecated=False
+    )
+    assert res == MergeFileResult(
+        True, hello_world.path, hello_txt.mode, testrepo.get(hello_txt.id).data.decode()
+    )
+
+    # path switch on theirs
+    res = testrepo.merge_file_from_index(
+        hello_txt, hello_txt, hello_world, use_deprecated=False
+    )
+    assert res == MergeFileResult(
+        True, hello_world.path, hello_txt.mode, testrepo.get(hello_txt.id).data.decode()
+    )
+
+    # path switch on both
+    res = testrepo.merge_file_from_index(
+        hello_txt, hello_world, hello_world, use_deprecated=False
+    )
+    assert res == MergeFileResult(
+        True, None, hello_txt.mode, testrepo.get(hello_txt.id).data.decode()
+    )
+
+    # path switch on ours, executable flag switch on theirs
+    res = testrepo.merge_file_from_index(
+        hello_txt, hello_world, hello_txt_executable, use_deprecated=False
+    )
+    assert res == MergeFileResult(
+        True,
+        hello_world.path,
+        hello_txt_executable.mode,
+        testrepo.get(hello_txt.id).data.decode(),
+    )
+
+    # path switch on theirs, executable flag switch on ours
+    res = testrepo.merge_file_from_index(
+        hello_txt, hello_txt_executable, hello_world, use_deprecated=False
+    )
+    assert res == MergeFileResult(
+        True,
+        hello_world.path,
+        hello_txt_executable.mode,
+        testrepo.get(hello_txt.id).data.decode(),
+    )