321 fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts) |
321 fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts) |
322 |
322 |
323 patch.diff(repo, node1, node2, fns, match=matchfn, |
323 patch.diff(repo, node1, node2, fns, match=matchfn, |
324 fp=fp, changes=changes, opts=self.diffopts()) |
324 fp=fp, changes=changes, opts=self.diffopts()) |
325 |
325 |
326 def mergeone(self, repo, mergeq, head, patch, rev, wlock): |
326 def mergeone(self, repo, mergeq, head, patch, rev): |
327 # first try just applying the patch |
327 # first try just applying the patch |
328 (err, n) = self.apply(repo, [ patch ], update_status=False, |
328 (err, n) = self.apply(repo, [ patch ], update_status=False, |
329 strict=True, merge=rev, wlock=wlock) |
329 strict=True, merge=rev) |
330 |
330 |
331 if err == 0: |
331 if err == 0: |
332 return (err, n) |
332 return (err, n) |
333 |
333 |
334 if n is None: |
334 if n is None: |
335 raise util.Abort(_("apply failed for patch %s") % patch) |
335 raise util.Abort(_("apply failed for patch %s") % patch) |
336 |
336 |
337 self.ui.warn("patch didn't work out, merging %s\n" % patch) |
337 self.ui.warn("patch didn't work out, merging %s\n" % patch) |
338 |
338 |
339 # apply failed, strip away that rev and merge. |
339 # apply failed, strip away that rev and merge. |
340 hg.clean(repo, head, wlock=wlock) |
340 hg.clean(repo, head) |
341 self.strip(repo, n, update=False, backup='strip', wlock=wlock) |
341 self.strip(repo, n, update=False, backup='strip') |
342 |
342 |
343 ctx = repo.changectx(rev) |
343 ctx = repo.changectx(rev) |
344 ret = hg.merge(repo, rev, wlock=wlock) |
344 ret = hg.merge(repo, rev) |
345 if ret: |
345 if ret: |
346 raise util.Abort(_("update returned %d") % ret) |
346 raise util.Abort(_("update returned %d") % ret) |
347 n = repo.commit(None, ctx.description(), ctx.user(), |
347 n = repo.commit(None, ctx.description(), ctx.user(), force=1) |
348 force=1, wlock=wlock) |
|
349 if n == None: |
348 if n == None: |
350 raise util.Abort(_("repo commit failed")) |
349 raise util.Abort(_("repo commit failed")) |
351 try: |
350 try: |
352 message, comments, user, date, patchfound = mergeq.readheaders(patch) |
351 message, comments, user, date, patchfound = mergeq.readheaders(patch) |
353 except: |
352 except: |
612 else: |
611 else: |
613 m, a, r, d = self.check_localchanges(repo, force) |
612 m, a, r, d = self.check_localchanges(repo, force) |
614 commitfiles = m + a + r |
613 commitfiles = m + a + r |
615 self.check_toppatch(repo) |
614 self.check_toppatch(repo) |
616 wlock = repo.wlock() |
615 wlock = repo.wlock() |
617 insert = self.full_series_end() |
616 try: |
618 if msg: |
617 insert = self.full_series_end() |
619 n = repo.commit(commitfiles, msg, force=True, wlock=wlock) |
618 if msg: |
620 else: |
619 n = repo.commit(commitfiles, msg, force=True) |
621 n = repo.commit(commitfiles, |
620 else: |
622 "[mq]: %s" % patch, force=True, wlock=wlock) |
621 n = repo.commit(commitfiles, "[mq]: %s" % patch, force=True) |
623 if n == None: |
622 if n == None: |
624 raise util.Abort(_("repo commit failed")) |
623 raise util.Abort(_("repo commit failed")) |
625 self.full_series[insert:insert] = [patch] |
624 self.full_series[insert:insert] = [patch] |
626 self.applied.append(statusentry(revlog.hex(n), patch)) |
625 self.applied.append(statusentry(revlog.hex(n), patch)) |
627 self.parse_series() |
626 self.parse_series() |
628 self.series_dirty = 1 |
627 self.series_dirty = 1 |
629 self.applied_dirty = 1 |
628 self.applied_dirty = 1 |
630 p = self.opener(patch, "w") |
629 p = self.opener(patch, "w") |
631 if msg: |
630 if msg: |
632 msg = msg + "\n" |
631 msg = msg + "\n" |
633 p.write(msg) |
632 p.write(msg) |
634 p.close() |
633 p.close() |
635 wlock = None |
634 wlock = None |
636 r = self.qrepo() |
635 r = self.qrepo() |
637 if r: r.add([patch]) |
636 if r: r.add([patch]) |
638 if commitfiles: |
637 if commitfiles: |
639 self.refresh(repo, short=True) |
638 self.refresh(repo, short=True, git=opts.get('git')) |
640 self.removeundo(repo) |
639 self.removeundo(repo) |
641 |
640 finally: |
642 def strip(self, repo, rev, update=True, backup="all", wlock=None): |
641 del wlock |
643 if not wlock: |
642 |
|
643 def strip(self, repo, rev, update=True, backup="all"): |
|
644 wlock = lock = None |
|
645 try: |
644 wlock = repo.wlock() |
646 wlock = repo.wlock() |
645 lock = repo.lock() |
647 lock = repo.lock() |
646 |
648 |
647 if update: |
649 if update: |
648 self.check_localchanges(repo, refresh=False) |
650 self.check_localchanges(repo, refresh=False) |
649 urev = self.qparents(repo, rev) |
651 urev = self.qparents(repo, rev) |
650 hg.clean(repo, urev, wlock=wlock) |
652 hg.clean(repo, urev) |
651 repo.dirstate.write() |
653 repo.dirstate.write() |
652 |
654 |
653 self.removeundo(repo) |
655 self.removeundo(repo) |
654 repair.strip(self.ui, repo, rev, backup) |
656 repair.strip(self.ui, repo, rev, backup) |
|
657 finally: |
|
658 del lock, wlock |
655 |
659 |
656 def isapplied(self, patch): |
660 def isapplied(self, patch): |
657 """returns (index, rev, patch)""" |
661 """returns (index, rev, patch)""" |
658 for i in xrange(len(self.applied)): |
662 for i in xrange(len(self.applied)): |
659 a = self.applied[i] |
663 a = self.applied[i] |
733 if i + off < len(self.series): |
737 if i + off < len(self.series): |
734 return self.series[i + off] |
738 return self.series[i + off] |
735 raise util.Abort(_("patch %s not in series") % patch) |
739 raise util.Abort(_("patch %s not in series") % patch) |
736 |
740 |
737 def push(self, repo, patch=None, force=False, list=False, |
741 def push(self, repo, patch=None, force=False, list=False, |
738 mergeq=None, wlock=None): |
742 mergeq=None): |
739 if not wlock: |
743 wlock = repo.wlock() |
740 wlock = repo.wlock() |
744 try: |
741 patch = self.lookup(patch) |
745 patch = self.lookup(patch) |
742 # Suppose our series file is: A B C and the current 'top' patch is B. |
746 # Suppose our series file is: A B C and the current 'top' |
743 # qpush C should be performed (moving forward) |
747 # patch is B. qpush C should be performed (moving forward) |
744 # qpush B is a NOP (no change) |
748 # qpush B is a NOP (no change) qpush A is an error (can't |
745 # qpush A is an error (can't go backwards with qpush) |
749 # go backwards with qpush) |
746 if patch: |
750 if patch: |
747 info = self.isapplied(patch) |
751 info = self.isapplied(patch) |
748 if info: |
752 if info: |
749 if info[0] < len(self.applied) - 1: |
753 if info[0] < len(self.applied) - 1: |
750 raise util.Abort(_("cannot push to a previous patch: %s") % |
754 raise util.Abort( |
751 patch) |
755 _("cannot push to a previous patch: %s") % patch) |
752 if info[0] < len(self.series) - 1: |
756 if info[0] < len(self.series) - 1: |
753 self.ui.warn(_('qpush: %s is already at the top\n') % patch) |
757 self.ui.warn( |
|
758 _('qpush: %s is already at the top\n') % patch) |
|
759 else: |
|
760 self.ui.warn(_('all patches are currently applied\n')) |
|
761 return |
|
762 |
|
763 # Following the above example, starting at 'top' of B: |
|
764 # qpush should be performed (pushes C), but a subsequent |
|
765 # qpush without an argument is an error (nothing to |
|
766 # apply). This allows a loop of "...while hg qpush..." to |
|
767 # work as it detects an error when done |
|
768 if self.series_end() == len(self.series): |
|
769 self.ui.warn(_('patch series already fully applied\n')) |
|
770 return 1 |
|
771 if not force: |
|
772 self.check_localchanges(repo) |
|
773 |
|
774 self.applied_dirty = 1; |
|
775 start = self.series_end() |
|
776 if start > 0: |
|
777 self.check_toppatch(repo) |
|
778 if not patch: |
|
779 patch = self.series[start] |
|
780 end = start + 1 |
|
781 else: |
|
782 end = self.series.index(patch, start) + 1 |
|
783 s = self.series[start:end] |
|
784 all_files = {} |
|
785 try: |
|
786 if mergeq: |
|
787 ret = self.mergepatch(repo, mergeq, s) |
754 else: |
788 else: |
755 self.ui.warn(_('all patches are currently applied\n')) |
789 ret = self.apply(repo, s, list, all_files=all_files) |
756 return |
790 except: |
757 |
791 self.ui.warn(_('cleaning up working directory...')) |
758 # Following the above example, starting at 'top' of B: |
792 node = repo.dirstate.parents()[0] |
759 # qpush should be performed (pushes C), but a subsequent qpush without |
793 hg.revert(repo, node, None) |
760 # an argument is an error (nothing to apply). This allows a loop |
794 unknown = repo.status()[4] |
761 # of "...while hg qpush..." to work as it detects an error when done |
795 # only remove unknown files that we know we touched or |
762 if self.series_end() == len(self.series): |
796 # created while patching |
763 self.ui.warn(_('patch series already fully applied\n')) |
797 for f in unknown: |
764 return 1 |
798 if f in all_files: |
765 if not force: |
799 util.unlink(repo.wjoin(f)) |
766 self.check_localchanges(repo) |
800 self.ui.warn(_('done\n')) |
767 |
801 raise |
768 self.applied_dirty = 1; |
802 top = self.applied[-1].name |
769 start = self.series_end() |
803 if ret[0]: |
770 if start > 0: |
804 self.ui.write( |
771 self.check_toppatch(repo) |
805 "Errors during apply, please fix and refresh %s\n" % top) |
772 if not patch: |
|
773 patch = self.series[start] |
|
774 end = start + 1 |
|
775 else: |
|
776 end = self.series.index(patch, start) + 1 |
|
777 s = self.series[start:end] |
|
778 all_files = {} |
|
779 try: |
|
780 if mergeq: |
|
781 ret = self.mergepatch(repo, mergeq, s, wlock) |
|
782 else: |
806 else: |
783 ret = self.apply(repo, s, list, wlock=wlock, |
807 self.ui.write("Now at: %s\n" % top) |
784 all_files=all_files) |
808 return ret[0] |
785 except: |
809 finally: |
786 self.ui.warn(_('cleaning up working directory...')) |
810 del wlock |
787 node = repo.dirstate.parents()[0] |
811 |
788 hg.revert(repo, node, None, wlock) |
812 def pop(self, repo, patch=None, force=False, update=True, all=False): |
789 unknown = repo.status(wlock=wlock)[4] |
|
790 # only remove unknown files that we know we touched or |
|
791 # created while patching |
|
792 for f in unknown: |
|
793 if f in all_files: |
|
794 util.unlink(repo.wjoin(f)) |
|
795 self.ui.warn(_('done\n')) |
|
796 raise |
|
797 top = self.applied[-1].name |
|
798 if ret[0]: |
|
799 self.ui.write("Errors during apply, please fix and refresh %s\n" % |
|
800 top) |
|
801 else: |
|
802 self.ui.write("Now at: %s\n" % top) |
|
803 return ret[0] |
|
804 |
|
805 def pop(self, repo, patch=None, force=False, update=True, all=False, |
|
806 wlock=None): |
|
807 def getfile(f, rev): |
813 def getfile(f, rev): |
808 t = repo.file(f).read(rev) |
814 t = repo.file(f).read(rev) |
809 repo.wfile(f, "w").write(t) |
815 repo.wfile(f, "w").write(t) |
810 |
816 |
811 if not wlock: |
817 wlock = repo.wlock() |
812 wlock = repo.wlock() |
818 try: |
813 if patch: |
819 if patch: |
814 # index, rev, patch |
820 # index, rev, patch |
815 info = self.isapplied(patch) |
821 info = self.isapplied(patch) |
816 if not info: |
822 if not info: |
817 patch = self.lookup(patch) |
823 patch = self.lookup(patch) |
818 info = self.isapplied(patch) |
824 info = self.isapplied(patch) |
819 if not info: |
825 if not info: |
820 raise util.Abort(_("patch %s is not applied") % patch) |
826 raise util.Abort(_("patch %s is not applied") % patch) |
821 |
827 |
822 if len(self.applied) == 0: |
828 if len(self.applied) == 0: |
823 # Allow qpop -a to work repeatedly, |
829 # Allow qpop -a to work repeatedly, |
824 # but not qpop without an argument |
830 # but not qpop without an argument |
825 self.ui.warn(_("no patches applied\n")) |
831 self.ui.warn(_("no patches applied\n")) |
826 return not all |
832 return not all |
827 |
833 |
828 if not update: |
834 if not update: |
829 parents = repo.dirstate.parents() |
835 parents = repo.dirstate.parents() |
830 rr = [ revlog.bin(x.rev) for x in self.applied ] |
836 rr = [ revlog.bin(x.rev) for x in self.applied ] |
831 for p in parents: |
837 for p in parents: |
832 if p in rr: |
838 if p in rr: |
833 self.ui.warn("qpop: forcing dirstate update\n") |
839 self.ui.warn("qpop: forcing dirstate update\n") |
834 update = True |
840 update = True |
835 |
841 |
836 if not force and update: |
842 if not force and update: |
837 self.check_localchanges(repo) |
843 self.check_localchanges(repo) |
838 |
844 |
839 self.applied_dirty = 1; |
845 self.applied_dirty = 1; |
840 end = len(self.applied) |
846 end = len(self.applied) |
841 if not patch: |
847 if not patch: |
842 if all: |
848 if all: |
843 popi = 0 |
849 popi = 0 |
|
850 else: |
|
851 popi = len(self.applied) - 1 |
844 else: |
852 else: |
845 popi = len(self.applied) - 1 |
853 popi = info[0] + 1 |
846 else: |
854 if popi >= end: |
847 popi = info[0] + 1 |
855 self.ui.warn("qpop: %s is already at the top\n" % patch) |
848 if popi >= end: |
856 return |
849 self.ui.warn("qpop: %s is already at the top\n" % patch) |
857 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name] |
850 return |
858 |
851 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name] |
859 start = info[0] |
852 |
860 rev = revlog.bin(info[1]) |
853 start = info[0] |
861 |
854 rev = revlog.bin(info[1]) |
862 # we know there are no local changes, so we can make a simplified |
855 |
863 # form of hg.update. |
856 # we know there are no local changes, so we can make a simplified |
864 if update: |
857 # form of hg.update. |
865 top = self.check_toppatch(repo) |
858 if update: |
866 qp = self.qparents(repo, rev) |
859 top = self.check_toppatch(repo) |
867 changes = repo.changelog.read(qp) |
860 qp = self.qparents(repo, rev) |
868 mmap = repo.manifest.read(changes[0]) |
861 changes = repo.changelog.read(qp) |
869 m, a, r, d, u = repo.status(qp, top)[:5] |
862 mmap = repo.manifest.read(changes[0]) |
870 if d: |
863 m, a, r, d, u = repo.status(qp, top)[:5] |
871 raise util.Abort("deletions found between repo revs") |
864 if d: |
872 for f in m: |
865 raise util.Abort("deletions found between repo revs") |
873 getfile(f, mmap[f]) |
866 for f in m: |
874 for f in r: |
867 getfile(f, mmap[f]) |
875 getfile(f, mmap[f]) |
868 for f in r: |
876 util.set_exec(repo.wjoin(f), mmap.execf(f)) |
869 getfile(f, mmap[f]) |
877 for f in m + r: |
870 util.set_exec(repo.wjoin(f), mmap.execf(f)) |
878 repo.dirstate.normal(f) |
871 repo.dirstate.update(m + r, 'n') |
879 for f in a: |
872 for f in a: |
880 try: |
873 try: |
881 os.unlink(repo.wjoin(f)) |
874 os.unlink(repo.wjoin(f)) |
882 except OSError, e: |
875 except OSError, e: |
883 if e.errno != errno.ENOENT: |
876 if e.errno != errno.ENOENT: |
884 raise |
877 raise |
885 try: os.removedirs(os.path.dirname(repo.wjoin(f))) |
878 try: os.removedirs(os.path.dirname(repo.wjoin(f))) |
886 except: pass |
879 except: pass |
887 repo.dirstate.forget(f) |
880 if a: |
888 repo.dirstate.setparents(qp, revlog.nullid) |
881 repo.dirstate.forget(a) |
889 self.strip(repo, rev, update=False, backup='strip') |
882 repo.dirstate.setparents(qp, revlog.nullid) |
890 del self.applied[start:end] |
883 self.strip(repo, rev, update=False, backup='strip', wlock=wlock) |
891 if len(self.applied): |
884 del self.applied[start:end] |
892 self.ui.write("Now at: %s\n" % self.applied[-1].name) |
885 if len(self.applied): |
893 else: |
886 self.ui.write("Now at: %s\n" % self.applied[-1].name) |
894 self.ui.write("Patch queue now empty\n") |
887 else: |
895 finally: |
888 self.ui.write("Patch queue now empty\n") |
896 del wlock |
889 |
897 |
890 def diff(self, repo, pats, opts): |
898 def diff(self, repo, pats, opts): |
891 top = self.check_toppatch(repo) |
899 top = self.check_toppatch(repo) |
892 if not top: |
900 if not top: |
893 self.ui.write("No patches applied\n") |
901 self.ui.write("No patches applied\n") |
900 def refresh(self, repo, pats=None, **opts): |
908 def refresh(self, repo, pats=None, **opts): |
901 if len(self.applied) == 0: |
909 if len(self.applied) == 0: |
902 self.ui.write("No patches applied\n") |
910 self.ui.write("No patches applied\n") |
903 return 1 |
911 return 1 |
904 wlock = repo.wlock() |
912 wlock = repo.wlock() |
905 self.check_toppatch(repo) |
913 try: |
906 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name) |
914 self.check_toppatch(repo) |
907 top = revlog.bin(top) |
915 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name) |
908 cparents = repo.changelog.parents(top) |
916 top = revlog.bin(top) |
909 patchparent = self.qparents(repo, top) |
917 cparents = repo.changelog.parents(top) |
910 message, comments, user, date, patchfound = self.readheaders(patchfn) |
918 patchparent = self.qparents(repo, top) |
911 |
919 message, comments, user, date, patchfound = self.readheaders(patchfn) |
912 patchf = self.opener(patchfn, 'r+') |
920 |
913 |
921 patchf = self.opener(patchfn, 'r+') |
914 # if the patch was a git patch, refresh it as a git patch |
922 |
915 for line in patchf: |
923 # if the patch was a git patch, refresh it as a git patch |
916 if line.startswith('diff --git'): |
924 for line in patchf: |
|
925 if line.startswith('diff --git'): |
|
926 self.diffopts().git = True |
|
927 break |
|
928 patchf.seek(0) |
|
929 patchf.truncate() |
|
930 |
|
931 msg = opts.get('msg', '').rstrip() |
|
932 if msg: |
|
933 if comments: |
|
934 # Remove existing message. |
|
935 ci = 0 |
|
936 subj = None |
|
937 for mi in xrange(len(message)): |
|
938 if comments[ci].lower().startswith('subject: '): |
|
939 subj = comments[ci][9:] |
|
940 while message[mi] != comments[ci] and message[mi] != subj: |
|
941 ci += 1 |
|
942 del comments[ci] |
|
943 comments.append(msg) |
|
944 if comments: |
|
945 comments = "\n".join(comments) + '\n\n' |
|
946 patchf.write(comments) |
|
947 |
|
948 if opts.get('git'): |
917 self.diffopts().git = True |
949 self.diffopts().git = True |
918 break |
950 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
919 patchf.seek(0) |
951 tip = repo.changelog.tip() |
920 patchf.truncate() |
952 if top == tip: |
921 |
953 # if the top of our patch queue is also the tip, there is an |
922 msg = opts.get('msg', '').rstrip() |
954 # optimization here. We update the dirstate in place and strip |
923 if msg: |
955 # off the tip commit. Then just commit the current directory |
924 if comments: |
956 # tree. We can also send repo.commit the list of files |
925 # Remove existing message. |
957 # changed to speed up the diff |
926 ci = 0 |
958 # |
927 subj = None |
959 # in short mode, we only diff the files included in the |
928 for mi in xrange(len(message)): |
960 # patch already |
929 if comments[ci].lower().startswith('subject: '): |
961 # |
930 subj = comments[ci][9:] |
962 # this should really read: |
931 while message[mi] != comments[ci] and message[mi] != subj: |
963 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5] |
932 ci += 1 |
964 # but we do it backwards to take advantage of manifest/chlog |
933 del comments[ci] |
965 # caching against the next repo.status call |
934 comments.append(msg) |
966 # |
935 if comments: |
967 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5] |
936 comments = "\n".join(comments) + '\n\n' |
968 changes = repo.changelog.read(tip) |
937 patchf.write(comments) |
969 man = repo.manifest.read(changes[0]) |
938 |
970 aaa = aa[:] |
939 if opts.get('git'): |
971 if opts.get('short'): |
940 self.diffopts().git = True |
972 filelist = mm + aa + dd |
941 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
973 match = dict.fromkeys(filelist).__contains__ |
942 tip = repo.changelog.tip() |
974 else: |
943 if top == tip: |
975 filelist = None |
944 # if the top of our patch queue is also the tip, there is an |
976 match = util.always |
945 # optimization here. We update the dirstate in place and strip |
977 m, a, r, d, u = repo.status(files=filelist, match=match)[:5] |
946 # off the tip commit. Then just commit the current directory |
978 |
947 # tree. We can also send repo.commit the list of files |
979 # we might end up with files that were added between |
948 # changed to speed up the diff |
980 # tip and the dirstate parent, but then changed in the |
949 # |
981 # local dirstate. in this case, we want them to only |
950 # in short mode, we only diff the files included in the |
982 # show up in the added section |
951 # patch already |
983 for x in m: |
952 # |
984 if x not in aa: |
953 # this should really read: |
985 mm.append(x) |
954 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5] |
986 # we might end up with files added by the local dirstate that |
955 # but we do it backwards to take advantage of manifest/chlog |
987 # were deleted by the patch. In this case, they should only |
956 # caching against the next repo.status call |
988 # show up in the changed section. |
957 # |
989 for x in a: |
958 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5] |
990 if x in dd: |
959 changes = repo.changelog.read(tip) |
991 del dd[dd.index(x)] |
960 man = repo.manifest.read(changes[0]) |
992 mm.append(x) |
961 aaa = aa[:] |
993 else: |
962 if opts.get('short'): |
994 aa.append(x) |
963 filelist = mm + aa + dd |
995 # make sure any files deleted in the local dirstate |
964 match = dict.fromkeys(filelist).__contains__ |
996 # are not in the add or change column of the patch |
|
997 forget = [] |
|
998 for x in d + r: |
|
999 if x in aa: |
|
1000 del aa[aa.index(x)] |
|
1001 forget.append(x) |
|
1002 continue |
|
1003 elif x in mm: |
|
1004 del mm[mm.index(x)] |
|
1005 dd.append(x) |
|
1006 |
|
1007 m = util.unique(mm) |
|
1008 r = util.unique(dd) |
|
1009 a = util.unique(aa) |
|
1010 c = [filter(matchfn, l) for l in (m, a, r, [], u)] |
|
1011 filelist = util.unique(c[0] + c[1] + c[2]) |
|
1012 patch.diff(repo, patchparent, files=filelist, match=matchfn, |
|
1013 fp=patchf, changes=c, opts=self.diffopts()) |
|
1014 patchf.close() |
|
1015 |
|
1016 repo.dirstate.setparents(*cparents) |
|
1017 copies = {} |
|
1018 for dst in a: |
|
1019 src = repo.dirstate.copied(dst) |
|
1020 if src is None: |
|
1021 continue |
|
1022 copies.setdefault(src, []).append(dst) |
|
1023 repo.dirstate.add(dst) |
|
1024 # remember the copies between patchparent and tip |
|
1025 # this may be slow, so don't do it if we're not tracking copies |
|
1026 if self.diffopts().git: |
|
1027 for dst in aaa: |
|
1028 f = repo.file(dst) |
|
1029 src = f.renamed(man[dst]) |
|
1030 if src: |
|
1031 copies[src[0]] = copies.get(dst, []) |
|
1032 if dst in a: |
|
1033 copies[src[0]].append(dst) |
|
1034 # we can't copy a file created by the patch itself |
|
1035 if dst in copies: |
|
1036 del copies[dst] |
|
1037 for src, dsts in copies.iteritems(): |
|
1038 for dst in dsts: |
|
1039 repo.dirstate.copy(src, dst) |
|
1040 for f in r: |
|
1041 repo.dirstate.remove(f) |
|
1042 # if the patch excludes a modified file, mark that |
|
1043 # file with mtime=0 so status can see it. |
|
1044 mm = [] |
|
1045 for i in xrange(len(m)-1, -1, -1): |
|
1046 if not matchfn(m[i]): |
|
1047 mm.append(m[i]) |
|
1048 del m[i] |
|
1049 for f in m: |
|
1050 repo.dirstate.normal(f) |
|
1051 for f in mm: |
|
1052 repo.dirstate.normaldirty(f) |
|
1053 for f in forget: |
|
1054 repo.dirstate.forget(f) |
|
1055 |
|
1056 if not msg: |
|
1057 if not message: |
|
1058 message = "[mq]: %s\n" % patchfn |
|
1059 else: |
|
1060 message = "\n".join(message) |
|
1061 else: |
|
1062 message = msg |
|
1063 |
|
1064 self.strip(repo, top, update=False, |
|
1065 backup='strip') |
|
1066 n = repo.commit(filelist, message, changes[1], match=matchfn, |
|
1067 force=1) |
|
1068 self.applied[-1] = statusentry(revlog.hex(n), patchfn) |
|
1069 self.applied_dirty = 1 |
|
1070 self.removeundo(repo) |
965 else: |
1071 else: |
966 filelist = None |
1072 self.printdiff(repo, patchparent, fp=patchf) |
967 match = util.always |
1073 patchf.close() |
968 m, a, r, d, u = repo.status(files=filelist, match=match)[:5] |
1074 added = repo.status()[1] |
969 |
1075 for a in added: |
970 # we might end up with files that were added between tip and |
1076 f = repo.wjoin(a) |
971 # the dirstate parent, but then changed in the local dirstate. |
1077 try: |
972 # in this case, we want them to only show up in the added section |
1078 os.unlink(f) |
973 for x in m: |
1079 except OSError, e: |
974 if x not in aa: |
1080 if e.errno != errno.ENOENT: |
975 mm.append(x) |
1081 raise |
976 # we might end up with files added by the local dirstate that |
1082 try: os.removedirs(os.path.dirname(f)) |
977 # were deleted by the patch. In this case, they should only |
1083 except: pass |
978 # show up in the changed section. |
1084 # forget the file copies in the dirstate |
979 for x in a: |
1085 # push should readd the files later on |
980 if x in dd: |
1086 repo.dirstate.forget(a) |
981 del dd[dd.index(x)] |
1087 self.pop(repo, force=True) |
982 mm.append(x) |
1088 self.push(repo, force=True) |
983 else: |
1089 finally: |
984 aa.append(x) |
1090 del wlock |
985 # make sure any files deleted in the local dirstate |
|
986 # are not in the add or change column of the patch |
|
987 forget = [] |
|
988 for x in d + r: |
|
989 if x in aa: |
|
990 del aa[aa.index(x)] |
|
991 forget.append(x) |
|
992 continue |
|
993 elif x in mm: |
|
994 del mm[mm.index(x)] |
|
995 dd.append(x) |
|
996 |
|
997 m = util.unique(mm) |
|
998 r = util.unique(dd) |
|
999 a = util.unique(aa) |
|
1000 c = [filter(matchfn, l) for l in (m, a, r, [], u)] |
|
1001 filelist = util.unique(c[0] + c[1] + c[2]) |
|
1002 patch.diff(repo, patchparent, files=filelist, match=matchfn, |
|
1003 fp=patchf, changes=c, opts=self.diffopts()) |
|
1004 patchf.close() |
|
1005 |
|
1006 repo.dirstate.setparents(*cparents) |
|
1007 copies = {} |
|
1008 for dst in a: |
|
1009 src = repo.dirstate.copied(dst) |
|
1010 if src is None: |
|
1011 continue |
|
1012 copies.setdefault(src, []).append(dst) |
|
1013 repo.dirstate.update(a, 'a') |
|
1014 # remember the copies between patchparent and tip |
|
1015 # this may be slow, so don't do it if we're not tracking copies |
|
1016 if self.diffopts().git: |
|
1017 for dst in aaa: |
|
1018 f = repo.file(dst) |
|
1019 src = f.renamed(man[dst]) |
|
1020 if src: |
|
1021 copies[src[0]] = copies.get(dst, []) |
|
1022 if dst in a: |
|
1023 copies[src[0]].append(dst) |
|
1024 # we can't copy a file created by the patch itself |
|
1025 if dst in copies: |
|
1026 del copies[dst] |
|
1027 for src, dsts in copies.iteritems(): |
|
1028 for dst in dsts: |
|
1029 repo.dirstate.copy(src, dst) |
|
1030 repo.dirstate.update(r, 'r') |
|
1031 # if the patch excludes a modified file, mark that file with mtime=0 |
|
1032 # so status can see it. |
|
1033 mm = [] |
|
1034 for i in xrange(len(m)-1, -1, -1): |
|
1035 if not matchfn(m[i]): |
|
1036 mm.append(m[i]) |
|
1037 del m[i] |
|
1038 repo.dirstate.update(m, 'n') |
|
1039 repo.dirstate.update(mm, 'n', st_mtime=-1, st_size=-1) |
|
1040 repo.dirstate.forget(forget) |
|
1041 |
|
1042 if not msg: |
|
1043 if not message: |
|
1044 message = "[mq]: %s\n" % patchfn |
|
1045 else: |
|
1046 message = "\n".join(message) |
|
1047 else: |
|
1048 message = msg |
|
1049 |
|
1050 self.strip(repo, top, update=False, backup='strip', wlock=wlock) |
|
1051 n = repo.commit(filelist, message, changes[1], match=matchfn, |
|
1052 force=1, wlock=wlock) |
|
1053 self.applied[-1] = statusentry(revlog.hex(n), patchfn) |
|
1054 self.applied_dirty = 1 |
|
1055 self.removeundo(repo) |
|
1056 else: |
|
1057 self.printdiff(repo, patchparent, fp=patchf) |
|
1058 patchf.close() |
|
1059 added = repo.status()[1] |
|
1060 for a in added: |
|
1061 f = repo.wjoin(a) |
|
1062 try: |
|
1063 os.unlink(f) |
|
1064 except OSError, e: |
|
1065 if e.errno != errno.ENOENT: |
|
1066 raise |
|
1067 try: os.removedirs(os.path.dirname(f)) |
|
1068 except: pass |
|
1069 # forget the file copies in the dirstate |
|
1070 # push should readd the files later on |
|
1071 repo.dirstate.forget(added) |
|
1072 self.pop(repo, force=True, wlock=wlock) |
|
1073 self.push(repo, force=True, wlock=wlock) |
|
1074 |
1091 |
1075 def init(self, repo, create=False): |
1092 def init(self, repo, create=False): |
1076 if not create and os.path.isdir(self.path): |
1093 if not create and os.path.isdir(self.path): |
1077 raise util.Abort(_("patch queue directory already exists")) |
1094 raise util.Abort(_("patch queue directory already exists")) |
1078 try: |
1095 try: |
2100 (clone, |
2129 (clone, |
2101 [('', 'pull', None, _('use pull protocol to copy metadata')), |
2130 [('', 'pull', None, _('use pull protocol to copy metadata')), |
2102 ('U', 'noupdate', None, _('do not update the new working directories')), |
2131 ('U', 'noupdate', None, _('do not update the new working directories')), |
2103 ('', 'uncompressed', None, |
2132 ('', 'uncompressed', None, |
2104 _('use uncompressed transfer (fast over LAN)')), |
2133 _('use uncompressed transfer (fast over LAN)')), |
2105 ('e', 'ssh', '', _('specify ssh command to use')), |
|
2106 ('p', 'patches', '', _('location of source patch repo')), |
2134 ('p', 'patches', '', _('location of source patch repo')), |
2107 ('', 'remotecmd', '', |
2135 ] + commands.remoteopts, |
2108 _('specify hg command to run on the remote side'))], |
|
2109 _('hg qclone [OPTION]... SOURCE [DEST]')), |
2136 _('hg qclone [OPTION]... SOURCE [DEST]')), |
2110 "qcommit|qci": |
2137 "qcommit|qci": |
2111 (commit, |
2138 (commit, |
2112 commands.table["^commit|ci"][1], |
2139 commands.table["^commit|ci"][1], |
2113 _('hg qcommit [OPTION]... [FILE]...')), |
2140 _('hg qcommit [OPTION]... [FILE]...')), |
2114 "^qdiff": |
2141 "^qdiff": |
2115 (diff, |
2142 (diff, |
2116 [('g', 'git', None, _('use git extended diff format')), |
2143 [('g', 'git', None, _('use git extended diff format')), |
2117 ('I', 'include', [], _('include names matching the given patterns')), |
2144 ] + commands.walkopts, |
2118 ('X', 'exclude', [], _('exclude names matching the given patterns'))], |
|
2119 _('hg qdiff [-I] [-X] [-g] [FILE]...')), |
2145 _('hg qdiff [-I] [-X] [-g] [FILE]...')), |
2120 "qdelete|qremove|qrm": |
2146 "qdelete|qremove|qrm": |
2121 (delete, |
2147 (delete, |
2122 [('k', 'keep', None, _('keep patch file')), |
2148 [('k', 'keep', None, _('keep patch file')), |
2123 ('r', 'rev', [], _('stop managing a revision'))], |
2149 ('r', 'rev', [], _('stop managing a revision'))], |