hgext/shelve.py
branchstable
changeset 20149 578b888c820e
parent 20103 b3483223f734
child 20407 955547eb2e20
child 20937 c0bf8bea10dd
equal deleted inserted replaced
20148:7ac03bfa1369 20149:578b888c820e
    89             name = fp.readline().strip()
    89             name = fp.readline().strip()
    90             wctx = fp.readline().strip()
    90             wctx = fp.readline().strip()
    91             pendingctx = fp.readline().strip()
    91             pendingctx = fp.readline().strip()
    92             parents = [bin(h) for h in fp.readline().split()]
    92             parents = [bin(h) for h in fp.readline().split()]
    93             stripnodes = [bin(h) for h in fp.readline().split()]
    93             stripnodes = [bin(h) for h in fp.readline().split()]
    94             unknownfiles = fp.readline()[:-1].split('\0')
       
    95         finally:
    94         finally:
    96             fp.close()
    95             fp.close()
    97 
    96 
    98         obj = cls()
    97         obj = cls()
    99         obj.name = name
    98         obj.name = name
   100         obj.wctx = repo[bin(wctx)]
    99         obj.wctx = repo[bin(wctx)]
   101         obj.pendingctx = repo[bin(pendingctx)]
   100         obj.pendingctx = repo[bin(pendingctx)]
   102         obj.parents = parents
   101         obj.parents = parents
   103         obj.stripnodes = stripnodes
   102         obj.stripnodes = stripnodes
   104         obj.unknownfiles = unknownfiles
       
   105 
   103 
   106         return obj
   104         return obj
   107 
   105 
   108     @classmethod
   106     @classmethod
   109     def save(cls, repo, name, originalwctx, pendingctx, stripnodes,
   107     def save(cls, repo, name, originalwctx, pendingctx, stripnodes):
   110              unknownfiles):
       
   111         fp = repo.opener(cls._filename, 'wb')
   108         fp = repo.opener(cls._filename, 'wb')
   112         fp.write('%i\n' % cls._version)
   109         fp.write('%i\n' % cls._version)
   113         fp.write('%s\n' % name)
   110         fp.write('%s\n' % name)
   114         fp.write('%s\n' % hex(originalwctx.node()))
   111         fp.write('%s\n' % hex(originalwctx.node()))
   115         fp.write('%s\n' % hex(pendingctx.node()))
   112         fp.write('%s\n' % hex(pendingctx.node()))
   116         fp.write('%s\n' % ' '.join([hex(p) for p in repo.dirstate.parents()]))
   113         fp.write('%s\n' % ' '.join([hex(p) for p in repo.dirstate.parents()]))
   117         fp.write('%s\n' % ' '.join([hex(n) for n in stripnodes]))
   114         fp.write('%s\n' % ' '.join([hex(n) for n in stripnodes]))
   118         fp.write('%s\n' % '\0'.join(unknownfiles))
       
   119         fp.close()
   115         fp.close()
   120 
   116 
   121     @classmethod
   117     @classmethod
   122     def clear(cls, repo):
   118     def clear(cls, repo):
   123         util.unlinkpath(repo.join(cls._filename), ignoremissing=True)
   119         util.unlinkpath(repo.join(cls._filename), ignoremissing=True)
   377                         repo.join('unshelverebasestate'))
   373                         repo.join('unshelverebasestate'))
   378             raise
   374             raise
   379 
   375 
   380         lock = repo.lock()
   376         lock = repo.lock()
   381 
   377 
   382         mergefiles(ui, repo, state.wctx, state.pendingctx, state.unknownfiles)
   378         mergefiles(ui, repo, state.wctx, state.pendingctx)
   383 
   379 
   384         repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve')
   380         repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve')
   385         shelvedstate.clear(repo)
   381         shelvedstate.clear(repo)
   386         ui.warn(_("unshelve of '%s' aborted\n") % state.name)
   382         ui.warn(_("unshelve of '%s' aborted\n") % state.name)
   387     finally:
   383     finally:
   388         lockmod.release(lock, wlock)
   384         lockmod.release(lock, wlock)
   389 
   385 
   390 def mergefiles(ui, repo, wctx, shelvectx, unknownfiles):
   386 def mergefiles(ui, repo, wctx, shelvectx):
   391     """updates to wctx and merges the changes from shelvectx into the
   387     """updates to wctx and merges the changes from shelvectx into the
   392     dirstate. drops any files in unknownfiles from the dirstate."""
   388     dirstate."""
   393     oldquiet = ui.quiet
   389     oldquiet = ui.quiet
   394     try:
   390     try:
   395         ui.quiet = True
   391         ui.quiet = True
   396         hg.update(repo, wctx.node())
   392         hg.update(repo, wctx.node())
   397         files = []
   393         files = []
   398         files.extend(shelvectx.files())
   394         files.extend(shelvectx.files())
   399         files.extend(shelvectx.parents()[0].files())
   395         files.extend(shelvectx.parents()[0].files())
       
   396 
       
   397         # revert will overwrite unknown files, so move them out of the way
       
   398         m, a, r, d, u = repo.status(unknown=True)[:5]
       
   399         for file in u:
       
   400             if file in files:
       
   401                 util.rename(file, file + ".orig")
   400         cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents(),
   402         cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents(),
   401                        *pathtofiles(repo, files),
   403                        *pathtofiles(repo, files),
   402                        **{'no_backup': True})
   404                        **{'no_backup': True})
   403     finally:
   405     finally:
   404         ui.quiet = oldquiet
   406         ui.quiet = oldquiet
   405 
       
   406     # Send untracked files back to being untracked
       
   407     dirstate = repo.dirstate
       
   408     for f in unknownfiles:
       
   409         dirstate.drop(f)
       
   410 
   407 
   411 def unshelvecleanup(ui, repo, name, opts):
   408 def unshelvecleanup(ui, repo, name, opts):
   412     """remove related files after an unshelve"""
   409     """remove related files after an unshelve"""
   413     if not opts['keep']:
   410     if not opts['keep']:
   414         for filetype in 'hg files patch'.split():
   411         for filetype in 'hg files patch'.split():
   444         shelvectx = repo['tip']
   441         shelvectx = repo['tip']
   445         if not shelvectx in state.pendingctx.children():
   442         if not shelvectx in state.pendingctx.children():
   446             # rebase was a no-op, so it produced no child commit
   443             # rebase was a no-op, so it produced no child commit
   447             shelvectx = state.pendingctx
   444             shelvectx = state.pendingctx
   448 
   445 
   449         mergefiles(ui, repo, state.wctx, shelvectx, state.unknownfiles)
   446         mergefiles(ui, repo, state.wctx, shelvectx)
   450 
   447 
   451         state.stripnodes.append(shelvectx.node())
   448         state.stripnodes.append(shelvectx.node())
   452         repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve')
   449         repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve')
   453         shelvedstate.clear(repo)
   450         shelvedstate.clear(repo)
   454         unshelvecleanup(ui, repo, state.name, opts)
   451         unshelvecleanup(ui, repo, state.name, opts)
   536         # where tmpwctx is an optional commit with the user's pending changes
   533         # where tmpwctx is an optional commit with the user's pending changes
   537         # and shelvectx is the unshelved changes. Then we merge it all down
   534         # and shelvectx is the unshelved changes. Then we merge it all down
   538         # to the original wctx.
   535         # to the original wctx.
   539 
   536 
   540         # Store pending changes in a commit
   537         # Store pending changes in a commit
   541         m, a, r, d, u = repo.status(unknown=True)[:5]
   538         m, a, r, d = repo.status()[:4]
   542         if m or a or r or d or u:
   539         if m or a or r or d:
   543             def commitfunc(ui, repo, message, match, opts):
   540             def commitfunc(ui, repo, message, match, opts):
   544                 hasmq = util.safehasattr(repo, 'mq')
   541                 hasmq = util.safehasattr(repo, 'mq')
   545                 if hasmq:
   542                 if hasmq:
   546                     saved, repo.mq.checkapplied = repo.mq.checkapplied, False
   543                     saved, repo.mq.checkapplied = repo.mq.checkapplied, False
   547 
   544 
   552                     if hasmq:
   549                     if hasmq:
   553                         repo.mq.checkapplied = saved
   550                         repo.mq.checkapplied = saved
   554 
   551 
   555             tempopts = {}
   552             tempopts = {}
   556             tempopts['message'] = "pending changes temporary commit"
   553             tempopts['message'] = "pending changes temporary commit"
   557             tempopts['addremove'] = True
       
   558             oldquiet = ui.quiet
   554             oldquiet = ui.quiet
   559             try:
   555             try:
   560                 ui.quiet = True
   556                 ui.quiet = True
   561                 node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
   557                 node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
   562             finally:
   558             finally:
   586             except error.InterventionRequired:
   582             except error.InterventionRequired:
   587                 tr.close()
   583                 tr.close()
   588 
   584 
   589                 stripnodes = [repo.changelog.node(rev)
   585                 stripnodes = [repo.changelog.node(rev)
   590                               for rev in xrange(oldtiprev, len(repo))]
   586                               for rev in xrange(oldtiprev, len(repo))]
   591                 shelvedstate.save(repo, basename, wctx, tmpwctx, stripnodes, u)
   587                 shelvedstate.save(repo, basename, wctx, tmpwctx, stripnodes)
   592 
   588 
   593                 util.rename(repo.join('rebasestate'),
   589                 util.rename(repo.join('rebasestate'),
   594                             repo.join('unshelverebasestate'))
   590                             repo.join('unshelverebasestate'))
   595                 raise error.InterventionRequired(
   591                 raise error.InterventionRequired(
   596                     _("unresolved conflicts (see 'hg resolve', then "
   592                     _("unresolved conflicts (see 'hg resolve', then "
   601 
   597 
   602             if not shelvectx in tmpwctx.children():
   598             if not shelvectx in tmpwctx.children():
   603                 # rebase was a no-op, so it produced no child commit
   599                 # rebase was a no-op, so it produced no child commit
   604                 shelvectx = tmpwctx
   600                 shelvectx = tmpwctx
   605 
   601 
   606         mergefiles(ui, repo, wctx, shelvectx, u)
   602         mergefiles(ui, repo, wctx, shelvectx)
   607         shelvedstate.clear(repo)
   603         shelvedstate.clear(repo)
   608 
   604 
   609         # The transaction aborting will strip all the commits for us,
   605         # The transaction aborting will strip all the commits for us,
   610         # but it doesn't update the inmemory structures, so addchangegroup
   606         # but it doesn't update the inmemory structures, so addchangegroup
   611         # hooks still fire and try to operate on the missing commits.
   607         # hooks still fire and try to operate on the missing commits.