def cdm_backup(ui, repo, if_newer=False): '''make backup copies of all workspace changes Backups will be stored in ~/cdm.backup/<basename of workspace>.''' name = backup_name(repo.root) bk = CdmBackup(ui, wslist[repo], name) if if_newer and not bk.need_backup(): ui.status('backup is up-to-date\n') else: bk.backup()
def cdm_backup(ui, repo, if_newer=False): '''backup workspace changes and metadata Create a backup copy of changes made in this workspace as compared to its parent workspace, as well as important metadata of this workspace. NOTE: Only changes as compared to the parent workspace are backed up. If you lose this workspace and its parent, you will not be able to restore a backup into a clone of the grandparent workspace. By default, backups are stored in the cdm.backup/ directory in your home directory. This is configurable using the cdm.backupdir configuration variable, for example: hg backup --config cdm.backupdir=/net/foo/backups or place the following in an appropriate hgrc file:: [cdm] backupdir = /net/foo/backups Backups have the same name as the workspace in which they were taken, with '-closed' appended in the case of O/N's usr/closed. ''' name = backup_name(repo.root) bk = CdmBackup(ui, wslist[repo], name) wlock = repo.wlock() lock = repo.lock() try: if if_newer and not bk.need_backup(): ui.status('backup is up-to-date\n') else: bk.backup() finally: lock.release() wlock.release()
def cdm_recommit(ui, repo, **opts): '''replace outgoing changesets with a single equivalent changeset Replace all outgoing changesets with a single changeset containing equivalent changes. This removes uninteresting changesets created during development that would only serve as noise in the gate. Any changed file that is now identical in content to that in the parent workspace (whether identical in history or otherwise) will not be included in the new changeset. Any merges information will also be removed. If no files are changed in comparison to the parent workspace, the outgoing changesets will be removed, but no new changeset created. recommit will refuse to run if the workspace contains more than one outgoing head, even if those heads are on the same branch. To recommit with only one branch containing outgoing changesets, your workspace must be on that branch and at that branch head. recommit will prompt you to take a backup if your workspace has been changed since the last backup was taken. In almost all cases, you should allow it to take one (the default). recommit cannot be run if the workspace contains any uncommitted changes, applied Mq patches, or has multiple outgoing heads (or branches). ''' ws = wslist[repo] if not os.getcwd().startswith(repo.root): raise util.Abort('recommit is not safe to run with -R') abort_if_dirty(ws) wlock = repo.wlock() lock = repo.lock() try: parent = ws.parent(opts['parent']) between = repo.changelog.nodesbetween(ws.findoutgoing(parent))[2] heads = set(between) & set(repo.heads()) if len(heads) > 1: ui.warn('Workspace has multiple outgoing heads (or branches):\n') for head in sorted(map(repo.changelog.rev, heads), reverse=True): ui.warn('\t%d\n' % head) raise util.Abort('you must merge before recommitting') # # We can safely use the worklist here, as we know (from the # abort_if_dirty() check above) that the working copy has not been # modified. # active = ws.active(parent) if filter(lambda b: len(b.parents()) > 1, active.bases()): raise util.Abort('Cannot recommit a merge of two non-outgoing ' 'changesets') if len(active.revs) <= 0: raise util.Abort("no changes to recommit") if len(active.files()) <= 0: ui.warn("Recommitting %d active changesets, but no active files\n" % len(active.revs)) # # During the course of a recommit, any file bearing a name # matching the source name of any renamed file will be # clobbered by the operation. # # As such, we ask the user before proceeding. # bogosity = [f.parentname for f in active if f.is_renamed() and os.path.exists(repo.wjoin(f.parentname))] if bogosity: ui.warn("The following file names are the original name of a " "rename and also present\n" "in the working directory:\n") for fname in bogosity: ui.warn(" %s\n" % fname) if not yes_no(ui, "These files will be removed by recommit." " Continue?", False): raise util.Abort("recommit would clobber files") user = opts['user'] or ui.username() comments = '\n'.join(active.comments()) message = cmdutil.logmessage(opts) or ui.edit(comments, user) if not message: raise util.Abort('empty commit message') bk = CdmBackup(ui, ws, backup_name(repo.root)) if bk.need_backup(): if yes_no(ui, 'Do you want to backup files first?', True): bk.backup() oldtags = repo.tags() clearedtags = [(name, nd, repo.changelog.rev(nd), local) for name, nd, local in active.tags()] ws.squishdeltas(active, message, user=user) finally: lock.release() wlock.release() if clearedtags: ui.write("Removed tags:\n") for name, nd, rev, local in sorted(clearedtags, key=lambda x: x[0].lower()): ui.write(" %5s:%s:\t%s%s\n" % (rev, node.short(nd), name, (local and ' (local)' or ''))) for ntag, nnode in sorted(repo.tags().items(), key=lambda x: x[0].lower()): if ntag in oldtags and ntag != "tip": if oldtags[ntag] != nnode: ui.write("tag '%s' now refers to revision %d:%s\n" % (ntag, repo.changelog.rev(nnode), node.short(nnode)))
def cdm_recommit(ui, repo, **opts): '''compact outgoing deltas into a single, conglomerate, delta''' if not os.getcwd().startswith(repo.root): raise util.Abort('recommit is not safe to run with -R') abort_if_dirty(wslist[repo]) heads = repo.heads() if len(heads) > 1: ui.warn('Workspace has multiple heads (or branches):\n') for head in heads: ui.warn('\t%d\n' % repo.changelog.rev(head)) raise util.Abort('you must merge before recommitting') wlock = repo.wlock() lock = repo.lock() try: active = wslist[repo].active(opts['parent']) if len(active.revs) <= 0: raise util.Abort("no changes to recommit") if len(active.files()) <= 0: ui.warn( "Recommitting %d active changesets, but no active files\n" % len(active.revs)) # # During the course of a recommit, any file bearing a name # matching the source name of any renamed file will be # clobbered by the operation. # # As such, we ask the user before proceeding. # bogosity = [ f.parentname for f in active if f.is_renamed() and os.path.exists(repo.wjoin(f.parentname)) ] if bogosity: ui.warn("The following file names are the original name of a " "rename and also present\n" "in the working directory:\n") for fname in bogosity: ui.warn(" %s\n" % fname) if not yes_no( ui, "These files will be removed by recommit." " Continue?", False): raise util.Abort("recommit would clobber files") user = opts['user'] or ui.username() comments = '\n'.join(active.comments()) message = cmdutil.logmessage(opts) or ui.edit(comments, user) if not message: raise util.Abort('empty commit message') bk = CdmBackup(ui, wslist[repo], backup_name(repo.root)) if bk.need_backup(): if yes_no(ui, 'Do you want to backup files first?', True): bk.backup() oldtags = repo.tags() clearedtags = [(name, nd, repo.changelog.rev(nd), local) for name, nd, local in active.tags()] wslist[repo].squishdeltas(active, message, user=user) finally: lock.release() wlock.release() if clearedtags: ui.write("Removed tags:\n") for name, nd, rev, local in sorted(clearedtags, key=lambda x: x[0].lower()): ui.write(" %5s:%s:\t%s%s\n" % (rev, node.short(nd), name, (local and ' (local)' or ''))) for ntag, nnode in sorted(repo.tags().items(), key=lambda x: x[0].lower()): if ntag in oldtags and ntag != "tip": if oldtags[ntag] != nnode: ui.write( "tag '%s' now refers to revision %d:%s\n" % (ntag, repo.changelog.rev(nnode), node.short(nnode)))