##// END OF EJS Templates
Fix up copy command to behave more like regular "cp"....
Bryan O'Sullivan -
r1249:a5355fa5 default
parent child Browse files
Show More
@@ -164,11 +164,22 b' commit [options] [files...]::'
164 164
165 165 aliases: ci
166 166
167 copy <source> <dest>::
168 Mark <dest> file as a copy or rename of a <source> one
167 copy <source ...> <dest>::
168 Mark dest as having copies of source files. If dest is a
169 directory, copies are put in that directory. If dest is a file,
170 there can only be one source.
171
172 By default, this command copies the contents of files as they
173 stand in the working directory. If invoked with --after, the
174 operation is recorded, but no copying is performed.
169 175
170 176 This command takes effect for the next commit.
171 177
178 Options:
179 -A, --after record a copy that has already occurred
180 -f, --force forcibly copy over an existing managed file
181 -p, --parents append source path to dest
182
172 183 diff [-a] [-r revision] [-r revision] [files ...]::
173 184 Show differences between revisions for the specified files.
174 185
@@ -685,9 +685,84 b' def commit(ui, repo, *pats, **opts):'
685 685 except ValueError, inst:
686 686 raise util.Abort(str(inst))
687 687
688 def copy(ui, repo, source, dest):
689 """mark a file as copied or renamed for the next commit"""
690 return repo.copy(*relpath(repo, (source, dest)))
688 def copy(ui, repo, *pats, **opts):
689 """mark files as copied for the next commit"""
690 if not pats:
691 raise util.Abort('no source or destination specified')
692 elif len(pats) == 1:
693 raise util.Abort('no destination specified')
694 pats = list(pats)
695 dest = pats.pop()
696 sources = []
697
698 def okaytocopy(abs, rel, exact):
699 reasons = {'?': 'is not managed',
700 'a': 'has been marked for add'}
701 reason = reasons.get(repo.dirstate.state(abs))
702 if reason:
703 if exact: ui.warn('%s: not copying - file %s\n' % (rel, reason))
704 else:
705 return True
706
707 for src, abs, rel, exact in walk(repo, pats, opts):
708 if okaytocopy(abs, rel, exact):
709 sources.append((abs, rel, exact))
710 if not sources:
711 raise util.Abort('no files to copy')
712
713 cwd = repo.getcwd()
714 absdest = util.canonpath(repo.root, cwd, dest)
715 reldest = util.pathto(cwd, absdest)
716 if os.path.exists(reldest):
717 destisfile = not os.path.isdir(reldest)
718 else:
719 destisfile = len(sources) == 1 or repo.dirstate.state(absdest) != '?'
720
721 if destisfile:
722 if opts['parents']:
723 raise util.Abort('with --parents, destination must be a directory')
724 elif len(sources) > 1:
725 raise util.Abort('with multiple sources, destination must be a '
726 'directory')
727 errs = 0
728 for abs, rel, exact in sources:
729 if opts['parents']:
730 mydest = os.path.join(dest, rel)
731 elif destisfile:
732 mydest = reldest
733 else:
734 mydest = os.path.join(dest, os.path.basename(rel))
735 myabsdest = util.canonpath(repo.root, cwd, mydest)
736 myreldest = util.pathto(cwd, myabsdest)
737 if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
738 ui.warn('%s: not overwriting - file already managed\n' % myreldest)
739 continue
740 mydestdir = os.path.dirname(myreldest) or '.'
741 if not opts['after']:
742 try:
743 if opts['parents']: os.makedirs(mydestdir)
744 elif not destisfile: os.mkdir(mydestdir)
745 except OSError, inst:
746 if inst.errno != errno.EEXIST: raise
747 if ui.verbose or not exact:
748 ui.status('copying %s to %s\n' % (rel, myreldest))
749 if not opts['after']:
750 try:
751 shutil.copyfile(rel, myreldest)
752 n = repo.manifest.tip()
753 mf = repo.manifest.readflags(n)
754 util.set_exec(myreldest, util.is_exec(rel, mf[abs]))
755 except IOError, inst:
756 if inst.errno == errno.ENOENT:
757 ui.warn('%s: deleted in working copy\n' % rel)
758 else:
759 ui.warn('%s: cannot copy - %s\n' % (rel, inst.strerror))
760 errs += 1
761 continue
762 repo.copy(abs, myabsdest)
763 if errs:
764 ui.warn('(consider using --after to record failed copies)\n')
765 return errs
691 766
692 767 def debugcheckstate(ui, repo):
693 768 """validate the correctness of the current dirstate"""
@@ -1677,7 +1752,13 b' table = {'
1677 1752 ('d', 'date', "", 'date code'),
1678 1753 ('u', 'user', "", 'user')],
1679 1754 'hg commit [OPTION]... [FILE]...'),
1680 "copy": (copy, [], 'hg copy SOURCE DEST'),
1755 "copy|cp": (copy,
1756 [('I', 'include', [], 'include path in search'),
1757 ('X', 'exclude', [], 'exclude path from search'),
1758 ('A', 'after', None, 'record a copy after it has happened'),
1759 ('f', 'force', None, 'replace destination if it exists'),
1760 ('p', 'parents', None, 'append source path to dest')],
1761 'hg copy [OPTION]... [SOURCE]... DEST'),
1681 1762 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1682 1763 "debugconfig": (debugconfig, [], 'debugconfig'),
1683 1764 "debugstate": (debugstate, [], 'debugstate'),
@@ -26,7 +26,7 b' echo "# should not be renamed"'
26 26 hg debugrename bar
27 27
28 28 cp foo bar
29 hg copy foo bar
29 hg copy -f foo bar
30 30 echo "# should show copy"
31 31 hg debugstate|grep '^copy'
32 32 hg commit -m3 -d"0 0"
@@ -43,7 +43,7 b' list of commands (use "hg help -v" to sh'
43 43 cat output the latest or given revision of a file
44 44 clone make a copy of an existing repository
45 45 commit commit the specified files or all outstanding changes
46 copy mark a file as copied or renamed for the next commit
46 copy mark files as copied for the next commit
47 47 diff diff working directory (or selected files)
48 48 export dump the header and diffs for one or more changesets
49 49 forget don't add the specified files on the next commit
@@ -84,7 +84,7 b' list of commands (use "hg help -v" to sh'
84 84 cat output the latest or given revision of a file
85 85 clone make a copy of an existing repository
86 86 commit commit the specified files or all outstanding changes
87 copy mark a file as copied or renamed for the next commit
87 copy mark files as copied for the next commit
88 88 diff diff working directory (or selected files)
89 89 export dump the header and diffs for one or more changesets
90 90 forget don't add the specified files on the next commit
General Comments 0
You need to be logged in to leave comments. Login now