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