@@ -986,6 +986,20 @@ def add(self, items, force=True, fprogress=lambda *args: None):
986
986
987
987
return entries_added
988
988
989
+ def _items_to_rela_paths (self , items ):
990
+ """Returns a list of repo-relative paths from the given items which
991
+ may be absolute or relative paths, entries or blobs"""
992
+ paths = list ()
993
+ for item in items :
994
+ if isinstance (item , (BaseIndexEntry ,Blob )):
995
+ paths .append (self ._to_relative_path (item .path ))
996
+ elif isinstance (item , basestring ):
997
+ paths .append (self ._to_relative_path (item ))
998
+ else :
999
+ raise TypeError ("Invalid item type: %r" % item )
1000
+ # END for each item
1001
+ return paths
1002
+
989
1003
@clear_cache
990
1004
@default_index
991
1005
def remove (self , items , working_tree = False , ** kwargs ):
@@ -1021,7 +1035,8 @@ def remove(self, items, working_tree=False, **kwargs):
1021
1035
as 'r' to allow recurive removal of
1022
1036
1023
1037
Returns
1024
- List(path_string, ...) list of paths that have been removed effectively.
1038
+ List(path_string, ...) list of repository relative paths that have
1039
+ been removed effectively.
1025
1040
This is interesting to know in case you have provided a directory or
1026
1041
globs. Paths are relative to the repository.
1027
1042
"""
@@ -1031,22 +1046,84 @@ def remove(self, items, working_tree=False, **kwargs):
1031
1046
args .append ("--" )
1032
1047
1033
1048
# preprocess paths
1034
- paths = list ()
1035
- for item in items :
1036
- if isinstance (item , (BaseIndexEntry ,Blob )):
1037
- paths .append (self ._to_relative_path (item .path ))
1038
- elif isinstance (item , basestring ):
1039
- paths .append (self ._to_relative_path (item ))
1040
- else :
1041
- raise TypeError ("Invalid item type: %r" % item )
1042
- # END for each item
1043
-
1049
+ paths = self ._items_to_rela_paths (items )
1044
1050
removed_paths = self .repo .git .rm (args , paths , ** kwargs ).splitlines ()
1045
1051
1046
1052
# process output to gain proper paths
1047
1053
# rm 'path'
1048
1054
return [ p [4 :- 1 ] for p in removed_paths ]
1055
+
1056
+ @clear_cache
1057
+ @default_index
1058
+ def move (self , items , skip_errors = False , ** kwargs ):
1059
+ """
1060
+ Rename/move the items, whereas the last item is considered the destination of
1061
+ the move operation. If the destination is a file, the first item ( of two )
1062
+ must be a file as well. If the destination is a directory, it may be preceeded
1063
+ by one or more directories or files.
1064
+
1065
+ The working tree will be affected in non-bare repositories.
1066
+
1067
+ ``items``
1068
+ Multiple types of items are supported, please see the 'remove' method
1069
+ for reference.
1070
+ ``skip_errors``
1071
+ If True, errors such as ones resulting from missing source files will
1072
+ be skpped.
1073
+ ``**kwargs``
1074
+ Additional arguments you would like to pass to git-mv, such as dry_run
1075
+ or force.
1076
+
1077
+ Returns
1078
+ List(tuple(source_path_string, destination_path_string), ...)
1079
+ A list of pairs, containing the source file moved as well as its
1080
+ actual destination. Relative to the repository root.
1081
+
1082
+ Raises
1083
+ ValueErorr: If only one item was given
1084
+ GitCommandError: If git could not handle your request
1085
+ """
1086
+ args = list ()
1087
+ if skip_errors :
1088
+ args .append ('-k' )
1089
+
1090
+ paths = self ._items_to_rela_paths (items )
1091
+ if len (paths ) < 2 :
1092
+ raise ValueError ("Please provide at least one source and one destination of the move operation" )
1093
+
1094
+ was_dry_run = kwargs .pop ('dry_run' , kwargs .pop ('n' , None ))
1095
+ kwargs ['dry_run' ] = True
1096
+
1097
+ # first execute rename in dryrun so the command tells us what it actually does
1098
+ # ( for later output )
1099
+ out = list ()
1100
+ mvlines = self .repo .git .mv (args , paths , ** kwargs ).splitlines ()
1101
+
1102
+ # parse result - first 0:n/2 lines are 'checking ', the remaining ones
1103
+ # are the 'renaming' ones which we parse
1104
+ for ln in xrange (len (mvlines )/ 2 , len (mvlines )):
1105
+ tokens = mvlines [ln ].split (' to ' )
1106
+ assert len (tokens ) == 2 , "Too many tokens in %s" % mvlines [ln ]
1107
+
1108
+ # [0] = Renaming x
1109
+ # [1] = y
1110
+ out .append ((tokens [0 ][9 :], tokens [1 ]))
1111
+ # END for each line to parse
1112
+
1113
+ # either prepare for the real run, or output the dry-run result
1114
+ if was_dry_run :
1115
+ return out
1116
+ # END handle dryrun
1049
1117
1118
+
1119
+ # now apply the actual operation
1120
+ kwargs .pop ('dry_run' )
1121
+ self .repo .git .mv (args , paths , ** kwargs )
1122
+
1123
+ return out
1124
+
1125
+
1126
+
1050
1127
@default_index
1051
1128
def commit (self , message , parent_commits = None , head = True ):
1052
1129
"""
0 commit comments