Revert implmentation and how to undo a bzr remove

benjl at cse.unsw.edu.au benjl at cse.unsw.edu.au
Sat Apr 9 21:44:13 BST 2005


Attached is an implementation of the revert command.

In implementing this I can upon two problems:

1/ How to revert an add:

This isn't too bad, it is just a question of whether doing
and "add" and then a "revert" should delete the file or
not. Currently I've implemented the same behaviour as 
would occur if you "add"ed a file and the "remove"d the file.
E.g: Don't delete the file. This behaviour is also what is described
in kill_version.txt:60.

Are there any arguments for actually deleting the file, so that the
working copy is the same as repository copy?

2/ How to revert a remove:

I've got no idea how to do this. It seems that you currently
can't:

bzr_test% touch foo                            
bzr_test% bzr add foo
bzr_test% bzr commit -m "Added foo"
bzr_test% bzr status               
bzr_test% bzr remove foo
bzr_test% bzr status    
?       foo
D       foo

Any advice on how this should be implemented?


Cheers,

Benno
-------------- next part --------------
*** modified file 'bzrlib/commands.py'
--- bzrlib/commands.py 
+++ bzrlib/commands.py 
@@ -430,6 +430,83 @@
             bailout("can't represent state %s {%s}" % (file_state, fid))
 
 
+def cmd_revert(revision=None):
+    """bzr revert: Revert changes in working tree.
+    
+usage: bzr revert [files]
+
+TODO: Revert selected files.
+"""
+    b = Branch('.')
+
+    ## TODO: Shouldn't be in the cmd function.
+    if revision == None:
+        old_tree = b.basis_tree()
+    else:
+        old_tree = b.revision_tree(b.lookup_revision(revision))
+        
+    new_tree = b.working_tree()
+    old_inv = old_tree.inventory
+    new_inv = new_tree.inventory
+
+    # TODO: Options to control putting on a prefix or suffix, perhaps as a format string
+    old_label = ''
+    new_label = ''
+
+    # We keep a queue of the work that needs to be done, since
+    # doing it immediately can cause real problems. E.g: reverting
+    # a rename, then diff_trees can't traverse trees correctly
+    work = []
+
+    def add_file(file, fid):
+        verbose = False
+        open(file, "w").write(old_tree.get_file(fid).read())
+        bzrlib.add.smart_add([file], verbose)
+
+    def revert_file(file, fid):
+        open(file, "w").write(old_tree.get_file(fid).read())
+
+    for file_state, fid, old_name, new_name, kind in bzrlib.diff_trees(old_tree, new_tree):
+        d = None
+
+        # Don't show this by default; maybe do it if an option is passed
+        # idlabel = '      {%s}' % fid
+        idlabel = ''
+
+        if file_state in ['.', '?', 'I']:
+            continue
+        elif file_state == 'A':
+            work.append(('*** removed %s %r' % (kind, new_name),
+                         b.remove,
+                         ([new_name])))
+        elif file_state == 'D':
+            # Add file
+            assert isinstance(old_name, types.StringTypes)
+            work.append(('*** added %s %r' % (kind, old_name),
+                         add_file,
+                         (old_name, fid)))
+        elif file_state in ['M', 'R']:
+            if file_state == 'M':
+                assert kind == 'file'
+                assert old_name == new_name
+                work.append(('*** reverted %s %r' % (kind, old_name),
+                             revert_file,
+                             (old_name, fid)))
+            elif file_state == 'R':
+                # Rename file
+                work.append(('*** renamed %s %r => %r' % (kind, new_name, old_name),
+                             b.rename_one,
+                             (b.relpath(new_name), b.relpath(old_name))))
+        else:
+            bailout("can't represent state %s {%s}" % (file_state, fid))
+
+    # We need to apply the changes in reverse order.
+    # Possibly it is better (more effecient) to build
+    # up the work list in reverse order to begin with.
+    work.reverse()
+    for help_string, operation, args in work:
+        print help_string
+        operation(*args)
 
 def cmd_deleted(show_ids=False):
     """List files deleted in the working tree.


More information about the bazaar mailing list