summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/git/index.py78
-rw-r--r--test/git/test_index.py15
2 files changed, 84 insertions, 9 deletions
diff --git a/lib/git/index.py b/lib/git/index.py
index 5bf654fe..d8ba6e18 100644
--- a/lib/git/index.py
+++ b/lib/git/index.py
@@ -126,6 +126,16 @@ class IndexEntry(tuple):
@property
def path(self):
return self[10]
+
+
+ @classmethod
+ def from_blob(cls, blob):
+ """
+ Returns
+ Minimal entry resembling the given blob objecft
+ """
+ time = struct.pack(">LL", 0, 0)
+ return IndexEntry((time, time, 0, 0, blob.mode, 0, 0, blob.size, blob.id, 0, blob.path))
class Index(object):
@@ -402,6 +412,61 @@ class Index(object):
yield output
# END for each entry
+ def unmerged_blobs(self):
+ """
+ Returns
+ Iterator yielding dict(path : list( tuple( stage, Blob, ...))), being
+ a dictionary associating a path in the index with a list containing
+ stage/blob pairs
+
+ Note:
+ Blobs that have been removed in one side simply do not exist in the
+ given stage. I.e. a file removed on the 'other' branch whose entries
+ are at stage 3 will not have a stage 3 entry.
+ """
+ is_unmerged_blob = lambda t: t[0] != 0
+ path_map = dict()
+ for stage, blob in self.iter_blobs(is_unmerged_blob):
+ path_map.setdefault(blob.path, list()).append((stage, blob))
+ # END for each unmerged blob
+
+ return path_map
+
+ def resolve_blobs(self, iter_blobs):
+ """
+ Resolve the blobs given in blob iterator. This will effectively remove the
+ index entries of the respective path at all non-null stages and add the given
+ blob as new stage null blob.
+
+ For each path there may only be one blob, otherwise a ValueError will be raised
+ claiming the path is already at stage 0.
+
+ Raise
+ ValueError if one of the blobs already existed at stage 0
+
+ Returns:
+ self
+ """
+ for blob in iter_blobs:
+ stage_null_key = (blob.path, 0)
+ if stage_null_key in self.entries:
+ raise ValueError( "Blob %r already at stage 0" % blob )
+ # END assert blob is not stage 0 already
+
+ # delete all possible stages
+ for stage in (1, 2, 3):
+ try:
+ del( self.entries[(blob.path, stage)] )
+ except KeyError:
+ pass
+ # END ignore key errors
+ # END for each possible stage
+
+ self.entries[stage_null_key] = IndexEntry.from_blob(blob)
+ # END for each blob
+
+ return self
+
def write_tree(self):
"""
Writes the Index in self to a corresponding Tree file into the repository
@@ -414,11 +479,16 @@ class Index(object):
tmp_index_mover = _TemporaryFileSwap(index_path)
self.to_file(self, index_path)
- tree_sha = self.repo.git.write_tree()
- # remove our index file so that the original index can move back into place
- # On linux it will silently overwrite, on windows it won't
- os.remove(index_path)
+ try:
+ tree_sha = self.repo.git.write_tree()
+ finally:
+ # remove our index file so that the original index can move back into place
+ # On linux it will silently overwrite, on windows it won't
+ if os.path.isfile(index_path):
+ os.remove(index_path)
+ # END remove our own index file beforehand
+ # END write tree handling
return Tree(self.repo, tree_sha, 0, '')
diff --git a/test/git/test_index.py b/test/git/test_index.py
index a4e01054..6208a1d9 100644
--- a/test/git/test_index.py
+++ b/test/git/test_index.py
@@ -75,23 +75,28 @@ class TestTree(TestCase):
self._cmp_tree_index(cur_sha, two_way_index)
# merge three trees - here we have a merge conflict
- tree_way_index = Index.from_tree(self.repo, common_ancestor_sha, cur_sha, other_sha)
- assert len(list(e for e in tree_way_index.entries.values() if e.stage != 0))
+ three_way_index = Index.from_tree(self.repo, common_ancestor_sha, cur_sha, other_sha)
+ assert len(list(e for e in three_way_index.entries.values() if e.stage != 0))
# ITERATE BLOBS
merge_required = lambda t: t[0] != 0
- merge_blobs = list(tree_way_index.iter_blobs(merge_required))
+ merge_blobs = list(three_way_index.iter_blobs(merge_required))
assert merge_blobs
assert merge_blobs[0][0] in (1,2,3)
assert isinstance(merge_blobs[0][1], Blob)
# writing a tree should fail with an unmerged index
- self.failUnlessRaises(GitCommandError, tree_way_index.write_tree)
+ self.failUnlessRaises(GitCommandError, three_way_index.write_tree)
# removed unmerged entries
- self.fail("remove unmerged")
+ unmerged_blob_map = three_way_index.unmerged_blobs()
+ assert unmerged_blob_map
+
+ # pick the first blob at the first stage we find and use it as resolved version
+ three_way_index.resolve_blobs( l[0][1] for l in unmerged_blob_map.itervalues() )
+ three_way_index.write_tree()
def test_custom_commit(self):