Skip to content

Commit d344abf

Browse files
committed
Fix traverse_trees_recursive()
1 parent fe5fef9 commit d344abf

File tree

2 files changed

+73
-83
lines changed

2 files changed

+73
-83
lines changed

‎git/index/fun.py

+69-79
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
S_IFREG,
1414
S_IXUSR,
1515
)
16-
1716
import subprocess
1817

1918
from git.cmd import PROC_CREATIONFLAGS, handle_process_output
@@ -58,11 +57,7 @@
5857

5958
if TYPE_CHECKING:
6059
from .base import IndexFile
61-
from git.objects.fun import EntryTupOrNone
62-
63-
64-
def is_three_entry_list(inp) -> TypeGuard[List['EntryTupOrNone']]:
65-
return isinstance(inp, (tuple, list)) and len(inp) == 3
60+
# from git.objects.fun import EntryTupOrNone
6661

6762
# ------------------------------------------------------------------------------------
6863

@@ -192,16 +187,16 @@ def entry_key(*entry: Union[BaseIndexEntry, PathLike, int]) -> Tuple[PathLike, i
192187
""":return: Key suitable to be used for the index.entries dictionary
193188
:param entry: One instance of type BaseIndexEntry or the path and the stage"""
194189

195-
def is_entry_tuple(entry: Tuple) -> TypeGuard[Tuple[PathLike, int]]:
196-
return isinstance(entry, tuple) and len(entry) == 2
190+
def is_entry_key_tup(entry_key: Tuple) -> TypeGuard[Tuple[PathLike, int]]:
191+
return isinstance(entry_key, tuple) and len(entry_key) == 2
197192

198193
if len(entry) == 1:
199194
entry_first = entry[0]
200195
assert isinstance(entry_first, BaseIndexEntry)
201196
return (entry_first.path, entry_first.stage)
202197
else:
203198
# entry = tuple(entry)
204-
assert is_entry_tuple(entry)
199+
assert is_entry_key_tup(entry)
205200
return entry
206201
# END handle entry
207202

@@ -340,79 +335,74 @@ def aggressive_tree_merge(odb, tree_shas: Sequence[bytes]) -> List[BaseIndexEntr
340335
raise ValueError("Cannot handle %i trees at once" % len(tree_shas))
341336

342337
# three trees
343-
entries = traverse_trees_recursive(odb, tree_shas, '')
344-
base = entries[0]
345-
ours = entries[1]
346-
theirs = entries[2]
347-
assert is_three_entry_list(entries), f"{type(entries)=} and {len(entries)=}" # type:ignore
348-
349-
if base is not None:
350-
# base version exists
351-
if ours is not None:
352-
# ours exists
353-
if theirs is not None:
354-
# it exists in all branches, if it was changed in both
355-
# its a conflict, otherwise we take the changed version
356-
# This should be the most common branch, so it comes first
357-
if(base[0] != ours[0] and base[0] != theirs[0] and ours[0] != theirs[0]) or \
358-
(base[1] != ours[1] and base[1] != theirs[1] and ours[1] != theirs[1]):
359-
# changed by both
360-
out.append(_tree_entry_to_baseindexentry(base, 1))
361-
out.append(_tree_entry_to_baseindexentry(ours, 2))
362-
out.append(_tree_entry_to_baseindexentry(theirs, 3))
363-
elif base[0] != ours[0] or base[1] != ours[1]:
364-
# only we changed it
365-
out.append(_tree_entry_to_baseindexentry(ours, 0))
338+
for base, ours, theirs in traverse_trees_recursive(odb, tree_shas, ''):
339+
if base is not None:
340+
# base version exists
341+
if ours is not None:
342+
# ours exists
343+
if theirs is not None:
344+
# it exists in all branches, if it was changed in both
345+
# its a conflict, otherwise we take the changed version
346+
# This should be the most common branch, so it comes first
347+
if(base[0] != ours[0] and base[0] != theirs[0] and ours[0] != theirs[0]) or \
348+
(base[1] != ours[1] and base[1] != theirs[1] and ours[1] != theirs[1]):
349+
# changed by both
350+
out.append(_tree_entry_to_baseindexentry(base, 1))
351+
out.append(_tree_entry_to_baseindexentry(ours, 2))
352+
out.append(_tree_entry_to_baseindexentry(theirs, 3))
353+
elif base[0] != ours[0] or base[1] != ours[1]:
354+
# only we changed it
355+
out.append(_tree_entry_to_baseindexentry(ours, 0))
356+
else:
357+
# either nobody changed it, or they did. In either
358+
# case, use theirs
359+
out.append(_tree_entry_to_baseindexentry(theirs, 0))
360+
# END handle modification
366361
else:
367-
# either nobody changed it, or they did. In either
368-
# case, use theirs
369-
out.append(_tree_entry_to_baseindexentry(theirs, 0))
370-
# END handle modification
371-
else:
372362

373-
if ours[0] != base[0] or ours[1] != base[1]:
374-
# they deleted it, we changed it, conflict
375-
out.append(_tree_entry_to_baseindexentry(base, 1))
376-
out.append(_tree_entry_to_baseindexentry(ours, 2))
377-
# else:
378-
# we didn't change it, ignore
379-
# pass
380-
# END handle our change
381-
# END handle theirs
382-
else:
383-
if theirs is None:
384-
# deleted in both, its fine - its out
385-
pass
363+
if ours[0] != base[0] or ours[1] != base[1]:
364+
# they deleted it, we changed it, conflict
365+
out.append(_tree_entry_to_baseindexentry(base, 1))
366+
out.append(_tree_entry_to_baseindexentry(ours, 2))
367+
# else:
368+
# we didn't change it, ignore
369+
# pass
370+
# END handle our change
371+
# END handle theirs
386372
else:
387-
if theirs[0] != base[0] or theirs[1] != base[1]:
388-
# deleted in ours, changed theirs, conflict
389-
out.append(_tree_entry_to_baseindexentry(base, 1))
390-
out.append(_tree_entry_to_baseindexentry(theirs, 3))
391-
# END theirs changed
392-
# else:
393-
# theirs didn't change
394-
# pass
395-
# END handle theirs
396-
# END handle ours
397-
else:
398-
# all three can't be None
399-
if ours is None and theirs is not None:
400-
# added in their branch
401-
out.append(_tree_entry_to_baseindexentry(theirs, 0))
402-
elif theirs is None and ours is not None:
403-
# added in our branch
404-
out.append(_tree_entry_to_baseindexentry(ours, 0))
405-
elif ours is not None and theirs is not None:
406-
# both have it, except for the base, see whether it changed
407-
if ours[0] != theirs[0] or ours[1] != theirs[1]:
408-
out.append(_tree_entry_to_baseindexentry(ours, 2))
409-
out.append(_tree_entry_to_baseindexentry(theirs, 3))
410-
else:
411-
# it was added the same in both
373+
if theirs is None:
374+
# deleted in both, its fine - its out
375+
pass
376+
else:
377+
if theirs[0] != base[0] or theirs[1] != base[1]:
378+
# deleted in ours, changed theirs, conflict
379+
out.append(_tree_entry_to_baseindexentry(base, 1))
380+
out.append(_tree_entry_to_baseindexentry(theirs, 3))
381+
# END theirs changed
382+
# else:
383+
# theirs didn't change
384+
# pass
385+
# END handle theirs
386+
# END handle ours
387+
else:
388+
# all three can't be None
389+
if ours is None and theirs is not None:
390+
# added in their branch
391+
out.append(_tree_entry_to_baseindexentry(theirs, 0))
392+
elif theirs is None and ours is not None:
393+
# added in our branch
412394
out.append(_tree_entry_to_baseindexentry(ours, 0))
413-
# END handle two items
414-
# END handle heads
415-
# END handle base exists
416-
# END for each entries tuple
395+
elif ours is not None and theirs is not None:
396+
# both have it, except for the base, see whether it changed
397+
if ours[0] != theirs[0] or ours[1] != theirs[1]:
398+
out.append(_tree_entry_to_baseindexentry(ours, 2))
399+
out.append(_tree_entry_to_baseindexentry(theirs, 3))
400+
else:
401+
# it was added the same in both
402+
out.append(_tree_entry_to_baseindexentry(ours, 0))
403+
# END handle two items
404+
# END handle heads
405+
# END handle base exists
406+
# END for each entries tuple
417407

418408
return out

‎git/objects/fun.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,9 @@ def _to_full_path(item: EntryTupOrNone, path_prefix: str) -> EntryTupOrNone:
144144

145145

146146
def traverse_trees_recursive(odb: 'GitCmdObjectDB', tree_shas: Sequence[Union[bytes, None]],
147-
path_prefix: str) -> List[EntryTupOrNone]:
147+
path_prefix: str) -> List[List[EntryTupOrNone]]:
148148
"""
149-
:return: list with entries according to the given binary tree-shas.
149+
:return: list of list with entries according to the given binary tree-shas.
150150
The result is encoded in a list
151151
of n tuple|None per blob/commit, (n == len(tree_shas)), where
152152
* [0] == 20 byte sha
@@ -170,7 +170,7 @@ def traverse_trees_recursive(odb: 'GitCmdObjectDB', tree_shas: Sequence[Union[by
170170
trees_data.append(data)
171171
# END for each sha to get data for
172172

173-
out = []
173+
out: List[List[EntryTupOrNone]] = []
174174

175175
# find all matching entries and recursively process them together if the match
176176
# is a tree. If the match is a non-tree item, put it into the result.
@@ -201,7 +201,7 @@ def traverse_trees_recursive(odb: 'GitCmdObjectDB', tree_shas: Sequence[Union[by
201201
out.extend(traverse_trees_recursive(
202202
odb, [((ei and ei[0]) or None) for ei in entries], path_prefix + name + '/'))
203203
else:
204-
out.extend([_to_full_path(e, path_prefix) for e in entries])
204+
out.append([_to_full_path(e, path_prefix) for e in entries])
205205

206206
# END handle recursion
207207
# finally mark it done

0 commit comments

Comments
 (0)