summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorLorry <lorry@roadtrain.codethink.co.uk>2012-08-22 14:49:51 +0100
committerLorry <lorry@roadtrain.codethink.co.uk>2012-08-22 14:49:51 +0100
commita498da43c7fdb9f24b73680c02a4a3588cc62d9a (patch)
treedaf8119dae1749b5165b68033a1b23a7375ce9ce /tests
downloadmercurial-tarball-a498da43c7fdb9f24b73680c02a4a3588cc62d9a.tar.gz
Tarball conversion
Diffstat (limited to 'tests')
-rw-r--r--tests/README7
-rw-r--r--tests/autodiff.py46
-rw-r--r--tests/binfile.binbin0 -> 593 bytes
-rw-r--r--tests/blacklists/README14
-rw-r--r--tests/blacklists/inotify-failures21
-rw-r--r--tests/blacklists/linux-vfat35
-rw-r--r--tests/bundles/darcs1.hgbin0 -> 1314 bytes
-rw-r--r--tests/bundles/legacy-encoding.hgbin0 -> 548 bytes
-rw-r--r--tests/bundles/rebase-revset.hgbin0 -> 1844 bytes
-rw-r--r--tests/bundles/rebase.hgbin0 -> 1663 bytes
-rwxr-xr-xtests/bundles/rebase.sh44
-rw-r--r--tests/bundles/remote.hgbin0 -> 1768 bytes
-rwxr-xr-xtests/bundles/remote.sh32
-rwxr-xr-xtests/bundles/rename.sh30
-rw-r--r--tests/bundles/renames.hgbin0 -> 1600 bytes
-rw-r--r--tests/bundles/tampered.hgbin0 -> 1171 bytes
-rw-r--r--tests/bundles/test-keyword.hgbin0 -> 302 bytes
-rw-r--r--tests/bundles/test-manifest.hgbin0 -> 596 bytes
-rw-r--r--tests/bundles/test-merge-symlinks.hgbin0 -> 947 bytes
-rw-r--r--tests/bundles/test-no-symlinks.hgbin0 -> 558 bytes
-rw-r--r--tests/bzr-definitions19
-rw-r--r--tests/cgienv29
-rwxr-xr-xtests/dummyssh24
-rwxr-xr-xtests/filtercr.py10
-rwxr-xr-xtests/filterpyflakes.py38
-rwxr-xr-xtests/get-with-headers.py53
-rw-r--r--tests/gpg/pubring.gpgbin0 -> 597 bytes
-rw-r--r--tests/gpg/random_seedbin0 -> 600 bytes
-rw-r--r--tests/gpg/secring.gpgbin0 -> 1248 bytes
-rw-r--r--tests/gpg/trustdb.gpgbin0 -> 1280 bytes
-rw-r--r--tests/heredoctest.py19
-rwxr-xr-xtests/hghave77
-rwxr-xr-xtests/hghave.py308
-rw-r--r--tests/hgterm.ti27
-rw-r--r--tests/histedit-helpers.sh6
-rwxr-xr-xtests/killdaemons.py25
-rwxr-xr-xtests/md5sum.py42
-rw-r--r--tests/missing-comment.hgbin0 -> 1077 bytes
-rw-r--r--tests/notcapable24
-rw-r--r--tests/printenv.py49
-rwxr-xr-xtests/readlink.py13
-rwxr-xr-xtests/revlog-formatv0.py60
-rwxr-xr-xtests/run-tests.py1324
-rw-r--r--tests/sitecustomize.py5
-rwxr-xr-xtests/svn-safe-append.py25
-rw-r--r--tests/svn/branches.svndump416
-rw-r--r--tests/svn/empty.svndump129
-rw-r--r--tests/svn/encoding.svndump280
-rw-r--r--tests/svn/move.svndump569
-rw-r--r--tests/svn/replace.svndump367
-rw-r--r--tests/svn/startrev.svndump240
-rwxr-xr-xtests/svn/svndump-branches.sh73
-rwxr-xr-xtests/svn/svndump-empty.sh47
-rwxr-xr-xtests/svn/svndump-encoding.sh57
-rwxr-xr-xtests/svn/svndump-move.sh83
-rwxr-xr-xtests/svn/svndump-replace.sh81
-rwxr-xr-xtests/svn/svndump-startrev.sh45
-rwxr-xr-xtests/svn/svndump-tags.sh57
-rw-r--r--tests/svn/tags.svndump364
-rw-r--r--tests/svnxml.py51
-rw-r--r--tests/test-1102.t17
-rw-r--r--tests/test-1993.t48
-rw-r--r--tests/test-586.t92
-rw-r--r--tests/test-abort-checkin.t35
-rw-r--r--tests/test-acl.t2133
-rw-r--r--tests/test-add.t140
-rw-r--r--tests/test-addremove-similar.t102
-rw-r--r--tests/test-addremove.t48
-rw-r--r--tests/test-alias.t428
-rw-r--r--tests/test-annotate.t322
-rw-r--r--tests/test-archive-symlinks.t40
-rw-r--r--tests/test-archive.t272
-rw-r--r--tests/test-atomictempfile.py48
-rw-r--r--tests/test-atomictempfile.py.out3
-rw-r--r--tests/test-audit-path.t92
-rw-r--r--tests/test-backout.t294
-rw-r--r--tests/test-backwards-remove.t16
-rw-r--r--tests/test-bad-extension.t15
-rw-r--r--tests/test-bad-pull.t33
-rw-r--r--tests/test-basic.t57
-rw-r--r--tests/test-batching.py175
-rw-r--r--tests/test-batching.py.out32
-rw-r--r--tests/test-bdiff.py66
-rw-r--r--tests/test-bdiff.py.out24
-rw-r--r--tests/test-bheads.t375
-rw-r--r--tests/test-bisect.t510
-rw-r--r--tests/test-bisect2.t795
-rw-r--r--tests/test-bisect3.t232
-rw-r--r--tests/test-bookmarks-current.t170
-rw-r--r--tests/test-bookmarks-merge.t93
-rw-r--r--tests/test-bookmarks-pushpull.t298
-rw-r--r--tests/test-bookmarks-rebase.t66
-rw-r--r--tests/test-bookmarks-strip.t116
-rw-r--r--tests/test-bookmarks.t459
-rw-r--r--tests/test-branch-option.t132
-rw-r--r--tests/test-branch-tag-confict.t65
-rw-r--r--tests/test-branches.t412
-rw-r--r--tests/test-bundle-r.t328
-rw-r--r--tests/test-bundle-type.t100
-rw-r--r--tests/test-bundle-vs-outgoing.t145
-rw-r--r--tests/test-bundle.t603
-rw-r--r--tests/test-casecollision-merge.t209
-rw-r--r--tests/test-casecollision.t71
-rw-r--r--tests/test-casefolding.t163
-rw-r--r--tests/test-cat.t23
-rw-r--r--tests/test-changelog-exec.t55
-rw-r--r--tests/test-check-code-hg.t183
-rw-r--r--tests/test-check-code.t142
-rw-r--r--tests/test-check-pyflakes.t6
-rw-r--r--tests/test-children.t125
-rw-r--r--tests/test-churn.t162
-rw-r--r--tests/test-clone-cgi.t31
-rw-r--r--tests/test-clone-pull-corruption.t52
-rw-r--r--tests/test-clone-r.t220
-rw-r--r--tests/test-clone-update-order.t105
-rw-r--r--tests/test-clone.t567
-rw-r--r--tests/test-command-template.t1383
-rw-r--r--tests/test-commandserver.py260
-rw-r--r--tests/test-commandserver.py.out165
-rw-r--r--tests/test-commit-amend.t357
-rw-r--r--tests/test-commit-multiple.t133
-rw-r--r--tests/test-commit-unresolved.t49
-rw-r--r--tests/test-commit.t307
-rw-r--r--tests/test-committer.t65
-rw-r--r--tests/test-config-case.t11
-rw-r--r--tests/test-conflict.t33
-rw-r--r--tests/test-confused-revert.t82
-rw-r--r--tests/test-context.py32
-rw-r--r--tests/test-context.py.out4
-rw-r--r--tests/test-contrib.t306
-rw-r--r--tests/test-convert-authormap.t58
-rw-r--r--tests/test-convert-baz.t163
-rw-r--r--tests/test-convert-bzr-114.t39
-rw-r--r--tests/test-convert-bzr-directories.t193
-rw-r--r--tests/test-convert-bzr-ghosts.t38
-rw-r--r--tests/test-convert-bzr-merges.t70
-rw-r--r--tests/test-convert-bzr-treeroot.t35
-rw-r--r--tests/test-convert-bzr.t286
-rw-r--r--tests/test-convert-clonebranches.t88
-rw-r--r--tests/test-convert-cvs-branch.t193
-rw-r--r--tests/test-convert-cvs-detectmerge.t233
-rw-r--r--tests/test-convert-cvs-synthetic.t217
-rw-r--r--tests/test-convert-cvs.t461
-rw-r--r--tests/test-convert-cvsnt-mergepoints.rlog42
-rw-r--r--tests/test-convert-cvsnt-mergepoints.t207
-rw-r--r--tests/test-convert-darcs.t110
-rw-r--r--tests/test-convert-datesort.t119
-rw-r--r--tests/test-convert-filemap.t596
-rw-r--r--tests/test-convert-git.t300
-rw-r--r--tests/test-convert-hg-sink.t124
-rw-r--r--tests/test-convert-hg-source.t149
-rw-r--r--tests/test-convert-hg-startrev.t174
-rw-r--r--tests/test-convert-hg-svn.t105
-rw-r--r--tests/test-convert-mtn-rename-directory.out23
-rw-r--r--tests/test-convert-mtn.t388
-rw-r--r--tests/test-convert-p4-filetypes.t733
-rw-r--r--tests/test-convert-p4.t152
-rw-r--r--tests/test-convert-splicemap.t222
-rw-r--r--tests/test-convert-svn-branches.t103
-rw-r--r--tests/test-convert-svn-encoding.t135
-rw-r--r--tests/test-convert-svn-move.t243
-rw-r--r--tests/test-convert-svn-sink.t432
-rw-r--r--tests/test-convert-svn-source.t203
-rw-r--r--tests/test-convert-svn-startrev.t90
-rw-r--r--tests/test-convert-svn-tags.t67
-rw-r--r--tests/test-convert-tagsbranch-topology.t90
-rw-r--r--tests/test-convert-tla.t135
-rw-r--r--tests/test-convert.t447
-rw-r--r--tests/test-copy-move-merge.t64
-rw-r--r--tests/test-copy.t216
-rw-r--r--tests/test-custom-filters.t66
-rw-r--r--tests/test-debugbuilddag.t350
-rw-r--r--tests/test-debugbundle.t37
-rw-r--r--tests/test-debugcommands.t25
-rw-r--r--tests/test-debugcomplete.t276
-rw-r--r--tests/test-debugindexdot.t25
-rw-r--r--tests/test-debugrename.t18
-rw-r--r--tests/test-default-push.t38
-rw-r--r--tests/test-demandimport.py39
-rw-r--r--tests/test-demandimport.py.out15
-rw-r--r--tests/test-diff-binary-file.t40
-rw-r--r--tests/test-diff-change.t93
-rw-r--r--tests/test-diff-color.t130
-rw-r--r--tests/test-diff-copy-depth.t51
-rw-r--r--tests/test-diff-hashes.t46
-rw-r--r--tests/test-diff-ignore-whitespace.t500
-rw-r--r--tests/test-diff-issue2761.t23
-rw-r--r--tests/test-diff-newlines.t18
-rw-r--r--tests/test-diff-reverse.t44
-rw-r--r--tests/test-diff-subdir.t47
-rw-r--r--tests/test-diff-unified.t198
-rw-r--r--tests/test-diff-upgrade.t283
-rw-r--r--tests/test-diffdir.t40
-rw-r--r--tests/test-diffstat.t72
-rw-r--r--tests/test-dirstate-race.t33
-rw-r--r--tests/test-dirstate.t56
-rw-r--r--tests/test-dispatch.py33
-rw-r--r--tests/test-dispatch.py.out23
-rw-r--r--tests/test-dispatch.t58
-rw-r--r--tests/test-doctest.py44
-rw-r--r--tests/test-double-merge.t67
-rw-r--r--tests/test-duplicateoptions.py36
-rw-r--r--tests/test-empty-dir.t23
-rw-r--r--tests/test-empty-file.t47
-rw-r--r--tests/test-empty-group.t127
-rw-r--r--tests/test-empty.t55
-rw-r--r--tests/test-encode.t63
-rw-r--r--tests/test-encoding-align.t145
-rw-r--r--tests/test-encoding-textwrap.t259
-rw-r--r--tests/test-encoding.t252
-rw-r--r--tests/test-eol-add.t125
-rw-r--r--tests/test-eol-clone.t76
-rw-r--r--tests/test-eol-hook.t218
-rw-r--r--tests/test-eol-patch.t400
-rw-r--r--tests/test-eol-tag.t39
-rw-r--r--tests/test-eol-update.t152
-rw-r--r--tests/test-eol.t528
-rw-r--r--tests/test-eolfilename.t72
-rw-r--r--tests/test-excessive-merge.t101
-rw-r--r--tests/test-execute-bit.t28
-rw-r--r--tests/test-export.t147
-rw-r--r--tests/test-extdiff.t204
-rw-r--r--tests/test-extension.t561
-rw-r--r--tests/test-extra-filelog-entry.t21
-rw-r--r--tests/test-fetch.t414
-rw-r--r--tests/test-filebranch.t149
-rw-r--r--tests/test-filecache.py95
-rw-r--r--tests/test-filecache.py.out15
-rwxr-xr-xtests/test-filelog.py55
-rw-r--r--tests/test-filelog.py.out2
-rw-r--r--tests/test-flags.t151
-rw-r--r--tests/test-fncache.t119
-rw-r--r--tests/test-gendoc.t57
-rw-r--r--tests/test-getbundle.t254
-rw-r--r--tests/test-git-export.t362
-rw-r--r--tests/test-globalopts.t449
-rw-r--r--tests/test-glog.t2088
-rw-r--r--tests/test-gpg.t34
-rw-r--r--tests/test-graft.t535
-rw-r--r--tests/test-grep.t176
-rw-r--r--tests/test-hardlinks.t352
-rw-r--r--tests/test-help.t804
-rw-r--r--tests/test-hg-parseurl.py13
-rw-r--r--tests/test-hg-parseurl.py.out8
-rw-r--r--tests/test-hgcia.t94
-rw-r--r--tests/test-hghave.t3
-rw-r--r--tests/test-hgignore.t126
-rw-r--r--tests/test-hgk.t20
-rw-r--r--tests/test-hgrc.t203
-rw-r--r--tests/test-hgweb-auth.py107
-rw-r--r--tests/test-hgweb-auth.py.out196
-rw-r--r--tests/test-hgweb-commands.t1363
-rw-r--r--tests/test-hgweb-descend-empties.t144
-rw-r--r--tests/test-hgweb-diffs.t986
-rw-r--r--tests/test-hgweb-empty.t399
-rw-r--r--tests/test-hgweb-filelog.t765
-rw-r--r--tests/test-hgweb-no-path-info.t109
-rw-r--r--tests/test-hgweb-no-request-uri.t143
-rw-r--r--tests/test-hgweb-non-interactive.t82
-rw-r--r--tests/test-hgweb-raw.t58
-rw-r--r--tests/test-hgweb-removed.t236
-rw-r--r--tests/test-hgweb.t492
-rw-r--r--tests/test-hgwebdir-paths.py40
-rw-r--r--tests/test-hgwebdir.t1015
-rw-r--r--tests/test-hgwebdirsym.t80
-rw-r--r--tests/test-highlight.t609
-rw-r--r--tests/test-histedit-bookmark-motion.t187
-rw-r--r--tests/test-histedit-commute.t359
-rw-r--r--tests/test-histedit-drop.t107
-rw-r--r--tests/test-histedit-edit.t178
-rw-r--r--tests/test-histedit-fold-non-commute.t147
-rw-r--r--tests/test-histedit-fold.t238
-rw-r--r--tests/test-histedit-no-change.t187
-rw-r--r--tests/test-histedit-non-commute-abort.t131
-rw-r--r--tests/test-histedit-non-commute.t244
-rw-r--r--tests/test-histedit-outgoing.t84
-rw-r--r--tests/test-histedit-revspec.t62
-rw-r--r--tests/test-hook.t644
-rw-r--r--tests/test-http-branchmap.t94
-rw-r--r--tests/test-http-clone-r.t200
-rw-r--r--tests/test-http-proxy.t124
-rw-r--r--tests/test-http.t207
-rw-r--r--tests/test-https.t281
-rw-r--r--tests/test-hup.t28
-rw-r--r--tests/test-hybridencode.py27
-rw-r--r--tests/test-hybridencode.py.out21
-rw-r--r--tests/test-i18n.t40
-rw-r--r--tests/test-identify.t124
-rw-r--r--tests/test-impexp-branch.t73
-rw-r--r--tests/test-import-bypass.t270
-rw-r--r--tests/test-import-context.t126
-rw-r--r--tests/test-import-eol.t146
-rw-r--r--tests/test-import-git.t611
-rw-r--r--tests/test-import-merge.t115
-rw-r--r--tests/test-import-unknown.t69
-rw-r--r--tests/test-import.t1155
-rw-r--r--tests/test-incoming-outgoing.t491
-rw-r--r--tests/test-inherit-mode.t152
-rw-r--r--tests/test-init.t199
-rw-r--r--tests/test-inotify-debuginotify.t41
-rw-r--r--tests/test-inotify-dirty-dirstate.t72
-rw-r--r--tests/test-inotify-issue1208.t38
-rw-r--r--tests/test-inotify-issue1371.t44
-rw-r--r--tests/test-inotify-issue1542.t36
-rw-r--r--tests/test-inotify-issue1556.t31
-rw-r--r--tests/test-inotify-lookup.t14
-rw-r--r--tests/test-inotify.t162
-rw-r--r--tests/test-install.t20
-rw-r--r--tests/test-interhg.t33
-rw-r--r--tests/test-issue1089.t26
-rw-r--r--tests/test-issue1175.t53
-rw-r--r--tests/test-issue1306.t96
-rw-r--r--tests/test-issue1438.t23
-rw-r--r--tests/test-issue1502.t41
-rw-r--r--tests/test-issue1802.t73
-rw-r--r--tests/test-issue1877.t46
-rw-r--r--tests/test-issue2137.t56
-rw-r--r--tests/test-issue3084.t110
-rw-r--r--tests/test-issue522.t56
-rw-r--r--tests/test-issue612.t34
-rw-r--r--tests/test-issue619.t30
-rw-r--r--tests/test-issue660.t145
-rw-r--r--tests/test-issue672.t101
-rw-r--r--tests/test-issue842.t39
-rw-r--r--tests/test-journal-exists.t36
-rw-r--r--tests/test-keyword.t1139
-rw-r--r--tests/test-known.t38
-rw-r--r--tests/test-largefiles-cache.t125
-rw-r--r--tests/test-largefiles-small-disk.t67
-rw-r--r--tests/test-largefiles.t1447
-rw-r--r--tests/test-lfconvert.t272
-rw-r--r--tests/test-locate.t121
-rw-r--r--tests/test-lock-badness.t24
-rw-r--r--tests/test-log.t1215
-rw-r--r--tests/test-mactext.t38
-rw-r--r--tests/test-manifest-merging.t37
-rw-r--r--tests/test-manifest.t69
-rw-r--r--tests/test-merge-closedheads.t87
-rw-r--r--tests/test-merge-commit.t184
-rw-r--r--tests/test-merge-default.t111
-rw-r--r--tests/test-merge-force.t45
-rw-r--r--tests/test-merge-internal-tools-pattern.t112
-rw-r--r--tests/test-merge-local.t138
-rw-r--r--tests/test-merge-prompt.t142
-rw-r--r--tests/test-merge-remove.t87
-rw-r--r--tests/test-merge-revert.t74
-rw-r--r--tests/test-merge-revert2.t94
-rw-r--r--tests/test-merge-subrepos.t25
-rw-r--r--tests/test-merge-symlinks.t63
-rw-r--r--tests/test-merge-tools.t806
-rw-r--r--tests/test-merge-types.t110
-rw-r--r--tests/test-merge1.t176
-rw-r--r--tests/test-merge10.t53
-rw-r--r--tests/test-merge2.t53
-rw-r--r--tests/test-merge4.t25
-rw-r--r--tests/test-merge5.t37
-rw-r--r--tests/test-merge6.t70
-rw-r--r--tests/test-merge7.t147
-rw-r--r--tests/test-merge8.t29
-rw-r--r--tests/test-merge9.t94
-rw-r--r--tests/test-minirst.py245
-rw-r--r--tests/test-minirst.py.out766
-rw-r--r--tests/test-mq-caches.t126
-rw-r--r--tests/test-mq-eol.t207
-rw-r--r--tests/test-mq-git.t210
-rw-r--r--tests/test-mq-guards.t509
-rw-r--r--tests/test-mq-header-date.t902
-rw-r--r--tests/test-mq-header-from.t971
-rw-r--r--tests/test-mq-merge.t173
-rw-r--r--tests/test-mq-missingfiles.t195
-rw-r--r--tests/test-mq-pull-from-bundle.t135
-rw-r--r--tests/test-mq-qclone-http.t153
-rw-r--r--tests/test-mq-qdelete.t197
-rw-r--r--tests/test-mq-qdiff.t177
-rw-r--r--tests/test-mq-qfold.t144
-rw-r--r--tests/test-mq-qgoto.t78
-rw-r--r--tests/test-mq-qimport-fail-cleanup.t42
-rw-r--r--tests/test-mq-qimport.t280
-rw-r--r--tests/test-mq-qnew.t235
-rw-r--r--tests/test-mq-qpush-exact.t289
-rw-r--r--tests/test-mq-qpush-fail.t426
-rw-r--r--tests/test-mq-qqueue.t188
-rw-r--r--tests/test-mq-qrefresh-interactive.t350
-rw-r--r--tests/test-mq-qrefresh-replace-log-message.t61
-rw-r--r--tests/test-mq-qrefresh.t546
-rw-r--r--tests/test-mq-qrename.t125
-rw-r--r--tests/test-mq-qsave.t15
-rw-r--r--tests/test-mq-safety.t216
-rw-r--r--tests/test-mq-strip.t468
-rw-r--r--tests/test-mq-subrepo-svn.t54
-rw-r--r--tests/test-mq-subrepo.t514
-rw-r--r--tests/test-mq-symlinks.t108
-rw-r--r--tests/test-mq.t1552
-rw-r--r--tests/test-mv-cp-st-diff.t1348
-rw-r--r--tests/test-nested-repo.t41
-rw-r--r--tests/test-newbranch.t330
-rw-r--r--tests/test-newcgi.t66
-rw-r--r--tests/test-newercgi.t60
-rw-r--r--tests/test-no-symlinks.t59
-rw-r--r--tests/test-notify-changegroup.t214
-rw-r--r--tests/test-notify.t475
-rw-r--r--tests/test-obsolete-changeset-exchange.t55
-rw-r--r--tests/test-obsolete.t508
-rw-r--r--tests/test-oldcgi.t76
-rw-r--r--tests/test-parents.t154
-rw-r--r--tests/test-parse-date.t236
-rw-r--r--tests/test-parseindex.t61
-rw-r--r--tests/test-parseindex2.py126
-rw-r--r--tests/test-parseindex2.py.out1
-rw-r--r--tests/test-patch-offset.t79
-rw-r--r--tests/test-patch.t89
-rw-r--r--tests/test-patchbomb.t2351
-rw-r--r--tests/test-paths.t65
-rw-r--r--tests/test-pending.t115
-rw-r--r--tests/test-permissions.t72
-rw-r--r--tests/test-phases-exchange.t1065
-rw-r--r--tests/test-phases.t479
-rw-r--r--tests/test-profile.t31
-rw-r--r--tests/test-progress.t216
-rw-r--r--tests/test-pull-branch.t216
-rw-r--r--tests/test-pull-http.t65
-rw-r--r--tests/test-pull-permission.t32
-rw-r--r--tests/test-pull-pull-corruption.t72
-rw-r--r--tests/test-pull-r.t104
-rw-r--r--tests/test-pull-update.t62
-rw-r--r--tests/test-pull.t92
-rw-r--r--tests/test-purge.t218
-rw-r--r--tests/test-push-cgi.t92
-rw-r--r--tests/test-push-hook-lock.t31
-rw-r--r--tests/test-push-http.t123
-rw-r--r--tests/test-push-r.t149
-rw-r--r--tests/test-push-validation.t53
-rw-r--r--tests/test-push-warn.t732
-rw-r--r--tests/test-qrecord.t402
-rw-r--r--tests/test-rebase-abort.t158
-rw-r--r--tests/test-rebase-bookmarks.t113
-rw-r--r--tests/test-rebase-cache.t387
-rw-r--r--tests/test-rebase-check-restore.t150
-rw-r--r--tests/test-rebase-collapse.t722
-rw-r--r--tests/test-rebase-conflicts.t121
-rw-r--r--tests/test-rebase-detach.t400
-rw-r--r--tests/test-rebase-interruptions.t268
-rw-r--r--tests/test-rebase-issue-noparam-single-rev.t128
-rw-r--r--tests/test-rebase-mq-skip.t139
-rw-r--r--tests/test-rebase-mq.t343
-rw-r--r--tests/test-rebase-named-branches.t243
-rw-r--r--tests/test-rebase-newancestor.t56
-rw-r--r--tests/test-rebase-parameters.t430
-rw-r--r--tests/test-rebase-pull.t116
-rw-r--r--tests/test-rebase-rename.t171
-rw-r--r--tests/test-rebase-scenario-global.t547
-rw-r--r--tests/test-rebuildstate.t30
-rw-r--r--tests/test-record.t1221
-rw-r--r--tests/test-relink.t100
-rw-r--r--tests/test-remove.t268
-rw-r--r--tests/test-rename-after-merge.t121
-rw-r--r--tests/test-rename-dir-merge.t159
-rw-r--r--tests/test-rename-merge1.t195
-rw-r--r--tests/test-rename-merge2.t754
-rw-r--r--tests/test-rename.t637
-rw-r--r--tests/test-repair-strip.t132
-rw-r--r--tests/test-requires.t19
-rw-r--r--tests/test-resolve.t46
-rw-r--r--tests/test-revert-flags.t23
-rw-r--r--tests/test-revert-unknown.t29
-rw-r--r--tests/test-revert.t278
-rw-r--r--tests/test-revlog-ancestry.py77
-rw-r--r--tests/test-revlog-ancestry.py.out15
-rw-r--r--tests/test-revlog-group-emptyiter.t35
-rw-r--r--tests/test-revlog-packentry.t23
-rw-r--r--tests/test-revset-dirstate-parents.t60
-rw-r--r--tests/test-revset-outgoing.t94
-rw-r--r--tests/test-revset.t817
-rw-r--r--tests/test-rollback.t187
-rw-r--r--tests/test-run-tests.t99
-rw-r--r--tests/test-schemes.t50
-rw-r--r--tests/test-serve.t84
-rw-r--r--tests/test-setdiscovery.t327
-rw-r--r--tests/test-share.t129
-rw-r--r--tests/test-simple-update.t58
-rw-r--r--tests/test-simplemerge.py415
-rw-r--r--tests/test-simplemerge.py.out5
-rw-r--r--tests/test-ssh-clone-r.t195
-rw-r--r--tests/test-ssh.t376
-rw-r--r--tests/test-static-http.t174
-rw-r--r--tests/test-status-color.t300
-rwxr-xr-xtests/test-status-inprocess.py31
-rw-r--r--tests/test-status-inprocess.py.out5
-rw-r--r--tests/test-status.t333
-rw-r--r--tests/test-strict.t49
-rw-r--r--tests/test-strip-cross.t143
-rw-r--r--tests/test-subrepo-deep-nested-change.t264
-rw-r--r--tests/test-subrepo-git.t534
-rw-r--r--tests/test-subrepo-missing.t71
-rw-r--r--tests/test-subrepo-paths.t61
-rw-r--r--tests/test-subrepo-recursion.t494
-rw-r--r--tests/test-subrepo-relative-path.t105
-rw-r--r--tests/test-subrepo-svn.t625
-rw-r--r--tests/test-subrepo.t1023
-rw-r--r--tests/test-symlink-os-yes-fs-no.py45
-rw-r--r--tests/test-symlink-os-yes-fs-no.py.out14
-rw-r--r--tests/test-symlink-placeholder.t72
-rw-r--r--tests/test-symlinks.t256
-rw-r--r--tests/test-tag.t319
-rw-r--r--tests/test-tags.t384
-rw-r--r--tests/test-template-engine.t39
-rw-r--r--tests/test-transplant.t634
-rw-r--r--tests/test-treediscovery-legacy.t371
-rw-r--r--tests/test-treediscovery.t504
-rw-r--r--tests/test-trusted.py197
-rw-r--r--tests/test-trusted.py.out179
-rw-r--r--tests/test-ui-color.py33
-rw-r--r--tests/test-ui-color.py.out5
-rw-r--r--tests/test-ui-config.py98
-rw-r--r--tests/test-ui-config.py.out49
-rw-r--r--tests/test-ui-verbosity.py47
-rw-r--r--tests/test-ui-verbosity.py.out66
-rw-r--r--tests/test-unbundlehash.t32
-rw-r--r--tests/test-unrelated-pull.t45
-rw-r--r--tests/test-up-local-change.t238
-rw-r--r--tests/test-update-branches.t156
-rw-r--r--tests/test-update-issue1456.t36
-rw-r--r--tests/test-update-renames.t27
-rw-r--r--tests/test-update-reverse.t85
-rw-r--r--tests/test-url-rev.t210
-rw-r--r--tests/test-url.py246
-rw-r--r--tests/test-username-newline.t25
-rw-r--r--tests/test-verify.t103
-rw-r--r--tests/test-walk.t333
-rw-r--r--tests/test-walkrepo.py55
-rw-r--r--tests/test-win32text.t426
-rw-r--r--tests/test-wireproto.py45
-rw-r--r--tests/test-wireproto.py.out2
-rw-r--r--tests/test-wireproto.t114
-rwxr-xr-xtests/tinyproxy.py147
535 files changed, 106411 insertions, 0 deletions
diff --git a/tests/README b/tests/README
new file mode 100644
index 0000000..41fe083
--- /dev/null
+++ b/tests/README
@@ -0,0 +1,7 @@
+To run the tests, do:
+
+cd tests/
+python run-tests.py
+
+See http://mercurial.selenic.com/wiki/WritingTests for
+more information on writing tests.
diff --git a/tests/autodiff.py b/tests/autodiff.py
new file mode 100644
index 0000000..155b9a0
--- /dev/null
+++ b/tests/autodiff.py
@@ -0,0 +1,46 @@
+# Extension dedicated to test patch.diff() upgrade modes
+#
+#
+from mercurial import scmutil, patch, util
+
+def autodiff(ui, repo, *pats, **opts):
+ diffopts = patch.diffopts(ui, opts)
+ git = opts.get('git', 'no')
+ brokenfiles = set()
+ losedatafn = None
+ if git in ('yes', 'no'):
+ diffopts.git = git == 'yes'
+ diffopts.upgrade = False
+ elif git == 'auto':
+ diffopts.git = False
+ diffopts.upgrade = True
+ elif git == 'warn':
+ diffopts.git = False
+ diffopts.upgrade = True
+ def losedatafn(fn=None, **kwargs):
+ brokenfiles.add(fn)
+ return True
+ elif git == 'abort':
+ diffopts.git = False
+ diffopts.upgrade = True
+ def losedatafn(fn=None, **kwargs):
+ raise util.Abort('losing data for %s' % fn)
+ else:
+ raise util.Abort('--git must be yes, no or auto')
+
+ node1, node2 = scmutil.revpair(repo, [])
+ m = scmutil.match(repo[node2], pats, opts)
+ it = patch.diff(repo, node1, node2, match=m, opts=diffopts,
+ losedatafn=losedatafn)
+ for chunk in it:
+ ui.write(chunk)
+ for fn in sorted(brokenfiles):
+ ui.write('data lost for: %s\n' % fn)
+
+cmdtable = {
+ "autodiff":
+ (autodiff,
+ [('', 'git', '', 'git upgrade mode (yes/no/auto/warn/abort)'),
+ ],
+ '[OPTION]... [FILE]...'),
+}
diff --git a/tests/binfile.bin b/tests/binfile.bin
new file mode 100644
index 0000000..37ba3d1
--- /dev/null
+++ b/tests/binfile.bin
Binary files differ
diff --git a/tests/blacklists/README b/tests/blacklists/README
new file mode 100644
index 0000000..e72906d
--- /dev/null
+++ b/tests/blacklists/README
@@ -0,0 +1,14 @@
+Put here definitions of blacklists for run-tests.py
+
+Create a file per blacklist. Each file should list the names of tests that you
+want to be skipped.
+File names are meant to be used as targets for run-tests.py --blacklist
+option.
+Lines starting with # are ignored. White spaces are stripped.
+
+e.g. if you create a blacklist/example file containing:
+ test-hgrc
+ # some comment
+ test-help
+then calling "run-tests.py --blacklist blacklists/example" will exclude
+test-hgrc and test-help from the list of tests to run.
diff --git a/tests/blacklists/inotify-failures b/tests/blacklists/inotify-failures
new file mode 100644
index 0000000..4860e08
--- /dev/null
+++ b/tests/blacklists/inotify-failures
@@ -0,0 +1,21 @@
+# When --inotify is activated, help output and config changes:
+test-debugcomplete
+test-empty
+test-fncache
+test-globalopts
+test-help
+test-hgrc
+test-inherit-mode
+test-qrecord
+test-strict
+
+# --inotify activates de facto the inotify extension. It does not play well
+# with inotify-specific tests, which activate/desactivate inotify at will:
+test-inotify
+test-inotify-debuginotify
+test-inotify-dirty-dirstate
+test-inotify-issue1208
+test-inotify-issue1371
+test-inotify-issue1542
+test-inotify-issue1556
+test-inotify-lookup
diff --git a/tests/blacklists/linux-vfat b/tests/blacklists/linux-vfat
new file mode 100644
index 0000000..2812bf0
--- /dev/null
+++ b/tests/blacklists/linux-vfat
@@ -0,0 +1,35 @@
+# invalid filenames
+test-add.t
+test-init.t
+test-clone.t
+test-contrib.t
+test-hgweb-raw.t
+test-walk.t
+
+# no sockets or fifos
+test-hup.t
+test-inotify-debuginotify.t
+test-inotify-dirty-dirstate.t
+test-inotify-issue1208.t
+test-inotify-issue1371.t
+test-inotify-issue1542.t
+test-inotify-lookup.t
+test-inotify.t
+test-inotify-issue1556.t
+
+# no hardlinks
+test-hardlinks.t
+test-relink.t
+
+# exec bit problems
+test-convert-bzr-114.t
+test-convert-bzr-directories.t
+test-convert-bzr-merges.t
+test-convert-bzr-treeroot.t
+test-convert-darcs.t
+test-merge-tools.t
+
+# debugstate exec bit false positives
+test-dirstate.t
+test-filebranch.t
+test-merge-remove.t
diff --git a/tests/bundles/darcs1.hg b/tests/bundles/darcs1.hg
new file mode 100644
index 0000000..130d07f
--- /dev/null
+++ b/tests/bundles/darcs1.hg
Binary files differ
diff --git a/tests/bundles/legacy-encoding.hg b/tests/bundles/legacy-encoding.hg
new file mode 100644
index 0000000..b3b9b25
--- /dev/null
+++ b/tests/bundles/legacy-encoding.hg
Binary files differ
diff --git a/tests/bundles/rebase-revset.hg b/tests/bundles/rebase-revset.hg
new file mode 100644
index 0000000..2a016a3
--- /dev/null
+++ b/tests/bundles/rebase-revset.hg
Binary files differ
diff --git a/tests/bundles/rebase.hg b/tests/bundles/rebase.hg
new file mode 100644
index 0000000..69f1b6d
--- /dev/null
+++ b/tests/bundles/rebase.hg
Binary files differ
diff --git a/tests/bundles/rebase.sh b/tests/bundles/rebase.sh
new file mode 100755
index 0000000..adae27a
--- /dev/null
+++ b/tests/bundles/rebase.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+hg init rebase
+cd rebase
+
+# @ 7: 'H'
+# |
+# | o 6: 'G'
+# |/|
+# o | 5: 'F'
+# | |
+# | o 4: 'E'
+# |/
+# | o 3: 'D'
+# | |
+# | o 2: 'C'
+# | |
+# | o 1: 'B'
+# |/
+# o 0: 'A'
+
+echo A > A
+hg ci -Am A
+echo B > B
+hg ci -Am B
+echo C > C
+hg ci -Am C
+echo D > D
+hg ci -Am D
+hg up -q -C 0
+echo E > E
+hg ci -Am E
+hg up -q -C 0
+echo F > F
+hg ci -Am F
+hg merge -r 4
+hg ci -m G
+hg up -q -C 5
+echo H > H
+hg ci -Am H
+
+hg bundle -a ../rebase.hg
+
+cd ..
+rm -Rf rebase
diff --git a/tests/bundles/remote.hg b/tests/bundles/remote.hg
new file mode 100644
index 0000000..04be619
--- /dev/null
+++ b/tests/bundles/remote.hg
Binary files differ
diff --git a/tests/bundles/remote.sh b/tests/bundles/remote.sh
new file mode 100755
index 0000000..9e8d923
--- /dev/null
+++ b/tests/bundles/remote.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+hg init remote
+cd remote
+
+echo "0" >> afile
+hg add afile
+hg commit -m "0.0"
+echo "1" >> afile
+hg commit -m "0.1"
+echo "2" >> afile
+hg commit -m "0.2"
+echo "3" >> afile
+hg commit -m "0.3"
+hg update -C 0
+echo "1" >> afile
+hg commit -m "1.1"
+echo "2" >> afile
+hg commit -m "1.2"
+echo "a line" > fred
+echo "3" >> afile
+hg add fred
+hg commit -m "1.3"
+hg mv afile adifferentfile
+hg commit -m "1.3m"
+hg update -C 3
+hg mv afile anotherfile
+hg commit -m "0.3m"
+
+hg bundle -a ../remote.hg
+
+cd ..
+rm -Rf remote
diff --git a/tests/bundles/rename.sh b/tests/bundles/rename.sh
new file mode 100755
index 0000000..f8eccf8
--- /dev/null
+++ b/tests/bundles/rename.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# @ 3: 'move2'
+# |
+# o 2: 'move1'
+# |
+# | o 1: 'change'
+# |/
+# o 0: 'add'
+
+hg init copies
+cd copies
+echo a > a
+echo b > b
+echo c > c
+hg ci -Am add
+echo a >> a
+echo b >> b
+echo c >> c
+hg ci -m change
+hg up -qC 0
+hg cp a d
+hg mv b e
+hg mv c f
+hg ci -m move1
+hg mv e g
+hg mv f c
+hg ci -m move2
+hg bundle -a ../renames.hg
+cd ..
diff --git a/tests/bundles/renames.hg b/tests/bundles/renames.hg
new file mode 100644
index 0000000..977a845
--- /dev/null
+++ b/tests/bundles/renames.hg
Binary files differ
diff --git a/tests/bundles/tampered.hg b/tests/bundles/tampered.hg
new file mode 100644
index 0000000..9270540
--- /dev/null
+++ b/tests/bundles/tampered.hg
Binary files differ
diff --git a/tests/bundles/test-keyword.hg b/tests/bundles/test-keyword.hg
new file mode 100644
index 0000000..2d0305f
--- /dev/null
+++ b/tests/bundles/test-keyword.hg
Binary files differ
diff --git a/tests/bundles/test-manifest.hg b/tests/bundles/test-manifest.hg
new file mode 100644
index 0000000..6ad9b5c
--- /dev/null
+++ b/tests/bundles/test-manifest.hg
Binary files differ
diff --git a/tests/bundles/test-merge-symlinks.hg b/tests/bundles/test-merge-symlinks.hg
new file mode 100644
index 0000000..2e1bb7d
--- /dev/null
+++ b/tests/bundles/test-merge-symlinks.hg
Binary files differ
diff --git a/tests/bundles/test-no-symlinks.hg b/tests/bundles/test-no-symlinks.hg
new file mode 100644
index 0000000..6c4b94a
--- /dev/null
+++ b/tests/bundles/test-no-symlinks.hg
Binary files differ
diff --git a/tests/bzr-definitions b/tests/bzr-definitions
new file mode 100644
index 0000000..5e9895f
--- /dev/null
+++ b/tests/bzr-definitions
@@ -0,0 +1,19 @@
+# this file holds the definitions that are used in various bzr tests
+
+"$TESTDIR/hghave" bzr || exit 80
+
+TERM=dumb; export TERM
+echo '[extensions]' >> $HGRCPATH
+echo 'convert = ' >> $HGRCPATH
+echo 'hgext.graphlog = ' >> $HGRCPATH
+
+glog()
+{
+ hg glog --template '{rev}@{branch} "{desc|firstline}" files: {files}\n' "$@"
+}
+
+manifest()
+{
+ echo "% manifest of $2"
+ hg -R $1 manifest -v -r $2
+}
diff --git a/tests/cgienv b/tests/cgienv
new file mode 100644
index 0000000..fd987d4
--- /dev/null
+++ b/tests/cgienv
@@ -0,0 +1,29 @@
+DOCUMENT_ROOT="/var/www/hg"; export DOCUMENT_ROOT
+GATEWAY_INTERFACE="CGI/1.1"; export GATEWAY_INTERFACE
+HTTP_ACCEPT="text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; export HTTP_ACCEPT
+HTTP_ACCEPT_CHARSET="ISO-8859-1,utf-8;q=0.7,*;q=0.7"; export HTTP_ACCEPT_CHARSET
+HTTP_ACCEPT_ENCODING="gzip,deflate"; export HTTP_ACCEPT_ENCODING
+HTTP_ACCEPT_LANGUAGE="en-us,en;q=0.5"; export HTTP_ACCEPT_LANGUAGE
+HTTP_CACHE_CONTROL="max-age=0"; export HTTP_CACHE_CONTROL
+HTTP_CONNECTION="keep-alive"; export HTTP_CONNECTION
+HTTP_HOST="hg.omnifarious.org"; export HTTP_HOST
+HTTP_KEEP_ALIVE="300"; export HTTP_KEEP_ALIVE
+HTTP_USER_AGENT="Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4"; export HTTP_USER_AGENT
+PATH_INFO="/"; export PATH_INFO
+PATH_TRANSLATED="/var/www/hg/index.html"; export PATH_TRANSLATED
+QUERY_STRING=""; export QUERY_STRING
+REMOTE_ADDR="127.0.0.2"; export REMOTE_ADDR
+REMOTE_PORT="44703"; export REMOTE_PORT
+REQUEST_METHOD="GET"; export REQUEST_METHOD
+REQUEST_URI="/test/"; export REQUEST_URI
+SCRIPT_FILENAME="/home/hopper/hg_public/test.cgi"; export SCRIPT_FILENAME
+SCRIPT_NAME="/test"; export SCRIPT_NAME
+SCRIPT_URI="http://hg.omnifarious.org/test/"; export SCRIPT_URI
+SCRIPT_URL="/test/"; export SCRIPT_URL
+SERVER_ADDR="127.0.0.1"; export SERVER_ADDR
+SERVER_ADMIN="eric@localhost"; export SERVER_ADMIN
+SERVER_NAME="hg.omnifarious.org"; export SERVER_NAME
+SERVER_PORT="80"; export SERVER_PORT
+SERVER_PROTOCOL="HTTP/1.1"; export SERVER_PROTOCOL
+SERVER_SIGNATURE="<address>Apache/2.0.53 (Fedora) Server at hg.omnifarious.org Port 80</address>"; export SERVER_SIGNATURE
+SERVER_SOFTWARE="Apache/2.0.53 (Fedora)"; export SERVER_SOFTWARE
diff --git a/tests/dummyssh b/tests/dummyssh
new file mode 100755
index 0000000..9b1430a
--- /dev/null
+++ b/tests/dummyssh
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+import sys
+import os
+
+os.chdir(os.getenv('TESTTMP'))
+
+if sys.argv[1] != "user@dummy":
+ sys.exit(-1)
+
+os.environ["SSH_CLIENT"] = "127.0.0.1 1 2"
+
+log = open("dummylog", "ab")
+log.write("Got arguments")
+for i, arg in enumerate(sys.argv[1:]):
+ log.write(" %d:%s" % (i+1, arg))
+log.write("\n")
+log.close()
+hgcmd = sys.argv[2]
+if os.name == 'nt':
+ # hack to make simple unix single quote quoting work on windows
+ hgcmd = hgcmd.replace("'", '"')
+r = os.system(hgcmd)
+sys.exit(bool(r))
diff --git a/tests/filtercr.py b/tests/filtercr.py
new file mode 100755
index 0000000..c743b22
--- /dev/null
+++ b/tests/filtercr.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+# Filter output by the progress extension to make it readable in tests
+
+import sys, re
+
+for line in sys.stdin:
+ line = re.sub(r'\r+[^\n]', lambda m: '\n' + m.group()[-1:], line)
+ sys.stdout.write(line)
+print
diff --git a/tests/filterpyflakes.py b/tests/filterpyflakes.py
new file mode 100755
index 0000000..240f1e1
--- /dev/null
+++ b/tests/filterpyflakes.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Filter output by pyflakes to control which warnings we check
+
+import sys, re, os
+
+def makekey(message):
+ # "path/file:line: message"
+ match = re.search(r"(line \d+)", message)
+ line = ''
+ if match:
+ line = match.group(0)
+ message = re.sub(r"(line \d+)", '', message)
+ return re.sub(r"([^:]*):([^:]+):([^']*)('[^']*')(.*)$",
+ r'\3:\5:\4:\1:\2:' + line,
+ message)
+
+lines = []
+for line in sys.stdin:
+ # We whitelist tests
+ pats = [
+ r"imported but unused",
+ r"local variable '.*' is assigned to but never used",
+ r"unable to detect undefined names",
+ ]
+ if not re.search('|'.join(pats), line):
+ continue
+ fn = line.split(':', 1)[0]
+ f = open(os.path.join(os.path.dirname(os.path.dirname(__file__)), fn))
+ data = f.read()
+ f.close()
+ if 'no-check-code' in data:
+ continue
+ lines.append(line)
+
+for line in sorted(lines, key = makekey):
+ sys.stdout.write(line)
+print
diff --git a/tests/get-with-headers.py b/tests/get-with-headers.py
new file mode 100755
index 0000000..6d20dfc
--- /dev/null
+++ b/tests/get-with-headers.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+"""This does HTTP GET requests given a host:port and path and returns
+a subset of the headers plus the body of the result."""
+
+import httplib, sys
+
+try:
+ import msvcrt, os
+ msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+ msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
+except ImportError:
+ pass
+
+twice = False
+if '--twice' in sys.argv:
+ sys.argv.remove('--twice')
+ twice = True
+
+reasons = {'Not modified': 'Not Modified'} # python 2.4
+
+tag = None
+def request(host, path, show):
+ assert not path.startswith('/'), path
+ global tag
+ headers = {}
+ if tag:
+ headers['If-None-Match'] = tag
+
+ conn = httplib.HTTPConnection(host)
+ conn.request("GET", '/' + path, None, headers)
+ response = conn.getresponse()
+ print response.status, reasons.get(response.reason, response.reason)
+ for h in [h.lower() for h in show]:
+ if response.getheader(h, None) is not None:
+ print "%s: %s" % (h, response.getheader(h))
+
+ print
+ data = response.read()
+ sys.stdout.write(data)
+
+ if twice and response.getheader('ETag', None):
+ tag = response.getheader('ETag')
+
+ return response.status
+
+status = request(sys.argv[1], sys.argv[2], sys.argv[3:])
+if twice:
+ status = request(sys.argv[1], sys.argv[2], sys.argv[3:])
+
+if 200 <= status <= 305:
+ sys.exit(0)
+sys.exit(1)
diff --git a/tests/gpg/pubring.gpg b/tests/gpg/pubring.gpg
new file mode 100644
index 0000000..1968054
--- /dev/null
+++ b/tests/gpg/pubring.gpg
Binary files differ
diff --git a/tests/gpg/random_seed b/tests/gpg/random_seed
new file mode 100644
index 0000000..87e0fc6
--- /dev/null
+++ b/tests/gpg/random_seed
Binary files differ
diff --git a/tests/gpg/secring.gpg b/tests/gpg/secring.gpg
new file mode 100644
index 0000000..aca0361
--- /dev/null
+++ b/tests/gpg/secring.gpg
Binary files differ
diff --git a/tests/gpg/trustdb.gpg b/tests/gpg/trustdb.gpg
new file mode 100644
index 0000000..4008cda
--- /dev/null
+++ b/tests/gpg/trustdb.gpg
Binary files differ
diff --git a/tests/heredoctest.py b/tests/heredoctest.py
new file mode 100644
index 0000000..7508c18
--- /dev/null
+++ b/tests/heredoctest.py
@@ -0,0 +1,19 @@
+import sys
+
+globalvars = {}
+localvars = {}
+lines = sys.stdin.readlines()
+while lines:
+ l = lines.pop(0)
+ if l.startswith('SALT'):
+ print l[:-1]
+ elif l.startswith('>>> '):
+ snippet = l[4:]
+ while lines and lines[0].startswith('... '):
+ l = lines.pop(0)
+ snippet += "\n" + l[4:]
+ c = compile(snippet, '<heredoc>', 'single')
+ try:
+ exec c in globalvars, localvars
+ except Exception, inst:
+ print repr(inst)
diff --git a/tests/hghave b/tests/hghave
new file mode 100755
index 0000000..dad1667
--- /dev/null
+++ b/tests/hghave
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+"""Test the running system for features availability. Exit with zero
+if all features are there, non-zero otherwise. If a feature name is
+prefixed with "no-", the absence of feature is tested.
+"""
+import optparse
+import sys
+import hghave
+
+checks = hghave.checks
+
+def list_features():
+ for name, feature in checks.iteritems():
+ desc = feature[1]
+ print name + ':', desc
+
+def test_features():
+ failed = 0
+ for name, feature in checks.iteritems():
+ check, _ = feature
+ try:
+ check()
+ except Exception, e:
+ print "feature %s failed: %s" % (name, e)
+ failed += 1
+ return failed
+
+parser = optparse.OptionParser("%prog [options] [features]")
+parser.add_option("--test-features", action="store_true",
+ help="test available features")
+parser.add_option("--list-features", action="store_true",
+ help="list available features")
+parser.add_option("-q", "--quiet", action="store_true",
+ help="check features silently")
+
+if __name__ == '__main__':
+ options, args = parser.parse_args()
+ if options.list_features:
+ list_features()
+ sys.exit(0)
+
+ if options.test_features:
+ sys.exit(test_features())
+
+ quiet = options.quiet
+
+ failures = 0
+
+ def error(msg):
+ global failures
+ if not quiet:
+ sys.stderr.write(msg + '\n')
+ failures += 1
+
+ for feature in args:
+ negate = feature.startswith('no-')
+ if negate:
+ feature = feature[3:]
+
+ if feature not in checks:
+ error('skipped: unknown feature: ' + feature)
+ continue
+
+ check, desc = checks[feature]
+ try:
+ available = check()
+ except Exception, e:
+ error('hghave check failed: ' + feature)
+ continue
+
+ if not negate and not available:
+ error('skipped: missing feature: ' + desc)
+ elif negate and available:
+ error('skipped: system supports %s' % desc)
+
+ if failures != 0:
+ sys.exit(1)
diff --git a/tests/hghave.py b/tests/hghave.py
new file mode 100755
index 0000000..9b93ec5
--- /dev/null
+++ b/tests/hghave.py
@@ -0,0 +1,308 @@
+import os, stat, socket
+import re
+import sys
+import tempfile
+
+tempprefix = 'hg-hghave-'
+
+def matchoutput(cmd, regexp, ignorestatus=False):
+ """Return True if cmd executes successfully and its output
+ is matched by the supplied regular expression.
+ """
+ r = re.compile(regexp)
+ fh = os.popen(cmd)
+ s = fh.read()
+ try:
+ ret = fh.close()
+ except IOError:
+ # Happen in Windows test environment
+ ret = 1
+ return (ignorestatus or ret is None) and r.search(s)
+
+def has_baz():
+ return matchoutput('baz --version 2>&1', r'baz Bazaar version')
+
+def has_bzr():
+ try:
+ import bzrlib
+ return bzrlib.__doc__ is not None
+ except ImportError:
+ return False
+
+def has_bzr114():
+ try:
+ import bzrlib
+ return (bzrlib.__doc__ is not None
+ and bzrlib.version_info[:2] >= (1, 14))
+ except ImportError:
+ return False
+
+def has_cvs():
+ re = r'Concurrent Versions System.*?server'
+ return matchoutput('cvs --version 2>&1', re) and not has_msys()
+
+def has_darcs():
+ return matchoutput('darcs --version', r'2\.[2-9]', True)
+
+def has_mtn():
+ return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
+ 'mtn --version', r'monotone 0\.', True)
+
+def has_eol_in_paths():
+ try:
+ fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
+ os.close(fd)
+ os.remove(path)
+ return True
+ except (IOError, OSError):
+ return False
+
+def has_executablebit():
+ try:
+ EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
+ fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
+ try:
+ os.close(fh)
+ m = os.stat(fn).st_mode & 0777
+ new_file_has_exec = m & EXECFLAGS
+ os.chmod(fn, m ^ EXECFLAGS)
+ exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
+ finally:
+ os.unlink(fn)
+ except (IOError, OSError):
+ # we don't care, the user probably won't be able to commit anyway
+ return False
+ return not (new_file_has_exec or exec_flags_cannot_flip)
+
+def has_icasefs():
+ # Stolen from mercurial.util
+ fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
+ os.close(fd)
+ try:
+ s1 = os.stat(path)
+ d, b = os.path.split(path)
+ p2 = os.path.join(d, b.upper())
+ if path == p2:
+ p2 = os.path.join(d, b.lower())
+ try:
+ s2 = os.stat(p2)
+ return s2 == s1
+ except OSError:
+ return False
+ finally:
+ os.remove(path)
+
+def has_inotify():
+ try:
+ import hgext.inotify.linux.watcher
+ except ImportError:
+ return False
+ name = tempfile.mktemp(dir='.', prefix=tempprefix)
+ sock = socket.socket(socket.AF_UNIX)
+ try:
+ sock.bind(name)
+ except socket.error, err:
+ return False
+ sock.close()
+ os.unlink(name)
+ return True
+
+def has_fifo():
+ if getattr(os, "mkfifo", None) is None:
+ return False
+ name = tempfile.mktemp(dir='.', prefix=tempprefix)
+ try:
+ os.mkfifo(name)
+ os.unlink(name)
+ return True
+ except OSError:
+ return False
+
+def has_cacheable_fs():
+ from mercurial import util
+
+ fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
+ os.close(fd)
+ try:
+ return util.cachestat(path).cacheable()
+ finally:
+ os.remove(path)
+
+def has_lsprof():
+ try:
+ import _lsprof
+ return True
+ except ImportError:
+ return False
+
+def has_gettext():
+ return matchoutput('msgfmt --version', 'GNU gettext-tools')
+
+def has_git():
+ return matchoutput('git --version 2>&1', r'^git version')
+
+def has_docutils():
+ try:
+ from docutils.core import publish_cmdline
+ return True
+ except ImportError:
+ return False
+
+def getsvnversion():
+ m = matchoutput('svn --version 2>&1', r'^svn,\s+version\s+(\d+)\.(\d+)')
+ if not m:
+ return (0, 0)
+ return (int(m.group(1)), int(m.group(2)))
+
+def has_svn15():
+ return getsvnversion() >= (1, 5)
+
+def has_svn13():
+ return getsvnversion() >= (1, 3)
+
+def has_svn():
+ return matchoutput('svn --version 2>&1', r'^svn, version') and \
+ matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
+
+def has_svn_bindings():
+ try:
+ import svn.core
+ version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
+ if version < (1, 4):
+ return False
+ return True
+ except ImportError:
+ return False
+
+def has_p4():
+ return (matchoutput('p4 -V', r'Rev\. P4/') and
+ matchoutput('p4d -V', r'Rev\. P4D/'))
+
+def has_symlink():
+ if getattr(os, "symlink", None) is None:
+ return False
+ name = tempfile.mktemp(dir='.', prefix=tempprefix)
+ try:
+ os.symlink(".", name)
+ os.unlink(name)
+ return True
+ except (OSError, AttributeError):
+ return False
+
+def has_hardlink():
+ from mercurial import util
+ fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
+ os.close(fh)
+ name = tempfile.mktemp(dir='.', prefix=tempprefix)
+ try:
+ try:
+ util.oslink(fn, name)
+ os.unlink(name)
+ return True
+ except OSError:
+ return False
+ finally:
+ os.unlink(fn)
+
+def has_tla():
+ return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
+
+def has_gpg():
+ return matchoutput('gpg --version 2>&1', r'GnuPG')
+
+def has_unix_permissions():
+ d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
+ try:
+ fname = os.path.join(d, 'foo')
+ for umask in (077, 007, 022):
+ os.umask(umask)
+ f = open(fname, 'w')
+ f.close()
+ mode = os.stat(fname).st_mode
+ os.unlink(fname)
+ if mode & 0777 != ~umask & 0666:
+ return False
+ return True
+ finally:
+ os.rmdir(d)
+
+def has_pyflakes():
+ return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
+ r"<stdin>:1: 're' imported but unused",
+ True)
+
+def has_pygments():
+ try:
+ import pygments
+ return True
+ except ImportError:
+ return False
+
+def has_outer_repo():
+ # failing for other reasons than 'no repo' imply that there is a repo
+ return not matchoutput('hg root 2>&1',
+ r'abort: no repository found', True)
+
+def has_ssl():
+ try:
+ import ssl
+ import OpenSSL
+ OpenSSL.SSL.Context
+ return True
+ except ImportError:
+ return False
+
+def has_windows():
+ return os.name == 'nt'
+
+def has_system_sh():
+ return os.name != 'nt'
+
+def has_serve():
+ return os.name != 'nt' # gross approximation
+
+def has_tic():
+ return matchoutput('test -x "`which tic`"', '')
+
+def has_msys():
+ return os.getenv('MSYSTEM')
+
+checks = {
+ "true": (lambda: True, "yak shaving"),
+ "false": (lambda: False, "nail clipper"),
+ "baz": (has_baz, "GNU Arch baz client"),
+ "bzr": (has_bzr, "Canonical's Bazaar client"),
+ "bzr114": (has_bzr114, "Canonical's Bazaar client >= 1.14"),
+ "cacheable": (has_cacheable_fs, "cacheable filesystem"),
+ "cvs": (has_cvs, "cvs client/server"),
+ "darcs": (has_darcs, "darcs client"),
+ "docutils": (has_docutils, "Docutils text processing library"),
+ "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
+ "execbit": (has_executablebit, "executable bit"),
+ "fifo": (has_fifo, "named pipes"),
+ "gettext": (has_gettext, "GNU Gettext (msgfmt)"),
+ "git": (has_git, "git command line client"),
+ "gpg": (has_gpg, "gpg client"),
+ "hardlink": (has_hardlink, "hardlinks"),
+ "icasefs": (has_icasefs, "case insensitive file system"),
+ "inotify": (has_inotify, "inotify extension support"),
+ "lsprof": (has_lsprof, "python lsprof module"),
+ "mtn": (has_mtn, "monotone client (>= 1.0)"),
+ "outer-repo": (has_outer_repo, "outer repo"),
+ "p4": (has_p4, "Perforce server and client"),
+ "pyflakes": (has_pyflakes, "Pyflakes python linter"),
+ "pygments": (has_pygments, "Pygments source highlighting library"),
+ "serve": (has_serve, "platform and python can manage 'hg serve -d'"),
+ "ssl": (has_ssl, "python >= 2.6 ssl module and python OpenSSL"),
+ "svn": (has_svn, "subversion client and admin tools"),
+ "svn13": (has_svn13, "subversion client and admin tools >= 1.3"),
+ "svn15": (has_svn15, "subversion client and admin tools >= 1.5"),
+ "svn-bindings": (has_svn_bindings, "subversion python bindings"),
+ "symlink": (has_symlink, "symbolic links"),
+ "system-sh": (has_system_sh, "system() uses sh"),
+ "tic": (has_tic, "terminfo compiler"),
+ "tla": (has_tla, "GNU Arch tla client"),
+ "unix-permissions": (has_unix_permissions, "unix-style permissions"),
+ "windows": (has_windows, "Windows"),
+ "msys": (has_msys, "Windows with MSYS"),
+}
diff --git a/tests/hgterm.ti b/tests/hgterm.ti
new file mode 100644
index 0000000..0a192b4
--- /dev/null
+++ b/tests/hgterm.ti
@@ -0,0 +1,27 @@
+hgterm,
+ am, km, mir, msgr, xenl,
+ colors#8, cols#80, it#8, lines#24, pairs#64,
+ acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+ bel=^G, bold=\E[1m, clear=\E[H\E[2J, cr=\r,
+ csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=\b,
+ cud=\E[%p1%dB, cud1=\n, cuf=\E[%p1%dC, cuf1=\E[C,
+ cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A,
+ dch=\E[%p1%dP, dch1=\E[P, dl=\E[%p1%dM, dl1=\E[M,
+ ed=\E[J, el=\E[K, enacs=\E)0, home=\E[H, ht=\t,
+ hts=\EH, il=\E[%p1%dL, il1=\E[L, ind=\n,
+ is2=\E[m\E[?7h\E[4l\E>\E7\E[r\E[?1;3;4;6l\E8, kbs=\b,
+ kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
+ kdch1=\E[3~, kf1=\E[11~, kf10=\E[21~, kf11=\E[23~,
+ kf12=\E[24~, kf13=\E[25~, kf14=\E[26~, kf15=\E[28~,
+ kf16=\E[29~, kf17=\E[31~, kf18=\E[32~, kf19=\E[33~,
+ kf2=\E[12~, kf20=\E[34~, kf3=\E[13~, kf4=\E[14~,
+ kf5=\E[15~, kf6=\E[17~, kf7=\E[18~, kf8=\E[19~,
+ kf9=\E[20~, kfnd=\E[1~, kich1=\E[2~, kmous=\E[M,
+ knp=\E[6~, kpp=\E[5~, kslt=\E[4~, op=\E[m, rc=\E8,
+ rev=\E[7m, ri=\EM, rmacs=^O, rmcup=\E[2J\E[?47l\E8,
+ rmir=\E[4l, rmkx=\E[?1l\E>, rmso=\E[m, rmul=\E[m,
+ rs2=\E[m\E[?7h\E[4l\E>\E7\E[r\E[?1;3;4;6l\E8, sc=\E7,
+ setab=\E[4%p1%dm, setaf=\E[3%p1%dm, sgr0=\E[m,
+ smacs=^N, smcup=\E7\E[?47h, smir=\E[4h,
+ smkx=\E[?1h\E=, smso=\E[7m, smul=\E[4m, tbc=\E[3g,
+ u6=\E[%i%d;%dR, u7=\E[6n, u8=\E[?1;2c, u9=\E[c,
diff --git a/tests/histedit-helpers.sh b/tests/histedit-helpers.sh
new file mode 100644
index 0000000..4475883
--- /dev/null
+++ b/tests/histedit-helpers.sh
@@ -0,0 +1,6 @@
+fixbundle() {
+ grep -v 'saving bundle' | grep -v 'saved backup' | \
+ grep -v added | grep -v adding | \
+ grep -v "unable to find 'e' for patching" | \
+ grep -v "e: No such file or directory"
+}
diff --git a/tests/killdaemons.py b/tests/killdaemons.py
new file mode 100755
index 0000000..63828fc
--- /dev/null
+++ b/tests/killdaemons.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+import os, time, errno, signal
+
+# Kill off any leftover daemon processes
+try:
+ fp = open(os.environ['DAEMON_PIDS'])
+ for line in fp:
+ try:
+ pid = int(line)
+ except ValueError:
+ continue
+ try:
+ os.kill(pid, 0)
+ os.kill(pid, signal.SIGTERM)
+ for i in range(10):
+ time.sleep(0.05)
+ os.kill(pid, 0)
+ os.kill(pid, signal.SIGKILL)
+ except OSError, err:
+ if err.errno != errno.ESRCH:
+ raise
+ fp.close()
+except IOError:
+ pass
diff --git a/tests/md5sum.py b/tests/md5sum.py
new file mode 100755
index 0000000..3eae5ed
--- /dev/null
+++ b/tests/md5sum.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#
+# Based on python's Tools/scripts/md5sum.py
+#
+# This software may be used and distributed according to the terms
+# of the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2, which is
+# GPL-compatible.
+
+import sys, os
+
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+
+try:
+ import msvcrt
+ msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+ msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
+except ImportError:
+ pass
+
+for filename in sys.argv[1:]:
+ try:
+ fp = open(filename, 'rb')
+ except IOError, msg:
+ sys.stderr.write('%s: Can\'t open: %s\n' % (filename, msg))
+ sys.exit(1)
+
+ m = md5()
+ try:
+ while True:
+ data = fp.read(8192)
+ if not data:
+ break
+ m.update(data)
+ except IOError, msg:
+ sys.stderr.write('%s: I/O error: %s\n' % (filename, msg))
+ sys.exit(1)
+ sys.stdout.write('%s %s\n' % (m.hexdigest(), filename))
+
+sys.exit(0)
diff --git a/tests/missing-comment.hg b/tests/missing-comment.hg
new file mode 100644
index 0000000..7a5be69
--- /dev/null
+++ b/tests/missing-comment.hg
Binary files differ
diff --git a/tests/notcapable b/tests/notcapable
new file mode 100644
index 0000000..ef8dc22
--- /dev/null
+++ b/tests/notcapable
@@ -0,0 +1,24 @@
+# Disable the $CAP wire protocol capability.
+
+if test -z "$CAP"
+then
+ echo "CAP environment variable not set."
+fi
+
+cat > notcapable-$CAP.py << EOF
+from mercurial import extensions, peer, localrepo
+def extsetup():
+ extensions.wrapfunction(peer.peerrepository, 'capable', wrapcapable)
+ extensions.wrapfunction(localrepo.localrepository, 'peer', wrappeer)
+def wrapcapable(orig, self, name, *args, **kwargs):
+ if name in '$CAP'.split(' '):
+ return False
+ return orig(self, name, *args, **kwargs)
+def wrappeer(orig, self):
+ # Since we're disabling some newer features, we need to make sure local
+ # repos add in the legacy features again.
+ return localrepo.locallegacypeer(self)
+EOF
+
+echo '[extensions]' >> $HGRCPATH
+echo "notcapable-$CAP = `pwd`/notcapable-$CAP.py" >> $HGRCPATH
diff --git a/tests/printenv.py b/tests/printenv.py
new file mode 100644
index 0000000..d00e149
--- /dev/null
+++ b/tests/printenv.py
@@ -0,0 +1,49 @@
+# simple script to be used in hooks
+#
+# put something like this in the repo .hg/hgrc:
+#
+# [hooks]
+# changegroup = python "$TESTDIR/printenv.py" <hookname> [exit] [output]
+#
+# - <hookname> is a mandatory argument (e.g. "changegroup")
+# - [exit] is the exit code of the hook (default: 0)
+# - [output] is the name of the output file (default: use sys.stdout)
+# the file will be opened in append mode.
+#
+import os
+import sys
+
+try:
+ import msvcrt
+ msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
+ msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+ msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
+except ImportError:
+ pass
+
+exitcode = 0
+out = sys.stdout
+
+name = sys.argv[1]
+if len(sys.argv) > 2:
+ exitcode = int(sys.argv[2])
+ if len(sys.argv) > 3:
+ out = open(sys.argv[3], "ab")
+
+# variables with empty values may not exist on all platforms, filter
+# them now for portability sake.
+env = [(k, v) for k, v in os.environ.iteritems()
+ if k.startswith("HG_") and v]
+env.sort()
+
+out.write("%s hook: " % name)
+if os.name == 'nt':
+ filter = lambda x: x.replace('\\', '/')
+else:
+ filter = lambda x: x
+vars = ["%s=%s" % (k, filter(v)) for k, v in env]
+out.write(" ".join(vars))
+out.write("\n")
+out.close()
+
+sys.exit(exitcode)
diff --git a/tests/readlink.py b/tests/readlink.py
new file mode 100755
index 0000000..0e86a67
--- /dev/null
+++ b/tests/readlink.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+import errno, os, sys
+
+for f in sys.argv[1:]:
+ try:
+ print f, '->', os.readlink(f)
+ except OSError, err:
+ if err.errno != errno.EINVAL:
+ raise
+ print f, 'not a symlink'
+
+sys.exit(0)
diff --git a/tests/revlog-formatv0.py b/tests/revlog-formatv0.py
new file mode 100755
index 0000000..e88b8cb
--- /dev/null
+++ b/tests/revlog-formatv0.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# Copyright 2010 Intevation GmbH
+# Author(s):
+# Thomas Arendsen Hein <thomas@intevation.de>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+"""Create a Mercurial repository in revlog format 0
+
+changeset: 0:a1ef0b125355
+tag: tip
+user: user
+date: Thu Jan 01 00:00:00 1970 +0000
+files: empty
+description:
+empty file
+"""
+
+import os, sys
+
+files = [
+ ('formatv0/.hg/00changelog.i',
+ '000000000000004400000000000000000000000000000000000000'
+ '000000000000000000000000000000000000000000000000000000'
+ '0000a1ef0b125355d27765928be600cfe85784284ab3'),
+ ('formatv0/.hg/00changelog.d',
+ '756163613935613961356635353036303562366138343738336237'
+ '61623536363738616436356635380a757365720a3020300a656d70'
+ '74790a0a656d7074792066696c65'),
+ ('formatv0/.hg/00manifest.i',
+ '000000000000003000000000000000000000000000000000000000'
+ '000000000000000000000000000000000000000000000000000000'
+ '0000aca95a9a5f550605b6a84783b7ab56678ad65f58'),
+ ('formatv0/.hg/00manifest.d',
+ '75656d707479006238306465356431333837353835343163356630'
+ '35323635616431343461623966613836643164620a'),
+ ('formatv0/.hg/data/empty.i',
+ '000000000000000000000000000000000000000000000000000000'
+ '000000000000000000000000000000000000000000000000000000'
+ '0000b80de5d138758541c5f05265ad144ab9fa86d1db'),
+ ('formatv0/.hg/data/empty.d',
+ ''),
+]
+
+def makedirs(name):
+ """recursive directory creation"""
+ parent = os.path.dirname(name)
+ if parent:
+ makedirs(parent)
+ os.mkdir(name)
+
+makedirs(os.path.join(*'formatv0/.hg/data'.split('/')))
+
+for name, data in files:
+ f = open(name, 'wb')
+ f.write(data.decode('hex'))
+ f.close()
+
+sys.exit(0)
diff --git a/tests/run-tests.py b/tests/run-tests.py
new file mode 100755
index 0000000..c9ef7d5
--- /dev/null
+++ b/tests/run-tests.py
@@ -0,0 +1,1324 @@
+#!/usr/bin/env python
+#
+# run-tests.py - Run a set of tests on Mercurial
+#
+# Copyright 2006 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+# Modifying this script is tricky because it has many modes:
+# - serial (default) vs parallel (-jN, N > 1)
+# - no coverage (default) vs coverage (-c, -C, -s)
+# - temp install (default) vs specific hg script (--with-hg, --local)
+# - tests are a mix of shell scripts and Python scripts
+#
+# If you change this script, it is recommended that you ensure you
+# haven't broken it by running it in various modes with a representative
+# sample of test scripts. For example:
+#
+# 1) serial, no coverage, temp install:
+# ./run-tests.py test-s*
+# 2) serial, no coverage, local hg:
+# ./run-tests.py --local test-s*
+# 3) serial, coverage, temp install:
+# ./run-tests.py -c test-s*
+# 4) serial, coverage, local hg:
+# ./run-tests.py -c --local test-s* # unsupported
+# 5) parallel, no coverage, temp install:
+# ./run-tests.py -j2 test-s*
+# 6) parallel, no coverage, local hg:
+# ./run-tests.py -j2 --local test-s*
+# 7) parallel, coverage, temp install:
+# ./run-tests.py -j2 -c test-s* # currently broken
+# 8) parallel, coverage, local install:
+# ./run-tests.py -j2 -c --local test-s* # unsupported (and broken)
+# 9) parallel, custom tmp dir:
+# ./run-tests.py -j2 --tmpdir /tmp/myhgtests
+#
+# (You could use any subset of the tests: test-s* happens to match
+# enough that it's worth doing parallel runs, few enough that it
+# completes fairly quickly, includes both shell and Python scripts, and
+# includes some scripts that run daemon processes.)
+
+from distutils import version
+import difflib
+import errno
+import optparse
+import os
+import shutil
+import subprocess
+import signal
+import sys
+import tempfile
+import time
+import re
+import threading
+
+processlock = threading.Lock()
+
+closefds = os.name == 'posix'
+def Popen4(cmd, wd, timeout):
+ processlock.acquire()
+ p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd,
+ close_fds=closefds,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ processlock.release()
+
+ p.fromchild = p.stdout
+ p.tochild = p.stdin
+ p.childerr = p.stderr
+
+ p.timeout = False
+ if timeout:
+ def t():
+ start = time.time()
+ while time.time() - start < timeout and p.returncode is None:
+ time.sleep(.1)
+ p.timeout = True
+ if p.returncode is None:
+ terminate(p)
+ threading.Thread(target=t).start()
+
+ return p
+
+# reserved exit code to skip test (used by hghave)
+SKIPPED_STATUS = 80
+SKIPPED_PREFIX = 'skipped: '
+FAILED_PREFIX = 'hghave check failed: '
+PYTHON = sys.executable.replace('\\', '/')
+IMPL_PATH = 'PYTHONPATH'
+if 'java' in sys.platform:
+ IMPL_PATH = 'JYTHONPATH'
+
+requiredtools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"]
+
+defaults = {
+ 'jobs': ('HGTEST_JOBS', 1),
+ 'timeout': ('HGTEST_TIMEOUT', 180),
+ 'port': ('HGTEST_PORT', 20059),
+ 'shell': ('HGTEST_SHELL', 'sh'),
+}
+
+def parselistfiles(files, listtype, warn=True):
+ entries = dict()
+ for filename in files:
+ try:
+ path = os.path.expanduser(os.path.expandvars(filename))
+ f = open(path, "r")
+ except IOError, err:
+ if err.errno != errno.ENOENT:
+ raise
+ if warn:
+ print "warning: no such %s file: %s" % (listtype, filename)
+ continue
+
+ for line in f.readlines():
+ line = line.split('#', 1)[0].strip()
+ if line:
+ entries[line] = filename
+
+ f.close()
+ return entries
+
+def parseargs():
+ parser = optparse.OptionParser("%prog [options] [tests]")
+
+ # keep these sorted
+ parser.add_option("--blacklist", action="append",
+ help="skip tests listed in the specified blacklist file")
+ parser.add_option("--whitelist", action="append",
+ help="always run tests listed in the specified whitelist file")
+ parser.add_option("-C", "--annotate", action="store_true",
+ help="output files annotated with coverage")
+ parser.add_option("--child", type="int",
+ help="run as child process, summary to given fd")
+ parser.add_option("-c", "--cover", action="store_true",
+ help="print a test coverage report")
+ parser.add_option("-d", "--debug", action="store_true",
+ help="debug mode: write output of test scripts to console"
+ " rather than capturing and diff'ing it (disables timeout)")
+ parser.add_option("-f", "--first", action="store_true",
+ help="exit on the first test failure")
+ parser.add_option("-H", "--htmlcov", action="store_true",
+ help="create an HTML report of the coverage of the files")
+ parser.add_option("--inotify", action="store_true",
+ help="enable inotify extension when running tests")
+ parser.add_option("-i", "--interactive", action="store_true",
+ help="prompt to accept changed output")
+ parser.add_option("-j", "--jobs", type="int",
+ help="number of jobs to run in parallel"
+ " (default: $%s or %d)" % defaults['jobs'])
+ parser.add_option("--keep-tmpdir", action="store_true",
+ help="keep temporary directory after running tests")
+ parser.add_option("-k", "--keywords",
+ help="run tests matching keywords")
+ parser.add_option("-l", "--local", action="store_true",
+ help="shortcut for --with-hg=<testdir>/../hg")
+ parser.add_option("-n", "--nodiff", action="store_true",
+ help="skip showing test changes")
+ parser.add_option("-p", "--port", type="int",
+ help="port on which servers should listen"
+ " (default: $%s or %d)" % defaults['port'])
+ parser.add_option("--pure", action="store_true",
+ help="use pure Python code instead of C extensions")
+ parser.add_option("-R", "--restart", action="store_true",
+ help="restart at last error")
+ parser.add_option("-r", "--retest", action="store_true",
+ help="retest failed tests")
+ parser.add_option("-S", "--noskips", action="store_true",
+ help="don't report skip tests verbosely")
+ parser.add_option("--shell", type="string",
+ help="shell to use (default: $%s or %s)" % defaults['shell'])
+ parser.add_option("-t", "--timeout", type="int",
+ help="kill errant tests after TIMEOUT seconds"
+ " (default: $%s or %d)" % defaults['timeout'])
+ parser.add_option("--tmpdir", type="string",
+ help="run tests in the given temporary directory"
+ " (implies --keep-tmpdir)")
+ parser.add_option("-v", "--verbose", action="store_true",
+ help="output verbose messages")
+ parser.add_option("--view", type="string",
+ help="external diff viewer")
+ parser.add_option("--with-hg", type="string",
+ metavar="HG",
+ help="test using specified hg script rather than a "
+ "temporary installation")
+ parser.add_option("-3", "--py3k-warnings", action="store_true",
+ help="enable Py3k warnings on Python 2.6+")
+ parser.add_option('--extra-config-opt', action="append",
+ help='set the given config opt in the test hgrc')
+
+ for option, (envvar, default) in defaults.items():
+ defaults[option] = type(default)(os.environ.get(envvar, default))
+ parser.set_defaults(**defaults)
+ (options, args) = parser.parse_args()
+
+ # jython is always pure
+ if 'java' in sys.platform or '__pypy__' in sys.modules:
+ options.pure = True
+
+ if options.with_hg:
+ options.with_hg = os.path.expanduser(options.with_hg)
+ if not (os.path.isfile(options.with_hg) and
+ os.access(options.with_hg, os.X_OK)):
+ parser.error('--with-hg must specify an executable hg script')
+ if not os.path.basename(options.with_hg) == 'hg':
+ sys.stderr.write('warning: --with-hg should specify an hg script\n')
+ if options.local:
+ testdir = os.path.dirname(os.path.realpath(sys.argv[0]))
+ hgbin = os.path.join(os.path.dirname(testdir), 'hg')
+ if os.name != 'nt' and not os.access(hgbin, os.X_OK):
+ parser.error('--local specified, but %r not found or not executable'
+ % hgbin)
+ options.with_hg = hgbin
+
+ options.anycoverage = options.cover or options.annotate or options.htmlcov
+ if options.anycoverage:
+ try:
+ import coverage
+ covver = version.StrictVersion(coverage.__version__).version
+ if covver < (3, 3):
+ parser.error('coverage options require coverage 3.3 or later')
+ except ImportError:
+ parser.error('coverage options now require the coverage package')
+
+ if options.anycoverage and options.local:
+ # this needs some path mangling somewhere, I guess
+ parser.error("sorry, coverage options do not work when --local "
+ "is specified")
+
+ global vlog
+ if options.verbose:
+ if options.jobs > 1 or options.child is not None:
+ pid = "[%d]" % os.getpid()
+ else:
+ pid = None
+ def vlog(*msg):
+ iolock.acquire()
+ if pid:
+ print pid,
+ for m in msg:
+ print m,
+ print
+ sys.stdout.flush()
+ iolock.release()
+ else:
+ vlog = lambda *msg: None
+
+ if options.tmpdir:
+ options.tmpdir = os.path.expanduser(options.tmpdir)
+
+ if options.jobs < 1:
+ parser.error('--jobs must be positive')
+ if options.interactive and options.jobs > 1:
+ print '(--interactive overrides --jobs)'
+ options.jobs = 1
+ if options.interactive and options.debug:
+ parser.error("-i/--interactive and -d/--debug are incompatible")
+ if options.debug:
+ if options.timeout != defaults['timeout']:
+ sys.stderr.write(
+ 'warning: --timeout option ignored with --debug\n')
+ options.timeout = 0
+ if options.py3k_warnings:
+ if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
+ parser.error('--py3k-warnings can only be used on Python 2.6+')
+ if options.blacklist:
+ options.blacklist = parselistfiles(options.blacklist, 'blacklist')
+ if options.whitelist:
+ options.whitelisted = parselistfiles(options.whitelist, 'whitelist',
+ warn=options.child is None)
+ else:
+ options.whitelisted = {}
+
+ return (options, args)
+
+def rename(src, dst):
+ """Like os.rename(), trade atomicity and opened files friendliness
+ for existing destination support.
+ """
+ shutil.copy(src, dst)
+ os.remove(src)
+
+def splitnewlines(text):
+ '''like str.splitlines, but only split on newlines.
+ keep line endings.'''
+ i = 0
+ lines = []
+ while True:
+ n = text.find('\n', i)
+ if n == -1:
+ last = text[i:]
+ if last:
+ lines.append(last)
+ return lines
+ lines.append(text[i:n + 1])
+ i = n + 1
+
+def parsehghaveoutput(lines):
+ '''Parse hghave log lines.
+ Return tuple of lists (missing, failed):
+ * the missing/unknown features
+ * the features for which existence check failed'''
+ missing = []
+ failed = []
+ for line in lines:
+ if line.startswith(SKIPPED_PREFIX):
+ line = line.splitlines()[0]
+ missing.append(line[len(SKIPPED_PREFIX):])
+ elif line.startswith(FAILED_PREFIX):
+ line = line.splitlines()[0]
+ failed.append(line[len(FAILED_PREFIX):])
+
+ return missing, failed
+
+def showdiff(expected, output, ref, err):
+ print
+ for line in difflib.unified_diff(expected, output, ref, err):
+ sys.stdout.write(line)
+
+def findprogram(program):
+ """Search PATH for a executable program"""
+ for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
+ name = os.path.join(p, program)
+ if os.name == 'nt' or os.access(name, os.X_OK):
+ return name
+ return None
+
+def checktools():
+ # Before we go any further, check for pre-requisite tools
+ # stuff from coreutils (cat, rm, etc) are not tested
+ for p in requiredtools:
+ if os.name == 'nt':
+ p += '.exe'
+ found = findprogram(p)
+ if found:
+ vlog("# Found prerequisite", p, "at", found)
+ else:
+ print "WARNING: Did not find prerequisite tool: "+p
+
+def terminate(proc):
+ """Terminate subprocess (with fallback for Python versions < 2.6)"""
+ vlog('# Terminating process %d' % proc.pid)
+ try:
+ getattr(proc, 'terminate', lambda : os.kill(proc.pid, signal.SIGTERM))()
+ except OSError:
+ pass
+
+def killdaemons():
+ # Kill off any leftover daemon processes
+ try:
+ fp = open(DAEMON_PIDS)
+ for line in fp:
+ try:
+ pid = int(line)
+ except ValueError:
+ continue
+ try:
+ os.kill(pid, 0)
+ vlog('# Killing daemon process %d' % pid)
+ os.kill(pid, signal.SIGTERM)
+ time.sleep(0.1)
+ os.kill(pid, 0)
+ vlog('# Daemon process %d is stuck - really killing it' % pid)
+ os.kill(pid, signal.SIGKILL)
+ except OSError, err:
+ if err.errno != errno.ESRCH:
+ raise
+ fp.close()
+ os.unlink(DAEMON_PIDS)
+ except IOError:
+ pass
+
+def cleanup(options):
+ if not options.keep_tmpdir:
+ vlog("# Cleaning up HGTMP", HGTMP)
+ shutil.rmtree(HGTMP, True)
+
+def usecorrectpython():
+ # some tests run python interpreter. they must use same
+ # interpreter we use or bad things will happen.
+ exedir, exename = os.path.split(sys.executable)
+ if exename in ('python', 'python.exe'):
+ path = findprogram(exename)
+ if os.path.dirname(path) == exedir:
+ return
+ else:
+ exename = 'python'
+ vlog('# Making python executable in test path use correct Python')
+ mypython = os.path.join(BINDIR, exename)
+ try:
+ os.symlink(sys.executable, mypython)
+ except AttributeError:
+ # windows fallback
+ shutil.copyfile(sys.executable, mypython)
+ shutil.copymode(sys.executable, mypython)
+
+def installhg(options):
+ vlog("# Performing temporary installation of HG")
+ installerrs = os.path.join("tests", "install.err")
+ pure = options.pure and "--pure" or ""
+
+ # Run installer in hg root
+ script = os.path.realpath(sys.argv[0])
+ hgroot = os.path.dirname(os.path.dirname(script))
+ os.chdir(hgroot)
+ nohome = '--home=""'
+ if os.name == 'nt':
+ # The --home="" trick works only on OS where os.sep == '/'
+ # because of a distutils convert_path() fast-path. Avoid it at
+ # least on Windows for now, deal with .pydistutils.cfg bugs
+ # when they happen.
+ nohome = ''
+ cmd = ('%s setup.py %s clean --all'
+ ' build --build-base="%s"'
+ ' install --force --prefix="%s" --install-lib="%s"'
+ ' --install-scripts="%s" %s >%s 2>&1'
+ % (sys.executable, pure, os.path.join(HGTMP, "build"),
+ INST, PYTHONDIR, BINDIR, nohome, installerrs))
+ vlog("# Running", cmd)
+ if os.system(cmd) == 0:
+ if not options.verbose:
+ os.remove(installerrs)
+ else:
+ f = open(installerrs)
+ for line in f:
+ print line,
+ f.close()
+ sys.exit(1)
+ os.chdir(TESTDIR)
+
+ usecorrectpython()
+
+ vlog("# Installing dummy diffstat")
+ f = open(os.path.join(BINDIR, 'diffstat'), 'w')
+ f.write('#!' + sys.executable + '\n'
+ 'import sys\n'
+ 'files = 0\n'
+ 'for line in sys.stdin:\n'
+ ' if line.startswith("diff "):\n'
+ ' files += 1\n'
+ 'sys.stdout.write("files patched: %d\\n" % files)\n')
+ f.close()
+ os.chmod(os.path.join(BINDIR, 'diffstat'), 0700)
+
+ if options.py3k_warnings and not options.anycoverage:
+ vlog("# Updating hg command to enable Py3k Warnings switch")
+ f = open(os.path.join(BINDIR, 'hg'), 'r')
+ lines = [line.rstrip() for line in f]
+ lines[0] += ' -3'
+ f.close()
+ f = open(os.path.join(BINDIR, 'hg'), 'w')
+ for line in lines:
+ f.write(line + '\n')
+ f.close()
+
+ hgbat = os.path.join(BINDIR, 'hg.bat')
+ if os.path.isfile(hgbat):
+ # hg.bat expects to be put in bin/scripts while run-tests.py
+ # installation layout put it in bin/ directly. Fix it
+ f = open(hgbat, 'rb')
+ data = f.read()
+ f.close()
+ if '"%~dp0..\python" "%~dp0hg" %*' in data:
+ data = data.replace('"%~dp0..\python" "%~dp0hg" %*',
+ '"%~dp0python" "%~dp0hg" %*')
+ f = open(hgbat, 'wb')
+ f.write(data)
+ f.close()
+ else:
+ print 'WARNING: cannot fix hg.bat reference to python.exe'
+
+ if options.anycoverage:
+ custom = os.path.join(TESTDIR, 'sitecustomize.py')
+ target = os.path.join(PYTHONDIR, 'sitecustomize.py')
+ vlog('# Installing coverage trigger to %s' % target)
+ shutil.copyfile(custom, target)
+ rc = os.path.join(TESTDIR, '.coveragerc')
+ vlog('# Installing coverage rc to %s' % rc)
+ os.environ['COVERAGE_PROCESS_START'] = rc
+ fn = os.path.join(INST, '..', '.coverage')
+ os.environ['COVERAGE_FILE'] = fn
+
+def outputcoverage(options):
+
+ vlog('# Producing coverage report')
+ os.chdir(PYTHONDIR)
+
+ def covrun(*args):
+ cmd = 'coverage %s' % ' '.join(args)
+ vlog('# Running: %s' % cmd)
+ os.system(cmd)
+
+ if options.child:
+ return
+
+ covrun('-c')
+ omit = ','.join(os.path.join(x, '*') for x in [BINDIR, TESTDIR])
+ covrun('-i', '-r', '"--omit=%s"' % omit) # report
+ if options.htmlcov:
+ htmldir = os.path.join(TESTDIR, 'htmlcov')
+ covrun('-i', '-b', '"--directory=%s"' % htmldir, '"--omit=%s"' % omit)
+ if options.annotate:
+ adir = os.path.join(TESTDIR, 'annotated')
+ if not os.path.isdir(adir):
+ os.mkdir(adir)
+ covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit)
+
+def pytest(test, wd, options, replacements):
+ py3kswitch = options.py3k_warnings and ' -3' or ''
+ cmd = '%s%s "%s"' % (PYTHON, py3kswitch, test)
+ vlog("# Running", cmd)
+ return run(cmd, wd, options, replacements)
+
+def shtest(test, wd, options, replacements):
+ cmd = '%s "%s"' % (options.shell, test)
+ vlog("# Running", cmd)
+ return run(cmd, wd, options, replacements)
+
+needescape = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
+escapesub = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
+escapemap = dict((chr(i), r'\x%02x' % i) for i in range(256))
+escapemap.update({'\\': '\\\\', '\r': r'\r'})
+def escapef(m):
+ return escapemap[m.group(0)]
+def stringescape(s):
+ return escapesub(escapef, s)
+
+def rematch(el, l):
+ try:
+ # ensure that the regex matches to the end of the string
+ return re.match(el + r'\Z', l)
+ except re.error:
+ # el is an invalid regex
+ return False
+
+def globmatch(el, l):
+ # The only supported special characters are * and ? plus / which also
+ # matches \ on windows. Escaping of these caracters is supported.
+ i, n = 0, len(el)
+ res = ''
+ while i < n:
+ c = el[i]
+ i += 1
+ if c == '\\' and el[i] in '*?\\/':
+ res += el[i - 1:i + 1]
+ i += 1
+ elif c == '*':
+ res += '.*'
+ elif c == '?':
+ res += '.'
+ elif c == '/' and os.name == 'nt':
+ res += '[/\\\\]'
+ else:
+ res += re.escape(c)
+ return rematch(res, l)
+
+def linematch(el, l):
+ if el == l: # perfect match (fast)
+ return True
+ if (el and
+ (el.endswith(" (re)\n") and rematch(el[:-6] + '\n', l) or
+ el.endswith(" (glob)\n") and globmatch(el[:-8] + '\n', l) or
+ el.endswith(" (esc)\n") and
+ (el[:-7].decode('string-escape') + '\n' == l or
+ el[:-7].decode('string-escape').replace('\r', '') +
+ '\n' == l and os.name == 'nt'))):
+ return True
+ return False
+
+def tsttest(test, wd, options, replacements):
+ # We generate a shell script which outputs unique markers to line
+ # up script results with our source. These markers include input
+ # line number and the last return code
+ salt = "SALT" + str(time.time())
+ def addsalt(line, inpython):
+ if inpython:
+ script.append('%s %d 0\n' % (salt, line))
+ else:
+ script.append('echo %s %s $?\n' % (salt, line))
+
+ # After we run the shell script, we re-unify the script output
+ # with non-active parts of the source, with synchronization by our
+ # SALT line number markers. The after table contains the
+ # non-active components, ordered by line number
+ after = {}
+ pos = prepos = -1
+
+ # Expected shellscript output
+ expected = {}
+
+ # We keep track of whether or not we're in a Python block so we
+ # can generate the surrounding doctest magic
+ inpython = False
+
+ # True or False when in a true or false conditional section
+ skipping = None
+
+ def hghave(reqs):
+ # TODO: do something smarter when all other uses of hghave is gone
+ tdir = TESTDIR.replace('\\', '/')
+ proc = Popen4('%s -c "%s/hghave %s"' %
+ (options.shell, tdir, ' '.join(reqs)), wd, 0)
+ proc.communicate()
+ ret = proc.wait()
+ if wifexited(ret):
+ ret = os.WEXITSTATUS(ret)
+ return ret == 0
+
+ f = open(test)
+ t = f.readlines()
+ f.close()
+
+ script = []
+ if options.debug:
+ script.append('set -x\n')
+ if os.getenv('MSYSTEM'):
+ script.append('alias pwd="pwd -W"\n')
+ for n, l in enumerate(t):
+ if not l.endswith('\n'):
+ l += '\n'
+ if l.startswith('#if'):
+ if skipping is not None:
+ after.setdefault(pos, []).append(' !!! nested #if\n')
+ skipping = not hghave(l.split()[1:])
+ after.setdefault(pos, []).append(l)
+ elif l.startswith('#else'):
+ if skipping is None:
+ after.setdefault(pos, []).append(' !!! missing #if\n')
+ skipping = not skipping
+ after.setdefault(pos, []).append(l)
+ elif l.startswith('#endif'):
+ if skipping is None:
+ after.setdefault(pos, []).append(' !!! missing #if\n')
+ skipping = None
+ after.setdefault(pos, []).append(l)
+ elif skipping:
+ after.setdefault(pos, []).append(l)
+ elif l.startswith(' >>> '): # python inlines
+ after.setdefault(pos, []).append(l)
+ prepos = pos
+ pos = n
+ if not inpython:
+ # we've just entered a Python block, add the header
+ inpython = True
+ addsalt(prepos, False) # make sure we report the exit code
+ script.append('%s -m heredoctest <<EOF\n' % PYTHON)
+ addsalt(n, True)
+ script.append(l[2:])
+ elif l.startswith(' ... '): # python inlines
+ after.setdefault(prepos, []).append(l)
+ script.append(l[2:])
+ elif l.startswith(' $ '): # commands
+ if inpython:
+ script.append("EOF\n")
+ inpython = False
+ after.setdefault(pos, []).append(l)
+ prepos = pos
+ pos = n
+ addsalt(n, False)
+ cmd = l[4:].split()
+ if len(cmd) == 2 and cmd[0] == 'cd':
+ l = ' $ cd %s || exit 1\n' % cmd[1]
+ script.append(l[4:])
+ elif l.startswith(' > '): # continuations
+ after.setdefault(prepos, []).append(l)
+ script.append(l[4:])
+ elif l.startswith(' '): # results
+ # queue up a list of expected results
+ expected.setdefault(pos, []).append(l[2:])
+ else:
+ if inpython:
+ script.append("EOF\n")
+ inpython = False
+ # non-command/result - queue up for merged output
+ after.setdefault(pos, []).append(l)
+
+ if inpython:
+ script.append("EOF\n")
+ if skipping is not None:
+ after.setdefault(pos, []).append(' !!! missing #endif\n')
+ addsalt(n + 1, False)
+
+ # Write out the script and execute it
+ fd, name = tempfile.mkstemp(suffix='hg-tst')
+ try:
+ for l in script:
+ os.write(fd, l)
+ os.close(fd)
+
+ cmd = '%s "%s"' % (options.shell, name)
+ vlog("# Running", cmd)
+ exitcode, output = run(cmd, wd, options, replacements)
+ # do not merge output if skipped, return hghave message instead
+ # similarly, with --debug, output is None
+ if exitcode == SKIPPED_STATUS or output is None:
+ return exitcode, output
+ finally:
+ os.remove(name)
+
+ # Merge the script output back into a unified test
+
+ pos = -1
+ postout = []
+ ret = 0
+ for n, l in enumerate(output):
+ lout, lcmd = l, None
+ if salt in l:
+ lout, lcmd = l.split(salt, 1)
+
+ if lout:
+ if lcmd:
+ # output block had no trailing newline, clean up
+ lout += ' (no-eol)\n'
+
+ # find the expected output at the current position
+ el = None
+ if pos in expected and expected[pos]:
+ el = expected[pos].pop(0)
+
+ if linematch(el, lout):
+ postout.append(" " + el)
+ else:
+ if needescape(lout):
+ lout = stringescape(lout.rstrip('\n')) + " (esc)\n"
+ postout.append(" " + lout) # let diff deal with it
+
+ if lcmd:
+ # add on last return code
+ ret = int(lcmd.split()[1])
+ if ret != 0:
+ postout.append(" [%s]\n" % ret)
+ if pos in after:
+ # merge in non-active test bits
+ postout += after.pop(pos)
+ pos = int(lcmd.split()[0])
+
+ if pos in after:
+ postout += after.pop(pos)
+
+ return exitcode, postout
+
+wifexited = getattr(os, "WIFEXITED", lambda x: False)
+def run(cmd, wd, options, replacements):
+ """Run command in a sub-process, capturing the output (stdout and stderr).
+ Return a tuple (exitcode, output). output is None in debug mode."""
+ # TODO: Use subprocess.Popen if we're running on Python 2.4
+ if options.debug:
+ proc = subprocess.Popen(cmd, shell=True, cwd=wd)
+ ret = proc.wait()
+ return (ret, None)
+
+ proc = Popen4(cmd, wd, options.timeout)
+ def cleanup():
+ terminate(proc)
+ ret = proc.wait()
+ if ret == 0:
+ ret = signal.SIGTERM << 8
+ killdaemons()
+ return ret
+
+ output = ''
+ proc.tochild.close()
+
+ try:
+ output = proc.fromchild.read()
+ except KeyboardInterrupt:
+ vlog('# Handling keyboard interrupt')
+ cleanup()
+ raise
+
+ ret = proc.wait()
+ if wifexited(ret):
+ ret = os.WEXITSTATUS(ret)
+
+ if proc.timeout:
+ ret = 'timeout'
+
+ if ret:
+ killdaemons()
+
+ for s, r in replacements:
+ output = re.sub(s, r, output)
+ return ret, splitnewlines(output)
+
+def runone(options, test):
+ '''tristate output:
+ None -> skipped
+ True -> passed
+ False -> failed'''
+
+ global results, resultslock, iolock
+
+ testpath = os.path.join(TESTDIR, test)
+
+ def result(l, e):
+ resultslock.acquire()
+ results[l].append(e)
+ resultslock.release()
+
+ def skip(msg):
+ if not options.verbose:
+ result('s', (test, msg))
+ else:
+ iolock.acquire()
+ print "\nSkipping %s: %s" % (testpath, msg)
+ iolock.release()
+ return None
+
+ def fail(msg, ret):
+ if not options.nodiff:
+ iolock.acquire()
+ print "\nERROR: %s %s" % (testpath, msg)
+ iolock.release()
+ if (not ret and options.interactive
+ and os.path.exists(testpath + ".err")):
+ iolock.acquire()
+ print "Accept this change? [n] ",
+ answer = sys.stdin.readline().strip()
+ iolock.release()
+ if answer.lower() in "y yes".split():
+ if test.endswith(".t"):
+ rename(testpath + ".err", testpath)
+ else:
+ rename(testpath + ".err", testpath + ".out")
+ result('p', test)
+ return
+ result('f', (test, msg))
+
+ def success():
+ result('p', test)
+
+ def ignore(msg):
+ result('i', (test, msg))
+
+ if (os.path.basename(test).startswith("test-") and '~' not in test and
+ ('.' not in test or test.endswith('.py') or
+ test.endswith('.bat') or test.endswith('.t'))):
+ if not os.path.exists(test):
+ skip("doesn't exist")
+ return None
+ else:
+ vlog('# Test file', test, 'not supported, ignoring')
+ return None # not a supported test, don't record
+
+ if not (options.whitelisted and test in options.whitelisted):
+ if options.blacklist and test in options.blacklist:
+ skip("blacklisted")
+ return None
+
+ if options.retest and not os.path.exists(test + ".err"):
+ ignore("not retesting")
+ return None
+
+ if options.keywords:
+ fp = open(test)
+ t = fp.read().lower() + test.lower()
+ fp.close()
+ for k in options.keywords.lower().split():
+ if k in t:
+ break
+ else:
+ ignore("doesn't match keyword")
+ return None
+
+ vlog("# Test", test)
+
+ # create a fresh hgrc
+ hgrc = open(HGRCPATH, 'w+')
+ hgrc.write('[ui]\n')
+ hgrc.write('slash = True\n')
+ hgrc.write('[defaults]\n')
+ hgrc.write('backout = -d "0 0"\n')
+ hgrc.write('commit = -d "0 0"\n')
+ hgrc.write('tag = -d "0 0"\n')
+ if options.inotify:
+ hgrc.write('[extensions]\n')
+ hgrc.write('inotify=\n')
+ hgrc.write('[inotify]\n')
+ hgrc.write('pidfile=%s\n' % DAEMON_PIDS)
+ hgrc.write('appendpid=True\n')
+ if options.extra_config_opt:
+ for opt in options.extra_config_opt:
+ section, key = opt.split('.', 1)
+ assert '=' in key, ('extra config opt %s must '
+ 'have an = for assignment' % opt)
+ hgrc.write('[%s]\n%s\n' % (section, key))
+ hgrc.close()
+
+ ref = os.path.join(TESTDIR, test+".out")
+ err = os.path.join(TESTDIR, test+".err")
+ if os.path.exists(err):
+ os.remove(err) # Remove any previous output files
+ try:
+ tf = open(testpath)
+ firstline = tf.readline().rstrip()
+ tf.close()
+ except IOError:
+ firstline = ''
+ lctest = test.lower()
+
+ if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
+ runner = pytest
+ elif lctest.endswith('.t'):
+ runner = tsttest
+ ref = testpath
+ else:
+ # do not try to run non-executable programs
+ if not os.access(testpath, os.X_OK):
+ return skip("not executable")
+ runner = shtest
+
+ # Make a tmp subdirectory to work in
+ testtmp = os.environ["TESTTMP"] = os.environ["HOME"] = \
+ os.path.join(HGTMP, os.path.basename(test))
+
+ replacements = [
+ (r':%s\b' % options.port, ':$HGPORT'),
+ (r':%s\b' % (options.port + 1), ':$HGPORT1'),
+ (r':%s\b' % (options.port + 2), ':$HGPORT2'),
+ ]
+ if os.name == 'nt':
+ replacements.append((r'\r\n', '\n'))
+ replacements.append(
+ (''.join(c.isalpha() and '[%s%s]' % (c.lower(), c.upper()) or
+ c in '/\\' and r'[/\\]' or
+ c.isdigit() and c or
+ '\\' + c
+ for c in testtmp), '$TESTTMP'))
+ else:
+ replacements.append((re.escape(testtmp), '$TESTTMP'))
+
+ os.mkdir(testtmp)
+ ret, out = runner(testpath, testtmp, options, replacements)
+ vlog("# Ret was:", ret)
+
+ mark = '.'
+
+ skipped = (ret == SKIPPED_STATUS)
+
+ # If we're not in --debug mode and reference output file exists,
+ # check test output against it.
+ if options.debug:
+ refout = None # to match "out is None"
+ elif os.path.exists(ref):
+ f = open(ref, "r")
+ refout = list(splitnewlines(f.read()))
+ f.close()
+ else:
+ refout = []
+
+ if (ret != 0 or out != refout) and not skipped and not options.debug:
+ # Save errors to a file for diagnosis
+ f = open(err, "wb")
+ for line in out:
+ f.write(line)
+ f.close()
+
+ if skipped:
+ mark = 's'
+ if out is None: # debug mode: nothing to parse
+ missing = ['unknown']
+ failed = None
+ else:
+ missing, failed = parsehghaveoutput(out)
+ if not missing:
+ missing = ['irrelevant']
+ if failed:
+ fail("hghave failed checking for %s" % failed[-1], ret)
+ skipped = False
+ else:
+ skip(missing[-1])
+ elif ret == 'timeout':
+ mark = 't'
+ fail("timed out", ret)
+ elif out != refout:
+ mark = '!'
+ if not options.nodiff:
+ iolock.acquire()
+ if options.view:
+ os.system("%s %s %s" % (options.view, ref, err))
+ else:
+ showdiff(refout, out, ref, err)
+ iolock.release()
+ if ret:
+ fail("output changed and returned error code %d" % ret, ret)
+ else:
+ fail("output changed", ret)
+ ret = 1
+ elif ret:
+ mark = '!'
+ fail("returned error code %d" % ret, ret)
+ else:
+ success()
+
+ if not options.verbose:
+ iolock.acquire()
+ sys.stdout.write(mark)
+ sys.stdout.flush()
+ iolock.release()
+
+ killdaemons()
+
+ if not options.keep_tmpdir:
+ shutil.rmtree(testtmp, True)
+ if skipped:
+ return None
+ return ret == 0
+
+_hgpath = None
+
+def _gethgpath():
+ """Return the path to the mercurial package that is actually found by
+ the current Python interpreter."""
+ global _hgpath
+ if _hgpath is not None:
+ return _hgpath
+
+ cmd = '%s -c "import mercurial; print mercurial.__path__[0]"'
+ pipe = os.popen(cmd % PYTHON)
+ try:
+ _hgpath = pipe.read().strip()
+ finally:
+ pipe.close()
+ return _hgpath
+
+def _checkhglib(verb):
+ """Ensure that the 'mercurial' package imported by python is
+ the one we expect it to be. If not, print a warning to stderr."""
+ expecthg = os.path.join(PYTHONDIR, 'mercurial')
+ actualhg = _gethgpath()
+ if os.path.abspath(actualhg) != os.path.abspath(expecthg):
+ sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
+ ' (expected %s)\n'
+ % (verb, actualhg, expecthg))
+
+def runchildren(options, tests):
+ if INST:
+ installhg(options)
+ _checkhglib("Testing")
+
+ optcopy = dict(options.__dict__)
+ optcopy['jobs'] = 1
+
+ # Because whitelist has to override keyword matches, we have to
+ # actually load the whitelist in the children as well, so we allow
+ # the list of whitelist files to pass through and be parsed in the
+ # children, but not the dict of whitelisted tests resulting from
+ # the parse, used here to override blacklisted tests.
+ whitelist = optcopy['whitelisted'] or []
+ del optcopy['whitelisted']
+
+ blacklist = optcopy['blacklist'] or []
+ del optcopy['blacklist']
+ blacklisted = []
+
+ if optcopy['with_hg'] is None:
+ optcopy['with_hg'] = os.path.join(BINDIR, "hg")
+ optcopy.pop('anycoverage', None)
+
+ opts = []
+ for opt, value in optcopy.iteritems():
+ name = '--' + opt.replace('_', '-')
+ if value is True:
+ opts.append(name)
+ elif isinstance(value, list):
+ for v in value:
+ opts.append(name + '=' + str(v))
+ elif value is not None:
+ opts.append(name + '=' + str(value))
+
+ tests.reverse()
+ jobs = [[] for j in xrange(options.jobs)]
+ while tests:
+ for job in jobs:
+ if not tests:
+ break
+ test = tests.pop()
+ if test not in whitelist and test in blacklist:
+ blacklisted.append(test)
+ else:
+ job.append(test)
+ fps = {}
+
+ for j, job in enumerate(jobs):
+ if not job:
+ continue
+ rfd, wfd = os.pipe()
+ childopts = ['--child=%d' % wfd, '--port=%d' % (options.port + j * 3)]
+ childtmp = os.path.join(HGTMP, 'child%d' % j)
+ childopts += ['--tmpdir', childtmp]
+ cmdline = [PYTHON, sys.argv[0]] + opts + childopts + job
+ vlog(' '.join(cmdline))
+ fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'r')
+ os.close(wfd)
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ failures = 0
+ tested, skipped, failed = 0, 0, 0
+ skips = []
+ fails = []
+ while fps:
+ pid, status = os.wait()
+ fp = fps.pop(pid)
+ l = fp.read().splitlines()
+ try:
+ test, skip, fail = map(int, l[:3])
+ except ValueError:
+ test, skip, fail = 0, 0, 0
+ split = -fail or len(l)
+ for s in l[3:split]:
+ skips.append(s.split(" ", 1))
+ for s in l[split:]:
+ fails.append(s.split(" ", 1))
+ tested += test
+ skipped += skip
+ failed += fail
+ vlog('pid %d exited, status %d' % (pid, status))
+ failures |= status
+ print
+ skipped += len(blacklisted)
+ if not options.noskips:
+ for s in skips:
+ print "Skipped %s: %s" % (s[0], s[1])
+ for s in blacklisted:
+ print "Skipped %s: blacklisted" % s
+ for s in fails:
+ print "Failed %s: %s" % (s[0], s[1])
+
+ _checkhglib("Tested")
+ print "# Ran %d tests, %d skipped, %d failed." % (
+ tested, skipped, failed)
+
+ if options.anycoverage:
+ outputcoverage(options)
+ sys.exit(failures != 0)
+
+results = dict(p=[], f=[], s=[], i=[])
+resultslock = threading.Lock()
+iolock = threading.Lock()
+
+def runqueue(options, tests, results):
+ for test in tests:
+ ret = runone(options, test)
+ if options.first and ret is not None and not ret:
+ break
+
+def runtests(options, tests):
+ global DAEMON_PIDS, HGRCPATH
+ DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
+ HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
+
+ try:
+ if INST:
+ installhg(options)
+ _checkhglib("Testing")
+
+ if options.restart:
+ orig = list(tests)
+ while tests:
+ if os.path.exists(tests[0] + ".err"):
+ break
+ tests.pop(0)
+ if not tests:
+ print "running all tests"
+ tests = orig
+
+ runqueue(options, tests, results)
+
+ failed = len(results['f'])
+ tested = len(results['p']) + failed
+ skipped = len(results['s'])
+ ignored = len(results['i'])
+
+ if options.child:
+ fp = os.fdopen(options.child, 'w')
+ fp.write('%d\n%d\n%d\n' % (tested, skipped, failed))
+ for s in results['s']:
+ fp.write("%s %s\n" % s)
+ for s in results['f']:
+ fp.write("%s %s\n" % s)
+ fp.close()
+ else:
+ print
+ for s in results['s']:
+ print "Skipped %s: %s" % s
+ for s in results['f']:
+ print "Failed %s: %s" % s
+ _checkhglib("Tested")
+ print "# Ran %d tests, %d skipped, %d failed." % (
+ tested, skipped + ignored, failed)
+
+ if options.anycoverage:
+ outputcoverage(options)
+ except KeyboardInterrupt:
+ failed = True
+ print "\ninterrupted!"
+
+ if failed:
+ sys.exit(1)
+
+def main():
+ (options, args) = parseargs()
+ if not options.child:
+ os.umask(022)
+
+ checktools()
+
+ if len(args) == 0:
+ args = os.listdir(".")
+ args.sort()
+
+ tests = args
+
+ # Reset some environment variables to well-known values so that
+ # the tests produce repeatable output.
+ os.environ['LANG'] = os.environ['LC_ALL'] = os.environ['LANGUAGE'] = 'C'
+ os.environ['TZ'] = 'GMT'
+ os.environ["EMAIL"] = "Foo Bar <foo.bar@example.com>"
+ os.environ['CDPATH'] = ''
+ os.environ['COLUMNS'] = '80'
+ os.environ['GREP_OPTIONS'] = ''
+ os.environ['http_proxy'] = ''
+ os.environ['no_proxy'] = ''
+ os.environ['NO_PROXY'] = ''
+ os.environ['TERM'] = 'xterm'
+
+ # unset env related to hooks
+ for k in os.environ.keys():
+ if k.startswith('HG_'):
+ # can't remove on solaris
+ os.environ[k] = ''
+ del os.environ[k]
+
+ global TESTDIR, HGTMP, INST, BINDIR, PYTHONDIR, COVERAGE_FILE
+ TESTDIR = os.environ["TESTDIR"] = os.getcwd()
+ if options.tmpdir:
+ options.keep_tmpdir = True
+ tmpdir = options.tmpdir
+ if os.path.exists(tmpdir):
+ # Meaning of tmpdir has changed since 1.3: we used to create
+ # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
+ # tmpdir already exists.
+ sys.exit("error: temp dir %r already exists" % tmpdir)
+
+ # Automatically removing tmpdir sounds convenient, but could
+ # really annoy anyone in the habit of using "--tmpdir=/tmp"
+ # or "--tmpdir=$HOME".
+ #vlog("# Removing temp dir", tmpdir)
+ #shutil.rmtree(tmpdir)
+ os.makedirs(tmpdir)
+ else:
+ d = None
+ if os.name == 'nt':
+ # without this, we get the default temp dir location, but
+ # in all lowercase, which causes troubles with paths (issue3490)
+ d = os.getenv('TMP')
+ tmpdir = tempfile.mkdtemp('', 'hgtests.', d)
+ HGTMP = os.environ['HGTMP'] = os.path.realpath(tmpdir)
+ DAEMON_PIDS = None
+ HGRCPATH = None
+
+ os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
+ os.environ["HGMERGE"] = "internal:merge"
+ os.environ["HGUSER"] = "test"
+ os.environ["HGENCODING"] = "ascii"
+ os.environ["HGENCODINGMODE"] = "strict"
+ os.environ["HGPORT"] = str(options.port)
+ os.environ["HGPORT1"] = str(options.port + 1)
+ os.environ["HGPORT2"] = str(options.port + 2)
+
+ if options.with_hg:
+ INST = None
+ BINDIR = os.path.dirname(os.path.realpath(options.with_hg))
+
+ # This looks redundant with how Python initializes sys.path from
+ # the location of the script being executed. Needed because the
+ # "hg" specified by --with-hg is not the only Python script
+ # executed in the test suite that needs to import 'mercurial'
+ # ... which means it's not really redundant at all.
+ PYTHONDIR = BINDIR
+ else:
+ INST = os.path.join(HGTMP, "install")
+ BINDIR = os.environ["BINDIR"] = os.path.join(INST, "bin")
+ PYTHONDIR = os.path.join(INST, "lib", "python")
+
+ os.environ["BINDIR"] = BINDIR
+ os.environ["PYTHON"] = PYTHON
+
+ if not options.child:
+ path = [BINDIR] + os.environ["PATH"].split(os.pathsep)
+ os.environ["PATH"] = os.pathsep.join(path)
+
+ # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
+ # can run .../tests/run-tests.py test-foo where test-foo
+ # adds an extension to HGRC
+ pypath = [PYTHONDIR, TESTDIR]
+ # We have to augment PYTHONPATH, rather than simply replacing
+ # it, in case external libraries are only available via current
+ # PYTHONPATH. (In particular, the Subversion bindings on OS X
+ # are in /opt/subversion.)
+ oldpypath = os.environ.get(IMPL_PATH)
+ if oldpypath:
+ pypath.append(oldpypath)
+ os.environ[IMPL_PATH] = os.pathsep.join(pypath)
+
+ COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
+
+ vlog("# Using TESTDIR", TESTDIR)
+ vlog("# Using HGTMP", HGTMP)
+ vlog("# Using PATH", os.environ["PATH"])
+ vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
+
+ try:
+ if len(tests) > 1 and options.jobs > 1:
+ runchildren(options, tests)
+ else:
+ runtests(options, tests)
+ finally:
+ time.sleep(.1)
+ cleanup(options)
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/sitecustomize.py b/tests/sitecustomize.py
new file mode 100644
index 0000000..50d281f
--- /dev/null
+++ b/tests/sitecustomize.py
@@ -0,0 +1,5 @@
+try:
+ import coverage
+ getattr(coverage, 'process_startup', lambda: None)()
+except ImportError:
+ pass
diff --git a/tests/svn-safe-append.py b/tests/svn-safe-append.py
new file mode 100755
index 0000000..bc70419
--- /dev/null
+++ b/tests/svn-safe-append.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+__doc__ = """Same as `echo a >> b`, but ensures a changed mtime of b.
+Without this svn will not detect workspace changes."""
+
+import sys, os
+
+text = sys.argv[1]
+fname = sys.argv[2]
+
+f = open(fname, "ab")
+try:
+ before = os.fstat(f.fileno()).st_mtime
+ f.write(text)
+ f.write("\n")
+finally:
+ f.close()
+inc = 1
+now = os.stat(fname).st_mtime
+while now == before:
+ t = now + inc
+ inc += 1
+ os.utime(fname, (t, t))
+ now = os.stat(fname).st_mtime
+
diff --git a/tests/svn/branches.svndump b/tests/svn/branches.svndump
new file mode 100644
index 0000000..650980b
--- /dev/null
+++ b/tests/svn/branches.svndump
@@ -0,0 +1,416 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 644ede6c-2b81-4367-9dc8-d786514f2cde
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2010-05-19T20:16:07.429098Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 112
+Content-length: 112
+
+K 7
+svn:log
+V 10
+init projA
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-19T20:16:07.461283Z
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 106
+Content-length: 106
+
+K 7
+svn:log
+V 5
+hello
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-19T20:16:08.121436Z
+PROPS-END
+
+Node-path: branches/notinbranch
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: e29311f6f1bf1af907f9ef9f44b8328b
+Text-content-sha1: e983f374794de9c64e3d1c1de1d490c0756eeeff
+Content-length: 12
+
+PROPS-END
+d
+
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Node-path: trunk/b
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 3b5d5c3712955042212316173ccf37be
+Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b
+Content-length: 12
+
+PROPS-END
+b
+
+
+Node-path: trunk/c
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 2cd6ee2c70b0bde53fbe6cac3c8b8bb1
+Text-content-sha1: 2b66fd261ee5c6cfc8de7fa466bab600bcfe4f69
+Content-length: 12
+
+PROPS-END
+c
+
+
+Node-path: trunk/dir
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/dir/e
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 9ffbf43126e33be52cd2bf7e01d627f9
+Text-content-sha1: 094e3afb2fe8dfe82f63731cdcd3b999f4856cff
+Content-length: 12
+
+PROPS-END
+e
+
+
+Revision-number: 3
+Prop-content-length: 132
+Content-length: 132
+
+K 7
+svn:log
+V 30
+branch trunk, remove c and dir
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-19T20:16:11.113124Z
+PROPS-END
+
+Node-path: branches/old
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk
+
+
+Node-path: branches/old/dir
+Node-action: delete
+
+
+Node-path: branches/old/c
+Node-action: delete
+
+
+Revision-number: 4
+Prop-content-length: 109
+Content-length: 109
+
+K 7
+svn:log
+V 8
+change a
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-19T20:16:13.060877Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: 0d227f1abf8c2932d342e9b99cc957eb
+Text-content-sha1: d7c8127a20a396cff08af086a1c695b0636f0c29
+Content-length: 4
+
+a
+a
+
+
+Revision-number: 5
+Prop-content-length: 109
+Content-length: 109
+
+K 7
+svn:log
+V 8
+change b
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-19T20:16:14.066212Z
+PROPS-END
+
+Node-path: branches/old/b
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: 06ac26ed8b614fc0b141e4542aa067c2
+Text-content-sha1: f6980469e74f7125178e88ec571e06fe6ce86e95
+Content-length: 4
+
+b
+b
+
+
+Revision-number: 6
+Prop-content-length: 119
+Content-length: 119
+
+K 7
+svn:log
+V 17
+move and update c
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-19T20:16:16.069449Z
+PROPS-END
+
+Node-path: branches/old/c
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 3
+Node-copyfrom-path: trunk/b
+Text-copy-source-md5: 3b5d5c3712955042212316173ccf37be
+Text-copy-source-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b
+Text-content-length: 4
+Text-content-md5: 33cb6785d50937d8d307ebb66d6259a7
+Text-content-sha1: 7a6478264aa11a0f4befef356c03e83f2b1f6eba
+Content-length: 4
+
+b
+c
+
+
+Node-path: trunk/b
+Node-action: delete
+
+
+Revision-number: 7
+Prop-content-length: 116
+Content-length: 116
+
+K 7
+svn:log
+V 14
+change b again
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-19T20:16:17.070868Z
+PROPS-END
+
+Node-path: branches/old/b
+Node-kind: file
+Node-action: change
+Text-content-length: 6
+Text-content-md5: cdcfb41554e2d092c13f5e6839e63577
+Text-content-sha1: 17ac58cabedebea235d1b5605531d5b1559797e9
+Content-length: 6
+
+b
+b
+b
+
+
+Revision-number: 8
+Prop-content-length: 114
+Content-length: 114
+
+K 7
+svn:log
+V 12
+move to old2
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-19T20:16:20.063098Z
+PROPS-END
+
+Node-path: branches/old2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 7
+Node-copyfrom-path: branches/old
+
+
+Node-path: branches/old
+Node-action: delete
+
+
+Revision-number: 9
+Prop-content-length: 118
+Content-length: 118
+
+K 7
+svn:log
+V 16
+move back to old
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-19T20:16:22.062931Z
+PROPS-END
+
+Node-path: branches/old
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 8
+Node-copyfrom-path: branches/old2
+
+
+Node-path: branches/old2
+Node-action: delete
+
+
+Revision-number: 10
+Prop-content-length: 118
+Content-length: 118
+
+K 7
+svn:log
+V 16
+last change to a
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-19T20:16:23.075562Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: change
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 2
+
+a
+
+
+Revision-number: 11
+Prop-content-length: 126
+Content-length: 126
+
+K 7
+svn:log
+V 24
+branch trunk@1 into old3
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-19T20:16:25.107655Z
+PROPS-END
+
+Node-path: branches/old3
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk
+
+
diff --git a/tests/svn/empty.svndump b/tests/svn/empty.svndump
new file mode 100644
index 0000000..6bd513f
--- /dev/null
+++ b/tests/svn/empty.svndump
@@ -0,0 +1,129 @@
+SVN-fs-dump-format-version: 2
+
+UUID: b70c45d5-2b76-4722-a373-d9babae61626
+
+Revision-number: 0
+Prop-content-length: 260
+Content-length: 260
+
+K 8
+svn:date
+V 27
+2012-04-18T11:35:14.752409Z
+K 17
+svn:sync-from-url
+V 73
+file:///Users/pmezard/dev/hg/hg-pmezard/tests/svn/temp/svn-repo/trunk/dir
+K 18
+svn:sync-from-uuid
+V 36
+56625b9e-e7e9-45be-ab61-052d41f0e1dd
+K 24
+svn:sync-last-merged-rev
+V 1
+4
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 112
+Content-length: 112
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-04-18T11:35:14.769622Z
+K 7
+svn:log
+V 10
+init projA
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 107
+Content-length: 107
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-04-18T11:35:15.052989Z
+K 7
+svn:log
+V 6
+adddir
+PROPS-END
+
+Node-path: trunk/dir
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/dir/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Revision-number: 3
+Prop-content-length: 105
+Content-length: 105
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-04-18T11:35:16.050353Z
+K 7
+svn:log
+V 4
+addb
+PROPS-END
+
+Revision-number: 4
+Prop-content-length: 105
+Content-length: 105
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-04-18T11:35:17.050768Z
+K 7
+svn:log
+V 4
+addc
+PROPS-END
+
diff --git a/tests/svn/encoding.svndump b/tests/svn/encoding.svndump
new file mode 100644
index 0000000..350635e
--- /dev/null
+++ b/tests/svn/encoding.svndump
@@ -0,0 +1,280 @@
+SVN-fs-dump-format-version: 2
+
+UUID: afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2009-06-21T16:34:55.835945Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 112
+Content-length: 112
+
+K 7
+svn:log
+V 10
+init projA
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-06-21T16:34:55.909545Z
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: tags
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 106
+Content-length: 106
+
+K 7
+svn:log
+V 5
+hello
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-06-21T16:34:56.150049Z
+PROPS-END
+
+Node-path: trunk/à
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/à/eÌ
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: e29311f6f1bf1af907f9ef9f44b8328b
+Text-content-sha1: e983f374794de9c64e3d1c1de1d490c0756eeeff
+Content-length: 12
+
+PROPS-END
+d
+
+
+Node-path: trunk/é
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 9ffbf43126e33be52cd2bf7e01d627f9
+Text-content-sha1: 094e3afb2fe8dfe82f63731cdcd3b999f4856cff
+Content-length: 12
+
+PROPS-END
+e
+
+
+Revision-number: 3
+Prop-content-length: 112
+Content-length: 112
+
+K 7
+svn:log
+V 10
+copy files
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-06-21T16:34:59.089402Z
+PROPS-END
+
+Node-path: trunk/è
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/é
+Text-copy-source-md5: 9ffbf43126e33be52cd2bf7e01d627f9
+Text-copy-source-sha1: 094e3afb2fe8dfe82f63731cdcd3b999f4856cff
+
+
+Node-path: trunk/ù
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/à
+
+
+Node-path: trunk/à
+Node-action: delete
+
+
+Node-path: trunk/é
+Node-action: delete
+
+
+Revision-number: 4
+Prop-content-length: 114
+Content-length: 114
+
+K 7
+svn:log
+V 12
+remove files
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-06-21T16:35:00.165121Z
+PROPS-END
+
+Node-path: trunk/è
+Node-action: delete
+
+
+Node-path: trunk/ù
+Node-action: delete
+
+
+Revision-number: 5
+Prop-content-length: 120
+Content-length: 120
+
+K 7
+svn:log
+V 18
+branch to branché
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-06-21T16:35:03.079138Z
+PROPS-END
+
+Node-path: branches/branché
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 4
+Node-copyfrom-path: trunk
+
+
+Revision-number: 6
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 19
+branch to branchée
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-06-21T16:35:06.060801Z
+PROPS-END
+
+Node-path: branches/branchée
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 5
+Node-copyfrom-path: branches/branché
+
+
+Revision-number: 7
+Prop-content-length: 110
+Content-length: 110
+
+K 7
+svn:log
+V 9
+tag trunk
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-06-21T16:35:09.061530Z
+PROPS-END
+
+Node-path: tags/branché
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 6
+Node-copyfrom-path: trunk
+
+
+Revision-number: 8
+Prop-content-length: 114
+Content-length: 114
+
+K 7
+svn:log
+V 12
+tag branché
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-06-21T16:35:11.068562Z
+PROPS-END
+
+Node-path: tags/branchée
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 6
+Node-copyfrom-path: branches/branchée
+
+
diff --git a/tests/svn/move.svndump b/tests/svn/move.svndump
new file mode 100644
index 0000000..eaf08d9
--- /dev/null
+++ b/tests/svn/move.svndump
@@ -0,0 +1,569 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 7d15f7c2-5863-4c16-aa2a-3418b1721d3a
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2010-05-09T13:02:37.336239Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 112
+Content-length: 112
+
+K 7
+svn:log
+V 10
+init projA
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:37.372834Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Node-path: trunk/d1
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/d1/b
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 3b5d5c3712955042212316173ccf37be
+Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b
+Content-length: 12
+
+PROPS-END
+b
+
+
+Node-path: trunk/d1/c
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 2cd6ee2c70b0bde53fbe6cac3c8b8bb1
+Text-content-sha1: 2b66fd261ee5c6cfc8de7fa466bab600bcfe4f69
+Content-length: 12
+
+PROPS-END
+c
+
+
+Node-path: trunk/d2
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/d2/d
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: e29311f6f1bf1af907f9ef9f44b8328b
+Text-content-sha1: e983f374794de9c64e3d1c1de1d490c0756eeeff
+Content-length: 12
+
+PROPS-END
+d
+
+
+Revision-number: 2
+Prop-content-length: 118
+Content-length: 118
+
+K 7
+svn:log
+V 16
+commitbeforemove
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:38.049068Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: 0d227f1abf8c2932d342e9b99cc957eb
+Text-content-sha1: d7c8127a20a396cff08af086a1c695b0636f0c29
+Content-length: 4
+
+a
+a
+
+
+Node-path: trunk/d1/c
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: 63fad9092ad37713ebe26b3193f89c41
+Text-content-sha1: ccfb93b7bac6f1520f0adc0eebc2cafe9da80f42
+Content-length: 4
+
+c
+c
+
+
+Revision-number: 3
+Prop-content-length: 112
+Content-length: 112
+
+K 7
+svn:log
+V 10
+movedtrunk
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:39.044479Z
+PROPS-END
+
+Node-path: subproject
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk
+
+
+Node-path: trunk
+Node-action: delete
+
+
+Revision-number: 4
+Prop-content-length: 113
+Content-length: 113
+
+K 7
+svn:log
+V 11
+createtrunk
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:40.057804Z
+PROPS-END
+
+Node-path: subproject/trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 5
+Prop-content-length: 116
+Content-length: 116
+
+K 7
+svn:log
+V 14
+createbranches
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:41.058871Z
+PROPS-END
+
+Node-path: subproject/branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 6
+Prop-content-length: 107
+Content-length: 107
+
+K 7
+svn:log
+V 6
+moved1
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:42.046689Z
+PROPS-END
+
+Node-path: subproject/trunk/d1
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 5
+Node-copyfrom-path: subproject/d1
+
+
+Node-path: subproject/d1
+Node-action: delete
+
+
+Revision-number: 7
+Prop-content-length: 107
+Content-length: 107
+
+K 7
+svn:log
+V 6
+moved2
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:42.071413Z
+PROPS-END
+
+Node-path: subproject/trunk/d2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 6
+Node-copyfrom-path: subproject/d2
+
+
+Node-path: subproject/d2
+Node-action: delete
+
+
+Revision-number: 8
+Prop-content-length: 119
+Content-length: 119
+
+K 7
+svn:log
+V 17
+changeb and rm d2
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:43.062018Z
+PROPS-END
+
+Node-path: subproject/trunk/d1/b
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: 06ac26ed8b614fc0b141e4542aa067c2
+Text-content-sha1: f6980469e74f7125178e88ec571e06fe6ce86e95
+Content-length: 4
+
+b
+b
+
+
+Node-path: subproject/trunk/d2
+Node-action: delete
+
+
+Revision-number: 9
+Prop-content-length: 113
+Content-length: 113
+
+K 7
+svn:log
+V 11
+moved1again
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:44.047997Z
+PROPS-END
+
+Node-path: subproject/branches/d1
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 8
+Node-copyfrom-path: subproject/trunk/d1
+
+
+Node-path: subproject/trunk/d1
+Node-action: delete
+
+
+Revision-number: 10
+Prop-content-length: 118
+Content-length: 118
+
+K 7
+svn:log
+V 16
+copyfilefrompast
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:44.086619Z
+PROPS-END
+
+Node-path: subproject/trunk/d
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 7
+Node-copyfrom-path: subproject/trunk/d2/d
+Text-copy-source-md5: e29311f6f1bf1af907f9ef9f44b8328b
+Text-copy-source-sha1: e983f374794de9c64e3d1c1de1d490c0756eeeff
+
+
+Revision-number: 11
+Prop-content-length: 117
+Content-length: 117
+
+K 7
+svn:log
+V 15
+copydirfrompast
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:44.111550Z
+PROPS-END
+
+Node-path: subproject/trunk/d2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 7
+Node-copyfrom-path: subproject/trunk/d2
+
+
+Revision-number: 12
+Prop-content-length: 107
+Content-length: 107
+
+K 7
+svn:log
+V 6
+add d3
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:45.067982Z
+PROPS-END
+
+Node-path: subproject/trunk/d3
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: subproject/trunk/d3/d31
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: subproject/trunk/d3/d31/e
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 9ffbf43126e33be52cd2bf7e01d627f9
+Text-content-sha1: 094e3afb2fe8dfe82f63731cdcd3b999f4856cff
+Content-length: 12
+
+PROPS-END
+e
+
+
+Node-path: subproject/trunk/d3/f
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 9a8ad92c50cae39aa2c5604fd0ab6d8c
+Text-content-sha1: a9fcd54b25e7e863d72cd47c08af46e61b74b561
+Content-length: 12
+
+PROPS-END
+f
+
+
+Revision-number: 13
+Prop-content-length: 128
+Content-length: 128
+
+K 7
+svn:log
+V 26
+copy dir and remove subdir
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:47.061259Z
+PROPS-END
+
+Node-path: subproject/trunk/d3/d31
+Node-action: delete
+
+
+Node-path: subproject/trunk/d4
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 12
+Node-copyfrom-path: subproject/trunk/d3
+
+
+Revision-number: 14
+Prop-content-length: 110
+Content-length: 110
+
+K 7
+svn:log
+V 9
+add d4old
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:49.063363Z
+PROPS-END
+
+Node-path: subproject/trunk/d4old
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: subproject/trunk/d4old/g
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: f5302386464f953ed581edac03556e55
+Text-content-sha1: a5938ace3f424be1a26904781cdb06d55b614e6b
+Content-length: 12
+
+PROPS-END
+g
+
+
+Revision-number: 15
+Prop-content-length: 125
+Content-length: 125
+
+K 7
+svn:log
+V 23
+rename d4old into d4new
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:51.047304Z
+PROPS-END
+
+Node-path: subproject/trunk/d4new
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 14
+Node-copyfrom-path: subproject/trunk/d4old
+
+
+Node-path: subproject/trunk/d4old
+Node-action: delete
+
+
diff --git a/tests/svn/replace.svndump b/tests/svn/replace.svndump
new file mode 100644
index 0000000..8fe58ba
--- /dev/null
+++ b/tests/svn/replace.svndump
@@ -0,0 +1,367 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 97a955ef-0269-44f2-a58f-abd4ad400b2b
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2010-11-26T18:01:12.912988Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 108
+Content-length: 108
+
+K 7
+svn:log
+V 7
+initial
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-11-26T18:01:13.106933Z
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Node-path: trunk/d
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/d/b
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 3b5d5c3712955042212316173ccf37be
+Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b
+Content-length: 12
+
+PROPS-END
+b
+
+
+Node-path: trunk/d2
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/d2/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Node-path: trunk/dlink
+Node-kind: file
+Node-action: add
+Prop-content-length: 33
+Text-content-length: 6
+Text-content-md5: cca56829f18345718a4980bb02b6d8c3
+Text-content-sha1: 7c54cc5d472b78c94a04382df34b0f4f0f4f2d49
+Content-length: 39
+
+K 11
+svn:special
+V 1
+*
+PROPS-END
+link d
+
+Node-path: trunk/dlink2
+Node-kind: file
+Node-action: add
+Prop-content-length: 33
+Text-content-length: 6
+Text-content-md5: cca56829f18345718a4980bb02b6d8c3
+Text-content-sha1: 7c54cc5d472b78c94a04382df34b0f4f0f4f2d49
+Content-length: 39
+
+K 11
+svn:special
+V 1
+*
+PROPS-END
+link d
+
+Node-path: trunk/dlink3
+Node-kind: file
+Node-action: add
+Prop-content-length: 33
+Text-content-length: 6
+Text-content-md5: cca56829f18345718a4980bb02b6d8c3
+Text-content-sha1: 7c54cc5d472b78c94a04382df34b0f4f0f4f2d49
+Content-length: 39
+
+K 11
+svn:special
+V 1
+*
+PROPS-END
+link d
+
+Revision-number: 2
+Prop-content-length: 117
+Content-length: 117
+
+K 7
+svn:log
+V 15
+clobber symlink
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-11-26T18:01:14.073483Z
+PROPS-END
+
+Node-path: trunk/dlink3
+Node-kind: file
+Node-action: change
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: e29311f6f1bf1af907f9ef9f44b8328b
+Text-content-sha1: e983f374794de9c64e3d1c1de1d490c0756eeeff
+Content-length: 12
+
+PROPS-END
+d
+
+
+Revision-number: 3
+Prop-content-length: 106
+Content-length: 106
+
+K 7
+svn:log
+V 8
+clobber1
+K 10
+svn:author
+V 4
+evil
+K 8
+svn:date
+V 27
+2010-11-26T18:01:16.205184Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: dir
+Node-action: delete
+
+Node-path: trunk/a
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/d
+
+
+
+
+Node-path: trunk/dlink
+Node-kind: dir
+Node-action: delete
+
+Node-path: trunk/dlink
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/d
+
+
+
+
+Revision-number: 4
+Prop-content-length: 106
+Content-length: 106
+
+K 7
+svn:log
+V 8
+clobber2
+K 10
+svn:author
+V 4
+evil
+K 8
+svn:date
+V 27
+2010-11-26T18:01:16.395962Z
+PROPS-END
+
+Node-path: trunk/dlink3
+Node-kind: file
+Node-action: delete
+
+Node-path: trunk/dlink3
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 3
+Node-copyfrom-path: trunk/dlink2
+Text-copy-source-md5: cca56829f18345718a4980bb02b6d8c3
+Text-copy-source-sha1: 7c54cc5d472b78c94a04382df34b0f4f0f4f2d49
+
+
+
+
+Revision-number: 5
+Prop-content-length: 106
+Content-length: 106
+
+K 7
+svn:log
+V 5
+adddb
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-11-26T18:01:16.445072Z
+PROPS-END
+
+Node-path: trunk/d2/b
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 3b5d5c3712955042212316173ccf37be
+Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b
+Content-length: 12
+
+PROPS-END
+b
+
+
+Revision-number: 6
+Prop-content-length: 107
+Content-length: 107
+
+K 7
+svn:log
+V 6
+branch
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-11-26T18:01:19.075874Z
+PROPS-END
+
+Node-path: branches/branch
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 5
+Node-copyfrom-path: trunk
+
+
+Node-path: branches/branch/d2/c
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 2cd6ee2c70b0bde53fbe6cac3c8b8bb1
+Text-content-sha1: 2b66fd261ee5c6cfc8de7fa466bab600bcfe4f69
+Content-length: 12
+
+PROPS-END
+c
+
+
+Node-path: branches/branch/d2/b
+Node-action: delete
+
+
+Revision-number: 7
+Prop-content-length: 109
+Content-length: 109
+
+K 7
+svn:log
+V 10
+clobberdir
+K 10
+svn:author
+V 4
+evil
+K 8
+svn:date
+V 27
+2010-11-26T18:01:21.202158Z
+PROPS-END
+
+Node-path: trunk/d2
+Node-kind: dir
+Node-action: delete
+
+Node-path: trunk/d2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 6
+Node-copyfrom-path: branches/branch/d2
+
+
+
+
diff --git a/tests/svn/startrev.svndump b/tests/svn/startrev.svndump
new file mode 100644
index 0000000..00c6fec
--- /dev/null
+++ b/tests/svn/startrev.svndump
@@ -0,0 +1,240 @@
+SVN-fs-dump-format-version: 2
+
+UUID: c731c652-65e9-4325-a17e-fed96a319f22
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2008-12-06T13:44:21.642421Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 112
+Content-length: 112
+
+K 7
+svn:log
+V 10
+init projA
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2008-12-06T13:44:21.759281Z
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: tags
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 109
+Content-length: 109
+
+K 7
+svn:log
+V 8
+createab
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2008-12-06T13:44:22.179257Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Content-length: 12
+
+PROPS-END
+a
+
+
+Node-path: trunk/b
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 3b5d5c3712955042212316173ccf37be
+Content-length: 12
+
+PROPS-END
+b
+
+
+Revision-number: 3
+Prop-content-length: 108
+Content-length: 108
+
+K 7
+svn:log
+V 7
+removeb
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2008-12-06T13:44:23.176546Z
+PROPS-END
+
+Node-path: trunk/b
+Node-action: delete
+
+
+Revision-number: 4
+Prop-content-length: 109
+Content-length: 109
+
+K 7
+svn:log
+V 8
+changeaa
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2008-12-06T13:44:25.147151Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: 0d227f1abf8c2932d342e9b99cc957eb
+Content-length: 4
+
+a
+a
+
+
+Revision-number: 5
+Prop-content-length: 119
+Content-length: 119
+
+K 7
+svn:log
+V 17
+branch, changeaaa
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2008-12-06T13:44:28.158475Z
+PROPS-END
+
+Node-path: branches/branch1
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 4
+Node-copyfrom-path: trunk
+Prop-content-length: 34
+Content-length: 34
+
+K 13
+svn:mergeinfo
+V 0
+
+PROPS-END
+
+
+Node-path: branches/branch1/a
+Node-kind: file
+Node-action: change
+Text-content-length: 6
+Text-content-md5: 7d4ebf8f298d22fc349a91725b00af1c
+Content-length: 6
+
+a
+a
+a
+
+
+Revision-number: 6
+Prop-content-length: 117
+Content-length: 117
+
+K 7
+svn:log
+V 15
+addc,changeaaaa
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2008-12-06T13:44:29.180655Z
+PROPS-END
+
+Node-path: branches/branch1/a
+Node-kind: file
+Node-action: change
+Text-content-length: 8
+Text-content-md5: d12178e74d8774e34361e0a08d1fd2b7
+Content-length: 8
+
+a
+a
+a
+a
+
+
+Node-path: branches/branch1/c
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 2cd6ee2c70b0bde53fbe6cac3c8b8bb1
+Content-length: 12
+
+PROPS-END
+c
+
+
diff --git a/tests/svn/svndump-branches.sh b/tests/svn/svndump-branches.sh
new file mode 100755
index 0000000..c721758
--- /dev/null
+++ b/tests/svn/svndump-branches.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+#
+# Use this script to generate branches.svndump
+#
+
+mkdir temp
+cd temp
+
+mkdir project-orig
+cd project-orig
+mkdir trunk
+mkdir branches
+cd ..
+
+svnadmin create svn-repo
+svnurl=file://`pwd`/svn-repo
+svn import project-orig $svnurl -m "init projA"
+
+svn co $svnurl project
+cd project
+echo a > trunk/a
+echo b > trunk/b
+echo c > trunk/c
+mkdir trunk/dir
+echo e > trunk/dir/e
+# Add a file within branches, used to confuse branch detection
+echo d > branches/notinbranch
+svn add trunk/a trunk/b trunk/c trunk/dir branches/notinbranch
+svn ci -m hello
+svn up
+
+# Branch to old
+svn copy trunk branches/old
+svn rm branches/old/c
+svn rm branches/old/dir
+svn ci -m "branch trunk, remove c and dir"
+svn up
+
+# Update trunk
+echo a >> trunk/a
+svn ci -m "change a"
+
+# Update old branch
+echo b >> branches/old/b
+svn ci -m "change b"
+
+# Create a cross-branch revision
+svn move trunk/b branches/old/c
+echo c >> branches/old/c
+svn ci -m "move and update c"
+
+# Update old branch again
+echo b >> branches/old/b
+svn ci -m "change b again"
+
+# Move back and forth between branch of similar names
+# This used to generate fake copy records
+svn up
+svn move branches/old branches/old2
+svn ci -m "move to old2"
+svn move branches/old2 branches/old
+svn ci -m "move back to old"
+
+# Update trunk again
+echo a > trunk/a
+svn ci -m "last change to a"
+
+# Branch again from a converted revision
+svn copy -r 1 $svnurl/trunk branches/old3
+svn ci -m "branch trunk@1 into old3"
+cd ..
+
+svnadmin dump svn-repo > ../branches.svndump
diff --git a/tests/svn/svndump-empty.sh b/tests/svn/svndump-empty.sh
new file mode 100755
index 0000000..a4e96b2
--- /dev/null
+++ b/tests/svn/svndump-empty.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# Use this script to generate empty.svndump
+#
+
+mkdir temp
+cd temp
+
+mkdir project-orig
+cd project-orig
+mkdir trunk
+mkdir branches
+mkdir tags
+cd ..
+
+svnadmin create svn-repo
+svnurl=file://`pwd`/svn-repo
+svn import project-orig $svnurl -m "init projA"
+
+svn co $svnurl project
+cd project
+mkdir trunk/dir
+echo a > trunk/dir/a
+svn add trunk/dir
+svn ci -m adddir
+
+echo b > trunk/b
+svn add trunk/b
+svn ci -m addb
+
+echo c > c
+svn add c
+svn ci -m addc
+cd ..
+
+# svnsync repo/trunk/dir only so the last two revisions are empty
+svnadmin create svn-empty
+cat > svn-empty/hooks/pre-revprop-change <<EOF
+#!/bin/sh
+exit 0
+EOF
+chmod +x svn-empty/hooks/pre-revprop-change
+svnsync init --username svnsync file://`pwd`/svn-empty file://`pwd`/svn-repo/trunk/dir
+svnsync sync file://`pwd`/svn-empty
+svn log -v file://`pwd`/svn-empty
+
+svnadmin dump svn-empty > ../empty.svndump
diff --git a/tests/svn/svndump-encoding.sh b/tests/svn/svndump-encoding.sh
new file mode 100755
index 0000000..d3f6711
--- /dev/null
+++ b/tests/svn/svndump-encoding.sh
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+#!/bin/sh
+#
+# Use this script to generate encoding.svndump
+#
+
+mkdir temp
+cd temp
+
+mkdir project-orig
+cd project-orig
+mkdir trunk
+mkdir branches
+mkdir tags
+cd ..
+
+svnadmin create svn-repo
+svnurl=file://`pwd`/svn-repo
+svn import project-orig $svnurl -m "init projA"
+
+svn co $svnurl project
+cd project
+echo e > trunk/é
+mkdir trunk/à
+echo d > trunk/à/é
+svn add trunk/é trunk/à
+svn ci -m hello
+
+# Copy files and directories
+svn mv trunk/é trunk/è
+svn mv trunk/à trunk/ù
+svn ci -m "copy files"
+
+# Remove files
+svn rm trunk/è
+svn rm trunk/ù
+svn ci -m 'remove files'
+
+# Create branches with and from weird names
+svn up
+svn cp trunk branches/branché
+echo a > branches/branché/a
+svn ci -m 'branch to branché'
+svn up
+svn cp branches/branché branches/branchée
+echo a >> branches/branché/a
+svn ci -m 'branch to branchée'
+
+# Create tag with weird name
+svn up
+svn cp trunk tags/branché
+svn ci -m 'tag trunk'
+svn cp branches/branchée tags/branchée
+svn ci -m 'tag branché'
+cd ..
+
+svnadmin dump svn-repo > ../encoding.svndump
diff --git a/tests/svn/svndump-move.sh b/tests/svn/svndump-move.sh
new file mode 100755
index 0000000..21b8c32
--- /dev/null
+++ b/tests/svn/svndump-move.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+#
+# Use this script to generate move.svndump
+#
+
+mkdir temp
+cd temp
+
+mkdir project-orig
+cd project-orig
+mkdir trunk
+echo a > trunk/a
+mkdir trunk/d1
+mkdir trunk/d2
+echo b > trunk/d1/b
+echo c > trunk/d1/c
+echo d > trunk/d2/d
+cd ..
+
+svnadmin create svn-repo
+svnurl=file://`pwd`/svn-repo
+svn import project-orig $svnurl -m "init projA"
+
+svn co $svnurl project
+cd project
+# Build a module renaming chain which used to confuse the converter.
+# Update svn repository
+echo a >> trunk/a
+echo c >> trunk/d1/c
+svn ci -m commitbeforemove
+svn mv $svnurl/trunk $svnurl/subproject -m movedtrunk
+svn up
+mkdir subproject/trunk
+svn add subproject/trunk
+svn ci -m createtrunk
+mkdir subproject/branches
+svn add subproject/branches
+svn ci -m createbranches
+svn mv $svnurl/subproject/d1 $svnurl/subproject/trunk/d1 -m moved1
+svn mv $svnurl/subproject/d2 $svnurl/subproject/trunk/d2 -m moved2
+svn up
+echo b >> subproject/trunk/d1/b
+
+svn rm subproject/trunk/d2
+svn ci -m "changeb and rm d2"
+svn mv $svnurl/subproject/trunk/d1 $svnurl/subproject/branches/d1 -m moved1again
+
+if svn help copy | grep 'SRC\[@REV\]' > /dev/null 2>&1; then
+ # SVN >= 1.5 replaced the -r REV syntax with @REV
+ # Copy a file from a past revision
+ svn copy $svnurl/subproject/trunk/d2/d@7 $svnurl/subproject/trunk -m copyfilefrompast
+ # Copy a directory from a past revision
+ svn copy $svnurl/subproject/trunk/d2@7 $svnurl/subproject/trunk -m copydirfrompast
+else
+ # Copy a file from a past revision
+ svn copy -r 7 $svnurl/subproject/trunk/d2/d $svnurl/subproject/trunk -m copyfilefrompast
+ # Copy a directory from a past revision
+ svn copy -r 7 $svnurl/subproject/trunk/d2 $svnurl/subproject/trunk -m copydirfrompast
+fi
+
+# Copy a directory while removing a subdirectory
+svn up
+mkdir -p subproject/trunk/d3/d31
+echo e > subproject/trunk/d3/d31/e
+echo f > subproject/trunk/d3/f
+svn add subproject/trunk/d3
+svn ci -m "add d3"
+svn copy subproject/trunk/d3 subproject/trunk/d4
+svn rm subproject/trunk/d3/d31
+svn ci -m "copy dir and remove subdir"
+
+# Test directory moves
+svn up
+mkdir -p subproject/trunk/d4old
+echo g > subproject/trunk/d4old/g
+svn add subproject/trunk/d4old
+svn ci -m "add d4old"
+svn mv subproject/trunk/d4old subproject/trunk/d4new
+svn ci -m "rename d4old into d4new"
+
+cd ..
+
+svnadmin dump svn-repo > ../move.svndump \ No newline at end of file
diff --git a/tests/svn/svndump-replace.sh b/tests/svn/svndump-replace.sh
new file mode 100755
index 0000000..c427431
--- /dev/null
+++ b/tests/svn/svndump-replace.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+RSVN="`pwd`/rsvn.py"
+export PATH=/bin:/usr/bin
+mkdir temp
+cd temp
+
+svnadmin create repo
+svn co file://`pwd`/repo wc
+
+cd wc
+mkdir trunk branches
+cd trunk
+echo a > a
+mkdir d
+echo b > d/b
+ln -s d dlink
+ln -s d dlink2
+ln -s d dlink3
+mkdir d2
+echo a > d2/a
+cd ..
+svn add *
+svn ci -m 'initial'
+# Clobber symlink with file with similar content
+cd trunk
+ls -Alh
+readlink dlink3 > dlink3tmp
+rm dlink3
+mv dlink3tmp dlink3
+svn propdel svn:special dlink3
+svn ci -m 'clobber symlink'
+cd ..
+svn up
+
+# Clobber files and symlink with directories
+cd ..
+cat > clobber.rsvn <<EOF
+rdelete trunk/a
+rdelete trunk/dlink
+rcopy trunk/d trunk/a
+rcopy trunk/d trunk/dlink
+EOF
+
+python $RSVN --message=clobber1 --username=evil `pwd`/repo < clobber.rsvn
+
+# Clobber non-symlink with symlink with same content (kudos openwrt)
+cat > clobber.rsvn <<EOF
+rdelete trunk/dlink3
+rcopy trunk/dlink2 trunk/dlink3
+EOF
+
+python $RSVN --message=clobber2 --username=evil `pwd`/repo < clobber.rsvn
+
+# Create d2 in branch so d2 has 'a' is in branch/d2 and trunk/d2,
+# 'b' is in trunk/d2 and 'c' is in branch/d2
+cd wc/trunk
+echo b > d2/b
+svn add d2/b
+svn ci -m adddb
+cd ..
+svn up
+svn cp trunk branches/branch
+cd branches/branch
+svn rm d2/b
+echo c > d2/c
+svn add d2/c
+cd ../..
+svn ci -m branch
+svn up
+cd ..
+
+cat > clobber.rsvn <<EOF
+rdelete trunk/d2
+rcopy branches/branch/d2 trunk/d2
+EOF
+python $RSVN --message=clobberdir --username=evil `pwd`/repo < clobber.rsvn
+
+svn log -v file://`pwd`/repo
+
+svnadmin dump repo > ../replace.svndump
diff --git a/tests/svn/svndump-startrev.sh b/tests/svn/svndump-startrev.sh
new file mode 100755
index 0000000..36c3a9f
--- /dev/null
+++ b/tests/svn/svndump-startrev.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+#
+# Use this script to generate startrev.svndump
+#
+
+mkdir temp
+cd temp
+
+mkdir project-orig
+cd project-orig
+mkdir trunk
+mkdir branches
+mkdir tags
+cd ..
+
+svnadmin create svn-repo
+svnurl=file://`pwd`/svn-repo
+svn import project-orig $svnurl -m "init projA"
+
+svn co $svnurl project
+cd project
+echo a > trunk/a
+echo b > trunk/b
+svn add trunk/a trunk/b
+svn ci -m createab
+svn rm trunk/b
+svn ci -m removeb
+svn up
+echo a >> trunk/a
+svn ci -m changeaa
+
+# Branch
+svn up
+svn copy trunk branches/branch1
+echo a >> branches/branch1/a
+svn ci -m "branch, changeaaa"
+
+echo a >> branches/branch1/a
+echo c > branches/branch1/c
+svn add branches/branch1/c
+svn ci -m "addc,changeaaaa"
+svn up
+cd ..
+
+svnadmin dump svn-repo > ../startrev.svndump \ No newline at end of file
diff --git a/tests/svn/svndump-tags.sh b/tests/svn/svndump-tags.sh
new file mode 100755
index 0000000..71cfd96
--- /dev/null
+++ b/tests/svn/svndump-tags.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# Use this script to generate tags.svndump
+#
+
+mkdir temp
+cd temp
+
+mkdir project-orig
+cd project-orig
+mkdir trunk
+mkdir branches
+mkdir tags
+mkdir unrelated
+cd ..
+
+svnadmin create svn-repo
+svnurl=file://`pwd`/svn-repo
+svn import project-orig $svnurl -m "init projA"
+
+svn co $svnurl project
+cd project
+echo a > trunk/a
+svn add trunk/a
+svn ci -m adda
+echo a >> trunk/a
+svn ci -m changea
+echo a >> trunk/a
+svn ci -m changea2
+# Add an unrelated commit to test that tags are bound to the
+# correct "from" revision and not a dummy one
+echo a >> unrelated/dummy
+svn add unrelated/dummy
+svn ci -m unrelatedchange
+# Tag current revision
+svn up
+svn copy trunk tags/trunk.v1
+svn copy trunk tags/trunk.badtag
+svn ci -m "tagging trunk.v1 trunk.badtag"
+echo a >> trunk/a
+svn ci -m changea3
+# Fix the bad tag
+# trunk.badtag should not show in converted tags
+svn up
+svn mv tags/trunk.badtag tags/trunk.goodtag
+svn ci -m "fix trunk.badtag"
+echo a >> trunk/a
+svn ci -m changea
+# Delete goodtag and recreate it, to test we pick the good one
+svn rm tags/trunk.goodtag
+svn ci -m removegoodtag
+svn up
+svn copy trunk tags/trunk.goodtag
+svn ci -m recreategoodtag
+cd ..
+
+svnadmin dump svn-repo > ../tags.svndump \ No newline at end of file
diff --git a/tests/svn/tags.svndump b/tests/svn/tags.svndump
new file mode 100644
index 0000000..154b390
--- /dev/null
+++ b/tests/svn/tags.svndump
@@ -0,0 +1,364 @@
+SVN-fs-dump-format-version: 2
+
+UUID: a9c3b03d-cffa-4248-8023-ecf4b2bdf5d5
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2009-04-29T19:26:51.708679Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 112
+Content-length: 112
+
+K 7
+svn:log
+V 10
+init projA
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-04-29T19:26:52.115023Z
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: tags
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: unrelated
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 105
+Content-length: 105
+
+K 7
+svn:log
+V 4
+adda
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-04-29T19:26:53.109819Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Revision-number: 3
+Prop-content-length: 108
+Content-length: 108
+
+K 7
+svn:log
+V 7
+changea
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-04-29T19:26:54.073017Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: 0d227f1abf8c2932d342e9b99cc957eb
+Text-content-sha1: d7c8127a20a396cff08af086a1c695b0636f0c29
+Content-length: 4
+
+a
+a
+
+
+Revision-number: 4
+Prop-content-length: 109
+Content-length: 109
+
+K 7
+svn:log
+V 8
+changea2
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-04-29T19:26:55.076032Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: change
+Text-content-length: 6
+Text-content-md5: 7d4ebf8f298d22fc349a91725b00af1c
+Text-content-sha1: 92f31bc48f52339253fce6cad9f2f0c95b302f7e
+Content-length: 6
+
+a
+a
+a
+
+
+Revision-number: 5
+Prop-content-length: 117
+Content-length: 117
+
+K 7
+svn:log
+V 15
+unrelatedchange
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-04-29T19:26:56.095784Z
+PROPS-END
+
+Node-path: unrelated/dummy
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Revision-number: 6
+Prop-content-length: 131
+Content-length: 131
+
+K 7
+svn:log
+V 29
+tagging trunk.v1 trunk.badtag
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-04-29T19:27:00.074864Z
+PROPS-END
+
+Node-path: tags/trunk.badtag
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 5
+Node-copyfrom-path: trunk
+
+
+Node-path: tags/trunk.v1
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 5
+Node-copyfrom-path: trunk
+
+
+Revision-number: 7
+Prop-content-length: 109
+Content-length: 109
+
+K 7
+svn:log
+V 8
+changea3
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-04-29T19:27:01.073910Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: change
+Text-content-length: 8
+Text-content-md5: d12178e74d8774e34361e0a08d1fd2b7
+Text-content-sha1: cce0b2a263066e26610df9082b7b3c810f71262e
+Content-length: 8
+
+a
+a
+a
+a
+
+
+Revision-number: 8
+Prop-content-length: 118
+Content-length: 118
+
+K 7
+svn:log
+V 16
+fix trunk.badtag
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-04-29T19:27:04.073542Z
+PROPS-END
+
+Node-path: tags/trunk.goodtag
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 7
+Node-copyfrom-path: tags/trunk.badtag
+
+
+Node-path: tags/trunk.badtag
+Node-action: delete
+
+
+Revision-number: 9
+Prop-content-length: 108
+Content-length: 108
+
+K 7
+svn:log
+V 7
+changea
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-04-29T19:27:05.095204Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: change
+Text-content-length: 10
+Text-content-md5: 3f65cbdca1b64c2f8f574fccae24f3a4
+Text-content-sha1: 5c077263421de2abff9dbe867921bc6810811aa2
+Content-length: 10
+
+a
+a
+a
+a
+a
+
+
+Revision-number: 10
+Prop-content-length: 115
+Content-length: 115
+
+K 7
+svn:log
+V 13
+removegoodtag
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-04-29T19:27:06.089193Z
+PROPS-END
+
+Node-path: tags/trunk.goodtag
+Node-action: delete
+
+
+Revision-number: 11
+Prop-content-length: 117
+Content-length: 117
+
+K 7
+svn:log
+V 15
+recreategoodtag
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2009-04-29T19:27:09.070471Z
+PROPS-END
+
+Node-path: tags/trunk.goodtag
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 10
+Node-copyfrom-path: trunk
+
+
diff --git a/tests/svnxml.py b/tests/svnxml.py
new file mode 100644
index 0000000..b3b2b63
--- /dev/null
+++ b/tests/svnxml.py
@@ -0,0 +1,51 @@
+# Read the output of a "svn log --xml" command on stdin, parse it and
+# print a subset of attributes common to all svn versions tested by
+# hg.
+import xml.dom.minidom, sys
+
+def xmltext(e):
+ return ''.join(c.data for c
+ in e.childNodes
+ if c.nodeType == c.TEXT_NODE)
+
+def parseentry(entry):
+ e = {}
+ e['revision'] = entry.getAttribute('revision')
+ e['author'] = xmltext(entry.getElementsByTagName('author')[0])
+ e['msg'] = xmltext(entry.getElementsByTagName('msg')[0])
+ e['paths'] = []
+ paths = entry.getElementsByTagName('paths')
+ if paths:
+ paths = paths[0]
+ for p in paths.getElementsByTagName('path'):
+ action = p.getAttribute('action')
+ path = xmltext(p)
+ frompath = p.getAttribute('copyfrom-path')
+ fromrev = p.getAttribute('copyfrom-rev')
+ e['paths'].append((path, action, frompath, fromrev))
+ return e
+
+def parselog(data):
+ entries = []
+ doc = xml.dom.minidom.parseString(data)
+ for e in doc.getElementsByTagName('logentry'):
+ entries.append(parseentry(e))
+ return entries
+
+def printentries(entries):
+ fp = sys.stdout
+ for e in entries:
+ for k in ('revision', 'author', 'msg'):
+ fp.write(('%s: %s\n' % (k, e[k])).encode('utf-8'))
+ for path, action, fpath, frev in sorted(e['paths']):
+ frominfo = ''
+ if frev:
+ frominfo = ' (from %s@%s)' % (fpath, frev)
+ p = ' %s %s%s\n' % (action, path, frominfo)
+ fp.write(p.encode('utf-8'))
+
+if __name__ == '__main__':
+ data = sys.stdin.read()
+ entries = parselog(data)
+ printentries(entries)
+
diff --git a/tests/test-1102.t b/tests/test-1102.t
new file mode 100644
index 0000000..61e01e5
--- /dev/null
+++ b/tests/test-1102.t
@@ -0,0 +1,17 @@
+ $ rm -rf a
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg ci -Am0
+ adding a
+ $ hg tag t1 # 1
+ $ hg tag --remove t1 # 2
+
+ $ hg co 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg tag -f -r0 t1
+ $ hg tags
+ tip 3:a49829c4fc11
+ t1 0:f7b1eb17ad24
+
+ $ cd ..
diff --git a/tests/test-1993.t b/tests/test-1993.t
new file mode 100644
index 0000000..317cba2
--- /dev/null
+++ b/tests/test-1993.t
@@ -0,0 +1,48 @@
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg ci -Am0
+ adding a
+ $ echo b > b
+ $ hg ci -Am1
+ adding b
+ $ hg tag -r0 default
+ warning: tag default conflicts with existing branch name
+ $ hg log
+ changeset: 2:30a83d1e4a1e
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag default for changeset f7b1eb17ad24
+
+ changeset: 1:925d80f479bb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ changeset: 0:f7b1eb17ad24
+ tag: default
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ $ hg update 'tag(default)'
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg parents
+ changeset: 0:f7b1eb17ad24
+ tag: default
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ $ hg update 'branch(default)'
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg parents
+ changeset: 2:30a83d1e4a1e
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag default for changeset f7b1eb17ad24
+
+
+ $ cd ..
diff --git a/tests/test-586.t b/tests/test-586.t
new file mode 100644
index 0000000..71b3cbf
--- /dev/null
+++ b/tests/test-586.t
@@ -0,0 +1,92 @@
+Issue586: removing remote files after merge appears to corrupt the
+dirstate
+
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+
+ $ hg init ../b
+ $ cd ../b
+ $ echo b > b
+ $ hg ci -Amb
+ adding b
+
+ $ hg pull -f ../a
+ pulling from ../a
+ searching for changes
+ warning: repository is unrelated
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg rm -f a
+ $ hg ci -Amc
+
+ $ hg st -A
+ C b
+ $ cd ..
+
+Issue1433: Traceback after two unrelated pull, two move, a merge and
+a commit (related to issue586)
+
+create test repos
+
+ $ hg init repoa
+ $ touch repoa/a
+ $ hg -R repoa ci -Am adda
+ adding a
+
+ $ hg init repob
+ $ touch repob/b
+ $ hg -R repob ci -Am addb
+ adding b
+
+ $ hg init repoc
+ $ cd repoc
+ $ hg pull ../repoa
+ pulling from ../repoa
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mkdir tst
+ $ hg mv * tst
+ $ hg ci -m "import a in tst"
+ $ hg pull -f ../repob
+ pulling from ../repob
+ searching for changes
+ warning: repository is unrelated
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+merge both repos
+
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ mkdir src
+
+move b content
+
+ $ hg mv b src
+ $ hg ci -m "import b in src"
+ $ hg manifest
+ src/b
+ tst/a
+
+ $ cd ..
diff --git a/tests/test-abort-checkin.t b/tests/test-abort-checkin.t
new file mode 100644
index 0000000..c7a3c98
--- /dev/null
+++ b/tests/test-abort-checkin.t
@@ -0,0 +1,35 @@
+ $ cat > abortcommit.py <<EOF
+ > from mercurial import util
+ > def hook(**args):
+ > raise util.Abort("no commits allowed")
+ > def reposetup(ui, repo):
+ > repo.ui.setconfig("hooks", "pretxncommit.nocommits", hook)
+ > EOF
+ $ abspath=`pwd`/abortcommit.py
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "abortcommit = $abspath" >> $HGRCPATH
+
+ $ hg init foo
+ $ cd foo
+ $ echo foo > foo
+ $ hg add foo
+
+mq may keep a reference to the repository so __del__ will not be
+called and .hg/journal.dirstate will not be deleted:
+
+ $ hg ci -m foo
+ error: pretxncommit.nocommits hook failed: no commits allowed
+ transaction abort!
+ rollback completed
+ abort: no commits allowed
+ [255]
+ $ hg ci -m foo
+ error: pretxncommit.nocommits hook failed: no commits allowed
+ transaction abort!
+ rollback completed
+ abort: no commits allowed
+ [255]
+
+ $ cd ..
diff --git a/tests/test-acl.t b/tests/test-acl.t
new file mode 100644
index 0000000..6105d5d
--- /dev/null
+++ b/tests/test-acl.t
@@ -0,0 +1,2133 @@
+ > do_push()
+ > {
+ > user=$1
+ > shift
+ > echo "Pushing as user $user"
+ > echo 'hgrc = """'
+ > sed -e 1,2d b/.hg/hgrc | grep -v fakegroups.py
+ > echo '"""'
+ > if test -f acl.config; then
+ > echo 'acl.config = """'
+ > cat acl.config
+ > echo '"""'
+ > fi
+ > # On AIX /etc/profile sets LOGNAME read-only. So
+ > # LOGNAME=$user hg --cws a --debug push ../b
+ > # fails with "This variable is read only."
+ > # Use env to work around this.
+ > env LOGNAME=$user hg --cwd a --debug push ../b
+ > hg --cwd b rollback
+ > hg --cwd b --quiet tip
+ > echo
+ > }
+
+ > init_config()
+ > {
+ > cat > fakegroups.py <<EOF
+ > from hgext import acl
+ > def fakegetusers(ui, group):
+ > try:
+ > return acl._getusersorig(ui, group)
+ > except:
+ > return ["fred", "betty"]
+ > acl._getusersorig = acl._getusers
+ > acl._getusers = fakegetusers
+ > EOF
+ > rm -f acl.config
+ > cat > $config <<EOF
+ > [hooks]
+ > pretxnchangegroup.acl = python:hgext.acl.hook
+ > [acl]
+ > sources = push
+ > [extensions]
+ > f=`pwd`/fakegroups.py
+ > EOF
+ > }
+
+ $ hg init a
+ $ cd a
+ $ mkdir foo foo/Bar quux
+ $ echo 'in foo' > foo/file.txt
+ $ echo 'in foo/Bar' > foo/Bar/file.txt
+ $ echo 'in quux' > quux/file.py
+ $ hg add -q
+ $ hg ci -m 'add files' -d '1000000 0'
+ $ echo >> foo/file.txt
+ $ hg ci -m 'change foo/file' -d '1000001 0'
+ $ echo >> foo/Bar/file.txt
+ $ hg ci -m 'change foo/Bar/file' -d '1000002 0'
+ $ echo >> quux/file.py
+ $ hg ci -m 'change quux/file' -d '1000003 0'
+ $ hg tip --quiet
+ 3:911600dab2ae
+
+ $ cd ..
+ $ hg clone -r 0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 3 changes to 3 files
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ config=b/.hg/hgrc
+
+Extension disabled for lack of a hook
+
+ $ do_push fred
+ Pushing as user fred
+ hgrc = """
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ listing keys for "phases"
+ try to push obsolete markers to remote
+ updating the branch cache
+ checking for updated bookmarks
+ listing keys for "bookmarks"
+ repository tip rolled back to revision 0 (undo push)
+ 0:6675d58eff77
+
+
+ $ echo '[hooks]' >> $config
+ $ echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
+
+Extension disabled for lack of acl.sources
+
+ $ do_push fred
+ Pushing as user fred
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ invalidating branch cache (tip differs)
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: changes have source "push" - skipping
+ listing keys for "phases"
+ try to push obsolete markers to remote
+ updating the branch cache
+ checking for updated bookmarks
+ listing keys for "bookmarks"
+ repository tip rolled back to revision 0 (undo push)
+ 0:6675d58eff77
+
+
+No [acl.allow]/[acl.deny]
+
+ $ echo '[acl]' >> $config
+ $ echo 'sources = push' >> $config
+ $ do_push fred
+ Pushing as user fred
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ invalidating branch cache (tip differs)
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "fred"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow not enabled
+ acl: acl.deny not enabled
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ acl: path access granted: "911600dab2ae"
+ listing keys for "phases"
+ try to push obsolete markers to remote
+ updating the branch cache
+ checking for updated bookmarks
+ listing keys for "bookmarks"
+ repository tip rolled back to revision 0 (undo push)
+ 0:6675d58eff77
+
+
+Empty [acl.allow]
+
+ $ echo '[acl.allow]' >> $config
+ $ do_push fred
+ Pushing as user fred
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ [acl.allow]
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ invalidating branch cache (tip differs)
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "fred"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 0 entries for user fred
+ acl: acl.deny not enabled
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
+ transaction abort!
+ rollback completed
+ abort: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
+ no rollback information available
+ 0:6675d58eff77
+
+
+fred is allowed inside foo/
+
+ $ echo 'foo/** = fred' >> $config
+ $ do_push fred
+ Pushing as user fred
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ [acl.allow]
+ foo/** = fred
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "fred"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 1 entries for user fred
+ acl: acl.deny not enabled
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ transaction abort!
+ rollback completed
+ abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ no rollback information available
+ 0:6675d58eff77
+
+
+Empty [acl.deny]
+
+ $ echo '[acl.deny]' >> $config
+ $ do_push barney
+ Pushing as user barney
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ [acl.allow]
+ foo/** = fred
+ [acl.deny]
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "barney"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 0 entries for user barney
+ acl: acl.deny enabled, 0 entries for user barney
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
+ transaction abort!
+ rollback completed
+ abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
+ no rollback information available
+ 0:6675d58eff77
+
+
+fred is allowed inside foo/, but not foo/bar/ (case matters)
+
+ $ echo 'foo/bar/** = fred' >> $config
+ $ do_push fred
+ Pushing as user fred
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ [acl.allow]
+ foo/** = fred
+ [acl.deny]
+ foo/bar/** = fred
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "fred"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 1 entries for user fred
+ acl: acl.deny enabled, 1 entries for user fred
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ transaction abort!
+ rollback completed
+ abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ no rollback information available
+ 0:6675d58eff77
+
+
+fred is allowed inside foo/, but not foo/Bar/
+
+ $ echo 'foo/Bar/** = fred' >> $config
+ $ do_push fred
+ Pushing as user fred
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ [acl.allow]
+ foo/** = fred
+ [acl.deny]
+ foo/bar/** = fred
+ foo/Bar/** = fred
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "fred"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 1 entries for user fred
+ acl: acl.deny enabled, 2 entries for user fred
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
+ transaction abort!
+ rollback completed
+ abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
+ no rollback information available
+ 0:6675d58eff77
+
+
+ $ echo 'barney is not mentioned => not allowed anywhere'
+ barney is not mentioned => not allowed anywhere
+ $ do_push barney
+ Pushing as user barney
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ [acl.allow]
+ foo/** = fred
+ [acl.deny]
+ foo/bar/** = fred
+ foo/Bar/** = fred
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "barney"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 0 entries for user barney
+ acl: acl.deny enabled, 0 entries for user barney
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
+ transaction abort!
+ rollback completed
+ abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
+ no rollback information available
+ 0:6675d58eff77
+
+
+barney is allowed everywhere
+
+ $ echo '[acl.allow]' >> $config
+ $ echo '** = barney' >> $config
+ $ do_push barney
+ Pushing as user barney
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ [acl.allow]
+ foo/** = fred
+ [acl.deny]
+ foo/bar/** = fred
+ foo/Bar/** = fred
+ [acl.allow]
+ ** = barney
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "barney"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 1 entries for user barney
+ acl: acl.deny enabled, 0 entries for user barney
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ acl: path access granted: "911600dab2ae"
+ listing keys for "phases"
+ try to push obsolete markers to remote
+ updating the branch cache
+ checking for updated bookmarks
+ listing keys for "bookmarks"
+ repository tip rolled back to revision 0 (undo push)
+ 0:6675d58eff77
+
+
+wilma can change files with a .txt extension
+
+ $ echo '**/*.txt = wilma' >> $config
+ $ do_push wilma
+ Pushing as user wilma
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ [acl.allow]
+ foo/** = fred
+ [acl.deny]
+ foo/bar/** = fred
+ foo/Bar/** = fred
+ [acl.allow]
+ ** = barney
+ **/*.txt = wilma
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ invalidating branch cache (tip differs)
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "wilma"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 1 entries for user wilma
+ acl: acl.deny enabled, 0 entries for user wilma
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ error: pretxnchangegroup.acl hook failed: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ transaction abort!
+ rollback completed
+ abort: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ no rollback information available
+ 0:6675d58eff77
+
+
+file specified by acl.config does not exist
+
+ $ echo '[acl]' >> $config
+ $ echo 'config = ../acl.config' >> $config
+ $ do_push barney
+ Pushing as user barney
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ [acl.allow]
+ foo/** = fred
+ [acl.deny]
+ foo/bar/** = fred
+ foo/Bar/** = fred
+ [acl.allow]
+ ** = barney
+ **/*.txt = wilma
+ [acl]
+ config = ../acl.config
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "barney"
+ error: pretxnchangegroup.acl hook raised an exception: [Errno 2] *: '../acl.config' (glob)
+ transaction abort!
+ rollback completed
+ abort: *: ../acl.config (glob)
+ no rollback information available
+ 0:6675d58eff77
+
+
+betty is allowed inside foo/ by a acl.config file
+
+ $ echo '[acl.allow]' >> acl.config
+ $ echo 'foo/** = betty' >> acl.config
+ $ do_push betty
+ Pushing as user betty
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ [acl.allow]
+ foo/** = fred
+ [acl.deny]
+ foo/bar/** = fred
+ foo/Bar/** = fred
+ [acl.allow]
+ ** = barney
+ **/*.txt = wilma
+ [acl]
+ config = ../acl.config
+ """
+ acl.config = """
+ [acl.allow]
+ foo/** = betty
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "betty"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 1 entries for user betty
+ acl: acl.deny enabled, 0 entries for user betty
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ error: pretxnchangegroup.acl hook failed: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ transaction abort!
+ rollback completed
+ abort: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ no rollback information available
+ 0:6675d58eff77
+
+
+acl.config can set only [acl.allow]/[acl.deny]
+
+ $ echo '[hooks]' >> acl.config
+ $ echo 'changegroup.acl = false' >> acl.config
+ $ do_push barney
+ Pushing as user barney
+ hgrc = """
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+ [acl]
+ sources = push
+ [acl.allow]
+ foo/** = fred
+ [acl.deny]
+ foo/bar/** = fred
+ foo/Bar/** = fred
+ [acl.allow]
+ ** = barney
+ **/*.txt = wilma
+ [acl]
+ config = ../acl.config
+ """
+ acl.config = """
+ [acl.allow]
+ foo/** = betty
+ [hooks]
+ changegroup.acl = false
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "barney"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 1 entries for user barney
+ acl: acl.deny enabled, 0 entries for user barney
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ acl: path access granted: "911600dab2ae"
+ listing keys for "phases"
+ try to push obsolete markers to remote
+ updating the branch cache
+ checking for updated bookmarks
+ listing keys for "bookmarks"
+ repository tip rolled back to revision 0 (undo push)
+ 0:6675d58eff77
+
+
+asterisk
+
+ $ init_config
+
+asterisk test
+
+ $ echo '[acl.allow]' >> $config
+ $ echo "** = fred" >> $config
+
+fred is always allowed
+
+ $ do_push fred
+ Pushing as user fred
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.allow]
+ ** = fred
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ invalidating branch cache (tip differs)
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "fred"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 1 entries for user fred
+ acl: acl.deny not enabled
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ acl: path access granted: "911600dab2ae"
+ listing keys for "phases"
+ try to push obsolete markers to remote
+ updating the branch cache
+ checking for updated bookmarks
+ listing keys for "bookmarks"
+ repository tip rolled back to revision 0 (undo push)
+ 0:6675d58eff77
+
+
+ $ echo '[acl.deny]' >> $config
+ $ echo "foo/Bar/** = *" >> $config
+
+no one is allowed inside foo/Bar/
+
+ $ do_push fred
+ Pushing as user fred
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.allow]
+ ** = fred
+ [acl.deny]
+ foo/Bar/** = *
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ invalidating branch cache (tip differs)
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "fred"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow enabled, 1 entries for user fred
+ acl: acl.deny enabled, 1 entries for user fred
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
+ transaction abort!
+ rollback completed
+ abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
+ no rollback information available
+ 0:6675d58eff77
+
+
+Groups
+
+ $ init_config
+
+OS-level groups
+
+ $ echo '[acl.allow]' >> $config
+ $ echo "** = @group1" >> $config
+
+@group1 is always allowed
+
+ $ do_push fred
+ Pushing as user fred
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.allow]
+ ** = @group1
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "fred"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: "group1" not defined in [acl.groups]
+ acl: acl.allow enabled, 1 entries for user fred
+ acl: acl.deny not enabled
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ acl: path access granted: "911600dab2ae"
+ listing keys for "phases"
+ try to push obsolete markers to remote
+ updating the branch cache
+ checking for updated bookmarks
+ listing keys for "bookmarks"
+ repository tip rolled back to revision 0 (undo push)
+ 0:6675d58eff77
+
+
+ $ echo '[acl.deny]' >> $config
+ $ echo "foo/Bar/** = @group1" >> $config
+
+@group is allowed inside anything but foo/Bar/
+
+ $ do_push fred
+ Pushing as user fred
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.allow]
+ ** = @group1
+ [acl.deny]
+ foo/Bar/** = @group1
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ invalidating branch cache (tip differs)
+ listing keys for "bookmarks"
+ 3 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ adding changesets
+ bundling: 1/3 changesets (33.33%)
+ bundling: 2/3 changesets (66.67%)
+ bundling: 3/3 changesets (100.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 2/3 files (66.67%)
+ bundling: quux/file.py 3/3 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ adding manifests
+ manifests: 1/3 chunks (33.33%)
+ manifests: 2/3 chunks (66.67%)
+ manifests: 3/3 chunks (100.00%)
+ adding file changes
+ adding foo/Bar/file.txt revisions
+ files: 1/3 chunks (33.33%)
+ adding foo/file.txt revisions
+ files: 2/3 chunks (66.67%)
+ adding quux/file.py revisions
+ files: 3/3 chunks (100.00%)
+ added 3 changesets with 3 changes to 3 files
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "fred"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: "group1" not defined in [acl.groups]
+ acl: acl.allow enabled, 1 entries for user fred
+ acl: "group1" not defined in [acl.groups]
+ acl: acl.deny enabled, 1 entries for user fred
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
+ transaction abort!
+ rollback completed
+ abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
+ no rollback information available
+ 0:6675d58eff77
+
+
+Invalid group
+
+Disable the fakegroups trick to get real failures
+
+ $ grep -v fakegroups $config > config.tmp
+ $ mv config.tmp $config
+ $ echo '[acl.allow]' >> $config
+ $ echo "** = @unlikelytoexist" >> $config
+ $ do_push fred 2>&1 | grep unlikelytoexist
+ ** = @unlikelytoexist
+ acl: "unlikelytoexist" not defined in [acl.groups]
+ error: pretxnchangegroup.acl hook failed: group 'unlikelytoexist' is undefined
+ abort: group 'unlikelytoexist' is undefined
+
+
+Branch acl tests setup
+
+ $ init_config
+ $ cd b
+ $ hg up
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch foobar
+ marked working directory as branch foobar
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg commit -m 'create foobar'
+ $ echo 'foo contents' > abc.txt
+ $ hg add abc.txt
+ $ hg commit -m 'foobar contents'
+ $ cd ..
+ $ hg --cwd a pull ../b
+ pulling from ../b
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads)
+
+Create additional changeset on foobar branch
+
+ $ cd a
+ $ hg up -C foobar
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo 'foo contents2' > abc.txt
+ $ hg commit -m 'foobar contents2'
+ $ cd ..
+
+
+No branch acls specified
+
+ $ do_push astro
+ Pushing as user astro
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 4 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
+ adding changesets
+ bundling: 1/4 changesets (25.00%)
+ bundling: 2/4 changesets (50.00%)
+ bundling: 3/4 changesets (75.00%)
+ bundling: 4/4 changesets (100.00%)
+ bundling: 1/4 manifests (25.00%)
+ bundling: 2/4 manifests (50.00%)
+ bundling: 3/4 manifests (75.00%)
+ bundling: 4/4 manifests (100.00%)
+ bundling: abc.txt 1/4 files (25.00%)
+ bundling: foo/Bar/file.txt 2/4 files (50.00%)
+ bundling: foo/file.txt 3/4 files (75.00%)
+ bundling: quux/file.py 4/4 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ changesets: 4 chunks
+ add changeset e8fc755d4d82
+ adding manifests
+ manifests: 1/4 chunks (25.00%)
+ manifests: 2/4 chunks (50.00%)
+ manifests: 3/4 chunks (75.00%)
+ manifests: 4/4 chunks (100.00%)
+ adding file changes
+ adding abc.txt revisions
+ files: 1/4 chunks (25.00%)
+ adding foo/Bar/file.txt revisions
+ files: 2/4 chunks (50.00%)
+ adding foo/file.txt revisions
+ files: 3/4 chunks (75.00%)
+ adding quux/file.py revisions
+ files: 4/4 chunks (100.00%)
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "astro"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches not enabled
+ acl: acl.allow not enabled
+ acl: acl.deny not enabled
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ acl: path access granted: "911600dab2ae"
+ acl: branch access granted: "e8fc755d4d82" on branch "foobar"
+ acl: path access granted: "e8fc755d4d82"
+ listing keys for "phases"
+ try to push obsolete markers to remote
+ updating the branch cache
+ checking for updated bookmarks
+ listing keys for "bookmarks"
+ repository tip rolled back to revision 2 (undo push)
+ 2:fb35475503ef
+
+
+Branch acl deny test
+
+ $ echo "[acl.deny.branches]" >> $config
+ $ echo "foobar = *" >> $config
+ $ do_push astro
+ Pushing as user astro
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.deny.branches]
+ foobar = *
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ invalidating branch cache (tip differs)
+ listing keys for "bookmarks"
+ 4 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
+ adding changesets
+ bundling: 1/4 changesets (25.00%)
+ bundling: 2/4 changesets (50.00%)
+ bundling: 3/4 changesets (75.00%)
+ bundling: 4/4 changesets (100.00%)
+ bundling: 1/4 manifests (25.00%)
+ bundling: 2/4 manifests (50.00%)
+ bundling: 3/4 manifests (75.00%)
+ bundling: 4/4 manifests (100.00%)
+ bundling: abc.txt 1/4 files (25.00%)
+ bundling: foo/Bar/file.txt 2/4 files (50.00%)
+ bundling: foo/file.txt 3/4 files (75.00%)
+ bundling: quux/file.py 4/4 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ changesets: 4 chunks
+ add changeset e8fc755d4d82
+ adding manifests
+ manifests: 1/4 chunks (25.00%)
+ manifests: 2/4 chunks (50.00%)
+ manifests: 3/4 chunks (75.00%)
+ manifests: 4/4 chunks (100.00%)
+ adding file changes
+ adding abc.txt revisions
+ files: 1/4 chunks (25.00%)
+ adding foo/Bar/file.txt revisions
+ files: 2/4 chunks (50.00%)
+ adding foo/file.txt revisions
+ files: 3/4 chunks (75.00%)
+ adding quux/file.py revisions
+ files: 4/4 chunks (100.00%)
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "astro"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches enabled, 1 entries for user astro
+ acl: acl.allow not enabled
+ acl: acl.deny not enabled
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ acl: path access granted: "911600dab2ae"
+ error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
+ transaction abort!
+ rollback completed
+ abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
+ no rollback information available
+ 2:fb35475503ef
+
+
+Branch acl empty allow test
+
+ $ init_config
+ $ echo "[acl.allow.branches]" >> $config
+ $ do_push astro
+ Pushing as user astro
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.allow.branches]
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 4 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
+ adding changesets
+ bundling: 1/4 changesets (25.00%)
+ bundling: 2/4 changesets (50.00%)
+ bundling: 3/4 changesets (75.00%)
+ bundling: 4/4 changesets (100.00%)
+ bundling: 1/4 manifests (25.00%)
+ bundling: 2/4 manifests (50.00%)
+ bundling: 3/4 manifests (75.00%)
+ bundling: 4/4 manifests (100.00%)
+ bundling: abc.txt 1/4 files (25.00%)
+ bundling: foo/Bar/file.txt 2/4 files (50.00%)
+ bundling: foo/file.txt 3/4 files (75.00%)
+ bundling: quux/file.py 4/4 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ changesets: 4 chunks
+ add changeset e8fc755d4d82
+ adding manifests
+ manifests: 1/4 chunks (25.00%)
+ manifests: 2/4 chunks (50.00%)
+ manifests: 3/4 chunks (75.00%)
+ manifests: 4/4 chunks (100.00%)
+ adding file changes
+ adding abc.txt revisions
+ files: 1/4 chunks (25.00%)
+ adding foo/Bar/file.txt revisions
+ files: 2/4 chunks (50.00%)
+ adding foo/file.txt revisions
+ files: 3/4 chunks (75.00%)
+ adding quux/file.py revisions
+ files: 4/4 chunks (100.00%)
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "astro"
+ acl: acl.allow.branches enabled, 0 entries for user astro
+ acl: acl.deny.branches not enabled
+ acl: acl.allow not enabled
+ acl: acl.deny not enabled
+ error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
+ transaction abort!
+ rollback completed
+ abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
+ no rollback information available
+ 2:fb35475503ef
+
+
+Branch acl allow other
+
+ $ init_config
+ $ echo "[acl.allow.branches]" >> $config
+ $ echo "* = george" >> $config
+ $ do_push astro
+ Pushing as user astro
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.allow.branches]
+ * = george
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 4 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
+ adding changesets
+ bundling: 1/4 changesets (25.00%)
+ bundling: 2/4 changesets (50.00%)
+ bundling: 3/4 changesets (75.00%)
+ bundling: 4/4 changesets (100.00%)
+ bundling: 1/4 manifests (25.00%)
+ bundling: 2/4 manifests (50.00%)
+ bundling: 3/4 manifests (75.00%)
+ bundling: 4/4 manifests (100.00%)
+ bundling: abc.txt 1/4 files (25.00%)
+ bundling: foo/Bar/file.txt 2/4 files (50.00%)
+ bundling: foo/file.txt 3/4 files (75.00%)
+ bundling: quux/file.py 4/4 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ changesets: 4 chunks
+ add changeset e8fc755d4d82
+ adding manifests
+ manifests: 1/4 chunks (25.00%)
+ manifests: 2/4 chunks (50.00%)
+ manifests: 3/4 chunks (75.00%)
+ manifests: 4/4 chunks (100.00%)
+ adding file changes
+ adding abc.txt revisions
+ files: 1/4 chunks (25.00%)
+ adding foo/Bar/file.txt revisions
+ files: 2/4 chunks (50.00%)
+ adding foo/file.txt revisions
+ files: 3/4 chunks (75.00%)
+ adding quux/file.py revisions
+ files: 4/4 chunks (100.00%)
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "astro"
+ acl: acl.allow.branches enabled, 0 entries for user astro
+ acl: acl.deny.branches not enabled
+ acl: acl.allow not enabled
+ acl: acl.deny not enabled
+ error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
+ transaction abort!
+ rollback completed
+ abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
+ no rollback information available
+ 2:fb35475503ef
+
+ $ do_push george
+ Pushing as user george
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.allow.branches]
+ * = george
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 4 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
+ adding changesets
+ bundling: 1/4 changesets (25.00%)
+ bundling: 2/4 changesets (50.00%)
+ bundling: 3/4 changesets (75.00%)
+ bundling: 4/4 changesets (100.00%)
+ bundling: 1/4 manifests (25.00%)
+ bundling: 2/4 manifests (50.00%)
+ bundling: 3/4 manifests (75.00%)
+ bundling: 4/4 manifests (100.00%)
+ bundling: abc.txt 1/4 files (25.00%)
+ bundling: foo/Bar/file.txt 2/4 files (50.00%)
+ bundling: foo/file.txt 3/4 files (75.00%)
+ bundling: quux/file.py 4/4 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ changesets: 4 chunks
+ add changeset e8fc755d4d82
+ adding manifests
+ manifests: 1/4 chunks (25.00%)
+ manifests: 2/4 chunks (50.00%)
+ manifests: 3/4 chunks (75.00%)
+ manifests: 4/4 chunks (100.00%)
+ adding file changes
+ adding abc.txt revisions
+ files: 1/4 chunks (25.00%)
+ adding foo/Bar/file.txt revisions
+ files: 2/4 chunks (50.00%)
+ adding foo/file.txt revisions
+ files: 3/4 chunks (75.00%)
+ adding quux/file.py revisions
+ files: 4/4 chunks (100.00%)
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "george"
+ acl: acl.allow.branches enabled, 1 entries for user george
+ acl: acl.deny.branches not enabled
+ acl: acl.allow not enabled
+ acl: acl.deny not enabled
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ acl: path access granted: "911600dab2ae"
+ acl: branch access granted: "e8fc755d4d82" on branch "foobar"
+ acl: path access granted: "e8fc755d4d82"
+ listing keys for "phases"
+ try to push obsolete markers to remote
+ updating the branch cache
+ checking for updated bookmarks
+ listing keys for "bookmarks"
+ repository tip rolled back to revision 2 (undo push)
+ 2:fb35475503ef
+
+
+Branch acl conflicting allow
+asterisk ends up applying to all branches and allowing george to
+push foobar into the remote
+
+ $ init_config
+ $ echo "[acl.allow.branches]" >> $config
+ $ echo "foobar = astro" >> $config
+ $ echo "* = george" >> $config
+ $ do_push george
+ Pushing as user george
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.allow.branches]
+ foobar = astro
+ * = george
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ invalidating branch cache (tip differs)
+ listing keys for "bookmarks"
+ 4 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
+ adding changesets
+ bundling: 1/4 changesets (25.00%)
+ bundling: 2/4 changesets (50.00%)
+ bundling: 3/4 changesets (75.00%)
+ bundling: 4/4 changesets (100.00%)
+ bundling: 1/4 manifests (25.00%)
+ bundling: 2/4 manifests (50.00%)
+ bundling: 3/4 manifests (75.00%)
+ bundling: 4/4 manifests (100.00%)
+ bundling: abc.txt 1/4 files (25.00%)
+ bundling: foo/Bar/file.txt 2/4 files (50.00%)
+ bundling: foo/file.txt 3/4 files (75.00%)
+ bundling: quux/file.py 4/4 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ changesets: 4 chunks
+ add changeset e8fc755d4d82
+ adding manifests
+ manifests: 1/4 chunks (25.00%)
+ manifests: 2/4 chunks (50.00%)
+ manifests: 3/4 chunks (75.00%)
+ manifests: 4/4 chunks (100.00%)
+ adding file changes
+ adding abc.txt revisions
+ files: 1/4 chunks (25.00%)
+ adding foo/Bar/file.txt revisions
+ files: 2/4 chunks (50.00%)
+ adding foo/file.txt revisions
+ files: 3/4 chunks (75.00%)
+ adding quux/file.py revisions
+ files: 4/4 chunks (100.00%)
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "george"
+ acl: acl.allow.branches enabled, 1 entries for user george
+ acl: acl.deny.branches not enabled
+ acl: acl.allow not enabled
+ acl: acl.deny not enabled
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ acl: path access granted: "911600dab2ae"
+ acl: branch access granted: "e8fc755d4d82" on branch "foobar"
+ acl: path access granted: "e8fc755d4d82"
+ listing keys for "phases"
+ try to push obsolete markers to remote
+ updating the branch cache
+ checking for updated bookmarks
+ listing keys for "bookmarks"
+ repository tip rolled back to revision 2 (undo push)
+ 2:fb35475503ef
+
+Branch acl conflicting deny
+
+ $ init_config
+ $ echo "[acl.deny.branches]" >> $config
+ $ echo "foobar = astro" >> $config
+ $ echo "default = astro" >> $config
+ $ echo "* = george" >> $config
+ $ do_push george
+ Pushing as user george
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.deny.branches]
+ foobar = astro
+ default = astro
+ * = george
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ invalidating branch cache (tip differs)
+ listing keys for "bookmarks"
+ 4 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
+ adding changesets
+ bundling: 1/4 changesets (25.00%)
+ bundling: 2/4 changesets (50.00%)
+ bundling: 3/4 changesets (75.00%)
+ bundling: 4/4 changesets (100.00%)
+ bundling: 1/4 manifests (25.00%)
+ bundling: 2/4 manifests (50.00%)
+ bundling: 3/4 manifests (75.00%)
+ bundling: 4/4 manifests (100.00%)
+ bundling: abc.txt 1/4 files (25.00%)
+ bundling: foo/Bar/file.txt 2/4 files (50.00%)
+ bundling: foo/file.txt 3/4 files (75.00%)
+ bundling: quux/file.py 4/4 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ changesets: 4 chunks
+ add changeset e8fc755d4d82
+ adding manifests
+ manifests: 1/4 chunks (25.00%)
+ manifests: 2/4 chunks (50.00%)
+ manifests: 3/4 chunks (75.00%)
+ manifests: 4/4 chunks (100.00%)
+ adding file changes
+ adding abc.txt revisions
+ files: 1/4 chunks (25.00%)
+ adding foo/Bar/file.txt revisions
+ files: 2/4 chunks (50.00%)
+ adding foo/file.txt revisions
+ files: 3/4 chunks (75.00%)
+ adding quux/file.py revisions
+ files: 4/4 chunks (100.00%)
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "george"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches enabled, 1 entries for user george
+ acl: acl.allow not enabled
+ acl: acl.deny not enabled
+ error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
+ transaction abort!
+ rollback completed
+ abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
+ no rollback information available
+ 2:fb35475503ef
+
+User 'astro' must not be denied
+
+ $ init_config
+ $ echo "[acl.deny.branches]" >> $config
+ $ echo "default = !astro" >> $config
+ $ do_push astro
+ Pushing as user astro
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.deny.branches]
+ default = !astro
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ listing keys for "bookmarks"
+ 4 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
+ adding changesets
+ bundling: 1/4 changesets (25.00%)
+ bundling: 2/4 changesets (50.00%)
+ bundling: 3/4 changesets (75.00%)
+ bundling: 4/4 changesets (100.00%)
+ bundling: 1/4 manifests (25.00%)
+ bundling: 2/4 manifests (50.00%)
+ bundling: 3/4 manifests (75.00%)
+ bundling: 4/4 manifests (100.00%)
+ bundling: abc.txt 1/4 files (25.00%)
+ bundling: foo/Bar/file.txt 2/4 files (50.00%)
+ bundling: foo/file.txt 3/4 files (75.00%)
+ bundling: quux/file.py 4/4 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ changesets: 4 chunks
+ add changeset e8fc755d4d82
+ adding manifests
+ manifests: 1/4 chunks (25.00%)
+ manifests: 2/4 chunks (50.00%)
+ manifests: 3/4 chunks (75.00%)
+ manifests: 4/4 chunks (100.00%)
+ adding file changes
+ adding abc.txt revisions
+ files: 1/4 chunks (25.00%)
+ adding foo/Bar/file.txt revisions
+ files: 2/4 chunks (50.00%)
+ adding foo/file.txt revisions
+ files: 3/4 chunks (75.00%)
+ adding quux/file.py revisions
+ files: 4/4 chunks (100.00%)
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "astro"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches enabled, 0 entries for user astro
+ acl: acl.allow not enabled
+ acl: acl.deny not enabled
+ acl: branch access granted: "ef1ea85a6374" on branch "default"
+ acl: path access granted: "ef1ea85a6374"
+ acl: branch access granted: "f9cafe1212c8" on branch "default"
+ acl: path access granted: "f9cafe1212c8"
+ acl: branch access granted: "911600dab2ae" on branch "default"
+ acl: path access granted: "911600dab2ae"
+ acl: branch access granted: "e8fc755d4d82" on branch "foobar"
+ acl: path access granted: "e8fc755d4d82"
+ listing keys for "phases"
+ try to push obsolete markers to remote
+ updating the branch cache
+ checking for updated bookmarks
+ listing keys for "bookmarks"
+ repository tip rolled back to revision 2 (undo push)
+ 2:fb35475503ef
+
+
+Non-astro users must be denied
+
+ $ do_push george
+ Pushing as user george
+ hgrc = """
+ [acl]
+ sources = push
+ [extensions]
+ [acl.deny.branches]
+ default = !astro
+ """
+ pushing to ../b
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ invalidating branch cache (tip differs)
+ listing keys for "bookmarks"
+ 4 changesets found
+ list of changesets:
+ ef1ea85a6374b77d6da9dcda9541f498f2d17df7
+ f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
+ 911600dab2ae7a9baff75958b84fe606851ce955
+ e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
+ adding changesets
+ bundling: 1/4 changesets (25.00%)
+ bundling: 2/4 changesets (50.00%)
+ bundling: 3/4 changesets (75.00%)
+ bundling: 4/4 changesets (100.00%)
+ bundling: 1/4 manifests (25.00%)
+ bundling: 2/4 manifests (50.00%)
+ bundling: 3/4 manifests (75.00%)
+ bundling: 4/4 manifests (100.00%)
+ bundling: abc.txt 1/4 files (25.00%)
+ bundling: foo/Bar/file.txt 2/4 files (50.00%)
+ bundling: foo/file.txt 3/4 files (75.00%)
+ bundling: quux/file.py 4/4 files (100.00%)
+ changesets: 1 chunks
+ add changeset ef1ea85a6374
+ changesets: 2 chunks
+ add changeset f9cafe1212c8
+ changesets: 3 chunks
+ add changeset 911600dab2ae
+ changesets: 4 chunks
+ add changeset e8fc755d4d82
+ adding manifests
+ manifests: 1/4 chunks (25.00%)
+ manifests: 2/4 chunks (50.00%)
+ manifests: 3/4 chunks (75.00%)
+ manifests: 4/4 chunks (100.00%)
+ adding file changes
+ adding abc.txt revisions
+ files: 1/4 chunks (25.00%)
+ adding foo/Bar/file.txt revisions
+ files: 2/4 chunks (50.00%)
+ adding foo/file.txt revisions
+ files: 3/4 chunks (75.00%)
+ adding quux/file.py revisions
+ files: 4/4 chunks (100.00%)
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ calling hook pretxnchangegroup.acl: hgext.acl.hook
+ acl: checking access for user "george"
+ acl: acl.allow.branches not enabled
+ acl: acl.deny.branches enabled, 1 entries for user george
+ acl: acl.allow not enabled
+ acl: acl.deny not enabled
+ error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
+ transaction abort!
+ rollback completed
+ abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
+ no rollback information available
+ 2:fb35475503ef
+
+
diff --git a/tests/test-add.t b/tests/test-add.t
new file mode 100644
index 0000000..85a9b4e
--- /dev/null
+++ b/tests/test-add.t
@@ -0,0 +1,140 @@
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg add -n
+ adding a
+ $ hg st
+ ? a
+ $ hg add
+ adding a
+ $ hg st
+ A a
+ $ hg forget a
+ $ hg add
+ adding a
+ $ hg st
+ A a
+
+ $ echo b > b
+ $ hg add -n b
+ $ hg st
+ A a
+ ? b
+ $ hg add b
+ $ hg st
+ A a
+ A b
+
+should fail
+
+ $ hg add b
+ b already tracked!
+ $ hg st
+ A a
+ A b
+
+#if no-windows
+ $ echo foo > con.xml
+ $ hg --config ui.portablefilenames=jump add con.xml
+ abort: ui.portablefilenames value is invalid ('jump')
+ [255]
+ $ hg --config ui.portablefilenames=abort add con.xml
+ abort: filename contains 'con', which is reserved on Windows: 'con.xml'
+ [255]
+ $ hg st
+ A a
+ A b
+ ? con.xml
+ $ hg add con.xml
+ warning: filename contains 'con', which is reserved on Windows: 'con.xml'
+ $ hg st
+ A a
+ A b
+ A con.xml
+ $ hg forget con.xml
+ $ rm con.xml
+#endif
+
+#if eol-in-paths
+ $ echo bla > 'hello:world'
+ $ hg --config ui.portablefilenames=abort add
+ adding hello:world
+ abort: filename contains ':', which is reserved on Windows: 'hello:world'
+ [255]
+ $ hg st
+ A a
+ A b
+ ? hello:world
+ $ hg --config ui.portablefilenames=ignore add
+ adding hello:world
+ $ hg st
+ A a
+ A b
+ A hello:world
+#endif
+
+ $ hg ci -m 0 --traceback
+
+should fail
+
+ $ hg add a
+ a already tracked!
+
+ $ echo aa > a
+ $ hg ci -m 1
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo aaa > a
+ $ hg ci -m 2
+ created new head
+
+ $ hg merge
+ merging a
+ warning: conflicts during merge.
+ merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ hg st
+ M a
+ ? a.orig
+
+should fail
+
+ $ hg add a
+ a already tracked!
+ $ hg st
+ M a
+ ? a.orig
+ $ hg resolve -m a
+ $ hg ci -m merge
+
+Issue683: peculiarity with hg revert of an removed then added file
+
+ $ hg forget a
+ $ hg add a
+ $ hg st
+ ? a.orig
+ $ hg rm a
+ $ hg st
+ R a
+ ? a.orig
+ $ echo a > a
+ $ hg add a
+ $ hg st
+ M a
+ ? a.orig
+
+ $ hg add c && echo "unexpected addition of missing file"
+ c: * (glob)
+ [1]
+ $ echo c > c
+ $ hg add d c && echo "unexpected addition of missing file"
+ d: * (glob)
+ [1]
+ $ hg st
+ M a
+ A c
+ ? a.orig
+
+ $ cd ..
diff --git a/tests/test-addremove-similar.t b/tests/test-addremove-similar.t
new file mode 100644
index 0000000..0da9c69
--- /dev/null
+++ b/tests/test-addremove-similar.t
@@ -0,0 +1,102 @@
+ $ hg init rep; cd rep
+
+ $ touch empty-file
+ $ python -c 'for x in range(10000): print x' > large-file
+
+ $ hg addremove
+ adding empty-file
+ adding large-file
+
+ $ hg commit -m A
+
+ $ rm large-file empty-file
+ $ python -c 'for x in range(10,10000): print x' > another-file
+
+ $ hg addremove -s50
+ adding another-file
+ removing empty-file
+ removing large-file
+ recording removal of large-file as rename to another-file (99% similar)
+
+ $ hg commit -m B
+
+comparing two empty files caused ZeroDivisionError in the past
+
+ $ hg update -C 0
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ rm empty-file
+ $ touch another-empty-file
+ $ hg addremove -s50
+ adding another-empty-file
+ removing empty-file
+
+ $ cd ..
+
+ $ hg init rep2; cd rep2
+
+ $ python -c 'for x in range(10000): print x' > large-file
+ $ python -c 'for x in range(50): print x' > tiny-file
+
+ $ hg addremove
+ adding large-file
+ adding tiny-file
+
+ $ hg commit -m A
+
+ $ python -c 'for x in range(70): print x' > small-file
+ $ rm tiny-file
+ $ rm large-file
+
+ $ hg addremove -s50
+ removing large-file
+ adding small-file
+ removing tiny-file
+ recording removal of tiny-file as rename to small-file (82% similar)
+
+ $ hg commit -m B
+
+should all fail
+
+ $ hg addremove -s foo
+ abort: similarity must be a number
+ [255]
+ $ hg addremove -s -1
+ abort: similarity must be between 0 and 100
+ [255]
+ $ hg addremove -s 1e6
+ abort: similarity must be between 0 and 100
+ [255]
+
+ $ cd ..
+
+Issue1527: repeated addremove causes util.Abort
+
+ $ hg init rep3; cd rep3
+ $ mkdir d
+ $ echo a > d/a
+ $ hg add d/a
+ $ hg commit -m 1
+
+ $ mv d/a d/b
+ $ hg addremove -s80
+ removing d/a
+ adding d/b
+ recording removal of d/a as rename to d/b (100% similar) (glob)
+ $ hg debugstate
+ r 0 0 1970-01-01 00:00:00 d/a
+ a 0 -1 unset d/b
+ copy: d/a -> d/b
+ $ mv d/b c
+
+no copies found here (since the target isn't in d
+
+ $ hg addremove -s80 d
+ removing d/b (glob)
+
+copies here
+
+ $ hg addremove -s80
+ adding c
+ recording removal of d/a as rename to c (100% similar) (glob)
+
+ $ cd ..
diff --git a/tests/test-addremove.t b/tests/test-addremove.t
new file mode 100644
index 0000000..45be3f4
--- /dev/null
+++ b/tests/test-addremove.t
@@ -0,0 +1,48 @@
+ $ hg init rep
+ $ cd rep
+ $ mkdir dir
+ $ touch foo dir/bar
+ $ hg -v addremove
+ adding dir/bar
+ adding foo
+ $ hg -v commit -m "add 1"
+ dir/bar
+ foo
+ committed changeset 0:6f7f953567a2
+ $ cd dir/
+ $ touch ../foo_2 bar_2
+ $ hg -v addremove
+ adding dir/bar_2
+ adding foo_2
+ $ hg -v commit -m "add 2"
+ dir/bar_2
+ foo_2
+ committed changeset 1:e65414bf35c5
+ $ cd ../..
+
+ $ hg init sim
+ $ cd sim
+ $ echo a > a
+ $ echo a >> a
+ $ echo a >> a
+ $ echo c > c
+ $ hg commit -Ama
+ adding a
+ adding c
+ $ mv a b
+ $ rm c
+ $ echo d > d
+ $ hg addremove -n -s 50 # issue 1696
+ removing a
+ adding b
+ removing c
+ adding d
+ recording removal of a as rename to b (100% similar)
+ $ hg addremove -s 50
+ removing a
+ adding b
+ removing c
+ adding d
+ recording removal of a as rename to b (100% similar)
+ $ hg commit -mb
+ $ cd ..
diff --git a/tests/test-alias.t b/tests/test-alias.t
new file mode 100644
index 0000000..cf19233
--- /dev/null
+++ b/tests/test-alias.t
@@ -0,0 +1,428 @@
+ $ HGFOO=BAR; export HGFOO
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ >
+ > [alias]
+ > # should clobber ci but not commit (issue2993)
+ > ci = version
+ > myinit = init
+ > optionalrepo = showconfig alias.myinit
+ > cleanstatus = status -c
+ > unknown = bargle
+ > ambiguous = s
+ > recursive = recursive
+ > nodefinition =
+ > no--cwd = status --cwd elsewhere
+ > no-R = status -R elsewhere
+ > no--repo = status --repo elsewhere
+ > no--repository = status --repository elsewhere
+ > mylog = log
+ > lognull = log -r null
+ > shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
+ > positional = log --template '{\$2} {\$1} | {date|isodate}\n'
+ > dln = lognull --debug
+ > nousage = rollback
+ > put = export -r 0 -o "\$FOO/%R.diff"
+ > blank = !printf '\n'
+ > self = !printf '\$0\n'
+ > echoall = !printf '\$@\n'
+ > echo1 = !printf '\$1\n'
+ > echo2 = !printf '\$2\n'
+ > echo13 = !printf '\$1 \$3\n'
+ > count = !hg log -r "\$@" --template=. | wc -c | sed -e 's/ //g'
+ > mcount = !hg log \$@ --template=. | wc -c | sed -e 's/ //g'
+ > rt = root
+ > tglog = glog --template "{rev}:{node|short}: '{desc}' {branches}\n"
+ > idalias = id
+ > idaliaslong = id
+ > idaliasshell = !echo test
+ > parentsshell1 = !echo one
+ > parentsshell2 = !echo two
+ > escaped1 = !printf 'test\$\$test\n'
+ > escaped2 = !sh -c 'echo "HGFOO is \$\$HGFOO"'
+ > escaped3 = !sh -c 'echo "\$1 is \$\$\$1"'
+ > escaped4 = !printf '\$\$0 \$\$@\n'
+ >
+ > [defaults]
+ > mylog = -q
+ > lognull = -q
+ > log = -v
+ > EOF
+
+
+basic
+
+ $ hg myinit alias
+
+
+unknown
+
+ $ hg unknown
+ alias 'unknown' resolves to unknown command 'bargle'
+ $ hg help unknown
+ alias 'unknown' resolves to unknown command 'bargle'
+
+
+ambiguous
+
+ $ hg ambiguous
+ alias 'ambiguous' resolves to ambiguous command 's'
+ $ hg help ambiguous
+ alias 'ambiguous' resolves to ambiguous command 's'
+
+
+recursive
+
+ $ hg recursive
+ alias 'recursive' resolves to unknown command 'recursive'
+ $ hg help recursive
+ alias 'recursive' resolves to unknown command 'recursive'
+
+
+no definition
+
+ $ hg nodef
+ no definition for alias 'nodefinition'
+ $ hg help nodef
+ no definition for alias 'nodefinition'
+
+
+invalid options
+
+ $ hg no--cwd
+ error in definition for alias 'no--cwd': --cwd may only be given on the command line
+ $ hg help no--cwd
+ error in definition for alias 'no--cwd': --cwd may only be given on the command line
+ $ hg no-R
+ error in definition for alias 'no-R': -R may only be given on the command line
+ $ hg help no-R
+ error in definition for alias 'no-R': -R may only be given on the command line
+ $ hg no--repo
+ error in definition for alias 'no--repo': --repo may only be given on the command line
+ $ hg help no--repo
+ error in definition for alias 'no--repo': --repo may only be given on the command line
+ $ hg no--repository
+ error in definition for alias 'no--repository': --repository may only be given on the command line
+ $ hg help no--repository
+ error in definition for alias 'no--repository': --repository may only be given on the command line
+
+optional repository
+
+#if no-outer-repo
+ $ hg optionalrepo
+ init
+#endif
+ $ cd alias
+ $ cat > .hg/hgrc <<EOF
+ > [alias]
+ > myinit = init -q
+ > EOF
+ $ hg optionalrepo
+ init -q
+
+no usage
+
+ $ hg nousage
+ no rollback information available
+
+ $ echo foo > foo
+ $ hg commit -Amfoo
+ adding foo
+
+
+with opts
+
+ $ hg cleanst
+ C foo
+
+
+with opts and whitespace
+
+ $ hg shortlog
+ 0 e63c23eaa88a | 1970-01-01 00:00 +0000
+
+positional arguments
+
+ $ hg positional
+ abort: too few arguments for command alias
+ [255]
+ $ hg positional a
+ abort: too few arguments for command alias
+ [255]
+ $ hg positional 'node|short' rev
+ 0 e63c23eaa88a | 1970-01-01 00:00 +0000
+
+interaction with defaults
+
+ $ hg mylog
+ 0:e63c23eaa88a
+ $ hg lognull
+ -1:000000000000
+
+
+properly recursive
+
+ $ hg dln
+ changeset: -1:0000000000000000000000000000000000000000
+ parent: -1:0000000000000000000000000000000000000000
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: -1:0000000000000000000000000000000000000000
+ user:
+ date: Thu Jan 01 00:00:00 1970 +0000
+ extra: branch=default
+
+
+
+path expanding
+
+ $ FOO=`pwd` hg put
+ $ cat 0.diff
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Node ID e63c23eaa88ae77967edcf4ea194d31167c478b0
+ # Parent 0000000000000000000000000000000000000000
+ foo
+
+ diff -r 000000000000 -r e63c23eaa88a foo
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/foo Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +foo
+
+
+simple shell aliases
+
+ $ hg blank
+
+ $ hg blank foo
+
+ $ hg self
+ self
+ $ hg echoall
+
+ $ hg echoall foo
+ foo
+ $ hg echoall 'test $2' foo
+ test $2 foo
+ $ hg echo1 foo bar baz
+ foo
+ $ hg echo2 foo bar baz
+ bar
+ $ hg echo13 foo bar baz test
+ foo baz
+ $ hg echo2 foo
+
+ $ echo bar > bar
+ $ hg commit -qA -m bar
+ $ hg count .
+ 1
+ $ hg count 'branch(default)'
+ 2
+ $ hg mcount -r '"branch(default)"'
+ 2
+
+ $ hg tglog
+ @ 1:7e7f92de180e: 'bar'
+ |
+ o 0:e63c23eaa88a: 'foo'
+
+
+
+shadowing
+
+ $ hg i
+ hg: command 'i' is ambiguous:
+ idalias idaliaslong idaliasshell identify import incoming init
+ [255]
+ $ hg id
+ 7e7f92de180e tip
+ $ hg ida
+ hg: command 'ida' is ambiguous:
+ idalias idaliaslong idaliasshell
+ [255]
+ $ hg idalias
+ 7e7f92de180e tip
+ $ hg idaliasl
+ 7e7f92de180e tip
+ $ hg idaliass
+ test
+ $ hg parentsshell
+ hg: command 'parentsshell' is ambiguous:
+ parentsshell1 parentsshell2
+ [255]
+ $ hg parentsshell1
+ one
+ $ hg parentsshell2
+ two
+
+
+shell aliases with global options
+
+ $ hg init sub
+ $ cd sub
+ $ hg count 'branch(default)'
+ 0
+ $ hg -v count 'branch(default)'
+ 0
+ $ hg -R .. count 'branch(default)'
+ 0
+ $ hg --cwd .. count 'branch(default)'
+ 2
+ $ hg echoall --cwd ..
+
+
+
+repo specific shell aliases
+
+ $ cat >> .hg/hgrc <<EOF
+ > [alias]
+ > subalias = !echo sub
+ > EOF
+ $ cat >> ../.hg/hgrc <<EOF
+ > [alias]
+ > mainalias = !echo main
+ > EOF
+
+
+shell alias defined in current repo
+
+ $ hg subalias
+ sub
+ $ hg --cwd .. subalias > /dev/null
+ hg: unknown command 'subalias'
+ [255]
+ $ hg -R .. subalias > /dev/null
+ hg: unknown command 'subalias'
+ [255]
+
+
+shell alias defined in other repo
+
+ $ hg mainalias > /dev/null
+ hg: unknown command 'mainalias'
+ [255]
+ $ hg -R .. mainalias
+ main
+ $ hg --cwd .. mainalias
+ main
+
+
+shell aliases with escaped $ chars
+
+ $ hg escaped1
+ test$test
+ $ hg escaped2
+ HGFOO is BAR
+ $ hg escaped3 HGFOO
+ HGFOO is BAR
+ $ hg escaped4 test
+ $0 $@
+
+
+invalid arguments
+
+ $ hg rt foo
+ hg rt: invalid arguments
+ hg rt
+
+ alias for: hg root
+
+ use "hg help rt" to show the full help text
+ [255]
+
+invalid global arguments for normal commands, aliases, and shell aliases
+
+ $ hg --invalid root
+ hg: option --invalid not recognized
+ Mercurial Distributed SCM
+
+ basic commands:
+
+ add add the specified files on the next commit
+ annotate show changeset information by line for each file
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ init create a new repository in the given directory
+ log show revision history of entire repository or files
+ merge merge working directory with another revision
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ remove remove the specified files on the next commit
+ serve start stand-alone webserver
+ status show changed files in the working directory
+ summary summarize working directory state
+ update update working directory (or switch revisions)
+
+ use "hg help" for the full list of commands or "hg -v" for details
+ [255]
+ $ hg --invalid mylog
+ hg: option --invalid not recognized
+ Mercurial Distributed SCM
+
+ basic commands:
+
+ add add the specified files on the next commit
+ annotate show changeset information by line for each file
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ init create a new repository in the given directory
+ log show revision history of entire repository or files
+ merge merge working directory with another revision
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ remove remove the specified files on the next commit
+ serve start stand-alone webserver
+ status show changed files in the working directory
+ summary summarize working directory state
+ update update working directory (or switch revisions)
+
+ use "hg help" for the full list of commands or "hg -v" for details
+ [255]
+ $ hg --invalid blank
+ hg: option --invalid not recognized
+ Mercurial Distributed SCM
+
+ basic commands:
+
+ add add the specified files on the next commit
+ annotate show changeset information by line for each file
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ init create a new repository in the given directory
+ log show revision history of entire repository or files
+ merge merge working directory with another revision
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ remove remove the specified files on the next commit
+ serve start stand-alone webserver
+ status show changed files in the working directory
+ summary summarize working directory state
+ update update working directory (or switch revisions)
+
+ use "hg help" for the full list of commands or "hg -v" for details
+ [255]
+
+This should show id:
+
+ $ hg --config alias.log='id' log
+ 000000000000 tip
+
+This shouldn't:
+
+ $ hg --config alias.log='id' history
+
+ $ cd ../..
diff --git a/tests/test-annotate.t b/tests/test-annotate.t
new file mode 100644
index 0000000..85a0985
--- /dev/null
+++ b/tests/test-annotate.t
@@ -0,0 +1,322 @@
+ $ HGMERGE=true; export HGMERGE
+
+init
+
+ $ hg init repo
+ $ cd repo
+
+commit
+
+ $ echo 'a' > a
+ $ hg ci -A -m test -u nobody -d '1 0'
+ adding a
+
+annotate -c
+
+ $ hg annotate -c a
+ 8435f90966e4: a
+
+annotate -cl
+
+ $ hg annotate -cl a
+ 8435f90966e4:1: a
+
+annotate -d
+
+ $ hg annotate -d a
+ Thu Jan 01 00:00:01 1970 +0000: a
+
+annotate -n
+
+ $ hg annotate -n a
+ 0: a
+
+annotate -nl
+
+ $ hg annotate -nl a
+ 0:1: a
+
+annotate -u
+
+ $ hg annotate -u a
+ nobody: a
+
+annotate -cdnu
+
+ $ hg annotate -cdnu a
+ nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
+
+annotate -cdnul
+
+ $ hg annotate -cdnul a
+ nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000:1: a
+
+ $ cat <<EOF >>a
+ > a
+ > a
+ > EOF
+ $ hg ci -ma1 -d '1 0'
+ $ hg cp a b
+ $ hg ci -mb -d '1 0'
+ $ cat <<EOF >> b
+ > b4
+ > b5
+ > b6
+ > EOF
+ $ hg ci -mb2 -d '2 0'
+
+annotate -n b
+
+ $ hg annotate -n b
+ 0: a
+ 1: a
+ 1: a
+ 3: b4
+ 3: b5
+ 3: b6
+
+annotate --no-follow b
+
+ $ hg annotate --no-follow b
+ 2: a
+ 2: a
+ 2: a
+ 3: b4
+ 3: b5
+ 3: b6
+
+annotate -nl b
+
+ $ hg annotate -nl b
+ 0:1: a
+ 1:2: a
+ 1:3: a
+ 3:4: b4
+ 3:5: b5
+ 3:6: b6
+
+annotate -nf b
+
+ $ hg annotate -nf b
+ 0 a: a
+ 1 a: a
+ 1 a: a
+ 3 b: b4
+ 3 b: b5
+ 3 b: b6
+
+annotate -nlf b
+
+ $ hg annotate -nlf b
+ 0 a:1: a
+ 1 a:2: a
+ 1 a:3: a
+ 3 b:4: b4
+ 3 b:5: b5
+ 3 b:6: b6
+
+ $ hg up -C 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat <<EOF >> b
+ > b4
+ > c
+ > b5
+ > EOF
+ $ hg ci -mb2.1 -d '2 0'
+ created new head
+ $ hg merge
+ merging b
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -mmergeb -d '3 0'
+
+annotate after merge
+
+ $ hg annotate -nf b
+ 0 a: a
+ 1 a: a
+ 1 a: a
+ 3 b: b4
+ 4 b: c
+ 3 b: b5
+
+annotate after merge with -l
+
+ $ hg annotate -nlf b
+ 0 a:1: a
+ 1 a:2: a
+ 1 a:3: a
+ 3 b:4: b4
+ 4 b:5: c
+ 3 b:5: b5
+
+ $ hg up -C 1
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg cp a b
+ $ cat <<EOF > b
+ > a
+ > z
+ > a
+ > EOF
+ $ hg ci -mc -d '3 0'
+ created new head
+ $ hg merge
+ merging b
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ cat <<EOF >> b
+ > b4
+ > c
+ > b5
+ > EOF
+ $ echo d >> b
+ $ hg ci -mmerge2 -d '4 0'
+
+annotate after rename merge
+
+ $ hg annotate -nf b
+ 0 a: a
+ 6 b: z
+ 1 a: a
+ 3 b: b4
+ 4 b: c
+ 3 b: b5
+ 7 b: d
+
+annotate after rename merge with -l
+
+ $ hg annotate -nlf b
+ 0 a:1: a
+ 6 b:2: z
+ 1 a:3: a
+ 3 b:4: b4
+ 4 b:5: c
+ 3 b:5: b5
+ 7 b:7: d
+
+Issue2807: alignment of line numbers with -l
+
+ $ echo more >> b
+ $ hg ci -mmore -d '5 0'
+ $ echo more >> b
+ $ hg ci -mmore -d '6 0'
+ $ echo more >> b
+ $ hg ci -mmore -d '7 0'
+ $ hg annotate -nlf b
+ 0 a: 1: a
+ 6 b: 2: z
+ 1 a: 3: a
+ 3 b: 4: b4
+ 4 b: 5: c
+ 3 b: 5: b5
+ 7 b: 7: d
+ 8 b: 8: more
+ 9 b: 9: more
+ 10 b:10: more
+
+linkrev vs rev
+
+ $ hg annotate -r tip -n a
+ 0: a
+ 1: a
+ 1: a
+
+linkrev vs rev with -l
+
+ $ hg annotate -r tip -nl a
+ 0:1: a
+ 1:2: a
+ 1:3: a
+
+Issue589: "undelete" sequence leads to crash
+
+annotate was crashing when trying to --follow something
+
+like A -> B -> A
+
+generate ABA rename configuration
+
+ $ echo foo > foo
+ $ hg add foo
+ $ hg ci -m addfoo
+ $ hg rename foo bar
+ $ hg ci -m renamefoo
+ $ hg rename bar foo
+ $ hg ci -m renamebar
+
+annotate after ABA with follow
+
+ $ hg annotate --follow foo
+ foo: foo
+
+missing file
+
+ $ hg ann nosuchfile
+ abort: nosuchfile: no such file in rev e9e6b4fa872f
+ [255]
+
+annotate file without '\n' on last line
+
+ $ printf "" > c
+ $ hg ci -A -m test -u nobody -d '1 0'
+ adding c
+ $ hg annotate c
+ $ printf "a\nb" > c
+ $ hg ci -m test
+ $ hg annotate c
+ [0-9]+: a (re)
+ [0-9]+: b (re)
+
+Test annotate with whitespace options
+
+ $ cd ..
+ $ hg init repo-ws
+ $ cd repo-ws
+ $ cat > a <<EOF
+ > aa
+ >
+ > b b
+ > EOF
+ $ hg ci -Am "adda"
+ adding a
+ $ cat > a <<EOF
+ > a a
+ >
+ >
+ > b b
+ > EOF
+ $ hg ci -m "changea"
+
+Annotate with no option
+
+ $ hg annotate a
+ 1: a a
+ 0:
+ 1:
+ 1: b b
+
+Annotate with --ignore-space-change
+
+ $ hg annotate --ignore-space-change a
+ 1: a a
+ 1:
+ 0:
+ 0: b b
+
+Annotate with --ignore-all-space
+
+ $ hg annotate --ignore-all-space a
+ 0: a a
+ 0:
+ 1:
+ 0: b b
+
+Annotate with --ignore-blank-lines (similar to no options case)
+
+ $ hg annotate --ignore-blank-lines a
+ 1: a a
+ 0:
+ 1:
+ 1: b b
+
+ $ cd ..
diff --git a/tests/test-archive-symlinks.t b/tests/test-archive-symlinks.t
new file mode 100644
index 0000000..a0f15b5
--- /dev/null
+++ b/tests/test-archive-symlinks.t
@@ -0,0 +1,40 @@
+ $ "$TESTDIR/hghave" symlink || exit 80
+
+ $ origdir=`pwd`
+
+ $ hg init repo
+ $ cd repo
+ $ ln -s nothing dangling
+
+avoid tar warnings about old timestamp
+
+ $ hg ci -d '2000-01-01 00:00:00 +0000' -qAm 'add symlink'
+
+ $ hg archive -t files ../archive
+ $ hg archive -t tar -p tar ../archive.tar
+ $ hg archive -t zip -p zip ../archive.zip
+
+files
+
+ $ cd "$origdir"
+ $ cd archive
+ $ "$TESTDIR/readlink.py" dangling
+ dangling -> nothing
+
+tar
+
+ $ cd "$origdir"
+ $ tar xf archive.tar
+ $ cd tar
+ $ "$TESTDIR/readlink.py" dangling
+ dangling -> nothing
+
+zip
+
+ $ cd "$origdir"
+ $ unzip archive.zip > /dev/null
+ $ cd zip
+ $ "$TESTDIR/readlink.py" dangling
+ dangling -> nothing
+
+ $ cd ..
diff --git a/tests/test-archive.t b/tests/test-archive.t
new file mode 100644
index 0000000..6da530f
--- /dev/null
+++ b/tests/test-archive.t
@@ -0,0 +1,272 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ hg init test
+ $ cd test
+ $ echo foo>foo
+ $ hg commit -Am 1 -d '1 0'
+ adding foo
+ $ echo bar>bar
+ $ hg commit -Am 2 -d '2 0'
+ adding bar
+ $ mkdir baz
+ $ echo bletch>baz/bletch
+ $ hg commit -Am 3 -d '1000000000 0'
+ adding baz/bletch
+ $ echo "[web]" >> .hg/hgrc
+ $ echo "name = test-archive" >> .hg/hgrc
+ $ cp .hg/hgrc .hg/hgrc-base
+ > test_archtype() {
+ > echo "allow_archive = $1" >> .hg/hgrc
+ > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ > cat hg.pid >> $DAEMON_PIDS
+ > echo % $1 allowed should give 200
+ > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.$2" | head -n 1
+ > echo % $3 and $4 disallowed should both give 403
+ > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.$3" | head -n 1
+ > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.$4" | head -n 1
+ > "$TESTDIR/killdaemons.py"
+ > cat errors.log
+ > cp .hg/hgrc-base .hg/hgrc
+ > }
+
+check http return codes
+
+ $ test_archtype gz tar.gz tar.bz2 zip
+ % gz allowed should give 200
+ 200 Script output follows
+ % tar.bz2 and zip disallowed should both give 403
+ 403 Archive type not allowed: bz2
+ 403 Archive type not allowed: zip
+ $ test_archtype bz2 tar.bz2 zip tar.gz
+ % bz2 allowed should give 200
+ 200 Script output follows
+ % zip and tar.gz disallowed should both give 403
+ 403 Archive type not allowed: zip
+ 403 Archive type not allowed: gz
+ $ test_archtype zip zip tar.gz tar.bz2
+ % zip allowed should give 200
+ 200 Script output follows
+ % tar.gz and tar.bz2 disallowed should both give 403
+ 403 Archive type not allowed: gz
+ 403 Archive type not allowed: bz2
+
+ $ echo "allow_archive = gz bz2 zip" >> .hg/hgrc
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+invalid arch type should give 404
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.invalid" | head -n 1
+ 404 Unsupported archive type: None
+
+ $ TIP=`hg id -v | cut -f1 -d' '`
+ $ QTIP=`hg id -q`
+ $ cat > getarchive.py <<EOF
+ > import os, sys, urllib2
+ > try:
+ > # Set stdout to binary mode for win32 platforms
+ > import msvcrt
+ > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+ > except ImportError:
+ > pass
+ > node, archive = sys.argv[1:]
+ > f = urllib2.urlopen('http://127.0.0.1:%s/?cmd=archive;node=%s;type=%s'
+ > % (os.environ['HGPORT'], node, archive))
+ > sys.stdout.write(f.read())
+ > EOF
+ $ python getarchive.py "$TIP" gz | gunzip | tar tf - 2>/dev/null
+ test-archive-2c0277f05ed4/.hg_archival.txt
+ test-archive-2c0277f05ed4/bar
+ test-archive-2c0277f05ed4/baz/bletch
+ test-archive-2c0277f05ed4/foo
+ $ python getarchive.py "$TIP" bz2 | bunzip2 | tar tf - 2>/dev/null
+ test-archive-2c0277f05ed4/.hg_archival.txt
+ test-archive-2c0277f05ed4/bar
+ test-archive-2c0277f05ed4/baz/bletch
+ test-archive-2c0277f05ed4/foo
+ $ python getarchive.py "$TIP" zip > archive.zip
+ $ unzip -t archive.zip
+ Archive: archive.zip
+ testing: test-archive-2c0277f05ed4/.hg_archival.txt OK
+ testing: test-archive-2c0277f05ed4/bar OK
+ testing: test-archive-2c0277f05ed4/baz/bletch OK
+ testing: test-archive-2c0277f05ed4/foo OK
+ No errors detected in compressed data of archive.zip.
+
+ $ "$TESTDIR/killdaemons.py"
+
+ $ hg archive -t tar test.tar
+ $ tar tf test.tar
+ test/.hg_archival.txt
+ test/bar
+ test/baz/bletch
+ test/foo
+
+ $ hg archive --debug -t tbz2 -X baz test.tar.bz2
+ archiving: 0/2 files (0.00%)
+ archiving: bar 1/2 files (50.00%)
+ archiving: foo 2/2 files (100.00%)
+ $ bunzip2 -dc test.tar.bz2 | tar tf - 2>/dev/null
+ test/.hg_archival.txt
+ test/bar
+ test/foo
+
+ $ hg archive -t tgz -p %b-%h test-%h.tar.gz
+ $ gzip -dc test-$QTIP.tar.gz | tar tf - 2>/dev/null
+ test-2c0277f05ed4/.hg_archival.txt
+ test-2c0277f05ed4/bar
+ test-2c0277f05ed4/baz/bletch
+ test-2c0277f05ed4/foo
+
+ $ hg archive autodetected_test.tar
+ $ tar tf autodetected_test.tar
+ autodetected_test/.hg_archival.txt
+ autodetected_test/bar
+ autodetected_test/baz/bletch
+ autodetected_test/foo
+
+The '-t' should override autodetection
+
+ $ hg archive -t tar autodetect_override_test.zip
+ $ tar tf autodetect_override_test.zip
+ autodetect_override_test.zip/.hg_archival.txt
+ autodetect_override_test.zip/bar
+ autodetect_override_test.zip/baz/bletch
+ autodetect_override_test.zip/foo
+
+ $ for ext in tar tar.gz tgz tar.bz2 tbz2 zip; do
+ > hg archive auto_test.$ext
+ > if [ -d auto_test.$ext ]; then
+ > echo "extension $ext was not autodetected."
+ > fi
+ > done
+
+ $ cat > md5comp.py <<EOF
+ > try:
+ > from hashlib import md5
+ > except ImportError:
+ > from md5 import md5
+ > import sys
+ > f1, f2 = sys.argv[1:3]
+ > h1 = md5(file(f1, 'rb').read()).hexdigest()
+ > h2 = md5(file(f2, 'rb').read()).hexdigest()
+ > print h1 == h2 or "md5 differ: " + repr((h1, h2))
+ > EOF
+
+archive name is stored in the archive, so create similar archives and
+rename them afterwards.
+
+ $ hg archive -t tgz tip.tar.gz
+ $ mv tip.tar.gz tip1.tar.gz
+ $ sleep 1
+ $ hg archive -t tgz tip.tar.gz
+ $ mv tip.tar.gz tip2.tar.gz
+ $ python md5comp.py tip1.tar.gz tip2.tar.gz
+ True
+
+ $ hg archive -t zip -p /illegal test.zip
+ abort: archive prefix contains illegal components
+ [255]
+ $ hg archive -t zip -p very/../bad test.zip
+
+ $ hg archive --config ui.archivemeta=false -t zip -r 2 test.zip
+ $ unzip -t test.zip
+ Archive: test.zip
+ testing: test/bar OK
+ testing: test/baz/bletch OK
+ testing: test/foo OK
+ No errors detected in compressed data of test.zip.
+
+ $ hg archive -t tar - | tar tf - 2>/dev/null
+ test-2c0277f05ed4/.hg_archival.txt
+ test-2c0277f05ed4/bar
+ test-2c0277f05ed4/baz/bletch
+ test-2c0277f05ed4/foo
+
+ $ hg archive -r 0 -t tar rev-%r.tar
+ $ if [ -f rev-0.tar ]; then
+ $ fi
+
+test .hg_archival.txt
+
+ $ hg archive ../test-tags
+ $ cat ../test-tags/.hg_archival.txt
+ repo: daa7f7c60e0a224faa4ff77ca41b2760562af264
+ node: 2c0277f05ed49d1c8328fb9ba92fba7a5ebcb33e
+ branch: default
+ latesttag: null
+ latesttagdistance: 3
+ $ hg tag -r 2 mytag
+ $ hg tag -r 2 anothertag
+ $ hg archive -r 2 ../test-lasttag
+ $ cat ../test-lasttag/.hg_archival.txt
+ repo: daa7f7c60e0a224faa4ff77ca41b2760562af264
+ node: 2c0277f05ed49d1c8328fb9ba92fba7a5ebcb33e
+ branch: default
+ tag: anothertag
+ tag: mytag
+
+ $ hg archive -t bogus test.bogus
+ abort: unknown archive type 'bogus'
+ [255]
+
+enable progress extension:
+
+ $ cp $HGRCPATH $HGRCPATH.no-progress
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > progress =
+ > [progress]
+ > assume-tty = 1
+ > format = topic bar number
+ > delay = 0
+ > refresh = 0
+ > width = 60
+ > EOF
+
+ $ hg archive ../with-progress 2>&1 | "$TESTDIR/filtercr.py"
+
+ archiving [ ] 0/4
+ archiving [ ] 0/4
+ archiving [=========> ] 1/4
+ archiving [=========> ] 1/4
+ archiving [====================> ] 2/4
+ archiving [====================> ] 2/4
+ archiving [===============================> ] 3/4
+ archiving [===============================> ] 3/4
+ archiving [==========================================>] 4/4
+ archiving [==========================================>] 4/4
+ \r (esc)
+
+cleanup after progress extension test:
+
+ $ cp $HGRCPATH.no-progress $HGRCPATH
+
+server errors
+
+ $ cat errors.log
+
+empty repo
+
+ $ hg init ../empty
+ $ cd ../empty
+ $ hg archive ../test-empty
+ abort: no working directory: please specify a revision
+ [255]
+
+old file -- date clamped to 1980
+
+ $ touch -t 197501010000 old
+ $ hg add old
+ $ hg commit -m old
+ $ hg archive ../old.zip
+ $ unzip -l ../old.zip
+ Archive: ../old.zip
+ \s*Length.* (re)
+ *-----* (glob)
+ *147*80*00:00*old/.hg_archival.txt (glob)
+ *0*80*00:00*old/old (glob)
+ *-----* (glob)
+ \s*147\s+2 files (re)
+
+ $ cd ..
diff --git a/tests/test-atomictempfile.py b/tests/test-atomictempfile.py
new file mode 100644
index 0000000..9ebd7c0
--- /dev/null
+++ b/tests/test-atomictempfile.py
@@ -0,0 +1,48 @@
+import os
+import glob
+from mercurial.util import atomictempfile
+
+# basic usage
+def test1_simple():
+ if os.path.exists('foo'):
+ os.remove('foo')
+ file = atomictempfile('foo')
+ (dir, basename) = os.path.split(file._tempname)
+ assert not os.path.isfile('foo')
+ assert basename in glob.glob('.foo-*')
+
+ file.write('argh\n')
+ file.close()
+
+ assert os.path.isfile('foo')
+ assert basename not in glob.glob('.foo-*')
+ print 'OK'
+
+# discard() removes the temp file without making the write permanent
+def test2_discard():
+ if os.path.exists('foo'):
+ os.remove('foo')
+ file = atomictempfile('foo')
+ (dir, basename) = os.path.split(file._tempname)
+
+ file.write('yo\n')
+ file.discard()
+
+ assert not os.path.isfile('foo')
+ assert basename not in os.listdir('.')
+ print 'OK'
+
+# if a programmer screws up and passes bad args to atomictempfile, they
+# get a plain ordinary TypeError, not infinite recursion
+def test3_oops():
+ try:
+ file = atomictempfile()
+ except TypeError:
+ print "OK"
+ else:
+ print "expected TypeError"
+
+if __name__ == '__main__':
+ test1_simple()
+ test2_discard()
+ test3_oops()
diff --git a/tests/test-atomictempfile.py.out b/tests/test-atomictempfile.py.out
new file mode 100644
index 0000000..0eabe36
--- /dev/null
+++ b/tests/test-atomictempfile.py.out
@@ -0,0 +1,3 @@
+OK
+OK
+OK
diff --git a/tests/test-audit-path.t b/tests/test-audit-path.t
new file mode 100644
index 0000000..d105e94
--- /dev/null
+++ b/tests/test-audit-path.t
@@ -0,0 +1,92 @@
+ $ hg init
+
+audit of .hg
+
+ $ hg add .hg/00changelog.i
+ abort: path contains illegal component: .hg/00changelog.i (glob)
+ [255]
+
+#if symlink
+
+Symlinks
+
+ $ mkdir a
+ $ echo a > a/a
+ $ hg ci -Ama
+ adding a/a
+ $ ln -s a b
+ $ echo b > a/b
+ $ hg add b/b
+ abort: path 'b/b' traverses symbolic link 'b' (glob)
+ [255]
+ $ hg add b
+
+should still fail - maybe
+
+ $ hg add b/b
+ abort: path 'b/b' traverses symbolic link 'b' (glob)
+ [255]
+
+#endif
+
+
+unbundle tampered bundle
+
+ $ hg init target
+ $ cd target
+ $ hg unbundle "$TESTDIR/bundles/tampered.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 6 changes to 6 files (+4 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+attack .hg/test
+
+ $ hg manifest -r0
+ .hg/test
+ $ hg update -Cr0
+ abort: path contains illegal component: .hg/test (glob)
+ [255]
+
+attack foo/.hg/test
+
+ $ hg manifest -r1
+ foo/.hg/test
+ $ hg update -Cr1
+ abort: path 'foo/.hg/test' is inside nested repo 'foo' (glob)
+ [255]
+
+attack back/test where back symlinks to ..
+
+ $ hg manifest -r2
+ back
+ back/test
+#if symlink
+ $ hg update -Cr2
+ abort: path 'back/test' traverses symbolic link 'back'
+ [255]
+#else
+('back' will be a file and cause some other system specific error)
+ $ hg update -Cr2
+ abort: * (glob)
+ [255]
+#endif
+
+attack ../test
+
+ $ hg manifest -r3
+ ../test
+ $ hg update -Cr3
+ abort: path contains illegal component: ../test (glob)
+ [255]
+
+attack /tmp/test
+
+ $ hg manifest -r4
+ /tmp/test
+ $ hg update -Cr4
+ abort: *: $TESTTMP/target//tmp/test (glob)
+ [255]
+
+ $ cd ..
diff --git a/tests/test-backout.t b/tests/test-backout.t
new file mode 100644
index 0000000..c2404f5
--- /dev/null
+++ b/tests/test-backout.t
@@ -0,0 +1,294 @@
+ $ hg init basic
+ $ cd basic
+
+should complain
+
+ $ hg backout
+ abort: please specify a revision to backout
+ [255]
+ $ hg backout -r 0 0
+ abort: please specify just one revision
+ [255]
+
+basic operation
+
+ $ echo a > a
+ $ hg commit -d '0 0' -A -m a
+ adding a
+ $ echo b >> a
+ $ hg commit -d '1 0' -m b
+
+ $ hg backout -d '2 0' tip --tool=true
+ reverting a
+ changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
+ $ cat a
+ a
+
+file that was removed is recreated
+
+ $ cd ..
+ $ hg init remove
+ $ cd remove
+
+ $ echo content > a
+ $ hg commit -d '0 0' -A -m a
+ adding a
+
+ $ hg rm a
+ $ hg commit -d '1 0' -m b
+
+ $ hg backout -d '2 0' tip --tool=true
+ adding a
+ changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
+ $ cat a
+ content
+
+backout of backout is as if nothing happened
+
+ $ hg backout -d '3 0' --merge tip --tool=true
+ removing a
+ changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
+ $ test -f a
+ [1]
+
+across branch
+
+ $ cd ..
+ $ hg init branch
+ $ cd branch
+ $ echo a > a
+ $ hg ci -Am0
+ adding a
+ $ echo b > b
+ $ hg ci -Am1
+ adding b
+ $ hg co -C 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+should fail
+
+ $ hg backout 1
+ abort: cannot backout change on a different branch
+ [255]
+ $ echo c > c
+ $ hg ci -Am2
+ adding c
+ created new head
+
+should fail
+
+ $ hg backout 1
+ abort: cannot backout change on a different branch
+ [255]
+
+backout with merge
+
+ $ cd ..
+ $ hg init merge
+ $ cd merge
+
+ $ echo line 1 > a
+ $ echo line 2 >> a
+ $ hg commit -d '0 0' -A -m a
+ adding a
+
+remove line 1
+
+ $ echo line 2 > a
+ $ hg commit -d '1 0' -m b
+
+ $ echo line 3 >> a
+ $ hg commit -d '2 0' -m c
+
+ $ hg backout --merge -d '3 0' 1 --tool=true
+ reverting a
+ created new head
+ changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
+ merging with changeset 3:26b8ccb9ad91
+ merging a
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -d '4 0' -m d
+
+check line 1 is back
+
+ $ cat a
+ line 1
+ line 2
+ line 3
+
+ $ cd ..
+
+backout should not back out subsequent changesets
+
+ $ hg init onecs
+ $ cd onecs
+ $ echo 1 > a
+ $ hg commit -d '0 0' -A -m a
+ adding a
+ $ echo 2 >> a
+ $ hg commit -d '1 0' -m b
+ $ echo 1 > b
+ $ hg commit -d '2 0' -A -m c
+ adding b
+
+without --merge
+ $ hg backout -d '3 0' 1 --tool=true
+ reverting a
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg locate b
+ b
+ $ hg update -C tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg locate b
+ b
+
+with --merge
+ $ hg backout --merge -d '3 0' 1 --tool=true
+ reverting a
+ created new head
+ changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
+ merging with changeset 3:3202beb76721
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg locate b
+ b
+ $ hg update -C tip
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg locate b
+ [1]
+
+ $ cd ..
+ $ hg init m
+ $ cd m
+ $ echo a > a
+ $ hg commit -d '0 0' -A -m a
+ adding a
+ $ echo b > b
+ $ hg commit -d '1 0' -A -m b
+ adding b
+ $ echo c > c
+ $ hg commit -d '2 0' -A -m b
+ adding c
+ $ hg update 1
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo d > d
+ $ hg commit -d '3 0' -A -m c
+ adding d
+ created new head
+ $ hg merge 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -d '4 0' -A -m d
+
+backout of merge should fail
+
+ $ hg backout 4
+ abort: cannot backout a merge changeset
+ [255]
+
+backout of merge with bad parent should fail
+
+ $ hg backout --parent 0 4
+ abort: cb9a9f314b8b is not a parent of b2f3bb92043e
+ [255]
+
+backout of non-merge with parent should fail
+
+ $ hg backout --parent 0 3
+ abort: cannot use --parent on non-merge changeset
+ [255]
+
+backout with valid parent should be ok
+
+ $ hg backout -d '5 0' --parent 2 4 --tool=true
+ removing d
+ changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
+
+ $ hg rollback
+ repository tip rolled back to revision 4 (undo commit)
+ working directory now based on revision 4
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg backout -d '6 0' --parent 3 4 --tool=true
+ removing c
+ changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
+
+ $ cd ..
+
+named branches
+
+ $ hg init named_branches
+ $ cd named_branches
+
+ $ echo default > default
+ $ hg ci -d '0 0' -Am default
+ adding default
+ $ hg branch branch1
+ marked working directory as branch branch1
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo branch1 > file1
+ $ hg ci -d '1 0' -Am file1
+ adding file1
+ $ hg branch branch2
+ marked working directory as branch branch2
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo branch2 > file2
+ $ hg ci -d '2 0' -Am file2
+ adding file2
+
+without --merge
+ $ hg backout -r 1 --tool=true
+ removing file1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch
+ branch2
+ $ hg status -A
+ R file1
+ C default
+ C file2
+
+with --merge
+ $ hg update -qC
+ $ hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true
+ removing file1
+ created new head
+ changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
+ merging with changeset 3:d4e8f6db59fb
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg update -q -C 2
+
+on branch2 with branch1 not merged, so file1 should still exist:
+
+ $ hg id
+ 45bbcd363bf0 (branch2)
+ $ hg st -A
+ C default
+ C file1
+ C file2
+
+on branch2 with branch1 merged, so file1 should be gone:
+
+ $ hg merge
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -d '4 0' -m 'merge backout of branch1'
+ $ hg id
+ 22149cdde76d (branch2) tip
+ $ hg st -A
+ C default
+ C file2
+
+on branch1, so no file1 and file2:
+
+ $ hg co -C branch1
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg id
+ bf1602f437f3 (branch1)
+ $ hg st -A
+ C default
+ C file1
+
+ $ cd ..
diff --git a/tests/test-backwards-remove.t b/tests/test-backwards-remove.t
new file mode 100644
index 0000000..044a44d
--- /dev/null
+++ b/tests/test-backwards-remove.t
@@ -0,0 +1,16 @@
+ $ hg init
+ $ echo This is file a1 > a
+ $ hg add a
+ $ hg commit -m "commit #0"
+ $ ls
+ a
+ $ echo This is file b1 > b
+ $ hg add b
+ $ hg commit -m "commit #1"
+ $ hg co 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+B should disappear
+
+ $ ls
+ a
diff --git a/tests/test-bad-extension.t b/tests/test-bad-extension.t
new file mode 100644
index 0000000..5476c1b
--- /dev/null
+++ b/tests/test-bad-extension.t
@@ -0,0 +1,15 @@
+ $ echo 'raise Exception("bit bucket overflow")' > badext.py
+ $ abspath=`pwd`/badext.py
+
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo "gpg =" >> $HGRCPATH
+ $ echo "hgext.gpg =" >> $HGRCPATH
+ $ echo "badext = $abspath" >> $HGRCPATH
+ $ echo "badext2 =" >> $HGRCPATH
+
+ $ hg -q help help
+ *** failed to import extension badext from $TESTTMP/badext.py: bit bucket overflow
+ *** failed to import extension badext2: No module named badext2
+ hg help [-ec] [TOPIC]
+
+ show help for a given topic or a help overview
diff --git a/tests/test-bad-pull.t b/tests/test-bad-pull.t
new file mode 100644
index 0000000..7e32388
--- /dev/null
+++ b/tests/test-bad-pull.t
@@ -0,0 +1,33 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+#if windows
+ $ hg clone http://localhost:$HGPORT/ copy
+ abort: * (glob)
+ [255]
+#else
+ $ hg clone http://localhost:$HGPORT/ copy
+ abort: error: Connection refused
+ [255]
+#endif
+
+ $ test -d copy
+ [1]
+
+ $ cat > dumb.py <<EOF
+ > import BaseHTTPServer, SimpleHTTPServer, os, signal
+ > def run(server_class=BaseHTTPServer.HTTPServer,
+ > handler_class=SimpleHTTPServer.SimpleHTTPRequestHandler):
+ > server_address = ('localhost', int(os.environ['HGPORT']))
+ > httpd = server_class(server_address, handler_class)
+ > open("listening", "w")
+ > httpd.handle_request()
+ > run()
+ > EOF
+
+ $ python dumb.py 2> log &
+ $ P=$!
+ $ while [ ! -f listening ]; do sleep 0; done
+ $ hg clone http://localhost:$HGPORT/foo copy2
+ abort: HTTP Error 404: * (glob)
+ [255]
+ $ wait $P
diff --git a/tests/test-basic.t b/tests/test-basic.t
new file mode 100644
index 0000000..4d350a5
--- /dev/null
+++ b/tests/test-basic.t
@@ -0,0 +1,57 @@
+Create a repository:
+
+ $ hg init t
+ $ cd t
+
+Make a changeset:
+
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m test
+
+This command is ancient:
+
+ $ hg history
+ changeset: 0:acb14030fe0a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: test
+
+
+Verify that updating to revision 0 via commands.update() works properly
+
+ $ cat <<EOF > update_to_rev0.py
+ > from mercurial import ui, hg, commands
+ > myui = ui.ui()
+ > repo = hg.repository(myui, path='.')
+ > commands.update(myui, repo, rev=0)
+ > EOF
+ $ hg up null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ python ./update_to_rev0.py
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg identify -n
+ 0
+
+
+Poke around at hashes:
+
+ $ hg manifest --debug
+ b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 a
+
+ $ hg cat a
+ a
+
+Verify should succeed:
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+
+At the end...
+
+ $ cd ..
diff --git a/tests/test-batching.py b/tests/test-batching.py
new file mode 100644
index 0000000..22fefb3
--- /dev/null
+++ b/tests/test-batching.py
@@ -0,0 +1,175 @@
+# test-batching.py - tests for transparent command batching
+#
+# Copyright 2011 Peter Arrenbrecht <peter@arrenbrecht.ch>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from mercurial.wireproto import localbatch, remotebatch, batchable, future
+
+# equivalent of repo.repository
+class thing(object):
+ def hello(self):
+ return "Ready."
+
+# equivalent of localrepo.localrepository
+class localthing(thing):
+ def foo(self, one, two=None):
+ if one:
+ return "%s and %s" % (one, two,)
+ return "Nope"
+ def bar(self, b, a):
+ return "%s und %s" % (b, a,)
+ def greet(self, name=None):
+ return "Hello, %s" % name
+ def batch(self):
+ '''Support for local batching.'''
+ return localbatch(self)
+
+# usage of "thing" interface
+def use(it):
+
+ # Direct call to base method shared between client and server.
+ print it.hello()
+
+ # Direct calls to proxied methods. They cause individual roundtrips.
+ print it.foo("Un", two="Deux")
+ print it.bar("Eins", "Zwei")
+
+ # Batched call to a couple of (possibly proxied) methods.
+ batch = it.batch()
+ # The calls return futures to eventually hold results.
+ foo = batch.foo(one="One", two="Two")
+ foo2 = batch.foo(None)
+ bar = batch.bar("Eins", "Zwei")
+ # We can call non-batchable proxy methods, but the break the current batch
+ # request and cause additional roundtrips.
+ greet = batch.greet(name="John Smith")
+ # We can also add local methods into the mix, but they break the batch too.
+ hello = batch.hello()
+ bar2 = batch.bar(b="Uno", a="Due")
+ # Only now are all the calls executed in sequence, with as few roundtrips
+ # as possible.
+ batch.submit()
+ # After the call to submit, the futures actually contain values.
+ print foo.value
+ print foo2.value
+ print bar.value
+ print greet.value
+ print hello.value
+ print bar2.value
+
+# local usage
+mylocal = localthing()
+print
+print "== Local"
+use(mylocal)
+
+# demo remoting; mimicks what wireproto and HTTP/SSH do
+
+# shared
+
+def escapearg(plain):
+ return (plain
+ .replace(':', '::')
+ .replace(',', ':,')
+ .replace(';', ':;')
+ .replace('=', ':='))
+def unescapearg(escaped):
+ return (escaped
+ .replace(':=', '=')
+ .replace(':;', ';')
+ .replace(':,', ',')
+ .replace('::', ':'))
+
+# server side
+
+# equivalent of wireproto's global functions
+class server(object):
+ def __init__(self, local):
+ self.local = local
+ def _call(self, name, args):
+ args = dict(arg.split('=', 1) for arg in args)
+ return getattr(self, name)(**args)
+ def perform(self, req):
+ print "REQ:", req
+ name, args = req.split('?', 1)
+ args = args.split('&')
+ vals = dict(arg.split('=', 1) for arg in args)
+ res = getattr(self, name)(**vals)
+ print " ->", res
+ return res
+ def batch(self, cmds):
+ res = []
+ for pair in cmds.split(';'):
+ name, args = pair.split(':', 1)
+ vals = {}
+ for a in args.split(','):
+ if a:
+ n, v = a.split('=')
+ vals[n] = unescapearg(v)
+ res.append(escapearg(getattr(self, name)(**vals)))
+ return ';'.join(res)
+ def foo(self, one, two):
+ return mangle(self.local.foo(unmangle(one), unmangle(two)))
+ def bar(self, b, a):
+ return mangle(self.local.bar(unmangle(b), unmangle(a)))
+ def greet(self, name):
+ return mangle(self.local.greet(unmangle(name)))
+myserver = server(mylocal)
+
+# local side
+
+# equivalent of wireproto.encode/decodelist, that is, type-specific marshalling
+# here we just transform the strings a bit to check we're properly en-/decoding
+def mangle(s):
+ return ''.join(chr(ord(c) + 1) for c in s)
+def unmangle(s):
+ return ''.join(chr(ord(c) - 1) for c in s)
+
+# equivalent of wireproto.wirerepository and something like http's wire format
+class remotething(thing):
+ def __init__(self, server):
+ self.server = server
+ def _submitone(self, name, args):
+ req = name + '?' + '&'.join(['%s=%s' % (n, v) for n, v in args])
+ return self.server.perform(req)
+ def _submitbatch(self, cmds):
+ req = []
+ for name, args in cmds:
+ args = ','.join(n + '=' + escapearg(v) for n, v in args)
+ req.append(name + ':' + args)
+ req = ';'.join(req)
+ res = self._submitone('batch', [('cmds', req,)])
+ return res.split(';')
+
+ def batch(self):
+ return remotebatch(self)
+
+ @batchable
+ def foo(self, one, two=None):
+ if not one:
+ yield "Nope", None
+ encargs = [('one', mangle(one),), ('two', mangle(two),)]
+ encresref = future()
+ yield encargs, encresref
+ yield unmangle(encresref.value)
+
+ @batchable
+ def bar(self, b, a):
+ encresref = future()
+ yield [('b', mangle(b),), ('a', mangle(a),)], encresref
+ yield unmangle(encresref.value)
+
+ # greet is coded directly. It therefore does not support batching. If it
+ # does appear in a batch, the batch is split around greet, and the call to
+ # greet is done in its own roundtrip.
+ def greet(self, name=None):
+ return unmangle(self._submitone('greet', [('name', mangle(name),)]))
+
+# demo remote usage
+
+myproxy = remotething(myserver)
+print
+print "== Remote"
+use(myproxy)
diff --git a/tests/test-batching.py.out b/tests/test-batching.py.out
new file mode 100644
index 0000000..4b677c2
--- /dev/null
+++ b/tests/test-batching.py.out
@@ -0,0 +1,32 @@
+
+== Local
+Ready.
+Un and Deux
+Eins und Zwei
+One and Two
+Nope
+Eins und Zwei
+Hello, John Smith
+Ready.
+Uno und Due
+
+== Remote
+Ready.
+REQ: foo?one=Vo&two=Efvy
+ -> Vo!boe!Efvy
+Un and Deux
+REQ: bar?b=Fjot&a=[xfj
+ -> Fjot!voe![xfj
+Eins und Zwei
+REQ: batch?cmds=foo:one=Pof,two=Uxp;bar:b=Fjot,a=[xfj
+ -> Pof!boe!Uxp;Fjot!voe![xfj
+REQ: greet?name=Kpio!Tnjui
+ -> Ifmmp-!Kpio!Tnjui
+REQ: batch?cmds=bar:b=Vop,a=Evf
+ -> Vop!voe!Evf
+One and Two
+Nope
+Eins und Zwei
+Hello, John Smith
+Ready.
+Uno und Due
diff --git a/tests/test-bdiff.py b/tests/test-bdiff.py
new file mode 100644
index 0000000..c17dfb0
--- /dev/null
+++ b/tests/test-bdiff.py
@@ -0,0 +1,66 @@
+import struct
+from mercurial import bdiff, mpatch
+
+def test1(a, b):
+ d = bdiff.bdiff(a, b)
+ c = a
+ if d:
+ c = mpatch.patches(a, [d])
+ if c != b:
+ print "***", repr(a), repr(b)
+ print "bad:"
+ print repr(c)[:200]
+ print repr(d)
+
+def test(a, b):
+ print "***", repr(a), repr(b)
+ test1(a, b)
+ test1(b, a)
+
+test("a\nc\n\n\n\n", "a\nb\n\n\n")
+test("a\nb\nc\n", "a\nc\n")
+test("", "")
+test("a\nb\nc", "a\nb\nc")
+test("a\nb\nc\nd\n", "a\nd\n")
+test("a\nb\nc\nd\n", "a\nc\ne\n")
+test("a\nb\nc\n", "a\nc\n")
+test("a\n", "c\na\nb\n")
+test("a\n", "")
+test("a\n", "b\nc\n")
+test("a\n", "c\na\n")
+test("", "adjfkjdjksdhfksj")
+test("", "ab")
+test("", "abc")
+test("a", "a")
+test("ab", "ab")
+test("abc", "abc")
+test("a\n", "a\n")
+test("a\nb", "a\nb")
+
+#issue1295
+def showdiff(a, b):
+ bin = bdiff.bdiff(a, b)
+ pos = 0
+ while pos < len(bin):
+ p1, p2, l = struct.unpack(">lll", bin[pos:pos + 12])
+ pos += 12
+ print p1, p2, repr(bin[pos:pos + l])
+ pos += l
+showdiff("x\n\nx\n\nx\n\nx\n\nz\n", "x\n\nx\n\ny\n\nx\n\nx\n\nz\n")
+showdiff("x\n\nx\n\nx\n\nx\n\nz\n", "x\n\nx\n\ny\n\nx\n\ny\n\nx\n\nz\n")
+
+print "done"
+
+def testfixws(a, b, allws):
+ c = bdiff.fixws(a, allws)
+ if c != b:
+ print "*** fixws", repr(a), repr(b), allws
+ print "got:"
+ print repr(c)
+
+testfixws(" \ta\r b\t\n", "ab\n", 1)
+testfixws(" \ta\r b\t\n", " a b\n", 0)
+testfixws("", "", 1)
+testfixws("", "", 0)
+
+print "done"
diff --git a/tests/test-bdiff.py.out b/tests/test-bdiff.py.out
new file mode 100644
index 0000000..9c00d05
--- /dev/null
+++ b/tests/test-bdiff.py.out
@@ -0,0 +1,24 @@
+*** 'a\nc\n\n\n\n' 'a\nb\n\n\n'
+*** 'a\nb\nc\n' 'a\nc\n'
+*** '' ''
+*** 'a\nb\nc' 'a\nb\nc'
+*** 'a\nb\nc\nd\n' 'a\nd\n'
+*** 'a\nb\nc\nd\n' 'a\nc\ne\n'
+*** 'a\nb\nc\n' 'a\nc\n'
+*** 'a\n' 'c\na\nb\n'
+*** 'a\n' ''
+*** 'a\n' 'b\nc\n'
+*** 'a\n' 'c\na\n'
+*** '' 'adjfkjdjksdhfksj'
+*** '' 'ab'
+*** '' 'abc'
+*** 'a' 'a'
+*** 'ab' 'ab'
+*** 'abc' 'abc'
+*** 'a\n' 'a\n'
+*** 'a\nb' 'a\nb'
+6 6 'y\n\n'
+6 6 'y\n\n'
+9 9 'y\n\n'
+done
+done
diff --git a/tests/test-bheads.t b/tests/test-bheads.t
new file mode 100644
index 0000000..2093813
--- /dev/null
+++ b/tests/test-bheads.t
@@ -0,0 +1,375 @@
+ $ heads()
+ > {
+ > hg heads --template '{rev}: {desc|firstline|strip} ({branches})\n' "$@"
+ > }
+
+ $ hg init a
+ $ cd a
+ $ echo 'root' >root
+ $ hg add root
+ $ hg commit -m "Adding root node"
+ $ heads
+ 0: Adding root node ()
+-------
+ $ heads .
+ 0: Adding root node ()
+
+=======
+
+ $ echo 'a' >a
+ $ hg add a
+ $ hg branch a
+ marked working directory as branch a
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg commit -m "Adding a branch"
+ $ heads
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+-------
+ $ heads .
+ 1: Adding a branch (a)
+
+=======
+
+ $ hg update -C 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo 'b' >b
+ $ hg add b
+ $ hg branch b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg commit -m "Adding b branch"
+ $ heads
+ 2: Adding b branch (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+-------
+ $ heads .
+ 2: Adding b branch (b)
+
+=======
+
+ $ echo 'bh1' >bh1
+ $ hg add bh1
+ $ hg commit -m "Adding b branch head 1"
+ $ heads
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+-------
+ $ heads .
+ 3: Adding b branch head 1 (b)
+
+=======
+
+ $ hg update -C 2
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo 'bh2' >bh2
+ $ hg add bh2
+ $ hg commit -m "Adding b branch head 2"
+ created new head
+ $ heads
+ 4: Adding b branch head 2 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+ $ heads .
+ 4: Adding b branch head 2 (b)
+ 3: Adding b branch head 1 (b)
+
+=======
+
+ $ hg update -C 2
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo 'bh3' >bh3
+ $ hg add bh3
+ $ hg commit -m "Adding b branch head 3"
+ created new head
+ $ heads
+ 5: Adding b branch head 3 (b)
+ 4: Adding b branch head 2 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+-------
+ $ heads .
+ 5: Adding b branch head 3 (b)
+ 4: Adding b branch head 2 (b)
+ 3: Adding b branch head 1 (b)
+
+=======
+
+ $ hg merge 4
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -m "Merging b branch head 2 and b branch head 3"
+ $ heads
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+-------
+ $ heads .
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+
+=======
+
+ $ echo 'c' >c
+ $ hg add c
+ $ hg branch c
+ marked working directory as branch c
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg commit -m "Adding c branch"
+ $ heads
+ 7: Adding c branch (c)
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+-------
+ $ heads .
+ 7: Adding c branch (c)
+
+=======
+
+ $ heads -r 3 .
+ no open branch heads found on branches c (started at 3)
+ [1]
+ $ heads -r 2 .
+ 7: Adding c branch (c)
+-------
+ $ hg update -C 4
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+-------
+ $ heads -r 3 .
+ 3: Adding b branch head 1 (b)
+-------
+ $ heads -r 2 .
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+-------
+ $ heads -r 7 .
+ no open branch heads found on branches b (started at 7)
+ [1]
+
+=======
+
+ $ for i in 0 1 2 3 4 5 6 7; do
+ > hg update -C "$i"
+ > heads
+ > echo '-------'
+ > heads .
+ > echo '-------'
+ > done
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ 7: Adding c branch (c)
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+ -------
+ 0: Adding root node ()
+ -------
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 7: Adding c branch (c)
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+ -------
+ 1: Adding a branch (a)
+ -------
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ 7: Adding c branch (c)
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+ -------
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ -------
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 7: Adding c branch (c)
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+ -------
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ -------
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ 7: Adding c branch (c)
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+ -------
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ -------
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ 7: Adding c branch (c)
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+ -------
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ -------
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 7: Adding c branch (c)
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+ -------
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ -------
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 7: Adding c branch (c)
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+ -------
+ 7: Adding c branch (c)
+ -------
+
+=======
+
+ $ for i in a b c z; do
+ > heads "$i"
+ > echo '-------'
+ > done
+ 1: Adding a branch (a)
+ -------
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ -------
+ 7: Adding c branch (c)
+ -------
+ abort: unknown revision 'z'!
+ -------
+
+=======
+
+ $ heads 0 1 2 3 4 5 6 7
+ 7: Adding c branch (c)
+ 6: Merging b branch head 2 and b branch head 3 (b)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+ 0: Adding root node ()
+
+Topological heads:
+
+ $ heads -t
+ 7: Adding c branch (c)
+ 3: Adding b branch head 1 (b)
+ 1: Adding a branch (a)
+
+ $ cd ..
+______________
+
+"created new head" message tests
+
+ $ hg init newheadmsg
+ $ cd newheadmsg
+
+Init: no msg
+
+ $ echo 1 > a
+ $ hg ci -Am "a0: Initial root"
+ adding a
+ $ echo 2 >> a
+ $ hg ci -m "a1 (HN)"
+
+ $ hg branch b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo 1 > b
+ $ hg ci -Am "b2: Initial root for branch b"
+ adding b
+ $ echo 2 >> b
+ $ hg ci -m "b3 (HN)"
+
+Case NN: msg
+
+ $ hg up -q null
+ $ hg branch -f b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo 1 > bb
+ $ hg ci -Am "b4 (NN): new topo root for branch b"
+ adding bb
+ created new head
+
+Case HN: no msg
+
+ $ echo 2 >> bb
+ $ hg ci -m "b5 (HN)"
+
+Case BN: msg
+
+ $ hg branch -f default
+ marked working directory as branch default
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo 1 > aa
+ $ hg ci -Am "a6 (BN): new branch root"
+ adding aa
+ created new head
+
+Case CN: msg
+
+ $ hg up -q 4
+ $ echo 3 >> bbb
+ $ hg ci -Am "b7 (CN): regular new head"
+ adding bbb
+ created new head
+
+Case BB: msg
+
+ $ hg up -q 4
+ $ hg merge -q 3
+ $ hg branch -f default
+ marked working directory as branch default
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m "a8 (BB): weird new branch root"
+ created new head
+
+Case CB: msg
+
+ $ hg up -q 4
+ $ hg merge -q 1
+ $ hg ci -m "b9 (CB): new head from branch merge"
+ created new head
+
+Case HB: no msg
+
+ $ hg up -q 7
+ $ hg merge -q 6
+ $ hg ci -m "b10 (HB): continuing head from branch merge"
+
+Case CC: msg
+
+ $ hg up -q 4
+ $ hg merge -q 2
+ $ hg ci -m "b11 (CC): new head from merge"
+ created new head
+
+Case CH: no msg
+
+ $ hg up -q 2
+ $ hg merge -q 10
+ $ hg ci -m "b12 (CH): continuing head from merge"
+
+Case HH: no msg
+
+ $ hg merge -q 3
+ $ hg ci -m "b12 (HH): merging two heads"
+
+ $ cd ..
diff --git a/tests/test-bisect.t b/tests/test-bisect.t
new file mode 100644
index 0000000..4e8b771
--- /dev/null
+++ b/tests/test-bisect.t
@@ -0,0 +1,510 @@
+ $ hg init
+
+
+committing changes
+
+ $ count=0
+ $ echo > a
+ $ while test $count -lt 32 ; do
+ > echo 'a' >> a
+ > test $count -eq 0 && hg add
+ > hg ci -m "msg $count" -d "$count 0"
+ > count=`expr $count + 1`
+ > done
+ adding a
+
+
+ $ hg log
+ changeset: 31:58c80a7c8a40
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:31 1970 +0000
+ summary: msg 31
+
+ changeset: 30:ed2d2f24b11c
+ user: test
+ date: Thu Jan 01 00:00:30 1970 +0000
+ summary: msg 30
+
+ changeset: 29:b5bd63375ab9
+ user: test
+ date: Thu Jan 01 00:00:29 1970 +0000
+ summary: msg 29
+
+ changeset: 28:8e0c2264c8af
+ user: test
+ date: Thu Jan 01 00:00:28 1970 +0000
+ summary: msg 28
+
+ changeset: 27:288867a866e9
+ user: test
+ date: Thu Jan 01 00:00:27 1970 +0000
+ summary: msg 27
+
+ changeset: 26:3efc6fd51aeb
+ user: test
+ date: Thu Jan 01 00:00:26 1970 +0000
+ summary: msg 26
+
+ changeset: 25:02a84173a97a
+ user: test
+ date: Thu Jan 01 00:00:25 1970 +0000
+ summary: msg 25
+
+ changeset: 24:10e0acd3809e
+ user: test
+ date: Thu Jan 01 00:00:24 1970 +0000
+ summary: msg 24
+
+ changeset: 23:5ec79163bff4
+ user: test
+ date: Thu Jan 01 00:00:23 1970 +0000
+ summary: msg 23
+
+ changeset: 22:06c7993750ce
+ user: test
+ date: Thu Jan 01 00:00:22 1970 +0000
+ summary: msg 22
+
+ changeset: 21:e5db6aa3fe2a
+ user: test
+ date: Thu Jan 01 00:00:21 1970 +0000
+ summary: msg 21
+
+ changeset: 20:7128fb4fdbc9
+ user: test
+ date: Thu Jan 01 00:00:20 1970 +0000
+ summary: msg 20
+
+ changeset: 19:52798545b482
+ user: test
+ date: Thu Jan 01 00:00:19 1970 +0000
+ summary: msg 19
+
+ changeset: 18:86977a90077e
+ user: test
+ date: Thu Jan 01 00:00:18 1970 +0000
+ summary: msg 18
+
+ changeset: 17:03515f4a9080
+ user: test
+ date: Thu Jan 01 00:00:17 1970 +0000
+ summary: msg 17
+
+ changeset: 16:a2e6ea4973e9
+ user: test
+ date: Thu Jan 01 00:00:16 1970 +0000
+ summary: msg 16
+
+ changeset: 15:e7fa0811edb0
+ user: test
+ date: Thu Jan 01 00:00:15 1970 +0000
+ summary: msg 15
+
+ changeset: 14:ce8f0998e922
+ user: test
+ date: Thu Jan 01 00:00:14 1970 +0000
+ summary: msg 14
+
+ changeset: 13:9d7d07bc967c
+ user: test
+ date: Thu Jan 01 00:00:13 1970 +0000
+ summary: msg 13
+
+ changeset: 12:1941b52820a5
+ user: test
+ date: Thu Jan 01 00:00:12 1970 +0000
+ summary: msg 12
+
+ changeset: 11:7b4cd9578619
+ user: test
+ date: Thu Jan 01 00:00:11 1970 +0000
+ summary: msg 11
+
+ changeset: 10:7c5eff49a6b6
+ user: test
+ date: Thu Jan 01 00:00:10 1970 +0000
+ summary: msg 10
+
+ changeset: 9:eb44510ef29a
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: msg 9
+
+ changeset: 8:453eb4dba229
+ user: test
+ date: Thu Jan 01 00:00:08 1970 +0000
+ summary: msg 8
+
+ changeset: 7:03750880c6b5
+ user: test
+ date: Thu Jan 01 00:00:07 1970 +0000
+ summary: msg 7
+
+ changeset: 6:a3d5c6fdf0d3
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: msg 6
+
+ changeset: 5:7874a09ea728
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ summary: msg 5
+
+ changeset: 4:9b2ba8336a65
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: msg 4
+
+ changeset: 3:b53bea5e2fcb
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: msg 3
+
+ changeset: 2:db07c04beaca
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: msg 2
+
+ changeset: 1:5cd978ea5149
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: msg 1
+
+ changeset: 0:b99c7b9c8e11
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: msg 0
+
+
+ $ hg up -C
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+bisect test
+
+ $ hg bisect -r
+ $ hg bisect -b
+ $ hg bisect -g 1
+ Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -g
+ Testing changeset 23:5ec79163bff4 (15 changesets remaining, ~3 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+skip
+
+ $ hg bisect -s
+ Testing changeset 24:10e0acd3809e (15 changesets remaining, ~3 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -g
+ Testing changeset 27:288867a866e9 (7 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -g
+ Testing changeset 29:b5bd63375ab9 (4 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -b
+ Testing changeset 28:8e0c2264c8af (2 changesets remaining, ~1 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -g
+ The first bad revision is:
+ changeset: 29:b5bd63375ab9
+ user: test
+ date: Thu Jan 01 00:00:29 1970 +0000
+ summary: msg 29
+
+
+mark revsets instead of single revs
+
+ $ hg bisect -r
+ $ hg bisect -b "0::3"
+ $ hg bisect -s "13::16"
+ $ hg bisect -g "26::tip"
+ Testing changeset 12:1941b52820a5 (23 changesets remaining, ~4 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat .hg/bisect.state
+ current 1941b52820a544549596820a8ae006842b0e2c64
+ skip 9d7d07bc967ca98ad0600c24953fd289ad5fa991
+ skip ce8f0998e922c179e80819d5066fbe46e2998784
+ skip e7fa0811edb063f6319531f0d0a865882138e180
+ skip a2e6ea4973e9196ddd3386493b0c214b41fd97d3
+ bad b99c7b9c8e11558adef3fad9af211c58d46f325b
+ bad 5cd978ea51499179507ee7b6f340d2dbaa401185
+ bad db07c04beaca44cf24832541e7f4a2346a95275b
+ bad b53bea5e2fcb30d3e00bd3409507a5659ce0fd8b
+ good 3efc6fd51aeb8594398044c6c846ca59ae021203
+ good 288867a866e9adb7a29880b66936c874b80f4651
+ good 8e0c2264c8af790daf3585ada0669d93dee09c83
+ good b5bd63375ab9a290419f2024b7f4ee9ea7ce90a8
+ good ed2d2f24b11c368fa8aa0da9f4e1db580abade59
+ good 58c80a7c8a4025a94cedaf7b4a4e3124e8909a96
+
+bisect reverse test
+
+ $ hg bisect -r
+ $ hg bisect -b null
+ $ hg bisect -g tip
+ Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -g
+ Testing changeset 7:03750880c6b5 (16 changesets remaining, ~4 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+skip
+
+ $ hg bisect -s
+ Testing changeset 6:a3d5c6fdf0d3 (16 changesets remaining, ~4 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -g
+ Testing changeset 2:db07c04beaca (7 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -g
+ Testing changeset 0:b99c7b9c8e11 (3 changesets remaining, ~1 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -b
+ Testing changeset 1:5cd978ea5149 (2 changesets remaining, ~1 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -g
+ The first good revision is:
+ changeset: 1:5cd978ea5149
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: msg 1
+
+
+ $ hg bisect -r
+ $ hg bisect -g tip
+ $ hg bisect -b tip
+ abort: starting revisions are not directly related
+ [255]
+
+ $ hg bisect -r
+ $ hg bisect -g null
+ $ hg bisect -bU tip
+ Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests)
+ $ hg id
+ 5cd978ea5149
+
+
+Issue1228: hg bisect crashes when you skip the last rev in bisection
+Issue1182: hg bisect exception
+
+ $ hg bisect -r
+ $ hg bisect -b 4
+ $ hg bisect -g 0
+ Testing changeset 2:db07c04beaca (4 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -s
+ Testing changeset 1:5cd978ea5149 (4 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -s
+ Testing changeset 3:b53bea5e2fcb (4 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -s
+ Due to skipped revisions, the first bad revision could be any of:
+ changeset: 1:5cd978ea5149
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: msg 1
+
+ changeset: 2:db07c04beaca
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: msg 2
+
+ changeset: 3:b53bea5e2fcb
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: msg 3
+
+ changeset: 4:9b2ba8336a65
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: msg 4
+
+
+
+reproduce non converging bisect, issue1182
+
+ $ hg bisect -r
+ $ hg bisect -g 0
+ $ hg bisect -b 2
+ Testing changeset 1:5cd978ea5149 (2 changesets remaining, ~1 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -s
+ Due to skipped revisions, the first bad revision could be any of:
+ changeset: 1:5cd978ea5149
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: msg 1
+
+ changeset: 2:db07c04beaca
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: msg 2
+
+
+
+test no action
+
+ $ hg bisect -r
+ $ hg bisect
+ abort: cannot bisect (no known good revisions)
+ [255]
+
+
+reproduce AssertionError, issue1445
+
+ $ hg bisect -r
+ $ hg bisect -b 6
+ $ hg bisect -g 0
+ Testing changeset 3:b53bea5e2fcb (6 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -s
+ Testing changeset 2:db07c04beaca (6 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -s
+ Testing changeset 4:9b2ba8336a65 (6 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -s
+ Testing changeset 1:5cd978ea5149 (6 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -s
+ Testing changeset 5:7874a09ea728 (6 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -g
+ The first bad revision is:
+ changeset: 6:a3d5c6fdf0d3
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: msg 6
+
+ $ hg log -r "bisect(good)"
+ changeset: 0:b99c7b9c8e11
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: msg 0
+
+ changeset: 5:7874a09ea728
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ summary: msg 5
+
+ $ hg log -r "bisect(bad)"
+ changeset: 6:a3d5c6fdf0d3
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: msg 6
+
+ $ hg log -r "bisect(current)"
+ changeset: 5:7874a09ea728
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ summary: msg 5
+
+ $ hg log -r "bisect(skip)"
+ changeset: 1:5cd978ea5149
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: msg 1
+
+ changeset: 2:db07c04beaca
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: msg 2
+
+ changeset: 3:b53bea5e2fcb
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: msg 3
+
+ changeset: 4:9b2ba8336a65
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: msg 4
+
+
+test legacy bisected() keyword
+
+ $ hg log -r "bisected(bad)"
+ changeset: 6:a3d5c6fdf0d3
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: msg 6
+
+
+ $ set +e
+
+test invalid command
+assuming that the shell returns 127 if command not found ...
+
+ $ hg bisect -r
+ $ hg bisect --command 'exit 127'
+ abort: failed to execute exit 127
+ [255]
+
+
+test bisecting command
+
+ $ cat > script.py <<EOF
+ > #!/usr/bin/env python
+ > import sys
+ > from mercurial import ui, hg
+ > repo = hg.repository(ui.ui(), '.')
+ > if repo['.'].rev() < 6:
+ > sys.exit(1)
+ > EOF
+ $ chmod +x script.py
+ $ hg bisect -r
+ $ hg bisect --good tip
+ $ hg bisect --bad 0
+ Testing changeset 15:e7fa0811edb0 (31 changesets remaining, ~4 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect --command "python \"$TESTTMP/script.py\" and some parameters"
+ changeset 15:e7fa0811edb0: good
+ changeset 7:03750880c6b5: good
+ changeset 3:b53bea5e2fcb: bad
+ changeset 5:7874a09ea728: bad
+ changeset 6:a3d5c6fdf0d3: good
+ The first good revision is:
+ changeset: 6:a3d5c6fdf0d3
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: msg 6
+
+
+
+test bisecting via a command without updating the working dir, and
+ensure that the bisect state file is updated before running a test
+command
+
+ $ hg update null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ cat > script.sh <<'EOF'
+ > #!/bin/sh
+ > test -n "$HG_NODE" || (echo HG_NODE missing; exit 127)
+ > current="`hg log -r \"bisect(current)\" --template {node}`"
+ > test "$current" = "$HG_NODE" || (echo current is bad: $current; exit 127)
+ > rev="`hg log -r $HG_NODE --template {rev}`"
+ > test "$rev" -ge 6
+ > EOF
+ $ chmod +x script.sh
+ $ hg bisect -r
+ $ hg bisect --good tip --noupdate
+ $ hg bisect --bad 0 --noupdate
+ Testing changeset 15:e7fa0811edb0 (31 changesets remaining, ~4 tests)
+ $ hg bisect --command "sh \"$TESTTMP/script.sh\" and some params" --noupdate
+ changeset 15:e7fa0811edb0: good
+ changeset 7:03750880c6b5: good
+ changeset 3:b53bea5e2fcb: bad
+ changeset 5:7874a09ea728: bad
+ changeset 6:a3d5c6fdf0d3: good
+ The first good revision is:
+ changeset: 6:a3d5c6fdf0d3
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: msg 6
+
+
+ensure that we still don't have a working dir
+
+ $ hg parents
diff --git a/tests/test-bisect2.t b/tests/test-bisect2.t
new file mode 100644
index 0000000..5414df7
--- /dev/null
+++ b/tests/test-bisect2.t
@@ -0,0 +1,795 @@
+# The tests in test-bisect are done on a linear history. Here the
+# following repository history is used for testing:
+#
+# 17
+# |
+# 18 16
+# \ /
+# 15
+# / \
+# / \
+# 10 13
+# / \ |
+# / \ | 14
+# 7 6 9 12 /
+# \ / \ | |/
+# 4 \ | 11
+# \ \ | /
+# 3 5 | /
+# \ / |/
+# 2 8
+# \ /
+# 1
+# |
+# 0
+
+init
+
+ $ hg init
+
+committing changes
+
+ $ echo > a
+ $ echo '0' >> a
+ $ hg add a
+ $ hg ci -m "0" -d "0 0"
+ $ echo '1' >> a
+ $ hg ci -m "1" -d "1 0"
+ $ echo '2' >> a
+ $ hg ci -m "2" -d "2 0"
+ $ echo '3' >> a
+ $ hg ci -m "3" -d "3 0"
+ $ echo '4' >> a
+ $ hg ci -m "4" -d "4 0"
+
+create branch
+
+ $ hg up -r 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo '5' >> b
+ $ hg add b
+ $ hg ci -m "5" -d "5 0"
+ created new head
+
+merge
+
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m "merge 4,5" -d "6 0"
+
+create branch
+
+ $ hg up -r 4
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo '7' > c
+ $ hg add c
+ $ hg ci -m "7" -d "7 0"
+ created new head
+
+create branch
+
+ $ hg up -r 1
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo '8' > d
+ $ hg add d
+ $ hg ci -m "8" -d "8 0"
+ created new head
+ $ echo '9' >> d
+ $ hg ci -m "9" -d "9 0"
+
+merge
+
+ $ hg merge -r 6
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m "merge 6,9" -d "10 0"
+
+create branch
+
+ $ hg up -r 8
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo '11' > e
+ $ hg add e
+ $ hg ci -m "11" -d "11 0"
+ created new head
+ $ echo '12' >> e
+ $ hg ci -m "12" -d "12 0"
+ $ echo '13' >> e
+ $ hg ci -m "13" -d "13 0"
+
+create branch
+
+ $ hg up -r 11
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo '14' > f
+ $ hg add f
+ $ hg ci -m "14" -d "14 0"
+ created new head
+
+merge
+
+ $ hg up -r 13 -C
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge -r 10
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m "merge 10,13" -d "15 0"
+ $ echo '16' >> e
+ $ hg ci -m "16" -d "16 0"
+ $ echo '17' >> e
+ $ hg ci -m "17" -d "17 0"
+
+create branch
+
+ $ hg up -r 15
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo '18' >> e
+ $ hg ci -m "18" -d "18 0"
+ created new head
+
+log
+
+ $ hg log
+ changeset: 18:d42e18c7bc9b
+ tag: tip
+ parent: 15:857b178a7cf3
+ user: test
+ date: Thu Jan 01 00:00:18 1970 +0000
+ summary: 18
+
+ changeset: 17:228c06deef46
+ user: test
+ date: Thu Jan 01 00:00:17 1970 +0000
+ summary: 17
+
+ changeset: 16:609d82a7ebae
+ user: test
+ date: Thu Jan 01 00:00:16 1970 +0000
+ summary: 16
+
+ changeset: 15:857b178a7cf3
+ parent: 13:b0a32c86eb31
+ parent: 10:429fcd26f52d
+ user: test
+ date: Thu Jan 01 00:00:15 1970 +0000
+ summary: merge 10,13
+
+ changeset: 14:faa450606157
+ parent: 11:82ca6f06eccd
+ user: test
+ date: Thu Jan 01 00:00:14 1970 +0000
+ summary: 14
+
+ changeset: 13:b0a32c86eb31
+ user: test
+ date: Thu Jan 01 00:00:13 1970 +0000
+ summary: 13
+
+ changeset: 12:9f259202bbe7
+ user: test
+ date: Thu Jan 01 00:00:12 1970 +0000
+ summary: 12
+
+ changeset: 11:82ca6f06eccd
+ parent: 8:dab8161ac8fc
+ user: test
+ date: Thu Jan 01 00:00:11 1970 +0000
+ summary: 11
+
+ changeset: 10:429fcd26f52d
+ parent: 9:3c77083deb4a
+ parent: 6:a214d5d3811a
+ user: test
+ date: Thu Jan 01 00:00:10 1970 +0000
+ summary: merge 6,9
+
+ changeset: 9:3c77083deb4a
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: 9
+
+ changeset: 8:dab8161ac8fc
+ parent: 1:4ca5088da217
+ user: test
+ date: Thu Jan 01 00:00:08 1970 +0000
+ summary: 8
+
+ changeset: 7:50c76098bbf2
+ parent: 4:5c668c22234f
+ user: test
+ date: Thu Jan 01 00:00:07 1970 +0000
+ summary: 7
+
+ changeset: 6:a214d5d3811a
+ parent: 5:385a529b6670
+ parent: 4:5c668c22234f
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: merge 4,5
+
+ changeset: 5:385a529b6670
+ parent: 2:051e12f87bf1
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ summary: 5
+
+ changeset: 4:5c668c22234f
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: 4
+
+ changeset: 3:0950834f0a9c
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: 3
+
+ changeset: 2:051e12f87bf1
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: 2
+
+ changeset: 1:4ca5088da217
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: 1
+
+ changeset: 0:33b1f9bc8bc5
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+
+hg up -C
+
+ $ hg up -C
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+complex bisect test 1 # first bad rev is 9
+
+ $ hg bisect -r
+ $ hg bisect -g 0
+ $ hg bisect -b 17 # -> update to rev 6
+ Testing changeset 6:a214d5d3811a (15 changesets remaining, ~3 tests)
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 17:228c06deef46
+ $ hg log -q -r 'bisect(untested)'
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ $ hg log -q -r 'bisect(ignored)'
+ $ hg bisect -g # -> update to rev 13
+ Testing changeset 13:b0a32c86eb31 (9 changesets remaining, ~3 tests)
+ 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bisect -s # -> update to rev 10
+ Testing changeset 10:429fcd26f52d (9 changesets remaining, ~3 tests)
+ 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bisect -b # -> update to rev 8
+ Testing changeset 8:dab8161ac8fc (3 changesets remaining, ~1 tests)
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bisect -g # -> update to rev 9
+ Testing changeset 9:3c77083deb4a (2 changesets remaining, ~1 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -b
+ The first bad revision is:
+ changeset: 9:3c77083deb4a
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: 9
+
+ $ hg log -q -r 'bisect(range)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+ 18:d42e18c7bc9b
+ $ hg log -q -r 'bisect(untested)'
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ $ hg log -q -r 'bisect(goods)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 8:dab8161ac8fc
+ $ hg log -q -r 'bisect(bads)'
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+ 18:d42e18c7bc9b
+
+complex bisect test 2 # first good rev is 13
+
+ $ hg bisect -r
+ $ hg bisect -g 18
+ $ hg bisect -b 1 # -> update to rev 6
+ Testing changeset 6:a214d5d3811a (13 changesets remaining, ~3 tests)
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bisect -s # -> update to rev 10
+ Testing changeset 10:429fcd26f52d (13 changesets remaining, ~3 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 6:a214d5d3811a
+ 18:d42e18c7bc9b
+ $ hg bisect -b # -> update to rev 12
+ Testing changeset 12:9f259202bbe7 (5 changesets remaining, ~2 tests)
+ 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 18:d42e18c7bc9b
+ $ hg log -q -r 'bisect(untested)'
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ $ hg bisect -b # -> update to rev 13
+ Testing changeset 13:b0a32c86eb31 (3 changesets remaining, ~1 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -g
+ The first good revision is:
+ changeset: 13:b0a32c86eb31
+ user: test
+ date: Thu Jan 01 00:00:13 1970 +0000
+ summary: 13
+
+ $ hg log -q -r 'bisect(range)'
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 18:d42e18c7bc9b
+
+complex bisect test 3
+
+first bad rev is 15
+10,9,13 are skipped an might be the first bad revisions as well
+
+ $ hg bisect -r
+ $ hg bisect -g 1
+ $ hg bisect -b 16 # -> update to rev 6
+ Testing changeset 6:a214d5d3811a (13 changesets remaining, ~3 tests)
+ 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 16:609d82a7ebae
+ 17:228c06deef46
+ $ hg bisect -g # -> update to rev 13
+ Testing changeset 13:b0a32c86eb31 (8 changesets remaining, ~3 tests)
+ 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bisect -s # -> update to rev 10
+ Testing changeset 10:429fcd26f52d (8 changesets remaining, ~3 tests)
+ 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bisect -s # -> update to rev 12
+ Testing changeset 12:9f259202bbe7 (8 changesets remaining, ~3 tests)
+ 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 10:429fcd26f52d
+ 13:b0a32c86eb31
+ 16:609d82a7ebae
+ 17:228c06deef46
+ $ hg bisect -g # -> update to rev 9
+ Testing changeset 9:3c77083deb4a (5 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bisect -s # -> update to rev 15
+ Testing changeset 15:857b178a7cf3 (5 changesets remaining, ~2 tests)
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(ignored)'
+ $ hg bisect -b
+ Due to skipped revisions, the first bad revision could be any of:
+ changeset: 9:3c77083deb4a
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: 9
+
+ changeset: 10:429fcd26f52d
+ parent: 9:3c77083deb4a
+ parent: 6:a214d5d3811a
+ user: test
+ date: Thu Jan 01 00:00:10 1970 +0000
+ summary: merge 6,9
+
+ changeset: 13:b0a32c86eb31
+ user: test
+ date: Thu Jan 01 00:00:13 1970 +0000
+ summary: 13
+
+ changeset: 15:857b178a7cf3
+ parent: 13:b0a32c86eb31
+ parent: 10:429fcd26f52d
+ user: test
+ date: Thu Jan 01 00:00:15 1970 +0000
+ summary: merge 10,13
+
+ $ hg log -q -r 'bisect(range)'
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ $ hg log -q -r 'bisect(ignored)'
+
+complex bisect test 4
+
+first good revision is 17
+15,16 are skipped an might be the first good revisions as well
+
+ $ hg bisect -r
+ $ hg bisect -g 17
+ $ hg bisect -b 8 # -> update to rev 10
+ Testing changeset 13:b0a32c86eb31 (8 changesets remaining, ~3 tests)
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bisect -b # -> update to rev 13
+ Testing changeset 10:429fcd26f52d (5 changesets remaining, ~2 tests)
+ 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bisect -b # -> update to rev 15
+ Testing changeset 15:857b178a7cf3 (3 changesets remaining, ~1 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 17:228c06deef46
+ $ hg bisect -s # -> update to rev 16
+ Testing changeset 16:609d82a7ebae (3 changesets remaining, ~1 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 17:228c06deef46
+ $ hg bisect -s
+ Due to skipped revisions, the first good revision could be any of:
+ changeset: 15:857b178a7cf3
+ parent: 13:b0a32c86eb31
+ parent: 10:429fcd26f52d
+ user: test
+ date: Thu Jan 01 00:00:15 1970 +0000
+ summary: merge 10,13
+
+ changeset: 16:609d82a7ebae
+ user: test
+ date: Thu Jan 01 00:00:16 1970 +0000
+ summary: 16
+
+ changeset: 17:228c06deef46
+ user: test
+ date: Thu Jan 01 00:00:17 1970 +0000
+ summary: 17
+
+ $ hg log -q -r 'bisect(range)'
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+
+test unrelated revs:
+
+ $ hg bisect --reset
+ $ hg bisect -b 7
+ $ hg bisect -g 14
+ abort: starting revisions are not directly related
+ [255]
+ $ hg log -q -r 'bisect(range)'
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 7:50c76098bbf2
+ 14:faa450606157
+ $ hg bisect --reset
+
+end at merge: 17 bad, 11 good (but 9 is first bad)
+
+ $ hg bisect -r
+ $ hg bisect -b 17
+ $ hg bisect -g 11
+ Testing changeset 13:b0a32c86eb31 (5 changesets remaining, ~2 tests)
+ 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(ignored)'
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ $ hg bisect -g
+ Testing changeset 15:857b178a7cf3 (3 changesets remaining, ~1 tests)
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bisect -b
+ The first bad revision is:
+ changeset: 15:857b178a7cf3
+ parent: 13:b0a32c86eb31
+ parent: 10:429fcd26f52d
+ user: test
+ date: Thu Jan 01 00:00:15 1970 +0000
+ summary: merge 10,13
+
+ Not all ancestors of this changeset have been checked.
+ Use bisect --extend to continue the bisection from
+ the common ancestor, dab8161ac8fc.
+ $ hg log -q -r 'bisect(range)'
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 8:dab8161ac8fc
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+ 18:d42e18c7bc9b
+ $ hg log -q -r 'bisect(untested)'
+ $ hg log -q -r 'bisect(ignored)'
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ $ hg bisect --extend
+ Extending search to changeset 8:dab8161ac8fc
+ 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(untested)'
+ $ hg log -q -r 'bisect(ignored)'
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ $ hg bisect -g # dab8161ac8fc
+ Testing changeset 9:3c77083deb4a (3 changesets remaining, ~1 tests)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(untested)'
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ $ hg log -q -r 'bisect(ignored)'
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ $ hg log -q -r 'bisect(goods)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 8:dab8161ac8fc
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ $ hg log -q -r 'bisect(bads)'
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+ 18:d42e18c7bc9b
+ $ hg bisect -b
+ The first bad revision is:
+ changeset: 9:3c77083deb4a
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: 9
+
+ $ hg log -q -r 'bisect(range)'
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 8:dab8161ac8fc
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+ 18:d42e18c7bc9b
+ $ hg log -q -r 'bisect(untested)'
+ $ hg log -q -r 'bisect(ignored)'
+ 2:051e12f87bf1
+ 3:0950834f0a9c
+ 4:5c668c22234f
+ 5:385a529b6670
+ 6:a214d5d3811a
+ $ hg log -q -r 'bisect(goods)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 8:dab8161ac8fc
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ $ hg log -q -r 'bisect(bads)'
+ 9:3c77083deb4a
+ 10:429fcd26f52d
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+ 18:d42e18c7bc9b
+
+user adds irrelevant but consistent information (here: -g 2) to bisect state
+
+ $ hg bisect -r
+ $ hg bisect -b 13
+ $ hg bisect -g 8
+ Testing changeset 11:82ca6f06eccd (3 changesets remaining, ~1 tests)
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(untested)'
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ $ hg bisect -g 2
+ Testing changeset 11:82ca6f06eccd (3 changesets remaining, ~1 tests)
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log -q -r 'bisect(untested)'
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ $ hg bisect -b
+ The first bad revision is:
+ changeset: 11:82ca6f06eccd
+ parent: 8:dab8161ac8fc
+ user: test
+ date: Thu Jan 01 00:00:11 1970 +0000
+ summary: 11
+
+ $ hg log -q -r 'bisect(range)'
+ 8:dab8161ac8fc
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ $ hg log -q -r 'bisect(pruned)'
+ 0:33b1f9bc8bc5
+ 1:4ca5088da217
+ 2:051e12f87bf1
+ 8:dab8161ac8fc
+ 11:82ca6f06eccd
+ 12:9f259202bbe7
+ 13:b0a32c86eb31
+ 14:faa450606157
+ 15:857b178a7cf3
+ 16:609d82a7ebae
+ 17:228c06deef46
+ 18:d42e18c7bc9b
+ $ hg log -q -r 'bisect(untested)'
diff --git a/tests/test-bisect3.t b/tests/test-bisect3.t
new file mode 100644
index 0000000..5d62120
--- /dev/null
+++ b/tests/test-bisect3.t
@@ -0,0 +1,232 @@
+# Here we create a simple DAG which has just enough of the required
+# topology to test all the bisection status labels:
+#
+# 13--14
+# /
+# 0--1--2--3---------9--10--11--12
+# \ /
+# 4--5--6--7--8
+
+
+ $ hg init
+
+ $ echo '0' >a
+ $ hg add a
+ $ hg ci -u test -d '0 0' -m '0'
+ $ echo '1' >a
+ $ hg ci -u test -d '1 0' -m '1'
+
+branch 2-3
+
+ $ echo '2' >b
+ $ hg add b
+ $ hg ci -u test -d '2 0' -m '2'
+ $ echo '3' >b
+ $ hg ci -u test -d '3 0' -m '3'
+
+branch 4-8
+
+ $ hg up -r 1
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo '4' >c
+ $ hg add c
+ $ hg ci -u test -d '4 0' -m '4'
+ created new head
+ $ echo '5' >c
+ $ hg ci -u test -d '5 0' -m '5'
+ $ echo '6' >c
+ $ hg ci -u test -d '6 0' -m '6'
+ $ echo '7' >c
+ $ hg ci -u test -d '7 0' -m '7'
+ $ echo '8' >c
+ $ hg ci -u test -d '8 0' -m '8'
+
+merge
+
+ $ hg merge -r 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -u test -d '9 0' -m '9=8+3'
+
+ $ echo '10' >a
+ $ hg ci -u test -d '10 0' -m '10'
+ $ echo '11' >a
+ $ hg ci -u test -d '11 0' -m '11'
+ $ echo '12' >a
+ $ hg ci -u test -d '12 0' -m '12'
+
+unrelated branch
+
+ $ hg up -r 3
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo '13' >d
+ $ hg add d
+ $ hg ci -u test -d '13 0' -m '13'
+ created new head
+ $ echo '14' >d
+ $ hg ci -u test -d '14 0' -m '14'
+
+mark changesets
+
+ $ hg bisect --reset
+ $ hg bisect --good 4
+ $ hg bisect --good 6
+ $ hg bisect --bad 12
+ Testing changeset 9:2197c557e14c (6 changesets remaining, ~2 tests)
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bisect --bad 10
+ Testing changeset 8:e74a86251f58 (4 changesets remaining, ~2 tests)
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bisect --skip 7
+ Testing changeset 8:e74a86251f58 (4 changesets remaining, ~2 tests)
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+test template
+
+ $ hg log --template '{rev}:{node|short} {bisect}\n'
+ 14:cbf2f3105bbf
+ 13:e07efca37c43
+ 12:98c6b56349c0 bad
+ 11:03f491376e63 bad (implicit)
+ 10:c012b15e2409 bad
+ 9:2197c557e14c untested
+ 8:e74a86251f58 untested
+ 7:a5f87041c899 skipped
+ 6:7d997bedcd8d good
+ 5:2dd1875f1028 good (implicit)
+ 4:2a1daef14cd4 good
+ 3:8417d459b90c ignored
+ 2:e1355ee1f23e ignored
+ 1:ce7c85e06a9f good (implicit)
+ 0:b4e73ffab476 good (implicit)
+ $ hg log --template '{bisect|shortbisect} {rev}:{node|short}\n'
+ 14:cbf2f3105bbf
+ 13:e07efca37c43
+ B 12:98c6b56349c0
+ B 11:03f491376e63
+ B 10:c012b15e2409
+ U 9:2197c557e14c
+ U 8:e74a86251f58
+ S 7:a5f87041c899
+ G 6:7d997bedcd8d
+ G 5:2dd1875f1028
+ G 4:2a1daef14cd4
+ I 3:8417d459b90c
+ I 2:e1355ee1f23e
+ G 1:ce7c85e06a9f
+ G 0:b4e73ffab476
+
+test style
+
+ $ hg log --style bisect
+ changeset: 14:cbf2f3105bbf
+ bisect:
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:14 1970 +0000
+ summary: 14
+
+ changeset: 13:e07efca37c43
+ bisect:
+ parent: 3:8417d459b90c
+ user: test
+ date: Thu Jan 01 00:00:13 1970 +0000
+ summary: 13
+
+ changeset: 12:98c6b56349c0
+ bisect: bad
+ user: test
+ date: Thu Jan 01 00:00:12 1970 +0000
+ summary: 12
+
+ changeset: 11:03f491376e63
+ bisect: bad (implicit)
+ user: test
+ date: Thu Jan 01 00:00:11 1970 +0000
+ summary: 11
+
+ changeset: 10:c012b15e2409
+ bisect: bad
+ user: test
+ date: Thu Jan 01 00:00:10 1970 +0000
+ summary: 10
+
+ changeset: 9:2197c557e14c
+ bisect: untested
+ parent: 8:e74a86251f58
+ parent: 3:8417d459b90c
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: 9=8+3
+
+ changeset: 8:e74a86251f58
+ bisect: untested
+ user: test
+ date: Thu Jan 01 00:00:08 1970 +0000
+ summary: 8
+
+ changeset: 7:a5f87041c899
+ bisect: skipped
+ user: test
+ date: Thu Jan 01 00:00:07 1970 +0000
+ summary: 7
+
+ changeset: 6:7d997bedcd8d
+ bisect: good
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: 6
+
+ changeset: 5:2dd1875f1028
+ bisect: good (implicit)
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ summary: 5
+
+ changeset: 4:2a1daef14cd4
+ bisect: good
+ parent: 1:ce7c85e06a9f
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: 4
+
+ changeset: 3:8417d459b90c
+ bisect: ignored
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: 3
+
+ changeset: 2:e1355ee1f23e
+ bisect: ignored
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: 2
+
+ changeset: 1:ce7c85e06a9f
+ bisect: good (implicit)
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: 1
+
+ changeset: 0:b4e73ffab476
+ bisect: good (implicit)
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ $ hg log --quiet --style bisect
+ 14:cbf2f3105bbf
+ 13:e07efca37c43
+ B 12:98c6b56349c0
+ B 11:03f491376e63
+ B 10:c012b15e2409
+ U 9:2197c557e14c
+ U 8:e74a86251f58
+ S 7:a5f87041c899
+ G 6:7d997bedcd8d
+ G 5:2dd1875f1028
+ G 4:2a1daef14cd4
+ I 3:8417d459b90c
+ I 2:e1355ee1f23e
+ G 1:ce7c85e06a9f
+ G 0:b4e73ffab476
diff --git a/tests/test-bookmarks-current.t b/tests/test-bookmarks-current.t
new file mode 100644
index 0000000..cc31c3e
--- /dev/null
+++ b/tests/test-bookmarks-current.t
@@ -0,0 +1,170 @@
+ $ hg init
+
+no bookmarks
+
+ $ hg bookmarks
+ no bookmarks set
+
+set bookmark X
+
+ $ hg bookmark X
+
+list bookmarks
+
+ $ hg bookmark
+ * X -1:000000000000
+
+list bookmarks with color
+
+ $ hg --config extensions.color= --config color.mode=ansi \
+ > bookmark --color=always
+ \x1b[0;32m * X -1:000000000000\x1b[0m (esc)
+
+update to bookmark X
+
+ $ hg update X
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+list bookmarks
+
+ $ hg bookmarks
+ * X -1:000000000000
+
+rename
+
+ $ hg bookmark -m X Z
+
+list bookmarks
+
+ $ cat .hg/bookmarks.current
+ Z (no-eol)
+ $ cat .hg/bookmarks
+ 0000000000000000000000000000000000000000 Z
+ $ hg bookmarks
+ * Z -1:000000000000
+
+new bookmark Y
+
+ $ hg bookmark Y
+
+list bookmarks
+
+ $ hg bookmark
+ * Y -1:000000000000
+ Z -1:000000000000
+
+commit
+
+ $ echo 'b' > b
+ $ hg add b
+ $ hg commit -m'test'
+
+list bookmarks
+
+ $ hg bookmark
+ * Y 0:719295282060
+ Z -1:000000000000
+
+Verify that switching to Z updates the current bookmark:
+ $ hg update Z
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bookmark
+ Y 0:719295282060
+ * Z -1:000000000000
+
+Switch back to Y for the remaining tests in this file:
+ $ hg update Y
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+delete bookmarks
+
+ $ hg bookmark -d Y
+ $ hg bookmark -d Z
+
+list bookmarks
+
+ $ hg bookmark
+ no bookmarks set
+
+update to tip
+
+ $ hg update tip
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+set bookmark Y using -r .
+
+ $ hg bookmark -r . Y
+
+list bookmarks
+
+ $ hg bookmark
+ * Y 0:719295282060
+
+set bookmark Z using -i
+
+ $ hg bookmark -r . -i Z
+ $ hg bookmarks
+ * Y 0:719295282060
+ Z 0:719295282060
+
+deactivate current bookmark using -i
+
+ $ hg bookmark -i Y
+ $ hg bookmarks
+ Y 0:719295282060
+ Z 0:719295282060
+
+ $ hg up -q Y
+ $ hg bookmarks
+ * Y 0:719295282060
+ Z 0:719295282060
+
+deactivate current bookmark while renaming
+
+ $ hg bookmark -i -m Y X
+ $ hg bookmarks
+ X 0:719295282060
+ Z 0:719295282060
+
+bare update moves the active bookmark forward
+
+ $ echo a > a
+ $ hg ci -Am1
+ adding a
+ $ hg update X
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bookmarks
+ * X 0:719295282060
+ Z 0:719295282060
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ updating bookmark X
+ $ hg bookmarks
+ * X 1:cc586d725fbe
+ Z 0:719295282060
+
+test deleting .hg/bookmarks.current when explicitly updating
+to a revision
+
+ $ echo a >> b
+ $ hg ci -m.
+ $ hg up -q X
+ $ test -f .hg/bookmarks.current
+
+try to update to it again to make sure we don't
+set and then unset it
+
+ $ hg up -q X
+ $ test -f .hg/bookmarks.current
+
+ $ hg up -q 1
+ $ test -f .hg/bookmarks.current
+ [1]
+
+when a bookmark is active, hg up -r . is
+analogus to hg book -i <active bookmark>
+
+ $ hg up -q X
+ $ hg up -q .
+ $ test -f .hg/bookmarks.current
+ [1]
diff --git a/tests/test-bookmarks-merge.t b/tests/test-bookmarks-merge.t
new file mode 100644
index 0000000..96ed2c9
--- /dev/null
+++ b/tests/test-bookmarks-merge.t
@@ -0,0 +1,93 @@
+# init
+
+ $ hg init
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m'a'
+ $ echo b > b
+ $ hg add b
+ $ hg commit -m'b'
+ $ hg up -C 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo c > c
+ $ hg add c
+ $ hg commit -m'c'
+ created new head
+
+# test merging of diverged bookmarks
+ $ hg bookmark -r 1 "c@diverge"
+ $ hg bookmark -r 1 b
+ $ hg bookmark c
+ $ hg bookmarks
+ b 1:d2ae7f538514
+ * c 2:d36c0562f908
+ c@diverge 1:d2ae7f538514
+ $ hg merge "c@diverge"
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -m'merge'
+ $ hg bookmarks
+ b 1:d2ae7f538514
+ * c 3:b8f96cf4688b
+
+ $ hg up -C 3
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo d > d
+ $ hg add d
+ $ hg commit -m'd'
+
+ $ hg up -C 3
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo e > e
+ $ hg add e
+ $ hg commit -m'e'
+ created new head
+ $ hg up -C 5
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bookmark e
+ $ hg bookmarks
+ b 1:d2ae7f538514
+ c 3:b8f96cf4688b
+ * e 5:26bee9c5bcf3
+
+# the picked side is bookmarked
+
+ $ hg up -C 4
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge
+ abort: heads are bookmarked - please merge with an explicit rev
+ (run 'hg heads' to see all heads)
+ [255]
+
+# our revision is bookmarked
+
+ $ hg up -C e
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge
+ abort: no matching bookmark to merge - please merge with an explicit rev or bookmark
+ (run 'hg heads' to see all heads)
+ [255]
+
+# merge bookmark heads
+
+ $ hg up -C 4
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo f > f
+ $ hg commit -Am "f"
+ adding f
+ $ hg up -C e
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg bookmarks -r 4 "e@diverged"
+ $ hg bookmarks
+ b 1:d2ae7f538514
+ c 3:b8f96cf4688b
+ * e 5:26bee9c5bcf3
+ e@diverged 4:a0546fcfe0fb
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -m'merge'
+ $ hg bookmarks
+ b 1:d2ae7f538514
+ c 3:b8f96cf4688b
+ * e 7:ca784329f0ba
diff --git a/tests/test-bookmarks-pushpull.t b/tests/test-bookmarks-pushpull.t
new file mode 100644
index 0000000..b62ca47
--- /dev/null
+++ b/tests/test-bookmarks-pushpull.t
@@ -0,0 +1,298 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+initialize
+
+ $ hg init a
+ $ cd a
+ $ echo 'test' > test
+ $ hg commit -Am'test'
+ adding test
+
+set bookmarks
+
+ $ hg bookmark X
+ $ hg bookmark Y
+ $ hg bookmark Z
+
+import bookmark by name
+
+ $ hg init ../b
+ $ cd ../b
+ $ hg book Y
+ $ hg book
+ * Y -1:000000000000
+ $ hg pull ../a
+ pulling from ../a
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating bookmark Y
+ adding remote bookmark X
+ adding remote bookmark Z
+ (run 'hg update' to get a working copy)
+ $ hg bookmarks
+ X 0:4e3505fd9583
+ Y 0:4e3505fd9583
+ Z 0:4e3505fd9583
+ $ hg debugpushkey ../a namespaces
+ bookmarks
+ phases
+ namespaces
+ $ hg debugpushkey ../a bookmarks
+ Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
+ X 4e3505fd95835d721066b76e75dbb8cc554d7f77
+ Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
+ $ hg pull -B X ../a
+ pulling from ../a
+ no changes found
+ importing bookmark X
+ $ hg bookmark
+ X 0:4e3505fd9583
+ Y 0:4e3505fd9583
+ Z 0:4e3505fd9583
+
+export bookmark by name
+
+ $ hg bookmark W
+ $ hg bookmark foo
+ $ hg bookmark foobar
+ $ hg push -B W ../a
+ pushing to ../a
+ searching for changes
+ no changes found
+ exporting bookmark W
+ [1]
+ $ hg -R ../a bookmarks
+ W -1:000000000000
+ X 0:4e3505fd9583
+ Y 0:4e3505fd9583
+ * Z 0:4e3505fd9583
+
+delete a remote bookmark
+
+ $ hg book -d W
+ $ hg push -B W ../a
+ pushing to ../a
+ searching for changes
+ no changes found
+ deleting remote bookmark W
+ [1]
+
+push/pull name that doesn't exist
+
+ $ hg push -B badname ../a
+ pushing to ../a
+ searching for changes
+ no changes found
+ bookmark badname does not exist on the local or remote repository!
+ [2]
+ $ hg pull -B anotherbadname ../a
+ pulling from ../a
+ abort: remote bookmark anotherbadname not found!
+ [255]
+
+divergent bookmarks
+
+ $ cd ../a
+ $ echo c1 > f1
+ $ hg ci -Am1
+ adding f1
+ $ hg book -f X
+ $ hg book
+ * X 1:0d2164f0ce0d
+ Y 0:4e3505fd9583
+ Z 1:0d2164f0ce0d
+
+ $ cd ../b
+ $ hg up
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ updating bookmark foobar
+ $ echo c2 > f2
+ $ hg ci -Am2
+ adding f2
+ $ hg book -f X
+ $ hg book
+ * X 1:9b140be10808
+ Y 0:4e3505fd9583
+ Z 0:4e3505fd9583
+ foo -1:000000000000
+ foobar 1:9b140be10808
+
+ $ hg pull --config paths.foo=../a foo
+ pulling from $TESTTMP/a (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ divergent bookmark X stored as X@foo
+ updating bookmark Z
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg book
+ * X 1:9b140be10808
+ X@foo 2:0d2164f0ce0d
+ Y 0:4e3505fd9583
+ Z 2:0d2164f0ce0d
+ foo -1:000000000000
+ foobar 1:9b140be10808
+ $ hg push -f ../a
+ pushing to ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ $ hg -R ../a book
+ * X 1:0d2164f0ce0d
+ Y 0:4e3505fd9583
+ Z 1:0d2164f0ce0d
+
+update a remote bookmark from a non-head to a head
+
+ $ hg up -q Y
+ $ echo c3 > f2
+ $ hg ci -Am3
+ adding f2
+ created new head
+ $ hg push ../a
+ pushing to ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ updating bookmark Y
+ $ hg -R ../a book
+ * X 1:0d2164f0ce0d
+ Y 3:f6fc62dde3c0
+ Z 1:0d2164f0ce0d
+
+diverging a remote bookmark fails
+
+ $ hg up -q 4e3505fd9583
+ $ echo c4 > f2
+ $ hg ci -Am4
+ adding f2
+ created new head
+ $ hg book -f Y
+
+ $ cat <<EOF > ../a/.hg/hgrc
+ > [web]
+ > push_ssl = false
+ > allow_push = *
+ > EOF
+
+ $ hg -R ../a serve -p $HGPORT2 -d --pid-file=../hg2.pid
+ $ cat ../hg2.pid >> $DAEMON_PIDS
+
+ $ hg push http://localhost:$HGPORT2/
+ pushing to http://localhost:$HGPORT2/
+ searching for changes
+ abort: push creates new remote head 4efff6d98829!
+ (did you forget to merge? use push -f to force)
+ [255]
+ $ hg -R ../a book
+ * X 1:0d2164f0ce0d
+ Y 3:f6fc62dde3c0
+ Z 1:0d2164f0ce0d
+
+hgweb
+
+ $ cat <<EOF > .hg/hgrc
+ > [web]
+ > push_ssl = false
+ > allow_push = *
+ > EOF
+
+ $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
+ $ cat ../hg.pid >> $DAEMON_PIDS
+ $ cd ../a
+
+ $ hg debugpushkey http://localhost:$HGPORT/ namespaces
+ bookmarks
+ phases
+ namespaces
+ $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
+ Y 4efff6d98829d9c824c621afd6e3f01865f5439f
+ foobar 9b140be1080824d768c5a4691a564088eede71f9
+ Z 0d2164f0ce0d8f1d6f94351eba04b794909be66c
+ foo 0000000000000000000000000000000000000000
+ X 9b140be1080824d768c5a4691a564088eede71f9
+ $ hg out -B http://localhost:$HGPORT/
+ comparing with http://localhost:$HGPORT/
+ searching for changed bookmarks
+ no changed bookmarks found
+ [1]
+ $ hg push -B Z http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ exporting bookmark Z
+ [1]
+ $ hg book -d Z
+ $ hg in -B http://localhost:$HGPORT/
+ comparing with http://localhost:$HGPORT/
+ searching for changed bookmarks
+ Z 0d2164f0ce0d
+ foo 000000000000
+ foobar 9b140be10808
+ $ hg pull -B Z http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ no changes found
+ adding remote bookmark foobar
+ adding remote bookmark Z
+ adding remote bookmark foo
+ divergent bookmark X stored as X@1
+ importing bookmark Z
+ $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 5 changes to 3 files (+3 heads)
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R cloned-bookmarks bookmarks
+ X 1:9b140be10808
+ Y 4:4efff6d98829
+ Z 2:0d2164f0ce0d
+ foo -1:000000000000
+ foobar 1:9b140be10808
+
+ $ cd ..
+
+Pushing a bookmark should only push the changes required by that
+bookmark, not all outgoing changes:
+ $ hg clone http://localhost:$HGPORT/ addmarks
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 5 changes to 3 files (+3 heads)
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd addmarks
+ $ echo foo > foo
+ $ hg add foo
+ $ hg commit -m 'add foo'
+ $ echo bar > bar
+ $ hg add bar
+ $ hg commit -m 'add bar'
+ $ hg co "tip^"
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg book add-foo
+ $ hg book -r tip add-bar
+Note: this push *must* push only a single changeset, as that's the point
+of this test.
+ $ hg push -B add-foo
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ exporting bookmark add-foo
+
+ $ cd ..
diff --git a/tests/test-bookmarks-rebase.t b/tests/test-bookmarks-rebase.t
new file mode 100644
index 0000000..1b89620
--- /dev/null
+++ b/tests/test-bookmarks-rebase.t
@@ -0,0 +1,66 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "rebase=" >> $HGRCPATH
+
+initialize repository
+
+ $ hg init
+
+ $ echo 'a' > a
+ $ hg ci -A -m "0"
+ adding a
+
+ $ echo 'b' > b
+ $ hg ci -A -m "1"
+ adding b
+
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo 'c' > c
+ $ hg ci -A -m "2"
+ adding c
+ created new head
+
+ $ echo 'd' > d
+ $ hg ci -A -m "3"
+ adding d
+
+ $ hg bookmark -r 1 one
+ $ hg bookmark -r 3 two
+
+bookmark list
+
+ $ hg bookmark
+ one 1:925d80f479bb
+ * two 3:2ae46b1d99a7
+
+rebase
+
+ $ hg rebase -s two -d one
+ saved backup bundle to $TESTTMP/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg log
+ changeset: 3:42e5ed2cdcf4
+ bookmark: two
+ tag: tip
+ parent: 1:925d80f479bb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3
+
+ changeset: 2:db815d6d32e6
+ parent: 0:f7b1eb17ad24
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 1:925d80f479bb
+ bookmark: one
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ changeset: 0:f7b1eb17ad24
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
diff --git a/tests/test-bookmarks-strip.t b/tests/test-bookmarks-strip.t
new file mode 100644
index 0000000..3c46d76
--- /dev/null
+++ b/tests/test-bookmarks-strip.t
@@ -0,0 +1,116 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init
+
+ $ echo qqq>qqq.txt
+
+rollback dry run without rollback information
+
+ $ hg rollback
+ no rollback information available
+ [1]
+
+add file
+
+ $ hg add
+ adding qqq.txt
+
+commit first revision
+
+ $ hg ci -m 1
+
+set bookmark
+
+ $ hg book test
+
+ $ echo www>>qqq.txt
+
+commit second revision
+
+ $ hg ci -m 2
+
+set bookmark
+
+ $ hg book test2
+
+update to -2 (inactives the active bookmark)
+
+ $ hg update -r -2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo eee>>qqq.txt
+
+commit new head
+
+ $ hg ci -m 3
+ created new head
+
+bookmarks updated?
+
+ $ hg book
+ test 1:25e1ee7a0081
+ test2 1:25e1ee7a0081
+
+strip to revision 1
+
+ $ hg strip 1
+ saved backup bundle to $TESTTMP/.hg/strip-backup/*-backup.hg (glob)
+
+list bookmarks
+
+ $ hg book
+ test 0:5c9ad3787638
+ test2 0:5c9ad3787638
+
+immediate rollback and reentrancy issue
+
+ $ echo "mq=!" >> $HGRCPATH
+ $ hg init repo
+ $ cd repo
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ echo b > b
+ $ hg ci -Am addb
+ adding b
+ $ hg bookmarks markb
+ $ hg rollback
+ repository tip rolled back to revision 0 (undo commit)
+ working directory now based on revision 0
+
+are you there?
+
+ $ hg bookmarks
+ no bookmarks set
+
+can we commit? (issue2692)
+
+ $ echo c > c
+ $ hg ci -Am rockon
+ adding c
+
+can you be added again?
+
+ $ hg bookmarks markb
+ $ hg bookmarks
+ * markb 1:fdb34407462c
+
+rollback dry run with rollback information
+
+ $ hg rollback -n
+ repository tip rolled back to revision 0 (undo commit)
+ $ hg bookmarks
+ * markb 1:fdb34407462c
+
+rollback dry run with rollback information and no commit undo
+
+ $ rm .hg/store/undo
+ $ hg rollback -n
+ no rollback information available
+ [1]
+ $ hg bookmarks
+ * markb 1:fdb34407462c
+
+ $ cd ..
+
diff --git a/tests/test-bookmarks.t b/tests/test-bookmarks.t
new file mode 100644
index 0000000..8b8d062
--- /dev/null
+++ b/tests/test-bookmarks.t
@@ -0,0 +1,459 @@
+ $ hg init
+
+no bookmarks
+
+ $ hg bookmarks
+ no bookmarks set
+
+bookmark rev -1
+
+ $ hg bookmark X
+
+list bookmarks
+
+ $ hg bookmarks
+ * X -1:000000000000
+
+list bookmarks with color
+
+ $ hg --config extensions.color= --config color.mode=ansi \
+ > bookmarks --color=always
+ \x1b[0;32m * X -1:000000000000\x1b[0m (esc)
+
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m 0
+
+bookmark X moved to rev 0
+
+ $ hg bookmarks
+ * X 0:f7b1eb17ad24
+
+look up bookmark
+
+ $ hg log -r X
+ changeset: 0:f7b1eb17ad24
+ bookmark: X
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+
+second bookmark for rev 0
+
+ $ hg bookmark X2
+
+bookmark rev -1 again
+
+ $ hg bookmark -r null Y
+
+list bookmarks
+
+ $ hg bookmarks
+ X 0:f7b1eb17ad24
+ * X2 0:f7b1eb17ad24
+ Y -1:000000000000
+
+ $ echo b > b
+ $ hg add b
+ $ hg commit -m 1
+
+bookmarks revset
+
+ $ hg log -r 'bookmark()'
+ changeset: 0:f7b1eb17ad24
+ bookmark: X
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ changeset: 1:925d80f479bb
+ bookmark: X2
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ $ hg log -r 'bookmark(Y)'
+ $ hg log -r 'bookmark(X2)'
+ changeset: 1:925d80f479bb
+ bookmark: X2
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ $ hg log -r 'bookmark("re:X")'
+ changeset: 0:f7b1eb17ad24
+ bookmark: X
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ changeset: 1:925d80f479bb
+ bookmark: X2
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ $ hg log -r 'bookmark(unknown)'
+ abort: bookmark 'unknown' does not exist
+ [255]
+
+ $ hg help revsets | grep 'bookmark('
+ "bookmark([name])"
+
+bookmarks X and X2 moved to rev 1, Y at rev -1
+
+ $ hg bookmarks
+ X 0:f7b1eb17ad24
+ * X2 1:925d80f479bb
+ Y -1:000000000000
+
+bookmark rev 0 again
+
+ $ hg bookmark -r 0 Z
+
+ $ hg update X
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo c > c
+ $ hg add c
+ $ hg commit -m 2
+ created new head
+
+bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
+
+ $ hg bookmarks
+ * X 2:db815d6d32e6
+ X2 1:925d80f479bb
+ Y -1:000000000000
+ Z 0:f7b1eb17ad24
+
+rename nonexistent bookmark
+
+ $ hg bookmark -m A B
+ abort: bookmark 'A' does not exist
+ [255]
+
+rename to existent bookmark
+
+ $ hg bookmark -m X Y
+ abort: bookmark 'Y' already exists (use -f to force)
+ [255]
+
+force rename to existent bookmark
+
+ $ hg bookmark -f -m X Y
+
+list bookmarks
+
+ $ hg bookmark
+ X2 1:925d80f479bb
+ * Y 2:db815d6d32e6
+ Z 0:f7b1eb17ad24
+
+rename without new name
+
+ $ hg bookmark -m Y
+ abort: new bookmark name required
+ [255]
+
+delete without name
+
+ $ hg bookmark -d
+ abort: bookmark name required
+ [255]
+
+delete nonexistent bookmark
+
+ $ hg bookmark -d A
+ abort: bookmark 'A' does not exist
+ [255]
+
+bookmark name with spaces should be stripped
+
+ $ hg bookmark ' x y '
+
+list bookmarks
+
+ $ hg bookmarks
+ X2 1:925d80f479bb
+ Y 2:db815d6d32e6
+ Z 0:f7b1eb17ad24
+ * x y 2:db815d6d32e6
+
+look up stripped bookmark name
+
+ $ hg log -r '"x y"'
+ changeset: 2:db815d6d32e6
+ bookmark: Y
+ bookmark: x y
+ tag: tip
+ parent: 0:f7b1eb17ad24
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+
+reject bookmark name with newline
+
+ $ hg bookmark '
+ > '
+ abort: bookmark name cannot contain newlines
+ [255]
+
+bookmark with existing name
+
+ $ hg bookmark Z
+ abort: bookmark 'Z' already exists (use -f to force)
+ [255]
+
+force bookmark with existing name
+
+ $ hg bookmark -f Z
+
+list bookmarks
+
+ $ hg bookmark
+ X2 1:925d80f479bb
+ Y 2:db815d6d32e6
+ * Z 2:db815d6d32e6
+ x y 2:db815d6d32e6
+
+revision but no bookmark name
+
+ $ hg bookmark -r .
+ abort: bookmark name required
+ [255]
+
+bookmark name with whitespace only
+
+ $ hg bookmark ' '
+ abort: bookmark names cannot consist entirely of whitespace
+ [255]
+
+invalid bookmark
+
+ $ hg bookmark 'foo:bar'
+ abort: bookmark 'foo:bar' contains illegal character
+ [255]
+
+the bookmark extension should be ignored now that it is part of core
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "bookmarks=" >> $HGRCPATH
+ $ hg bookmarks
+ X2 1:925d80f479bb
+ Y 2:db815d6d32e6
+ * Z 2:db815d6d32e6
+ x y 2:db815d6d32e6
+
+test summary
+
+ $ hg summary
+ parent: 2:db815d6d32e6 tip
+ 2
+ branch: default
+ bookmarks: *Z Y x y
+ commit: (clean)
+ update: 1 new changesets, 2 branch heads (merge)
+
+test id
+
+ $ hg id
+ db815d6d32e6 tip Y/Z/x y
+
+test rollback
+
+ $ echo foo > f1
+ $ hg ci -Amr
+ adding f1
+ $ hg bookmark -f Y -r 1
+ $ hg bookmark -f Z -r 1
+ $ hg rollback
+ repository tip rolled back to revision 2 (undo commit)
+ working directory now based on revision 2
+ $ hg bookmarks
+ X2 1:925d80f479bb
+ Y 2:db815d6d32e6
+ * Z 2:db815d6d32e6
+ x y 2:db815d6d32e6
+
+test clone
+
+ $ hg bookmark -r 2 -i @
+ $ hg bookmark -r 2 -i a@
+ $ hg bookmarks
+ @ 2:db815d6d32e6
+ X2 1:925d80f479bb
+ Y 2:db815d6d32e6
+ * Z 2:db815d6d32e6
+ a@ 2:db815d6d32e6
+ x y 2:db815d6d32e6
+ $ hg clone . cloned-bookmarks
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R cloned-bookmarks bookmarks
+ @ 2:db815d6d32e6
+ X2 1:925d80f479bb
+ Y 2:db815d6d32e6
+ Z 2:db815d6d32e6
+ a@ 2:db815d6d32e6
+ x y 2:db815d6d32e6
+
+test clone with pull protocol
+
+ $ hg clone --pull . cloned-bookmarks-pull
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 3 files (+1 heads)
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R cloned-bookmarks-pull bookmarks
+ @ 2:db815d6d32e6
+ X2 1:925d80f479bb
+ Y 2:db815d6d32e6
+ Z 2:db815d6d32e6
+ a@ 2:db815d6d32e6
+ x y 2:db815d6d32e6
+
+ $ hg bookmark -d @
+ $ hg bookmark -d a@
+
+test clone with a specific revision
+
+ $ hg clone -r 925d80 . cloned-bookmarks-rev
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R cloned-bookmarks-rev bookmarks
+ X2 1:925d80f479bb
+
+create bundle with two heads
+
+ $ hg clone . tobundle
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo x > tobundle/x
+ $ hg -R tobundle add tobundle/x
+ $ hg -R tobundle commit -m'x'
+ $ hg -R tobundle update -r -2
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo y > tobundle/y
+ $ hg -R tobundle branch test
+ marked working directory as branch test
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg -R tobundle add tobundle/y
+ $ hg -R tobundle commit -m'y'
+ $ hg -R tobundle bundle tobundle.hg
+ searching for changes
+ 2 changesets found
+ $ hg unbundle tobundle.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg bookmarks
+ X2 1:925d80f479bb
+ Y 2:db815d6d32e6
+ * Z 3:125c9a1d6df6
+ x y 2:db815d6d32e6
+
+test wrongly formated bookmark
+
+ $ echo '' >> .hg/bookmarks
+ $ hg bookmarks
+ X2 1:925d80f479bb
+ Y 2:db815d6d32e6
+ * Z 3:125c9a1d6df6
+ x y 2:db815d6d32e6
+ $ echo "Ican'thasformatedlines" >> .hg/bookmarks
+ $ hg bookmarks
+ malformed line in .hg/bookmarks: "Ican'thasformatedlines"
+ X2 1:925d80f479bb
+ Y 2:db815d6d32e6
+ * Z 3:125c9a1d6df6
+ x y 2:db815d6d32e6
+
+test missing revisions
+
+ $ echo "925d80f479bc z" > .hg/bookmarks
+ $ hg book
+ no bookmarks set
+
+test stripping a non-checked-out but bookmarked revision
+
+ $ hg --config extensions.graphlog= log --graph
+ o changeset: 4:9ba5f110a0b3
+ | branch: test
+ | tag: tip
+ | parent: 2:db815d6d32e6
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: y
+ |
+ | @ changeset: 3:125c9a1d6df6
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: x
+ |
+ o changeset: 2:db815d6d32e6
+ | parent: 0:f7b1eb17ad24
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: 2
+ |
+ | o changeset: 1:925d80f479bb
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: 1
+ |
+ o changeset: 0:f7b1eb17ad24
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ $ hg book should-end-on-two
+ $ hg co --clean 4
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg book four
+ $ hg --config extensions.mq= strip 3
+ saved backup bundle to * (glob)
+should-end-on-two should end up pointing to revision 2, as that's the
+tipmost surviving ancestor of the stripped revision.
+ $ hg --config extensions.graphlog= log --graph
+ @ changeset: 3:9ba5f110a0b3
+ | branch: test
+ | bookmark: four
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: y
+ |
+ o changeset: 2:db815d6d32e6
+ | bookmark: should-end-on-two
+ | parent: 0:f7b1eb17ad24
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: 2
+ |
+ | o changeset: 1:925d80f479bb
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: 1
+ |
+ o changeset: 0:f7b1eb17ad24
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
diff --git a/tests/test-branch-option.t b/tests/test-branch-option.t
new file mode 100644
index 0000000..fa81c33
--- /dev/null
+++ b/tests/test-branch-option.t
@@ -0,0 +1,132 @@
+test branch selection options
+
+ $ hg init branch
+ $ cd branch
+ $ hg branch a
+ marked working directory as branch a
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a > foo
+ $ hg ci -d '0 0' -Ama
+ adding foo
+ $ echo a2 > foo
+ $ hg ci -d '0 0' -ma2
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch c
+ marked working directory as branch c
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo c > foo
+ $ hg ci -d '0 0' -mc
+ $ hg tag -l z
+ $ cd ..
+ $ hg clone -r 0 branch branch2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch a
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd branch2
+ $ hg up 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b > foo
+ $ hg ci -d '0 0' -mb
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --encoding utf-8 branch æ
+ marked working directory as branch \xc3\xa6 (esc)
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo ae1 > foo
+ $ hg ci -d '0 0' -mae1
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --encoding utf-8 branch -f æ
+ marked working directory as branch \xc3\xa6 (esc)
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo ae2 > foo
+ $ hg ci -d '0 0' -mae2
+ created new head
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch -f b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b2 > foo
+ $ hg ci -d '0 0' -mb2
+ created new head
+
+unknown branch and fallback
+
+ $ hg in -qbz
+ abort: unknown branch 'z'!
+ [255]
+ $ hg in -q ../branch#z
+ 2:f25d57ab0566
+ $ hg out -qbz
+ abort: unknown branch 'z'!
+ [255]
+
+in rev c branch a
+
+ $ hg in -qr c ../branch#a
+ 1:dd6e60a716c6
+ 2:f25d57ab0566
+ $ hg in -qr c -b a
+ 1:dd6e60a716c6
+ 2:f25d57ab0566
+
+out branch .
+
+ $ hg out -q ../branch#.
+ 1:b84708d77ab7
+ 4:65511d0e2b55
+ $ hg out -q -b .
+ 1:b84708d77ab7
+ 4:65511d0e2b55
+
+out branch . non-ascii
+
+ $ hg --encoding utf-8 up æ
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --encoding latin1 out -q ../branch#.
+ 2:df5a44224d4e
+ 3:4f4a5125ca10
+ $ hg --encoding latin1 out -q -b .
+ 2:df5a44224d4e
+ 3:4f4a5125ca10
+
+clone branch b
+
+ $ cd ..
+ $ hg clone branch2#b branch3
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files (+1 heads)
+ updating to branch b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -q -R branch3 heads b
+ 2:65511d0e2b55
+ 1:b84708d77ab7
+ $ hg -q -R branch3 parents
+ 2:65511d0e2b55
+ $ rm -rf branch3
+
+clone rev a branch b
+
+ $ hg clone -r a branch2#b branch3
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files (+1 heads)
+ updating to branch a
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -q -R branch3 heads b
+ 2:65511d0e2b55
+ 1:b84708d77ab7
+ $ hg -q -R branch3 parents
+ 0:5b65ba7c951d
+ $ rm -rf branch3
diff --git a/tests/test-branch-tag-confict.t b/tests/test-branch-tag-confict.t
new file mode 100644
index 0000000..0bb6ffa
--- /dev/null
+++ b/tests/test-branch-tag-confict.t
@@ -0,0 +1,65 @@
+Initial setup.
+
+ $ hg init repo
+ $ cd repo
+ $ touch thefile
+ $ hg ci -A -m 'Initial commit.'
+ adding thefile
+
+Create a tag.
+
+ $ hg tag branchortag
+
+Create a branch with the same name as the tag.
+
+ $ hg branch branchortag
+ marked working directory as branch branchortag
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m 'Create a branch with the same name as a tag.'
+
+This is what we have:
+
+ $ hg log
+ changeset: 2:10519b3f489a
+ branch: branchortag
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Create a branch with the same name as a tag.
+
+ changeset: 1:2635c45ca99b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag branchortag for changeset f57387372b5d
+
+ changeset: 0:f57387372b5d
+ tag: branchortag
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Initial commit.
+
+Update to the tag:
+
+ $ hg up 'tag(branchortag)'
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg parents
+ changeset: 0:f57387372b5d
+ tag: branchortag
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Initial commit.
+
+Updating to the branch:
+
+ $ hg up 'branch(branchortag)'
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg parents
+ changeset: 2:10519b3f489a
+ branch: branchortag
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Create a branch with the same name as a tag.
+
+
+ $ cd ..
diff --git a/tests/test-branches.t b/tests/test-branches.t
new file mode 100644
index 0000000..29d9c13
--- /dev/null
+++ b/tests/test-branches.t
@@ -0,0 +1,412 @@
+ $ hg init a
+ $ cd a
+ $ echo 'root' >root
+ $ hg add root
+ $ hg commit -d '0 0' -m "Adding root node"
+
+ $ echo 'a' >a
+ $ hg add a
+ $ hg branch a
+ marked working directory as branch a
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg commit -d '1 0' -m "Adding a branch"
+
+ $ hg branch q
+ marked working directory as branch q
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo 'aa' >a
+ $ hg branch -C
+ reset working directory to branch a
+ $ hg commit -d '2 0' -m "Adding to a branch"
+
+ $ hg update -C 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo 'b' >b
+ $ hg add b
+ $ hg branch b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg commit -d '2 0' -m "Adding b branch"
+
+ $ echo 'bh1' >bh1
+ $ hg add bh1
+ $ hg commit -d '3 0' -m "Adding b branch head 1"
+
+ $ hg update -C 2
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo 'bh2' >bh2
+ $ hg add bh2
+ $ hg commit -d '4 0' -m "Adding b branch head 2"
+
+ $ echo 'c' >c
+ $ hg add c
+ $ hg branch c
+ marked working directory as branch c
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg commit -d '5 0' -m "Adding c branch"
+
+ $ hg branch tip
+ abort: the name 'tip' is reserved
+ [255]
+ $ hg branch null
+ abort: the name 'null' is reserved
+ [255]
+ $ hg branch .
+ abort: the name '.' is reserved
+ [255]
+
+ $ echo 'd' >d
+ $ hg add d
+ $ hg branch 'a branch name much longer than the default justification used by branches'
+ marked working directory as branch a branch name much longer than the default justification used by branches
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg commit -d '6 0' -m "Adding d branch"
+
+ $ hg branches
+ a branch name much longer than the default justification used by branches 7:10ff5895aa57
+ b 4:aee39cd168d0
+ c 6:589736a22561 (inactive)
+ a 5:d8cbc61dbaa6 (inactive)
+ default 0:19709c5a4e75 (inactive)
+
+-------
+
+ $ hg branches -a
+ a branch name much longer than the default justification used by branches 7:10ff5895aa57
+ b 4:aee39cd168d0
+
+--- Branch a
+
+ $ hg log -b a
+ changeset: 5:d8cbc61dbaa6
+ branch: a
+ parent: 2:881fe2b92ad0
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: Adding b branch head 2
+
+ changeset: 2:881fe2b92ad0
+ branch: a
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: Adding to a branch
+
+ changeset: 1:dd6b440dd85a
+ branch: a
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: Adding a branch
+
+
+---- Branch b
+
+ $ hg log -b b
+ changeset: 4:aee39cd168d0
+ branch: b
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: Adding b branch head 1
+
+ changeset: 3:ac22033332d1
+ branch: b
+ parent: 0:19709c5a4e75
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: Adding b branch
+
+
+---- going to test branch closing
+
+ $ hg branches
+ a branch name much longer than the default justification used by branches 7:10ff5895aa57
+ b 4:aee39cd168d0
+ c 6:589736a22561 (inactive)
+ a 5:d8cbc61dbaa6 (inactive)
+ default 0:19709c5a4e75 (inactive)
+ $ hg up -C b
+ 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
+ $ echo 'xxx1' >> b
+ $ hg commit -d '7 0' -m 'adding cset to branch b'
+ $ hg up -C aee39cd168d0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo 'xxx2' >> b
+ $ hg commit -d '8 0' -m 'adding head to branch b'
+ created new head
+ $ echo 'xxx3' >> b
+ $ hg commit -d '9 0' -m 'adding another cset to branch b'
+ $ hg branches
+ b 10:bfbe841b666e
+ a branch name much longer than the default justification used by branches 7:10ff5895aa57
+ c 6:589736a22561 (inactive)
+ a 5:d8cbc61dbaa6 (inactive)
+ default 0:19709c5a4e75 (inactive)
+ $ hg heads --closed
+ changeset: 10:bfbe841b666e
+ branch: b
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: adding another cset to branch b
+
+ changeset: 8:eebb944467c9
+ branch: b
+ parent: 4:aee39cd168d0
+ user: test
+ date: Thu Jan 01 00:00:07 1970 +0000
+ summary: adding cset to branch b
+
+ changeset: 7:10ff5895aa57
+ branch: a branch name much longer than the default justification used by branches
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: Adding d branch
+
+ changeset: 6:589736a22561
+ branch: c
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ summary: Adding c branch
+
+ changeset: 5:d8cbc61dbaa6
+ branch: a
+ parent: 2:881fe2b92ad0
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: Adding b branch head 2
+
+ changeset: 0:19709c5a4e75
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Adding root node
+
+ $ hg heads
+ changeset: 10:bfbe841b666e
+ branch: b
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: adding another cset to branch b
+
+ changeset: 8:eebb944467c9
+ branch: b
+ parent: 4:aee39cd168d0
+ user: test
+ date: Thu Jan 01 00:00:07 1970 +0000
+ summary: adding cset to branch b
+
+ changeset: 7:10ff5895aa57
+ branch: a branch name much longer than the default justification used by branches
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: Adding d branch
+
+ changeset: 6:589736a22561
+ branch: c
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ summary: Adding c branch
+
+ changeset: 5:d8cbc61dbaa6
+ branch: a
+ parent: 2:881fe2b92ad0
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: Adding b branch head 2
+
+ changeset: 0:19709c5a4e75
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Adding root node
+
+ $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
+ $ hg branches -a
+ b 8:eebb944467c9
+ a branch name much longer than the default justification used by branches 7:10ff5895aa57
+ $ hg up -C b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
+
+--- b branch should be inactive
+
+ $ hg branches
+ a branch name much longer than the default justification used by branches 7:10ff5895aa57
+ c 6:589736a22561 (inactive)
+ a 5:d8cbc61dbaa6 (inactive)
+ default 0:19709c5a4e75 (inactive)
+ $ hg branches -c
+ a branch name much longer than the default justification used by branches 7:10ff5895aa57
+ b 12:e3d49c0575d8 (closed)
+ c 6:589736a22561 (inactive)
+ a 5:d8cbc61dbaa6 (inactive)
+ default 0:19709c5a4e75 (inactive)
+ $ hg branches -a
+ a branch name much longer than the default justification used by branches 7:10ff5895aa57
+ $ hg branches -q
+ a branch name much longer than the default justification used by branches
+ c
+ a
+ default
+ $ hg heads b
+ no open branch heads found on branches b
+ [1]
+ $ hg heads --closed b
+ changeset: 12:e3d49c0575d8
+ branch: b
+ tag: tip
+ parent: 8:eebb944467c9
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: close this part branch too
+
+ changeset: 11:d3f163457ebf
+ branch: b
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: prune bad branch
+
+ $ echo 'xxx4' >> b
+ $ hg commit -d '9 0' -m 'reopen branch with a change'
+ reopening closed branch head 12
+
+--- branch b is back in action
+
+ $ hg branches -a
+ b 13:e23b5505d1ad
+ a branch name much longer than the default justification used by branches 7:10ff5895aa57
+
+---- test heads listings
+
+ $ hg heads
+ changeset: 13:e23b5505d1ad
+ branch: b
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: reopen branch with a change
+
+ changeset: 7:10ff5895aa57
+ branch: a branch name much longer than the default justification used by branches
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: Adding d branch
+
+ changeset: 6:589736a22561
+ branch: c
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ summary: Adding c branch
+
+ changeset: 5:d8cbc61dbaa6
+ branch: a
+ parent: 2:881fe2b92ad0
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: Adding b branch head 2
+
+ changeset: 0:19709c5a4e75
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Adding root node
+
+
+branch default
+
+ $ hg heads default
+ changeset: 0:19709c5a4e75
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Adding root node
+
+
+branch a
+
+ $ hg heads a
+ changeset: 5:d8cbc61dbaa6
+ branch: a
+ parent: 2:881fe2b92ad0
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: Adding b branch head 2
+
+ $ hg heads --active a
+ no open branch heads found on branches a
+ [1]
+
+branch b
+
+ $ hg heads b
+ changeset: 13:e23b5505d1ad
+ branch: b
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: reopen branch with a change
+
+ $ hg heads --closed b
+ changeset: 13:e23b5505d1ad
+ branch: b
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: reopen branch with a change
+
+ changeset: 11:d3f163457ebf
+ branch: b
+ user: test
+ date: Thu Jan 01 00:00:09 1970 +0000
+ summary: prune bad branch
+
+default branch colors:
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "color =" >> $HGRCPATH
+ $ echo "[color]" >> $HGRCPATH
+ $ echo "mode = ansi" >> $HGRCPATH
+
+ $ hg up -C c
+ 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
+ $ hg up -C b
+ 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ hg branches --color=always
+ \x1b[0;32mb\x1b[0m \x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
+ \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m \x1b[0;33m7:10ff5895aa57\x1b[0m (esc)
+ \x1b[0;0ma\x1b[0m \x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
+ \x1b[0;0mdefault\x1b[0m \x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
+
+default closed branch color:
+
+ $ hg branches --color=always --closed
+ \x1b[0;32mb\x1b[0m \x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
+ \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m \x1b[0;33m7:10ff5895aa57\x1b[0m (esc)
+ \x1b[0;30;1mc\x1b[0m \x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
+ \x1b[0;0ma\x1b[0m \x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
+ \x1b[0;0mdefault\x1b[0m \x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "color =" >> $HGRCPATH
+ $ echo "[color]" >> $HGRCPATH
+ $ echo "branches.active = green" >> $HGRCPATH
+ $ echo "branches.closed = blue" >> $HGRCPATH
+ $ echo "branches.current = red" >> $HGRCPATH
+ $ echo "branches.inactive = magenta" >> $HGRCPATH
+ $ echo "log.changeset = cyan" >> $HGRCPATH
+
+custom branch colors:
+
+ $ hg branches --color=always
+ \x1b[0;31mb\x1b[0m \x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
+ \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m \x1b[0;36m7:10ff5895aa57\x1b[0m (esc)
+ \x1b[0;35ma\x1b[0m \x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
+ \x1b[0;35mdefault\x1b[0m \x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
+
+custom closed branch color:
+
+ $ hg branches --color=always --closed
+ \x1b[0;31mb\x1b[0m \x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
+ \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m \x1b[0;36m7:10ff5895aa57\x1b[0m (esc)
+ \x1b[0;34mc\x1b[0m \x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
+ \x1b[0;35ma\x1b[0m \x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
+ \x1b[0;35mdefault\x1b[0m \x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
+
+ $ cd ..
diff --git a/tests/test-bundle-r.t b/tests/test-bundle-r.t
new file mode 100644
index 0000000..ce03f01
--- /dev/null
+++ b/tests/test-bundle-r.t
@@ -0,0 +1,328 @@
+ $ hg init test
+ $ cd test
+ $ hg unbundle "$TESTDIR/bundles/remote.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 7 changes to 4 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+
+ $ for i in 0 1 2 3 4 5 6 7 8; do
+ > mkdir test-"$i"
+ > hg --cwd test-"$i" init
+ > hg -R test bundle -r "$i" test-"$i".hg test-"$i"
+ > cd test-"$i"
+ > hg unbundle ../test-"$i".hg
+ > hg verify
+ > hg tip -q
+ > cd ..
+ > done
+ searching for changes
+ 1 changesets found
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+ 0:bfaf4b5cbf01
+ searching for changes
+ 2 changesets found
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ (run 'hg update' to get a working copy)
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+ 1:21f32785131f
+ searching for changes
+ 3 changesets found
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+ (run 'hg update' to get a working copy)
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+ 2:4ce51a113780
+ searching for changes
+ 4 changesets found
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 1 files
+ (run 'hg update' to get a working copy)
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 4 changesets, 4 total revisions
+ 3:93ee6ab32777
+ searching for changes
+ 2 changesets found
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ (run 'hg update' to get a working copy)
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+ 1:c70afb1ee985
+ searching for changes
+ 3 changesets found
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+ (run 'hg update' to get a working copy)
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+ 2:f03ae5a9b979
+ searching for changes
+ 4 changesets found
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 5 changes to 2 files
+ (run 'hg update' to get a working copy)
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 4 changesets, 5 total revisions
+ 3:095cb14b1b4d
+ searching for changes
+ 5 changesets found
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 6 changes to 3 files
+ (run 'hg update' to get a working copy)
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 5 changesets, 6 total revisions
+ 4:faa2e4234c7a
+ searching for changes
+ 5 changesets found
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 5 changes to 2 files
+ (run 'hg update' to get a working copy)
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 5 changesets, 5 total revisions
+ 4:916f1afdef90
+ $ cd test-8
+ $ hg pull ../test-7
+ pulling from ../test-7
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 2 changes to 3 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 9 changesets, 7 total revisions
+ $ hg rollback
+ repository tip rolled back to revision 4 (undo pull)
+ $ cd ..
+
+should fail
+
+ $ hg -R test bundle --base 2 -r tip test-bundle-branch1.hg test-3
+ abort: --base is incompatible with specifying a destination
+ [255]
+ $ hg -R test bundle -r tip test-bundle-branch1.hg
+ abort: repository default-push not found!
+ [255]
+
+ $ hg -R test bundle --base 2 -r tip test-bundle-branch1.hg
+ 2 changesets found
+ $ hg -R test bundle --base 2 -r 7 test-bundle-branch2.hg
+ 4 changesets found
+ $ hg -R test bundle --base 2 test-bundle-all.hg
+ 6 changesets found
+ $ hg -R test bundle --base 3 -r tip test-bundle-should-fail.hg
+ 1 changesets found
+
+empty bundle
+
+ $ hg -R test bundle --base 7 --base 8 test-bundle-empty.hg
+ no changes found
+ [1]
+
+issue76 msg2163
+
+ $ hg -R test bundle --base 3 -r 3 -r 3 test-bundle-cset-3.hg
+ no changes found
+ [1]
+
+Issue1910: 'hg bundle --base $head' does not exclude $head from
+result
+
+ $ hg -R test bundle --base 7 test-bundle-cset-7.hg
+ 4 changesets found
+
+ $ hg clone test-2 test-9
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd test-9
+
+revision 2
+
+ $ hg tip -q
+ 2:4ce51a113780
+ $ hg unbundle ../test-bundle-should-fail.hg
+ adding changesets
+ transaction abort!
+ rollback completed
+ abort: 00changelog.i@93ee6ab32777: unknown parent!
+ [255]
+
+revision 2
+
+ $ hg tip -q
+ 2:4ce51a113780
+ $ hg unbundle ../test-bundle-all.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 4 changes to 4 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+revision 8
+
+ $ hg tip -q
+ 8:916f1afdef90
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 9 changesets, 7 total revisions
+ $ hg rollback
+ repository tip rolled back to revision 2 (undo unbundle)
+
+revision 2
+
+ $ hg tip -q
+ 2:4ce51a113780
+ $ hg unbundle ../test-bundle-branch1.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ (run 'hg update' to get a working copy)
+
+revision 4
+
+ $ hg tip -q
+ 4:916f1afdef90
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 5 changesets, 5 total revisions
+ $ hg rollback
+ repository tip rolled back to revision 2 (undo unbundle)
+ $ hg unbundle ../test-bundle-branch2.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 3 changes to 3 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+revision 6
+
+ $ hg tip -q
+ 6:faa2e4234c7a
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 7 changesets, 6 total revisions
+ $ hg rollback
+ repository tip rolled back to revision 2 (undo unbundle)
+ $ hg unbundle ../test-bundle-cset-7.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ (run 'hg update' to get a working copy)
+
+revision 4
+
+ $ hg tip -q
+ 4:916f1afdef90
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 5 changesets, 5 total revisions
+
+ $ cd ../test
+ $ hg merge 7
+ note: possible conflict - afile was renamed multiple times to:
+ anotherfile
+ adifferentfile
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m merge
+ $ cd ..
+ $ hg -R test bundle --base 2 test-bundle-head.hg
+ 7 changesets found
+ $ hg clone test-2 test-10
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd test-10
+ $ hg unbundle ../test-bundle-head.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 7 changesets with 4 changes to 4 files
+ (run 'hg update' to get a working copy)
+
+revision 9
+
+ $ hg tip -q
+ 9:03fc0b0e347c
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 10 changesets, 7 total revisions
+
+ $ cd ..
diff --git a/tests/test-bundle-type.t b/tests/test-bundle-type.t
new file mode 100644
index 0000000..5b8fc24
--- /dev/null
+++ b/tests/test-bundle-type.t
@@ -0,0 +1,100 @@
+bundle w/o type option
+
+ $ hg init t1
+ $ hg init t2
+ $ cd t1
+ $ echo blablablablabla > file.txt
+ $ hg ci -Ama
+ adding file.txt
+ $ hg log | grep summary
+ summary: a
+ $ hg bundle ../b1 ../t2
+ searching for changes
+ 1 changesets found
+
+ $ cd ../t2
+ $ hg pull ../b1
+ pulling from ../b1
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log | grep summary
+ summary: a
+ $ cd ..
+
+test bundle types
+
+ $ for t in "None" "bzip2" "gzip"; do
+ > echo % test bundle type $t
+ > hg init t$t
+ > cd t1
+ > hg bundle -t $t ../b$t ../t$t
+ > cut -b 1-6 ../b$t | head -n 1
+ > cd ../t$t
+ > hg pull ../b$t
+ > hg up
+ > hg log | grep summary
+ > cd ..
+ > done
+ % test bundle type None
+ searching for changes
+ 1 changesets found
+ HG10UN
+ pulling from ../bNone
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ summary: a
+ % test bundle type bzip2
+ searching for changes
+ 1 changesets found
+ HG10BZ
+ pulling from ../bbzip2
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ summary: a
+ % test bundle type gzip
+ searching for changes
+ 1 changesets found
+ HG10GZ
+ pulling from ../bgzip
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ summary: a
+
+test garbage file
+
+ $ echo garbage > bgarbage
+ $ hg init tgarbage
+ $ cd tgarbage
+ $ hg pull ../bgarbage
+ abort: ../bgarbage: not a Mercurial bundle
+ [255]
+ $ cd ..
+
+test invalid bundle type
+
+ $ cd t1
+ $ hg bundle -a -t garbage ../bgarbage
+ abort: unknown bundle type specified with --type
+ [255]
+ $ cd ..
diff --git a/tests/test-bundle-vs-outgoing.t b/tests/test-bundle-vs-outgoing.t
new file mode 100644
index 0000000..f4bab19
--- /dev/null
+++ b/tests/test-bundle-vs-outgoing.t
@@ -0,0 +1,145 @@
+this structure seems to tickle a bug in bundle's search for
+changesets, so first we have to recreate it
+
+o 8
+|
+| o 7
+| |
+| o 6
+|/|
+o | 5
+| |
+o | 4
+| |
+| o 3
+| |
+| o 2
+|/
+o 1
+|
+o 0
+
+ $ mkrev()
+ > {
+ > revno=$1
+ > echo "rev $revno"
+ > echo "rev $revno" > foo.txt
+ > hg -q ci -m"rev $revno"
+ > }
+
+setup test repo1
+
+ $ hg init repo1
+ $ cd repo1
+ $ echo "rev 0" > foo.txt
+ $ hg ci -Am"rev 0"
+ adding foo.txt
+ $ mkrev 1
+ rev 1
+
+first branch
+
+ $ mkrev 2
+ rev 2
+ $ mkrev 3
+ rev 3
+
+back to rev 1 to create second branch
+
+ $ hg up -r1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mkrev 4
+ rev 4
+ $ mkrev 5
+ rev 5
+
+merge first branch to second branch
+
+ $ hg up -C -r5
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ HGMERGE=internal:local hg merge
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ echo "merge rev 5, rev 3" > foo.txt
+ $ hg ci -m"merge first branch to second branch"
+
+one more commit following the merge
+
+ $ mkrev 7
+ rev 7
+
+back to "second branch" to make another head
+
+ $ hg up -r5
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mkrev 8
+ rev 8
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "graphlog=" >> $HGRCPATH
+
+the story so far
+
+ $ hg glog --template "{rev}\n"
+ @ 8
+ |
+ | o 7
+ | |
+ | o 6
+ |/|
+ o | 5
+ | |
+ o | 4
+ | |
+ | o 3
+ | |
+ | o 2
+ |/
+ o 1
+ |
+ o 0
+
+
+check that "hg outgoing" really does the right thing
+
+sanity check of outgoing: expect revs 4 5 6 7 8
+
+ $ hg clone -r3 . ../repo2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+this should (and does) report 5 outgoing revisions: 4 5 6 7 8
+
+ $ hg outgoing --template "{rev}\n" ../repo2
+ comparing with ../repo2
+ searching for changes
+ 4
+ 5
+ 6
+ 7
+ 8
+
+test bundle (destination repo): expect 5 revisions
+
+this should bundle the same 5 revisions that outgoing reported, but it
+
+actually bundles 7
+
+ $ hg bundle foo.bundle ../repo2
+ searching for changes
+ 5 changesets found
+
+test bundle (base revision): expect 5 revisions
+
+this should (and does) give exactly the same result as bundle
+
+with a destination repo... i.e. it's wrong too
+
+ $ hg bundle --base 3 foo.bundle
+ 5 changesets found
+
+ $ cd ..
diff --git a/tests/test-bundle.t b/tests/test-bundle.t
new file mode 100644
index 0000000..305d8eb
--- /dev/null
+++ b/tests/test-bundle.t
@@ -0,0 +1,603 @@
+Setting up test
+
+ $ hg init test
+ $ cd test
+ $ echo 0 > afile
+ $ hg add afile
+ $ hg commit -m "0.0"
+ $ echo 1 >> afile
+ $ hg commit -m "0.1"
+ $ echo 2 >> afile
+ $ hg commit -m "0.2"
+ $ echo 3 >> afile
+ $ hg commit -m "0.3"
+ $ hg update -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo 1 >> afile
+ $ hg commit -m "1.1"
+ created new head
+ $ echo 2 >> afile
+ $ hg commit -m "1.2"
+ $ echo "a line" > fred
+ $ echo 3 >> afile
+ $ hg add fred
+ $ hg commit -m "1.3"
+ $ hg mv afile adifferentfile
+ $ hg commit -m "1.3m"
+ $ hg update -C 3
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg mv afile anotherfile
+ $ hg commit -m "0.3m"
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 9 changesets, 7 total revisions
+ $ cd ..
+ $ hg init empty
+
+Bundle and phase
+
+ $ hg -R test phase --force --secret 0
+ $ hg -R test bundle phase.hg empty
+ searching for changes
+ no changes found (ignored 9 secret changesets)
+ [1]
+ $ hg -R test phase --draft -r 'head()'
+
+Bundle --all
+
+ $ hg -R test bundle --all all.hg
+ 9 changesets found
+
+Bundle test to full.hg
+
+ $ hg -R test bundle full.hg empty
+ searching for changes
+ 9 changesets found
+
+Unbundle full.hg in test
+
+ $ hg -R test unbundle full.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 0 changesets with 0 changes to 4 files
+ (run 'hg update' to get a working copy)
+
+Verify empty
+
+ $ hg -R empty heads
+ [1]
+ $ hg -R empty verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 0 files, 0 changesets, 0 total revisions
+
+Pull full.hg into test (using --cwd)
+
+ $ hg --cwd test pull ../full.hg
+ pulling from ../full.hg
+ searching for changes
+ no changes found
+
+Pull full.hg into empty (using --cwd)
+
+ $ hg --cwd empty pull ../full.hg
+ pulling from ../full.hg
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 7 changes to 4 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+Rollback empty
+
+ $ hg -R empty rollback
+ repository tip rolled back to revision -1 (undo pull)
+
+Pull full.hg into empty again (using --cwd)
+
+ $ hg --cwd empty pull ../full.hg
+ pulling from ../full.hg
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 7 changes to 4 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+Pull full.hg into test (using -R)
+
+ $ hg -R test pull full.hg
+ pulling from full.hg
+ searching for changes
+ no changes found
+
+Pull full.hg into empty (using -R)
+
+ $ hg -R empty pull full.hg
+ pulling from full.hg
+ searching for changes
+ no changes found
+
+Rollback empty
+
+ $ hg -R empty rollback
+ repository tip rolled back to revision -1 (undo pull)
+
+Pull full.hg into empty again (using -R)
+
+ $ hg -R empty pull full.hg
+ pulling from full.hg
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 7 changes to 4 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+Log -R full.hg in fresh empty
+
+ $ rm -r empty
+ $ hg init empty
+ $ cd empty
+ $ hg -R bundle://../full.hg log
+ changeset: 8:aa35859c02ea
+ tag: tip
+ parent: 3:eebf5a27f8ca
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.3m
+
+ changeset: 7:a6a34bfa0076
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.3m
+
+ changeset: 6:7373c1169842
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.3
+
+ changeset: 5:1bb50a9436a7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.2
+
+ changeset: 4:095197eb4973
+ parent: 0:f9ee2f85a263
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.1
+
+ changeset: 3:eebf5a27f8ca
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.3
+
+ changeset: 2:e38ba6f5b7e0
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.2
+
+ changeset: 1:34c2bf6b0626
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.1
+
+ changeset: 0:f9ee2f85a263
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.0
+
+Make sure bundlerepo doesn't leak tempfiles (issue2491)
+
+ $ ls .hg
+ 00changelog.i
+ cache
+ requires
+ store
+
+Pull ../full.hg into empty (with hook)
+
+ $ echo "[hooks]" >> .hg/hgrc
+ $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
+
+doesn't work (yet ?)
+
+hg -R bundle://../full.hg verify
+
+ $ hg pull bundle://../full.hg
+ pulling from bundle:../full.hg
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 7 changes to 4 files (+1 heads)
+ changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_SOURCE=pull HG_URL=bundle:../full.hg
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+Rollback empty
+
+ $ hg rollback
+ repository tip rolled back to revision -1 (undo pull)
+ $ cd ..
+
+Log -R bundle:empty+full.hg
+
+ $ hg -R bundle:empty+full.hg log --template="{rev} "; echo ""
+ 8 7 6 5 4 3 2 1 0
+
+Pull full.hg into empty again (using -R; with hook)
+
+ $ hg -R empty pull full.hg
+ pulling from full.hg
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 7 changes to 4 files (+1 heads)
+ changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_SOURCE=pull HG_URL=bundle:empty+full.hg
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+Create partial clones
+
+ $ rm -r empty
+ $ hg init empty
+ $ hg clone -r 3 test partial
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg clone partial partial2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd partial
+
+Log -R full.hg in partial
+
+ $ hg -R bundle://../full.hg log
+ changeset: 8:aa35859c02ea
+ tag: tip
+ parent: 3:eebf5a27f8ca
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.3m
+
+ changeset: 7:a6a34bfa0076
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.3m
+
+ changeset: 6:7373c1169842
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.3
+
+ changeset: 5:1bb50a9436a7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.2
+
+ changeset: 4:095197eb4973
+ parent: 0:f9ee2f85a263
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.1
+
+ changeset: 3:eebf5a27f8ca
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.3
+
+ changeset: 2:e38ba6f5b7e0
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.2
+
+ changeset: 1:34c2bf6b0626
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.1
+
+ changeset: 0:f9ee2f85a263
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.0
+
+
+Incoming full.hg in partial
+
+ $ hg incoming bundle://../full.hg
+ comparing with bundle:../full.hg
+ searching for changes
+ changeset: 4:095197eb4973
+ parent: 0:f9ee2f85a263
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.1
+
+ changeset: 5:1bb50a9436a7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.2
+
+ changeset: 6:7373c1169842
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.3
+
+ changeset: 7:a6a34bfa0076
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.3m
+
+ changeset: 8:aa35859c02ea
+ tag: tip
+ parent: 3:eebf5a27f8ca
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.3m
+
+
+Outgoing -R full.hg vs partial2 in partial
+
+ $ hg -R bundle://../full.hg outgoing ../partial2
+ comparing with ../partial2
+ searching for changes
+ changeset: 4:095197eb4973
+ parent: 0:f9ee2f85a263
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.1
+
+ changeset: 5:1bb50a9436a7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.2
+
+ changeset: 6:7373c1169842
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.3
+
+ changeset: 7:a6a34bfa0076
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.3m
+
+ changeset: 8:aa35859c02ea
+ tag: tip
+ parent: 3:eebf5a27f8ca
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.3m
+
+
+Outgoing -R does-not-exist.hg vs partial2 in partial
+
+ $ hg -R bundle://../does-not-exist.hg outgoing ../partial2
+ abort: *../does-not-exist.hg* (glob)
+ [255]
+ $ cd ..
+
+hide outer repo
+ $ hg init
+
+Direct clone from bundle (all-history)
+
+ $ hg clone full.hg full-clone
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 7 changes to 4 files (+1 heads)
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R full-clone heads
+ changeset: 8:aa35859c02ea
+ tag: tip
+ parent: 3:eebf5a27f8ca
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.3m
+
+ changeset: 7:a6a34bfa0076
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1.3m
+
+ $ rm -r full-clone
+
+When cloning from a non-copiable repository into '', do not
+recurse infinitely (issue 2528)
+
+ $ hg clone full.hg ''
+ abort: empty destination path is not valid
+ [255]
+
+test for http://mercurial.selenic.com/bts/issue216
+
+Unbundle incremental bundles into fresh empty in one go
+
+ $ rm -r empty
+ $ hg init empty
+ $ hg -R test bundle --base null -r 0 ../0.hg
+ 1 changesets found
+ $ hg -R test bundle --base 0 -r 1 ../1.hg
+ 1 changesets found
+ $ hg -R empty unbundle -u ../0.hg ../1.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+test for 540d1059c802
+
+test for 540d1059c802
+
+ $ hg init orig
+ $ cd orig
+ $ echo foo > foo
+ $ hg add foo
+ $ hg ci -m 'add foo'
+
+ $ hg clone . ../copy
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg tag foo
+
+ $ cd ../copy
+ $ echo >> foo
+ $ hg ci -m 'change foo'
+ $ hg bundle ../bundle.hg ../orig
+ searching for changes
+ 1 changesets found
+
+ $ cd ../orig
+ $ hg incoming ../bundle.hg
+ comparing with ../bundle.hg
+ searching for changes
+ changeset: 2:ed1b79f46b9a
+ tag: tip
+ parent: 0:bbd179dfa0a7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change foo
+
+ $ cd ..
+
+test bundle with # in the filename (issue2154):
+
+ $ cp bundle.hg 'test#bundle.hg'
+ $ cd orig
+ $ hg incoming '../test#bundle.hg'
+ comparing with ../test
+ abort: unknown revision 'bundle.hg'!
+ [255]
+
+note that percent encoding is not handled:
+
+ $ hg incoming ../test%23bundle.hg
+ abort: repository ../test%23bundle.hg not found!
+ [255]
+ $ cd ..
+
+test for http://mercurial.selenic.com/bts/issue1144
+
+test that verify bundle does not traceback
+
+partial history bundle, fails w/ unkown parent
+
+ $ hg -R bundle.hg verify
+ abort: 00changelog.i@bbd179dfa0a7: unknown parent!
+ [255]
+
+full history bundle, refuses to verify non-local repo
+
+ $ hg -R all.hg verify
+ abort: cannot verify bundle or remote repos
+ [255]
+
+but, regular verify must continue to work
+
+ $ hg -R orig verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 2 changesets, 2 total revisions
+
+diff against bundle
+
+ $ hg init b
+ $ cd b
+ $ hg -R ../all.hg diff -r tip
+ diff -r aa35859c02ea anotherfile
+ --- a/anotherfile Thu Jan 01 00:00:00 1970 +0000
+ +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,4 +0,0 @@
+ -0
+ -1
+ -2
+ -3
+ $ cd ..
+
+bundle single branch
+
+ $ hg init branchy
+ $ cd branchy
+ $ echo a >a
+ $ echo x >x
+ $ hg ci -Ama
+ adding a
+ adding x
+ $ echo c >c
+ $ echo xx >x
+ $ hg ci -Amc
+ adding c
+ $ echo c1 >c1
+ $ hg ci -Amc1
+ adding c1
+ $ hg up 0
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo b >b
+ $ hg ci -Amb
+ adding b
+ created new head
+ $ echo b1 >b1
+ $ echo xx >x
+ $ hg ci -Amb1
+ adding b1
+ $ hg clone -q -r2 . part
+
+== bundling via incoming
+
+ $ hg in -R part --bundle incoming.hg --template "{node}\n" .
+ comparing with .
+ searching for changes
+ 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
+ 057f4db07f61970e1c11e83be79e9d08adc4dc31
+
+== bundling
+
+ $ hg bundle bundle.hg part --debug
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ 2 changesets found
+ list of changesets:
+ 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
+ 057f4db07f61970e1c11e83be79e9d08adc4dc31
+ bundling: 1/2 changesets (50.00%)
+ bundling: 2/2 changesets (100.00%)
+ bundling: 1/2 manifests (50.00%)
+ bundling: 2/2 manifests (100.00%)
+ bundling: b 1/3 files (33.33%)
+ bundling: b1 2/3 files (66.67%)
+ bundling: x 3/3 files (100.00%)
+
+== Test for issue3441
+
+ $ hg clone -q -r0 . part2
+ $ hg -q -R part2 pull bundle.hg
+ $ hg -R part2 verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 3 changesets, 5 total revisions
+
+ $ cd ..
diff --git a/tests/test-casecollision-merge.t b/tests/test-casecollision-merge.t
new file mode 100644
index 0000000..39e0ed2
--- /dev/null
+++ b/tests/test-casecollision-merge.t
@@ -0,0 +1,209 @@
+run only on case-insensitive filesystems
+
+ $ "$TESTDIR/hghave" icasefs || exit 80
+
+################################
+test for branch merging
+################################
+
+test for rename awareness of case-folding collision check:
+
+(1) colliding file is one renamed from collided file:
+this is also case for issue3370.
+
+ $ hg init merge_renameaware_1
+ $ cd merge_renameaware_1
+
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m '#0'
+ $ hg rename a tmp
+ $ hg rename tmp A
+ $ hg commit -m '#1'
+ $ hg update 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo 'modified at #2' > a
+ $ hg commit -m '#2'
+ created new head
+
+ $ hg merge
+ merging a and A to A
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg status -A
+ M A
+ a
+ R a
+ $ cat A
+ modified at #2
+
+ $ hg update --clean 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge
+ merging A and a to A
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg status -A
+ M A
+ a
+ $ cat A
+ modified at #2
+
+ $ cd ..
+
+(2) colliding file is not related to collided file
+
+ $ hg init merge_renameaware_2
+ $ cd merge_renameaware_2
+
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m '#0'
+ $ hg remove a
+ $ hg commit -m '#1'
+ $ echo A > A
+ $ hg add A
+ $ hg commit -m '#2'
+ $ hg update --clean 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo 'modified at #3' > a
+ $ hg commit -m '#3'
+ created new head
+
+ $ hg merge
+ abort: case-folding collision between A and a
+ [255]
+ $ hg parents --template '{rev}\n'
+ 3
+ $ hg status -A
+ C a
+ $ cat a
+ modified at #3
+
+ $ hg update --clean 2
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge
+ abort: case-folding collision between a and A
+ [255]
+ $ hg parents --template '{rev}\n'
+ 2
+ $ hg status -A
+ C A
+ $ cat A
+ A
+
+ $ cd ..
+
+
+################################
+test for linear updates
+################################
+
+test for rename awareness of case-folding collision check:
+
+(1) colliding file is one renamed from collided file
+
+ $ hg init linearupdate_renameaware_1
+ $ cd linearupdate_renameaware_1
+
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m '#0'
+ $ hg rename a tmp
+ $ hg rename tmp A
+ $ hg commit -m '#1'
+
+ $ hg update 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ echo 'this is added line' >> a
+ $ hg update 1
+ merging a and A to A
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ $ hg status -A
+ M A
+ $ cat A
+ a
+ this is added line
+
+ $ cd ..
+
+(2) colliding file is not related to collided file
+
+ $ hg init linearupdate_renameaware_2
+ $ cd linearupdate_renameaware_2
+
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m '#0'
+ $ hg remove a
+ $ hg commit -m '#1'
+ $ echo A > A
+ $ hg add A
+ $ hg commit -m '#2'
+
+ $ hg update 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg parents --template '{rev}\n'
+ 0
+ $ hg status -A
+ C a
+ $ cat A
+ a
+ $ hg up -qC 2
+
+ $ hg update --check 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg parents --template '{rev}\n'
+ 0
+ $ hg status -A
+ C a
+ $ cat a
+ a
+
+ $ hg update --clean 2
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg parents --template '{rev}\n'
+ 2
+ $ hg status -A
+ C A
+ $ cat A
+ A
+
+ $ cd ..
+
+(3) colliding file is not related to collided file: added in working dir
+
+ $ hg init linearupdate_renameaware_3
+ $ cd linearupdate_renameaware_3
+
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m '#0'
+ $ hg rename a b
+ $ hg commit -m '#1'
+ $ hg update 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ echo B > B
+ $ hg add B
+ $ hg status
+ A B
+ $ hg update
+ abort: case-folding collision between b and B
+ [255]
+
+ $ hg update --check
+ abort: uncommitted local changes
+ [255]
+
+ $ hg update --clean
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg parents --template '{rev}\n'
+ 1
+ $ hg status -A
+ C b
+ $ cat b
+ a
+
+ $ cd ..
diff --git a/tests/test-casecollision.t b/tests/test-casecollision.t
new file mode 100644
index 0000000..235c7f2
--- /dev/null
+++ b/tests/test-casecollision.t
@@ -0,0 +1,71 @@
+run only on case-sensitive filesystems
+
+ $ "$TESTDIR/hghave" no-icasefs || exit 80
+
+test file addition with colliding case
+
+ $ hg init repo1
+ $ cd repo1
+ $ echo a > a
+ $ echo A > A
+ $ hg add a
+ $ hg st
+ A a
+ ? A
+ $ hg add --config ui.portablefilenames=abort A
+ abort: possible case-folding collision for A
+ [255]
+ $ hg st
+ A a
+ ? A
+ $ hg add A
+ warning: possible case-folding collision for A
+ $ hg st
+ A A
+ A a
+ $ hg forget A
+ $ hg st
+ A a
+ ? A
+ $ hg add --config ui.portablefilenames=no A
+ $ hg st
+ A A
+ A a
+ $ mkdir b
+ $ touch b/c b/D
+ $ hg add b
+ adding b/D
+ adding b/c
+ $ touch b/d b/C
+ $ hg add b/C
+ warning: possible case-folding collision for b/C
+ $ hg add b/d
+ warning: possible case-folding collision for b/d
+ $ touch b/a1 b/a2
+ $ hg add b
+ adding b/a1
+ adding b/a2
+ $ touch b/A2 b/a1.1
+ $ hg add b/a1.1 b/A2
+ warning: possible case-folding collision for b/A2
+ $ touch b/f b/F
+ $ hg add b/f b/F
+ warning: possible case-folding collision for b/f
+ $ touch g G
+ $ hg add g G
+ warning: possible case-folding collision for g
+ $ mkdir h H
+ $ touch h/x H/x
+ $ hg add h/x H/x
+ warning: possible case-folding collision for h/x
+ $ touch h/s H/s
+ $ hg add h/s
+ $ hg add H/s
+ warning: possible case-folding collision for H/s
+
+case changing rename must not warn or abort
+
+ $ echo c > c
+ $ hg ci -qAmx
+ $ hg mv c C
+ $ cd ..
diff --git a/tests/test-casefolding.t b/tests/test-casefolding.t
new file mode 100644
index 0000000..5f59617
--- /dev/null
+++ b/tests/test-casefolding.t
@@ -0,0 +1,163 @@
+ $ "$TESTDIR/hghave" icasefs || exit 80
+
+ $ hg debugfs | grep 'case-sensitive:'
+ case-sensitive: no
+
+test file addition with bad case
+
+ $ hg init repo1
+ $ cd repo1
+ $ echo a > a
+ $ hg add A
+ adding a
+ $ hg st
+ A a
+ $ hg ci -m adda
+ $ hg manifest
+ a
+ $ cd ..
+
+test case collision on rename (issue750)
+
+ $ hg init repo2
+ $ cd repo2
+ $ echo a > a
+ $ hg --debug ci -Am adda
+ adding a
+ a
+ committed changeset 0:07f4944404050f47db2e5c5071e0e84e7a27bba9
+
+Case-changing renames should work:
+
+ $ hg mv a A
+ $ hg mv A a
+ $ hg st
+
+test changing case of path components
+
+ $ mkdir D
+ $ echo b > D/b
+ $ hg ci -Am addb D/b
+ $ hg mv D/b d/b
+ D/b: not overwriting - file exists
+ $ hg mv D/b d/c
+ $ hg st
+ A D/c
+ R D/b
+ $ mv D temp
+ $ mv temp d
+ $ hg st
+ A D/c
+ R D/b
+ $ hg revert -aq
+ $ rm d/c
+ $ echo c > D/c
+ $ hg add D/c
+ $ hg st
+ A D/c
+ $ hg ci -m addc D/c
+ $ hg mv d/b d/e
+ moving D/b to D/e (glob)
+ $ hg st
+ A D/e
+ R D/b
+ $ hg revert -aq
+ $ rm d/e
+ $ hg mv d/b D/B
+ moving D/b to D/B (glob)
+ $ hg st
+ A D/B
+ R D/b
+ $ cd ..
+
+test case collision between revisions (issue912)
+
+ $ hg init repo3
+ $ cd repo3
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ hg rm a
+ $ hg ci -Am removea
+ $ echo A > A
+
+on linux hfs keeps the old case stored, force it
+
+ $ mv a aa
+ $ mv aa A
+ $ hg ci -Am addA
+ adding A
+
+used to fail under case insensitive fs
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg up -C
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+no clobbering of untracked files with wrong casing
+
+ $ hg up -r null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo gold > a
+ $ hg up
+ A: untracked file differs
+ abort: untracked files in working directory differ from files in requested revision
+ [255]
+ $ cat a
+ gold
+
+ $ cd ..
+
+issue 3342: file in nested directory causes unexpected abort
+
+ $ hg init issue3342
+ $ cd issue3342
+
+ $ mkdir -p a/B/c/D
+ $ echo e > a/B/c/D/e
+ $ hg add a/B/c/D/e
+
+ $ cd ..
+
+issue 3340: mq does not handle case changes correctly
+
+in addition to reported case, 'hg qrefresh' is also tested against
+case changes.
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init issue3340
+ $ cd issue3340
+
+ $ echo a > mIxEdCaSe
+ $ hg add mIxEdCaSe
+ $ hg commit -m '#0'
+ $ hg rename mIxEdCaSe tmp
+ $ hg rename tmp MiXeDcAsE
+ $ hg status -A
+ A MiXeDcAsE
+ mIxEdCaSe
+ R mIxEdCaSe
+ $ hg qnew changecase
+ $ hg status -A
+ C MiXeDcAsE
+
+ $ hg qpop -a
+ popping changecase
+ patch queue now empty
+ $ hg qnew refresh-casechange
+ $ hg status -A
+ C mIxEdCaSe
+ $ hg rename mIxEdCaSe tmp
+ $ hg rename tmp MiXeDcAsE
+ $ hg status -A
+ A MiXeDcAsE
+ mIxEdCaSe
+ R mIxEdCaSe
+ $ hg qrefresh
+ $ hg status -A
+ C MiXeDcAsE
+
+ $ cd ..
diff --git a/tests/test-cat.t b/tests/test-cat.t
new file mode 100644
index 0000000..d069262
--- /dev/null
+++ b/tests/test-cat.t
@@ -0,0 +1,23 @@
+ $ hg init
+ $ echo 0 > a
+ $ echo 0 > b
+ $ hg ci -A -m m
+ adding a
+ adding b
+ $ hg rm a
+ $ hg cat a
+ 0
+ $ hg cat --decode a # more tests in test-encode
+ 0
+ $ echo 1 > b
+ $ hg ci -m m
+ $ echo 2 > b
+ $ hg cat -r 0 a
+ 0
+ $ hg cat -r 0 b
+ 0
+ $ hg cat -r 1 a
+ a: no such file in rev 7040230c159c
+ [1]
+ $ hg cat -r 1 b
+ 1
diff --git a/tests/test-changelog-exec.t b/tests/test-changelog-exec.t
new file mode 100644
index 0000000..028f8e5
--- /dev/null
+++ b/tests/test-changelog-exec.t
@@ -0,0 +1,55 @@
+b51a8138292a introduced a regression where we would mention in the
+changelog executable files added by the second parent of a merge. Test
+that that doesn't happen anymore
+
+ $ "$TESTDIR/hghave" execbit || exit 80
+
+ $ hg init repo
+ $ cd repo
+ $ echo foo > foo
+ $ hg ci -qAm 'add foo'
+
+ $ echo bar > bar
+ $ chmod +x bar
+ $ hg ci -qAm 'add bar'
+
+manifest of p2:
+
+ $ hg manifest
+ bar
+ foo
+
+ $ hg up -qC 0
+ $ echo >> foo
+ $ hg ci -m 'change foo'
+ created new head
+
+manifest of p1:
+
+ $ hg manifest
+ foo
+
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m 'merge'
+
+this should not mention bar:
+
+ $ hg tip -v
+ changeset: 3:ef2fc9b4a51b
+ tag: tip
+ parent: 2:ed1b79f46b9a
+ parent: 1:d394a8db219b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ description:
+ merge
+
+
+
+ $ hg debugindex bar
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 5 ..... 1 b004912a8510 000000000000 000000000000 (re)
+
+ $ cd ..
diff --git a/tests/test-check-code-hg.t b/tests/test-check-code-hg.t
new file mode 100644
index 0000000..89f1d1a
--- /dev/null
+++ b/tests/test-check-code-hg.t
@@ -0,0 +1,183 @@
+ $ check_code="$TESTDIR"/../contrib/check-code.py
+ $ cd "$TESTDIR"/..
+ $ if hg identify -q > /dev/null; then :
+ > else
+ > echo "skipped: not a Mercurial working dir" >&2
+ > exit 80
+ > fi
+ $ hg manifest | xargs "$check_code" || echo 'FAILURE IS NOT AN OPTION!!!'
+
+ $ hg manifest | xargs "$check_code" --warnings --nolineno --per-file=0 || true
+ hgext/convert/cvsps.py:0:
+ > ui.write('Ancestors: %s\n' % (','.join(r)))
+ warning: unwrapped ui message
+ hgext/convert/cvsps.py:0:
+ > ui.write('Parent: %d\n' % cs.parents[0].id)
+ warning: unwrapped ui message
+ hgext/convert/cvsps.py:0:
+ > ui.write('Parents: %s\n' %
+ warning: unwrapped ui message
+ hgext/convert/cvsps.py:0:
+ > ui.write('Branchpoints: %s \n' % ', '.join(branchpoints))
+ warning: unwrapped ui message
+ hgext/convert/cvsps.py:0:
+ > ui.write('Author: %s\n' % cs.author)
+ warning: unwrapped ui message
+ hgext/convert/cvsps.py:0:
+ > ui.write('Branch: %s\n' % (cs.branch or 'HEAD'))
+ warning: unwrapped ui message
+ hgext/convert/cvsps.py:0:
+ > ui.write('Date: %s\n' % util.datestr(cs.date,
+ warning: unwrapped ui message
+ hgext/convert/cvsps.py:0:
+ > ui.write('Log:\n')
+ warning: unwrapped ui message
+ hgext/convert/cvsps.py:0:
+ > ui.write('Members: \n')
+ warning: unwrapped ui message
+ hgext/convert/cvsps.py:0:
+ > ui.write('PatchSet %d \n' % cs.id)
+ warning: unwrapped ui message
+ hgext/convert/cvsps.py:0:
+ > ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1],
+ warning: unwrapped ui message
+ hgext/hgk.py:0:
+ > ui.write("parent %s\n" % p)
+ warning: unwrapped ui message
+ hgext/hgk.py:0:
+ > ui.write('k=%s\nv=%s\n' % (name, value))
+ warning: unwrapped ui message
+ hgext/hgk.py:0:
+ > ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
+ warning: unwrapped ui message
+ hgext/hgk.py:0:
+ > ui.write("branch %s\n\n" % ctx.branch())
+ warning: unwrapped ui message
+ hgext/hgk.py:0:
+ > ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
+ warning: unwrapped ui message
+ hgext/hgk.py:0:
+ > ui.write("revision %d\n" % ctx.rev())
+ warning: unwrapped ui message
+ hgext/hgk.py:0:
+ > ui.write("tree %s\n" % short(ctx.changeset()[0]))
+ warning: unwrapped ui message
+ hgext/mq.py:0:
+ > ui.write("mq: %s\n" % ', '.join(m))
+ warning: unwrapped ui message
+ hgext/patchbomb.py:0:
+ > ui.write('Subject: %s\n' % subj)
+ warning: unwrapped ui message
+ hgext/patchbomb.py:0:
+ > ui.write('From: %s\n' % sender)
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.note('branch %s\n' % data)
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.note('node %s\n' % str(data))
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.note('tag %s\n' % name)
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write("unpruned common: %s\n" % " ".join([short(n)
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write("local is subset\n")
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write("remote is subset\n")
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('deltas against other : ' + fmt % pcfmt(numother,
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write("match: %s\n" % m(d[0]))
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('path %s\n' % k)
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write("digraph G {\n")
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write("internal: %s %s\n" % d)
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write("standard: %s\n" % util.datestr(d))
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('avg chain length : ' + fmt % avgchainlen)
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('compression ratio : ' + fmt % compratio)
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('delta size (min/max/avg) : %d / %d / %d\n'
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('flags : %s\n' % ', '.join(flags))
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('format : %d\n' % format)
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('revision size : ' + fmt2 % totalsize)
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('revisions : ' + fmt2 % numrevs)
+ warning: unwrapped ui message
+ warning: unwrapped ui message
+ mercurial/commands.py:0:
+ > ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
+ warning: unwrapped ui message
+ tests/autodiff.py:0:
+ > ui.write('data lost for: %s\n' % fn)
+ warning: unwrapped ui message
+ tests/test-convert-mtn.t:0:
+ > > function get_passphrase(keypair_id)
+ don't use 'function', use old style
+ tests/test-import-git.t:0:
+ > > Mc\${NkU|\`?^000jF3jhEB
+ ^ must be quoted
+ tests/test-import.t:0:
+ > > diff -Naur proj-orig/foo proj-new/foo
+ don't use 'diff -N'
+ don't use 'diff -N'
+ tests/test-schemes.t:0:
+ > > z = file:\$PWD/
+ don't use $PWD, use `pwd`
+ tests/test-ui-color.py:0:
+ > testui.warn('warning\n')
+ warning: unwrapped ui message
+ tests/test-ui-color.py:0:
+ > testui.write('buffered\n')
+ warning: unwrapped ui message
diff --git a/tests/test-check-code.t b/tests/test-check-code.t
new file mode 100644
index 0000000..ee061d8
--- /dev/null
+++ b/tests/test-check-code.t
@@ -0,0 +1,142 @@
+ $ cat > correct.py <<EOF
+ > def toto(arg1, arg2):
+ > del arg2
+ > return (5 + 6, 9)
+ > EOF
+ $ cat > wrong.py <<EOF
+ > def toto( arg1, arg2):
+ > del(arg2)
+ > return ( 5+6, 9)
+ > EOF
+ $ cat > quote.py <<EOF
+ > # let's use quote in comments
+ > (''' ( 4x5 )
+ > but """\\''' and finally''',
+ > """let's fool checkpatch""", '1+2',
+ > '"""', 42+1, """and
+ > ( 4-1 ) """, "( 1+1 )\" and ")
+ > a, '\\\\\\\\', "\\\\\\" x-2", "c-1"
+ > EOF
+ $ cat > non-py24.py <<EOF
+ > # Using builtins that does not exist in Python 2.4
+ > if any():
+ > x = all()
+ > y = format(x)
+ >
+ > # Do not complain about our own definition
+ > def any(x):
+ > pass
+ >
+ > # try/except/finally block does not exist in Python 2.4
+ > try:
+ > pass
+ > except StandardError, inst:
+ > pass
+ > finally:
+ > pass
+ >
+ > # nested try/finally+try/except is allowed
+ > try:
+ > try:
+ > pass
+ > except StandardError, inst:
+ > pass
+ > finally:
+ > pass
+ > EOF
+ $ cat > classstyle.py <<EOF
+ > class newstyle_class(object):
+ > pass
+ >
+ > class oldstyle_class:
+ > pass
+ >
+ > class empty():
+ > pass
+ >
+ > no_class = 1:
+ > pass
+ > EOF
+ $ check_code="$TESTDIR"/../contrib/check-code.py
+ $ "$check_code" ./wrong.py ./correct.py ./quote.py ./non-py24.py ./classstyle.py
+ ./wrong.py:1:
+ > def toto( arg1, arg2):
+ gratuitous whitespace in () or []
+ ./wrong.py:2:
+ > del(arg2)
+ Python keyword is not a function
+ ./wrong.py:3:
+ > return ( 5+6, 9)
+ gratuitous whitespace in () or []
+ missing whitespace in expression
+ ./quote.py:5:
+ > '"""', 42+1, """and
+ missing whitespace in expression
+ ./non-py24.py:2:
+ > if any():
+ any/all/format not available in Python 2.4
+ ./non-py24.py:3:
+ > x = all()
+ any/all/format not available in Python 2.4
+ ./non-py24.py:4:
+ > y = format(x)
+ any/all/format not available in Python 2.4
+ ./non-py24.py:11:
+ > try:
+ no try/except/finally in Py2.4
+ ./classstyle.py:4:
+ > class oldstyle_class:
+ old-style class, use class foo(object)
+ ./classstyle.py:7:
+ > class empty():
+ class foo() not available in Python 2.4, use class foo(object)
+ [1]
+
+ $ cat > is-op.py <<EOF
+ > # is-operator comparing number or string literal
+ > x = None
+ > y = x is 'foo'
+ > y = x is "foo"
+ > y = x is 5346
+ > y = x is -6
+ > y = x is not 'foo'
+ > y = x is not "foo"
+ > y = x is not 5346
+ > y = x is not -6
+ > EOF
+
+ $ "$check_code" ./is-op.py
+ ./is-op.py:3:
+ > y = x is 'foo'
+ object comparison with literal
+ ./is-op.py:4:
+ > y = x is "foo"
+ object comparison with literal
+ ./is-op.py:5:
+ > y = x is 5346
+ object comparison with literal
+ ./is-op.py:6:
+ > y = x is -6
+ object comparison with literal
+ ./is-op.py:7:
+ > y = x is not 'foo'
+ object comparison with literal
+ ./is-op.py:8:
+ > y = x is not "foo"
+ object comparison with literal
+ ./is-op.py:9:
+ > y = x is not 5346
+ object comparison with literal
+ ./is-op.py:10:
+ > y = x is not -6
+ object comparison with literal
+ [1]
+
+ $ cat > warning.py <<EOF
+ > except:
+ > EOF
+ $ "$check_code" warning.py --warning --nolineno
+ warning.py:0:
+ > except:
+ warning: naked except clause
+ [1]
diff --git a/tests/test-check-pyflakes.t b/tests/test-check-pyflakes.t
new file mode 100644
index 0000000..3b5c272
--- /dev/null
+++ b/tests/test-check-pyflakes.t
@@ -0,0 +1,6 @@
+ $ "$TESTDIR/hghave" pyflakes || exit 80
+ $ cd "`dirname "$TESTDIR"`"
+ $ pyflakes mercurial hgext 2>&1 | "$TESTDIR/filterpyflakes.py"
+ hgext/inotify/linux/__init__.py:*: 'from _inotify import *' used; unable to detect undefined names (glob)
+
+
diff --git a/tests/test-children.t b/tests/test-children.t
new file mode 100644
index 0000000..ca812ef
--- /dev/null
+++ b/tests/test-children.t
@@ -0,0 +1,125 @@
+test children command
+
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > children =
+ > EOF
+
+init
+ $ hg init t
+ $ cd t
+
+no working directory
+ $ hg children
+
+setup
+ $ echo 0 > file0
+ $ hg ci -qAm 0 -d '0 0'
+
+ $ echo 1 > file1
+ $ hg ci -qAm 1 -d '1 0'
+
+ $ echo 2 >> file0
+ $ hg ci -qAm 2 -d '2 0'
+
+ $ hg co null
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo 3 > file3
+ $ hg ci -qAm 3 -d '3 0'
+
+hg children at revision 3 (tip)
+ $ hg children
+
+ $ hg co null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+hg children at nullrev (should be 0 and 3)
+ $ hg children
+ changeset: 0:4df8521a7374
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ changeset: 3:e2962852269d
+ tag: tip
+ parent: -1:000000000000
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: 3
+
+ $ hg co 1
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+hg children at revision 1 (should be 2)
+ $ hg children
+ changeset: 2:8f5eea5023c2
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: 2
+
+ $ hg co 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+hg children at revision 2 (other head)
+ $ hg children
+
+ $ for i in null 0 1 2 3; do
+ > echo "hg children -r $i"
+ > hg children -r $i
+ > done
+ hg children -r null
+ changeset: 0:4df8521a7374
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ changeset: 3:e2962852269d
+ tag: tip
+ parent: -1:000000000000
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: 3
+
+ hg children -r 0
+ changeset: 1:708c093edef0
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: 1
+
+ hg children -r 1
+ changeset: 2:8f5eea5023c2
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: 2
+
+ hg children -r 2
+ hg children -r 3
+
+hg children -r 0 file0 (should be 2)
+ $ hg children -r 0 file0
+ changeset: 2:8f5eea5023c2
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: 2
+
+
+hg children -r 1 file0 (should be 2)
+ $ hg children -r 1 file0
+ changeset: 2:8f5eea5023c2
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: 2
+
+
+ $ hg co 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+hg children file0 at revision 0 (should be 2)
+ $ hg children file0
+ changeset: 2:8f5eea5023c2
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: 2
+
+
+ $ cd ..
diff --git a/tests/test-churn.t b/tests/test-churn.t
new file mode 100644
index 0000000..b744d64
--- /dev/null
+++ b/tests/test-churn.t
@@ -0,0 +1,162 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "churn=" >> $HGRCPATH
+
+create test repository
+
+ $ hg init repo
+ $ cd repo
+ $ echo a > a
+ $ hg ci -Am adda -u user1 -d 6:00
+ adding a
+ $ echo b >> a
+ $ echo b > b
+ $ hg ci -m changeba -u user2 -d 9:00 a
+ $ hg ci -Am addb -u user2 -d 9:30
+ adding b
+ $ echo c >> a
+ $ echo c >> b
+ $ echo c > c
+ $ hg ci -m changeca -u user3 -d 12:00 a
+ $ hg ci -m changecb -u user3 -d 12:15 b
+ $ hg ci -Am addc -u user3 -d 12:30
+ adding c
+ $ mkdir -p d/e
+ $ echo abc > d/e/f1.txt
+ $ hg ci -Am "add d/e/f1.txt" -u user1 -d 12:45 d/e/f1.txt
+ $ mkdir -p d/g
+ $ echo def > d/g/f2.txt
+ $ hg ci -Am "add d/g/f2.txt" -u user1 -d 13:00 d/g/f2.txt
+
+
+churn separate directories
+
+ $ cd d
+ $ hg churn e
+ user1 1 ***************************************************************
+
+churn all
+
+ $ hg churn
+ user3 3 ***************************************************************
+ user1 3 ***************************************************************
+ user2 2 ******************************************
+
+churn excluding one dir
+
+ $ hg churn -X e
+ user3 3 ***************************************************************
+ user2 2 ******************************************
+ user1 2 ******************************************
+
+churn up to rev 2
+
+ $ hg churn -r :2
+ user2 2 ***************************************************************
+ user1 1 ********************************
+ $ cd ..
+
+churn with aliases
+
+ $ cat > ../aliases <<EOF
+ > user1 alias1
+ > user3 alias3
+ > not-an-alias
+ > EOF
+
+churn with .hgchurn
+
+ $ mv ../aliases .hgchurn
+ $ hg churn
+ skipping malformed alias: not-an-alias
+ alias3 3 **************************************************************
+ alias1 3 **************************************************************
+ user2 2 *****************************************
+ $ rm .hgchurn
+
+churn with column specifier
+
+ $ COLUMNS=40 hg churn
+ user3 3 ***********************
+ user1 3 ***********************
+ user2 2 ***************
+
+churn by hour
+
+ $ hg churn -f '%H' -s
+ 06 1 *****************
+ 09 2 *********************************
+ 12 4 ******************************************************************
+ 13 1 *****************
+
+
+churn with separated added/removed lines
+
+ $ hg rm d/g/f2.txt
+ $ hg ci -Am "removed d/g/f2.txt" -u user1 -d 14:00 d/g/f2.txt
+ $ hg churn --diffstat
+ user1 +3/-1 +++++++++++++++++++++++++++++++++++++++++--------------
+ user3 +3/-0 +++++++++++++++++++++++++++++++++++++++++
+ user2 +2/-0 +++++++++++++++++++++++++++
+
+churn --diffstat with color
+
+ $ hg --config extensions.color= churn --config color.mode=ansi \
+ > --diffstat --color=always
+ user1 +3/-1 \x1b[0;32m+++++++++++++++++++++++++++++++++++++++++\x1b[0m\x1b[0;31m--------------\x1b[0m (esc)
+ user3 +3/-0 \x1b[0;32m+++++++++++++++++++++++++++++++++++++++++\x1b[0m (esc)
+ user2 +2/-0 \x1b[0;32m+++++++++++++++++++++++++++\x1b[0m (esc)
+
+
+changeset number churn
+
+ $ hg churn -c
+ user1 4 ***************************************************************
+ user3 3 ***********************************************
+ user2 2 ********************************
+
+ $ echo 'with space = no-space' >> ../aliases
+ $ echo a >> a
+ $ hg commit -m a -u 'with space' -d 15:00
+
+churn with space in alias
+
+ $ hg churn --aliases ../aliases -r tip
+ no-space 1 ************************************************************
+
+ $ cd ..
+
+
+Issue833: ZeroDivisionError
+
+ $ hg init issue-833
+ $ cd issue-833
+ $ touch foo
+ $ hg ci -Am foo
+ adding foo
+
+this was failing with a ZeroDivisionError
+
+ $ hg churn
+ test 0
+ $ cd ..
+
+Ignore trailing or leading spaces in emails
+
+ $ cd repo
+ $ touch bar
+ $ hg ci -Am'bar' -u 'user4 <user4@x.com>'
+ adding bar
+ $ touch foo
+ $ hg ci -Am'foo' -u 'user4 < user4@x.com >'
+ adding foo
+ $ hg log -l2 --template '[{author|email}]\n'
+ [ user4@x.com ]
+ [user4@x.com]
+ $ hg churn -c
+ user1 4 *********************************************************
+ user3 3 *******************************************
+ user4@x.com 2 *****************************
+ user2 2 *****************************
+ with space 1 **************
+
+ $ cd ..
diff --git a/tests/test-clone-cgi.t b/tests/test-clone-cgi.t
new file mode 100644
index 0000000..f857f07
--- /dev/null
+++ b/tests/test-clone-cgi.t
@@ -0,0 +1,31 @@
+ $ "$TESTDIR/hghave" no-msys || exit 80 # MSYS will translate web paths as if they were file paths
+
+This is a test of the wire protocol over CGI-based hgweb.
+initialize repository
+
+ $ hg init test
+ $ cd test
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+ $ cd ..
+ $ cat >hgweb.cgi <<HGWEB
+ > #
+ > # An example CGI script to use hgweb, edit as necessary
+ > import cgitb
+ > cgitb.enable()
+ > from mercurial import demandimport; demandimport.enable()
+ > from mercurial.hgweb import hgweb
+ > from mercurial.hgweb import wsgicgi
+ > application = hgweb("test", "Empty test repository")
+ > wsgicgi.launch(application)
+ > HGWEB
+ $ chmod 755 hgweb.cgi
+
+try hgweb request
+
+ $ . "$TESTDIR/cgienv"
+ $ QUERY_STRING="cmd=changegroup&roots=0000000000000000000000000000000000000000"; export QUERY_STRING
+ $ python hgweb.cgi >page1 2>&1
+ $ python "$TESTDIR/md5sum.py" page1
+ 1f424bb22ec05c3c6bc866b6e67efe43 page1
diff --git a/tests/test-clone-pull-corruption.t b/tests/test-clone-pull-corruption.t
new file mode 100644
index 0000000..b92269c
--- /dev/null
+++ b/tests/test-clone-pull-corruption.t
@@ -0,0 +1,52 @@
+Corrupt an hg repo with a pull started during an aborted commit
+Create two repos, so that one of them can pull from the other one.
+
+ $ hg init source
+ $ cd source
+ $ touch foo
+ $ hg add foo
+ $ hg ci -m 'add foo'
+ $ hg clone . ../corrupted
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo >> foo
+ $ hg ci -m 'change foo'
+
+Add a hook to wait 5 seconds and then abort the commit
+
+ $ cd ../corrupted
+ $ echo "[hooks]" >> .hg/hgrc
+ $ echo "pretxncommit = sh -c 'sleep 5; exit 1'" >> .hg/hgrc
+
+start a commit...
+
+ $ touch bar
+ $ hg add bar
+ $ hg ci -m 'add bar' &
+
+... and start a pull while the commit is still running
+
+ $ sleep 1
+ $ hg pull ../source 2>/dev/null
+ pulling from ../source
+ transaction abort!
+ rollback completed
+ abort: pretxncommit hook exited with status 1
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+
+see what happened
+
+ $ wait
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+
+ $ cd ..
diff --git a/tests/test-clone-r.t b/tests/test-clone-r.t
new file mode 100644
index 0000000..afd8498
--- /dev/null
+++ b/tests/test-clone-r.t
@@ -0,0 +1,220 @@
+ $ hg init test
+ $ cd test
+
+ $ echo 0 >> afile
+ $ hg add afile
+ $ hg commit -m "0.0"
+
+ $ echo 1 >> afile
+ $ hg commit -m "0.1"
+
+ $ echo 2 >> afile
+ $ hg commit -m "0.2"
+
+ $ echo 3 >> afile
+ $ hg commit -m "0.3"
+
+ $ hg update -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo 1 >> afile
+ $ hg commit -m "1.1"
+ created new head
+
+ $ echo 2 >> afile
+ $ hg commit -m "1.2"
+
+ $ echo a line > fred
+ $ echo 3 >> afile
+ $ hg add fred
+ $ hg commit -m "1.3"
+ $ hg mv afile adifferentfile
+ $ hg commit -m "1.3m"
+
+ $ hg update -C 3
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+ $ hg mv afile anotherfile
+ $ hg commit -m "0.3m"
+
+ $ hg debugindex -f 1 afile
+ rev flag offset length size ..... link p1 p2 nodeid (re)
+ 0 0000 0 3 2 ..... 0 -1 -1 362fef284ce2 (re)
+ 1 0000 3 5 4 ..... 1 0 -1 125144f7e028 (re)
+ 2 0000 8 7 6 ..... 2 1 -1 4c982badb186 (re)
+ 3 0000 15 9 8 ..... 3 2 -1 19b1fc555737 (re)
+
+ $ hg debugindex adifferentfile
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 75 ..... 7 2565f3199a74 000000000000 000000000000 (re)
+
+ $ hg debugindex anotherfile
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 75 ..... 8 2565f3199a74 000000000000 000000000000 (re)
+
+ $ hg debugindex fred
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 8 ..... 6 12ab3bcc5ea4 000000000000 000000000000 (re)
+
+ $ hg debugindex --manifest
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 48 ..... 0 43eadb1d2d06 000000000000 000000000000 (re)
+ 1 48 48 ..... 1 8b89697eba2c 43eadb1d2d06 000000000000 (re)
+ 2 96 48 ..... 2 626a32663c2f 8b89697eba2c 000000000000 (re)
+ 3 144 48 ..... 3 f54c32f13478 626a32663c2f 000000000000 (re)
+ 4 192 .. ..... 6 de68e904d169 626a32663c2f 000000000000 (re)
+ 5 2.. 68 ..... 7 09bb521d218d de68e904d169 000000000000 (re)
+ 6 3.. 54 ..... 8 1fde233dfb0f f54c32f13478 000000000000 (re)
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 9 changesets, 7 total revisions
+
+ $ cd ..
+
+ $ for i in 0 1 2 3 4 5 6 7 8; do
+ > echo
+ > echo ---- hg clone -r "$i" test test-"$i"
+ > hg clone -r "$i" test test-"$i"
+ > cd test-"$i"
+ > hg verify
+ > cd ..
+ > done
+
+ ---- hg clone -r 0 test test-0
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+
+ ---- hg clone -r 1 test test-1
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+
+ ---- hg clone -r 2 test test-2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+
+ ---- hg clone -r 3 test test-3
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 4 changesets, 4 total revisions
+
+ ---- hg clone -r 4 test test-4
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+
+ ---- hg clone -r 5 test test-5
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+
+ ---- hg clone -r 6 test test-6
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 5 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 4 changesets, 5 total revisions
+
+ ---- hg clone -r 7 test test-7
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 6 changes to 3 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 5 changesets, 6 total revisions
+
+ ---- hg clone -r 8 test test-8
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 5 changes to 2 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 5 changesets, 5 total revisions
+
+ $ cd test-8
+ $ hg pull ../test-7
+ pulling from ../test-7
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 2 changes to 3 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 9 changesets, 7 total revisions
+ $ cd ..
+
diff --git a/tests/test-clone-update-order.t b/tests/test-clone-update-order.t
new file mode 100644
index 0000000..8a4f89d
--- /dev/null
+++ b/tests/test-clone-update-order.t
@@ -0,0 +1,105 @@
+ $ hg init
+ $ echo foo > bar
+ $ hg commit -Am default
+ adding bar
+ $ hg up -r null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg branch mine
+ marked working directory as branch mine
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo hello > world
+ $ hg commit -Am hello
+ adding world
+ $ hg up -r null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg branch other
+ marked working directory as branch other
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo good > bye
+ $ hg commit -Am other
+ adding bye
+ $ hg up -r mine
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ hg clone -U -u . .#other ../b -r 0 -r 1 -r 2 -b other
+ abort: cannot specify both --noupdate and --updaterev
+ [255]
+
+ $ hg clone -U .#other ../b -r 0 -r 1 -r 2 -b other
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 3 files (+2 heads)
+ $ rm -rf ../b
+
+ $ hg clone -u . .#other ../b -r 0 -r 1 -r 2 -b other
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 3 files (+2 heads)
+ updating to branch mine
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf ../b
+
+ $ hg clone -u 0 .#other ../b -r 0 -r 1 -r 2 -b other
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 3 files (+2 heads)
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf ../b
+
+ $ hg clone -u 1 .#other ../b -r 0 -r 1 -r 2 -b other
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 3 files (+2 heads)
+ updating to branch mine
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf ../b
+
+ $ hg clone -u 2 .#other ../b -r 0 -r 1 -r 2 -b other
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 3 files (+2 heads)
+ updating to branch other
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf ../b
+
+Test -r mine ... mine is ignored:
+
+ $ hg clone -u 2 .#other ../b -r mine -r 0 -r 1 -r 2 -b other
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 3 files (+2 heads)
+ updating to branch other
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf ../b
+
+ $ hg clone .#other ../b -b default -b mine
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 3 files (+2 heads)
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf ../b
+
+ $ hg clone .#other ../b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch other
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf ../b
+
+ $ hg clone -U . ../c -r 1 -r 2 > /dev/null
+ $ hg clone ../c ../b
+ updating to branch other
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf ../b ../c
+
diff --git a/tests/test-clone.t b/tests/test-clone.t
new file mode 100644
index 0000000..3f83949
--- /dev/null
+++ b/tests/test-clone.t
@@ -0,0 +1,567 @@
+Prepare repo a:
+
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m test
+ $ echo first line > b
+ $ hg add b
+
+Create a non-inlined filelog:
+
+ $ python -c 'file("data1", "wb").write("".join("%s\n" % x for x in range(10000)))'
+ $ for j in 0 1 2 3 4 5 6 7 8 9; do
+ > cat data1 >> b
+ > hg commit -m test
+ > done
+
+List files in store/data (should show a 'b.d'):
+
+ $ for i in .hg/store/data/*; do
+ > echo $i
+ > done
+ .hg/store/data/a.i
+ .hg/store/data/b.d
+ .hg/store/data/b.i
+
+Default operation:
+
+ $ hg clone . ../b
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../b
+ $ cat a
+ a
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 11 changesets, 11 total revisions
+
+Invalid dest '' must abort:
+
+ $ hg clone . ''
+ abort: empty destination path is not valid
+ [255]
+
+No update, with debug option:
+
+#if hardlink
+ $ hg --debug clone -U . ../c
+ linked 8 files
+ listing keys for "bookmarks"
+#else
+ $ hg --debug clone -U . ../c
+ copied 8 files
+ listing keys for "bookmarks"
+#endif
+ $ cd ../c
+ $ cat a 2>/dev/null || echo "a not present"
+ a not present
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 11 changesets, 11 total revisions
+
+Default destination:
+
+ $ mkdir ../d
+ $ cd ../d
+ $ hg clone ../a
+ destination directory: a
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd a
+ $ hg cat a
+ a
+ $ cd ../..
+
+Check that we drop the 'file:' from the path before writing the .hgrc:
+
+ $ hg clone file:a e
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ grep 'file:' e/.hg/hgrc
+ [1]
+
+Check that path aliases are expanded:
+
+ $ hg clone -q -U --config 'paths.foobar=a#0' foobar f
+ $ hg -R f showconfig paths.default
+ $TESTTMP/a#0 (glob)
+
+Use --pull:
+
+ $ hg clone --pull a g
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 11 changesets with 11 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R g verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 11 changesets, 11 total revisions
+
+Invalid dest '' with --pull must abort (issue2528):
+
+ $ hg clone --pull a ''
+ abort: empty destination path is not valid
+ [255]
+
+Clone to '.':
+
+ $ mkdir h
+ $ cd h
+ $ hg clone ../a .
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+
+
+*** Tests for option -u ***
+
+Adding some more history to repo a:
+
+ $ cd a
+ $ hg tag ref1
+ $ echo the quick brown fox >a
+ $ hg ci -m "hacked default"
+ $ hg up ref1
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg branch stable
+ marked working directory as branch stable
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo some text >a
+ $ hg ci -m "starting branch stable"
+ $ hg tag ref2
+ $ echo some more text >a
+ $ hg ci -m "another change for branch stable"
+ $ hg up ref2
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg parents
+ changeset: 13:e8ece76546a6
+ branch: stable
+ tag: ref2
+ parent: 10:a7949464abda
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: starting branch stable
+
+
+Repo a has two heads:
+
+ $ hg heads
+ changeset: 15:0aae7cf88f0d
+ branch: stable
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: another change for branch stable
+
+ changeset: 12:f21241060d6a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: hacked default
+
+
+ $ cd ..
+
+
+Testing --noupdate with --updaterev (must abort):
+
+ $ hg clone --noupdate --updaterev 1 a ua
+ abort: cannot specify both --noupdate and --updaterev
+ [255]
+
+
+Testing clone -u:
+
+ $ hg clone -u . a ua
+ updating to branch stable
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Repo ua has both heads:
+
+ $ hg -R ua heads
+ changeset: 15:0aae7cf88f0d
+ branch: stable
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: another change for branch stable
+
+ changeset: 12:f21241060d6a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: hacked default
+
+
+Same revision checked out in repo a and ua:
+
+ $ hg -R a parents --template "{node|short}\n"
+ e8ece76546a6
+ $ hg -R ua parents --template "{node|short}\n"
+ e8ece76546a6
+
+ $ rm -r ua
+
+
+Testing clone --pull -u:
+
+ $ hg clone --pull -u . a ua
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 16 changesets with 16 changes to 3 files (+1 heads)
+ updating to branch stable
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Repo ua has both heads:
+
+ $ hg -R ua heads
+ changeset: 15:0aae7cf88f0d
+ branch: stable
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: another change for branch stable
+
+ changeset: 12:f21241060d6a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: hacked default
+
+
+Same revision checked out in repo a and ua:
+
+ $ hg -R a parents --template "{node|short}\n"
+ e8ece76546a6
+ $ hg -R ua parents --template "{node|short}\n"
+ e8ece76546a6
+
+ $ rm -r ua
+
+
+Testing clone -u <branch>:
+
+ $ hg clone -u stable a ua
+ updating to branch stable
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Repo ua has both heads:
+
+ $ hg -R ua heads
+ changeset: 15:0aae7cf88f0d
+ branch: stable
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: another change for branch stable
+
+ changeset: 12:f21241060d6a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: hacked default
+
+
+Branch 'stable' is checked out:
+
+ $ hg -R ua parents
+ changeset: 15:0aae7cf88f0d
+ branch: stable
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: another change for branch stable
+
+
+ $ rm -r ua
+
+
+Testing default checkout:
+
+ $ hg clone a ua
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Repo ua has both heads:
+
+ $ hg -R ua heads
+ changeset: 15:0aae7cf88f0d
+ branch: stable
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: another change for branch stable
+
+ changeset: 12:f21241060d6a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: hacked default
+
+
+Branch 'default' is checked out:
+
+ $ hg -R ua parents
+ changeset: 12:f21241060d6a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: hacked default
+
+
+ $ rm -r ua
+
+
+Testing #<branch>:
+
+ $ hg clone -u . a#stable ua
+ adding changesets
+ adding manifests
+ adding file changes
+ added 14 changesets with 14 changes to 3 files
+ updating to branch stable
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
+
+ $ hg -R ua heads
+ changeset: 13:0aae7cf88f0d
+ branch: stable
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: another change for branch stable
+
+ changeset: 10:a7949464abda
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: test
+
+
+Same revision checked out in repo a and ua:
+
+ $ hg -R a parents --template "{node|short}\n"
+ e8ece76546a6
+ $ hg -R ua parents --template "{node|short}\n"
+ e8ece76546a6
+
+ $ rm -r ua
+
+
+Testing -u -r <branch>:
+
+ $ hg clone -u . -r stable a ua
+ adding changesets
+ adding manifests
+ adding file changes
+ added 14 changesets with 14 changes to 3 files
+ updating to branch stable
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
+
+ $ hg -R ua heads
+ changeset: 13:0aae7cf88f0d
+ branch: stable
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: another change for branch stable
+
+ changeset: 10:a7949464abda
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: test
+
+
+Same revision checked out in repo a and ua:
+
+ $ hg -R a parents --template "{node|short}\n"
+ e8ece76546a6
+ $ hg -R ua parents --template "{node|short}\n"
+ e8ece76546a6
+
+ $ rm -r ua
+
+
+Testing -r <branch>:
+
+ $ hg clone -r stable a ua
+ adding changesets
+ adding manifests
+ adding file changes
+ added 14 changesets with 14 changes to 3 files
+ updating to branch stable
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
+
+ $ hg -R ua heads
+ changeset: 13:0aae7cf88f0d
+ branch: stable
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: another change for branch stable
+
+ changeset: 10:a7949464abda
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: test
+
+
+Branch 'stable' is checked out:
+
+ $ hg -R ua parents
+ changeset: 13:0aae7cf88f0d
+ branch: stable
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: another change for branch stable
+
+
+ $ rm -r ua
+
+
+Issue2267: Error in 1.6 hg.py: TypeError: 'NoneType' object is not
+iterable in addbranchrevs()
+
+ $ cat <<EOF > simpleclone.py
+ > from mercurial import ui, hg
+ > myui = ui.ui()
+ > repo = hg.repository(myui, 'a')
+ > hg.clone(myui, {}, repo, dest="ua")
+ > EOF
+
+ $ python simpleclone.py
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ rm -r ua
+
+ $ cat <<EOF > branchclone.py
+ > from mercurial import ui, hg, extensions
+ > myui = ui.ui()
+ > extensions.loadall(myui)
+ > repo = hg.repository(myui, 'a')
+ > hg.clone(myui, {}, repo, dest="ua", branch=["stable",])
+ > EOF
+
+ $ python branchclone.py
+ adding changesets
+ adding manifests
+ adding file changes
+ added 14 changesets with 14 changes to 3 files
+ updating to branch stable
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -r ua
+
+
+Testing failures:
+
+ $ mkdir fail
+ $ cd fail
+
+No local source
+
+ $ hg clone a b
+ abort: repository a not found!
+ [255]
+
+No remote source
+
+ $ hg clone http://127.0.0.1:3121/a b
+ abort: error: *refused* (glob)
+ [255]
+ $ rm -rf b # work around bug with http clone
+
+
+#if unix-permissions
+
+Inaccessible source
+
+ $ mkdir a
+ $ chmod 000 a
+ $ hg clone a b
+ abort: repository a not found!
+ [255]
+
+Inaccessible destination
+
+ $ hg init b
+ $ cd b
+ $ hg clone . ../a
+ abort: Permission denied: ../a
+ [255]
+ $ cd ..
+ $ chmod 700 a
+ $ rm -r a b
+
+#endif
+
+
+#if fifo
+
+Source of wrong type
+
+ $ mkfifo a
+ $ hg clone a b
+ abort: repository a not found!
+ [255]
+ $ rm a
+
+#endif
+
+Default destination, same directory
+
+ $ hg init q
+ $ hg clone q
+ destination directory: q
+ abort: destination 'q' is not empty
+ [255]
+
+destination directory not empty
+
+ $ mkdir a
+ $ echo stuff > a/a
+ $ hg clone q a
+ abort: destination 'a' is not empty
+ [255]
+
+
+#if unix-permissions
+
+leave existing directory in place after clone failure
+
+ $ hg init c
+ $ cd c
+ $ echo c > c
+ $ hg commit -A -m test
+ adding c
+ $ chmod -rx .hg/store/data
+ $ cd ..
+ $ mkdir d
+ $ hg clone c d 2> err
+ [255]
+ $ test -d d
+ $ test -d d/.hg
+ [1]
+
+reenable perm to allow deletion
+
+ $ chmod +rx c/.hg/store/data
+
+#endif
+
+ $ cd ..
diff --git a/tests/test-command-template.t b/tests/test-command-template.t
new file mode 100644
index 0000000..d3fa338
--- /dev/null
+++ b/tests/test-command-template.t
@@ -0,0 +1,1383 @@
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg add a
+ $ echo line 1 > b
+ $ echo line 2 >> b
+ $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
+
+ $ hg add b
+ $ echo other 1 > c
+ $ echo other 2 >> c
+ $ echo >> c
+ $ echo other 3 >> c
+ $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
+
+ $ hg add c
+ $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
+ $ echo c >> c
+ $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
+
+ $ echo foo > .hg/branch
+ $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
+
+ $ hg co -q 3
+ $ echo other 4 >> d
+ $ hg add d
+ $ hg commit -m 'new head' -d '1500000 0' -u 'person'
+
+ $ hg merge -q foo
+ $ hg commit -m 'merge' -d '1500001 0' -u 'person'
+
+Second branch starting at nullrev:
+
+ $ hg update null
+ 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+ $ echo second > second
+ $ hg add second
+ $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
+ created new head
+
+ $ echo third > third
+ $ hg add third
+ $ hg mv second fourth
+ $ hg commit -m third -d "2020-01-01 10:01"
+
+Quoting for ui.logtemplate
+
+ $ hg tip --config "ui.logtemplate={rev}\n"
+ 8
+ $ hg tip --config "ui.logtemplate='{rev}\n'"
+ 8
+ $ hg tip --config 'ui.logtemplate="{rev}\n"'
+ 8
+
+Make sure user/global hgrc does not affect tests
+
+ $ echo '[ui]' > .hg/hgrc
+ $ echo 'logtemplate =' >> .hg/hgrc
+ $ echo 'style =' >> .hg/hgrc
+
+Default style is like normal output:
+
+ $ hg log > log.out
+ $ hg log --style default > style.out
+ $ cmp log.out style.out || diff -u log.out style.out
+
+ $ hg log -v > log.out
+ $ hg log -v --style default > style.out
+ $ cmp log.out style.out || diff -u log.out style.out
+
+ $ hg log --debug > log.out
+ $ hg log --debug --style default > style.out
+ $ cmp log.out style.out || diff -u log.out style.out
+
+Revision with no copies (used to print a traceback):
+
+ $ hg tip -v --template '\n'
+
+
+Compact style works:
+
+ $ hg log --style compact
+ 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
+ third
+
+ 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
+ second
+
+ 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
+ merge
+
+ 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
+ new head
+
+ 4 bbe44766e73d 1970-01-17 04:53 +0000 person
+ new branch
+
+ 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
+ no user, no domain
+
+ 2 97054abb4ab8 1970-01-14 21:20 +0000 other
+ no person
+
+ 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
+ other 1
+
+ 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
+ line 1
+
+
+ $ hg log -v --style compact
+ 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
+ third
+
+ 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
+ second
+
+ 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
+ merge
+
+ 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
+ new head
+
+ 4 bbe44766e73d 1970-01-17 04:53 +0000 person
+ new branch
+
+ 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
+ no user, no domain
+
+ 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
+ no person
+
+ 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
+ other 1
+ other 2
+
+ other 3
+
+ 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
+ line 1
+ line 2
+
+
+ $ hg log --debug --style compact
+ 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
+ third
+
+ 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
+ second
+
+ 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
+ merge
+
+ 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
+ new head
+
+ 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
+ new branch
+
+ 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
+ no user, no domain
+
+ 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
+ no person
+
+ 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
+ other 1
+ other 2
+
+ other 3
+
+ 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
+ line 1
+ line 2
+
+
+Test xml styles:
+
+ $ hg log --style xml
+ <?xml version="1.0"?>
+ <log>
+ <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
+ <tag>tip</tag>
+ <author email="test">test</author>
+ <date>2020-01-01T10:01:00+00:00</date>
+ <msg xml:space="preserve">third</msg>
+ </logentry>
+ <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <author email="user@hostname">User Name</author>
+ <date>1970-01-12T13:46:40+00:00</date>
+ <msg xml:space="preserve">second</msg>
+ </logentry>
+ <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
+ <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
+ <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
+ <author email="person">person</author>
+ <date>1970-01-18T08:40:01+00:00</date>
+ <msg xml:space="preserve">merge</msg>
+ </logentry>
+ <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
+ <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
+ <author email="person">person</author>
+ <date>1970-01-18T08:40:00+00:00</date>
+ <msg xml:space="preserve">new head</msg>
+ </logentry>
+ <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
+ <branch>foo</branch>
+ <author email="person">person</author>
+ <date>1970-01-17T04:53:20+00:00</date>
+ <msg xml:space="preserve">new branch</msg>
+ </logentry>
+ <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
+ <author email="person">person</author>
+ <date>1970-01-16T01:06:40+00:00</date>
+ <msg xml:space="preserve">no user, no domain</msg>
+ </logentry>
+ <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
+ <author email="other@place">other</author>
+ <date>1970-01-14T21:20:00+00:00</date>
+ <msg xml:space="preserve">no person</msg>
+ </logentry>
+ <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
+ <author email="other@place">A. N. Other</author>
+ <date>1970-01-13T17:33:20+00:00</date>
+ <msg xml:space="preserve">other 1
+ other 2
+
+ other 3</msg>
+ </logentry>
+ <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
+ <author email="user@hostname">User Name</author>
+ <date>1970-01-12T13:46:40+00:00</date>
+ <msg xml:space="preserve">line 1
+ line 2</msg>
+ </logentry>
+ </log>
+
+ $ hg log -v --style xml
+ <?xml version="1.0"?>
+ <log>
+ <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
+ <tag>tip</tag>
+ <author email="test">test</author>
+ <date>2020-01-01T10:01:00+00:00</date>
+ <msg xml:space="preserve">third</msg>
+ <paths>
+ <path action="A">fourth</path>
+ <path action="A">third</path>
+ <path action="R">second</path>
+ </paths>
+ <copies>
+ <copy source="second">fourth</copy>
+ </copies>
+ </logentry>
+ <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <author email="user@hostname">User Name</author>
+ <date>1970-01-12T13:46:40+00:00</date>
+ <msg xml:space="preserve">second</msg>
+ <paths>
+ <path action="A">second</path>
+ </paths>
+ </logentry>
+ <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
+ <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
+ <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
+ <author email="person">person</author>
+ <date>1970-01-18T08:40:01+00:00</date>
+ <msg xml:space="preserve">merge</msg>
+ <paths>
+ </paths>
+ </logentry>
+ <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
+ <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
+ <author email="person">person</author>
+ <date>1970-01-18T08:40:00+00:00</date>
+ <msg xml:space="preserve">new head</msg>
+ <paths>
+ <path action="A">d</path>
+ </paths>
+ </logentry>
+ <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
+ <branch>foo</branch>
+ <author email="person">person</author>
+ <date>1970-01-17T04:53:20+00:00</date>
+ <msg xml:space="preserve">new branch</msg>
+ <paths>
+ </paths>
+ </logentry>
+ <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
+ <author email="person">person</author>
+ <date>1970-01-16T01:06:40+00:00</date>
+ <msg xml:space="preserve">no user, no domain</msg>
+ <paths>
+ <path action="M">c</path>
+ </paths>
+ </logentry>
+ <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
+ <author email="other@place">other</author>
+ <date>1970-01-14T21:20:00+00:00</date>
+ <msg xml:space="preserve">no person</msg>
+ <paths>
+ <path action="A">c</path>
+ </paths>
+ </logentry>
+ <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
+ <author email="other@place">A. N. Other</author>
+ <date>1970-01-13T17:33:20+00:00</date>
+ <msg xml:space="preserve">other 1
+ other 2
+
+ other 3</msg>
+ <paths>
+ <path action="A">b</path>
+ </paths>
+ </logentry>
+ <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
+ <author email="user@hostname">User Name</author>
+ <date>1970-01-12T13:46:40+00:00</date>
+ <msg xml:space="preserve">line 1
+ line 2</msg>
+ <paths>
+ <path action="A">a</path>
+ </paths>
+ </logentry>
+ </log>
+
+ $ hg log --debug --style xml
+ <?xml version="1.0"?>
+ <log>
+ <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
+ <tag>tip</tag>
+ <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <author email="test">test</author>
+ <date>2020-01-01T10:01:00+00:00</date>
+ <msg xml:space="preserve">third</msg>
+ <paths>
+ <path action="A">fourth</path>
+ <path action="A">third</path>
+ <path action="R">second</path>
+ </paths>
+ <copies>
+ <copy source="second">fourth</copy>
+ </copies>
+ <extra key="branch">default</extra>
+ </logentry>
+ <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <author email="user@hostname">User Name</author>
+ <date>1970-01-12T13:46:40+00:00</date>
+ <msg xml:space="preserve">second</msg>
+ <paths>
+ <path action="A">second</path>
+ </paths>
+ <extra key="branch">default</extra>
+ </logentry>
+ <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
+ <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
+ <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
+ <author email="person">person</author>
+ <date>1970-01-18T08:40:01+00:00</date>
+ <msg xml:space="preserve">merge</msg>
+ <paths>
+ </paths>
+ <extra key="branch">default</extra>
+ </logentry>
+ <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
+ <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <author email="person">person</author>
+ <date>1970-01-18T08:40:00+00:00</date>
+ <msg xml:space="preserve">new head</msg>
+ <paths>
+ <path action="A">d</path>
+ </paths>
+ <extra key="branch">default</extra>
+ </logentry>
+ <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
+ <branch>foo</branch>
+ <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <author email="person">person</author>
+ <date>1970-01-17T04:53:20+00:00</date>
+ <msg xml:space="preserve">new branch</msg>
+ <paths>
+ </paths>
+ <extra key="branch">foo</extra>
+ </logentry>
+ <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
+ <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <author email="person">person</author>
+ <date>1970-01-16T01:06:40+00:00</date>
+ <msg xml:space="preserve">no user, no domain</msg>
+ <paths>
+ <path action="M">c</path>
+ </paths>
+ <extra key="branch">default</extra>
+ </logentry>
+ <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
+ <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <author email="other@place">other</author>
+ <date>1970-01-14T21:20:00+00:00</date>
+ <msg xml:space="preserve">no person</msg>
+ <paths>
+ <path action="A">c</path>
+ </paths>
+ <extra key="branch">default</extra>
+ </logentry>
+ <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
+ <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <author email="other@place">A. N. Other</author>
+ <date>1970-01-13T17:33:20+00:00</date>
+ <msg xml:space="preserve">other 1
+ other 2
+
+ other 3</msg>
+ <paths>
+ <path action="A">b</path>
+ </paths>
+ <extra key="branch">default</extra>
+ </logentry>
+ <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <parent revision="-1" node="0000000000000000000000000000000000000000" />
+ <author email="user@hostname">User Name</author>
+ <date>1970-01-12T13:46:40+00:00</date>
+ <msg xml:space="preserve">line 1
+ line 2</msg>
+ <paths>
+ <path action="A">a</path>
+ </paths>
+ <extra key="branch">default</extra>
+ </logentry>
+ </log>
+
+
+Error if style not readable:
+
+#if unix-permissions
+ $ touch q
+ $ chmod 0 q
+ $ hg log --style ./q
+ abort: Permission denied: ./q
+ [255]
+#endif
+
+Error if no style:
+
+ $ hg log --style notexist
+ abort: style not found: notexist
+ [255]
+
+Error if style missing key:
+
+ $ echo 'q = q' > t
+ $ hg log --style ./t
+ abort: "changeset" not in template map
+ [255]
+
+Error if include fails:
+
+ $ echo 'changeset = q' >> t
+#if unix-permissions
+ $ hg log --style ./t
+ abort: template file ./q: Permission denied
+ [255]
+ $ rm q
+#endif
+
+Include works:
+
+ $ echo '{rev}' > q
+ $ hg log --style ./t
+ 8
+ 7
+ 6
+ 5
+ 4
+ 3
+ 2
+ 1
+ 0
+
+ui.style works:
+
+ $ echo '[ui]' > .hg/hgrc
+ $ echo 'style = t' >> .hg/hgrc
+ $ hg log
+ 8
+ 7
+ 6
+ 5
+ 4
+ 3
+ 2
+ 1
+ 0
+
+
+Issue338:
+
+ $ hg log --style=changelog > changelog
+
+ $ cat changelog
+ 2020-01-01 test <test>
+
+ * fourth, second, third:
+ third
+ [95c24699272e] [tip]
+
+ 1970-01-12 User Name <user@hostname>
+
+ * second:
+ second
+ [29114dbae42b]
+
+ 1970-01-18 person <person>
+
+ * merge
+ [d41e714fe50d]
+
+ * d:
+ new head
+ [13207e5a10d9]
+
+ 1970-01-17 person <person>
+
+ * new branch
+ [bbe44766e73d] <foo>
+
+ 1970-01-16 person <person>
+
+ * c:
+ no user, no domain
+ [10e46f2dcbf4]
+
+ 1970-01-14 other <other@place>
+
+ * c:
+ no person
+ [97054abb4ab8]
+
+ 1970-01-13 A. N. Other <other@place>
+
+ * b:
+ other 1 other 2
+
+ other 3
+ [b608e9d1a3f0]
+
+ 1970-01-12 User Name <user@hostname>
+
+ * a:
+ line 1 line 2
+ [1e4e1b8f71e0]
+
+
+Issue2130: xml output for 'hg heads' is malformed
+
+ $ hg heads --style changelog
+ 2020-01-01 test <test>
+
+ * fourth, second, third:
+ third
+ [95c24699272e] [tip]
+
+ 1970-01-18 person <person>
+
+ * merge
+ [d41e714fe50d]
+
+ 1970-01-17 person <person>
+
+ * new branch
+ [bbe44766e73d] <foo>
+
+
+Keys work:
+
+ $ for key in author branch branches date desc file_adds file_dels file_mods \
+ > file_copies file_copies_switch files \
+ > manifest node parents rev tags diffstat extras; do
+ > for mode in '' --verbose --debug; do
+ > hg log $mode --template "$key$mode: {$key}\n"
+ > done
+ > done
+ author: test
+ author: User Name <user@hostname>
+ author: person
+ author: person
+ author: person
+ author: person
+ author: other@place
+ author: A. N. Other <other@place>
+ author: User Name <user@hostname>
+ author--verbose: test
+ author--verbose: User Name <user@hostname>
+ author--verbose: person
+ author--verbose: person
+ author--verbose: person
+ author--verbose: person
+ author--verbose: other@place
+ author--verbose: A. N. Other <other@place>
+ author--verbose: User Name <user@hostname>
+ author--debug: test
+ author--debug: User Name <user@hostname>
+ author--debug: person
+ author--debug: person
+ author--debug: person
+ author--debug: person
+ author--debug: other@place
+ author--debug: A. N. Other <other@place>
+ author--debug: User Name <user@hostname>
+ branch: default
+ branch: default
+ branch: default
+ branch: default
+ branch: foo
+ branch: default
+ branch: default
+ branch: default
+ branch: default
+ branch--verbose: default
+ branch--verbose: default
+ branch--verbose: default
+ branch--verbose: default
+ branch--verbose: foo
+ branch--verbose: default
+ branch--verbose: default
+ branch--verbose: default
+ branch--verbose: default
+ branch--debug: default
+ branch--debug: default
+ branch--debug: default
+ branch--debug: default
+ branch--debug: foo
+ branch--debug: default
+ branch--debug: default
+ branch--debug: default
+ branch--debug: default
+ branches:
+ branches:
+ branches:
+ branches:
+ branches: foo
+ branches:
+ branches:
+ branches:
+ branches:
+ branches--verbose:
+ branches--verbose:
+ branches--verbose:
+ branches--verbose:
+ branches--verbose: foo
+ branches--verbose:
+ branches--verbose:
+ branches--verbose:
+ branches--verbose:
+ branches--debug:
+ branches--debug:
+ branches--debug:
+ branches--debug:
+ branches--debug: foo
+ branches--debug:
+ branches--debug:
+ branches--debug:
+ branches--debug:
+ date: 1577872860.00
+ date: 1000000.00
+ date: 1500001.00
+ date: 1500000.00
+ date: 1400000.00
+ date: 1300000.00
+ date: 1200000.00
+ date: 1100000.00
+ date: 1000000.00
+ date--verbose: 1577872860.00
+ date--verbose: 1000000.00
+ date--verbose: 1500001.00
+ date--verbose: 1500000.00
+ date--verbose: 1400000.00
+ date--verbose: 1300000.00
+ date--verbose: 1200000.00
+ date--verbose: 1100000.00
+ date--verbose: 1000000.00
+ date--debug: 1577872860.00
+ date--debug: 1000000.00
+ date--debug: 1500001.00
+ date--debug: 1500000.00
+ date--debug: 1400000.00
+ date--debug: 1300000.00
+ date--debug: 1200000.00
+ date--debug: 1100000.00
+ date--debug: 1000000.00
+ desc: third
+ desc: second
+ desc: merge
+ desc: new head
+ desc: new branch
+ desc: no user, no domain
+ desc: no person
+ desc: other 1
+ other 2
+
+ other 3
+ desc: line 1
+ line 2
+ desc--verbose: third
+ desc--verbose: second
+ desc--verbose: merge
+ desc--verbose: new head
+ desc--verbose: new branch
+ desc--verbose: no user, no domain
+ desc--verbose: no person
+ desc--verbose: other 1
+ other 2
+
+ other 3
+ desc--verbose: line 1
+ line 2
+ desc--debug: third
+ desc--debug: second
+ desc--debug: merge
+ desc--debug: new head
+ desc--debug: new branch
+ desc--debug: no user, no domain
+ desc--debug: no person
+ desc--debug: other 1
+ other 2
+
+ other 3
+ desc--debug: line 1
+ line 2
+ file_adds: fourth third
+ file_adds: second
+ file_adds:
+ file_adds: d
+ file_adds:
+ file_adds:
+ file_adds: c
+ file_adds: b
+ file_adds: a
+ file_adds--verbose: fourth third
+ file_adds--verbose: second
+ file_adds--verbose:
+ file_adds--verbose: d
+ file_adds--verbose:
+ file_adds--verbose:
+ file_adds--verbose: c
+ file_adds--verbose: b
+ file_adds--verbose: a
+ file_adds--debug: fourth third
+ file_adds--debug: second
+ file_adds--debug:
+ file_adds--debug: d
+ file_adds--debug:
+ file_adds--debug:
+ file_adds--debug: c
+ file_adds--debug: b
+ file_adds--debug: a
+ file_dels: second
+ file_dels:
+ file_dels:
+ file_dels:
+ file_dels:
+ file_dels:
+ file_dels:
+ file_dels:
+ file_dels:
+ file_dels--verbose: second
+ file_dels--verbose:
+ file_dels--verbose:
+ file_dels--verbose:
+ file_dels--verbose:
+ file_dels--verbose:
+ file_dels--verbose:
+ file_dels--verbose:
+ file_dels--verbose:
+ file_dels--debug: second
+ file_dels--debug:
+ file_dels--debug:
+ file_dels--debug:
+ file_dels--debug:
+ file_dels--debug:
+ file_dels--debug:
+ file_dels--debug:
+ file_dels--debug:
+ file_mods:
+ file_mods:
+ file_mods:
+ file_mods:
+ file_mods:
+ file_mods: c
+ file_mods:
+ file_mods:
+ file_mods:
+ file_mods--verbose:
+ file_mods--verbose:
+ file_mods--verbose:
+ file_mods--verbose:
+ file_mods--verbose:
+ file_mods--verbose: c
+ file_mods--verbose:
+ file_mods--verbose:
+ file_mods--verbose:
+ file_mods--debug:
+ file_mods--debug:
+ file_mods--debug:
+ file_mods--debug:
+ file_mods--debug:
+ file_mods--debug: c
+ file_mods--debug:
+ file_mods--debug:
+ file_mods--debug:
+ file_copies: fourth (second)
+ file_copies:
+ file_copies:
+ file_copies:
+ file_copies:
+ file_copies:
+ file_copies:
+ file_copies:
+ file_copies:
+ file_copies--verbose: fourth (second)
+ file_copies--verbose:
+ file_copies--verbose:
+ file_copies--verbose:
+ file_copies--verbose:
+ file_copies--verbose:
+ file_copies--verbose:
+ file_copies--verbose:
+ file_copies--verbose:
+ file_copies--debug: fourth (second)
+ file_copies--debug:
+ file_copies--debug:
+ file_copies--debug:
+ file_copies--debug:
+ file_copies--debug:
+ file_copies--debug:
+ file_copies--debug:
+ file_copies--debug:
+ file_copies_switch:
+ file_copies_switch:
+ file_copies_switch:
+ file_copies_switch:
+ file_copies_switch:
+ file_copies_switch:
+ file_copies_switch:
+ file_copies_switch:
+ file_copies_switch:
+ file_copies_switch--verbose:
+ file_copies_switch--verbose:
+ file_copies_switch--verbose:
+ file_copies_switch--verbose:
+ file_copies_switch--verbose:
+ file_copies_switch--verbose:
+ file_copies_switch--verbose:
+ file_copies_switch--verbose:
+ file_copies_switch--verbose:
+ file_copies_switch--debug:
+ file_copies_switch--debug:
+ file_copies_switch--debug:
+ file_copies_switch--debug:
+ file_copies_switch--debug:
+ file_copies_switch--debug:
+ file_copies_switch--debug:
+ file_copies_switch--debug:
+ file_copies_switch--debug:
+ files: fourth second third
+ files: second
+ files:
+ files: d
+ files:
+ files: c
+ files: c
+ files: b
+ files: a
+ files--verbose: fourth second third
+ files--verbose: second
+ files--verbose:
+ files--verbose: d
+ files--verbose:
+ files--verbose: c
+ files--verbose: c
+ files--verbose: b
+ files--verbose: a
+ files--debug: fourth second third
+ files--debug: second
+ files--debug:
+ files--debug: d
+ files--debug:
+ files--debug: c
+ files--debug: c
+ files--debug: b
+ files--debug: a
+ manifest: 6:94961b75a2da
+ manifest: 5:f2dbc354b94e
+ manifest: 4:4dc3def4f9b4
+ manifest: 4:4dc3def4f9b4
+ manifest: 3:cb5a1327723b
+ manifest: 3:cb5a1327723b
+ manifest: 2:6e0e82995c35
+ manifest: 1:4e8d705b1e53
+ manifest: 0:a0c8bcbbb45c
+ manifest--verbose: 6:94961b75a2da
+ manifest--verbose: 5:f2dbc354b94e
+ manifest--verbose: 4:4dc3def4f9b4
+ manifest--verbose: 4:4dc3def4f9b4
+ manifest--verbose: 3:cb5a1327723b
+ manifest--verbose: 3:cb5a1327723b
+ manifest--verbose: 2:6e0e82995c35
+ manifest--verbose: 1:4e8d705b1e53
+ manifest--verbose: 0:a0c8bcbbb45c
+ manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
+ manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
+ manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
+ manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
+ manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
+ manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
+ manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
+ manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
+ manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
+ node: 95c24699272ef57d062b8bccc32c878bf841784a
+ node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
+ node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
+ node: 13207e5a10d9fd28ec424934298e176197f2c67f
+ node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
+ node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
+ node: 97054abb4ab824450e9164180baf491ae0078465
+ node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
+ node: 1e4e1b8f71e05681d422154f5421e385fec3454f
+ node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
+ node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
+ node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
+ node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
+ node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
+ node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
+ node--verbose: 97054abb4ab824450e9164180baf491ae0078465
+ node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
+ node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
+ node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
+ node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
+ node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
+ node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
+ node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
+ node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
+ node--debug: 97054abb4ab824450e9164180baf491ae0078465
+ node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
+ node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
+ parents:
+ parents: -1:000000000000
+ parents: 5:13207e5a10d9 4:bbe44766e73d
+ parents: 3:10e46f2dcbf4
+ parents:
+ parents:
+ parents:
+ parents:
+ parents:
+ parents--verbose:
+ parents--verbose: -1:000000000000
+ parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
+ parents--verbose: 3:10e46f2dcbf4
+ parents--verbose:
+ parents--verbose:
+ parents--verbose:
+ parents--verbose:
+ parents--verbose:
+ parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
+ parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
+ parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
+ parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
+ parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
+ parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
+ parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
+ parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
+ parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
+ rev: 8
+ rev: 7
+ rev: 6
+ rev: 5
+ rev: 4
+ rev: 3
+ rev: 2
+ rev: 1
+ rev: 0
+ rev--verbose: 8
+ rev--verbose: 7
+ rev--verbose: 6
+ rev--verbose: 5
+ rev--verbose: 4
+ rev--verbose: 3
+ rev--verbose: 2
+ rev--verbose: 1
+ rev--verbose: 0
+ rev--debug: 8
+ rev--debug: 7
+ rev--debug: 6
+ rev--debug: 5
+ rev--debug: 4
+ rev--debug: 3
+ rev--debug: 2
+ rev--debug: 1
+ rev--debug: 0
+ tags: tip
+ tags:
+ tags:
+ tags:
+ tags:
+ tags:
+ tags:
+ tags:
+ tags:
+ tags--verbose: tip
+ tags--verbose:
+ tags--verbose:
+ tags--verbose:
+ tags--verbose:
+ tags--verbose:
+ tags--verbose:
+ tags--verbose:
+ tags--verbose:
+ tags--debug: tip
+ tags--debug:
+ tags--debug:
+ tags--debug:
+ tags--debug:
+ tags--debug:
+ tags--debug:
+ tags--debug:
+ tags--debug:
+ diffstat: 3: +2/-1
+ diffstat: 1: +1/-0
+ diffstat: 0: +0/-0
+ diffstat: 1: +1/-0
+ diffstat: 0: +0/-0
+ diffstat: 1: +1/-0
+ diffstat: 1: +4/-0
+ diffstat: 1: +2/-0
+ diffstat: 1: +1/-0
+ diffstat--verbose: 3: +2/-1
+ diffstat--verbose: 1: +1/-0
+ diffstat--verbose: 0: +0/-0
+ diffstat--verbose: 1: +1/-0
+ diffstat--verbose: 0: +0/-0
+ diffstat--verbose: 1: +1/-0
+ diffstat--verbose: 1: +4/-0
+ diffstat--verbose: 1: +2/-0
+ diffstat--verbose: 1: +1/-0
+ diffstat--debug: 3: +2/-1
+ diffstat--debug: 1: +1/-0
+ diffstat--debug: 0: +0/-0
+ diffstat--debug: 1: +1/-0
+ diffstat--debug: 0: +0/-0
+ diffstat--debug: 1: +1/-0
+ diffstat--debug: 1: +4/-0
+ diffstat--debug: 1: +2/-0
+ diffstat--debug: 1: +1/-0
+ extras: branch=default
+ extras: branch=default
+ extras: branch=default
+ extras: branch=default
+ extras: branch=foo
+ extras: branch=default
+ extras: branch=default
+ extras: branch=default
+ extras: branch=default
+ extras--verbose: branch=default
+ extras--verbose: branch=default
+ extras--verbose: branch=default
+ extras--verbose: branch=default
+ extras--verbose: branch=foo
+ extras--verbose: branch=default
+ extras--verbose: branch=default
+ extras--verbose: branch=default
+ extras--verbose: branch=default
+ extras--debug: branch=default
+ extras--debug: branch=default
+ extras--debug: branch=default
+ extras--debug: branch=default
+ extras--debug: branch=foo
+ extras--debug: branch=default
+ extras--debug: branch=default
+ extras--debug: branch=default
+ extras--debug: branch=default
+
+
+Filters work:
+
+ $ hg log --template '{author|domain}\n'
+
+ hostname
+
+
+
+
+ place
+ place
+ hostname
+
+ $ hg log --template '{author|person}\n'
+ test
+ User Name
+ person
+ person
+ person
+ person
+ other
+ A. N. Other
+ User Name
+
+ $ hg log --template '{author|user}\n'
+ test
+ user
+ person
+ person
+ person
+ person
+ other
+ other
+ user
+
+ $ hg log --template '{date|date}\n'
+ Wed Jan 01 10:01:00 2020 +0000
+ Mon Jan 12 13:46:40 1970 +0000
+ Sun Jan 18 08:40:01 1970 +0000
+ Sun Jan 18 08:40:00 1970 +0000
+ Sat Jan 17 04:53:20 1970 +0000
+ Fri Jan 16 01:06:40 1970 +0000
+ Wed Jan 14 21:20:00 1970 +0000
+ Tue Jan 13 17:33:20 1970 +0000
+ Mon Jan 12 13:46:40 1970 +0000
+
+ $ hg log --template '{date|isodate}\n'
+ 2020-01-01 10:01 +0000
+ 1970-01-12 13:46 +0000
+ 1970-01-18 08:40 +0000
+ 1970-01-18 08:40 +0000
+ 1970-01-17 04:53 +0000
+ 1970-01-16 01:06 +0000
+ 1970-01-14 21:20 +0000
+ 1970-01-13 17:33 +0000
+ 1970-01-12 13:46 +0000
+
+ $ hg log --template '{date|isodatesec}\n'
+ 2020-01-01 10:01:00 +0000
+ 1970-01-12 13:46:40 +0000
+ 1970-01-18 08:40:01 +0000
+ 1970-01-18 08:40:00 +0000
+ 1970-01-17 04:53:20 +0000
+ 1970-01-16 01:06:40 +0000
+ 1970-01-14 21:20:00 +0000
+ 1970-01-13 17:33:20 +0000
+ 1970-01-12 13:46:40 +0000
+
+ $ hg log --template '{date|rfc822date}\n'
+ Wed, 01 Jan 2020 10:01:00 +0000
+ Mon, 12 Jan 1970 13:46:40 +0000
+ Sun, 18 Jan 1970 08:40:01 +0000
+ Sun, 18 Jan 1970 08:40:00 +0000
+ Sat, 17 Jan 1970 04:53:20 +0000
+ Fri, 16 Jan 1970 01:06:40 +0000
+ Wed, 14 Jan 1970 21:20:00 +0000
+ Tue, 13 Jan 1970 17:33:20 +0000
+ Mon, 12 Jan 1970 13:46:40 +0000
+
+ $ hg log --template '{desc|firstline}\n'
+ third
+ second
+ merge
+ new head
+ new branch
+ no user, no domain
+ no person
+ other 1
+ line 1
+
+ $ hg log --template '{node|short}\n'
+ 95c24699272e
+ 29114dbae42b
+ d41e714fe50d
+ 13207e5a10d9
+ bbe44766e73d
+ 10e46f2dcbf4
+ 97054abb4ab8
+ b608e9d1a3f0
+ 1e4e1b8f71e0
+
+ $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
+ <changeset author="test"/>
+ <changeset author="User Name &lt;user@hostname&gt;"/>
+ <changeset author="person"/>
+ <changeset author="person"/>
+ <changeset author="person"/>
+ <changeset author="person"/>
+ <changeset author="other@place"/>
+ <changeset author="A. N. Other &lt;other@place&gt;"/>
+ <changeset author="User Name &lt;user@hostname&gt;"/>
+
+ $ hg log --template '{rev}: {children}\n'
+ 8:
+ 7: 8:95c24699272e
+ 6:
+ 5: 6:d41e714fe50d
+ 4: 6:d41e714fe50d
+ 3: 4:bbe44766e73d 5:13207e5a10d9
+ 2: 3:10e46f2dcbf4
+ 1: 2:97054abb4ab8
+ 0: 1:b608e9d1a3f0
+
+Formatnode filter works:
+
+ $ hg -q log -r 0 --template '{node|formatnode}\n'
+ 1e4e1b8f71e0
+
+ $ hg log -r 0 --template '{node|formatnode}\n'
+ 1e4e1b8f71e0
+
+ $ hg -v log -r 0 --template '{node|formatnode}\n'
+ 1e4e1b8f71e0
+
+ $ hg --debug log -r 0 --template '{node|formatnode}\n'
+ 1e4e1b8f71e05681d422154f5421e385fec3454f
+
+Age filter:
+
+ $ hg log --template '{date|age}\n' > /dev/null || exit 1
+
+ >>> from datetime import datetime
+ >>> fp = open('a', 'w')
+ >>> fp.write(str(datetime.now().year + 8) + '-01-01 00:00')
+ >>> fp.close()
+ $ hg add a
+ $ hg commit -m future -d "`cat a`"
+
+ $ hg log -l1 --template '{date|age}\n'
+ 7 years from now
+
+Error on syntax:
+
+ $ echo 'x = "f' >> t
+ $ hg log
+ abort: t:3: unmatched quotes
+ [255]
+
+ $ cd ..
+
+
+latesttag:
+
+ $ hg init latesttag
+ $ cd latesttag
+
+ $ echo a > file
+ $ hg ci -Am a -d '0 0'
+ adding file
+
+ $ echo b >> file
+ $ hg ci -m b -d '1 0'
+
+ $ echo c >> head1
+ $ hg ci -Am h1c -d '2 0'
+ adding head1
+
+ $ hg update -q 1
+ $ echo d >> head2
+ $ hg ci -Am h2d -d '3 0'
+ adding head2
+ created new head
+
+ $ echo e >> head2
+ $ hg ci -m h2e -d '4 0'
+
+ $ hg merge -q
+ $ hg ci -m merge -d '5 0'
+
+No tag set:
+
+ $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+ 5: null+5
+ 4: null+4
+ 3: null+3
+ 2: null+3
+ 1: null+2
+ 0: null+1
+
+One common tag: longuest path wins:
+
+ $ hg tag -r 1 -m t1 -d '6 0' t1
+ $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+ 6: t1+4
+ 5: t1+3
+ 4: t1+2
+ 3: t1+1
+ 2: t1+1
+ 1: t1+0
+ 0: null+1
+
+One ancestor tag: more recent wins:
+
+ $ hg tag -r 2 -m t2 -d '7 0' t2
+ $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+ 7: t2+3
+ 6: t2+2
+ 5: t2+1
+ 4: t1+2
+ 3: t1+1
+ 2: t2+0
+ 1: t1+0
+ 0: null+1
+
+Two branch tags: more recent wins:
+
+ $ hg tag -r 3 -m t3 -d '8 0' t3
+ $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+ 8: t3+5
+ 7: t3+4
+ 6: t3+3
+ 5: t3+2
+ 4: t3+1
+ 3: t3+0
+ 2: t2+0
+ 1: t1+0
+ 0: null+1
+
+Merged tag overrides:
+
+ $ hg tag -r 5 -m t5 -d '9 0' t5
+ $ hg tag -r 3 -m at3 -d '10 0' at3
+ $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+ 10: t5+5
+ 9: t5+4
+ 8: t5+3
+ 7: t5+2
+ 6: t5+1
+ 5: t5+0
+ 4: at3:t3+1
+ 3: at3:t3+0
+ 2: t2+0
+ 1: t1+0
+ 0: null+1
+
+ $ cd ..
+
+
+Style path expansion: issue1948 - ui.style option doesn't work on OSX
+if it is a relative path
+
+ $ mkdir -p home/styles
+
+ $ cat > home/styles/teststyle <<EOF
+ > changeset = 'test {rev}:{node|short}\n'
+ > EOF
+
+ $ HOME=`pwd`/home; export HOME
+
+ $ cat > latesttag/.hg/hgrc <<EOF
+ > [ui]
+ > style = ~/styles/teststyle
+ > EOF
+
+ $ hg -R latesttag tip
+ test 10:dee8f28249af
+
+Test recursive showlist template (issue1989):
+
+ $ cat > style1989 <<EOF
+ > changeset = '{file_mods}{manifest}{extras}'
+ > file_mod = 'M|{author|person}\n'
+ > manifest = '{rev},{author}\n'
+ > extra = '{key}: {author}\n'
+ > EOF
+
+ $ hg -R latesttag log -r tip --style=style1989
+ M|test
+ 10,test
+ branch: test
+
diff --git a/tests/test-commandserver.py b/tests/test-commandserver.py
new file mode 100644
index 0000000..db6e76d
--- /dev/null
+++ b/tests/test-commandserver.py
@@ -0,0 +1,260 @@
+import sys, os, struct, subprocess, cStringIO, re, shutil
+
+def connect(path=None):
+ cmdline = ['hg', 'serve', '--cmdserver', 'pipe']
+ if path:
+ cmdline += ['-R', path]
+
+ server = subprocess.Popen(cmdline, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+
+ return server
+
+def writeblock(server, data):
+ server.stdin.write(struct.pack('>I', len(data)))
+ server.stdin.write(data)
+ server.stdin.flush()
+
+def readchannel(server):
+ data = server.stdout.read(5)
+ if not data:
+ raise EOFError
+ channel, length = struct.unpack('>cI', data)
+ if channel in 'IL':
+ return channel, length
+ else:
+ return channel, server.stdout.read(length)
+
+def runcommand(server, args, output=sys.stdout, error=sys.stderr, input=None):
+ print ' runcommand', ' '.join(args)
+ sys.stdout.flush()
+ server.stdin.write('runcommand\n')
+ writeblock(server, '\0'.join(args))
+
+ if not input:
+ input = cStringIO.StringIO()
+
+ while True:
+ ch, data = readchannel(server)
+ if ch == 'o':
+ output.write(data)
+ output.flush()
+ elif ch == 'e':
+ error.write(data)
+ error.flush()
+ elif ch == 'I':
+ writeblock(server, input.read(data))
+ elif ch == 'L':
+ writeblock(server, input.readline(data))
+ elif ch == 'r':
+ return struct.unpack('>i', data)[0]
+ else:
+ print "unexpected channel %c: %r" % (ch, data)
+ if ch.isupper():
+ return
+
+def check(func, repopath=None):
+ print
+ print 'testing %s:' % func.__name__
+ print
+ sys.stdout.flush()
+ server = connect(repopath)
+ try:
+ return func(server)
+ finally:
+ server.stdin.close()
+ server.wait()
+
+def unknowncommand(server):
+ server.stdin.write('unknowncommand\n')
+
+def hellomessage(server):
+ ch, data = readchannel(server)
+ # escaping python tests output not supported
+ print '%c, %r' % (ch, re.sub('encoding: [a-zA-Z0-9-]+', 'encoding: ***',
+ data))
+
+ # run an arbitrary command to make sure the next thing the server sends
+ # isn't part of the hello message
+ runcommand(server, ['id'])
+
+def checkruncommand(server):
+ # hello block
+ readchannel(server)
+
+ # no args
+ runcommand(server, [])
+
+ # global options
+ runcommand(server, ['id', '--quiet'])
+
+ # make sure global options don't stick through requests
+ runcommand(server, ['id'])
+
+ # --config
+ runcommand(server, ['id', '--config', 'ui.quiet=True'])
+
+ # make sure --config doesn't stick
+ runcommand(server, ['id'])
+
+def inputeof(server):
+ readchannel(server)
+ server.stdin.write('runcommand\n')
+ # close stdin while server is waiting for input
+ server.stdin.close()
+
+ # server exits with 1 if the pipe closed while reading the command
+ print 'server exit code =', server.wait()
+
+def serverinput(server):
+ readchannel(server)
+
+ patch = """
+# HG changeset patch
+# User test
+# Date 0 0
+# Node ID c103a3dec114d882c98382d684d8af798d09d857
+# Parent 0000000000000000000000000000000000000000
+1
+
+diff -r 000000000000 -r c103a3dec114 a
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/a Thu Jan 01 00:00:00 1970 +0000
+@@ -0,0 +1,1 @@
++1
+"""
+
+ runcommand(server, ['import', '-'], input=cStringIO.StringIO(patch))
+ runcommand(server, ['log'])
+
+def cwd(server):
+ """ check that --cwd doesn't persist between requests """
+ readchannel(server)
+ os.mkdir('foo')
+ f = open('foo/bar', 'wb')
+ f.write('a')
+ f.close()
+ runcommand(server, ['--cwd', 'foo', 'st', 'bar'])
+ runcommand(server, ['st', 'foo/bar'])
+ os.remove('foo/bar')
+
+def localhgrc(server):
+ """ check that local configs for the cached repo aren't inherited when -R
+ is used """
+ readchannel(server)
+
+ # the cached repo local hgrc contains ui.foo=bar, so showconfig should
+ # show it
+ runcommand(server, ['showconfig'])
+
+ # but not for this repo
+ runcommand(server, ['init', 'foo'])
+ runcommand(server, ['-R', 'foo', 'showconfig', 'ui', 'defaults'])
+ shutil.rmtree('foo')
+
+def hook(**args):
+ print 'hook talking'
+ print 'now try to read something: %r' % sys.stdin.read()
+
+def hookoutput(server):
+ readchannel(server)
+ runcommand(server, ['--config',
+ 'hooks.pre-identify=python:test-commandserver.hook',
+ 'id'],
+ input=cStringIO.StringIO('some input'))
+
+def outsidechanges(server):
+ readchannel(server)
+ f = open('a', 'ab')
+ f.write('a\n')
+ f.close()
+ runcommand(server, ['status'])
+ os.system('hg ci -Am2')
+ runcommand(server, ['tip'])
+ runcommand(server, ['status'])
+
+def bookmarks(server):
+ readchannel(server)
+ runcommand(server, ['bookmarks'])
+
+ # changes .hg/bookmarks
+ os.system('hg bookmark -i bm1')
+ os.system('hg bookmark -i bm2')
+ runcommand(server, ['bookmarks'])
+
+ # changes .hg/bookmarks.current
+ os.system('hg upd bm1 -q')
+ runcommand(server, ['bookmarks'])
+
+ runcommand(server, ['bookmarks', 'bm3'])
+ f = open('a', 'ab')
+ f.write('a\n')
+ f.close()
+ runcommand(server, ['commit', '-Amm'])
+ runcommand(server, ['bookmarks'])
+
+def tagscache(server):
+ readchannel(server)
+ runcommand(server, ['id', '-t', '-r', '0'])
+ os.system('hg tag -r 0 foo')
+ runcommand(server, ['id', '-t', '-r', '0'])
+
+def setphase(server):
+ readchannel(server)
+ runcommand(server, ['phase', '-r', '.'])
+ os.system('hg phase -r . -p')
+ runcommand(server, ['phase', '-r', '.'])
+
+def rollback(server):
+ readchannel(server)
+ runcommand(server, ['phase', '-r', '.', '-p'])
+ f = open('a', 'ab')
+ f.write('a\n')
+ f.close()
+ runcommand(server, ['commit', '-Am.'])
+ runcommand(server, ['rollback'])
+ runcommand(server, ['phase', '-r', '.'])
+
+def branch(server):
+ readchannel(server)
+ runcommand(server, ['branch'])
+ os.system('hg branch foo')
+ runcommand(server, ['branch'])
+ os.system('hg branch default')
+
+def hgignore(server):
+ readchannel(server)
+ f = open('.hgignore', 'ab')
+ f.write('')
+ f.close()
+ runcommand(server, ['commit', '-Am.'])
+ f = open('ignored-file', 'ab')
+ f.write('')
+ f.close()
+ f = open('.hgignore', 'ab')
+ f.write('ignored-file')
+ f.close()
+ runcommand(server, ['status', '-i', '-u'])
+
+if __name__ == '__main__':
+ os.system('hg init')
+
+ check(hellomessage)
+ check(unknowncommand)
+ check(checkruncommand)
+ check(inputeof)
+ check(serverinput)
+ check(cwd)
+
+ hgrc = open('.hg/hgrc', 'a')
+ hgrc.write('[ui]\nfoo=bar\n')
+ hgrc.close()
+ check(localhgrc)
+ check(hookoutput)
+ check(outsidechanges)
+ check(bookmarks)
+ check(tagscache)
+ check(setphase)
+ check(rollback)
+ check(branch)
+ check(hgignore)
diff --git a/tests/test-commandserver.py.out b/tests/test-commandserver.py.out
new file mode 100644
index 0000000..054ba6c
--- /dev/null
+++ b/tests/test-commandserver.py.out
@@ -0,0 +1,165 @@
+
+testing hellomessage:
+
+o, 'capabilities: getencoding runcommand\nencoding: ***'
+ runcommand id
+000000000000 tip
+
+testing unknowncommand:
+
+abort: unknown command unknowncommand
+
+testing checkruncommand:
+
+ runcommand
+Mercurial Distributed SCM
+
+basic commands:
+
+ add add the specified files on the next commit
+ annotate show changeset information by line for each file
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ init create a new repository in the given directory
+ log show revision history of entire repository or files
+ merge merge working directory with another revision
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ remove remove the specified files on the next commit
+ serve start stand-alone webserver
+ status show changed files in the working directory
+ summary summarize working directory state
+ update update working directory (or switch revisions)
+
+use "hg help" for the full list of commands or "hg -v" for details
+ runcommand id --quiet
+000000000000
+ runcommand id
+000000000000 tip
+ runcommand id --config ui.quiet=True
+000000000000
+ runcommand id
+000000000000 tip
+
+testing inputeof:
+
+server exit code = 1
+
+testing serverinput:
+
+ runcommand import -
+applying patch from stdin
+ runcommand log
+changeset: 0:eff892de26ec
+tag: tip
+user: test
+date: Thu Jan 01 00:00:00 1970 +0000
+summary: 1
+
+
+testing cwd:
+
+ runcommand --cwd foo st bar
+? bar
+ runcommand st foo/bar
+? foo/bar
+
+testing localhgrc:
+
+ runcommand showconfig
+bundle.mainreporoot=$TESTTMP
+defaults.backout=-d "0 0"
+defaults.commit=-d "0 0"
+defaults.tag=-d "0 0"
+ui.slash=True
+ui.foo=bar
+ runcommand init foo
+ runcommand -R foo showconfig ui defaults
+defaults.backout=-d "0 0"
+defaults.commit=-d "0 0"
+defaults.tag=-d "0 0"
+ui.slash=True
+
+testing hookoutput:
+
+ runcommand --config hooks.pre-identify=python:test-commandserver.hook id
+hook talking
+now try to read something: 'some input'
+eff892de26ec tip
+
+testing outsidechanges:
+
+ runcommand status
+M a
+ runcommand tip
+changeset: 1:d3a0a68be6de
+tag: tip
+user: test
+date: Thu Jan 01 00:00:00 1970 +0000
+summary: 2
+
+ runcommand status
+
+testing bookmarks:
+
+ runcommand bookmarks
+no bookmarks set
+ runcommand bookmarks
+ bm1 1:d3a0a68be6de
+ bm2 1:d3a0a68be6de
+ runcommand bookmarks
+ * bm1 1:d3a0a68be6de
+ bm2 1:d3a0a68be6de
+ runcommand bookmarks bm3
+ runcommand commit -Amm
+ runcommand bookmarks
+ bm1 1:d3a0a68be6de
+ bm2 1:d3a0a68be6de
+ * bm3 2:aef17e88f5f0
+
+testing tagscache:
+
+ runcommand id -t -r 0
+
+ runcommand id -t -r 0
+foo
+
+testing setphase:
+
+ runcommand phase -r .
+3: draft
+ runcommand phase -r .
+3: public
+
+testing rollback:
+
+ runcommand phase -r . -p
+no phases changed
+ runcommand commit -Am.
+ runcommand rollback
+repository tip rolled back to revision 3 (undo commit)
+working directory now based on revision 3
+ runcommand phase -r .
+3: public
+
+testing branch:
+
+ runcommand branch
+default
+marked working directory as branch foo
+(branches are permanent and global, did you want a bookmark?)
+ runcommand branch
+foo
+marked working directory as branch default
+(branches are permanent and global, did you want a bookmark?)
+
+testing hgignore:
+
+ runcommand commit -Am.
+adding .hgignore
+ runcommand status -i -u
+I ignored-file
diff --git a/tests/test-commit-amend.t b/tests/test-commit-amend.t
new file mode 100644
index 0000000..8550fb5
--- /dev/null
+++ b/tests/test-commit-amend.t
@@ -0,0 +1,357 @@
+ $ hg init
+
+Setup:
+
+ $ echo a >> a
+ $ hg ci -Am 'base'
+ adding a
+
+Refuse to amend public csets:
+
+ $ hg phase -r . -p
+ $ hg ci --amend
+ abort: cannot amend public changesets
+ [255]
+ $ hg phase -r . -f -d
+
+ $ echo a >> a
+ $ hg ci -Am 'base1'
+
+Nothing to amend:
+
+ $ hg ci --amend
+ nothing changed
+ [1]
+
+ $ cat >> $HGRCPATH <<EOF
+ > [hooks]
+ > pretxncommit.foo = sh -c "echo \"pretxncommit \$HG_NODE\"; hg id -r \$HG_NODE"
+ > EOF
+
+Amending changeset with changes in working dir:
+
+ $ echo a >> a
+ $ hg ci --amend -m 'amend base1'
+ pretxncommit 9cd25b479c51be2f4ed2c38e7abdf7ce67d8e0dc
+ 9cd25b479c51 tip
+ saved backup bundle to $TESTTMP/.hg/strip-backup/489edb5b847d-amend-backup.hg (glob)
+ $ echo 'pretxncommit.foo = ' >> $HGRCPATH
+ $ hg diff -c .
+ diff -r ad120869acf0 -r 9cd25b479c51 a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,3 @@
+ a
+ +a
+ +a
+ $ hg log
+ changeset: 1:9cd25b479c51
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: amend base1
+
+ changeset: 0:ad120869acf0
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: base
+
+
+Add new file:
+
+ $ echo b > b
+ $ hg ci --amend -Am 'amend base1 new file'
+ adding b
+ saved backup bundle to $TESTTMP/.hg/strip-backup/9cd25b479c51-amend-backup.hg (glob)
+
+Remove file that was added in amended commit:
+
+ $ hg rm b
+ $ hg ci --amend -m 'amend base1 remove new file'
+ saved backup bundle to $TESTTMP/.hg/strip-backup/e2bb3ecffd2f-amend-backup.hg (glob)
+
+ $ hg cat b
+ b: no such file in rev 664a9b2d60cd
+ [1]
+
+No changes, just a different message:
+
+ $ hg ci -v --amend -m 'no changes, new message'
+ amending changeset 664a9b2d60cd
+ copying changeset 664a9b2d60cd to ad120869acf0
+ a
+ stripping amended changeset 664a9b2d60cd
+ 1 changesets found
+ saved backup bundle to $TESTTMP/.hg/strip-backup/664a9b2d60cd-amend-backup.hg (glob)
+ 1 changesets found
+ adding branch
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ committed changeset 1:ea6e356ff2ad
+ $ hg diff -c .
+ diff -r ad120869acf0 -r ea6e356ff2ad a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,3 @@
+ a
+ +a
+ +a
+ $ hg log
+ changeset: 1:ea6e356ff2ad
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: no changes, new message
+
+ changeset: 0:ad120869acf0
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: base
+
+
+Disable default date on commit so when -d isn't given, the old date is preserved:
+
+ $ echo '[defaults]' >> $HGRCPATH
+ $ echo 'commit=' >> $HGRCPATH
+
+Test -u/-d:
+
+ $ hg ci --amend -u foo -d '1 0'
+ saved backup bundle to $TESTTMP/.hg/strip-backup/ea6e356ff2ad-amend-backup.hg (glob)
+ $ echo a >> a
+ $ hg ci --amend -u foo -d '1 0'
+ saved backup bundle to $TESTTMP/.hg/strip-backup/377b91ce8b56-amend-backup.hg (glob)
+ $ hg log -r .
+ changeset: 1:2c94e4a5756f
+ tag: tip
+ user: foo
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: no changes, new message
+
+
+Open editor with old commit message if a message isn't given otherwise:
+
+ $ cat > editor.sh << '__EOF__'
+ > #!/bin/sh
+ > cat $1
+ > echo "another precious commit message" > "$1"
+ > __EOF__
+ $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
+ amending changeset 2c94e4a5756f
+ copying changeset 2c94e4a5756f to ad120869acf0
+ no changes, new message
+
+
+ HG: Enter commit message. Lines beginning with 'HG:' are removed.
+ HG: Leave message empty to abort commit.
+ HG: --
+ HG: user: foo
+ HG: branch 'default'
+ HG: changed a
+ a
+ stripping amended changeset 2c94e4a5756f
+ 1 changesets found
+ saved backup bundle to $TESTTMP/.hg/strip-backup/2c94e4a5756f-amend-backup.hg (glob)
+ 1 changesets found
+ adding branch
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ committed changeset 1:ffb49186f961
+
+Same, but with changes in working dir (different code path):
+
+ $ echo a >> a
+ $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
+ amending changeset ffb49186f961
+ another precious commit message
+
+
+ HG: Enter commit message. Lines beginning with 'HG:' are removed.
+ HG: Leave message empty to abort commit.
+ HG: --
+ HG: user: foo
+ HG: branch 'default'
+ HG: changed a
+ a
+ copying changeset 27f3aacd3011 to ad120869acf0
+ a
+ stripping intermediate changeset 27f3aacd3011
+ stripping amended changeset ffb49186f961
+ 2 changesets found
+ saved backup bundle to $TESTTMP/.hg/strip-backup/ffb49186f961-amend-backup.hg (glob)
+ 1 changesets found
+ adding branch
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ committed changeset 1:fb6cca43446f
+
+ $ rm editor.sh
+ $ hg log -r .
+ changeset: 1:fb6cca43446f
+ tag: tip
+ user: foo
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: another precious commit message
+
+
+Moving bookmarks, preserve active bookmark:
+
+ $ hg book book1
+ $ hg book book2
+ $ hg ci --amend -m 'move bookmarks'
+ saved backup bundle to $TESTTMP/.hg/strip-backup/fb6cca43446f-amend-backup.hg (glob)
+ $ hg book
+ book1 1:0cf1c7a51bcf
+ * book2 1:0cf1c7a51bcf
+ $ echo a >> a
+ $ hg ci --amend -m 'move bookmarks'
+ saved backup bundle to $TESTTMP/.hg/strip-backup/0cf1c7a51bcf-amend-backup.hg (glob)
+ $ hg book
+ book1 1:7344472bd951
+ * book2 1:7344472bd951
+
+ $ echo '[defaults]' >> $HGRCPATH
+ $ echo "commit=-d '0 0'" >> $HGRCPATH
+
+Moving branches:
+
+ $ hg branch foo
+ marked working directory as branch foo
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a >> a
+ $ hg ci -m 'branch foo'
+ $ hg branch default -f
+ marked working directory as branch default
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci --amend -m 'back to default'
+ saved backup bundle to $TESTTMP/.hg/strip-backup/1661ca36a2db-amend-backup.hg (glob)
+ $ hg branches
+ default 2:f24ee5961967
+
+Close branch:
+
+ $ hg up -q 0
+ $ echo b >> b
+ $ hg branch foo
+ marked working directory as branch foo
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Am 'fork'
+ adding b
+ $ echo b >> b
+ $ hg ci -mb
+ $ hg ci --amend --close-branch -m 'closing branch foo'
+ saved backup bundle to $TESTTMP/.hg/strip-backup/c962248fa264-amend-backup.hg (glob)
+
+Same thing, different code path:
+
+ $ echo b >> b
+ $ hg ci -m 'reopen branch'
+ reopening closed branch head 4
+ $ echo b >> b
+ $ hg ci --amend --close-branch
+ saved backup bundle to $TESTTMP/.hg/strip-backup/5e302dcc12b8-amend-backup.hg (glob)
+ $ hg branches
+ default 2:f24ee5961967
+
+Refuse to amend merges:
+
+ $ hg up -q default
+ $ hg merge foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci --amend
+ abort: cannot amend while merging
+ [255]
+ $ hg ci -m 'merge'
+ $ hg ci --amend
+ abort: cannot amend merge changesets
+ [255]
+
+Follow copies/renames:
+
+ $ hg mv b c
+ $ hg ci -m 'b -> c'
+ $ hg mv c d
+ $ hg ci --amend -m 'b -> d'
+ saved backup bundle to $TESTTMP/.hg/strip-backup/9c207120aa98-amend-backup.hg (glob)
+ $ hg st --rev '.^' --copies d
+ A d
+ b
+ $ hg cp d e
+ $ hg ci -m 'e = d'
+ $ hg cp e f
+ $ hg ci --amend -m 'f = d'
+ saved backup bundle to $TESTTMP/.hg/strip-backup/fda2b3b27b22-amend-backup.hg (glob)
+ $ hg st --rev '.^' --copies f
+ A f
+ d
+
+ $ mv f f.orig
+ $ hg rm -A f
+ $ hg ci -m removef
+ $ hg cp a f
+ $ mv f.orig f
+ $ hg ci --amend -m replacef
+ saved backup bundle to $TESTTMP/.hg/strip-backup/20a7413547f9-amend-backup.hg (glob)
+ $ hg st --change . --copies
+ $ hg log -r . --template "{file_copies}\n"
+
+
+Move added file (issue3410):
+
+ $ echo g >> g
+ $ hg ci -Am g
+ adding g
+ $ hg mv g h
+ $ hg ci --amend
+ saved backup bundle to $TESTTMP/.hg/strip-backup/5daa77a5d616-amend-backup.hg (glob)
+ $ hg st --change . --copies h
+ A h
+ $ hg log -r . --template "{file_copies}\n"
+
+
+Can't rollback an amend:
+
+ $ hg rollback
+ no rollback information available
+ [1]
+
+Preserve extra dict (issue3430):
+
+ $ hg branch a
+ marked working directory as branch a
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a >> a
+ $ hg ci -ma
+ $ hg ci --amend -m "a'"
+ saved backup bundle to $TESTTMP/.hg/strip-backup/167f8e3031df-amend-backup.hg (glob)
+ $ hg log -r . --template "{branch}\n"
+ a
+ $ hg ci --amend -m "a''"
+ saved backup bundle to $TESTTMP/.hg/strip-backup/ceac1a44c806-amend-backup.hg (glob)
+ $ hg log -r . --template "{branch}\n"
+ a
+
+Also preserve other entries in the dict that are in the old commit,
+first graft something so there's an additional entry:
+
+ $ hg up 0 -q
+ $ echo z > z
+ $ hg ci -Am 'fork'
+ adding z
+ created new head
+ $ hg up 11
+ 5 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg graft 12
+ grafting revision 12
+ $ hg ci --amend -m 'graft amend'
+ saved backup bundle to $TESTTMP/.hg/strip-backup/18a5124daf7a-amend-backup.hg (glob)
+ $ hg log -r . --debug | grep extra
+ extra: branch=a
+ extra: source=2647734878ef0236dda712fae9c1651cf694ea8a
diff --git a/tests/test-commit-multiple.t b/tests/test-commit-multiple.t
new file mode 100644
index 0000000..3337b76
--- /dev/null
+++ b/tests/test-commit-multiple.t
@@ -0,0 +1,133 @@
+# reproduce issue2264, issue2516
+
+create test repo
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > transplant =
+ > graphlog =
+ > EOF
+ $ hg init repo
+ $ cd repo
+ $ template="{rev} {desc|firstline} [{branch}]\n"
+
+# we need to start out with two changesets on the default branch
+# in order to avoid the cute little optimization where transplant
+# pulls rather than transplants
+add initial changesets
+ $ echo feature1 > file1
+ $ hg ci -Am"feature 1"
+ adding file1
+ $ echo feature2 >> file2
+ $ hg ci -Am"feature 2"
+ adding file2
+
+# The changes to 'bugfix' are enough to show the bug: in fact, with only
+# those changes, it's a very noisy crash ("RuntimeError: nothing
+# committed after transplant"). But if we modify a second file in the
+# transplanted changesets, the bug is much more subtle: transplant
+# silently drops the second change to 'bugfix' on the floor, and we only
+# see it when we run 'hg status' after transplanting. Subtle data loss
+# bugs are worse than crashes, so reproduce the subtle case here.
+commit bug fixes on bug fix branch
+ $ hg branch fixes
+ marked working directory as branch fixes
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo fix1 > bugfix
+ $ echo fix1 >> file1
+ $ hg ci -Am"fix 1"
+ adding bugfix
+ $ echo fix2 > bugfix
+ $ echo fix2 >> file1
+ $ hg ci -Am"fix 2"
+ $ hg glog --template="$template"
+ @ 3 fix 2 [fixes]
+ |
+ o 2 fix 1 [fixes]
+ |
+ o 1 feature 2 [default]
+ |
+ o 0 feature 1 [default]
+
+transplant bug fixes onto release branch
+ $ hg update 0
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg branch release
+ marked working directory as branch release
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg transplant 2 3
+ applying [0-9a-f]{12} (re)
+ [0-9a-f]{12} transplanted to [0-9a-f]{12} (re)
+ applying [0-9a-f]{12} (re)
+ [0-9a-f]{12} transplanted to [0-9a-f]{12} (re)
+ $ hg glog --template="$template"
+ @ 5 fix 2 [release]
+ |
+ o 4 fix 1 [release]
+ |
+ | o 3 fix 2 [fixes]
+ | |
+ | o 2 fix 1 [fixes]
+ | |
+ | o 1 feature 2 [default]
+ |/
+ o 0 feature 1 [default]
+
+ $ hg status
+ $ hg status --rev 0:4
+ M file1
+ A bugfix
+ $ hg status --rev 4:5
+ M bugfix
+ M file1
+
+now test that we fixed the bug for all scripts/extensions
+ $ cat > $TESTTMP/committwice.py <<__EOF__
+ > from mercurial import ui, hg, match, node
+ > from time import sleep
+ >
+ > def replacebyte(fn, b):
+ > f = open(fn, "rb+")
+ > f.seek(0, 0)
+ > f.write(b)
+ > f.close()
+ >
+ > def printfiles(repo, rev):
+ > print "revision %s files: %s" % (rev, repo[rev].files())
+ >
+ > repo = hg.repository(ui.ui(), '.')
+ > assert len(repo) == 6, \
+ > "initial: len(repo): %d, expected: 6" % len(repo)
+ >
+ > replacebyte("bugfix", "u")
+ > sleep(2)
+ > try:
+ > print "PRE: len(repo): %d" % len(repo)
+ > wlock = repo.wlock()
+ > lock = repo.lock()
+ > replacebyte("file1", "x")
+ > repo.commit(text="x", user="test", date=(0, 0))
+ > replacebyte("file1", "y")
+ > repo.commit(text="y", user="test", date=(0, 0))
+ > print "POST: len(repo): %d" % len(repo)
+ > finally:
+ > lock.release()
+ > wlock.release()
+ > printfiles(repo, 6)
+ > printfiles(repo, 7)
+ > __EOF__
+ $ $PYTHON $TESTTMP/committwice.py
+ PRE: len(repo): 6
+ POST: len(repo): 8
+ revision 6 files: ['bugfix', 'file1']
+ revision 7 files: ['file1']
+
+Do a size-preserving modification outside of that process
+ $ echo abcd > bugfix
+ $ hg status
+ M bugfix
+ $ hg log --template "{rev} {desc} {files}\n" -r5:
+ 5 fix 2 bugfix file1
+ 6 x bugfix file1
+ 7 y file1
+
+ $ cd ..
diff --git a/tests/test-commit-unresolved.t b/tests/test-commit-unresolved.t
new file mode 100644
index 0000000..70a3300
--- /dev/null
+++ b/tests/test-commit-unresolved.t
@@ -0,0 +1,49 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "graphlog=" >> $HGRCPATH
+
+ $ addcommit () {
+ > echo $1 > $1
+ > hg add $1
+ > hg commit -d "${2} 0" -m $1
+ > }
+
+ $ commit () {
+ > hg commit -d "${2} 0" -m $1
+ > }
+
+ $ hg init a
+ $ cd a
+ $ addcommit "A" 0
+ $ addcommit "B" 1
+ $ echo "C" >> A
+ $ commit "C" 2
+
+ $ hg update -C 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo "D" >> A
+ $ commit "D" 3
+ created new head
+
+Merging a conflict araises
+
+ $ hg merge
+ merging A
+ warning: conflicts during merge.
+ merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+
+Correct the conflict without marking the file as resolved
+
+ $ echo "ABCD" > A
+ $ hg commit -m "Merged"
+ abort: unresolved merge conflicts (see hg help resolve)
+ [255]
+
+Mark the conflict as resolved and commit
+
+ $ hg resolve -m A
+ $ hg commit -m "Merged"
+
+ $ cd ..
diff --git a/tests/test-commit.t b/tests/test-commit.t
new file mode 100644
index 0000000..21fd277
--- /dev/null
+++ b/tests/test-commit.t
@@ -0,0 +1,307 @@
+commit date test
+
+ $ hg init test
+ $ cd test
+ $ echo foo > foo
+ $ hg add foo
+ $ HGEDITOR=true hg commit -m ""
+ abort: empty commit message
+ [255]
+ $ hg commit -d '0 0' -m commit-1
+ $ echo foo >> foo
+ $ hg commit -d '1 4444444' -m commit-3
+ abort: impossible time zone offset: 4444444
+ [255]
+ $ hg commit -d '1 15.1' -m commit-4
+ abort: invalid date: '1\t15.1'
+ [255]
+ $ hg commit -d 'foo bar' -m commit-5
+ abort: invalid date: 'foo bar'
+ [255]
+ $ hg commit -d ' 1 4444' -m commit-6
+ $ hg commit -d '111111111111 0' -m commit-7
+ abort: date exceeds 32 bits: 111111111111
+ [255]
+ $ hg commit -d '-7654321 3600' -m commit-7
+ abort: negative date value: -7654321
+ [255]
+
+commit added file that has been deleted
+
+ $ echo bar > bar
+ $ hg add bar
+ $ rm bar
+ $ hg commit -m commit-8
+ nothing changed (1 missing files, see 'hg status')
+ [1]
+ $ hg commit -m commit-8-2 bar
+ abort: bar: file not found!
+ [255]
+
+ $ hg -q revert -a --no-backup
+
+ $ mkdir dir
+ $ echo boo > dir/file
+ $ hg add
+ adding dir/file (glob)
+ $ hg -v commit -m commit-9 dir
+ dir/file
+ committed changeset 2:d2a76177cb42
+
+ $ echo > dir.file
+ $ hg add
+ adding dir.file
+ $ hg commit -m commit-10 dir dir.file
+ abort: dir: no match under directory!
+ [255]
+
+ $ echo >> dir/file
+ $ mkdir bleh
+ $ mkdir dir2
+ $ cd bleh
+ $ hg commit -m commit-11 .
+ abort: bleh: no match under directory!
+ [255]
+ $ hg commit -m commit-12 ../dir ../dir2
+ abort: dir2: no match under directory!
+ [255]
+ $ hg -v commit -m commit-13 ../dir
+ dir/file
+ committed changeset 3:1cd62a2d8db5
+ $ cd ..
+
+ $ hg commit -m commit-14 does-not-exist
+ abort: does-not-exist: * (glob)
+ [255]
+
+#if symlink
+ $ ln -s foo baz
+ $ hg commit -m commit-15 baz
+ abort: baz: file not tracked!
+ [255]
+#endif
+
+ $ touch quux
+ $ hg commit -m commit-16 quux
+ abort: quux: file not tracked!
+ [255]
+ $ echo >> dir/file
+ $ hg -v commit -m commit-17 dir/file
+ dir/file
+ committed changeset 4:49176991390e
+
+An empty date was interpreted as epoch origin
+
+ $ echo foo >> foo
+ $ hg commit -d '' -m commit-no-date
+ $ hg tip --template '{date|isodate}\n' | grep '1970'
+ [1]
+
+Make sure we do not obscure unknown requires file entries (issue2649)
+
+ $ echo foo >> foo
+ $ echo fake >> .hg/requires
+ $ hg commit -m bla
+ abort: unknown repository format: requires features 'fake' (upgrade Mercurial)!
+ [255]
+
+ $ cd ..
+
+
+partial subdir commit test
+
+ $ hg init test2
+ $ cd test2
+ $ mkdir foo
+ $ echo foo > foo/foo
+ $ mkdir bar
+ $ echo bar > bar/bar
+ $ hg add
+ adding bar/bar (glob)
+ adding foo/foo (glob)
+ $ hg ci -m commit-subdir-1 foo
+ $ hg ci -m commit-subdir-2 bar
+
+subdir log 1
+
+ $ hg log -v foo
+ changeset: 0:f97e73a25882
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: foo/foo
+ description:
+ commit-subdir-1
+
+
+
+subdir log 2
+
+ $ hg log -v bar
+ changeset: 1:aa809156d50d
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: bar/bar
+ description:
+ commit-subdir-2
+
+
+
+full log
+
+ $ hg log -v
+ changeset: 1:aa809156d50d
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: bar/bar
+ description:
+ commit-subdir-2
+
+
+ changeset: 0:f97e73a25882
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: foo/foo
+ description:
+ commit-subdir-1
+
+
+ $ cd ..
+
+
+dot and subdir commit test
+
+ $ hg init test3
+ $ cd test3
+ $ mkdir foo
+ $ echo foo content > foo/plain-file
+ $ hg add foo/plain-file
+ $ hg ci -m commit-foo-subdir foo
+ $ echo modified foo content > foo/plain-file
+ $ hg ci -m commit-foo-dot .
+
+full log
+
+ $ hg log -v
+ changeset: 1:95b38e3a5b2e
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: foo/plain-file
+ description:
+ commit-foo-dot
+
+
+ changeset: 0:65d4e9386227
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: foo/plain-file
+ description:
+ commit-foo-subdir
+
+
+
+subdir log
+
+ $ cd foo
+ $ hg log .
+ changeset: 1:95b38e3a5b2e
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit-foo-dot
+
+ changeset: 0:65d4e9386227
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit-foo-subdir
+
+ $ cd ..
+ $ cd ..
+
+Issue1049: Hg permits partial commit of merge without warning
+
+ $ hg init issue1049
+ $ cd issue1049
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+ $ echo a >> a
+ $ hg ci -mb
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b >> a
+ $ hg ci -mc
+ created new head
+ $ HGMERGE=true hg merge
+ merging a
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+should fail because we are specifying a file name
+
+ $ hg ci -mmerge a
+ abort: cannot partially commit a merge (do not specify files or patterns)
+ [255]
+
+should fail because we are specifying a pattern
+
+ $ hg ci -mmerge -I a
+ abort: cannot partially commit a merge (do not specify files or patterns)
+ [255]
+
+should succeed
+
+ $ hg ci -mmerge
+ $ cd ..
+
+
+test commit message content
+
+ $ hg init commitmsg
+ $ cd commitmsg
+ $ echo changed > changed
+ $ echo removed > removed
+ $ hg ci -qAm init
+
+ $ hg rm removed
+ $ echo changed >> changed
+ $ echo added > added
+ $ hg add added
+ $ HGEDITOR=cat hg ci -A
+
+
+ HG: Enter commit message. Lines beginning with 'HG:' are removed.
+ HG: Leave message empty to abort commit.
+ HG: --
+ HG: user: test
+ HG: branch 'default'
+ HG: added added
+ HG: changed changed
+ HG: removed removed
+ abort: empty commit message
+ [255]
+ $ cd ..
+
+
+commit copy
+
+ $ hg init dir2
+ $ cd dir2
+ $ echo bleh > bar
+ $ hg add bar
+ $ hg ci -m 'add bar'
+
+ $ hg cp bar foo
+ $ echo >> bar
+ $ hg ci -m 'cp bar foo; change bar'
+
+ $ hg debugrename foo
+ foo renamed from bar:26d3ca0dfd18e44d796b564e38dd173c9668d3a9
+ $ hg debugindex bar
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 6 ..... 0 26d3ca0dfd18 000000000000 000000000000 (re)
+ 1 6 7 ..... 1 d267bddd54f7 26d3ca0dfd18 000000000000 (re)
+
+ $ cd ..
diff --git a/tests/test-committer.t b/tests/test-committer.t
new file mode 100644
index 0000000..5208f4e
--- /dev/null
+++ b/tests/test-committer.t
@@ -0,0 +1,65 @@
+ $ unset HGUSER
+ $ EMAIL="My Name <myname@example.com>"
+ $ export EMAIL
+
+ $ hg init test
+ $ cd test
+ $ touch asdf
+ $ hg add asdf
+ $ hg commit -m commit-1
+ $ hg tip
+ changeset: 0:53f268a58230
+ tag: tip
+ user: My Name <myname@example.com>
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit-1
+
+
+ $ unset EMAIL
+ $ echo 1234 > asdf
+ $ hg commit -u "foo@bar.com" -m commit-1
+ $ hg tip
+ changeset: 1:3871b2a9e9bf
+ tag: tip
+ user: foo@bar.com
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit-1
+
+ $ echo "[ui]" >> .hg/hgrc
+ $ echo "username = foobar <foo@bar.com>" >> .hg/hgrc
+ $ echo 12 > asdf
+ $ hg commit -m commit-1
+ $ hg tip
+ changeset: 2:8eeac6695c1c
+ tag: tip
+ user: foobar <foo@bar.com>
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit-1
+
+ $ echo 1 > asdf
+ $ hg commit -u "foo@bar.com" -m commit-1
+ $ hg tip
+ changeset: 3:957606a725e4
+ tag: tip
+ user: foo@bar.com
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit-1
+
+ $ echo 123 > asdf
+ $ echo "[ui]" > .hg/hgrc
+ $ echo "username = " >> .hg/hgrc
+ $ hg commit -m commit-1
+ abort: no username supplied (see "hg help config")
+ [255]
+ $ rm .hg/hgrc
+ $ hg commit -m commit-1 2>&1
+ no username found, using '[^']*' instead (re)
+
+ $ echo space > asdf
+ $ hg commit -u ' ' -m commit-1
+ transaction abort!
+ rollback completed
+ abort: empty username!
+ [255]
+
+ $ cd ..
diff --git a/tests/test-config-case.t b/tests/test-config-case.t
new file mode 100644
index 0000000..9ef0be8
--- /dev/null
+++ b/tests/test-config-case.t
@@ -0,0 +1,11 @@
+hide outer repo
+ $ hg init
+
+ $ echo '[Section]' >> $HGRCPATH
+ $ echo 'KeY = Case Sensitive' >> $HGRCPATH
+ $ echo 'key = lower case' >> $HGRCPATH
+
+ $ hg showconfig Section
+ Section.KeY=Case Sensitive
+ Section.key=lower case
+
diff --git a/tests/test-conflict.t b/tests/test-conflict.t
new file mode 100644
index 0000000..113b429
--- /dev/null
+++ b/tests/test-conflict.t
@@ -0,0 +1,33 @@
+ $ hg init
+ $ echo "nothing" > a
+ $ hg add a
+ $ hg commit -m ancestor
+ $ echo "something" > a
+ $ hg commit -m branch1
+ $ hg co 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo "something else" > a
+ $ hg commit -m branch2
+ created new head
+
+ $ hg merge 1
+ merging a
+ warning: conflicts during merge.
+ merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+
+ $ hg id
+ 32e80765d7fe+75234512624c+ tip
+
+ $ cat a
+ <<<<<<< local
+ something else
+ =======
+ something
+ >>>>>>> other
+
+ $ hg status
+ M a
+ ? a.orig
diff --git a/tests/test-confused-revert.t b/tests/test-confused-revert.t
new file mode 100644
index 0000000..3a1e0f4
--- /dev/null
+++ b/tests/test-confused-revert.t
@@ -0,0 +1,82 @@
+ $ hg init
+ $ echo foo > a
+ $ hg add a
+ $ hg commit -m "1"
+
+ $ echo bar > b
+ $ hg add b
+ $ hg remove a
+
+Should show a removed and b added:
+
+ $ hg status
+ A b
+ R a
+
+ $ hg revert --all
+ undeleting a
+ forgetting b
+
+Should show b unknown and a back to normal:
+
+ $ hg status
+ ? b
+
+ $ rm b
+
+ $ hg co -C 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo foo-a > a
+ $ hg commit -m "2a"
+
+ $ hg co -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo foo-b > a
+ $ hg commit -m "2b"
+ created new head
+
+ $ HGMERGE=true hg merge 1
+ merging a
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+Should show foo-b:
+
+ $ cat a
+ foo-b
+
+ $ echo bar > b
+ $ hg add b
+ $ rm a
+ $ hg remove a
+
+Should show a removed and b added:
+
+ $ hg status
+ A b
+ R a
+
+Revert should fail:
+
+ $ hg revert
+ abort: uncommitted merge with no revision specified
+ (use "hg update" or see "hg help revert")
+ [255]
+
+Revert should be ok now:
+
+ $ hg revert -r2 --all
+ undeleting a
+ forgetting b
+
+Should show b unknown and a marked modified (merged):
+
+ $ hg status
+ M a
+ ? b
+
+Should show foo-b:
+
+ $ cat a
+ foo-b
+
diff --git a/tests/test-context.py b/tests/test-context.py
new file mode 100644
index 0000000..e54e526
--- /dev/null
+++ b/tests/test-context.py
@@ -0,0 +1,32 @@
+import os
+from mercurial import hg, ui, context, encoding
+
+u = ui.ui()
+
+repo = hg.repository(u, 'test1', create=1)
+os.chdir('test1')
+
+# create 'foo' with fixed time stamp
+f = open('foo', 'w')
+f.write('foo\n')
+f.close()
+os.utime('foo', (1000, 1000))
+
+# add+commit 'foo'
+repo[None].add(['foo'])
+repo.commit(text='commit1', date="0 0")
+
+print "workingfilectx.date =", repo[None]['foo'].date()
+
+# test memctx with non-ASCII commit message
+
+def filectxfn(repo, memctx, path):
+ return context.memfilectx("foo", "")
+
+ctx = context.memctx(repo, ['tip', None],
+ encoding.tolocal("Gr\xc3\xbcezi!"),
+ ["foo"], filectxfn)
+ctx.commit()
+for enc in "ASCII", "Latin-1", "UTF-8":
+ encoding.encoding = enc
+ print "%-8s: %s" % (enc, repo["tip"].description())
diff --git a/tests/test-context.py.out b/tests/test-context.py.out
new file mode 100644
index 0000000..9ad193d
--- /dev/null
+++ b/tests/test-context.py.out
@@ -0,0 +1,4 @@
+workingfilectx.date = (1000, 0)
+ASCII : Gr?ezi!
+Latin-1 : Grüezi!
+UTF-8 : Grüezi!
diff --git a/tests/test-contrib.t b/tests/test-contrib.t
new file mode 100644
index 0000000..98acb43
--- /dev/null
+++ b/tests/test-contrib.t
@@ -0,0 +1,306 @@
+Set vars:
+
+ $ CONTRIBDIR="$TESTDIR/../contrib"
+
+Prepare repo-a:
+
+ $ hg init repo-a
+ $ cd repo-a
+
+ $ echo this is file a > a
+ $ hg add a
+ $ hg commit -m first
+
+ $ echo adding to file a >> a
+ $ hg commit -m second
+
+ $ echo adding more to file a >> a
+ $ hg commit -m third
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+
+Dumping revlog of file a to stdout:
+
+ $ python "$CONTRIBDIR/dumprevlog" .hg/store/data/a.i
+ file: .hg/store/data/a.i
+ node: 183d2312b35066fb6b3b449b84efc370d50993d0
+ linkrev: 0
+ parents: 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
+ length: 15
+ -start-
+ this is file a
+
+ -end-
+ node: b1047953b6e6b633c0d8197eaa5116fbdfd3095b
+ linkrev: 1
+ parents: 183d2312b35066fb6b3b449b84efc370d50993d0 0000000000000000000000000000000000000000
+ length: 32
+ -start-
+ this is file a
+ adding to file a
+
+ -end-
+ node: 8c4fd1f7129b8cdec6c7f58bf48fb5237a4030c1
+ linkrev: 2
+ parents: b1047953b6e6b633c0d8197eaa5116fbdfd3095b 0000000000000000000000000000000000000000
+ length: 54
+ -start-
+ this is file a
+ adding to file a
+ adding more to file a
+
+ -end-
+
+Dump all revlogs to file repo.dump:
+
+ $ find .hg/store -name "*.i" | sort | xargs python "$CONTRIBDIR/dumprevlog" > ../repo.dump
+ $ cd ..
+
+Undumping into repo-b:
+
+ $ hg init repo-b
+ $ cd repo-b
+ $ python "$CONTRIBDIR/undumprevlog" < ../repo.dump
+ .hg/store/00changelog.i
+ .hg/store/00manifest.i
+ .hg/store/data/a.i
+ $ cd ..
+
+Rebuild fncache with clone --pull:
+
+ $ hg clone --pull -U repo-b repo-c
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+
+Verify:
+
+ $ hg -R repo-c verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+
+Compare repos:
+
+ $ hg -R repo-c incoming repo-a
+ comparing with repo-a
+ searching for changes
+ no changes found
+ [1]
+
+ $ hg -R repo-a incoming repo-c
+ comparing with repo-c
+ searching for changes
+ no changes found
+ [1]
+
+
+#if hardlink
+
+Test shrink-revlog:
+ $ cd repo-a
+ $ hg --config extensions.shrink="$CONTRIBDIR/shrink-revlog.py" shrink
+ shrinking $TESTTMP/repo-a/.hg/store/00manifest.i (glob)
+ reading revs
+ sorting revs
+ writing revs
+ old file size: 324 bytes ( 0.0 MiB)
+ new file size: 324 bytes ( 0.0 MiB)
+ shrinkage: 0.0% (1.0x)
+ note: old revlog saved in:
+ $TESTTMP/repo-a/.hg/store/00manifest.i.old (glob)
+ $TESTTMP/repo-a/.hg/store/00manifest.d.old (glob)
+ (You can delete those files when you are satisfied that your
+ repository is still sane. Running 'hg verify' is strongly recommended.)
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+ $ cd ..
+
+#endif
+
+Test simplemerge command:
+
+ $ cp "$CONTRIBDIR/simplemerge" .
+ $ echo base > base
+ $ echo local > local
+ $ cat base >> local
+ $ cp local orig
+ $ cat base > other
+ $ echo other >> other
+
+changing local directly
+
+ $ python simplemerge local base other && echo "merge succeeded"
+ merge succeeded
+ $ cat local
+ local
+ base
+ other
+ $ cp orig local
+
+printing to stdout
+
+ $ python simplemerge -p local base other
+ local
+ base
+ other
+
+local:
+
+ $ cat local
+ local
+ base
+
+conflicts
+
+ $ cp base conflict-local
+ $ cp other conflict-other
+ $ echo not other >> conflict-local
+ $ echo end >> conflict-local
+ $ echo end >> conflict-other
+ $ python simplemerge -p conflict-local base conflict-other
+ base
+ <<<<<<< conflict-local
+ not other
+ =======
+ other
+ >>>>>>> conflict-other
+ end
+ warning: conflicts during merge.
+ [1]
+
+--no-minimal
+
+ $ python simplemerge -p --no-minimal conflict-local base conflict-other
+ base
+ <<<<<<< conflict-local
+ not other
+ end
+ =======
+ other
+ end
+ >>>>>>> conflict-other
+ warning: conflicts during merge.
+ [1]
+
+1 label
+
+ $ python simplemerge -p -L foo conflict-local base conflict-other
+ base
+ <<<<<<< foo
+ not other
+ =======
+ other
+ >>>>>>> conflict-other
+ end
+ warning: conflicts during merge.
+ [1]
+
+2 labels
+
+ $ python simplemerge -p -L foo -L bar conflict-local base conflict-other
+ base
+ <<<<<<< foo
+ not other
+ =======
+ other
+ >>>>>>> bar
+ end
+ warning: conflicts during merge.
+ [1]
+
+too many labels
+
+ $ python simplemerge -p -L foo -L bar -L baz conflict-local base conflict-other
+ abort: can only specify two labels.
+ [255]
+
+binary file
+
+ $ python -c "f = file('binary-local', 'w'); f.write('\x00'); f.close()"
+ $ cat orig >> binary-local
+ $ python simplemerge -p binary-local base other
+ warning: binary-local looks like a binary file.
+ [1]
+
+binary file --text
+
+ $ python simplemerge -a -p binary-local base other 2>&1
+ warning: binary-local looks like a binary file.
+ \x00local (esc)
+ base
+ other
+
+help
+
+ $ python simplemerge --help
+ simplemerge [OPTS] LOCAL BASE OTHER
+
+ Simple three-way file merge utility with a minimal feature set.
+
+ Apply to LOCAL the changes necessary to go from BASE to OTHER.
+
+ By default, LOCAL is overwritten with the results of this operation.
+
+ options:
+ -L --label labels to use on conflict markers
+ -a --text treat all files as text
+ -p --print print results instead of overwriting LOCAL
+ --no-minimal do not try to minimize conflict regions
+ -h --help display help and exit
+ -q --quiet suppress output
+
+wrong number of arguments
+
+ $ python simplemerge
+ simplemerge: wrong number of arguments
+ simplemerge [OPTS] LOCAL BASE OTHER
+
+ Simple three-way file merge utility with a minimal feature set.
+
+ Apply to LOCAL the changes necessary to go from BASE to OTHER.
+
+ By default, LOCAL is overwritten with the results of this operation.
+
+ options:
+ -L --label labels to use on conflict markers
+ -a --text treat all files as text
+ -p --print print results instead of overwriting LOCAL
+ --no-minimal do not try to minimize conflict regions
+ -h --help display help and exit
+ -q --quiet suppress output
+ [1]
+
+bad option
+
+ $ python simplemerge --foo -p local base other
+ simplemerge: option --foo not recognized
+ simplemerge [OPTS] LOCAL BASE OTHER
+
+ Simple three-way file merge utility with a minimal feature set.
+
+ Apply to LOCAL the changes necessary to go from BASE to OTHER.
+
+ By default, LOCAL is overwritten with the results of this operation.
+
+ options:
+ -L --label labels to use on conflict markers
+ -a --text treat all files as text
+ -p --print print results instead of overwriting LOCAL
+ --no-minimal do not try to minimize conflict regions
+ -h --help display help and exit
+ -q --quiet suppress output
+ [1]
diff --git a/tests/test-convert-authormap.t b/tests/test-convert-authormap.t
new file mode 100644
index 0000000..9d5ca9f
--- /dev/null
+++ b/tests/test-convert-authormap.t
@@ -0,0 +1,58 @@
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert=
+ > EOF
+
+Prepare orig repo
+
+ $ hg init orig
+ $ cd orig
+ $ echo foo > foo
+ $ HGUSER='user name' hg ci -qAm 'foo'
+ $ cd ..
+
+Explicit --authors
+
+ $ cat > authormap.txt <<EOF
+ > user name = Long User Name
+ >
+ > # comment
+ > this line is ignored
+ > EOF
+ $ hg convert --authors authormap.txt orig new
+ initializing destination new repository
+ ignoring bad line in author map file authormap.txt: this line is ignored
+ scanning source...
+ sorting...
+ converting...
+ 0 foo
+ writing author map file $TESTTMP/new/.hg/authormap (glob)
+ $ cat new/.hg/authormap
+ user name=Long User Name
+ $ hg -Rnew log
+ changeset: 0:d89716e88087
+ tag: tip
+ user: Long User Name
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: foo
+
+ $ rm -rf new
+
+Implicit .hg/authormap
+
+ $ hg init new
+ $ mv authormap.txt new/.hg/authormap
+ $ hg convert orig new
+ ignoring bad line in author map file $TESTTMP/new/.hg/authormap: this line is ignored (glob)
+ scanning source...
+ sorting...
+ converting...
+ 0 foo
+ $ hg -Rnew log
+ changeset: 0:d89716e88087
+ tag: tip
+ user: Long User Name
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: foo
+
diff --git a/tests/test-convert-baz.t b/tests/test-convert-baz.t
new file mode 100644
index 0000000..763e83c
--- /dev/null
+++ b/tests/test-convert-baz.t
@@ -0,0 +1,163 @@
+ $ "$TESTDIR/hghave" baz symlink || exit 80
+
+ $ baz my-id "mercurial <mercurial@selenic.com>"
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert=" >> $HGRCPATH
+ $ echo 'graphlog =' >> $HGRCPATH
+
+create baz archive
+ $ baz make-archive baz@mercurial--convert hg-test-convert-baz
+
+initialize baz repo
+ $ mkdir baz-repo
+ $ cd baz-repo/
+ $ baz init-tree baz@mercurial--convert/baz--test--0
+ $ baz import
+ * creating version baz@mercurial--convert/baz--test--0
+ * imported baz@mercurial--convert/baz--test--0
+
+create initial files
+ $ echo 'this is a file' > a
+ $ baz add a
+ $ mkdir src
+ $ baz add src
+ $ cd src
+ $ dd count=1 if=/dev/zero of=b > /dev/null 2> /dev/null
+ $ baz add b
+HACK: hide GNU tar-1.22 "tar: The --preserve option is deprecated, use --preserve-permissions --preserve-order instead"
+ $ baz commit -s "added a file, src and src/b (binary)" 2>&1 | grep -v '^tar'
+ * build pristine tree for baz@mercurial--convert/baz--test--0--base-0
+ * Scanning for full-tree revision: .
+ * from import revision: baz@mercurial--convert/baz--test--0--base-0
+ A/ .arch-ids
+ A/ src
+ A/ src/.arch-ids
+ A .arch-ids/a.id
+ A a
+ A src/.arch-ids/=id
+ A src/.arch-ids/b.id
+ A src/b
+ * update pristine tree (baz@mercurial--convert/baz--test--0--base-0 => baz--test--0--patch-1)
+ * committed baz@mercurial--convert/baz--test--0--patch-1
+
+create link file and modify a
+ $ ln -s ../a a-link
+ $ baz add a-link
+ $ echo 'this a modification to a' >> ../a
+ $ baz commit -s "added link to a and modify a"
+ A src/.arch-ids/a-link.id
+ A src/a-link
+ M a
+ * update pristine tree (baz@mercurial--convert/baz--test--0--patch-1 => baz--test--0--patch-2)
+ * committed baz@mercurial--convert/baz--test--0--patch-2
+
+create second link and modify b
+ $ ln -s ../a a-link-2
+ $ baz add a-link-2
+ $ dd count=1 seek=1 if=/dev/zero of=b > /dev/null 2> /dev/null
+ $ baz commit -s "added second link and modify b"
+ A src/.arch-ids/a-link-2.id
+ A src/a-link-2
+ Mb src/b
+ * update pristine tree (baz@mercurial--convert/baz--test--0--patch-2 => baz--test--0--patch-3)
+ * committed baz@mercurial--convert/baz--test--0--patch-3
+
+b file to link and a-link-2 to regular file
+ $ rm -f a-link-2
+ $ echo 'this is now a regular file' > a-link-2
+ $ ln -sf ../a b
+ $ baz commit -s "file to link and link to file test"
+ fl src/b
+ lf src/a-link-2
+ * update pristine tree (baz@mercurial--convert/baz--test--0--patch-3 => baz--test--0--patch-4)
+ * committed baz@mercurial--convert/baz--test--0--patch-4
+
+move a-link-2 file and src directory
+ $ cd ..
+ $ baz mv src/a-link-2 c
+ $ baz mv src test
+ $ baz commit -s "move and rename a-link-2 file and src directory"
+ D/ src/.arch-ids
+ A/ test/.arch-ids
+ /> src test
+ => src/.arch-ids/a-link-2.id .arch-ids/c.id
+ => src/a-link-2 c
+ => src/.arch-ids/=id test/.arch-ids/=id
+ => src/.arch-ids/a-link.id test/.arch-ids/a-link.id
+ => src/.arch-ids/b.id test/.arch-ids/b.id
+ * update pristine tree (baz@mercurial--convert/baz--test--0--patch-4 => baz--test--0--patch-5)
+ * committed baz@mercurial--convert/baz--test--0--patch-5
+
+move and add the moved file again
+ $ echo e > e
+ $ baz add e
+ $ baz commit -s "add e"
+ A .arch-ids/e.id
+ A e
+ * update pristine tree (baz@mercurial--convert/baz--test--0--patch-5 => baz--test--0--patch-6)
+ * committed baz@mercurial--convert/baz--test--0--patch-6
+ $ baz mv e f
+ $ echo ee > e
+ $ baz add e
+ $ baz commit -s "move e and recreate it again"
+ A .arch-ids/e.id
+ A e
+ => .arch-ids/e.id .arch-ids/f.id
+ => e f
+ * update pristine tree (baz@mercurial--convert/baz--test--0--patch-6 => baz--test--0--patch-7)
+ * committed baz@mercurial--convert/baz--test--0--patch-7
+ $ cd ..
+
+converting baz repo to Mercurial
+ $ hg convert baz-repo baz-repo-hg
+ initializing destination baz-repo-hg repository
+ analyzing tree version baz@mercurial--convert/baz--test--0...
+ scanning source...
+ sorting...
+ converting...
+ 7 initial import
+ 6 added a file, src and src/b (binary)
+ 5 added link to a and modify a
+ 4 added second link and modify b
+ 3 file to link and link to file test
+ 2 move and rename a-link-2 file and src directory
+ 1 add e
+ 0 move e and recreate it again
+
+ $ baz register-archive -d baz@mercurial--convert
+
+ $ glog()
+ > {
+ > hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
+ > }
+
+show graph log
+ $ glog -R baz-repo-hg
+ o 7 "move e and recreate it again" files: e f
+ |
+ o 6 "add e" files: e
+ |
+ o 5 "move and rename a-link-2 file and src directory" files: c src/a-link src/a-link-2 src/b test/a-link test/b
+ |
+ o 4 "file to link and link to file test" files: src/a-link-2 src/b
+ |
+ o 3 "added second link and modify b" files: src/a-link-2 src/b
+ |
+ o 2 "added link to a and modify a" files: a src/a-link
+ |
+ o 1 "added a file, src and src/b (binary)" files: a src/b
+ |
+ o 0 "initial import" files:
+
+ $ hg up -q -R baz-repo-hg
+ $ hg -R baz-repo-hg manifest --debug
+ c4072c4b72e1cabace081888efa148ee80ca3cbb 644 a
+ 0201ac32a3a8e86e303dff60366382a54b48a72e 644 c
+ 1a4a864db0073705a11b1439f563bfa4b46d9246 644 e
+ 09e0222742fc3f75777fa9d68a5d8af7294cb5e7 644 f
+ c0067ba5ff0b7c9a3eb17270839d04614c435623 644 @ test/a-link
+ 375f4263d86feacdea7e3c27100abd1560f2a973 644 @ test/b
+ $ hg -R baz-repo-hg log -r 5 -r 7 -C --debug | grep copies
+ copies: c (src/a-link-2) test/a-link (src/a-link) test/b (src/b)
+ copies: f (e)
diff --git a/tests/test-convert-bzr-114.t b/tests/test-convert-bzr-114.t
new file mode 100644
index 0000000..47df890
--- /dev/null
+++ b/tests/test-convert-bzr-114.t
@@ -0,0 +1,39 @@
+
+ $ "$TESTDIR/hghave" bzr114 || exit 80
+ $ . "$TESTDIR/bzr-definitions"
+
+The file/directory replacement can only be reproduced on
+bzr >= 1.4. Merge it back in test-convert-bzr-directories once
+this version becomes mainstream.
+replace file with dir
+
+ $ mkdir test-replace-file-with-dir
+ $ cd test-replace-file-with-dir
+ $ bzr init -q source
+ $ cd source
+ $ echo d > d
+ $ bzr add -q d
+ $ bzr commit -q -m 'add d file'
+ $ rm d
+ $ mkdir d
+ $ bzr add -q d
+ $ bzr commit -q -m 'replace with d dir'
+ $ echo a > d/a
+ $ bzr add -q d/a
+ $ bzr commit -q -m 'add d/a'
+ $ cd ..
+ $ hg convert source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 2 add d file
+ 1 replace with d dir
+ 0 add d/a
+ $ manifest source-hg tip
+ % manifest of tip
+ 644 d/a
+ $ cd source-hg
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../..
diff --git a/tests/test-convert-bzr-directories.t b/tests/test-convert-bzr-directories.t
new file mode 100644
index 0000000..653d7b1
--- /dev/null
+++ b/tests/test-convert-bzr-directories.t
@@ -0,0 +1,193 @@
+
+ $ . "$TESTDIR/bzr-definitions"
+
+empty directory
+
+ $ mkdir test-empty
+ $ cd test-empty
+ $ bzr init -q source
+ $ cd source
+ $ echo content > a
+ $ bzr add -q a
+ $ bzr commit -q -m 'Initial add'
+ $ mkdir empty
+ $ bzr add -q empty
+ $ bzr commit -q -m 'Empty directory added'
+ $ echo content > empty/something
+ $ bzr add -q empty/something
+ $ bzr commit -q -m 'Added file into directory'
+ $ cd ..
+ $ hg convert source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 2 Initial add
+ 1 Empty directory added
+ 0 Added file into directory
+ $ manifest source-hg 1
+ % manifest of 1
+ 644 a
+ $ manifest source-hg tip
+ % manifest of tip
+ 644 a
+ 644 empty/something
+ $ cd ..
+
+directory renames
+
+ $ mkdir test-dir-rename
+ $ cd test-dir-rename
+ $ bzr init -q source
+ $ cd source
+ $ mkdir tpyo
+ $ echo content > tpyo/something
+ $ bzr add -q tpyo
+ $ bzr commit -q -m 'Added directory'
+ $ bzr mv tpyo typo
+ tpyo => typo
+ $ bzr commit -q -m 'Oops, typo'
+ $ cd ..
+ $ hg convert source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 Added directory
+ 0 Oops, typo
+ $ manifest source-hg 0
+ % manifest of 0
+ 644 tpyo/something
+ $ manifest source-hg tip
+ % manifest of tip
+ 644 typo/something
+ $ cd ..
+
+nested directory renames
+
+ $ mkdir test-nested-dir-rename
+ $ cd test-nested-dir-rename
+ $ bzr init -q source
+ $ cd source
+ $ mkdir -p firstlevel/secondlevel/thirdlevel
+ $ echo content > firstlevel/secondlevel/file
+ $ echo this_needs_to_be_there_too > firstlevel/secondlevel/thirdlevel/stuff
+ $ bzr add -q firstlevel
+ $ bzr commit -q -m 'Added nested directories'
+ $ bzr mv firstlevel/secondlevel secondlevel
+ firstlevel/secondlevel => secondlevel
+ $ bzr commit -q -m 'Moved secondlevel one level up'
+ $ cd ..
+ $ hg convert source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 Added nested directories
+ 0 Moved secondlevel one level up
+ $ manifest source-hg tip
+ % manifest of tip
+ 644 secondlevel/file
+ 644 secondlevel/thirdlevel/stuff
+ $ cd ..
+
+directory remove
+
+ $ mkdir test-dir-remove
+ $ cd test-dir-remove
+ $ bzr init -q source
+ $ cd source
+ $ mkdir src
+ $ echo content > src/sourcecode
+ $ bzr add -q src
+ $ bzr commit -q -m 'Added directory'
+ $ bzr rm -q src
+ $ bzr commit -q -m 'Removed directory'
+ $ cd ..
+ $ hg convert source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 Added directory
+ 0 Removed directory
+ $ manifest source-hg 0
+ % manifest of 0
+ 644 src/sourcecode
+ $ manifest source-hg tip
+ % manifest of tip
+ $ cd ..
+
+directory replace
+
+ $ mkdir test-dir-replace
+ $ cd test-dir-replace
+ $ bzr init -q source
+ $ cd source
+ $ mkdir first second
+ $ echo content > first/file
+ $ echo morecontent > first/dummy
+ $ echo othercontent > second/something
+ $ bzr add -q first second
+ $ bzr commit -q -m 'Initial layout'
+ $ bzr mv first/file second/file
+ first/file => second/file
+ $ bzr mv first third
+ first => third
+ $ bzr commit -q -m 'Some conflicting moves'
+ $ cd ..
+ $ hg convert source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 Initial layout
+ 0 Some conflicting moves
+ $ manifest source-hg tip
+ % manifest of tip
+ 644 second/file
+ 644 second/something
+ 644 third/dummy
+ $ cd ..
+
+divergent nested renames (issue3089)
+
+ $ mkdir test-divergent-renames
+ $ cd test-divergent-renames
+ $ bzr init -q source
+ $ cd source
+ $ mkdir -p a/c
+ $ echo a > a/fa
+ $ echo c > a/c/fc
+ $ bzr add -q a
+ $ bzr commit -q -m 'Initial layout'
+ $ bzr mv a b
+ a => b
+ $ mkdir a
+ $ bzr add a
+ add(ed|ing) a (re)
+ $ bzr mv b/c a/c
+ b/c => a/c
+ $ bzr status
+ added:
+ a/
+ renamed:
+ a/? => b/? (re)
+ a/c/? => a/c/? (re)
+ $ bzr commit -q -m 'Divergent renames'
+ $ cd ..
+ $ hg convert source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 Initial layout
+ 0 Divergent renames
+ $ hg -R source-hg st -C --change 1
+ A b/fa
+ a/fa
+ R a/fa
+ $ hg -R source-hg manifest -r 1
+ a/c/fc
+ b/fa
+ $ cd ..
diff --git a/tests/test-convert-bzr-ghosts.t b/tests/test-convert-bzr-ghosts.t
new file mode 100644
index 0000000..ef9cd96
--- /dev/null
+++ b/tests/test-convert-bzr-ghosts.t
@@ -0,0 +1,38 @@
+
+ $ . "$TESTDIR/bzr-definitions"
+ $ cat > ghostcreator.py <<EOF
+ > import sys
+ > from bzrlib import workingtree
+ > wt = workingtree.WorkingTree.open('.')
+ >
+ > message, ghostrev = sys.argv[1:]
+ > wt.set_parent_ids(wt.get_parent_ids() + [ghostrev])
+ > wt.commit(message)
+ > EOF
+
+ghost revisions
+
+ $ mkdir test-ghost-revisions
+ $ cd test-ghost-revisions
+ $ bzr init -q source
+ $ cd source
+ $ echo content > somefile
+ $ bzr add -q somefile
+ $ bzr commit -q -m 'Initial layout setup'
+ $ echo morecontent >> somefile
+ $ python ../../ghostcreator.py 'Commit with ghost revision' ghostrev
+ $ cd ..
+ $ hg convert source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 Initial layout setup
+ 0 Commit with ghost revision
+ $ glog -R source-hg
+ o 1@source "Commit with ghost revision" files: somefile
+ |
+ o 0@source "Initial layout setup" files: somefile
+
+
+ $ cd ..
diff --git a/tests/test-convert-bzr-merges.t b/tests/test-convert-bzr-merges.t
new file mode 100644
index 0000000..1c10bbc
--- /dev/null
+++ b/tests/test-convert-bzr-merges.t
@@ -0,0 +1,70 @@
+N.B. bzr 1.13 has a bug that breaks this test. If you see this
+test fail, check your bzr version. Upgrading to bzr 1.13.1
+should fix it.
+
+ $ . "$TESTDIR/bzr-definitions"
+
+test multiple merges at once
+
+ $ mkdir test-multimerge
+ $ cd test-multimerge
+ $ bzr init -q source
+ $ cd source
+ $ echo content > file
+ $ bzr add -q file
+ $ bzr commit -q -m 'Initial add'
+ $ cd ..
+ $ bzr branch -q source source-branch1
+ $ cd source-branch1
+ $ echo morecontent >> file
+ $ echo evenmorecontent > file-branch1
+ $ bzr add -q file-branch1
+ $ bzr commit -q -m 'Added branch1 file'
+ $ cd ../source
+ $ sleep 1
+ $ echo content > file-parent
+ $ bzr add -q file-parent
+ $ bzr commit -q -m 'Added parent file'
+ $ cd ..
+ $ bzr branch -q source source-branch2
+ $ cd source-branch2
+ $ echo somecontent > file-branch2
+ $ bzr add -q file-branch2
+ $ bzr commit -q -m 'Added brach2 file'
+ $ sleep 1
+ $ cd ../source
+ $ bzr merge -q ../source-branch1
+ $ bzr merge -q --force ../source-branch2
+ $ bzr commit -q -m 'Merged branches'
+ $ cd ..
+ $ hg convert --datesort source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 4 Initial add
+ 3 Added branch1 file
+ 2 Added parent file
+ 1 Added brach2 file
+ 0 Merged branches
+ $ glog -R source-hg
+ o 5@source "(octopus merge fixup)" files:
+ |\
+ | o 4@source "Merged branches" files: file-branch2
+ | |\
+ o---+ 3@source-branch2 "Added brach2 file" files: file-branch2
+ / /
+ | o 2@source "Added parent file" files: file-parent
+ | |
+ o | 1@source-branch1 "Added branch1 file" files: file file-branch1
+ |/
+ o 0@source "Initial add" files: file
+
+ $ manifest source-hg tip
+ % manifest of tip
+ 644 file
+ 644 file-branch1
+ 644 file-branch2
+ 644 file-parent
+
+ $ cd ..
diff --git a/tests/test-convert-bzr-treeroot.t b/tests/test-convert-bzr-treeroot.t
new file mode 100644
index 0000000..5e59e32
--- /dev/null
+++ b/tests/test-convert-bzr-treeroot.t
@@ -0,0 +1,35 @@
+
+ $ . "$TESTDIR/bzr-definitions"
+ $ cat > treeset.py <<EOF
+ > import sys
+ > from bzrlib import workingtree
+ > wt = workingtree.WorkingTree.open('.')
+ >
+ > message, rootid = sys.argv[1:]
+ > wt.set_root_id('tree_root-%s' % rootid)
+ > wt.commit(message)
+ > EOF
+
+change the id of the tree root
+
+ $ mkdir test-change-treeroot-id
+ $ cd test-change-treeroot-id
+ $ bzr init -q source
+ $ cd source
+ $ echo content > file
+ $ bzr add -q file
+ $ bzr commit -q -m 'Initial add'
+ $ python ../../treeset.py 'Changed root' new
+ $ cd ..
+ $ hg convert source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 Initial add
+ 0 Changed root
+ $ manifest source-hg tip
+ % manifest of tip
+ 644 file
+
+ $ cd ..
diff --git a/tests/test-convert-bzr.t b/tests/test-convert-bzr.t
new file mode 100644
index 0000000..709df79
--- /dev/null
+++ b/tests/test-convert-bzr.t
@@ -0,0 +1,286 @@
+ $ . "$TESTDIR/bzr-definitions"
+
+create and rename on the same file in the same step
+
+ $ mkdir test-createandrename
+ $ cd test-createandrename
+ $ bzr init -q source
+
+test empty repo conversion (issue3233)
+
+ $ hg convert source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+
+back to the rename stuff
+
+ $ cd source
+ $ echo a > a
+ $ echo c > c
+ $ echo e > e
+ $ bzr add -q a c e
+ $ bzr commit -q -m 'Initial add: a, c, e'
+ $ bzr mv a b
+ a => b
+ $ bzr mv c d
+ c => d
+ $ bzr mv e f
+ e => f
+ $ echo a2 >> a
+ $ mkdir e
+ $ bzr add -q a e
+ $ bzr commit -q -m 'rename a into b, create a, rename c into d'
+ $ cd ..
+ $ hg convert source source-hg
+ scanning source...
+ sorting...
+ converting...
+ 1 Initial add: a, c, e
+ 0 rename a into b, create a, rename c into d
+ $ glog -R source-hg
+ o 1@source "rename a into b, create a, rename c into d" files: a b c d e f
+ |
+ o 0@source "Initial add: a, c, e" files: a c e
+
+
+manifest
+
+ $ hg manifest -R source-hg -r tip
+ a
+ b
+ d
+ f
+
+test --rev option
+
+ $ hg convert -r 1 source source-1-hg
+ initializing destination source-1-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 0 Initial add: a, c, e
+ $ glog -R source-1-hg
+ o 0@source "Initial add: a, c, e" files: a c e
+
+
+test with filemap
+
+ $ cat > filemap <<EOF
+ > exclude a
+ > EOF
+ $ hg convert --filemap filemap source source-filemap-hg
+ initializing destination source-filemap-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 Initial add: a, c, e
+ 0 rename a into b, create a, rename c into d
+ $ hg -R source-filemap-hg manifest -r tip
+ b
+ d
+ f
+
+convert from lightweight checkout
+
+ $ bzr checkout --lightweight source source-light
+ $ hg convert -s bzr source-light source-light-hg
+ initializing destination source-light-hg repository
+ warning: lightweight checkouts may cause conversion failures, try with a regular branch instead.
+ $TESTTMP/test-createandrename/source-light does not look like a Bazaar repository
+ abort: source-light: missing or unsupported repository
+ [255]
+
+extract timestamps that look just like hg's {date|isodate}:
+yyyy-mm-dd HH:MM zzzz (no seconds!)
+compare timestamps
+
+ $ cd source
+ $ bzr log | \
+ > sed '/timestamp/!d;s/.\{15\}\([0-9: -]\{16\}\):.. \(.[0-9]\{4\}\)/\1 \2/' \
+ > > ../bzr-timestamps
+ $ cd ..
+ $ hg -R source-hg log --template "{date|isodate}\n" > hg-timestamps
+ $ diff -u bzr-timestamps hg-timestamps
+ $ cd ..
+
+merge
+
+ $ mkdir test-merge
+ $ cd test-merge
+ $ cat > helper.py <<EOF
+ > import sys
+ > from bzrlib import workingtree
+ > wt = workingtree.WorkingTree.open('.')
+ >
+ > message, stamp = sys.argv[1:]
+ > wt.commit(message, timestamp=int(stamp))
+ > EOF
+ $ bzr init -q source
+ $ cd source
+ $ echo content > a
+ $ echo content2 > b
+ $ bzr add -q a b
+ $ bzr commit -q -m 'Initial add'
+ $ cd ..
+ $ bzr branch -q source source-improve
+ $ cd source
+ $ echo more >> a
+ $ python ../helper.py 'Editing a' 100
+ $ cd ../source-improve
+ $ echo content3 >> b
+ $ python ../helper.py 'Editing b' 200
+ $ cd ../source
+ $ bzr merge -q ../source-improve
+ $ bzr commit -q -m 'Merged improve branch'
+ $ cd ..
+ $ hg convert --datesort source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 3 Initial add
+ 2 Editing a
+ 1 Editing b
+ 0 Merged improve branch
+ $ glog -R source-hg
+ o 3@source "Merged improve branch" files:
+ |\
+ | o 2@source-improve "Editing b" files: b
+ | |
+ o | 1@source "Editing a" files: a
+ |/
+ o 0@source "Initial add" files: a b
+
+ $ cd ..
+
+#if symlink execbit
+
+symlinks and executable files
+
+ $ mkdir test-symlinks
+ $ cd test-symlinks
+ $ bzr init -q source
+ $ cd source
+ $ touch program
+ $ chmod +x program
+ $ ln -s program altname
+ $ mkdir d
+ $ echo a > d/a
+ $ ln -s a syma
+ $ bzr add -q altname program syma d/a
+ $ bzr commit -q -m 'Initial setup'
+ $ touch newprog
+ $ chmod +x newprog
+ $ rm altname
+ $ ln -s newprog altname
+ $ chmod -x program
+ $ bzr add -q newprog
+ $ bzr commit -q -m 'Symlink changed, x bits changed'
+ $ cd ..
+ $ hg convert source source-hg
+ initializing destination source-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 Initial setup
+ 0 Symlink changed, x bits changed
+ $ manifest source-hg 0
+ % manifest of 0
+ 644 @ altname
+ 644 d/a
+ 755 * program
+ 644 @ syma
+ $ manifest source-hg tip
+ % manifest of tip
+ 644 @ altname
+ 644 d/a
+ 755 * newprog
+ 644 program
+ 644 @ syma
+
+test the symlinks can be recreated
+
+ $ cd source-hg
+ $ hg up
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg cat syma; echo
+ a
+ $ cd ../..
+
+#endif
+
+Multiple branches
+
+ $ bzr init-repo -q --no-trees repo
+ $ bzr init -q repo/trunk
+ $ bzr co repo/trunk repo-trunk
+ $ cd repo-trunk
+ $ echo a > a
+ $ bzr add -q a
+ $ bzr ci -qm adda
+ $ bzr tag trunk-tag
+ Created tag trunk-tag.
+ $ bzr switch -b branch
+ Tree is up to date at revision 1.
+ Switched to branch: *repo/branch/ (glob)
+ $ sleep 1
+ $ echo b > b
+ $ bzr add -q b
+ $ bzr ci -qm addb
+ $ bzr tag branch-tag
+ Created tag branch-tag.
+ $ bzr switch --force ../repo/trunk
+ Updated to revision 1.
+ Switched to branch: */repo/trunk/ (glob)
+ $ sleep 1
+ $ echo a >> a
+ $ bzr ci -qm changea
+ $ cd ..
+ $ hg convert --datesort repo repo-bzr
+ initializing destination repo-bzr repository
+ scanning source...
+ sorting...
+ converting...
+ 2 adda
+ 1 addb
+ 0 changea
+ updating tags
+ $ (cd repo-bzr; glog)
+ o 3@default "update tags" files: .hgtags
+ |
+ o 2@default "changea" files: a
+ |
+ | o 1@branch "addb" files: b
+ |/
+ o 0@default "adda" files: a
+
+
+Test tags (converted identifiers are not stable because bzr ones are
+not and get incorporated in extra fields).
+
+ $ hg -R repo-bzr tags
+ tip 3:* (glob)
+ branch-tag 1:* (glob)
+ trunk-tag 0:* (glob)
+
+Nested repositories (issue3254)
+
+ $ bzr init-repo -q --no-trees repo/inner
+ $ bzr init -q repo/inner/trunk
+ $ bzr co repo/inner/trunk inner-trunk
+ $ cd inner-trunk
+ $ echo b > b
+ $ bzr add -q b
+ $ bzr ci -qm addb
+ $ cd ..
+ $ hg convert --datesort repo noinner-bzr
+ initializing destination noinner-bzr repository
+ scanning source...
+ sorting...
+ converting...
+ 2 adda
+ 1 addb
+ 0 changea
+ updating tags
diff --git a/tests/test-convert-clonebranches.t b/tests/test-convert-clonebranches.t
new file mode 100644
index 0000000..6a297ef
--- /dev/null
+++ b/tests/test-convert-clonebranches.t
@@ -0,0 +1,88 @@
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert = " >> $HGRCPATH
+ $ echo "[convert]" >> $HGRCPATH
+ $ echo "hg.tagsbranch=0" >> $HGRCPATH
+ $ hg init source
+ $ cd source
+ $ echo a > a
+ $ hg ci -qAm adda
+
+Add a merge with one parent in the same branch
+
+ $ echo a >> a
+ $ hg ci -qAm changea
+ $ hg up -qC 0
+ $ hg branch branch0
+ marked working directory as branch branch0
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b > b
+ $ hg ci -qAm addb
+ $ hg up -qC
+ $ hg merge default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -qm mergeab
+ $ hg tag -ql mergeab
+ $ cd ..
+
+Miss perl... sometimes
+
+ $ cat > filter.py <<EOF
+ > import sys, re
+ >
+ > r = re.compile(r'^(?:\d+|pulling from)')
+ > sys.stdout.writelines([l for l in sys.stdin if r.search(l)])
+ > EOF
+
+convert
+
+ $ hg convert -v --config convert.hg.clonebranches=1 source dest |
+ > python filter.py
+ 3 adda
+ 2 changea
+ 1 addb
+ pulling from default into branch0
+ 1 changesets found
+ 0 mergeab
+ pulling from default into branch0
+ 1 changesets found
+
+Add a merge with both parents and child in different branches
+
+ $ cd source
+ $ hg branch branch1
+ marked working directory as branch branch1
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a > file1
+ $ hg ci -qAm c1
+ $ hg up -qC mergeab
+ $ hg branch branch2
+ marked working directory as branch branch2
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a > file2
+ $ hg ci -qAm c2
+ $ hg merge branch1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg branch branch3
+ marked working directory as branch branch3
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -qAm c3
+ $ cd ..
+
+incremental conversion
+
+ $ hg convert -v --config convert.hg.clonebranches=1 source dest |
+ > python filter.py
+ 2 c1
+ pulling from branch0 into branch1
+ 4 changesets found
+ 1 c2
+ pulling from branch0 into branch2
+ 4 changesets found
+ 0 c3
+ pulling from branch2 into branch3
+ 5 changesets found
+ pulling from branch1 into branch3
+ 1 changesets found
diff --git a/tests/test-convert-cvs-branch.t b/tests/test-convert-cvs-branch.t
new file mode 100644
index 0000000..ba35c02
--- /dev/null
+++ b/tests/test-convert-cvs-branch.t
@@ -0,0 +1,193 @@
+This is http://mercurial.selenic.com/bts/issue1148
+and http://mercurial.selenic.com/bts/issue1447
+
+ $ "$TESTDIR/hghave" cvs || exit 80
+ $ cvscall()
+ > {
+ > cvs -f "$@" > /dev/null
+ > }
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert = " >> $HGRCPATH
+ $ echo "graphlog = " >> $HGRCPATH
+ $ echo "[convert]" >> $HGRCPATH
+ $ echo "cvsps.cache=0" >> $HGRCPATH
+
+create cvs repository
+
+ $ mkdir cvsrepo
+ $ cd cvsrepo
+ $ CVSROOT=`pwd`
+ $ export CVSROOT
+ $ CVS_OPTIONS=-f
+ $ export CVS_OPTIONS
+ $ cd ..
+ $ cvscall -q -d "$CVSROOT" init
+
+Create a new project
+
+ $ mkdir src
+ $ cd src
+ $ echo "1" > a
+ $ echo "1" > b
+ $ cvscall import -m "init" src v0 r0 | sort
+ $ cd ..
+ $ cvscall co src
+ cvs checkout: Updating src
+ $ cd src
+
+Branch the project
+
+ $ cvscall tag -b BRANCH
+ cvs tag: Tagging .
+ $ cvscall up -r BRANCH > /dev/null
+ cvs update: Updating .
+
+Modify file a, then b, then a
+
+ $ sleep 1
+ $ echo "2" > a
+ $ cvscall ci -m "mod a"
+ cvs commit: Examining .
+ $ echo "2" > b
+ $ cvscall ci -m "mod b"
+ cvs commit: Examining .
+ $ sleep 1
+ $ echo "3" > a
+ $ cvscall ci -m "mod a again"
+ cvs commit: Examining .
+
+Convert
+
+ $ cd ..
+ $ hg convert src
+ assuming destination src-hg
+ initializing destination src-hg repository
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ 7 log entries
+ creating changesets
+ 5 changeset entries
+ sorting...
+ converting...
+ 4 Initial revision
+ 3 init
+ 2 mod a
+ 1 mod b
+ 0 mod a again
+ updating tags
+
+Check the result
+
+ $ hg -R src-hg glog --template '{rev} ({branches}) {desc} files: {files}\n'
+ o 5 () update tags files: .hgtags
+ |
+ | o 4 (BRANCH) mod a again files: a
+ | |
+ | o 3 (BRANCH) mod b files: b
+ | |
+ | o 2 (BRANCH) mod a files: a
+ | |
+ | o 1 (v0) init files:
+ |/
+ o 0 () Initial revision files: a b
+
+
+
+issue 1447
+
+ $ cvscall()
+ > {
+ > cvs -f "$@" > /dev/null
+ > sleep 1
+ > }
+ $ cvsci()
+ > {
+ > cvs -f ci "$@" >/dev/null
+ > sleep 1
+ > }
+ $ cvscall -Q -d `pwd`/cvsmaster2 init
+ $ cd cvsmaster2
+ $ CVSROOT=`pwd`
+ $ export CVSROOT
+ $ mkdir foo
+ $ cd ..
+ $ cvscall -Q co -d cvswork2 foo
+ $ cd cvswork2
+ $ echo foo > a.txt
+ $ echo bar > b.txt
+ $ cvscall -Q add a.txt b.txt
+ $ cvsci -m "Initial commit"
+ cvs commit: Examining .
+ $ echo foo > b.txt
+ $ cvsci -m "Fix b on HEAD"
+ cvs commit: Examining .
+ $ echo bar > a.txt
+ $ cvsci -m "Small fix in a on HEAD"
+ cvs commit: Examining .
+ $ cvscall -Q tag -b BRANCH
+ $ cvscall -Q up -P -rBRANCH
+ $ echo baz > b.txt
+ $ cvsci -m "Change on BRANCH in b"
+ cvs commit: Examining .
+ $ hg debugcvsps -x --parents foo
+ collecting CVS rlog
+ 5 log entries
+ creating changesets
+ 4 changeset entries
+ ---------------------
+ PatchSet 1
+ Date: * (glob)
+ Author: * (glob)
+ Branch: HEAD
+ Tag: (none)
+ Log:
+ Initial commit
+
+ Members:
+ a.txt:INITIAL->1.1
+ b.txt:INITIAL->1.1
+
+ ---------------------
+ PatchSet 2
+ Date: * (glob)
+ Author: * (glob)
+ Branch: HEAD
+ Tag: (none)
+ Branchpoints: BRANCH
+ Parent: 1
+ Log:
+ Fix b on HEAD
+
+ Members:
+ b.txt:1.1->1.2
+
+ ---------------------
+ PatchSet 3
+ Date: * (glob)
+ Author: * (glob)
+ Branch: HEAD
+ Tag: (none)
+ Branchpoints: BRANCH
+ Parent: 2
+ Log:
+ Small fix in a on HEAD
+
+ Members:
+ a.txt:1.1->1.2
+
+ ---------------------
+ PatchSet 4
+ Date: * (glob)
+ Author: * (glob)
+ Branch: BRANCH
+ Tag: (none)
+ Parent: 3
+ Log:
+ Change on BRANCH in b
+
+ Members:
+ b.txt:1.2->1.2.2.1
+
+
+ $ cd ..
diff --git a/tests/test-convert-cvs-detectmerge.t b/tests/test-convert-cvs-detectmerge.t
new file mode 100644
index 0000000..9807782
--- /dev/null
+++ b/tests/test-convert-cvs-detectmerge.t
@@ -0,0 +1,233 @@
+Test config convert.cvsps.mergefrom config setting.
+(Should test similar mergeto feature, but I don't understand it yet.)
+Requires builtin cvsps.
+
+ $ "$TESTDIR/hghave" cvs || exit 80
+ $ CVSROOT=`pwd`/cvsrepo
+ $ export CVSROOT
+
+ $ cvscall()
+ > {
+ > cvs -f "$@"
+ > }
+
+output of 'cvs ci' varies unpredictably, so just discard it
+XXX copied from test-convert-cvs-synthetic
+
+ $ cvsci()
+ > {
+ > sleep 1
+ > cvs -f ci "$@" > /dev/null
+ > }
+
+XXX copied from test-convert-cvs-synthetic
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert = " >> $HGRCPATH
+ $ echo "graphlog = " >> $HGRCPATH
+ $ echo "[convert]" >> $HGRCPATH
+ $ echo "cvsps.cache=0" >> $HGRCPATH
+ $ echo "cvsps.mergefrom=\[MERGE from (\S+)\]" >> $HGRCPATH
+
+create cvs repository with one project
+
+ $ mkdir cvsrepo
+ $ cvscall -q -d "$CVSROOT" init
+ $ mkdir cvsrepo/proj
+
+populate cvs repository
+
+ $ cvscall -Q co proj
+ $ cd proj
+ $ touch file1
+ $ cvscall -Q add file1
+ $ cvsci -m"add file1 on trunk"
+ cvs commit: Examining .
+
+create two release branches
+
+ $ cvscall -q tag -b v1_0
+ T file1
+ $ cvscall -q tag -b v1_1
+ T file1
+
+modify file1 on branch v1_0
+
+ $ cvscall -Q update -rv1_0
+ $ sleep 1
+ $ echo "change" >> file1
+ $ cvsci -m"add text"
+ cvs commit: Examining .
+
+make unrelated change on v1_1
+
+ $ cvscall -Q update -rv1_1
+ $ touch unrelated
+ $ cvscall -Q add unrelated
+ $ cvsci -m"unrelated change"
+ cvs commit: Examining .
+
+merge file1 to v1_1
+
+ $ cvscall -Q update -jv1_0
+ RCS file: $TESTTMP/cvsrepo/proj/file1,v
+ retrieving revision 1.1
+ retrieving revision 1.1.2.1
+ Merging differences between 1.1 and 1.1.2.1 into file1
+ $ cvsci -m"add text [MERGE from v1_0]"
+ cvs commit: Examining .
+
+merge change to trunk
+
+ $ cvscall -Q update -A
+ $ cvscall -Q update -jv1_1
+ RCS file: $TESTTMP/cvsrepo/proj/file1,v
+ retrieving revision 1.1
+ retrieving revision 1.1.4.1
+ Merging differences between 1.1 and 1.1.4.1 into file1
+ $ cvsci -m"add text [MERGE from v1_1]"
+ cvs commit: Examining .
+
+non-merged change on trunk
+
+ $ echo "foo" > file2
+ $ cvscall -Q add file2
+ $ cvsci -m"add file2 on trunk" file2
+
+this will create rev 1.3
+change on trunk to backport
+
+ $ echo "backport me" >> file1
+ $ cvsci -m"add other text" file1
+ $ cvscall log file1
+
+ RCS file: $TESTTMP/cvsrepo/proj/file1,v
+ Working file: file1
+ head: 1.3
+ branch:
+ locks: strict
+ access list:
+ symbolic names:
+ v1_1: 1.1.0.4
+ v1_0: 1.1.0.2
+ keyword substitution: kv
+ total revisions: 5; selected revisions: 5
+ description:
+ ----------------------------
+ revision 1.3
+ date: * (glob)
+ add other text
+ ----------------------------
+ revision 1.2
+ date: * (glob)
+ add text [MERGE from v1_1]
+ ----------------------------
+ revision 1.1
+ date: * (glob)
+ branches: 1.1.2; 1.1.4;
+ add file1 on trunk
+ ----------------------------
+ revision 1.1.4.1
+ date: * (glob)
+ add text [MERGE from v1_0]
+ ----------------------------
+ revision 1.1.2.1
+ date: * (glob)
+ add text
+ =============================================================================
+
+XXX how many ways are there to spell "trunk" with CVS?
+backport trunk change to v1_1
+
+ $ cvscall -Q update -rv1_1
+ $ cvscall -Q update -j1.2 -j1.3 file1
+ RCS file: $TESTTMP/cvsrepo/proj/file1,v
+ retrieving revision 1.2
+ retrieving revision 1.3
+ Merging differences between 1.2 and 1.3 into file1
+ $ cvsci -m"add other text [MERGE from HEAD]" file1
+
+fix bug on v1_1, merge to trunk with error
+
+ $ cvscall -Q update -rv1_1
+ $ echo "merge forward" >> file1
+ $ cvscall -Q tag unmerged
+ $ cvsci -m"fix file1"
+ cvs commit: Examining .
+ $ cvscall -Q update -A
+ $ cvscall -Q update -junmerged -jv1_1
+ RCS file: $TESTTMP/cvsrepo/proj/file1,v
+ retrieving revision 1.1.4.2
+ retrieving revision 1.1.4.3
+ Merging differences between 1.1.4.2 and 1.1.4.3 into file1
+
+note the typo in the commit log message
+
+ $ cvsci -m"fix file1 [MERGE from v1-1]"
+ cvs commit: Examining .
+ $ cvs -Q tag -d unmerged
+
+convert to hg
+
+ $ cd ..
+ $ hg convert proj proj.hg
+ initializing destination proj.hg repository
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ 12 log entries
+ creating changesets
+ warning: CVS commit message references non-existent branch 'v1-1':
+ fix file1 [MERGE from v1-1]
+ 10 changeset entries
+ sorting...
+ converting...
+ 9 add file1 on trunk
+ 8 add text
+ 7 unrelated change
+ 6 add text [MERGE from v1_0]
+ 5 add text [MERGE from v1_1]
+ 4 add file2 on trunk
+ 3 add other text
+ 2 add other text [MERGE from HEAD]
+ 1 fix file1
+ 0 fix file1 [MERGE from v1-1]
+
+complete log
+
+ $ template="{rev}: '{branches}' {desc}\n"
+ $ hg -R proj.hg log --template="$template"
+ 9: '' fix file1 [MERGE from v1-1]
+ 8: 'v1_1' fix file1
+ 7: 'v1_1' add other text [MERGE from HEAD]
+ 6: '' add other text
+ 5: '' add file2 on trunk
+ 4: '' add text [MERGE from v1_1]
+ 3: 'v1_1' add text [MERGE from v1_0]
+ 2: 'v1_1' unrelated change
+ 1: 'v1_0' add text
+ 0: '' add file1 on trunk
+
+graphical log
+
+ $ hg -R proj.hg glog --template="$template"
+ o 9: '' fix file1 [MERGE from v1-1]
+ |
+ | o 8: 'v1_1' fix file1
+ | |
+ | o 7: 'v1_1' add other text [MERGE from HEAD]
+ |/|
+ o | 6: '' add other text
+ | |
+ o | 5: '' add file2 on trunk
+ | |
+ o | 4: '' add text [MERGE from v1_1]
+ |\|
+ | o 3: 'v1_1' add text [MERGE from v1_0]
+ | |\
+ +---o 2: 'v1_1' unrelated change
+ | |
+ | o 1: 'v1_0' add text
+ |/
+ o 0: '' add file1 on trunk
+
diff --git a/tests/test-convert-cvs-synthetic.t b/tests/test-convert-cvs-synthetic.t
new file mode 100644
index 0000000..fe6cc5d
--- /dev/null
+++ b/tests/test-convert-cvs-synthetic.t
@@ -0,0 +1,217 @@
+This feature requires use of builtin cvsps!
+
+ $ "$TESTDIR/hghave" cvs || exit 80
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert = " >> $HGRCPATH
+ $ echo "graphlog = " >> $HGRCPATH
+
+create cvs repository with one project
+
+ $ mkdir cvsrepo
+ $ cd cvsrepo
+ $ CVSROOT=`pwd`
+ $ export CVSROOT
+ $ CVS_OPTIONS=-f
+ $ export CVS_OPTIONS
+ $ cd ..
+ $ cvscall()
+ > {
+ > cvs -f "$@"
+ > }
+
+output of 'cvs ci' varies unpredictably, so just discard it
+
+ $ cvsci()
+ > {
+ > sleep 1
+ > cvs -f ci "$@" >/dev/null
+ > }
+ $ cvscall -d "$CVSROOT" init
+ $ mkdir cvsrepo/proj
+ $ cvscall -q co proj
+
+create file1 on the trunk
+
+ $ cd proj
+ $ touch file1
+ $ cvscall -Q add file1
+ $ cvsci -m"add file1 on trunk" file1
+
+create two branches
+
+ $ cvscall -q tag -b v1_0
+ T file1
+ $ cvscall -q tag -b v1_1
+ T file1
+
+create file2 on branch v1_0
+
+ $ cvscall -Q up -rv1_0
+ $ touch file2
+ $ cvscall -Q add file2
+ $ cvsci -m"add file2" file2
+
+create file3, file4 on branch v1_1
+
+ $ cvscall -Q up -rv1_1
+ $ touch file3
+ $ touch file4
+ $ cvscall -Q add file3 file4
+ $ cvsci -m"add file3, file4 on branch v1_1" file3 file4
+
+merge file2 from v1_0 to v1_1
+
+ $ cvscall -Q up -jv1_0
+ $ cvsci -m"MERGE from v1_0: add file2"
+ cvs commit: Examining .
+
+Step things up a notch: now we make the history really hairy, with
+changes bouncing back and forth between trunk and v1_2 and merges
+going both ways. (I.e., try to model the real world.)
+create branch v1_2
+
+ $ cvscall -Q up -A
+ $ cvscall -q tag -b v1_2
+ T file1
+
+create file5 on branch v1_2
+
+ $ cvscall -Q up -rv1_2
+ $ touch file5
+ $ cvs -Q add file5
+ $ cvsci -m"add file5 on v1_2"
+ cvs commit: Examining .
+
+create file6 on trunk post-v1_2
+
+ $ cvscall -Q up -A
+ $ touch file6
+ $ cvscall -Q add file6
+ $ cvsci -m"add file6 on trunk post-v1_2"
+ cvs commit: Examining .
+
+merge file5 from v1_2 to trunk
+
+ $ cvscall -Q up -A
+ $ cvscall -Q up -jv1_2 file5
+ $ cvsci -m"MERGE from v1_2: add file5"
+ cvs commit: Examining .
+
+merge file6 from trunk to v1_2
+
+ $ cvscall -Q up -rv1_2
+ $ cvscall up -jHEAD file6
+ U file6
+ $ cvsci -m"MERGE from HEAD: add file6"
+ cvs commit: Examining .
+
+cvs rlog output
+
+ $ cvscall -q rlog proj | egrep '^(RCS file|revision)'
+ RCS file: $TESTTMP/cvsrepo/proj/file1,v
+ revision 1.1
+ RCS file: $TESTTMP/cvsrepo/proj/Attic/file2,v
+ revision 1.1
+ revision 1.1.4.2
+ revision 1.1.4.1
+ revision 1.1.2.1
+ RCS file: $TESTTMP/cvsrepo/proj/Attic/file3,v
+ revision 1.1
+ revision 1.1.2.1
+ RCS file: $TESTTMP/cvsrepo/proj/Attic/file4,v
+ revision 1.1
+ revision 1.1.2.1
+ RCS file: $TESTTMP/cvsrepo/proj/file5,v
+ revision 1.2
+ revision 1.1
+ revision 1.1.2.1
+ RCS file: $TESTTMP/cvsrepo/proj/file6,v
+ revision 1.1
+ revision 1.1.2.2
+ revision 1.1.2.1
+
+convert to hg (#1)
+
+ $ cd ..
+ $ hg convert --datesort proj proj.hg
+ initializing destination proj.hg repository
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ 15 log entries
+ creating changesets
+ 8 changeset entries
+ sorting...
+ converting...
+ 7 add file1 on trunk
+ 6 add file2
+ 5 add file3, file4 on branch v1_1
+ 4 MERGE from v1_0: add file2
+ 3 add file5 on v1_2
+ 2 add file6 on trunk post-v1_2
+ 1 MERGE from v1_2: add file5
+ 0 MERGE from HEAD: add file6
+
+hg glog output (#1)
+
+ $ hg -R proj.hg glog --template "{rev} {desc}\n"
+ o 7 MERGE from HEAD: add file6
+ |
+ | o 6 MERGE from v1_2: add file5
+ | |
+ | o 5 add file6 on trunk post-v1_2
+ | |
+ o | 4 add file5 on v1_2
+ |/
+ | o 3 MERGE from v1_0: add file2
+ | |
+ | o 2 add file3, file4 on branch v1_1
+ |/
+ | o 1 add file2
+ |/
+ o 0 add file1 on trunk
+
+
+convert to hg (#2: with merge detection)
+
+ $ hg convert \
+ > --config convert.cvsps.mergefrom='"^MERGE from (\S+):"' \
+ > --datesort \
+ > proj proj.hg2
+ initializing destination proj.hg2 repository
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ 15 log entries
+ creating changesets
+ 8 changeset entries
+ sorting...
+ converting...
+ 7 add file1 on trunk
+ 6 add file2
+ 5 add file3, file4 on branch v1_1
+ 4 MERGE from v1_0: add file2
+ 3 add file5 on v1_2
+ 2 add file6 on trunk post-v1_2
+ 1 MERGE from v1_2: add file5
+ 0 MERGE from HEAD: add file6
+
+hg glog output (#2)
+
+ $ hg -R proj.hg2 glog --template "{rev} {desc}\n"
+ o 7 MERGE from HEAD: add file6
+ |
+ | o 6 MERGE from v1_2: add file5
+ | |
+ | o 5 add file6 on trunk post-v1_2
+ | |
+ o | 4 add file5 on v1_2
+ |/
+ | o 3 MERGE from v1_0: add file2
+ | |
+ | o 2 add file3, file4 on branch v1_1
+ |/
+ | o 1 add file2
+ |/
+ o 0 add file1 on trunk
+
diff --git a/tests/test-convert-cvs.t b/tests/test-convert-cvs.t
new file mode 100644
index 0000000..365db71
--- /dev/null
+++ b/tests/test-convert-cvs.t
@@ -0,0 +1,461 @@
+
+ $ "$TESTDIR/hghave" cvs || exit 80
+ $ cvscall()
+ > {
+ > cvs -f "$@"
+ > }
+ $ hgcat()
+ > {
+ > hg --cwd src-hg cat -r tip "$1"
+ > }
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert = " >> $HGRCPATH
+ $ echo "graphlog = " >> $HGRCPATH
+ $ cat > cvshooks.py <<EOF
+ > def cvslog(ui,repo,hooktype,log):
+ > print "%s hook: %d entries"%(hooktype,len(log))
+ >
+ > def cvschangesets(ui,repo,hooktype,changesets):
+ > print "%s hook: %d changesets"%(hooktype,len(changesets))
+ > EOF
+ $ hookpath=`pwd`
+ $ echo "[hooks]" >> $HGRCPATH
+ $ echo "cvslog=python:$hookpath/cvshooks.py:cvslog" >> $HGRCPATH
+ $ echo "cvschangesets=python:$hookpath/cvshooks.py:cvschangesets" >> $HGRCPATH
+
+create cvs repository
+
+ $ mkdir cvsrepo
+ $ cd cvsrepo
+ $ CVSROOT=`pwd`
+ $ export CVSROOT
+ $ CVS_OPTIONS=-f
+ $ export CVS_OPTIONS
+ $ cd ..
+ $ cvscall -q -d "$CVSROOT" init
+
+create source directory
+
+ $ mkdir src-temp
+ $ cd src-temp
+ $ echo a > a
+ $ mkdir b
+ $ cd b
+ $ echo c > c
+ $ cd ..
+
+import source directory
+
+ $ cvscall -q import -m import src INITIAL start
+ N src/a
+ N src/b/c
+
+ No conflicts created by this import
+
+ $ cd ..
+
+checkout source directory
+
+ $ cvscall -q checkout src
+ U src/a
+ U src/b/c
+
+commit a new revision changing b/c
+
+ $ cd src
+ $ sleep 1
+ $ echo c >> b/c
+ $ cvscall -q commit -mci0 . | grep '<--'
+ $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
+ $ cd ..
+
+convert fresh repo
+
+ $ hg convert src src-hg
+ initializing destination src-hg repository
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ 5 log entries
+ cvslog hook: 5 entries
+ creating changesets
+ 3 changeset entries
+ cvschangesets hook: 3 changesets
+ sorting...
+ converting...
+ 2 Initial revision
+ 1 import
+ 0 ci0
+ updating tags
+ $ hgcat a
+ a
+ $ hgcat b/c
+ c
+ c
+
+convert fresh repo with --filemap
+
+ $ echo include b/c > filemap
+ $ hg convert --filemap filemap src src-filemap
+ initializing destination src-filemap repository
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ 5 log entries
+ cvslog hook: 5 entries
+ creating changesets
+ 3 changeset entries
+ cvschangesets hook: 3 changesets
+ sorting...
+ converting...
+ 2 Initial revision
+ 1 import
+ filtering out empty revision
+ repository tip rolled back to revision 0 (undo commit)
+ 0 ci0
+ updating tags
+ $ hgcat b/c
+ c
+ c
+ $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
+ 2 update tags files: .hgtags
+ 1 ci0 files: b/c
+ 0 Initial revision files: b/c
+
+convert full repository (issue1649)
+
+ $ cvscall -q -d "$CVSROOT" checkout -d srcfull "." | grep -v CVSROOT
+ U srcfull/src/a
+ U srcfull/src/b/c
+ $ ls srcfull
+ CVS
+ CVSROOT
+ src
+ $ hg convert srcfull srcfull-hg \
+ > | grep -v 'log entries' | grep -v 'hook:' \
+ > | grep -v '^[0-3] .*' # filter instable changeset order
+ initializing destination srcfull-hg repository
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ creating changesets
+ 4 changeset entries
+ sorting...
+ converting...
+ updating tags
+ $ hg cat -r tip --cwd srcfull-hg src/a
+ a
+ $ hg cat -r tip --cwd srcfull-hg src/b/c
+ c
+ c
+
+commit new file revisions
+
+ $ cd src
+ $ echo a >> a
+ $ echo c >> b/c
+ $ cvscall -q commit -mci1 . | grep '<--'
+ $TESTTMP/cvsrepo/src/a,v <-- a
+ $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
+ $ cd ..
+
+convert again
+
+ $ hg convert src src-hg
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ 7 log entries
+ cvslog hook: 7 entries
+ creating changesets
+ 4 changeset entries
+ cvschangesets hook: 4 changesets
+ sorting...
+ converting...
+ 0 ci1
+ $ hgcat a
+ a
+ a
+ $ hgcat b/c
+ c
+ c
+ c
+
+convert again with --filemap
+
+ $ hg convert --filemap filemap src src-filemap
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ 7 log entries
+ cvslog hook: 7 entries
+ creating changesets
+ 4 changeset entries
+ cvschangesets hook: 4 changesets
+ sorting...
+ converting...
+ 0 ci1
+ $ hgcat b/c
+ c
+ c
+ c
+ $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
+ 3 ci1 files: b/c
+ 2 update tags files: .hgtags
+ 1 ci0 files: b/c
+ 0 Initial revision files: b/c
+
+commit branch
+
+ $ cd src
+ $ cvs -q update -r1.1 b/c
+ U b/c
+ $ cvs -q tag -b branch
+ T a
+ T b/c
+ $ cvs -q update -r branch > /dev/null
+ $ echo d >> b/c
+ $ cvs -q commit -mci2 . | grep '<--'
+ $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
+ $ cd ..
+
+convert again
+
+ $ hg convert src src-hg
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ 8 log entries
+ cvslog hook: 8 entries
+ creating changesets
+ 5 changeset entries
+ cvschangesets hook: 5 changesets
+ sorting...
+ converting...
+ 0 ci2
+ $ hgcat b/c
+ c
+ d
+
+convert again with --filemap
+
+ $ hg convert --filemap filemap src src-filemap
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ 8 log entries
+ cvslog hook: 8 entries
+ creating changesets
+ 5 changeset entries
+ cvschangesets hook: 5 changesets
+ sorting...
+ converting...
+ 0 ci2
+ $ hgcat b/c
+ c
+ d
+ $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
+ 4 ci2 files: b/c
+ 3 ci1 files: b/c
+ 2 update tags files: .hgtags
+ 1 ci0 files: b/c
+ 0 Initial revision files: b/c
+
+commit a new revision with funny log message
+
+ $ cd src
+ $ sleep 1
+ $ echo e >> a
+ $ cvscall -q commit -m'funny
+ > ----------------------------
+ > log message' . | grep '<--' |\
+ > sed -e 's:.*src/\(.*\),v.*:checking in src/\1,v:g'
+ checking in src/a,v
+
+commit new file revisions with some fuzz
+
+ $ sleep 1
+ $ echo f >> a
+ $ cvscall -q commit -mfuzzy . | grep '<--'
+ $TESTTMP/cvsrepo/src/a,v <-- a
+ $ sleep 4 # the two changes will be split if fuzz < 4
+ $ echo g >> b/c
+ $ cvscall -q commit -mfuzzy . | grep '<--'
+ $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
+ $ cd ..
+
+convert again
+
+ $ hg convert --config convert.cvsps.fuzz=2 src src-hg
+ connecting to $TESTTMP/cvsrepo
+ scanning source...
+ collecting CVS rlog
+ 11 log entries
+ cvslog hook: 11 entries
+ creating changesets
+ 8 changeset entries
+ cvschangesets hook: 8 changesets
+ sorting...
+ converting...
+ 2 funny
+ 1 fuzzy
+ 0 fuzzy
+ $ hg -R src-hg glog --template '{rev} ({branches}) {desc} files: {files}\n'
+ o 8 (branch) fuzzy files: b/c
+ |
+ o 7 (branch) fuzzy files: a
+ |
+ o 6 (branch) funny
+ | ----------------------------
+ | log message files: a
+ o 5 (branch) ci2 files: b/c
+
+ o 4 () ci1 files: a b/c
+ |
+ o 3 () update tags files: .hgtags
+ |
+ o 2 () ci0 files: b/c
+ |
+ | o 1 (INITIAL) import files:
+ |/
+ o 0 () Initial revision files: a b/c
+
+
+testing debugcvsps
+
+ $ cd src
+ $ hg debugcvsps --fuzz=2
+ collecting CVS rlog
+ 11 log entries
+ cvslog hook: 11 entries
+ creating changesets
+ 10 changeset entries
+ cvschangesets hook: 10 changesets
+ ---------------------
+ PatchSet 1
+ Date: * (glob)
+ Author: * (glob)
+ Branch: HEAD
+ Tag: (none)
+ Branchpoints: INITIAL
+ Log:
+ Initial revision
+
+ Members:
+ a:INITIAL->1.1
+
+ ---------------------
+ PatchSet 2
+ Date: * (glob)
+ Author: * (glob)
+ Branch: HEAD
+ Tag: (none)
+ Branchpoints: INITIAL, branch
+ Log:
+ Initial revision
+
+ Members:
+ b/c:INITIAL->1.1
+
+ ---------------------
+ PatchSet 3
+ Date: * (glob)
+ Author: * (glob)
+ Branch: INITIAL
+ Tag: start
+ Log:
+ import
+
+ Members:
+ a:1.1->1.1.1.1
+ b/c:1.1->1.1.1.1
+
+ ---------------------
+ PatchSet 4
+ Date: * (glob)
+ Author: * (glob)
+ Branch: HEAD
+ Tag: (none)
+ Log:
+ ci0
+
+ Members:
+ b/c:1.1->1.2
+
+ ---------------------
+ PatchSet 5
+ Date: * (glob)
+ Author: * (glob)
+ Branch: HEAD
+ Tag: (none)
+ Branchpoints: branch
+ Log:
+ ci1
+
+ Members:
+ a:1.1->1.2
+
+ ---------------------
+ PatchSet 6
+ Date: * (glob)
+ Author: * (glob)
+ Branch: HEAD
+ Tag: (none)
+ Log:
+ ci1
+
+ Members:
+ b/c:1.2->1.3
+
+ ---------------------
+ PatchSet 7
+ Date: * (glob)
+ Author: * (glob)
+ Branch: branch
+ Tag: (none)
+ Log:
+ ci2
+
+ Members:
+ b/c:1.1->1.1.2.1
+
+ ---------------------
+ PatchSet 8
+ Date: * (glob)
+ Author: * (glob)
+ Branch: branch
+ Tag: (none)
+ Log:
+ funny
+ ----------------------------
+ log message
+
+ Members:
+ a:1.2->1.2.2.1
+
+ ---------------------
+ PatchSet 9
+ Date: * (glob)
+ Author: * (glob)
+ Branch: branch
+ Tag: (none)
+ Log:
+ fuzzy
+
+ Members:
+ a:1.2.2.1->1.2.2.2
+
+ ---------------------
+ PatchSet 10
+ Date: * (glob)
+ Author: * (glob)
+ Branch: branch
+ Tag: (none)
+ Log:
+ fuzzy
+
+ Members:
+ b/c:1.1.2.1->1.1.2.2
+
+
+ $ cd ..
diff --git a/tests/test-convert-cvsnt-mergepoints.rlog b/tests/test-convert-cvsnt-mergepoints.rlog
new file mode 100644
index 0000000..a690f81
--- /dev/null
+++ b/tests/test-convert-cvsnt-mergepoints.rlog
@@ -0,0 +1,42 @@
+head: 1.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ MYBRANCH1_2: 1.1.2.2.0.2
+ MYBRANCH1_1: 1.1.0.4
+ MYBRANCH1: 1.1.0.2
+keyword substitution: kv
+total revisions: 8; selected revisions: 8
+description:
+----------------------------
+revision 1.2
+date: 2009/04/02 07:00:32; author: user; state: Exp; lines: +1 -1; kopt: kv; commitid: 14d449d462903487; mergepoint: 1.1.2.2.2.1; filename: foo.txt;
+merge
+----------------------------
+revision 1.1
+date: 2009/04/02 06:50:43; author: user; state: Exp; kopt: kv; commitid: 17ac49d460432d04; filename: foo.txt;
+branches: 1.1.2; 1.1.4;
+foo.txt
+----------------------------
+revision 1.1.4.2
+date: 2009/04/02 07:02:51; author: user; state: Exp; lines: +1 -0; kopt: kv; commitid: 170049d4631b364d; mergepoint: 1.1.2.2; filename: foo.txt;
+merge
+----------------------------
+revision 1.1.4.1
+date: 2009/04/02 06:53:42; author: user; state: Exp; lines: +1 -1; kopt: kv; commitid: dc849d460f52f49; filename: foo.txt;
+quux
+----------------------------
+revision 1.1.2.2
+date: 2009/04/02 06:53:20; author: user; state: Exp; lines: +1 -1; kopt: kv; commitid: 8ec49d460e02f04; filename: foo.txt;
+branches: 1.1.2.2.2;
+baz
+----------------------------
+revision 1.1.2.1
+date: 2009/04/02 06:52:38; author: user; state: Exp; lines: +1 -1; kopt: kv; commitid: d5049d460b62e7b; filename: foo.txt;
+bar
+----------------------------
+revision 1.1.2.2.2.1
+date: 2009/04/02 06:55:42; author: user; state: Exp; lines: +1 -1; kopt: kv; commitid: 11c849d4616d30d1; filename: foo.txt;
+bazzie
+=============================================================================
diff --git a/tests/test-convert-cvsnt-mergepoints.t b/tests/test-convert-cvsnt-mergepoints.t
new file mode 100644
index 0000000..1e3d02b
--- /dev/null
+++ b/tests/test-convert-cvsnt-mergepoints.t
@@ -0,0 +1,207 @@
+
+ $ "$TESTDIR/hghave" cvs || exit 80
+ $ filterpath()
+ > {
+ > eval "$@" | sed "s:$CVSROOT:*REPO*:g"
+ > }
+ $ cvscall()
+ > {
+ > cvs -f "$@"
+ > }
+
+output of 'cvs ci' varies unpredictably, so discard most of it
+-- just keep the part that matters
+
+ $ cvsci()
+ > {
+ > cvs -f ci -f "$@" > /dev/null
+ > }
+ $ hgcat()
+ > {
+ > hg --cwd src-hg cat -r tip "$1"
+ > }
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert = " >> $HGRCPATH
+ $ echo "graphlog = " >> $HGRCPATH
+
+create cvs repository
+
+ $ mkdir cvsmaster
+ $ cd cvsmaster
+ $ CVSROOT=`pwd`
+ $ export CVSROOT
+ $ CVS_OPTIONS=-f
+ $ export CVS_OPTIONS
+ $ cd ..
+ $ filterpath cvscall -Q -d "$CVSROOT" init
+
+checkout #1: add foo.txt
+
+ $ cvscall -Q checkout -d cvsworktmp .
+ $ cd cvsworktmp
+ $ mkdir foo
+ $ cvscall -Q add foo
+ $ cd foo
+ $ echo foo > foo.txt
+ $ cvscall -Q add foo.txt
+ $ cvsci -m "add foo.txt" foo.txt
+ $ cd ../..
+ $ rm -rf cvsworktmp
+
+checkout #2: create MYBRANCH1 and modify foo.txt on it
+
+ $ cvscall -Q checkout -d cvswork foo
+ $ cd cvswork
+ $ cvscall -q rtag -b -R MYBRANCH1 foo
+ $ cvscall -Q update -P -r MYBRANCH1
+ $ echo bar > foo.txt
+ $ cvsci -m "bar" foo.txt
+ $ echo baz > foo.txt
+ $ cvsci -m "baz" foo.txt
+
+create MYBRANCH1_2 and modify foo.txt some more
+
+ $ cvscall -q rtag -b -R -r MYBRANCH1 MYBRANCH1_2 foo
+ $ cvscall -Q update -P -r MYBRANCH1_2
+ $ echo bazzie > foo.txt
+ $ cvsci -m "bazzie" foo.txt
+
+create MYBRANCH1_1 and modify foo.txt yet again
+
+ $ cvscall -q rtag -b -R MYBRANCH1_1 foo
+ $ cvscall -Q update -P -r MYBRANCH1_1
+ $ echo quux > foo.txt
+ $ cvsci -m "quux" foo.txt
+
+merge MYBRANCH1 to MYBRANCH1_1
+
+ $ filterpath cvscall -Q update -P -jMYBRANCH1
+ rcsmerge: warning: conflicts during merge
+ RCS file: *REPO*/foo/foo.txt,v
+ retrieving revision 1.1
+ retrieving revision 1.1.2.2
+ Merging differences between 1.1 and 1.1.2.2 into foo.txt
+
+carefully placed sleep to dodge cvs bug (optimization?) where it
+sometimes ignores a "commit" command if it comes too fast (the -f
+option in cvsci seems to work for all the other commits in this
+script)
+
+ $ sleep 1
+ $ echo xyzzy > foo.txt
+ $ cvsci -m "merge1+clobber" foo.txt
+
+#if unix-permissions
+
+return to trunk and merge MYBRANCH1_2
+
+ $ cvscall -Q update -P -A
+ $ filterpath cvscall -Q update -P -jMYBRANCH1_2
+ RCS file: *REPO*/foo/foo.txt,v
+ retrieving revision 1.1
+ retrieving revision 1.1.2.2.2.1
+ Merging differences between 1.1 and 1.1.2.2.2.1 into foo.txt
+ $ cvsci -m "merge2" foo.txt
+ $ REALCVS=`which cvs`
+ $ echo "for x in \$*; do if [ \"\$x\" = \"rlog\" ]; then echo \"RCS file: $CVSROOT/foo/foo.txt,v\"; cat \"$TESTDIR/test-convert-cvsnt-mergepoints.rlog\"; exit 0; fi; done; $REALCVS \$*" > ../cvs
+ $ chmod +x ../cvs
+ $ PATH=..:${PATH} hg debugcvsps --parents foo
+ collecting CVS rlog
+ 7 log entries
+ creating changesets
+ 7 changeset entries
+ ---------------------
+ PatchSet 1
+ Date: * (glob)
+ Author: user
+ Branch: HEAD
+ Tag: (none)
+ Branchpoints: MYBRANCH1_1, MYBRANCH1
+ Log:
+ foo.txt
+
+ Members:
+ foo.txt:INITIAL->1.1
+
+ ---------------------
+ PatchSet 2
+ Date: * (glob)
+ Author: user
+ Branch: MYBRANCH1
+ Tag: (none)
+ Parent: 1
+ Log:
+ bar
+
+ Members:
+ foo.txt:1.1->1.1.2.1
+
+ ---------------------
+ PatchSet 3
+ Date: * (glob)
+ Author: user
+ Branch: MYBRANCH1
+ Tag: (none)
+ Branchpoints: MYBRANCH1_2
+ Parent: 2
+ Log:
+ baz
+
+ Members:
+ foo.txt:1.1.2.1->1.1.2.2
+
+ ---------------------
+ PatchSet 4
+ Date: * (glob)
+ Author: user
+ Branch: MYBRANCH1_1
+ Tag: (none)
+ Parent: 1
+ Log:
+ quux
+
+ Members:
+ foo.txt:1.1->1.1.4.1
+
+ ---------------------
+ PatchSet 5
+ Date: * (glob)
+ Author: user
+ Branch: MYBRANCH1_2
+ Tag: (none)
+ Parent: 3
+ Log:
+ bazzie
+
+ Members:
+ foo.txt:1.1.2.2->1.1.2.2.2.1
+
+ ---------------------
+ PatchSet 6
+ Date: * (glob)
+ Author: user
+ Branch: HEAD
+ Tag: (none)
+ Parents: 1,5
+ Log:
+ merge
+
+ Members:
+ foo.txt:1.1->1.2
+
+ ---------------------
+ PatchSet 7
+ Date: * (glob)
+ Author: user
+ Branch: MYBRANCH1_1
+ Tag: (none)
+ Parents: 4,3
+ Log:
+ merge
+
+ Members:
+ foo.txt:1.1.4.1->1.1.4.2
+
+#endif
+
+ $ cd ..
diff --git a/tests/test-convert-darcs.t b/tests/test-convert-darcs.t
new file mode 100644
index 0000000..b32cbde
--- /dev/null
+++ b/tests/test-convert-darcs.t
@@ -0,0 +1,110 @@
+
+ $ "$TESTDIR/hghave" darcs || exit 80
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert=" >> $HGRCPATH
+ $ echo 'graphlog =' >> $HGRCPATH
+ $ DARCS_EMAIL='test@example.org'; export DARCS_EMAIL
+
+skip if we can't import elementtree
+
+ $ mkdir dummy
+ $ mkdir dummy/_darcs
+ $ if hg convert dummy 2>&1 | grep ElementTree > /dev/null; then
+ > echo 'skipped: missing feature: elementtree module'
+ > exit 80
+ > fi
+
+#if no-outer-repo
+
+try converting darcs1 repository
+
+ $ hg clone -q "$TESTDIR/bundles/darcs1.hg" darcs
+ $ hg convert -s darcs darcs/darcs1 2>&1 | grep darcs-1.0
+ darcs-1.0 repository format is unsupported, please upgrade
+
+#endif
+
+initialize darcs repo
+
+ $ mkdir darcs-repo
+ $ cd darcs-repo
+ $ darcs init
+ $ echo a > a
+ $ darcs record -a -l -m p0
+ Finished recording patch 'p0'
+ $ cd ..
+
+branch and update
+
+ $ darcs get -q darcs-repo darcs-clone >/dev/null
+ $ cd darcs-clone
+ $ echo c >> a
+ $ echo c > c
+ $ darcs record -a -l -m p1.1
+ Finished recording patch 'p1.1'
+ $ cd ..
+
+update source
+
+ $ cd darcs-repo
+ $ echo b >> a
+ $ echo b > b
+ $ darcs record -a -l -m p1.2
+ Finished recording patch 'p1.2'
+
+ $ darcs pull -q -a --no-set-default ../darcs-clone
+ Backing up ./a(*) (glob)
+ We have conflicts in the following files:
+ ./a
+ $ sleep 1
+ $ echo e > a
+ $ echo f > f
+ $ mkdir dir
+ $ echo d > dir/d
+ $ echo d > dir/d2
+ $ darcs record -a -l -m p2
+ Finished recording patch 'p2'
+
+test file and directory move
+
+ $ darcs mv f ff
+
+Test remove + move
+
+ $ darcs remove dir/d2
+ $ rm dir/d2
+ $ darcs mv dir dir2
+ $ darcs record -a -l -m p3
+ Finished recording patch 'p3'
+
+The converter does not currently handle patch conflicts very well.
+When they occur, it reverts *all* changes and moves forward,
+letting the conflict resolving patch fix collisions.
+Unfortunately, non-conflicting changes, like the addition of the
+"c" file in p1.1 patch are reverted too.
+Just to say that manifest not listing "c" here is a bug.
+
+ $ cd ..
+ $ hg convert darcs-repo darcs-repo-hg
+ initializing destination darcs-repo-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 4 p0
+ 3 p1.2
+ 2 p1.1
+ 1 p2
+ 0 p3
+ $ hg log -R darcs-repo-hg -g --template '{rev} "{desc|firstline}" ({author}) files: {files}\n' "$@"
+ 4 "p3" (test@example.org) files: dir/d dir/d2 dir2/d f ff
+ 3 "p2" (test@example.org) files: a dir/d dir/d2 f
+ 2 "p1.1" (test@example.org) files:
+ 1 "p1.2" (test@example.org) files: a b
+ 0 "p0" (test@example.org) files: a
+
+ $ hg up -q -R darcs-repo-hg
+ $ hg -R darcs-repo-hg manifest --debug
+ 7225b30cdf38257d5cc7780772c051b6f33e6d6b 644 a
+ 1e88685f5ddec574a34c70af492f95b6debc8741 644 b
+ 37406831adc447ec2385014019599dfec953c806 644 dir2/d
+ b783a337463792a5c7d548ad85a7d3253c16ba8c 644 ff
diff --git a/tests/test-convert-datesort.t b/tests/test-convert-datesort.t
new file mode 100644
index 0000000..486f656
--- /dev/null
+++ b/tests/test-convert-datesort.t
@@ -0,0 +1,119 @@
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert=
+ > graphlog=
+ > EOF
+ $ hg init t
+ $ cd t
+ $ echo a >> a
+ $ hg ci -Am a0 -d '1 0'
+ adding a
+ $ hg branch brancha
+ marked working directory as branch brancha
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a >> a
+ $ hg ci -m a1 -d '2 0'
+ $ echo a >> a
+ $ hg ci -m a2 -d '3 0'
+ $ echo a >> a
+ $ hg ci -m a3 -d '4 0'
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch branchb
+ marked working directory as branch branchb
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b >> b
+ $ hg ci -Am b0 -d '6 0'
+ adding b
+ $ hg up -C brancha
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo a >> a
+ $ hg ci -m a4 -d '5 0'
+ $ echo a >> a
+ $ hg ci -m a5 -d '7 0'
+ $ echo a >> a
+ $ hg ci -m a6 -d '8 0'
+ $ hg up -C branchb
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b >> b
+ $ hg ci -m b1 -d '9 0'
+ $ cd ..
+
+convert with datesort
+
+ $ hg convert --datesort t t-datesort
+ initializing destination t-datesort repository
+ scanning source...
+ sorting...
+ converting...
+ 8 a0
+ 7 a1
+ 6 a2
+ 5 a3
+ 4 a4
+ 3 b0
+ 2 a5
+ 1 a6
+ 0 b1
+
+graph converted repo
+
+ $ hg -R t-datesort glog --template '{rev} "{desc}"\n'
+ o 8 "b1"
+ |
+ | o 7 "a6"
+ | |
+ | o 6 "a5"
+ | |
+ o | 5 "b0"
+ | |
+ | o 4 "a4"
+ | |
+ | o 3 "a3"
+ | |
+ | o 2 "a2"
+ | |
+ | o 1 "a1"
+ |/
+ o 0 "a0"
+
+
+convert with datesort (default mode)
+
+ $ hg convert t t-sourcesort
+ initializing destination t-sourcesort repository
+ scanning source...
+ sorting...
+ converting...
+ 8 a0
+ 7 a1
+ 6 a2
+ 5 a3
+ 4 b0
+ 3 a4
+ 2 a5
+ 1 a6
+ 0 b1
+
+graph converted repo
+
+ $ hg -R t-sourcesort glog --template '{rev} "{desc}"\n'
+ o 8 "b1"
+ |
+ | o 7 "a6"
+ | |
+ | o 6 "a5"
+ | |
+ | o 5 "a4"
+ | |
+ o | 4 "b0"
+ | |
+ | o 3 "a3"
+ | |
+ | o 2 "a2"
+ | |
+ | o 1 "a1"
+ |/
+ o 0 "a0"
+
diff --git a/tests/test-convert-filemap.t b/tests/test-convert-filemap.t
new file mode 100644
index 0000000..e351d7c
--- /dev/null
+++ b/tests/test-convert-filemap.t
@@ -0,0 +1,596 @@
+
+ $ HGMERGE=true; export HGMERGE
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo 'graphlog =' >> $HGRCPATH
+ $ echo 'convert =' >> $HGRCPATH
+ $ glog()
+ > {
+ > hg glog --template '{rev} "{desc}" files: {files}\n' "$@"
+ > }
+ $ hg init source
+ $ cd source
+ $ echo foo > foo
+ $ echo baz > baz
+ $ mkdir -p dir/subdir
+ $ echo dir/file >> dir/file
+ $ echo dir/file2 >> dir/file2
+ $ echo dir/file3 >> dir/file3 # to be corrupted in rev 0
+ $ echo dir/subdir/file3 >> dir/subdir/file3
+ $ echo dir/subdir/file4 >> dir/subdir/file4
+ $ hg ci -d '0 0' -qAm '0: add foo baz dir/'
+ $ echo bar > bar
+ $ echo quux > quux
+ $ echo dir/file4 >> dir/file4 # to be corrupted in rev 1
+ $ hg copy foo copied
+ $ hg ci -d '1 0' -qAm '1: add bar quux; copy foo to copied'
+ $ echo >> foo
+ $ hg ci -d '2 0' -m '2: change foo'
+ $ hg up -qC 1
+ $ echo >> bar
+ $ echo >> quux
+ $ hg ci -d '3 0' -m '3: change bar quux'
+ created new head
+ $ hg up -qC 2
+ $ hg merge -qr 3
+ $ echo >> bar
+ $ echo >> baz
+ $ hg ci -d '4 0' -m '4: first merge; change bar baz'
+ $ echo >> bar
+ $ echo 1 >> baz
+ $ echo >> quux
+ $ hg ci -d '5 0' -m '5: change bar baz quux'
+ $ hg up -qC 4
+ $ echo >> foo
+ $ echo 2 >> baz
+ $ hg ci -d '6 0' -m '6: change foo baz'
+ created new head
+ $ hg up -qC 5
+ $ hg merge -qr 6
+ $ echo >> bar
+ $ hg ci -d '7 0' -m '7: second merge; change bar'
+ $ echo >> foo
+ $ hg ci -m '8: change foo'
+ $ glog
+ @ 8 "8: change foo" files: foo
+ |
+ o 7 "7: second merge; change bar" files: bar baz
+ |\
+ | o 6 "6: change foo baz" files: baz foo
+ | |
+ o | 5 "5: change bar baz quux" files: bar baz quux
+ |/
+ o 4 "4: first merge; change bar baz" files: bar baz
+ |\
+ | o 3 "3: change bar quux" files: bar quux
+ | |
+ o | 2 "2: change foo" files: foo
+ |/
+ o 1 "1: add bar quux; copy foo to copied" files: bar copied dir/file4 quux
+ |
+ o 0 "0: add foo baz dir/" files: baz dir/file dir/file2 dir/file3 dir/subdir/file3 dir/subdir/file4 foo
+
+
+final file versions in this repo:
+
+ $ hg manifest --debug
+ 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
+ 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
+ 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
+ 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir/file
+ 75e6d3f8328f5f6ace6bf10b98df793416a09dca 644 dir/file2
+ e96dce0bc6a217656a3a410e5e6bec2c4f42bf7c 644 dir/file3
+ 6edd55f559cdce67132b12ca09e09cee08b60442 644 dir/file4
+ 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir/subdir/file3
+ 57a1c1511590f3de52874adfa04effe8a77d64af 644 dir/subdir/file4
+ 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
+ bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
+ $ hg debugrename copied
+ copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
+
+ $ cd ..
+ $ splitrepo()
+ > {
+ > msg="$1"
+ > files="$2"
+ > opts=$3
+ > echo "% $files: $msg"
+ > prefix=`echo "$files" | sed -e 's/ /-/g'`
+ > fmap="$prefix.fmap"
+ > repo="$prefix.repo"
+ > for i in $files; do
+ > echo "include $i" >> "$fmap"
+ > done
+ > hg -q convert $opts --filemap "$fmap" --datesort source "$repo"
+ > hg up -q -R "$repo"
+ > glog -R "$repo"
+ > hg -R "$repo" manifest --debug
+ > }
+ $ splitrepo 'skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd' foo
+ % foo: skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd
+ @ 3 "8: change foo" files: foo
+ |
+ o 2 "6: change foo baz" files: foo
+ |
+ o 1 "2: change foo" files: foo
+ |
+ o 0 "0: add foo baz dir/" files: foo
+
+ 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
+ $ splitrepo 'merges are not merges anymore' bar
+ % bar: merges are not merges anymore
+ @ 4 "7: second merge; change bar" files: bar
+ |
+ o 3 "5: change bar baz quux" files: bar
+ |
+ o 2 "4: first merge; change bar baz" files: bar
+ |
+ o 1 "3: change bar quux" files: bar
+ |
+ o 0 "1: add bar quux; copy foo to copied" files: bar
+
+ 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
+ $ splitrepo '1st merge is not a merge anymore; 2nd still is' baz
+ % baz: 1st merge is not a merge anymore; 2nd still is
+ @ 4 "7: second merge; change bar" files: baz
+ |\
+ | o 3 "6: change foo baz" files: baz
+ | |
+ o | 2 "5: change bar baz quux" files: baz
+ |/
+ o 1 "4: first merge; change bar baz" files: baz
+ |
+ o 0 "0: add foo baz dir/" files: baz
+
+ 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
+ $ splitrepo 'we add additional merges when they are interesting' 'foo quux'
+ % foo quux: we add additional merges when they are interesting
+ @ 8 "8: change foo" files: foo
+ |
+ o 7 "7: second merge; change bar" files:
+ |\
+ | o 6 "6: change foo baz" files: foo
+ | |
+ o | 5 "5: change bar baz quux" files: quux
+ |/
+ o 4 "4: first merge; change bar baz" files:
+ |\
+ | o 3 "3: change bar quux" files: quux
+ | |
+ o | 2 "2: change foo" files: foo
+ |/
+ o 1 "1: add bar quux; copy foo to copied" files: quux
+ |
+ o 0 "0: add foo baz dir/" files: foo
+
+ 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
+ bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
+ $ splitrepo 'partial conversion' 'bar quux' '-r 3'
+ % bar quux: partial conversion
+ @ 1 "3: change bar quux" files: bar quux
+ |
+ o 0 "1: add bar quux; copy foo to copied" files: bar quux
+
+ b79105bedc55102f394e90a789c9c380117c1b4a 644 bar
+ db0421cc6b685a458c8d86c7d5c004f94429ea23 644 quux
+ $ splitrepo 'complete the partial conversion' 'bar quux'
+ % bar quux: complete the partial conversion
+ @ 4 "7: second merge; change bar" files: bar
+ |
+ o 3 "5: change bar baz quux" files: bar quux
+ |
+ o 2 "4: first merge; change bar baz" files: bar
+ |
+ o 1 "3: change bar quux" files: bar quux
+ |
+ o 0 "1: add bar quux; copy foo to copied" files: bar quux
+
+ 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
+ bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
+ $ rm -r foo.repo
+ $ splitrepo 'partial conversion' 'foo' '-r 3'
+ % foo: partial conversion
+ @ 0 "0: add foo baz dir/" files: foo
+
+ 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo
+ $ splitrepo 'complete the partial conversion' 'foo'
+ % foo: complete the partial conversion
+ @ 3 "8: change foo" files: foo
+ |
+ o 2 "6: change foo baz" files: foo
+ |
+ o 1 "2: change foo" files: foo
+ |
+ o 0 "0: add foo baz dir/" files: foo
+
+ 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
+ $ splitrepo 'copied file; source not included in new repo' copied
+ % copied: copied file; source not included in new repo
+ @ 0 "1: add bar quux; copy foo to copied" files: copied
+
+ 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 copied
+ $ hg --cwd copied.repo debugrename copied
+ copied not renamed
+ $ splitrepo 'copied file; source included in new repo' 'foo copied'
+ % foo copied: copied file; source included in new repo
+ @ 4 "8: change foo" files: foo
+ |
+ o 3 "6: change foo baz" files: foo
+ |
+ o 2 "2: change foo" files: foo
+ |
+ o 1 "1: add bar quux; copy foo to copied" files: copied
+ |
+ o 0 "0: add foo baz dir/" files: foo
+
+ 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
+ 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
+ $ hg --cwd foo-copied.repo debugrename copied
+ copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
+ $ cat > renames.fmap <<EOF
+ > include dir
+ > exclude dir/file2
+ > rename dir dir2
+ > include foo
+ > include copied
+ > rename foo foo2
+ > rename copied copied2
+ > exclude dir/subdir
+ > include dir/subdir/file3
+ > EOF
+ $ rm source/.hg/store/data/dir/file3.i
+ $ rm source/.hg/store/data/dir/file4.i
+ $ hg -q convert --filemap renames.fmap --datesort source dummydest
+ abort: data/dir/file3.i@e96dce0bc6a2: no match found!
+ [255]
+ $ hg -q convert --filemap renames.fmap --datesort --config convert.hg.ignoreerrors=1 source renames.repo
+ ignoring: data/dir/file3.i@e96dce0bc6a2: no match found
+ ignoring: data/dir/file4.i@6edd55f559cd: no match found
+ $ hg up -q -R renames.repo
+ $ glog -R renames.repo
+ @ 4 "8: change foo" files: foo2
+ |
+ o 3 "6: change foo baz" files: foo2
+ |
+ o 2 "2: change foo" files: foo2
+ |
+ o 1 "1: add bar quux; copy foo to copied" files: copied2
+ |
+ o 0 "0: add foo baz dir/" files: dir2/file dir2/subdir/file3 foo2
+
+ $ hg -R renames.repo manifest --debug
+ d43feacba7a4f1f2080dde4a4b985bd8a0236d46 644 copied2
+ 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir2/file
+ 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir2/subdir/file3
+ 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo2
+ $ hg --cwd renames.repo debugrename copied2
+ copied2 renamed from foo2:2ed2a3912a0b24502043eae84ee4b279c18b90dd
+
+copied:
+
+ $ hg --cwd source cat copied
+ foo
+
+copied2:
+
+ $ hg --cwd renames.repo cat copied2
+ foo
+
+filemap errors
+
+ $ cat > errors.fmap <<EOF
+ > include dir/ # beware that comments changes error line numbers!
+ > exclude /dir
+ > rename dir//dir /dir//dir/ "out of sync"
+ > include
+ > EOF
+ $ hg -q convert --filemap errors.fmap source errors.repo
+ errors.fmap:1: superfluous / in exclude 'dir/'
+ errors.fmap:3: superfluous / in include '/dir'
+ errors.fmap:3: superfluous / in rename '/dir'
+ errors.fmap:3: superfluous / in exclude 'dir//dir'
+ errors.fmap:4: unknown directive 'out of sync'
+ errors.fmap:5: path to exclude is missing
+ abort: errors in filemap
+ [255]
+
+test branch closing revision pruning if branch is pruned
+
+ $ hg init branchpruning
+ $ cd branchpruning
+ $ hg branch foo
+ marked working directory as branch foo
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ hg ci --close-branch -m closefoo
+ $ hg up 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch empty
+ marked working directory as branch empty
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m emptybranch
+ $ hg ci --close-branch -m closeempty
+ $ hg up 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch default
+ marked working directory as branch default
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b > b
+ $ hg ci -Am addb
+ adding b
+ $ hg ci --close-branch -m closedefault
+ $ cat > filemap <<EOF
+ > include b
+ > EOF
+ $ cd ..
+ $ hg convert branchpruning branchpruning-hg1
+ initializing destination branchpruning-hg1 repository
+ scanning source...
+ sorting...
+ converting...
+ 5 adda
+ 4 closefoo
+ 3 emptybranch
+ 2 closeempty
+ 1 addb
+ 0 closedefault
+ $ glog -R branchpruning-hg1
+ o 5 "closedefault" files:
+ |
+ o 4 "addb" files: b
+ |
+ | o 3 "closeempty" files:
+ | |
+ | o 2 "emptybranch" files:
+ |/
+ | o 1 "closefoo" files:
+ |/
+ o 0 "adda" files: a
+
+
+exercise incremental conversion at the same time
+
+ $ hg convert -r0 --filemap branchpruning/filemap branchpruning branchpruning-hg2
+ initializing destination branchpruning-hg2 repository
+ scanning source...
+ sorting...
+ converting...
+ 0 adda
+ $ hg convert -r4 --filemap branchpruning/filemap branchpruning branchpruning-hg2
+ scanning source...
+ sorting...
+ converting...
+ 0 addb
+ $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2
+ scanning source...
+ sorting...
+ converting...
+ 3 closefoo
+ 2 emptybranch
+ 1 closeempty
+ 0 closedefault
+ $ glog -R branchpruning-hg2
+ o 1 "closedefault" files:
+ |
+ o 0 "addb" files: b
+
+
+filemap rename undoing revision rename
+
+ $ hg init renameundo
+ $ cd renameundo
+ $ echo 1 > a
+ $ echo 1 > c
+ $ hg ci -qAm add
+ $ hg mv -q a b/a
+ $ hg mv -q c b/c
+ $ hg ci -qm rename
+ $ echo 2 > b/a
+ $ echo 2 > b/c
+ $ hg ci -qm modify
+ $ cd ..
+
+ $ echo "rename b ." > renameundo.fmap
+ $ hg convert --filemap renameundo.fmap renameundo renameundo2
+ initializing destination renameundo2 repository
+ scanning source...
+ sorting...
+ converting...
+ 2 add
+ 1 rename
+ filtering out empty revision
+ repository tip rolled back to revision 0 (undo commit)
+ 0 modify
+ $ glog -R renameundo2
+ o 1 "modify" files: a c
+ |
+ o 0 "add" files: a c
+
+
+
+test merge parents/empty merges pruning
+
+ $ glog()
+ > {
+ > hg glog --template '{rev}:{node|short}@{branch} "{desc}" files: {files}\n' "$@"
+ > }
+
+test anonymous branch pruning
+
+ $ hg init anonymousbranch
+ $ cd anonymousbranch
+ $ echo a > a
+ $ echo b > b
+ $ hg ci -Am add
+ adding a
+ adding b
+ $ echo a >> a
+ $ hg ci -m changea
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b >> b
+ $ hg ci -m changeb
+ created new head
+ $ hg up 1
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m merge
+ $ cd ..
+
+ $ cat > filemap <<EOF
+ > include a
+ > EOF
+ $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg
+ initializing destination anonymousbranch-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 3 add
+ 2 changea
+ 1 changeb
+ 0 merge
+ $ glog -R anonymousbranch
+ @ 3:c71d5201a498@default "merge" files:
+ |\
+ | o 2:607eb44b17f9@default "changeb" files: b
+ | |
+ o | 1:1f60ea617824@default "changea" files: a
+ |/
+ o 0:0146e6129113@default "add" files: a b
+
+ $ glog -R anonymousbranch-hg
+ o 1:cda818e7219b@default "changea" files: a
+ |
+ o 0:c334dc3be0da@default "add" files: a
+
+ $ cat anonymousbranch-hg/.hg/shamap
+ 0146e6129113dba9ac90207cfdf2d7ed35257ae5 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
+ 1f60ea61782421edf8d051ff4fcb61b330f26a4a cda818e7219b5f7f3fb9f49780054ed6a1905ec3
+ 607eb44b17f9348cd5cbd26e16af87ba77b0b037 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
+ c71d5201a498b2658d105a6bf69d7a0df2649aea cda818e7219b5f7f3fb9f49780054ed6a1905ec3
+
+ $ cat > filemap <<EOF
+ > include b
+ > EOF
+ $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg2
+ initializing destination anonymousbranch-hg2 repository
+ scanning source...
+ sorting...
+ converting...
+ 3 add
+ 2 changea
+ 1 changeb
+ 0 merge
+ $ glog -R anonymousbranch
+ @ 3:c71d5201a498@default "merge" files:
+ |\
+ | o 2:607eb44b17f9@default "changeb" files: b
+ | |
+ o | 1:1f60ea617824@default "changea" files: a
+ |/
+ o 0:0146e6129113@default "add" files: a b
+
+ $ glog -R anonymousbranch-hg2
+ o 1:62dd350b0df6@default "changeb" files: b
+ |
+ o 0:4b9ced861657@default "add" files: b
+
+ $ cat anonymousbranch-hg2/.hg/shamap
+ 0146e6129113dba9ac90207cfdf2d7ed35257ae5 4b9ced86165703791653059a1db6ed864630a523
+ 1f60ea61782421edf8d051ff4fcb61b330f26a4a 4b9ced86165703791653059a1db6ed864630a523
+ 607eb44b17f9348cd5cbd26e16af87ba77b0b037 62dd350b0df695f7d2c82a02e0499b16fd790f22
+ c71d5201a498b2658d105a6bf69d7a0df2649aea 62dd350b0df695f7d2c82a02e0499b16fd790f22
+
+test named branch pruning
+
+ $ hg init namedbranch
+ $ cd namedbranch
+ $ echo a > a
+ $ echo b > b
+ $ hg ci -Am add
+ adding a
+ adding b
+ $ echo a >> a
+ $ hg ci -m changea
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch foo
+ marked working directory as branch foo
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b >> b
+ $ hg ci -m changeb
+ $ hg up default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m merge
+ $ cd ..
+
+ $ cat > filemap <<EOF
+ > include a
+ > EOF
+ $ hg convert --filemap filemap namedbranch namedbranch-hg
+ initializing destination namedbranch-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 3 add
+ 2 changea
+ 1 changeb
+ 0 merge
+ $ glog -R namedbranch
+ @ 3:73899bcbe45c@default "merge" files:
+ |\
+ | o 2:8097982d19fc@foo "changeb" files: b
+ | |
+ o | 1:1f60ea617824@default "changea" files: a
+ |/
+ o 0:0146e6129113@default "add" files: a b
+
+ $ glog -R namedbranch-hg
+ o 1:cda818e7219b@default "changea" files: a
+ |
+ o 0:c334dc3be0da@default "add" files: a
+
+
+ $ cd namedbranch
+ $ hg --config extensions.mq= strip tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/namedbranch/.hg/strip-backup/73899bcbe45c-backup.hg (glob)
+ $ hg up foo
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m merge
+ $ cd ..
+
+ $ hg convert --filemap filemap namedbranch namedbranch-hg2
+ initializing destination namedbranch-hg2 repository
+ scanning source...
+ sorting...
+ converting...
+ 3 add
+ 2 changea
+ 1 changeb
+ 0 merge
+ $ glog -R namedbranch
+ @ 3:e1959de76e1b@foo "merge" files:
+ |\
+ | o 2:8097982d19fc@foo "changeb" files: b
+ | |
+ o | 1:1f60ea617824@default "changea" files: a
+ |/
+ o 0:0146e6129113@default "add" files: a b
+
+ $ glog -R namedbranch-hg2
+ o 2:dcf314454667@foo "merge" files:
+ |\
+ | o 1:cda818e7219b@default "changea" files: a
+ |/
+ o 0:c334dc3be0da@default "add" files: a
+
diff --git a/tests/test-convert-git.t b/tests/test-convert-git.t
new file mode 100644
index 0000000..e4261b7
--- /dev/null
+++ b/tests/test-convert-git.t
@@ -0,0 +1,300 @@
+
+ $ "$TESTDIR/hghave" git || exit 80
+ $ echo "[core]" >> $HOME/.gitconfig
+ $ echo "autocrlf = false" >> $HOME/.gitconfig
+ $ echo "[core]" >> $HOME/.gitconfig
+ $ echo "autocrlf = false" >> $HOME/.gitconfig
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert=" >> $HGRCPATH
+ $ echo 'hgext.graphlog =' >> $HGRCPATH
+ $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
+ $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
+ $ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
+ $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
+ $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
+ $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
+ $ count=10
+ $ commit()
+ > {
+ > GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
+ > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
+ > git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
+ > count=`expr $count + 1`
+ > }
+ $ mkdir git-repo
+ $ cd git-repo
+ $ git init-db >/dev/null 2>/dev/null
+ $ echo a > a
+ $ mkdir d
+ $ echo b > d/b
+ $ git add a d
+ $ commit -a -m t1
+
+Remove the directory, then try to replace it with a file
+(issue 754)
+
+ $ git rm -f d/b
+ rm 'd/b'
+ $ commit -m t2
+ $ echo d > d
+ $ git add d
+ $ commit -m t3
+ $ echo b >> a
+ $ commit -a -m t4.1
+ $ git checkout -b other HEAD~ >/dev/null 2>/dev/null
+ $ echo c > a
+ $ echo a >> a
+ $ commit -a -m t4.2
+ $ git checkout master >/dev/null 2>/dev/null
+ $ git pull --no-commit . other > /dev/null 2>/dev/null
+ $ commit -m 'Merge branch other'
+ $ cd ..
+ $ hg convert --datesort git-repo
+ assuming destination git-repo-hg
+ initializing destination git-repo-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 5 t1
+ 4 t2
+ 3 t3
+ 2 t4.1
+ 1 t4.2
+ 0 Merge branch other
+ updating bookmarks
+ $ hg up -q -R git-repo-hg
+ $ hg -R git-repo-hg tip -v
+ changeset: 5:c78094926be2
+ bookmark: master
+ tag: tip
+ parent: 3:f5f5cb45432b
+ parent: 4:4e174f80c67c
+ user: test <test@example.org>
+ date: Mon Jan 01 00:00:15 2007 +0000
+ files: a
+ description:
+ Merge branch other
+
+
+ $ count=10
+ $ mkdir git-repo2
+ $ cd git-repo2
+ $ git init-db >/dev/null 2>/dev/null
+ $ echo foo > foo
+ $ git add foo
+ $ commit -a -m 'add foo'
+ $ echo >> foo
+ $ commit -a -m 'change foo'
+ $ git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
+ $ echo quux >> quux
+ $ git add quux
+ $ commit -a -m 'add quux'
+ $ echo bar > bar
+ $ git add bar
+ $ commit -a -m 'add bar'
+ $ git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
+ $ echo baz > baz
+ $ git add baz
+ $ commit -a -m 'add baz'
+ $ git checkout master >/dev/null 2>/dev/null
+ $ git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
+ $ commit -m 'Octopus merge'
+ $ echo bar >> bar
+ $ commit -a -m 'change bar'
+ $ git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
+ $ echo >> foo
+ $ commit -a -m 'change foo'
+ $ git checkout master >/dev/null 2>/dev/null
+ $ git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
+ $ commit -m 'Discard change to foo'
+ $ cd ..
+ $ glog()
+ > {
+ > hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
+ > }
+ $ splitrepo()
+ > {
+ > msg="$1"
+ > files="$2"
+ > opts=$3
+ > echo "% $files: $msg"
+ > prefix=`echo "$files" | sed -e 's/ /-/g'`
+ > fmap="$prefix.fmap"
+ > repo="$prefix.repo"
+ > for i in $files; do
+ > echo "include $i" >> "$fmap"
+ > done
+ > hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
+ > hg up -q -R "$repo"
+ > glog -R "$repo"
+ > hg -R "$repo" manifest --debug
+ > }
+
+full conversion
+
+ $ hg -q convert --datesort git-repo2 fullrepo
+ $ hg up -q -R fullrepo
+ $ glog -R fullrepo
+ @ 9 "Discard change to foo" files: foo
+ |\
+ | o 8 "change foo" files: foo
+ | |
+ o | 7 "change bar" files: bar
+ |/
+ o 6 "(octopus merge fixup)" files:
+ |\
+ | o 5 "Octopus merge" files: baz
+ | |\
+ o | | 4 "add baz" files: baz
+ | | |
+ +---o 3 "add bar" files: bar
+ | |
+ o | 2 "add quux" files: quux
+ | |
+ | o 1 "change foo" files: foo
+ |/
+ o 0 "add foo" files: foo
+
+ $ hg -R fullrepo manifest --debug
+ 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
+ 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
+ 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
+ 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
+ $ splitrepo 'octopus merge' 'foo bar baz'
+ % foo bar baz: octopus merge
+ @ 8 "Discard change to foo" files: foo
+ |\
+ | o 7 "change foo" files: foo
+ | |
+ o | 6 "change bar" files: bar
+ |/
+ o 5 "(octopus merge fixup)" files:
+ |\
+ | o 4 "Octopus merge" files: baz
+ | |\
+ o | | 3 "add baz" files: baz
+ | | |
+ +---o 2 "add bar" files: bar
+ | |
+ | o 1 "change foo" files: foo
+ |/
+ o 0 "add foo" files: foo
+
+ 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
+ 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
+ 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
+ $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
+ % foo baz quux: only some parents of an octopus merge; "discard" a head
+ @ 6 "Discard change to foo" files: foo
+ |
+ o 5 "change foo" files: foo
+ |
+ o 4 "Octopus merge" files:
+ |\
+ | o 3 "add baz" files: baz
+ | |
+ | o 2 "add quux" files: quux
+ | |
+ o | 1 "change foo" files: foo
+ |/
+ o 0 "add foo" files: foo
+
+ 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
+ 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
+ 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
+
+test binary conversion (issue 1359)
+
+ $ mkdir git-repo3
+ $ cd git-repo3
+ $ git init-db >/dev/null 2>/dev/null
+ $ python -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
+ $ git add b
+ $ commit -a -m addbinary
+ $ cd ..
+
+convert binary file
+
+ $ hg convert git-repo3 git-repo3-hg
+ initializing destination git-repo3-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 0 addbinary
+ updating bookmarks
+ $ cd git-repo3-hg
+ $ hg up -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ python -c 'print len(file("b", "rb").read())'
+ 4096
+ $ cd ..
+
+test author vs committer
+
+ $ mkdir git-repo4
+ $ cd git-repo4
+ $ git init-db >/dev/null 2>/dev/null
+ $ echo >> foo
+ $ git add foo
+ $ commit -a -m addfoo
+ $ echo >> foo
+ $ GIT_AUTHOR_NAME="nottest"
+ $ commit -a -m addfoo2
+ $ cd ..
+
+convert author committer
+
+ $ hg convert git-repo4 git-repo4-hg
+ initializing destination git-repo4-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 addfoo
+ 0 addfoo2
+ updating bookmarks
+ $ hg -R git-repo4-hg log -v
+ changeset: 1:d63e967f93da
+ bookmark: master
+ tag: tip
+ user: nottest <test@example.org>
+ date: Mon Jan 01 00:00:21 2007 +0000
+ files: foo
+ description:
+ addfoo2
+
+ committer: test <test@example.org>
+
+
+ changeset: 0:0735477b0224
+ user: test <test@example.org>
+ date: Mon Jan 01 00:00:20 2007 +0000
+ files: foo
+ description:
+ addfoo
+
+
+
+--sourceorder should fail
+
+ $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
+ initializing destination git-repo4-sourcesort-hg repository
+ abort: --sourcesort is not supported by this data source
+ [255]
+
+damage git repository and convert again
+
+ $ cat > damage.py <<EOF
+ > import os
+ > import stat
+ > for root, dirs, files in os.walk('git-repo4/.git/objects'):
+ > if files:
+ > path = os.path.join(root, files[0])
+ > if os.name == 'nt':
+ > os.chmod(path, stat.S_IWUSR)
+ > os.remove(path)
+ > break
+ > EOF
+ $ python damage.py
+ $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | \
+ > grep 'abort:' | sed 's/abort:.*/abort:/g'
+ abort:
diff --git a/tests/test-convert-hg-sink.t b/tests/test-convert-hg-sink.t
new file mode 100644
index 0000000..999faf8
--- /dev/null
+++ b/tests/test-convert-hg-sink.t
@@ -0,0 +1,124 @@
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert=
+ > [convert]
+ > hg.saverev=False
+ > EOF
+ $ hg init orig
+ $ cd orig
+ $ echo foo > foo
+ $ echo bar > bar
+ $ hg ci -qAm 'add foo and bar'
+ $ hg rm foo
+ $ hg ci -m 'remove foo'
+ $ mkdir foo
+ $ echo file > foo/file
+ $ hg ci -qAm 'add foo/file'
+ $ hg tag some-tag
+ $ hg log
+ changeset: 3:593cbf6fb2b4
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag some-tag for changeset ad681a868e44
+
+ changeset: 2:ad681a868e44
+ tag: some-tag
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo/file
+
+ changeset: 1:cbba8ecc03b7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: remove foo
+
+ changeset: 0:327daa9251fa
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo and bar
+
+ $ cd ..
+ $ hg convert orig new 2>&1 | grep -v 'subversion python bindings could not be loaded'
+ initializing destination new repository
+ scanning source...
+ sorting...
+ converting...
+ 3 add foo and bar
+ 2 remove foo
+ 1 add foo/file
+ 0 Added tag some-tag for changeset ad681a868e44
+ $ cd new
+ $ hg out ../orig
+ comparing with ../orig
+ searching for changes
+ no changes found
+ [1]
+
+dirstate should be empty:
+
+ $ hg debugstate
+ $ hg parents -q
+ $ hg up -C
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg copy bar baz
+
+put something in the dirstate:
+
+ $ hg debugstate > debugstate
+ $ grep baz debugstate
+ a 0 -1 unset baz
+ copy: bar -> baz
+
+add a new revision in the original repo
+
+ $ cd ../orig
+ $ echo baz > baz
+ $ hg ci -qAm 'add baz'
+ $ cd ..
+ $ hg convert orig new 2>&1 | grep -v 'subversion python bindings could not be loaded'
+ scanning source...
+ sorting...
+ converting...
+ 0 add baz
+ $ cd new
+ $ hg out ../orig
+ comparing with ../orig
+ searching for changes
+ no changes found
+ [1]
+
+dirstate should be the same (no output below):
+
+ $ hg debugstate > new-debugstate
+ $ diff debugstate new-debugstate
+
+no copies
+
+ $ hg up -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg debugrename baz
+ baz not renamed
+ $ cd ..
+
+test tag rewriting
+
+ $ cat > filemap <<EOF
+ > exclude foo
+ > EOF
+ $ hg convert --filemap filemap orig new-filemap 2>&1 | grep -v 'subversion python bindings could not be loaded'
+ initializing destination new-filemap repository
+ scanning source...
+ sorting...
+ converting...
+ 4 add foo and bar
+ 3 remove foo
+ 2 add foo/file
+ 1 Added tag some-tag for changeset ad681a868e44
+ 0 add baz
+ $ cd new-filemap
+ $ hg tags
+ tip 2:6f4fd1df87fb
+ some-tag 0:ba8636729451
+ $ cd ..
diff --git a/tests/test-convert-hg-source.t b/tests/test-convert-hg-source.t
new file mode 100644
index 0000000..a39b2b7
--- /dev/null
+++ b/tests/test-convert-hg-source.t
@@ -0,0 +1,149 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert=
+ > [convert]
+ > hg.saverev=False
+ > EOF
+ $ hg init orig
+ $ cd orig
+ $ echo foo > foo
+ $ echo bar > bar
+ $ hg ci -qAm 'add foo bar' -d '0 0'
+ $ echo >> foo
+ $ hg ci -m 'change foo' -d '1 0'
+ $ hg up -qC 0
+ $ hg copy --after --force foo bar
+ $ hg copy foo baz
+ $ hg ci -m 'make bar and baz copies of foo' -d '2 0'
+ created new head
+ $ hg bookmark premerge1
+ $ hg merge -r 1
+ merging baz and foo to baz
+ 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m 'merge local copy' -d '3 0'
+ $ hg up -C 1
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bookmark premerge2
+ $ hg merge 2
+ merging foo and baz to baz
+ 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m 'merge remote copy' -d '4 0'
+ created new head
+#if execbit
+ $ chmod +x baz
+#else
+ $ echo some other change to make sure we get a rev 5 > baz
+#endif
+ $ hg ci -m 'mark baz executable' -d '5 0'
+ $ cd ..
+ $ hg convert --datesort orig new 2>&1 | grep -v 'subversion python bindings could not be loaded'
+ initializing destination new repository
+ scanning source...
+ sorting...
+ converting...
+ 5 add foo bar
+ 4 change foo
+ 3 make bar and baz copies of foo
+ 2 merge local copy
+ 1 merge remote copy
+ 0 mark baz executable
+ updating bookmarks
+ $ cd new
+ $ hg out ../orig
+ comparing with ../orig
+ searching for changes
+ no changes found
+ [1]
+#if execbit
+ $ hg bookmarks
+ premerge1 3:973ef48a98a4
+ premerge2 5:13d9b87cf8f8
+#else
+Different hash because no x bit
+ $ hg bookmarks
+ premerge1 3:973ef48a98a4
+ premerge2 5:df0779bcf33c
+#endif
+ $ cd ..
+
+check shamap LF and CRLF handling
+
+ $ cat > rewrite.py <<EOF
+ > import sys
+ > # Interlace LF and CRLF
+ > lines = [(l.rstrip() + ((i % 2) and '\n' or '\r\n'))
+ > for i, l in enumerate(file(sys.argv[1]))]
+ > file(sys.argv[1], 'wb').write(''.join(lines))
+ > EOF
+ $ python rewrite.py new/.hg/shamap
+ $ cd orig
+ $ hg up -qC 1
+ $ echo foo >> foo
+ $ hg ci -qm 'change foo again'
+ $ hg up -qC 2
+ $ echo foo >> foo
+ $ hg ci -qm 'change foo again again'
+ $ cd ..
+ $ hg convert --datesort orig new 2>&1 | grep -v 'subversion python bindings could not be loaded'
+ scanning source...
+ sorting...
+ converting...
+ 1 change foo again again
+ 0 change foo again
+ updating bookmarks
+
+init broken repository
+
+ $ hg init broken
+ $ cd broken
+ $ echo a >> a
+ $ echo b >> b
+ $ hg ci -qAm init
+ $ echo a >> a
+ $ echo b >> b
+ $ hg copy b c
+ $ hg ci -qAm changeall
+ $ hg up -qC 0
+ $ echo bc >> b
+ $ hg ci -m changebagain
+ created new head
+ $ HGMERGE=internal:local hg -q merge
+ $ hg ci -m merge
+ $ hg mv b d
+ $ hg ci -m moveb
+
+break it
+
+ $ rm .hg/store/data/b.*
+ $ cd ..
+ $ hg --config convert.hg.ignoreerrors=True convert broken fixed
+ initializing destination fixed repository
+ scanning source...
+ sorting...
+ converting...
+ 4 init
+ ignoring: data/b.i@1e88685f5dde: no match found
+ 3 changeall
+ 2 changebagain
+ 1 merge
+ 0 moveb
+ $ hg -R fixed verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 5 changesets, 5 total revisions
+
+manifest -r 0
+
+ $ hg -R fixed manifest -r 0
+ a
+
+manifest -r tip
+
+ $ hg -R fixed manifest -r tip
+ a
+ c
+ d
diff --git a/tests/test-convert-hg-startrev.t b/tests/test-convert-hg-startrev.t
new file mode 100644
index 0000000..4d62cf2
--- /dev/null
+++ b/tests/test-convert-hg-startrev.t
@@ -0,0 +1,174 @@
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog =
+ > convert =
+ > [convert]
+ > hg.saverev = yes
+ > EOF
+
+ $ glog()
+ > {
+ > hg -R "$1" glog --template '{rev} "{desc}" files: {files}\n'
+ > }
+
+ $ hg init source
+ $ cd source
+
+ $ echo a > a
+ $ echo b > b
+ $ hg ci -d '0 0' -qAm '0: add a b'
+ $ echo c > c
+ $ hg ci -d '1 0' -qAm '1: add c'
+ $ hg copy a e
+ $ echo b >> b
+ $ hg ci -d '2 0' -qAm '2: copy e from a, change b'
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo a >> a
+ $ hg ci -d '3 0' -qAm '3: change a'
+ $ hg merge
+ merging a and e to e
+ 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg copy b d
+ $ hg ci -d '4 0' -qAm '4: merge 2 and 3, copy d from b'
+ $ echo a >> a
+ $ hg ci -d '5 0' -qAm '5: change a'
+ $ cd ..
+
+Convert from null revision
+
+ $ hg convert --config convert.hg.startrev=null source full
+ initializing destination full repository
+ scanning source...
+ sorting...
+ converting...
+ 5 0: add a b
+ 4 1: add c
+ 3 2: copy e from a, change b
+ 2 3: change a
+ 1 4: merge 2 and 3, copy d from b
+ 0 5: change a
+
+ $ glog full
+ o 5 "5: change a" files: a
+ |
+ o 4 "4: merge 2 and 3, copy d from b" files: d e
+ |\
+ | o 3 "3: change a" files: a
+ | |
+ o | 2 "2: copy e from a, change b" files: b e
+ | |
+ o | 1 "1: add c" files: c
+ |/
+ o 0 "0: add a b" files: a b
+
+ $ rm -Rf full
+
+Convert from zero revision
+
+ $ hg convert --config convert.hg.startrev=0 source full
+ initializing destination full repository
+ scanning source...
+ sorting...
+ converting...
+ 5 0: add a b
+ 4 1: add c
+ 3 2: copy e from a, change b
+ 2 3: change a
+ 1 4: merge 2 and 3, copy d from b
+ 0 5: change a
+
+ $ glog full
+ o 5 "5: change a" files: a
+ |
+ o 4 "4: merge 2 and 3, copy d from b" files: d e
+ |\
+ | o 3 "3: change a" files: a
+ | |
+ o | 2 "2: copy e from a, change b" files: b e
+ | |
+ o | 1 "1: add c" files: c
+ |/
+ o 0 "0: add a b" files: a b
+
+Convert from merge parent
+
+ $ hg convert --config convert.hg.startrev=1 source conv1
+ initializing destination conv1 repository
+ scanning source...
+ sorting...
+ converting...
+ 3 1: add c
+ 2 2: copy e from a, change b
+ 1 4: merge 2 and 3, copy d from b
+ 0 5: change a
+
+ $ glog conv1
+ o 3 "5: change a" files: a
+ |
+ o 2 "4: merge 2 and 3, copy d from b" files: a d e
+ |
+ o 1 "2: copy e from a, change b" files: b e
+ |
+ o 0 "1: add c" files: a b c
+
+ $ cd conv1
+ $ hg up -q
+
+Check copy preservation
+
+ $ hg log --follow --copies e
+ changeset: 2:79818a521a40
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: 4: merge 2 and 3, copy d from b
+
+ changeset: 1:3e6201832cce
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: 2: copy e from a, change b
+
+Check copy removal on missing parent
+
+ $ hg log --follow --copies d
+ changeset: 2:79818a521a40
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: 4: merge 2 and 3, copy d from b
+
+ $ hg cat -r tip a b
+ a
+ a
+ a
+ b
+ b
+ $ hg -q verify
+ $ cd ..
+
+Convert from merge
+
+ $ hg convert --config convert.hg.startrev=4 source conv4
+ initializing destination conv4 repository
+ scanning source...
+ sorting...
+ converting...
+ 1 4: merge 2 and 3, copy d from b
+ 0 5: change a
+ $ glog conv4
+ o 1 "5: change a" files: a
+ |
+ o 0 "4: merge 2 and 3, copy d from b" files: a b c d e
+
+ $ cd conv4
+ $ hg up -C
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg cat -r tip a b
+ a
+ a
+ a
+ b
+ b
+ $ hg -q verify
+ $ cd ..
diff --git a/tests/test-convert-hg-svn.t b/tests/test-convert-hg-svn.t
new file mode 100644
index 0000000..d7ebedd
--- /dev/null
+++ b/tests/test-convert-hg-svn.t
@@ -0,0 +1,105 @@
+
+ $ "$TESTDIR/hghave" svn svn-bindings || exit 80
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert = " >> $HGRCPATH
+ $ echo "mq = " >> $HGRCPATH
+
+ $ SVNREPOPATH=`pwd`/svn-repo
+#if windows
+ $ SVNREPOURL=file:///`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
+#else
+ $ SVNREPOURL=file://`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
+#endif
+
+ $ svnadmin create "$SVNREPOPATH"
+ $ cat > "$SVNREPOPATH"/hooks/pre-revprop-change <<EOF
+ > #!/bin/sh
+ >
+ > REPOS="$1"
+ > REV="$2"
+ > USER="$3"
+ > PROPNAME="$4"
+ > ACTION="$5"
+ >
+ > if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi
+ > if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-branch" ]; then exit 0; fi
+ > if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-rev" ]; then exit 0; fi
+ >
+ > echo "Changing prohibited revision property" >&2
+ > exit 1
+ > EOF
+ $ chmod +x "$SVNREPOPATH"/hooks/pre-revprop-change
+ $ svn co "$SVNREPOURL" "$SVNREPOPATH"-wc
+ Checked out revision 0.
+ $ cd "$SVNREPOPATH"-wc
+ $ echo a > a
+ $ svn add a
+ A a
+ $ svn ci -m'added a' a
+ Adding a
+ Transmitting file data .
+ Committed revision 1.
+ $ cd ..
+
+initial roundtrip
+
+ $ hg convert -s svn -d hg "$SVNREPOPATH"-wc "$SVNREPOPATH"-hg | grep -v initializing
+ scanning source...
+ sorting...
+ converting...
+ 0 added a
+ $ hg convert -s hg -d svn "$SVNREPOPATH"-hg "$SVNREPOPATH"-wc
+ scanning source...
+ sorting...
+ converting...
+
+second roundtrip should do nothing
+
+ $ hg convert -s svn -d hg "$SVNREPOPATH"-wc "$SVNREPOPATH"-hg
+ scanning source...
+ sorting...
+ converting...
+ $ hg convert -s hg -d svn "$SVNREPOPATH"-hg "$SVNREPOPATH"-wc
+ scanning source...
+ sorting...
+ converting...
+
+new hg rev
+
+ $ hg clone "$SVNREPOPATH"-hg "$SVNREPOPATH"-work
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd "$SVNREPOPATH"-work
+ $ echo b > b
+ $ hg add b
+ $ hg ci -mb
+
+adding an empty revision
+
+ $ hg qnew -m emtpy empty
+ $ hg qfinish -a
+ $ cd ..
+
+echo hg to svn
+
+ $ hg --cwd "$SVNREPOPATH"-hg pull -q "$SVNREPOPATH"-work
+ $ hg convert -s hg -d svn "$SVNREPOPATH"-hg "$SVNREPOPATH"-wc
+ scanning source...
+ sorting...
+ converting...
+ 1 b
+ 0 emtpy
+
+svn back to hg should do nothing
+
+ $ hg convert -s svn -d hg "$SVNREPOPATH"-wc "$SVNREPOPATH"-hg
+ scanning source...
+ sorting...
+ converting...
+
+hg back to svn should do nothing
+
+ $ hg convert -s hg -d svn "$SVNREPOPATH"-hg "$SVNREPOPATH"-wc
+ scanning source...
+ sorting...
+ converting...
diff --git a/tests/test-convert-mtn-rename-directory.out b/tests/test-convert-mtn-rename-directory.out
new file mode 100644
index 0000000..4ec1d87
--- /dev/null
+++ b/tests/test-convert-mtn-rename-directory.out
@@ -0,0 +1,23 @@
+% tedious monotone keys configuration
+% create monotone repository
+mtn: adding dir1 to workspace manifest
+mtn: adding dir1/subdir1 to workspace manifest
+mtn: adding dir1/subdir1/file1 to workspace manifest
+mtn: beginning commit on branch 'com.selenic.test'
+mtn: committed revision 5ed13ff5582d8d1e319f079b694a37d2b45edfc8
+% rename directory
+mtn: skipping dir1, already accounted for in workspace
+mtn: renaming dir1/subdir1 to dir1/subdir2 in workspace manifest
+mtn: beginning commit on branch 'com.selenic.test'
+mtn: committed revision 985204142a822b22ee86b509d61f3c5ab6857d2b
+% convert
+assuming destination repo.mtn-hg
+initializing destination repo.mtn-hg repository
+scanning source...
+sorting...
+converting...
+1 initialize
+0 rename
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% manifest
+dir1/subdir2/file1
diff --git a/tests/test-convert-mtn.t b/tests/test-convert-mtn.t
new file mode 100644
index 0000000..17083ee
--- /dev/null
+++ b/tests/test-convert-mtn.t
@@ -0,0 +1,388 @@
+
+ $ "$TESTDIR/hghave" mtn || exit 80
+
+Monotone directory is called .monotone on *nix and monotone
+on Windows. Having a variable here ease test patching.
+
+ $ mtndir=.monotone
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert=" >> $HGRCPATH
+ $ echo 'graphlog =' >> $HGRCPATH
+
+Windows version of monotone home
+
+ $ APPDATA=$HOME; export APPDATA
+
+tedious monotone keys configuration
+The /dev/null redirection is necessary under Windows, or
+it complains about home directory permissions
+
+ $ mtn --quiet genkey test@selenic.com 1>/dev/null 2>&1 <<EOF
+ > passphrase
+ > passphrase
+ > EOF
+ $ cat >> $HOME/$mtndir/monotonerc <<EOF
+ > function get_passphrase(keypair_id)
+ > return "passphrase"
+ > end
+ > EOF
+
+create monotone repository
+
+ $ mtn db init --db=repo.mtn
+ $ mtn --db=repo.mtn --branch=com.selenic.test setup workingdir
+ $ cd workingdir
+ $ echo a > a
+ $ mkdir dir
+ $ echo b > dir/b
+ $ echo d > dir/d
+ $ python -c 'file("bin", "wb").write("a\\x00b")'
+ $ echo c > c
+ $ mtn add a dir/b dir/d c bin
+ mtn: adding 'a' to workspace manifest
+ mtn: adding 'bin' to workspace manifest
+ mtn: adding 'c' to workspace manifest
+ mtn: adding 'dir' to workspace manifest
+ mtn: adding 'dir/b' to workspace manifest
+ mtn: adding 'dir/d' to workspace manifest
+ $ mtn ci -m initialize
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision 0f6e5e4f2e7d2a8ef312408f57618abf026afd90
+
+update monotone working directory
+
+ $ mtn mv a dir/a
+ mtn: skipping 'dir', already accounted for in workspace
+ mtn: renaming 'a' to 'dir/a' in workspace manifest
+ $ echo a >> dir/a
+ $ echo b >> dir/b
+ $ mtn drop c
+ mtn: dropping 'c' from workspace manifest
+ $ python -c 'file("bin", "wb").write("b\\x00c")'
+ $ mtn ci -m update1
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision 51d0a982464573a2a2cf5ee2c9219c652aaebeff
+ $ cd ..
+
+convert once
+
+ $ hg convert -s mtn repo.mtn
+ assuming destination repo.mtn-hg
+ initializing destination repo.mtn-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 initialize
+ 0 update1
+ $ cd workingdir
+ $ echo e > e
+ $ mtn add e
+ mtn: adding 'e' to workspace manifest
+ $ mtn drop dir/b
+ mtn: dropping 'dir/b' from workspace manifest
+ $ mtn mv bin bin2
+ mtn: renaming 'bin' to 'bin2' in workspace manifest
+ $ mtn ci -m 'update2 "with" quotes'
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision ebe58335d85d8cb176b6d0a12be04f5314b998da
+
+test directory move
+
+ $ mkdir -p dir1/subdir1
+ $ mkdir -p dir1/subdir2_other
+ $ echo file1 > dir1/subdir1/file1
+ $ echo file2 > dir1/subdir2_other/file1
+ $ mtn add dir1/subdir1/file1 dir1/subdir2_other/file1
+ mtn: adding 'dir1' to workspace manifest
+ mtn: adding 'dir1/subdir1' to workspace manifest
+ mtn: adding 'dir1/subdir1/file1' to workspace manifest
+ mtn: adding 'dir1/subdir2_other' to workspace manifest
+ mtn: adding 'dir1/subdir2_other/file1' to workspace manifest
+ $ mtn ci -m createdir1
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision a8d62bc04fee4d2936d28e98bbcc81686dd74306
+ $ mtn rename dir1/subdir1 dir1/subdir2
+ mtn: skipping 'dir1', already accounted for in workspace
+ mtn: renaming 'dir1/subdir1' to 'dir1/subdir2' in workspace manifest
+ $ mtn ci -m movedir1
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision 2c3d241bbbfe538b1b51d910f5676407e3f4d3a6
+
+test subdirectory move
+
+ $ mtn mv dir dir2
+ mtn: renaming 'dir' to 'dir2' in workspace manifest
+ $ echo newfile > dir2/newfile
+ $ mtn drop dir2/d
+ mtn: dropping 'dir2/d' from workspace manifest
+ $ mtn add dir2/newfile
+ mtn: adding 'dir2/newfile' to workspace manifest
+ $ mtn ci -m movedir
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision fdb5a02dae8bfce3a79b3393680af471016e1b4c
+
+Test directory removal with empty directory
+
+ $ mkdir dir2/dir
+ $ mkdir dir2/dir/subdir
+ $ echo f > dir2/dir/subdir/f
+ $ mkdir dir2/dir/emptydir
+ $ mtn add --quiet -R dir2/dir
+ $ mtn ci -m emptydir
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision 8bbf76d717001d24964e4604739fdcd0f539fc88
+ $ mtn drop -R dir2/dir
+ mtn: dropping 'dir2/dir/subdir/f' from workspace manifest
+ mtn: dropping 'dir2/dir/subdir' from workspace manifest
+ mtn: dropping 'dir2/dir/emptydir' from workspace manifest
+ mtn: dropping 'dir2/dir' from workspace manifest
+ $ mtn ci -m dropdirectory
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision 2323d4bc324e6c82628dc04d47a9fd32ad24e322
+
+test directory and file move
+
+ $ mkdir -p dir3/d1
+ $ echo a > dir3/a
+ $ mtn add dir3/a dir3/d1
+ mtn: adding 'dir3' to workspace manifest
+ mtn: adding 'dir3/a' to workspace manifest
+ mtn: adding 'dir3/d1' to workspace manifest
+ $ mtn ci -m dirfilemove
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision 47b192f720faa622f48c68d1eb075b26d405aa8b
+ $ mtn mv dir3/a dir3/d1/a
+ mtn: skipping 'dir3/d1', already accounted for in workspace
+ mtn: renaming 'dir3/a' to 'dir3/d1/a' in workspace manifest
+ $ mtn mv dir3/d1 dir3/d2
+ mtn: skipping 'dir3', already accounted for in workspace
+ mtn: renaming 'dir3/d1' to 'dir3/d2' in workspace manifest
+ $ mtn ci -m dirfilemove2
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision 8b543a400d3ee7f6d4bb1835b9b9e3747c8cb632
+
+test directory move into another directory move
+
+ $ mkdir dir4
+ $ mkdir dir5
+ $ echo a > dir4/a
+ $ mtn add dir4/a dir5
+ mtn: adding 'dir4' to workspace manifest
+ mtn: adding 'dir4/a' to workspace manifest
+ mtn: adding 'dir5' to workspace manifest
+ $ mtn ci -m dirdirmove
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision 466e0b2afc7a55aa2b4ab2f57cb240bb6cd66fc7
+ $ mtn mv dir5 dir6
+ mtn: renaming 'dir5' to 'dir6' in workspace manifest
+ $ mtn mv dir4 dir6/dir4
+ mtn: skipping 'dir6', already accounted for in workspace
+ mtn: renaming 'dir4' to 'dir6/dir4' in workspace manifest
+ $ mtn ci -m dirdirmove2
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision 3d1f77ebad0c23a5d14911be3b670f990991b749
+
+test diverging directory moves
+
+ $ mkdir -p dir7/dir9/dir8
+ $ echo a > dir7/dir9/dir8/a
+ $ echo b > dir7/dir9/b
+ $ echo c > dir7/c
+ $ mtn add -R dir7
+ mtn: adding 'dir7' to workspace manifest
+ mtn: adding 'dir7/c' to workspace manifest
+ mtn: adding 'dir7/dir9' to workspace manifest
+ mtn: adding 'dir7/dir9/b' to workspace manifest
+ mtn: adding 'dir7/dir9/dir8' to workspace manifest
+ mtn: adding 'dir7/dir9/dir8/a' to workspace manifest
+ $ mtn ci -m divergentdirmove
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision 08a08511f18b428d840199b062de90d0396bc2ed
+ $ mtn mv dir7 dir7-2
+ mtn: renaming 'dir7' to 'dir7-2' in workspace manifest
+ $ mtn mv dir7-2/dir9 dir9-2
+ mtn: renaming 'dir7-2/dir9' to 'dir9-2' in workspace manifest
+ $ mtn mv dir9-2/dir8 dir8-2
+ mtn: renaming 'dir9-2/dir8' to 'dir8-2' in workspace manifest
+ $ mtn ci -m divergentdirmove2
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision 4a736634505795f17786fffdf2c9cbf5b11df6f6
+
+test large file support (> 32kB)
+
+ $ python -c 'for x in range(10000): print x' > large-file
+ $ $TESTDIR/md5sum.py large-file
+ 5d6de8a95c3b6bf9e0ffb808ba5299c1 large-file
+ $ mtn add large-file
+ mtn: adding 'large-file' to workspace manifest
+ $ mtn ci -m largefile
+ mtn: beginning commit on branch 'com.selenic.test'
+ mtn: committed revision f0a20fecd10dc4392d18fe69a03f1f4919d3387b
+
+test suspending (closing a branch)
+
+ $ mtn suspend f0a20fecd10dc4392d18fe69a03f1f4919d3387b 2> /dev/null
+ $ cd ..
+
+convert incrementally
+
+ $ hg convert -s mtn repo.mtn
+ assuming destination repo.mtn-hg
+ scanning source...
+ sorting...
+ converting...
+ 12 update2 "with" quotes
+ 11 createdir1
+ 10 movedir1
+ 9 movedir
+ 8 emptydir
+ 7 dropdirectory
+ 6 dirfilemove
+ 5 dirfilemove2
+ 4 dirdirmove
+ 3 dirdirmove2
+ 2 divergentdirmove
+ 1 divergentdirmove2
+ 0 largefile
+ $ glog()
+ > {
+ > hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
+ > }
+ $ cd repo.mtn-hg
+ $ hg up -C
+ 12 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ glog
+ @ 14 "largefile" files: large-file
+ |
+ o 13 "divergentdirmove2" files: dir7-2/c dir7/c dir7/dir9/b dir7/dir9/dir8/a dir8-2/a dir9-2/b
+ |
+ o 12 "divergentdirmove" files: dir7/c dir7/dir9/b dir7/dir9/dir8/a
+ |
+ o 11 "dirdirmove2" files: dir4/a dir6/dir4/a
+ |
+ o 10 "dirdirmove" files: dir4/a
+ |
+ o 9 "dirfilemove2" files: dir3/a dir3/d2/a
+ |
+ o 8 "dirfilemove" files: dir3/a
+ |
+ o 7 "dropdirectory" files: dir2/dir/subdir/f
+ |
+ o 6 "emptydir" files: dir2/dir/subdir/f
+ |
+ o 5 "movedir" files: dir/a dir/d dir2/a dir2/newfile
+ |
+ o 4 "movedir1" files: dir1/subdir1/file1 dir1/subdir2/file1
+ |
+ o 3 "createdir1" files: dir1/subdir1/file1 dir1/subdir2_other/file1
+ |
+ o 2 "update2 "with" quotes" files: bin bin2 dir/b e
+ |
+ o 1 "update1" files: a bin c dir/a dir/b
+ |
+ o 0 "initialize" files: a bin c dir/b dir/d
+
+
+manifest
+
+ $ hg manifest
+ bin2
+ dir1/subdir2/file1
+ dir1/subdir2_other/file1
+ dir2/a
+ dir2/newfile
+ dir3/d2/a
+ dir6/dir4/a
+ dir7-2/c
+ dir8-2/a
+ dir9-2/b
+ e
+ large-file
+
+contents
+
+ $ cat dir2/a
+ a
+ a
+ $ test -d dir2/dir && echo 'removed dir2/dir is still there!'
+ [1]
+
+file move
+
+ $ hg log -v -C -r 1 | grep copies
+ copies: dir/a (a)
+
+check directory move
+
+ $ hg manifest -r 4
+ bin2
+ dir/a
+ dir/d
+ dir1/subdir2/file1
+ dir1/subdir2_other/file1
+ e
+ $ test -d dir1/subdir2 || echo 'new dir1/subdir2 does not exist!'
+ $ test -d dir1/subdir1 && echo 'renamed dir1/subdir1 is still there!'
+ [1]
+ $ hg log -v -C -r 4 | grep copies
+ copies: dir1/subdir2/file1 (dir1/subdir1/file1)
+
+check file remove with directory move
+
+ $ hg manifest -r 5
+ bin2
+ dir1/subdir2/file1
+ dir1/subdir2_other/file1
+ dir2/a
+ dir2/newfile
+ e
+
+check file move with directory move
+
+ $ hg manifest -r 9
+ bin2
+ dir1/subdir2/file1
+ dir1/subdir2_other/file1
+ dir2/a
+ dir2/newfile
+ dir3/d2/a
+ e
+
+check file directory directory move
+
+ $ hg manifest -r 11
+ bin2
+ dir1/subdir2/file1
+ dir1/subdir2_other/file1
+ dir2/a
+ dir2/newfile
+ dir3/d2/a
+ dir6/dir4/a
+ e
+
+check divergent directory moves
+
+ $ hg manifest -r 13
+ bin2
+ dir1/subdir2/file1
+ dir1/subdir2_other/file1
+ dir2/a
+ dir2/newfile
+ dir3/d2/a
+ dir6/dir4/a
+ dir7-2/c
+ dir8-2/a
+ dir9-2/b
+ e
+
+test large file support (> 32kB)
+
+ $ $TESTDIR/md5sum.py large-file
+ 5d6de8a95c3b6bf9e0ffb808ba5299c1 large-file
+
+check branch closing
+
+ $ hg branches -a
+ $ hg branches -c
+ com.selenic.test 14:* (closed) (glob)
+
diff --git a/tests/test-convert-p4-filetypes.t b/tests/test-convert-p4-filetypes.t
new file mode 100644
index 0000000..3405486
--- /dev/null
+++ b/tests/test-convert-p4-filetypes.t
@@ -0,0 +1,733 @@
+ $ "$TESTDIR/hghave" p4 execbit symlink || exit 80
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert = " >> $HGRCPATH
+
+create p4 depot
+ $ P4ROOT=`pwd`/depot; export P4ROOT
+ $ P4AUDIT=$P4ROOT/audit; export P4AUDIT
+ $ P4JOURNAL=$P4ROOT/journal; export P4JOURNAL
+ $ P4LOG=$P4ROOT/log; export P4LOG
+ $ P4PORT=localhost:16661; export P4PORT
+ $ P4DEBUG=1; export P4DEBUG
+ $ P4CHARSET=utf8; export P4CHARSET
+
+start the p4 server
+ $ [ ! -d $P4ROOT ] && mkdir $P4ROOT
+ $ p4d -f -J off -xi >$P4ROOT/stdout 2>$P4ROOT/stderr
+ $ p4d -f -J off >$P4ROOT/stdout 2>$P4ROOT/stderr &
+ $ echo $! >> $DAEMON_PIDS
+ $ trap "echo stopping the p4 server ; p4 admin stop" EXIT
+
+wait for the server to initialize
+ $ while ! p4 ; do
+ > sleep 1
+ > done >/dev/null 2>/dev/null
+
+create a client spec
+ $ P4CLIENT=hg-p4-import; export P4CLIENT
+ $ DEPOTPATH=//depot/test-mercurial-import/...
+ $ p4 client -o | sed '/^View:/,$ d' >p4client
+ $ echo View: >>p4client
+ $ echo " $DEPOTPATH //$P4CLIENT/..." >>p4client
+ $ p4 client -i <p4client
+ Client hg-p4-import saved.
+
+populate the depot
+ $ TYPES="text binary symlink"
+ $ TYPES="$TYPES text+m text+w text+x text+k text+kx text+ko text+l text+C text+D text+F text+S text+S2"
+ $ TYPES="$TYPES binary+k binary+x binary+kx symlink+k"
+ $ TYPES="$TYPES ctext cxtext ktext kxtext ltext tempobj ubinary uxbinary xbinary xltext xtempobj xtext"
+not testing these
+ $ #TYPES="$TYPES apple resource unicode utf16 uresource xunicode xutf16"
+ $ for T in $TYPES ; do
+ > T2=`echo $T | tr [:upper:] [:lower:]`
+ > case $T in
+ > apple)
+ > ;;
+ > symlink*)
+ > echo "this is target $T" >target_$T2
+ > ln -s target_$T file_$T2
+ > p4 add target_$T2
+ > p4 add -t $T file_$T2
+ > ;;
+ > binary*)
+ > python -c "file('file_$T2', 'wb').write('this is $T')"
+ > p4 add -t $T file_$T2
+ > ;;
+ > *)
+ > echo "this is $T" >file_$T2
+ > p4 add -t $T file_$T2
+ > ;;
+ > esac
+ > done
+ //depot/test-mercurial-import/file_text#1 - opened for add
+ //depot/test-mercurial-import/file_binary#1 - opened for add
+ //depot/test-mercurial-import/target_symlink#1 - opened for add
+ //depot/test-mercurial-import/file_symlink#1 - opened for add
+ //depot/test-mercurial-import/file_text+m#1 - opened for add
+ //depot/test-mercurial-import/file_text+w#1 - opened for add
+ //depot/test-mercurial-import/file_text+x#1 - opened for add
+ //depot/test-mercurial-import/file_text+k#1 - opened for add
+ //depot/test-mercurial-import/file_text+kx#1 - opened for add
+ //depot/test-mercurial-import/file_text+ko#1 - opened for add
+ //depot/test-mercurial-import/file_text+l#1 - opened for add
+ //depot/test-mercurial-import/file_text+c#1 - opened for add
+ //depot/test-mercurial-import/file_text+d#1 - opened for add
+ //depot/test-mercurial-import/file_text+f#1 - opened for add
+ //depot/test-mercurial-import/file_text+s#1 - opened for add
+ //depot/test-mercurial-import/file_text+s2#1 - opened for add
+ //depot/test-mercurial-import/file_binary+k#1 - opened for add
+ //depot/test-mercurial-import/file_binary+x#1 - opened for add
+ //depot/test-mercurial-import/file_binary+kx#1 - opened for add
+ //depot/test-mercurial-import/target_symlink+k#1 - opened for add
+ //depot/test-mercurial-import/file_symlink+k#1 - opened for add
+ //depot/test-mercurial-import/file_ctext#1 - opened for add
+ //depot/test-mercurial-import/file_cxtext#1 - opened for add
+ //depot/test-mercurial-import/file_ktext#1 - opened for add
+ //depot/test-mercurial-import/file_kxtext#1 - opened for add
+ //depot/test-mercurial-import/file_ltext#1 - opened for add
+ //depot/test-mercurial-import/file_tempobj#1 - opened for add
+ //depot/test-mercurial-import/file_ubinary#1 - opened for add
+ //depot/test-mercurial-import/file_uxbinary#1 - opened for add
+ //depot/test-mercurial-import/file_xbinary#1 - opened for add
+ //depot/test-mercurial-import/file_xltext#1 - opened for add
+ //depot/test-mercurial-import/file_xtempobj#1 - opened for add
+ //depot/test-mercurial-import/file_xtext#1 - opened for add
+ $ p4 submit -d initial
+ Submitting change 1.
+ Locking 33 files ...
+ add //depot/test-mercurial-import/file_binary#1
+ add //depot/test-mercurial-import/file_binary+k#1
+ add //depot/test-mercurial-import/file_binary+kx#1
+ add //depot/test-mercurial-import/file_binary+x#1
+ add //depot/test-mercurial-import/file_ctext#1
+ add //depot/test-mercurial-import/file_cxtext#1
+ add //depot/test-mercurial-import/file_ktext#1
+ add //depot/test-mercurial-import/file_kxtext#1
+ add //depot/test-mercurial-import/file_ltext#1
+ add //depot/test-mercurial-import/file_symlink#1
+ add //depot/test-mercurial-import/file_symlink+k#1
+ add //depot/test-mercurial-import/file_tempobj#1
+ add //depot/test-mercurial-import/file_text#1
+ add //depot/test-mercurial-import/file_text+c#1
+ add //depot/test-mercurial-import/file_text+d#1
+ add //depot/test-mercurial-import/file_text+f#1
+ add //depot/test-mercurial-import/file_text+k#1
+ add //depot/test-mercurial-import/file_text+ko#1
+ add //depot/test-mercurial-import/file_text+kx#1
+ add //depot/test-mercurial-import/file_text+l#1
+ add //depot/test-mercurial-import/file_text+m#1
+ add //depot/test-mercurial-import/file_text+s#1
+ add //depot/test-mercurial-import/file_text+s2#1
+ add //depot/test-mercurial-import/file_text+w#1
+ add //depot/test-mercurial-import/file_text+x#1
+ add //depot/test-mercurial-import/file_ubinary#1
+ add //depot/test-mercurial-import/file_uxbinary#1
+ add //depot/test-mercurial-import/file_xbinary#1
+ add //depot/test-mercurial-import/file_xltext#1
+ add //depot/test-mercurial-import/file_xtempobj#1
+ add //depot/test-mercurial-import/file_xtext#1
+ add //depot/test-mercurial-import/target_symlink#1
+ add //depot/test-mercurial-import/target_symlink+k#1
+ Change 1 submitted.
+ //depot/test-mercurial-import/file_binary+k#1 - refreshing
+ //depot/test-mercurial-import/file_binary+kx#1 - refreshing
+ //depot/test-mercurial-import/file_ktext#1 - refreshing
+ //depot/test-mercurial-import/file_kxtext#1 - refreshing
+ //depot/test-mercurial-import/file_symlink+k#1 - refreshing
+ //depot/test-mercurial-import/file_text+k#1 - refreshing
+ //depot/test-mercurial-import/file_text+ko#1 - refreshing
+ //depot/test-mercurial-import/file_text+kx#1 - refreshing
+
+test keyword expansion
+ $ p4 edit file_* target_*
+ //depot/test-mercurial-import/file_binary#1 - opened for edit
+ //depot/test-mercurial-import/file_binary+k#1 - opened for edit
+ //depot/test-mercurial-import/file_binary+kx#1 - opened for edit
+ //depot/test-mercurial-import/file_binary+x#1 - opened for edit
+ //depot/test-mercurial-import/file_ctext#1 - opened for edit
+ //depot/test-mercurial-import/file_cxtext#1 - opened for edit
+ //depot/test-mercurial-import/file_ktext#1 - opened for edit
+ //depot/test-mercurial-import/file_kxtext#1 - opened for edit
+ //depot/test-mercurial-import/file_ltext#1 - opened for edit
+ //depot/test-mercurial-import/file_symlink#1 - opened for edit
+ //depot/test-mercurial-import/file_symlink+k#1 - opened for edit
+ //depot/test-mercurial-import/file_tempobj#1 - opened for edit
+ //depot/test-mercurial-import/file_text#1 - opened for edit
+ //depot/test-mercurial-import/file_text+c#1 - opened for edit
+ //depot/test-mercurial-import/file_text+d#1 - opened for edit
+ //depot/test-mercurial-import/file_text+f#1 - opened for edit
+ //depot/test-mercurial-import/file_text+k#1 - opened for edit
+ //depot/test-mercurial-import/file_text+ko#1 - opened for edit
+ //depot/test-mercurial-import/file_text+kx#1 - opened for edit
+ //depot/test-mercurial-import/file_text+l#1 - opened for edit
+ //depot/test-mercurial-import/file_text+m#1 - opened for edit
+ //depot/test-mercurial-import/file_text+s#1 - opened for edit
+ //depot/test-mercurial-import/file_text+s2#1 - opened for edit
+ //depot/test-mercurial-import/file_text+w#1 - opened for edit
+ //depot/test-mercurial-import/file_text+x#1 - opened for edit
+ //depot/test-mercurial-import/file_ubinary#1 - opened for edit
+ //depot/test-mercurial-import/file_uxbinary#1 - opened for edit
+ //depot/test-mercurial-import/file_xbinary#1 - opened for edit
+ //depot/test-mercurial-import/file_xltext#1 - opened for edit
+ //depot/test-mercurial-import/file_xtempobj#1 - opened for edit
+ //depot/test-mercurial-import/file_xtext#1 - opened for edit
+ //depot/test-mercurial-import/target_symlink#1 - opened for edit
+ //depot/test-mercurial-import/target_symlink+k#1 - opened for edit
+ $ for T in $TYPES ; do
+ > T2=`echo $T | tr [:upper:] [:lower:]`
+ > echo '$Id$' >>file_$T2
+ > echo '$Header$' >>file_$T2
+ > echo '$Date$' >>file_$T2
+ > echo '$DateTime$' >>file_$T2
+ > echo '$Change$' >>file_$T2
+ > echo '$File$' >>file_$T2
+ > echo '$Revision$' >>file_$T2
+ > echo '$Header$$Header$Header$' >>file_$T2
+ > done
+
+ $ ln -s 'target_$Header$' crazy_symlink+k
+ $ p4 add -t symlink+k crazy_symlink+k
+ //depot/test-mercurial-import/crazy_symlink+k#1 - opened for add
+
+ $ p4 submit -d keywords
+ Submitting change 2.
+ Locking 34 files ...
+ add //depot/test-mercurial-import/crazy_symlink+k#1
+ edit //depot/test-mercurial-import/file_binary#2
+ edit //depot/test-mercurial-import/file_binary+k#2
+ edit //depot/test-mercurial-import/file_binary+kx#2
+ edit //depot/test-mercurial-import/file_binary+x#2
+ edit //depot/test-mercurial-import/file_ctext#2
+ edit //depot/test-mercurial-import/file_cxtext#2
+ edit //depot/test-mercurial-import/file_ktext#2
+ edit //depot/test-mercurial-import/file_kxtext#2
+ edit //depot/test-mercurial-import/file_ltext#2
+ edit //depot/test-mercurial-import/file_symlink#2
+ edit //depot/test-mercurial-import/file_symlink+k#2
+ edit //depot/test-mercurial-import/file_tempobj#2
+ edit //depot/test-mercurial-import/file_text#2
+ edit //depot/test-mercurial-import/file_text+c#2
+ edit //depot/test-mercurial-import/file_text+d#2
+ edit //depot/test-mercurial-import/file_text+f#2
+ edit //depot/test-mercurial-import/file_text+k#2
+ edit //depot/test-mercurial-import/file_text+ko#2
+ edit //depot/test-mercurial-import/file_text+kx#2
+ edit //depot/test-mercurial-import/file_text+l#2
+ edit //depot/test-mercurial-import/file_text+m#2
+ edit //depot/test-mercurial-import/file_text+s#2
+ edit //depot/test-mercurial-import/file_text+s2#2
+ edit //depot/test-mercurial-import/file_text+w#2
+ edit //depot/test-mercurial-import/file_text+x#2
+ edit //depot/test-mercurial-import/file_ubinary#2
+ edit //depot/test-mercurial-import/file_uxbinary#2
+ edit //depot/test-mercurial-import/file_xbinary#2
+ edit //depot/test-mercurial-import/file_xltext#2
+ edit //depot/test-mercurial-import/file_xtempobj#2
+ edit //depot/test-mercurial-import/file_xtext#2
+ edit //depot/test-mercurial-import/target_symlink#2
+ edit //depot/test-mercurial-import/target_symlink+k#2
+ Change 2 submitted.
+ //depot/test-mercurial-import/crazy_symlink+k#1 - refreshing
+ //depot/test-mercurial-import/file_binary+k#2 - refreshing
+ //depot/test-mercurial-import/file_binary+kx#2 - refreshing
+ //depot/test-mercurial-import/file_ktext#2 - refreshing
+ //depot/test-mercurial-import/file_kxtext#2 - refreshing
+ //depot/test-mercurial-import/file_symlink+k#2 - refreshing
+ //depot/test-mercurial-import/file_text+k#2 - refreshing
+ //depot/test-mercurial-import/file_text+ko#2 - refreshing
+ //depot/test-mercurial-import/file_text+kx#2 - refreshing
+
+check keywords in p4
+ $ grep -H Header file_*
+ file_binary:$Header$
+ file_binary:$Header$$Header$Header$
+ file_binary+k:$Header: //depot/test-mercurial-import/file_binary+k#2 $
+ file_binary+k:$Header: //depot/test-mercurial-import/file_binary+k#2 $$Header: //depot/test-mercurial-import/file_binary+k#2 $Header$
+ file_binary+kx:$Header: //depot/test-mercurial-import/file_binary+kx#2 $
+ file_binary+kx:$Header: //depot/test-mercurial-import/file_binary+kx#2 $$Header: //depot/test-mercurial-import/file_binary+kx#2 $Header$
+ file_binary+x:$Header$
+ file_binary+x:$Header$$Header$Header$
+ file_ctext:$Header$
+ file_ctext:$Header$$Header$Header$
+ file_cxtext:$Header$
+ file_cxtext:$Header$$Header$Header$
+ file_ktext:$Header: //depot/test-mercurial-import/file_ktext#2 $
+ file_ktext:$Header: //depot/test-mercurial-import/file_ktext#2 $$Header: //depot/test-mercurial-import/file_ktext#2 $Header$
+ file_kxtext:$Header: //depot/test-mercurial-import/file_kxtext#2 $
+ file_kxtext:$Header: //depot/test-mercurial-import/file_kxtext#2 $$Header: //depot/test-mercurial-import/file_kxtext#2 $Header$
+ file_ltext:$Header$
+ file_ltext:$Header$$Header$Header$
+ file_symlink:$Header$
+ file_symlink:$Header$$Header$Header$
+ file_symlink+k:$Header$
+ file_symlink+k:$Header$$Header$Header$
+ file_tempobj:$Header$
+ file_tempobj:$Header$$Header$Header$
+ file_text:$Header$
+ file_text:$Header$$Header$Header$
+ file_text+c:$Header$
+ file_text+c:$Header$$Header$Header$
+ file_text+d:$Header$
+ file_text+d:$Header$$Header$Header$
+ file_text+f:$Header$
+ file_text+f:$Header$$Header$Header$
+ file_text+k:$Header: //depot/test-mercurial-import/file_text+k#2 $
+ file_text+k:$Header: //depot/test-mercurial-import/file_text+k#2 $$Header: //depot/test-mercurial-import/file_text+k#2 $Header$
+ file_text+ko:$Header: //depot/test-mercurial-import/file_text+ko#2 $
+ file_text+ko:$Header: //depot/test-mercurial-import/file_text+ko#2 $$Header: //depot/test-mercurial-import/file_text+ko#2 $Header$
+ file_text+kx:$Header: //depot/test-mercurial-import/file_text+kx#2 $
+ file_text+kx:$Header: //depot/test-mercurial-import/file_text+kx#2 $$Header: //depot/test-mercurial-import/file_text+kx#2 $Header$
+ file_text+l:$Header$
+ file_text+l:$Header$$Header$Header$
+ file_text+m:$Header$
+ file_text+m:$Header$$Header$Header$
+ file_text+s:$Header$
+ file_text+s:$Header$$Header$Header$
+ file_text+s2:$Header$
+ file_text+s2:$Header$$Header$Header$
+ file_text+w:$Header$
+ file_text+w:$Header$$Header$Header$
+ file_text+x:$Header$
+ file_text+x:$Header$$Header$Header$
+ file_ubinary:$Header$
+ file_ubinary:$Header$$Header$Header$
+ file_uxbinary:$Header$
+ file_uxbinary:$Header$$Header$Header$
+ file_xbinary:$Header$
+ file_xbinary:$Header$$Header$Header$
+ file_xltext:$Header$
+ file_xltext:$Header$$Header$Header$
+ file_xtempobj:$Header$
+ file_xtempobj:$Header$$Header$Header$
+ file_xtext:$Header$
+ file_xtext:$Header$$Header$Header$
+
+convert
+ $ hg convert -s p4 $DEPOTPATH dst
+ initializing destination dst repository
+ reading p4 views
+ collecting p4 changelists
+ 1 initial
+ 2 keywords
+ scanning source...
+ sorting...
+ converting...
+ 1 initial
+ 0 keywords
+ $ hg -R dst log --template 'rev={rev} desc="{desc}" tags="{tags}" files="{files}"\n'
+ rev=1 desc="keywords" tags="tip" files="crazy_symlink+k file_binary file_binary+k file_binary+kx file_binary+x file_ctext file_cxtext file_ktext file_kxtext file_ltext file_text file_text+c file_text+d file_text+f file_text+k file_text+ko file_text+kx file_text+l file_text+m file_text+s file_text+s2 file_text+w file_text+x file_ubinary file_uxbinary file_xbinary file_xltext file_xtext target_symlink target_symlink+k"
+ rev=0 desc="initial" tags="" files="file_binary file_binary+k file_binary+kx file_binary+x file_ctext file_cxtext file_ktext file_kxtext file_ltext file_symlink file_symlink+k file_text file_text+c file_text+d file_text+f file_text+k file_text+ko file_text+kx file_text+l file_text+m file_text+s2 file_text+w file_text+x file_ubinary file_uxbinary file_xbinary file_xltext file_xtext target_symlink target_symlink+k"
+
+revision 0
+ $ hg -R dst update 0
+ 30 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ head dst/file_* | cat -v
+ ==> dst/file_binary <==
+ this is binary
+ ==> dst/file_binary+k <==
+ this is binary+k
+ ==> dst/file_binary+kx <==
+ this is binary+kx
+ ==> dst/file_binary+x <==
+ this is binary+x
+ ==> dst/file_ctext <==
+ this is ctext
+
+ ==> dst/file_cxtext <==
+ this is cxtext
+
+ ==> dst/file_ktext <==
+ this is ktext
+
+ ==> dst/file_kxtext <==
+ this is kxtext
+
+ ==> dst/file_ltext <==
+ this is ltext
+
+ ==> dst/file_symlink <==
+ this is target symlink
+
+ ==> dst/file_symlink+k <==
+ this is target symlink+k
+
+ ==> dst/file_text <==
+ this is text
+
+ ==> dst/file_text+c <==
+ this is text+C
+
+ ==> dst/file_text+d <==
+ this is text+D
+
+ ==> dst/file_text+f <==
+ this is text+F
+
+ ==> dst/file_text+k <==
+ this is text+k
+
+ ==> dst/file_text+ko <==
+ this is text+ko
+
+ ==> dst/file_text+kx <==
+ this is text+kx
+
+ ==> dst/file_text+l <==
+ this is text+l
+
+ ==> dst/file_text+m <==
+ this is text+m
+
+ ==> dst/file_text+s2 <==
+ this is text+S2
+
+ ==> dst/file_text+w <==
+ this is text+w
+
+ ==> dst/file_text+x <==
+ this is text+x
+
+ ==> dst/file_ubinary <==
+ this is ubinary
+
+ ==> dst/file_uxbinary <==
+ this is uxbinary
+
+ ==> dst/file_xbinary <==
+ this is xbinary
+
+ ==> dst/file_xltext <==
+ this is xltext
+
+ ==> dst/file_xtext <==
+ this is xtext
+
+revision 1
+ $ hg -R dst update 1
+ 30 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ head dst/file_* | cat -v
+ ==> dst/file_binary <==
+ this is binary$Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_binary+k <==
+ this is binary+k$Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_binary+kx <==
+ this is binary+kx$Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_binary+x <==
+ this is binary+x$Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_ctext <==
+ this is ctext
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_cxtext <==
+ this is cxtext
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_ktext <==
+ this is ktext
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_kxtext <==
+ this is kxtext
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_ltext <==
+ this is ltext
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_symlink <==
+ this is target symlink
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_symlink+k <==
+ this is target symlink+k
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text <==
+ this is text
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+c <==
+ this is text+C
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+d <==
+ this is text+D
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+f <==
+ this is text+F
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+k <==
+ this is text+k
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+ko <==
+ this is text+ko
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+kx <==
+ this is text+kx
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+l <==
+ this is text+l
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+m <==
+ this is text+m
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+s <==
+ this is text+S
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+s2 <==
+ this is text+S2
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+w <==
+ this is text+w
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_text+x <==
+ this is text+x
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_ubinary <==
+ this is ubinary
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_uxbinary <==
+ this is uxbinary
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_xbinary <==
+ this is xbinary
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_xltext <==
+ this is xltext
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+ ==> dst/file_xtext <==
+ this is xtext
+ $Id$
+ $Header$
+ $Date$
+ $DateTime$
+ $Change$
+ $File$
+ $Revision$
+ $Header$$Header$Header$
+
+crazy_symlink
+ $ readlink crazy_symlink+k
+ target_$Header: //depot/test-mercurial-import/crazy_symlink+k#1 $
+ $ readlink dst/crazy_symlink+k
+ target_$Header$
+
+exit trap:
+ stopping the p4 server
diff --git a/tests/test-convert-p4.t b/tests/test-convert-p4.t
new file mode 100644
index 0000000..6a59759
--- /dev/null
+++ b/tests/test-convert-p4.t
@@ -0,0 +1,152 @@
+ $ "$TESTDIR/hghave" p4 || exit 80
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert = " >> $HGRCPATH
+
+create p4 depot
+ $ P4ROOT=`pwd`/depot; export P4ROOT
+ $ P4AUDIT=$P4ROOT/audit; export P4AUDIT
+ $ P4JOURNAL=$P4ROOT/journal; export P4JOURNAL
+ $ P4LOG=$P4ROOT/log; export P4LOG
+ $ P4PORT=localhost:16661; export P4PORT
+ $ P4DEBUG=1; export P4DEBUG
+
+start the p4 server
+ $ [ ! -d $P4ROOT ] && mkdir $P4ROOT
+ $ p4d -f -J off >$P4ROOT/stdout 2>$P4ROOT/stderr &
+ $ echo $! >> $DAEMON_PIDS
+ $ trap "echo stopping the p4 server ; p4 admin stop" EXIT
+
+ $ # wait for the server to initialize
+ $ while ! p4 ; do
+ > sleep 1
+ > done >/dev/null 2>/dev/null
+
+create a client spec
+ $ P4CLIENT=hg-p4-import; export P4CLIENT
+ $ DEPOTPATH=//depot/test-mercurial-import/...
+ $ p4 client -o | sed '/^View:/,$ d' >p4client
+ $ echo View: >>p4client
+ $ echo " $DEPOTPATH //$P4CLIENT/..." >>p4client
+ $ p4 client -i <p4client
+ Client hg-p4-import saved.
+
+populate the depot
+ $ echo a > a
+ $ mkdir b
+ $ echo c > b/c
+ $ p4 add a b/c
+ //depot/test-mercurial-import/a#1 - opened for add
+ //depot/test-mercurial-import/b/c#1 - opened for add
+ $ p4 submit -d initial
+ Submitting change 1.
+ Locking 2 files ...
+ add //depot/test-mercurial-import/a#1
+ add //depot/test-mercurial-import/b/c#1
+ Change 1 submitted.
+
+change some files
+ $ p4 edit a
+ //depot/test-mercurial-import/a#1 - opened for edit
+ $ echo aa >> a
+ $ p4 submit -d "change a"
+ Submitting change 2.
+ Locking 1 files ...
+ edit //depot/test-mercurial-import/a#2
+ Change 2 submitted.
+
+ $ p4 edit b/c
+ //depot/test-mercurial-import/b/c#1 - opened for edit
+ $ echo cc >> b/c
+ $ p4 submit -d "change b/c"
+ Submitting change 3.
+ Locking 1 files ...
+ edit //depot/test-mercurial-import/b/c#2
+ Change 3 submitted.
+
+convert
+ $ hg convert -s p4 $DEPOTPATH dst
+ initializing destination dst repository
+ reading p4 views
+ collecting p4 changelists
+ 1 initial
+ 2 change a
+ 3 change b/c
+ scanning source...
+ sorting...
+ converting...
+ 2 initial
+ 1 change a
+ 0 change b/c
+ $ hg -R dst log --template 'rev={rev} desc="{desc}" tags="{tags}" files="{files}"\n'
+ rev=2 desc="change b/c" tags="tip" files="b/c"
+ rev=1 desc="change a" tags="" files="a"
+ rev=0 desc="initial" tags="" files="a b/c"
+
+change some files
+ $ p4 edit a b/c
+ //depot/test-mercurial-import/a#2 - opened for edit
+ //depot/test-mercurial-import/b/c#2 - opened for edit
+ $ echo aaa >> a
+ $ echo ccc >> b/c
+ $ p4 submit -d "change a b/c"
+ Submitting change 4.
+ Locking 2 files ...
+ edit //depot/test-mercurial-import/a#3
+ edit //depot/test-mercurial-import/b/c#3
+ Change 4 submitted.
+
+convert again
+ $ hg convert -s p4 $DEPOTPATH dst
+ reading p4 views
+ collecting p4 changelists
+ 1 initial
+ 2 change a
+ 3 change b/c
+ 4 change a b/c
+ scanning source...
+ sorting...
+ converting...
+ 0 change a b/c
+ $ hg -R dst log --template 'rev={rev} desc="{desc}" tags="{tags}" files="{files}"\n'
+ rev=3 desc="change a b/c" tags="tip" files="a b/c"
+ rev=2 desc="change b/c" tags="" files="b/c"
+ rev=1 desc="change a" tags="" files="a"
+ rev=0 desc="initial" tags="" files="a b/c"
+
+interesting names
+ $ echo dddd > "d d"
+ $ mkdir " e"
+ $ echo fff >" e/ f"
+ $ p4 add "d d" " e/ f"
+ //depot/test-mercurial-import/d d#1 - opened for add
+ //depot/test-mercurial-import/ e/ f#1 - opened for add
+ $ p4 submit -d "add d e f"
+ Submitting change 5.
+ Locking 2 files ...
+ add //depot/test-mercurial-import/ e/ f#1
+ add //depot/test-mercurial-import/d d#1
+ Change 5 submitted.
+
+convert again
+ $ hg convert -s p4 $DEPOTPATH dst
+ reading p4 views
+ collecting p4 changelists
+ 1 initial
+ 2 change a
+ 3 change b/c
+ 4 change a b/c
+ 5 add d e f
+ scanning source...
+ sorting...
+ converting...
+ 0 add d e f
+ $ hg -R dst log --template 'rev={rev} desc="{desc}" tags="{tags}" files="{files}"\n'
+ rev=4 desc="add d e f" tags="tip" files=" e/ f d d"
+ rev=3 desc="change a b/c" tags="" files="a b/c"
+ rev=2 desc="change b/c" tags="" files="b/c"
+ rev=1 desc="change a" tags="" files="a"
+ rev=0 desc="initial" tags="" files="a b/c"
+
+exit trap:
+ stopping the p4 server
diff --git a/tests/test-convert-splicemap.t b/tests/test-convert-splicemap.t
new file mode 100644
index 0000000..d5bb15f
--- /dev/null
+++ b/tests/test-convert-splicemap.t
@@ -0,0 +1,222 @@
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert=" >> $HGRCPATH
+ $ echo 'graphlog =' >> $HGRCPATH
+ $ glog()
+ > {
+ > hg glog --template '{rev}:{node|short} "{desc|firstline}"\
+ > files: {files}\n' "$@"
+ > }
+ $ hg init repo1
+ $ cd repo1
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ echo b > b
+ $ echo a >> a
+ $ hg ci -Am addb
+ adding b
+ $ PARENTID1=`hg id --debug -i`
+ $ echo c > c
+ $ hg ci -Am addc
+ adding c
+ $ PARENTID2=`hg id --debug -i`
+ $ cd ..
+ $ glog -R repo1
+ @ 2:e55c719b85b6 "addc" files: c
+ |
+ o 1:6d4c2037ddc2 "addb" files: a b
+ |
+ o 0:07f494440405 "adda" files: a
+
+
+ $ hg init repo2
+ $ cd repo2
+ $ echo b > a
+ $ echo d > d
+ $ hg ci -Am addaandd
+ adding a
+ adding d
+ $ CHILDID1=`hg id --debug -i`
+ $ echo d >> d
+ $ hg ci -Am changed
+ $ CHILDID2=`hg id --debug -i`
+ $ echo e > e
+ $ hg ci -Am adde
+ adding e
+ $ cd ..
+ $ glog -R repo2
+ @ 2:a39b65753b0a "adde" files: e
+ |
+ o 1:e4ea00df9189 "changed" files: d
+ |
+ o 0:527cdedf31fb "addaandd" files: a d
+
+
+test invalid splicemap
+
+ $ cat > splicemap <<EOF
+ > $CHILDID2
+ > EOF
+ $ hg convert --splicemap splicemap repo2 repo1
+ abort: syntax error in splicemap(1): child parent1[,parent2] expected
+ [255]
+
+splice repo2 on repo1
+
+ $ cat > splicemap <<EOF
+ > $CHILDID1 $PARENTID1
+ > $CHILDID2 $PARENTID2,$CHILDID1
+ >
+ > EOF
+ $ cat splicemap
+ 527cdedf31fbd5ea708aa14eeecf53d4676f38db 6d4c2037ddc2cb2627ac3a244ecce35283268f8e
+ e4ea00df91897da3079a10fab658c1eddba6617b e55c719b85b60e5102fac26110ba626e7cb6b7dc,527cdedf31fbd5ea708aa14eeecf53d4676f38db
+
+ $ hg clone repo1 target1
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg convert --splicemap splicemap repo2 target1
+ scanning source...
+ sorting...
+ converting...
+ 2 addaandd
+ spliced in ['6d4c2037ddc2cb2627ac3a244ecce35283268f8e'] as parents of 527cdedf31fbd5ea708aa14eeecf53d4676f38db
+ 1 changed
+ spliced in ['e55c719b85b60e5102fac26110ba626e7cb6b7dc', '527cdedf31fbd5ea708aa14eeecf53d4676f38db'] as parents of e4ea00df91897da3079a10fab658c1eddba6617b
+ 0 adde
+ $ glog -R target1
+ o 5:16bc847b02aa "adde" files: e
+ |
+ o 4:e30e4fee3418 "changed" files: d
+ |\
+ | o 3:e673348c3a3c "addaandd" files: a d
+ | |
+ @ | 2:e55c719b85b6 "addc" files: c
+ |/
+ o 1:6d4c2037ddc2 "addb" files: a b
+ |
+ o 0:07f494440405 "adda" files: a
+
+
+
+
+Test splicemap and conversion order
+
+ $ hg init ordered
+ $ cd ordered
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ hg branch branch
+ marked working directory as branch branch
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a >> a
+ $ hg ci -Am changea
+ $ echo a >> a
+ $ hg ci -Am changeaagain
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b > b
+ $ hg ci -Am addb
+ adding b
+
+We want 2 to depend on 1 and 3. Since 3 is always converted after 2,
+the bug should be exhibited with all conversion orders.
+
+ $ cat > ../splicemap <<EOF
+ > `(hg id -r 2 -i --debug)` `(hg id -r 1 -i --debug)`, `(hg id -r 3 -i --debug)`
+ > EOF
+ $ cd ..
+ $ cat splicemap
+ 7c364e7fa7d70ae525610c016317ed717b519d97 717d54d67e6c31fd75ffef2ff3042bdd98418437, 102a90ea7b4a3361e4082ed620918c261189a36a
+
+Test regular conversion
+
+ $ hg convert --splicemap splicemap ordered ordered-hg1
+ initializing destination ordered-hg1 repository
+ scanning source...
+ sorting...
+ converting...
+ 3 adda
+ 2 changea
+ 1 addb
+ 0 changeaagain
+ spliced in ['717d54d67e6c31fd75ffef2ff3042bdd98418437', '102a90ea7b4a3361e4082ed620918c261189a36a'] as parents of 7c364e7fa7d70ae525610c016317ed717b519d97
+ $ glog -R ordered-hg1
+ o 3:4cb04b9afbf2 "changeaagain" files: a
+ |\
+ | o 2:102a90ea7b4a "addb" files: b
+ | |
+ o | 1:717d54d67e6c "changea" files: a
+ |/
+ o 0:07f494440405 "adda" files: a
+
+
+Test conversion with parent revisions already in dest, using source
+and destination identifiers. Test unknown splicemap target.
+
+ $ hg convert -r1 ordered ordered-hg2
+ initializing destination ordered-hg2 repository
+ scanning source...
+ sorting...
+ converting...
+ 1 adda
+ 0 changea
+ $ hg convert -r3 ordered ordered-hg2
+ scanning source...
+ sorting...
+ converting...
+ 0 addb
+ $ cat > splicemap <<EOF
+ > `(hg -R ordered id -r 2 -i --debug)` \
+ > `(hg -R ordered-hg2 id -r 1 -i --debug)`,\
+ > `(hg -R ordered-hg2 id -r 2 -i --debug)`
+ > deadbeef102a90ea7b4a3361e4082ed620918c26 deadbeef102a90ea7b4a3361e4082ed620918c27
+ > EOF
+ $ hg convert --splicemap splicemap ordered ordered-hg2
+ scanning source...
+ splice map revision deadbeef102a90ea7b4a3361e4082ed620918c26 is not being converted, ignoring
+ sorting...
+ converting...
+ 0 changeaagain
+ spliced in ['717d54d67e6c31fd75ffef2ff3042bdd98418437', '102a90ea7b4a3361e4082ed620918c261189a36a'] as parents of 7c364e7fa7d70ae525610c016317ed717b519d97
+ $ glog -R ordered-hg2
+ o 3:4cb04b9afbf2 "changeaagain" files: a
+ |\
+ | o 2:102a90ea7b4a "addb" files: b
+ | |
+ o | 1:717d54d67e6c "changea" files: a
+ |/
+ o 0:07f494440405 "adda" files: a
+
+
+Test empty conversion
+
+ $ hg convert --splicemap splicemap ordered ordered-hg2
+ scanning source...
+ splice map revision deadbeef102a90ea7b4a3361e4082ed620918c26 is not being converted, ignoring
+ sorting...
+ converting...
+
+Test clonebranches
+
+ $ hg --config convert.hg.clonebranches=true convert \
+ > --splicemap splicemap ordered ordered-hg3
+ initializing destination ordered-hg3 repository
+ scanning source...
+ abort: revision 717d54d67e6c31fd75ffef2ff3042bdd98418437 not found in destination repository (lookups with clonebranches=true are not implemented)
+ [255]
+
+Test invalid dependency
+
+ $ cat > splicemap <<EOF
+ > `(hg -R ordered id -r 2 -i --debug)` \
+ > deadbeef102a90ea7b4a3361e4082ed620918c26,\
+ > `(hg -R ordered-hg2 id -r 2 -i --debug)`
+ > EOF
+ $ hg convert --splicemap splicemap ordered ordered-hg4
+ initializing destination ordered-hg4 repository
+ scanning source...
+ abort: unknown splice map parent: deadbeef102a90ea7b4a3361e4082ed620918c26
+ [255]
diff --git a/tests/test-convert-svn-branches.t b/tests/test-convert-svn-branches.t
new file mode 100644
index 0000000..95df843
--- /dev/null
+++ b/tests/test-convert-svn-branches.t
@@ -0,0 +1,103 @@
+
+ $ "$TESTDIR/hghave" svn svn-bindings || exit 80
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert =
+ > graphlog =
+ > EOF
+
+ $ svnadmin create svn-repo
+ $ svnadmin load -q svn-repo < "$TESTDIR/svn/branches.svndump"
+
+Convert trunk and branches
+
+ $ cat > branchmap <<EOF
+ > old3 newbranch
+ >
+ >
+ > EOF
+ $ hg convert --branchmap=branchmap --datesort -r 10 svn-repo A-hg
+ initializing destination A-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 10 init projA
+ 9 hello
+ 8 branch trunk, remove c and dir
+ 7 change a
+ 6 change b
+ 5 move and update c
+ 4 move and update c
+ 3 change b again
+ 2 move to old2
+ 1 move back to old
+ 0 last change to a
+
+Test template keywords
+
+ $ hg -R A-hg log --template '{rev} {svnuuid}{svnpath}@{svnrev}\n'
+ 10 644ede6c-2b81-4367-9dc8-d786514f2cde/trunk@10
+ 9 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old@9
+ 8 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old2@8
+ 7 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old@7
+ 6 644ede6c-2b81-4367-9dc8-d786514f2cde/trunk@6
+ 5 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old@6
+ 4 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old@5
+ 3 644ede6c-2b81-4367-9dc8-d786514f2cde/trunk@4
+ 2 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old@3
+ 1 644ede6c-2b81-4367-9dc8-d786514f2cde/trunk@2
+ 0 644ede6c-2b81-4367-9dc8-d786514f2cde/trunk@1
+
+Convert again
+
+ $ hg convert --branchmap=branchmap --datesort svn-repo A-hg
+ scanning source...
+ sorting...
+ converting...
+ 0 branch trunk@1 into old3
+
+ $ cd A-hg
+ $ hg glog --template 'branch={branches} {rev} {desc|firstline} files: {files}\n'
+ o branch=newbranch 11 branch trunk@1 into old3 files:
+ |
+ | o branch= 10 last change to a files: a
+ | |
+ | | o branch=old 9 move back to old files:
+ | | |
+ | | o branch=old2 8 move to old2 files:
+ | | |
+ | | o branch=old 7 change b again files: b
+ | | |
+ | o | branch= 6 move and update c files: b
+ | | |
+ | | o branch=old 5 move and update c files: c
+ | | |
+ | | o branch=old 4 change b files: b
+ | | |
+ | o | branch= 3 change a files: a
+ | | |
+ | | o branch=old 2 branch trunk, remove c and dir files: c
+ | |/
+ | o branch= 1 hello files: a b c dir/e
+ |/
+ o branch= 0 init projA files:
+
+
+ $ hg branches
+ newbranch 11:a6d7cc050ad1
+ default 10:6e2b33404495
+ old 9:93c4b0f99529
+ old2 8:b52884d7bead (inactive)
+ $ hg tags -q
+ tip
+ $ cd ..
+
+Test hg failing to call itself
+
+ $ HG=foobar hg convert svn-repo B-hg
+ * (glob)
+ initializing destination B-hg repository
+ abort: Mercurial failed to run itself, check hg executable is in PATH
+ [255]
+
diff --git a/tests/test-convert-svn-encoding.t b/tests/test-convert-svn-encoding.t
new file mode 100644
index 0000000..744b2b2
--- /dev/null
+++ b/tests/test-convert-svn-encoding.t
@@ -0,0 +1,135 @@
+
+ $ "$TESTDIR/hghave" svn svn-bindings || exit 80
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert =
+ > graphlog =
+ > EOF
+
+ $ svnadmin create svn-repo
+ $ svnadmin load -q svn-repo < "$TESTDIR/svn/encoding.svndump"
+
+Convert while testing all possible outputs
+
+ $ hg --debug convert svn-repo A-hg
+ initializing destination A-hg repository
+ reparent to file://*/svn-repo (glob)
+ run hg sink pre-conversion action
+ scanning source...
+ found trunk at 'trunk'
+ found tags at 'tags'
+ found branches at 'branches'
+ found branch branch\xc3\xa9 at 5 (esc)
+ found branch branch\xc3\xa9e at 6 (esc)
+ scanning: 1 revisions
+ reparent to file://*/svn-repo/trunk (glob)
+ fetching revision log for "/trunk" from 4 to 0
+ parsing revision 4 (2 changes)
+ parsing revision 3 (4 changes)
+ parsing revision 2 (3 changes)
+ parsing revision 1 (3 changes)
+ no copyfrom path, don't know what to do.
+ '/branches' is not under '/trunk', ignoring
+ '/tags' is not under '/trunk', ignoring
+ scanning: 2 revisions
+ reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
+ fetching revision log for "/branches/branch\xc3\xa9" from 5 to 0 (esc)
+ parsing revision 5 (1 changes)
+ reparent to file://*/svn-repo (glob)
+ reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
+ found parent of branch /branches/branch\xc3\xa9 at 4: /trunk (esc)
+ scanning: 3 revisions
+ reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
+ fetching revision log for "/branches/branch\xc3\xa9e" from 6 to 0 (esc)
+ parsing revision 6 (1 changes)
+ reparent to file://*/svn-repo (glob)
+ reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
+ found parent of branch /branches/branch\xc3\xa9e at 5: /branches/branch\xc3\xa9 (esc)
+ scanning: 4 revisions
+ scanning: 5 revisions
+ scanning: 6 revisions
+ sorting...
+ converting...
+ 5 init projA
+ source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@1
+ converting: 0/6 revisions (0.00%)
+ 4 hello
+ source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@2
+ converting: 1/6 revisions (16.67%)
+ reparent to file://*/svn-repo/trunk (glob)
+ scanning paths: /trunk/\xc3\xa0 0/3 (0.00%) (esc)
+ scanning paths: /trunk/\xc3\xa0/e\xcc\x81 1/3 (33.33%) (esc)
+ scanning paths: /trunk/\xc3\xa9 2/3 (66.67%) (esc)
+ \xc3\xa0/e\xcc\x81 (esc)
+ getting files: \xc3\xa0/e\xcc\x81 1/2 (50.00%) (esc)
+ \xc3\xa9 (esc)
+ getting files: \xc3\xa9 2/2 (100.00%) (esc)
+ 3 copy files
+ source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@3
+ converting: 2/6 revisions (33.33%)
+ scanning paths: /trunk/\xc3\xa0 0/4 (0.00%) (esc)
+ gone from -1
+ reparent to file://*/svn-repo (glob)
+ reparent to file://*/svn-repo/trunk (glob)
+ scanning paths: /trunk/\xc3\xa8 1/4 (25.00%) (esc)
+ copied to \xc3\xa8 from \xc3\xa9@2 (esc)
+ scanning paths: /trunk/\xc3\xa9 2/4 (50.00%) (esc)
+ gone from -1
+ reparent to file://*/svn-repo (glob)
+ reparent to file://*/svn-repo/trunk (glob)
+ scanning paths: /trunk/\xc3\xb9 3/4 (75.00%) (esc)
+ mark /trunk/\xc3\xb9 came from \xc3\xa0:2 (esc)
+ \xc3\xa0/e\xcc\x81 (esc)
+ getting files: \xc3\xa0/e\xcc\x81 1/4 (25.00%) (esc)
+ \xc3\xa8 (esc)
+ getting files: \xc3\xa8 2/4 (50.00%) (esc)
+ \xc3\xa8: copy \xc3\xa9:6b67ccefd5ce6de77e7ead4f5292843a0255329f (esc)
+ \xc3\xa9 (esc)
+ getting files: \xc3\xa9 3/4 (75.00%) (esc)
+ \xc3\xb9/e\xcc\x81 (esc)
+ getting files: \xc3\xb9/e\xcc\x81 4/4 (100.00%) (esc)
+ \xc3\xb9/e\xcc\x81: copy \xc3\xa0/e\xcc\x81:a9092a3d84a37b9993b5c73576f6de29b7ea50f6 (esc)
+ 2 remove files
+ source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@4
+ converting: 3/6 revisions (50.00%)
+ scanning paths: /trunk/\xc3\xa8 0/2 (0.00%) (esc)
+ gone from -1
+ reparent to file://*/svn-repo (glob)
+ reparent to file://*/svn-repo/trunk (glob)
+ scanning paths: /trunk/\xc3\xb9 1/2 (50.00%) (esc)
+ gone from -1
+ reparent to file://*/svn-repo (glob)
+ reparent to file://*/svn-repo/trunk (glob)
+ \xc3\xa8 (esc)
+ getting files: \xc3\xa8 1/2 (50.00%) (esc)
+ \xc3\xb9/e\xcc\x81 (esc)
+ getting files: \xc3\xb9/e\xcc\x81 2/2 (100.00%) (esc)
+ 1 branch to branch?
+ source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/branches/branch?@5
+ converting: 4/6 revisions (66.67%)
+ reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
+ scanning paths: /branches/branch\xc3\xa9 0/1 (0.00%) (esc)
+ 0 branch to branch?e
+ source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/branches/branch?e@6
+ converting: 5/6 revisions (83.33%)
+ reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
+ scanning paths: /branches/branch\xc3\xa9e 0/1 (0.00%) (esc)
+ reparent to file://*/svn-repo (glob)
+ reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
+ reparent to file://*/svn-repo (glob)
+ reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
+ updating tags
+ .hgtags
+ run hg sink post-conversion action
+ $ cd A-hg
+ $ hg up
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Check tags are in UTF-8
+
+ $ cat .hgtags
+ e94e4422020e715add80525e8f0f46c9968689f1 branch\xc3\xa9e (esc)
+ f7e66f98380ed1e53a797c5c7a7a2616a7ab377d branch\xc3\xa9 (esc)
+
+ $ cd ..
diff --git a/tests/test-convert-svn-move.t b/tests/test-convert-svn-move.t
new file mode 100644
index 0000000..b8f0dde
--- /dev/null
+++ b/tests/test-convert-svn-move.t
@@ -0,0 +1,243 @@
+
+ $ "$TESTDIR/hghave" svn svn-bindings || exit 80
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert =
+ > graphlog =
+ > EOF
+
+ $ svnadmin create svn-repo
+ $ svnadmin load -q svn-repo < "$TESTDIR/svn/move.svndump"
+ $ SVNREPOPATH=`pwd`/svn-repo
+#if windows
+ $ SVNREPOURL=file:///`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
+#else
+ $ SVNREPOURL=file://`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
+#endif
+
+Convert trunk and branches
+
+ $ hg convert --datesort "$SVNREPOURL"/subproject A-hg
+ initializing destination A-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 13 createtrunk
+ 12 moved1
+ 11 moved1
+ 10 moved2
+ 9 changeb and rm d2
+ 8 changeb and rm d2
+ 7 moved1again
+ 6 moved1again
+ 5 copyfilefrompast
+ 4 copydirfrompast
+ 3 add d3
+ 2 copy dir and remove subdir
+ 1 add d4old
+ 0 rename d4old into d4new
+
+ $ cd A-hg
+ $ hg glog --template '{rev} {desc|firstline} files: {files}\n'
+ o 13 rename d4old into d4new files: d4new/g d4old/g
+ |
+ o 12 add d4old files: d4old/g
+ |
+ o 11 copy dir and remove subdir files: d3/d31/e d4/d31/e d4/f
+ |
+ o 10 add d3 files: d3/d31/e d3/f
+ |
+ o 9 copydirfrompast files: d2/d
+ |
+ o 8 copyfilefrompast files: d
+ |
+ o 7 moved1again files: d1/b d1/c
+ |
+ | o 6 moved1again files:
+ | |
+ o | 5 changeb and rm d2 files: d1/b d2/d
+ | |
+ | o 4 changeb and rm d2 files: b
+ | |
+ o | 3 moved2 files: d2/d
+ | |
+ o | 2 moved1 files: d1/b d1/c
+ | |
+ | o 1 moved1 files: b c
+ |
+ o 0 createtrunk files:
+
+
+Check move copy records
+
+ $ hg st --rev 12:13 --copies
+ A d4new/g
+ d4old/g
+ R d4old/g
+
+Check branches
+
+ $ hg branches
+ default 13:* (glob)
+ d1 6:* (glob)
+ $ cd ..
+
+ $ mkdir test-replace
+ $ cd test-replace
+ $ svnadmin create svn-repo
+ $ svnadmin load -q svn-repo < "$TESTDIR/svn/replace.svndump"
+
+Convert files being replaced by directories
+
+ $ hg convert svn-repo hg-repo
+ initializing destination hg-repo repository
+ scanning source...
+ sorting...
+ converting...
+ 6 initial
+ 5 clobber symlink
+ 4 clobber1
+ 3 clobber2
+ 2 adddb
+ 1 branch
+ 0 clobberdir
+
+ $ cd hg-repo
+
+Manifest before
+
+ $ hg -v manifest -r 1
+ 644 a
+ 644 d/b
+ 644 d2/a
+ 644 @ dlink
+ 644 @ dlink2
+ 644 dlink3
+
+Manifest after clobber1
+
+ $ hg -v manifest -r 2
+ 644 a/b
+ 644 d/b
+ 644 d2/a
+ 644 dlink/b
+ 644 @ dlink2
+ 644 dlink3
+
+Manifest after clobber2
+
+ $ hg -v manifest -r 3
+ 644 a/b
+ 644 d/b
+ 644 d2/a
+ 644 dlink/b
+ 644 @ dlink2
+ 644 @ dlink3
+
+Manifest after clobberdir
+
+ $ hg -v manifest -r 6
+ 644 a/b
+ 644 d/b
+ 644 d2/a
+ 644 d2/c
+ 644 dlink/b
+ 644 @ dlink2
+ 644 @ dlink3
+
+Try updating
+
+ $ hg up -qC default
+ $ cd ..
+
+Test convert progress bar'
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > progress =
+ > [progress]
+ > assume-tty = 1
+ > delay = 0
+ > changedelay = 0
+ > format = topic bar number
+ > refresh = 0
+ > width = 60
+ > EOF
+
+ $ hg convert svn-repo hg-progress 2>&1 | "$TESTDIR/filtercr.py"
+
+ scanning [ <=> ] 1
+ scanning [ <=> ] 2
+ scanning [ <=> ] 3
+ scanning [ <=> ] 4
+ scanning [ <=> ] 5
+ scanning [ <=> ] 6
+ scanning [ <=> ] 7
+
+ converting [ ] 0/7
+ getting files [=====> ] 1/6
+ getting files [============> ] 2/6
+ getting files [==================> ] 3/6
+ getting files [=========================> ] 4/6
+ getting files [===============================> ] 5/6
+ getting files [======================================>] 6/6
+
+ converting [=====> ] 1/7
+ scanning paths [ ] 0/1
+ getting files [======================================>] 1/1
+
+ converting [===========> ] 2/7
+ scanning paths [ ] 0/2
+ scanning paths [==================> ] 1/2
+ getting files [========> ] 1/4
+ getting files [==================> ] 2/4
+ getting files [============================> ] 3/4
+ getting files [======================================>] 4/4
+
+ converting [=================> ] 3/7
+ scanning paths [ ] 0/1
+ getting files [======================================>] 1/1
+
+ converting [=======================> ] 4/7
+ scanning paths [ ] 0/1
+ getting files [======================================>] 1/1
+
+ converting [=============================> ] 5/7
+ scanning paths [ ] 0/3
+ scanning paths [===========> ] 1/3
+ scanning paths [========================> ] 2/3
+ getting files [===> ] 1/8
+ getting files [========> ] 2/8
+ getting files [=============> ] 3/8
+ getting files [==================> ] 4/8
+ getting files [=======================> ] 5/8
+ getting files [============================> ] 6/8
+ getting files [=================================> ] 7/8
+ getting files [======================================>] 8/8
+
+ converting [===================================> ] 6/7
+ scanning paths [ ] 0/1
+ getting files [===> ] 1/8
+ getting files [========> ] 2/8
+ getting files [=============> ] 3/8
+ getting files [==================> ] 4/8
+ getting files [=======================> ] 5/8
+ getting files [============================> ] 6/8
+ getting files [=================================> ] 7/8
+ getting files [======================================>] 8/8
+
+ initializing destination hg-progress repository
+ scanning source...
+ sorting...
+ converting...
+ 6 initial
+ 5 clobber symlink
+ 4 clobber1
+ 3 clobber2
+ 2 adddb
+ 1 branch
+ 0 clobberdir
+
+
+ $ cd ..
diff --git a/tests/test-convert-svn-sink.t b/tests/test-convert-svn-sink.t
new file mode 100644
index 0000000..ab39f7f
--- /dev/null
+++ b/tests/test-convert-svn-sink.t
@@ -0,0 +1,432 @@
+ $ "$TESTDIR/hghave" svn13 || exit 80
+
+ $ svnupanddisplay()
+ > {
+ > (
+ > cd $1;
+ > svn up -q;
+ > svn st -v | sed 's/ */ /g' | sort
+ > limit=''
+ > if [ $2 -gt 0 ]; then
+ > limit="--limit=$2"
+ > fi
+ > svn log --xml -v $limit | python "$TESTDIR/svnxml.py"
+ > )
+ > }
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert =
+ > graphlog =
+ > EOF
+
+ $ hg init a
+
+Add
+
+ $ echo a > a/a
+ $ mkdir -p a/d1/d2
+ $ echo b > a/d1/d2/b
+ $ hg --cwd a ci -d '0 0' -A -m 'add a file'
+ adding a
+ adding d1/d2/b
+
+Modify
+
+ $ "$TESTDIR/svn-safe-append.py" a a/a
+ $ hg --cwd a ci -d '1 0' -m 'modify a file'
+ $ hg --cwd a tip -q
+ 1:e0e2b8a9156b
+
+ $ hg convert -d svn a
+ assuming destination a-hg
+ initializing svn repository 'a-hg'
+ initializing svn working copy 'a-hg-wc'
+ scanning source...
+ sorting...
+ converting...
+ 1 add a file
+ 0 modify a file
+ $ svnupanddisplay a-hg-wc 2
+ 2 1 test d1
+ 2 1 test d1/d2 (glob)
+ 2 1 test d1/d2/b (glob)
+ 2 2 test .
+ 2 2 test a
+ revision: 2
+ author: test
+ msg: modify a file
+ M /a
+ revision: 1
+ author: test
+ msg: add a file
+ A /a
+ A /d1
+ A /d1/d2
+ A /d1/d2/b
+ $ ls a a-hg-wc
+ a:
+ a
+ d1
+
+ a-hg-wc:
+ a
+ d1
+ $ cmp a/a a-hg-wc/a
+
+Rename
+
+ $ hg --cwd a mv a b
+ $ hg --cwd a ci -d '2 0' -m 'rename a file'
+ $ hg --cwd a tip -q
+ 2:eb5169441d43
+
+ $ hg convert -d svn a
+ assuming destination a-hg
+ initializing svn working copy 'a-hg-wc'
+ scanning source...
+ sorting...
+ converting...
+ 0 rename a file
+ $ svnupanddisplay a-hg-wc 1
+ 3 1 test d1
+ 3 1 test d1/d2 (glob)
+ 3 1 test d1/d2/b (glob)
+ 3 3 test .
+ 3 3 test b
+ revision: 3
+ author: test
+ msg: rename a file
+ D /a
+ A /b (from /a@2)
+ $ ls a a-hg-wc
+ a:
+ b
+ d1
+
+ a-hg-wc:
+ b
+ d1
+
+Copy
+
+ $ hg --cwd a cp b c
+
+ $ hg --cwd a ci -d '3 0' -m 'copy a file'
+ $ hg --cwd a tip -q
+ 3:60effef6ab48
+
+ $ hg convert -d svn a
+ assuming destination a-hg
+ initializing svn working copy 'a-hg-wc'
+ scanning source...
+ sorting...
+ converting...
+ 0 copy a file
+ $ svnupanddisplay a-hg-wc 1
+ 4 1 test d1
+ 4 1 test d1/d2 (glob)
+ 4 1 test d1/d2/b (glob)
+ 4 3 test b
+ 4 4 test .
+ 4 4 test c
+ revision: 4
+ author: test
+ msg: copy a file
+ A /c (from /b@3)
+ $ ls a a-hg-wc
+ a:
+ b
+ c
+ d1
+
+ a-hg-wc:
+ b
+ c
+ d1
+
+ $ hg --cwd a rm b
+
+Remove
+
+ $ hg --cwd a ci -d '4 0' -m 'remove a file'
+ $ hg --cwd a tip -q
+ 4:87bbe3013fb6
+
+ $ hg convert -d svn a
+ assuming destination a-hg
+ initializing svn working copy 'a-hg-wc'
+ scanning source...
+ sorting...
+ converting...
+ 0 remove a file
+ $ svnupanddisplay a-hg-wc 1
+ 5 1 test d1
+ 5 1 test d1/d2 (glob)
+ 5 1 test d1/d2/b (glob)
+ 5 4 test c
+ 5 5 test .
+ revision: 5
+ author: test
+ msg: remove a file
+ D /b
+ $ ls a a-hg-wc
+ a:
+ c
+ d1
+
+ a-hg-wc:
+ c
+ d1
+
+Executable
+
+#if execbit
+ $ chmod +x a/c
+#else
+ $ echo fake >> a/c
+#endif
+ $ hg --cwd a ci -d '5 0' -m 'make a file executable'
+#if execbit
+ $ hg --cwd a tip -q
+ 5:ff42e473c340
+#else
+ $ hg --cwd a tip -q
+ 5:817a700c8cf1
+#endif
+
+ $ hg convert -d svn a
+ assuming destination a-hg
+ initializing svn working copy 'a-hg-wc'
+ scanning source...
+ sorting...
+ converting...
+ 0 make a file executable
+ $ svnupanddisplay a-hg-wc 1
+ 6 1 test d1
+ 6 1 test d1/d2 (glob)
+ 6 1 test d1/d2/b (glob)
+ 6 6 test .
+ 6 6 test c
+ revision: 6
+ author: test
+ msg: make a file executable
+ M /c
+#if execbit
+ $ test -x a-hg-wc/c
+#endif
+
+#if symlink
+
+Symlinks
+
+ $ ln -s a/missing a/link
+ $ hg --cwd a commit -Am 'add symlink'
+ adding link
+ $ hg --cwd a mv link newlink
+ $ hg --cwd a commit -m 'move symlink'
+ $ hg convert -d svn a
+ assuming destination a-hg
+ initializing svn working copy 'a-hg-wc'
+ scanning source...
+ sorting...
+ converting...
+ 1 add symlink
+ 0 move symlink
+ $ svnupanddisplay a-hg-wc 1
+ 8 1 test d1
+ 8 1 test d1/d2
+ 8 1 test d1/d2/b
+ 8 6 test c
+ 8 8 test .
+ 8 8 test newlink
+ revision: 8
+ author: test
+ msg: move symlink
+ D /link
+ A /newlink (from /link@7)
+
+#endif
+
+ $ rm -rf a a-hg a-hg-wc
+
+
+Executable in new directory
+
+ $ hg init a
+
+ $ mkdir a/d1
+ $ echo a > a/d1/a
+#if execbit
+ $ chmod +x a/d1/a
+#else
+ $ echo fake >> a/d1/a
+#endif
+ $ hg --cwd a ci -d '0 0' -A -m 'add executable file in new directory'
+ adding d1/a
+
+ $ hg convert -d svn a
+ assuming destination a-hg
+ initializing svn repository 'a-hg'
+ initializing svn working copy 'a-hg-wc'
+ scanning source...
+ sorting...
+ converting...
+ 0 add executable file in new directory
+ $ svnupanddisplay a-hg-wc 1
+ 1 1 test .
+ 1 1 test d1
+ 1 1 test d1/a (glob)
+ revision: 1
+ author: test
+ msg: add executable file in new directory
+ A /d1
+ A /d1/a
+#if execbit
+ $ test -x a-hg-wc/d1/a
+#endif
+
+Copy to new directory
+
+ $ mkdir a/d2
+ $ hg --cwd a cp d1/a d2/a
+ $ hg --cwd a ci -d '1 0' -A -m 'copy file to new directory'
+
+ $ hg convert -d svn a
+ assuming destination a-hg
+ initializing svn working copy 'a-hg-wc'
+ scanning source...
+ sorting...
+ converting...
+ 0 copy file to new directory
+ $ svnupanddisplay a-hg-wc 1
+ 2 1 test d1
+ 2 1 test d1/a (glob)
+ 2 2 test .
+ 2 2 test d2
+ 2 2 test d2/a (glob)
+ revision: 2
+ author: test
+ msg: copy file to new directory
+ A /d2
+ A /d2/a (from /d1/a@1)
+
+Branchy history
+
+ $ hg init b
+ $ echo base > b/b
+ $ hg --cwd b ci -d '0 0' -Ambase
+ adding b
+
+ $ "$TESTDIR/svn-safe-append.py" left-1 b/b
+ $ echo left-1 > b/left-1
+ $ hg --cwd b ci -d '1 0' -Amleft-1
+ adding left-1
+
+ $ "$TESTDIR/svn-safe-append.py" left-2 b/b
+ $ echo left-2 > b/left-2
+ $ hg --cwd b ci -d '2 0' -Amleft-2
+ adding left-2
+
+ $ hg --cwd b up 0
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+ $ "$TESTDIR/svn-safe-append.py" right-1 b/b
+ $ echo right-1 > b/right-1
+ $ hg --cwd b ci -d '3 0' -Amright-1
+ adding right-1
+ created new head
+
+ $ "$TESTDIR/svn-safe-append.py" right-2 b/b
+ $ echo right-2 > b/right-2
+ $ hg --cwd b ci -d '4 0' -Amright-2
+ adding right-2
+
+ $ hg --cwd b up -C 2
+ 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg --cwd b merge
+ merging b
+ warning: conflicts during merge.
+ merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ hg --cwd b revert -r 2 b
+ $ hg --cwd b resolve -m b
+ $ hg --cwd b ci -d '5 0' -m 'merge'
+
+Expect 4 changes
+
+ $ hg convert -d svn b
+ assuming destination b-hg
+ initializing svn repository 'b-hg'
+ initializing svn working copy 'b-hg-wc'
+ scanning source...
+ sorting...
+ converting...
+ 5 base
+ 4 left-1
+ 3 left-2
+ 2 right-1
+ 1 right-2
+ 0 merge
+
+ $ svnupanddisplay b-hg-wc 0
+ 4 2 test left-1
+ 4 3 test b
+ 4 3 test left-2
+ 4 4 test .
+ 4 4 test right-1
+ 4 4 test right-2
+ revision: 4
+ author: test
+ msg: merge
+ A /right-1
+ A /right-2
+ revision: 3
+ author: test
+ msg: left-2
+ M /b
+ A /left-2
+ revision: 2
+ author: test
+ msg: left-1
+ M /b
+ A /left-1
+ revision: 1
+ author: test
+ msg: base
+ A /b
+
+Tags are not supported, but must not break conversion
+
+ $ rm -rf a a-hg a-hg-wc
+ $ hg init a
+ $ echo a > a/a
+ $ hg --cwd a ci -d '0 0' -A -m 'Add file a'
+ adding a
+ $ hg --cwd a tag -d '1 0' -m 'Tagged as v1.0' v1.0
+
+ $ hg convert -d svn a
+ assuming destination a-hg
+ initializing svn repository 'a-hg'
+ initializing svn working copy 'a-hg-wc'
+ scanning source...
+ sorting...
+ converting...
+ 1 Add file a
+ 0 Tagged as v1.0
+ writing Subversion tags is not yet implemented
+ $ svnupanddisplay a-hg-wc 2
+ 2 1 test a
+ 2 2 test .
+ 2 2 test .hgtags
+ revision: 2
+ author: test
+ msg: Tagged as v1.0
+ A /.hgtags
+ revision: 1
+ author: test
+ msg: Add file a
+ A /a
+ $ rm -rf a a-hg a-hg-wc
diff --git a/tests/test-convert-svn-source.t b/tests/test-convert-svn-source.t
new file mode 100644
index 0000000..544f3a5
--- /dev/null
+++ b/tests/test-convert-svn-source.t
@@ -0,0 +1,203 @@
+
+ $ "$TESTDIR/hghave" svn svn-bindings || exit 80
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert =
+ > graphlog =
+ > [convert]
+ > svn.trunk = mytrunk
+ > EOF
+
+ $ svnadmin create svn-repo
+ $ SVNREPOPATH=`pwd`/svn-repo
+#if windows
+ $ SVNREPOURL=file:///`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
+#else
+ $ SVNREPOURL=file://`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
+#endif
+
+Now test that it works with trunk/tags layout, but no branches yet.
+
+Initial svn import
+
+ $ mkdir projB
+ $ cd projB
+ $ mkdir mytrunk
+ $ mkdir tags
+ $ cd ..
+
+ $ svn import -m "init projB" projB "$SVNREPOURL/proj%20B" | sort
+
+ Adding projB/mytrunk (glob)
+ Adding projB/tags (glob)
+ Committed revision 1.
+
+Update svn repository
+
+ $ svn co "$SVNREPOURL/proj%20B/mytrunk" B
+ Checked out revision 1.
+ $ cd B
+ $ echo hello > 'letter .txt'
+ $ svn add 'letter .txt'
+ A letter .txt
+ $ svn ci -m hello
+ Adding letter .txt
+ Transmitting file data .
+ Committed revision 2.
+
+ $ "$TESTDIR/svn-safe-append.py" world 'letter .txt'
+ $ svn ci -m world
+ Sending letter .txt
+ Transmitting file data .
+ Committed revision 3.
+
+ $ svn copy -m "tag v0.1" "$SVNREPOURL/proj%20B/mytrunk" "$SVNREPOURL/proj%20B/tags/v0.1"
+
+ Committed revision 4.
+
+ $ "$TESTDIR/svn-safe-append.py" 'nice day today!' 'letter .txt'
+ $ svn ci -m "nice day"
+ Sending letter .txt
+ Transmitting file data .
+ Committed revision 5.
+ $ cd ..
+
+Convert to hg once
+
+ $ hg convert "$SVNREPOURL/proj%20B" B-hg
+ initializing destination B-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 3 init projB
+ 2 hello
+ 1 world
+ 0 nice day
+ updating tags
+
+Update svn repository again
+
+ $ cd B
+ $ "$TESTDIR/svn-safe-append.py" "see second letter" 'letter .txt'
+ $ echo "nice to meet you" > letter2.txt
+ $ svn add letter2.txt
+ A letter2.txt
+ $ svn ci -m "second letter"
+ Sending letter .txt
+ Adding letter2.txt
+ Transmitting file data ..
+ Committed revision 6.
+
+ $ svn copy -m "tag v0.2" "$SVNREPOURL/proj%20B/mytrunk" "$SVNREPOURL/proj%20B/tags/v0.2"
+
+ Committed revision 7.
+
+ $ "$TESTDIR/svn-safe-append.py" "blah-blah-blah" letter2.txt
+ $ svn ci -m "work in progress"
+ Sending letter2.txt
+ Transmitting file data .
+ Committed revision 8.
+ $ cd ..
+
+ $ hg convert -s svn "$SVNREPOURL/proj%20B/non-existent-path" dest
+ initializing destination dest repository
+ abort: no revision found in module /proj B/non-existent-path
+ [255]
+
+########################################
+
+Test incremental conversion
+
+ $ hg convert "$SVNREPOURL/proj%20B" B-hg
+ scanning source...
+ sorting...
+ converting...
+ 1 second letter
+ 0 work in progress
+ updating tags
+
+ $ cd B-hg
+ $ hg glog --template '{rev} {desc|firstline} files: {files}\n'
+ o 7 update tags files: .hgtags
+ |
+ o 6 work in progress files: letter2.txt
+ |
+ o 5 second letter files: letter .txt letter2.txt
+ |
+ o 4 update tags files: .hgtags
+ |
+ o 3 nice day files: letter .txt
+ |
+ o 2 world files: letter .txt
+ |
+ o 1 hello files: letter .txt
+ |
+ o 0 init projB files:
+
+ $ hg tags -q
+ tip
+ v0.2
+ v0.1
+ $ cd ..
+
+Test filemap
+ $ echo 'include letter2.txt' > filemap
+ $ hg convert --filemap filemap "$SVNREPOURL/proj%20B/mytrunk" fmap
+ initializing destination fmap repository
+ scanning source...
+ sorting...
+ converting...
+ 5 init projB
+ 4 hello
+ 3 world
+ 2 nice day
+ 1 second letter
+ 0 work in progress
+ $ hg -R fmap branch -q
+ default
+ $ hg glog -R fmap --template '{rev} {desc|firstline} files: {files}\n'
+ o 1 work in progress files: letter2.txt
+ |
+ o 0 second letter files: letter2.txt
+
+
+Test stop revision
+ $ hg convert --rev 1 "$SVNREPOURL/proj%20B/mytrunk" stoprev
+ initializing destination stoprev repository
+ scanning source...
+ sorting...
+ converting...
+ 0 init projB
+ $ hg -R stoprev branch -q
+ default
+
+Check convert_revision extra-records.
+This is also the only place testing more than one extra field in a revision.
+
+ $ cd stoprev
+ $ hg tip --debug | grep extra
+ extra: branch=default
+ extra: convert_revision=svn:........-....-....-....-............/proj B/mytrunk@1 (re)
+ $ cd ..
+
+Test converting empty heads (issue3347)
+
+ $ svnadmin create svn-empty
+ $ svnadmin load -q svn-empty < "$TESTDIR/svn/empty.svndump"
+ $ hg --config convert.svn.trunk= convert svn-empty
+ assuming destination svn-empty-hg
+ initializing destination svn-empty-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 init projA
+ 0 adddir
+ $ hg --config convert.svn.trunk= convert "$SVNREPOURL/../svn-empty/trunk"
+ assuming destination trunk-hg
+ initializing destination trunk-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 init projA
+ 0 adddir
diff --git a/tests/test-convert-svn-startrev.t b/tests/test-convert-svn-startrev.t
new file mode 100644
index 0000000..3ce1f55
--- /dev/null
+++ b/tests/test-convert-svn-startrev.t
@@ -0,0 +1,90 @@
+
+ $ "$TESTDIR/hghave" svn svn-bindings || exit 80
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert =
+ > graphlog =
+ > EOF
+ $ convert()
+ > {
+ > startrev=$1
+ > repopath=A-r$startrev-hg
+ > hg convert --config convert.svn.startrev=$startrev \
+ > --config convert.svn.trunk=branches/branch1 \
+ > --config convert.svn.branches=" " \
+ > --config convert.svn.tags= \
+ > --datesort svn-repo $repopath
+ > hg -R $repopath glog \
+ > --template '{rev} {desc|firstline} files: {files}\n'
+ > echo
+ > }
+
+ $ svnadmin create svn-repo
+ $ svnadmin load -q svn-repo < "$TESTDIR/svn/startrev.svndump"
+
+Convert before branching point
+
+ $ convert 3
+ initializing destination A-r3-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 3 removeb
+ 2 changeaa
+ 1 branch, changeaaa
+ 0 addc,changeaaaa
+ o 3 addc,changeaaaa files: a c
+ |
+ o 2 branch, changeaaa files: a
+ |
+ o 1 changeaa files: a
+ |
+ o 0 removeb files: a
+
+
+
+Convert before branching point
+
+ $ convert 4
+ initializing destination A-r4-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 2 changeaa
+ 1 branch, changeaaa
+ 0 addc,changeaaaa
+ o 2 addc,changeaaaa files: a c
+ |
+ o 1 branch, changeaaa files: a
+ |
+ o 0 changeaa files: a
+
+
+
+Convert at branching point
+
+ $ convert 5
+ initializing destination A-r5-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 1 branch, changeaaa
+ 0 addc,changeaaaa
+ o 1 addc,changeaaaa files: a c
+ |
+ o 0 branch, changeaaa files: a
+
+
+
+Convert last revision only
+
+ $ convert 6
+ initializing destination A-r6-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 0 addc,changeaaaa
+ o 0 addc,changeaaaa files: a c
+
+
diff --git a/tests/test-convert-svn-tags.t b/tests/test-convert-svn-tags.t
new file mode 100644
index 0000000..2f93e0e
--- /dev/null
+++ b/tests/test-convert-svn-tags.t
@@ -0,0 +1,67 @@
+
+ $ "$TESTDIR/hghave" svn svn-bindings || exit 80
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert =
+ > graphlog =
+ > EOF
+
+ $ svnadmin create svn-repo
+ $ svnadmin load -q svn-repo < "$TESTDIR/svn/tags.svndump"
+
+Convert
+ $ hg convert --datesort svn-repo A-hg
+ initializing destination A-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 5 init projA
+ 4 adda
+ 3 changea
+ 2 changea2
+ 1 changea3
+ 0 changea
+ updating tags
+
+ $ cd A-hg
+ $ hg glog --template '{rev} {desc|firstline} tags: {tags}\n'
+ o 6 update tags tags: tip
+ |
+ o 5 changea tags: trunk.goodtag
+ |
+ o 4 changea3 tags:
+ |
+ o 3 changea2 tags: trunk.v1
+ |
+ o 2 changea tags:
+ |
+ o 1 adda tags:
+ |
+ o 0 init projA tags:
+
+
+ $ hg tags -q
+ tip
+ trunk.goodtag
+ trunk.v1
+
+ $ cd ..
+
+Convert without tags
+
+ $ hg convert --datesort --config convert.svn.tags= svn-repo A-notags-hg
+ initializing destination A-notags-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 5 init projA
+ 4 adda
+ 3 changea
+ 2 changea2
+ 1 changea3
+ 0 changea
+
+ $ hg -R A-notags-hg tags -q
+ tip
+
diff --git a/tests/test-convert-tagsbranch-topology.t b/tests/test-convert-tagsbranch-topology.t
new file mode 100644
index 0000000..0af7e79
--- /dev/null
+++ b/tests/test-convert-tagsbranch-topology.t
@@ -0,0 +1,90 @@
+
+ $ "$TESTDIR/hghave" git || exit 80
+ $ echo "[core]" >> $HOME/.gitconfig
+ $ echo "autocrlf = false" >> $HOME/.gitconfig
+ $ echo "[core]" >> $HOME/.gitconfig
+ $ echo "autocrlf = false" >> $HOME/.gitconfig
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert=" >> $HGRCPATH
+ $ echo 'hgext.graphlog =' >> $HGRCPATH
+ $ echo '[convert]' >> $HGRCPATH
+ $ echo 'hg.usebranchnames = True' >> $HGRCPATH
+ $ echo 'hg.tagsbranch = tags-update' >> $HGRCPATH
+ $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
+ $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
+ $ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
+ $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
+ $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
+ $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
+ $ count=10
+ $ action()
+ > {
+ > GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
+ > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
+ > git "$@" >/dev/null 2>/dev/null || echo "git command error"
+ > count=`expr $count + 1`
+ > }
+ $ glog()
+ > {
+ > hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
+ > }
+ $ convertrepo()
+ > {
+ > hg convert --datesort git-repo hg-repo
+ > }
+
+Build a GIT repo with at least 1 tag
+
+ $ mkdir git-repo
+ $ cd git-repo
+ $ git init >/dev/null 2>&1
+ $ echo a > a
+ $ git add a
+ $ action commit -m "rev1"
+ $ action tag -m "tag1" tag1
+ $ cd ..
+
+Do a first conversion
+
+ $ convertrepo
+ initializing destination hg-repo repository
+ scanning source...
+ sorting...
+ converting...
+ 0 rev1
+ updating tags
+ updating bookmarks
+
+Simulate upstream updates after first conversion
+
+ $ cd git-repo
+ $ echo b > a
+ $ git add a
+ $ action commit -m "rev2"
+ $ action tag -m "tag2" tag2
+ $ cd ..
+
+Perform an incremental conversion
+
+ $ convertrepo
+ scanning source...
+ sorting...
+ converting...
+ 0 rev2
+ updating tags
+ updating bookmarks
+
+Print the log
+
+ $ cd hg-repo
+ $ glog
+ o 3 "update tags" files: .hgtags
+ |
+ | o 2 "rev2" files: a
+ | |
+ o | 1 "update tags" files: .hgtags
+ /
+ o 0 "rev1" files: a
+
+
+ $ cd ..
diff --git a/tests/test-convert-tla.t b/tests/test-convert-tla.t
new file mode 100644
index 0000000..8437e57
--- /dev/null
+++ b/tests/test-convert-tla.t
@@ -0,0 +1,135 @@
+
+ $ "$TESTDIR/hghave" tla symlink || exit 80
+ $ tla my-id "mercurial <mercurial@selenic.com>"
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "convert=" >> $HGRCPATH
+ $ echo 'graphlog =' >> $HGRCPATH
+
+create tla archive
+
+ $ tla make-archive tla@mercurial--convert `pwd`/hg-test-convert-tla
+
+initialize tla repo
+
+ $ mkdir tla-repo
+ $ cd tla-repo/
+ $ tla init-tree tla@mercurial--convert/tla--test--0
+ $ tla import
+ * creating version tla@mercurial--convert/tla--test--0
+ * imported tla@mercurial--convert/tla--test--0
+
+create initial files
+
+ $ echo 'this is a file' > a
+ $ tla add a
+ $ mkdir src
+ $ tla add src
+ $ cd src
+ $ dd count=1 if=/dev/zero of=b > /dev/null 2> /dev/null
+ $ tla add b
+ $ tla commit -s "added a file, src and src/b (binary)"
+ A/ .arch-ids
+ A/ src
+ A/ src/.arch-ids
+ A .arch-ids/a.id
+ A a
+ A src/.arch-ids/=id
+ A src/.arch-ids/b.id
+ A src/b
+ * update pristine tree (tla@mercurial--convert/tla--test--0--base-0 => tla--test--0--patch-1)
+ * committed tla@mercurial--convert/tla--test--0--patch-1
+
+create link file and modify a
+
+ $ ln -s ../a a-link
+ $ tla add a-link
+ $ echo 'this a modification to a' >> ../a
+ $ tla commit -s "added link to a and modify a"
+ A src/.arch-ids/a-link.id
+ A src/a-link
+ M a
+ * update pristine tree (tla@mercurial--convert/tla--test--0--patch-1 => tla--test--0--patch-2)
+ * committed tla@mercurial--convert/tla--test--0--patch-2
+
+create second link and modify b
+
+ $ ln -s ../a a-link-2
+ $ tla add a-link-2
+ $ dd count=1 seek=1 if=/dev/zero of=b > /dev/null 2> /dev/null
+ $ tla commit -s "added second link and modify b"
+ A src/.arch-ids/a-link-2.id
+ A src/a-link-2
+ Mb src/b
+ * update pristine tree (tla@mercurial--convert/tla--test--0--patch-2 => tla--test--0--patch-3)
+ * committed tla@mercurial--convert/tla--test--0--patch-3
+
+b file to link and a-link-2 to regular file
+
+ $ rm -f a-link-2
+ $ echo 'this is now a regular file' > a-link-2
+ $ ln -sf ../a b
+ $ tla commit -s "file to link and link to file test"
+ fl src/b
+ lf src/a-link-2
+ * update pristine tree (tla@mercurial--convert/tla--test--0--patch-3 => tla--test--0--patch-4)
+ * committed tla@mercurial--convert/tla--test--0--patch-4
+
+move a-link-2 file and src directory
+
+ $ cd ..
+ $ tla mv src/a-link-2 c
+ $ tla mv src test
+ $ tla commit -s "move and rename a-link-2 file and src directory"
+ D/ src/.arch-ids
+ A/ test/.arch-ids
+ /> src test
+ => src/.arch-ids/a-link-2.id .arch-ids/c.id
+ => src/a-link-2 c
+ => src/.arch-ids/=id test/.arch-ids/=id
+ => src/.arch-ids/a-link.id test/.arch-ids/a-link.id
+ => src/.arch-ids/b.id test/.arch-ids/b.id
+ * update pristine tree (tla@mercurial--convert/tla--test--0--patch-4 => tla--test--0--patch-5)
+ * committed tla@mercurial--convert/tla--test--0--patch-5
+ $ cd ..
+
+converting tla repo to Mercurial
+
+ $ hg convert tla-repo tla-repo-hg
+ initializing destination tla-repo-hg repository
+ analyzing tree version tla@mercurial--convert/tla--test--0...
+ scanning source...
+ sorting...
+ converting...
+ 5 initial import
+ 4 added a file, src and src/b (binary)
+ 3 added link to a and modify a
+ 2 added second link and modify b
+ 1 file to link and link to file test
+ 0 move and rename a-link-2 file and src directory
+ $ tla register-archive -d tla@mercurial--convert
+ $ glog()
+ > {
+ > hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
+ > }
+
+show graph log
+
+ $ glog -R tla-repo-hg
+ o 5 "move and rename a-link-2 file and src directory" files: c src/a-link src/a-link-2 src/b test/a-link test/b
+ |
+ o 4 "file to link and link to file test" files: src/a-link-2 src/b
+ |
+ o 3 "added second link and modify b" files: src/a-link-2 src/b
+ |
+ o 2 "added link to a and modify a" files: a src/a-link
+ |
+ o 1 "added a file, src and src/b (binary)" files: a src/b
+ |
+ o 0 "initial import" files:
+
+ $ hg up -q -R tla-repo-hg
+ $ hg -R tla-repo-hg manifest --debug
+ c4072c4b72e1cabace081888efa148ee80ca3cbb 644 a
+ 0201ac32a3a8e86e303dff60366382a54b48a72e 644 c
+ c0067ba5ff0b7c9a3eb17270839d04614c435623 644 @ test/a-link
+ 375f4263d86feacdea7e3c27100abd1560f2a973 644 @ test/b
diff --git a/tests/test-convert.t b/tests/test-convert.t
new file mode 100644
index 0000000..26a7441
--- /dev/null
+++ b/tests/test-convert.t
@@ -0,0 +1,447 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > convert=
+ > [convert]
+ > hg.saverev=False
+ > EOF
+ $ hg help convert
+ hg convert [OPTION]... SOURCE [DEST [REVMAP]]
+
+ convert a foreign SCM repository to a Mercurial one.
+
+ Accepted source formats [identifiers]:
+
+ - Mercurial [hg]
+ - CVS [cvs]
+ - Darcs [darcs]
+ - git [git]
+ - Subversion [svn]
+ - Monotone [mtn]
+ - GNU Arch [gnuarch]
+ - Bazaar [bzr]
+ - Perforce [p4]
+
+ Accepted destination formats [identifiers]:
+
+ - Mercurial [hg]
+ - Subversion [svn] (history on branches is not preserved)
+
+ If no revision is given, all revisions will be converted. Otherwise,
+ convert will only import up to the named revision (given in a format
+ understood by the source).
+
+ If no destination directory name is specified, it defaults to the basename
+ of the source with "-hg" appended. If the destination repository doesn't
+ exist, it will be created.
+
+ By default, all sources except Mercurial will use --branchsort. Mercurial
+ uses --sourcesort to preserve original revision numbers order. Sort modes
+ have the following effects:
+
+ --branchsort convert from parent to child revision when possible, which
+ means branches are usually converted one after the other.
+ It generates more compact repositories.
+ --datesort sort revisions by date. Converted repositories have good-
+ looking changelogs but are often an order of magnitude
+ larger than the same ones generated by --branchsort.
+ --sourcesort try to preserve source revisions order, only supported by
+ Mercurial sources.
+
+ If "REVMAP" isn't given, it will be put in a default location
+ ("<dest>/.hg/shamap" by default). The "REVMAP" is a simple text file that
+ maps each source commit ID to the destination ID for that revision, like
+ so:
+
+ <source ID> <destination ID>
+
+ If the file doesn't exist, it's automatically created. It's updated on
+ each commit copied, so "hg convert" can be interrupted and can be run
+ repeatedly to copy new commits.
+
+ The authormap is a simple text file that maps each source commit author to
+ a destination commit author. It is handy for source SCMs that use unix
+ logins to identify authors (eg: CVS). One line per author mapping and the
+ line format is:
+
+ source author = destination author
+
+ Empty lines and lines starting with a "#" are ignored.
+
+ The filemap is a file that allows filtering and remapping of files and
+ directories. Each line can contain one of the following directives:
+
+ include path/to/file-or-dir
+
+ exclude path/to/file-or-dir
+
+ rename path/to/source path/to/destination
+
+ Comment lines start with "#". A specified path matches if it equals the
+ full relative name of a file or one of its parent directories. The
+ "include" or "exclude" directive with the longest matching path applies,
+ so line order does not matter.
+
+ The "include" directive causes a file, or all files under a directory, to
+ be included in the destination repository, and the exclusion of all other
+ files and directories not explicitly included. The "exclude" directive
+ causes files or directories to be omitted. The "rename" directive renames
+ a file or directory if it is converted. To rename from a subdirectory into
+ the root of the repository, use "." as the path to rename to.
+
+ The splicemap is a file that allows insertion of synthetic history,
+ letting you specify the parents of a revision. This is useful if you want
+ to e.g. give a Subversion merge two parents, or graft two disconnected
+ series of history together. Each entry contains a key, followed by a
+ space, followed by one or two comma-separated values:
+
+ key parent1, parent2
+
+ The key is the revision ID in the source revision control system whose
+ parents should be modified (same format as a key in .hg/shamap). The
+ values are the revision IDs (in either the source or destination revision
+ control system) that should be used as the new parents for that node. For
+ example, if you have merged "release-1.0" into "trunk", then you should
+ specify the revision on "trunk" as the first parent and the one on the
+ "release-1.0" branch as the second.
+
+ The branchmap is a file that allows you to rename a branch when it is
+ being brought in from whatever external repository. When used in
+ conjunction with a splicemap, it allows for a powerful combination to help
+ fix even the most badly mismanaged repositories and turn them into nicely
+ structured Mercurial repositories. The branchmap contains lines of the
+ form:
+
+ original_branch_name new_branch_name
+
+ where "original_branch_name" is the name of the branch in the source
+ repository, and "new_branch_name" is the name of the branch is the
+ destination repository. No whitespace is allowed in the branch names. This
+ can be used to (for instance) move code in one repository from "default"
+ to a named branch.
+
+ Mercurial Source
+ ################
+
+ The Mercurial source recognizes the following configuration options, which
+ you can set on the command line with "--config":
+
+ convert.hg.ignoreerrors
+ ignore integrity errors when reading. Use it to fix
+ Mercurial repositories with missing revlogs, by converting
+ from and to Mercurial. Default is False.
+ convert.hg.saverev
+ store original revision ID in changeset (forces target IDs
+ to change). It takes a boolean argument and defaults to
+ False.
+ convert.hg.startrev
+ convert start revision and its descendants. It takes a hg
+ revision identifier and defaults to 0.
+
+ CVS Source
+ ##########
+
+ CVS source will use a sandbox (i.e. a checked-out copy) from CVS to
+ indicate the starting point of what will be converted. Direct access to
+ the repository files is not needed, unless of course the repository is
+ ":local:". The conversion uses the top level directory in the sandbox to
+ find the CVS repository, and then uses CVS rlog commands to find files to
+ convert. This means that unless a filemap is given, all files under the
+ starting directory will be converted, and that any directory
+ reorganization in the CVS sandbox is ignored.
+
+ The following options can be used with "--config":
+
+ convert.cvsps.cache
+ Set to False to disable remote log caching, for testing and
+ debugging purposes. Default is True.
+ convert.cvsps.fuzz
+ Specify the maximum time (in seconds) that is allowed
+ between commits with identical user and log message in a
+ single changeset. When very large files were checked in as
+ part of a changeset then the default may not be long enough.
+ The default is 60.
+ convert.cvsps.mergeto
+ Specify a regular expression to which commit log messages
+ are matched. If a match occurs, then the conversion process
+ will insert a dummy revision merging the branch on which
+ this log message occurs to the branch indicated in the
+ regex. Default is "{{mergetobranch ([-\w]+)}}"
+ convert.cvsps.mergefrom
+ Specify a regular expression to which commit log messages
+ are matched. If a match occurs, then the conversion process
+ will add the most recent revision on the branch indicated in
+ the regex as the second parent of the changeset. Default is
+ "{{mergefrombranch ([-\w]+)}}"
+ hook.cvslog Specify a Python function to be called at the end of
+ gathering the CVS log. The function is passed a list with
+ the log entries, and can modify the entries in-place, or add
+ or delete them.
+ hook.cvschangesets
+ Specify a Python function to be called after the changesets
+ are calculated from the CVS log. The function is passed a
+ list with the changeset entries, and can modify the
+ changesets in-place, or add or delete them.
+
+ An additional "debugcvsps" Mercurial command allows the builtin changeset
+ merging code to be run without doing a conversion. Its parameters and
+ output are similar to that of cvsps 2.1. Please see the command help for
+ more details.
+
+ Subversion Source
+ #################
+
+ Subversion source detects classical trunk/branches/tags layouts. By
+ default, the supplied "svn://repo/path/" source URL is converted as a
+ single branch. If "svn://repo/path/trunk" exists it replaces the default
+ branch. If "svn://repo/path/branches" exists, its subdirectories are
+ listed as possible branches. If "svn://repo/path/tags" exists, it is
+ looked for tags referencing converted branches. Default "trunk",
+ "branches" and "tags" values can be overridden with following options. Set
+ them to paths relative to the source URL, or leave them blank to disable
+ auto detection.
+
+ The following options can be set with "--config":
+
+ convert.svn.branches
+ specify the directory containing branches. The default is
+ "branches".
+ convert.svn.tags
+ specify the directory containing tags. The default is
+ "tags".
+ convert.svn.trunk
+ specify the name of the trunk branch. The default is
+ "trunk".
+
+ Source history can be retrieved starting at a specific revision, instead
+ of being integrally converted. Only single branch conversions are
+ supported.
+
+ convert.svn.startrev
+ specify start Subversion revision number. The default is 0.
+
+ Perforce Source
+ ###############
+
+ The Perforce (P4) importer can be given a p4 depot path or a client
+ specification as source. It will convert all files in the source to a flat
+ Mercurial repository, ignoring labels, branches and integrations. Note
+ that when a depot path is given you then usually should specify a target
+ directory, because otherwise the target may be named "...-hg".
+
+ It is possible to limit the amount of source history to be converted by
+ specifying an initial Perforce revision:
+
+ convert.p4.startrev
+ specify initial Perforce revision (a Perforce changelist
+ number).
+
+ Mercurial Destination
+ #####################
+
+ The following options are supported:
+
+ convert.hg.clonebranches
+ dispatch source branches in separate clones. The default is
+ False.
+ convert.hg.tagsbranch
+ branch name for tag revisions, defaults to "default".
+ convert.hg.usebranchnames
+ preserve branch names. The default is True.
+
+ options:
+
+ -s --source-type TYPE source repository type
+ -d --dest-type TYPE destination repository type
+ -r --rev REV import up to target revision REV
+ -A --authormap FILE remap usernames using this file
+ --filemap FILE remap file names using contents of file
+ --splicemap FILE splice synthesized history into place
+ --branchmap FILE change branch names while converting
+ --branchsort try to sort changesets by branches
+ --datesort try to sort changesets by date
+ --sourcesort preserve source changesets order
+
+ use "hg -v help convert" to show more info
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg ci -d'0 0' -Ama
+ adding a
+ $ hg cp a b
+ $ hg ci -d'1 0' -mb
+ $ hg rm a
+ $ hg ci -d'2 0' -mc
+ $ hg mv b a
+ $ hg ci -d'3 0' -md
+ $ echo a >> a
+ $ hg ci -d'4 0' -me
+ $ cd ..
+ $ hg convert a 2>&1 | grep -v 'subversion python bindings could not be loaded'
+ assuming destination a-hg
+ initializing destination a-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 4 a
+ 3 b
+ 2 c
+ 1 d
+ 0 e
+ $ hg --cwd a-hg pull ../a
+ pulling from ../a
+ searching for changes
+ no changes found
+
+conversion to existing file should fail
+
+ $ touch bogusfile
+ $ hg convert a bogusfile
+ initializing destination bogusfile repository
+ abort: cannot create new bundle repository
+ [255]
+
+#if unix-permissions
+
+conversion to dir without permissions should fail
+
+ $ mkdir bogusdir
+ $ chmod 000 bogusdir
+
+ $ hg convert a bogusdir
+ abort: Permission denied: bogusdir
+ [255]
+
+user permissions should succeed
+
+ $ chmod 700 bogusdir
+ $ hg convert a bogusdir
+ initializing destination bogusdir repository
+ scanning source...
+ sorting...
+ converting...
+ 4 a
+ 3 b
+ 2 c
+ 1 d
+ 0 e
+
+#endif
+
+test pre and post conversion actions
+
+ $ echo 'include b' > filemap
+ $ hg convert --debug --filemap filemap a partialb | \
+ > grep 'run hg'
+ run hg source pre-conversion action
+ run hg sink pre-conversion action
+ run hg sink post-conversion action
+ run hg source post-conversion action
+
+converting empty dir should fail "nicely
+
+ $ mkdir emptydir
+
+override $PATH to ensure p4 not visible; use $PYTHON in case we're
+running from a devel copy, not a temp installation
+
+ $ PATH="$BINDIR" $PYTHON "$BINDIR"/hg convert emptydir
+ assuming destination emptydir-hg
+ initializing destination emptydir-hg repository
+ emptydir does not look like a CVS checkout
+ emptydir does not look like a Git repository
+ emptydir does not look like a Subversion repository
+ emptydir is not a local Mercurial repository
+ emptydir does not look like a darcs repository
+ emptydir does not look like a monotone repository
+ emptydir does not look like a GNU Arch repository
+ emptydir does not look like a Bazaar repository
+ cannot find required "p4" tool
+ abort: emptydir: missing or unsupported repository
+ [255]
+
+convert with imaginary source type
+
+ $ hg convert --source-type foo a a-foo
+ initializing destination a-foo repository
+ abort: foo: invalid source repository type
+ [255]
+
+convert with imaginary sink type
+
+ $ hg convert --dest-type foo a a-foo
+ abort: foo: invalid destination repository type
+ [255]
+
+testing: convert must not produce duplicate entries in fncache
+
+ $ hg convert a b
+ initializing destination b repository
+ scanning source...
+ sorting...
+ converting...
+ 4 a
+ 3 b
+ 2 c
+ 1 d
+ 0 e
+
+contents of fncache file:
+
+ $ cat b/.hg/store/fncache | sort
+ data/a.i
+ data/b.i
+
+test bogus URL
+
+ $ hg convert -q bzr+ssh://foobar@selenic.com/baz baz
+ abort: bzr+ssh://foobar@selenic.com/baz: missing or unsupported repository
+ [255]
+
+test revset converted() lookup
+
+ $ hg --config convert.hg.saverev=True convert a c
+ initializing destination c repository
+ scanning source...
+ sorting...
+ converting...
+ 4 a
+ 3 b
+ 2 c
+ 1 d
+ 0 e
+ $ echo f > c/f
+ $ hg -R c ci -d'0 0' -Amf
+ adding f
+ created new head
+ $ hg -R c log -r "converted(09d945a62ce6)"
+ changeset: 1:98c3dd46a874
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b
+
+ $ hg -R c log -r "converted()"
+ changeset: 0:31ed57b2037c
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ changeset: 1:98c3dd46a874
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b
+
+ changeset: 2:3b9ca06ef716
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: c
+
+ changeset: 3:4e0debd37cf2
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: d
+
+ changeset: 4:9de3bc9349c5
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: e
+
diff --git a/tests/test-copy-move-merge.t b/tests/test-copy-move-merge.t
new file mode 100644
index 0000000..cc64b4c
--- /dev/null
+++ b/tests/test-copy-move-merge.t
@@ -0,0 +1,64 @@
+ $ hg init t
+ $ cd t
+
+ $ echo 1 > a
+ $ hg ci -qAm "first"
+
+ $ hg cp a b
+ $ hg mv a c
+ $ echo 2 >> b
+ $ echo 2 >> c
+
+ $ hg ci -qAm "second"
+
+ $ hg co -C 0
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+ $ echo 0 > a
+ $ echo 1 >> a
+
+ $ hg ci -qAm "other"
+
+ $ hg merge --debug
+ searching for copies back to rev 1
+ unmatched files in other:
+ b
+ c
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ c -> a *
+ b -> a *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: b8bf91eeebbc, local: add3f11052fa+, remote: 17c05bb7fcb6
+ a: remote moved to c -> m
+ a: remote moved to b -> m
+ preserving a for resolve of b
+ preserving a for resolve of c
+ removing a
+ updating: a 1/2 files (50.00%)
+ picked tool 'internal:merge' for b (binary False symlink False)
+ merging a and b to b
+ my b@add3f11052fa+ other b@17c05bb7fcb6 ancestor a@b8bf91eeebbc
+ premerge successful
+ updating: a 2/2 files (100.00%)
+ picked tool 'internal:merge' for c (binary False symlink False)
+ merging a and c to c
+ my c@add3f11052fa+ other c@17c05bb7fcb6 ancestor a@b8bf91eeebbc
+ premerge successful
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+file b
+ $ cat b
+ 0
+ 1
+ 2
+
+file c
+ $ cat c
+ 0
+ 1
+ 2
+
+ $ cd ..
diff --git a/tests/test-copy.t b/tests/test-copy.t
new file mode 100644
index 0000000..a3cd463
--- /dev/null
+++ b/tests/test-copy.t
@@ -0,0 +1,216 @@
+
+ $ mkdir part1
+ $ cd part1
+
+ $ hg init
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m "1"
+ $ hg status
+ $ hg copy a b
+ $ hg --config ui.portablefilenames=abort copy a con.xml
+ abort: filename contains 'con', which is reserved on Windows: 'con.xml'
+ [255]
+ $ hg status
+ A b
+ $ hg sum
+ parent: 0:c19d34741b0a tip
+ 1
+ branch: default
+ commit: 1 copied
+ update: (current)
+ $ hg --debug commit -m "2"
+ b
+ b: copy a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
+ committed changeset 1:93580a2c28a50a56f63526fb305067e6fbf739c4
+
+we should see two history entries
+
+ $ hg history -v
+ changeset: 1:93580a2c28a5
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: b
+ description:
+ 2
+
+
+ changeset: 0:c19d34741b0a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: a
+ description:
+ 1
+
+
+
+we should see one log entry for a
+
+ $ hg log a
+ changeset: 0:c19d34741b0a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+
+this should show a revision linked to changeset 0
+
+ $ hg debugindex a
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 0 b789fdd96dc2 000000000000 000000000000 (re)
+
+we should see one log entry for b
+
+ $ hg log b
+ changeset: 1:93580a2c28a5
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+
+this should show a revision linked to changeset 1
+
+ $ hg debugindex b
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 65 ..... 1 37d9b5d994ea 000000000000 000000000000 (re)
+
+this should show the rename information in the metadata
+
+ $ hg debugdata b 0 | head -3 | tail -2
+ copy: a
+ copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
+
+ $ "$TESTDIR/md5sum.py" .hg/store/data/b.i
+ 4999f120a3b88713bbefddd195cf5133 .hg/store/data/b.i
+ $ hg cat b > bsum
+ $ "$TESTDIR/md5sum.py" bsum
+ 60b725f10c9c85c70d97880dfe8191b3 bsum
+ $ hg cat a > asum
+ $ "$TESTDIR/md5sum.py" asum
+ 60b725f10c9c85c70d97880dfe8191b3 asum
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 2 changesets, 2 total revisions
+
+ $ cd ..
+
+
+ $ mkdir part2
+ $ cd part2
+
+ $ hg init
+ $ echo foo > foo
+should fail - foo is not managed
+ $ hg mv foo bar
+ foo: not copying - file is not managed
+ abort: no files to copy
+ [255]
+ $ hg st -A
+ ? foo
+ $ hg add foo
+dry-run; print a warning that this is not a real copy; foo is added
+ $ hg mv --dry-run foo bar
+ foo has not been committed yet, so no copy data will be stored for bar.
+ $ hg st -A
+ A foo
+should print a warning that this is not a real copy; bar is added
+ $ hg mv foo bar
+ foo has not been committed yet, so no copy data will be stored for bar.
+ $ hg st -A
+ A bar
+should print a warning that this is not a real copy; foo is added
+ $ hg cp bar foo
+ bar has not been committed yet, so no copy data will be stored for foo.
+ $ hg rm -f bar
+ $ rm bar
+ $ hg st -A
+ A foo
+ $ hg commit -m1
+
+moving a missing file
+ $ rm foo
+ $ hg mv foo foo3
+ foo: deleted in working copy
+ foo3 does not exist!
+ $ hg up -qC .
+
+copy --after to a nonexistant target filename
+ $ hg cp -A foo dummy
+ foo: not recording copy - dummy does not exist
+
+dry-run; should show that foo is clean
+ $ hg copy --dry-run foo bar
+ $ hg st -A
+ C foo
+should show copy
+ $ hg copy foo bar
+ $ hg st -C
+ A bar
+ foo
+
+shouldn't show copy
+ $ hg commit -m2
+ $ hg st -C
+
+should match
+ $ hg debugindex foo
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 5 ..... 0 2ed2a3912a0b 000000000000 000000000000 (re)
+ $ hg debugrename bar
+ bar renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
+
+ $ echo bleah > foo
+ $ echo quux > bar
+ $ hg commit -m3
+
+should not be renamed
+ $ hg debugrename bar
+ bar not renamed
+
+ $ hg copy -f foo bar
+should show copy
+ $ hg st -C
+ M bar
+ foo
+ $ hg commit -m3
+
+should show no parents for tip
+ $ hg debugindex bar
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 69 ..... 1 7711d36246cc 000000000000 000000000000 (re)
+ 1 69 6 ..... 2 bdf70a2b8d03 7711d36246cc 000000000000 (re)
+ 2 75 81 ..... 3 b2558327ea8d 000000000000 000000000000 (re)
+should match
+ $ hg debugindex foo
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 5 ..... 0 2ed2a3912a0b 000000000000 000000000000 (re)
+ 1 5 7 ..... 2 dd12c926cf16 2ed2a3912a0b 000000000000 (re)
+ $ hg debugrename bar
+ bar renamed from foo:dd12c926cf165e3eb4cf87b084955cb617221c17
+
+should show no copies
+ $ hg st -C
+
+copy --after on an added file
+ $ cp bar baz
+ $ hg add baz
+ $ hg cp -A bar baz
+ $ hg st -C
+ A baz
+ bar
+
+foo was clean:
+ $ hg st -AC foo
+ C foo
+but it's considered modified after a copy --after --force
+ $ hg copy -Af bar foo
+ $ hg st -AC foo
+ M foo
+ bar
+
+ $ cd ..
diff --git a/tests/test-custom-filters.t b/tests/test-custom-filters.t
new file mode 100644
index 0000000..cd4acdf
--- /dev/null
+++ b/tests/test-custom-filters.t
@@ -0,0 +1,66 @@
+ $ hg init
+
+ $ cat > .hg/hgrc <<EOF
+ > [extensions]
+ > prefixfilter = prefix.py
+ > [encode]
+ > *.txt = stripprefix: Copyright 2046, The Masters
+ > [decode]
+ > *.txt = insertprefix: Copyright 2046, The Masters
+ > EOF
+
+ $ cat > prefix.py <<EOF
+ > from mercurial import util
+ > def stripprefix(s, cmd, filename, **kwargs):
+ > header = '%s\n' % cmd
+ > if s[:len(header)] != header:
+ > raise util.Abort('missing header "%s" in %s' % (cmd, filename))
+ > return s[len(header):]
+ > def insertprefix(s, cmd):
+ > return '%s\n%s' % (cmd, s)
+ > def reposetup(ui, repo):
+ > repo.adddatafilter('stripprefix:', stripprefix)
+ > repo.adddatafilter('insertprefix:', insertprefix)
+ > EOF
+
+ $ cat > .hgignore <<EOF
+ > .hgignore
+ > prefix.py
+ > prefix.pyc
+ > EOF
+
+ $ cat > stuff.txt <<EOF
+ > Copyright 2046, The Masters
+ > Some stuff to ponder very carefully.
+ > EOF
+ $ hg add stuff.txt
+ $ hg ci -m stuff
+
+Repository data:
+
+ $ hg cat stuff.txt
+ Some stuff to ponder very carefully.
+
+Fresh checkout:
+
+ $ rm stuff.txt
+ $ hg up -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat stuff.txt
+ Copyright 2046, The Masters
+ Some stuff to ponder very carefully.
+ $ echo "Very very carefully." >> stuff.txt
+ $ hg stat
+ M stuff.txt
+
+ $ echo "Unauthorized material subject to destruction." > morestuff.txt
+
+Problem encoding:
+
+ $ hg add morestuff.txt
+ $ hg ci -m morestuff
+ abort: missing header "Copyright 2046, The Masters" in morestuff.txt
+ [255]
+ $ hg stat
+ M stuff.txt
+ A morestuff.txt
diff --git a/tests/test-debugbuilddag.t b/tests/test-debugbuilddag.t
new file mode 100644
index 0000000..e07941a
--- /dev/null
+++ b/tests/test-debugbuilddag.t
@@ -0,0 +1,350 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "graphlog=" >> $HGRCPATH
+
+plain
+
+ $ hg init
+ $ hg debugbuilddag '+2:f +3:p2 @temp <f+4 @default /p2 +2' \
+ > --config extensions.progress= --config progress.assume-tty=1 \
+ > --config progress.delay=0 --config progress.refresh=0 \
+ > --config progress.format=topic,bar,number \
+ > --config progress.width=60 2>&1 | \
+ > python "$TESTDIR/filtercr.py"
+
+ building [ ] 0/12
+ building [ ] 0/12
+ building [ ] 0/12
+ building [ ] 0/12
+ building [==> ] 1/12
+ building [==> ] 1/12
+ building [==> ] 1/12
+ building [==> ] 1/12
+ building [======> ] 2/12
+ building [======> ] 2/12
+ building [=========> ] 3/12
+ building [=========> ] 3/12
+ building [=============> ] 4/12
+ building [=============> ] 4/12
+ building [=============> ] 4/12
+ building [=============> ] 4/12
+ building [=============> ] 4/12
+ building [=============> ] 4/12
+ building [================> ] 5/12
+ building [================> ] 5/12
+ building [====================> ] 6/12
+ building [====================> ] 6/12
+ building [=======================> ] 7/12
+ building [=======================> ] 7/12
+ building [===========================> ] 8/12
+ building [===========================> ] 8/12
+ building [===========================> ] 8/12
+ building [===========================> ] 8/12
+ building [==============================> ] 9/12
+ building [==============================> ] 9/12
+ building [==================================> ] 10/12
+ building [==================================> ] 10/12
+ building [=====================================> ] 11/12
+ building [=====================================> ] 11/12
+ \r (esc)
+
+tags
+ $ cat .hg/localtags
+ 66f7d451a68b85ed82ff5fcc254daf50c74144bd f
+ bebd167eb94d257ace0e814aeb98e6972ed2970d p2
+dag
+ $ hg debugdag -t -b
+ +2:f
+ +3:p2
+ @temp*f+3
+ @default*/p2+2:tip
+tip
+ $ hg id
+ 000000000000
+glog
+ $ hg glog --template '{rev}: {desc} [{branches}] @ {date}\n'
+ o 11: r11 [] @ 11.00
+ |
+ o 10: r10 [] @ 10.00
+ |
+ o 9: r9 [] @ 9.00
+ |\
+ | o 8: r8 [temp] @ 8.00
+ | |
+ | o 7: r7 [temp] @ 7.00
+ | |
+ | o 6: r6 [temp] @ 6.00
+ | |
+ | o 5: r5 [temp] @ 5.00
+ | |
+ o | 4: r4 [] @ 4.00
+ | |
+ o | 3: r3 [] @ 3.00
+ | |
+ o | 2: r2 [] @ 2.00
+ |/
+ o 1: r1 [] @ 1.00
+ |
+ o 0: r0 [] @ 0.00
+
+
+overwritten files, starting on a non-default branch
+
+ $ rm -r .hg
+ $ hg init
+ $ hg debugbuilddag '@start.@default.:f +3:p2 @temp <f+4 @default /p2 +2' -q -o
+tags
+ $ cat .hg/localtags
+ f778700ebd50fcf282b23a4446bd155da6453eb6 f
+ bbccf169769006e2490efd2a02f11c3d38d462bd p2
+dag
+ $ hg debugdag -t -b
+ @start+1
+ @default+1:f
+ +3:p2
+ @temp*f+3
+ @default*/p2+2:tip
+tip
+ $ hg id
+ 000000000000
+glog
+ $ hg glog --template '{rev}: {desc} [{branches}] @ {date}\n'
+ o 11: r11 [] @ 11.00
+ |
+ o 10: r10 [] @ 10.00
+ |
+ o 9: r9 [] @ 9.00
+ |\
+ | o 8: r8 [temp] @ 8.00
+ | |
+ | o 7: r7 [temp] @ 7.00
+ | |
+ | o 6: r6 [temp] @ 6.00
+ | |
+ | o 5: r5 [temp] @ 5.00
+ | |
+ o | 4: r4 [] @ 4.00
+ | |
+ o | 3: r3 [] @ 3.00
+ | |
+ o | 2: r2 [] @ 2.00
+ |/
+ o 1: r1 [] @ 1.00
+ |
+ o 0: r0 [start] @ 0.00
+
+glog of
+ $ hg glog --template '{rev}: {desc} [{branches}]\n' of
+ o 11: r11 []
+ |
+ o 10: r10 []
+ |
+ o 9: r9 []
+ |\
+ | o 8: r8 [temp]
+ | |
+ | o 7: r7 [temp]
+ | |
+ | o 6: r6 [temp]
+ | |
+ | o 5: r5 [temp]
+ | |
+ o | 4: r4 []
+ | |
+ o | 3: r3 []
+ | |
+ o | 2: r2 []
+ |/
+ o 1: r1 []
+ |
+ o 0: r0 [start]
+
+tags
+ $ hg tags -v
+ tip 11:9ffe238a67a2
+ p2 4:bbccf1697690 local
+ f 1:f778700ebd50 local
+cat of
+ $ hg cat of --rev tip
+ r11
+
+
+new and mergeable files
+
+ $ rm -r .hg
+ $ hg init
+ $ hg debugbuilddag '+2:f +3:p2 @temp <f+4 @default /p2 +2' -q -mn
+dag
+ $ hg debugdag -t -b
+ +2:f
+ +3:p2
+ @temp*f+3
+ @default*/p2+2:tip
+tip
+ $ hg id
+ 000000000000
+glog
+ $ hg glog --template '{rev}: {desc} [{branches}] @ {date}\n'
+ o 11: r11 [] @ 11.00
+ |
+ o 10: r10 [] @ 10.00
+ |
+ o 9: r9 [] @ 9.00
+ |\
+ | o 8: r8 [temp] @ 8.00
+ | |
+ | o 7: r7 [temp] @ 7.00
+ | |
+ | o 6: r6 [temp] @ 6.00
+ | |
+ | o 5: r5 [temp] @ 5.00
+ | |
+ o | 4: r4 [] @ 4.00
+ | |
+ o | 3: r3 [] @ 3.00
+ | |
+ o | 2: r2 [] @ 2.00
+ |/
+ o 1: r1 [] @ 1.00
+ |
+ o 0: r0 [] @ 0.00
+
+glog mf
+ $ hg glog --template '{rev}: {desc} [{branches}]\n' mf
+ o 11: r11 []
+ |
+ o 10: r10 []
+ |
+ o 9: r9 []
+ |\
+ | o 8: r8 [temp]
+ | |
+ | o 7: r7 [temp]
+ | |
+ | o 6: r6 [temp]
+ | |
+ | o 5: r5 [temp]
+ | |
+ o | 4: r4 []
+ | |
+ o | 3: r3 []
+ | |
+ o | 2: r2 []
+ |/
+ o 1: r1 []
+ |
+ o 0: r0 []
+
+
+man r4
+ $ hg manifest -r4
+ mf
+ nf0
+ nf1
+ nf2
+ nf3
+ nf4
+cat r4 mf
+ $ hg cat -r4 mf
+ 0 r0
+ 1
+ 2 r1
+ 3
+ 4 r2
+ 5
+ 6 r3
+ 7
+ 8 r4
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+man r8
+ $ hg manifest -r8
+ mf
+ nf0
+ nf1
+ nf5
+ nf6
+ nf7
+ nf8
+cat r8 mf
+ $ hg cat -r8 mf
+ 0 r0
+ 1
+ 2 r1
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10 r5
+ 11
+ 12 r6
+ 13
+ 14 r7
+ 15
+ 16 r8
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+man
+ $ hg manifest --rev tip
+ mf
+ nf0
+ nf1
+ nf10
+ nf11
+ nf2
+ nf3
+ nf4
+ nf5
+ nf6
+ nf7
+ nf8
+ nf9
+cat mf
+ $ hg cat mf --rev tip
+ 0 r0
+ 1
+ 2 r1
+ 3
+ 4 r2
+ 5
+ 6 r3
+ 7
+ 8 r4
+ 9
+ 10 r5
+ 11
+ 12 r6
+ 13
+ 14 r7
+ 15
+ 16 r8
+ 17
+ 18 r9
+ 19
+ 20 r10
+ 21
+ 22 r11
+ 23
+
+
+
diff --git a/tests/test-debugbundle.t b/tests/test-debugbundle.t
new file mode 100644
index 0000000..4e911ea
--- /dev/null
+++ b/tests/test-debugbundle.t
@@ -0,0 +1,37 @@
+
+Create a test repository:
+
+ $ hg init repo
+ $ cd repo
+ $ touch a ; hg add a ; hg ci -ma
+ $ touch b ; hg add b ; hg ci -mb
+ $ touch c ; hg add c ; hg ci -mc
+ $ hg bundle --base 0 --rev tip bundle.hg
+ 2 changesets found
+
+Terse output:
+
+ $ hg debugbundle bundle.hg
+ 0e067c57feba1a5694ca4844f05588bb1bf82342
+ 991a3460af53952d10ec8a295d3d2cc2e5fa9690
+
+Verbose output:
+
+ $ hg debugbundle --all bundle.hg
+ format: id, p1, p2, cset, delta base, len(delta)
+
+ changelog
+ 0e067c57feba1a5694ca4844f05588bb1bf82342 3903775176ed42b1458a6281db4a0ccf4d9f287a 0000000000000000000000000000000000000000 0e067c57feba1a5694ca4844f05588bb1bf82342 3903775176ed42b1458a6281db4a0ccf4d9f287a 80
+ 991a3460af53952d10ec8a295d3d2cc2e5fa9690 0e067c57feba1a5694ca4844f05588bb1bf82342 0000000000000000000000000000000000000000 991a3460af53952d10ec8a295d3d2cc2e5fa9690 0e067c57feba1a5694ca4844f05588bb1bf82342 80
+
+ manifest
+ 686dbf0aeca417636fa26a9121c681eabbb15a20 8515d4bfda768e04af4c13a69a72e28c7effbea7 0000000000000000000000000000000000000000 0e067c57feba1a5694ca4844f05588bb1bf82342 8515d4bfda768e04af4c13a69a72e28c7effbea7 55
+ ae25a31b30b3490a981e7b96a3238cc69583fda1 686dbf0aeca417636fa26a9121c681eabbb15a20 0000000000000000000000000000000000000000 991a3460af53952d10ec8a295d3d2cc2e5fa9690 686dbf0aeca417636fa26a9121c681eabbb15a20 55
+
+ b
+ b80de5d138758541c5f05265ad144ab9fa86d1db 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0e067c57feba1a5694ca4844f05588bb1bf82342 0000000000000000000000000000000000000000 12
+
+ c
+ b80de5d138758541c5f05265ad144ab9fa86d1db 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 991a3460af53952d10ec8a295d3d2cc2e5fa9690 0000000000000000000000000000000000000000 12
+
+ $ cd ..
diff --git a/tests/test-debugcommands.t b/tests/test-debugcommands.t
new file mode 100644
index 0000000..ecd1eb1
--- /dev/null
+++ b/tests/test-debugcommands.t
@@ -0,0 +1,25 @@
+ $ hg init debugrevlog
+ $ cd debugrevlog
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ hg debugrevlog -m
+ format : 1
+ flags : inline
+
+ revisions : 1
+ merges : 0 ( 0.00%)
+ normal : 1 (100.00%)
+ revisions : 1
+ full : 1 (100.00%)
+ deltas : 0 ( 0.00%)
+ revision size : 44
+ full : 44 (100.00%)
+ deltas : 0 ( 0.00%)
+
+ avg chain length : 0
+ compression ratio : 0
+
+ uncompressed data size (min/max/avg) : 43 / 43 / 43
+ full revision size (min/max/avg) : 44 / 44 / 44
+ delta size (min/max/avg) : 0 / 0 / 0
diff --git a/tests/test-debugcomplete.t b/tests/test-debugcomplete.t
new file mode 100644
index 0000000..b23b23d
--- /dev/null
+++ b/tests/test-debugcomplete.t
@@ -0,0 +1,276 @@
+Show all commands except debug commands
+ $ hg debugcomplete
+ add
+ addremove
+ annotate
+ archive
+ backout
+ bisect
+ bookmarks
+ branch
+ branches
+ bundle
+ cat
+ clone
+ commit
+ copy
+ diff
+ export
+ forget
+ graft
+ grep
+ heads
+ help
+ identify
+ import
+ incoming
+ init
+ locate
+ log
+ manifest
+ merge
+ outgoing
+ parents
+ paths
+ phase
+ pull
+ push
+ recover
+ remove
+ rename
+ resolve
+ revert
+ rollback
+ root
+ serve
+ showconfig
+ status
+ summary
+ tag
+ tags
+ tip
+ unbundle
+ update
+ verify
+ version
+
+Show all commands that start with "a"
+ $ hg debugcomplete a
+ add
+ addremove
+ annotate
+ archive
+
+Do not show debug commands if there are other candidates
+ $ hg debugcomplete d
+ diff
+
+Show debug commands if there are no other candidates
+ $ hg debugcomplete debug
+ debugancestor
+ debugbuilddag
+ debugbundle
+ debugcheckstate
+ debugcommands
+ debugcomplete
+ debugconfig
+ debugdag
+ debugdata
+ debugdate
+ debugdiscovery
+ debugfileset
+ debugfsinfo
+ debuggetbundle
+ debugignore
+ debugindex
+ debugindexdot
+ debuginstall
+ debugknown
+ debugobsolete
+ debugpushkey
+ debugpvec
+ debugrebuildstate
+ debugrename
+ debugrevlog
+ debugrevspec
+ debugsetparents
+ debugstate
+ debugsub
+ debugwalk
+ debugwireargs
+
+Do not show the alias of a debug command if there are other candidates
+(this should hide rawcommit)
+ $ hg debugcomplete r
+ recover
+ remove
+ rename
+ resolve
+ revert
+ rollback
+ root
+Show the alias of a debug command if there are no other candidates
+ $ hg debugcomplete rawc
+
+
+Show the global options
+ $ hg debugcomplete --options | sort
+ --config
+ --cwd
+ --debug
+ --debugger
+ --encoding
+ --encodingmode
+ --help
+ --noninteractive
+ --profile
+ --quiet
+ --repository
+ --time
+ --traceback
+ --verbose
+ --version
+ -R
+ -h
+ -q
+ -v
+ -y
+
+Show the options for the "serve" command
+ $ hg debugcomplete --options serve | sort
+ --accesslog
+ --address
+ --certificate
+ --cmdserver
+ --config
+ --cwd
+ --daemon
+ --daemon-pipefds
+ --debug
+ --debugger
+ --encoding
+ --encodingmode
+ --errorlog
+ --help
+ --ipv6
+ --name
+ --noninteractive
+ --pid-file
+ --port
+ --prefix
+ --profile
+ --quiet
+ --repository
+ --stdio
+ --style
+ --templates
+ --time
+ --traceback
+ --verbose
+ --version
+ --web-conf
+ -6
+ -A
+ -E
+ -R
+ -a
+ -d
+ -h
+ -n
+ -p
+ -q
+ -t
+ -v
+ -y
+
+Show an error if we use --options with an ambiguous abbreviation
+ $ hg debugcomplete --options s
+ hg: command 's' is ambiguous:
+ serve showconfig status summary
+ [255]
+
+Show all commands + options
+ $ hg debugcommands
+ add: include, exclude, subrepos, dry-run
+ annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude
+ clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
+ commit: addremove, close-branch, amend, include, exclude, message, logfile, date, user, subrepos
+ diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
+ export: output, switch-parent, rev, text, git, nodates
+ forget: include, exclude
+ init: ssh, remotecmd, insecure
+ log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, hidden, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
+ merge: force, rev, preview, tool
+ phase: public, draft, secret, force, rev
+ pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
+ push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
+ remove: after, force, include, exclude
+ serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
+ status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
+ summary: remote
+ update: clean, check, date, rev
+ addremove: similarity, include, exclude, dry-run
+ archive: no-decode, prefix, rev, type, subrepos, include, exclude
+ backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
+ bisect: reset, good, bad, skip, extend, command, noupdate
+ bookmarks: force, rev, delete, rename, inactive
+ branch: force, clean
+ branches: active, closed
+ bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
+ cat: output, rev, decode, include, exclude
+ copy: after, force, include, exclude, dry-run
+ debugancestor:
+ debugbuilddag: mergeable-file, overwritten-file, new-file
+ debugbundle: all
+ debugcheckstate:
+ debugcommands:
+ debugcomplete: options
+ debugdag: tags, branches, dots, spaces
+ debugdata: changelog, manifest
+ debugdate: extended
+ debugdiscovery: old, nonheads, ssh, remotecmd, insecure
+ debugfileset:
+ debugfsinfo:
+ debuggetbundle: head, common, type
+ debugignore:
+ debugindex: changelog, manifest, format
+ debugindexdot:
+ debuginstall:
+ debugknown:
+ debugobsolete: date, user
+ debugpushkey:
+ debugpvec:
+ debugrebuildstate: rev
+ debugrename: rev
+ debugrevlog: changelog, manifest, dump
+ debugrevspec:
+ debugsetparents:
+ debugstate: nodates, datesort
+ debugsub: rev
+ debugwalk: include, exclude
+ debugwireargs: three, four, five, ssh, remotecmd, insecure
+ graft: rev, continue, edit, log, currentdate, currentuser, date, user, tool, dry-run
+ grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
+ heads: rev, topo, active, closed, style, template
+ help: extension, command, keyword
+ identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
+ import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
+ incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
+ locate: rev, print0, fullpath, include, exclude
+ manifest: rev, all
+ outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
+ parents: rev, style, template
+ paths:
+ recover:
+ rename: after, force, include, exclude, dry-run
+ resolve: all, list, mark, unmark, no-status, tool, include, exclude
+ revert: all, date, rev, no-backup, include, exclude, dry-run
+ rollback: dry-run, force
+ root:
+ showconfig: untrusted
+ tag: force, local, rev, remove, edit, message, date, user
+ tags:
+ tip: patch, git, style, template
+ unbundle: update
+ verify:
+ version:
diff --git a/tests/test-debugindexdot.t b/tests/test-debugindexdot.t
new file mode 100644
index 0000000..98ee015
--- /dev/null
+++ b/tests/test-debugindexdot.t
@@ -0,0 +1,25 @@
+Just exercize debugindexdot
+Create a short file history including a merge.
+ $ hg init t
+ $ cd t
+ $ echo a > a
+ $ hg ci -qAm t1 -d '0 0'
+ $ echo a >> a
+ $ hg ci -m t2 -d '1 0'
+ $ hg up -qC 0
+ $ echo b >> a
+ $ hg ci -m t3 -d '2 0'
+ created new head
+ $ HGMERGE=true hg merge -q
+ $ hg ci -m merge -d '3 0'
+
+ $ hg debugindexdot .hg/store/data/a.i
+ digraph G {
+ -1 -> 0
+ 0 -> 1
+ 0 -> 2
+ 2 -> 3
+ 1 -> 3
+ }
+
+ $ cd ..
diff --git a/tests/test-debugrename.t b/tests/test-debugrename.t
new file mode 100644
index 0000000..59f3518
--- /dev/null
+++ b/tests/test-debugrename.t
@@ -0,0 +1,18 @@
+ $ hg init
+ $ echo a > a
+ $ hg ci -Am t
+ adding a
+
+ $ hg mv a b
+ $ hg ci -Am t1
+ $ hg debugrename b
+ b renamed from a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
+
+ $ hg mv b a
+ $ hg ci -Am t2
+ $ hg debugrename a
+ a renamed from b:37d9b5d994eab34eda9c16b195ace52c7b129980
+
+ $ hg debugrename --rev 1 b
+ b renamed from a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
+
diff --git a/tests/test-default-push.t b/tests/test-default-push.t
new file mode 100644
index 0000000..5c7d492
--- /dev/null
+++ b/tests/test-default-push.t
@@ -0,0 +1,38 @@
+ $ hg init a
+
+ $ echo a > a/a
+ $ hg --cwd a ci -Ama
+ adding a
+
+ $ hg clone a c
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg clone a b
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo b >> b/a
+ $ hg --cwd b ci -mb
+
+Push should push to 'default' when 'default-push' not set:
+
+ $ hg --cwd b push
+ pushing to $TESTTMP/a (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+Push should push to 'default-push' when set:
+
+ $ echo 'default-push = ../c' >> b/.hg/hgrc
+ $ hg --cwd b push
+ pushing to $TESTTMP/c (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
diff --git a/tests/test-demandimport.py b/tests/test-demandimport.py
new file mode 100644
index 0000000..59bc4f2
--- /dev/null
+++ b/tests/test-demandimport.py
@@ -0,0 +1,39 @@
+from mercurial import demandimport
+demandimport.enable()
+
+import re
+
+rsub = re.sub
+def f(obj):
+ l = repr(obj)
+ l = rsub("0x[0-9a-fA-F]+", "0x?", l)
+ l = rsub("from '.*'", "from '?'", l)
+ l = rsub("'<[a-z]*>'", "'<whatever>'", l)
+ return l
+
+import os
+
+print "os =", f(os)
+print "os.system =", f(os.system)
+print "os =", f(os)
+
+from mercurial import util
+
+print "util =", f(util)
+print "util.system =", f(util.system)
+print "util =", f(util)
+print "util.system =", f(util.system)
+
+import re as fred
+print "fred =", f(fred)
+
+import sys as re
+print "re =", f(re)
+
+print "fred =", f(fred)
+print "fred.sub =", f(fred.sub)
+print "fred =", f(fred)
+
+print "re =", f(re)
+print "re.stderr =", f(re.stderr)
+print "re =", f(re)
diff --git a/tests/test-demandimport.py.out b/tests/test-demandimport.py.out
new file mode 100644
index 0000000..c024e5d
--- /dev/null
+++ b/tests/test-demandimport.py.out
@@ -0,0 +1,15 @@
+os = <unloaded module 'os'>
+os.system = <built-in function system>
+os = <module 'os' from '?'>
+util = <unloaded module 'util'>
+util.system = <function system at 0x?>
+util = <module 'mercurial.util' from '?'>
+util.system = <function system at 0x?>
+fred = <unloaded module 're'>
+re = <unloaded module 'sys'>
+fred = <unloaded module 're'>
+fred.sub = <function sub at 0x?>
+fred = <proxied module 're'>
+re = <unloaded module 'sys'>
+re.stderr = <open file '<whatever>', mode 'w' at 0x?>
+re = <proxied module 'sys'>
diff --git a/tests/test-diff-binary-file.t b/tests/test-diff-binary-file.t
new file mode 100644
index 0000000..eac24c9
--- /dev/null
+++ b/tests/test-diff-binary-file.t
@@ -0,0 +1,40 @@
+ $ hg init a
+ $ cd a
+ $ cp "$TESTDIR/binfile.bin" .
+ $ hg add binfile.bin
+ $ hg ci -m 'add binfile.bin'
+
+ $ echo >> binfile.bin
+ $ hg ci -m 'change binfile.bin'
+
+ $ hg revert -r 0 binfile.bin
+ $ hg ci -m 'revert binfile.bin'
+
+ $ hg diff --nodates -r 0 -r 1
+ diff -r 48b371597640 -r acea2ab458c8 binfile.bin
+ Binary file binfile.bin has changed
+
+ $ hg diff --nodates -r 0 -r 2
+
+ $ hg diff --git -r 0 -r 1
+ diff --git a/binfile.bin b/binfile.bin
+ index 37ba3d1c6f17137d9c5f5776fa040caf5fe73ff9..58dc31a9e2f40f74ff3b45903f7d620b8e5b7356
+ GIT binary patch
+ literal 594
+ zc$@)J0<HatP)<h;3K|Lk000e1NJLTq000mG000mO0ssI2kdbIM00009a7bBm000XU
+ z000XU0RWnu7ytkO2XskIMF-Uh9TW;VpMjwv0005-Nkl<ZD9@FWPs=e;7{<>W$NUkd
+ zX$nnYLt$-$V!?uy+1V%`z&Eh=ah|duER<4|QWhju3gb^nF*8iYobxWG-qqXl=2~5M
+ z*IoDB)sG^CfNuoBmqLTVU^<;@nwHP!1wrWd`{(mHo6VNXWtyh{alzqmsH*yYzpvLT
+ zLdY<T=ks|woh-`&01!ej#(xbV1f|pI*=%;d-%F*E*X#ZH`4I%6SS+$EJDE&ct=8po
+ ziN#{?_j|kD%Cd|oiqds`xm@;oJ-^?NG3Gdqrs?5u*zI;{nogxsx~^|Fn^Y?Gdc6<;
+ zfMJ+iF1J`LMx&A2?dEwNW8ClebzPTbIh{@$hS6*`kH@1d%Lo7fA#}N1)oN7`gm$~V
+ z+wDx#)OFqMcE{s!JN0-xhG8ItAjVkJwEcb`3WWlJfU2r?;Pd%dmR+q@mSri5q9_W-
+ zaR2~ECX?B2w+zELozC0s*6Z~|QG^f{3I#<`?)Q7U-JZ|q5W;9Q8i_=pBuSzunx=U;
+ z9C)5jBoYw9^?EHyQl(M}1OlQcCX>lXB*ODN003Z&P17_@)3Pi=i0wb04<W?v-u}7K
+ zXmmQA+wDgE!qR9o8jr`%=ab_&uh(l?R=r;Tjiqon91I2-hIu?57~@*4h7h9uORK#=
+ gQItJW-{SoTm)8|5##k|m00000NkvXXu0mjf3JwksH2?qr
+
+
+ $ hg diff --git -r 0 -r 2
+
+ $ cd ..
diff --git a/tests/test-diff-change.t b/tests/test-diff-change.t
new file mode 100644
index 0000000..05d34ad
--- /dev/null
+++ b/tests/test-diff-change.t
@@ -0,0 +1,93 @@
+Testing diff --change
+
+ $ hg init a
+ $ cd a
+
+ $ echo "first" > file.txt
+ $ hg add file.txt
+ $ hg commit -m 'first commit' # 0
+
+ $ echo "second" > file.txt
+ $ hg commit -m 'second commit' # 1
+
+ $ echo "third" > file.txt
+ $ hg commit -m 'third commit' # 2
+
+ $ hg diff --nodates --change 1
+ diff -r 4bb65dda5db4 -r e9b286083166 file.txt
+ --- a/file.txt
+ +++ b/file.txt
+ @@ -1,1 +1,1 @@
+ -first
+ +second
+
+ $ hg diff --change e9b286083166
+ diff -r 4bb65dda5db4 -r e9b286083166 file.txt
+ --- a/file.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/file.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,1 @@
+ -first
+ +second
+
+Test dumb revspecs (issue3474)
+
+ $ hg diff -r 2:2
+ $ hg diff -r "2 and 1"
+ abort: empty revision range
+ [255]
+
+Testing diff --change when merge:
+
+ $ for i in 1 2 3 4 5 6 7 8 9 10; do
+ > echo $i >> file.txt
+ > done
+ $ hg commit -m "lots of text" # 3
+
+ $ sed -e 's,^2$,x,' file.txt > file.txt.tmp
+ $ mv file.txt.tmp file.txt
+ $ hg commit -m "change 2 to x" # 4
+
+ $ hg up -r 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ sed -e 's,^8$,y,' file.txt > file.txt.tmp
+ $ mv file.txt.tmp file.txt
+ $ hg commit -m "change 8 to y"
+ created new head
+
+ $ hg up -C -r 4
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge -r 5
+ merging file.txt
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -m "merge 8 to y" # 6
+
+ $ hg diff --change 5
+ diff -r ae119d680c82 -r 9085c5c02e52 file.txt
+ --- a/file.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/file.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -6,6 +6,6 @@
+ 5
+ 6
+ 7
+ -8
+ +y
+ 9
+ 10
+
+must be similar to 'hg diff --change 5':
+
+ $ hg diff -c 6
+ diff -r 273b50f17c6d -r 979ca961fd2e file.txt
+ --- a/file.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/file.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -6,6 +6,6 @@
+ 5
+ 6
+ 7
+ -8
+ +y
+ 9
+ 10
+
+ $ cd ..
diff --git a/tests/test-diff-color.t b/tests/test-diff-color.t
new file mode 100644
index 0000000..fe898d9
--- /dev/null
+++ b/tests/test-diff-color.t
@@ -0,0 +1,130 @@
+Setup
+
+ $ echo "[color]" >> $HGRCPATH
+ $ echo "mode = ansi" >> $HGRCPATH
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "color=" >> $HGRCPATH
+ $ hg init repo
+ $ cd repo
+ $ cat > a <<EOF
+ > c
+ > c
+ > a
+ > a
+ > b
+ > a
+ > a
+ > c
+ > c
+ > EOF
+ $ hg ci -Am adda
+ adding a
+ $ cat > a <<EOF
+ > c
+ > c
+ > a
+ > a
+ > dd
+ > a
+ > a
+ > c
+ > c
+ > EOF
+
+default context
+
+ $ hg diff --nodates --color=always
+ \x1b[0;1mdiff -r cf9f4ba66af2 a\x1b[0m (esc)
+ \x1b[0;31;1m--- a/a\x1b[0m (esc)
+ \x1b[0;32;1m+++ b/a\x1b[0m (esc)
+ \x1b[0;35m@@ -2,7 +2,7 @@\x1b[0m (esc)
+ c
+ a
+ a
+ \x1b[0;31m-b\x1b[0m (esc)
+ \x1b[0;32m+dd\x1b[0m (esc)
+ a
+ a
+ c
+
+--unified=2
+
+ $ hg diff --nodates -U 2 --color=always
+ \x1b[0;1mdiff -r cf9f4ba66af2 a\x1b[0m (esc)
+ \x1b[0;31;1m--- a/a\x1b[0m (esc)
+ \x1b[0;32;1m+++ b/a\x1b[0m (esc)
+ \x1b[0;35m@@ -3,5 +3,5 @@\x1b[0m (esc)
+ a
+ a
+ \x1b[0;31m-b\x1b[0m (esc)
+ \x1b[0;32m+dd\x1b[0m (esc)
+ a
+ a
+
+diffstat
+
+ $ hg diff --stat --color=always
+ a | 2 \x1b[0;32m+\x1b[0m\x1b[0;31m-\x1b[0m (esc)
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+ $ echo "record=" >> $HGRCPATH
+ $ echo "[ui]" >> $HGRCPATH
+ $ echo "interactive=true" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "git=True" >> $HGRCPATH
+
+#if execbit
+
+record
+
+ $ chmod +x a
+ $ hg record --color=always -m moda a <<EOF
+ > y
+ > y
+ > EOF
+ \x1b[0;1mdiff --git a/a b/a\x1b[0m (esc)
+ \x1b[0;36;1mold mode 100644\x1b[0m (esc)
+ \x1b[0;36;1mnew mode 100755\x1b[0m (esc)
+ 1 hunks, 1 lines changed
+ \x1b[0;33mexamine changes to 'a'? [Ynesfdaq?]\x1b[0m (esc)
+ \x1b[0;35m@@ -2,7 +2,7 @@\x1b[0m (esc)
+ c
+ a
+ a
+ \x1b[0;31m-b\x1b[0m (esc)
+ \x1b[0;32m+dd\x1b[0m (esc)
+ a
+ a
+ c
+ \x1b[0;33mrecord this change to 'a'? [Ynesfdaq?]\x1b[0m (esc)
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ hg rollback
+ repository tip rolled back to revision 0 (undo commit)
+ working directory now based on revision 0
+
+qrecord
+
+ $ hg qrecord --color=always -m moda patch <<EOF
+ > y
+ > y
+ > EOF
+ \x1b[0;1mdiff --git a/a b/a\x1b[0m (esc)
+ \x1b[0;36;1mold mode 100644\x1b[0m (esc)
+ \x1b[0;36;1mnew mode 100755\x1b[0m (esc)
+ 1 hunks, 1 lines changed
+ \x1b[0;33mexamine changes to 'a'? [Ynesfdaq?]\x1b[0m (esc)
+ \x1b[0;35m@@ -2,7 +2,7 @@\x1b[0m (esc)
+ c
+ a
+ a
+ \x1b[0;31m-b\x1b[0m (esc)
+ \x1b[0;32m+dd\x1b[0m (esc)
+ a
+ a
+ c
+ \x1b[0;33mrecord this change to 'a'? [Ynesfdaq?]\x1b[0m (esc)
+
+#endif
+
+ $ cd ..
diff --git a/tests/test-diff-copy-depth.t b/tests/test-diff-copy-depth.t
new file mode 100644
index 0000000..6c7061f
--- /dev/null
+++ b/tests/test-diff-copy-depth.t
@@ -0,0 +1,51 @@
+ $ for i in aaa zzz; do
+ > hg init t
+ > cd t
+ >
+ > echo
+ > echo "-- With $i"
+ >
+ > touch file
+ > hg add file
+ > hg ci -m "Add"
+ >
+ > hg cp file $i
+ > hg ci -m "a -> $i"
+ >
+ > hg cp $i other-file
+ > echo "different" >> $i
+ > hg ci -m "$i -> other-file"
+ >
+ > hg cp other-file somename
+ >
+ > echo "Status":
+ > hg st -C
+ > echo
+ > echo "Diff:"
+ > hg diff -g
+ >
+ > cd ..
+ > rm -rf t
+ > done
+
+ -- With aaa
+ Status:
+ A somename
+ other-file
+
+ Diff:
+ diff --git a/other-file b/somename
+ copy from other-file
+ copy to somename
+
+ -- With zzz
+ Status:
+ A somename
+ other-file
+
+ Diff:
+ diff --git a/other-file b/somename
+ copy from other-file
+ copy to somename
+
+
diff --git a/tests/test-diff-hashes.t b/tests/test-diff-hashes.t
new file mode 100644
index 0000000..718f46e
--- /dev/null
+++ b/tests/test-diff-hashes.t
@@ -0,0 +1,46 @@
+ $ hg init a
+ $ cd a
+
+ $ hg diff inexistent1 inexistent2
+ inexistent1: * (glob)
+ inexistent2: * (glob)
+
+ $ echo bar > foo
+ $ hg add foo
+ $ hg ci -m 'add foo'
+
+ $ echo foobar > foo
+ $ hg ci -m 'change foo'
+
+ $ hg --quiet diff -r 0 -r 1
+ --- a/foo Thu Jan 01 00:00:00 1970 +0000
+ +++ b/foo Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,1 @@
+ -bar
+ +foobar
+
+ $ hg diff -r 0 -r 1
+ diff -r a99fb63adac3 -r 9b8568d3af2f foo
+ --- a/foo Thu Jan 01 00:00:00 1970 +0000
+ +++ b/foo Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,1 @@
+ -bar
+ +foobar
+
+ $ hg --verbose diff -r 0 -r 1
+ diff -r a99fb63adac3 -r 9b8568d3af2f foo
+ --- a/foo Thu Jan 01 00:00:00 1970 +0000
+ +++ b/foo Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,1 @@
+ -bar
+ +foobar
+
+ $ hg --debug diff -r 0 -r 1
+ diff -r a99fb63adac3f31816a22f665bc3b7a7655b30f4 -r 9b8568d3af2f1749445eef03aede868a6f39f210 foo
+ --- a/foo Thu Jan 01 00:00:00 1970 +0000
+ +++ b/foo Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,1 @@
+ -bar
+ +foobar
+
+ $ cd ..
diff --git a/tests/test-diff-ignore-whitespace.t b/tests/test-diff-ignore-whitespace.t
new file mode 100644
index 0000000..35ca98d
--- /dev/null
+++ b/tests/test-diff-ignore-whitespace.t
@@ -0,0 +1,500 @@
+GNU diff is the reference for all of these results.
+
+Prepare tests:
+
+ $ echo '[alias]' >> $HGRCPATH
+ $ echo 'ndiff = diff --nodates' >> $HGRCPATH
+
+ $ hg init
+ $ printf 'hello world\ngoodbye world\n' >foo
+ $ hg ci -Amfoo -ufoo
+ adding foo
+
+
+Test added blank lines:
+
+ $ printf '\nhello world\n\ngoodbye world\n\n' >foo
+
+>>> two diffs showing three added lines <<<
+
+ $ hg ndiff
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,5 @@
+ +
+ hello world
+ +
+ goodbye world
+ +
+ $ hg ndiff -b
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,5 @@
+ +
+ hello world
+ +
+ goodbye world
+ +
+
+>>> no diffs <<<
+
+ $ hg ndiff -B
+ $ hg ndiff -Bb
+
+
+Test added horizontal space first on a line():
+
+ $ printf '\t hello world\ngoodbye world\n' >foo
+
+>>> four diffs showing added space first on the first line <<<
+
+ $ hg ndiff
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ -hello world
+ + hello world
+ goodbye world
+
+ $ hg ndiff -b
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ -hello world
+ + hello world
+ goodbye world
+
+ $ hg ndiff -B
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ -hello world
+ + hello world
+ goodbye world
+
+ $ hg ndiff -Bb
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ -hello world
+ + hello world
+ goodbye world
+
+
+Test added horizontal space last on a line:
+
+ $ printf 'hello world\t \ngoodbye world\n' >foo
+
+>>> two diffs showing space appended to the first line <<<
+
+ $ hg ndiff
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ -hello world
+ +hello world
+ goodbye world
+
+ $ hg ndiff -B
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ -hello world
+ +hello world
+ goodbye world
+
+>>> no diffs <<<
+
+ $ hg ndiff -b
+ $ hg ndiff -Bb
+
+
+Test added horizontal space in the middle of a word:
+
+ $ printf 'hello world\ngood bye world\n' >foo
+
+>>> four diffs showing space inserted into "goodbye" <<<
+
+ $ hg ndiff
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ hello world
+ -goodbye world
+ +good bye world
+
+ $ hg ndiff -B
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ hello world
+ -goodbye world
+ +good bye world
+
+ $ hg ndiff -b
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ hello world
+ -goodbye world
+ +good bye world
+
+ $ hg ndiff -Bb
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ hello world
+ -goodbye world
+ +good bye world
+
+
+Test increased horizontal whitespace amount:
+
+ $ printf 'hello world\ngoodbye\t\t \tworld\n' >foo
+
+>>> two diffs showing changed whitespace amount in the last line <<<
+
+ $ hg ndiff
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ hello world
+ -goodbye world
+ +goodbye world
+
+ $ hg ndiff -B
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ hello world
+ -goodbye world
+ +goodbye world
+
+>>> no diffs <<<
+
+ $ hg ndiff -b
+ $ hg ndiff -Bb
+
+
+Test added blank line with horizontal whitespace:
+
+ $ printf 'hello world\n \t\ngoodbye world\n' >foo
+
+>>> three diffs showing added blank line with horizontal space <<<
+
+ $ hg ndiff
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,3 @@
+ hello world
+ +
+ goodbye world
+
+ $ hg ndiff -B
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,3 @@
+ hello world
+ +
+ goodbye world
+
+ $ hg ndiff -b
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,3 @@
+ hello world
+ +
+ goodbye world
+
+>>> no diffs <<<
+
+ $ hg ndiff -Bb
+
+
+Test added blank line with other whitespace:
+
+ $ printf 'hello world\n \t\ngoodbye world \n' >foo
+
+>>> three diffs showing added blank line with other space <<<
+
+ $ hg ndiff
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,3 @@
+ -hello world
+ -goodbye world
+ +hello world
+ +
+ +goodbye world
+
+ $ hg ndiff -B
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,3 @@
+ -hello world
+ -goodbye world
+ +hello world
+ +
+ +goodbye world
+
+ $ hg ndiff -b
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,3 @@
+ hello world
+ +
+ goodbye world
+
+>>> no diffs <<<
+
+ $ hg ndiff -Bb
+
+
+Test whitespace changes:
+
+ $ printf 'helloworld\ngoodbye\tworld \n' >foo
+
+>>> four diffs showing changed whitespace <<<
+
+ $ hg ndiff
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ -hello world
+ -goodbye world
+ +helloworld
+ +goodbye world
+
+ $ hg ndiff -B
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ -hello world
+ -goodbye world
+ +helloworld
+ +goodbye world
+
+ $ hg ndiff -b
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ -hello world
+ +helloworld
+ goodbye world
+
+ $ hg ndiff -Bb
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,2 @@
+ -hello world
+ +helloworld
+ goodbye world
+
+>>> no diffs <<<
+
+ $ hg ndiff -w
+
+
+Test whitespace changes and blank lines:
+
+ $ printf 'helloworld\n\n\n\ngoodbye\tworld \n' >foo
+
+>>> five diffs showing changed whitespace <<<
+
+ $ hg ndiff
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,5 @@
+ -hello world
+ -goodbye world
+ +helloworld
+ +
+ +
+ +
+ +goodbye world
+
+ $ hg ndiff -B
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,5 @@
+ -hello world
+ -goodbye world
+ +helloworld
+ +
+ +
+ +
+ +goodbye world
+
+ $ hg ndiff -b
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,5 @@
+ -hello world
+ +helloworld
+ +
+ +
+ +
+ goodbye world
+
+ $ hg ndiff -Bb
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,5 @@
+ -hello world
+ +helloworld
+ +
+ +
+ +
+ goodbye world
+
+ $ hg ndiff -w
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,5 @@
+ hello world
+ +
+ +
+ +
+ goodbye world
+
+>>> no diffs <<<
+
+ $ hg ndiff -wB
+
+
+Test \r (carriage return) as used in "DOS" line endings:
+
+ $ printf 'hello world\r\n\r\ngoodbye\rworld\n' >foo
+
+ $ hg ndiff
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,3 @@
+ -hello world
+ -goodbye world
+ +hello world\r (esc)
+ +\r (esc)
+ +goodbye\rworld (esc)
+
+No completely blank lines to ignore:
+
+ $ hg ndiff --ignore-blank-lines
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,3 @@
+ -hello world
+ -goodbye world
+ +hello world\r (esc)
+ +\r (esc)
+ +goodbye\rworld (esc)
+
+Only new line noticed:
+
+ $ hg ndiff --ignore-space-change
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,3 @@
+ hello world
+ +\r (esc)
+ goodbye world
+
+ $ hg ndiff --ignore-all-space
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,3 @@
+ hello world
+ +\r (esc)
+ goodbye world
+
+New line not noticed when space change ignored:
+
+ $ hg ndiff --ignore-blank-lines --ignore-all-space
+
+Do not ignore all newlines, only blank lines
+
+ $ printf 'hello \nworld\ngoodbye world\n' > foo
+ $ hg ndiff --ignore-blank-lines
+ diff -r 540c40a65b78 foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,2 +1,3 @@
+ -hello world
+ +hello
+ +world
+ goodbye world
+
+Test hunk offsets adjustments with --ignore-blank-lines
+
+ $ hg revert -aC
+ reverting foo
+ $ printf '\nb\nx\nd\n' > a
+ $ printf 'b\ny\nd\n' > b
+ $ hg add a b
+ $ hg ci -m add
+ $ hg cat -r . a > b
+ $ hg cat -r . b > a
+ $ hg diff -B --nodates a > ../diffa
+ $ cat ../diffa
+ diff -r 0e66aa54f318 a
+ --- a/a
+ +++ b/a
+ @@ -1,4 +1,4 @@
+
+ b
+ -x
+ +y
+ d
+ $ hg diff -B --nodates b > ../diffb
+ $ cat ../diffb
+ diff -r 0e66aa54f318 b
+ --- a/b
+ +++ b/b
+ @@ -1,3 +1,3 @@
+ b
+ -y
+ +x
+ d
+ $ hg revert -aC
+ reverting a
+ reverting b
+ $ hg import --no-commit ../diffa
+ applying ../diffa
+ $ hg revert -aC
+ reverting a
+ $ hg import --no-commit ../diffb
+ applying ../diffb
+ $ hg revert -aC
+ reverting b
diff --git a/tests/test-diff-issue2761.t b/tests/test-diff-issue2761.t
new file mode 100644
index 0000000..55b2a85
--- /dev/null
+++ b/tests/test-diff-issue2761.t
@@ -0,0 +1,23 @@
+Test issue2761
+
+ $ hg init
+
+ $ touch to-be-deleted
+ $ hg add
+ adding to-be-deleted
+ $ hg ci -m first
+ $ echo a > to-be-deleted
+ $ hg ci -m second
+ $ rm to-be-deleted
+ $ hg diff -r 0
+
+Same issue, different code path
+
+ $ hg up -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ touch doesnt-exist-in-1
+ $ hg add
+ adding doesnt-exist-in-1
+ $ hg ci -m third
+ $ rm doesnt-exist-in-1
+ $ hg diff -r 1
diff --git a/tests/test-diff-newlines.t b/tests/test-diff-newlines.t
new file mode 100644
index 0000000..565b756
--- /dev/null
+++ b/tests/test-diff-newlines.t
@@ -0,0 +1,18 @@
+ $ hg init
+
+ $ python -c 'file("a", "wb").write("confuse str.splitlines\nembedded\rnewline\n")'
+ $ hg ci -Ama -d '1 0'
+ adding a
+
+ $ echo clean diff >> a
+ $ hg ci -mb -d '2 0'
+
+ $ hg diff -r0 -r1
+ diff -r 107ba6f817b5 -r 310ce7989cdc a
+ --- a/a Thu Jan 01 00:00:01 1970 +0000
+ +++ b/a Thu Jan 01 00:00:02 1970 +0000
+ @@ -1,2 +1,3 @@
+ confuse str.splitlines
+ embedded\rnewline (esc)
+ +clean diff
+
diff --git a/tests/test-diff-reverse.t b/tests/test-diff-reverse.t
new file mode 100644
index 0000000..20729c2
--- /dev/null
+++ b/tests/test-diff-reverse.t
@@ -0,0 +1,44 @@
+ $ hg init
+
+ $ cat > a <<EOF
+ > a
+ > b
+ > c
+ > EOF
+ $ hg ci -Am adda
+ adding a
+
+ $ cat > a <<EOF
+ > d
+ > e
+ > f
+ > EOF
+ $ hg ci -m moda
+
+ $ hg diff --reverse -r0 -r1
+ diff -r 2855cdcfcbb7 -r 8e1805a3cf6e a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,3 +1,3 @@
+ -d
+ -e
+ -f
+ +a
+ +b
+ +c
+
+ $ cat >> a <<EOF
+ > g
+ > h
+ > EOF
+ $ hg diff --reverse --nodates
+ diff -r 2855cdcfcbb7 a
+ --- a/a
+ +++ b/a
+ @@ -1,5 +1,3 @@
+ d
+ e
+ f
+ -g
+ -h
+
diff --git a/tests/test-diff-subdir.t b/tests/test-diff-subdir.t
new file mode 100644
index 0000000..e10a87c
--- /dev/null
+++ b/tests/test-diff-subdir.t
@@ -0,0 +1,47 @@
+ $ hg init
+
+ $ mkdir alpha
+ $ touch alpha/one
+ $ mkdir beta
+ $ touch beta/two
+
+ $ hg add alpha/one beta/two
+ $ hg ci -m "start"
+
+ $ echo 1 > alpha/one
+ $ echo 2 > beta/two
+
+everything
+
+ $ hg diff --nodates
+ diff -r 7d5ef1aea329 alpha/one
+ --- a/alpha/one
+ +++ b/alpha/one
+ @@ -0,0 +1,1 @@
+ +1
+ diff -r 7d5ef1aea329 beta/two
+ --- a/beta/two
+ +++ b/beta/two
+ @@ -0,0 +1,1 @@
+ +2
+
+beta only
+
+ $ hg diff --nodates beta
+ diff -r 7d5ef1aea329 beta/two
+ --- a/beta/two
+ +++ b/beta/two
+ @@ -0,0 +1,1 @@
+ +2
+
+inside beta
+
+ $ cd beta
+ $ hg diff --nodates .
+ diff -r 7d5ef1aea329 beta/two
+ --- a/beta/two
+ +++ b/beta/two
+ @@ -0,0 +1,1 @@
+ +2
+
+ $ cd ..
diff --git a/tests/test-diff-unified.t b/tests/test-diff-unified.t
new file mode 100644
index 0000000..a79d520
--- /dev/null
+++ b/tests/test-diff-unified.t
@@ -0,0 +1,198 @@
+ $ hg init repo
+ $ cd repo
+ $ cat > a <<EOF
+ > c
+ > c
+ > a
+ > a
+ > b
+ > a
+ > a
+ > c
+ > c
+ > EOF
+ $ hg ci -Am adda
+ adding a
+
+ $ cat > a <<EOF
+ > c
+ > c
+ > a
+ > a
+ > dd
+ > a
+ > a
+ > c
+ > c
+ > EOF
+
+default context
+
+ $ hg diff --nodates
+ diff -r cf9f4ba66af2 a
+ --- a/a
+ +++ b/a
+ @@ -2,7 +2,7 @@
+ c
+ a
+ a
+ -b
+ +dd
+ a
+ a
+ c
+
+invalid --unified
+
+ $ hg diff --nodates -U foo
+ abort: diff context lines count must be an integer, not 'foo'
+ [255]
+
+
+ $ hg diff --nodates -U 2
+ diff -r cf9f4ba66af2 a
+ --- a/a
+ +++ b/a
+ @@ -3,5 +3,5 @@
+ a
+ a
+ -b
+ +dd
+ a
+ a
+
+ $ hg --config diff.unified=2 diff --nodates
+ diff -r cf9f4ba66af2 a
+ --- a/a
+ +++ b/a
+ @@ -3,5 +3,5 @@
+ a
+ a
+ -b
+ +dd
+ a
+ a
+
+ $ hg diff --nodates -U 1
+ diff -r cf9f4ba66af2 a
+ --- a/a
+ +++ b/a
+ @@ -4,3 +4,3 @@
+ a
+ -b
+ +dd
+ a
+
+invalid diff.unified
+
+ $ hg --config diff.unified=foo diff --nodates
+ abort: diff context lines count must be an integer, not 'foo'
+ [255]
+
+ $ cd ..
+
+
+0 lines of context hunk header matches gnu diff hunk header
+
+ $ hg init diffzero
+ $ cd diffzero
+ $ cat > f1 << EOF
+ > c2
+ > c4
+ > c5
+ > EOF
+ $ hg commit -Am0
+ adding f1
+
+ $ cat > f2 << EOF
+ > c1
+ > c2
+ > c3
+ > c4
+ > EOF
+ $ mv f2 f1
+ $ hg diff -U0 --nodates
+ diff -r 55d8ff78db23 f1
+ --- a/f1
+ +++ b/f1
+ @@ -0,0 +1,1 @@
+ +c1
+ @@ -1,0 +3,1 @@
+ +c3
+ @@ -3,1 +4,0 @@
+ -c5
+
+ $ hg diff -U0 --nodates --git
+ diff --git a/f1 b/f1
+ --- a/f1
+ +++ b/f1
+ @@ -0,0 +1,1 @@
+ +c1
+ @@ -1,0 +3,1 @@
+ +c3
+ @@ -3,1 +4,0 @@
+ -c5
+
+ $ hg diff -U0 --nodates -p
+ diff -r 55d8ff78db23 f1
+ --- a/f1
+ +++ b/f1
+ @@ -0,0 +1,1 @@
+ +c1
+ @@ -1,0 +3,1 @@ c2
+ +c3
+ @@ -3,1 +4,0 @@ c4
+ -c5
+
+ $ echo a > f1
+ $ hg ci -m movef2
+
+Test diff headers terminating with TAB when necessary (issue3357)
+Regular diff --nodates, file creation
+
+ $ hg mv f1 'f 1'
+ $ echo b > 'f 1'
+ $ hg diff --nodates 'f 1'
+ diff -r 7574207d0d15 f 1
+ --- /dev/null
+ +++ b/f 1
+ @@ -0,0 +1,1 @@
+ +b
+
+Git diff, adding space
+
+ $ hg diff --git
+ diff --git a/f1 b/f 1
+ rename from f1
+ rename to f 1
+ --- a/f1
+ +++ b/f 1
+ @@ -1,1 +1,1 @@
+ -a
+ +b
+
+Regular diff --nodates, file deletion
+
+ $ hg ci -m addspace
+ $ hg mv 'f 1' f1
+ $ echo a > f1
+ $ hg diff --nodates 'f 1'
+ diff -r ca50fe67c9c7 f 1
+ --- a/f 1
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -b
+
+Git diff, removing space
+
+ $ hg diff --git
+ diff --git a/f 1 b/f1
+ rename from f 1
+ rename to f1
+ --- a/f 1
+ +++ b/f1
+ @@ -1,1 +1,1 @@
+ -b
+ +a
+
+ $ cd ..
diff --git a/tests/test-diff-upgrade.t b/tests/test-diff-upgrade.t
new file mode 100644
index 0000000..94c299a
--- /dev/null
+++ b/tests/test-diff-upgrade.t
@@ -0,0 +1,283 @@
+ $ "$TESTDIR/hghave" execbit || exit 80
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "autodiff=$TESTDIR/autodiff.py" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "nodates=1" >> $HGRCPATH
+
+ $ hg init repo
+ $ cd repo
+
+
+
+make a combination of new, changed and deleted file
+
+ $ echo regular > regular
+ $ echo rmregular > rmregular
+ $ python -c "file('bintoregular', 'wb').write('\0')"
+ $ touch rmempty
+ $ echo exec > exec
+ $ chmod +x exec
+ $ echo rmexec > rmexec
+ $ chmod +x rmexec
+ $ echo setexec > setexec
+ $ echo unsetexec > unsetexec
+ $ chmod +x unsetexec
+ $ echo binary > binary
+ $ python -c "file('rmbinary', 'wb').write('\0')"
+ $ hg ci -Am addfiles
+ adding binary
+ adding bintoregular
+ adding exec
+ adding regular
+ adding rmbinary
+ adding rmempty
+ adding rmexec
+ adding rmregular
+ adding setexec
+ adding unsetexec
+ $ echo regular >> regular
+ $ echo newregular >> newregular
+ $ rm rmempty
+ $ touch newempty
+ $ rm rmregular
+ $ echo exec >> exec
+ $ echo newexec > newexec
+ $ echo bintoregular > bintoregular
+ $ chmod +x newexec
+ $ rm rmexec
+ $ chmod +x setexec
+ $ chmod -x unsetexec
+ $ python -c "file('binary', 'wb').write('\0\0')"
+ $ python -c "file('newbinary', 'wb').write('\0')"
+ $ rm rmbinary
+ $ hg addremove -s 0
+ adding newbinary
+ adding newempty
+ adding newexec
+ adding newregular
+ removing rmbinary
+ removing rmempty
+ removing rmexec
+ removing rmregular
+
+git=no: regular diff for all files
+
+ $ hg autodiff --git=no
+ diff -r a66d19b9302d binary
+ Binary file binary has changed
+ diff -r a66d19b9302d bintoregular
+ Binary file bintoregular has changed
+ diff -r a66d19b9302d exec
+ --- a/exec
+ +++ b/exec
+ @@ -1,1 +1,2 @@
+ exec
+ +exec
+ diff -r a66d19b9302d newbinary
+ Binary file newbinary has changed
+ diff -r a66d19b9302d newexec
+ --- /dev/null
+ +++ b/newexec
+ @@ -0,0 +1,1 @@
+ +newexec
+ diff -r a66d19b9302d newregular
+ --- /dev/null
+ +++ b/newregular
+ @@ -0,0 +1,1 @@
+ +newregular
+ diff -r a66d19b9302d regular
+ --- a/regular
+ +++ b/regular
+ @@ -1,1 +1,2 @@
+ regular
+ +regular
+ diff -r a66d19b9302d rmbinary
+ Binary file rmbinary has changed
+ diff -r a66d19b9302d rmexec
+ --- a/rmexec
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -rmexec
+ diff -r a66d19b9302d rmregular
+ --- a/rmregular
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -rmregular
+
+git=yes: git diff for single regular file
+
+ $ hg autodiff --git=yes regular
+ diff --git a/regular b/regular
+ --- a/regular
+ +++ b/regular
+ @@ -1,1 +1,2 @@
+ regular
+ +regular
+
+git=auto: regular diff for regular files and non-binary removals
+
+ $ hg autodiff --git=auto regular newregular rmregular rmexec
+ diff -r a66d19b9302d newregular
+ --- /dev/null
+ +++ b/newregular
+ @@ -0,0 +1,1 @@
+ +newregular
+ diff -r a66d19b9302d regular
+ --- a/regular
+ +++ b/regular
+ @@ -1,1 +1,2 @@
+ regular
+ +regular
+ diff -r a66d19b9302d rmexec
+ --- a/rmexec
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -rmexec
+ diff -r a66d19b9302d rmregular
+ --- a/rmregular
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -rmregular
+
+ $ for f in exec newexec setexec unsetexec binary newbinary newempty rmempty rmbinary bintoregular; do
+ > echo
+ > echo '% git=auto: git diff for' $f
+ > hg autodiff --git=auto $f
+ > done
+
+ % git=auto: git diff for exec
+ diff -r a66d19b9302d exec
+ --- a/exec
+ +++ b/exec
+ @@ -1,1 +1,2 @@
+ exec
+ +exec
+
+ % git=auto: git diff for newexec
+ diff --git a/newexec b/newexec
+ new file mode 100755
+ --- /dev/null
+ +++ b/newexec
+ @@ -0,0 +1,1 @@
+ +newexec
+
+ % git=auto: git diff for setexec
+ diff --git a/setexec b/setexec
+ old mode 100644
+ new mode 100755
+
+ % git=auto: git diff for unsetexec
+ diff --git a/unsetexec b/unsetexec
+ old mode 100755
+ new mode 100644
+
+ % git=auto: git diff for binary
+ diff --git a/binary b/binary
+ index a9128c283485202893f5af379dd9beccb6e79486..09f370e38f498a462e1ca0faa724559b6630c04f
+ GIT binary patch
+ literal 2
+ Jc${Nk0000200961
+
+
+ % git=auto: git diff for newbinary
+ diff --git a/newbinary b/newbinary
+ new file mode 100644
+ index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d
+ GIT binary patch
+ literal 1
+ Ic${MZ000310RR91
+
+
+ % git=auto: git diff for newempty
+ diff --git a/newempty b/newempty
+ new file mode 100644
+
+ % git=auto: git diff for rmempty
+ diff --git a/rmempty b/rmempty
+ deleted file mode 100644
+
+ % git=auto: git diff for rmbinary
+ diff --git a/rmbinary b/rmbinary
+ deleted file mode 100644
+ Binary file rmbinary has changed
+
+ % git=auto: git diff for bintoregular
+ diff --git a/bintoregular b/bintoregular
+ index f76dd238ade08917e6712764a16a22005a50573d..9c42f2b6427d8bf034b7bc23986152dc01bfd3ab
+ GIT binary patch
+ literal 13
+ Uc$`bh%qz(+N=+}#Ni5<5043uE82|tP
+
+
+git=warn: regular diff with data loss warnings
+
+ $ hg autodiff --git=warn
+ diff -r a66d19b9302d binary
+ Binary file binary has changed
+ diff -r a66d19b9302d bintoregular
+ Binary file bintoregular has changed
+ diff -r a66d19b9302d exec
+ --- a/exec
+ +++ b/exec
+ @@ -1,1 +1,2 @@
+ exec
+ +exec
+ diff -r a66d19b9302d newbinary
+ Binary file newbinary has changed
+ diff -r a66d19b9302d newexec
+ --- /dev/null
+ +++ b/newexec
+ @@ -0,0 +1,1 @@
+ +newexec
+ diff -r a66d19b9302d newregular
+ --- /dev/null
+ +++ b/newregular
+ @@ -0,0 +1,1 @@
+ +newregular
+ diff -r a66d19b9302d regular
+ --- a/regular
+ +++ b/regular
+ @@ -1,1 +1,2 @@
+ regular
+ +regular
+ diff -r a66d19b9302d rmbinary
+ Binary file rmbinary has changed
+ diff -r a66d19b9302d rmexec
+ --- a/rmexec
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -rmexec
+ diff -r a66d19b9302d rmregular
+ --- a/rmregular
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -rmregular
+ data lost for: binary
+ data lost for: bintoregular
+ data lost for: newbinary
+ data lost for: newempty
+ data lost for: newexec
+ data lost for: rmbinary
+ data lost for: rmempty
+ data lost for: setexec
+ data lost for: unsetexec
+
+git=abort: fail on execute bit change
+
+ $ hg autodiff --git=abort regular setexec
+ abort: losing data for setexec
+ [255]
+
+git=abort: succeed on regular file
+
+ $ hg autodiff --git=abort regular
+ diff -r a66d19b9302d regular
+ --- a/regular
+ +++ b/regular
+ @@ -1,1 +1,2 @@
+ regular
+ +regular
+
+ $ cd ..
+
diff --git a/tests/test-diffdir.t b/tests/test-diffdir.t
new file mode 100644
index 0000000..f13bdbf
--- /dev/null
+++ b/tests/test-diffdir.t
@@ -0,0 +1,40 @@
+ $ hg init
+ $ touch a
+ $ hg add a
+ $ hg ci -m "a"
+
+ $ echo 123 > b
+ $ hg add b
+ $ hg diff --nodates
+ diff -r 3903775176ed b
+ --- /dev/null
+ +++ b/b
+ @@ -0,0 +1,1 @@
+ +123
+
+ $ hg diff --nodates -r tip
+ diff -r 3903775176ed b
+ --- /dev/null
+ +++ b/b
+ @@ -0,0 +1,1 @@
+ +123
+
+ $ echo foo > a
+ $ hg diff --nodates
+ diff -r 3903775176ed a
+ --- a/a
+ +++ b/a
+ @@ -0,0 +1,1 @@
+ +foo
+ diff -r 3903775176ed b
+ --- /dev/null
+ +++ b/b
+ @@ -0,0 +1,1 @@
+ +123
+
+ $ hg diff -r ""
+ hg: parse error: empty query
+ [255]
+ $ hg diff -r tip -r ""
+ hg: parse error: empty query
+ [255]
diff --git a/tests/test-diffstat.t b/tests/test-diffstat.t
new file mode 100644
index 0000000..5d03cdc
--- /dev/null
+++ b/tests/test-diffstat.t
@@ -0,0 +1,72 @@
+ $ hg init repo
+ $ cd repo
+ $ i=0; while [ "$i" -lt 213 ]; do echo a >> a; i=`expr $i + 1`; done
+ $ hg add a
+ $ cp a b
+ $ hg add b
+
+Wide diffstat:
+
+ $ hg diff --stat
+ a | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ b | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 426 insertions(+), 0 deletions(-)
+
+diffstat width:
+
+ $ COLUMNS=24 hg diff --config ui.interactive=true --stat
+ a | 213 ++++++++++++++
+ b | 213 ++++++++++++++
+ 2 files changed, 426 insertions(+), 0 deletions(-)
+
+ $ hg ci -m adda
+
+ $ cat >> a <<EOF
+ > a
+ > a
+ > a
+ > EOF
+
+Narrow diffstat:
+
+ $ hg diff --stat
+ a | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+ $ hg ci -m appenda
+
+ >>> open("c", "wb").write("\0")
+ $ touch d
+ $ hg add c d
+
+Binary diffstat:
+
+ $ hg diff --stat
+ c | Bin
+ 1 files changed, 0 insertions(+), 0 deletions(-)
+
+Binary git diffstat:
+
+ $ hg diff --stat --git
+ c | Bin
+ d | 0
+ 2 files changed, 0 insertions(+), 0 deletions(-)
+
+ $ hg ci -m createb
+
+ >>> open("file with spaces", "wb").write("\0")
+ $ hg add "file with spaces"
+
+Filename with spaces diffstat:
+
+ $ hg diff --stat
+ file with spaces | Bin
+ 1 files changed, 0 insertions(+), 0 deletions(-)
+
+Filename with spaces git diffstat:
+
+ $ hg diff --stat --git
+ file with spaces | Bin
+ 1 files changed, 0 insertions(+), 0 deletions(-)
+
+ $ cd ..
diff --git a/tests/test-dirstate-race.t b/tests/test-dirstate-race.t
new file mode 100644
index 0000000..d9bd97c
--- /dev/null
+++ b/tests/test-dirstate-race.t
@@ -0,0 +1,33 @@
+ $ hg init
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m test
+
+Do we ever miss a sub-second change?:
+
+ $ for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
+ > hg co -qC 0
+ > echo b > a
+ > hg st
+ > done
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+ M a
+
diff --git a/tests/test-dirstate.t b/tests/test-dirstate.t
new file mode 100644
index 0000000..6b65f59
--- /dev/null
+++ b/tests/test-dirstate.t
@@ -0,0 +1,56 @@
+------ Test dirstate._dirs refcounting
+
+ $ hg init t
+ $ cd t
+ $ mkdir -p a/b/c/d
+ $ touch a/b/c/d/x
+ $ touch a/b/c/d/y
+ $ touch a/b/c/d/z
+ $ hg ci -Am m
+ adding a/b/c/d/x
+ adding a/b/c/d/y
+ adding a/b/c/d/z
+ $ hg mv a z
+ moving a/b/c/d/x to z/b/c/d/x (glob)
+ moving a/b/c/d/y to z/b/c/d/y (glob)
+ moving a/b/c/d/z to z/b/c/d/z (glob)
+
+Test name collisions
+
+ $ rm z/b/c/d/x
+ $ mkdir z/b/c/d/x
+ $ touch z/b/c/d/x/y
+ $ hg add z/b/c/d/x/y
+ abort: file 'z/b/c/d/x' in dirstate clashes with 'z/b/c/d/x/y'
+ [255]
+ $ rm -rf z/b/c/d
+ $ touch z/b/c/d
+ $ hg add z/b/c/d
+ abort: directory 'z/b/c/d' already in dirstate
+ [255]
+
+ $ cd ..
+
+Issue1790: dirstate entry locked into unset if file mtime is set into
+the future
+
+Prepare test repo:
+
+ $ hg init u
+ $ cd u
+ $ echo a > a
+ $ hg add
+ adding a
+ $ hg ci -m1
+
+Set mtime of a into the future:
+
+ $ touch -t 202101011200 a
+
+Status must not set a's entry to unset (issue1790):
+
+ $ hg status
+ $ hg debugstate
+ n 644 2 2021-01-01 12:00:00 a
+ $ cd ..
+
diff --git a/tests/test-dispatch.py b/tests/test-dispatch.py
new file mode 100644
index 0000000..51ed4e8
--- /dev/null
+++ b/tests/test-dispatch.py
@@ -0,0 +1,33 @@
+import os
+from mercurial import dispatch
+
+def testdispatch(cmd):
+ """Simple wrapper around dispatch.dispatch()
+
+ Prints command and result value, but does not handle quoting.
+ """
+ print "running: %s" % (cmd,)
+ req = dispatch.request(cmd.split())
+ result = dispatch.dispatch(req)
+ print "result: %r" % (result,)
+
+
+testdispatch("init test1")
+os.chdir('test1')
+
+# create file 'foo', add and commit
+f = open('foo', 'wb')
+f.write('foo\n')
+f.close()
+testdispatch("add foo")
+testdispatch("commit -m commit1 -d 2000-01-01 foo")
+
+# append to file 'foo' and commit
+f = open('foo', 'ab')
+f.write('bar\n')
+f.close()
+testdispatch("commit -m commit2 -d 2000-01-02 foo")
+
+# check 88803a69b24 (fancyopts modified command table)
+testdispatch("log -r 0")
+testdispatch("log -r tip")
diff --git a/tests/test-dispatch.py.out b/tests/test-dispatch.py.out
new file mode 100644
index 0000000..2169f22
--- /dev/null
+++ b/tests/test-dispatch.py.out
@@ -0,0 +1,23 @@
+running: init test1
+result: None
+running: add foo
+result: 0
+running: commit -m commit1 -d 2000-01-01 foo
+result: None
+running: commit -m commit2 -d 2000-01-02 foo
+result: None
+running: log -r 0
+changeset: 0:0e4634943879
+user: test
+date: Sat Jan 01 00:00:00 2000 +0000
+summary: commit1
+
+result: None
+running: log -r tip
+changeset: 1:45589e459b2e
+tag: tip
+user: test
+date: Sun Jan 02 00:00:00 2000 +0000
+summary: commit2
+
+result: None
diff --git a/tests/test-dispatch.t b/tests/test-dispatch.t
new file mode 100644
index 0000000..3b11d14
--- /dev/null
+++ b/tests/test-dispatch.t
@@ -0,0 +1,58 @@
+test command parsing and dispatch
+
+ $ hg init a
+ $ cd a
+
+Redundant options used to crash (issue436):
+ $ hg -v log -v
+ $ hg -v log -v x
+
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+
+Missing arg:
+
+ $ hg cat
+ hg cat: invalid arguments
+ hg cat [OPTION]... FILE...
+
+ output the current or given revision of files
+
+ options:
+
+ -o --output FORMAT print output to file with formatted name
+ -r --rev REV print the given revision
+ --decode apply any matching decode filter
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+
+ [+] marked option can be specified multiple times
+
+ use "hg help cat" to show the full help text
+ [255]
+
+[defaults]
+
+ $ hg cat a
+ a
+ $ cat >> $HGRCPATH <<EOF
+ > [defaults]
+ > cat = -r null
+ > EOF
+ $ hg cat a
+ a: no such file in rev 000000000000
+ [1]
+
+ $ cd "$TESTTMP"
+
+#if no-outer-repo
+
+No repo:
+
+ $ cd $dir
+ $ hg cat
+ abort: no repository found in '$TESTTMP' (.hg not found)!
+ [255]
+
+#endif
diff --git a/tests/test-doctest.py b/tests/test-doctest.py
new file mode 100644
index 0000000..8f143c1
--- /dev/null
+++ b/tests/test-doctest.py
@@ -0,0 +1,44 @@
+# this is hack to make sure no escape characters are inserted into the output
+import os
+if 'TERM' in os.environ:
+ del os.environ['TERM']
+import doctest
+
+import mercurial.util
+doctest.testmod(mercurial.util)
+
+import mercurial.changelog
+doctest.testmod(mercurial.changelog)
+
+import mercurial.dagparser
+doctest.testmod(mercurial.dagparser, optionflags=doctest.NORMALIZE_WHITESPACE)
+
+import mercurial.match
+doctest.testmod(mercurial.match)
+
+import mercurial.store
+doctest.testmod(mercurial.store)
+
+import mercurial.ui
+doctest.testmod(mercurial.ui)
+
+import mercurial.url
+doctest.testmod(mercurial.url)
+
+import mercurial.encoding
+doctest.testmod(mercurial.encoding)
+
+import mercurial.hgweb.hgwebdir_mod
+doctest.testmod(mercurial.hgweb.hgwebdir_mod)
+
+import hgext.convert.cvsps
+doctest.testmod(hgext.convert.cvsps)
+
+import mercurial.revset
+doctest.testmod(mercurial.revset)
+
+import mercurial.minirst
+doctest.testmod(mercurial.minirst)
+
+import mercurial.templatefilters
+doctest.testmod(mercurial.templatefilters)
diff --git a/tests/test-double-merge.t b/tests/test-double-merge.t
new file mode 100644
index 0000000..a703c5b
--- /dev/null
+++ b/tests/test-double-merge.t
@@ -0,0 +1,67 @@
+ $ hg init repo
+ $ cd repo
+
+ $ echo line 1 > foo
+ $ hg ci -qAm 'add foo'
+
+copy foo to bar and change both files
+ $ hg cp foo bar
+ $ echo line 2-1 >> foo
+ $ echo line 2-2 >> bar
+ $ hg ci -m 'cp foo bar; change both'
+
+in another branch, change foo in a way that doesn't conflict with
+the other changes
+ $ hg up -qC 0
+ $ echo line 0 > foo
+ $ hg cat foo >> foo
+ $ hg ci -m 'change foo'
+ created new head
+
+we get conflicts that shouldn't be there
+ $ hg merge -P
+ changeset: 1:484bf6903104
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: cp foo bar; change both
+
+ $ hg merge --debug
+ searching for copies back to rev 1
+ unmatched files in other:
+ bar
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ bar -> foo *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: e6dc8efe11cc, local: 6a0df1dad128+, remote: 484bf6903104
+ foo: versions differ -> m
+ foo: remote copied to bar -> m
+ preserving foo for resolve of bar
+ preserving foo for resolve of foo
+ updating: foo 1/2 files (50.00%)
+ picked tool 'internal:merge' for bar (binary False symlink False)
+ merging foo and bar to bar
+ my bar@6a0df1dad128+ other bar@484bf6903104 ancestor foo@e6dc8efe11cc
+ premerge successful
+ updating: foo 2/2 files (100.00%)
+ picked tool 'internal:merge' for foo (binary False symlink False)
+ merging foo
+ my foo@6a0df1dad128+ other foo@484bf6903104 ancestor foo@e6dc8efe11cc
+ premerge successful
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+contents of foo
+ $ cat foo
+ line 0
+ line 1
+ line 2-1
+
+contents of bar
+ $ cat bar
+ line 0
+ line 1
+ line 2-2
+
+ $ cd ..
diff --git a/tests/test-duplicateoptions.py b/tests/test-duplicateoptions.py
new file mode 100644
index 0000000..22964c4
--- /dev/null
+++ b/tests/test-duplicateoptions.py
@@ -0,0 +1,36 @@
+import os
+from mercurial import ui, commands, extensions
+
+ignore = set(['highlight', 'inotify', 'win32text', 'factotum'])
+
+if os.name != 'nt':
+ ignore.add('win32mbcs')
+
+disabled = [ext for ext in extensions.disabled().keys() if ext not in ignore]
+
+hgrc = open(os.environ["HGRCPATH"], 'w')
+hgrc.write('[extensions]\n')
+
+for ext in disabled:
+ hgrc.write(ext + '=\n')
+
+hgrc.close()
+
+u = ui.ui()
+extensions.loadall(u)
+
+globalshort = set()
+globallong = set()
+for option in commands.globalopts:
+ option[0] and globalshort.add(option[0])
+ option[1] and globallong.add(option[1])
+
+for cmd, entry in commands.table.iteritems():
+ seenshort = globalshort.copy()
+ seenlong = globallong.copy()
+ for option in entry[1]:
+ if (option[0] and option[0] in seenshort) or \
+ (option[1] and option[1] in seenlong):
+ print "command '" + cmd + "' has duplicate option " + str(option)
+ seenshort.add(option[0])
+ seenlong.add(option[1])
diff --git a/tests/test-empty-dir.t b/tests/test-empty-dir.t
new file mode 100644
index 0000000..16a7a33
--- /dev/null
+++ b/tests/test-empty-dir.t
@@ -0,0 +1,23 @@
+ $ hg init
+
+ $ echo 123 > a
+ $ hg add a
+ $ hg commit -m "first" a
+
+ $ mkdir sub
+ $ echo 321 > sub/b
+ $ hg add sub/b
+ $ hg commit -m "second" sub/b
+
+ $ cat sub/b
+ 321
+
+ $ hg co 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ cat sub/b 2>/dev/null || echo "sub/b not present"
+ sub/b not present
+
+ $ test -d sub || echo "sub not present"
+ sub not present
+
diff --git a/tests/test-empty-file.t b/tests/test-empty-file.t
new file mode 100644
index 0000000..07e7c58
--- /dev/null
+++ b/tests/test-empty-file.t
@@ -0,0 +1,47 @@
+ $ hg init a
+ $ cd a
+ $ touch empty1
+ $ hg add empty1
+ $ hg commit -m 'add empty1'
+
+ $ touch empty2
+ $ hg add empty2
+ $ hg commit -m 'add empty2'
+
+ $ hg up -C 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ touch empty3
+ $ hg add empty3
+ $ hg commit -m 'add empty3'
+ created new head
+
+ $ hg heads
+ changeset: 2:a1cb177e0d44
+ tag: tip
+ parent: 0:1e1d9c4e5b64
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add empty3
+
+ changeset: 1:097d2b0e17f6
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add empty2
+
+
+ $ hg merge 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+Before changeset 05257fd28591, we didn't notice the
+empty file that came from rev 1:
+
+ $ hg status
+ M empty2
+ $ hg commit -m merge
+ $ hg manifest --debug tip
+ b80de5d138758541c5f05265ad144ab9fa86d1db 644 empty1
+ b80de5d138758541c5f05265ad144ab9fa86d1db 644 empty2
+ b80de5d138758541c5f05265ad144ab9fa86d1db 644 empty3
+
+ $ cd ..
diff --git a/tests/test-empty-group.t b/tests/test-empty-group.t
new file mode 100644
index 0000000..9dbb33d
--- /dev/null
+++ b/tests/test-empty-group.t
@@ -0,0 +1,127 @@
+# A B
+#
+# 3 4 3
+# |\/| |\
+# |/\| | \
+# 1 2 1 2
+# \ / \ /
+# 0 0
+#
+# if the result of the merge of 1 and 2
+# is the same in 3 and 4, no new manifest
+# will be created and the manifest group
+# will be empty during the pull
+#
+# (plus we test a failure where outgoing
+# wrongly reported the number of csets)
+
+ $ hg init a
+ $ cd a
+ $ touch init
+ $ hg ci -A -m 0
+ adding init
+ $ touch x y
+ $ hg ci -A -m 1
+ adding x
+ adding y
+
+ $ hg update 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ touch x y
+ $ hg ci -A -m 2
+ adding x
+ adding y
+ created new head
+
+ $ hg merge 1
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -A -m m1
+
+ $ hg update -C 1
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge 2
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -A -m m2
+ created new head
+
+ $ cd ..
+
+ $ hg clone -r 3 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 3 changes to 3 files
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg clone -r 4 a c
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 3 changes to 3 files
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg -R a outgoing b
+ comparing with b
+ searching for changes
+ changeset: 4:1ec3c74fc0e0
+ tag: tip
+ parent: 1:79f9e10cd04e
+ parent: 2:8e1bb01c1a24
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: m2
+
+ $ hg -R a outgoing c
+ comparing with c
+ searching for changes
+ changeset: 3:d15a0c284984
+ parent: 2:8e1bb01c1a24
+ parent: 1:79f9e10cd04e
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: m1
+
+ $ hg -R b outgoing c
+ comparing with c
+ searching for changes
+ changeset: 3:d15a0c284984
+ tag: tip
+ parent: 2:8e1bb01c1a24
+ parent: 1:79f9e10cd04e
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: m1
+
+ $ hg -R c outgoing b
+ comparing with b
+ searching for changes
+ changeset: 3:1ec3c74fc0e0
+ tag: tip
+ parent: 1:79f9e10cd04e
+ parent: 2:8e1bb01c1a24
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: m2
+
+
+ $ hg -R b pull a
+ pulling from a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 0 changes to 0 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ $ hg -R c pull a
+ pulling from a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 0 changes to 0 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
diff --git a/tests/test-empty.t b/tests/test-empty.t
new file mode 100644
index 0000000..5f25f36
--- /dev/null
+++ b/tests/test-empty.t
@@ -0,0 +1,55 @@
+Create an empty repo:
+
+ $ hg init a
+ $ cd a
+
+Try some commands:
+
+ $ hg log
+ $ hg grep wah
+ [1]
+ $ hg manifest
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 0 files, 0 changesets, 0 total revisions
+
+Check the basic files created:
+
+ $ ls .hg
+ 00changelog.i
+ requires
+ store
+
+Should be empty:
+
+ $ ls .hg/store
+
+Poke at a clone:
+
+ $ cd ..
+ $ hg clone a b
+ updating to branch default
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd b
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 0 files, 0 changesets, 0 total revisions
+ $ ls .hg
+ 00changelog.i
+ branch
+ dirstate
+ hgrc
+ requires
+ store
+
+Should be empty:
+
+ $ ls .hg/store
+
+ $ cd ..
diff --git a/tests/test-encode.t b/tests/test-encode.t
new file mode 100644
index 0000000..863bba3
--- /dev/null
+++ b/tests/test-encode.t
@@ -0,0 +1,63 @@
+Test encode/decode filters
+
+ $ hg init
+ $ cat > .hg/hgrc <<EOF
+ > [encode]
+ > not.gz = tr [:lower:] [:upper:]
+ > *.gz = gzip -d
+ > [decode]
+ > not.gz = tr [:upper:] [:lower:]
+ > *.gz = gzip
+ > EOF
+ $ echo "this is a test" | gzip > a.gz
+ $ echo "this is a test" > not.gz
+ $ hg add *
+ $ hg ci -m "test"
+
+no changes
+
+ $ hg status
+ $ touch *
+
+no changes
+
+ $ hg status
+
+check contents in repo are encoded
+
+ $ hg debugdata a.gz 0
+ this is a test
+ $ hg debugdata not.gz 0
+ THIS IS A TEST
+
+check committed content was decoded
+
+ $ gunzip < a.gz
+ this is a test
+ $ cat not.gz
+ this is a test
+ $ rm *
+ $ hg co -C
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+check decoding of our new working dir copy
+
+ $ gunzip < a.gz
+ this is a test
+ $ cat not.gz
+ this is a test
+
+check hg cat operation
+
+ $ hg cat a.gz
+ this is a test
+ $ hg cat --decode a.gz | gunzip
+ this is a test
+ $ mkdir subdir
+ $ cd subdir
+ $ hg -R .. cat ../a.gz
+ this is a test
+ $ hg -R .. cat --decode ../a.gz | gunzip
+ this is a test
+
+ $ cd ..
diff --git a/tests/test-encoding-align.t b/tests/test-encoding-align.t
new file mode 100644
index 0000000..b0ce561
--- /dev/null
+++ b/tests/test-encoding-align.t
@@ -0,0 +1,145 @@
+Test alignment of multibyte characters
+
+ $ HGENCODING=utf-8
+ $ export HGENCODING
+ $ hg init t
+ $ cd t
+ $ python << EOF
+ > # (byte, width) = (6, 4)
+ > s = "\xe7\x9f\xad\xe5\x90\x8d"
+ > # (byte, width) = (7, 7): odd width is good for alignment test
+ > m = "MIDDLE_"
+ > # (byte, width) = (18, 12)
+ > l = "\xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d"
+ > f = file('s', 'w'); f.write(s); f.close()
+ > f = file('m', 'w'); f.write(m); f.close()
+ > f = file('l', 'w'); f.write(l); f.close()
+ > # instant extension to show list of options
+ > f = file('showoptlist.py', 'w'); f.write("""# encoding: utf-8
+ > def showoptlist(ui, repo, *pats, **opts):
+ > '''dummy command to show option descriptions'''
+ > return 0
+ > cmdtable = {
+ > 'showoptlist':
+ > (showoptlist,
+ > [('s', 'opt1', '', 'short width' + ' %(s)s' * 8, '%(s)s'),
+ > ('m', 'opt2', '', 'middle width' + ' %(m)s' * 8, '%(m)s'),
+ > ('l', 'opt3', '', 'long width' + ' %(l)s' * 8, '%(l)s')
+ > ],
+ > ""
+ > )
+ > }
+ > """ % globals())
+ > f.close()
+ > EOF
+ $ S=`cat s`
+ $ M=`cat m`
+ $ L=`cat l`
+
+alignment of option descriptions in help
+
+ $ cat <<EOF > .hg/hgrc
+ > [extensions]
+ > ja_ext = `pwd`/showoptlist.py
+ > EOF
+
+check alignment of option descriptions in help
+
+ $ hg help showoptlist
+ hg showoptlist
+
+ dummy command to show option descriptions
+
+ options:
+
+ -s --opt1 \xe7\x9f\xad\xe5\x90\x8d short width \xe7\x9f\xad\xe5\x90\x8d \xe7\x9f\xad\xe5\x90\x8d \xe7\x9f\xad\xe5\x90\x8d \xe7\x9f\xad\xe5\x90\x8d \xe7\x9f\xad\xe5\x90\x8d \xe7\x9f\xad\xe5\x90\x8d \xe7\x9f\xad\xe5\x90\x8d \xe7\x9f\xad\xe5\x90\x8d (esc)
+ -m --opt2 MIDDLE_ middle width MIDDLE_ MIDDLE_ MIDDLE_ MIDDLE_ MIDDLE_
+ MIDDLE_ MIDDLE_ MIDDLE_
+ -l --opt3 \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d long width \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d (esc)
+ \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d (esc)
+ \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d (esc)
+
+ use "hg -v help showoptlist" to show more info
+
+
+ $ rm -f s; touch s
+ $ rm -f m; touch m
+ $ rm -f l; touch l
+
+add files
+
+ $ cp s $S
+ $ hg add $S
+ $ cp m $M
+ $ hg add $M
+ $ cp l $L
+ $ hg add $L
+
+commit(1)
+
+ $ echo 'first line(1)' >> s; cp s $S
+ $ echo 'first line(2)' >> m; cp m $M
+ $ echo 'first line(3)' >> l; cp l $L
+ $ hg commit -m 'first commit' -u $S
+
+commit(2)
+
+ $ echo 'second line(1)' >> s; cp s $S
+ $ echo 'second line(2)' >> m; cp m $M
+ $ echo 'second line(3)' >> l; cp l $L
+ $ hg commit -m 'second commit' -u $M
+
+commit(3)
+
+ $ echo 'third line(1)' >> s; cp s $S
+ $ echo 'third line(2)' >> m; cp m $M
+ $ echo 'third line(3)' >> l; cp l $L
+ $ hg commit -m 'third commit' -u $L
+
+check alignment of user names in annotate
+
+ $ hg annotate -u $M
+ \xe7\x9f\xad\xe5\x90\x8d: first line(2) (esc)
+ MIDDLE_: second line(2)
+ \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d: third line(2) (esc)
+
+check alignment of filenames in diffstat
+
+ $ hg diff -c tip --stat
+ MIDDLE_ | 1 +
+ \xe7\x9f\xad\xe5\x90\x8d | 1 + (esc)
+ \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d | 1 + (esc)
+ 3 files changed, 3 insertions(+), 0 deletions(-)
+
+add branches/tags
+
+ $ hg branch $S
+ marked working directory as branch \xe7\x9f\xad\xe5\x90\x8d (esc)
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg tag $S
+ $ hg branch $M
+ marked working directory as branch MIDDLE_
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg tag $M
+ $ hg branch $L
+ marked working directory as branch \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d (esc)
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg tag $L
+
+check alignment of branches
+
+ $ hg tags
+ tip 5:d745ff46155b
+ \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d 4:9259be597f19 (esc)
+ MIDDLE_ 3:b06c5b6def9e
+ \xe7\x9f\xad\xe5\x90\x8d 2:64a70663cee8 (esc)
+
+check alignment of tags
+
+ $ hg tags
+ tip 5:d745ff46155b
+ \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d 4:9259be597f19 (esc)
+ MIDDLE_ 3:b06c5b6def9e
+ \xe7\x9f\xad\xe5\x90\x8d 2:64a70663cee8 (esc)
+
+ $ cd ..
diff --git a/tests/test-encoding-textwrap.t b/tests/test-encoding-textwrap.t
new file mode 100644
index 0000000..67b0488
--- /dev/null
+++ b/tests/test-encoding-textwrap.t
@@ -0,0 +1,259 @@
+Test text wrapping for multibyte characters
+
+ $ mkdir t
+ $ cd t
+
+define commands to display help text
+
+ $ cat << EOF > show.py
+ > # Japanese full-width characters:
+ > def show_full_ja(ui, **opts):
+ > u'''\u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051 \u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051 \u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051
+ >
+ > \u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051 \u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051 \u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051 \u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051
+ >
+ > \u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051\u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051\u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051\u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051
+ > '''
+ >
+ > # Japanese half-width characters:
+ > def show_half_ja(ui, *opts):
+ > u'''\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79 \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79 \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79 \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79
+ >
+ > \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79 \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79 \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79 \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79 \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79 \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79 \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79 \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79
+ >
+ > \uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79
+ > '''
+ >
+ > # Japanese ambiguous-width characters:
+ > def show_ambig_ja(ui, **opts):
+ > u'''\u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb \u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb \u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb
+ >
+ > \u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb \u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb \u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb \u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb \u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb \u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb \u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb
+ >
+ > \u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb\u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb\u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb\u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb\u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb\u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb\u03b1\u03b2\u03b3\u03b4\u03c5\u03b6\u03b7\u03b8\u25cb
+ > '''
+ >
+ > # Russian ambiguous-width characters:
+ > def show_ambig_ru(ui, **opts):
+ > u'''\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438
+ >
+ > \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438
+ >
+ > \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438
+ > '''
+ >
+ > cmdtable = {
+ > 'show_full_ja': (show_full_ja, [], ""),
+ > 'show_half_ja': (show_half_ja, [], ""),
+ > 'show_ambig_ja': (show_ambig_ja, [], ""),
+ > 'show_ambig_ru': (show_ambig_ru, [], ""),
+ > }
+ > EOF
+
+"COLUMNS=60" means that there is no lines which has grater than 58 width
+
+(1) test text wrapping for non-ambiguous-width characters
+
+(1-1) display Japanese full-width characters in cp932
+
+ $ COLUMNS=60 hg --encoding cp932 --config extensions.show=./show.py help show_full_ja
+ hg show_full_ja
+
+ \x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf \x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf \x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf (esc)
+
+ \x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf \x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf (esc)
+ \x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf \x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf (esc)
+
+ \x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf\x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf\x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf (esc)
+ \x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf (esc)
+
+ use "hg -v help show_full_ja" to show more info
+
+(1-2) display Japanese full-width characters in utf-8
+
+ $ COLUMNS=60 hg --encoding utf-8 --config extensions.show=./show.py help show_full_ja
+ hg show_full_ja
+
+ \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91 (esc)
+
+ \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91 (esc)
+ \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91 (esc)
+
+ \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91 (esc)
+ \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91 (esc)
+
+ use "hg -v help show_full_ja" to show more info
+
+
+(1-3) display Japanese half-width characters in cp932
+
+ $ COLUMNS=60 hg --encoding cp932 --config extensions.show=./show.py help show_half_ja
+ hg show_half_ja
+
+ \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 (esc)
+
+ \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 (esc)
+ \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 (esc)
+
+ \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 (esc)
+ \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 (esc)
+
+ use "hg -v help show_half_ja" to show more info
+
+(1-4) display Japanese half-width characters in utf-8
+
+ $ COLUMNS=60 hg --encoding utf-8 --config extensions.show=./show.py help show_half_ja
+ hg show_half_ja
+
+ \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 (esc)
+
+ \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 (esc)
+ \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 (esc)
+
+ \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 (esc)
+ \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 (esc)
+
+ use "hg -v help show_half_ja" to show more info
+
+
+
+(2) test text wrapping for ambiguous-width characters
+
+(2-1) treat width of ambiguous characters as narrow (default)
+
+(2-1-1) display Japanese ambiguous-width characters in cp932
+
+ $ COLUMNS=60 hg --encoding cp932 --config extensions.show=./show.py help show_ambig_ja
+ hg show_ambig_ja
+
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+
+ use "hg -v help show_ambig_ja" to show more info
+
+(2-1-2) display Japanese ambiguous-width characters in utf-8
+
+ $ COLUMNS=60 hg --encoding utf-8 --config extensions.show=./show.py help show_ambig_ja
+ hg show_ambig_ja
+
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+
+ use "hg -v help show_ambig_ja" to show more info
+
+(2-1-3) display Russian ambiguous-width characters in cp1251
+
+ $ COLUMNS=60 hg --encoding cp1251 --config extensions.show=./show.py help show_ambig_ru
+ hg show_ambig_ru
+
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+
+ use "hg -v help show_ambig_ru" to show more info
+
+(2-1-4) display Russian ambiguous-width characters in utf-8
+
+ $ COLUMNS=60 hg --encoding utf-8 --config extensions.show=./show.py help show_ambig_ru
+ hg show_ambig_ru
+
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+
+ use "hg -v help show_ambig_ru" to show more info
+
+
+(2-2) treat width of ambiguous characters as wide
+
+(2-2-1) display Japanese ambiguous-width characters in cp932
+
+ $ COLUMNS=60 HGENCODINGAMBIGUOUS=wide hg --encoding cp932 --config extensions.show=./show.py help show_ambig_ja
+ hg show_ambig_ja
+
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc)
+
+ use "hg -v help show_ambig_ja" to show more info
+
+(2-2-2) display Japanese ambiguous-width characters in utf-8
+
+ $ COLUMNS=60 HGENCODINGAMBIGUOUS=wide hg --encoding utf-8 --config extensions.show=./show.py help show_ambig_ja
+ hg show_ambig_ja
+
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc)
+
+ use "hg -v help show_ambig_ja" to show more info
+
+(2-2-3) display Russian ambiguous-width characters in cp1251
+
+ $ COLUMNS=60 HGENCODINGAMBIGUOUS=wide hg --encoding cp1251 --config extensions.show=./show.py help show_ambig_ru
+ hg show_ambig_ru
+
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc)
+
+ use "hg -v help show_ambig_ru" to show more info
+
+(2-2-4) display Russian ambiguous-width charactes in utf-8
+
+ $ COLUMNS=60 HGENCODINGAMBIGUOUS=wide hg --encoding utf-8 --config extensions.show=./show.py help show_ambig_ru
+ hg show_ambig_ru
+
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc)
+
+ use "hg -v help show_ambig_ru" to show more info
+
+ $ cd ..
diff --git a/tests/test-encoding.t b/tests/test-encoding.t
new file mode 100644
index 0000000..ee884ba
--- /dev/null
+++ b/tests/test-encoding.t
@@ -0,0 +1,252 @@
+Test character encoding
+
+ $ hg init t
+ $ cd t
+
+we need a repo with some legacy latin-1 changesets
+
+ $ hg unbundle "$TESTDIR/bundles/legacy-encoding.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg co
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ python << EOF
+ > f = file('latin-1', 'w'); f.write("latin-1 e' encoded: \xe9"); f.close()
+ > f = file('utf-8', 'w'); f.write("utf-8 e' encoded: \xc3\xa9"); f.close()
+ > f = file('latin-1-tag', 'w'); f.write("\xe9"); f.close()
+ > EOF
+
+should fail with encoding error
+
+ $ echo "plain old ascii" > a
+ $ hg st
+ M a
+ ? latin-1
+ ? latin-1-tag
+ ? utf-8
+ $ HGENCODING=ascii hg ci -l latin-1
+ transaction abort!
+ rollback completed
+ abort: decoding near ' encoded: \xe9': 'ascii' codec can't decode byte 0xe9 in position 20: ordinal not in range(128)! (esc)
+ [255]
+
+these should work
+
+ $ echo "latin-1" > a
+ $ HGENCODING=latin-1 hg ci -l latin-1
+ $ echo "utf-8" > a
+ $ HGENCODING=utf-8 hg ci -l utf-8
+ $ HGENCODING=latin-1 hg tag `cat latin-1-tag`
+ $ HGENCODING=latin-1 hg branch `cat latin-1-tag`
+ marked working directory as branch \xe9 (esc)
+ (branches are permanent and global, did you want a bookmark?)
+ $ HGENCODING=latin-1 hg ci -m 'latin1 branch'
+ $ rm .hg/branch
+
+hg log (ascii)
+
+ $ hg --encoding ascii log
+ changeset: 5:a52c0692f24a
+ branch: ?
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: latin1 branch
+
+ changeset: 4:94db611b4196
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag ? for changeset ca661e7520de
+
+ changeset: 3:ca661e7520de
+ tag: ?
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: utf-8 e' encoded: ?
+
+ changeset: 2:650c6f3d55dd
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: latin-1 e' encoded: ?
+
+ changeset: 1:0e5b7e3f9c4a
+ user: test
+ date: Mon Jan 12 13:46:40 1970 +0000
+ summary: koi8-r: ????? = u'\u0440\u0442\u0443\u0442\u044c'
+
+ changeset: 0:1e78a93102a3
+ user: test
+ date: Mon Jan 12 13:46:40 1970 +0000
+ summary: latin-1 e': ? = u'\xe9'
+
+
+hg log (latin-1)
+
+ $ hg --encoding latin-1 log
+ changeset: 5:a52c0692f24a
+ branch: \xe9 (esc)
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: latin1 branch
+
+ changeset: 4:94db611b4196
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag \xe9 for changeset ca661e7520de (esc)
+
+ changeset: 3:ca661e7520de
+ tag: \xe9 (esc)
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: utf-8 e' encoded: \xe9 (esc)
+
+ changeset: 2:650c6f3d55dd
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: latin-1 e' encoded: \xe9 (esc)
+
+ changeset: 1:0e5b7e3f9c4a
+ user: test
+ date: Mon Jan 12 13:46:40 1970 +0000
+ summary: koi8-r: \xd2\xd4\xd5\xd4\xd8 = u'\\u0440\\u0442\\u0443\\u0442\\u044c' (esc)
+
+ changeset: 0:1e78a93102a3
+ user: test
+ date: Mon Jan 12 13:46:40 1970 +0000
+ summary: latin-1 e': \xe9 = u'\\xe9' (esc)
+
+
+hg log (utf-8)
+
+ $ hg --encoding utf-8 log
+ changeset: 5:a52c0692f24a
+ branch: \xc3\xa9 (esc)
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: latin1 branch
+
+ changeset: 4:94db611b4196
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag \xc3\xa9 for changeset ca661e7520de (esc)
+
+ changeset: 3:ca661e7520de
+ tag: \xc3\xa9 (esc)
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: utf-8 e' encoded: \xc3\xa9 (esc)
+
+ changeset: 2:650c6f3d55dd
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: latin-1 e' encoded: \xc3\xa9 (esc)
+
+ changeset: 1:0e5b7e3f9c4a
+ user: test
+ date: Mon Jan 12 13:46:40 1970 +0000
+ summary: koi8-r: \xc3\x92\xc3\x94\xc3\x95\xc3\x94\xc3\x98 = u'\\u0440\\u0442\\u0443\\u0442\\u044c' (esc)
+
+ changeset: 0:1e78a93102a3
+ user: test
+ date: Mon Jan 12 13:46:40 1970 +0000
+ summary: latin-1 e': \xc3\xa9 = u'\\xe9' (esc)
+
+
+hg tags (ascii)
+
+ $ HGENCODING=ascii hg tags
+ tip 5:a52c0692f24a
+ ? 3:ca661e7520de
+
+hg tags (latin-1)
+
+ $ HGENCODING=latin-1 hg tags
+ tip 5:a52c0692f24a
+ \xe9 3:ca661e7520de (esc)
+
+hg tags (utf-8)
+
+ $ HGENCODING=utf-8 hg tags
+ tip 5:a52c0692f24a
+ \xc3\xa9 3:ca661e7520de (esc)
+
+hg branches (ascii)
+
+ $ HGENCODING=ascii hg branches
+ ? 5:a52c0692f24a
+ default 4:94db611b4196 (inactive)
+
+hg branches (latin-1)
+
+ $ HGENCODING=latin-1 hg branches
+ \xe9 5:a52c0692f24a (esc)
+ default 4:94db611b4196 (inactive)
+
+hg branches (utf-8)
+
+ $ HGENCODING=utf-8 hg branches
+ \xc3\xa9 5:a52c0692f24a (esc)
+ default 4:94db611b4196 (inactive)
+ $ echo '[ui]' >> .hg/hgrc
+ $ echo 'fallbackencoding = koi8-r' >> .hg/hgrc
+
+hg log (utf-8)
+
+ $ HGENCODING=utf-8 hg log
+ changeset: 5:a52c0692f24a
+ branch: \xc3\xa9 (esc)
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: latin1 branch
+
+ changeset: 4:94db611b4196
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag \xc3\xa9 for changeset ca661e7520de (esc)
+
+ changeset: 3:ca661e7520de
+ tag: \xc3\xa9 (esc)
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: utf-8 e' encoded: \xc3\xa9 (esc)
+
+ changeset: 2:650c6f3d55dd
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: latin-1 e' encoded: \xc3\xa9 (esc)
+
+ changeset: 1:0e5b7e3f9c4a
+ user: test
+ date: Mon Jan 12 13:46:40 1970 +0000
+ summary: koi8-r: \xd1\x80\xd1\x82\xd1\x83\xd1\x82\xd1\x8c = u'\\u0440\\u0442\\u0443\\u0442\\u044c' (esc)
+
+ changeset: 0:1e78a93102a3
+ user: test
+ date: Mon Jan 12 13:46:40 1970 +0000
+ summary: latin-1 e': \xd0\x98 = u'\\xe9' (esc)
+
+
+hg log (dolphin)
+
+ $ HGENCODING=dolphin hg log
+ abort: unknown encoding: dolphin
+ (please check your locale settings)
+ [255]
+ $ HGENCODING=ascii hg branch `cat latin-1-tag`
+ abort: decoding near '\xe9': 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)! (esc)
+ [255]
+ $ cp latin-1-tag .hg/branch
+ $ HGENCODING=latin-1 hg ci -m 'auto-promote legacy name'
+
+Test roundtrip encoding of lookup tables when not using UTF-8 (issue2763)
+
+ $ HGENCODING=latin-1 hg up `cat latin-1-tag`
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ cd ..
diff --git a/tests/test-eol-add.t b/tests/test-eol-add.t
new file mode 100644
index 0000000..aa06fed
--- /dev/null
+++ b/tests/test-eol-add.t
@@ -0,0 +1,125 @@
+Test adding .hgeol
+
+ $ cat >> $HGRCPATH <<EOF
+ > [diff]
+ > git = 1
+ > EOF
+ $ seteol () {
+ > if [ $1 = "LF" ]; then
+ > EOL='\n'
+ > else
+ > EOL='\r\n'
+ > fi
+ > }
+ $ makerepo () {
+ > echo
+ > echo "# ==== setup repository ===="
+ > echo '% hg init'
+ > hg init repo
+ > cd repo
+ > printf "first\nsecond\nthird\n" > a.txt
+ > hg commit -d '100 0' --addremove -m 'LF commit'
+ > cd ..
+ > }
+ $ dotest () {
+ > seteol $1
+ > echo
+ > echo "% hg clone repo repo-$1"
+ > hg clone repo repo-$1
+ > cd repo-$1
+ > cat > .hg/hgrc <<EOF
+ > [extensions]
+ > eol =
+ > [eol]
+ > native = LF
+ > EOF
+ > cat > .hgeol <<EOF
+ > [patterns]
+ > **.txt = native
+ > [repository]
+ > native = $1
+ > EOF
+ > echo '% hg add .hgeol'
+ > hg add .hgeol
+ > echo '% hg status'
+ > hg status
+ > echo '% hg commit'
+ > hg commit -d '200 0' -m 'Added .hgeol file'
+ > echo '% hg status'
+ > hg status
+ > echo '% hg tip -p'
+ > hg tip -p
+ > cd ..
+ > rm -r repo-$1
+ > }
+ $ makerepo
+
+ # ==== setup repository ====
+ % hg init
+ adding a.txt
+ $ dotest LF
+
+ % hg clone repo repo-LF
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % hg add .hgeol
+ % hg status
+ A .hgeol
+ % hg commit
+ % hg status
+ % hg tip -p
+ changeset: 1:33503edb53b0
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:03:20 1970 +0000
+ summary: Added .hgeol file
+
+ diff --git a/.hgeol b/.hgeol
+ new file mode 100644
+ --- /dev/null
+ +++ b/.hgeol
+ @@ -0,0 +1,4 @@
+ +[patterns]
+ +**.txt = native
+ +[repository]
+ +native = LF
+
+ $ dotest CRLF
+
+ % hg clone repo repo-CRLF
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % hg add .hgeol
+ % hg status
+ M a.txt
+ A .hgeol
+ % hg commit
+ % hg status
+ % hg tip -p
+ changeset: 1:6e64eaa9eb23
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:03:20 1970 +0000
+ summary: Added .hgeol file
+
+ diff --git a/.hgeol b/.hgeol
+ new file mode 100644
+ --- /dev/null
+ +++ b/.hgeol
+ @@ -0,0 +1,4 @@
+ +[patterns]
+ +**.txt = native
+ +[repository]
+ +native = CRLF
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,3 @@
+ -first
+ -second
+ -third
+ +first\r (esc)
+ +second\r (esc)
+ +third\r (esc)
+
+ $ rm -r repo
diff --git a/tests/test-eol-clone.t b/tests/test-eol-clone.t
new file mode 100644
index 0000000..b9b4358
--- /dev/null
+++ b/tests/test-eol-clone.t
@@ -0,0 +1,76 @@
+Testing cloning with the EOL extension
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > eol =
+ >
+ > [eol]
+ > native = CRLF
+ > EOF
+
+setup repository
+
+ $ hg init repo
+ $ cd repo
+ $ cat > .hgeol <<EOF
+ > [patterns]
+ > **.txt = native
+ > EOF
+ $ printf "first\r\nsecond\r\nthird\r\n" > a.txt
+ $ hg commit --addremove -m 'checkin'
+ adding .hgeol
+ adding a.txt
+
+Clone
+
+ $ cd ..
+ $ hg clone repo repo-2
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd repo-2
+ $ cat a.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ $ hg cat a.txt
+ first
+ second
+ third
+ $ hg remove .hgeol
+ $ hg commit -m 'remove eol'
+ $ hg push --quiet
+ $ cd ..
+
+Test clone of repo with .hgeol in working dir, but no .hgeol in tip
+
+ $ hg clone repo repo-3
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd repo-3
+
+ $ cat a.txt
+ first
+ second
+ third
+
+Test clone of revision with .hgeol
+
+ $ cd ..
+ $ hg clone -r 0 repo repo-4
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd repo-4
+ $ cat .hgeol
+ [patterns]
+ **.txt = native
+
+ $ cat a.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+
+ $ cd ..
diff --git a/tests/test-eol-hook.t b/tests/test-eol-hook.t
new file mode 100644
index 0000000..9fdfe5e
--- /dev/null
+++ b/tests/test-eol-hook.t
@@ -0,0 +1,218 @@
+Test the EOL hook
+
+ $ hg init main
+ $ cat > main/.hg/hgrc <<EOF
+ > [hooks]
+ > pretxnchangegroup = python:hgext.eol.hook
+ > EOF
+ $ hg clone main fork
+ updating to branch default
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd fork
+
+Create repo
+ $ cat > .hgeol <<EOF
+ > [patterns]
+ > mixed.txt = BIN
+ > crlf.txt = CRLF
+ > **.txt = native
+ > EOF
+ $ hg add .hgeol
+ $ hg commit -m 'Commit .hgeol'
+
+ $ printf "first\nsecond\nthird\n" > a.txt
+ $ hg add a.txt
+ $ hg commit -m 'LF a.txt'
+ $ hg push ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+
+ $ printf "first\r\nsecond\r\nthird\n" > a.txt
+ $ hg commit -m 'CRLF a.txt'
+ $ hg push ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ error: pretxnchangegroup hook failed: end-of-line check failed:
+ a.txt in a8ee6548cd86 should not have CRLF line endings
+ transaction abort!
+ rollback completed
+ abort: end-of-line check failed:
+ a.txt in a8ee6548cd86 should not have CRLF line endings
+ [255]
+
+ $ printf "first\nsecond\nthird\n" > a.txt
+ $ hg commit -m 'LF a.txt (fixed)'
+ $ hg push ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+
+ $ printf "first\nsecond\nthird\n" > crlf.txt
+ $ hg add crlf.txt
+ $ hg commit -m 'LF crlf.txt'
+ $ hg push ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ error: pretxnchangegroup hook failed: end-of-line check failed:
+ crlf.txt in 004ba2132725 should not have LF line endings
+ transaction abort!
+ rollback completed
+ abort: end-of-line check failed:
+ crlf.txt in 004ba2132725 should not have LF line endings
+ [255]
+
+ $ printf "first\r\nsecond\r\nthird\r\n" > crlf.txt
+ $ hg commit -m 'CRLF crlf.txt (fixed)'
+ $ hg push ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+
+ $ printf "first\r\nsecond" > b.txt
+ $ hg add b.txt
+ $ hg commit -m 'CRLF b.txt'
+ $ hg push ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ error: pretxnchangegroup hook failed: end-of-line check failed:
+ b.txt in fbcf9b1025f5 should not have CRLF line endings
+ transaction abort!
+ rollback completed
+ abort: end-of-line check failed:
+ b.txt in fbcf9b1025f5 should not have CRLF line endings
+ [255]
+
+ $ hg up -r -2
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ printf "some\nother\nfile" > c.txt
+ $ hg add c.txt
+ $ hg commit -m "LF c.txt, b.txt doesn't exist here"
+ created new head
+ $ hg push -f ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ error: pretxnchangegroup hook failed: end-of-line check failed:
+ b.txt in fbcf9b1025f5 should not have CRLF line endings
+ transaction abort!
+ rollback completed
+ abort: end-of-line check failed:
+ b.txt in fbcf9b1025f5 should not have CRLF line endings
+ [255]
+
+Test checkheadshook alias
+
+ $ cat > ../main/.hg/hgrc <<EOF
+ > [hooks]
+ > pretxnchangegroup = python:hgext.eol.checkheadshook
+ > EOF
+ $ hg push -f ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ error: pretxnchangegroup hook failed: end-of-line check failed:
+ b.txt in fbcf9b1025f5 should not have CRLF line endings
+ transaction abort!
+ rollback completed
+ abort: end-of-line check failed:
+ b.txt in fbcf9b1025f5 should not have CRLF line endings
+ [255]
+
+We can fix the head and push again
+
+ $ hg up 6
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ printf "first\nsecond" > b.txt
+ $ hg ci -m "remove CRLF from b.txt"
+ $ hg push -f ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 2 files (+1 heads)
+ $ hg -R ../main rollback
+ repository tip rolled back to revision 5 (undo push)
+
+Test it still fails with checkallhook
+
+ $ cat > ../main/.hg/hgrc <<EOF
+ > [hooks]
+ > pretxnchangegroup = python:hgext.eol.checkallhook
+ > EOF
+ $ hg push -f ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 2 files (+1 heads)
+ error: pretxnchangegroup hook failed: end-of-line check failed:
+ b.txt in fbcf9b1025f5 should not have CRLF line endings
+ transaction abort!
+ rollback completed
+ abort: end-of-line check failed:
+ b.txt in fbcf9b1025f5 should not have CRLF line endings
+ [255]
+
+But we can push the clean head
+
+ $ hg push -r7 -f ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+Test multiple files/revisions output
+
+ $ printf "another\r\nbad\r\none" > d.txt
+ $ hg add d.txt
+ $ hg ci -m "add d.txt"
+ $ hg push -f ../main
+ pushing to ../main
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 2 files (+1 heads)
+ error: pretxnchangegroup hook failed: end-of-line check failed:
+ d.txt in a7040e68714f should not have CRLF line endings
+ b.txt in fbcf9b1025f5 should not have CRLF line endings
+ transaction abort!
+ rollback completed
+ abort: end-of-line check failed:
+ d.txt in a7040e68714f should not have CRLF line endings
+ b.txt in fbcf9b1025f5 should not have CRLF line endings
+ [255]
+
+ $ cd ..
diff --git a/tests/test-eol-patch.t b/tests/test-eol-patch.t
new file mode 100644
index 0000000..e2786f8
--- /dev/null
+++ b/tests/test-eol-patch.t
@@ -0,0 +1,400 @@
+Test EOL patching
+
+ $ cat >> $HGRCPATH <<EOF
+ > [diff]
+ > git = 1
+ > EOF
+
+Set up helpers
+
+ $ seteol () {
+ > if [ $1 = "LF" ]; then
+ > EOL='\n'
+ > else
+ > EOL='\r\n'
+ > fi
+ > }
+
+ $ makerepo () {
+ > seteol $1
+ > echo
+ > echo "# ==== setup $1 repository ===="
+ > echo '% hg init'
+ > hg init repo
+ > cd repo
+ > cat > .hgeol <<EOF
+ > [repository]
+ > native = $1
+ > [patterns]
+ > unix.txt = LF
+ > win.txt = CRLF
+ > **.txt = native
+ > EOF
+ > printf "first\r\nsecond\r\nthird\r\n" > win.txt
+ > printf "first\nsecond\nthird\n" > unix.txt
+ > printf "first${EOL}second${EOL}third${EOL}" > native.txt
+ > hg commit --addremove -m 'checkin'
+ > cd ..
+ > }
+
+ $ dotest () {
+ > seteol $1
+ > echo
+ > echo "% hg clone repo repo-$1"
+ > hg clone --noupdate repo repo-$1
+ > cd repo-$1
+ > cat > .hg/hgrc <<EOF
+ > [extensions]
+ > eol =
+ > [eol]
+ > native = $1
+ > EOF
+ > hg update
+ > echo '% native.txt'
+ > cat native.txt
+ > echo '% unix.txt'
+ > cat unix.txt
+ > echo '% win.txt'
+ > cat win.txt
+ > printf "first${EOL}third${EOL}" > native.txt
+ > printf "first\r\nthird\r\n" > win.txt
+ > printf "first\nthird\n" > unix.txt
+ > echo '% hg diff'
+ > hg diff > p
+ > cat p
+ > echo '% hg revert'
+ > hg revert --all
+ > echo '% hg import'
+ > hg import -m 'patch' p
+ > echo '% native.txt'
+ > cat native.txt
+ > echo '% unix.txt'
+ > cat unix.txt
+ > echo '% win.txt'
+ > cat win.txt
+ > echo '% hg diff -c tip'
+ > hg diff -c tip
+ > cd ..
+ > rm -r repo-$1
+ > }
+
+Run tests
+
+ $ makerepo LF
+
+ # ==== setup LF repository ====
+ % hg init
+ adding .hgeol
+ adding native.txt
+ adding unix.txt
+ adding win.txt
+ $ dotest LF
+
+ % hg clone repo repo-LF
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % native.txt
+ first
+ second
+ third
+ % unix.txt
+ first
+ second
+ third
+ % win.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % hg diff
+ diff --git a/native.txt b/native.txt
+ --- a/native.txt
+ +++ b/native.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/unix.txt b/unix.txt
+ --- a/unix.txt
+ +++ b/unix.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/win.txt b/win.txt
+ --- a/win.txt
+ +++ b/win.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ % hg revert
+ reverting native.txt
+ reverting unix.txt
+ reverting win.txt
+ % hg import
+ applying p
+ % native.txt
+ first
+ third
+ % unix.txt
+ first
+ third
+ % win.txt
+ first\r (esc)
+ third\r (esc)
+ % hg diff -c tip
+ diff --git a/native.txt b/native.txt
+ --- a/native.txt
+ +++ b/native.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/unix.txt b/unix.txt
+ --- a/unix.txt
+ +++ b/unix.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/win.txt b/win.txt
+ --- a/win.txt
+ +++ b/win.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ $ dotest CRLF
+
+ % hg clone repo repo-CRLF
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % native.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % unix.txt
+ first
+ second
+ third
+ % win.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % hg diff
+ diff --git a/native.txt b/native.txt
+ --- a/native.txt
+ +++ b/native.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/unix.txt b/unix.txt
+ --- a/unix.txt
+ +++ b/unix.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/win.txt b/win.txt
+ --- a/win.txt
+ +++ b/win.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ % hg revert
+ reverting native.txt
+ reverting unix.txt
+ reverting win.txt
+ % hg import
+ applying p
+ % native.txt
+ first\r (esc)
+ third\r (esc)
+ % unix.txt
+ first
+ third
+ % win.txt
+ first\r (esc)
+ third\r (esc)
+ % hg diff -c tip
+ diff --git a/native.txt b/native.txt
+ --- a/native.txt
+ +++ b/native.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/unix.txt b/unix.txt
+ --- a/unix.txt
+ +++ b/unix.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/win.txt b/win.txt
+ --- a/win.txt
+ +++ b/win.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ $ rm -r repo
+ $ makerepo CRLF
+
+ # ==== setup CRLF repository ====
+ % hg init
+ adding .hgeol
+ adding native.txt
+ adding unix.txt
+ adding win.txt
+ $ dotest LF
+
+ % hg clone repo repo-LF
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % native.txt
+ first
+ second
+ third
+ % unix.txt
+ first
+ second
+ third
+ % win.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % hg diff
+ diff --git a/native.txt b/native.txt
+ --- a/native.txt
+ +++ b/native.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ diff --git a/unix.txt b/unix.txt
+ --- a/unix.txt
+ +++ b/unix.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/win.txt b/win.txt
+ --- a/win.txt
+ +++ b/win.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ % hg revert
+ reverting native.txt
+ reverting unix.txt
+ reverting win.txt
+ % hg import
+ applying p
+ % native.txt
+ first
+ third
+ % unix.txt
+ first
+ third
+ % win.txt
+ first\r (esc)
+ third\r (esc)
+ % hg diff -c tip
+ diff --git a/native.txt b/native.txt
+ --- a/native.txt
+ +++ b/native.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ diff --git a/unix.txt b/unix.txt
+ --- a/unix.txt
+ +++ b/unix.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/win.txt b/win.txt
+ --- a/win.txt
+ +++ b/win.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ $ dotest CRLF
+
+ % hg clone repo repo-CRLF
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % native.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % unix.txt
+ first
+ second
+ third
+ % win.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % hg diff
+ diff --git a/native.txt b/native.txt
+ --- a/native.txt
+ +++ b/native.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ diff --git a/unix.txt b/unix.txt
+ --- a/unix.txt
+ +++ b/unix.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/win.txt b/win.txt
+ --- a/win.txt
+ +++ b/win.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ % hg revert
+ reverting native.txt
+ reverting unix.txt
+ reverting win.txt
+ % hg import
+ applying p
+ % native.txt
+ first\r (esc)
+ third\r (esc)
+ % unix.txt
+ first
+ third
+ % win.txt
+ first\r (esc)
+ third\r (esc)
+ % hg diff -c tip
+ diff --git a/native.txt b/native.txt
+ --- a/native.txt
+ +++ b/native.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ diff --git a/unix.txt b/unix.txt
+ --- a/unix.txt
+ +++ b/unix.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ diff --git a/win.txt b/win.txt
+ --- a/win.txt
+ +++ b/win.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ $ rm -r repo
diff --git a/tests/test-eol-tag.t b/tests/test-eol-tag.t
new file mode 100644
index 0000000..56fad6b
--- /dev/null
+++ b/tests/test-eol-tag.t
@@ -0,0 +1,39 @@
+http://mercurial.selenic.com/bts/issue2493
+
+Testing tagging with the EOL extension
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > eol =
+ >
+ > [eol]
+ > native = CRLF
+ > EOF
+
+setup repository
+
+ $ hg init repo
+ $ cd repo
+ $ cat > .hgeol <<EOF
+ > [patterns]
+ > ** = native
+ > EOF
+ $ printf "first\r\nsecond\r\nthird\r\n" > a.txt
+ $ hg commit --addremove -m 'checkin'
+ adding .hgeol
+ adding a.txt
+
+Tag:
+
+ $ hg tag 1.0
+
+Rewrite .hgtags file as it would look on a new checkout:
+
+ $ hg update -q null
+ $ hg update -q
+
+Touch .hgtags file again:
+
+ $ hg tag 2.0
+
+ $ cd ..
diff --git a/tests/test-eol-update.t b/tests/test-eol-update.t
new file mode 100644
index 0000000..2189cfa
--- /dev/null
+++ b/tests/test-eol-update.t
@@ -0,0 +1,152 @@
+Test EOL update
+
+ $ cat >> $HGRCPATH <<EOF
+ > [diff]
+ > git = 1
+ > EOF
+
+ $ seteol () {
+ > if [ $1 = "LF" ]; then
+ > EOL='\n'
+ > else
+ > EOL='\r\n'
+ > fi
+ > }
+
+ $ makerepo () {
+ > echo
+ > echo "# ==== setup repository ===="
+ > echo '% hg init'
+ > hg init repo
+ > cd repo
+ >
+ > cat > .hgeol <<EOF
+ > [patterns]
+ > **.txt = LF
+ > EOF
+ >
+ > printf "first\nsecond\nthird\n" > a.txt
+ > hg commit --addremove -m 'LF commit'
+ >
+ > cat > .hgeol <<EOF
+ > [patterns]
+ > **.txt = CRLF
+ > EOF
+ >
+ > printf "first\r\nsecond\r\nthird\r\n" > a.txt
+ > hg commit -m 'CRLF commit'
+ >
+ > cd ..
+ > }
+
+ $ dotest () {
+ > seteol $1
+ >
+ > echo
+ > echo "% hg clone repo repo-$1"
+ > hg clone --noupdate repo repo-$1
+ > cd repo-$1
+ >
+ > cat > .hg/hgrc <<EOF
+ > [extensions]
+ > eol =
+ > EOF
+ >
+ > hg update
+ >
+ > echo '% a.txt (before)'
+ > cat a.txt
+ >
+ > printf "first${EOL}third${EOL}" > a.txt
+ >
+ > echo '% a.txt (after)'
+ > cat a.txt
+ > echo '% hg diff'
+ > hg diff
+ >
+ > echo '% hg update 0'
+ > hg update 0
+ >
+ > echo '% a.txt'
+ > cat a.txt
+ > echo '% hg diff'
+ > hg diff
+ >
+ >
+ > cd ..
+ > rm -r repo-$1
+ > }
+
+ $ makerepo
+
+ # ==== setup repository ====
+ % hg init
+ adding .hgeol
+ adding a.txt
+ $ dotest LF
+
+ % hg clone repo repo-LF
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % a.txt (before)
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % a.txt (after)
+ first
+ third
+ % hg diff
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ % hg update 0
+ merging a.txt
+ 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ % a.txt
+ first
+ third
+ % hg diff
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ $ dotest CRLF
+
+ % hg clone repo repo-CRLF
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % a.txt (before)
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % a.txt (after)
+ first\r (esc)
+ third\r (esc)
+ % hg diff
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,2 @@
+ first\r (esc)
+ -second\r (esc)
+ third\r (esc)
+ % hg update 0
+ merging a.txt
+ 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ % a.txt
+ first
+ third
+ % hg diff
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,2 @@
+ first
+ -second
+ third
+ $ rm -r repo
diff --git a/tests/test-eol.t b/tests/test-eol.t
new file mode 100644
index 0000000..2b8f585
--- /dev/null
+++ b/tests/test-eol.t
@@ -0,0 +1,528 @@
+Test EOL extension
+
+ $ cat >> $HGRCPATH <<EOF
+ > [diff]
+ > git = True
+ > EOF
+
+Set up helpers
+
+ $ cat > switch-eol.py <<EOF
+ > import sys
+ > try:
+ > import os, msvcrt
+ > msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
+ > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+ > except ImportError:
+ > pass
+ > (old, new) = sys.argv[1] == 'LF' and ('\n', '\r\n') or ('\r\n', '\n')
+ > print "%% switching encoding from %r to %r" % (old, new)
+ > for path in sys.argv[2:]:
+ > data = file(path, 'rb').read()
+ > data = data.replace(old, new)
+ > file(path, 'wb').write(data)
+ > EOF
+
+ $ seteol () {
+ > if [ $1 = "LF" ]; then
+ > EOL='\n'
+ > else
+ > EOL='\r\n'
+ > fi
+ > }
+
+ $ makerepo () {
+ > seteol $1
+ > echo "% setup $1 repository"
+ > hg init repo
+ > cd repo
+ > cat > .hgeol <<EOF
+ > [repository]
+ > native = $1
+ > [patterns]
+ > mixed.txt = BIN
+ > **.txt = native
+ > EOF
+ > printf "first${EOL}second${EOL}third${EOL}" > a.txt
+ > hg commit --addremove -m 'checkin'
+ > echo
+ > cd ..
+ > }
+
+ $ dotest () {
+ > seteol $1
+ > echo "% hg clone repo repo-$1"
+ > hg clone --noupdate repo repo-$1
+ > cd repo-$1
+ > cat > .hg/hgrc <<EOF
+ > [extensions]
+ > eol =
+ > [eol]
+ > native = $1
+ > EOF
+ > hg update
+ > echo '% a.txt'
+ > cat a.txt
+ > echo '% hg cat a.txt'
+ > hg cat a.txt
+ > printf "fourth${EOL}" >> a.txt
+ > echo '% a.txt'
+ > cat a.txt
+ > hg diff
+ > python ../switch-eol.py $1 a.txt
+ > echo '% hg diff only reports a single changed line:'
+ > hg diff
+ > echo "% reverting back to $1 format"
+ > hg revert a.txt
+ > cat a.txt
+ > printf "first\r\nsecond\n" > mixed.txt
+ > hg add mixed.txt
+ > echo "% hg commit of inconsistent .txt file marked as binary (should work)"
+ > hg commit -m 'binary file'
+ > echo "% hg commit of inconsistent .txt file marked as native (should fail)"
+ > printf "first\nsecond\r\nthird\nfourth\r\n" > a.txt
+ > hg commit -m 'inconsistent file'
+ > echo "% hg commit --config eol.only-consistent=False (should work)"
+ > hg commit --config eol.only-consistent=False -m 'inconsistent file'
+ > echo "% hg commit of binary .txt file marked as native (binary files always okay)"
+ > printf "first${EOL}\0${EOL}third${EOL}" > a.txt
+ > hg commit -m 'binary file'
+ > cd ..
+ > rm -r repo-$1
+ > }
+
+ $ makemixedrepo () {
+ > echo
+ > echo "# setup $1 repository"
+ > hg init mixed
+ > cd mixed
+ > printf "foo\r\nbar\r\nbaz\r\n" > win.txt
+ > printf "foo\nbar\nbaz\n" > unix.txt
+ > #printf "foo\r\nbar\nbaz\r\n" > mixed.txt
+ > hg commit --addremove -m 'created mixed files'
+ > echo "# setting repository-native EOLs to $1"
+ > cat > .hgeol <<EOF
+ > [repository]
+ > native = $1
+ > [patterns]
+ > **.txt = native
+ > EOF
+ > hg commit --addremove -m 'added .hgeol'
+ > cd ..
+ > }
+
+ $ testmixed () {
+ > echo
+ > echo "% hg clone mixed mixed-$1"
+ > hg clone mixed mixed-$1
+ > cd mixed-$1
+ > echo '% hg status (eol extension not yet activated)'
+ > hg status
+ > cat > .hg/hgrc <<EOF
+ > [extensions]
+ > eol =
+ > [eol]
+ > native = $1
+ > EOF
+ > echo '% hg status (eol activated)'
+ > hg status
+ > echo '% hg commit'
+ > hg commit -m 'synchronized EOLs'
+ > echo '% hg status'
+ > hg status
+ > cd ..
+ > rm -r mixed-$1
+ > }
+
+Basic tests
+
+ $ makerepo LF
+ % setup LF repository
+ adding .hgeol
+ adding a.txt
+
+ $ dotest LF
+ % hg clone repo repo-LF
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % a.txt
+ first
+ second
+ third
+ % hg cat a.txt
+ first
+ second
+ third
+ % a.txt
+ first
+ second
+ third
+ fourth
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,4 @@
+ first
+ second
+ third
+ +fourth
+ % switching encoding from '\n' to '\r\n'
+ % hg diff only reports a single changed line:
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,4 @@
+ first
+ second
+ third
+ +fourth
+ % reverting back to LF format
+ first
+ second
+ third
+ % hg commit of inconsistent .txt file marked as binary (should work)
+ % hg commit of inconsistent .txt file marked as native (should fail)
+ abort: inconsistent newline style in a.txt
+
+ % hg commit --config eol.only-consistent=False (should work)
+ % hg commit of binary .txt file marked as native (binary files always okay)
+ $ dotest CRLF
+ % hg clone repo repo-CRLF
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % a.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % hg cat a.txt
+ first
+ second
+ third
+ % a.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ fourth\r (esc)
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,4 @@
+ first
+ second
+ third
+ +fourth
+ % switching encoding from '\r\n' to '\n'
+ % hg diff only reports a single changed line:
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,4 @@
+ first
+ second
+ third
+ +fourth
+ % reverting back to CRLF format
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % hg commit of inconsistent .txt file marked as binary (should work)
+ % hg commit of inconsistent .txt file marked as native (should fail)
+ abort: inconsistent newline style in a.txt
+
+ % hg commit --config eol.only-consistent=False (should work)
+ % hg commit of binary .txt file marked as native (binary files always okay)
+ $ rm -r repo
+ $ makerepo CRLF
+ % setup CRLF repository
+ adding .hgeol
+ adding a.txt
+
+ $ dotest LF
+ % hg clone repo repo-LF
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % a.txt
+ first
+ second
+ third
+ % hg cat a.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % a.txt
+ first
+ second
+ third
+ fourth
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,4 @@
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ +fourth\r (esc)
+ % switching encoding from '\n' to '\r\n'
+ % hg diff only reports a single changed line:
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,4 @@
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ +fourth\r (esc)
+ % reverting back to LF format
+ first
+ second
+ third
+ % hg commit of inconsistent .txt file marked as binary (should work)
+ % hg commit of inconsistent .txt file marked as native (should fail)
+ abort: inconsistent newline style in a.txt
+
+ % hg commit --config eol.only-consistent=False (should work)
+ % hg commit of binary .txt file marked as native (binary files always okay)
+ $ dotest CRLF
+ % hg clone repo repo-CRLF
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % a.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % hg cat a.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % a.txt
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ fourth\r (esc)
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,4 @@
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ +fourth\r (esc)
+ % switching encoding from '\r\n' to '\n'
+ % hg diff only reports a single changed line:
+ diff --git a/a.txt b/a.txt
+ --- a/a.txt
+ +++ b/a.txt
+ @@ -1,3 +1,4 @@
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ +fourth\r (esc)
+ % reverting back to CRLF format
+ first\r (esc)
+ second\r (esc)
+ third\r (esc)
+ % hg commit of inconsistent .txt file marked as binary (should work)
+ % hg commit of inconsistent .txt file marked as native (should fail)
+ abort: inconsistent newline style in a.txt
+
+ % hg commit --config eol.only-consistent=False (should work)
+ % hg commit of binary .txt file marked as native (binary files always okay)
+ $ rm -r repo
+
+Mixed tests
+
+ $ makemixedrepo LF
+
+ # setup LF repository
+ adding unix.txt
+ adding win.txt
+ # setting repository-native EOLs to LF
+ adding .hgeol
+ $ testmixed LF
+
+ % hg clone mixed mixed-LF
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % hg status (eol extension not yet activated)
+ % hg status (eol activated)
+ M win.txt
+ % hg commit
+ % hg status
+ $ testmixed CRLF
+
+ % hg clone mixed mixed-CRLF
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % hg status (eol extension not yet activated)
+ % hg status (eol activated)
+ M win.txt
+ % hg commit
+ % hg status
+ $ rm -r mixed
+ $ makemixedrepo CRLF
+
+ # setup CRLF repository
+ adding unix.txt
+ adding win.txt
+ # setting repository-native EOLs to CRLF
+ adding .hgeol
+ $ testmixed LF
+
+ % hg clone mixed mixed-LF
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % hg status (eol extension not yet activated)
+ % hg status (eol activated)
+ M unix.txt
+ % hg commit
+ % hg status
+ $ testmixed CRLF
+
+ % hg clone mixed mixed-CRLF
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % hg status (eol extension not yet activated)
+ % hg status (eol activated)
+ M unix.txt
+ % hg commit
+ % hg status
+ $ rm -r mixed
+
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo 'eol =' >> $HGRCPATH
+
+#if unix-permissions
+
+Test issue2569 -- eol extension takes write lock on reading:
+
+ $ hg init repo
+ $ cd repo
+ $ touch .hgeol
+ $ hg status
+ ? .hgeol
+ $ chmod -R -w .hg
+ $ sleep 1
+ $ touch .hgeol
+ $ hg status --traceback
+ ? .hgeol
+ $ chmod -R u+w .hg
+ $ cd ..
+
+#endif
+
+Test cleverencode: and cleverdecode: aliases for win32text extension
+
+ $ echo '[encode]' >> $HGRCPATH
+ $ echo '**.txt = cleverencode:' >> $HGRCPATH
+ $ echo '[decode]' >> $HGRCPATH
+ $ echo '**.txt = cleverdecode:' >> $HGRCPATH
+
+ $ hg init win32compat
+ $ cd win32compat
+ $ printf "foo\r\nbar\r\nbaz\r\n" > win.txt
+ $ printf "foo\nbar\nbaz\n" > unix.txt
+ $ hg add
+ adding unix.txt
+ adding win.txt
+ $ hg commit -m checkin
+
+Check that both files have LF line-endings in the repository:
+
+ $ hg cat win.txt
+ foo
+ bar
+ baz
+ $ hg cat unix.txt
+ foo
+ bar
+ baz
+
+Test handling of a broken .hgeol file:
+
+ $ touch .hgeol
+ $ hg add .hgeol
+ $ hg commit -m 'clean version'
+ $ echo "bad" > .hgeol
+ $ hg status
+ warning: ignoring .hgeol file due to parse error at .hgeol:1: bad
+ M .hgeol
+ $ hg revert .hgeol
+ warning: ignoring .hgeol file due to parse error at .hgeol:1: bad
+ $ hg status
+ ? .hgeol.orig
+
+Test eol.only-consistent can be specified in .hgeol
+
+ $ cd $TESTTMP
+ $ hg init only-consistent
+ $ cd only-consistent
+ $ printf "first\nsecond\r\n" > a.txt
+ $ hg add a.txt
+ $ cat > .hgeol << EOF
+ > [eol]
+ > only-consistent = True
+ > EOF
+ $ hg commit -m 'inconsistent'
+ abort: inconsistent newline style in a.txt
+
+ [255]
+ $ cat > .hgeol << EOF
+ > [eol]
+ > only-consistent = False
+ > EOF
+ $ hg commit -m 'consistent'
+
+
+Test trailing newline
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > eol=
+ > EOF
+
+setup repository
+
+ $ cd $TESTTMP
+ $ hg init trailing
+ $ cd trailing
+ $ cat > .hgeol <<EOF
+ > [patterns]
+ > **.txt = native
+ > [eol]
+ > fix-trailing-newline = False
+ > EOF
+
+add text without trailing newline
+
+ $ printf "first\nsecond" > a.txt
+ $ hg commit --addremove -m 'checking in'
+ adding .hgeol
+ adding a.txt
+ $ rm a.txt
+ $ hg update -C -q
+ $ cat a.txt
+ first
+ second (no-eol)
+
+ $ cat > .hgeol <<EOF
+ > [patterns]
+ > **.txt = native
+ > [eol]
+ > fix-trailing-newline = True
+ > EOF
+ $ printf "third\nfourth" > a.txt
+ $ hg commit -m 'checking in with newline fix'
+ $ rm a.txt
+ $ hg update -C -q
+ $ cat a.txt
+ third
+ fourth
+
+append a line without trailing newline
+
+ $ printf "fifth" >> a.txt
+ $ hg commit -m 'adding another line line'
+ $ rm a.txt
+ $ hg update -C -q
+ $ cat a.txt
+ third
+ fourth
+ fifth
+
+ $ cd ..
diff --git a/tests/test-eolfilename.t b/tests/test-eolfilename.t
new file mode 100644
index 0000000..632d0c0
--- /dev/null
+++ b/tests/test-eolfilename.t
@@ -0,0 +1,72 @@
+http://mercurial.selenic.com/bts/issue352
+
+ $ "$TESTDIR/hghave" eol-in-paths || exit 80
+
+test issue352
+
+ $ hg init foo
+ $ cd foo
+ $ A=`printf 'he\rllo'`
+ $ echo foo > "$A"
+ $ hg add
+ adding he\rllo (esc)
+ abort: '\n' and '\r' disallowed in filenames: 'he\rllo'
+ [255]
+ $ hg ci -A -m m
+ adding he\rllo (esc)
+ abort: '\n' and '\r' disallowed in filenames: 'he\rllo'
+ [255]
+ $ rm "$A"
+ $ echo foo > "hell
+ > o"
+ $ hg add
+ adding hell
+ o
+ abort: '\n' and '\r' disallowed in filenames: 'hell\no'
+ [255]
+ $ hg ci -A -m m
+ adding hell
+ o
+ abort: '\n' and '\r' disallowed in filenames: 'hell\no'
+ [255]
+ $ echo foo > "$A"
+ $ hg debugwalk
+ f he\rllo he\rllo (esc)
+ f hell
+ o hell
+ o
+
+ $ echo bla > quickfox
+ $ hg add quickfox
+ $ hg ci -m 2
+ $ A=`printf 'quick\rfox'`
+ $ hg cp quickfox "$A"
+ abort: '\n' and '\r' disallowed in filenames: 'quick\rfox'
+ [255]
+ $ hg mv quickfox "$A"
+ abort: '\n' and '\r' disallowed in filenames: 'quick\rfox'
+ [255]
+
+http://mercurial.selenic.com/bts/issue2036
+
+ $ cd ..
+
+test issue2039
+
+ $ hg init bar
+ $ cd bar
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "color=" >> $HGRCPATH
+ $ echo "[color]" >> $HGRCPATH
+ $ echo "mode = ansi" >> $HGRCPATH
+ $ A=`printf 'foo\nbar'`
+ $ B=`printf 'foo\nbar.baz'`
+ $ touch "$A"
+ $ touch "$B"
+ $ hg status --color=always
+ \x1b[0;35;1;4m? foo\x1b[0m (esc)
+ \x1b[0;35;1;4mbar\x1b[0m (esc)
+ \x1b[0;35;1;4m? foo\x1b[0m (esc)
+ \x1b[0;35;1;4mbar.baz\x1b[0m (esc)
+
+ $ cd ..
diff --git a/tests/test-excessive-merge.t b/tests/test-excessive-merge.t
new file mode 100644
index 0000000..8d324b8
--- /dev/null
+++ b/tests/test-excessive-merge.t
@@ -0,0 +1,101 @@
+ $ hg init
+
+ $ echo foo > a
+ $ echo foo > b
+ $ hg add a b
+
+ $ hg ci -m "test"
+
+ $ echo blah > a
+
+ $ hg ci -m "branch a"
+
+ $ hg co 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo blah > b
+
+ $ hg ci -m "branch b"
+ created new head
+ $ HGMERGE=true hg merge 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg ci -m "merge b/a -> blah"
+
+ $ hg co 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ HGMERGE=true hg merge 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m "merge a/b -> blah"
+ created new head
+
+ $ hg log
+ changeset: 4:2ee31f665a86
+ tag: tip
+ parent: 1:96155394af80
+ parent: 2:92cc4c306b19
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: merge a/b -> blah
+
+ changeset: 3:e16a66a37edd
+ parent: 2:92cc4c306b19
+ parent: 1:96155394af80
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: merge b/a -> blah
+
+ changeset: 2:92cc4c306b19
+ parent: 0:5e0375449e74
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: branch b
+
+ changeset: 1:96155394af80
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: branch a
+
+ changeset: 0:5e0375449e74
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: test
+
+ $ hg debugindex --changelog
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 60 ..... 0 5e0375449e74 000000000000 000000000000 (re)
+ 1 60 62 ..... 1 96155394af80 5e0375449e74 000000000000 (re)
+ 2 122 62 ..... 2 92cc4c306b19 5e0375449e74 000000000000 (re)
+ 3 184 69 ..... 3 e16a66a37edd 92cc4c306b19 96155394af80 (re)
+ 4 253 29 ..... 4 2ee31f665a86 96155394af80 92cc4c306b19 (re)
+
+revision 1
+ $ hg manifest --debug 1
+ 79d7492df40aa0fa093ec4209be78043c181f094 644 a
+ 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 b
+revision 2
+ $ hg manifest --debug 2
+ 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 a
+ 79d7492df40aa0fa093ec4209be78043c181f094 644 b
+revision 3
+ $ hg manifest --debug 3
+ 79d7492df40aa0fa093ec4209be78043c181f094 644 a
+ 79d7492df40aa0fa093ec4209be78043c181f094 644 b
+revision 4
+ $ hg manifest --debug 4
+ 79d7492df40aa0fa093ec4209be78043c181f094 644 a
+ 79d7492df40aa0fa093ec4209be78043c181f094 644 b
+
+ $ hg debugindex a
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 5 ..... 0 2ed2a3912a0b 000000000000 000000000000 (re)
+ 1 5 6 ..... 1 79d7492df40a 2ed2a3912a0b 000000000000 (re)
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 5 changesets, 4 total revisions
diff --git a/tests/test-execute-bit.t b/tests/test-execute-bit.t
new file mode 100644
index 0000000..ad49bb2
--- /dev/null
+++ b/tests/test-execute-bit.t
@@ -0,0 +1,28 @@
+ $ "$TESTDIR/hghave" execbit || exit 80
+
+ $ hg init
+ $ echo a > a
+ $ hg ci -Am'not executable'
+ adding a
+
+ $ chmod +x a
+ $ hg ci -m'executable'
+ $ hg id
+ 79abf14474dc tip
+
+Make sure we notice the change of mode if the cached size == -1:
+
+ $ hg rm a
+ $ hg revert -r 0 a
+ $ hg debugstate
+ n 0 -1 unset a
+ $ hg status
+ M a
+
+ $ hg up 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ d69afc33ff8a
+ $ test -x a && echo executable -- bad || echo not executable -- good
+ not executable -- good
+
diff --git a/tests/test-export.t b/tests/test-export.t
new file mode 100644
index 0000000..a371f7b
--- /dev/null
+++ b/tests/test-export.t
@@ -0,0 +1,147 @@
+ $ hg init repo
+ $ cd repo
+ $ touch foo
+ $ hg add foo
+ $ for i in 0 1 2 3 4 5 6 7 8 9 10 11; do
+ > echo "foo-$i" >> foo
+ > hg ci -m "foo-$i"
+ > done
+
+ $ for out in "%nof%N" "%%%H" "%b-%R" "%h" "%r" "%m"; do
+ > echo
+ > echo "# foo-$out.patch"
+ > hg export -v -o "foo-$out.patch" 2:tip
+ > done
+
+ # foo-%nof%N.patch
+ exporting patches:
+ foo-01of10.patch
+ foo-02of10.patch
+ foo-03of10.patch
+ foo-04of10.patch
+ foo-05of10.patch
+ foo-06of10.patch
+ foo-07of10.patch
+ foo-08of10.patch
+ foo-09of10.patch
+ foo-10of10.patch
+
+ # foo-%%%H.patch
+ exporting patches:
+ foo-%617188a1c80f869a7b66c85134da88a6fb145f67.patch
+ foo-%dd41a5ff707a5225204105611ba49cc5c229d55f.patch
+ foo-%f95a5410f8664b6e1490a4af654e4b7d41a7b321.patch
+ foo-%4346bcfde53b4d9042489078bcfa9c3e28201db2.patch
+ foo-%afda8c3a009cc99449a05ad8aa4655648c4ecd34.patch
+ foo-%35284ce2b6b99c9d2ac66268fe99e68e1974e1aa.patch
+ foo-%9688c41894e6931305fa7165a37f6568050b4e9b.patch
+ foo-%747d3c68f8ec44bb35816bfcd59aeb50b9654c2f.patch
+ foo-%5f17a83f5fbd9414006a5e563eab4c8a00729efd.patch
+ foo-%f3acbafac161ec68f1598af38f794f28847ca5d3.patch
+
+ # foo-%b-%R.patch
+ exporting patches:
+ foo-repo-2.patch
+ foo-repo-3.patch
+ foo-repo-4.patch
+ foo-repo-5.patch
+ foo-repo-6.patch
+ foo-repo-7.patch
+ foo-repo-8.patch
+ foo-repo-9.patch
+ foo-repo-10.patch
+ foo-repo-11.patch
+
+ # foo-%h.patch
+ exporting patches:
+ foo-617188a1c80f.patch
+ foo-dd41a5ff707a.patch
+ foo-f95a5410f866.patch
+ foo-4346bcfde53b.patch
+ foo-afda8c3a009c.patch
+ foo-35284ce2b6b9.patch
+ foo-9688c41894e6.patch
+ foo-747d3c68f8ec.patch
+ foo-5f17a83f5fbd.patch
+ foo-f3acbafac161.patch
+
+ # foo-%r.patch
+ exporting patches:
+ foo-02.patch
+ foo-03.patch
+ foo-04.patch
+ foo-05.patch
+ foo-06.patch
+ foo-07.patch
+ foo-08.patch
+ foo-09.patch
+ foo-10.patch
+ foo-11.patch
+
+ # foo-%m.patch
+ exporting patches:
+ foo-foo_2.patch
+ foo-foo_3.patch
+ foo-foo_4.patch
+ foo-foo_5.patch
+ foo-foo_6.patch
+ foo-foo_7.patch
+ foo-foo_8.patch
+ foo-foo_9.patch
+ foo-foo_10.patch
+ foo-foo_11.patch
+
+Exporting 4 changesets to a file:
+
+ $ hg export -o export_internal 1 2 3 4
+ $ grep HG export_internal | wc -l
+ \s*4 (re)
+
+Exporting 4 changesets to a file:
+
+ $ hg export 1 2 3 4 | grep HG | wc -l
+ \s*4 (re)
+
+Exporting revision -2 to a file:
+
+ $ hg export -- -2
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Node ID 5f17a83f5fbd9414006a5e563eab4c8a00729efd
+ # Parent 747d3c68f8ec44bb35816bfcd59aeb50b9654c2f
+ foo-10
+
+ diff -r 747d3c68f8ec -r 5f17a83f5fbd foo
+ --- a/foo Thu Jan 01 00:00:00 1970 +0000
+ +++ b/foo Thu Jan 01 00:00:00 1970 +0000
+ @@ -8,3 +8,4 @@
+ foo-7
+ foo-8
+ foo-9
+ +foo-10
+
+Checking if only alphanumeric characters are used in the file name (%m option):
+
+ $ echo "line" >> foo
+ $ hg commit -m " !\"#$%&(,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\`abcdefghijklmnopqrstuvwxyz{|}~"
+ $ hg export -v -o %m.patch tip
+ exporting patch:
+ ____________0123456789_______ABCDEFGHIJKLMNOPQRSTUVWXYZ______abcdefghijklmnopqrstuvwxyz____.patch
+
+Catch exporting unknown revisions (especially empty revsets, see issue3353)
+
+ $ hg export
+ abort: export requires at least one changeset
+ [255]
+ $ hg export ""
+ hg: parse error: empty query
+ [255]
+ $ hg export 999
+ abort: unknown revision '999'!
+ [255]
+ $ hg export "not all()"
+ abort: export requires at least one changeset
+ [255]
+
+ $ cd ..
diff --git a/tests/test-extdiff.t b/tests/test-extdiff.t
new file mode 100644
index 0000000..d4190c4
--- /dev/null
+++ b/tests/test-extdiff.t
@@ -0,0 +1,204 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "extdiff=" >> $HGRCPATH
+
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ echo b > b
+ $ hg add
+ adding a
+ adding b
+
+Should diff cloned directories:
+
+ $ hg extdiff -o -r $opt
+ Only in a: a
+ Only in a: b
+ [1]
+
+ $ echo "[extdiff]" >> $HGRCPATH
+ $ echo "cmd.falabala=echo" >> $HGRCPATH
+ $ echo "opts.falabala=diffing" >> $HGRCPATH
+
+ $ hg falabala
+ diffing a.000000000000 a
+ [1]
+
+ $ hg help falabala
+ hg falabala [OPTION]... [FILE]...
+
+ use 'echo' to diff repository (or selected files)
+
+ Show differences between revisions for the specified files, using the
+ 'echo' program.
+
+ When two revision arguments are given, then changes are shown between
+ those revisions. If only one revision is specified then that revision is
+ compared to the working directory, and, when no revisions are specified,
+ the working directory files are compared to its parent.
+
+ options:
+
+ -o --option OPT [+] pass option to comparison program
+ -r --rev REV [+] revision
+ -c --change REV change made by revision
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+
+ [+] marked option can be specified multiple times
+
+ use "hg -v help falabala" to show more info
+
+ $ hg ci -d '0 0' -mtest1
+
+ $ echo b >> a
+ $ hg ci -d '1 0' -mtest2
+
+Should diff cloned files directly:
+
+ $ hg falabala -r 0:1
+ diffing */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
+ [1]
+
+Test diff during merge:
+
+ $ hg update -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo c >> c
+ $ hg add c
+ $ hg ci -m "new branch" -d '1 0'
+ created new head
+ $ hg merge 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+Should diff cloned file against wc file:
+
+ $ hg falabala
+ diffing */extdiff.*/a.2a13a4d2da36/a */a/a (glob)
+ [1]
+
+
+Test --change option:
+
+ $ hg ci -d '2 0' -mtest3
+ $ hg falabala -c 1
+ diffing */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
+ [1]
+
+Check diff are made from the first parent:
+
+ $ hg falabala -c 3 || echo "diff-like tools yield a non-zero exit code"
+ diffing */extdiff.*/a.2a13a4d2da36/a a.46c0e4daeb72/a (glob)
+ diff-like tools yield a non-zero exit code
+
+#if execbit
+
+Test extdiff of multiple files in tmp dir:
+
+ $ hg update -C 0 > /dev/null
+ $ echo changed > a
+ $ echo changed > b
+ $ chmod +x b
+
+Diff in working directory, before:
+
+ $ hg diff --git
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,1 @@
+ -a
+ +changed
+ diff --git a/b b/b
+ old mode 100644
+ new mode 100755
+ --- a/b
+ +++ b/b
+ @@ -1,1 +1,1 @@
+ -b
+ +changed
+
+
+Edit with extdiff -p:
+
+Prepare custom diff/edit tool:
+
+ $ cat > 'diff tool.py' << EOT
+ > #!/usr/bin/env python
+ > import time
+ > time.sleep(1) # avoid unchanged-timestamp problems
+ > file('a/a', 'ab').write('edited\n')
+ > file('a/b', 'ab').write('edited\n')
+ > EOT
+
+ $ chmod +x 'diff tool.py'
+
+will change to /tmp/extdiff.TMP and populate directories a.TMP and a
+and start tool
+
+ $ hg extdiff -p "`pwd`/diff tool.py"
+ [1]
+
+Diff in working directory, after:
+
+ $ hg diff --git
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,2 @@
+ -a
+ +changed
+ +edited
+ diff --git a/b b/b
+ old mode 100644
+ new mode 100755
+ --- a/b
+ +++ b/b
+ @@ -1,1 +1,2 @@
+ -b
+ +changed
+ +edited
+
+Test extdiff with --option:
+
+ $ hg extdiff -p echo -o this -c 1
+ this */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
+ [1]
+
+ $ hg falabala -o this -c 1
+ diffing this */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
+ [1]
+
+Test with revsets:
+
+ $ hg extdif -p echo -c "rev(1)"
+ */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
+ [1]
+
+ $ hg extdif -p echo -r "0::1"
+ */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
+ [1]
+
+ $ cd ..
+
+#endif
+
+#if symlink
+
+Test symlinks handling (issue1909)
+
+ $ hg init testsymlinks
+ $ cd testsymlinks
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ echo a >> a
+ $ ln -s missing linka
+ $ hg add linka
+ $ hg falabala -r 0 --traceback
+ diffing testsymlinks.07f494440405 testsymlinks
+ [1]
+ $ cd ..
+
+#endif
diff --git a/tests/test-extension.t b/tests/test-extension.t
new file mode 100644
index 0000000..0f4be50
--- /dev/null
+++ b/tests/test-extension.t
@@ -0,0 +1,561 @@
+Test basic extension support
+
+ $ cat > foobar.py <<EOF
+ > import os
+ > from mercurial import commands
+ >
+ > def uisetup(ui):
+ > ui.write("uisetup called\\n")
+ >
+ > def reposetup(ui, repo):
+ > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
+ > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
+ >
+ > def foo(ui, *args, **kwargs):
+ > ui.write("Foo\\n")
+ >
+ > def bar(ui, *args, **kwargs):
+ > ui.write("Bar\\n")
+ >
+ > cmdtable = {
+ > "foo": (foo, [], "hg foo"),
+ > "bar": (bar, [], "hg bar"),
+ > }
+ >
+ > commands.norepo += ' bar'
+ > EOF
+ $ abspath=`pwd`/foobar.py
+
+ $ mkdir barfoo
+ $ cp foobar.py barfoo/__init__.py
+ $ barfoopath=`pwd`/barfoo
+
+ $ hg init a
+ $ cd a
+ $ echo foo > file
+ $ hg add file
+ $ hg commit -m 'add file'
+
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo "foobar = $abspath" >> $HGRCPATH
+ $ hg foo
+ uisetup called
+ reposetup called for a
+ ui == repo.ui
+ Foo
+
+ $ cd ..
+ $ hg clone a b
+ uisetup called
+ reposetup called for a
+ ui == repo.ui
+ reposetup called for b
+ ui == repo.ui
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg bar
+ uisetup called
+ Bar
+ $ echo 'foobar = !' >> $HGRCPATH
+
+module/__init__.py-style
+
+ $ echo "barfoo = $barfoopath" >> $HGRCPATH
+ $ cd a
+ $ hg foo
+ uisetup called
+ reposetup called for a
+ ui == repo.ui
+ Foo
+ $ echo 'barfoo = !' >> $HGRCPATH
+
+Check that extensions are loaded in phases:
+
+ $ cat > foo.py <<EOF
+ > import os
+ > name = os.path.basename(__file__).rsplit('.', 1)[0]
+ > print "1) %s imported" % name
+ > def uisetup(ui):
+ > print "2) %s uisetup" % name
+ > def extsetup():
+ > print "3) %s extsetup" % name
+ > def reposetup(ui, repo):
+ > print "4) %s reposetup" % name
+ > EOF
+
+ $ cp foo.py bar.py
+ $ echo 'foo = foo.py' >> $HGRCPATH
+ $ echo 'bar = bar.py' >> $HGRCPATH
+
+Command with no output, we just want to see the extensions loaded:
+
+ $ hg paths
+ 1) foo imported
+ 1) bar imported
+ 2) foo uisetup
+ 2) bar uisetup
+ 3) foo extsetup
+ 3) bar extsetup
+ 4) foo reposetup
+ 4) bar reposetup
+
+Check hgweb's load order:
+
+ $ cat > hgweb.cgi <<EOF
+ > #!/usr/bin/env python
+ > from mercurial import demandimport; demandimport.enable()
+ > from mercurial.hgweb import hgweb
+ > from mercurial.hgweb import wsgicgi
+ >
+ > application = hgweb('.', 'test repo')
+ > wsgicgi.launch(application)
+ > EOF
+
+ $ SCRIPT_NAME='/' SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
+ > | grep '^[0-9]) ' # ignores HTML output
+ 1) foo imported
+ 1) bar imported
+ 2) foo uisetup
+ 2) bar uisetup
+ 3) foo extsetup
+ 3) bar extsetup
+ 4) foo reposetup
+ 4) bar reposetup
+ 4) foo reposetup
+ 4) bar reposetup
+
+ $ echo 'foo = !' >> $HGRCPATH
+ $ echo 'bar = !' >> $HGRCPATH
+
+ $ cd ..
+
+hide outer repo
+ $ hg init
+
+ $ cat > empty.py <<EOF
+ > '''empty cmdtable
+ > '''
+ > cmdtable = {}
+ > EOF
+ $ emptypath=`pwd`/empty.py
+ $ echo "empty = $emptypath" >> $HGRCPATH
+ $ hg help empty
+ empty extension - empty cmdtable
+
+ no commands defined
+
+ $ echo 'empty = !' >> $HGRCPATH
+
+ $ cat > debugextension.py <<EOF
+ > '''only debugcommands
+ > '''
+ > def debugfoobar(ui, repo, *args, **opts):
+ > "yet another debug command"
+ > pass
+ >
+ > def foo(ui, repo, *args, **opts):
+ > """yet another foo command
+ >
+ > This command has been DEPRECATED since forever.
+ > """
+ > pass
+ >
+ > cmdtable = {
+ > "debugfoobar": (debugfoobar, (), "hg debugfoobar"),
+ > "foo": (foo, (), "hg foo")
+ > }
+ > EOF
+ $ debugpath=`pwd`/debugextension.py
+ $ echo "debugextension = $debugpath" >> $HGRCPATH
+
+ $ hg help debugextension
+ debugextension extension - only debugcommands
+
+ no commands defined
+
+ $ hg --verbose help debugextension
+ debugextension extension - only debugcommands
+
+ list of commands:
+
+ foo yet another foo command
+
+ global options:
+
+ -R --repository REPO repository root directory or name of overlay bundle
+ file
+ --cwd DIR change working directory
+ -y --noninteractive do not prompt, automatically pick the first choice for
+ all prompts
+ -q --quiet suppress output
+ -v --verbose enable additional output
+ --config CONFIG [+] set/override config option (use 'section.name=value')
+ --debug enable debugging output
+ --debugger start debugger
+ --encoding ENCODE set the charset encoding (default: ascii)
+ --encodingmode MODE set the charset encoding mode (default: strict)
+ --traceback always print a traceback on exception
+ --time time how long the command takes
+ --profile print command execution profile
+ --version output version information and exit
+ -h --help display help and exit
+
+ [+] marked option can be specified multiple times
+
+ $ hg --debug help debugextension
+ debugextension extension - only debugcommands
+
+ list of commands:
+
+ debugfoobar yet another debug command
+ foo yet another foo command
+
+ global options:
+
+ -R --repository REPO repository root directory or name of overlay bundle
+ file
+ --cwd DIR change working directory
+ -y --noninteractive do not prompt, automatically pick the first choice for
+ all prompts
+ -q --quiet suppress output
+ -v --verbose enable additional output
+ --config CONFIG [+] set/override config option (use 'section.name=value')
+ --debug enable debugging output
+ --debugger start debugger
+ --encoding ENCODE set the charset encoding (default: ascii)
+ --encodingmode MODE set the charset encoding mode (default: strict)
+ --traceback always print a traceback on exception
+ --time time how long the command takes
+ --profile print command execution profile
+ --version output version information and exit
+ -h --help display help and exit
+
+ [+] marked option can be specified multiple times
+ $ echo 'debugextension = !' >> $HGRCPATH
+
+Extension module help vs command help:
+
+ $ echo 'extdiff =' >> $HGRCPATH
+ $ hg help extdiff
+ hg extdiff [OPT]... [FILE]...
+
+ use external program to diff repository (or selected files)
+
+ Show differences between revisions for the specified files, using an
+ external program. The default program used is diff, with default options
+ "-Npru".
+
+ To select a different program, use the -p/--program option. The program
+ will be passed the names of two directories to compare. To pass additional
+ options to the program, use -o/--option. These will be passed before the
+ names of the directories to compare.
+
+ When two revision arguments are given, then changes are shown between
+ those revisions. If only one revision is specified then that revision is
+ compared to the working directory, and, when no revisions are specified,
+ the working directory files are compared to its parent.
+
+ use "hg help -e extdiff" to show help for the extdiff extension
+
+ options:
+
+ -p --program CMD comparison program to run
+ -o --option OPT [+] pass option to comparison program
+ -r --rev REV [+] revision
+ -c --change REV change made by revision
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+
+ [+] marked option can be specified multiple times
+
+ use "hg -v help extdiff" to show more info
+
+ $ hg help --extension extdiff
+ extdiff extension - command to allow external programs to compare revisions
+
+ The extdiff Mercurial extension allows you to use external programs to compare
+ revisions, or revision with working directory. The external diff programs are
+ called with a configurable set of options and two non-option arguments: paths
+ to directories containing snapshots of files to compare.
+
+ The extdiff extension also allows you to configure new diff commands, so you
+ do not need to type "hg extdiff -p kdiff3" always.
+
+ [extdiff]
+ # add new command that runs GNU diff(1) in 'context diff' mode
+ cdiff = gdiff -Nprc5
+ ## or the old way:
+ #cmd.cdiff = gdiff
+ #opts.cdiff = -Nprc5
+
+ # add new command called vdiff, runs kdiff3
+ vdiff = kdiff3
+
+ # add new command called meld, runs meld (no need to name twice)
+ meld =
+
+ # add new command called vimdiff, runs gvimdiff with DirDiff plugin
+ # (see http://www.vim.org/scripts/script.php?script_id=102) Non
+ # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
+ # your .vimrc
+ vimdiff = gvim -f "+next" \
+ "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
+
+ Tool arguments can include variables that are expanded at runtime:
+
+ $parent1, $plabel1 - filename, descriptive label of first parent
+ $child, $clabel - filename, descriptive label of child revision
+ $parent2, $plabel2 - filename, descriptive label of second parent
+ $root - repository root
+ $parent is an alias for $parent1.
+
+ The extdiff extension will look in your [diff-tools] and [merge-tools]
+ sections for diff tool arguments, when none are specified in [extdiff].
+
+ [extdiff]
+ kdiff3 =
+
+ [diff-tools]
+ kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
+
+ You can use -I/-X and list of file or directory names like normal "hg diff"
+ command. The extdiff extension makes snapshots of only needed files, so
+ running the external diff program will actually be pretty fast (at least
+ faster than having to compare the entire tree).
+
+ list of commands:
+
+ extdiff use external program to diff repository (or selected files)
+
+ use "hg -v help extdiff" to show builtin aliases and global options
+
+ $ echo 'extdiff = !' >> $HGRCPATH
+
+Test help topic with same name as extension
+
+ $ cat > multirevs.py <<EOF
+ > from mercurial import commands
+ > """multirevs extension
+ > Big multi-line module docstring."""
+ > def multirevs(ui, repo, arg, *args, **opts):
+ > """multirevs command"""
+ > pass
+ > cmdtable = {
+ > "multirevs": (multirevs, [], 'ARG')
+ > }
+ > commands.norepo += ' multirevs'
+ > EOF
+ $ echo "multirevs = multirevs.py" >> $HGRCPATH
+
+ $ hg help multirevs
+ Specifying Multiple Revisions
+
+ When Mercurial accepts more than one revision, they may be specified
+ individually, or provided as a topologically continuous range, separated
+ by the ":" character.
+
+ The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
+ revision identifiers. Both BEGIN and END are optional. If BEGIN is not
+ specified, it defaults to revision number 0. If END is not specified, it
+ defaults to the tip. The range ":" thus means "all revisions".
+
+ If BEGIN is greater than END, revisions are treated in reverse order.
+
+ A range acts as a closed interval. This means that a range of 3:5 gives 3,
+ 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
+
+ use "hg help -c multirevs" to see help for the multirevs command
+
+ $ hg help -c multirevs
+ hg multirevs ARG
+
+ multirevs command
+
+ use "hg -v help multirevs" to show more info
+
+ $ hg multirevs
+ hg multirevs: invalid arguments
+ hg multirevs ARG
+
+ multirevs command
+
+ use "hg help multirevs" to show the full help text
+ [255]
+
+ $ echo "multirevs = !" >> $HGRCPATH
+
+Issue811: Problem loading extensions twice (by site and by user)
+
+ $ debugpath=`pwd`/debugissue811.py
+ $ cat > debugissue811.py <<EOF
+ > '''show all loaded extensions
+ > '''
+ > from mercurial import extensions, commands
+ >
+ > def debugextensions(ui):
+ > "yet another debug command"
+ > ui.write("%s\n" % '\n'.join([x for x, y in extensions.extensions()]))
+ >
+ > cmdtable = {"debugextensions": (debugextensions, (), "hg debugextensions")}
+ > commands.norepo += " debugextensions"
+ > EOF
+ $ echo "debugissue811 = $debugpath" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "hgext.mq=" >> $HGRCPATH
+ $ echo "hgext/mq=" >> $HGRCPATH
+
+Show extensions:
+
+ $ hg debugextensions
+ debugissue811
+ mq
+
+Disabled extension commands:
+
+ $ HGRCPATH=
+ $ export HGRCPATH
+ $ hg help email
+ 'email' is provided by the following extension:
+
+ patchbomb command to send changesets as (a series of) patch emails
+
+ use "hg help extensions" for information on enabling extensions
+ $ hg qdel
+ hg: unknown command 'qdel'
+ 'qdelete' is provided by the following extension:
+
+ mq manage a stack of patches
+
+ use "hg help extensions" for information on enabling extensions
+ [255]
+ $ hg churn
+ hg: unknown command 'churn'
+ 'churn' is provided by the following extension:
+
+ churn command to display statistics about repository history
+
+ use "hg help extensions" for information on enabling extensions
+ [255]
+
+Disabled extensions:
+
+ $ hg help churn
+ churn extension - command to display statistics about repository history
+
+ use "hg help extensions" for information on enabling extensions
+ $ hg help patchbomb
+ patchbomb extension - command to send changesets as (a series of) patch emails
+
+ use "hg help extensions" for information on enabling extensions
+
+Broken disabled extension and command:
+
+ $ mkdir hgext
+ $ echo > hgext/__init__.py
+ $ cat > hgext/broken.py <<EOF
+ > "broken extension'
+ > EOF
+ $ cat > path.py <<EOF
+ > import os, sys
+ > sys.path.insert(0, os.environ['HGEXTPATH'])
+ > EOF
+ $ HGEXTPATH=`pwd`
+ $ export HGEXTPATH
+
+ $ hg --config extensions.path=./path.py help broken
+ broken extension - (no help text available)
+
+ use "hg help extensions" for information on enabling extensions
+
+ $ cat > hgext/forest.py <<EOF
+ > cmdtable = None
+ > EOF
+ $ hg --config extensions.path=./path.py help foo > /dev/null
+ warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
+ hg: unknown command 'foo'
+ warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
+ [255]
+
+ $ cat > throw.py <<EOF
+ > from mercurial import cmdutil, commands
+ > cmdtable = {}
+ > command = cmdutil.command(cmdtable)
+ > class Bogon(Exception): pass
+ >
+ > @command('throw', [], 'hg throw')
+ > def throw(ui, **opts):
+ > """throws an exception"""
+ > raise Bogon()
+ > commands.norepo += " throw"
+ > EOF
+No declared supported version, extension complains:
+ $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
+ ** Unknown exception encountered with possibly-broken third-party extension throw
+ ** which supports versions unknown of Mercurial.
+ ** Please disable throw and try your action again.
+ ** If that fixes the bug please report it to the extension author.
+ ** Python * (glob)
+ ** Mercurial Distributed SCM * (glob)
+ ** Extensions loaded: throw
+If the extension specifies a buglink, show that:
+ $ echo 'buglink = "http://example.com/bts"' >> throw.py
+ $ rm -f throw.pyc throw.pyo
+ $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
+ ** Unknown exception encountered with possibly-broken third-party extension throw
+ ** which supports versions unknown of Mercurial.
+ ** Please disable throw and try your action again.
+ ** If that fixes the bug please report it to http://example.com/bts
+ ** Python * (glob)
+ ** Mercurial Distributed SCM (*) (glob)
+ ** Extensions loaded: throw
+If the extensions declare outdated versions, accuse the older extension first:
+ $ echo "from mercurial import util" >> older.py
+ $ echo "util.version = lambda:'2.2'" >> older.py
+ $ echo "testedwith = '1.9.3'" >> older.py
+ $ echo "testedwith = '2.1.1'" >> throw.py
+ $ rm -f throw.pyc throw.pyo
+ $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
+ > throw 2>&1 | egrep '^\*\*'
+ ** Unknown exception encountered with possibly-broken third-party extension older
+ ** which supports versions 1.9.3 of Mercurial.
+ ** Please disable older and try your action again.
+ ** If that fixes the bug please report it to the extension author.
+ ** Python * (glob)
+ ** Mercurial Distributed SCM (version 2.2)
+ ** Extensions loaded: throw, older
+One extension only tested with older, one only with newer versions:
+ $ echo "util.version = lambda:'2.1.0'" >> older.py
+ $ rm -f older.pyc older.pyo
+ $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
+ > throw 2>&1 | egrep '^\*\*'
+ ** Unknown exception encountered with possibly-broken third-party extension older
+ ** which supports versions 1.9.3 of Mercurial.
+ ** Please disable older and try your action again.
+ ** If that fixes the bug please report it to the extension author.
+ ** Python * (glob)
+ ** Mercurial Distributed SCM (version 2.1.0)
+ ** Extensions loaded: throw, older
+Older extension is tested with current version, the other only with newer:
+ $ echo "util.version = lambda:'1.9.3'" >> older.py
+ $ rm -f older.pyc older.pyo
+ $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
+ > throw 2>&1 | egrep '^\*\*'
+ ** Unknown exception encountered with possibly-broken third-party extension throw
+ ** which supports versions 2.1.1 of Mercurial.
+ ** Please disable throw and try your action again.
+ ** If that fixes the bug please report it to http://example.com/bts
+ ** Python * (glob)
+ ** Mercurial Distributed SCM (version 1.9.3)
+ ** Extensions loaded: throw, older
+
+Declare the version as supporting this hg version, show regular bts link:
+ $ hgver=`python -c 'from mercurial import util; print util.version().split("+")[0]'`
+ $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
+ $ rm -f throw.pyc throw.pyo
+ $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
+ ** unknown exception encountered, please report by visiting
+ ** http://mercurial.selenic.com/wiki/BugTracker
+ ** Python * (glob)
+ ** Mercurial Distributed SCM (*) (glob)
+ ** Extensions loaded: throw
diff --git a/tests/test-extra-filelog-entry.t b/tests/test-extra-filelog-entry.t
new file mode 100644
index 0000000..701e23b
--- /dev/null
+++ b/tests/test-extra-filelog-entry.t
@@ -0,0 +1,21 @@
+Issue351: mq: qrefresh can create extra revlog entry
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init
+ $ hg qinit
+
+ $ echo b > b
+ $ hg ci -A -m foo
+ adding b
+
+ $ echo cc > b
+ $ hg qnew -f foo.diff
+ $ echo b > b
+ $ hg qrefresh
+
+ $ hg debugindex b
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 0 1e88685f5dde 000000000000 000000000000 (re)
+
diff --git a/tests/test-fetch.t b/tests/test-fetch.t
new file mode 100644
index 0000000..d52742f
--- /dev/null
+++ b/tests/test-fetch.t
@@ -0,0 +1,414 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "fetch=" >> $HGRCPATH
+
+test fetch with default branches only
+
+ $ hg init a
+ $ echo a > a/a
+ $ hg --cwd a commit -Ama
+ adding a
+ $ hg clone a b
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg clone a c
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b > a/b
+ $ hg --cwd a commit -Amb
+ adding b
+ $ hg --cwd a parents -q
+ 1:d2ae7f538514
+
+should pull one change
+
+ $ hg --cwd b fetch ../a
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd b parents -q
+ 1:d2ae7f538514
+ $ echo c > c/c
+ $ hg --cwd c commit -Amc
+ adding c
+ $ hg clone c d
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg clone c e
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+We cannot use the default commit message if fetching from a local
+repo, because the path of the repo will be included in the commit
+message, making every commit appear different.
+should merge c into a
+
+ $ hg --cwd c fetch -d '0 0' -m 'automated merge' ../a
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ updating to 2:d2ae7f538514
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ merging with 1:d36c0562f908
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ new changeset 3:a323a0c43ec4 merges remote changes with local
+ $ ls c
+ a
+ b
+ c
+ $ hg --cwd a serve -a localhost -p $HGPORT -d --pid-file=hg.pid
+ $ cat a/hg.pid >> "$DAEMON_PIDS"
+
+fetch over http, no auth
+
+ $ hg --cwd d fetch http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ updating to 2:d2ae7f538514
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ merging with 1:d36c0562f908
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ new changeset 3:* merges remote changes with local (glob)
+ $ hg --cwd d tip --template '{desc}\n'
+ Automated merge with http://localhost:$HGPORT/
+
+fetch over http with auth (should be hidden in desc)
+
+ $ hg --cwd e fetch http://user:password@localhost:$HGPORT/
+ pulling from http://user:***@localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ updating to 2:d2ae7f538514
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ merging with 1:d36c0562f908
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ new changeset 3:* merges remote changes with local (glob)
+ $ hg --cwd e tip --template '{desc}\n'
+ Automated merge with http://localhost:$HGPORT/
+ $ hg clone a f
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg clone a g
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo f > f/f
+ $ hg --cwd f ci -Amf
+ adding f
+ $ echo g > g/g
+ $ hg --cwd g ci -Amg
+ adding g
+ $ hg clone -q f h
+ $ hg clone -q g i
+
+should merge f into g
+
+ $ hg --cwd g fetch -d '0 0' --switch -m 'automated merge' ../f
+ pulling from ../f
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ merging with 3:6343ca3eff20
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ new changeset 4:f7faa0b7d3c6 merges remote changes with local
+ $ rm i/g
+
+should abort, because i is modified
+
+ $ hg --cwd i fetch ../h
+ abort: working directory is missing some files
+ [255]
+
+test fetch with named branches
+
+ $ hg init nbase
+ $ echo base > nbase/a
+ $ hg -R nbase ci -Am base
+ adding a
+ $ hg -R nbase branch a
+ marked working directory as branch a
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a > nbase/a
+ $ hg -R nbase ci -m a
+ $ hg -R nbase up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R nbase branch b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b > nbase/b
+ $ hg -R nbase ci -Am b
+ adding b
+
+pull in change on foreign branch
+
+ $ hg clone nbase n1
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg clone nbase n2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R n1 up -C a
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo aa > n1/a
+ $ hg -R n1 ci -m a1
+ $ hg -R n2 up -C b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R n2 fetch -m 'merge' n1
+ pulling from n1
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+parent should be 2 (no automatic update)
+
+ $ hg -R n2 parents --template '{rev}\n'
+ 2
+ $ rm -fr n1 n2
+
+pull in changes on both foreign and local branches
+
+ $ hg clone nbase n1
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg clone nbase n2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R n1 up -C a
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo aa > n1/a
+ $ hg -R n1 ci -m a1
+ $ hg -R n1 up -C b
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo bb > n1/b
+ $ hg -R n1 ci -m b1
+ $ hg -R n2 up -C b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R n2 fetch -m 'merge' n1
+ pulling from n1
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+parent should be 4 (fast forward)
+
+ $ hg -R n2 parents --template '{rev}\n'
+ 4
+ $ rm -fr n1 n2
+
+pull changes on foreign (2 new heads) and local (1 new head) branches
+with a local change
+
+ $ hg clone nbase n1
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg clone nbase n2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R n1 up -C a
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a1 > n1/a
+ $ hg -R n1 ci -m a1
+ $ hg -R n1 up -C b
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo bb > n1/b
+ $ hg -R n1 ci -m b1
+ $ hg -R n1 up -C 1
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo a2 > n1/a
+ $ hg -R n1 ci -m a2
+ created new head
+ $ hg -R n2 up -C b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo change >> n2/c
+ $ hg -R n2 ci -A -m local
+ adding c
+ $ hg -R n2 fetch -d '0 0' -m 'merge' n1
+ pulling from n1
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 2 files (+2 heads)
+ updating to 5:3c4a837a864f
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ merging with 3:1267f84a9ea5
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ new changeset 7:2cf2a1261f21 merges remote changes with local
+
+parent should be 7 (new merge changeset)
+
+ $ hg -R n2 parents --template '{rev}\n'
+ 7
+ $ rm -fr n1 n2
+
+pull in changes on foreign (merge of local branch) and local (2 new
+heads) with a local change
+
+ $ hg clone nbase n1
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg clone nbase n2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R n1 up -C a
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R n1 merge b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg -R n1 ci -m merge
+ $ hg -R n1 up -C 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo c > n1/a
+ $ hg -R n1 ci -m c
+ $ hg -R n1 up -C 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo cc > n1/a
+ $ hg -R n1 ci -m cc
+ created new head
+ $ hg -R n2 up -C b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo change >> n2/b
+ $ hg -R n2 ci -A -m local
+ $ hg -R n2 fetch -m 'merge' n1
+ pulling from n1
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 2 changes to 1 files (+2 heads)
+ not merging with 1 other new branch heads (use "hg heads ." and "hg merge" to merge them)
+ [1]
+
+parent should be 3 (fetch did not merge anything)
+
+ $ hg -R n2 parents --template '{rev}\n'
+ 3
+ $ rm -fr n1 n2
+
+pull in change on different branch than dirstate
+
+ $ hg init n1
+ $ echo a > n1/a
+ $ hg -R n1 ci -Am initial
+ adding a
+ $ hg clone n1 n2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b > n1/a
+ $ hg -R n1 ci -m next
+ $ hg -R n2 branch topic
+ marked working directory as branch topic
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg -R n2 fetch -m merge n1
+ abort: working dir not at branch tip (use "hg update" to check out branch tip)
+ [255]
+
+parent should be 0 (fetch did not update or merge anything)
+
+ $ hg -R n2 parents --template '{rev}\n'
+ 0
+ $ rm -fr n1 n2
+
+test fetch with inactive branches
+
+ $ hg init ib1
+ $ echo a > ib1/a
+ $ hg --cwd ib1 ci -Am base
+ adding a
+ $ hg --cwd ib1 branch second
+ marked working directory as branch second
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b > ib1/b
+ $ hg --cwd ib1 ci -Am onsecond
+ adding b
+ $ hg --cwd ib1 branch -f default
+ marked working directory as branch default
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo c > ib1/c
+ $ hg --cwd ib1 ci -Am newdefault
+ adding c
+ created new head
+ $ hg clone ib1 ib2
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+fetch should succeed
+
+ $ hg --cwd ib2 fetch ../ib1
+ pulling from ../ib1
+ searching for changes
+ no changes found
+ $ rm -fr ib1 ib2
+
+test issue1726
+
+ $ hg init i1726r1
+ $ echo a > i1726r1/a
+ $ hg --cwd i1726r1 ci -Am base
+ adding a
+ $ hg clone i1726r1 i1726r2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b > i1726r1/a
+ $ hg --cwd i1726r1 ci -m second
+ $ echo c > i1726r2/a
+ $ hg --cwd i1726r2 ci -m third
+ $ HGMERGE=true hg --cwd i1726r2 fetch ../i1726r1
+ pulling from ../i1726r1
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ updating to 2:7837755a2789
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ merging with 1:d1f0c6c48ebd
+ merging a
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ new changeset 3:* merges remote changes with local (glob)
+ $ hg --cwd i1726r2 heads default --template '{rev}\n'
+ 3
+
+test issue2047
+
+ $ hg -q init i2047a
+ $ cd i2047a
+ $ echo a > a
+ $ hg -q ci -Am a
+ $ hg -q branch stable
+ $ echo b > b
+ $ hg -q ci -Am b
+ $ cd ..
+ $ hg -q clone -r 0 i2047a i2047b
+ $ cd i2047b
+ $ hg fetch ../i2047a
+ pulling from ../i2047a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+ $ cd ..
diff --git a/tests/test-filebranch.t b/tests/test-filebranch.t
new file mode 100644
index 0000000..5558fb0
--- /dev/null
+++ b/tests/test-filebranch.t
@@ -0,0 +1,149 @@
+This test makes sure that we don't mark a file as merged with its ancestor
+when we do a merge.
+
+ $ cat <<EOF > merge
+ > import sys, os
+ > print "merging for", os.path.basename(sys.argv[1])
+ > EOF
+ $ HGMERGE="python ../merge"; export HGMERGE
+
+Creating base:
+
+ $ hg init a
+ $ cd a
+ $ echo 1 > foo
+ $ echo 1 > bar
+ $ echo 1 > baz
+ $ echo 1 > quux
+ $ hg add foo bar baz quux
+ $ hg commit -m "base"
+
+ $ cd ..
+ $ hg clone a b
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Creating branch a:
+
+ $ cd a
+ $ echo 2a > foo
+ $ echo 2a > bar
+ $ hg commit -m "branch a"
+
+Creating branch b:
+
+ $ cd ..
+ $ cd b
+ $ echo 2b > foo
+ $ echo 2b > baz
+ $ hg commit -m "branch b"
+
+We shouldn't have anything but n state here:
+
+ $ hg debugstate --nodates | grep -v "^n"
+ [1]
+
+Merging:
+
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ $ hg merge -v
+ resolving manifests
+ getting bar
+ merging foo
+ merging for foo
+ 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ echo 2m > foo
+ $ echo 2b > baz
+ $ echo new > quux
+
+We shouldn't have anything but foo in merge state here:
+
+ $ hg debugstate --nodates | grep "^m"
+ m 644 3 foo
+
+ $ hg ci -m "merge"
+
+main: we should have a merge here:
+
+ $ hg debugindex --changelog
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 73 ..... 0 cdca01651b96 000000000000 000000000000 (re)
+ 1 73 68 ..... 1 f6718a9cb7f3 cdca01651b96 000000000000 (re)
+ 2 141 68 ..... 2 bdd988058d16 cdca01651b96 000000000000 (re)
+ 3 209 66 ..... 3 d8a521142a3c f6718a9cb7f3 bdd988058d16 (re)
+
+log should show foo and quux changed:
+
+ $ hg log -v -r tip
+ changeset: 3:d8a521142a3c
+ tag: tip
+ parent: 1:f6718a9cb7f3
+ parent: 2:bdd988058d16
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: foo quux
+ description:
+ merge
+
+
+
+foo: we should have a merge here:
+
+ $ hg debugindex foo
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 0 b8e02f643373 000000000000 000000000000 (re)
+ 1 3 4 ..... 1 2ffeddde1b65 b8e02f643373 000000000000 (re)
+ 2 7 4 ..... 2 33d1fb69067a b8e02f643373 000000000000 (re)
+ 3 11 4 ..... 3 aa27919ee430 2ffeddde1b65 33d1fb69067a (re)
+
+bar: we should not have a merge here:
+
+ $ hg debugindex bar
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 0 b8e02f643373 000000000000 000000000000 (re)
+ 1 3 4 ..... 2 33d1fb69067a b8e02f643373 000000000000 (re)
+
+baz: we should not have a merge here:
+
+ $ hg debugindex baz
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 0 b8e02f643373 000000000000 000000000000 (re)
+ 1 3 4 ..... 1 2ffeddde1b65 b8e02f643373 000000000000 (re)
+
+quux: we should not have a merge here:
+
+ $ hg debugindex quux
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 0 b8e02f643373 000000000000 000000000000 (re)
+ 1 3 5 ..... 3 6128c0f33108 b8e02f643373 000000000000 (re)
+
+Manifest entries should match tips of all files:
+
+ $ hg manifest --debug
+ 33d1fb69067a0139622a3fa3b7ba1cdb1367972e 644 bar
+ 2ffeddde1b65b4827f6746174a145474129fa2ce 644 baz
+ aa27919ee4303cfd575e1fb932dd64d75aa08be4 644 foo
+ 6128c0f33108e8cfbb4e0824d13ae48b466d7280 644 quux
+
+Everything should be clean now:
+
+ $ hg status
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 4 changesets, 10 total revisions
+
+ $ cd ..
diff --git a/tests/test-filecache.py b/tests/test-filecache.py
new file mode 100644
index 0000000..552a62a
--- /dev/null
+++ b/tests/test-filecache.py
@@ -0,0 +1,95 @@
+import sys, os, subprocess
+
+if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'],
+ 'cacheable']):
+ sys.exit(80)
+
+from mercurial import util, scmutil, extensions
+
+filecache = scmutil.filecache
+
+class fakerepo(object):
+ def __init__(self):
+ self._filecache = {}
+
+ def join(self, p):
+ return p
+
+ def sjoin(self, p):
+ return p
+
+ @filecache('x')
+ def cached(self):
+ print 'creating'
+
+ def invalidate(self):
+ for k in self._filecache:
+ try:
+ delattr(self, k)
+ except AttributeError:
+ pass
+
+def basic(repo):
+ # file doesn't exist, calls function
+ repo.cached
+
+ repo.invalidate()
+ # file still doesn't exist, uses cache
+ repo.cached
+
+ # create empty file
+ f = open('x', 'w')
+ f.close()
+ repo.invalidate()
+ # should recreate the object
+ repo.cached
+
+ f = open('x', 'w')
+ f.write('a')
+ f.close()
+ repo.invalidate()
+ # should recreate the object
+ repo.cached
+
+ repo.invalidate()
+ # stats file again, nothing changed, reuses object
+ repo.cached
+
+ # atomic replace file, size doesn't change
+ # hopefully st_mtime doesn't change as well so this doesn't use the cache
+ # because of inode change
+ f = scmutil.opener('.')('x', 'w', atomictemp=True)
+ f.write('b')
+ f.close()
+
+ repo.invalidate()
+ repo.cached
+
+def fakeuncacheable():
+ def wrapcacheable(orig, *args, **kwargs):
+ return False
+
+ def wrapinit(orig, *args, **kwargs):
+ pass
+
+ originit = extensions.wrapfunction(util.cachestat, '__init__', wrapinit)
+ origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable',
+ wrapcacheable)
+
+ try:
+ os.remove('x')
+ except OSError:
+ pass
+
+ basic(fakerepo())
+
+ util.cachestat.cacheable = origcacheable
+ util.cachestat.__init__ = originit
+
+print 'basic:'
+print
+basic(fakerepo())
+print
+print 'fakeuncacheable:'
+print
+fakeuncacheable()
diff --git a/tests/test-filecache.py.out b/tests/test-filecache.py.out
new file mode 100644
index 0000000..dc386fe
--- /dev/null
+++ b/tests/test-filecache.py.out
@@ -0,0 +1,15 @@
+basic:
+
+creating
+creating
+creating
+creating
+
+fakeuncacheable:
+
+creating
+creating
+creating
+creating
+creating
+creating
diff --git a/tests/test-filelog.py b/tests/test-filelog.py
new file mode 100755
index 0000000..bf9f437
--- /dev/null
+++ b/tests/test-filelog.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+"""
+Tests the behaviour of filelog w.r.t. data starting with '\1\n'
+"""
+from mercurial import ui, hg
+from mercurial.node import nullid, hex
+
+myui = ui.ui()
+repo = hg.repository(myui, path='.', create=True)
+
+fl = repo.file('foobar')
+
+def addrev(text, renamed=False):
+ if renamed:
+ # data doesnt matter. Just make sure filelog.renamed() returns True
+ meta = dict(copyrev=hex(nullid), copy='bar')
+ else:
+ meta = {}
+
+ lock = t = None
+ try:
+ lock = repo.lock()
+ t = repo.transaction('commit')
+ node = fl.add(text, meta, t, 0, nullid, nullid)
+ return node
+ finally:
+ if t:
+ t.close()
+ if lock:
+ lock.release()
+
+def error(text):
+ print 'ERROR: ' + text
+
+textwith = '\1\nfoo'
+without = 'foo'
+
+node = addrev(textwith)
+if not textwith == fl.read(node):
+ error('filelog.read for data starting with \\1\\n')
+if fl.cmp(node, textwith) or not fl.cmp(node, without):
+ error('filelog.cmp for data starting with \\1\\n')
+if fl.size(0) != len(textwith):
+ error('FIXME: This is a known failure of filelog.size for data starting '
+ 'with \\1\\n')
+
+node = addrev(textwith, renamed=True)
+if not textwith == fl.read(node):
+ error('filelog.read for a renaming + data starting with \\1\\n')
+if fl.cmp(node, textwith) or not fl.cmp(node, without):
+ error('filelog.cmp for a renaming + data starting with \\1\\n')
+if fl.size(1) != len(textwith):
+ error('filelog.size for a renaming + data starting with \\1\\n')
+
+print 'OK.'
diff --git a/tests/test-filelog.py.out b/tests/test-filelog.py.out
new file mode 100644
index 0000000..d9ecd51
--- /dev/null
+++ b/tests/test-filelog.py.out
@@ -0,0 +1,2 @@
+ERROR: FIXME: This is a known failure of filelog.size for data starting with \1\n
+OK.
diff --git a/tests/test-flags.t b/tests/test-flags.t
new file mode 100644
index 0000000..0c4d11f
--- /dev/null
+++ b/tests/test-flags.t
@@ -0,0 +1,151 @@
+ $ "$TESTDIR/hghave" execbit || exit 80
+
+ $ umask 027
+
+ $ hg init test1
+ $ cd test1
+ $ touch a b
+ $ hg add a b
+ $ hg ci -m "added a b"
+
+ $ cd ..
+ $ hg clone test1 test3
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg init test2
+ $ cd test2
+ $ hg pull ../test1
+ pulling from ../test1
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hg co
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ chmod +x a
+ $ hg ci -m "chmod +x a"
+
+the changelog should mention file a:
+
+ $ hg tip --template '{files}\n'
+ a
+
+ $ cd ../test1
+ $ echo 123 >>a
+ $ hg ci -m "a updated"
+
+ $ hg pull ../test2
+ pulling from ../test2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 0 changes to 0 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg heads
+ changeset: 2:7f4313b42a34
+ tag: tip
+ parent: 0:22a449e20da5
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: chmod +x a
+
+ changeset: 1:c6ecefc45368
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a updated
+
+ $ hg history
+ changeset: 2:7f4313b42a34
+ tag: tip
+ parent: 0:22a449e20da5
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: chmod +x a
+
+ changeset: 1:c6ecefc45368
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a updated
+
+ changeset: 0:22a449e20da5
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: added a b
+
+
+ $ hg -v merge
+ resolving manifests
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cd ../test3
+ $ echo 123 >>b
+ $ hg ci -m "b updated"
+
+ $ hg pull ../test2
+ pulling from ../test2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 0 changes to 0 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg heads
+ changeset: 2:7f4313b42a34
+ tag: tip
+ parent: 0:22a449e20da5
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: chmod +x a
+
+ changeset: 1:dc57ead75f79
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b updated
+
+ $ hg history
+ changeset: 2:7f4313b42a34
+ tag: tip
+ parent: 0:22a449e20da5
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: chmod +x a
+
+ changeset: 1:dc57ead75f79
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b updated
+
+ changeset: 0:22a449e20da5
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: added a b
+
+
+ $ hg -v merge
+ resolving manifests
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ ls -l ../test[123]/a > foo
+ $ cut -b 1-10 < foo
+ -rwxr-x---
+ -rwxr-x---
+ -rwxr-x---
+
+ $ hg debugindex a
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 0 ..... 0 b80de5d13875 000000000000 000000000000 (re)
+ $ hg debugindex -R ../test2 a
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 0 ..... 0 b80de5d13875 000000000000 000000000000 (re)
+ $ hg debugindex -R ../test1 a
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 0 ..... 0 b80de5d13875 000000000000 000000000000 (re)
+ 1 0 5 ..... 1 7fe919cc0336 b80de5d13875 000000000000 (re)
+
+ $ cd ..
diff --git a/tests/test-fncache.t b/tests/test-fncache.t
new file mode 100644
index 0000000..643088c
--- /dev/null
+++ b/tests/test-fncache.t
@@ -0,0 +1,119 @@
+Init repo1:
+
+ $ hg init repo1
+ $ cd repo1
+ $ echo "some text" > a
+ $ hg add
+ adding a
+ $ hg ci -m first
+ $ cat .hg/store/fncache | sort
+ data/a.i
+
+Testing a.i/b:
+
+ $ mkdir a.i
+ $ echo "some other text" > a.i/b
+ $ hg add
+ adding a.i/b (glob)
+ $ hg ci -m second
+ $ cat .hg/store/fncache | sort
+ data/a.i
+ data/a.i.hg/b.i
+
+Testing a.i.hg/c:
+
+ $ mkdir a.i.hg
+ $ echo "yet another text" > a.i.hg/c
+ $ hg add
+ adding a.i.hg/c (glob)
+ $ hg ci -m third
+ $ cat .hg/store/fncache | sort
+ data/a.i
+ data/a.i.hg.hg/c.i
+ data/a.i.hg/b.i
+
+Testing verify:
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 3 changesets, 3 total revisions
+
+ $ rm .hg/store/fncache
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ data/a.i@0: missing revlog!
+ data/a.i.hg/c.i@2: missing revlog!
+ data/a.i/b.i@1: missing revlog!
+ 3 files, 3 changesets, 3 total revisions
+ 3 integrity errors encountered!
+ (first damaged changeset appears to be 0)
+ [1]
+ $ cd ..
+
+Non store repo:
+
+ $ hg --config format.usestore=False init foo
+ $ cd foo
+ $ mkdir tst.d
+ $ echo foo > tst.d/foo
+ $ hg ci -Amfoo
+ adding tst.d/foo
+ $ find .hg | sort
+ .hg
+ .hg/00changelog.i
+ .hg/00manifest.i
+ .hg/cache
+ .hg/cache/branchheads
+ .hg/data
+ .hg/data/tst.d.hg
+ .hg/data/tst.d.hg/foo.i
+ .hg/dirstate
+ .hg/last-message.txt
+ .hg/phaseroots
+ .hg/requires
+ .hg/undo
+ .hg/undo.bookmarks
+ .hg/undo.branch
+ .hg/undo.desc
+ .hg/undo.dirstate
+ .hg/undo.phaseroots
+ $ cd ..
+
+Non fncache repo:
+
+ $ hg --config format.usefncache=False init bar
+ $ cd bar
+ $ mkdir tst.d
+ $ echo foo > tst.d/Foo
+ $ hg ci -Amfoo
+ adding tst.d/Foo
+ $ find .hg | sort
+ .hg
+ .hg/00changelog.i
+ .hg/cache
+ .hg/cache/branchheads
+ .hg/dirstate
+ .hg/last-message.txt
+ .hg/requires
+ .hg/store
+ .hg/store/00changelog.i
+ .hg/store/00manifest.i
+ .hg/store/data
+ .hg/store/data/tst.d.hg
+ .hg/store/data/tst.d.hg/_foo.i
+ .hg/store/phaseroots
+ .hg/store/undo
+ .hg/store/undo.phaseroots
+ .hg/undo.bookmarks
+ .hg/undo.branch
+ .hg/undo.desc
+ .hg/undo.dirstate
+ $ cd ..
+
diff --git a/tests/test-gendoc.t b/tests/test-gendoc.t
new file mode 100644
index 0000000..63a67d7
--- /dev/null
+++ b/tests/test-gendoc.t
@@ -0,0 +1,57 @@
+Test document extraction
+
+ $ "$TESTDIR/hghave" docutils || exit 80
+ $ HGENCODING=UTF-8
+ $ export HGENCODING
+ $ { echo C; find "$TESTDIR/../i18n" -name "*.po" | sort; } | while read PO; do
+ > LOCALE=`basename "$PO" .po`
+ > echo
+ > echo "% extracting documentation from $LOCALE"
+ > echo ".. -*- coding: utf-8 -*-" > gendoc-$LOCALE.txt
+ > echo "" >> gendoc-$LOCALE.txt
+ > LC_ALL=$LOCALE python "$TESTDIR/../doc/gendoc.py" >> gendoc-$LOCALE.txt 2> /dev/null || exit
+ >
+ > # We call runrst without adding "--halt warning" to make it report
+ > # all errors instead of stopping on the first one.
+ > echo "checking for parse errors"
+ > python "$TESTDIR/../doc/runrst" html gendoc-$LOCALE.txt /dev/null
+ > done
+
+ % extracting documentation from C
+ checking for parse errors
+
+ % extracting documentation from da
+ checking for parse errors
+
+ % extracting documentation from de
+ checking for parse errors
+
+ % extracting documentation from el
+ checking for parse errors
+
+ % extracting documentation from fr
+ checking for parse errors
+
+ % extracting documentation from it
+ checking for parse errors
+
+ % extracting documentation from ja
+ checking for parse errors
+
+ % extracting documentation from pt_BR
+ checking for parse errors
+
+ % extracting documentation from ro
+ checking for parse errors
+
+ % extracting documentation from ru
+ checking for parse errors
+
+ % extracting documentation from sv
+ checking for parse errors
+
+ % extracting documentation from zh_CN
+ checking for parse errors
+
+ % extracting documentation from zh_TW
+ checking for parse errors
diff --git a/tests/test-getbundle.t b/tests/test-getbundle.t
new file mode 100644
index 0000000..83feda6
--- /dev/null
+++ b/tests/test-getbundle.t
@@ -0,0 +1,254 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+= Test the getbundle() protocol function =
+
+Enable graphlog extension:
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "graphlog=" >> $HGRCPATH
+
+Create a test repository:
+
+ $ hg init repo
+ $ cd repo
+ $ hg debugbuilddag -n -m '+2 :fork +5 :p1 *fork +6 :p2 /p1 :m1 +3' > /dev/null
+ $ hg glog --template '{node}\n'
+ o 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
+ |
+ o 4801a72e5d88cb515b0c7e40fae34180f3f837f2
+ |
+ o 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
+ |
+ o 8365676dbab05860ce0d9110f2af51368b961bbd
+ |\
+ | o 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
+ | |
+ | o 13c0170174366b441dc68e8e33757232fa744458
+ | |
+ | o 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
+ | |
+ | o 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
+ | |
+ | o 928b5f94cdb278bb536eba552de348a4e92ef24d
+ | |
+ | o f34414c64173e0ecb61b25dc55e116dbbcc89bee
+ | |
+ | o 8931463777131cd73923e560b760061f2aa8a4bc
+ | |
+ o | 6621d79f61b23ec74cf4b69464343d9e0980ec8b
+ | |
+ o | bac16991d12ff45f9dc43c52da1946dfadb83e80
+ | |
+ o | ff42371d57168345fdf1a3aac66a51f6a45d41d2
+ | |
+ o | d5f6e1ea452285324836a49d7d3c2a63cfed1d31
+ | |
+ o | 713346a995c363120712aed1aee7e04afd867638
+ |/
+ o 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
+ |
+ o 7704483d56b2a7b5db54dcee7c62378ac629b348
+
+ $ cd ..
+
+
+= Test locally =
+
+Get everything:
+
+ $ hg debuggetbundle repo bundle
+ $ hg debugbundle bundle
+ 7704483d56b2a7b5db54dcee7c62378ac629b348
+ 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
+ 713346a995c363120712aed1aee7e04afd867638
+ d5f6e1ea452285324836a49d7d3c2a63cfed1d31
+ ff42371d57168345fdf1a3aac66a51f6a45d41d2
+ bac16991d12ff45f9dc43c52da1946dfadb83e80
+ 6621d79f61b23ec74cf4b69464343d9e0980ec8b
+ 8931463777131cd73923e560b760061f2aa8a4bc
+ f34414c64173e0ecb61b25dc55e116dbbcc89bee
+ 928b5f94cdb278bb536eba552de348a4e92ef24d
+ 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
+ 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
+ 13c0170174366b441dc68e8e33757232fa744458
+ 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
+ 8365676dbab05860ce0d9110f2af51368b961bbd
+ 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
+ 4801a72e5d88cb515b0c7e40fae34180f3f837f2
+ 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
+
+Get part of linear run:
+
+ $ hg debuggetbundle repo bundle -H 4801a72e5d88cb515b0c7e40fae34180f3f837f2 -C 8365676dbab05860ce0d9110f2af51368b961bbd
+ $ hg debugbundle bundle
+ 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
+ 4801a72e5d88cb515b0c7e40fae34180f3f837f2
+
+Get missing branch and merge:
+
+ $ hg debuggetbundle repo bundle -H 4801a72e5d88cb515b0c7e40fae34180f3f837f2 -C 13c0170174366b441dc68e8e33757232fa744458
+ $ hg debugbundle bundle
+ 713346a995c363120712aed1aee7e04afd867638
+ d5f6e1ea452285324836a49d7d3c2a63cfed1d31
+ ff42371d57168345fdf1a3aac66a51f6a45d41d2
+ bac16991d12ff45f9dc43c52da1946dfadb83e80
+ 6621d79f61b23ec74cf4b69464343d9e0980ec8b
+ 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
+ 8365676dbab05860ce0d9110f2af51368b961bbd
+ 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
+ 4801a72e5d88cb515b0c7e40fae34180f3f837f2
+
+Get from only one head:
+
+ $ hg debuggetbundle repo bundle -H 928b5f94cdb278bb536eba552de348a4e92ef24d -C 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
+ $ hg debugbundle bundle
+ 8931463777131cd73923e560b760061f2aa8a4bc
+ f34414c64173e0ecb61b25dc55e116dbbcc89bee
+ 928b5f94cdb278bb536eba552de348a4e92ef24d
+
+Get parts of two branches:
+
+ $ hg debuggetbundle repo bundle -H 13c0170174366b441dc68e8e33757232fa744458 -C 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 -H bac16991d12ff45f9dc43c52da1946dfadb83e80 -C d5f6e1ea452285324836a49d7d3c2a63cfed1d31
+ $ hg debugbundle bundle
+ ff42371d57168345fdf1a3aac66a51f6a45d41d2
+ bac16991d12ff45f9dc43c52da1946dfadb83e80
+ 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
+ 13c0170174366b441dc68e8e33757232fa744458
+
+Check that we get all needed file changes:
+
+ $ hg debugbundle bundle --all
+ format: id, p1, p2, cset, delta base, len(delta)
+
+ changelog
+ ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 99
+ bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 99
+ 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 bac16991d12ff45f9dc43c52da1946dfadb83e80 102
+ 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 102
+
+ manifest
+ dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 591f732a3faf1fb903815273f3c199a514a61ccb 113
+ 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 dac7984588fc4eea7acbf39693a9c1b06f5b175d 113
+ eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0772616e6b48a76afb6c1458e193cbb3dae2e4ff 295
+ b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 eb498cd9af6c44108e43041e951ce829e29f6c80 114
+
+ mf
+ 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 17
+ c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 18
+ 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 c7b583de053293870e145f45bd2d61643563fd06 149
+ 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 266ee3c0302a5a18f1cf96817ac79a51836179e9 19
+
+ nf11
+ 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 16
+
+ nf12
+ ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 0000000000000000000000000000000000000000 16
+
+ nf4
+ 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 15
+
+ nf5
+ 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 0000000000000000000000000000000000000000 15
+
+Get branch and merge:
+
+ $ hg debuggetbundle repo bundle -C 7704483d56b2a7b5db54dcee7c62378ac629b348 -H 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
+ $ hg debugbundle bundle
+ 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
+ 713346a995c363120712aed1aee7e04afd867638
+ d5f6e1ea452285324836a49d7d3c2a63cfed1d31
+ ff42371d57168345fdf1a3aac66a51f6a45d41d2
+ bac16991d12ff45f9dc43c52da1946dfadb83e80
+ 6621d79f61b23ec74cf4b69464343d9e0980ec8b
+ 8931463777131cd73923e560b760061f2aa8a4bc
+ f34414c64173e0ecb61b25dc55e116dbbcc89bee
+ 928b5f94cdb278bb536eba552de348a4e92ef24d
+ 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
+ 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
+ 13c0170174366b441dc68e8e33757232fa744458
+ 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
+ 8365676dbab05860ce0d9110f2af51368b961bbd
+ 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
+
+
+= Test via HTTP =
+
+Get everything:
+
+ $ hg serve -R repo -p $HGPORT -d --pid-file=hg.pid -E error.log -A access.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg debuggetbundle http://localhost:$HGPORT/ bundle
+ $ hg debugbundle bundle
+ 7704483d56b2a7b5db54dcee7c62378ac629b348
+ 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
+ 713346a995c363120712aed1aee7e04afd867638
+ d5f6e1ea452285324836a49d7d3c2a63cfed1d31
+ ff42371d57168345fdf1a3aac66a51f6a45d41d2
+ bac16991d12ff45f9dc43c52da1946dfadb83e80
+ 6621d79f61b23ec74cf4b69464343d9e0980ec8b
+ 8931463777131cd73923e560b760061f2aa8a4bc
+ f34414c64173e0ecb61b25dc55e116dbbcc89bee
+ 928b5f94cdb278bb536eba552de348a4e92ef24d
+ 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
+ 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
+ 13c0170174366b441dc68e8e33757232fa744458
+ 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
+ 8365676dbab05860ce0d9110f2af51368b961bbd
+ 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
+ 4801a72e5d88cb515b0c7e40fae34180f3f837f2
+ 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
+
+Get parts of two branches:
+
+ $ hg debuggetbundle http://localhost:$HGPORT/ bundle -H 13c0170174366b441dc68e8e33757232fa744458 -C 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 -H bac16991d12ff45f9dc43c52da1946dfadb83e80 -C d5f6e1ea452285324836a49d7d3c2a63cfed1d31
+ $ hg debugbundle bundle
+ ff42371d57168345fdf1a3aac66a51f6a45d41d2
+ bac16991d12ff45f9dc43c52da1946dfadb83e80
+ 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
+ 13c0170174366b441dc68e8e33757232fa744458
+
+Check that we get all needed file changes:
+
+ $ hg debugbundle bundle --all
+ format: id, p1, p2, cset, delta base, len(delta)
+
+ changelog
+ ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 99
+ bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 99
+ 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 bac16991d12ff45f9dc43c52da1946dfadb83e80 102
+ 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 102
+
+ manifest
+ dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 591f732a3faf1fb903815273f3c199a514a61ccb 113
+ 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 dac7984588fc4eea7acbf39693a9c1b06f5b175d 113
+ eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0772616e6b48a76afb6c1458e193cbb3dae2e4ff 295
+ b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 eb498cd9af6c44108e43041e951ce829e29f6c80 114
+
+ mf
+ 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 17
+ c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 18
+ 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 c7b583de053293870e145f45bd2d61643563fd06 149
+ 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 266ee3c0302a5a18f1cf96817ac79a51836179e9 19
+
+ nf11
+ 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 16
+
+ nf12
+ ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 0000000000000000000000000000000000000000 16
+
+ nf4
+ 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 15
+
+ nf5
+ 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 0000000000000000000000000000000000000000 15
+
+Verify we hit the HTTP server:
+
+ $ cat access.log
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=700b7e19db54103633c4bf4a6a6b6d55f4d50c03+d5f6e1ea452285324836a49d7d3c2a63cfed1d31&heads=13c0170174366b441dc68e8e33757232fa744458+bac16991d12ff45f9dc43c52da1946dfadb83e80 (glob)
+
+ $ cat error.log
+
diff --git a/tests/test-git-export.t b/tests/test-git-export.t
new file mode 100644
index 0000000..3efdc16
--- /dev/null
+++ b/tests/test-git-export.t
@@ -0,0 +1,362 @@
+ $ hg init
+ $ echo start > start
+ $ hg ci -Amstart
+ adding start
+
+New file:
+
+ $ echo new > new
+ $ hg ci -Amnew
+ adding new
+ $ hg diff --git -r 0
+ diff --git a/new b/new
+ new file mode 100644
+ --- /dev/null
+ +++ b/new
+ @@ -0,0 +1,1 @@
+ +new
+
+Copy:
+
+ $ hg cp new copy
+ $ hg ci -mcopy
+ $ hg diff --git -r 1:tip
+ diff --git a/new b/copy
+ copy from new
+ copy to copy
+
+Rename:
+
+ $ hg mv copy rename
+ $ hg ci -mrename
+ $ hg diff --git -r 2:tip
+ diff --git a/copy b/rename
+ rename from copy
+ rename to rename
+
+Delete:
+
+ $ hg rm rename
+ $ hg ci -mdelete
+ $ hg diff --git -r 3:tip
+ diff --git a/rename b/rename
+ deleted file mode 100644
+ --- a/rename
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -new
+
+ $ cat > src <<EOF
+ > 1
+ > 2
+ > 3
+ > 4
+ > 5
+ > EOF
+ $ hg ci -Amsrc
+ adding src
+
+#if execbit
+
+chmod 644:
+
+ $ chmod +x src
+ $ hg ci -munexec
+ $ hg diff --git -r 5:tip
+ diff --git a/src b/src
+ old mode 100644
+ new mode 100755
+
+Rename+mod+chmod:
+
+ $ hg mv src dst
+ $ chmod -x dst
+ $ echo a >> dst
+ $ hg ci -mrenamemod
+ $ hg diff --git -r 6:tip
+ diff --git a/src b/dst
+ old mode 100755
+ new mode 100644
+ rename from src
+ rename to dst
+ --- a/src
+ +++ b/dst
+ @@ -3,3 +3,4 @@
+ 3
+ 4
+ 5
+ +a
+
+Nonexistent in tip+chmod:
+
+ $ hg diff --git -r 5:6
+ diff --git a/src b/src
+ old mode 100644
+ new mode 100755
+
+#else
+
+Dummy changes when no exec bit, mocking the execbit commit structure
+
+ $ echo change >> src
+ $ hg ci -munexec
+ $ hg mv src dst
+ $ hg ci -mrenamemod
+
+#endif
+
+Binary diff:
+
+ $ cp "$TESTDIR/binfile.bin" .
+ $ hg add binfile.bin
+ $ hg diff --git > b.diff
+ $ cat b.diff
+ diff --git a/binfile.bin b/binfile.bin
+ new file mode 100644
+ index 0000000000000000000000000000000000000000..37ba3d1c6f17137d9c5f5776fa040caf5fe73ff9
+ GIT binary patch
+ literal 593
+ zc$@)I0<QguP)<h;3K|Lk000e1NJLTq000mG000mO0ssI2kdbIM00009a7bBm000XU
+ z000XU0RWnu7ytkO2XskIMF-Uh9TW;VpMjwv0005-Nkl<ZD9@FWPs=e;7{<>W$NUkd
+ zX$nnYLt$-$V!?uy+1V%`z&Eh=ah|duER<4|QWhju3gb^nF*8iYobxWG-qqXl=2~5M
+ z*IoDB)sG^CfNuoBmqLTVU^<;@nwHP!1wrWd`{(mHo6VNXWtyh{alzqmsH*yYzpvLT
+ zLdY<T=ks|woh-`&01!ej#(xbV1f|pI*=%;d-%F*E*X#ZH`4I%6SS+$EJDE&ct=8po
+ ziN#{?_j|kD%Cd|oiqds`xm@;oJ-^?NG3Gdqrs?5u*zI;{nogxsx~^|Fn^Y?Gdc6<;
+ zfMJ+iF1J`LMx&A2?dEwNW8ClebzPTbIh{@$hS6*`kH@1d%Lo7fA#}N1)oN7`gm$~V
+ z+wDx#)OFqMcE{s!JN0-xhG8ItAjVkJwEcb`3WWlJfU2r?;Pd%dmR+q@mSri5q9_W-
+ zaR2~ECX?B2w+zELozC0s*6Z~|QG^f{3I#<`?)Q7U-JZ|q5W;9Q8i_=pBuSzunx=U;
+ z9C)5jBoYw9^?EHyQl(M}1OlQcCX>lXB*ODN003Z&P17_@)3Pi=i0wb04<W?v-u}7K
+ zXmmQA+wDgE!qR9o8jr`%=ab_&uh(l?R=r;Tjiqon91I2-hIu?57~@*4h7h9uORK#=
+ fQItJW-{SoTm)8|5##k|m00000NkvXXu0mjf{mKw4
+
+
+Import binary diff:
+
+ $ hg revert binfile.bin
+ $ rm binfile.bin
+ $ hg import -mfoo b.diff
+ applying b.diff
+ $ cmp binfile.bin "$TESTDIR/binfile.bin"
+
+Rename binary file:
+
+ $ hg mv binfile.bin renamed.bin
+ $ hg diff --git
+ diff --git a/binfile.bin b/renamed.bin
+ rename from binfile.bin
+ rename to renamed.bin
+
+Diff across many revisions:
+
+ $ hg mv dst dst2
+ $ hg ci -m 'mv dst dst2'
+
+ $ echo >> start
+ $ hg ci -m 'change start'
+
+ $ hg revert -r -2 start
+ $ hg mv dst2 dst3
+ $ hg ci -m 'mv dst2 dst3; revert start'
+
+ $ hg diff --git -r 9:11
+ diff --git a/dst2 b/dst3
+ rename from dst2
+ rename to dst3
+
+Reversed:
+
+ $ hg diff --git -r 11:9
+ diff --git a/dst3 b/dst2
+ rename from dst3
+ rename to dst2
+
+
+ $ echo a >> foo
+ $ hg add foo
+ $ hg ci -m 'add foo'
+ $ echo b >> foo
+ $ hg ci -m 'change foo'
+ $ hg mv foo bar
+ $ hg ci -m 'mv foo bar'
+ $ echo c >> bar
+ $ hg ci -m 'change bar'
+
+File created before r1 and renamed before r2:
+
+ $ hg diff --git -r -3:-1
+ diff --git a/foo b/bar
+ rename from foo
+ rename to bar
+ --- a/foo
+ +++ b/bar
+ @@ -1,2 +1,3 @@
+ a
+ b
+ +c
+
+Reversed:
+
+ $ hg diff --git -r -1:-3
+ diff --git a/bar b/foo
+ rename from bar
+ rename to foo
+ --- a/bar
+ +++ b/foo
+ @@ -1,3 +1,2 @@
+ a
+ b
+ -c
+
+File created in r1 and renamed before r2:
+
+ $ hg diff --git -r -4:-1
+ diff --git a/foo b/bar
+ rename from foo
+ rename to bar
+ --- a/foo
+ +++ b/bar
+ @@ -1,1 +1,3 @@
+ a
+ +b
+ +c
+
+Reversed:
+
+ $ hg diff --git -r -1:-4
+ diff --git a/bar b/foo
+ rename from bar
+ rename to foo
+ --- a/bar
+ +++ b/foo
+ @@ -1,3 +1,1 @@
+ a
+ -b
+ -c
+
+File created after r1 and renamed before r2:
+
+ $ hg diff --git -r -5:-1
+ diff --git a/bar b/bar
+ new file mode 100644
+ --- /dev/null
+ +++ b/bar
+ @@ -0,0 +1,3 @@
+ +a
+ +b
+ +c
+
+Reversed:
+
+ $ hg diff --git -r -1:-5
+ diff --git a/bar b/bar
+ deleted file mode 100644
+ --- a/bar
+ +++ /dev/null
+ @@ -1,3 +0,0 @@
+ -a
+ -b
+ -c
+
+
+Comparing with the working dir:
+
+ $ echo >> start
+ $ hg ci -m 'change start again'
+
+ $ echo > created
+ $ hg add created
+ $ hg ci -m 'add created'
+
+ $ hg mv created created2
+ $ hg ci -m 'mv created created2'
+
+ $ hg mv created2 created3
+
+There's a copy in the working dir:
+
+ $ hg diff --git
+ diff --git a/created2 b/created3
+ rename from created2
+ rename to created3
+
+There's another copy between the original rev and the wd:
+
+ $ hg diff --git -r -2
+ diff --git a/created b/created3
+ rename from created
+ rename to created3
+
+The source of the copy was created after the original rev:
+
+ $ hg diff --git -r -3
+ diff --git a/created3 b/created3
+ new file mode 100644
+ --- /dev/null
+ +++ b/created3
+ @@ -0,0 +1,1 @@
+ +
+ $ hg ci -m 'mv created2 created3'
+
+
+ $ echo > brand-new
+ $ hg add brand-new
+ $ hg ci -m 'add brand-new'
+ $ hg mv brand-new brand-new2
+
+Created in parent of wd; renamed in the wd:
+
+ $ hg diff --git
+ diff --git a/brand-new b/brand-new2
+ rename from brand-new
+ rename to brand-new2
+
+Created between r1 and parent of wd; renamed in the wd:
+
+ $ hg diff --git -r -2
+ diff --git a/brand-new2 b/brand-new2
+ new file mode 100644
+ --- /dev/null
+ +++ b/brand-new2
+ @@ -0,0 +1,1 @@
+ +
+ $ hg ci -m 'mv brand-new brand-new2'
+
+One file is copied to many destinations and removed:
+
+ $ hg cp brand-new2 brand-new3
+ $ hg mv brand-new2 brand-new3-2
+ $ hg ci -m 'multiple renames/copies'
+ $ hg diff --git -r -2 -r -1
+ diff --git a/brand-new2 b/brand-new3
+ rename from brand-new2
+ rename to brand-new3
+ diff --git a/brand-new2 b/brand-new3-2
+ copy from brand-new2
+ copy to brand-new3-2
+
+Reversed:
+
+ $ hg diff --git -r -1 -r -2
+ diff --git a/brand-new3 b/brand-new2
+ rename from brand-new3
+ rename to brand-new2
+ diff --git a/brand-new3-2 b/brand-new3-2
+ deleted file mode 100644
+ --- a/brand-new3-2
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -
+
+There should be a trailing TAB if there are spaces in the file name:
+
+ $ echo foo > 'with spaces'
+ $ hg add 'with spaces'
+ $ hg diff --git
+ diff --git a/with spaces b/with spaces
+ new file mode 100644
+ --- /dev/null
+ +++ b/with spaces
+ @@ -0,0 +1,1 @@
+ +foo
+ $ hg ci -m 'add filename with spaces'
+
diff --git a/tests/test-globalopts.t b/tests/test-globalopts.t
new file mode 100644
index 0000000..53716cd
--- /dev/null
+++ b/tests/test-globalopts.t
@@ -0,0 +1,449 @@
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg ci -A -d'1 0' -m a
+ adding a
+
+ $ cd ..
+
+ $ hg init b
+ $ cd b
+ $ echo b > b
+ $ hg ci -A -d'1 0' -m b
+ adding b
+
+ $ cd ..
+
+ $ hg clone a c
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd c
+ $ cat >> .hg/hgrc <<EOF
+ > [paths]
+ > relative = ../a
+ > EOF
+ $ hg pull -f ../b
+ pulling from ../b
+ searching for changes
+ warning: repository is unrelated
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cd ..
+
+Testing -R/--repository:
+
+ $ hg -R a tip
+ changeset: 0:8580ff50825a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: a
+
+ $ hg --repository b tip
+ changeset: 0:b6c483daf290
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b
+
+
+-R with a URL:
+
+ $ hg -R file:a identify
+ 8580ff50825a tip
+ $ hg -R file://localhost/`pwd`/a/ identify
+ 8580ff50825a tip
+
+-R with path aliases:
+
+ $ cd c
+ $ hg -R default identify
+ 8580ff50825a tip
+ $ hg -R relative identify
+ 8580ff50825a tip
+ $ echo '[paths]' >> $HGRCPATH
+ $ echo 'relativetohome = a' >> $HGRCPATH
+ $ HOME=`pwd`/../ hg -R relativetohome identify
+ 8580ff50825a tip
+ $ cd ..
+
+#if no-outer-repo
+
+Implicit -R:
+
+ $ hg ann a/a
+ 0: a
+ $ hg ann a/a a/a
+ 0: a
+ $ hg ann a/a b/b
+ abort: no repository found in '$TESTTMP' (.hg not found)!
+ [255]
+ $ hg -R b ann a/a
+ abort: a/a not under root
+ [255]
+ $ hg log
+ abort: no repository found in '$TESTTMP' (.hg not found)!
+ [255]
+
+#endif
+
+Abbreviation of long option:
+
+ $ hg --repo c tip
+ changeset: 1:b6c483daf290
+ tag: tip
+ parent: -1:000000000000
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b
+
+
+earlygetopt with duplicate options (36d23de02da1):
+
+ $ hg --cwd a --cwd b --cwd c tip
+ changeset: 1:b6c483daf290
+ tag: tip
+ parent: -1:000000000000
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b
+
+ $ hg --repo c --repository b -R a tip
+ changeset: 0:8580ff50825a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: a
+
+
+earlygetopt short option without following space:
+
+ $ hg -q -Rb tip
+ 0:b6c483daf290
+
+earlygetopt with illegal abbreviations:
+
+ $ hg --confi "foo.bar=baz"
+ abort: option --config may not be abbreviated!
+ [255]
+ $ hg --cw a tip
+ abort: option --cwd may not be abbreviated!
+ [255]
+ $ hg --rep a tip
+ abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
+ [255]
+ $ hg --repositor a tip
+ abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
+ [255]
+ $ hg -qR a tip
+ abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
+ [255]
+ $ hg -qRa tip
+ abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
+ [255]
+
+Testing --cwd:
+
+ $ hg --cwd a parents
+ changeset: 0:8580ff50825a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: a
+
+
+Testing -y/--noninteractive - just be sure it is parsed:
+
+ $ hg --cwd a tip -q --noninteractive
+ 0:8580ff50825a
+ $ hg --cwd a tip -q -y
+ 0:8580ff50825a
+
+Testing -q/--quiet:
+
+ $ hg -R a -q tip
+ 0:8580ff50825a
+ $ hg -R b -q tip
+ 0:b6c483daf290
+ $ hg -R c --quiet parents
+ 0:8580ff50825a
+ 1:b6c483daf290
+
+Testing -v/--verbose:
+
+ $ hg --cwd c head -v
+ changeset: 1:b6c483daf290
+ tag: tip
+ parent: -1:000000000000
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ files: b
+ description:
+ b
+
+
+ changeset: 0:8580ff50825a
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ files: a
+ description:
+ a
+
+
+ $ hg --cwd b tip --verbose
+ changeset: 0:b6c483daf290
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ files: b
+ description:
+ b
+
+
+
+Testing --config:
+
+ $ hg --cwd c --config paths.quuxfoo=bar paths | grep quuxfoo > /dev/null && echo quuxfoo
+ quuxfoo
+ $ hg --cwd c --config '' tip -q
+ abort: malformed --config option: '' (use --config section.name=value)
+ [255]
+ $ hg --cwd c --config a.b tip -q
+ abort: malformed --config option: 'a.b' (use --config section.name=value)
+ [255]
+ $ hg --cwd c --config a tip -q
+ abort: malformed --config option: 'a' (use --config section.name=value)
+ [255]
+ $ hg --cwd c --config a.= tip -q
+ abort: malformed --config option: 'a.=' (use --config section.name=value)
+ [255]
+ $ hg --cwd c --config .b= tip -q
+ abort: malformed --config option: '.b=' (use --config section.name=value)
+ [255]
+
+Testing --debug:
+
+ $ hg --cwd c log --debug
+ changeset: 1:b6c483daf2907ce5825c0bb50f5716226281cc1a
+ tag: tip
+ parent: -1:0000000000000000000000000000000000000000
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 1:23226e7a252cacdc2d99e4fbdc3653441056de49
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ files+: b
+ extra: branch=default
+ description:
+ b
+
+
+ changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
+ parent: -1:0000000000000000000000000000000000000000
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ files+: a
+ extra: branch=default
+ description:
+ a
+
+
+
+Testing --traceback:
+
+ $ hg --cwd c --config x --traceback id 2>&1 | grep -i 'traceback'
+ Traceback (most recent call last):
+
+Testing --time:
+
+ $ hg --cwd a --time id
+ 8580ff50825a tip
+ time: real * (glob)
+
+Testing --version:
+
+ $ hg --version -q
+ Mercurial Distributed SCM * (glob)
+
+hide outer repo
+ $ hg init
+
+Testing -h/--help:
+
+ $ hg -h
+ Mercurial Distributed SCM
+
+ list of commands:
+
+ add add the specified files on the next commit
+ addremove add all new files, delete all missing files
+ annotate show changeset information by line for each file
+ archive create an unversioned archive of a repository revision
+ backout reverse effect of earlier changeset
+ bisect subdivision search of changesets
+ bookmarks track a line of development with movable markers
+ branch set or show the current branch name
+ branches list repository named branches
+ bundle create a changegroup file
+ cat output the current or given revision of files
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ copy mark files as copied for the next commit
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ graft copy changes from other branches onto the current branch
+ grep search for a pattern in specified files and revisions
+ heads show current repository heads or show branch heads
+ help show help for a given topic or a help overview
+ identify identify the working copy or specified revision
+ import import an ordered set of patches
+ incoming show new changesets found in source
+ init create a new repository in the given directory
+ locate locate files matching specific patterns
+ log show revision history of entire repository or files
+ manifest output the current or given revision of the project manifest
+ merge merge working directory with another revision
+ outgoing show changesets not found in the destination
+ parents show the parents of the working directory or revision
+ paths show aliases for remote repositories
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ recover roll back an interrupted transaction
+ remove remove the specified files on the next commit
+ rename rename files; equivalent of copy + remove
+ resolve redo merges or set/view the merge status of files
+ revert restore files to their checkout state
+ rollback roll back the last transaction (dangerous)
+ root print the root (top) of the current working directory
+ serve start stand-alone webserver
+ showconfig show combined config settings from all hgrc files
+ status show changed files in the working directory
+ summary summarize working directory state
+ tag add one or more tags for the current or given revision
+ tags list repository tags
+ tip show the tip revision
+ unbundle apply one or more changegroup files
+ update update working directory (or switch revisions)
+ verify verify the integrity of the repository
+ version output version and copyright information
+
+ additional help topics:
+
+ config Configuration Files
+ dates Date Formats
+ diffs Diff Formats
+ environment Environment Variables
+ extensions Using Additional Features
+ filesets Specifying File Sets
+ glossary Glossary
+ hgignore Syntax for Mercurial Ignore Files
+ hgweb Configuring hgweb
+ merge-tools Merge Tools
+ multirevs Specifying Multiple Revisions
+ patterns File Name Patterns
+ phases Working with Phases
+ revisions Specifying Single Revisions
+ revsets Specifying Revision Sets
+ subrepos Subrepositories
+ templating Template Usage
+ urls URL Paths
+
+ use "hg -v help" to show builtin aliases and global options
+
+
+
+ $ hg --help
+ Mercurial Distributed SCM
+
+ list of commands:
+
+ add add the specified files on the next commit
+ addremove add all new files, delete all missing files
+ annotate show changeset information by line for each file
+ archive create an unversioned archive of a repository revision
+ backout reverse effect of earlier changeset
+ bisect subdivision search of changesets
+ bookmarks track a line of development with movable markers
+ branch set or show the current branch name
+ branches list repository named branches
+ bundle create a changegroup file
+ cat output the current or given revision of files
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ copy mark files as copied for the next commit
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ graft copy changes from other branches onto the current branch
+ grep search for a pattern in specified files and revisions
+ heads show current repository heads or show branch heads
+ help show help for a given topic or a help overview
+ identify identify the working copy or specified revision
+ import import an ordered set of patches
+ incoming show new changesets found in source
+ init create a new repository in the given directory
+ locate locate files matching specific patterns
+ log show revision history of entire repository or files
+ manifest output the current or given revision of the project manifest
+ merge merge working directory with another revision
+ outgoing show changesets not found in the destination
+ parents show the parents of the working directory or revision
+ paths show aliases for remote repositories
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ recover roll back an interrupted transaction
+ remove remove the specified files on the next commit
+ rename rename files; equivalent of copy + remove
+ resolve redo merges or set/view the merge status of files
+ revert restore files to their checkout state
+ rollback roll back the last transaction (dangerous)
+ root print the root (top) of the current working directory
+ serve start stand-alone webserver
+ showconfig show combined config settings from all hgrc files
+ status show changed files in the working directory
+ summary summarize working directory state
+ tag add one or more tags for the current or given revision
+ tags list repository tags
+ tip show the tip revision
+ unbundle apply one or more changegroup files
+ update update working directory (or switch revisions)
+ verify verify the integrity of the repository
+ version output version and copyright information
+
+ additional help topics:
+
+ config Configuration Files
+ dates Date Formats
+ diffs Diff Formats
+ environment Environment Variables
+ extensions Using Additional Features
+ filesets Specifying File Sets
+ glossary Glossary
+ hgignore Syntax for Mercurial Ignore Files
+ hgweb Configuring hgweb
+ merge-tools Merge Tools
+ multirevs Specifying Multiple Revisions
+ patterns File Name Patterns
+ phases Working with Phases
+ revisions Specifying Single Revisions
+ revsets Specifying Revision Sets
+ subrepos Subrepositories
+ templating Template Usage
+ urls URL Paths
+
+ use "hg -v help" to show builtin aliases and global options
+
+Not tested: --debugger
+
diff --git a/tests/test-glog.t b/tests/test-glog.t
new file mode 100644
index 0000000..25d3fcc
--- /dev/null
+++ b/tests/test-glog.t
@@ -0,0 +1,2088 @@
+@ (34) head
+|
+| o (33) head
+| |
+o | (32) expand
+|\ \
+| o \ (31) expand
+| |\ \
+| | o \ (30) expand
+| | |\ \
+| | | o | (29) regular commit
+| | | | |
+| | o | | (28) merge zero known
+| | |\ \ \
+o | | | | | (27) collapse
+|/ / / / /
+| | o---+ (26) merge one known; far right
+| | | | |
++---o | | (25) merge one known; far left
+| | | | |
+| | o | | (24) merge one known; immediate right
+| | |\| |
+| | o | | (23) merge one known; immediate left
+| |/| | |
++---o---+ (22) merge two known; one far left, one far right
+| | / /
+o | | | (21) expand
+|\ \ \ \
+| o---+-+ (20) merge two known; two far right
+| / / /
+o | | | (19) expand
+|\ \ \ \
++---+---o (18) merge two known; two far left
+| | | |
+| o | | (17) expand
+| |\ \ \
+| | o---+ (16) merge two known; one immediate right, one near right
+| | |/ /
+o | | | (15) expand
+|\ \ \ \
+| o-----+ (14) merge two known; one immediate right, one far right
+| |/ / /
+o | | | (13) expand
+|\ \ \ \
++---o | | (12) merge two known; one immediate right, one far left
+| | |/ /
+| o | | (11) expand
+| |\ \ \
+| | o---+ (10) merge two known; one immediate left, one near right
+| |/ / /
+o | | | (9) expand
+|\ \ \ \
+| o-----+ (8) merge two known; one immediate left, one far right
+|/ / / /
+o | | | (7) expand
+|\ \ \ \
++---o | | (6) merge two known; one immediate left, one far left
+| |/ / /
+| o | | (5) expand
+| |\ \ \
+| | o | | (4) merge two known; one immediate left, one immediate right
+| |/|/ /
+| o / / (3) collapse
+|/ / /
+o / / (2) collapse
+|/ /
+o / (1) collapse
+|/
+o (0) root
+
+
+ $ commit()
+ > {
+ > rev=$1
+ > msg=$2
+ > shift 2
+ > if [ "$#" -gt 0 ]; then
+ > hg debugsetparents "$@"
+ > fi
+ > echo $rev > a
+ > hg commit -Aqd "$rev 0" -m "($rev) $msg"
+ > }
+
+ $ cat > printrevset.py <<EOF
+ > from mercurial import extensions, revset, commands, cmdutil
+ >
+ > def uisetup(ui):
+ > def printrevset(orig, ui, repo, *pats, **opts):
+ > if opts.get('print_revset'):
+ > expr = cmdutil.getgraphlogrevs(repo, pats, opts)[1]
+ > if expr:
+ > tree = revset.parse(expr)[0]
+ > else:
+ > tree = []
+ > ui.write('%r\n' % (opts.get('rev', []),))
+ > ui.write(revset.prettyformat(tree) + '\n')
+ > return 0
+ > return orig(ui, repo, *pats, **opts)
+ > entry = extensions.wrapcommand(commands.table, 'log', printrevset)
+ > entry[1].append(('', 'print-revset', False,
+ > 'print generated revset and exit (DEPRECATED)'))
+ > EOF
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "graphlog=" >> $HGRCPATH
+ $ echo "printrevset=`pwd`/printrevset.py" >> $HGRCPATH
+
+ $ hg init repo
+ $ cd repo
+
+Empty repo:
+
+ $ hg glog
+
+
+Building DAG:
+
+ $ commit 0 "root"
+ $ commit 1 "collapse" 0
+ $ commit 2 "collapse" 1
+ $ commit 3 "collapse" 2
+ $ commit 4 "merge two known; one immediate left, one immediate right" 1 3
+ $ commit 5 "expand" 3 4
+ $ commit 6 "merge two known; one immediate left, one far left" 2 5
+ $ commit 7 "expand" 2 5
+ $ commit 8 "merge two known; one immediate left, one far right" 0 7
+ $ commit 9 "expand" 7 8
+ $ commit 10 "merge two known; one immediate left, one near right" 0 6
+ $ commit 11 "expand" 6 10
+ $ commit 12 "merge two known; one immediate right, one far left" 1 9
+ $ commit 13 "expand" 9 11
+ $ commit 14 "merge two known; one immediate right, one far right" 0 12
+ $ commit 15 "expand" 13 14
+ $ commit 16 "merge two known; one immediate right, one near right" 0 1
+ $ commit 17 "expand" 12 16
+ $ commit 18 "merge two known; two far left" 1 15
+ $ commit 19 "expand" 15 17
+ $ commit 20 "merge two known; two far right" 0 18
+ $ commit 21 "expand" 19 20
+ $ commit 22 "merge two known; one far left, one far right" 18 21
+ $ commit 23 "merge one known; immediate left" 1 22
+ $ commit 24 "merge one known; immediate right" 0 23
+ $ commit 25 "merge one known; far left" 21 24
+ $ commit 26 "merge one known; far right" 18 25
+ $ commit 27 "collapse" 21
+ $ commit 28 "merge zero known" 1 26
+ $ commit 29 "regular commit" 0
+ $ commit 30 "expand" 28 29
+ $ commit 31 "expand" 21 30
+ $ commit 32 "expand" 27 31
+ $ commit 33 "head" 18
+ $ commit 34 "head" 32
+
+
+ $ hg glog -q
+ @ 34:fea3ac5810e0
+ |
+ | o 33:68608f5145f9
+ | |
+ o | 32:d06dffa21a31
+ |\ \
+ | o \ 31:621d83e11f67
+ | |\ \
+ | | o \ 30:6e11cd4b648f
+ | | |\ \
+ | | | o | 29:cd9bb2be7593
+ | | | | |
+ | | o | | 28:44ecd0b9ae99
+ | | |\ \ \
+ o | | | | | 27:886ed638191b
+ |/ / / / /
+ | | o---+ 26:7f25b6c2f0b9
+ | | | | |
+ +---o | | 25:91da8ed57247
+ | | | | |
+ | | o | | 24:a9c19a3d96b7
+ | | |\| |
+ | | o | | 23:a01cddf0766d
+ | |/| | |
+ +---o---+ 22:e0d9cccacb5d
+ | | / /
+ o | | | 21:d42a756af44d
+ |\ \ \ \
+ | o---+-+ 20:d30ed6450e32
+ | / / /
+ o | | | 19:31ddc2c1573b
+ |\ \ \ \
+ +---+---o 18:1aa84d96232a
+ | | | |
+ | o | | 17:44765d7c06e0
+ | |\ \ \
+ | | o---+ 16:3677d192927d
+ | | |/ /
+ o | | | 15:1dda3f72782d
+ |\ \ \ \
+ | o-----+ 14:8eac370358ef
+ | |/ / /
+ o | | | 13:22d8966a97e3
+ |\ \ \ \
+ +---o | | 12:86b91144a6e9
+ | | |/ /
+ | o | | 11:832d76e6bdf2
+ | |\ \ \
+ | | o---+ 10:74c64d036d72
+ | |/ / /
+ o | | | 9:7010c0af0a35
+ |\ \ \ \
+ | o-----+ 8:7a0b11f71937
+ |/ / / /
+ o | | | 7:b632bb1b1224
+ |\ \ \ \
+ +---o | | 6:b105a072e251
+ | |/ / /
+ | o | | 5:4409d547b708
+ | |\ \ \
+ | | o | | 4:26a8bac39d9f
+ | |/|/ /
+ | o / / 3:27eef8ed80b4
+ |/ / /
+ o / / 2:3d9a33b8d1e1
+ |/ /
+ o / 1:6db2ef61d156
+ |/
+ o 0:e6eb3150255d
+
+
+ $ hg glog
+ @ changeset: 34:fea3ac5810e0
+ | tag: tip
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+ | o changeset: 33:68608f5145f9
+ | | parent: 18:1aa84d96232a
+ | | user: test
+ | | date: Thu Jan 01 00:00:33 1970 +0000
+ | | summary: (33) head
+ | |
+ o | changeset: 32:d06dffa21a31
+ |\ \ parent: 27:886ed638191b
+ | | | parent: 31:621d83e11f67
+ | | | user: test
+ | | | date: Thu Jan 01 00:00:32 1970 +0000
+ | | | summary: (32) expand
+ | | |
+ | o | changeset: 31:621d83e11f67
+ | |\ \ parent: 21:d42a756af44d
+ | | | | parent: 30:6e11cd4b648f
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:31 1970 +0000
+ | | | | summary: (31) expand
+ | | | |
+ | | o | changeset: 30:6e11cd4b648f
+ | | |\ \ parent: 28:44ecd0b9ae99
+ | | | | | parent: 29:cd9bb2be7593
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:30 1970 +0000
+ | | | | | summary: (30) expand
+ | | | | |
+ | | | o | changeset: 29:cd9bb2be7593
+ | | | | | parent: 0:e6eb3150255d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:29 1970 +0000
+ | | | | | summary: (29) regular commit
+ | | | | |
+ | | o | | changeset: 28:44ecd0b9ae99
+ | | |\ \ \ parent: 1:6db2ef61d156
+ | | | | | | parent: 26:7f25b6c2f0b9
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
+ | | | | | | summary: (28) merge zero known
+ | | | | | |
+ o | | | | | changeset: 27:886ed638191b
+ |/ / / / / parent: 21:d42a756af44d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:27 1970 +0000
+ | | | | | summary: (27) collapse
+ | | | | |
+ | | o---+ changeset: 26:7f25b6c2f0b9
+ | | | | | parent: 18:1aa84d96232a
+ | | | | | parent: 25:91da8ed57247
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:26 1970 +0000
+ | | | | | summary: (26) merge one known; far right
+ | | | | |
+ +---o | | changeset: 25:91da8ed57247
+ | | | | | parent: 21:d42a756af44d
+ | | | | | parent: 24:a9c19a3d96b7
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:25 1970 +0000
+ | | | | | summary: (25) merge one known; far left
+ | | | | |
+ | | o | | changeset: 24:a9c19a3d96b7
+ | | |\| | parent: 0:e6eb3150255d
+ | | | | | parent: 23:a01cddf0766d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:24 1970 +0000
+ | | | | | summary: (24) merge one known; immediate right
+ | | | | |
+ | | o | | changeset: 23:a01cddf0766d
+ | |/| | | parent: 1:6db2ef61d156
+ | | | | | parent: 22:e0d9cccacb5d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:23 1970 +0000
+ | | | | | summary: (23) merge one known; immediate left
+ | | | | |
+ +---o---+ changeset: 22:e0d9cccacb5d
+ | | | | parent: 18:1aa84d96232a
+ | | / / parent: 21:d42a756af44d
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:22 1970 +0000
+ | | | | summary: (22) merge two known; one far left, one far right
+ | | | |
+ o | | | changeset: 21:d42a756af44d
+ |\ \ \ \ parent: 19:31ddc2c1573b
+ | | | | | parent: 20:d30ed6450e32
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:21 1970 +0000
+ | | | | | summary: (21) expand
+ | | | | |
+ | o---+-+ changeset: 20:d30ed6450e32
+ | | | | parent: 0:e6eb3150255d
+ | / / / parent: 18:1aa84d96232a
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:20 1970 +0000
+ | | | | summary: (20) merge two known; two far right
+ | | | |
+ o | | | changeset: 19:31ddc2c1573b
+ |\ \ \ \ parent: 15:1dda3f72782d
+ | | | | | parent: 17:44765d7c06e0
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:19 1970 +0000
+ | | | | | summary: (19) expand
+ | | | | |
+ +---+---o changeset: 18:1aa84d96232a
+ | | | | parent: 1:6db2ef61d156
+ | | | | parent: 15:1dda3f72782d
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:18 1970 +0000
+ | | | | summary: (18) merge two known; two far left
+ | | | |
+ | o | | changeset: 17:44765d7c06e0
+ | |\ \ \ parent: 12:86b91144a6e9
+ | | | | | parent: 16:3677d192927d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:17 1970 +0000
+ | | | | | summary: (17) expand
+ | | | | |
+ | | o---+ changeset: 16:3677d192927d
+ | | | | | parent: 0:e6eb3150255d
+ | | |/ / parent: 1:6db2ef61d156
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:16 1970 +0000
+ | | | | summary: (16) merge two known; one immediate right, one near right
+ | | | |
+ o | | | changeset: 15:1dda3f72782d
+ |\ \ \ \ parent: 13:22d8966a97e3
+ | | | | | parent: 14:8eac370358ef
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:15 1970 +0000
+ | | | | | summary: (15) expand
+ | | | | |
+ | o-----+ changeset: 14:8eac370358ef
+ | | | | | parent: 0:e6eb3150255d
+ | |/ / / parent: 12:86b91144a6e9
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:14 1970 +0000
+ | | | | summary: (14) merge two known; one immediate right, one far right
+ | | | |
+ o | | | changeset: 13:22d8966a97e3
+ |\ \ \ \ parent: 9:7010c0af0a35
+ | | | | | parent: 11:832d76e6bdf2
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:13 1970 +0000
+ | | | | | summary: (13) expand
+ | | | | |
+ +---o | | changeset: 12:86b91144a6e9
+ | | |/ / parent: 1:6db2ef61d156
+ | | | | parent: 9:7010c0af0a35
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:12 1970 +0000
+ | | | | summary: (12) merge two known; one immediate right, one far left
+ | | | |
+ | o | | changeset: 11:832d76e6bdf2
+ | |\ \ \ parent: 6:b105a072e251
+ | | | | | parent: 10:74c64d036d72
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:11 1970 +0000
+ | | | | | summary: (11) expand
+ | | | | |
+ | | o---+ changeset: 10:74c64d036d72
+ | | | | | parent: 0:e6eb3150255d
+ | |/ / / parent: 6:b105a072e251
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:10 1970 +0000
+ | | | | summary: (10) merge two known; one immediate left, one near right
+ | | | |
+ o | | | changeset: 9:7010c0af0a35
+ |\ \ \ \ parent: 7:b632bb1b1224
+ | | | | | parent: 8:7a0b11f71937
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:09 1970 +0000
+ | | | | | summary: (9) expand
+ | | | | |
+ | o-----+ changeset: 8:7a0b11f71937
+ | | | | | parent: 0:e6eb3150255d
+ |/ / / / parent: 7:b632bb1b1224
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:08 1970 +0000
+ | | | | summary: (8) merge two known; one immediate left, one far right
+ | | | |
+ o | | | changeset: 7:b632bb1b1224
+ |\ \ \ \ parent: 2:3d9a33b8d1e1
+ | | | | | parent: 5:4409d547b708
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:07 1970 +0000
+ | | | | | summary: (7) expand
+ | | | | |
+ +---o | | changeset: 6:b105a072e251
+ | |/ / / parent: 2:3d9a33b8d1e1
+ | | | | parent: 5:4409d547b708
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:06 1970 +0000
+ | | | | summary: (6) merge two known; one immediate left, one far left
+ | | | |
+ | o | | changeset: 5:4409d547b708
+ | |\ \ \ parent: 3:27eef8ed80b4
+ | | | | | parent: 4:26a8bac39d9f
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:05 1970 +0000
+ | | | | | summary: (5) expand
+ | | | | |
+ | | o | | changeset: 4:26a8bac39d9f
+ | |/|/ / parent: 1:6db2ef61d156
+ | | | | parent: 3:27eef8ed80b4
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:04 1970 +0000
+ | | | | summary: (4) merge two known; one immediate left, one immediate right
+ | | | |
+ | o | | changeset: 3:27eef8ed80b4
+ |/ / / user: test
+ | | | date: Thu Jan 01 00:00:03 1970 +0000
+ | | | summary: (3) collapse
+ | | |
+ o | | changeset: 2:3d9a33b8d1e1
+ |/ / user: test
+ | | date: Thu Jan 01 00:00:02 1970 +0000
+ | | summary: (2) collapse
+ | |
+ o | changeset: 1:6db2ef61d156
+ |/ user: test
+ | date: Thu Jan 01 00:00:01 1970 +0000
+ | summary: (1) collapse
+ |
+ o changeset: 0:e6eb3150255d
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: (0) root
+
+
+File glog:
+ $ hg glog a
+ @ changeset: 34:fea3ac5810e0
+ | tag: tip
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+ | o changeset: 33:68608f5145f9
+ | | parent: 18:1aa84d96232a
+ | | user: test
+ | | date: Thu Jan 01 00:00:33 1970 +0000
+ | | summary: (33) head
+ | |
+ o | changeset: 32:d06dffa21a31
+ |\ \ parent: 27:886ed638191b
+ | | | parent: 31:621d83e11f67
+ | | | user: test
+ | | | date: Thu Jan 01 00:00:32 1970 +0000
+ | | | summary: (32) expand
+ | | |
+ | o | changeset: 31:621d83e11f67
+ | |\ \ parent: 21:d42a756af44d
+ | | | | parent: 30:6e11cd4b648f
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:31 1970 +0000
+ | | | | summary: (31) expand
+ | | | |
+ | | o | changeset: 30:6e11cd4b648f
+ | | |\ \ parent: 28:44ecd0b9ae99
+ | | | | | parent: 29:cd9bb2be7593
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:30 1970 +0000
+ | | | | | summary: (30) expand
+ | | | | |
+ | | | o | changeset: 29:cd9bb2be7593
+ | | | | | parent: 0:e6eb3150255d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:29 1970 +0000
+ | | | | | summary: (29) regular commit
+ | | | | |
+ | | o | | changeset: 28:44ecd0b9ae99
+ | | |\ \ \ parent: 1:6db2ef61d156
+ | | | | | | parent: 26:7f25b6c2f0b9
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
+ | | | | | | summary: (28) merge zero known
+ | | | | | |
+ o | | | | | changeset: 27:886ed638191b
+ |/ / / / / parent: 21:d42a756af44d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:27 1970 +0000
+ | | | | | summary: (27) collapse
+ | | | | |
+ | | o---+ changeset: 26:7f25b6c2f0b9
+ | | | | | parent: 18:1aa84d96232a
+ | | | | | parent: 25:91da8ed57247
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:26 1970 +0000
+ | | | | | summary: (26) merge one known; far right
+ | | | | |
+ +---o | | changeset: 25:91da8ed57247
+ | | | | | parent: 21:d42a756af44d
+ | | | | | parent: 24:a9c19a3d96b7
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:25 1970 +0000
+ | | | | | summary: (25) merge one known; far left
+ | | | | |
+ | | o | | changeset: 24:a9c19a3d96b7
+ | | |\| | parent: 0:e6eb3150255d
+ | | | | | parent: 23:a01cddf0766d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:24 1970 +0000
+ | | | | | summary: (24) merge one known; immediate right
+ | | | | |
+ | | o | | changeset: 23:a01cddf0766d
+ | |/| | | parent: 1:6db2ef61d156
+ | | | | | parent: 22:e0d9cccacb5d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:23 1970 +0000
+ | | | | | summary: (23) merge one known; immediate left
+ | | | | |
+ +---o---+ changeset: 22:e0d9cccacb5d
+ | | | | parent: 18:1aa84d96232a
+ | | / / parent: 21:d42a756af44d
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:22 1970 +0000
+ | | | | summary: (22) merge two known; one far left, one far right
+ | | | |
+ o | | | changeset: 21:d42a756af44d
+ |\ \ \ \ parent: 19:31ddc2c1573b
+ | | | | | parent: 20:d30ed6450e32
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:21 1970 +0000
+ | | | | | summary: (21) expand
+ | | | | |
+ | o---+-+ changeset: 20:d30ed6450e32
+ | | | | parent: 0:e6eb3150255d
+ | / / / parent: 18:1aa84d96232a
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:20 1970 +0000
+ | | | | summary: (20) merge two known; two far right
+ | | | |
+ o | | | changeset: 19:31ddc2c1573b
+ |\ \ \ \ parent: 15:1dda3f72782d
+ | | | | | parent: 17:44765d7c06e0
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:19 1970 +0000
+ | | | | | summary: (19) expand
+ | | | | |
+ +---+---o changeset: 18:1aa84d96232a
+ | | | | parent: 1:6db2ef61d156
+ | | | | parent: 15:1dda3f72782d
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:18 1970 +0000
+ | | | | summary: (18) merge two known; two far left
+ | | | |
+ | o | | changeset: 17:44765d7c06e0
+ | |\ \ \ parent: 12:86b91144a6e9
+ | | | | | parent: 16:3677d192927d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:17 1970 +0000
+ | | | | | summary: (17) expand
+ | | | | |
+ | | o---+ changeset: 16:3677d192927d
+ | | | | | parent: 0:e6eb3150255d
+ | | |/ / parent: 1:6db2ef61d156
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:16 1970 +0000
+ | | | | summary: (16) merge two known; one immediate right, one near right
+ | | | |
+ o | | | changeset: 15:1dda3f72782d
+ |\ \ \ \ parent: 13:22d8966a97e3
+ | | | | | parent: 14:8eac370358ef
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:15 1970 +0000
+ | | | | | summary: (15) expand
+ | | | | |
+ | o-----+ changeset: 14:8eac370358ef
+ | | | | | parent: 0:e6eb3150255d
+ | |/ / / parent: 12:86b91144a6e9
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:14 1970 +0000
+ | | | | summary: (14) merge two known; one immediate right, one far right
+ | | | |
+ o | | | changeset: 13:22d8966a97e3
+ |\ \ \ \ parent: 9:7010c0af0a35
+ | | | | | parent: 11:832d76e6bdf2
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:13 1970 +0000
+ | | | | | summary: (13) expand
+ | | | | |
+ +---o | | changeset: 12:86b91144a6e9
+ | | |/ / parent: 1:6db2ef61d156
+ | | | | parent: 9:7010c0af0a35
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:12 1970 +0000
+ | | | | summary: (12) merge two known; one immediate right, one far left
+ | | | |
+ | o | | changeset: 11:832d76e6bdf2
+ | |\ \ \ parent: 6:b105a072e251
+ | | | | | parent: 10:74c64d036d72
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:11 1970 +0000
+ | | | | | summary: (11) expand
+ | | | | |
+ | | o---+ changeset: 10:74c64d036d72
+ | | | | | parent: 0:e6eb3150255d
+ | |/ / / parent: 6:b105a072e251
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:10 1970 +0000
+ | | | | summary: (10) merge two known; one immediate left, one near right
+ | | | |
+ o | | | changeset: 9:7010c0af0a35
+ |\ \ \ \ parent: 7:b632bb1b1224
+ | | | | | parent: 8:7a0b11f71937
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:09 1970 +0000
+ | | | | | summary: (9) expand
+ | | | | |
+ | o-----+ changeset: 8:7a0b11f71937
+ | | | | | parent: 0:e6eb3150255d
+ |/ / / / parent: 7:b632bb1b1224
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:08 1970 +0000
+ | | | | summary: (8) merge two known; one immediate left, one far right
+ | | | |
+ o | | | changeset: 7:b632bb1b1224
+ |\ \ \ \ parent: 2:3d9a33b8d1e1
+ | | | | | parent: 5:4409d547b708
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:07 1970 +0000
+ | | | | | summary: (7) expand
+ | | | | |
+ +---o | | changeset: 6:b105a072e251
+ | |/ / / parent: 2:3d9a33b8d1e1
+ | | | | parent: 5:4409d547b708
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:06 1970 +0000
+ | | | | summary: (6) merge two known; one immediate left, one far left
+ | | | |
+ | o | | changeset: 5:4409d547b708
+ | |\ \ \ parent: 3:27eef8ed80b4
+ | | | | | parent: 4:26a8bac39d9f
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:05 1970 +0000
+ | | | | | summary: (5) expand
+ | | | | |
+ | | o | | changeset: 4:26a8bac39d9f
+ | |/|/ / parent: 1:6db2ef61d156
+ | | | | parent: 3:27eef8ed80b4
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:04 1970 +0000
+ | | | | summary: (4) merge two known; one immediate left, one immediate right
+ | | | |
+ | o | | changeset: 3:27eef8ed80b4
+ |/ / / user: test
+ | | | date: Thu Jan 01 00:00:03 1970 +0000
+ | | | summary: (3) collapse
+ | | |
+ o | | changeset: 2:3d9a33b8d1e1
+ |/ / user: test
+ | | date: Thu Jan 01 00:00:02 1970 +0000
+ | | summary: (2) collapse
+ | |
+ o | changeset: 1:6db2ef61d156
+ |/ user: test
+ | date: Thu Jan 01 00:00:01 1970 +0000
+ | summary: (1) collapse
+ |
+ o changeset: 0:e6eb3150255d
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: (0) root
+
+
+File glog per revset:
+
+ $ hg glog -r 'file("a")'
+ @ changeset: 34:fea3ac5810e0
+ | tag: tip
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+ | o changeset: 33:68608f5145f9
+ | | parent: 18:1aa84d96232a
+ | | user: test
+ | | date: Thu Jan 01 00:00:33 1970 +0000
+ | | summary: (33) head
+ | |
+ o | changeset: 32:d06dffa21a31
+ |\ \ parent: 27:886ed638191b
+ | | | parent: 31:621d83e11f67
+ | | | user: test
+ | | | date: Thu Jan 01 00:00:32 1970 +0000
+ | | | summary: (32) expand
+ | | |
+ | o | changeset: 31:621d83e11f67
+ | |\ \ parent: 21:d42a756af44d
+ | | | | parent: 30:6e11cd4b648f
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:31 1970 +0000
+ | | | | summary: (31) expand
+ | | | |
+ | | o | changeset: 30:6e11cd4b648f
+ | | |\ \ parent: 28:44ecd0b9ae99
+ | | | | | parent: 29:cd9bb2be7593
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:30 1970 +0000
+ | | | | | summary: (30) expand
+ | | | | |
+ | | | o | changeset: 29:cd9bb2be7593
+ | | | | | parent: 0:e6eb3150255d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:29 1970 +0000
+ | | | | | summary: (29) regular commit
+ | | | | |
+ | | o | | changeset: 28:44ecd0b9ae99
+ | | |\ \ \ parent: 1:6db2ef61d156
+ | | | | | | parent: 26:7f25b6c2f0b9
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
+ | | | | | | summary: (28) merge zero known
+ | | | | | |
+ o | | | | | changeset: 27:886ed638191b
+ |/ / / / / parent: 21:d42a756af44d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:27 1970 +0000
+ | | | | | summary: (27) collapse
+ | | | | |
+ | | o---+ changeset: 26:7f25b6c2f0b9
+ | | | | | parent: 18:1aa84d96232a
+ | | | | | parent: 25:91da8ed57247
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:26 1970 +0000
+ | | | | | summary: (26) merge one known; far right
+ | | | | |
+ +---o | | changeset: 25:91da8ed57247
+ | | | | | parent: 21:d42a756af44d
+ | | | | | parent: 24:a9c19a3d96b7
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:25 1970 +0000
+ | | | | | summary: (25) merge one known; far left
+ | | | | |
+ | | o | | changeset: 24:a9c19a3d96b7
+ | | |\| | parent: 0:e6eb3150255d
+ | | | | | parent: 23:a01cddf0766d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:24 1970 +0000
+ | | | | | summary: (24) merge one known; immediate right
+ | | | | |
+ | | o | | changeset: 23:a01cddf0766d
+ | |/| | | parent: 1:6db2ef61d156
+ | | | | | parent: 22:e0d9cccacb5d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:23 1970 +0000
+ | | | | | summary: (23) merge one known; immediate left
+ | | | | |
+ +---o---+ changeset: 22:e0d9cccacb5d
+ | | | | parent: 18:1aa84d96232a
+ | | / / parent: 21:d42a756af44d
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:22 1970 +0000
+ | | | | summary: (22) merge two known; one far left, one far right
+ | | | |
+ o | | | changeset: 21:d42a756af44d
+ |\ \ \ \ parent: 19:31ddc2c1573b
+ | | | | | parent: 20:d30ed6450e32
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:21 1970 +0000
+ | | | | | summary: (21) expand
+ | | | | |
+ | o---+-+ changeset: 20:d30ed6450e32
+ | | | | parent: 0:e6eb3150255d
+ | / / / parent: 18:1aa84d96232a
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:20 1970 +0000
+ | | | | summary: (20) merge two known; two far right
+ | | | |
+ o | | | changeset: 19:31ddc2c1573b
+ |\ \ \ \ parent: 15:1dda3f72782d
+ | | | | | parent: 17:44765d7c06e0
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:19 1970 +0000
+ | | | | | summary: (19) expand
+ | | | | |
+ +---+---o changeset: 18:1aa84d96232a
+ | | | | parent: 1:6db2ef61d156
+ | | | | parent: 15:1dda3f72782d
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:18 1970 +0000
+ | | | | summary: (18) merge two known; two far left
+ | | | |
+ | o | | changeset: 17:44765d7c06e0
+ | |\ \ \ parent: 12:86b91144a6e9
+ | | | | | parent: 16:3677d192927d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:17 1970 +0000
+ | | | | | summary: (17) expand
+ | | | | |
+ | | o---+ changeset: 16:3677d192927d
+ | | | | | parent: 0:e6eb3150255d
+ | | |/ / parent: 1:6db2ef61d156
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:16 1970 +0000
+ | | | | summary: (16) merge two known; one immediate right, one near right
+ | | | |
+ o | | | changeset: 15:1dda3f72782d
+ |\ \ \ \ parent: 13:22d8966a97e3
+ | | | | | parent: 14:8eac370358ef
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:15 1970 +0000
+ | | | | | summary: (15) expand
+ | | | | |
+ | o-----+ changeset: 14:8eac370358ef
+ | | | | | parent: 0:e6eb3150255d
+ | |/ / / parent: 12:86b91144a6e9
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:14 1970 +0000
+ | | | | summary: (14) merge two known; one immediate right, one far right
+ | | | |
+ o | | | changeset: 13:22d8966a97e3
+ |\ \ \ \ parent: 9:7010c0af0a35
+ | | | | | parent: 11:832d76e6bdf2
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:13 1970 +0000
+ | | | | | summary: (13) expand
+ | | | | |
+ +---o | | changeset: 12:86b91144a6e9
+ | | |/ / parent: 1:6db2ef61d156
+ | | | | parent: 9:7010c0af0a35
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:12 1970 +0000
+ | | | | summary: (12) merge two known; one immediate right, one far left
+ | | | |
+ | o | | changeset: 11:832d76e6bdf2
+ | |\ \ \ parent: 6:b105a072e251
+ | | | | | parent: 10:74c64d036d72
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:11 1970 +0000
+ | | | | | summary: (11) expand
+ | | | | |
+ | | o---+ changeset: 10:74c64d036d72
+ | | | | | parent: 0:e6eb3150255d
+ | |/ / / parent: 6:b105a072e251
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:10 1970 +0000
+ | | | | summary: (10) merge two known; one immediate left, one near right
+ | | | |
+ o | | | changeset: 9:7010c0af0a35
+ |\ \ \ \ parent: 7:b632bb1b1224
+ | | | | | parent: 8:7a0b11f71937
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:09 1970 +0000
+ | | | | | summary: (9) expand
+ | | | | |
+ | o-----+ changeset: 8:7a0b11f71937
+ | | | | | parent: 0:e6eb3150255d
+ |/ / / / parent: 7:b632bb1b1224
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:08 1970 +0000
+ | | | | summary: (8) merge two known; one immediate left, one far right
+ | | | |
+ o | | | changeset: 7:b632bb1b1224
+ |\ \ \ \ parent: 2:3d9a33b8d1e1
+ | | | | | parent: 5:4409d547b708
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:07 1970 +0000
+ | | | | | summary: (7) expand
+ | | | | |
+ +---o | | changeset: 6:b105a072e251
+ | |/ / / parent: 2:3d9a33b8d1e1
+ | | | | parent: 5:4409d547b708
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:06 1970 +0000
+ | | | | summary: (6) merge two known; one immediate left, one far left
+ | | | |
+ | o | | changeset: 5:4409d547b708
+ | |\ \ \ parent: 3:27eef8ed80b4
+ | | | | | parent: 4:26a8bac39d9f
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:05 1970 +0000
+ | | | | | summary: (5) expand
+ | | | | |
+ | | o | | changeset: 4:26a8bac39d9f
+ | |/|/ / parent: 1:6db2ef61d156
+ | | | | parent: 3:27eef8ed80b4
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:04 1970 +0000
+ | | | | summary: (4) merge two known; one immediate left, one immediate right
+ | | | |
+ | o | | changeset: 3:27eef8ed80b4
+ |/ / / user: test
+ | | | date: Thu Jan 01 00:00:03 1970 +0000
+ | | | summary: (3) collapse
+ | | |
+ o | | changeset: 2:3d9a33b8d1e1
+ |/ / user: test
+ | | date: Thu Jan 01 00:00:02 1970 +0000
+ | | summary: (2) collapse
+ | |
+ o | changeset: 1:6db2ef61d156
+ |/ user: test
+ | date: Thu Jan 01 00:00:01 1970 +0000
+ | summary: (1) collapse
+ |
+ o changeset: 0:e6eb3150255d
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: (0) root
+
+
+
+File glog per revset (only merges):
+
+ $ hg log -G -r 'file("a")' -m
+ o changeset: 32:d06dffa21a31
+ |\ parent: 27:886ed638191b
+ | | parent: 31:621d83e11f67
+ | | user: test
+ | | date: Thu Jan 01 00:00:32 1970 +0000
+ | | summary: (32) expand
+ | |
+ o | changeset: 31:621d83e11f67
+ |\| parent: 21:d42a756af44d
+ | | parent: 30:6e11cd4b648f
+ | | user: test
+ | | date: Thu Jan 01 00:00:31 1970 +0000
+ | | summary: (31) expand
+ | |
+ o | changeset: 30:6e11cd4b648f
+ |\ \ parent: 28:44ecd0b9ae99
+ | | | parent: 29:cd9bb2be7593
+ | | | user: test
+ | | | date: Thu Jan 01 00:00:30 1970 +0000
+ | | | summary: (30) expand
+ | | |
+ o | | changeset: 28:44ecd0b9ae99
+ |\ \ \ parent: 1:6db2ef61d156
+ | | | | parent: 26:7f25b6c2f0b9
+ | | | | user: test
+ | | | | date: Thu Jan 01 00:00:28 1970 +0000
+ | | | | summary: (28) merge zero known
+ | | | |
+ o | | | changeset: 26:7f25b6c2f0b9
+ |\ \ \ \ parent: 18:1aa84d96232a
+ | | | | | parent: 25:91da8ed57247
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:26 1970 +0000
+ | | | | | summary: (26) merge one known; far right
+ | | | | |
+ | o-----+ changeset: 25:91da8ed57247
+ | | | | | parent: 21:d42a756af44d
+ | | | | | parent: 24:a9c19a3d96b7
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:25 1970 +0000
+ | | | | | summary: (25) merge one known; far left
+ | | | | |
+ | o | | | changeset: 24:a9c19a3d96b7
+ | |\ \ \ \ parent: 0:e6eb3150255d
+ | | | | | | parent: 23:a01cddf0766d
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:24 1970 +0000
+ | | | | | | summary: (24) merge one known; immediate right
+ | | | | | |
+ | o---+ | | changeset: 23:a01cddf0766d
+ | | | | | | parent: 1:6db2ef61d156
+ | | | | | | parent: 22:e0d9cccacb5d
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:23 1970 +0000
+ | | | | | | summary: (23) merge one known; immediate left
+ | | | | | |
+ | o-------+ changeset: 22:e0d9cccacb5d
+ | | | | | | parent: 18:1aa84d96232a
+ |/ / / / / parent: 21:d42a756af44d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:22 1970 +0000
+ | | | | | summary: (22) merge two known; one far left, one far right
+ | | | | |
+ | | | | o changeset: 21:d42a756af44d
+ | | | | |\ parent: 19:31ddc2c1573b
+ | | | | | | parent: 20:d30ed6450e32
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:21 1970 +0000
+ | | | | | | summary: (21) expand
+ | | | | | |
+ +-+-------o changeset: 20:d30ed6450e32
+ | | | | | parent: 0:e6eb3150255d
+ | | | | | parent: 18:1aa84d96232a
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:20 1970 +0000
+ | | | | | summary: (20) merge two known; two far right
+ | | | | |
+ | | | | o changeset: 19:31ddc2c1573b
+ | | | | |\ parent: 15:1dda3f72782d
+ | | | | | | parent: 17:44765d7c06e0
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:19 1970 +0000
+ | | | | | | summary: (19) expand
+ | | | | | |
+ o---+---+ | changeset: 18:1aa84d96232a
+ | | | | | parent: 1:6db2ef61d156
+ / / / / / parent: 15:1dda3f72782d
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:18 1970 +0000
+ | | | | | summary: (18) merge two known; two far left
+ | | | | |
+ | | | | o changeset: 17:44765d7c06e0
+ | | | | |\ parent: 12:86b91144a6e9
+ | | | | | | parent: 16:3677d192927d
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:17 1970 +0000
+ | | | | | | summary: (17) expand
+ | | | | | |
+ +-+-------o changeset: 16:3677d192927d
+ | | | | | parent: 0:e6eb3150255d
+ | | | | | parent: 1:6db2ef61d156
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:16 1970 +0000
+ | | | | | summary: (16) merge two known; one immediate right, one near right
+ | | | | |
+ | | | o | changeset: 15:1dda3f72782d
+ | | | |\ \ parent: 13:22d8966a97e3
+ | | | | | | parent: 14:8eac370358ef
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:15 1970 +0000
+ | | | | | | summary: (15) expand
+ | | | | | |
+ +-------o | changeset: 14:8eac370358ef
+ | | | | |/ parent: 0:e6eb3150255d
+ | | | | | parent: 12:86b91144a6e9
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:14 1970 +0000
+ | | | | | summary: (14) merge two known; one immediate right, one far right
+ | | | | |
+ | | | o | changeset: 13:22d8966a97e3
+ | | | |\ \ parent: 9:7010c0af0a35
+ | | | | | | parent: 11:832d76e6bdf2
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:13 1970 +0000
+ | | | | | | summary: (13) expand
+ | | | | | |
+ | +---+---o changeset: 12:86b91144a6e9
+ | | | | | parent: 1:6db2ef61d156
+ | | | | | parent: 9:7010c0af0a35
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:12 1970 +0000
+ | | | | | summary: (12) merge two known; one immediate right, one far left
+ | | | | |
+ | | | | o changeset: 11:832d76e6bdf2
+ | | | | |\ parent: 6:b105a072e251
+ | | | | | | parent: 10:74c64d036d72
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:11 1970 +0000
+ | | | | | | summary: (11) expand
+ | | | | | |
+ +---------o changeset: 10:74c64d036d72
+ | | | | |/ parent: 0:e6eb3150255d
+ | | | | | parent: 6:b105a072e251
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:10 1970 +0000
+ | | | | | summary: (10) merge two known; one immediate left, one near right
+ | | | | |
+ | | | o | changeset: 9:7010c0af0a35
+ | | | |\ \ parent: 7:b632bb1b1224
+ | | | | | | parent: 8:7a0b11f71937
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:09 1970 +0000
+ | | | | | | summary: (9) expand
+ | | | | | |
+ +-------o | changeset: 8:7a0b11f71937
+ | | | |/ / parent: 0:e6eb3150255d
+ | | | | | parent: 7:b632bb1b1224
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:08 1970 +0000
+ | | | | | summary: (8) merge two known; one immediate left, one far right
+ | | | | |
+ | | | o | changeset: 7:b632bb1b1224
+ | | | |\ \ parent: 2:3d9a33b8d1e1
+ | | | | | | parent: 5:4409d547b708
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:07 1970 +0000
+ | | | | | | summary: (7) expand
+ | | | | | |
+ | | | +---o changeset: 6:b105a072e251
+ | | | | |/ parent: 2:3d9a33b8d1e1
+ | | | | | parent: 5:4409d547b708
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:06 1970 +0000
+ | | | | | summary: (6) merge two known; one immediate left, one far left
+ | | | | |
+ | | | o | changeset: 5:4409d547b708
+ | | | |\ \ parent: 3:27eef8ed80b4
+ | | | | | | parent: 4:26a8bac39d9f
+ | | | | | | user: test
+ | | | | | | date: Thu Jan 01 00:00:05 1970 +0000
+ | | | | | | summary: (5) expand
+ | | | | | |
+ | +---o | | changeset: 4:26a8bac39d9f
+ | | | |/ / parent: 1:6db2ef61d156
+ | | | | | parent: 3:27eef8ed80b4
+ | | | | | user: test
+ | | | | | date: Thu Jan 01 00:00:04 1970 +0000
+ | | | | | summary: (4) merge two known; one immediate left, one immediate right
+ | | | | |
+
+
+Empty revision range - display nothing:
+ $ hg glog -r 1..0
+
+ $ cd ..
+
+#if no-outer-repo
+
+From outer space:
+ $ hg glog -l1 repo
+ @ changeset: 34:fea3ac5810e0
+ | tag: tip
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+ $ hg glog -l1 repo/a
+ @ changeset: 34:fea3ac5810e0
+ | tag: tip
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+ $ hg glog -l1 repo/missing
+
+#endif
+
+File log with revs != cset revs:
+ $ hg init flog
+ $ cd flog
+ $ echo one >one
+ $ hg add one
+ $ hg commit -mone
+ $ echo two >two
+ $ hg add two
+ $ hg commit -mtwo
+ $ echo more >two
+ $ hg commit -mmore
+ $ hg glog two
+ @ changeset: 2:12c28321755b
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: more
+ |
+ o changeset: 1:5ac72c0599bf
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: two
+ |
+
+Issue1896: File log with explicit style
+ $ hg glog --style=default one
+ o changeset: 0:3d578b4a1f53
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: one
+
+Issue2395: glog --style header and footer
+ $ hg glog --style=xml one
+ <?xml version="1.0"?>
+ <log>
+ o <logentry revision="0" node="3d578b4a1f537d5fcf7301bfa9c0b97adfaa6fb1">
+ <author email="test">test</author>
+ <date>1970-01-01T00:00:00+00:00</date>
+ <msg xml:space="preserve">one</msg>
+ </logentry>
+ </log>
+
+ $ cd ..
+
+Incoming and outgoing:
+
+ $ hg clone -U -r31 repo repo2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 31 changesets with 31 changes to 1 files
+ $ cd repo2
+
+ $ hg incoming --graph ../repo
+ comparing with ../repo
+ searching for changes
+ o changeset: 34:fea3ac5810e0
+ | tag: tip
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+ | o changeset: 33:68608f5145f9
+ | parent: 18:1aa84d96232a
+ | user: test
+ | date: Thu Jan 01 00:00:33 1970 +0000
+ | summary: (33) head
+ |
+ o changeset: 32:d06dffa21a31
+ | parent: 27:886ed638191b
+ | parent: 31:621d83e11f67
+ | user: test
+ | date: Thu Jan 01 00:00:32 1970 +0000
+ | summary: (32) expand
+ |
+ o changeset: 27:886ed638191b
+ parent: 21:d42a756af44d
+ user: test
+ date: Thu Jan 01 00:00:27 1970 +0000
+ summary: (27) collapse
+
+ $ cd ..
+
+ $ hg -R repo outgoing --graph repo2
+ comparing with repo2
+ searching for changes
+ @ changeset: 34:fea3ac5810e0
+ | tag: tip
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+ | o changeset: 33:68608f5145f9
+ | parent: 18:1aa84d96232a
+ | user: test
+ | date: Thu Jan 01 00:00:33 1970 +0000
+ | summary: (33) head
+ |
+ o changeset: 32:d06dffa21a31
+ | parent: 27:886ed638191b
+ | parent: 31:621d83e11f67
+ | user: test
+ | date: Thu Jan 01 00:00:32 1970 +0000
+ | summary: (32) expand
+ |
+ o changeset: 27:886ed638191b
+ parent: 21:d42a756af44d
+ user: test
+ date: Thu Jan 01 00:00:27 1970 +0000
+ summary: (27) collapse
+
+
+File + limit with revs != cset revs:
+ $ cd repo
+ $ touch b
+ $ hg ci -Aqm0
+ $ hg glog -l2 a
+ o changeset: 34:fea3ac5810e0
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+ | o changeset: 33:68608f5145f9
+ | | parent: 18:1aa84d96232a
+ | | user: test
+ | | date: Thu Jan 01 00:00:33 1970 +0000
+ | | summary: (33) head
+ | |
+
+File + limit + -ra:b, (b - a) < limit:
+ $ hg glog -l3000 -r32:tip a
+ o changeset: 34:fea3ac5810e0
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+ | o changeset: 33:68608f5145f9
+ | | parent: 18:1aa84d96232a
+ | | user: test
+ | | date: Thu Jan 01 00:00:33 1970 +0000
+ | | summary: (33) head
+ | |
+ o | changeset: 32:d06dffa21a31
+ |\ \ parent: 27:886ed638191b
+ | | | parent: 31:621d83e11f67
+ | | | user: test
+ | | | date: Thu Jan 01 00:00:32 1970 +0000
+ | | | summary: (32) expand
+ | | |
+
+Point out a common and an uncommon unshown parent
+
+ $ hg glog -r 'rev(8) or rev(9)'
+ o changeset: 9:7010c0af0a35
+ |\ parent: 7:b632bb1b1224
+ | | parent: 8:7a0b11f71937
+ | | user: test
+ | | date: Thu Jan 01 00:00:09 1970 +0000
+ | | summary: (9) expand
+ | |
+ o | changeset: 8:7a0b11f71937
+ |\| parent: 0:e6eb3150255d
+ | | parent: 7:b632bb1b1224
+ | | user: test
+ | | date: Thu Jan 01 00:00:08 1970 +0000
+ | | summary: (8) merge two known; one immediate left, one far right
+ | |
+
+File + limit + -ra:b, b < tip:
+
+ $ hg glog -l1 -r32:34 a
+ o changeset: 34:fea3ac5810e0
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+
+file(File) + limit + -ra:b, b < tip:
+
+ $ hg glog -l1 -r32:34 -r 'file("a")'
+ o changeset: 34:fea3ac5810e0
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+
+limit(file(File) and a::b), b < tip:
+
+ $ hg glog -r 'limit(file("a") and 32::34, 1)'
+ o changeset: 32:d06dffa21a31
+ |\ parent: 27:886ed638191b
+ | | parent: 31:621d83e11f67
+ | | user: test
+ | | date: Thu Jan 01 00:00:32 1970 +0000
+ | | summary: (32) expand
+ | |
+
+File + limit + -ra:b, b < tip:
+
+ $ hg glog -r 'limit(file("a") and 34::32, 1)'
+
+File + limit + -ra:b, b < tip, (b - a) < limit:
+
+ $ hg glog -l10 -r33:34 a
+ o changeset: 34:fea3ac5810e0
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+ | o changeset: 33:68608f5145f9
+ | | parent: 18:1aa84d96232a
+ | | user: test
+ | | date: Thu Jan 01 00:00:33 1970 +0000
+ | | summary: (33) head
+ | |
+
+Do not crash or produce strange graphs if history is buggy
+
+ $ hg branch branch
+ marked working directory as branch branch
+ (branches are permanent and global, did you want a bookmark?)
+ $ commit 36 "buggy merge: identical parents" 35 35
+ $ hg glog -l5
+ @ changeset: 36:08a19a744424
+ | branch: branch
+ | tag: tip
+ | parent: 35:9159c3644c5e
+ | parent: 35:9159c3644c5e
+ | user: test
+ | date: Thu Jan 01 00:00:36 1970 +0000
+ | summary: (36) buggy merge: identical parents
+ |
+ o changeset: 35:9159c3644c5e
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: 0
+ |
+ o changeset: 34:fea3ac5810e0
+ | parent: 32:d06dffa21a31
+ | user: test
+ | date: Thu Jan 01 00:00:34 1970 +0000
+ | summary: (34) head
+ |
+ | o changeset: 33:68608f5145f9
+ | | parent: 18:1aa84d96232a
+ | | user: test
+ | | date: Thu Jan 01 00:00:33 1970 +0000
+ | | summary: (33) head
+ | |
+ o | changeset: 32:d06dffa21a31
+ |\ \ parent: 27:886ed638191b
+ | | | parent: 31:621d83e11f67
+ | | | user: test
+ | | | date: Thu Jan 01 00:00:32 1970 +0000
+ | | | summary: (32) expand
+ | | |
+
+Test log -G options
+
+ $ testlog() {
+ > hg log -G --print-revset "$@"
+ > hg log --template 'nodetag {rev}\n' "$@" | grep nodetag \
+ > | sed 's/.*nodetag/nodetag/' > log.nodes
+ > hg log -G --template 'nodetag {rev}\n' "$@" | grep nodetag \
+ > | sed 's/.*nodetag/nodetag/' > glog.nodes
+ > diff -u log.nodes glog.nodes | grep '^[-+@ ]' || :
+ > }
+
+glog always reorders nodes which explains the difference with log
+
+ $ testlog -r 27 -r 25 -r 21 -r 34 -r 32 -r 31
+ ['27', '25', '21', '34', '32', '31']
+ []
+ --- log.nodes * (glob)
+ +++ glog.nodes * (glob)
+ @@ -1,6 +1,6 @@
+ -nodetag 27
+ -nodetag 25
+ -nodetag 21
+ nodetag 34
+ nodetag 32
+ nodetag 31
+ +nodetag 27
+ +nodetag 25
+ +nodetag 21
+ $ testlog -u test -u not-a-user
+ []
+ (group
+ (group
+ (or
+ (func
+ ('symbol', 'user')
+ ('string', 'test'))
+ (func
+ ('symbol', 'user')
+ ('string', 'not-a-user')))))
+ $ testlog -b not-a-branch
+ abort: unknown revision 'not-a-branch'!
+ abort: unknown revision 'not-a-branch'!
+ abort: unknown revision 'not-a-branch'!
+ $ testlog -b 35 -b 36 --only-branch branch
+ []
+ (group
+ (group
+ (or
+ (or
+ (func
+ ('symbol', 'branch')
+ ('string', 'default'))
+ (func
+ ('symbol', 'branch')
+ ('string', 'branch')))
+ (func
+ ('symbol', 'branch')
+ ('string', 'branch')))))
+ $ testlog -k expand -k merge
+ []
+ (group
+ (group
+ (or
+ (func
+ ('symbol', 'keyword')
+ ('string', 'expand'))
+ (func
+ ('symbol', 'keyword')
+ ('string', 'merge')))))
+ $ testlog --only-merges
+ []
+ (group
+ (func
+ ('symbol', 'merge')
+ None))
+ $ testlog --no-merges
+ []
+ (group
+ (not
+ (func
+ ('symbol', 'merge')
+ None)))
+ $ testlog --date '2 0 to 4 0'
+ []
+ (group
+ (func
+ ('symbol', 'date')
+ ('string', '2 0 to 4 0')))
+ $ hg log -G -d 'brace ) in a date'
+ abort: invalid date: 'brace ) in a date'
+ [255]
+ $ testlog --prune 31 --prune 32
+ []
+ (group
+ (group
+ (and
+ (not
+ (group
+ (or
+ ('string', '31')
+ (func
+ ('symbol', 'ancestors')
+ ('string', '31')))))
+ (not
+ (group
+ (or
+ ('string', '32')
+ (func
+ ('symbol', 'ancestors')
+ ('string', '32'))))))))
+
+Dedicated repo for --follow and paths filtering. The g is crafted to
+have 2 filelog topological heads in a linear changeset graph.
+
+ $ cd ..
+ $ hg init follow
+ $ cd follow
+ $ testlog --follow
+ []
+ []
+ $ echo a > a
+ $ echo aa > aa
+ $ echo f > f
+ $ hg ci -Am "add a" a aa f
+ $ hg cp a b
+ $ hg cp f g
+ $ hg ci -m "copy a b"
+ $ mkdir dir
+ $ hg mv b dir
+ $ echo g >> g
+ $ echo f >> f
+ $ hg ci -m "mv b dir/b"
+ $ hg mv a b
+ $ hg cp -f f g
+ $ echo a > d
+ $ hg add d
+ $ hg ci -m "mv a b; add d"
+ $ hg mv dir/b e
+ $ hg ci -m "mv dir/b e"
+ $ hg glog --template '({rev}) {desc|firstline}\n'
+ @ (4) mv dir/b e
+ |
+ o (3) mv a b; add d
+ |
+ o (2) mv b dir/b
+ |
+ o (1) copy a b
+ |
+ o (0) add a
+
+
+ $ testlog a
+ []
+ (group
+ (group
+ (func
+ ('symbol', 'filelog')
+ ('string', 'a'))))
+ $ testlog a b
+ []
+ (group
+ (group
+ (or
+ (func
+ ('symbol', 'filelog')
+ ('string', 'a'))
+ (func
+ ('symbol', 'filelog')
+ ('string', 'b')))))
+
+Test falling back to slow path for non-existing files
+
+ $ testlog a c
+ []
+ (group
+ (func
+ ('symbol', '_matchfiles')
+ (list
+ (list
+ (list
+ ('string', 'r:')
+ ('string', 'd:relpath'))
+ ('string', 'p:a'))
+ ('string', 'p:c'))))
+
+Test multiple --include/--exclude/paths
+
+ $ testlog --include a --include e --exclude b --exclude e a e
+ []
+ (group
+ (func
+ ('symbol', '_matchfiles')
+ (list
+ (list
+ (list
+ (list
+ (list
+ (list
+ (list
+ ('string', 'r:')
+ ('string', 'd:relpath'))
+ ('string', 'p:a'))
+ ('string', 'p:e'))
+ ('string', 'i:a'))
+ ('string', 'i:e'))
+ ('string', 'x:b'))
+ ('string', 'x:e'))))
+
+Test glob expansion of pats
+
+ $ expandglobs=`python -c "import mercurial.util; \
+ > print mercurial.util.expandglobs and 'true' or 'false'"`
+ $ if [ $expandglobs = "true" ]; then
+ > testlog 'a*';
+ > else
+ > testlog a*;
+ > fi;
+ []
+ (group
+ (group
+ (func
+ ('symbol', 'filelog')
+ ('string', 'aa'))))
+
+Test --follow on a directory
+
+ $ testlog -f dir
+ abort: cannot follow file not in parent revision: "dir"
+ abort: cannot follow file not in parent revision: "dir"
+ abort: cannot follow file not in parent revision: "dir"
+
+Test --follow on file not in parent revision
+
+ $ testlog -f a
+ abort: cannot follow file not in parent revision: "a"
+ abort: cannot follow file not in parent revision: "a"
+ abort: cannot follow file not in parent revision: "a"
+
+Test --follow and patterns
+
+ $ testlog -f 'glob:*'
+ abort: can only follow copies/renames for explicit filenames
+ abort: can only follow copies/renames for explicit filenames
+ abort: can only follow copies/renames for explicit filenames
+
+Test --follow on a single rename
+
+ $ hg up -q 2
+ $ testlog -f a
+ []
+ (group
+ (group
+ (func
+ ('symbol', 'follow')
+ ('string', 'a'))))
+
+Test --follow and multiple renames
+
+ $ hg up -q tip
+ $ testlog -f e
+ []
+ (group
+ (group
+ (func
+ ('symbol', 'follow')
+ ('string', 'e'))))
+
+Test --follow and multiple filelog heads
+
+ $ hg up -q 2
+ $ testlog -f g
+ []
+ (group
+ (group
+ (func
+ ('symbol', 'follow')
+ ('string', 'g'))))
+ $ cat log.nodes
+ nodetag 2
+ nodetag 1
+ nodetag 0
+ $ hg up -q tip
+ $ testlog -f g
+ []
+ (group
+ (group
+ (func
+ ('symbol', 'follow')
+ ('string', 'g'))))
+ $ cat log.nodes
+ nodetag 3
+ nodetag 2
+ nodetag 0
+
+Test --follow and multiple files
+
+ $ testlog -f g e
+ []
+ (group
+ (group
+ (or
+ (func
+ ('symbol', 'follow')
+ ('string', 'g'))
+ (func
+ ('symbol', 'follow')
+ ('string', 'e')))))
+ $ cat log.nodes
+ nodetag 4
+ nodetag 3
+ nodetag 2
+ nodetag 1
+ nodetag 0
+
+Test --follow-first
+
+ $ hg up -q 3
+ $ echo ee > e
+ $ hg ci -Am "add another e" e
+ created new head
+ $ hg merge --tool internal:other 4
+ 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ echo merge > e
+ $ hg ci -m "merge 5 and 4"
+ $ testlog --follow-first
+ []
+ (group
+ (func
+ ('symbol', '_firstancestors')
+ ('symbol', '6')))
+
+Cannot compare with log --follow-first FILE as it never worked
+
+ $ hg log -G --print-revset --follow-first e
+ []
+ (group
+ (group
+ (func
+ ('symbol', '_followfirst')
+ ('string', 'e'))))
+ $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
+ @ 6 merge 5 and 4
+ |\
+ o | 5 add another e
+ | |
+
+Test --copies
+
+ $ hg log -G --copies --template "{rev} {desc|firstline} \
+ > copies: {file_copies_switch}\n"
+ @ 6 merge 5 and 4 copies:
+ |\
+ | o 5 add another e copies:
+ | |
+ o | 4 mv dir/b e copies: e (dir/b)
+ |/
+ o 3 mv a b; add d copies: b (a)g (f)
+ |
+ o 2 mv b dir/b copies: dir/b (b)
+ |
+ o 1 copy a b copies: b (a)g (f)
+ |
+ o 0 add a copies:
+
+Test "set:..." and parent revision
+
+ $ hg up -q 4
+ $ testlog "set:copied()"
+ []
+ (group
+ (func
+ ('symbol', '_matchfiles')
+ (list
+ (list
+ ('string', 'r:')
+ ('string', 'd:relpath'))
+ ('string', 'p:set:copied()'))))
+ $ testlog --include "set:copied()"
+ []
+ (group
+ (func
+ ('symbol', '_matchfiles')
+ (list
+ (list
+ ('string', 'r:')
+ ('string', 'd:relpath'))
+ ('string', 'i:set:copied()'))))
+ $ testlog -r "sort(file('set:copied()'), -rev)"
+ ["sort(file('set:copied()'), -rev)"]
+ []
+
+Test --removed
+
+ $ testlog --removed
+ []
+ []
+ $ testlog --removed a
+ []
+ (group
+ (func
+ ('symbol', '_matchfiles')
+ (list
+ (list
+ ('string', 'r:')
+ ('string', 'd:relpath'))
+ ('string', 'p:a'))))
+ $ testlog --removed --follow a
+ abort: can only follow copies/renames for explicit filenames
+ abort: can only follow copies/renames for explicit filenames
+ abort: can only follow copies/renames for explicit filenames
+
+Test --patch and --stat with --follow and --follow-first
+
+ $ hg up -q 3
+ $ hg log -G --git --patch b
+ o changeset: 1:216d4c92cf98
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: copy a b
+ |
+ | diff --git a/a b/b
+ | copy from a
+ | copy to b
+ |
+
+ $ hg log -G --git --stat b
+ o changeset: 1:216d4c92cf98
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: copy a b
+ |
+ | a | 0
+ | 1 files changed, 0 insertions(+), 0 deletions(-)
+ |
+
+ $ hg log -G --git --patch --follow b
+ o changeset: 1:216d4c92cf98
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: copy a b
+ |
+ | diff --git a/a b/b
+ | copy from a
+ | copy to b
+ |
+ o changeset: 0:f8035bb17114
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+ diff --git a/a b/a
+ new file mode 100644
+ --- /dev/null
+ +++ b/a
+ @@ -0,0 +1,1 @@
+ +a
+
+
+ $ hg log -G --git --stat --follow b
+ o changeset: 1:216d4c92cf98
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: copy a b
+ |
+ | a | 0
+ | 1 files changed, 0 insertions(+), 0 deletions(-)
+ |
+ o changeset: 0:f8035bb17114
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+ a | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+
+ $ hg up -q 6
+ $ hg log -G --git --patch --follow-first e
+ @ changeset: 6:fc281d8ff18d
+ |\ tag: tip
+ | | parent: 5:99b31f1c2782
+ | | parent: 4:17d952250a9d
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: merge 5 and 4
+ | |
+ | | diff --git a/e b/e
+ | | --- a/e
+ | | +++ b/e
+ | | @@ -1,1 +1,1 @@
+ | | -ee
+ | | +merge
+ | |
+ o | changeset: 5:99b31f1c2782
+ | | parent: 3:5918b8d165d1
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: add another e
+ | |
+ | | diff --git a/e b/e
+ | | new file mode 100644
+ | | --- /dev/null
+ | | +++ b/e
+ | | @@ -0,0 +1,1 @@
+ | | +ee
+ | |
+
+Test old-style --rev
+
+ $ hg tag 'foo-bar'
+ $ testlog -r 'foo-bar'
+ ['foo-bar']
+ []
+
+Test --follow and forward --rev
+
+ $ hg up -q 6
+ $ echo g > g
+ $ hg ci -Am 'add g' g
+ created new head
+ $ hg up -q 2
+ $ hg log -G --template "{rev} {desc|firstline}\n"
+ o 8 add g
+ |
+ | o 7 Added tag foo-bar for changeset fc281d8ff18d
+ |/
+ o 6 merge 5 and 4
+ |\
+ | o 5 add another e
+ | |
+ o | 4 mv dir/b e
+ |/
+ o 3 mv a b; add d
+ |
+ @ 2 mv b dir/b
+ |
+ o 1 copy a b
+ |
+ o 0 add a
+
+ $ testlog --follow -r6 -r8 -r5 -r7 -r4
+ ['6', '8', '5', '7', '4']
+ (group
+ (func
+ ('symbol', 'descendants')
+ ('symbol', '6')))
+ --- log.nodes * (glob)
+ +++ glog.nodes * (glob)
+ @@ -1,3 +1,3 @@
+ -nodetag 6
+ nodetag 8
+ nodetag 7
+ +nodetag 6
+
+Test --follow-first and forward --rev
+
+ $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
+ ['6', '8', '5', '7', '4']
+ (group
+ (func
+ ('symbol', '_firstdescendants')
+ ('symbol', '6')))
+ --- log.nodes * (glob)
+ +++ glog.nodes * (glob)
+ @@ -1,3 +1,3 @@
+ -nodetag 6
+ nodetag 8
+ nodetag 7
+ +nodetag 6
+
+Test --follow and backward --rev
+
+ $ testlog --follow -r6 -r5 -r7 -r8 -r4
+ ['6', '5', '7', '8', '4']
+ (group
+ (func
+ ('symbol', 'ancestors')
+ ('symbol', '6')))
+
+Test --follow-first and backward --rev
+
+ $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
+ ['6', '5', '7', '8', '4']
+ (group
+ (func
+ ('symbol', '_firstancestors')
+ ('symbol', '6')))
+
+Test subdir
+
+ $ hg up -q 3
+ $ cd dir
+ $ testlog .
+ []
+ (group
+ (func
+ ('symbol', '_matchfiles')
+ (list
+ (list
+ ('string', 'r:')
+ ('string', 'd:relpath'))
+ ('string', 'p:.'))))
+ $ testlog ../b
+ []
+ (group
+ (group
+ (func
+ ('symbol', 'filelog')
+ ('string', '../b'))))
+ $ testlog -f ../b
+ []
+ (group
+ (group
+ (func
+ ('symbol', 'follow')
+ ('string', 'b'))))
+ $ cd ..
+
+Test --hidden
+
+ $ cat > $HGTMP/testhidden.py << EOF
+ > def reposetup(ui, repo):
+ > for line in repo.opener('hidden'):
+ > ctx = repo[line.strip()]
+ > repo.hiddenrevs.add(ctx.rev())
+ > EOF
+ $ echo '[extensions]' >> .hg/hgrc
+ $ echo "hidden=$HGTMP/testhidden.py" >> .hg/hgrc
+ $ hg id --debug -i -r 0 > .hg/hidden
+ $ testlog
+ []
+ []
+ $ testlog --hidden
+ []
+ []
+
+A template without trailing newline should do something sane
+
+ $ hg glog -r ::2 --template '{rev} {desc}'
+ o 2 mv b dir/b
+ |
+ o 1 copy a b
+ |
+
+Extra newlines must be preserved
+
+ $ hg glog -r ::2 --template '\n{rev} {desc}\n\n'
+ o
+ | 2 mv b dir/b
+ |
+ o
+ | 1 copy a b
+ |
+
+The almost-empty template should do something sane too ...
+
+ $ hg glog -r ::2 --template '\n'
+ o
+ |
+ o
+ |
+
+ $ cd ..
diff --git a/tests/test-gpg.t b/tests/test-gpg.t
new file mode 100644
index 0000000..5ec6fa0
--- /dev/null
+++ b/tests/test-gpg.t
@@ -0,0 +1,34 @@
+Test the GPG extension
+
+ $ "$TESTDIR/hghave" gpg || exit 80
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > gpg=
+ >
+ > [gpg]
+ > cmd=gpg --no-permission-warning --no-secmem-warning --no-auto-check-trustdb --homedir "$TESTDIR/gpg"
+ > EOF
+ $ hg init r
+ $ cd r
+ $ echo foo > foo
+ $ hg ci -Amfoo
+ adding foo
+
+ $ hg sigs
+
+ $ hg sign 0
+ signing 0:e63c23eaa88a
+
+ $ hg sigs
+ hgtest 0:e63c23eaa88ae77967edcf4ea194d31167c478b0
+
+ $ hg sigcheck 0
+ e63c23eaa88a is signed by:
+ hgtest
+
+verify that this test has not modified the trustdb.gpg file back in
+the main hg working dir
+ $ "$TESTDIR/md5sum.py" "$TESTDIR/gpg/trustdb.gpg"
+ f6b9c78c65fa9536e7512bb2ceb338ae */gpg/trustdb.gpg (glob)
+
+ $ cd ..
diff --git a/tests/test-graft.t b/tests/test-graft.t
new file mode 100644
index 0000000..6ec5aec
--- /dev/null
+++ b/tests/test-graft.t
@@ -0,0 +1,535 @@
+Create a repo with some stuff in it:
+
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ echo a > d
+ $ echo a > e
+ $ hg ci -qAm0
+ $ echo b > a
+ $ hg ci -m1 -u bar
+ $ hg mv a b
+ $ hg ci -m2
+ $ hg cp b c
+ $ hg ci -m3 -u baz
+ $ echo b > d
+ $ echo f > e
+ $ hg ci -m4
+ $ hg up -q 3
+ $ echo b > e
+ $ hg branch -q stable
+ $ hg ci -m5
+ $ hg merge -q default --tool internal:local
+ $ hg branch -q default
+ $ hg ci -m6
+ $ hg phase --public 3
+ $ hg phase --force --secret 6
+
+ $ hg --config extensions.graphlog= log -G --template '{author}@{rev}.{phase}: {desc}\n'
+ @ test@6.secret: 6
+ |\
+ | o test@5.draft: 5
+ | |
+ o | test@4.draft: 4
+ |/
+ o baz@3.public: 3
+ |
+ o test@2.public: 2
+ |
+ o bar@1.public: 1
+ |
+ o test@0.public: 0
+
+
+Need to specify a rev:
+
+ $ hg graft
+ abort: no revisions specified
+ [255]
+
+Can't graft ancestor:
+
+ $ hg graft 1 2
+ skipping ancestor revision 1
+ skipping ancestor revision 2
+ [255]
+
+Specify revisions with -r:
+
+ $ hg graft -r 1 -r 2
+ skipping ancestor revision 1
+ skipping ancestor revision 2
+ [255]
+
+ $ hg graft -r 1 2
+ skipping ancestor revision 2
+ skipping ancestor revision 1
+ [255]
+
+Can't graft with dirty wd:
+
+ $ hg up -q 0
+ $ echo foo > a
+ $ hg graft 1
+ abort: outstanding uncommitted changes
+ [255]
+ $ hg revert a
+
+Graft a rename:
+
+ $ hg graft 2 -u foo
+ grafting revision 2
+ merging a and b to b
+ $ hg export tip --git
+ # HG changeset patch
+ # User foo
+ # Date 0 0
+ # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
+ # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
+ 2
+
+ diff --git a/a b/b
+ rename from a
+ rename to b
+
+Look for extra:source
+
+ $ hg log --debug -r tip
+ changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
+ tag: tip
+ phase: draft
+ parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files+: b
+ files-: a
+ extra: branch=default
+ extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
+ description:
+ 2
+
+
+
+Graft out of order, skipping a merge and a duplicate
+
+ $ hg graft 1 5 4 3 'merge()' 2 -n
+ skipping ungraftable merge revision 6
+ skipping already grafted revision 2
+ grafting revision 1
+ grafting revision 5
+ grafting revision 4
+ grafting revision 3
+
+ $ hg graft 1 5 4 3 'merge()' 2 --debug
+ skipping ungraftable merge revision 6
+ scanning for duplicate grafts
+ skipping already grafted revision 2
+ grafting revision 1
+ searching for copies back to rev 1
+ unmatched files in local:
+ b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
+ b: local copied/moved to a -> m
+ preserving b for resolve of b
+ updating: b 1/1 files (100.00%)
+ picked tool 'internal:merge' for b (binary False symlink False)
+ merging b and a to b
+ my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
+ premerge successful
+ b
+ grafting revision 5
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
+ e: remote is newer -> g
+ updating: e 1/1 files (100.00%)
+ getting e
+ e
+ grafting revision 4
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
+ e: versions differ -> m
+ d: remote is newer -> g
+ preserving e for resolve of e
+ updating: d 1/2 files (50.00%)
+ getting d
+ updating: e 2/2 files (100.00%)
+ picked tool 'internal:merge' for e (binary False symlink False)
+ merging e
+ my e@1905859650ec+ other e@9c233e8e184d ancestor e@68795b066622
+ warning: conflicts during merge.
+ merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts, can't continue
+ (use hg resolve and hg graft --continue)
+ [255]
+
+Continue without resolve should fail:
+
+ $ hg graft -c
+ grafting revision 4
+ abort: unresolved merge conflicts (see hg help resolve)
+ [255]
+
+Fix up:
+
+ $ echo b > e
+ $ hg resolve -m e
+
+Continue with a revision should fail:
+
+ $ hg graft -c 6
+ abort: can't specify --continue and revisions
+ [255]
+
+ $ hg graft -c -r 6
+ abort: can't specify --continue and revisions
+ [255]
+
+Continue for real, clobber usernames
+
+ $ hg graft -c -U
+ grafting revision 4
+ grafting revision 3
+
+Compare with original:
+
+ $ hg diff -r 6
+ $ hg status --rev 0:. -C
+ M d
+ M e
+ A b
+ a
+ A c
+ a
+ R a
+
+View graph:
+
+ $ hg --config extensions.graphlog= log -G --template '{author}@{rev}.{phase}: {desc}\n'
+ @ test@11.draft: 3
+ |
+ o test@10.draft: 4
+ |
+ o test@9.draft: 5
+ |
+ o bar@8.draft: 1
+ |
+ o foo@7.draft: 2
+ |
+ | o test@6.secret: 6
+ | |\
+ | | o test@5.draft: 5
+ | | |
+ | o | test@4.draft: 4
+ | |/
+ | o baz@3.public: 3
+ | |
+ | o test@2.public: 2
+ | |
+ | o bar@1.public: 1
+ |/
+ o test@0.public: 0
+
+Graft again onto another branch should preserve the original source
+ $ hg up -q 0
+ $ echo 'g'>g
+ $ hg add g
+ $ hg ci -m 7
+ created new head
+ $ hg graft 7
+ grafting revision 7
+
+ $ hg log -r 7 --template '{rev}:{node}\n'
+ 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
+ $ hg log -r 2 --template '{rev}:{node}\n'
+ 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
+
+ $ hg log --debug -r tip
+ changeset: 13:9db0f28fd3747e92c57d015f53b5593aeec53c2d
+ tag: tip
+ phase: draft
+ parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files+: b
+ files-: a
+ extra: branch=default
+ extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
+ description:
+ 2
+
+
+Disallow grafting an already grafted cset onto its original branch
+ $ hg up -q 6
+ $ hg graft 7
+ skipping already grafted revision 7 (was grafted from 2)
+ [255]
+
+Disallow grafting already grafted csets with the same origin onto each other
+ $ hg up -q 13
+ $ hg graft 2
+ skipping already grafted revision 2
+ [255]
+ $ hg graft 7
+ skipping already grafted revision 7 (same origin 2)
+ [255]
+
+ $ hg up -q 7
+ $ hg graft 2
+ skipping already grafted revision 2
+ [255]
+ $ hg graft tip
+ skipping already grafted revision 13 (same origin 2)
+ [255]
+
+Graft with --log
+
+ $ hg up -Cq 1
+ $ hg graft 3 --log -u foo
+ grafting revision 3
+ warning: can't find ancestor for 'c' copied from 'b'!
+ $ hg log --template '{rev} {parents} {desc}\n' -r tip
+ 14 1:5d205f8b35b6 3
+ (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
+
+Resolve conflicted graft
+ $ hg up -q 0
+ $ echo b > a
+ $ hg ci -m 8
+ created new head
+ $ echo a > a
+ $ hg ci -m 9
+ $ hg graft 1 --tool internal:fail
+ grafting revision 1
+ abort: unresolved conflicts, can't continue
+ (use hg resolve and hg graft --continue)
+ [255]
+ $ hg resolve --all
+ merging a
+ $ hg graft -c
+ grafting revision 1
+ $ hg export tip --git
+ # HG changeset patch
+ # User bar
+ # Date 0 0
+ # Node ID 64ecd9071ce83c6e62f538d8ce7709d53f32ebf7
+ # Parent 4bdb9a9d0b84ffee1d30f0dfc7744cade17aa19c
+ 1
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,1 @@
+ -a
+ +b
+
+Resolve conflicted graft with rename
+ $ echo c > a
+ $ hg ci -m 10
+ $ hg graft 2 --tool internal:fail
+ grafting revision 2
+ abort: unresolved conflicts, can't continue
+ (use hg resolve and hg graft --continue)
+ [255]
+ $ hg resolve --all
+ merging a and b to b
+ $ hg graft -c
+ grafting revision 2
+ $ hg export tip --git
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Node ID 2e80e1351d6ed50302fe1e05f8bd1d4d412b6e11
+ # Parent e5a51ae854a8bbaaf25cc5c6a57ff46042dadbb4
+ 2
+
+ diff --git a/a b/b
+ rename from a
+ rename to b
+
+Test simple origin(), with and without args
+ $ hg log -r 'origin()'
+ changeset: 1:5d205f8b35b6
+ user: bar
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ changeset: 2:5c095ad7e90f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 3:4c60f11aa304
+ user: baz
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3
+
+ changeset: 4:9c233e8e184d
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 4
+
+ changeset: 5:97f8bfe72746
+ branch: stable
+ parent: 3:4c60f11aa304
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 5
+
+ $ hg log -r 'origin(7)'
+ changeset: 2:5c095ad7e90f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+Now transplant a graft to test following through copies
+ $ hg up -q 0
+ $ hg branch -q dev
+ $ hg ci -qm "dev branch"
+ $ hg --config extensions.transplant= transplant -q 7
+ $ hg log -r 'origin(.)'
+ changeset: 2:5c095ad7e90f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+Test simple destination
+ $ hg log -r 'destination()'
+ changeset: 7:ef0ef43d49e7
+ parent: 0:68795b066622
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 8:6b9e5368ca4e
+ user: bar
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ changeset: 9:1905859650ec
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 5
+
+ changeset: 10:52dc0b4c6907
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 4
+
+ changeset: 11:882b35362a6b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3
+
+ changeset: 13:9db0f28fd374
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 14:f64defefacee
+ parent: 1:5d205f8b35b6
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3
+
+ changeset: 17:64ecd9071ce8
+ user: bar
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ changeset: 19:2e80e1351d6e
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 21:7e61b508e709
+ branch: dev
+ tag: tip
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ $ hg log -r 'destination(2)'
+ changeset: 7:ef0ef43d49e7
+ parent: 0:68795b066622
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 13:9db0f28fd374
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 19:2e80e1351d6e
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 21:7e61b508e709
+ branch: dev
+ tag: tip
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+Transplants of grafts can find a destination...
+ $ hg log -r 'destination(7)'
+ changeset: 21:7e61b508e709
+ branch: dev
+ tag: tip
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+... grafts of grafts unfortunately can't
+ $ hg graft -q 13
+ $ hg log -r 'destination(13)'
+All copies of a cset
+ $ hg log -r 'origin(13) or destination(origin(13))'
+ changeset: 2:5c095ad7e90f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 7:ef0ef43d49e7
+ parent: 0:68795b066622
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 13:9db0f28fd374
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 19:2e80e1351d6e
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 21:7e61b508e709
+ branch: dev
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 22:1313d0a825e2
+ branch: dev
+ tag: tip
+ user: foo
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
diff --git a/tests/test-grep.t b/tests/test-grep.t
new file mode 100644
index 0000000..0b4c3f2
--- /dev/null
+++ b/tests/test-grep.t
@@ -0,0 +1,176 @@
+ $ hg init t
+ $ cd t
+ $ echo import > port
+ $ hg add port
+ $ hg commit -m 0 -u spam -d '0 0'
+ $ echo export >> port
+ $ hg commit -m 1 -u eggs -d '1 0'
+ $ echo export > port
+ $ echo vaportight >> port
+ $ echo 'import/export' >> port
+ $ hg commit -m 2 -u spam -d '2 0'
+ $ echo 'import/export' >> port
+ $ hg commit -m 3 -u eggs -d '3 0'
+ $ head -n 3 port > port1
+ $ mv port1 port
+ $ hg commit -m 4 -u spam -d '4 0'
+
+pattern error
+
+ $ hg grep '**test**'
+ grep: invalid match pattern: nothing to repeat
+ [1]
+
+simple
+
+ $ hg grep port port
+ port:4:export
+ port:4:vaportight
+ port:4:import/export
+
+simple with color
+
+ $ hg --config extensions.color= grep --config color.mode=ansi \
+ > --color=always port port
+ port:4:ex\x1b[0;31;1mport\x1b[0m (esc)
+ port:4:va\x1b[0;31;1mport\x1b[0might (esc)
+ port:4:im\x1b[0;31;1mport\x1b[0m/export (esc)
+
+all
+
+ $ hg grep --traceback --all -nu port port
+ port:4:4:-:spam:import/export
+ port:3:4:+:eggs:import/export
+ port:2:1:-:spam:import
+ port:2:2:-:spam:export
+ port:2:1:+:spam:export
+ port:2:2:+:spam:vaportight
+ port:2:3:+:spam:import/export
+ port:1:2:+:eggs:export
+ port:0:1:+:spam:import
+
+other
+
+ $ hg grep import port
+ port:4:import/export
+
+ $ hg cp port port2
+ $ hg commit -m 4 -u spam -d '5 0'
+
+follow
+
+ $ hg grep --traceback -f 'import\n\Z' port2
+ port:0:import
+
+ $ echo deport >> port2
+ $ hg commit -m 5 -u eggs -d '6 0'
+ $ hg grep -f --all -nu port port2
+ port2:6:4:+:eggs:deport
+ port:4:4:-:spam:import/export
+ port:3:4:+:eggs:import/export
+ port:2:1:-:spam:import
+ port:2:2:-:spam:export
+ port:2:1:+:spam:export
+ port:2:2:+:spam:vaportight
+ port:2:3:+:spam:import/export
+ port:1:2:+:eggs:export
+ port:0:1:+:spam:import
+
+ $ cd ..
+ $ hg init t2
+ $ cd t2
+ $ hg grep foobar foo
+ [1]
+ $ hg grep foobar
+ [1]
+ $ echo blue >> color
+ $ echo black >> color
+ $ hg add color
+ $ hg ci -m 0
+ $ echo orange >> color
+ $ hg ci -m 1
+ $ echo black > color
+ $ hg ci -m 2
+ $ echo orange >> color
+ $ echo blue >> color
+ $ hg ci -m 3
+ $ hg grep orange
+ color:3:orange
+ $ hg grep --all orange
+ color:3:+:orange
+ color:2:-:orange
+ color:1:+:orange
+
+
+match in last "line" without newline
+
+ $ python -c 'fp = open("noeol", "wb"); fp.write("no infinite loop"); fp.close();'
+ $ hg ci -Amnoeol
+ adding noeol
+ $ hg grep loop
+ noeol:4:no infinite loop
+
+ $ cd ..
+
+Issue685: trackback in grep -r after rename
+
+Got a traceback when using grep on a single
+revision with renamed files.
+
+ $ hg init issue685
+ $ cd issue685
+ $ echo octarine > color
+ $ hg ci -Amcolor
+ adding color
+ $ hg rename color colour
+ $ hg ci -Am rename
+ $ hg grep octarine
+ colour:1:octarine
+ color:0:octarine
+
+Used to crash here
+
+ $ hg grep -r 1 octarine
+ colour:1:octarine
+ $ cd ..
+
+
+Issue337: test that grep follows parent-child relationships instead
+of just using revision numbers.
+
+ $ hg init issue337
+ $ cd issue337
+
+ $ echo white > color
+ $ hg commit -A -m "0 white"
+ adding color
+
+ $ echo red > color
+ $ hg commit -A -m "1 red"
+
+ $ hg update 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo black > color
+ $ hg commit -A -m "2 black"
+ created new head
+
+ $ hg update --clean 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo blue > color
+ $ hg commit -A -m "3 blue"
+
+ $ hg grep --all red
+ color:3:-:red
+ color:1:+:red
+
+ $ cd ..
+
+ $ hg init a
+ $ cd a
+ $ cp "$TESTDIR/binfile.bin" .
+ $ hg add binfile.bin
+ $ hg ci -m 'add binfile.bin'
+ $ hg grep "MaCam" --all
+ binfile.bin:0:+: Binary file matches
+
+ $ cd ..
diff --git a/tests/test-hardlinks.t b/tests/test-hardlinks.t
new file mode 100644
index 0000000..65978e1
--- /dev/null
+++ b/tests/test-hardlinks.t
@@ -0,0 +1,352 @@
+ $ "$TESTDIR/hghave" hardlink || exit 80
+
+ $ cat > nlinks.py <<EOF
+ > import sys
+ > from mercurial import util
+ > for f in sorted(sys.stdin.readlines()):
+ > f = f[:-1]
+ > print util.nlinks(f), f
+ > EOF
+
+ $ nlinksdir()
+ > {
+ > find $1 -type f | python $TESTTMP/nlinks.py
+ > }
+
+Some implementations of cp can't create hardlinks (replaces 'cp -al' on Linux):
+
+ $ cat > linkcp.py <<EOF
+ > from mercurial import util
+ > import sys
+ > util.copyfiles(sys.argv[1], sys.argv[2], hardlink=True)
+ > EOF
+
+ $ linkcp()
+ > {
+ > python $TESTTMP/linkcp.py $1 $2
+ > }
+
+Prepare repo r1:
+
+ $ hg init r1
+ $ cd r1
+
+ $ echo c1 > f1
+ $ hg add f1
+ $ hg ci -m0
+
+ $ mkdir d1
+ $ cd d1
+ $ echo c2 > f2
+ $ hg add f2
+ $ hg ci -m1
+ $ cd ../..
+
+ $ nlinksdir r1/.hg/store
+ 1 r1/.hg/store/00changelog.i
+ 1 r1/.hg/store/00manifest.i
+ 1 r1/.hg/store/data/d1/f2.i
+ 1 r1/.hg/store/data/f1.i
+ 1 r1/.hg/store/fncache
+ 1 r1/.hg/store/phaseroots
+ 1 r1/.hg/store/undo
+ 1 r1/.hg/store/undo.phaseroots
+
+
+Create hardlinked clone r2:
+
+ $ hg clone -U --debug r1 r2
+ linked 7 files
+ listing keys for "bookmarks"
+
+Create non-hardlinked clone r3:
+
+ $ hg clone --pull r1 r3
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+
+Repos r1 and r2 should now contain hardlinked files:
+
+ $ nlinksdir r1/.hg/store
+ 2 r1/.hg/store/00changelog.i
+ 2 r1/.hg/store/00manifest.i
+ 2 r1/.hg/store/data/d1/f2.i
+ 2 r1/.hg/store/data/f1.i
+ 2 r1/.hg/store/fncache
+ 1 r1/.hg/store/phaseroots
+ 1 r1/.hg/store/undo
+ 1 r1/.hg/store/undo.phaseroots
+
+ $ nlinksdir r2/.hg/store
+ 2 r2/.hg/store/00changelog.i
+ 2 r2/.hg/store/00manifest.i
+ 2 r2/.hg/store/data/d1/f2.i
+ 2 r2/.hg/store/data/f1.i
+ 2 r2/.hg/store/fncache
+
+Repo r3 should not be hardlinked:
+
+ $ nlinksdir r3/.hg/store
+ 1 r3/.hg/store/00changelog.i
+ 1 r3/.hg/store/00manifest.i
+ 1 r3/.hg/store/data/d1/f2.i
+ 1 r3/.hg/store/data/f1.i
+ 1 r3/.hg/store/fncache
+ 1 r3/.hg/store/phaseroots
+ 1 r3/.hg/store/undo
+ 1 r3/.hg/store/undo.phaseroots
+
+
+Create a non-inlined filelog in r3:
+
+ $ cd r3/d1
+ >>> f = open('data1', 'wb')
+ >>> for x in range(10000):
+ ... f.write("%s\n" % str(x))
+ >>> f.close()
+ $ for j in 0 1 2 3 4 5 6 7 8 9; do
+ > cat data1 >> f2
+ > hg commit -m$j
+ > done
+ $ cd ../..
+
+ $ nlinksdir r3/.hg/store
+ 1 r3/.hg/store/00changelog.i
+ 1 r3/.hg/store/00manifest.i
+ 1 r3/.hg/store/data/d1/f2.d
+ 1 r3/.hg/store/data/d1/f2.i
+ 1 r3/.hg/store/data/f1.i
+ 1 r3/.hg/store/fncache
+ 1 r3/.hg/store/phaseroots
+ 1 r3/.hg/store/undo
+ 1 r3/.hg/store/undo.phaseroots
+
+Push to repo r1 should break up most hardlinks in r2:
+
+ $ hg -R r2 verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 2 changesets, 2 total revisions
+
+ $ cd r3
+ $ hg push
+ pushing to $TESTTMP/r1 (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 10 changesets with 10 changes to 1 files
+
+ $ cd ..
+
+ $ nlinksdir r2/.hg/store
+ 1 r2/.hg/store/00changelog.i
+ 1 r2/.hg/store/00manifest.i
+ 1 r2/.hg/store/data/d1/f2.i
+ 2 r2/.hg/store/data/f1.i
+ 1 r2/.hg/store/fncache
+
+ $ hg -R r2 verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 2 changesets, 2 total revisions
+
+
+ $ cd r1
+ $ hg up
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Committing a change to f1 in r1 must break up hardlink f1.i in r2:
+
+ $ echo c1c1 >> f1
+ $ hg ci -m00
+ $ cd ..
+
+ $ nlinksdir r2/.hg/store
+ 1 r2/.hg/store/00changelog.i
+ 1 r2/.hg/store/00manifest.i
+ 1 r2/.hg/store/data/d1/f2.i
+ 1 r2/.hg/store/data/f1.i
+ 1 r2/.hg/store/fncache
+
+
+ $ cd r3
+ $ hg tip --template '{rev}:{node|short}\n'
+ 11:a6451b6bc41f
+ $ echo bla > f1
+ $ hg ci -m1
+ $ cd ..
+
+Create hardlinked copy r4 of r3 (on Linux, we would call 'cp -al'):
+
+ $ linkcp r3 r4
+
+r4 has hardlinks in the working dir (not just inside .hg):
+
+ $ nlinksdir r4
+ 2 r4/.hg/00changelog.i
+ 2 r4/.hg/branch
+ 2 r4/.hg/cache/branchheads
+ 2 r4/.hg/cache/tags
+ 2 r4/.hg/dirstate
+ 2 r4/.hg/hgrc
+ 2 r4/.hg/last-message.txt
+ 2 r4/.hg/requires
+ 2 r4/.hg/store/00changelog.i
+ 2 r4/.hg/store/00manifest.i
+ 2 r4/.hg/store/data/d1/f2.d
+ 2 r4/.hg/store/data/d1/f2.i
+ 2 r4/.hg/store/data/f1.i
+ 2 r4/.hg/store/fncache
+ 2 r4/.hg/store/phaseroots
+ 2 r4/.hg/store/undo
+ 2 r4/.hg/store/undo.phaseroots
+ 2 r4/.hg/undo.bookmarks
+ 2 r4/.hg/undo.branch
+ 2 r4/.hg/undo.desc
+ 2 r4/.hg/undo.dirstate
+ 2 r4/d1/data1
+ 2 r4/d1/f2
+ 2 r4/f1
+
+Update back to revision 11 in r4 should break hardlink of file f1:
+
+ $ hg -R r4 up 11
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ nlinksdir r4
+ 2 r4/.hg/00changelog.i
+ 1 r4/.hg/branch
+ 2 r4/.hg/cache/branchheads
+ 2 r4/.hg/cache/tags
+ 1 r4/.hg/dirstate
+ 2 r4/.hg/hgrc
+ 2 r4/.hg/last-message.txt
+ 2 r4/.hg/requires
+ 2 r4/.hg/store/00changelog.i
+ 2 r4/.hg/store/00manifest.i
+ 2 r4/.hg/store/data/d1/f2.d
+ 2 r4/.hg/store/data/d1/f2.i
+ 2 r4/.hg/store/data/f1.i
+ 2 r4/.hg/store/fncache
+ 2 r4/.hg/store/phaseroots
+ 2 r4/.hg/store/undo
+ 2 r4/.hg/store/undo.phaseroots
+ 2 r4/.hg/undo.bookmarks
+ 2 r4/.hg/undo.branch
+ 2 r4/.hg/undo.desc
+ 2 r4/.hg/undo.dirstate
+ 2 r4/d1/data1
+ 2 r4/d1/f2
+ 1 r4/f1
+
+
+Test hardlinking outside hg:
+
+ $ mkdir x
+ $ echo foo > x/a
+
+ $ linkcp x y
+ $ echo bar >> y/a
+
+No diff if hardlink:
+
+ $ diff x/a y/a
+
+Test mq hardlinking:
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init a
+ $ cd a
+
+ $ hg qimport -n foo - << EOF
+ > # HG changeset patch
+ > # Date 1 0
+ > diff -r 2588a8b53d66 a
+ > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ > +++ b/a Wed Jul 23 15:54:29 2008 +0200
+ > @@ -0,0 +1,1 @@
+ > +a
+ > EOF
+ adding foo to series file
+
+ $ hg qpush
+ applying foo
+ now at: foo
+
+ $ cd ..
+ $ linkcp a b
+ $ cd b
+
+ $ hg qimport -n bar - << EOF
+ > # HG changeset patch
+ > # Date 2 0
+ > diff -r 2588a8b53d66 a
+ > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ > +++ b/b Wed Jul 23 15:54:29 2008 +0200
+ > @@ -0,0 +1,1 @@
+ > +b
+ > EOF
+ adding bar to series file
+
+ $ hg qpush
+ applying bar
+ now at: bar
+
+ $ cat .hg/patches/status
+ 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
+ 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar
+
+ $ cat .hg/patches/series
+ foo
+ bar
+
+ $ cat ../a/.hg/patches/status
+ 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
+
+ $ cat ../a/.hg/patches/series
+ foo
+
+Test tags hardlinking:
+
+ $ hg qdel -r qbase:qtip
+ patch foo finalized without changeset message
+ patch bar finalized without changeset message
+
+ $ hg tag -l lfoo
+ $ hg tag foo
+
+ $ cd ..
+ $ linkcp b c
+ $ cd c
+
+ $ hg tag -l -r 0 lbar
+ $ hg tag -r 0 bar
+
+ $ cat .hgtags
+ 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
+ 430ed4828a74fa4047bc816a25500f7472ab4bfe bar
+
+ $ cat .hg/localtags
+ 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
+ 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar
+
+ $ cat ../b/.hgtags
+ 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
+
+ $ cat ../b/.hg/localtags
+ 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
+
+ $ cd ..
diff --git a/tests/test-help.t b/tests/test-help.t
new file mode 100644
index 0000000..fe1eb25
--- /dev/null
+++ b/tests/test-help.t
@@ -0,0 +1,804 @@
+Short help:
+
+ $ hg
+ Mercurial Distributed SCM
+
+ basic commands:
+
+ add add the specified files on the next commit
+ annotate show changeset information by line for each file
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ init create a new repository in the given directory
+ log show revision history of entire repository or files
+ merge merge working directory with another revision
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ remove remove the specified files on the next commit
+ serve start stand-alone webserver
+ status show changed files in the working directory
+ summary summarize working directory state
+ update update working directory (or switch revisions)
+
+ use "hg help" for the full list of commands or "hg -v" for details
+
+ $ hg -q
+ add add the specified files on the next commit
+ annotate show changeset information by line for each file
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ init create a new repository in the given directory
+ log show revision history of entire repository or files
+ merge merge working directory with another revision
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ remove remove the specified files on the next commit
+ serve start stand-alone webserver
+ status show changed files in the working directory
+ summary summarize working directory state
+ update update working directory (or switch revisions)
+
+ $ hg help
+ Mercurial Distributed SCM
+
+ list of commands:
+
+ add add the specified files on the next commit
+ addremove add all new files, delete all missing files
+ annotate show changeset information by line for each file
+ archive create an unversioned archive of a repository revision
+ backout reverse effect of earlier changeset
+ bisect subdivision search of changesets
+ bookmarks track a line of development with movable markers
+ branch set or show the current branch name
+ branches list repository named branches
+ bundle create a changegroup file
+ cat output the current or given revision of files
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ copy mark files as copied for the next commit
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ graft copy changes from other branches onto the current branch
+ grep search for a pattern in specified files and revisions
+ heads show current repository heads or show branch heads
+ help show help for a given topic or a help overview
+ identify identify the working copy or specified revision
+ import import an ordered set of patches
+ incoming show new changesets found in source
+ init create a new repository in the given directory
+ locate locate files matching specific patterns
+ log show revision history of entire repository or files
+ manifest output the current or given revision of the project manifest
+ merge merge working directory with another revision
+ outgoing show changesets not found in the destination
+ parents show the parents of the working directory or revision
+ paths show aliases for remote repositories
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ recover roll back an interrupted transaction
+ remove remove the specified files on the next commit
+ rename rename files; equivalent of copy + remove
+ resolve redo merges or set/view the merge status of files
+ revert restore files to their checkout state
+ rollback roll back the last transaction (dangerous)
+ root print the root (top) of the current working directory
+ serve start stand-alone webserver
+ showconfig show combined config settings from all hgrc files
+ status show changed files in the working directory
+ summary summarize working directory state
+ tag add one or more tags for the current or given revision
+ tags list repository tags
+ tip show the tip revision
+ unbundle apply one or more changegroup files
+ update update working directory (or switch revisions)
+ verify verify the integrity of the repository
+ version output version and copyright information
+
+ additional help topics:
+
+ config Configuration Files
+ dates Date Formats
+ diffs Diff Formats
+ environment Environment Variables
+ extensions Using Additional Features
+ filesets Specifying File Sets
+ glossary Glossary
+ hgignore Syntax for Mercurial Ignore Files
+ hgweb Configuring hgweb
+ merge-tools Merge Tools
+ multirevs Specifying Multiple Revisions
+ patterns File Name Patterns
+ phases Working with Phases
+ revisions Specifying Single Revisions
+ revsets Specifying Revision Sets
+ subrepos Subrepositories
+ templating Template Usage
+ urls URL Paths
+
+ use "hg -v help" to show builtin aliases and global options
+
+ $ hg -q help
+ add add the specified files on the next commit
+ addremove add all new files, delete all missing files
+ annotate show changeset information by line for each file
+ archive create an unversioned archive of a repository revision
+ backout reverse effect of earlier changeset
+ bisect subdivision search of changesets
+ bookmarks track a line of development with movable markers
+ branch set or show the current branch name
+ branches list repository named branches
+ bundle create a changegroup file
+ cat output the current or given revision of files
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ copy mark files as copied for the next commit
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ graft copy changes from other branches onto the current branch
+ grep search for a pattern in specified files and revisions
+ heads show current repository heads or show branch heads
+ help show help for a given topic or a help overview
+ identify identify the working copy or specified revision
+ import import an ordered set of patches
+ incoming show new changesets found in source
+ init create a new repository in the given directory
+ locate locate files matching specific patterns
+ log show revision history of entire repository or files
+ manifest output the current or given revision of the project manifest
+ merge merge working directory with another revision
+ outgoing show changesets not found in the destination
+ parents show the parents of the working directory or revision
+ paths show aliases for remote repositories
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ recover roll back an interrupted transaction
+ remove remove the specified files on the next commit
+ rename rename files; equivalent of copy + remove
+ resolve redo merges or set/view the merge status of files
+ revert restore files to their checkout state
+ rollback roll back the last transaction (dangerous)
+ root print the root (top) of the current working directory
+ serve start stand-alone webserver
+ showconfig show combined config settings from all hgrc files
+ status show changed files in the working directory
+ summary summarize working directory state
+ tag add one or more tags for the current or given revision
+ tags list repository tags
+ tip show the tip revision
+ unbundle apply one or more changegroup files
+ update update working directory (or switch revisions)
+ verify verify the integrity of the repository
+ version output version and copyright information
+
+ additional help topics:
+
+ config Configuration Files
+ dates Date Formats
+ diffs Diff Formats
+ environment Environment Variables
+ extensions Using Additional Features
+ filesets Specifying File Sets
+ glossary Glossary
+ hgignore Syntax for Mercurial Ignore Files
+ hgweb Configuring hgweb
+ merge-tools Merge Tools
+ multirevs Specifying Multiple Revisions
+ patterns File Name Patterns
+ phases Working with Phases
+ revisions Specifying Single Revisions
+ revsets Specifying Revision Sets
+ subrepos Subrepositories
+ templating Template Usage
+ urls URL Paths
+
+Test short command list with verbose option
+
+ $ hg -v help shortlist
+ Mercurial Distributed SCM
+
+ basic commands:
+
+ add add the specified files on the next commit
+ annotate, blame
+ show changeset information by line for each file
+ clone make a copy of an existing repository
+ commit, ci commit the specified files or all outstanding changes
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ init create a new repository in the given directory
+ log, history show revision history of entire repository or files
+ merge merge working directory with another revision
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ remove, rm remove the specified files on the next commit
+ serve start stand-alone webserver
+ status, st show changed files in the working directory
+ summary, sum summarize working directory state
+ update, up, checkout, co
+ update working directory (or switch revisions)
+
+ global options:
+
+ -R --repository REPO repository root directory or name of overlay bundle
+ file
+ --cwd DIR change working directory
+ -y --noninteractive do not prompt, automatically pick the first choice for
+ all prompts
+ -q --quiet suppress output
+ -v --verbose enable additional output
+ --config CONFIG [+] set/override config option (use 'section.name=value')
+ --debug enable debugging output
+ --debugger start debugger
+ --encoding ENCODE set the charset encoding (default: ascii)
+ --encodingmode MODE set the charset encoding mode (default: strict)
+ --traceback always print a traceback on exception
+ --time time how long the command takes
+ --profile print command execution profile
+ --version output version information and exit
+ -h --help display help and exit
+
+ [+] marked option can be specified multiple times
+
+ use "hg help" for the full list of commands
+
+ $ hg add -h
+ hg add [OPTION]... [FILE]...
+
+ add the specified files on the next commit
+
+ Schedule files to be version controlled and added to the repository.
+
+ The files will be added to the repository at the next commit. To undo an
+ add before that, see "hg forget".
+
+ If no names are given, add all files to the repository.
+
+ Returns 0 if all files are successfully added.
+
+ options:
+
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+ -S --subrepos recurse into subrepositories
+ -n --dry-run do not perform actions, just print output
+
+ [+] marked option can be specified multiple times
+
+ use "hg -v help add" to show more info
+
+Verbose help for add
+
+ $ hg add -hv
+ hg add [OPTION]... [FILE]...
+
+ add the specified files on the next commit
+
+ Schedule files to be version controlled and added to the repository.
+
+ The files will be added to the repository at the next commit. To undo an
+ add before that, see "hg forget".
+
+ If no names are given, add all files to the repository.
+
+ An example showing how new (unknown) files are added automatically by "hg
+ add":
+
+ $ ls
+ foo.c
+ $ hg status
+ ? foo.c
+ $ hg add
+ adding foo.c
+ $ hg status
+ A foo.c
+
+ Returns 0 if all files are successfully added.
+
+ options:
+
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+ -S --subrepos recurse into subrepositories
+ -n --dry-run do not perform actions, just print output
+
+ [+] marked option can be specified multiple times
+
+ global options:
+
+ -R --repository REPO repository root directory or name of overlay bundle
+ file
+ --cwd DIR change working directory
+ -y --noninteractive do not prompt, automatically pick the first choice for
+ all prompts
+ -q --quiet suppress output
+ -v --verbose enable additional output
+ --config CONFIG [+] set/override config option (use 'section.name=value')
+ --debug enable debugging output
+ --debugger start debugger
+ --encoding ENCODE set the charset encoding (default: ascii)
+ --encodingmode MODE set the charset encoding mode (default: strict)
+ --traceback always print a traceback on exception
+ --time time how long the command takes
+ --profile print command execution profile
+ --version output version information and exit
+ -h --help display help and exit
+
+ [+] marked option can be specified multiple times
+
+Test help option with version option
+
+ $ hg add -h --version
+ Mercurial Distributed SCM (version *) (glob)
+ (see http://mercurial.selenic.com for more information)
+
+ Copyright (C) 2005-2012 Matt Mackall and others
+ This is free software; see the source for copying conditions. There is NO
+ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ $ hg add --skjdfks
+ hg add: option --skjdfks not recognized
+ hg add [OPTION]... [FILE]...
+
+ add the specified files on the next commit
+
+ options:
+
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+ -S --subrepos recurse into subrepositories
+ -n --dry-run do not perform actions, just print output
+
+ [+] marked option can be specified multiple times
+
+ use "hg help add" to show the full help text
+ [255]
+
+Test ambiguous command help
+
+ $ hg help ad
+ list of commands:
+
+ add add the specified files on the next commit
+ addremove add all new files, delete all missing files
+
+ use "hg -v help ad" to show builtin aliases and global options
+
+Test command without options
+
+ $ hg help verify
+ hg verify
+
+ verify the integrity of the repository
+
+ Verify the integrity of the current repository.
+
+ This will perform an extensive check of the repository's integrity,
+ validating the hashes and checksums of each entry in the changelog,
+ manifest, and tracked files, as well as the integrity of their crosslinks
+ and indices.
+
+ Returns 0 on success, 1 if errors are encountered.
+
+ use "hg -v help verify" to show more info
+
+ $ hg help diff
+ hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
+
+ diff repository (or selected files)
+
+ Show differences between revisions for the specified files.
+
+ Differences between files are shown using the unified diff format.
+
+ Note:
+ diff may generate unexpected results for merges, as it will default to
+ comparing against the working directory's first parent changeset if no
+ revisions are specified.
+
+ When two revision arguments are given, then changes are shown between
+ those revisions. If only one revision is specified then that revision is
+ compared to the working directory, and, when no revisions are specified,
+ the working directory files are compared to its parent.
+
+ Alternatively you can specify -c/--change with a revision to see the
+ changes in that changeset relative to its first parent.
+
+ Without the -a/--text option, diff will avoid generating diffs of files it
+ detects as binary. With -a, diff will generate a diff anyway, probably
+ with undesirable results.
+
+ Use the -g/--git option to generate diffs in the git extended diff format.
+ For more information, read "hg help diffs".
+
+ Returns 0 on success.
+
+ options:
+
+ -r --rev REV [+] revision
+ -c --change REV change made by revision
+ -a --text treat all files as text
+ -g --git use git extended diff format
+ --nodates omit dates from diff headers
+ -p --show-function show which function each change is in
+ --reverse produce a diff that undoes the changes
+ -w --ignore-all-space ignore white space when comparing lines
+ -b --ignore-space-change ignore changes in the amount of white space
+ -B --ignore-blank-lines ignore changes whose lines are all blank
+ -U --unified NUM number of lines of context to show
+ --stat output diffstat-style summary of changes
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+ -S --subrepos recurse into subrepositories
+
+ [+] marked option can be specified multiple times
+
+ use "hg -v help diff" to show more info
+
+ $ hg help status
+ hg status [OPTION]... [FILE]...
+
+ aliases: st
+
+ show changed files in the working directory
+
+ Show status of files in the repository. If names are given, only files
+ that match are shown. Files that are clean or ignored or the source of a
+ copy/move operation, are not listed unless -c/--clean, -i/--ignored,
+ -C/--copies or -A/--all are given. Unless options described with "show
+ only ..." are given, the options -mardu are used.
+
+ Option -q/--quiet hides untracked (unknown and ignored) files unless
+ explicitly requested with -u/--unknown or -i/--ignored.
+
+ Note:
+ status may appear to disagree with diff if permissions have changed or
+ a merge has occurred. The standard diff format does not report
+ permission changes and diff only reports changes relative to one merge
+ parent.
+
+ If one revision is given, it is used as the base revision. If two
+ revisions are given, the differences between them are shown. The --change
+ option can also be used as a shortcut to list the changed files of a
+ revision from its first parent.
+
+ The codes used to show the status of files are:
+
+ M = modified
+ A = added
+ R = removed
+ C = clean
+ ! = missing (deleted by non-hg command, but still tracked)
+ ? = not tracked
+ I = ignored
+ = origin of the previous file listed as A (added)
+
+ Returns 0 on success.
+
+ options:
+
+ -A --all show status of all files
+ -m --modified show only modified files
+ -a --added show only added files
+ -r --removed show only removed files
+ -d --deleted show only deleted (but tracked) files
+ -c --clean show only files without changes
+ -u --unknown show only unknown (not tracked) files
+ -i --ignored show only ignored files
+ -n --no-status hide status prefix
+ -C --copies show source of copied files
+ -0 --print0 end filenames with NUL, for use with xargs
+ --rev REV [+] show difference from revision
+ --change REV list the changed files of a revision
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+ -S --subrepos recurse into subrepositories
+
+ [+] marked option can be specified multiple times
+
+ use "hg -v help status" to show more info
+
+ $ hg -q help status
+ hg status [OPTION]... [FILE]...
+
+ show changed files in the working directory
+
+ $ hg help foo
+ hg: unknown command 'foo'
+ Mercurial Distributed SCM
+
+ basic commands:
+
+ add add the specified files on the next commit
+ annotate show changeset information by line for each file
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ init create a new repository in the given directory
+ log show revision history of entire repository or files
+ merge merge working directory with another revision
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ remove remove the specified files on the next commit
+ serve start stand-alone webserver
+ status show changed files in the working directory
+ summary summarize working directory state
+ update update working directory (or switch revisions)
+
+ use "hg help" for the full list of commands or "hg -v" for details
+ [255]
+
+ $ hg skjdfks
+ hg: unknown command 'skjdfks'
+ Mercurial Distributed SCM
+
+ basic commands:
+
+ add add the specified files on the next commit
+ annotate show changeset information by line for each file
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ init create a new repository in the given directory
+ log show revision history of entire repository or files
+ merge merge working directory with another revision
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ remove remove the specified files on the next commit
+ serve start stand-alone webserver
+ status show changed files in the working directory
+ summary summarize working directory state
+ update update working directory (or switch revisions)
+
+ use "hg help" for the full list of commands or "hg -v" for details
+ [255]
+
+ $ cat > helpext.py <<EOF
+ > import os
+ > from mercurial import commands
+ >
+ > def nohelp(ui, *args, **kwargs):
+ > pass
+ >
+ > cmdtable = {
+ > "nohelp": (nohelp, [], "hg nohelp"),
+ > }
+ >
+ > commands.norepo += ' nohelp'
+ > EOF
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
+
+Test command with no help text
+
+ $ hg help nohelp
+ hg nohelp
+
+ (no help text available)
+
+ use "hg -v help nohelp" to show more info
+
+ $ hg help -k nohelp
+ Commands:
+
+ nohelp hg nohelp
+
+ Extension Commands:
+
+ nohelp (no help text available)
+
+Test that default list of commands omits extension commands
+
+ $ hg help
+ Mercurial Distributed SCM
+
+ list of commands:
+
+ add add the specified files on the next commit
+ addremove add all new files, delete all missing files
+ annotate show changeset information by line for each file
+ archive create an unversioned archive of a repository revision
+ backout reverse effect of earlier changeset
+ bisect subdivision search of changesets
+ bookmarks track a line of development with movable markers
+ branch set or show the current branch name
+ branches list repository named branches
+ bundle create a changegroup file
+ cat output the current or given revision of files
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ copy mark files as copied for the next commit
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ graft copy changes from other branches onto the current branch
+ grep search for a pattern in specified files and revisions
+ heads show current repository heads or show branch heads
+ help show help for a given topic or a help overview
+ identify identify the working copy or specified revision
+ import import an ordered set of patches
+ incoming show new changesets found in source
+ init create a new repository in the given directory
+ locate locate files matching specific patterns
+ log show revision history of entire repository or files
+ manifest output the current or given revision of the project manifest
+ merge merge working directory with another revision
+ outgoing show changesets not found in the destination
+ parents show the parents of the working directory or revision
+ paths show aliases for remote repositories
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ recover roll back an interrupted transaction
+ remove remove the specified files on the next commit
+ rename rename files; equivalent of copy + remove
+ resolve redo merges or set/view the merge status of files
+ revert restore files to their checkout state
+ rollback roll back the last transaction (dangerous)
+ root print the root (top) of the current working directory
+ serve start stand-alone webserver
+ showconfig show combined config settings from all hgrc files
+ status show changed files in the working directory
+ summary summarize working directory state
+ tag add one or more tags for the current or given revision
+ tags list repository tags
+ tip show the tip revision
+ unbundle apply one or more changegroup files
+ update update working directory (or switch revisions)
+ verify verify the integrity of the repository
+ version output version and copyright information
+
+ enabled extensions:
+
+ helpext (no help text available)
+
+ additional help topics:
+
+ config Configuration Files
+ dates Date Formats
+ diffs Diff Formats
+ environment Environment Variables
+ extensions Using Additional Features
+ filesets Specifying File Sets
+ glossary Glossary
+ hgignore Syntax for Mercurial Ignore Files
+ hgweb Configuring hgweb
+ merge-tools Merge Tools
+ multirevs Specifying Multiple Revisions
+ patterns File Name Patterns
+ phases Working with Phases
+ revisions Specifying Single Revisions
+ revsets Specifying Revision Sets
+ subrepos Subrepositories
+ templating Template Usage
+ urls URL Paths
+
+ use "hg -v help" to show builtin aliases and global options
+
+
+
+Test list of commands with command with no help text
+
+ $ hg help helpext
+ helpext extension - no help text available
+
+ list of commands:
+
+ nohelp (no help text available)
+
+ use "hg -v help helpext" to show builtin aliases and global options
+
+Test a help topic
+
+ $ hg help revs
+ Specifying Single Revisions
+
+ Mercurial supports several ways to specify individual revisions.
+
+ A plain integer is treated as a revision number. Negative integers are
+ treated as sequential offsets from the tip, with -1 denoting the tip, -2
+ denoting the revision prior to the tip, and so forth.
+
+ A 40-digit hexadecimal string is treated as a unique revision identifier.
+
+ A hexadecimal string less than 40 characters long is treated as a unique
+ revision identifier and is referred to as a short-form identifier. A
+ short-form identifier is only valid if it is the prefix of exactly one
+ full-length identifier.
+
+ Any other string is treated as a bookmark, tag, or branch name. A bookmark
+ is a movable pointer to a revision. A tag is a permanent name associated
+ with a revision. A branch name denotes the tipmost revision of that
+ branch. Bookmark, tag, and branch names must not contain the ":"
+ character.
+
+ The reserved name "tip" always identifies the most recent revision.
+
+ The reserved name "null" indicates the null revision. This is the revision
+ of an empty repository, and the parent of revision 0.
+
+ The reserved name "." indicates the working directory parent. If no
+ working directory is checked out, it is equivalent to null. If an
+ uncommitted merge is in progress, "." is the revision of the first parent.
+
+Test templating help
+
+ $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
+ desc String. The text of the changeset description.
+ diffstat String. Statistics of changes with the following format:
+ firstline Any text. Returns the first line of text.
+ nonempty Any text. Returns '(none)' if the string is empty.
+
+Test help hooks
+
+ $ cat > helphook1.py <<EOF
+ > from mercurial import help
+ >
+ > def rewrite(topic, doc):
+ > return doc + '\nhelphook1\n'
+ >
+ > def extsetup(ui):
+ > help.addtopichook('revsets', rewrite)
+ > EOF
+ $ cat > helphook2.py <<EOF
+ > from mercurial import help
+ >
+ > def rewrite(topic, doc):
+ > return doc + '\nhelphook2\n'
+ >
+ > def extsetup(ui):
+ > help.addtopichook('revsets', rewrite)
+ > EOF
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
+ $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
+ $ hg help revsets | grep helphook
+ helphook1
+ helphook2
+
+Test keyword search help
+
+ $ hg help -k clone
+ Topics:
+
+ config Configuration Files
+ extensions Using Additional Features
+ glossary Glossary
+ phases Working with Phases
+ subrepos Subrepositories
+ urls URL Paths
+
+ Commands:
+
+ clone make a copy of an existing repository
+ paths show aliases for remote repositories
+ update update working directory (or switch revisions)
+
+ Extensions:
+
+ relink recreates hardlinks between repository clones
+
+ Extension Commands:
+
+ qclone clone main and patch repository at same time
+
diff --git a/tests/test-hg-parseurl.py b/tests/test-hg-parseurl.py
new file mode 100644
index 0000000..83c4832
--- /dev/null
+++ b/tests/test-hg-parseurl.py
@@ -0,0 +1,13 @@
+from mercurial.hg import parseurl
+
+def testparse(url, branch=[]):
+ print '%s, branches: %r' % parseurl(url, branch)
+
+testparse('http://example.com/no/anchor')
+testparse('http://example.com/an/anchor#foo')
+testparse('http://example.com/no/anchor/branches', branch=['foo'])
+testparse('http://example.com/an/anchor/branches#bar', branch=['foo'])
+testparse('http://example.com/an/anchor/branches-None#foo', branch=None)
+testparse('http://example.com/')
+testparse('http://example.com')
+testparse('http://example.com#foo')
diff --git a/tests/test-hg-parseurl.py.out b/tests/test-hg-parseurl.py.out
new file mode 100644
index 0000000..dd19f30
--- /dev/null
+++ b/tests/test-hg-parseurl.py.out
@@ -0,0 +1,8 @@
+http://example.com/no/anchor, branches: (None, [])
+http://example.com/an/anchor, branches: ('foo', [])
+http://example.com/no/anchor/branches, branches: (None, ['foo'])
+http://example.com/an/anchor/branches, branches: ('bar', ['foo'])
+http://example.com/an/anchor/branches-None, branches: ('foo', [])
+http://example.com/, branches: (None, [])
+http://example.com/, branches: (None, [])
+http://example.com/, branches: ('foo', [])
diff --git a/tests/test-hgcia.t b/tests/test-hgcia.t
new file mode 100644
index 0000000..10e9418
--- /dev/null
+++ b/tests/test-hgcia.t
@@ -0,0 +1,94 @@
+Test the CIA extension
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > hgcia=
+ >
+ > [hooks]
+ > changegroup.cia = python:hgext.hgcia.hook
+ >
+ > [web]
+ > baseurl = http://hgserver/
+ >
+ > [cia]
+ > user = testuser
+ > project = testproject
+ > test = True
+ > EOF
+
+ $ hg init src
+ $ hg init cia
+ $ cd src
+ $ echo foo > foo
+ $ hg ci -Amfoo
+ adding foo
+ $ hg push ../cia
+ pushing to ../cia
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+ <message>
+ <generator>
+ <name>Mercurial (hgcia)</name>
+ <version>0.1</version>
+ <url>http://hg.kublai.com/mercurial/hgcia</url>
+ <user>testuser</user>
+ </generator>
+ <source>
+ <project>testproject</project>
+ <branch>default</branch>
+ </source>
+ <body>
+ <commit>
+ <author>test</author>
+ <version>0:e63c23eaa88a</version>
+ <log>foo</log>
+ <url>http://hgserver/rev/e63c23eaa88a</url>
+ <files><file uri="http://hgserver/file/e63c23eaa88a/foo" action="add">foo</file></files>
+ </commit>
+ </body>
+ <timestamp>0</timestamp>
+ </message>
+
+ $ cat >> $HGRCPATH <<EOF
+ > strip = 0
+ > EOF
+
+ $ echo bar > bar
+ $ hg ci -Ambar
+ adding bar
+ $ hg push ../cia
+ pushing to ../cia
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+ <message>
+ <generator>
+ <name>Mercurial (hgcia)</name>
+ <version>0.1</version>
+ <url>http://hg.kublai.com/mercurial/hgcia</url>
+ <user>testuser</user>
+ </generator>
+ <source>
+ <project>testproject</project>
+ <branch>default</branch>
+ </source>
+ <body>
+ <commit>
+ <author>test</author>
+ <version>1:c0c7cf58edc5</version>
+ <log>bar</log>
+ <url>http://hgserver/$TESTTMP/cia/rev/c0c7cf58edc5</url>
+ <files><file uri="http://hgserver/$TESTTMP/cia/file/c0c7cf58edc5/bar" action="add">bar</file></files>
+ </commit>
+ </body>
+ <timestamp>0</timestamp>
+ </message>
+
+ $ cd ..
diff --git a/tests/test-hghave.t b/tests/test-hghave.t
new file mode 100644
index 0000000..a9af241
--- /dev/null
+++ b/tests/test-hghave.t
@@ -0,0 +1,3 @@
+Testing that hghave does not crash when checking features
+
+ $ "$TESTDIR/hghave" --test-features 2>/dev/null
diff --git a/tests/test-hgignore.t b/tests/test-hgignore.t
new file mode 100644
index 0000000..3b4a9aa
--- /dev/null
+++ b/tests/test-hgignore.t
@@ -0,0 +1,126 @@
+ $ hg init
+
+Issue562: .hgignore requires newline at end:
+
+ $ touch foo
+ $ touch bar
+ $ touch baz
+ $ cat > makeignore.py <<EOF
+ > f = open(".hgignore", "w")
+ > f.write("ignore\n")
+ > f.write("foo\n")
+ > # No EOL here
+ > f.write("bar")
+ > f.close()
+ > EOF
+
+ $ python makeignore.py
+
+Should display baz only:
+
+ $ hg status
+ ? baz
+
+ $ rm foo bar baz .hgignore makeignore.py
+
+ $ touch a.o
+ $ touch a.c
+ $ touch syntax
+ $ mkdir dir
+ $ touch dir/a.o
+ $ touch dir/b.o
+ $ touch dir/c.o
+
+ $ hg add dir/a.o
+ $ hg commit -m 0
+ $ hg add dir/b.o
+
+ $ hg status
+ A dir/b.o
+ ? a.c
+ ? a.o
+ ? dir/c.o
+ ? syntax
+
+ $ echo "*.o" > .hgignore
+ $ hg status
+ abort: $TESTTMP/.hgignore: invalid pattern (relre): *.o (glob)
+ [255]
+
+ $ echo ".*\.o" > .hgignore
+ $ hg status
+ A dir/b.o
+ ? .hgignore
+ ? a.c
+ ? syntax
+
+Check it does not ignore the current directory '.':
+
+ $ echo "^\." > .hgignore
+ $ hg status
+ A dir/b.o
+ ? a.c
+ ? a.o
+ ? dir/c.o
+ ? syntax
+
+ $ echo "glob:**.o" > .hgignore
+ $ hg status
+ A dir/b.o
+ ? .hgignore
+ ? a.c
+ ? syntax
+
+ $ echo "glob:*.o" > .hgignore
+ $ hg status
+ A dir/b.o
+ ? .hgignore
+ ? a.c
+ ? syntax
+
+ $ echo "syntax: glob" > .hgignore
+ $ echo "re:.*\.o" >> .hgignore
+ $ hg status
+ A dir/b.o
+ ? .hgignore
+ ? a.c
+ ? syntax
+
+ $ echo "syntax: invalid" > .hgignore
+ $ hg status
+ $TESTTMP/.hgignore: ignoring invalid syntax 'invalid' (glob)
+ A dir/b.o
+ ? .hgignore
+ ? a.c
+ ? a.o
+ ? dir/c.o
+ ? syntax
+
+ $ echo "syntax: glob" > .hgignore
+ $ echo "*.o" >> .hgignore
+ $ hg status
+ A dir/b.o
+ ? .hgignore
+ ? a.c
+ ? syntax
+
+ $ echo "relglob:syntax*" > .hgignore
+ $ hg status
+ A dir/b.o
+ ? .hgignore
+ ? a.c
+ ? a.o
+ ? dir/c.o
+
+ $ echo "relglob:*" > .hgignore
+ $ hg status
+ A dir/b.o
+
+ $ cd dir
+ $ hg status .
+ A b.o
+
+ $ hg debugignore
+ (?:(?:|.*/)[^/]*(?:/|$))
+
+ $ cd ..
diff --git a/tests/test-hgk.t b/tests/test-hgk.t
new file mode 100644
index 0000000..acdbd06
--- /dev/null
+++ b/tests/test-hgk.t
@@ -0,0 +1,20 @@
+Minimal hgk check
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "hgk=" >> $HGRCPATH
+ $ hg init repo
+ $ cd repo
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ hg debug-cat-file commit 0
+ tree a0c8bcbbb45c
+ parent 000000000000
+ author test 0 0
+ committer test 0 0
+ revision 0
+ branch default
+
+ adda
+
+ $ cd ..
diff --git a/tests/test-hgrc.t b/tests/test-hgrc.t
new file mode 100644
index 0000000..65434ac
--- /dev/null
+++ b/tests/test-hgrc.t
@@ -0,0 +1,203 @@
+hide outer repo
+ $ hg init
+
+Use hgrc within $TESTTMP
+
+ $ HGRCPATH=`pwd`/hgrc
+ $ export HGRCPATH
+
+Use an alternate var for scribbling on hgrc to keep check-code from
+complaining about the important settings we may be overwriting:
+
+ $ HGRC=`pwd`/hgrc
+ $ export HGRC
+
+Basic syntax error
+
+ $ echo "invalid" > $HGRC
+ $ hg version
+ hg: parse error at $TESTTMP/hgrc:1: invalid
+ [255]
+ $ echo "" > $HGRC
+
+Issue1199: Can't use '%' in hgrc (eg url encoded username)
+
+ $ hg init "foo%bar"
+ $ hg clone "foo%bar" foobar
+ updating to branch default
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd foobar
+ $ cat .hg/hgrc
+ [paths]
+ default = $TESTTMP/foo%bar (glob)
+ $ hg paths
+ default = $TESTTMP/foo%bar (glob)
+ $ hg showconfig
+ bundle.mainreporoot=$TESTTMP/foobar (glob)
+ paths.default=$TESTTMP/foo%bar (glob)
+ $ cd ..
+
+issue1829: wrong indentation
+
+ $ echo '[foo]' > $HGRC
+ $ echo ' x = y' >> $HGRC
+ $ hg version
+ hg: parse error at $TESTTMP/hgrc:2: x = y
+ [255]
+
+ $ python -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
+ > > $HGRC
+ $ hg showconfig foo
+ foo.bar=a\nb\nc\nde\nfg
+ foo.baz=bif cb
+
+ $ FAKEPATH=/path/to/nowhere
+ $ export FAKEPATH
+ $ echo '%include $FAKEPATH/no-such-file' > $HGRC
+ $ hg version
+ Mercurial Distributed SCM (version *) (glob)
+ (see http://mercurial.selenic.com for more information)
+
+ Copyright (C) 2005-2012 Matt Mackall and others
+ This is free software; see the source for copying conditions. There is NO
+ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ $ unset FAKEPATH
+
+make sure global options given on the cmdline take precedence
+
+ $ hg showconfig --config ui.verbose=True --quiet
+ bundle.mainreporoot=$TESTTMP
+ ui.verbose=False
+ ui.debug=False
+ ui.quiet=True
+
+ $ touch foobar/untracked
+ $ cat >> foobar/.hg/hgrc <<EOF
+ > [ui]
+ > verbose=True
+ > EOF
+ $ hg -R foobar st -q
+
+username expansion
+
+ $ olduser=$HGUSER
+ $ unset HGUSER
+
+ $ FAKEUSER='John Doe'
+ $ export FAKEUSER
+ $ echo '[ui]' > $HGRC
+ $ echo 'username = $FAKEUSER' >> $HGRC
+
+ $ hg init usertest
+ $ cd usertest
+ $ touch bar
+ $ hg commit --addremove --quiet -m "added bar"
+ $ hg log --template "{author}\n"
+ John Doe
+ $ cd ..
+
+ $ hg showconfig
+ bundle.mainreporoot=$TESTTMP
+ ui.username=$FAKEUSER
+
+ $ unset FAKEUSER
+ $ HGUSER=$olduser
+ $ export HGUSER
+
+showconfig with multiple arguments
+
+ $ echo "[alias]" > $HGRC
+ $ echo "log = log -g" >> $HGRC
+ $ echo "[defaults]" >> $HGRC
+ $ echo "identify = -n" >> $HGRC
+ $ hg showconfig alias defaults
+ alias.log=log -g
+ defaults.identify=-n
+ $ hg showconfig alias defaults.identify
+ abort: only one config item permitted
+ [255]
+ $ hg showconfig alias.log defaults.identify
+ abort: only one config item permitted
+ [255]
+
+HGPLAIN
+
+ $ echo "[ui]" > $HGRC
+ $ echo "debug=true" >> $HGRC
+ $ echo "fallbackencoding=ASCII" >> $HGRC
+ $ echo "quiet=true" >> $HGRC
+ $ echo "slash=true" >> $HGRC
+ $ echo "traceback=true" >> $HGRC
+ $ echo "verbose=true" >> $HGRC
+ $ echo "style=~/.hgstyle" >> $HGRC
+ $ echo "logtemplate={node}" >> $HGRC
+ $ echo "[defaults]" >> $HGRC
+ $ echo "identify=-n" >> $HGRC
+ $ echo "[alias]" >> $HGRC
+ $ echo "log=log -g" >> $HGRC
+
+customized hgrc
+
+ $ hg showconfig
+ read config from: $TESTTMP/hgrc
+ $TESTTMP/hgrc:13: alias.log=log -g
+ none: bundle.mainreporoot=$TESTTMP
+ $TESTTMP/hgrc:11: defaults.identify=-n
+ $TESTTMP/hgrc:2: ui.debug=true
+ $TESTTMP/hgrc:3: ui.fallbackencoding=ASCII
+ $TESTTMP/hgrc:4: ui.quiet=true
+ $TESTTMP/hgrc:5: ui.slash=true
+ $TESTTMP/hgrc:6: ui.traceback=true
+ $TESTTMP/hgrc:7: ui.verbose=true
+ $TESTTMP/hgrc:8: ui.style=~/.hgstyle
+ $TESTTMP/hgrc:9: ui.logtemplate={node}
+
+plain hgrc
+
+ $ HGPLAIN=; export HGPLAIN
+ $ hg showconfig --config ui.traceback=True --debug
+ read config from: $TESTTMP/hgrc
+ none: bundle.mainreporoot=$TESTTMP
+ none: ui.traceback=True
+ none: ui.verbose=False
+ none: ui.debug=True
+ none: ui.quiet=False
+
+plain mode with exceptions
+
+ $ cat > plain.py <<EOF
+ > def uisetup(ui):
+ > ui.write('plain: %r\n' % ui.plain())
+ > EOF
+ $ echo "[extensions]" >> $HGRC
+ $ echo "plain=./plain.py" >> $HGRC
+ $ HGPLAINEXCEPT=; export HGPLAINEXCEPT
+ $ hg showconfig --config ui.traceback=True --debug
+ plain: True
+ read config from: $TESTTMP/hgrc
+ none: bundle.mainreporoot=$TESTTMP
+ $TESTTMP/hgrc:15: extensions.plain=./plain.py
+ none: ui.traceback=True
+ none: ui.verbose=False
+ none: ui.debug=True
+ none: ui.quiet=False
+ $ unset HGPLAIN
+ $ hg showconfig --config ui.traceback=True --debug
+ plain: True
+ read config from: $TESTTMP/hgrc
+ none: bundle.mainreporoot=$TESTTMP
+ $TESTTMP/hgrc:15: extensions.plain=./plain.py
+ none: ui.traceback=True
+ none: ui.verbose=False
+ none: ui.debug=True
+ none: ui.quiet=False
+ $ HGPLAINEXCEPT=i18n; export HGPLAINEXCEPT
+ $ hg showconfig --config ui.traceback=True --debug
+ plain: True
+ read config from: $TESTTMP/hgrc
+ none: bundle.mainreporoot=$TESTTMP
+ $TESTTMP/hgrc:15: extensions.plain=./plain.py
+ none: ui.traceback=True
+ none: ui.verbose=False
+ none: ui.debug=True
+ none: ui.quiet=False
diff --git a/tests/test-hgweb-auth.py b/tests/test-hgweb-auth.py
new file mode 100644
index 0000000..8b1f78a
--- /dev/null
+++ b/tests/test-hgweb-auth.py
@@ -0,0 +1,107 @@
+from mercurial import demandimport; demandimport.enable()
+import urllib2
+from mercurial import ui, util
+from mercurial import url
+from mercurial.error import Abort
+
+class myui(ui.ui):
+ def interactive(self):
+ return False
+
+origui = myui()
+
+def writeauth(items):
+ ui = origui.copy()
+ for name, value in items.iteritems():
+ ui.setconfig('auth', name, value)
+ return ui
+
+def dumpdict(dict):
+ return '{' + ', '.join(['%s: %s' % (k, dict[k])
+ for k in sorted(dict.iterkeys())]) + '}'
+
+def test(auth, urls=None):
+ print 'CFG:', dumpdict(auth)
+ prefixes = set()
+ for k in auth:
+ prefixes.add(k.split('.', 1)[0])
+ for p in prefixes:
+ for name in ('.username', '.password'):
+ if (p + name) not in auth:
+ auth[p + name] = p
+ auth = dict((k, v) for k, v in auth.iteritems() if v is not None)
+
+ ui = writeauth(auth)
+
+ def _test(uri):
+ print 'URI:', uri
+ try:
+ pm = url.passwordmgr(ui)
+ u, authinfo = util.url(uri).authinfo()
+ if authinfo is not None:
+ pm.add_password(*authinfo)
+ print ' ', pm.find_user_password('test', u)
+ except Abort, e:
+ print 'abort'
+
+ if not urls:
+ urls = [
+ 'http://example.org/foo',
+ 'http://example.org/foo/bar',
+ 'http://example.org/bar',
+ 'https://example.org/foo',
+ 'https://example.org/foo/bar',
+ 'https://example.org/bar',
+ 'https://x@example.org/bar',
+ 'https://y@example.org/bar',
+ ]
+ for u in urls:
+ _test(u)
+
+
+print '\n*** Test in-uri schemes\n'
+test({'x.prefix': 'http://example.org'})
+test({'x.prefix': 'https://example.org'})
+test({'x.prefix': 'http://example.org', 'x.schemes': 'https'})
+test({'x.prefix': 'https://example.org', 'x.schemes': 'http'})
+
+print '\n*** Test separately configured schemes\n'
+test({'x.prefix': 'example.org', 'x.schemes': 'http'})
+test({'x.prefix': 'example.org', 'x.schemes': 'https'})
+test({'x.prefix': 'example.org', 'x.schemes': 'http https'})
+
+print '\n*** Test prefix matching\n'
+test({'x.prefix': 'http://example.org/foo',
+ 'y.prefix': 'http://example.org/bar'})
+test({'x.prefix': 'http://example.org/foo',
+ 'y.prefix': 'http://example.org/foo/bar'})
+test({'x.prefix': '*', 'y.prefix': 'https://example.org/bar'})
+
+print '\n*** Test user matching\n'
+test({'x.prefix': 'http://example.org/foo',
+ 'x.username': None,
+ 'x.password': 'xpassword'},
+ urls=['http://y@example.org/foo'])
+test({'x.prefix': 'http://example.org/foo',
+ 'x.username': None,
+ 'x.password': 'xpassword',
+ 'y.prefix': 'http://example.org/foo',
+ 'y.username': 'y',
+ 'y.password': 'ypassword'},
+ urls=['http://y@example.org/foo'])
+test({'x.prefix': 'http://example.org/foo/bar',
+ 'x.username': None,
+ 'x.password': 'xpassword',
+ 'y.prefix': 'http://example.org/foo',
+ 'y.username': 'y',
+ 'y.password': 'ypassword'},
+ urls=['http://y@example.org/foo/bar'])
+
+def testauthinfo(fullurl, authurl):
+ print 'URIs:', fullurl, authurl
+ pm = urllib2.HTTPPasswordMgrWithDefaultRealm()
+ pm.add_password(*util.url(fullurl).authinfo()[1])
+ print pm.find_user_password('test', authurl)
+
+print '\n*** Test urllib2 and util.url\n'
+testauthinfo('http://user@example.com:8080/foo', 'http://example.com:8080/foo')
diff --git a/tests/test-hgweb-auth.py.out b/tests/test-hgweb-auth.py.out
new file mode 100644
index 0000000..f82bb3e
--- /dev/null
+++ b/tests/test-hgweb-auth.py.out
@@ -0,0 +1,196 @@
+
+*** Test in-uri schemes
+
+CFG: {x.prefix: http://example.org}
+URI: http://example.org/foo
+ ('x', 'x')
+URI: http://example.org/foo/bar
+ ('x', 'x')
+URI: http://example.org/bar
+ ('x', 'x')
+URI: https://example.org/foo
+ abort
+URI: https://example.org/foo/bar
+ abort
+URI: https://example.org/bar
+ abort
+URI: https://x@example.org/bar
+ abort
+URI: https://y@example.org/bar
+ abort
+CFG: {x.prefix: https://example.org}
+URI: http://example.org/foo
+ abort
+URI: http://example.org/foo/bar
+ abort
+URI: http://example.org/bar
+ abort
+URI: https://example.org/foo
+ ('x', 'x')
+URI: https://example.org/foo/bar
+ ('x', 'x')
+URI: https://example.org/bar
+ ('x', 'x')
+URI: https://x@example.org/bar
+ ('x', 'x')
+URI: https://y@example.org/bar
+ abort
+CFG: {x.prefix: http://example.org, x.schemes: https}
+URI: http://example.org/foo
+ ('x', 'x')
+URI: http://example.org/foo/bar
+ ('x', 'x')
+URI: http://example.org/bar
+ ('x', 'x')
+URI: https://example.org/foo
+ abort
+URI: https://example.org/foo/bar
+ abort
+URI: https://example.org/bar
+ abort
+URI: https://x@example.org/bar
+ abort
+URI: https://y@example.org/bar
+ abort
+CFG: {x.prefix: https://example.org, x.schemes: http}
+URI: http://example.org/foo
+ abort
+URI: http://example.org/foo/bar
+ abort
+URI: http://example.org/bar
+ abort
+URI: https://example.org/foo
+ ('x', 'x')
+URI: https://example.org/foo/bar
+ ('x', 'x')
+URI: https://example.org/bar
+ ('x', 'x')
+URI: https://x@example.org/bar
+ ('x', 'x')
+URI: https://y@example.org/bar
+ abort
+
+*** Test separately configured schemes
+
+CFG: {x.prefix: example.org, x.schemes: http}
+URI: http://example.org/foo
+ ('x', 'x')
+URI: http://example.org/foo/bar
+ ('x', 'x')
+URI: http://example.org/bar
+ ('x', 'x')
+URI: https://example.org/foo
+ abort
+URI: https://example.org/foo/bar
+ abort
+URI: https://example.org/bar
+ abort
+URI: https://x@example.org/bar
+ abort
+URI: https://y@example.org/bar
+ abort
+CFG: {x.prefix: example.org, x.schemes: https}
+URI: http://example.org/foo
+ abort
+URI: http://example.org/foo/bar
+ abort
+URI: http://example.org/bar
+ abort
+URI: https://example.org/foo
+ ('x', 'x')
+URI: https://example.org/foo/bar
+ ('x', 'x')
+URI: https://example.org/bar
+ ('x', 'x')
+URI: https://x@example.org/bar
+ ('x', 'x')
+URI: https://y@example.org/bar
+ abort
+CFG: {x.prefix: example.org, x.schemes: http https}
+URI: http://example.org/foo
+ ('x', 'x')
+URI: http://example.org/foo/bar
+ ('x', 'x')
+URI: http://example.org/bar
+ ('x', 'x')
+URI: https://example.org/foo
+ ('x', 'x')
+URI: https://example.org/foo/bar
+ ('x', 'x')
+URI: https://example.org/bar
+ ('x', 'x')
+URI: https://x@example.org/bar
+ ('x', 'x')
+URI: https://y@example.org/bar
+ abort
+
+*** Test prefix matching
+
+CFG: {x.prefix: http://example.org/foo, y.prefix: http://example.org/bar}
+URI: http://example.org/foo
+ ('x', 'x')
+URI: http://example.org/foo/bar
+ ('x', 'x')
+URI: http://example.org/bar
+ ('y', 'y')
+URI: https://example.org/foo
+ abort
+URI: https://example.org/foo/bar
+ abort
+URI: https://example.org/bar
+ abort
+URI: https://x@example.org/bar
+ abort
+URI: https://y@example.org/bar
+ abort
+CFG: {x.prefix: http://example.org/foo, y.prefix: http://example.org/foo/bar}
+URI: http://example.org/foo
+ ('x', 'x')
+URI: http://example.org/foo/bar
+ ('y', 'y')
+URI: http://example.org/bar
+ abort
+URI: https://example.org/foo
+ abort
+URI: https://example.org/foo/bar
+ abort
+URI: https://example.org/bar
+ abort
+URI: https://x@example.org/bar
+ abort
+URI: https://y@example.org/bar
+ abort
+CFG: {x.prefix: *, y.prefix: https://example.org/bar}
+URI: http://example.org/foo
+ abort
+URI: http://example.org/foo/bar
+ abort
+URI: http://example.org/bar
+ abort
+URI: https://example.org/foo
+ ('x', 'x')
+URI: https://example.org/foo/bar
+ ('x', 'x')
+URI: https://example.org/bar
+ ('y', 'y')
+URI: https://x@example.org/bar
+ ('x', 'x')
+URI: https://y@example.org/bar
+ ('y', 'y')
+
+*** Test user matching
+
+CFG: {x.password: xpassword, x.prefix: http://example.org/foo, x.username: None}
+URI: http://y@example.org/foo
+ ('y', 'xpassword')
+CFG: {x.password: xpassword, x.prefix: http://example.org/foo, x.username: None, y.password: ypassword, y.prefix: http://example.org/foo, y.username: y}
+URI: http://y@example.org/foo
+ ('y', 'ypassword')
+CFG: {x.password: xpassword, x.prefix: http://example.org/foo/bar, x.username: None, y.password: ypassword, y.prefix: http://example.org/foo, y.username: y}
+URI: http://y@example.org/foo/bar
+ ('y', 'xpassword')
+
+*** Test urllib2 and util.url
+
+URIs: http://user@example.com:8080/foo http://example.com:8080/foo
+('user', '')
diff --git a/tests/test-hgweb-commands.t b/tests/test-hgweb-commands.t
new file mode 100644
index 0000000..acf337e
--- /dev/null
+++ b/tests/test-hgweb-commands.t
@@ -0,0 +1,1363 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+An attempt at more fully testing the hgweb web interface.
+The following things are tested elsewhere and are therefore omitted:
+- archive, tested in test-archive
+- unbundle, tested in test-push-http
+- changegroupsubset, tested in test-pull
+
+Set up the repo
+
+ $ hg init test
+ $ cd test
+ $ mkdir da
+ $ echo foo > da/foo
+ $ echo foo > foo
+ $ hg ci -Ambase
+ adding da/foo
+ adding foo
+ $ hg tag 1.0
+ $ hg bookmark something
+ $ hg bookmark -r0 anotherthing
+ $ echo another > foo
+ $ hg branch stable
+ marked working directory as branch stable
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Ambranch
+ $ hg branch unstable
+ marked working directory as branch unstable
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Ambranch
+ $ echo [graph] >> .hg/hgrc
+ $ echo default.width = 3 >> .hg/hgrc
+ $ echo stable.width = 3 >> .hg/hgrc
+ $ echo stable.color = FF0000 >> .hg/hgrc
+ $ hg serve --config server.uncompressed=False -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg log -G --template '{rev}:{node|short} {desc}\n'
+ @ 3:ba87b23d29ca branch
+ |
+ o 2:1d22e65f027e branch
+ |
+ o 1:a4f92ed23982 Added tag 1.0 for changeset 2ef0ac749a14
+ |
+ o 0:2ef0ac749a14 base
+
+
+Logs and changes
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log/?style=atom'
+ 200 Script output follows
+
+ <?xml version="1.0" encoding="ascii"?>
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <!-- Changelog -->
+ <id>http://*:$HGPORT/</id> (glob)
+ <link rel="self" href="http://*:$HGPORT/atom-log"/> (glob)
+ <link rel="alternate" href="http://*:$HGPORT/"/> (glob)
+ <title>test Changelog</title>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+
+ <entry>
+ <title>branch</title>
+ <id>http://*:$HGPORT/#changeset-ba87b23d29ca67a305625d81a20ac279c1e3f444</id> (glob)
+ <link href="http://*:$HGPORT/rev/ba87b23d29ca"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">branch</pre>
+ </div>
+ </content>
+ </entry>
+ <entry>
+ <title>branch</title>
+ <id>http://*:$HGPORT/#changeset-1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe</id> (glob)
+ <link href="http://*:$HGPORT/rev/1d22e65f027e"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">branch</pre>
+ </div>
+ </content>
+ </entry>
+ <entry>
+ <title>Added tag 1.0 for changeset 2ef0ac749a14</title>
+ <id>http://*:$HGPORT/#changeset-a4f92ed23982be056b9852de5dfe873eaac7f0de</id> (glob)
+ <link href="http://*:$HGPORT/rev/a4f92ed23982"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">Added tag 1.0 for changeset 2ef0ac749a14</pre>
+ </div>
+ </content>
+ </entry>
+ <entry>
+ <title>base</title>
+ <id>http://*:$HGPORT/#changeset-2ef0ac749a14e4f57a5a822464a0902c6f7f448f</id> (glob)
+ <link href="http://*:$HGPORT/rev/2ef0ac749a14"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">base</pre>
+ </div>
+ </content>
+ </entry>
+
+ </feed>
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log/1/?style=atom'
+ 200 Script output follows
+
+ <?xml version="1.0" encoding="ascii"?>
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <!-- Changelog -->
+ <id>http://*:$HGPORT/</id> (glob)
+ <link rel="self" href="http://*:$HGPORT/atom-log"/> (glob)
+ <link rel="alternate" href="http://*:$HGPORT/"/> (glob)
+ <title>test Changelog</title>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+
+ <entry>
+ <title>branch</title>
+ <id>http://*:$HGPORT/#changeset-ba87b23d29ca67a305625d81a20ac279c1e3f444</id> (glob)
+ <link href="http://*:$HGPORT/rev/ba87b23d29ca"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">branch</pre>
+ </div>
+ </content>
+ </entry>
+ <entry>
+ <title>branch</title>
+ <id>http://*:$HGPORT/#changeset-1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe</id> (glob)
+ <link href="http://*:$HGPORT/rev/1d22e65f027e"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">branch</pre>
+ </div>
+ </content>
+ </entry>
+ <entry>
+ <title>Added tag 1.0 for changeset 2ef0ac749a14</title>
+ <id>http://*:$HGPORT/#changeset-a4f92ed23982be056b9852de5dfe873eaac7f0de</id> (glob)
+ <link href="http://*:$HGPORT/rev/a4f92ed23982"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">Added tag 1.0 for changeset 2ef0ac749a14</pre>
+ </div>
+ </content>
+ </entry>
+ <entry>
+ <title>base</title>
+ <id>http://*:$HGPORT/#changeset-2ef0ac749a14e4f57a5a822464a0902c6f7f448f</id> (glob)
+ <link href="http://*:$HGPORT/rev/2ef0ac749a14"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">base</pre>
+ </div>
+ </content>
+ </entry>
+
+ </feed>
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log/1/foo/?style=atom'
+ 200 Script output follows
+
+ <?xml version="1.0" encoding="ascii"?>
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <id>http://*:$HGPORT/atom-log/tip/foo</id> (glob)
+ <link rel="self" href="http://*:$HGPORT/atom-log/tip/foo"/> (glob)
+ <title>test: foo history</title>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+
+ <entry>
+ <title>base</title>
+ <id>http://*:$HGPORT/#changeset-2ef0ac749a14e4f57a5a822464a0902c6f7f448f</id> (glob)
+ <link href="http://*:$HGPORT/rev/2ef0ac749a14"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">base</pre>
+ </div>
+ </content>
+ </entry>
+
+ </feed>
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'shortlog/'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: log</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log" title="Atom feed for test" />
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log" title="RSS feed for test" />
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li class="active">log</li>
+ <li><a href="/graph/ba87b23d29ca">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/ba87b23d29ca">changeset</a></li>
+ <li><a href="/file/ba87b23d29ca">browse</a></li>
+ </ul>
+ <ul>
+
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>log</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="navigate">
+ <a href="/shortlog/3?revcount=30">less</a>
+ <a href="/shortlog/3?revcount=120">more</a>
+ | rev 3: <a href="/shortlog/2ef0ac749a14">(0)</a> <a href="/shortlog/tip">tip</a>
+ </div>
+
+ <table class="bigtable">
+ <tr>
+ <th class="age">age</th>
+ <th class="author">author</th>
+ <th class="description">description</th>
+ </tr>
+ <tr class="parity0">
+ <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ <td class="author">test</td>
+ <td class="description"><a href="/rev/ba87b23d29ca">branch</a><span class="branchhead">unstable</span> <span class="tag">tip</span> <span class="tag">something</span> </td>
+ </tr>
+ <tr class="parity1">
+ <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ <td class="author">test</td>
+ <td class="description"><a href="/rev/1d22e65f027e">branch</a><span class="branchhead">stable</span> </td>
+ </tr>
+ <tr class="parity0">
+ <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ <td class="author">test</td>
+ <td class="description"><a href="/rev/a4f92ed23982">Added tag 1.0 for changeset 2ef0ac749a14</a><span class="branchhead">default</span> </td>
+ </tr>
+ <tr class="parity1">
+ <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ <td class="author">test</td>
+ <td class="description"><a href="/rev/2ef0ac749a14">base</a><span class="tag">1.0</span> <span class="tag">anotherthing</span> </td>
+ </tr>
+
+ </table>
+
+ <div class="navigate">
+ <a href="/shortlog/3?revcount=30">less</a>
+ <a href="/shortlog/3?revcount=120">more</a>
+ | rev 3: <a href="/shortlog/2ef0ac749a14">(0)</a> <a href="/shortlog/tip">tip</a>
+ </div>
+
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'rev/0/'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: 2ef0ac749a14</title>
+ </head>
+ <body>
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/2ef0ac749a14">log</a></li>
+ <li><a href="/graph/2ef0ac749a14">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li class="active">changeset</li>
+ <li><a href="/raw-rev/2ef0ac749a14">raw</a></li>
+ <li><a href="/file/2ef0ac749a14">browse</a></li>
+ </ul>
+ <ul>
+
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+
+ <h2><a href="/">test</a></h2>
+ <h3>changeset 0:2ef0ac749a14 <span class="tag">1.0</span> <span class="tag">anotherthing</span> </h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">base</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th class="author">author</th>
+ <td class="author">&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th class="date">date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
+ <tr>
+ <th class="author">parents</th>
+ <td class="author"></td>
+ </tr>
+ <tr>
+ <th class="author">children</th>
+ <td class="author"> <a href="/rev/a4f92ed23982">a4f92ed23982</a></td>
+ </tr>
+ <tr>
+ <th class="files">files</th>
+ <td class="files"><a href="/file/2ef0ac749a14/da/foo">da/foo</a> <a href="/file/2ef0ac749a14/foo">foo</a> </td>
+ </tr>
+ <tr>
+ <th class="diffstat">diffstat</th>
+ <td class="diffstat">
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+
+ <a id="diffstatexpand" href="javascript:showDiffstat()"/>[<tt>+</tt>]</a>
+ <div id="diffstatdetails" style="display:none;">
+ <a href="javascript:hideDiffstat()"/>[<tt>-</tt>]</a>
+ <p>
+ <table> <tr class="parity0">
+ <td class="diffstat-file"><a href="#l1.1">da/foo</a></td>
+ <td class="diffstat-total" align="right">1</td>
+ <td class="diffstat-graph">
+ <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
+ <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
+ </td>
+ </tr>
+ <tr class="parity1">
+ <td class="diffstat-file"><a href="#l2.1">foo</a></td>
+ <td class="diffstat-total" align="right">1</td>
+ <td class="diffstat-graph">
+ <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
+ <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> line diff</div>
+
+ <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ b/da/foo Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -0,0 +1,1 @@
+ </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="plusline">+foo
+ </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l2.2" id="l2.2"> 2.2</a> <span class="plusline">+++ b/foo Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="atline">@@ -0,0 +1,1 @@
+ </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="plusline">+foo
+ </span></pre></div>
+ </div>
+
+ </div>
+ </div>
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'rev/1/?style=raw'
+ 200 Script output follows
+
+
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Node ID a4f92ed23982be056b9852de5dfe873eaac7f0de
+ # Parent 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
+ Added tag 1.0 for changeset 2ef0ac749a14
+
+ diff -r 2ef0ac749a14 -r a4f92ed23982 .hgtags
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +2ef0ac749a14e4f57a5a822464a0902c6f7f448f 1.0
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=base'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: searching for base</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog">log</a></li>
+ <li><a href="/graph">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>searching for 'base'</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30"></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="navigate">
+ <a href="/search/?rev=base&revcount=5">less</a>
+ <a href="/search/?rev=base&revcount=20">more</a>
+ </div>
+
+ <table class="bigtable">
+ <tr>
+ <th class="age">age</th>
+ <th class="author">author</th>
+ <th class="description">description</th>
+ </tr>
+ <tr class="parity0">
+ <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ <td class="author">test</td>
+ <td class="description"><a href="/rev/2ef0ac749a14">base</a><span class="tag">1.0</span> <span class="tag">anotherthing</span> </td>
+ </tr>
+
+ </table>
+
+ <div class="navigate">
+ <a href="/search/?rev=base&revcount=5">less</a>
+ <a href="/search/?rev=base&revcount=20">more</a>
+ </div>
+
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+File-related
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/1/foo/?style=raw'
+ 200 Script output follows
+
+ foo
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'annotate/1/foo/?style=raw'
+ 200 Script output follows
+
+
+ test@0: foo
+
+
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/1/?style=raw'
+ 200 Script output follows
+
+
+ drwxr-xr-x da
+ -rw-r--r-- 45 .hgtags
+ -rw-r--r-- 4 foo
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/1/foo'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: a4f92ed23982 foo</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/a4f92ed23982">log</a></li>
+ <li><a href="/graph/a4f92ed23982">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/a4f92ed23982">changeset</a></li>
+ <li><a href="/file/a4f92ed23982/">browse</a></li>
+ </ul>
+ <ul>
+ <li class="active">file</li>
+ <li><a href="/file/tip/foo">latest</a></li>
+ <li><a href="/diff/a4f92ed23982/foo">diff</a></li>
+ <li><a href="/comparison/a4f92ed23982/foo">comparison</a></li>
+ <li><a href="/annotate/a4f92ed23982/foo">annotate</a></li>
+ <li><a href="/log/a4f92ed23982/foo">file log</a></li>
+ <li><a href="/raw-file/a4f92ed23982/foo">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>view foo @ 1:a4f92ed23982</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">Added tag 1.0 for changeset 2ef0ac749a14</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th class="author">author</th>
+ <td class="author">&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th class="date">date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ </tr>
+ <tr>
+ <th class="author">parents</th>
+ <td class="author"></td>
+ </tr>
+ <tr>
+ <th class="author">children</th>
+ <td class="author"><a href="/file/1d22e65f027e/foo">1d22e65f027e</a> </td>
+ </tr>
+
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> line source</div>
+
+ <div class="parity0 source"><a href="#l1" id="l1"> 1</a> foo
+ </div>
+ <div class="sourcelast"></div>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'filediff/0/foo/?style=raw'
+ 200 Script output follows
+
+
+ diff -r 000000000000 -r 2ef0ac749a14 foo
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/foo Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +foo
+
+
+
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'filediff/1/foo/?style=raw'
+ 200 Script output follows
+
+
+
+
+
+
+
+Overviews
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'raw-tags'
+ 200 Script output follows
+
+ tip ba87b23d29ca67a305625d81a20ac279c1e3f444
+ 1.0 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'raw-branches'
+ 200 Script output follows
+
+ unstable ba87b23d29ca67a305625d81a20ac279c1e3f444 open
+ stable 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe inactive
+ default a4f92ed23982be056b9852de5dfe873eaac7f0de inactive
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'raw-bookmarks'
+ 200 Script output follows
+
+ anotherthing 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
+ something ba87b23d29ca67a305625d81a20ac279c1e3f444
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'summary/?style=gitweb'
+ 200 Script output follows
+
+ <?xml version="1.0" encoding="ascii"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow"/>
+ <link rel="stylesheet" href="/static/style-gitweb.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: Summary</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log" title="Atom feed for test"/>
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log" title="RSS feed for test"/>
+ </head>
+ <body>
+
+ <div class="page_header">
+ <a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="/summary?style=gitweb">test</a> / summary
+
+ <form action="/log">
+ <input type="hidden" name="style" value="gitweb" />
+ <div class="search">
+ <input type="text" name="rev" />
+ </div>
+ </form>
+ </div>
+
+ <div class="page_nav">
+ summary |
+ <a href="/shortlog?style=gitweb">shortlog</a> |
+ <a href="/log?style=gitweb">changelog</a> |
+ <a href="/graph?style=gitweb">graph</a> |
+ <a href="/tags?style=gitweb">tags</a> |
+ <a href="/bookmarks?style=gitweb">bookmarks</a> |
+ <a href="/branches?style=gitweb">branches</a> |
+ <a href="/file/ba87b23d29ca?style=gitweb">files</a> |
+ <a href="/help?style=gitweb">help</a>
+ <br/>
+ </div>
+
+ <div class="title">&nbsp;</div>
+ <table cellspacing="0">
+ <tr><td>description</td><td>unknown</td></tr>
+ <tr><td>owner</td><td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td></tr>
+ <tr><td>last change</td><td>Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
+ </table>
+
+ <div><a class="title" href="/shortlog?style=gitweb">changes</a></div>
+ <table cellspacing="0">
+
+ <tr class="parity0">
+ <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+ <td><i>test</i></td>
+ <td>
+ <a class="list" href="/rev/ba87b23d29ca?style=gitweb">
+ <b>branch</b>
+ <span class="logtags"><span class="branchtag" title="unstable">unstable</span> <span class="tagtag" title="tip">tip</span> <span class="bookmarktag" title="something">something</span> </span>
+ </a>
+ </td>
+ <td class="link" nowrap>
+ <a href="/rev/ba87b23d29ca?style=gitweb">changeset</a> |
+ <a href="/file/ba87b23d29ca?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="parity1">
+ <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+ <td><i>test</i></td>
+ <td>
+ <a class="list" href="/rev/1d22e65f027e?style=gitweb">
+ <b>branch</b>
+ <span class="logtags"><span class="branchtag" title="stable">stable</span> </span>
+ </a>
+ </td>
+ <td class="link" nowrap>
+ <a href="/rev/1d22e65f027e?style=gitweb">changeset</a> |
+ <a href="/file/1d22e65f027e?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="parity0">
+ <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+ <td><i>test</i></td>
+ <td>
+ <a class="list" href="/rev/a4f92ed23982?style=gitweb">
+ <b>Added tag 1.0 for changeset 2ef0ac749a14</b>
+ <span class="logtags"><span class="branchtag" title="default">default</span> </span>
+ </a>
+ </td>
+ <td class="link" nowrap>
+ <a href="/rev/a4f92ed23982?style=gitweb">changeset</a> |
+ <a href="/file/a4f92ed23982?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="parity1">
+ <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+ <td><i>test</i></td>
+ <td>
+ <a class="list" href="/rev/2ef0ac749a14?style=gitweb">
+ <b>base</b>
+ <span class="logtags"><span class="tagtag" title="1.0">1.0</span> <span class="bookmarktag" title="anotherthing">anotherthing</span> </span>
+ </a>
+ </td>
+ <td class="link" nowrap>
+ <a href="/rev/2ef0ac749a14?style=gitweb">changeset</a> |
+ <a href="/file/2ef0ac749a14?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="light"><td colspan="4"><a class="list" href="/shortlog?style=gitweb">...</a></td></tr>
+ </table>
+
+ <div><a class="title" href="/tags?style=gitweb">tags</a></div>
+ <table cellspacing="0">
+
+ <tr class="parity0">
+ <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+ <td><a class="list" href="/rev/2ef0ac749a14?style=gitweb"><b>1.0</b></a></td>
+ <td class="link">
+ <a href="/rev/2ef0ac749a14?style=gitweb">changeset</a> |
+ <a href="/log/2ef0ac749a14?style=gitweb">changelog</a> |
+ <a href="/file/2ef0ac749a14?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="light"><td colspan="3"><a class="list" href="/tags?style=gitweb">...</a></td></tr>
+ </table>
+
+ <div><a class="title" href="/bookmarks?style=gitweb">bookmarks</a></div>
+ <table cellspacing="0">
+
+ <tr class="parity0">
+ <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+ <td><a class="list" href="/rev/2ef0ac749a14?style=gitweb"><b>anotherthing</b></a></td>
+ <td class="link">
+ <a href="/rev/2ef0ac749a14?style=gitweb">changeset</a> |
+ <a href="/log/2ef0ac749a14?style=gitweb">changelog</a> |
+ <a href="/file/2ef0ac749a14?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="parity1">
+ <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+ <td><a class="list" href="/rev/ba87b23d29ca?style=gitweb"><b>something</b></a></td>
+ <td class="link">
+ <a href="/rev/ba87b23d29ca?style=gitweb">changeset</a> |
+ <a href="/log/ba87b23d29ca?style=gitweb">changelog</a> |
+ <a href="/file/ba87b23d29ca?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="light"><td colspan="3"><a class="list" href="/bookmarks?style=gitweb">...</a></td></tr>
+ </table>
+
+ <div><a class="title" href="/branches?style=gitweb">branches</a></div>
+ <table cellspacing="0">
+
+ <tr class="parity0">
+ <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+ <td><a class="list" href="/shortlog/ba87b23d29ca?style=gitweb"><b>ba87b23d29ca</b></a></td>
+ <td class="">unstable</td>
+ <td class="link">
+ <a href="/changeset/ba87b23d29ca?style=gitweb">changeset</a> |
+ <a href="/log/ba87b23d29ca?style=gitweb">changelog</a> |
+ <a href="/file/ba87b23d29ca?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="parity1">
+ <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+ <td><a class="list" href="/shortlog/1d22e65f027e?style=gitweb"><b>1d22e65f027e</b></a></td>
+ <td class="">stable</td>
+ <td class="link">
+ <a href="/changeset/1d22e65f027e?style=gitweb">changeset</a> |
+ <a href="/log/1d22e65f027e?style=gitweb">changelog</a> |
+ <a href="/file/1d22e65f027e?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="parity0">
+ <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+ <td><a class="list" href="/shortlog/a4f92ed23982?style=gitweb"><b>a4f92ed23982</b></a></td>
+ <td class="">default</td>
+ <td class="link">
+ <a href="/changeset/a4f92ed23982?style=gitweb">changeset</a> |
+ <a href="/log/a4f92ed23982?style=gitweb">changelog</a> |
+ <a href="/file/a4f92ed23982?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="light">
+ <td colspan="4"><a class="list" href="/branches?style=gitweb">...</a></td>
+ </tr>
+ </table>
+ <script type="text/javascript">process_dates()</script>
+ <div class="page_footer">
+ <div class="page_footer_text">test</div>
+ <div class="rss_logo">
+ <a href="/rss-log">RSS</a>
+ <a href="/atom-log">Atom</a>
+ </div>
+ <br />
+
+ </div>
+ </body>
+ </html>
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/?style=gitweb'
+ 200 Script output follows
+
+ <?xml version="1.0" encoding="ascii"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow"/>
+ <link rel="stylesheet" href="/static/style-gitweb.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: Graph</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log" title="Atom feed for test"/>
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log" title="RSS feed for test"/>
+ <!--[if IE]><script type="text/javascript" src="/static/excanvas.js"></script><![endif]-->
+ </head>
+ <body>
+
+ <div class="page_header">
+ <a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="/summary?style=gitweb">test</a> / graph
+ </div>
+
+ <form action="/log">
+ <input type="hidden" name="style" value="gitweb" />
+ <div class="search">
+ <input type="text" name="rev" />
+ </div>
+ </form>
+ <div class="page_nav">
+ <a href="/summary?style=gitweb">summary</a> |
+ <a href="/shortlog?style=gitweb">shortlog</a> |
+ <a href="/log/3?style=gitweb">changelog</a> |
+ graph |
+ <a href="/tags?style=gitweb">tags</a> |
+ <a href="/bookmarks?style=gitweb">bookmarks</a> |
+ <a href="/branches?style=gitweb">branches</a> |
+ <a href="/file/ba87b23d29ca?style=gitweb">files</a> |
+ <a href="/help?style=gitweb">help</a>
+ <br/>
+ <a href="/graph/3?style=gitweb&revcount=30">less</a>
+ <a href="/graph/3?style=gitweb&revcount=120">more</a>
+ | <a href="/graph/2ef0ac749a14?style=gitweb">(0)</a> <a href="/graph/tip?style=gitweb">tip</a> <br/>
+ </div>
+
+ <div class="title">&nbsp;</div>
+
+ <noscript>The revision graph only works with JavaScript-enabled browsers.</noscript>
+
+ <div id="wrapper">
+ <ul id="nodebgs"></ul>
+ <canvas id="graph" width="480" height="168"></canvas>
+ <ul id="graphnodes"></ul>
+ </div>
+
+ <script>
+ <!-- hide script content
+
+ var data = [["ba87b23d29ca", [0, 1], [[0, 0, 1, 3, "FF0000"]], "branch", "test", "1970-01-01", ["unstable", true], ["tip"], ["something"]], ["1d22e65f027e", [0, 1], [[0, 0, 1, 3, ""]], "branch", "test", "1970-01-01", ["stable", true], [], []], ["a4f92ed23982", [0, 1], [[0, 0, 1, 3, ""]], "Added tag 1.0 for changeset 2ef0ac749a14", "test", "1970-01-01", ["default", true], [], []], ["2ef0ac749a14", [0, 1], [], "base", "test", "1970-01-01", ["default", false], ["1.0"], ["anotherthing"]]];
+ var graph = new Graph();
+ graph.scale(39);
+
+ var revlink = '<li style="_STYLE"><span class="desc">';
+ revlink += '<a class="list" href="/rev/_NODEID?style=gitweb" title="_NODEID"><b>_DESC</b></a>';
+ revlink += '</span> _TAGS';
+ revlink += '<span class="info">_DATE, by _USER</span></li>';
+
+ graph.vertex = function(x, y, color, parity, cur) {
+
+ this.ctx.beginPath();
+ color = this.setColor(color, 0.25, 0.75);
+ this.ctx.arc(x, y, radius, 0, Math.PI * 2, true);
+ this.ctx.fill();
+
+ var bg = '<li class="bg parity' + parity + '"></li>';
+ var left = (this.columns + 1) * this.bg_height;
+ var nstyle = 'padding-left: ' + left + 'px;';
+ var item = revlink.replace(/_STYLE/, nstyle);
+ item = item.replace(/_PARITY/, 'parity' + parity);
+ item = item.replace(/_NODEID/, cur[0]);
+ item = item.replace(/_NODEID/, cur[0]);
+ item = item.replace(/_DESC/, cur[3]);
+ item = item.replace(/_USER/, cur[4]);
+ item = item.replace(/_DATE/, cur[5]);
+
+ var tagspan = '';
+ if (cur[7].length || cur[8].length || (cur[6][0] != 'default' || cur[6][1])) {
+ tagspan = '<span class="logtags">';
+ if (cur[6][1]) {
+ tagspan += '<span class="branchtag" title="' + cur[6][0] + '">';
+ tagspan += cur[6][0] + '</span> ';
+ } else if (!cur[6][1] && cur[6][0] != 'default') {
+ tagspan += '<span class="inbranchtag" title="' + cur[6][0] + '">';
+ tagspan += cur[6][0] + '</span> ';
+ }
+ if (cur[7].length) {
+ for (var t in cur[7]) {
+ var tag = cur[7][t];
+ tagspan += '<span class="tagtag">' + tag + '</span> ';
+ }
+ }
+ if (cur[8].length) {
+ for (var t in cur[8]) {
+ var bookmark = cur[8][t];
+ tagspan += '<span class="bookmarktag">' + bookmark + '</span> ';
+ }
+ }
+ tagspan += '</span>';
+ }
+
+ item = item.replace(/_TAGS/, tagspan);
+ return [bg, item];
+
+ }
+
+ graph.render(data);
+
+ // stop hiding script -->
+ </script>
+
+ <div class="page_nav">
+ <a href="/graph/3?style=gitweb&revcount=30">less</a>
+ <a href="/graph/3?style=gitweb&revcount=120">more</a>
+ | <a href="/graph/2ef0ac749a14?style=gitweb">(0)</a> <a href="/graph/tip?style=gitweb">tip</a>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+ <div class="page_footer">
+ <div class="page_footer_text">test</div>
+ <div class="rss_logo">
+ <a href="/rss-log">RSS</a>
+ <a href="/atom-log">Atom</a>
+ </div>
+ <br />
+
+ </div>
+ </body>
+ </html>
+
+raw graph
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/?style=raw'
+ 200 Script output follows
+
+
+ # HG graph
+ # Node ID ba87b23d29ca67a305625d81a20ac279c1e3f444
+ # Rows shown 4
+
+ changeset: ba87b23d29ca
+ user: test
+ date: 1970-01-01
+ summary: branch
+ branch: unstable
+ tag: tip
+ bookmark: something
+
+ node: (0, 0) (color 1)
+ edge: (0, 0) -> (0, 1) (color 1)
+
+ changeset: 1d22e65f027e
+ user: test
+ date: 1970-01-01
+ summary: branch
+ branch: stable
+
+ node: (0, 1) (color 1)
+ edge: (0, 1) -> (0, 2) (color 1)
+
+ changeset: a4f92ed23982
+ user: test
+ date: 1970-01-01
+ summary: Added tag 1.0 for changeset 2ef0ac749a14
+ branch: default
+
+ node: (0, 2) (color 1)
+ edge: (0, 2) -> (0, 3) (color 1)
+
+ changeset: 2ef0ac749a14
+ user: test
+ date: 1970-01-01
+ summary: base
+ tag: 1.0
+ bookmark: anotherthing
+
+ node: (0, 3) (color 1)
+
+
+
+capabilities
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=capabilities'; echo
+ 200 Script output follows
+
+ lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
+
+heads
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=heads'
+ 200 Script output follows
+
+ ba87b23d29ca67a305625d81a20ac279c1e3f444
+
+branches
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=branches&nodes=0000000000000000000000000000000000000000'
+ 200 Script output follows
+
+ 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
+
+changegroup
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=changegroup&roots=0000000000000000000000000000000000000000'
+ 200 Script output follows
+
+ x\x9c\xbdTMHTQ\x14\x1e\xfc\xef\xd9&\x10\x11*x\x88\x81\x9aN\xf7\xddw\xdf{\xf7Y\x0efR\xb4\x11\xb1U\x82\xc5\xfd\x9d!c\x06\x9c'd\xa0\x99X\x82\x92i\xablUZ-*\x08\x84\x82\x02KkQ\xf8\x13\xe4\xaa\x8dn\x94\x906)\xd5B\x02\xeb\xbe\x9c\x01\x85\xc9\x996\x1d\xf8x\x97{\xefy\xe7;\xe7|\xe7\x06\x02\x81\xb1\xe0\xda\x13\xefN\xd1\xca\x8f\xcb-\xbde\xfc\xeepU\xecJ\xc3\xcd@\x86\x96\xc6\xb7^`\xe9"[H\xe4\x18T\x1a\x16p]\xc3\x96\x14\x13\xcbt\xa1tM\x0c\x1c\x0b2,M\xcd\x13qO\x03:\xd089"c1\xcd\x87FI\\\xa8\xbf|\xbc\xbf\x11\\p{_\xe5\xb6\xddn^j\xdd\xec\x0f=z\xb7\xb6\x94)\xebT\xbe\x89\xa3 (esc)
+ \x1f6!6p\x00\xc4H`L\x18\x83\xdc\xa6\x8c\x0b\x84\x01\x06\x06s\xb84\x1cn2F4u\x19*\xd4*\x14\x04#a\x8f\x84\xe3\xfe^\xc8OS\xa1\xfc8\xe7\x82\xebj[7\x82@\x97\xb1v\x9dEH4,\xe2\xc2\xd3\xa1\x90\x800\x07\xb9\xc4@\xea\xee\xe4\xc1\xd2\xcf\xe7\xb3\xba[\xf2\xf6X\xdd]C\x1d\x05\xf3\x87\x1f,l\xeeBt\x87\xa5\xf2\xdd\x9e\x90*\xa9kC\xac"!\x17\x12)!c\x000\xd7\x05&\xb5\xa9\xc5\xa8-Ln (esc)
+ \x0c|\xf2A\x85\x1a\x85bUy\x9d\xb6\x93(\x8b\xd4\xc4=B/\x8a?\rP'G\x15\x98B\xde\xd6\xa9Zy/\xfb'j+f\xc2\xe3\xb9\xb4\xf5\xea\x98\xf6\xa6sz\xf9{\xc3.\xa4vX*\xdf\x04\x0f\xff[\xb4\x8dGG4\xc1$\xe1:\xb9\xbaq\xf2\xeb\xa9\xfd\xebM\xa3\xc5?\x07\xce\xdc\xda\xc0\xf9\xcd\xef\xbf\xa5\xd3g\xd2\xd2\xa8\xa5uKu\x01(8$\xa6k@\x02(D\x16\x80\x00\x99\x82\x08\xa5\r\x81(t\\f`\xea\x02\xce\xb5\x7f\xba\xac\x02\x8c\\x\x98\x9f\xd5\xb7:0W\xdd6\xbf\xd2\xd3s\xa0k\xbd\xeb\xd8L\xa6 \xa5Q\x86\x91Pc\x80\x98\x8cB,L\x07#\x80\x04\x82\xb6\x8d)\xa3\x08X\x02\x00\xear\x0c-`b\x9b\x18>\xa1\x1b\xf9g\xe9@\xd1\xe9\xca_US{G\xb3\x9f?\x9b\x8d\xd6\x86zR\x91LE\xe8/\xdd& (esc)
+ C
+ \xd5~u\xb0e#\x08\r\x8c\xd5\xf83\x93\x01B\x95\xe8\x1c\x03\xdb\x92s*\x99`\xcc0\x88\xb4d\xb2\xbd\x85\xc9,\x14\xb7\xf1\xd9\xf2\xe5Ku\x8d\xf5rp\xb6\xee\\\xe0\xc5\xa7C\xd9\xd7\xefe\xda\xe94\xc5\xaa\xde>\x8a\x02I\xcb!\x16\xc1\x10"\x1b\x11\xe0\x02\xc8l\xe9H\x84\xb0\xf4\xa78\xc9-\xf1(\xa9\x15\x0f.\x8c\x8fT\x16\x965\xe9'\xbe\xac6\xaeLtN\x0f\x0e/fJ-\x8d\x08s\x12#\xe7[\xfe\xff\x0b\x17\xb9\xc6KK\xfa\xa2o\xa7\x1e\x87\xfaKb\x8b\xaf?\xcc\xed{z>\xd3\xb8\xbb\xcc}\x8eB\x01\x89\xc6\xbc\x88hO\xa6\x15\xf8\rr4\xb3\xe5 (no-eol) (esc)
+
+stream_out
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=stream_out'
+ 200 Script output follows
+
+ 1
+
+failing unbundle, requires POST request
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=unbundle'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+Static files
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'static/style.css'
+ 200 Script output follows
+
+ a { text-decoration:none; }
+ .age { white-space:nowrap; }
+ .date { white-space:nowrap; }
+ .indexlinks { white-space:nowrap; }
+ .parity0 { background-color: #ddd; }
+ .parity1 { background-color: #eee; }
+ .lineno { width: 60px; color: #aaa; font-size: smaller;
+ text-align: right; }
+ .plusline { color: green; }
+ .minusline { color: red; }
+ .atline { color: purple; }
+ .annotate { font-size: smaller; text-align: right; padding-right: 1em; }
+ .buttons a {
+ background-color: #666;
+ padding: 2pt;
+ color: white;
+ font-family: sans;
+ font-weight: bold;
+ }
+ .navigate a {
+ background-color: #ccc;
+ padding: 2pt;
+ font-family: sans;
+ color: black;
+ }
+
+ .metatag {
+ background-color: #888;
+ color: white;
+ text-align: right;
+ }
+
+ /* Common */
+ pre { margin: 0; }
+
+ .logo {
+ float: right;
+ clear: right;
+ }
+
+ /* Changelog/Filelog entries */
+ .logEntry { width: 100%; }
+ .logEntry .age { width: 15%; }
+ .logEntry th { font-weight: normal; text-align: right; vertical-align: top; }
+ .logEntry th.age, .logEntry th.firstline { font-weight: bold; }
+ .logEntry th.firstline { text-align: left; width: inherit; }
+
+ /* Shortlog entries */
+ .slogEntry { width: 100%; }
+ .slogEntry .age { width: 8em; }
+ .slogEntry td { font-weight: normal; text-align: left; vertical-align: top; }
+ .slogEntry td.author { width: 15em; }
+
+ /* Tag entries */
+ #tagEntries { list-style: none; margin: 0; padding: 0; }
+ #tagEntries .tagEntry { list-style: none; margin: 0; padding: 0; }
+
+ /* Changeset entry */
+ #changesetEntry { }
+ #changesetEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
+ #changesetEntry th.files, #changesetEntry th.description { vertical-align: top; }
+
+ /* File diff view */
+ #filediffEntry { }
+ #filediffEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
+
+ /* Graph */
+ div#wrapper {
+ position: relative;
+ margin: 0;
+ padding: 0;
+ }
+
+ canvas {
+ position: absolute;
+ z-index: 5;
+ top: -0.6em;
+ margin: 0;
+ }
+
+ ul#nodebgs {
+ list-style: none inside none;
+ padding: 0;
+ margin: 0;
+ top: -0.7em;
+ }
+
+ ul#graphnodes li, ul#nodebgs li {
+ height: 39px;
+ }
+
+ ul#graphnodes {
+ position: absolute;
+ z-index: 10;
+ top: -0.85em;
+ list-style: none inside none;
+ padding: 0;
+ }
+
+ ul#graphnodes li .info {
+ display: block;
+ font-size: 70%;
+ position: relative;
+ top: -1px;
+ }
+
+Stop and restart with HGENCODING=cp932 and preferuncompressed
+
+ $ "$TESTDIR/killdaemons.py"
+ $ HGENCODING=cp932 hg serve --config server.preferuncompressed=True -n test \
+ > -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+commit message with Japanese Kanji 'Noh', which ends with '\x5c'
+
+ $ echo foo >> foo
+ $ HGENCODING=cp932 hg ci -m `python -c 'print("\x94\x5c")'`
+
+Graph json escape of multibyte character
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/' \
+ > | grep '^var data ='
+ var data = [["548001d11f45", [0, 1], [[0, 0, 1, -1, ""]], "\u80fd", "test", "1970-01-01", ["unstable", true], ["tip"], ["something"]], ["ba87b23d29ca", [0, 1], [[0, 0, 1, 3, "FF0000"]], "branch", "test", "1970-01-01", ["unstable", false], [], []], ["1d22e65f027e", [0, 1], [[0, 0, 1, 3, ""]], "branch", "test", "1970-01-01", ["stable", true], [], []], ["a4f92ed23982", [0, 1], [[0, 0, 1, 3, ""]], "Added tag 1.0 for changeset 2ef0ac749a14", "test", "1970-01-01", ["default", true], [], []], ["2ef0ac749a14", [0, 1], [], "base", "test", "1970-01-01", ["default", false], ["1.0"], ["anotherthing"]]];
+
+capabilities
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=capabilities'; echo
+ 200 Script output follows
+
+ lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream-preferred stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
+
+heads
+
+ERRORS ENCOUNTERED
+
+ $ cat errors.log
+ $ "$TESTDIR/killdaemons.py"
+
+ $ cd ..
+
+Test graph paging
+
+ $ mkcommit() {
+ > echo $1 >> a
+ > hg ci -Am $1 a
+ > }
+
+ $ hg init graph
+ $ cd graph
+ $ mkcommit 0
+ $ mkcommit 1
+ $ mkcommit 2
+ $ mkcommit 3
+ $ mkcommit 4
+ $ mkcommit 5
+ $ hg serve --config server.uncompressed=False \
+ > --config web.maxshortchanges=2 \
+ > -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg log -G --template '{rev}:{node|short} {desc}\n'
+ @ 5:aed2d9c1d0e7 5
+ |
+ o 4:b60a39a85a01 4
+ |
+ o 3:ada793dcc118 3
+ |
+ o 2:ab4f1438558b 2
+ |
+ o 1:e06180cbfb0c 1
+ |
+ o 0:b4e73ffab476 0
+
+
+Test paging
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT \
+ > 'graph/?style=raw' | grep changeset
+ changeset: aed2d9c1d0e7
+ changeset: b60a39a85a01
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT \
+ > 'graph/?style=raw&revcount=3' | grep changeset
+ changeset: aed2d9c1d0e7
+ changeset: b60a39a85a01
+ changeset: ada793dcc118
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT \
+ > 'graph/e06180cbfb0?style=raw&revcount=3' | grep changeset
+ changeset: ab4f1438558b
+ changeset: e06180cbfb0c
+ changeset: b4e73ffab476
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT \
+ > 'graph/b4e73ffab47?style=raw&revcount=3' | grep changeset
+ changeset: ab4f1438558b
+ changeset: e06180cbfb0c
+ changeset: b4e73ffab476
+
+ $ cat errors.log
+
+ $ cd ..
diff --git a/tests/test-hgweb-descend-empties.t b/tests/test-hgweb-descend-empties.t
new file mode 100644
index 0000000..b97c018
--- /dev/null
+++ b/tests/test-hgweb-descend-empties.t
@@ -0,0 +1,144 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+Test chains of near empty directories, terminating 3 different ways:
+- a1: file at level 4 (deepest)
+- b1: two dirs at level 3
+- e1: file at level 2
+
+Set up the repo
+
+ $ hg init test
+ $ cd test
+ $ mkdir -p a1/a2/a3/a4
+ $ mkdir -p b1/b2/b3/b4
+ $ mkdir -p b1/b2/c3/c4
+ $ mkdir -p d1/d2/d3/d4
+ $ echo foo > a1/a2/a3/a4/foo
+ $ echo foo > b1/b2/b3/b4/foo
+ $ echo foo > b1/b2/c3/c4/foo
+ $ echo foo > d1/d2/d3/d4/foo
+ $ echo foo > d1/d2/foo
+ $ hg ci -Ama
+ adding a1/a2/a3/a4/foo
+ adding b1/b2/b3/b4/foo
+ adding b1/b2/c3/c4/foo
+ adding d1/d2/d3/d4/foo
+ adding d1/d2/foo
+ $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+manifest with descending
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: 9087c84a0f5d /</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/9087c84a0f5d">log</a></li>
+ <li><a href="/graph/9087c84a0f5d">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/9087c84a0f5d">changeset</a></li>
+ <li class="active">browse</li>
+ </ul>
+ <ul>
+
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>directory / @ 0:9087c84a0f5d <span class="tag">tip</span> </h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <table class="bigtable">
+ <tr>
+ <th class="name">name</th>
+ <th class="size">size</th>
+ <th class="permissions">permissions</th>
+ </tr>
+ <tr class="fileline parity0">
+ <td class="name"><a href="/file/9087c84a0f5d/">[up]</a></td>
+ <td class="size"></td>
+ <td class="permissions">drwxr-xr-x</td>
+ </tr>
+
+ <tr class="fileline parity1">
+ <td class="name">
+ <a href="/file/9087c84a0f5d/a1">
+ <img src="/static/coal-folder.png" alt="dir."/> a1/
+ </a>
+ <a href="/file/9087c84a0f5d/a1/a2/a3/a4">
+ a2/a3/a4
+ </a>
+ </td>
+ <td class="size"></td>
+ <td class="permissions">drwxr-xr-x</td>
+ </tr>
+ <tr class="fileline parity0">
+ <td class="name">
+ <a href="/file/9087c84a0f5d/b1">
+ <img src="/static/coal-folder.png" alt="dir."/> b1/
+ </a>
+ <a href="/file/9087c84a0f5d/b1/b2">
+ b2
+ </a>
+ </td>
+ <td class="size"></td>
+ <td class="permissions">drwxr-xr-x</td>
+ </tr>
+ <tr class="fileline parity1">
+ <td class="name">
+ <a href="/file/9087c84a0f5d/d1">
+ <img src="/static/coal-folder.png" alt="dir."/> d1/
+ </a>
+ <a href="/file/9087c84a0f5d/d1/d2">
+ d2
+ </a>
+ </td>
+ <td class="size"></td>
+ <td class="permissions">drwxr-xr-x</td>
+ </tr>
+
+ </table>
+ </div>
+ </div>
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+ $ cat errors.log
+
+ $ cd ..
diff --git a/tests/test-hgweb-diffs.t b/tests/test-hgweb-diffs.t
new file mode 100644
index 0000000..f96f42b
--- /dev/null
+++ b/tests/test-hgweb-diffs.t
@@ -0,0 +1,986 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+setting up repo
+
+ $ hg init test
+ $ cd test
+ $ echo a > a
+ $ echo b > b
+ $ hg ci -Ama
+ adding a
+ adding b
+
+change permissions for git diffs
+
+ $ hg import -q --bypass - <<EOF
+ > # HG changeset patch
+ > # User test
+ > # Date 0 0
+ > b
+ >
+ > diff --git a/a b/a
+ > old mode 100644
+ > new mode 100755
+ > diff --git a/b b/b
+ > deleted file mode 100644
+ > --- a/b
+ > +++ /dev/null
+ > @@ -1,1 +0,0 @@
+ > -b
+ > EOF
+
+set up hgweb
+
+ $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+revision
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/0'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: 0cd96de13884</title>
+ </head>
+ <body>
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/0cd96de13884">log</a></li>
+ <li><a href="/graph/0cd96de13884">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li class="active">changeset</li>
+ <li><a href="/raw-rev/0cd96de13884">raw</a></li>
+ <li><a href="/file/0cd96de13884">browse</a></li>
+ </ul>
+ <ul>
+
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+
+ <h2><a href="/">test</a></h2>
+ <h3>changeset 0:0cd96de13884 </h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">a</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th class="author">author</th>
+ <td class="author">&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th class="date">date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
+ <tr>
+ <th class="author">parents</th>
+ <td class="author"></td>
+ </tr>
+ <tr>
+ <th class="author">children</th>
+ <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
+ </tr>
+ <tr>
+ <th class="files">files</th>
+ <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
+ </tr>
+ <tr>
+ <th class="diffstat">diffstat</th>
+ <td class="diffstat">
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+
+ <a id="diffstatexpand" href="javascript:showDiffstat()"/>[<tt>+</tt>]</a>
+ <div id="diffstatdetails" style="display:none;">
+ <a href="javascript:hideDiffstat()"/>[<tt>-</tt>]</a>
+ <p>
+ <table> <tr class="parity0">
+ <td class="diffstat-file"><a href="#l1.1">a</a></td>
+ <td class="diffstat-total" align="right">1</td>
+ <td class="diffstat-graph">
+ <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
+ <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
+ </td>
+ </tr>
+ <tr class="parity1">
+ <td class="diffstat-file"><a href="#l2.1">b</a></td>
+ <td class="diffstat-total" align="right">1</td>
+ <td class="diffstat-graph">
+ <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
+ <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> line diff</div>
+
+ <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -0,0 +1,1 @@
+ </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="plusline">+a
+ </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l2.2" id="l2.2"> 2.2</a> <span class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="atline">@@ -0,0 +1,1 @@
+ </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="plusline">+b
+ </span></pre></div>
+ </div>
+
+ </div>
+ </div>
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+raw revision
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
+ 200 Script output follows
+
+
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
+
+ a
+
+ diff -r 000000000000 -r 0cd96de13884 a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+ diff -r 000000000000 -r 0cd96de13884 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+
+diff removed file
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/b'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: b diff</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/559edbd9ed20">log</a></li>
+ <li><a href="/graph/559edbd9ed20">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/559edbd9ed20">changeset</a></li>
+ <li><a href="/file/559edbd9ed20">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/file/559edbd9ed20/b">file</a></li>
+ <li><a href="/file/tip/b">latest</a></li>
+ <li class="active">diff</li>
+ <li><a href="/comparison/559edbd9ed20/b">comparison</a></li>
+ <li><a href="/annotate/559edbd9ed20/b">annotate</a></li>
+ <li><a href="/log/559edbd9ed20/b">file log</a></li>
+ <li><a href="/raw-file/559edbd9ed20/b">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>diff b @ 1:559edbd9ed20</h3>
+
+ <form class="search" action="/log">
+ <p></p>
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">b</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th>author</th>
+ <td>&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th>date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ </tr>
+ <tr>
+ <th>parents</th>
+ <td><a href="/file/0cd96de13884/b">0cd96de13884</a> </td>
+ </tr>
+ <tr>
+ <th>children</th>
+ <td></td>
+ </tr>
+
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> line diff</div>
+
+ <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- a/b Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -1,1 +0,0 @@
+ </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="minusline">-b
+ </span></pre></div>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+set up hgweb with git diffs
+
+ $ "$TESTDIR/killdaemons.py"
+ $ hg serve --config 'diff.git=1' -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+revision
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/0'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: 0cd96de13884</title>
+ </head>
+ <body>
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/0cd96de13884">log</a></li>
+ <li><a href="/graph/0cd96de13884">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li class="active">changeset</li>
+ <li><a href="/raw-rev/0cd96de13884">raw</a></li>
+ <li><a href="/file/0cd96de13884">browse</a></li>
+ </ul>
+ <ul>
+
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+
+ <h2><a href="/">test</a></h2>
+ <h3>changeset 0:0cd96de13884 </h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">a</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th class="author">author</th>
+ <td class="author">&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th class="date">date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
+ <tr>
+ <th class="author">parents</th>
+ <td class="author"></td>
+ </tr>
+ <tr>
+ <th class="author">children</th>
+ <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
+ </tr>
+ <tr>
+ <th class="files">files</th>
+ <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
+ </tr>
+ <tr>
+ <th class="diffstat">diffstat</th>
+ <td class="diffstat">
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+
+ <a id="diffstatexpand" href="javascript:showDiffstat()"/>[<tt>+</tt>]</a>
+ <div id="diffstatdetails" style="display:none;">
+ <a href="javascript:hideDiffstat()"/>[<tt>-</tt>]</a>
+ <p>
+ <table> <tr class="parity0">
+ <td class="diffstat-file"><a href="#l1.1">a</a></td>
+ <td class="diffstat-total" align="right">1</td>
+ <td class="diffstat-graph">
+ <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
+ <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
+ </td>
+ </tr>
+ <tr class="parity1">
+ <td class="diffstat-file"><a href="#l2.1">b</a></td>
+ <td class="diffstat-total" align="right">1</td>
+ <td class="diffstat-graph">
+ <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
+ <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> line diff</div>
+
+ <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> new file mode 100644
+ <a href="#l1.2" id="l1.2"> 1.2</a> <span class="minusline">--- /dev/null
+ </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="plusline">+++ b/a
+ </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="atline">@@ -0,0 +1,1 @@
+ </span><a href="#l1.5" id="l1.5"> 1.5</a> <span class="plusline">+a
+ </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> new file mode 100644
+ <a href="#l2.2" id="l2.2"> 2.2</a> <span class="minusline">--- /dev/null
+ </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="plusline">+++ b/b
+ </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="atline">@@ -0,0 +1,1 @@
+ </span><a href="#l2.5" id="l2.5"> 2.5</a> <span class="plusline">+b
+ </span></pre></div>
+ </div>
+
+ </div>
+ </div>
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+revision
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
+ 200 Script output follows
+
+
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
+
+ a
+
+ diff --git a/a b/a
+ new file mode 100644
+ --- /dev/null
+ +++ b/a
+ @@ -0,0 +1,1 @@
+ +a
+ diff --git a/b b/b
+ new file mode 100644
+ --- /dev/null
+ +++ b/b
+ @@ -0,0 +1,1 @@
+ +b
+
+
+diff removed file
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/a'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: a diff</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/559edbd9ed20">log</a></li>
+ <li><a href="/graph/559edbd9ed20">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/559edbd9ed20">changeset</a></li>
+ <li><a href="/file/559edbd9ed20">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/file/559edbd9ed20/a">file</a></li>
+ <li><a href="/file/tip/a">latest</a></li>
+ <li class="active">diff</li>
+ <li><a href="/comparison/559edbd9ed20/a">comparison</a></li>
+ <li><a href="/annotate/559edbd9ed20/a">annotate</a></li>
+ <li><a href="/log/559edbd9ed20/a">file log</a></li>
+ <li><a href="/raw-file/559edbd9ed20/a">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>diff a @ 1:559edbd9ed20</h3>
+
+ <form class="search" action="/log">
+ <p></p>
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">b</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th>author</th>
+ <td>&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th>date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ </tr>
+ <tr>
+ <th>parents</th>
+ <td></td>
+ </tr>
+ <tr>
+ <th>children</th>
+ <td></td>
+ </tr>
+
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> line diff</div>
+
+ <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> old mode 100644
+ <a href="#l1.2" id="l1.2"> 1.2</a> new mode 100755
+ </pre></div>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+comparison new file
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/0/a'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: a comparison</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/0cd96de13884">log</a></li>
+ <li><a href="/graph/0cd96de13884">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/0cd96de13884">changeset</a></li>
+ <li><a href="/file/0cd96de13884">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/file/0cd96de13884/a">file</a></li>
+ <li><a href="/file/tip/a">latest</a></li>
+ <li><a href="/diff/0cd96de13884/a">diff</a></li>
+ <li class="active">comparison</li>
+ <li><a href="/annotate/0cd96de13884/a">annotate</a></li>
+ <li><a href="/log/0cd96de13884/a">file log</a></li>
+ <li><a href="/raw-file/0cd96de13884/a">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>comparison a @ 0:0cd96de13884</h3>
+
+ <form class="search" action="/log">
+ <p></p>
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">a</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th>author</th>
+ <td>&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th>date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ </tr>
+ <tr>
+ <th>parents</th>
+ <td></td>
+ </tr>
+ <tr>
+ <th>children</th>
+ <td></td>
+ </tr>
+
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> comparison</div>
+ <div class="legend">
+ <span class="legendinfo equal">equal</span>
+ <span class="legendinfo delete">deleted</span>
+ <span class="legendinfo insert">inserted</span>
+ <span class="legendinfo replace">replaced</span>
+ </div>
+
+ <table class="bigtable">
+ <thead class="header">
+ <tr>
+ <th>-1:000000000000</th>
+ <th>0:b789fdd96dc2</th>
+ </tr>
+ </thead>
+
+ <tbody class="block">
+
+ <tr>
+ <td class="source insert"><a href="#r1" id="r1"> </a> </td>
+ <td class="source insert"><a href="#r1" id="r1"> 1</a> a</td>
+ </tr>
+ </tbody>
+ </table>
+
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+comparison existing file
+
+ $ hg up
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo a >> a
+ $ hg ci -mc
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: a comparison</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/d73db4d812ff">log</a></li>
+ <li><a href="/graph/d73db4d812ff">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/d73db4d812ff">changeset</a></li>
+ <li><a href="/file/d73db4d812ff">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/file/d73db4d812ff/a">file</a></li>
+ <li><a href="/file/tip/a">latest</a></li>
+ <li><a href="/diff/d73db4d812ff/a">diff</a></li>
+ <li class="active">comparison</li>
+ <li><a href="/annotate/d73db4d812ff/a">annotate</a></li>
+ <li><a href="/log/d73db4d812ff/a">file log</a></li>
+ <li><a href="/raw-file/d73db4d812ff/a">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>comparison a @ 2:d73db4d812ff</h3>
+
+ <form class="search" action="/log">
+ <p></p>
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">c</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th>author</th>
+ <td>&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th>date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ </tr>
+ <tr>
+ <th>parents</th>
+ <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
+ </tr>
+ <tr>
+ <th>children</th>
+ <td></td>
+ </tr>
+
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> comparison</div>
+ <div class="legend">
+ <span class="legendinfo equal">equal</span>
+ <span class="legendinfo delete">deleted</span>
+ <span class="legendinfo insert">inserted</span>
+ <span class="legendinfo replace">replaced</span>
+ </div>
+
+ <table class="bigtable">
+ <thead class="header">
+ <tr>
+ <th>0:b789fdd96dc2</th>
+ <th>1:a80d06849b33</th>
+ </tr>
+ </thead>
+
+ <tbody class="block">
+
+ <tr>
+ <td class="source equal"><a href="#l1r1" id="l1r1"> 1</a> a</td>
+ <td class="source equal"><a href="#l1r1" id="l1r1"> 1</a> a</td>
+ </tr>
+ <tr>
+ <td class="source insert"><a href="#r2" id="r2"> </a> </td>
+ <td class="source insert"><a href="#r2" id="r2"> 2</a> a</td>
+ </tr>
+ </tbody>
+ </table>
+
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+comparison removed file
+
+ $ hg rm a
+ $ hg ci -md
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: a comparison</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/20e80271eb7a">log</a></li>
+ <li><a href="/graph/20e80271eb7a">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/20e80271eb7a">changeset</a></li>
+ <li><a href="/file/20e80271eb7a">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/file/20e80271eb7a/a">file</a></li>
+ <li><a href="/file/tip/a">latest</a></li>
+ <li><a href="/diff/20e80271eb7a/a">diff</a></li>
+ <li class="active">comparison</li>
+ <li><a href="/annotate/20e80271eb7a/a">annotate</a></li>
+ <li><a href="/log/20e80271eb7a/a">file log</a></li>
+ <li><a href="/raw-file/20e80271eb7a/a">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>comparison a @ 3:20e80271eb7a</h3>
+
+ <form class="search" action="/log">
+ <p></p>
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">d</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th>author</th>
+ <td>&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th>date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ </tr>
+ <tr>
+ <th>parents</th>
+ <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
+ </tr>
+ <tr>
+ <th>children</th>
+ <td></td>
+ </tr>
+
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> comparison</div>
+ <div class="legend">
+ <span class="legendinfo equal">equal</span>
+ <span class="legendinfo delete">deleted</span>
+ <span class="legendinfo insert">inserted</span>
+ <span class="legendinfo replace">replaced</span>
+ </div>
+
+ <table class="bigtable">
+ <thead class="header">
+ <tr>
+ <th>1:a80d06849b33</th>
+ <th>-1:000000000000</th>
+ </tr>
+ </thead>
+
+ <tbody class="block">
+
+ <tr>
+ <td class="source delete"><a href="#l1" id="l1"> 1</a> a</td>
+ <td class="source delete"><a href="#l1" id="l1"> </a> </td>
+ </tr>
+ <tr>
+ <td class="source delete"><a href="#l2" id="l2"> 2</a> a</td>
+ <td class="source delete"><a href="#l2" id="l2"> </a> </td>
+ </tr>
+ </tbody>
+ </table>
+
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+ $ cd ..
+
+test import rev as raw-rev
+
+ $ hg clone -r0 test test1
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd test1
+ $ hg import -q --bypass --exact http://localhost:$HGPORT/rev/1
+
+raw revision with diff block numbers
+
+ $ "$TESTDIR/killdaemons.py"
+ $ cat <<EOF > .hg/hgrc
+ > [web]
+ > templates = rawdiff
+ > EOF
+ $ mkdir rawdiff
+ $ cat <<EOF > rawdiff/map
+ > mimetype = 'text/plain; charset={encoding}'
+ > changeset = '{diff}'
+ > difflineplus = '{line}'
+ > difflineminus = '{line}'
+ > difflineat = '{line}'
+ > diffline = '{line}'
+ > filenodelink = ''
+ > filenolink = ''
+ > fileline = '{line}'
+ > diffblock = 'Block: {blockno}\n{lines}\n'
+ > EOF
+ $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
+ 200 Script output follows
+
+ Block: 1
+ diff -r 000000000000 -r 0cd96de13884 a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ Block: 2
+ diff -r 000000000000 -r 0cd96de13884 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+ $ "$TESTDIR/killdaemons.py"
+ $ rm .hg/hgrc rawdiff/map
+ $ rmdir rawdiff
+ $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+errors
+
+ $ cat ../test/errors.log
+
+ $ cd ..
diff --git a/tests/test-hgweb-empty.t b/tests/test-hgweb-empty.t
new file mode 100644
index 0000000..33d6cfd
--- /dev/null
+++ b/tests/test-hgweb-empty.t
@@ -0,0 +1,399 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+Some tests for hgweb in an empty repository
+
+ $ hg init test
+ $ cd test
+ $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'shortlog')
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: log</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log" title="Atom feed for test" />
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log" title="RSS feed for test" />
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li class="active">log</li>
+ <li><a href="/graph/000000000000">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/000000000000">changeset</a></li>
+ <li><a href="/file/000000000000">browse</a></li>
+ </ul>
+ <ul>
+
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>log</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="navigate">
+ <a href="/shortlog/-1?revcount=30">less</a>
+ <a href="/shortlog/-1?revcount=120">more</a>
+ | rev -1: <a href="/shortlog/000000000000">(0)</a> <a href="/shortlog/tip">tip</a>
+ </div>
+
+ <table class="bigtable">
+ <tr>
+ <th class="age">age</th>
+ <th class="author">author</th>
+ <th class="description">description</th>
+ </tr>
+
+ </table>
+
+ <div class="navigate">
+ <a href="/shortlog/-1?revcount=30">less</a>
+ <a href="/shortlog/-1?revcount=120">more</a>
+ | rev -1: <a href="/shortlog/000000000000">(0)</a> <a href="/shortlog/tip">tip</a>
+ </div>
+
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log')
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: log</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log" title="Atom feed for test" />
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log" title="RSS feed for test" />
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li class="active">log</li>
+ <li><a href="/graph/000000000000">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/000000000000">changeset</a></li>
+ <li><a href="/file/000000000000">browse</a></li>
+ </ul>
+ <ul>
+
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>log</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="navigate">
+ <a href="/shortlog/-1?revcount=5">less</a>
+ <a href="/shortlog/-1?revcount=20">more</a>
+ | rev -1: <a href="/shortlog/000000000000">(0)</a> <a href="/shortlog/tip">tip</a>
+ </div>
+
+ <table class="bigtable">
+ <tr>
+ <th class="age">age</th>
+ <th class="author">author</th>
+ <th class="description">description</th>
+ </tr>
+
+ </table>
+
+ <div class="navigate">
+ <a href="/shortlog/-1?revcount=5">less</a>
+ <a href="/shortlog/-1?revcount=20">more</a>
+ | rev -1: <a href="/shortlog/000000000000">(0)</a> <a href="/shortlog/tip">tip</a>
+ </div>
+
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'graph')
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: revision graph</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log" title="Atom feed for test: log" />
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log" title="RSS feed for test: log" />
+ <!--[if IE]><script type="text/javascript" src="/static/excanvas.js"></script><![endif]-->
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/000000000000">log</a></li>
+ <li class="active">graph</li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/000000000000">changeset</a></li>
+ <li><a href="/file/000000000000">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>graph</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="navigate">
+ <a href="/graph/-1?revcount=30">less</a>
+ <a href="/graph/-1?revcount=120">more</a>
+ | rev -1: <a href="/graph/000000000000">(0)</a> <a href="/graph/tip">tip</a>
+ </div>
+
+ <noscript><p>The revision graph only works with JavaScript-enabled browsers.</p></noscript>
+
+ <div id="wrapper">
+ <ul id="nodebgs"></ul>
+ <canvas id="graph" width="480" height="12"></canvas>
+ <ul id="graphnodes"></ul>
+ </div>
+
+ <script type="text/javascript">
+ <!-- hide script content
+
+ var data = [];
+ var graph = new Graph();
+ graph.scale(39);
+
+ var revlink = '<li style="_STYLE"><span class="desc">';
+ revlink += '<a href="/rev/_NODEID" title="_NODEID">_DESC</a>';
+ revlink += '</span>_TAGS<span class="info">_DATE, by _USER</span></li>';
+
+ graph.vertex = function(x, y, color, parity, cur) {
+
+ this.ctx.beginPath();
+ color = this.setColor(color, 0.25, 0.75);
+ this.ctx.arc(x, y, radius, 0, Math.PI * 2, true);
+ this.ctx.fill();
+
+ var bg = '<li class="bg parity' + parity + '"></li>';
+ var left = (this.columns + 1) * this.bg_height;
+ var nstyle = 'padding-left: ' + left + 'px;';
+ var item = revlink.replace(/_STYLE/, nstyle);
+ item = item.replace(/_PARITY/, 'parity' + parity);
+ item = item.replace(/_NODEID/, cur[0]);
+ item = item.replace(/_NODEID/, cur[0]);
+ item = item.replace(/_DESC/, cur[3]);
+ item = item.replace(/_USER/, cur[4]);
+ item = item.replace(/_DATE/, cur[5]);
+
+ var tagspan = '';
+ if (cur[7].length || cur[8].length || (cur[6][0] != 'default' || cur[6][1])) {
+ tagspan = '<span class="logtags">';
+ if (cur[6][1]) {
+ tagspan += '<span class="branchhead" title="' + cur[6][0] + '">';
+ tagspan += cur[6][0] + '</span> ';
+ } else if (!cur[6][1] && cur[6][0] != 'default') {
+ tagspan += '<span class="branchname" title="' + cur[6][0] + '">';
+ tagspan += cur[6][0] + '</span> ';
+ }
+ if (cur[7].length) {
+ for (var t in cur[7]) {
+ var tag = cur[7][t];
+ tagspan += '<span class="tag">' + tag + '</span> ';
+ }
+ }
+ if (cur[8].length) {
+ for (var b in cur[8]) {
+ var bookmark = cur[8][b];
+ tagspan += '<span class="tag">' + bookmark + '</span> ';
+ }
+ }
+ tagspan += '</span>';
+ }
+
+ item = item.replace(/_TAGS/, tagspan);
+ return [bg, item];
+
+ }
+
+ graph.render(data);
+
+ // stop hiding script -->
+ </script>
+
+ <div class="navigate">
+ <a href="/graph/-1?revcount=30">less</a>
+ <a href="/graph/-1?revcount=120">more</a>
+ | rev -1: <a href="/graph/000000000000">(0)</a> <a href="/graph/tip">tip</a>
+ </div>
+
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file')
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: 000000000000 /</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/000000000000">log</a></li>
+ <li><a href="/graph/000000000000">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/000000000000">changeset</a></li>
+ <li class="active">browse</li>
+ </ul>
+ <ul>
+
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>directory / @ -1:000000000000 <span class="tag">tip</span> </h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <table class="bigtable">
+ <tr>
+ <th class="name">name</th>
+ <th class="size">size</th>
+ <th class="permissions">permissions</th>
+ </tr>
+ <tr class="fileline parity0">
+ <td class="name"><a href="/file/000000000000/">[up]</a></td>
+ <td class="size"></td>
+ <td class="permissions">drwxr-xr-x</td>
+ </tr>
+
+
+ </table>
+ </div>
+ </div>
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+ $ cd ..
diff --git a/tests/test-hgweb-filelog.t b/tests/test-hgweb-filelog.t
new file mode 100644
index 0000000..95d7f9e
--- /dev/null
+++ b/tests/test-hgweb-filelog.t
@@ -0,0 +1,765 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ hg init test
+ $ cd test
+ $ echo b > b
+ $ hg ci -Am "b"
+ adding b
+ $ echo a > a
+ $ hg ci -Am "first a"
+ adding a
+ $ hg rm a
+ $ hg ci -m "del a"
+ $ echo b > a
+ $ hg ci -Am "second a"
+ adding a
+ $ hg rm a
+ $ hg ci -m "del2 a"
+ $ hg mv b c
+ $ hg ci -m "mv b"
+ $ echo c >> c
+ $ hg ci -m "change c"
+ $ hg log -p
+ changeset: 6:b7682196df1c
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change c
+
+ diff -r 1a6696706df2 -r b7682196df1c c
+ --- a/c Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,2 @@
+ b
+ +c
+
+ changeset: 5:1a6696706df2
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: mv b
+
+ diff -r 52e848cdcd88 -r 1a6696706df2 b
+ --- a/b Thu Jan 01 00:00:00 1970 +0000
+ +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +0,0 @@
+ -b
+ diff -r 52e848cdcd88 -r 1a6696706df2 c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+ changeset: 4:52e848cdcd88
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: del2 a
+
+ diff -r 01de2d66a28d -r 52e848cdcd88 a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +0,0 @@
+ -b
+
+ changeset: 3:01de2d66a28d
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: second a
+
+ diff -r be3ebcc91739 -r 01de2d66a28d a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+ changeset: 2:be3ebcc91739
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: del a
+
+ diff -r 5ed941583260 -r be3ebcc91739 a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +0,0 @@
+ -a
+
+ changeset: 1:5ed941583260
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: first a
+
+ diff -r 6563da9dcf87 -r 5ed941583260 a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ changeset: 0:6563da9dcf87
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+ diff -r 000000000000 -r 6563da9dcf87 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+ $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+tip - two revisions
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/tip/a')
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: a history</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log/tip/a" title="Atom feed for test:a" />
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log/tip/a" title="RSS feed for test:a" />
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/01de2d66a28d">log</a></li>
+ <li><a href="/graph/01de2d66a28d">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/01de2d66a28d">changeset</a></li>
+ <li><a href="/file/01de2d66a28d">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/file/01de2d66a28d/a">file</a></li>
+ <li><a href="/diff/01de2d66a28d/a">diff</a></li>
+ <li><a href="/comparison/01de2d66a28d/a">comparison</a></li>
+ <li><a href="/annotate/01de2d66a28d/a">annotate</a></li>
+ <li class="active">file log</li>
+ <li><a href="/raw-file/01de2d66a28d/a">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>log a</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="navigate">
+ <a href="/log/01de2d66a28d/a?revcount=30">less</a>
+ <a href="/log/01de2d66a28d/a?revcount=120">more</a>
+ | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
+
+ <table class="bigtable">
+ <tr>
+ <th class="age">age</th>
+ <th class="author">author</th>
+ <th class="description">description</th>
+ </tr>
+ <tr class="parity0">
+ <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ <td class="author">test</td>
+ <td class="description"><a href="/rev/01de2d66a28d">second a</a></td>
+ </tr>
+ <tr class="parity1">
+ <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ <td class="author">test</td>
+ <td class="description"><a href="/rev/5ed941583260">first a</a></td>
+ </tr>
+
+ </table>
+
+ <div class="navigate">
+ <a href="/log/01de2d66a28d/a?revcount=30">less</a>
+ <a href="/log/01de2d66a28d/a?revcount=120">more</a>
+ | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
+ </div>
+
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+second version - two revisions
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/3/a')
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: a history</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log/tip/a" title="Atom feed for test:a" />
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log/tip/a" title="RSS feed for test:a" />
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/01de2d66a28d">log</a></li>
+ <li><a href="/graph/01de2d66a28d">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/01de2d66a28d">changeset</a></li>
+ <li><a href="/file/01de2d66a28d">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/file/01de2d66a28d/a">file</a></li>
+ <li><a href="/diff/01de2d66a28d/a">diff</a></li>
+ <li><a href="/comparison/01de2d66a28d/a">comparison</a></li>
+ <li><a href="/annotate/01de2d66a28d/a">annotate</a></li>
+ <li class="active">file log</li>
+ <li><a href="/raw-file/01de2d66a28d/a">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>log a</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="navigate">
+ <a href="/log/01de2d66a28d/a?revcount=30">less</a>
+ <a href="/log/01de2d66a28d/a?revcount=120">more</a>
+ | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
+
+ <table class="bigtable">
+ <tr>
+ <th class="age">age</th>
+ <th class="author">author</th>
+ <th class="description">description</th>
+ </tr>
+ <tr class="parity0">
+ <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ <td class="author">test</td>
+ <td class="description"><a href="/rev/01de2d66a28d">second a</a></td>
+ </tr>
+ <tr class="parity1">
+ <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ <td class="author">test</td>
+ <td class="description"><a href="/rev/5ed941583260">first a</a></td>
+ </tr>
+
+ </table>
+
+ <div class="navigate">
+ <a href="/log/01de2d66a28d/a?revcount=30">less</a>
+ <a href="/log/01de2d66a28d/a?revcount=120">more</a>
+ | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
+ </div>
+
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+first deleted - one revision
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/2/a')
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: a history</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log/tip/a" title="Atom feed for test:a" />
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log/tip/a" title="RSS feed for test:a" />
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/5ed941583260">log</a></li>
+ <li><a href="/graph/5ed941583260">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/5ed941583260">changeset</a></li>
+ <li><a href="/file/5ed941583260">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/file/5ed941583260/a">file</a></li>
+ <li><a href="/diff/5ed941583260/a">diff</a></li>
+ <li><a href="/comparison/5ed941583260/a">comparison</a></li>
+ <li><a href="/annotate/5ed941583260/a">annotate</a></li>
+ <li class="active">file log</li>
+ <li><a href="/raw-file/5ed941583260/a">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>log a</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="navigate">
+ <a href="/log/5ed941583260/a?revcount=30">less</a>
+ <a href="/log/5ed941583260/a?revcount=120">more</a>
+ | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
+
+ <table class="bigtable">
+ <tr>
+ <th class="age">age</th>
+ <th class="author">author</th>
+ <th class="description">description</th>
+ </tr>
+ <tr class="parity0">
+ <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ <td class="author">test</td>
+ <td class="description"><a href="/rev/5ed941583260">first a</a></td>
+ </tr>
+
+ </table>
+
+ <div class="navigate">
+ <a href="/log/5ed941583260/a?revcount=30">less</a>
+ <a href="/log/5ed941583260/a?revcount=120">more</a>
+ | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
+ </div>
+
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+first version - one revision
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/1/a')
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: a history</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log/tip/a" title="Atom feed for test:a" />
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log/tip/a" title="RSS feed for test:a" />
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/5ed941583260">log</a></li>
+ <li><a href="/graph/5ed941583260">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/5ed941583260">changeset</a></li>
+ <li><a href="/file/5ed941583260">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/file/5ed941583260/a">file</a></li>
+ <li><a href="/diff/5ed941583260/a">diff</a></li>
+ <li><a href="/comparison/5ed941583260/a">comparison</a></li>
+ <li><a href="/annotate/5ed941583260/a">annotate</a></li>
+ <li class="active">file log</li>
+ <li><a href="/raw-file/5ed941583260/a">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>log a</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="navigate">
+ <a href="/log/5ed941583260/a?revcount=30">less</a>
+ <a href="/log/5ed941583260/a?revcount=120">more</a>
+ | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
+
+ <table class="bigtable">
+ <tr>
+ <th class="age">age</th>
+ <th class="author">author</th>
+ <th class="description">description</th>
+ </tr>
+ <tr class="parity0">
+ <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ <td class="author">test</td>
+ <td class="description"><a href="/rev/5ed941583260">first a</a></td>
+ </tr>
+
+ </table>
+
+ <div class="navigate">
+ <a href="/log/5ed941583260/a?revcount=30">less</a>
+ <a href="/log/5ed941583260/a?revcount=120">more</a>
+ | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
+ </div>
+
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+before addition - error
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/0/a')
+ 404 Not Found
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: error</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog">log</a></li>
+ <li><a href="/graph">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+
+ <h2><a href="/">test</a></h2>
+ <h3>error</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30"></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">
+ <p>
+ An error occurred while processing your request:
+ </p>
+ <p>
+ a@6563da9dcf87: not found in manifest
+ </p>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ [1]
+
+should show base link, use spartan because it shows it
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/tip/c?style=spartan')
+ 200 Script output follows
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+ <html>
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png">
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: c history</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log/tip/c" title="Atom feed for test:c">
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log/tip/c" title="RSS feed for test:c">
+ </head>
+ <body>
+
+ <div class="buttons">
+ <a href="/log?style=spartan">changelog</a>
+ <a href="/shortlog?style=spartan">shortlog</a>
+ <a href="/graph?style=spartan">graph</a>
+ <a href="/tags?style=spartan">tags</a>
+ <a href="/branches?style=spartan">branches</a>
+ <a href="/file/b7682196df1c/c?style=spartan">file</a>
+ <a href="/annotate/b7682196df1c/c?style=spartan">annotate</a>
+ <a href="/help?style=spartan">help</a>
+ <a type="application/rss+xml" href="/rss-log/tip/c">rss</a>
+ <a type="application/atom+xml" href="/atom-log/tip/c" title="Atom feed for test:c">atom</a>
+ </div>
+
+ <h2>c revision history</h2>
+
+ <p>navigate: <small class="navigate"><a href="/log/1a6696706df2/c?style=spartan">(0)</a> <a href="/log/tip/c?style=spartan">tip</a> </small></p>
+
+ <table class="logEntry parity0">
+ <tr>
+ <th><span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span>:</th>
+ <th class="firstline"><a href="/rev/b7682196df1c?style=spartan">change c</a></th>
+ </tr>
+ <tr>
+ <th class="revision">revision 1:</td>
+ <td class="node">
+ <a href="/file/b7682196df1c/c?style=spartan">b7682196df1c</a>
+ <a href="/diff/b7682196df1c/c?style=spartan">(diff)</a>
+ <a href="/annotate/b7682196df1c/c?style=spartan">(annotate)</a>
+ </td>
+ </tr>
+
+ <tr>
+ <th class="author">author:</th>
+ <td class="author">&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th class="date">date:</th>
+ <td class="date">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ </tr>
+ </table>
+
+
+ <table class="logEntry parity1">
+ <tr>
+ <th><span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span>:</th>
+ <th class="firstline"><a href="/rev/1a6696706df2?style=spartan">mv b</a></th>
+ </tr>
+ <tr>
+ <th class="revision">revision 0:</td>
+ <td class="node">
+ <a href="/file/1a6696706df2/c?style=spartan">1a6696706df2</a>
+ <a href="/diff/1a6696706df2/c?style=spartan">(diff)</a>
+ <a href="/annotate/1a6696706df2/c?style=spartan">(annotate)</a>
+ </td>
+ </tr>
+
+ <tr>
+ <th>base:</th>
+ <td>
+ <a href="/file/1e88685f5dde/b?style=spartan">
+ b@1e88685f5dde
+ </a>
+ </td>
+ </tr>
+ <tr>
+ <th class="author">author:</th>
+ <td class="author">&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th class="date">date:</th>
+ <td class="date">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ </tr>
+ </table>
+
+
+
+
+ <script type="text/javascript">process_dates()</script>
+
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+ </div>
+
+ </body>
+ </html>
+
+
+rss log
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rss-log/tip/a')
+ 200 Script output follows
+
+ <?xml version="1.0" encoding="ascii"?>
+ <rss version="2.0">
+ <channel>
+ <link>http://*:$HGPORT/</link> (glob)
+ <language>en-us</language>
+
+ <title>test: a history</title>
+ <description>a revision history</description>
+ <item>
+ <title>second a</title>
+ <link>http://*:$HGPORT/log01de2d66a28d/a</link> (glob)
+ <description><![CDATA[second a]]></description>
+ <author>&#116;&#101;&#115;&#116;</author>
+ <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
+ </item>
+ <item>
+ <title>first a</title>
+ <link>http://*:$HGPORT/log5ed941583260/a</link> (glob)
+ <description><![CDATA[first a]]></description>
+ <author>&#116;&#101;&#115;&#116;</author>
+ <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
+ </item>
+
+ </channel>
+ </rss>
+
+atom log
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'atom-log/tip/a')
+ 200 Script output follows
+
+ <?xml version="1.0" encoding="ascii"?>
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <id>http://*:$HGPORT/atom-log/tip/a</id> (glob)
+ <link rel="self" href="http://*:$HGPORT/atom-log/tip/a"/> (glob)
+ <title>test: a history</title>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+
+ <entry>
+ <title>second a</title>
+ <id>http://*:$HGPORT/#changeset-01de2d66a28df5549090991dccda788726948517</id> (glob)
+ <link href="http://*:$HGPORT/rev/01de2d66a28d"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">second a</pre>
+ </div>
+ </content>
+ </entry>
+ <entry>
+ <title>first a</title>
+ <id>http://*:$HGPORT/#changeset-5ed941583260248620985524192fdc382ef57c36</id> (glob)
+ <link href="http://*:$HGPORT/rev/5ed941583260"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">first a</pre>
+ </div>
+ </content>
+ </entry>
+
+ </feed>
+
+errors
+
+ $ cat errors.log
+
+ $ cd ..
diff --git a/tests/test-hgweb-no-path-info.t b/tests/test-hgweb-no-path-info.t
new file mode 100644
index 0000000..dfcc571
--- /dev/null
+++ b/tests/test-hgweb-no-path-info.t
@@ -0,0 +1,109 @@
+This tests if hgweb and hgwebdir still work if the REQUEST_URI variable is
+no longer passed with the request. Instead, SCRIPT_NAME and PATH_INFO
+should be used from d74fc8dec2b4 onward to route the request.
+
+ $ hg init repo
+ $ cd repo
+ $ echo foo > bar
+ $ hg add bar
+ $ hg commit -m "test"
+ $ hg tip
+ changeset: 0:61c9426e69fe
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: test
+
+ $ cat > request.py <<EOF
+ > from mercurial.hgweb import hgweb, hgwebdir
+ > from StringIO import StringIO
+ > import os, sys
+ >
+ > errors = StringIO()
+ > input = StringIO()
+ >
+ > def startrsp(status, headers):
+ > print '---- STATUS'
+ > print status
+ > print '---- HEADERS'
+ > print [i for i in headers if i[0] != 'ETag']
+ > print '---- DATA'
+ > return output.write
+ >
+ > env = {
+ > 'wsgi.version': (1, 0),
+ > 'wsgi.url_scheme': 'http',
+ > 'wsgi.errors': errors,
+ > 'wsgi.input': input,
+ > 'wsgi.multithread': False,
+ > 'wsgi.multiprocess': False,
+ > 'wsgi.run_once': False,
+ > 'REQUEST_METHOD': 'GET',
+ > 'SCRIPT_NAME': '',
+ > 'SERVER_NAME': '127.0.0.1',
+ > 'SERVER_PORT': os.environ['HGPORT'],
+ > 'SERVER_PROTOCOL': 'HTTP/1.0'
+ > }
+ >
+ > def process(app):
+ > content = app(env, startrsp)
+ > sys.stdout.write(output.getvalue())
+ > sys.stdout.write(''.join(content))
+ > print '---- ERRORS'
+ > print errors.getvalue()
+ >
+ > output = StringIO()
+ > env['QUERY_STRING'] = 'style=atom'
+ > process(hgweb('.', name='repo'))
+ >
+ > output = StringIO()
+ > env['QUERY_STRING'] = 'style=raw'
+ > process(hgwebdir({'repo': '.'}))
+ > EOF
+ $ python request.py
+ ---- STATUS
+ 200 Script output follows
+ ---- HEADERS
+ [('Content-Type', 'application/atom+xml; charset=ascii')]
+ ---- DATA
+ <?xml version="1.0" encoding="ascii"?>
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <!-- Changelog -->
+ <id>http://127.0.0.1:$HGPORT/</id>
+ <link rel="self" href="http://127.0.0.1:$HGPORT/atom-log"/>
+ <link rel="alternate" href="http://127.0.0.1:$HGPORT/"/>
+ <title>repo Changelog</title>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+
+ <entry>
+ <title>test</title>
+ <id>http://127.0.0.1:$HGPORT/#changeset-61c9426e69fef294feed5e2bbfc97d39944a5b1c</id>
+ <link href="http://127.0.0.1:$HGPORT/rev/61c9426e69fe"/>
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">test</pre>
+ </div>
+ </content>
+ </entry>
+
+ </feed>
+ ---- ERRORS
+
+ ---- STATUS
+ 200 Script output follows
+ ---- HEADERS
+ [('Content-Type', 'text/plain; charset=ascii')]
+ ---- DATA
+
+ repo/
+
+ ---- ERRORS
+
+
+ $ cd ..
diff --git a/tests/test-hgweb-no-request-uri.t b/tests/test-hgweb-no-request-uri.t
new file mode 100644
index 0000000..e6fb1f8
--- /dev/null
+++ b/tests/test-hgweb-no-request-uri.t
@@ -0,0 +1,143 @@
+This tests if hgweb and hgwebdir still work if the REQUEST_URI variable is
+no longer passed with the request. Instead, SCRIPT_NAME and PATH_INFO
+should be used from d74fc8dec2b4 onward to route the request.
+
+ $ hg init repo
+ $ cd repo
+ $ echo foo > bar
+ $ hg add bar
+ $ hg commit -m "test"
+ $ hg tip
+ changeset: 0:61c9426e69fe
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: test
+
+ $ cat > request.py <<EOF
+ > from mercurial.hgweb import hgweb, hgwebdir
+ > from StringIO import StringIO
+ > import os, sys
+ >
+ > errors = StringIO()
+ > input = StringIO()
+ >
+ > def startrsp(status, headers):
+ > print '---- STATUS'
+ > print status
+ > print '---- HEADERS'
+ > print [i for i in headers if i[0] != 'ETag']
+ > print '---- DATA'
+ > return output.write
+ >
+ > env = {
+ > 'wsgi.version': (1, 0),
+ > 'wsgi.url_scheme': 'http',
+ > 'wsgi.errors': errors,
+ > 'wsgi.input': input,
+ > 'wsgi.multithread': False,
+ > 'wsgi.multiprocess': False,
+ > 'wsgi.run_once': False,
+ > 'REQUEST_METHOD': 'GET',
+ > 'SCRIPT_NAME': '',
+ > 'SERVER_NAME': '127.0.0.1',
+ > 'SERVER_PORT': os.environ['HGPORT'],
+ > 'SERVER_PROTOCOL': 'HTTP/1.0'
+ > }
+ >
+ > def process(app):
+ > content = app(env, startrsp)
+ > sys.stdout.write(output.getvalue())
+ > sys.stdout.write(''.join(content))
+ > print '---- ERRORS'
+ > print errors.getvalue()
+ >
+ > output = StringIO()
+ > env['PATH_INFO'] = '/'
+ > env['QUERY_STRING'] = 'style=atom'
+ > process(hgweb('.', name = 'repo'))
+ >
+ > output = StringIO()
+ > env['PATH_INFO'] = '/file/tip/'
+ > env['QUERY_STRING'] = 'style=raw'
+ > process(hgweb('.', name = 'repo'))
+ >
+ > output = StringIO()
+ > env['PATH_INFO'] = '/'
+ > env['QUERY_STRING'] = 'style=raw'
+ > process(hgwebdir({'repo': '.'}))
+ >
+ > output = StringIO()
+ > env['PATH_INFO'] = '/repo/file/tip/'
+ > env['QUERY_STRING'] = 'style=raw'
+ > process(hgwebdir({'repo': '.'}))
+ > EOF
+ $ python request.py
+ ---- STATUS
+ 200 Script output follows
+ ---- HEADERS
+ [('Content-Type', 'application/atom+xml; charset=ascii')]
+ ---- DATA
+ <?xml version="1.0" encoding="ascii"?>
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <!-- Changelog -->
+ <id>http://127.0.0.1:$HGPORT/</id>
+ <link rel="self" href="http://127.0.0.1:$HGPORT/atom-log"/>
+ <link rel="alternate" href="http://127.0.0.1:$HGPORT/"/>
+ <title>repo Changelog</title>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+
+ <entry>
+ <title>test</title>
+ <id>http://127.0.0.1:$HGPORT/#changeset-61c9426e69fef294feed5e2bbfc97d39944a5b1c</id>
+ <link href="http://127.0.0.1:$HGPORT/rev/61c9426e69fe"/>
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:00+00:00</updated>
+ <published>1970-01-01T00:00:00+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">test</pre>
+ </div>
+ </content>
+ </entry>
+
+ </feed>
+ ---- ERRORS
+
+ ---- STATUS
+ 200 Script output follows
+ ---- HEADERS
+ [('Content-Type', 'text/plain; charset=ascii')]
+ ---- DATA
+
+ -rw-r--r-- 4 bar
+
+
+ ---- ERRORS
+
+ ---- STATUS
+ 200 Script output follows
+ ---- HEADERS
+ [('Content-Type', 'text/plain; charset=ascii')]
+ ---- DATA
+
+ /repo/
+
+ ---- ERRORS
+
+ ---- STATUS
+ 200 Script output follows
+ ---- HEADERS
+ [('Content-Type', 'text/plain; charset=ascii')]
+ ---- DATA
+
+ -rw-r--r-- 4 bar
+
+
+ ---- ERRORS
+
+
+ $ cd ..
diff --git a/tests/test-hgweb-non-interactive.t b/tests/test-hgweb-non-interactive.t
new file mode 100644
index 0000000..da04036
--- /dev/null
+++ b/tests/test-hgweb-non-interactive.t
@@ -0,0 +1,82 @@
+Tests if hgweb can run without touching sys.stdin, as is required
+by the WSGI standard and strictly implemented by mod_wsgi.
+
+ $ hg init repo
+ $ cd repo
+ $ echo foo > bar
+ $ hg add bar
+ $ hg commit -m "test"
+ $ cat > request.py <<EOF
+ > from mercurial import dispatch
+ > from mercurial.hgweb.hgweb_mod import hgweb
+ > from mercurial.ui import ui
+ > from mercurial import hg
+ > from StringIO import StringIO
+ > import os, sys
+ >
+ > class FileLike(object):
+ > def __init__(self, real):
+ > self.real = real
+ > def fileno(self):
+ > print >> sys.__stdout__, 'FILENO'
+ > return self.real.fileno()
+ > def read(self):
+ > print >> sys.__stdout__, 'READ'
+ > return self.real.read()
+ > def readline(self):
+ > print >> sys.__stdout__, 'READLINE'
+ > return self.real.readline()
+ >
+ > sys.stdin = FileLike(sys.stdin)
+ > errors = StringIO()
+ > input = StringIO()
+ > output = StringIO()
+ >
+ > def startrsp(status, headers):
+ > print '---- STATUS'
+ > print status
+ > print '---- HEADERS'
+ > print [i for i in headers if i[0] != 'ETag']
+ > print '---- DATA'
+ > return output.write
+ >
+ > env = {
+ > 'wsgi.version': (1, 0),
+ > 'wsgi.url_scheme': 'http',
+ > 'wsgi.errors': errors,
+ > 'wsgi.input': input,
+ > 'wsgi.multithread': False,
+ > 'wsgi.multiprocess': False,
+ > 'wsgi.run_once': False,
+ > 'REQUEST_METHOD': 'GET',
+ > 'SCRIPT_NAME': '',
+ > 'PATH_INFO': '',
+ > 'QUERY_STRING': '',
+ > 'SERVER_NAME': '127.0.0.1',
+ > 'SERVER_PORT': os.environ['HGPORT'],
+ > 'SERVER_PROTOCOL': 'HTTP/1.0'
+ > }
+ >
+ > i = hgweb('.')
+ > i(env, startrsp)
+ > print '---- ERRORS'
+ > print errors.getvalue()
+ > print '---- OS.ENVIRON wsgi variables'
+ > print sorted([x for x in os.environ if x.startswith('wsgi')])
+ > print '---- request.ENVIRON wsgi variables'
+ > print sorted([x for x in i.repo.ui.environ if x.startswith('wsgi')])
+ > EOF
+ $ python request.py
+ ---- STATUS
+ 200 Script output follows
+ ---- HEADERS
+ [('Content-Type', 'text/html; charset=ascii')]
+ ---- DATA
+ ---- ERRORS
+
+ ---- OS.ENVIRON wsgi variables
+ []
+ ---- request.ENVIRON wsgi variables
+ ['wsgi.errors', 'wsgi.input', 'wsgi.multiprocess', 'wsgi.multithread', 'wsgi.run_once', 'wsgi.url_scheme', 'wsgi.version']
+
+ $ cd ..
diff --git a/tests/test-hgweb-raw.t b/tests/test-hgweb-raw.t
new file mode 100644
index 0000000..b982ba3
--- /dev/null
+++ b/tests/test-hgweb-raw.t
@@ -0,0 +1,58 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+Test raw style of hgweb
+
+ $ hg init test
+ $ cd test
+ $ mkdir sub
+ $ cat >'sub/some text%.txt' <<ENDSOME
+ > This is just some random text
+ > that will go inside the file and take a few lines.
+ > It is very boring to read, but computers don't
+ > care about things like that.
+ > ENDSOME
+ $ hg add 'sub/some text%.txt'
+ $ hg commit -d "1 0" -m "Just some text"
+
+ $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid
+
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '?f=bf0ff59095c9;file=sub/some%20text%25.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
+
+ $ while kill `cat hg.pid` 2>/dev/null; do sleep 0; done
+
+ $ cat getoutput.txt
+ 200 Script output follows
+ content-type: application/binary
+ content-length: 157
+ content-disposition: inline; filename="some text%.txt"
+
+ This is just some random text
+ that will go inside the file and take a few lines.
+ It is very boring to read, but computers don't
+ care about things like that.
+ $ cat access.log error.log
+ 127.0.0.1 - - [*] "GET /?f=bf0ff59095c9;file=sub/some%20text%25.txt;style=raw HTTP/1.1" 200 - (glob)
+
+ $ rm access.log error.log
+ $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid \
+ > --config web.guessmime=True
+
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '?f=bf0ff59095c9;file=sub/some%20text%25.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
+ $ while kill `cat hg.pid` 2>/dev/null; do sleep 0; done
+
+ $ cat getoutput.txt
+ 200 Script output follows
+ content-type: text/plain; charset="ascii"
+ content-length: 157
+ content-disposition: inline; filename="some text%.txt"
+
+ This is just some random text
+ that will go inside the file and take a few lines.
+ It is very boring to read, but computers don't
+ care about things like that.
+ $ cat access.log error.log
+ 127.0.0.1 - - [*] "GET /?f=bf0ff59095c9;file=sub/some%20text%25.txt;style=raw HTTP/1.1" 200 - (glob)
+
+ $ cd ..
diff --git a/tests/test-hgweb-removed.t b/tests/test-hgweb-removed.t
new file mode 100644
index 0000000..d96997c
--- /dev/null
+++ b/tests/test-hgweb-removed.t
@@ -0,0 +1,236 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+setting up repo
+
+ $ hg init test
+ $ cd test
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+ $ hg rm a
+ $ hg ci -mdel
+
+set up hgweb
+
+ $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+revision
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: c78f6c5cbea9</title>
+ </head>
+ <body>
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/c78f6c5cbea9">log</a></li>
+ <li><a href="/graph/c78f6c5cbea9">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li class="active">changeset</li>
+ <li><a href="/raw-rev/c78f6c5cbea9">raw</a></li>
+ <li><a href="/file/c78f6c5cbea9">browse</a></li>
+ </ul>
+ <ul>
+
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+
+ <h2><a href="/">test</a></h2>
+ <h3>changeset 1:c78f6c5cbea9 <span class="tag">tip</span> </h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">del</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th class="author">author</th>
+ <td class="author">&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th class="date">date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
+ <tr>
+ <th class="author">parents</th>
+ <td class="author"><a href="/rev/cb9a9f314b8b">cb9a9f314b8b</a> </td>
+ </tr>
+ <tr>
+ <th class="author">children</th>
+ <td class="author"></td>
+ </tr>
+ <tr>
+ <th class="files">files</th>
+ <td class="files">a </td>
+ </tr>
+ <tr>
+ <th class="diffstat">diffstat</th>
+ <td class="diffstat">
+ 1 files changed, 0 insertions(+), 1 deletions(-)
+
+ <a id="diffstatexpand" href="javascript:showDiffstat()"/>[<tt>+</tt>]</a>
+ <div id="diffstatdetails" style="display:none;">
+ <a href="javascript:hideDiffstat()"/>[<tt>-</tt>]</a>
+ <p>
+ <table> <tr class="parity0">
+ <td class="diffstat-file"><a href="#l1.1">a</a></td>
+ <td class="diffstat-total" align="right">1</td>
+ <td class="diffstat-graph">
+ <span class="diffstat-add" style="width:0.0%;">&nbsp;</span>
+ <span class="diffstat-remove" style="width:100.0%;">&nbsp;</span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> line diff</div>
+
+ <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- a/a Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -1,1 +0,0 @@
+ </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="minusline">-a
+ </span></pre></div>
+ </div>
+
+ </div>
+ </div>
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+diff removed file
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/a'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: a diff</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/c78f6c5cbea9">log</a></li>
+ <li><a href="/graph/c78f6c5cbea9">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/c78f6c5cbea9">changeset</a></li>
+ <li><a href="/file/c78f6c5cbea9">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/file/c78f6c5cbea9/a">file</a></li>
+ <li><a href="/file/tip/a">latest</a></li>
+ <li class="active">diff</li>
+ <li><a href="/comparison/c78f6c5cbea9/a">comparison</a></li>
+ <li><a href="/annotate/c78f6c5cbea9/a">annotate</a></li>
+ <li><a href="/log/c78f6c5cbea9/a">file log</a></li>
+ <li><a href="/raw-file/c78f6c5cbea9/a">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>diff a @ 1:c78f6c5cbea9</h3>
+
+ <form class="search" action="/log">
+ <p></p>
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">del</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th>author</th>
+ <td>&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th>date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ </tr>
+ <tr>
+ <th>parents</th>
+ <td><a href="/file/cb9a9f314b8b/a">cb9a9f314b8b</a> </td>
+ </tr>
+ <tr>
+ <th>children</th>
+ <td></td>
+ </tr>
+
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> line diff</div>
+
+ <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- a/a Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
+ </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -1,1 +0,0 @@
+ </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="minusline">-a
+ </span></pre></div>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+ $ cd ..
diff --git a/tests/test-hgweb.t b/tests/test-hgweb.t
new file mode 100644
index 0000000..e8846a3
--- /dev/null
+++ b/tests/test-hgweb.t
@@ -0,0 +1,492 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+Some tests for hgweb. Tests static files, plain files and different 404's.
+
+ $ hg init test
+ $ cd test
+ $ mkdir da
+ $ echo foo > da/foo
+ $ echo foo > foo
+ $ hg ci -Ambase
+ adding da/foo
+ adding foo
+ $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+manifest
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/?style=raw')
+ 200 Script output follows
+
+
+ drwxr-xr-x da
+ -rw-r--r-- 4 foo
+
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/da?style=raw')
+ 200 Script output follows
+
+
+ -rw-r--r-- 4 foo
+
+
+
+plain file
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/foo?style=raw'
+ 200 Script output follows
+
+ foo
+
+should give a 404 - static file that does not exist
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'static/bogus'
+ 404 Not Found
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: error</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog">log</a></li>
+ <li><a href="/graph">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+
+ <h2><a href="/">test</a></h2>
+ <h3>error</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30"></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">
+ <p>
+ An error occurred while processing your request:
+ </p>
+ <p>
+ Not Found
+ </p>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ [1]
+
+should give a 404 - bad revision
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/spam/foo?style=raw'
+ 404 Not Found
+
+
+ error: revision not found: spam
+ [1]
+
+should give a 400 - bad command
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/foo?cmd=spam&style=raw'
+ 400* (glob)
+
+
+ error: no such method: spam
+ [1]
+
+should give a 404 - file does not exist
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/bork?style=raw'
+ 404 Not Found
+
+
+ error: bork@2ef0ac749a14: not found in manifest
+ [1]
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/bork'
+ 404 Not Found
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: error</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog">log</a></li>
+ <li><a href="/graph">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+
+ <h2><a href="/">test</a></h2>
+ <h3>error</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30"></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">
+ <p>
+ An error occurred while processing your request:
+ </p>
+ <p>
+ bork@2ef0ac749a14: not found in manifest
+ </p>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ [1]
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/bork?style=raw'
+ 404 Not Found
+
+
+ error: bork@2ef0ac749a14: not found in manifest
+ [1]
+
+try bad style
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/?style=foobar')
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: 2ef0ac749a14 /</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/2ef0ac749a14">log</a></li>
+ <li><a href="/graph/2ef0ac749a14">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/2ef0ac749a14">changeset</a></li>
+ <li class="active">browse</li>
+ </ul>
+ <ul>
+
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>directory / @ 0:2ef0ac749a14 <span class="tag">tip</span> </h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <table class="bigtable">
+ <tr>
+ <th class="name">name</th>
+ <th class="size">size</th>
+ <th class="permissions">permissions</th>
+ </tr>
+ <tr class="fileline parity0">
+ <td class="name"><a href="/file/2ef0ac749a14/">[up]</a></td>
+ <td class="size"></td>
+ <td class="permissions">drwxr-xr-x</td>
+ </tr>
+
+ <tr class="fileline parity1">
+ <td class="name">
+ <a href="/file/2ef0ac749a14/da">
+ <img src="/static/coal-folder.png" alt="dir."/> da/
+ </a>
+ <a href="/file/2ef0ac749a14/da/">
+
+ </a>
+ </td>
+ <td class="size"></td>
+ <td class="permissions">drwxr-xr-x</td>
+ </tr>
+
+ <tr class="fileline parity0">
+ <td class="filename">
+ <a href="/file/2ef0ac749a14/foo">
+ <img src="/static/coal-file.png" alt="file"/> foo
+ </a>
+ </td>
+ <td class="size">4</td>
+ <td class="permissions">-rw-r--r--</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+stop and restart
+
+ $ "$TESTDIR/killdaemons.py"
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+Test the access/error files are opened in append mode
+
+ $ python -c "print len(file('access.log').readlines()), 'log lines written'"
+ 10 log lines written
+
+static file
+
+ $ "$TESTDIR/get-with-headers.py" --twice localhost:$HGPORT 'static/style-gitweb.css'
+ 200 Script output follows
+
+ body { font-family: sans-serif; font-size: 12px; margin:0px; border:solid #d9d8d1; border-width:1px; margin:10px; }
+ a { color:#0000cc; }
+ a:hover, a:visited, a:active { color:#880000; }
+ div.page_header { height:25px; padding:8px; font-size:18px; font-weight:bold; background-color:#d9d8d1; }
+ div.page_header a:visited { color:#0000cc; }
+ div.page_header a:hover { color:#880000; }
+ div.page_nav { padding:8px; }
+ div.page_nav a:visited { color:#0000cc; }
+ div.page_path { padding:8px; border:solid #d9d8d1; border-width:0px 0px 1px}
+ div.page_footer { padding:4px 8px; background-color: #d9d8d1; }
+ div.page_footer_text { float:left; color:#555555; font-style:italic; }
+ div.page_body { padding:8px; }
+ div.title, a.title {
+ display:block; padding:6px 8px;
+ font-weight:bold; background-color:#edece6; text-decoration:none; color:#000000;
+ }
+ a.title:hover { background-color: #d9d8d1; }
+ div.title_text { padding:6px 0px; border: solid #d9d8d1; border-width:0px 0px 1px; }
+ div.log_body { padding:8px 8px 8px 150px; }
+ .age { white-space:nowrap; }
+ span.age { position:relative; float:left; width:142px; font-style:italic; }
+ div.log_link {
+ padding:0px 8px;
+ font-size:10px; font-family:sans-serif; font-style:normal;
+ position:relative; float:left; width:136px;
+ }
+ div.list_head { padding:6px 8px 4px; border:solid #d9d8d1; border-width:1px 0px 0px; font-style:italic; }
+ a.list { text-decoration:none; color:#000000; }
+ a.list:hover { text-decoration:underline; color:#880000; }
+ table { padding:8px 4px; }
+ th { padding:2px 5px; font-size:12px; text-align:left; }
+ tr.light:hover, .parity0:hover { background-color:#edece6; }
+ tr.dark, .parity1 { background-color:#f6f6f0; }
+ tr.dark:hover, .parity1:hover { background-color:#edece6; }
+ td { padding:2px 5px; font-size:12px; vertical-align:top; }
+ td.closed { background-color: #99f; }
+ td.link { padding:2px 5px; font-family:sans-serif; font-size:10px; }
+ td.indexlinks { white-space: nowrap; }
+ td.indexlinks a {
+ padding: 2px 5px; line-height: 10px;
+ border: 1px solid;
+ color: #ffffff; background-color: #7777bb;
+ border-color: #aaaadd #333366 #333366 #aaaadd;
+ font-weight: bold; text-align: center; text-decoration: none;
+ font-size: 10px;
+ }
+ td.indexlinks a:hover { background-color: #6666aa; }
+ div.pre { font-family:monospace; font-size:12px; white-space:pre; }
+ div.diff_info { font-family:monospace; color:#000099; background-color:#edece6; font-style:italic; }
+ div.index_include { border:solid #d9d8d1; border-width:0px 0px 1px; padding:12px 8px; }
+ div.search { margin:4px 8px; position:absolute; top:56px; right:12px }
+ .linenr { color:#999999; text-decoration:none }
+ div.rss_logo { float: right; white-space: nowrap; }
+ div.rss_logo a {
+ padding:3px 6px; line-height:10px;
+ border:1px solid; border-color:#fcc7a5 #7d3302 #3e1a01 #ff954e;
+ color:#ffffff; background-color:#ff6600;
+ font-weight:bold; font-family:sans-serif; font-size:10px;
+ text-align:center; text-decoration:none;
+ }
+ div.rss_logo a:hover { background-color:#ee5500; }
+ pre { margin: 0; }
+ span.logtags span {
+ padding: 0px 4px;
+ font-size: 10px;
+ font-weight: normal;
+ border: 1px solid;
+ background-color: #ffaaff;
+ border-color: #ffccff #ff00ee #ff00ee #ffccff;
+ }
+ span.logtags span.tagtag {
+ background-color: #ffffaa;
+ border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
+ }
+ span.logtags span.branchtag {
+ background-color: #aaffaa;
+ border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
+ }
+ span.logtags span.inbranchtag {
+ background-color: #d5dde6;
+ border-color: #e3ecf4 #9398f4 #9398f4 #e3ecf4;
+ }
+ span.logtags span.bookmarktag {
+ background-color: #afdffa;
+ border-color: #ccecff #46ace6 #46ace6 #ccecff;
+ }
+
+ /* Graph */
+ div#wrapper {
+ position: relative;
+ margin: 0;
+ padding: 0;
+ margin-top: 3px;
+ }
+
+ canvas {
+ position: absolute;
+ z-index: 5;
+ top: -0.9em;
+ margin: 0;
+ }
+
+ ul#nodebgs {
+ list-style: none inside none;
+ padding: 0;
+ margin: 0;
+ top: -0.7em;
+ }
+
+ ul#graphnodes li, ul#nodebgs li {
+ height: 39px;
+ }
+
+ ul#graphnodes {
+ position: absolute;
+ z-index: 10;
+ top: -0.8em;
+ list-style: none inside none;
+ padding: 0;
+ }
+
+ ul#graphnodes li .info {
+ display: block;
+ font-size: 100%;
+ position: relative;
+ top: -3px;
+ font-style: italic;
+ }
+
+ /* Comparison */
+ .legend {
+ padding: 1.5% 0 1.5% 0;
+ }
+
+ .legendinfo {
+ border: 1px solid #d9d8d1;
+ font-size: 80%;
+ text-align: center;
+ padding: 0.5%;
+ }
+
+ .equal {
+ background-color: #ffffff;
+ }
+
+ .delete {
+ background-color: #faa;
+ color: #333;
+ }
+
+ .insert {
+ background-color: #ffa;
+ }
+
+ .replace {
+ background-color: #e8e8e8;
+ }
+
+ .comparison {
+ overflow-x: auto;
+ }
+
+ .header th {
+ text-align: center;
+ }
+
+ .block {
+ border-top: 1px solid #d9d8d1;
+ }
+ 304 Not Modified
+
+
+errors
+
+ $ cat errors.log
+
+ $ cd ..
diff --git a/tests/test-hgwebdir-paths.py b/tests/test-hgwebdir-paths.py
new file mode 100644
index 0000000..b9118b3
--- /dev/null
+++ b/tests/test-hgwebdir-paths.py
@@ -0,0 +1,40 @@
+import os
+from mercurial import hg, ui
+from mercurial.hgweb.hgwebdir_mod import hgwebdir
+
+os.mkdir('webdir')
+os.chdir('webdir')
+
+webdir = os.path.realpath('.')
+
+u = ui.ui()
+hg.repository(u, 'a', create=1)
+hg.repository(u, 'b', create=1)
+os.chdir('b')
+hg.repository(u, 'd', create=1)
+os.chdir('..')
+hg.repository(u, 'c', create=1)
+os.chdir('..')
+
+paths = {'t/a/': '%s/a' % webdir,
+ 'b': '%s/b' % webdir,
+ 'coll': '%s/*' % webdir,
+ 'rcoll': '%s/**' % webdir}
+
+config = os.path.join(webdir, 'hgwebdir.conf')
+configfile = open(config, 'w')
+configfile.write('[paths]\n')
+for k, v in paths.items():
+ configfile.write('%s = %s\n' % (k, v))
+configfile.close()
+
+confwd = hgwebdir(config)
+dictwd = hgwebdir(paths)
+
+assert len(confwd.repos) == len(dictwd.repos), 'different numbers'
+assert len(confwd.repos) == 9, 'expected 9 repos, found %d' % len(confwd.repos)
+
+found = dict(confwd.repos)
+for key, path in dictwd.repos:
+ assert key in found, 'repository %s was not found' % key
+ assert found[key] == path, 'different paths for repo %s' % key
diff --git a/tests/test-hgwebdir.t b/tests/test-hgwebdir.t
new file mode 100644
index 0000000..4e3a58b
--- /dev/null
+++ b/tests/test-hgwebdir.t
@@ -0,0 +1,1015 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+hide outer repo and work in dir without '.hg'
+ $ hg init
+ $ mkdir dir
+ $ cd dir
+
+Tests some basic hgwebdir functionality. Tests setting up paths and
+collection, different forms of 404s and the subdirectory support.
+
+ $ mkdir webdir
+ $ cd webdir
+ $ hg init a
+ $ echo a > a/a
+ $ hg --cwd a ci -Ama -d'1 0'
+ adding a
+
+create a mercurial queue repository
+
+ $ hg --cwd a qinit --config extensions.hgext.mq= -c
+ $ hg init b
+ $ echo b > b/b
+ $ hg --cwd b ci -Amb -d'2 0'
+ adding b
+
+create a nested repository
+
+ $ cd b
+ $ hg init d
+ $ echo d > d/d
+ $ hg --cwd d ci -Amd -d'3 0'
+ adding d
+ $ cd ..
+ $ hg init c
+ $ echo c > c/c
+ $ hg --cwd c ci -Amc -d'3 0'
+ adding c
+
+create a subdirectory containing repositories and subrepositories
+
+ $ mkdir notrepo
+ $ cd notrepo
+ $ hg init e
+ $ echo e > e/e
+ $ hg --cwd e ci -Ame -d'4 0'
+ adding e
+ $ hg init e/e2
+ $ echo e2 > e/e2/e2
+ $ hg --cwd e/e2 ci -Ame2 -d '4 0'
+ adding e2
+ $ hg init f
+ $ echo f > f/f
+ $ hg --cwd f ci -Amf -d'4 0'
+ adding f
+ $ hg init f/f2
+ $ echo f2 > f/f2/f2
+ $ hg --cwd f/f2 ci -Amf2 -d '4 0'
+ adding f2
+ $ cd ..
+
+create repository without .hg/store
+
+ $ hg init nostore
+ $ rm -R nostore/.hg/store
+ $ root=`pwd`
+ $ cd ..
+
+serve
+ $ cat > paths.conf <<EOF
+ > [paths]
+ > a=$root/a
+ > b=$root/b
+ > EOF
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf paths.conf \
+ > -A access-paths.log -E error-paths-1.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+should give a 404 - file does not exist
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/file/tip/bork?style=raw'
+ 404 Not Found
+
+
+ error: bork@8580ff50825a: not found in manifest
+ [1]
+
+should succeed
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '?style=raw'
+ 200 Script output follows
+
+
+ /a/
+ /b/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/file/tip/a?style=raw'
+ 200 Script output follows
+
+ a
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'b/file/tip/b?style=raw'
+ 200 Script output follows
+
+ b
+
+should give a 404 - repo is not published
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'c/file/tip/c?style=raw'
+ 404 Not Found
+
+
+ error: repository c/file/tip/c not found
+ [1]
+
+atom-log without basedir
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/atom-log' | grep '<link'
+ <link rel="self" href="http://*:$HGPORT/a/atom-log"/> (glob)
+ <link rel="alternate" href="http://*:$HGPORT/a/"/> (glob)
+ <link href="http://*:$HGPORT/a/rev/8580ff50825a"/> (glob)
+
+rss-log without basedir
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/rss-log' | grep '<guid'
+ <guid isPermaLink="true">http://*:$HGPORT/a/rev/8580ff50825a</guid> (glob)
+ $ cat > paths.conf <<EOF
+ > [paths]
+ > t/a/=$root/a
+ > b=$root/b
+ > coll=$root/*
+ > rcoll=$root/**
+ > star=*
+ > starstar=**
+ > astar=webdir/a/*
+ > EOF
+ $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
+ > -A access-paths.log -E error-paths-2.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+should succeed, slashy names
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
+ 200 Script output follows
+
+
+ /t/a/
+ /b/
+ /coll/a/
+ /coll/a/.hg/patches/
+ /coll/b/
+ /coll/c/
+ /coll/notrepo/e/
+ /coll/notrepo/f/
+ /rcoll/a/
+ /rcoll/a/.hg/patches/
+ /rcoll/b/
+ /rcoll/b/d/
+ /rcoll/c/
+ /rcoll/notrepo/e/
+ /rcoll/notrepo/e/e2/
+ /rcoll/notrepo/f/
+ /rcoll/notrepo/f/f2/
+ /star/webdir/a/
+ /star/webdir/a/.hg/patches/
+ /star/webdir/b/
+ /star/webdir/c/
+ /star/webdir/notrepo/e/
+ /star/webdir/notrepo/f/
+ /starstar/webdir/a/
+ /starstar/webdir/a/.hg/patches/
+ /starstar/webdir/b/
+ /starstar/webdir/b/d/
+ /starstar/webdir/c/
+ /starstar/webdir/notrepo/e/
+ /starstar/webdir/notrepo/e/e2/
+ /starstar/webdir/notrepo/f/
+ /starstar/webdir/notrepo/f/f2/
+ /astar/
+ /astar/.hg/patches/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=paper'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>Mercurial repositories index</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
+ </div>
+ <div class="main">
+ <h2>Mercurial Repositories</h2>
+
+ <table class="bigtable">
+ <tr>
+ <th><a href="?sort=name">Name</a></th>
+ <th><a href="?sort=description">Description</a></th>
+ <th><a href="?sort=contact">Contact</a></th>
+ <th><a href="?sort=lastchange">Last modified</a></th>
+ <th>&nbsp;</th>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/t/a/?style=paper">t/a</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/b/?style=paper">b</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/coll/a/?style=paper">coll/a</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/coll/a/.hg/patches/?style=paper">coll/a/.hg/patches</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/coll/b/?style=paper">coll/b</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/coll/c/?style=paper">coll/c</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/coll/notrepo/e/?style=paper">coll/notrepo/e</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/coll/notrepo/f/?style=paper">coll/notrepo/f</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/rcoll/a/.hg/patches/?style=paper">rcoll/a/.hg/patches</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/rcoll/b/?style=paper">rcoll/b</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/rcoll/b/d/?style=paper">rcoll/b/d</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/rcoll/c/?style=paper">rcoll/c</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/rcoll/notrepo/e/?style=paper">rcoll/notrepo/e</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/rcoll/notrepo/e/e2/?style=paper">rcoll/notrepo/e/e2</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/rcoll/notrepo/f/?style=paper">rcoll/notrepo/f</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/rcoll/notrepo/f/f2/?style=paper">rcoll/notrepo/f/f2</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/star/webdir/a/?style=paper">star/webdir/a</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/star/webdir/a/.hg/patches/?style=paper">star/webdir/a/.hg/patches</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/star/webdir/b/?style=paper">star/webdir/b</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/star/webdir/c/?style=paper">star/webdir/c</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/star/webdir/notrepo/e/?style=paper">star/webdir/notrepo/e</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/star/webdir/notrepo/f/?style=paper">star/webdir/notrepo/f</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/starstar/webdir/a/?style=paper">starstar/webdir/a</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/starstar/webdir/a/.hg/patches/?style=paper">starstar/webdir/a/.hg/patches</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/starstar/webdir/b/?style=paper">starstar/webdir/b</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/starstar/webdir/b/d/?style=paper">starstar/webdir/b/d</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/starstar/webdir/c/?style=paper">starstar/webdir/c</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/starstar/webdir/notrepo/e/?style=paper">starstar/webdir/notrepo/e</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/starstar/webdir/notrepo/e/e2/?style=paper">starstar/webdir/notrepo/e/e2</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/starstar/webdir/notrepo/f/?style=paper">starstar/webdir/notrepo/f</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/starstar/webdir/notrepo/f/f2/?style=paper">starstar/webdir/notrepo/f/f2</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/astar/?style=paper">astar</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/astar/.hg/patches/?style=paper">astar/.hg/patches</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ </table>
+ </div>
+ </div>
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't?style=raw'
+ 200 Script output follows
+
+
+ /t/a/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
+ 200 Script output follows
+
+
+ /t/a/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=paper'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>Mercurial repositories index</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
+ </div>
+ <div class="main">
+ <h2>Mercurial Repositories</h2>
+
+ <table class="bigtable">
+ <tr>
+ <th><a href="?sort=name">Name</a></th>
+ <th><a href="?sort=description">Description</a></th>
+ <th><a href="?sort=contact">Contact</a></th>
+ <th><a href="?sort=lastchange">Last modified</a></th>
+ <th>&nbsp;</th>
+ </tr>
+
+ <tr class="parity0">
+ <td><a href="/t/a/?style=paper">a</a></td>
+ <td>unknown</td>
+ <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
+ <td class="age">*</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ </table>
+ </div>
+ </div>
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a?style=atom'
+ 200 Script output follows
+
+ <?xml version="1.0" encoding="ascii"?>
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <!-- Changelog -->
+ <id>http://*:$HGPORT1/t/a/</id> (glob)
+ <link rel="self" href="http://*:$HGPORT1/t/a/atom-log"/> (glob)
+ <link rel="alternate" href="http://*:$HGPORT1/t/a/"/> (glob)
+ <title>t/a Changelog</title>
+ <updated>1970-01-01T00:00:01+00:00</updated>
+
+ <entry>
+ <title>a</title>
+ <id>http://*:$HGPORT1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id> (glob)
+ <link href="http://*:$HGPORT1/t/a/rev/8580ff50825a"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:01+00:00</updated>
+ <published>1970-01-01T00:00:01+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">a</pre>
+ </div>
+ </content>
+ </entry>
+
+ </feed>
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a/?style=atom'
+ 200 Script output follows
+
+ <?xml version="1.0" encoding="ascii"?>
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <!-- Changelog -->
+ <id>http://*:$HGPORT1/t/a/</id> (glob)
+ <link rel="self" href="http://*:$HGPORT1/t/a/atom-log"/> (glob)
+ <link rel="alternate" href="http://*:$HGPORT1/t/a/"/> (glob)
+ <title>t/a Changelog</title>
+ <updated>1970-01-01T00:00:01+00:00</updated>
+
+ <entry>
+ <title>a</title>
+ <id>http://*:$HGPORT1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id> (glob)
+ <link href="http://*:$HGPORT1/t/a/rev/8580ff50825a"/> (glob)
+ <author>
+ <name>test</name>
+ <email>&#116;&#101;&#115;&#116;</email>
+ </author>
+ <updated>1970-01-01T00:00:01+00:00</updated>
+ <published>1970-01-01T00:00:01+00:00</published>
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <pre xml:space="preserve">a</pre>
+ </div>
+ </content>
+ </entry>
+
+ </feed>
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a/file/tip/a?style=raw'
+ 200 Script output follows
+
+ a
+
+Test [paths] '*' extension
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
+ 200 Script output follows
+
+
+ /coll/a/
+ /coll/a/.hg/patches/
+ /coll/b/
+ /coll/c/
+ /coll/notrepo/e/
+ /coll/notrepo/f/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
+ 200 Script output follows
+
+ a
+
+Test [paths] '**' extension
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
+ 200 Script output follows
+
+
+ /rcoll/a/
+ /rcoll/a/.hg/patches/
+ /rcoll/b/
+ /rcoll/b/d/
+ /rcoll/c/
+ /rcoll/notrepo/e/
+ /rcoll/notrepo/e/e2/
+ /rcoll/notrepo/f/
+ /rcoll/notrepo/f/f2/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
+ 200 Script output follows
+
+ d
+
+Test collapse = True
+
+ $ "$TESTDIR/killdaemons.py"
+ $ cat >> paths.conf <<EOF
+ > [web]
+ > collapse=true
+ > EOF
+ $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
+ > -A access-paths.log -E error-paths-3.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
+ 200 Script output follows
+
+
+ /coll/a/
+ /coll/a/.hg/patches/
+ /coll/b/
+ /coll/c/
+ /coll/notrepo/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
+ 200 Script output follows
+
+ a
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
+ 200 Script output follows
+
+
+ /rcoll/a/
+ /rcoll/a/.hg/patches/
+ /rcoll/b/
+ /rcoll/b/d/
+ /rcoll/c/
+ /rcoll/notrepo/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
+ 200 Script output follows
+
+ d
+
+Test intermediate directories
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
+ 200 Script output follows
+
+
+ /rcoll/notrepo/e/
+ /rcoll/notrepo/e/e2/
+ /rcoll/notrepo/f/
+ /rcoll/notrepo/f/f2/
+
+
+Test repositories inside intermediate directories
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/e/file/tip/e?style=raw'
+ 200 Script output follows
+
+ e
+
+Test subrepositories inside intermediate directories
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/f/f2/file/tip/f2?style=raw'
+ 200 Script output follows
+
+ f2
+
+Test descend = False
+
+ $ "$TESTDIR/killdaemons.py"
+ $ cat >> paths.conf <<EOF
+ > descend=false
+ > EOF
+ $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
+ > -A access-paths.log -E error-paths-4.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
+ 200 Script output follows
+
+
+ /coll/a/
+ /coll/b/
+ /coll/c/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
+ 200 Script output follows
+
+ a
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
+ 200 Script output follows
+
+
+ /rcoll/a/
+ /rcoll/b/
+ /rcoll/c/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
+ 200 Script output follows
+
+ d
+
+Test intermediate directories
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
+ 200 Script output follows
+
+
+ /rcoll/notrepo/e/
+ /rcoll/notrepo/f/
+
+
+Test repositories inside intermediate directories
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/e/file/tip/e?style=raw'
+ 200 Script output follows
+
+ e
+
+Test subrepositories inside intermediate directories
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/f/f2/file/tip/f2?style=raw'
+ 200 Script output follows
+
+ f2
+
+Test [paths] '*' in a repo root
+
+ $ hg id http://localhost:$HGPORT1/astar
+ 8580ff50825a
+
+ $ "$TESTDIR/killdaemons.py"
+ $ cat > paths.conf <<EOF
+ > [paths]
+ > t/a = $root/a
+ > t/b = $root/b
+ > c = $root/c
+ > EOF
+ $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
+ > -A access-paths.log -E error-paths-5.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
+ 200 Script output follows
+
+
+ /t/a/
+ /t/b/
+ /c/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
+ 200 Script output follows
+
+
+ /t/a/
+ /t/b/
+
+
+Test collapse = True
+
+ $ "$TESTDIR/killdaemons.py"
+ $ cat >> paths.conf <<EOF
+ > [web]
+ > collapse=true
+ > EOF
+ $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
+ > -A access-paths.log -E error-paths-6.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
+ 200 Script output follows
+
+
+ /t/
+ /c/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
+ 200 Script output follows
+
+
+ /t/a/
+ /t/b/
+
+
+test descend = False
+
+ $ "$TESTDIR/killdaemons.py"
+ $ cat >> paths.conf <<EOF
+ > descend=false
+ > EOF
+ $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
+ > -A access-paths.log -E error-paths-7.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
+ 200 Script output follows
+
+
+ /c/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
+ 200 Script output follows
+
+
+ /t/a/
+ /t/b/
+
+ $ "$TESTDIR/killdaemons.py"
+ $ cat > paths.conf <<EOF
+ > [paths]
+ > nostore = $root/nostore
+ > inexistent = $root/inexistent
+ > EOF
+ $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
+ > -A access-paths.log -E error-paths-8.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+test inexistent and inaccessible repo should be ignored silently
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 ''
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>Mercurial repositories index</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
+ </div>
+ <div class="main">
+ <h2>Mercurial Repositories</h2>
+
+ <table class="bigtable">
+ <tr>
+ <th><a href="?sort=name">Name</a></th>
+ <th><a href="?sort=description">Description</a></th>
+ <th><a href="?sort=contact">Contact</a></th>
+ <th><a href="?sort=lastchange">Last modified</a></th>
+ <th>&nbsp;</th>
+ </tr>
+
+ </table>
+ </div>
+ </div>
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+ $ cat > collections.conf <<EOF
+ > [collections]
+ > $root=$root
+ > EOF
+ $ hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
+ > --pid-file=hg.pid --webdir-conf collections.conf \
+ > -A access-collections.log -E error-collections.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+collections: should succeed
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '?style=raw'
+ 200 Script output follows
+
+
+ /a/
+ /a/.hg/patches/
+ /b/
+ /c/
+ /notrepo/e/
+ /notrepo/f/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/file/tip/a?style=raw'
+ 200 Script output follows
+
+ a
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'b/file/tip/b?style=raw'
+ 200 Script output follows
+
+ b
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'c/file/tip/c?style=raw'
+ 200 Script output follows
+
+ c
+
+atom-log with basedir /
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/atom-log' | grep '<link'
+ <link rel="self" href="http://hg.example.com:8080/a/atom-log"/>
+ <link rel="alternate" href="http://hg.example.com:8080/a/"/>
+ <link href="http://hg.example.com:8080/a/rev/8580ff50825a"/>
+
+rss-log with basedir /
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/rss-log' | grep '<guid'
+ <guid isPermaLink="true">http://hg.example.com:8080/a/rev/8580ff50825a</guid>
+ $ "$TESTDIR/killdaemons.py"
+ $ hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
+ > --pid-file=hg.pid --webdir-conf collections.conf \
+ > -A access-collections-2.log -E error-collections-2.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+atom-log with basedir /foo/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/atom-log' | grep '<link'
+ <link rel="self" href="http://hg.example.com:8080/foo/a/atom-log"/>
+ <link rel="alternate" href="http://hg.example.com:8080/foo/a/"/>
+ <link href="http://hg.example.com:8080/foo/a/rev/8580ff50825a"/>
+
+rss-log with basedir /foo/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/rss-log' | grep '<guid'
+ <guid isPermaLink="true">http://hg.example.com:8080/foo/a/rev/8580ff50825a</guid>
+
+paths errors 1
+
+ $ cat error-paths-1.log
+
+paths errors 2
+
+ $ cat error-paths-2.log
+
+paths errors 3
+
+ $ cat error-paths-3.log
+
+paths errors 4
+
+ $ cat error-paths-4.log
+
+paths errors 5
+
+ $ cat error-paths-5.log
+
+paths errors 6
+
+ $ cat error-paths-6.log
+
+paths errors 7
+
+ $ cat error-paths-7.log
+
+paths errors 8
+
+ $ cat error-paths-8.log
+
+collections errors
+
+ $ cat error-collections.log
+
+collections errors 2
+
+ $ cat error-collections-2.log
diff --git a/tests/test-hgwebdirsym.t b/tests/test-hgwebdirsym.t
new file mode 100644
index 0000000..ee479e2
--- /dev/null
+++ b/tests/test-hgwebdirsym.t
@@ -0,0 +1,80 @@
+Tests whether or not hgwebdir properly handles various symlink topologies.
+
+ $ "$TESTDIR/hghave" serve symlink || exit 80
+
+hide outer repo
+ $ hg init
+
+ $ hg init a
+ $ echo a > a/a
+ $ hg --cwd a ci -Ama -d'1 0'
+ adding a
+ $ mkdir webdir
+ $ cd webdir
+ $ hg init b
+ $ echo b > b/b
+ $ hg --cwd b ci -Amb -d'2 0'
+ adding b
+ $ hg init c
+ $ echo c > c/c
+ $ hg --cwd c ci -Amc -d'3 0'
+ adding c
+ $ ln -s ../a al
+ $ ln -s ../webdir circle
+ $ root=`pwd`
+ $ cd ..
+ $ cat > collections.conf <<EOF
+ > [collections]
+ > $root=$root
+ > EOF
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf collections.conf \
+ > -A access-collections.log -E error-collections.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+should succeed
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '?style=raw'
+ 200 Script output follows
+
+
+ /al/
+ /b/
+ /c/
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'al/file/tip/a?style=raw'
+ 200 Script output follows
+
+ a
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'b/file/tip/b?style=raw'
+ 200 Script output follows
+
+ b
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'c/file/tip/c?style=raw'
+ 200 Script output follows
+
+ c
+
+should fail
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/al/file/tip/a?style=raw'
+ 404 Not Found
+
+
+ error: repository circle/al/file/tip/a not found
+ [1]
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/b/file/tip/a?style=raw'
+ 404 Not Found
+
+
+ error: repository circle/b/file/tip/a not found
+ [1]
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/c/file/tip/a?style=raw'
+ 404 Not Found
+
+
+ error: repository circle/c/file/tip/a not found
+ [1]
+
+collections errors
+
+ $ cat error-collections.log
diff --git a/tests/test-highlight.t b/tests/test-highlight.t
new file mode 100644
index 0000000..53ea7e1
--- /dev/null
+++ b/tests/test-highlight.t
@@ -0,0 +1,609 @@
+
+ $ "$TESTDIR/hghave" pygments serve || exit 80
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > highlight =
+ > [web]
+ > pygments_style = friendly
+ > EOF
+ $ hg init test
+ $ cd test
+
+create random Python file to exercise Pygments
+
+ $ cat <<EOF > primes.py
+ > #!/usr/bin/env python
+ >
+ > """Fun with generators. Corresponding Haskell implementation:
+ >
+ > primes = 2 : sieve [3, 5..]
+ > where sieve (p:ns) = p : sieve [n | n <- ns, mod n p /= 0]
+ > """
+ >
+ > from itertools import dropwhile, ifilter, islice, count, chain
+ >
+ > def primes():
+ > """Generate all primes."""
+ > def sieve(ns):
+ > p = ns.next()
+ > # It is important to yield *here* in order to stop the
+ > # infinite recursion.
+ > yield p
+ > ns = ifilter(lambda n: n % p != 0, ns)
+ > for n in sieve(ns):
+ > yield n
+ >
+ > odds = ifilter(lambda i: i % 2 == 1, count())
+ > return chain([2], sieve(dropwhile(lambda n: n < 3, odds)))
+ >
+ > if __name__ == "__main__":
+ > import sys
+ > try:
+ > n = int(sys.argv[1])
+ > except (ValueError, IndexError):
+ > n = 10
+ > p = primes()
+ > print "The first %d primes: %s" % (n, list(islice(p, n)))
+ > EOF
+ $ hg ci -Ama
+ adding primes.py
+
+hg serve
+
+ $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+hgweb filerevision, html
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/primes.py') \
+ > | sed "s/class=\"k\"/class=\"kn\"/g" | sed "s/class=\"mf\"/class=\"mi\"/g"
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <link rel="stylesheet" href="/highlightcss" type="text/css" />
+ <title>test: 853dcd4de2a6 primes.py</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/853dcd4de2a6">log</a></li>
+ <li><a href="/graph/853dcd4de2a6">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/853dcd4de2a6">changeset</a></li>
+ <li><a href="/file/853dcd4de2a6/">browse</a></li>
+ </ul>
+ <ul>
+ <li class="active">file</li>
+ <li><a href="/file/tip/primes.py">latest</a></li>
+ <li><a href="/diff/853dcd4de2a6/primes.py">diff</a></li>
+ <li><a href="/comparison/853dcd4de2a6/primes.py">comparison</a></li>
+ <li><a href="/annotate/853dcd4de2a6/primes.py">annotate</a></li>
+ <li><a href="/log/853dcd4de2a6/primes.py">file log</a></li>
+ <li><a href="/raw-file/853dcd4de2a6/primes.py">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>view primes.py @ 0:853dcd4de2a6</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">a</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th class="author">author</th>
+ <td class="author">&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th class="date">date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ </tr>
+ <tr>
+ <th class="author">parents</th>
+ <td class="author"></td>
+ </tr>
+ <tr>
+ <th class="author">children</th>
+ <td class="author"></td>
+ </tr>
+
+ </table>
+
+ <div class="overflow">
+ <div class="sourcefirst"> line source</div>
+
+ <div class="parity0 source"><a href="#l1" id="l1"> 1</a> <span class="c">#!/usr/bin/env python</span></div>
+ <div class="parity1 source"><a href="#l2" id="l2"> 2</a> </div>
+ <div class="parity0 source"><a href="#l3" id="l3"> 3</a> <span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></div>
+ <div class="parity1 source"><a href="#l4" id="l4"> 4</a> </div>
+ <div class="parity0 source"><a href="#l5" id="l5"> 5</a> <span class="sd">primes = 2 : sieve [3, 5..]</span></div>
+ <div class="parity1 source"><a href="#l6" id="l6"> 6</a> <span class="sd"> where sieve (p:ns) = p : sieve [n | n &lt;- ns, mod n p /= 0]</span></div>
+ <div class="parity0 source"><a href="#l7" id="l7"> 7</a> <span class="sd">&quot;&quot;&quot;</span></div>
+ <div class="parity1 source"><a href="#l8" id="l8"> 8</a> </div>
+ <div class="parity0 source"><a href="#l9" id="l9"> 9</a> <span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">dropwhile</span><span class="p">,</span> <span class="n">ifilter</span><span class="p">,</span> <span class="n">islice</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">chain</span></div>
+ <div class="parity1 source"><a href="#l10" id="l10"> 10</a> </div>
+ <div class="parity0 source"><a href="#l11" id="l11"> 11</a> <span class="kn">def</span> <span class="nf">primes</span><span class="p">():</span></div>
+ <div class="parity1 source"><a href="#l12" id="l12"> 12</a> <span class="sd">&quot;&quot;&quot;Generate all primes.&quot;&quot;&quot;</span></div>
+ <div class="parity0 source"><a href="#l13" id="l13"> 13</a> <span class="kn">def</span> <span class="nf">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></div>
+ <div class="parity1 source"><a href="#l14" id="l14"> 14</a> <span class="n">p</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">next</span><span class="p">()</span></div>
+ <div class="parity0 source"><a href="#l15" id="l15"> 15</a> <span class="c"># It is important to yield *here* in order to stop the</span></div>
+ <div class="parity1 source"><a href="#l16" id="l16"> 16</a> <span class="c"># infinite recursion.</span></div>
+ <div class="parity0 source"><a href="#l17" id="l17"> 17</a> <span class="kn">yield</span> <span class="n">p</span></div>
+ <div class="parity1 source"><a href="#l18" id="l18"> 18</a> <span class="n">ns</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></div>
+ <div class="parity0 source"><a href="#l19" id="l19"> 19</a> <span class="kn">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></div>
+ <div class="parity1 source"><a href="#l20" id="l20"> 20</a> <span class="kn">yield</span> <span class="n">n</span></div>
+ <div class="parity0 source"><a href="#l21" id="l21"> 21</a> </div>
+ <div class="parity1 source"><a href="#l22" id="l22"> 22</a> <span class="n">odds</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">count</span><span class="p">())</span></div>
+ <div class="parity0 source"><a href="#l23" id="l23"> 23</a> <span class="kn">return</span> <span class="n">chain</span><span class="p">([</span><span class="mi">2</span><span class="p">],</span> <span class="n">sieve</span><span class="p">(</span><span class="n">dropwhile</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></div>
+ <div class="parity1 source"><a href="#l24" id="l24"> 24</a> </div>
+ <div class="parity0 source"><a href="#l25" id="l25"> 25</a> <span class="kn">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span></div>
+ <div class="parity1 source"><a href="#l26" id="l26"> 26</a> <span class="kn">import</span> <span class="nn">sys</span></div>
+ <div class="parity0 source"><a href="#l27" id="l27"> 27</a> <span class="kn">try</span><span class="p">:</span></div>
+ <div class="parity1 source"><a href="#l28" id="l28"> 28</a> <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span></div>
+ <div class="parity0 source"><a href="#l29" id="l29"> 29</a> <span class="kn">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span></div>
+ <div class="parity1 source"><a href="#l30" id="l30"> 30</a> <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></div>
+ <div class="parity0 source"><a href="#l31" id="l31"> 31</a> <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></div>
+ <div class="parity1 source"><a href="#l32" id="l32"> 32</a> <span class="kn">print</span> <span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">)))</span></div>
+ <div class="sourcelast"></div>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+hgweb fileannotate, html
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/primes.py') \
+ > | sed "s/class=\"k\"/class=\"kn\"/g" | sed "s/class=\"mi\"/class=\"mf\"/g"
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <link rel="stylesheet" href="/highlightcss" type="text/css" />
+ <title>test: primes.py annotate</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/853dcd4de2a6">log</a></li>
+ <li><a href="/graph/853dcd4de2a6">graph</a></li>
+ <li><a href="/tags">tags</a></li>
+ <li><a href="/bookmarks">bookmarks</a></li>
+ <li><a href="/branches">branches</a></li>
+ </ul>
+
+ <ul>
+ <li><a href="/rev/853dcd4de2a6">changeset</a></li>
+ <li><a href="/file/853dcd4de2a6/">browse</a></li>
+ </ul>
+ <ul>
+ <li><a href="/file/853dcd4de2a6/primes.py">file</a></li>
+ <li><a href="/file/tip/primes.py">latest</a></li>
+ <li><a href="/diff/853dcd4de2a6/primes.py">diff</a></li>
+ <li><a href="/comparison/853dcd4de2a6/primes.py">comparison</a></li>
+ <li class="active">annotate</li>
+ <li><a href="/log/853dcd4de2a6/primes.py">file log</a></li>
+ <li><a href="/raw-annotate/853dcd4de2a6/primes.py">raw</a></li>
+ </ul>
+ <ul>
+ <li><a href="/help">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2><a href="/">test</a></h2>
+ <h3>annotate primes.py @ 0:853dcd4de2a6</h3>
+
+ <form class="search" action="/log">
+
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">find changesets by author, revision,
+ files, or words in the commit message</div>
+ </form>
+
+ <div class="description">a</div>
+
+ <table id="changesetEntry">
+ <tr>
+ <th class="author">author</th>
+ <td class="author">&#116;&#101;&#115;&#116;</td>
+ </tr>
+ <tr>
+ <th class="date">date</th>
+ <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
+ </tr>
+ <tr>
+ <th class="author">parents</th>
+ <td class="author"></td>
+ </tr>
+ <tr>
+ <th class="author">children</th>
+ <td class="author"></td>
+ </tr>
+
+ </table>
+
+ <div class="overflow">
+ <table class="bigtable">
+ <tr>
+ <th class="annotate">rev</th>
+ <th class="line">&nbsp;&nbsp;line source</th>
+ </tr>
+
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l1"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l1" id="l1"> 1</a> <span class="c">#!/usr/bin/env python</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l2"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l2" id="l2"> 2</a> </td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l3"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l3" id="l3"> 3</a> <span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l4"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l4" id="l4"> 4</a> </td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l5"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l5" id="l5"> 5</a> <span class="sd">primes = 2 : sieve [3, 5..]</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l6"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l6" id="l6"> 6</a> <span class="sd"> where sieve (p:ns) = p : sieve [n | n &lt;- ns, mod n p /= 0]</span></td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l7"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l7" id="l7"> 7</a> <span class="sd">&quot;&quot;&quot;</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l8"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l8" id="l8"> 8</a> </td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l9"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l9" id="l9"> 9</a> <span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">dropwhile</span><span class="p">,</span> <span class="n">ifilter</span><span class="p">,</span> <span class="n">islice</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">chain</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l10"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l10" id="l10"> 10</a> </td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l11"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l11" id="l11"> 11</a> <span class="kn">def</span> <span class="nf">primes</span><span class="p">():</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l12"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l12" id="l12"> 12</a> <span class="sd">&quot;&quot;&quot;Generate all primes.&quot;&quot;&quot;</span></td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l13"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l13" id="l13"> 13</a> <span class="kn">def</span> <span class="nf">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l14"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l14" id="l14"> 14</a> <span class="n">p</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">next</span><span class="p">()</span></td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l15"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l15" id="l15"> 15</a> <span class="c"># It is important to yield *here* in order to stop the</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l16"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l16" id="l16"> 16</a> <span class="c"># infinite recursion.</span></td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l17"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l17" id="l17"> 17</a> <span class="kn">yield</span> <span class="n">p</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l18"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l18" id="l18"> 18</a> <span class="n">ns</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">!=</span> <span class="mf">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l19"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l19" id="l19"> 19</a> <span class="kn">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l20"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l20" id="l20"> 20</a> <span class="kn">yield</span> <span class="n">n</span></td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l21"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l21" id="l21"> 21</a> </td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l22"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l22" id="l22"> 22</a> <span class="n">odds</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span> <span class="o">%</span> <span class="mf">2</span> <span class="o">==</span> <span class="mf">1</span><span class="p">,</span> <span class="n">count</span><span class="p">())</span></td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l23"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l23" id="l23"> 23</a> <span class="kn">return</span> <span class="n">chain</span><span class="p">([</span><span class="mf">2</span><span class="p">],</span> <span class="n">sieve</span><span class="p">(</span><span class="n">dropwhile</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mf">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l24"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l24" id="l24"> 24</a> </td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l25"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l25" id="l25"> 25</a> <span class="kn">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l26"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l26" id="l26"> 26</a> <span class="kn">import</span> <span class="nn">sys</span></td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l27"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l27" id="l27"> 27</a> <span class="kn">try</span><span class="p">:</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l28"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l28" id="l28"> 28</a> <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mf">1</span><span class="p">])</span></td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l29"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l29" id="l29"> 29</a> <span class="kn">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l30"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l30" id="l30"> 30</a> <span class="n">n</span> <span class="o">=</span> <span class="mf">10</span></td>
+ </tr>
+ <tr class="parity0">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l31"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l31" id="l31"> 31</a> <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></td>
+ </tr>
+ <tr class="parity1">
+ <td class="annotate">
+ <a href="/annotate/853dcd4de2a6/primes.py#l32"
+ title="853dcd4de2a6: a">test@0</a>
+ </td>
+ <td class="source"><a href="#l32" id="l32"> 32</a> <span class="kn">print</span> <span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">)))</span></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+hgweb fileannotate, raw
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/primes.py?style=raw') \
+ > | sed "s/test@//" > a
+ $ echo "200 Script output follows" > b
+ $ echo "" >> b
+ $ echo "" >> b
+ $ hg annotate "primes.py" >> b
+ $ echo "" >> b
+ $ echo "" >> b
+ $ echo "" >> b
+ $ echo "" >> b
+ $ diff -u b a
+
+hgweb filerevision, raw
+
+ $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/primes.py?style=raw') \
+ > > a
+ $ echo "200 Script output follows" > b
+ $ echo "" >> b
+ $ hg cat primes.py >> b
+ $ diff -u b a
+
+hgweb highlightcss friendly
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'highlightcss' > out
+ $ head -n 4 out
+ 200 Script output follows
+
+ /* pygments_style = friendly */
+
+ $ rm out
+
+errors encountered
+
+ $ cat errors.log
+ $ "$TESTDIR/killdaemons.py"
+
+Change the pygments style
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > pygments_style = fruity
+ > EOF
+
+hg serve again
+
+ $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+hgweb highlightcss fruity
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'highlightcss' > out
+ $ head -n 4 out
+ 200 Script output follows
+
+ /* pygments_style = fruity */
+
+ $ rm out
+
+errors encountered
+
+ $ cat errors.log
+ $ cd ..
+ $ hg init eucjp
+ $ cd eucjp
+ $ python -c 'print("\265\376")' >> eucjp.txt # Japanese kanji "Kyo"
+ $ hg ci -Ama
+ adding eucjp.txt
+ $ hgserveget () {
+ > "$TESTDIR/killdaemons.py"
+ > echo % HGENCODING="$1" hg serve
+ > HGENCODING="$1" hg serve -p $HGPORT -d -n test --pid-file=hg.pid -E errors.log
+ > cat hg.pid >> $DAEMON_PIDS
+ >
+ > echo % hgweb filerevision, html
+ > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "file/tip/$2" \
+ > | grep '<div class="parity0 source">'
+ > echo % errors encountered
+ > cat errors.log
+ > }
+ $ hgserveget euc-jp eucjp.txt
+ % HGENCODING=euc-jp hg serve
+ % hgweb filerevision, html
+ <div class="parity0 source"><a href="#l1" id="l1"> 1</a> \xb5\xfe</div> (esc)
+ % errors encountered
+ $ hgserveget utf-8 eucjp.txt
+ % HGENCODING=utf-8 hg serve
+ % hgweb filerevision, html
+ <div class="parity0 source"><a href="#l1" id="l1"> 1</a> \xef\xbf\xbd\xef\xbf\xbd</div> (esc)
+ % errors encountered
+ $ hgserveget us-ascii eucjp.txt
+ % HGENCODING=us-ascii hg serve
+ % hgweb filerevision, html
+ <div class="parity0 source"><a href="#l1" id="l1"> 1</a> ??</div>
+ % errors encountered
+
+ $ cd ..
diff --git a/tests/test-histedit-bookmark-motion.t b/tests/test-histedit-bookmark-motion.t
new file mode 100644
index 0000000..8ab9907
--- /dev/null
+++ b/tests/test-histedit-bookmark-motion.t
@@ -0,0 +1,187 @@
+ $ . "$TESTDIR/histedit-helpers.sh"
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > histedit=
+ > EOF
+
+ $ hg init r
+ $ cd r
+
+ $ for x in a b c d e f ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+
+ $ hg book -r 1 will-move-backwards
+ $ hg book -r 2 two
+ $ hg book -r 2 also-two
+ $ hg book -r 3 three
+ $ hg book -r 4 four
+ $ hg book -r tip five
+ $ hg log --graph
+ @ changeset: 5:652413bf663e
+ | bookmark: five
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:e860deea161a
+ | bookmark: four
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:055a42cdd887
+ | bookmark: three
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | bookmark: also-two
+ | bookmark: two
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | bookmark: will-move-backwards
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ HGEDITOR=cat hg histedit 1
+ pick d2ae7f538514 1 b
+ pick 177f92b77385 2 c
+ pick 055a42cdd887 3 d
+ pick e860deea161a 4 e
+ pick 652413bf663e 5 f
+
+ # Edit history between d2ae7f538514 and 652413bf663e
+ #
+ # Commands:
+ # p, pick = use commit
+ # e, edit = use commit, but stop for amending
+ # f, fold = use commit, but fold into previous commit (combines N and N-1)
+ # d, drop = remove commit from history
+ # m, mess = edit message without changing commit content
+ #
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat >> commands.txt <<EOF
+ > pick 177f92b77385 2 c
+ > drop d2ae7f538514 1 b
+ > pick 055a42cdd887 3 d
+ > fold e860deea161a 4 e
+ > pick 652413bf663e 5 f
+ > EOF
+ $ hg histedit 1 --commands commands.txt --verbose | grep histedit
+ histedit: Should update metadata for the following changes:
+ histedit: 055a42cdd887 to ae467701c500
+ histedit: moving bookmarks three
+ histedit: 177f92b77385 to d36c0562f908
+ histedit: moving bookmarks also-two, two
+ histedit: 652413bf663e to 0efacef7cb48
+ histedit: moving bookmarks five
+ histedit: d2ae7f538514 to cb9a9f314b8b
+ histedit: moving bookmarks will-move-backwards
+ histedit: e860deea161a to ae467701c500
+ histedit: moving bookmarks four
+ saved backup bundle to $TESTTMP/r/.hg/strip-backup/d2ae7f538514-backup.hg (glob)
+ saved backup bundle to $TESTTMP/r/.hg/strip-backup/34a9919932c1-backup.hg (glob)
+ $ hg log --graph
+ @ changeset: 3:0efacef7cb48
+ | bookmark: five
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 2:ae467701c500
+ | bookmark: four
+ | bookmark: three
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 1:d36c0562f908
+ | bookmark: also-two
+ | bookmark: two
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 0:cb9a9f314b8b
+ bookmark: will-move-backwards
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ HGEDITOR=cat hg histedit 1
+ pick d36c0562f908 1 c
+ pick ae467701c500 2 d
+ pick 0efacef7cb48 3 f
+
+ # Edit history between d36c0562f908 and 0efacef7cb48
+ #
+ # Commands:
+ # p, pick = use commit
+ # e, edit = use commit, but stop for amending
+ # f, fold = use commit, but fold into previous commit (combines N and N-1)
+ # d, drop = remove commit from history
+ # m, mess = edit message without changing commit content
+ #
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat > commands.txt << EOF
+ > pick d36c0562f908 1 c
+ > pick 0efacef7cb48 3 f
+ > pick ae467701c500 2 d
+ > EOF
+ $ hg histedit 1 --commands commands.txt --verbose | grep histedit
+ histedit: Should update metadata for the following changes:
+ histedit: 0efacef7cb48 to 1be9c35b4cb2
+ histedit: moving bookmarks five
+ histedit: 0efacef7cb48 to 7c044e3e33a9
+ histedit: ae467701c500 to 1be9c35b4cb2
+ histedit: moving bookmarks four, three
+ saved backup bundle to $TESTTMP/r/.hg/strip-backup/ae467701c500-backup.hg (glob)
+
+We expect 'five' to stay at tip, since the tipmost bookmark is most
+likely the useful signal.
+
+ $ hg log --graph
+ @ changeset: 3:1be9c35b4cb2
+ | bookmark: five
+ | bookmark: four
+ | bookmark: three
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:7c044e3e33a9
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 1:d36c0562f908
+ | bookmark: also-two
+ | bookmark: two
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 0:cb9a9f314b8b
+ bookmark: will-move-backwards
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
diff --git a/tests/test-histedit-commute.t b/tests/test-histedit-commute.t
new file mode 100644
index 0000000..7c1257b
--- /dev/null
+++ b/tests/test-histedit-commute.t
@@ -0,0 +1,359 @@
+ $ . "$TESTDIR/histedit-helpers.sh"
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > histedit=
+ > EOF
+
+ $ EDITED="$TESTTMP/editedhistory"
+ $ cat > $EDITED <<EOF
+ > pick 177f92b77385 c
+ > pick e860deea161a e
+ > pick 652413bf663e f
+ > pick 055a42cdd887 d
+ > EOF
+ $ initrepo ()
+ > {
+ > hg init r
+ > cd r
+ > for x in a b c d e f ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+ > }
+
+ $ initrepo
+
+log before edit
+ $ hg log --graph
+ @ changeset: 5:652413bf663e
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:e860deea161a
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+show the edit commands offered
+ $ HGEDITOR=cat hg histedit 177f92b77385
+ pick 177f92b77385 2 c
+ pick 055a42cdd887 3 d
+ pick e860deea161a 4 e
+ pick 652413bf663e 5 f
+
+ # Edit history between 177f92b77385 and 652413bf663e
+ #
+ # Commands:
+ # p, pick = use commit
+ # e, edit = use commit, but stop for amending
+ # f, fold = use commit, but fold into previous commit (combines N and N-1)
+ # d, drop = remove commit from history
+ # m, mess = edit message without changing commit content
+ #
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+edit the history
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+rules should end up in .hg/histedit-last-edit.txt:
+ $ cat .hg/histedit-last-edit.txt
+ pick 177f92b77385 c
+ pick e860deea161a e
+ pick 652413bf663e f
+ pick 055a42cdd887 d
+
+log after edit
+ $ hg log --graph
+ @ changeset: 5:853c68da763f
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 4:26f6a030ae82
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 3:b069cc29fb22
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+put things back
+
+ $ cat > $EDITED <<EOF
+ > pick 177f92b77385 c
+ > pick 853c68da763f d
+ > pick b069cc29fb22 e
+ > pick 26f6a030ae82 f
+ > EOF
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg log --graph
+ @ changeset: 5:652413bf663e
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:e860deea161a
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+slightly different this time
+
+ $ cat > $EDITED <<EOF
+ > pick 055a42cdd887 d
+ > pick 652413bf663e f
+ > pick e860deea161a e
+ > pick 177f92b77385 c
+ > EOF
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log --graph
+ @ changeset: 5:99a62755c625
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 4:7c6fdd608667
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:c4f52e213402
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 2:bfe4a5a76b37
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+keep prevents stripping dead revs
+ $ cat > $EDITED <<EOF
+ > pick bfe4a5a76b37 d
+ > pick c4f52e213402 f
+ > pick 99a62755c625 c
+ > pick 7c6fdd608667 e
+ > EOF
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit bfe4a5a76b37 --keep 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log --graph
+ > cat > $EDITED <<EOF
+ > pick 7c6fdd608667 e
+ > pick 99a62755c625 c
+ > EOF
+ @ changeset: 7:99e266581538
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 6:5ad36efb0653
+ | parent: 3:c4f52e213402
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ | o changeset: 5:99a62755c625
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: c
+ | |
+ | o changeset: 4:7c6fdd608667
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:c4f52e213402
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 2:bfe4a5a76b37
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+try with --rev
+ $ hg histedit --commands "$EDITED" --rev -2 2>&1 | fixbundle
+ abort: may not use changesets other than the ones listed
+ $ hg log --graph
+ @ changeset: 7:99e266581538
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 6:5ad36efb0653
+ | parent: 3:c4f52e213402
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ | o changeset: 5:99a62755c625
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: c
+ | |
+ | o changeset: 4:7c6fdd608667
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:c4f52e213402
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 2:bfe4a5a76b37
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+should also work if a commit message is missing
+ $ BUNDLE="$TESTDIR/missing-comment.hg"
+ $ hg init missing
+ $ cd missing
+ $ hg unbundle $BUNDLE
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg co tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log --graph
+ @ changeset: 2:bd22688093b3
+ | tag: tip
+ | user: Robert Altman <robert.altman@telventDTN.com>
+ | date: Mon Nov 28 16:40:04 2011 +0000
+ | summary: Update file.
+ |
+ o changeset: 1:3b3e956f9171
+ | user: Robert Altman <robert.altman@telventDTN.com>
+ | date: Mon Nov 28 16:37:57 2011 +0000
+ |
+ o changeset: 0:141947992243
+ user: Robert Altman <robert.altman@telventDTN.com>
+ date: Mon Nov 28 16:35:28 2011 +0000
+ summary: Checked in text file
+
+ $ hg histedit 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
diff --git a/tests/test-histedit-drop.t b/tests/test-histedit-drop.t
new file mode 100644
index 0000000..f425263
--- /dev/null
+++ b/tests/test-histedit-drop.t
@@ -0,0 +1,107 @@
+ $ . "$TESTDIR/histedit-helpers.sh"
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > histedit=
+ > EOF
+
+ $ EDITED="$TESTTMP/editedhistory"
+ $ cat > $EDITED <<EOF
+ > drop 177f92b77385 c
+ > pick e860deea161a e
+ > pick 652413bf663e f
+ > pick 055a42cdd887 d
+ > EOF
+ $ initrepo ()
+ > {
+ > hg init r
+ > cd r
+ > for x in a b c d e f ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+ > }
+
+ $ initrepo
+
+log before edit
+ $ hg log --graph
+ @ changeset: 5:652413bf663e
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:e860deea161a
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+edit the history
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+log after edit
+ $ hg log --graph
+ @ changeset: 4:708943196e52
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 3:75cbdffecadb
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 2:493dc0964412
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+manifest after edit
+ $ hg manifest
+ a
+ b
+ d
+ e
+ f
+
+ $ cd ..
diff --git a/tests/test-histedit-edit.t b/tests/test-histedit-edit.t
new file mode 100644
index 0000000..0ebe620
--- /dev/null
+++ b/tests/test-histedit-edit.t
@@ -0,0 +1,178 @@
+ $ . "$TESTDIR/histedit-helpers.sh"
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > histedit=
+ > EOF
+
+ $ EDITED="$TESTTMP/editedhistory"
+ $ cat > $EDITED <<EOF
+ > pick 177f92b77385 c
+ > pick 055a42cdd887 d
+ > edit e860deea161a e
+ > pick 652413bf663e f
+ > EOF
+ $ initrepo ()
+ > {
+ > hg init r
+ > cd r
+ > for x in a b c d e f ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+ > }
+
+ $ initrepo
+
+log before edit
+ $ hg log --graph
+ @ changeset: 5:652413bf663e
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:e860deea161a
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+edit the history
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ abort: Make changes as needed, you may commit or record as needed now.
+ When you are finished, run hg histedit --continue to resume.
+
+commit, then edit the revision
+ $ hg ci -m 'wat'
+ created new head
+ $ echo a > e
+ $ HGEDITOR='echo foobaz > ' hg histedit --continue 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg log --graph
+ @ changeset: 6:bf757c081cd0
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 5:d6b15fed32d4
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: foobaz
+ |
+ o changeset: 4:1a60820cd1f6
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: wat
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+ $ hg cat e
+ a
+
+ $ cat > $EDITED <<EOF
+ > edit bf757c081cd0 f
+ > EOF
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit tip 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ abort: Make changes as needed, you may commit or record as needed now.
+ When you are finished, run hg histedit --continue to resume.
+ $ hg status
+ A f
+ $ HGEDITOR='true' hg histedit --continue
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg status
+
+log after edit
+ $ hg log --limit 1
+ changeset: 6:bf757c081cd0
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: f
+
+
+say we'll change the message, but don't.
+ $ cat > ../edit.sh <<EOF
+ > cat "\$1" | sed s/pick/mess/ > tmp
+ > mv tmp "\$1"
+ > EOF
+ $ HGEDITOR="sh ../edit.sh" hg histedit tip 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg status
+ $ hg log --limit 1
+ changeset: 6:bf757c081cd0
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: f
+
+
+modify the message
+ $ cat > $EDITED <<EOF
+ > mess bf757c081cd0 f
+ > EOF
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit tip 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg status
+ $ hg log --limit 1
+ changeset: 6:0b16746f8e89
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: mess bf757c081cd0 f
+
+
+rollback should not work after a histedit
+ $ hg rollback
+ no rollback information available
+ [1]
+
+ $ cd ..
diff --git a/tests/test-histedit-fold-non-commute.t b/tests/test-histedit-fold-non-commute.t
new file mode 100644
index 0000000..502446b
--- /dev/null
+++ b/tests/test-histedit-fold-non-commute.t
@@ -0,0 +1,147 @@
+ $ . "$TESTDIR/histedit-helpers.sh"
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > histedit=
+ > EOF
+
+ $ EDITED="$TESTTMP/editedhistory"
+ $ cat > $EDITED <<EOF
+ > pick 177f92b77385 c
+ > pick 055a42cdd887 d
+ > fold bfa474341cc9 does not commute with e
+ > pick e860deea161a e
+ > pick 652413bf663e f
+ > EOF
+ $ initrepo ()
+ > {
+ > hg init $1
+ > cd $1
+ > for x in a b c d e f ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+ > echo a >> e
+ > hg ci -m 'does not commute with e'
+ > cd ..
+ > }
+
+ $ initrepo r
+ $ cd r
+
+log before edit
+ $ hg log --graph
+ @ changeset: 6:bfa474341cc9
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: does not commute with e
+ |
+ o changeset: 5:652413bf663e
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:e860deea161a
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+edit the history
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ 1 out of 1 hunks FAILED -- saving rejects to file e.rej
+ abort: Fix up the change and run hg histedit --continue
+
+fix up
+ $ echo a > e
+ $ hg add e
+ $ cat > cat.py <<EOF
+ > import sys
+ > print open(sys.argv[1]).read()
+ > print
+ > print
+ > EOF
+ $ HGEDITOR="python cat.py" hg histedit --continue 2>&1 | fixbundle | grep -v '2 files removed'
+ d
+ ***
+ does not commute with e
+
+
+
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ file e already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file e.rej
+ abort: Fix up the change and run hg histedit --continue
+
+just continue this time
+ $ hg histedit --continue 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+log after edit
+ $ hg log --graph
+ @ changeset: 4:f768fd60ca34
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 3:671efe372e33
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+contents of e
+ $ hg cat e
+ a
+
+manifest
+ $ hg manifest
+ a
+ b
+ c
+ d
+ e
+ f
+
+ $ cd ..
diff --git a/tests/test-histedit-fold.t b/tests/test-histedit-fold.t
new file mode 100644
index 0000000..645cbc2
--- /dev/null
+++ b/tests/test-histedit-fold.t
@@ -0,0 +1,238 @@
+ $ . "$TESTDIR/histedit-helpers.sh"
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > histedit=
+ > EOF
+
+ $ EDITED="$TESTTMP/editedhistory"
+ $ cat > $EDITED <<EOF
+ > pick e860deea161a e
+ > pick 652413bf663e f
+ > fold 177f92b77385 c
+ > pick 055a42cdd887 d
+ > EOF
+ $ initrepo ()
+ > {
+ > hg init r
+ > cd r
+ > for x in a b c d e f ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+ > }
+
+ $ initrepo
+
+log before edit
+ $ hg log --graph
+ @ changeset: 5:652413bf663e
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:e860deea161a
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+edit the history
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+log after edit
+ $ hg log --graph
+ @ changeset: 4:82b0c1ff1777
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 3:150aafb44a91
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: pick e860deea161a e
+ |
+ o changeset: 2:493dc0964412
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+post-fold manifest
+ $ hg manifest
+ a
+ b
+ c
+ d
+ e
+ f
+
+ $ cd ..
+
+folding and creating no new change doesn't break:
+ $ mkdir fold-to-empty-test
+ $ cd fold-to-empty-test
+ $ hg init
+ $ printf "1\n2\n3\n" > file
+ $ hg add file
+ $ hg commit -m '1+2+3'
+ $ echo 4 >> file
+ $ hg commit -m '+4'
+ $ echo 5 >> file
+ $ hg commit -m '+5'
+ $ echo 6 >> file
+ $ hg commit -m '+6'
+ $ hg log --graph
+ @ changeset: 3:251d831eeec5
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: +6
+ |
+ o changeset: 2:888f9082bf99
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: +5
+ |
+ o changeset: 1:617f94f13c0f
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: +4
+ |
+ o changeset: 0:0189ba417d34
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1+2+3
+
+
+ $ cat > editor.py <<EOF
+ > import re, sys
+ > rules = sys.argv[1]
+ > data = open(rules).read()
+ > data = re.sub(r'pick ([0-9a-f]{12} 2 \+5)', r'drop \1', data)
+ > data = re.sub(r'pick ([0-9a-f]{12} 2 \+6)', r'fold \1', data)
+ > open(rules, 'w').write(data)
+ > EOF
+
+ $ HGEDITOR='python editor.py' hg histedit 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ patching file file
+ Hunk #1 FAILED at 2
+ 1 out of 1 hunks FAILED -- saving rejects to file file.rej
+ abort: Fix up the change and run hg histedit --continue
+ [255]
+There were conflicts, but we'll continue without resolving. This
+should effectively drop the changes from +6.
+ $ hg status
+ ? editor.py
+ ? file.rej
+ $ hg histedit --continue
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/*-backup.hg (glob)
+ $ hg log --graph
+ @ changeset: 1:617f94f13c0f
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: +4
+ |
+ o changeset: 0:0189ba417d34
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1+2+3
+
+
+ $ cd ..
+
+Test corner case where folded revision is separated from its parent by a
+dropped revision.
+
+
+ $ hg init fold-with-dropped
+ $ cd fold-with-dropped
+ $ printf "1\n2\n3\n" > file
+ $ hg commit -Am '1+2+3'
+ adding file
+ $ echo 4 >> file
+ $ hg commit -m '+4'
+ $ echo 5 >> file
+ $ hg commit -m '+5'
+ $ echo 6 >> file
+ $ hg commit -m '+6'
+ $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n'
+ @ 3:251d831eeec5 +6
+ |
+ o 2:888f9082bf99 +5
+ |
+ o 1:617f94f13c0f +4
+ |
+ o 0:0189ba417d34 1+2+3
+
+ $ EDITED="$TESTTMP/editcommands"
+ $ cat > $EDITED <<EOF
+ > pick 617f94f13c0f 1 +4
+ > drop 888f9082bf99 2 +5
+ > fold 251d831eeec5 3 +6
+ > EOF
+ $ HGEDITOR="cat $EDITED >" hg histedit 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ patching file file
+ Hunk #1 FAILED at 2
+ 1 out of 1 hunks FAILED -- saving rejects to file file.rej
+ abort: Fix up the change and run hg histedit --continue
+ [255]
+ $ echo 5 >> file
+ $ hg commit -m '+5.2'
+ created new head
+ $ echo 6 >> file
+ $ HGEDITOR=cat hg histedit --continue
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ +4
+ ***
+ +5.2
+ ***
+ +6
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/fold-with-dropped/.hg/strip-backup/617f94f13c0f-backup.hg (glob)
+ $ cd ..
+
diff --git a/tests/test-histedit-no-change.t b/tests/test-histedit-no-change.t
new file mode 100644
index 0000000..6d9ce27
--- /dev/null
+++ b/tests/test-histedit-no-change.t
@@ -0,0 +1,187 @@
+test for old histedit issue #6:
+editing a changeset without any actual change would corrupt the repository
+
+ $ . "$TESTDIR/histedit-helpers.sh"
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > histedit=
+ > EOF
+
+ $ initrepo ()
+ > {
+ > dir="$1"
+ > comment="$2"
+ > if [ -n "${comment}" ]; then
+ > echo % ${comment}
+ > echo % ${comment} | sed 's:.:-:g'
+ > fi
+ > hg init ${dir}
+ > cd ${dir}
+ > for x in a b c d e f ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+ > cd ..
+ > }
+
+ $ geneditor ()
+ > {
+ > # generate an editor script for selecting changesets to be edited
+ > choice=$1 # changesets that should be edited (using sed line ranges)
+ > cat <<EOF | sed 's:^....::'
+ > # editing the rules, replacing 'pick' with 'edit' for the chosen lines
+ > sed '${choice}s:^pick:edit:' "\$1" > "\${1}.tmp"
+ > mv "\${1}.tmp" "\$1"
+ > # displaying the resulting rules, minus comments and empty lines
+ > sed '/^#/d;/^$/d;s:^:| :' "\$1" >&2
+ > EOF
+ > }
+
+ $ startediting ()
+ > {
+ > # begin an editing session
+ > choice="$1" # changesets that should be edited
+ > number="$2" # number of changesets considered (from tip)
+ > comment="$3"
+ > geneditor "${choice}" > edit.sh
+ > echo % start editing the history ${comment}
+ > HGEDITOR="sh ./edit.sh" hg histedit -- -${number} 2>&1 | fixbundle
+ > }
+
+ $ continueediting ()
+ > {
+ > # continue an edit already in progress
+ > editor="$1" # message editor when finalizing editing
+ > comment="$2"
+ > echo % finalize changeset editing ${comment}
+ > HGEDITOR=${editor} hg histedit --continue 2>&1 | fixbundle
+ > }
+
+ $ graphlog ()
+ > {
+ > comment="${1:-log}"
+ > echo % "${comment}"
+ > hg glog --template '{rev} {node} \"{desc|firstline}\"\n'
+ > }
+
+
+ $ initrepo r1 "test editing with no change"
+ % test editing with no change
+ -----------------------------
+ $ cd r1
+ $ graphlog "log before editing"
+ % log before editing
+ @ 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
+ |
+ o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
+ |
+ o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
+ |
+ o 2 177f92b773850b59254aa5e923436f921b55483b "c"
+ |
+ o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
+ |
+ o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
+
+ $ startediting 2 3 "(not changing anything)" # edit the 2nd of 3 changesets
+ % start editing the history (not changing anything)
+ | pick 055a42cdd887 3 d
+ | edit e860deea161a 4 e
+ | pick 652413bf663e 5 f
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ abort: Make changes as needed, you may commit or record as needed now.
+ When you are finished, run hg histedit --continue to resume.
+ $ continueediting true "(leaving commit message unaltered)"
+ % finalize changeset editing (leaving commit message unaltered)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+check state of working copy
+ $ hg id
+ 652413bf663e tip
+
+ $ graphlog "log after history editing"
+ % log after history editing
+ @ 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
+ |
+ o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
+ |
+ o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
+ |
+ o 2 177f92b773850b59254aa5e923436f921b55483b "c"
+ |
+ o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
+ |
+ o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
+
+
+ $ cd ..
+
+ $ initrepo r2 "test editing with no change, then abort"
+ % test editing with no change, then abort
+ -----------------------------------------
+ $ cd r2
+ $ graphlog "log before editing"
+ % log before editing
+ @ 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
+ |
+ o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
+ |
+ o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
+ |
+ o 2 177f92b773850b59254aa5e923436f921b55483b "c"
+ |
+ o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
+ |
+ o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
+
+ $ startediting 1,2 3 "(not changing anything)" # edit the 1st two of 3 changesets
+ % start editing the history (not changing anything)
+ | edit 055a42cdd887 3 d
+ | edit e860deea161a 4 e
+ | pick 652413bf663e 5 f
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ abort: Make changes as needed, you may commit or record as needed now.
+ When you are finished, run hg histedit --continue to resume.
+ $ continueediting true "(leaving commit message unaltered)"
+ % finalize changeset editing (leaving commit message unaltered)
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ abort: Make changes as needed, you may commit or record as needed now.
+ When you are finished, run hg histedit --continue to resume.
+ $ graphlog "log after first edit"
+ % log after first edit
+ o 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
+ |
+ o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
+ |
+ @ 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
+ |
+ o 2 177f92b773850b59254aa5e923436f921b55483b "c"
+ |
+ o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
+ |
+ o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
+
+
+abort editing session
+ $ hg histedit --abort 2>&1 | fixbundle
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ graphlog "log after abort"
+ % log after abort
+ @ 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
+ |
+ o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
+ |
+ o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
+ |
+ o 2 177f92b773850b59254aa5e923436f921b55483b "c"
+ |
+ o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
+ |
+ o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
+
+
+ $ cd ..
diff --git a/tests/test-histedit-non-commute-abort.t b/tests/test-histedit-non-commute-abort.t
new file mode 100644
index 0000000..925a624
--- /dev/null
+++ b/tests/test-histedit-non-commute-abort.t
@@ -0,0 +1,131 @@
+ $ . "$TESTDIR/histedit-helpers.sh"
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > histedit=
+ > EOF
+
+ $ EDITED="$TESTTMP/editedhistory"
+ $ cat > $EDITED <<EOF
+ > pick 177f92b77385 c
+ > pick 055a42cdd887 d
+ > pick bfa474341cc9 does not commute with e
+ > pick e860deea161a e
+ > pick 652413bf663e f
+ > EOF
+ $ initrepo ()
+ > {
+ > hg init r
+ > cd r
+ > for x in a b c d e f ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+ > echo a >> e
+ > hg ci -m 'does not commute with e'
+ > cd ..
+ > }
+
+ $ initrepo
+ $ cd r
+
+log before edit
+ $ hg log --graph
+ @ changeset: 6:bfa474341cc9
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: does not commute with e
+ |
+ o changeset: 5:652413bf663e
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:e860deea161a
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+edit the history
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ 1 out of 1 hunks FAILED -- saving rejects to file e.rej
+ abort: Fix up the change and run hg histedit --continue
+
+fix up (pre abort)
+ $ echo a > e
+ $ hg add e
+ $ hg histedit --continue 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ file e already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file e.rej
+ abort: Fix up the change and run hg histedit --continue
+
+abort the edit
+ $ hg histedit --abort 2>&1 | fixbundle
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+log after abort
+ $ hg log --graph
+ @ changeset: 6:bfa474341cc9
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: does not commute with e
+ |
+ o changeset: 5:652413bf663e
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:e860deea161a
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+ $ cd ..
diff --git a/tests/test-histedit-non-commute.t b/tests/test-histedit-non-commute.t
new file mode 100644
index 0000000..31d6096
--- /dev/null
+++ b/tests/test-histedit-non-commute.t
@@ -0,0 +1,244 @@
+ $ . "$TESTDIR/histedit-helpers.sh"
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > histedit=
+ > EOF
+
+ $ EDITED="$TESTTMP/editedhistory"
+ $ cat > $EDITED <<EOF
+ > pick 177f92b77385 c
+ > pick 055a42cdd887 d
+ > pick bfa474341cc9 does not commute with e
+ > pick e860deea161a e
+ > pick 652413bf663e f
+ > EOF
+ $ initrepo ()
+ > {
+ > hg init $1
+ > cd $1
+ > for x in a b c d e f ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+ > echo a >> e
+ > hg ci -m 'does not commute with e'
+ > cd ..
+ > }
+
+ $ initrepo r1
+ $ cd r1
+
+log before edit
+ $ hg log --graph
+ @ changeset: 6:bfa474341cc9
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: does not commute with e
+ |
+ o changeset: 5:652413bf663e
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:e860deea161a
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+edit the history
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ 1 out of 1 hunks FAILED -- saving rejects to file e.rej
+ abort: Fix up the change and run hg histedit --continue
+
+abort the edit
+ $ hg histedit --abort 2>&1 | fixbundle
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+
+second edit set
+
+ $ hg log --graph
+ @ changeset: 6:bfa474341cc9
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: does not commute with e
+ |
+ o changeset: 5:652413bf663e
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:e860deea161a
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+edit the history
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ 1 out of 1 hunks FAILED -- saving rejects to file e.rej
+ abort: Fix up the change and run hg histedit --continue
+
+fix up
+ $ echo a > e
+ $ hg add e
+ $ hg histedit --continue 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ file e already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file e.rej
+ abort: Fix up the change and run hg histedit --continue
+
+just continue this time
+ $ hg histedit --continue 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+log after edit
+ $ hg log --graph
+ @ changeset: 5:9ab84894b459
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:1fff3ae8199d
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: does not commute with e
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+start over
+
+ $ cd ..
+
+ $ initrepo r2
+ $ cd r2
+ $ cat > $EDITED <<EOF
+ > pick 177f92b77385 c
+ > pick 055a42cdd887 d
+ > mess bfa474341cc9 does not commute with e
+ > pick e860deea161a e
+ > pick 652413bf663e f
+ > EOF
+
+edit the history, this time with a fold action
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ 1 out of 1 hunks FAILED -- saving rejects to file e.rej
+ abort: Fix up the change and run hg histedit --continue
+
+ $ echo a > e
+ $ hg add e
+ $ HGEDITOR="cat \"$EDITED\" > " hg histedit --continue 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ file e already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file e.rej
+ abort: Fix up the change and run hg histedit --continue
+second edit also fails, but just continue
+ $ hg histedit --continue 2>&1 | fixbundle
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+post message fix
+ $ hg log --graph
+ @ changeset: 5:6459970fb49b
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: f
+ |
+ o changeset: 4:556f27c874b0
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: pick 177f92b77385 c
+ |
+ o changeset: 3:055a42cdd887
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 2:177f92b77385
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:d2ae7f538514
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+ $ cd ..
diff --git a/tests/test-histedit-outgoing.t b/tests/test-histedit-outgoing.t
new file mode 100644
index 0000000..8025891
--- /dev/null
+++ b/tests/test-histedit-outgoing.t
@@ -0,0 +1,84 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > histedit=
+ > EOF
+
+ $ initrepos ()
+ > {
+ > hg init r
+ > cd r
+ > for x in a b c ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+ > cd ..
+ > hg clone r r2 | grep -v updating
+ > cd r2
+ > for x in d e f ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+ > cd ..
+ > hg init r3
+ > cd r3
+ > for x in g h i ; do
+ > echo $x > $x
+ > hg add $x
+ > hg ci -m $x
+ > done
+ > cd ..
+ > }
+
+ $ initrepos
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+show the edit commands offered by outgoing
+ $ cd r2
+ $ HGEDITOR=cat hg histedit --outgoing ../r | grep -v comparing | grep -v searching
+ pick 055a42cdd887 3 d
+ pick e860deea161a 4 e
+ pick 652413bf663e 5 f
+
+ # Edit history between 055a42cdd887 and 652413bf663e
+ #
+ # Commands:
+ # p, pick = use commit
+ # e, edit = use commit, but stop for amending
+ # f, fold = use commit, but fold into previous commit (combines N and N-1)
+ # d, drop = remove commit from history
+ # m, mess = edit message without changing commit content
+ #
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+
+show the error from unrelated repos
+ $ cd r3
+ $ HGEDITOR=cat hg histedit --outgoing ../r | grep -v comparing | grep -v searching
+ abort: repository is unrelated
+ [1]
+ $ cd ..
+
+show the error from unrelated repos
+ $ cd r3
+ $ HGEDITOR=cat hg histedit --force --outgoing ../r
+ comparing with ../r
+ searching for changes
+ warning: repository is unrelated
+ pick 2a4042b45417 0 g
+ pick 68c46b4927ce 1 h
+ pick 51281e65ba79 2 i
+
+ # Edit history between 2a4042b45417 and 51281e65ba79
+ #
+ # Commands:
+ # p, pick = use commit
+ # e, edit = use commit, but stop for amending
+ # f, fold = use commit, but fold into previous commit (combines N and N-1)
+ # d, drop = remove commit from history
+ # m, mess = edit message without changing commit content
+ #
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
diff --git a/tests/test-histedit-revspec.t b/tests/test-histedit-revspec.t
new file mode 100644
index 0000000..06601d3
--- /dev/null
+++ b/tests/test-histedit-revspec.t
@@ -0,0 +1,62 @@
+This test requires parentrevspec support in revsets, so check for that
+and skip the test if we're on an unusual hg that supports .t tests but
+not parentrevspec.
+ $ python -c 'from mercurial import revset ; revset.methods["parentpost"]' || exit 80
+
+Enable extensions used by this test.
+ $ cat >>$HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > histedit=
+ > EOF
+
+Repo setup.
+ $ hg init foo
+ $ cd foo
+ $ echo alpha >> alpha
+ $ hg addr
+ adding alpha
+ $ hg ci -m one
+ $ echo alpha >> alpha
+ $ hg ci -m two
+ $ echo alpha >> alpha
+ $ hg ci -m three
+ $ echo alpha >> alpha
+ $ hg ci -m four
+ $ echo alpha >> alpha
+ $ hg ci -m five
+
+ $ hg log --style compact --graph
+ @ 4[tip] 08d98a8350f3 1970-01-01 00:00 +0000 test
+ | five
+ |
+ o 3 c8e68270e35a 1970-01-01 00:00 +0000 test
+ | four
+ |
+ o 2 eb57da33312f 1970-01-01 00:00 +0000 test
+ | three
+ |
+ o 1 579e40513370 1970-01-01 00:00 +0000 test
+ | two
+ |
+ o 0 6058cbb6cfd7 1970-01-01 00:00 +0000 test
+ one
+
+
+Run a dummy edit to make sure we get tip^^ correctly via revsingle.
+ $ HGEDITOR=cat hg histedit "tip^^"
+ pick eb57da33312f 2 three
+ pick c8e68270e35a 3 four
+ pick 08d98a8350f3 4 five
+
+ # Edit history between eb57da33312f and 08d98a8350f3
+ #
+ # Commands:
+ # p, pick = use commit
+ # e, edit = use commit, but stop for amending
+ # f, fold = use commit, but fold into previous commit (combines N and N-1)
+ # d, drop = remove commit from history
+ # m, mess = edit message without changing commit content
+ #
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
diff --git a/tests/test-hook.t b/tests/test-hook.t
new file mode 100644
index 0000000..8b0b12c
--- /dev/null
+++ b/tests/test-hook.t
@@ -0,0 +1,644 @@
+commit hooks can see env vars
+
+ $ hg init a
+ $ cd a
+ $ cat > .hg/hgrc <<EOF
+ > [hooks]
+ > commit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit"
+ > commit.b = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit.b"
+ > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= python \"$TESTDIR/printenv.py\" precommit"
+ > pretxncommit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" pretxncommit"
+ > pretxncommit.tip = hg -q tip
+ > pre-identify = python "$TESTDIR/printenv.py" pre-identify 1
+ > pre-cat = python "$TESTDIR/printenv.py" pre-cat
+ > post-cat = python "$TESTDIR/printenv.py" post-cat
+ > EOF
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m a
+ precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
+ pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
+ 0:cb9a9f314b8b
+ commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
+ commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
+
+ $ hg clone . ../b
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../b
+
+changegroup hooks can see env vars
+
+ $ cat > .hg/hgrc <<EOF
+ > [hooks]
+ > prechangegroup = python "$TESTDIR/printenv.py" prechangegroup
+ > changegroup = python "$TESTDIR/printenv.py" changegroup
+ > incoming = python "$TESTDIR/printenv.py" incoming
+ > EOF
+
+pretxncommit and commit hooks can see both parents of merge
+
+ $ cd ../a
+ $ echo b >> a
+ $ hg commit -m a1 -d "1 0"
+ precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+ pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
+ 1:ab228980c14d
+ commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+ commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+ $ hg update -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b > b
+ $ hg add b
+ $ hg commit -m b -d '1 0'
+ precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+ pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
+ 2:ee9deb46ab31
+ commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+ commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+ created new head
+ $ hg merge 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -m merge -d '2 0'
+ precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
+ pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
+ 3:07f3376c1e65
+ commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
+ commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
+
+test generic hooks
+
+ $ hg id
+ pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
+ warning: pre-identify hook exited with status 1
+ [1]
+ $ hg cat b
+ pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
+ b
+ post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
+
+ $ cd ../b
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 2 changes to 2 files
+ changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
+ incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
+ incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
+ incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
+ (run 'hg update' to get a working copy)
+
+tag hooks can see env vars
+
+ $ cd ../a
+ $ cat >> .hg/hgrc <<EOF
+ > pretag = python "$TESTDIR/printenv.py" pretag
+ > tag = sh -c "HG_PARENT1= HG_PARENT2= python \"$TESTDIR/printenv.py\" tag"
+ > EOF
+ $ hg tag -d '3 0' a
+ pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
+ precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
+ pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
+ 4:539e4b31b6dc
+ tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
+ commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
+ commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
+ $ hg tag -l la
+ pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
+ tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
+
+pretag hook can forbid tagging
+
+ $ echo "pretag.forbid = python \"$TESTDIR/printenv.py\" pretag.forbid 1" >> .hg/hgrc
+ $ hg tag -d '4 0' fa
+ pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
+ pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
+ abort: pretag.forbid hook exited with status 1
+ [255]
+ $ hg tag -l fla
+ pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
+ pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
+ abort: pretag.forbid hook exited with status 1
+ [255]
+
+pretxncommit hook can see changeset, can roll back txn, changeset no
+more there after
+
+ $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
+ $ echo "pretxncommit.forbid1 = python \"$TESTDIR/printenv.py\" pretxncommit.forbid 1" >> .hg/hgrc
+ $ echo z > z
+ $ hg add z
+ $ hg -q tip
+ 4:539e4b31b6dc
+ $ hg commit -m 'fail' -d '4 0'
+ precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
+ pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
+ 5:6f611f8018c1
+ 5:6f611f8018c1
+ pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
+ transaction abort!
+ rollback completed
+ abort: pretxncommit.forbid1 hook exited with status 1
+ [255]
+ $ hg -q tip
+ 4:539e4b31b6dc
+
+precommit hook can prevent commit
+
+ $ echo "precommit.forbid = python \"$TESTDIR/printenv.py\" precommit.forbid 1" >> .hg/hgrc
+ $ hg commit -m 'fail' -d '4 0'
+ precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
+ precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
+ abort: precommit.forbid hook exited with status 1
+ [255]
+ $ hg -q tip
+ 4:539e4b31b6dc
+
+preupdate hook can prevent update
+
+ $ echo "preupdate = python \"$TESTDIR/printenv.py\" preupdate" >> .hg/hgrc
+ $ hg update 1
+ preupdate hook: HG_PARENT1=ab228980c14d
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+update hook
+
+ $ echo "update = python \"$TESTDIR/printenv.py\" update" >> .hg/hgrc
+ $ hg update
+ preupdate hook: HG_PARENT1=539e4b31b6dc
+ update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+pushkey hook
+
+ $ echo "pushkey = python \"$TESTDIR/printenv.py\" pushkey" >> .hg/hgrc
+ $ cd ../b
+ $ hg bookmark -r null foo
+ $ hg push -B foo ../a
+ pushing to ../a
+ searching for changes
+ no changes found
+ exporting bookmark foo
+ pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
+ [1]
+ $ cd ../a
+
+listkeys hook
+
+ $ echo "listkeys = python \"$TESTDIR/printenv.py\" listkeys" >> .hg/hgrc
+ $ hg bookmark -r null bar
+ $ cd ../b
+ $ hg pull -B bar ../a
+ pulling from ../a
+ listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
+ no changes found
+ listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
+ listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
+ adding remote bookmark bar
+ importing bookmark bar
+ $ cd ../a
+
+test that prepushkey can prevent incoming keys
+
+ $ echo "prepushkey = python \"$TESTDIR/printenv.py\" prepushkey.forbid 1" >> .hg/hgrc
+ $ cd ../b
+ $ hg bookmark -r null baz
+ $ hg push -B baz ../a
+ pushing to ../a
+ searching for changes
+ no changes found
+ listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
+ listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
+ listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
+ exporting bookmark baz
+ prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
+ abort: prepushkey hook exited with status 1
+ [255]
+ $ cd ../a
+
+test that prelistkeys can prevent listing keys
+
+ $ echo "prelistkeys = python \"$TESTDIR/printenv.py\" prelistkeys.forbid 1" >> .hg/hgrc
+ $ hg bookmark -r null quux
+ $ cd ../b
+ $ hg pull -B quux ../a
+ pulling from ../a
+ prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
+ abort: prelistkeys hook exited with status 1
+ [255]
+ $ cd ../a
+
+prechangegroup hook can prevent incoming changes
+
+ $ cd ../b
+ $ hg -q tip
+ 3:07f3376c1e65
+ $ cat > .hg/hgrc <<EOF
+ > [hooks]
+ > prechangegroup.forbid = python "$TESTDIR/printenv.py" prechangegroup.forbid 1
+ > EOF
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
+ abort: prechangegroup.forbid hook exited with status 1
+ [255]
+
+pretxnchangegroup hook can see incoming changes, can roll back txn,
+incoming changes no longer there after
+
+ $ cat > .hg/hgrc <<EOF
+ > [hooks]
+ > pretxnchangegroup.forbid0 = hg tip -q
+ > pretxnchangegroup.forbid1 = python "$TESTDIR/printenv.py" pretxnchangegroup.forbid 1
+ > EOF
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 4:539e4b31b6dc
+ pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
+ transaction abort!
+ rollback completed
+ abort: pretxnchangegroup.forbid1 hook exited with status 1
+ [255]
+ $ hg -q tip
+ 3:07f3376c1e65
+
+outgoing hooks can see env vars
+
+ $ rm .hg/hgrc
+ $ cat > ../a/.hg/hgrc <<EOF
+ > [hooks]
+ > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
+ > outgoing = python "$TESTDIR/printenv.py" outgoing
+ > EOF
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ preoutgoing hook: HG_SOURCE=pull
+ adding changesets
+ outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ adding remote bookmark quux
+ (run 'hg update' to get a working copy)
+ $ hg rollback
+ repository tip rolled back to revision 3 (undo pull)
+
+preoutgoing hook can prevent outgoing changes
+
+ $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> ../a/.hg/hgrc
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ preoutgoing hook: HG_SOURCE=pull
+ preoutgoing.forbid hook: HG_SOURCE=pull
+ abort: preoutgoing.forbid hook exited with status 1
+ [255]
+
+outgoing hooks work for local clones
+
+ $ cd ..
+ $ cat > a/.hg/hgrc <<EOF
+ > [hooks]
+ > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
+ > outgoing = python "$TESTDIR/printenv.py" outgoing
+ > EOF
+ $ hg clone a c
+ preoutgoing hook: HG_SOURCE=clone
+ outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf c
+
+preoutgoing hook can prevent outgoing changes for local clones
+
+ $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> a/.hg/hgrc
+ $ hg clone a zzz
+ preoutgoing hook: HG_SOURCE=clone
+ preoutgoing.forbid hook: HG_SOURCE=clone
+ abort: preoutgoing.forbid hook exited with status 1
+ [255]
+
+ $ cd "$TESTTMP/b"
+
+ $ cat > hooktests.py <<EOF
+ > from mercurial import util
+ >
+ > uncallable = 0
+ >
+ > def printargs(args):
+ > args.pop('ui', None)
+ > args.pop('repo', None)
+ > a = list(args.items())
+ > a.sort()
+ > print 'hook args:'
+ > for k, v in a:
+ > print ' ', k, v
+ >
+ > def passhook(**args):
+ > printargs(args)
+ >
+ > def failhook(**args):
+ > printargs(args)
+ > return True
+ >
+ > class LocalException(Exception):
+ > pass
+ >
+ > def raisehook(**args):
+ > raise LocalException('exception from hook')
+ >
+ > def aborthook(**args):
+ > raise util.Abort('raise abort from hook')
+ >
+ > def brokenhook(**args):
+ > return 1 + {}
+ >
+ > def verbosehook(ui, **args):
+ > ui.note('verbose output from hook\n')
+ >
+ > def printtags(ui, repo, **args):
+ > print repo.tags().keys()
+ >
+ > class container:
+ > unreachable = 1
+ > EOF
+
+test python hooks
+
+#if windows
+ $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
+#else
+ $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
+#endif
+ $ export PYTHONPATH
+
+ $ echo '[hooks]' > ../a/.hg/hgrc
+ $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
+ $ hg pull ../a 2>&1 | grep 'raised an exception'
+ error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
+
+ $ echo '[hooks]' > ../a/.hg/hgrc
+ $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
+ $ hg pull ../a 2>&1 | grep 'raised an exception'
+ error: preoutgoing.raise hook raised an exception: exception from hook
+
+ $ echo '[hooks]' > ../a/.hg/hgrc
+ $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ error: preoutgoing.abort hook failed: raise abort from hook
+ abort: raise abort from hook
+ [255]
+
+ $ echo '[hooks]' > ../a/.hg/hgrc
+ $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ hook args:
+ hooktype preoutgoing
+ source pull
+ abort: preoutgoing.fail hook failed
+ [255]
+
+ $ echo '[hooks]' > ../a/.hg/hgrc
+ $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
+ [255]
+
+ $ echo '[hooks]' > ../a/.hg/hgrc
+ $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
+ [255]
+
+ $ echo '[hooks]' > ../a/.hg/hgrc
+ $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
+ [255]
+
+ $ echo '[hooks]' > ../a/.hg/hgrc
+ $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
+ [255]
+
+ $ echo '[hooks]' > ../a/.hg/hgrc
+ $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
+ [255]
+
+ $ echo '[hooks]' > ../a/.hg/hgrc
+ $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ hook args:
+ hooktype preoutgoing
+ source pull
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ adding remote bookmark quux
+ (run 'hg update' to get a working copy)
+
+make sure --traceback works
+
+ $ echo '[hooks]' > .hg/hgrc
+ $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
+
+ $ echo aa > a
+ $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
+ Traceback (most recent call last):
+
+ $ cd ..
+ $ hg init c
+ $ cd c
+
+ $ cat > hookext.py <<EOF
+ > def autohook(**args):
+ > print "Automatically installed hook"
+ >
+ > def reposetup(ui, repo):
+ > repo.ui.setconfig("hooks", "commit.auto", autohook)
+ > EOF
+ $ echo '[extensions]' >> .hg/hgrc
+ $ echo 'hookext = hookext.py' >> .hg/hgrc
+
+ $ touch foo
+ $ hg add foo
+ $ hg ci -d '0 0' -m 'add foo'
+ Automatically installed hook
+ $ echo >> foo
+ $ hg ci --debug -d '0 0' -m 'change foo'
+ foo
+ calling hook commit.auto: <function autohook at *> (glob)
+ Automatically installed hook
+ committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
+
+ $ hg showconfig hooks
+ hooks.commit.auto=<function autohook at *> (glob)
+
+test python hook configured with python:[file]:[hook] syntax
+
+ $ cd ..
+ $ mkdir d
+ $ cd d
+ $ hg init repo
+ $ mkdir hooks
+
+ $ cd hooks
+ $ cat > testhooks.py <<EOF
+ > def testhook(**args):
+ > print 'hook works'
+ > EOF
+ $ echo '[hooks]' > ../repo/.hg/hgrc
+ $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
+
+ $ cd ../repo
+ $ hg commit -d '0 0'
+ hook works
+ nothing changed
+ [1]
+
+ $ echo '[hooks]' > .hg/hgrc
+ $ echo "update.ne = python:`pwd`/nonexisting.py:testhook" >> .hg/hgrc
+ $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
+
+ $ hg up null
+ loading update.ne hook failed:
+ abort: No such file or directory: $TESTTMP/d/repo/nonexisting.py
+ [255]
+
+ $ hg id
+ loading pre-identify.npmd hook failed:
+ abort: No module named repo!
+ [255]
+
+ $ cd ../../b
+
+make sure --traceback works on hook import failure
+
+ $ cat > importfail.py <<EOF
+ > import somebogusmodule
+ > # dereference something in the module to force demandimport to load it
+ > somebogusmodule.whatever
+ > EOF
+
+ $ echo '[hooks]' > .hg/hgrc
+ $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
+
+ $ echo a >> a
+ $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
+ exception from first failed import attempt:
+ Traceback (most recent call last):
+ ImportError: No module named somebogusmodule
+ exception from second failed import attempt:
+ Traceback (most recent call last):
+ ImportError: No module named hgext_importfail
+ Traceback (most recent call last):
+ Abort: precommit.importfail hook is invalid (import of "importfail" failed)
+ abort: precommit.importfail hook is invalid (import of "importfail" failed)
+
+Issue1827: Hooks Update & Commit not completely post operation
+
+commit and update hooks should run after command completion
+
+ $ echo '[hooks]' > .hg/hgrc
+ $ echo 'commit = hg id' >> .hg/hgrc
+ $ echo 'update = hg id' >> .hg/hgrc
+ $ echo bb > a
+ $ hg ci -ma
+ 223eafe2750c tip
+ $ hg up 0
+ cb9a9f314b8b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+make sure --verbose (and --quiet/--debug etc.) are propogated to the local ui
+that is passed to pre/post hooks
+
+ $ echo '[hooks]' > .hg/hgrc
+ $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
+ $ hg id
+ cb9a9f314b8b
+ $ hg id --verbose
+ calling hook pre-identify: hooktests.verbosehook
+ verbose output from hook
+ cb9a9f314b8b
+
+Ensure hooks can be prioritized
+
+ $ echo '[hooks]' > .hg/hgrc
+ $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
+ $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
+ $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
+ $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
+ $ hg id --verbose
+ calling hook pre-identify.b: hooktests.verbosehook
+ verbose output from hook
+ calling hook pre-identify.a: hooktests.verbosehook
+ verbose output from hook
+ calling hook pre-identify.c: hooktests.verbosehook
+ verbose output from hook
+ cb9a9f314b8b
+
+new tags must be visible in pretxncommit (issue3210)
+
+ $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
+ $ hg tag -f foo
+ ['a', 'foo', 'tip']
+
+new commits must be visible in pretxnchangegroup (issue3428)
+
+ $ cd ..
+ $ hg init to
+ $ echo '[hooks]' >> to/.hg/hgrc
+ $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
+ $ echo a >> to/a
+ $ hg --cwd to ci -Ama
+ adding a
+ $ hg clone to from
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo aa >> from/a
+ $ hg --cwd from ci -mb
+ $ hg --cwd from push
+ pushing to $TESTTMP/to (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ changeset: 1:9836a07b9b9d
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
diff --git a/tests/test-http-branchmap.t b/tests/test-http-branchmap.t
new file mode 100644
index 0000000..1f0b95a
--- /dev/null
+++ b/tests/test-http-branchmap.t
@@ -0,0 +1,94 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ hgserve() {
+ > hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid -E errors.log -v $@
+ > cat hg.pid >> "$DAEMON_PIDS"
+ > }
+ $ hg init a
+ $ hg --encoding utf-8 -R a branch æ
+ marked working directory as branch \xc3\xa6 (esc)
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo foo > a/foo
+ $ hg -R a ci -Am foo
+ adding foo
+ $ hgserve -R a --config web.push_ssl=False --config web.allow_push=* --encoding latin1
+ listening at http://*:$HGPORT1/ (bound to 127.0.0.1:$HGPORT1) (glob)
+ $ hg --encoding utf-8 clone http://localhost:$HGPORT1 b
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch \xc3\xa6 (esc)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --encoding utf-8 -R b log
+ changeset: 0:867c11ce77b8
+ branch: \xc3\xa6 (esc)
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: foo
+
+ $ echo bar >> b/foo
+ $ hg -R b ci -m bar
+ $ hg --encoding utf-8 -R b push
+ pushing to http://localhost:$HGPORT1/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ $ hg -R a --encoding utf-8 log
+ changeset: 1:58e7c90d67cb
+ branch: \xc3\xa6 (esc)
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: bar
+
+ changeset: 0:867c11ce77b8
+ branch: \xc3\xa6 (esc)
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: foo
+
+ $ kill `cat hg.pid`
+
+verify 7e7d56fe4833 (encoding fallback in branchmap to maintain compatibility with 1.3.x)
+
+ $ cat <<EOF > oldhg
+ > import sys
+ > from mercurial import ui, hg, commands
+ >
+ > class StdoutWrapper(object):
+ > def __init__(self, stdout):
+ > self._file = stdout
+ >
+ > def write(self, data):
+ > if data == '47\n':
+ > # latin1 encoding is one %xx (3 bytes) shorter
+ > data = '44\n'
+ > elif data.startswith('%C3%A6 '):
+ > # translate to latin1 encoding
+ > data = '%%E6 %s' % data[7:]
+ > self._file.write(data)
+ >
+ > def __getattr__(self, name):
+ > return getattr(self._file, name)
+ >
+ > sys.stdout = StdoutWrapper(sys.stdout)
+ > sys.stderr = StdoutWrapper(sys.stderr)
+ >
+ > myui = ui.ui()
+ > repo = hg.repository(myui, 'a')
+ > commands.serve(myui, repo, stdio=True, cmdserver=False)
+ > EOF
+ $ echo baz >> b/foo
+ $ hg -R b ci -m baz
+ $ hg push -R b -e 'python oldhg' ssh://dummy/ --encoding latin1
+ pushing to ssh://dummy/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
diff --git a/tests/test-http-clone-r.t b/tests/test-http-clone-r.t
new file mode 100644
index 0000000..454fd3b
--- /dev/null
+++ b/tests/test-http-clone-r.t
@@ -0,0 +1,200 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+creating 'remote
+
+ $ hg init remote
+ $ cd remote
+ $ hg unbundle "$TESTDIR/bundles/remote.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 7 changes to 4 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Starting server
+
+ $ hg serve -p $HGPORT -E ../error.log -d --pid-file=../hg1.pid
+ $ cd ..
+ $ cat hg1.pid >> $DAEMON_PIDS
+
+clone remote via stream
+
+ $ for i in 0 1 2 3 4 5 6 7 8; do
+ > hg clone -r "$i" http://localhost:$HGPORT/ test-"$i"
+ > if cd test-"$i"; then
+ > hg verify
+ > cd ..
+ > fi
+ > done
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 4 changesets, 4 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 5 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 4 changesets, 5 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 6 changes to 3 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 5 changesets, 6 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 5 changes to 2 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 5 changesets, 5 total revisions
+ $ cd test-8
+ $ hg pull ../test-7
+ pulling from ../test-7
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 2 changes to 3 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 9 changesets, 7 total revisions
+ $ cd ..
+ $ cd test-1
+ $ hg pull -r 4 http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 0 changes to 0 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 2 total revisions
+ $ hg pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 5 changes to 4 files
+ (run 'hg update' to get a working copy)
+ $ cd ..
+ $ cd test-2
+ $ hg pull -r 5 http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 0 changes to 0 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 5 changesets, 3 total revisions
+ $ hg pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 4 files
+ (run 'hg update' to get a working copy)
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 9 changesets, 7 total revisions
+ $ cd ..
+ $ cat error.log
diff --git a/tests/test-http-proxy.t b/tests/test-http-proxy.t
new file mode 100644
index 0000000..a8d6890
--- /dev/null
+++ b/tests/test-http-proxy.t
@@ -0,0 +1,124 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg ci -Ama -d '1123456789 0'
+ adding a
+ $ hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=hg.pid
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ cd ..
+ $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
+ $ while [ ! -f proxy.pid ]; do sleep 0; done
+ $ cat proxy.pid >> $DAEMON_PIDS
+
+url for proxy, stream
+
+ $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone --uncompressed http://localhost:$HGPORT/ b
+ streaming all changes
+ 3 files to transfer, 303 bytes of data
+ transferred * bytes in * seconds (*/sec) (glob)
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd b
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+ $ cd ..
+
+url for proxy, pull
+
+ $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone http://localhost:$HGPORT/ b-pull
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd b-pull
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+ $ cd ..
+
+host:port for proxy
+
+ $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ c
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+proxy url with user name and password
+
+ $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ d
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+url with user name and password
+
+ $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://user:passwd@localhost:$HGPORT/ e
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+bad host:port for proxy
+
+ $ http_proxy=localhost:$HGPORT2 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ f
+ abort: error: Connection refused
+ [255]
+
+do not use the proxy if it is in the no list
+
+ $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.no=localhost http://localhost:$HGPORT/ g
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat proxy.log
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=stream_out HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
+
diff --git a/tests/test-http.t b/tests/test-http.t
new file mode 100644
index 0000000..6c3f6b4
--- /dev/null
+++ b/tests/test-http.t
@@ -0,0 +1,207 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ hg init test
+ $ cd test
+ $ echo foo>foo
+ $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
+ $ echo foo>foo.d/foo
+ $ echo bar>foo.d/bAr.hg.d/BaR
+ $ echo bar>foo.d/baR.d.hg/bAR
+ $ hg commit -A -m 1
+ adding foo
+ adding foo.d/bAr.hg.d/BaR
+ adding foo.d/baR.d.hg/bAR
+ adding foo.d/foo
+ $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
+ $ hg --config server.uncompressed=False serve -p $HGPORT1 -d --pid-file=../hg2.pid
+
+Test server address cannot be reused
+
+#if windows
+ $ hg serve -p $HGPORT1 2>&1
+ abort: cannot start server at ':$HGPORT1': * (glob)
+ [255]
+#else
+ $ hg serve -p $HGPORT1 2>&1
+ abort: cannot start server at ':$HGPORT1': Address already in use
+ [255]
+#endif
+ $ cd ..
+ $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
+
+clone via stream
+
+ $ hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1
+ streaming all changes
+ 6 files to transfer, 606 bytes of data
+ transferred * bytes in * seconds (*/sec) (glob)
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg verify -R copy
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 1 changesets, 4 total revisions
+
+try to clone via stream, should use pull instead
+
+ $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 4 changes to 4 files
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+clone via pull
+
+ $ hg clone http://localhost:$HGPORT1/ copy-pull
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 4 changes to 4 files
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg verify -R copy-pull
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 1 changesets, 4 total revisions
+ $ cd test
+ $ echo bar > bar
+ $ hg commit -A -d '1 0' -m 2
+ adding bar
+ $ cd ..
+
+incoming via HTTP
+
+ $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 4 changes to 4 files
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd partial
+ $ touch LOCAL
+ $ hg ci -qAm LOCAL
+ $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
+ comparing with http://localhost:$HGPORT1/
+ searching for changes
+ 2
+ $ cd ..
+
+pull
+
+ $ cd copy-pull
+ $ echo '[hooks]' >> .hg/hgrc
+ $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
+ $ hg pull
+ pulling from http://localhost:$HGPORT1/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=http://localhost:$HGPORT1/
+ (run 'hg update' to get a working copy)
+ $ cd ..
+
+clone from invalid URL
+
+ $ hg clone http://localhost:$HGPORT/bad
+ abort: HTTP Error 404: Not Found
+ [255]
+
+test http authentication
++ use the same server to test server side streaming preference
+
+ $ cd test
+ $ cat << EOT > userpass.py
+ > import base64
+ > from mercurial.hgweb import common
+ > def perform_authentication(hgweb, req, op):
+ > auth = req.env.get('HTTP_AUTHORIZATION')
+ > if not auth:
+ > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
+ > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
+ > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
+ > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
+ > def extsetup():
+ > common.permhooks.insert(0, perform_authentication)
+ > EOT
+ $ hg --config extensions.x=userpass.py serve -p $HGPORT2 -d --pid-file=pid \
+ > --config server.preferuncompressed=True
+ $ cat pid >> $DAEMON_PIDS
+
+ $ hg id http://localhost:$HGPORT2/
+ abort: http authorization required
+ [255]
+ $ hg id http://user@localhost:$HGPORT2/
+ abort: http authorization required
+ [255]
+ $ hg id http://user:pass@localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ echo '[auth]' >> .hg/hgrc
+ $ echo 'l.schemes=http' >> .hg/hgrc
+ $ echo 'l.prefix=lo' >> .hg/hgrc
+ $ echo 'l.username=user' >> .hg/hgrc
+ $ echo 'l.password=pass' >> .hg/hgrc
+ $ hg id http://localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ hg id http://localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ hg id http://user@localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
+ streaming all changes
+ 7 files to transfer, 916 bytes of data
+ transferred * bytes in * seconds (*/sec) (glob)
+ updating to branch default
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg id http://user2@localhost:$HGPORT2/
+ abort: http authorization required
+ [255]
+ $ hg id http://user:pass2@localhost:$HGPORT2/
+ abort: HTTP Error 403: no
+ [255]
+
+ $ cd ..
+
+clone of serve with repo in root and unserved subrepo (issue2970)
+
+ $ hg --cwd test init sub
+ $ echo empty > test/sub/empty
+ $ hg --cwd test/sub add empty
+ $ hg --cwd test/sub commit -qm 'add empty'
+ $ hg --cwd test/sub tag -r 0 something
+ $ echo sub = sub > test/.hgsub
+ $ hg --cwd test add .hgsub
+ $ hg --cwd test commit -qm 'add subrepo'
+ $ hg clone http://localhost:$HGPORT noslash-clone
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 7 changes to 7 files
+ updating to branch default
+ abort: HTTP Error 404: Not Found
+ [255]
+ $ hg clone http://localhost:$HGPORT/ slash-clone
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 7 changes to 7 files
+ updating to branch default
+ abort: HTTP Error 404: Not Found
+ [255]
+
+check error log
+
+ $ cat error.log
diff --git a/tests/test-https.t b/tests/test-https.t
new file mode 100644
index 0000000..c702de8
--- /dev/null
+++ b/tests/test-https.t
@@ -0,0 +1,281 @@
+Proper https client requires the built-in ssl from Python 2.6.
+
+ $ "$TESTDIR/hghave" serve ssl || exit 80
+
+Certificates created with:
+ printf '.\n.\n.\n.\n.\nlocalhost\nhg@localhost\n' | \
+ openssl req -newkey rsa:512 -keyout priv.pem -nodes -x509 -days 9000 -out pub.pem
+Can be dumped with:
+ openssl x509 -in pub.pem -text
+
+ $ cat << EOT > priv.pem
+ > -----BEGIN PRIVATE KEY-----
+ > MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApjCWeYGrIa/Vo7LH
+ > aRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8
+ > j/xgSwIDAQABAkBxHC6+Qlf0VJXGlb6NL16yEVVTQxqDS6hA9zqu6TZjrr0YMfzc
+ > EGNIiZGt7HCBL0zO+cPDg/LeCZc6HQhf0KrhAiEAzlJq4hWWzvguWFIJWSoBeBUG
+ > MF1ACazQO7PYE8M0qfECIQDONHHP0SKZzz/ZwBZcAveC5K61f/v9hONFwbeYulzR
+ > +wIgc9SvbtgB/5Yzpp//4ZAEnR7oh5SClCvyB+KSx52K3nECICbhQphhoXmI10wy
+ > aMTellaq0bpNMHFDziqH9RsqAHhjAiEAgYGxfzkftt5IUUn/iFK89aaIpyrpuaAh
+ > HY8gUVkVRVs=
+ > -----END PRIVATE KEY-----
+ > EOT
+
+ $ cat << EOT > pub.pem
+ > -----BEGIN CERTIFICATE-----
+ > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
+ > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
+ > MTAxNDIwMzAxNFoXDTM1MDYwNTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0
+ > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
+ > ADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX
+ > 6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA+amm
+ > r24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQw
+ > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAFArvQFiAZJgQczRsbYlG1xl
+ > t+truk37w5B3m3Ick1ntRcQrqs+hf0CO1q6Squ144geYaQ8CDirSR92fICELI1c=
+ > -----END CERTIFICATE-----
+ > EOT
+ $ cat priv.pem pub.pem >> server.pem
+ $ PRIV=`pwd`/server.pem
+
+ $ cat << EOT > pub-other.pem
+ > -----BEGIN CERTIFICATE-----
+ > MIIBqzCCAVWgAwIBAgIJALwZS731c/ORMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
+ > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
+ > MTAxNDIwNDUxNloXDTM1MDYwNTIwNDUxNlowMTESMBAGA1UEAwwJbG9jYWxob3N0
+ > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
+ > ADBIAkEAsxsapLbHrqqUKuQBxdpK4G3m2LjtyrTSdpzzzFlecxd5yhNP6AyWrufo
+ > K4VMGo2xlu9xOo88nDSUNSKPuD09MwIDAQABo1AwTjAdBgNVHQ4EFgQUoIB1iMhN
+ > y868rpQ2qk9dHnU6ebswHwYDVR0jBBgwFoAUoIB1iMhNy868rpQ2qk9dHnU6ebsw
+ > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJ544f125CsE7J2t55PdFaF6
+ > bBlNBb91FCywBgSjhBjf+GG3TNPwrPdc3yqeq+hzJiuInqbOBv9abmMyq8Wsoig=
+ > -----END CERTIFICATE-----
+ > EOT
+
+pub.pem patched with other notBefore / notAfter:
+
+ $ cat << EOT > pub-not-yet.pem
+ > -----BEGIN CERTIFICATE-----
+ > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
+ > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTM1MDYwNTIwMzAxNFoXDTM1MDYw
+ > NTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
+ > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
+ > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
+ > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
+ > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJXV41gWnkgC7jcpPpFRSUSZaxyzrXmD1CIqQf0WgVDb
+ > /12E0vR2DuZitgzUYtBaofM81aTtc0a2/YsrmqePGm0=
+ > -----END CERTIFICATE-----
+ > EOT
+ $ cat priv.pem pub-not-yet.pem > server-not-yet.pem
+
+ $ cat << EOT > pub-expired.pem
+ > -----BEGIN CERTIFICATE-----
+ > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
+ > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEwMTAxNDIwMzAxNFoXDTEwMTAx
+ > NDIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
+ > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
+ > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
+ > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
+ > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJfk57DTRf2nUbYaMSlVAARxMNbFGOjQhAUtY400GhKt
+ > 2uiKCNGKXVXD3AHWe13yHc5KttzbHQStE5Nm/DlWBWQ=
+ > -----END CERTIFICATE-----
+ > EOT
+ $ cat priv.pem pub-expired.pem > server-expired.pem
+
+ $ hg init test
+ $ cd test
+ $ echo foo>foo
+ $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
+ $ echo foo>foo.d/foo
+ $ echo bar>foo.d/bAr.hg.d/BaR
+ $ echo bar>foo.d/baR.d.hg/bAR
+ $ hg commit -A -m 1
+ adding foo
+ adding foo.d/bAr.hg.d/BaR
+ adding foo.d/baR.d.hg/bAR
+ adding foo.d/foo
+ $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
+ $ cat ../hg0.pid >> $DAEMON_PIDS
+
+cacert not found
+
+ $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
+ abort: could not find web.cacerts: no-such.pem
+ [255]
+
+Test server address cannot be reused
+
+#if windows
+ $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
+ abort: cannot start server at ':$HGPORT': (glob)
+ [255]
+#else
+ $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
+ abort: cannot start server at ':$HGPORT': Address already in use
+ [255]
+#endif
+ $ cd ..
+
+clone via pull
+
+ $ hg clone https://localhost:$HGPORT/ copy-pull
+ warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 4 changes to 4 files
+ warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg verify -R copy-pull
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 1 changesets, 4 total revisions
+ $ cd test
+ $ echo bar > bar
+ $ hg commit -A -d '1 0' -m 2
+ adding bar
+ $ cd ..
+
+pull without cacert
+
+ $ cd copy-pull
+ $ echo '[hooks]' >> .hg/hgrc
+ $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
+ $ hg pull
+ warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
+ pulling from https://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
+ changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=https://localhost:$HGPORT/
+ (run 'hg update' to get a working copy)
+ $ cd ..
+
+cacert configured in local repo
+
+ $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
+ $ echo "[web]" >> copy-pull/.hg/hgrc
+ $ echo "cacerts=`pwd`/pub.pem" >> copy-pull/.hg/hgrc
+ $ hg -R copy-pull pull --traceback
+ pulling from https://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
+
+cacert configured globally, also testing expansion of environment
+variables in the filename
+
+ $ echo "[web]" >> $HGRCPATH
+ $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
+ $ P=`pwd` hg -R copy-pull pull
+ pulling from https://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ P=`pwd` hg -R copy-pull pull --insecure
+ warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
+ pulling from https://localhost:$HGPORT/
+ searching for changes
+ no changes found
+
+cacert mismatch
+
+ $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/
+ abort: 127.0.0.1 certificate error: certificate is for localhost
+ (configure hostfingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca or use --insecure to connect insecurely)
+ [255]
+ $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/ --insecure
+ warning: 127.0.0.1 certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
+ pulling from https://127.0.0.1:$HGPORT/
+ searching for changes
+ no changes found
+ $ hg -R copy-pull pull --config web.cacerts=pub-other.pem
+ abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
+ [255]
+ $ hg -R copy-pull pull --config web.cacerts=pub-other.pem --insecure
+ warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
+ pulling from https://localhost:$HGPORT/
+ searching for changes
+ no changes found
+
+Test server cert which isn't valid yet
+
+ $ hg -R test serve -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
+ $ cat hg1.pid >> $DAEMON_PIDS
+ $ hg -R copy-pull pull --config web.cacerts=pub-not-yet.pem https://localhost:$HGPORT1/
+ abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
+ [255]
+
+Test server cert which no longer is valid
+
+ $ hg -R test serve -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
+ $ cat hg2.pid >> $DAEMON_PIDS
+ $ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
+ abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
+ [255]
+
+Fingerprints
+
+ $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
+ $ echo "localhost = 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca" >> copy-pull/.hg/hgrc
+ $ echo "127.0.0.1 = 914f1aff87249c09b6859b88b1906d30756491ca" >> copy-pull/.hg/hgrc
+
+- works without cacerts
+ $ hg -R copy-pull id https://localhost:$HGPORT/ --config web.cacerts=
+ 5fed3813f7f5
+
+- fails when cert doesn't match hostname (port is ignored)
+ $ hg -R copy-pull id https://localhost:$HGPORT1/
+ abort: certificate for localhost has unexpected fingerprint 28:ff:71:bf:65:31:14:23:ad:62:92:b4:0e:31:99:18:fc:83:e3:9b
+ (check hostfingerprint configuration)
+ [255]
+
+- ignores that certificate doesn't match hostname
+ $ hg -R copy-pull id https://127.0.0.1:$HGPORT/
+ 5fed3813f7f5
+
+ $ while kill `cat hg1.pid` 2>/dev/null; do sleep 0; done
+
+Prepare for connecting through proxy
+
+ $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
+ $ while [ ! -f proxy.pid ]; do sleep 0; done
+ $ cat proxy.pid >> $DAEMON_PIDS
+
+ $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
+ $ echo "always=True" >> copy-pull/.hg/hgrc
+ $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
+ $ echo "localhost =" >> copy-pull/.hg/hgrc
+
+Test unvalidated https through proxy
+
+ $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure --traceback
+ warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
+ pulling from https://localhost:$HGPORT/
+ searching for changes
+ no changes found
+
+Test https with cacert and fingerprint through proxy
+
+ $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub.pem
+ pulling from https://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://127.0.0.1:$HGPORT/
+ pulling from https://127.0.0.1:$HGPORT/
+ searching for changes
+ no changes found
+
+Test https with cert problems through proxy
+
+ $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-other.pem
+ abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
+ [255]
+ $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
+ abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
+ [255]
diff --git a/tests/test-hup.t b/tests/test-hup.t
new file mode 100644
index 0000000..9745643
--- /dev/null
+++ b/tests/test-hup.t
@@ -0,0 +1,28 @@
+Test hangup signal in the middle of transaction
+
+ $ "$TESTDIR/hghave" serve fifo || exit 80
+ $ hg init
+ $ mkfifo p
+ $ hg serve --stdio < p 1>out 2>&1 &
+ $ P=$!
+
+Do test while holding fifo open
+
+ $ (
+ > echo lock
+ > echo addchangegroup
+ > while [ ! -s .hg/store/journal ]; do sleep 0; done
+ > kill -HUP $P
+ > ) > p
+
+ $ wait
+ $ cat out
+ 0
+ 0
+ adding changesets
+ transaction abort!
+ rollback completed
+ killed!
+
+ $ echo .hg/* .hg/store/*
+ .hg/00changelog.i .hg/journal.bookmarks .hg/journal.branch .hg/journal.desc .hg/journal.dirstate .hg/requires .hg/store .hg/store/00changelog.i .hg/store/00changelog.i.a .hg/store/journal.phaseroots
diff --git a/tests/test-hybridencode.py b/tests/test-hybridencode.py
new file mode 100644
index 0000000..e727276
--- /dev/null
+++ b/tests/test-hybridencode.py
@@ -0,0 +1,27 @@
+from mercurial import store
+
+auxencode = lambda f: store._auxencode(f, True)
+hybridencode = lambda f: store._hybridencode(f, auxencode)
+
+enc = hybridencode # used for 'dotencode' repo format
+
+def show(s):
+ print "A = '%s'" % s
+ print "B = '%s'" % enc(s)
+ print
+
+show('data/aux.bla/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c.i')
+
+show('data/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/'
+ 'TENTH/ELEVENTH/LOREMIPSUM.TXT.i')
+show('data/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/'
+ 'wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules'
+ '.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider.i')
+show('data/AUX.THE-QUICK-BROWN-FOX-JU:MPS-OVER-THE-LAZY-DOG-THE-QUICK-'
+ 'BROWN-FOX-JUMPS-OVER-THE-LAZY-DOG.TXT.i')
+show('data/Project Planning/Resources/AnotherLongDirectoryName/'
+ 'Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt')
+show('data/Project.Planning/Resources/AnotherLongDirectoryName/'
+ 'Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt')
+show('data/foo.../foo / /a./_. /__/.x../ bla/.FOO/something.i')
+
diff --git a/tests/test-hybridencode.py.out b/tests/test-hybridencode.py.out
new file mode 100644
index 0000000..0c4dd9a
--- /dev/null
+++ b/tests/test-hybridencode.py.out
@@ -0,0 +1,21 @@
+A = 'data/aux.bla/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c.i'
+B = 'data/au~78.bla/bla.aux/pr~6e/_p_r_n/lpt/co~6d3/nu~6c/coma/foo._n_u_l/normal.c.i'
+
+A = 'data/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT.i'
+B = 'dh/au~78/second/x.prn/fourth/fi~3afth/sixth/seventh/eighth/nineth/tenth/loremia20419e358ddff1bf8751e38288aff1d7c32ec05.i'
+
+A = 'data/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider.i'
+B = 'dh/enterpri/openesba/contrib-/corba-bc/netbeans/wsdlexte/src/main/java/org.net7018f27961fdf338a598a40c4683429e7ffb9743.i'
+
+A = 'data/AUX.THE-QUICK-BROWN-FOX-JU:MPS-OVER-THE-LAZY-DOG-THE-QUICK-BROWN-FOX-JUMPS-OVER-THE-LAZY-DOG.TXT.i'
+B = 'dh/au~78.the-quick-brown-fox-ju~3amps-over-the-lazy-dog-the-quick-brown-fox-jud4dcadd033000ab2b26eb66bae1906bcb15d4a70.i'
+
+A = 'data/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt'
+B = 'dh/project_/resource/anotherl/followed/andanoth/andthenanextremelylongfilenaf93030515d9849cfdca52937c2204d19f83913e5.txt'
+
+A = 'data/Project.Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt'
+B = 'dh/project_/resource/anotherl/followed/andanoth/andthenanextremelylongfilena0fd7c506f5c9d58204444fc67e9499006bd2d445.txt'
+
+A = 'data/foo.../foo / /a./_. /__/.x../ bla/.FOO/something.i'
+B = 'data/foo..~2e/foo ~20/~20/a~2e/__.~20/____/~2ex.~2e/~20 bla/~2e_f_o_o/something.i'
+
diff --git a/tests/test-i18n.t b/tests/test-i18n.t
new file mode 100644
index 0000000..ec90fd0
--- /dev/null
+++ b/tests/test-i18n.t
@@ -0,0 +1,40 @@
+Translations are optional:
+
+ $ "$TESTDIR/hghave" gettext || exit 80
+
+#if no-outer-repo
+
+Test that translations are compiled and installed correctly.
+
+Default encoding in tests is "ascii" and the translation is encoded
+using the "replace" error handler:
+
+ $ LANGUAGE=pt_BR hg tip
+ abortado: n?o foi encontrado um reposit?rio em '$TESTTMP' (.hg n?o encontrado)!
+ [255]
+
+Using a more accomodating encoding:
+
+ $ HGENCODING=UTF-8 LANGUAGE=pt_BR hg tip
+ abortado: n\xc3\xa3o foi encontrado um reposit\xc3\xb3rio em '$TESTTMP' (.hg n\xc3\xa3o encontrado)! (esc)
+ [255]
+
+Different encoding:
+
+ $ HGENCODING=Latin-1 LANGUAGE=pt_BR hg tip
+ abortado: n\xe3o foi encontrado um reposit\xf3rio em '$TESTTMP' (.hg n\xe3o encontrado)! (esc)
+ [255]
+
+#endif
+
+Test keyword search in translated help text:
+
+ $ HGENCODING=UTF-8 LANGUAGE=de hg help -k blättern
+ Topics:
+
+ extensions Benutzung erweiterter Funktionen
+
+ Erweiterungen:
+
+ pager Verwendet einen externen Pager zum Bl\xc3\xa4ttern in der Ausgabe von Befehlen (esc)
+
diff --git a/tests/test-identify.t b/tests/test-identify.t
new file mode 100644
index 0000000..823badb
--- /dev/null
+++ b/tests/test-identify.t
@@ -0,0 +1,124 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+#if no-outer-repo
+
+no repo
+
+ $ hg id
+ abort: there is no Mercurial repository here (.hg not found)
+ [255]
+
+#endif
+
+create repo
+
+ $ hg init test
+ $ cd test
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+
+basic id usage
+
+ $ hg id
+ cb9a9f314b8b tip
+ $ hg id --debug
+ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b tip
+ $ hg id -q
+ cb9a9f314b8b
+ $ hg id -v
+ cb9a9f314b8b tip
+
+with options
+
+ $ hg id -r.
+ cb9a9f314b8b tip
+ $ hg id -n
+ 0
+ $ hg id -t
+ tip
+ $ hg id -b
+ default
+ $ hg id -i
+ cb9a9f314b8b
+ $ hg id -n -t -b -i
+ cb9a9f314b8b 0 default tip
+
+with modifications
+
+ $ echo b > a
+ $ hg id -n -t -b -i
+ cb9a9f314b8b+ 0+ default tip
+
+other local repo
+
+ $ cd ..
+ $ hg -R test id
+ cb9a9f314b8b+ tip
+#if no-outer-repo
+ $ hg id test
+ cb9a9f314b8b+ tip
+#endif
+
+with remote http repo
+
+ $ cd test
+ $ hg serve -p $HGPORT1 -d --pid-file=hg.pid
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg id http://localhost:$HGPORT1/
+ cb9a9f314b8b
+
+remote with rev number?
+
+ $ hg id -n http://localhost:$HGPORT1/
+ abort: can't query remote revision number, branch, or tags
+ [255]
+
+remote with tags?
+
+ $ hg id -t http://localhost:$HGPORT1/
+ abort: can't query remote revision number, branch, or tags
+ [255]
+
+remote with branch?
+
+ $ hg id -b http://localhost:$HGPORT1/
+ abort: can't query remote revision number, branch, or tags
+ [255]
+
+test bookmark support
+
+ $ hg bookmark Y
+ $ hg bookmark Z
+ $ hg bookmarks
+ Y 0:cb9a9f314b8b
+ * Z 0:cb9a9f314b8b
+ $ hg id
+ cb9a9f314b8b+ tip Y/Z
+ $ hg id --bookmarks
+ Y Z
+
+test remote identify with bookmarks
+
+ $ hg id http://localhost:$HGPORT1/
+ cb9a9f314b8b Y/Z
+ $ hg id --bookmarks http://localhost:$HGPORT1/
+ Y Z
+ $ hg id -r . http://localhost:$HGPORT1/
+ cb9a9f314b8b Y/Z
+ $ hg id --bookmarks -r . http://localhost:$HGPORT1/
+ Y Z
+
+Make sure we do not obscure unknown requires file entries (issue2649)
+
+ $ echo fake >> .hg/requires
+ $ hg id
+ abort: unknown repository format: requires features 'fake' (upgrade Mercurial)!
+ [255]
+
+ $ cd ..
+#if no-outer-repo
+ $ hg id test
+ abort: unknown repository format: requires features 'fake' (upgrade Mercurial)!
+ [255]
+#endif
diff --git a/tests/test-impexp-branch.t b/tests/test-impexp-branch.t
new file mode 100644
index 0000000..c089a46
--- /dev/null
+++ b/tests/test-impexp-branch.t
@@ -0,0 +1,73 @@
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo 'mq =' >> $HGRCPATH
+
+ $ cat >findbranch.py <<EOF
+ > import re, sys
+ >
+ > head_re = re.compile('^#(?:(?:\\s+([A-Za-z][A-Za-z0-9_]*)(?:\\s.*)?)|(?:\\s*))$')
+ >
+ > for line in sys.stdin:
+ > hmatch = head_re.match(line)
+ > if not hmatch:
+ > sys.exit(1)
+ > if hmatch.group(1) == 'Branch':
+ > sys.exit(0)
+ > sys.exit(1)
+ > EOF
+
+ $ hg init a
+ $ cd a
+ $ echo "Rev 1" >rev
+ $ hg add rev
+ $ hg commit -m "No branch."
+ $ hg branch abranch
+ marked working directory as branch abranch
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo "Rev 2" >rev
+ $ hg commit -m "With branch."
+
+ $ hg export 0 > ../r0.patch
+ $ hg export 1 > ../r1.patch
+ $ cd ..
+
+ $ if python findbranch.py < r0.patch; then
+ > echo "Export of default branch revision has Branch header" 1>&2
+ > exit 1
+ > fi
+
+ $ if python findbranch.py < r1.patch; then
+ > : # Do nothing
+ > else
+ > echo "Export of branch revision is missing Branch header" 1>&2
+ > exit 1
+ > fi
+
+Make sure import still works with branch information in patches.
+
+ $ hg init b
+ $ cd b
+ $ hg import ../r0.patch
+ applying ../r0.patch
+ $ hg import ../r1.patch
+ applying ../r1.patch
+ $ cd ..
+
+ $ hg init c
+ $ cd c
+ $ hg import --exact ../r0.patch
+ applying ../r0.patch
+ $ hg import --exact ../r1.patch
+ applying ../r1.patch
+
+Test --exact and patch header separators (issue3356)
+
+ $ hg strip --no-backup .
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ >>> import re
+ >>> p = file('../r1.patch', 'rb').read()
+ >>> p = re.sub(r'Parent\s+', 'Parent ', p)
+ >>> file('../r1-ws.patch', 'wb').write(p)
+ $ hg import --exact ../r1-ws.patch
+ applying ../r1-ws.patch
+
+ $ cd ..
diff --git a/tests/test-import-bypass.t b/tests/test-import-bypass.t
new file mode 100644
index 0000000..bbee13b
--- /dev/null
+++ b/tests/test-import-bypass.t
@@ -0,0 +1,270 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "purge=" >> $HGRCPATH
+ $ echo "graphlog=" >> $HGRCPATH
+
+ $ shortlog() {
+ > hg glog --template '{rev}:{node|short} {author} {date|hgdate} - {branch} - {desc|firstline}\n'
+ > }
+
+Test --bypass with other options
+
+ $ hg init repo-options
+ $ cd repo-options
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ echo a >> a
+ $ hg branch foo
+ marked working directory as branch foo
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Am changea
+ $ hg export . > ../test.diff
+ $ hg up null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+Test importing an existing revision
+
+ $ hg import --bypass --exact ../test.diff
+ applying ../test.diff
+ $ shortlog
+ o 1:4e322f7ce8e3 test 0 0 - foo - changea
+ |
+ o 0:07f494440405 test 0 0 - default - adda
+
+
+Test failure without --exact
+
+ $ hg import --bypass ../test.diff
+ applying ../test.diff
+ unable to find 'a' for patching
+ abort: patch failed to apply
+ [255]
+ $ hg st
+ $ shortlog
+ o 1:4e322f7ce8e3 test 0 0 - foo - changea
+ |
+ o 0:07f494440405 test 0 0 - default - adda
+
+
+Test --user, --date and --message
+
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg import --bypass --u test2 -d '1 0' -m patch2 ../test.diff
+ applying ../test.diff
+ $ cat .hg/last-message.txt
+ patch2 (no-eol)
+ $ shortlog
+ o 2:2e127d1da504 test2 1 0 - default - patch2
+ |
+ | o 1:4e322f7ce8e3 test 0 0 - foo - changea
+ |/
+ @ 0:07f494440405 test 0 0 - default - adda
+
+ $ hg rollback
+ repository tip rolled back to revision 1 (undo import)
+
+Test --import-branch
+
+ $ hg import --bypass --import-branch ../test.diff
+ applying ../test.diff
+ $ shortlog
+ o 1:4e322f7ce8e3 test 0 0 - foo - changea
+ |
+ @ 0:07f494440405 test 0 0 - default - adda
+
+ $ hg rollback
+ repository tip rolled back to revision 1 (undo import)
+
+Test --strip
+
+ $ hg import --bypass --strip 0 - <<EOF
+ > # HG changeset patch
+ > # User test
+ > # Date 0 0
+ > # Branch foo
+ > # Node ID 4e322f7ce8e3e4203950eac9ece27bf7e45ffa6c
+ > # Parent 07f4944404050f47db2e5c5071e0e84e7a27bba9
+ > changea
+ >
+ > diff -r 07f494440405 -r 4e322f7ce8e3 a
+ > --- a Thu Jan 01 00:00:00 1970 +0000
+ > +++ a Thu Jan 01 00:00:00 1970 +0000
+ > @@ -1,1 +1,2 @@
+ > a
+ > +a
+ > EOF
+ applying patch from stdin
+ $ hg rollback
+ repository tip rolled back to revision 1 (undo import)
+
+Test unsupported combinations
+
+ $ hg import --bypass --no-commit ../test.diff
+ abort: cannot use --no-commit with --bypass
+ [255]
+ $ hg import --bypass --similarity 50 ../test.diff
+ abort: cannot use --similarity with --bypass
+ [255]
+
+Test commit editor
+
+ $ cat > ../test.diff <<EOF
+ > diff -r 07f494440405 -r 4e322f7ce8e3 a
+ > --- a/a Thu Jan 01 00:00:00 1970 +0000
+ > +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ > @@ -1,1 +1,2 @@
+ > -a
+ > +b
+ > +c
+ > EOF
+ $ HGEDITOR=cat hg import --bypass ../test.diff
+ applying ../test.diff
+
+
+ HG: Enter commit message. Lines beginning with 'HG:' are removed.
+ HG: Leave message empty to abort commit.
+ HG: --
+ HG: user: test
+ HG: branch 'default'
+ HG: changed a
+ abort: empty commit message
+ [255]
+
+Test patch.eol is handled
+
+ $ python -c 'file("a", "wb").write("a\r\n")'
+ $ hg ci -m makeacrlf
+ $ hg import -m 'should fail because of eol' --bypass ../test.diff
+ applying ../test.diff
+ patching file a
+ Hunk #1 FAILED at 0
+ abort: patch failed to apply
+ [255]
+ $ hg --config patch.eol=auto import -d '0 0' -m 'test patch.eol' --bypass ../test.diff
+ applying ../test.diff
+ $ shortlog
+ o 3:c606edafba99 test 0 0 - default - test patch.eol
+ |
+ @ 2:872023de769d test 0 0 - default - makeacrlf
+ |
+ | o 1:4e322f7ce8e3 test 0 0 - foo - changea
+ |/
+ o 0:07f494440405 test 0 0 - default - adda
+
+
+Test applying multiple patches
+
+ $ hg up -qC 0
+ $ echo e > e
+ $ hg ci -Am adde
+ adding e
+ created new head
+ $ hg export . > ../patch1.diff
+ $ hg up -qC 1
+ $ echo f > f
+ $ hg ci -Am addf
+ adding f
+ $ hg export . > ../patch2.diff
+ $ cd ..
+ $ hg clone -r1 repo-options repo-multi1
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ updating to branch foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd repo-multi1
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg import --bypass ../patch1.diff ../patch2.diff
+ applying ../patch1.diff
+ applying ../patch2.diff
+ $ shortlog
+ o 3:bc8ca3f8a7c4 test 0 0 - default - addf
+ |
+ o 2:16581080145e test 0 0 - default - adde
+ |
+ | o 1:4e322f7ce8e3 test 0 0 - foo - changea
+ |/
+ @ 0:07f494440405 test 0 0 - default - adda
+
+
+Test applying multiple patches with --exact
+
+ $ cd ..
+ $ hg clone -r1 repo-options repo-multi2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ updating to branch foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd repo-multi2
+ $ hg import --bypass --exact ../patch1.diff ../patch2.diff
+ applying ../patch1.diff
+ applying ../patch2.diff
+ $ shortlog
+ o 3:d60cb8989666 test 0 0 - foo - addf
+ |
+ | o 2:16581080145e test 0 0 - default - adde
+ | |
+ @ | 1:4e322f7ce8e3 test 0 0 - foo - changea
+ |/
+ o 0:07f494440405 test 0 0 - default - adda
+
+
+ $ cd ..
+
+#if symlink execbit
+
+Test complicated patch with --exact
+
+ $ hg init repo-exact
+ $ cd repo-exact
+ $ echo a > a
+ $ echo c > c
+ $ echo d > d
+ $ echo e > e
+ $ echo f > f
+ $ chmod +x f
+ $ ln -s c linkc
+ $ hg ci -Am t
+ adding a
+ adding c
+ adding d
+ adding e
+ adding f
+ adding linkc
+ $ hg cp a aa1
+ $ echo b >> a
+ $ echo b > b
+ $ hg add b
+ $ hg cp a aa2
+ $ echo aa >> aa2
+ $ chmod +x e
+ $ chmod -x f
+ $ ln -s a linka
+ $ hg rm d
+ $ hg rm linkc
+ $ hg mv c cc
+ $ hg ci -m patch
+ $ hg export --git . > ../test.diff
+ $ hg up -C null
+ 0 files updated, 0 files merged, 7 files removed, 0 files unresolved
+ $ hg purge
+ $ hg st
+ $ hg import --bypass --exact ../test.diff
+ applying ../test.diff
+
+The patch should have matched the exported revision and generated no additional
+data. If not, diff both heads to debug it.
+
+ $ shortlog
+ o 1:2978fd5c8aa4 test 0 0 - default - patch
+ |
+ o 0:a0e19e636a43 test 0 0 - default - t
+
+#endif
+
+ $ cd ..
diff --git a/tests/test-import-context.t b/tests/test-import-context.t
new file mode 100644
index 0000000..848cd41
--- /dev/null
+++ b/tests/test-import-context.t
@@ -0,0 +1,126 @@
+Test applying context diffs
+
+ $ cat > writepatterns.py <<EOF
+ > import sys
+ >
+ > path = sys.argv[1]
+ > lasteol = sys.argv[2] == '1'
+ > patterns = sys.argv[3:]
+ >
+ > fp = file(path, 'wb')
+ > for i, pattern in enumerate(patterns):
+ > count = int(pattern[0:-1])
+ > char = pattern[-1] + '\n'
+ > if not lasteol and i == len(patterns) - 1:
+ > fp.write((char*count)[:-1])
+ > else:
+ > fp.write(char*count)
+ > fp.close()
+ > EOF
+ $ cat > cat.py <<EOF
+ > import sys
+ > sys.stdout.write(repr(file(sys.argv[1], 'rb').read()) + '\n')
+ > EOF
+
+Initialize the test repository
+
+ $ hg init repo
+ $ cd repo
+ $ python ../writepatterns.py a 0 5A 1B 5C 1D
+ $ python ../writepatterns.py b 1 1A 1B
+ $ python ../writepatterns.py c 1 5A
+ $ python ../writepatterns.py d 1 5A 1B
+ $ hg add
+ adding a
+ adding b
+ adding c
+ adding d
+ $ hg ci -m addfiles
+
+Add file, missing a last end of line
+
+ $ hg import --no-commit - <<EOF
+ > *** /dev/null 2010-10-16 18:05:49.000000000 +0200
+ > --- b/newnoeol 2010-10-16 18:23:26.000000000 +0200
+ > ***************
+ > *** 0 ****
+ > --- 1,2 ----
+ > + a
+ > + b
+ > \ No newline at end of file
+ > *** a/a Sat Oct 16 16:35:51 2010
+ > --- b/a Sat Oct 16 16:35:51 2010
+ > ***************
+ > *** 3,12 ****
+ > A
+ > A
+ > A
+ > ! B
+ > C
+ > C
+ > C
+ > C
+ > C
+ > ! D
+ > \ No newline at end of file
+ > --- 3,13 ----
+ > A
+ > A
+ > A
+ > ! E
+ > C
+ > C
+ > C
+ > C
+ > C
+ > ! F
+ > ! F
+ >
+ > *** a/b 2010-10-16 18:40:38.000000000 +0200
+ > --- /dev/null 2010-10-16 18:05:49.000000000 +0200
+ > ***************
+ > *** 1,2 ****
+ > - A
+ > - B
+ > --- 0 ----
+ > *** a/c Sat Oct 16 21:34:26 2010
+ > --- b/c Sat Oct 16 21:34:27 2010
+ > ***************
+ > *** 3,5 ****
+ > --- 3,7 ----
+ > A
+ > A
+ > A
+ > + B
+ > + B
+ > *** a/d Sat Oct 16 21:47:20 2010
+ > --- b/d Sat Oct 16 21:47:22 2010
+ > ***************
+ > *** 2,6 ****
+ > A
+ > A
+ > A
+ > - A
+ > - B
+ > --- 2,4 ----
+ > EOF
+ applying patch from stdin
+ $ hg st
+ M a
+ M c
+ M d
+ A newnoeol
+ R b
+
+What's in a
+
+ $ python ../cat.py a
+ 'A\nA\nA\nA\nA\nE\nC\nC\nC\nC\nC\nF\nF\n'
+ $ python ../cat.py newnoeol
+ 'a\nb'
+ $ python ../cat.py c
+ 'A\nA\nA\nA\nA\nB\nB\n'
+ $ python ../cat.py d
+ 'A\nA\nA\nA\n'
+
+ $ cd ..
diff --git a/tests/test-import-eol.t b/tests/test-import-eol.t
new file mode 100644
index 0000000..dd2a69f
--- /dev/null
+++ b/tests/test-import-eol.t
@@ -0,0 +1,146 @@
+ $ cat > makepatch.py <<EOF
+ > f = file('eol.diff', 'wb')
+ > w = f.write
+ > w('test message\n')
+ > w('diff --git a/a b/a\n')
+ > w('--- a/a\n')
+ > w('+++ b/a\n')
+ > w('@@ -1,5 +1,5 @@\n')
+ > w(' a\n')
+ > w('-bbb\r\n')
+ > w('+yyyy\r\n')
+ > w(' cc\r\n')
+ > w(' \n')
+ > w(' d\n')
+ > w('-e\n')
+ > w('\ No newline at end of file\n')
+ > w('+z\r\n')
+ > w('\ No newline at end of file\r\n')
+ > EOF
+
+ $ hg init repo
+ $ cd repo
+ $ echo '\.diff' > .hgignore
+
+
+Test different --eol values
+
+ $ python -c 'file("a", "wb").write("a\nbbb\ncc\n\nd\ne")'
+ $ hg ci -Am adda
+ adding .hgignore
+ adding a
+ $ python ../makepatch.py
+
+
+invalid eol
+
+ $ hg --config patch.eol='LFCR' import eol.diff
+ applying eol.diff
+ abort: unsupported line endings type: LFCR
+ [255]
+ $ hg revert -a
+
+
+force LF
+
+ $ hg --traceback --config patch.eol='LF' import eol.diff
+ applying eol.diff
+ $ cat a
+ a
+ yyyy
+ cc
+
+ d
+ e (no-eol)
+ $ hg st
+
+
+force CRLF
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --traceback --config patch.eol='CRLF' import eol.diff
+ applying eol.diff
+ $ cat a
+ a\r (esc)
+ yyyy\r (esc)
+ cc\r (esc)
+ \r (esc)
+ d\r (esc)
+ e (no-eol)
+ $ hg st
+
+
+auto EOL on LF file
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --traceback --config patch.eol='auto' import eol.diff
+ applying eol.diff
+ $ cat a
+ a
+ yyyy
+ cc
+
+ d
+ e (no-eol)
+ $ hg st
+
+
+auto EOL on CRLF file
+
+ $ python -c 'file("a", "wb").write("a\r\nbbb\r\ncc\r\n\r\nd\r\ne")'
+ $ hg commit -m 'switch EOLs in a'
+ $ hg --traceback --config patch.eol='auto' import eol.diff
+ applying eol.diff
+ $ cat a
+ a\r (esc)
+ yyyy\r (esc)
+ cc\r (esc)
+ \r (esc)
+ d\r (esc)
+ e (no-eol)
+ $ hg st
+
+
+auto EOL on new file or source without any EOL
+
+ $ python -c 'file("noeol", "wb").write("noeol")'
+ $ hg add noeol
+ $ hg commit -m 'add noeol'
+ $ python -c 'file("noeol", "wb").write("noeol\r\nnoeol\n")'
+ $ python -c 'file("neweol", "wb").write("neweol\nneweol\r\n")'
+ $ hg add neweol
+ $ hg diff --git > noeol.diff
+ $ hg revert --no-backup noeol neweol
+ $ rm neweol
+ $ hg --traceback --config patch.eol='auto' import -m noeol noeol.diff
+ applying noeol.diff
+ $ cat noeol
+ noeol\r (esc)
+ noeol
+ $ cat neweol
+ neweol
+ neweol\r (esc)
+ $ hg st
+
+
+Test --eol and binary patches
+
+ $ python -c 'file("b", "wb").write("a\x00\nb\r\nd")'
+ $ hg ci -Am addb
+ adding b
+ $ python -c 'file("b", "wb").write("a\x00\nc\r\nd")'
+ $ hg diff --git > bin.diff
+ $ hg revert --no-backup b
+
+binary patch with --eol
+
+ $ hg import --config patch.eol='CRLF' -m changeb bin.diff
+ applying bin.diff
+ $ cat b
+ a\x00 (esc)
+ c\r (esc)
+ d (no-eol)
+ $ hg st
+ $ cd ..
diff --git a/tests/test-import-git.t b/tests/test-import-git.t
new file mode 100644
index 0000000..caba23b
--- /dev/null
+++ b/tests/test-import-git.t
@@ -0,0 +1,611 @@
+ $ hg init repo
+ $ cd repo
+
+New file:
+
+ $ hg import -d "1000000 0" -mnew - <<EOF
+ > diff --git a/new b/new
+ > new file mode 100644
+ > index 0000000..7898192
+ > --- /dev/null
+ > +++ b/new
+ > @@ -0,0 +1 @@
+ > +a
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 0:ae3ee40d2079
+
+New empty file:
+
+ $ hg import -d "1000000 0" -mempty - <<EOF
+ > diff --git a/empty b/empty
+ > new file mode 100644
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 1:ab199dc869b5
+
+ $ hg locate empty
+ empty
+
+chmod +x:
+
+ $ hg import -d "1000000 0" -msetx - <<EOF
+ > diff --git a/new b/new
+ > old mode 100644
+ > new mode 100755
+ > EOF
+ applying patch from stdin
+
+#if execbit
+ $ hg tip -q
+ 2:3a34410f282e
+ $ test -x new
+ $ hg rollback -q
+#else
+ $ hg tip -q
+ 1:ab199dc869b5
+#endif
+
+Copy and removing x bit:
+
+ $ hg import -f -d "1000000 0" -mcopy - <<EOF
+ > diff --git a/new b/copy
+ > old mode 100755
+ > new mode 100644
+ > similarity index 100%
+ > copy from new
+ > copy to copy
+ > diff --git a/new b/copyx
+ > similarity index 100%
+ > copy from new
+ > copy to copyx
+ > EOF
+ applying patch from stdin
+
+ $ test -f copy
+#if execbit
+ $ test ! -x copy
+ $ test -x copyx
+ $ hg tip -q
+ 2:21dfaae65c71
+#else
+ $ hg tip -q
+ 2:0efdaa8e3bf3
+#endif
+
+ $ hg up -qCr1
+ $ hg rollback -q
+
+Copy (like above but independent of execbit):
+
+ $ hg import -d "1000000 0" -mcopy - <<EOF
+ > diff --git a/new b/copy
+ > similarity index 100%
+ > copy from new
+ > copy to copy
+ > diff --git a/new b/copyx
+ > similarity index 100%
+ > copy from new
+ > copy to copyx
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 2:0efdaa8e3bf3
+ $ test -f copy
+
+ $ cat copy
+ a
+
+ $ hg cat copy
+ a
+
+Rename:
+
+ $ hg import -d "1000000 0" -mrename - <<EOF
+ > diff --git a/copy b/rename
+ > similarity index 100%
+ > rename from copy
+ > rename to rename
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 3:b1f57753fad2
+
+ $ hg locate
+ copyx
+ empty
+ new
+ rename
+
+Delete:
+
+ $ hg import -d "1000000 0" -mdelete - <<EOF
+ > diff --git a/copyx b/copyx
+ > deleted file mode 100755
+ > index 7898192..0000000
+ > --- a/copyx
+ > +++ /dev/null
+ > @@ -1 +0,0 @@
+ > -a
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 4:1bd1da94b9b2
+
+ $ hg locate
+ empty
+ new
+ rename
+
+ $ test -f copyx
+ [1]
+
+Regular diff:
+
+ $ hg import -d "1000000 0" -mregular - <<EOF
+ > diff --git a/rename b/rename
+ > index 7898192..72e1fe3 100644
+ > --- a/rename
+ > +++ b/rename
+ > @@ -1 +1,5 @@
+ > a
+ > +a
+ > +a
+ > +a
+ > +a
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 5:46fe99cb3035
+
+Copy and modify:
+
+ $ hg import -d "1000000 0" -mcopymod - <<EOF
+ > diff --git a/rename b/copy2
+ > similarity index 80%
+ > copy from rename
+ > copy to copy2
+ > index 72e1fe3..b53c148 100644
+ > --- a/rename
+ > +++ b/copy2
+ > @@ -1,5 +1,5 @@
+ > a
+ > a
+ > -a
+ > +b
+ > a
+ > a
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 6:ffeb3197c12d
+
+ $ hg cat copy2
+ a
+ a
+ b
+ a
+ a
+
+Rename and modify:
+
+ $ hg import -d "1000000 0" -mrenamemod - <<EOF
+ > diff --git a/copy2 b/rename2
+ > similarity index 80%
+ > rename from copy2
+ > rename to rename2
+ > index b53c148..8f81e29 100644
+ > --- a/copy2
+ > +++ b/rename2
+ > @@ -1,5 +1,5 @@
+ > a
+ > a
+ > b
+ > -a
+ > +c
+ > a
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 7:401aede9e6bb
+
+ $ hg locate copy2
+ [1]
+ $ hg cat rename2
+ a
+ a
+ b
+ c
+ a
+
+One file renamed multiple times:
+
+ $ hg import -d "1000000 0" -mmultirenames - <<EOF
+ > diff --git a/rename2 b/rename3
+ > rename from rename2
+ > rename to rename3
+ > diff --git a/rename2 b/rename3-2
+ > rename from rename2
+ > rename to rename3-2
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 8:2ef727e684e8
+
+ $ hg log -vr. --template '{rev} {files} / {file_copies}\n'
+ 8 rename2 rename3 rename3-2 / rename3 (rename2)rename3-2 (rename2)
+
+ $ hg locate rename2 rename3 rename3-2
+ rename3
+ rename3-2
+
+ $ hg cat rename3
+ a
+ a
+ b
+ c
+ a
+
+ $ hg cat rename3-2
+ a
+ a
+ b
+ c
+ a
+
+ $ echo foo > foo
+ $ hg add foo
+ $ hg ci -m 'add foo'
+
+Binary files and regular patch hunks:
+
+ $ hg import -d "1000000 0" -m binaryregular - <<EOF
+ > diff --git a/binary b/binary
+ > new file mode 100644
+ > index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4
+ > GIT binary patch
+ > literal 4
+ > Lc\${NkU|;|M00aO5
+ >
+ > diff --git a/foo b/foo2
+ > rename from foo
+ > rename to foo2
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 10:27377172366e
+
+ $ cat foo2
+ foo
+
+ $ hg manifest --debug | grep binary
+ 045c85ba38952325e126c70962cc0f9d9077bc67 644 binary
+
+Multiple binary files:
+
+ $ hg import -d "1000000 0" -m multibinary - <<EOF
+ > diff --git a/mbinary1 b/mbinary1
+ > new file mode 100644
+ > index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4
+ > GIT binary patch
+ > literal 4
+ > Lc\${NkU|;|M00aO5
+ >
+ > diff --git a/mbinary2 b/mbinary2
+ > new file mode 100644
+ > index 0000000000000000000000000000000000000000..112363ac1917b417ffbd7f376ca786a1e5fa7490
+ > GIT binary patch
+ > literal 5
+ > Mc\${NkU|\`?^000jF3jhEB
+ >
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 11:18b73a84b4ab
+
+ $ hg manifest --debug | grep mbinary
+ 045c85ba38952325e126c70962cc0f9d9077bc67 644 mbinary1
+ a874b471193996e7cb034bb301cac7bdaf3e3f46 644 mbinary2
+
+Filenames with spaces:
+
+ $ hg import -d "1000000 0" -m spaces - <<EOF
+ > diff --git a/foo bar b/foo bar
+ > new file mode 100644
+ > index 0000000..257cc56
+ > --- /dev/null
+ > +++ b/foo bar
+ > @@ -0,0 +1 @@
+ > +foo
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 12:47500ce1614e
+
+ $ cat "foo bar"
+ foo
+
+Copy then modify the original file:
+
+ $ hg import -d "1000000 0" -m copy-mod-orig - <<EOF
+ > diff --git a/foo2 b/foo2
+ > index 257cc56..fe08ec6 100644
+ > --- a/foo2
+ > +++ b/foo2
+ > @@ -1 +1,2 @@
+ > foo
+ > +new line
+ > diff --git a/foo2 b/foo3
+ > similarity index 100%
+ > copy from foo2
+ > copy to foo3
+ > EOF
+ applying patch from stdin
+
+ $ hg tip -q
+ 13:6757efb07ea9
+
+ $ cat foo3
+ foo
+
+Move text file and patch as binary
+
+ $ echo a > text2
+ $ hg ci -Am0
+ adding text2
+ $ hg import -d "1000000 0" -m rename-as-binary - <<"EOF"
+ > diff --git a/text2 b/binary2
+ > rename from text2
+ > rename to binary2
+ > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
+ > GIT binary patch
+ > literal 5
+ > Mc$`b*O5$Pw00T?_*Z=?k
+ >
+ > EOF
+ applying patch from stdin
+
+ $ cat binary2
+ a
+ b
+ \x00 (no-eol) (esc)
+
+ $ hg st --copies --change .
+ A binary2
+ text2
+ R text2
+
+Invalid base85 content
+
+ $ hg rollback
+ repository tip rolled back to revision 14 (undo import)
+ working directory now based on revision 14
+ $ hg revert -aq
+ $ hg import -d "1000000 0" -m invalid-binary - <<"EOF"
+ > diff --git a/text2 b/binary2
+ > rename from text2
+ > rename to binary2
+ > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
+ > GIT binary patch
+ > literal 5
+ > Mc$`b*O.$Pw00T?_*Z=?k
+ >
+ > EOF
+ applying patch from stdin
+ abort: could not decode "binary2" binary patch: bad base85 character at position 6
+ [255]
+
+ $ hg revert -aq
+ $ hg import -d "1000000 0" -m rename-as-binary - <<"EOF"
+ > diff --git a/text2 b/binary2
+ > rename from text2
+ > rename to binary2
+ > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
+ > GIT binary patch
+ > literal 6
+ > Mc$`b*O5$Pw00T?_*Z=?k
+ >
+ > EOF
+ applying patch from stdin
+ abort: "binary2" length is 5 bytes, should be 6
+ [255]
+
+ $ hg revert -aq
+ $ hg import -d "1000000 0" -m rename-as-binary - <<"EOF"
+ > diff --git a/text2 b/binary2
+ > rename from text2
+ > rename to binary2
+ > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
+ > GIT binary patch
+ > Mc$`b*O5$Pw00T?_*Z=?k
+ >
+ > EOF
+ applying patch from stdin
+ abort: could not extract "binary2" binary data
+ [255]
+
+Simulate a copy/paste turning LF into CRLF (issue2870)
+
+ $ hg revert -aq
+ $ cat > binary.diff <<"EOF"
+ > diff --git a/text2 b/binary2
+ > rename from text2
+ > rename to binary2
+ > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
+ > GIT binary patch
+ > literal 5
+ > Mc$`b*O5$Pw00T?_*Z=?k
+ >
+ > EOF
+ >>> fp = file('binary.diff', 'rb')
+ >>> data = fp.read()
+ >>> fp.close()
+ >>> file('binary.diff', 'wb').write(data.replace('\n', '\r\n'))
+ $ rm binary2
+ $ hg import --no-commit binary.diff
+ applying binary.diff
+
+ $ cd ..
+
+Consecutive import with renames (issue2459)
+
+ $ hg init issue2459
+ $ cd issue2459
+ $ hg import --no-commit --force - <<EOF
+ > diff --git a/a b/a
+ > new file mode 100644
+ > EOF
+ applying patch from stdin
+ $ hg import --no-commit --force - <<EOF
+ > diff --git a/a b/b
+ > rename from a
+ > rename to b
+ > EOF
+ applying patch from stdin
+ a has not been committed yet, so no copy data will be stored for b.
+ $ hg debugstate
+ a 0 -1 unset b
+ $ hg ci -m done
+ $ cd ..
+
+Renames and strip
+
+ $ hg init renameandstrip
+ $ cd renameandstrip
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ hg import --no-commit -p2 - <<EOF
+ > diff --git a/foo/a b/foo/b
+ > rename from foo/a
+ > rename to foo/b
+ > EOF
+ applying patch from stdin
+ $ hg st --copies
+ A b
+ a
+ R a
+
+Renames, similarity and git diff
+
+ $ hg revert -aC
+ undeleting a
+ forgetting b
+ $ rm b
+ $ hg import --similarity 90 --no-commit - <<EOF
+ > diff --git a/a b/b
+ > rename from a
+ > rename to b
+ > EOF
+ applying patch from stdin
+ $ hg st --copies
+ A b
+ a
+ R a
+ $ cd ..
+
+Pure copy with existing destination
+
+ $ hg init copytoexisting
+ $ cd copytoexisting
+ $ echo a > a
+ $ echo b > b
+ $ hg ci -Am add
+ adding a
+ adding b
+ $ hg import --no-commit - <<EOF
+ > diff --git a/a b/b
+ > copy from a
+ > copy to b
+ > EOF
+ applying patch from stdin
+ abort: cannot create b: destination already exists
+ [255]
+ $ cat b
+ b
+
+Copy and changes with existing destination
+
+ $ hg import --no-commit - <<EOF
+ > diff --git a/a b/b
+ > copy from a
+ > copy to b
+ > --- a/a
+ > +++ b/b
+ > @@ -1,1 +1,2 @@
+ > a
+ > +b
+ > EOF
+ applying patch from stdin
+ cannot create b: destination already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file b.rej
+ abort: patch failed to apply
+ [255]
+ $ cat b
+ b
+
+#if symlink
+
+ $ ln -s b linkb
+ $ hg add linkb
+ $ hg ci -m addlinkb
+ $ hg import --no-commit - <<EOF
+ > diff --git a/linkb b/linkb
+ > deleted file mode 120000
+ > --- a/linkb
+ > +++ /dev/null
+ > @@ -1,1 +0,0 @@
+ > -badhunk
+ > \ No newline at end of file
+ > EOF
+ applying patch from stdin
+ patching file linkb
+ Hunk #1 FAILED at 0
+ 1 out of 1 hunks FAILED -- saving rejects to file linkb.rej
+ abort: patch failed to apply
+ [255]
+ $ hg st
+ ? b.rej
+ ? linkb.rej
+
+#endif
+
+Test corner case involving copies and multiple hunks (issue3384)
+
+ $ hg revert -qa
+ $ hg import --no-commit - <<EOF
+ > diff --git a/a b/c
+ > copy from a
+ > copy to c
+ > --- a/a
+ > +++ b/c
+ > @@ -1,1 +1,2 @@
+ > a
+ > +a
+ > @@ -2,1 +2,2 @@
+ > a
+ > +a
+ > diff --git a/a b/a
+ > --- a/a
+ > +++ b/a
+ > @@ -1,1 +1,2 @@
+ > a
+ > +b
+ > EOF
+ applying patch from stdin
+
+ $ cd ..
diff --git a/tests/test-import-merge.t b/tests/test-import-merge.t
new file mode 100644
index 0000000..924f076
--- /dev/null
+++ b/tests/test-import-merge.t
@@ -0,0 +1,115 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ tipparents() {
+ > hg parents --template "{rev}:{node|short} {desc|firstline}\n" -r tip
+ > }
+
+Test import and merge diffs
+
+ $ hg init repo
+ $ cd repo
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ echo a >> a
+ $ hg ci -m changea
+ $ echo c > c
+ $ hg ci -Am addc
+ adding c
+ $ hg up 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo b > b
+ $ hg ci -Am addb
+ adding b
+ created new head
+ $ hg up 1
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m merge
+ $ hg export . > ../merge.diff
+ $ cd ..
+ $ hg clone -r2 repo repo2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd repo2
+ $ hg pull -r3 ../repo
+ pulling from ../repo
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+Test without --exact and diff.p1 == workingdir.p1
+
+ $ hg up 1
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg import ../merge.diff
+ applying ../merge.diff
+ $ tipparents
+ 1:540395c44225 changea
+ 3:102a90ea7b4a addb
+ $ hg strip --no-backup tip
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+Test without --exact and diff.p1 != workingdir.p1
+
+ $ hg up 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg import ../merge.diff
+ applying ../merge.diff
+ $ tipparents
+ 2:890ecaa90481 addc
+ $ hg strip --no-backup tip
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+Test with --exact
+
+ $ hg import --exact ../merge.diff
+ applying ../merge.diff
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ tipparents
+ 1:540395c44225 changea
+ 3:102a90ea7b4a addb
+ $ hg strip --no-backup tip
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+Test with --bypass and diff.p1 == workingdir.p1
+
+ $ hg up 1
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg import --bypass ../merge.diff
+ applying ../merge.diff
+ $ tipparents
+ 1:540395c44225 changea
+ 3:102a90ea7b4a addb
+ $ hg strip --no-backup tip
+
+Test with --bypass and diff.p1 != workingdir.p1
+
+ $ hg up 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg import --bypass ../merge.diff
+ applying ../merge.diff
+ $ tipparents
+ 2:890ecaa90481 addc
+ $ hg strip --no-backup tip
+
+Test with --bypass and --exact
+
+ $ hg import --bypass --exact ../merge.diff
+ applying ../merge.diff
+ $ tipparents
+ 1:540395c44225 changea
+ 3:102a90ea7b4a addb
+ $ hg strip --no-backup tip
+
+ $ cd ..
diff --git a/tests/test-import-unknown.t b/tests/test-import-unknown.t
new file mode 100644
index 0000000..a143676
--- /dev/null
+++ b/tests/test-import-unknown.t
@@ -0,0 +1,69 @@
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > purge =
+ > EOF
+
+ $ hg init test
+ $ cd test
+ $ echo a > changed
+ $ echo a > removed
+ $ echo a > source
+ $ hg ci -Am addfiles
+ adding changed
+ adding removed
+ adding source
+ $ echo a >> changed
+ $ echo a > added
+ $ hg add added
+ $ hg rm removed
+ $ hg cp source copied
+ $ hg diff --git > ../unknown.diff
+
+Test adding on top of an unknown file
+
+ $ hg up -qC 0
+ $ hg purge
+ $ echo a > added
+ $ hg import --no-commit ../unknown.diff
+ applying ../unknown.diff
+ file added already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file added.rej
+ abort: patch failed to apply
+ [255]
+
+Test modifying an unknown file
+
+ $ hg revert -aq
+ $ hg purge
+ $ hg rm changed
+ $ hg ci -m removechanged
+ $ echo a > changed
+ $ hg import --no-commit ../unknown.diff
+ applying ../unknown.diff
+ abort: cannot patch changed: file is not tracked
+ [255]
+
+Test removing an unknown file
+
+ $ hg up -qC 0
+ $ hg purge
+ $ hg rm removed
+ $ hg ci -m removeremoved
+ created new head
+ $ echo a > removed
+ $ hg import --no-commit ../unknown.diff
+ applying ../unknown.diff
+ abort: cannot patch removed: file is not tracked
+ [255]
+
+Test copying onto an unknown file
+
+ $ hg up -qC 0
+ $ hg purge
+ $ echo a > copied
+ $ hg import --no-commit ../unknown.diff
+ applying ../unknown.diff
+ abort: cannot create copied: destination already exists
+ [255]
+
+ $ cd ..
diff --git a/tests/test-import.t b/tests/test-import.t
new file mode 100644
index 0000000..ccd35cc
--- /dev/null
+++ b/tests/test-import.t
@@ -0,0 +1,1155 @@
+ $ hg init a
+ $ mkdir a/d1
+ $ mkdir a/d1/d2
+ $ echo line 1 > a/a
+ $ echo line 1 > a/d1/d2/a
+ $ hg --cwd a ci -Ama
+ adding a
+ adding d1/d2/a
+
+ $ echo line 2 >> a/a
+ $ hg --cwd a ci -u someone -d '1 0' -m'second change'
+
+import with no args:
+
+ $ hg --cwd a import
+ abort: need at least one patch to import
+ [255]
+
+generate patches for the test
+
+ $ hg --cwd a export tip > exported-tip.patch
+ $ hg --cwd a diff -r0:1 > diffed-tip.patch
+
+
+import exported patch
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd b import ../exported-tip.patch
+ applying ../exported-tip.patch
+
+message and committer should be same
+
+ $ hg --cwd b tip
+ changeset: 1:1d4bd90af0e4
+ tag: tip
+ user: someone
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: second change
+
+ $ rm -r b
+
+
+import exported patch with external patcher
+
+ $ cat > dummypatch.py <<EOF
+ > print 'patching file a'
+ > file('a', 'wb').write('line2\n')
+ > EOF
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --config ui.patch='python ../dummypatch.py' --cwd b import ../exported-tip.patch
+ applying ../exported-tip.patch
+ $ cat b/a
+ line2
+ $ rm -r b
+
+
+import of plain diff should fail without message
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd b import ../diffed-tip.patch
+ applying ../diffed-tip.patch
+ abort: empty commit message
+ [255]
+ $ rm -r b
+
+
+import of plain diff should be ok with message
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd b import -mpatch ../diffed-tip.patch
+ applying ../diffed-tip.patch
+ $ rm -r b
+
+
+import of plain diff with specific date and user
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd b import -mpatch -d '1 0' -u 'user@nowhere.net' ../diffed-tip.patch
+ applying ../diffed-tip.patch
+ $ hg -R b tip -pv
+ changeset: 1:ca68f19f3a40
+ tag: tip
+ user: user@nowhere.net
+ date: Thu Jan 01 00:00:01 1970 +0000
+ files: a
+ description:
+ patch
+
+
+ diff -r 80971e65b431 -r ca68f19f3a40 a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -1,1 +1,2 @@
+ line 1
+ +line 2
+
+ $ rm -r b
+
+
+import of plain diff should be ok with --no-commit
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd b import --no-commit ../diffed-tip.patch
+ applying ../diffed-tip.patch
+ $ hg --cwd b diff --nodates
+ diff -r 80971e65b431 a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,2 @@
+ line 1
+ +line 2
+ $ rm -r b
+
+
+import of malformed plain diff should fail
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ sed 's/1,1/foo/' < diffed-tip.patch > broken.patch
+ $ hg --cwd b import -mpatch ../broken.patch
+ applying ../broken.patch
+ abort: bad hunk #1
+ [255]
+ $ rm -r b
+
+
+hg -R repo import
+put the clone in a subdir - having a directory named "a"
+used to hide a bug.
+
+ $ mkdir dir
+ $ hg clone -r0 a dir/b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd dir
+ $ hg -R b import ../exported-tip.patch
+ applying ../exported-tip.patch
+ $ cd ..
+ $ rm -r dir
+
+
+import from stdin
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd b import - < exported-tip.patch
+ applying patch from stdin
+ $ rm -r b
+
+
+import two patches in one stream
+
+ $ hg init b
+ $ hg --cwd a export 0:tip | hg --cwd b import -
+ applying patch from stdin
+ $ hg --cwd a id
+ 1d4bd90af0e4 tip
+ $ hg --cwd b id
+ 1d4bd90af0e4 tip
+ $ rm -r b
+
+
+override commit message
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd b import -m 'override' - < exported-tip.patch
+ applying patch from stdin
+ $ hg --cwd b tip | grep override
+ summary: override
+ $ rm -r b
+
+ $ cat > mkmsg.py <<EOF
+ > import email.Message, sys
+ > msg = email.Message.Message()
+ > patch = open(sys.argv[1], 'rb').read()
+ > msg.set_payload('email commit message\n' + patch)
+ > msg['Subject'] = 'email patch'
+ > msg['From'] = 'email patcher'
+ > file(sys.argv[2], 'wb').write(msg.as_string())
+ > EOF
+
+
+plain diff in email, subject, message body
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ python mkmsg.py diffed-tip.patch msg.patch
+ $ hg --cwd b import ../msg.patch
+ applying ../msg.patch
+ $ hg --cwd b tip | grep email
+ user: email patcher
+ summary: email patch
+ $ rm -r b
+
+
+plain diff in email, no subject, message body
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ grep -v '^Subject:' msg.patch | hg --cwd b import -
+ applying patch from stdin
+ $ rm -r b
+
+
+plain diff in email, subject, no message body
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ grep -v '^email ' msg.patch | hg --cwd b import -
+ applying patch from stdin
+ $ rm -r b
+
+
+plain diff in email, no subject, no message body, should fail
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ egrep -v '^(Subject|email)' msg.patch | hg --cwd b import -
+ applying patch from stdin
+ abort: empty commit message
+ [255]
+ $ rm -r b
+
+
+hg export in email, should use patch header
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ python mkmsg.py exported-tip.patch msg.patch
+ $ cat msg.patch | hg --cwd b import -
+ applying patch from stdin
+ $ hg --cwd b tip | grep second
+ summary: second change
+ $ rm -r b
+
+
+subject: duplicate detection, removal of [PATCH]
+The '---' tests the gitsendmail handling without proper mail headers
+
+ $ cat > mkmsg2.py <<EOF
+ > import email.Message, sys
+ > msg = email.Message.Message()
+ > patch = open(sys.argv[1], 'rb').read()
+ > msg.set_payload('email patch\n\nnext line\n---\n' + patch)
+ > msg['Subject'] = '[PATCH] email patch'
+ > msg['From'] = 'email patcher'
+ > file(sys.argv[2], 'wb').write(msg.as_string())
+ > EOF
+
+
+plain diff in email, [PATCH] subject, message body with subject
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ python mkmsg2.py diffed-tip.patch msg.patch
+ $ cat msg.patch | hg --cwd b import -
+ applying patch from stdin
+ $ hg --cwd b tip --template '{desc}\n'
+ email patch
+
+ next line
+ ---
+ $ rm -r b
+
+
+Issue963: Parent of working dir incorrect after import of multiple
+patches and rollback
+
+We weren't backing up the correct dirstate file when importing many
+patches: import patch1 patch2; rollback
+
+ $ echo line 3 >> a/a
+ $ hg --cwd a ci -m'third change'
+ $ hg --cwd a export -o '../patch%R' 1 2
+ $ hg clone -qr0 a b
+ $ hg --cwd b parents --template 'parent: {rev}\n'
+ parent: 0
+ $ hg --cwd b import -v ../patch1 ../patch2
+ applying ../patch1
+ patching file a
+ a
+ created 1d4bd90af0e4
+ applying ../patch2
+ patching file a
+ a
+ created 6d019af21222
+ $ hg --cwd b rollback
+ repository tip rolled back to revision 0 (undo import)
+ working directory now based on revision 0
+ $ hg --cwd b parents --template 'parent: {rev}\n'
+ parent: 0
+ $ rm -r b
+
+
+importing a patch in a subdirectory failed at the commit stage
+
+ $ echo line 2 >> a/d1/d2/a
+ $ hg --cwd a ci -u someoneelse -d '1 0' -m'subdir change'
+
+hg import in a subdirectory
+
+ $ hg clone -r0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd a export tip > tmp
+ $ sed -e 's/d1\/d2\///' < tmp > subdir-tip.patch
+ $ dir=`pwd`
+ $ cd b/d1/d2 2>&1 > /dev/null
+ $ hg import ../../../subdir-tip.patch
+ applying ../../../subdir-tip.patch
+ $ cd "$dir"
+
+message should be 'subdir change'
+committer should be 'someoneelse'
+
+ $ hg --cwd b tip
+ changeset: 1:3577f5aea227
+ tag: tip
+ user: someoneelse
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: subdir change
+
+
+should be empty
+
+ $ hg --cwd b status
+
+
+Test fuzziness (ambiguous patch location, fuzz=2)
+
+ $ hg init fuzzy
+ $ cd fuzzy
+ $ echo line1 > a
+ $ echo line0 >> a
+ $ echo line3 >> a
+ $ hg ci -Am adda
+ adding a
+ $ echo line1 > a
+ $ echo line2 >> a
+ $ echo line0 >> a
+ $ echo line3 >> a
+ $ hg ci -m change a
+ $ hg export tip > fuzzy-tip.patch
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo line1 > a
+ $ echo line0 >> a
+ $ echo line1 >> a
+ $ echo line0 >> a
+ $ hg ci -m brancha
+ created new head
+ $ hg import --no-commit -v fuzzy-tip.patch
+ applying fuzzy-tip.patch
+ patching file a
+ Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
+ applied to working directory
+ $ hg revert -a
+ reverting a
+
+
+import with --no-commit should have written .hg/last-message.txt
+
+ $ cat .hg/last-message.txt
+ change (no-eol)
+
+
+test fuzziness with eol=auto
+
+ $ hg --config patch.eol=auto import --no-commit -v fuzzy-tip.patch
+ applying fuzzy-tip.patch
+ patching file a
+ Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
+ applied to working directory
+ $ cd ..
+
+
+Test hunk touching empty files (issue906)
+
+ $ hg init empty
+ $ cd empty
+ $ touch a
+ $ touch b1
+ $ touch c1
+ $ echo d > d
+ $ hg ci -Am init
+ adding a
+ adding b1
+ adding c1
+ adding d
+ $ echo a > a
+ $ echo b > b1
+ $ hg mv b1 b2
+ $ echo c > c1
+ $ hg copy c1 c2
+ $ rm d
+ $ touch d
+ $ hg diff --git
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -0,0 +1,1 @@
+ +a
+ diff --git a/b1 b/b2
+ rename from b1
+ rename to b2
+ --- a/b1
+ +++ b/b2
+ @@ -0,0 +1,1 @@
+ +b
+ diff --git a/c1 b/c1
+ --- a/c1
+ +++ b/c1
+ @@ -0,0 +1,1 @@
+ +c
+ diff --git a/c1 b/c2
+ copy from c1
+ copy to c2
+ --- a/c1
+ +++ b/c2
+ @@ -0,0 +1,1 @@
+ +c
+ diff --git a/d b/d
+ --- a/d
+ +++ b/d
+ @@ -1,1 +0,0 @@
+ -d
+ $ hg ci -m empty
+ $ hg export --git tip > empty.diff
+ $ hg up -C 0
+ 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg import empty.diff
+ applying empty.diff
+ $ for name in a b1 b2 c1 c2 d; do
+ > echo % $name file
+ > test -f $name && cat $name
+ > done
+ % a file
+ a
+ % b1 file
+ % b2 file
+ b
+ % c1 file
+ c
+ % c2 file
+ c
+ % d file
+ $ cd ..
+
+
+Test importing a patch ending with a binary file removal
+
+ $ hg init binaryremoval
+ $ cd binaryremoval
+ $ echo a > a
+ $ python -c "file('b', 'wb').write('a\x00b')"
+ $ hg ci -Am addall
+ adding a
+ adding b
+ $ hg rm a
+ $ hg rm b
+ $ hg st
+ R a
+ R b
+ $ hg ci -m remove
+ $ hg export --git . > remove.diff
+ $ cat remove.diff | grep git
+ diff --git a/a b/a
+ diff --git a/b b/b
+ $ hg up -C 0
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg import remove.diff
+ applying remove.diff
+ $ hg manifest
+ $ cd ..
+
+
+Issue927: test update+rename with common name
+
+ $ hg init t
+ $ cd t
+ $ touch a
+ $ hg ci -Am t
+ adding a
+ $ echo a > a
+
+Here, bfile.startswith(afile)
+
+ $ hg copy a a2
+ $ hg ci -m copya
+ $ hg export --git tip > copy.diff
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg import copy.diff
+ applying copy.diff
+
+a should contain an 'a'
+
+ $ cat a
+ a
+
+and a2 should have duplicated it
+
+ $ cat a2
+ a
+ $ cd ..
+
+
+test -p0
+
+ $ hg init p0
+ $ cd p0
+ $ echo a > a
+ $ hg ci -Am t
+ adding a
+ $ hg import -p0 - << EOF
+ > foobar
+ > --- a Sat Apr 12 22:43:58 2008 -0400
+ > +++ a Sat Apr 12 22:44:05 2008 -0400
+ > @@ -1,1 +1,1 @@
+ > -a
+ > +bb
+ > EOF
+ applying patch from stdin
+ $ hg status
+ $ cat a
+ bb
+ $ cd ..
+
+
+test paths outside repo root
+
+ $ mkdir outside
+ $ touch outside/foo
+ $ hg init inside
+ $ cd inside
+ $ hg import - <<EOF
+ > diff --git a/a b/b
+ > rename from ../outside/foo
+ > rename to bar
+ > EOF
+ applying patch from stdin
+ abort: path contains illegal component: ../outside/foo (glob)
+ [255]
+ $ cd ..
+
+
+test import with similarity and git and strip (issue295 et al.)
+
+ $ hg init sim
+ $ cd sim
+ $ echo 'this is a test' > a
+ $ hg ci -Ama
+ adding a
+ $ cat > ../rename.diff <<EOF
+ > diff --git a/foo/a b/foo/a
+ > deleted file mode 100644
+ > --- a/foo/a
+ > +++ /dev/null
+ > @@ -1,1 +0,0 @@
+ > -this is a test
+ > diff --git a/foo/b b/foo/b
+ > new file mode 100644
+ > --- /dev/null
+ > +++ b/foo/b
+ > @@ -0,0 +1,2 @@
+ > +this is a test
+ > +foo
+ > EOF
+ $ hg import --no-commit -v -s 1 ../rename.diff -p2
+ applying ../rename.diff
+ patching file a
+ patching file b
+ adding b
+ recording removal of a as rename to b (88% similar)
+ applied to working directory
+ $ hg st -C
+ A b
+ a
+ R a
+ $ hg revert -a
+ undeleting a
+ forgetting b
+ $ rm b
+ $ hg import --no-commit -v -s 100 ../rename.diff -p2
+ applying ../rename.diff
+ patching file a
+ patching file b
+ adding b
+ applied to working directory
+ $ hg st -C
+ A b
+ R a
+ $ cd ..
+
+
+Issue1495: add empty file from the end of patch
+
+ $ hg init addemptyend
+ $ cd addemptyend
+ $ touch a
+ $ hg addremove
+ adding a
+ $ hg ci -m "commit"
+ $ cat > a.patch <<EOF
+ > add a, b
+ > diff --git a/a b/a
+ > --- a/a
+ > +++ b/a
+ > @@ -0,0 +1,1 @@
+ > +a
+ > diff --git a/b b/b
+ > new file mode 100644
+ > EOF
+ $ hg import --no-commit a.patch
+ applying a.patch
+
+apply a good patch followed by an empty patch (mainly to ensure
+that dirstate is *not* updated when import crashes)
+ $ hg update -q -C .
+ $ rm b
+ $ touch empty.patch
+ $ hg import a.patch empty.patch
+ applying a.patch
+ applying empty.patch
+ transaction abort!
+ rollback completed
+ abort: empty.patch: no diffs found
+ [255]
+ $ hg tip --template '{rev} {desc|firstline}\n'
+ 0 commit
+ $ hg -q status
+ M a
+ $ cd ..
+
+create file when source is not /dev/null
+
+ $ cat > create.patch <<EOF
+ > diff -Naur proj-orig/foo proj-new/foo
+ > --- proj-orig/foo 1969-12-31 16:00:00.000000000 -0800
+ > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
+ > @@ -0,0 +1,1 @@
+ > +a
+ > EOF
+
+some people have patches like the following too
+
+ $ cat > create2.patch <<EOF
+ > diff -Naur proj-orig/foo proj-new/foo
+ > --- proj-orig/foo.orig 1969-12-31 16:00:00.000000000 -0800
+ > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
+ > @@ -0,0 +1,1 @@
+ > +a
+ > EOF
+ $ hg init oddcreate
+ $ cd oddcreate
+ $ hg import --no-commit ../create.patch
+ applying ../create.patch
+ $ cat foo
+ a
+ $ rm foo
+ $ hg revert foo
+ $ hg import --no-commit ../create2.patch
+ applying ../create2.patch
+ $ cat foo
+ a
+
+ $ cd ..
+
+Issue1859: first line mistaken for email headers
+
+ $ hg init emailconfusion
+ $ cd emailconfusion
+ $ cat > a.patch <<EOF
+ > module: summary
+ >
+ > description
+ >
+ >
+ > diff -r 000000000000 -r 9b4c1e343b55 test.txt
+ > --- /dev/null
+ > +++ b/a
+ > @@ -0,0 +1,1 @@
+ > +a
+ > EOF
+ $ hg import -d '0 0' a.patch
+ applying a.patch
+ $ hg parents -v
+ changeset: 0:5a681217c0ad
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: a
+ description:
+ module: summary
+
+ description
+
+
+ $ cd ..
+
+
+in commit message
+
+ $ hg init commitconfusion
+ $ cd commitconfusion
+ $ cat > a.patch <<EOF
+ > module: summary
+ >
+ > --- description
+ >
+ > diff --git a/a b/a
+ > new file mode 100644
+ > --- /dev/null
+ > +++ b/a
+ > @@ -0,0 +1,1 @@
+ > +a
+ > EOF
+ > hg import -d '0 0' a.patch
+ > hg parents -v
+ > cd ..
+ >
+ > echo '% tricky header splitting'
+ > cat > trickyheaders.patch <<EOF
+ > From: User A <user@a>
+ > Subject: [PATCH] from: tricky!
+ >
+ > # HG changeset patch
+ > # User User B
+ > # Date 1266264441 18000
+ > # Branch stable
+ > # Node ID f2be6a1170ac83bf31cb4ae0bad00d7678115bc0
+ > # Parent 0000000000000000000000000000000000000000
+ > from: tricky!
+ >
+ > That is not a header.
+ >
+ > diff -r 000000000000 -r f2be6a1170ac foo
+ > --- /dev/null
+ > +++ b/foo
+ > @@ -0,0 +1,1 @@
+ > +foo
+ > EOF
+ applying a.patch
+ changeset: 0:f34d9187897d
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: a
+ description:
+ module: summary
+
+
+ % tricky header splitting
+
+ $ hg init trickyheaders
+ $ cd trickyheaders
+ $ hg import -d '0 0' ../trickyheaders.patch
+ applying ../trickyheaders.patch
+ $ hg export --git tip
+ # HG changeset patch
+ # User User B
+ # Date 0 0
+ # Node ID eb56ab91903632294ac504838508cb370c0901d2
+ # Parent 0000000000000000000000000000000000000000
+ from: tricky!
+
+ That is not a header.
+
+ diff --git a/foo b/foo
+ new file mode 100644
+ --- /dev/null
+ +++ b/foo
+ @@ -0,0 +1,1 @@
+ +foo
+ $ cd ..
+
+
+Issue2102: hg export and hg import speak different languages
+
+ $ hg init issue2102
+ $ cd issue2102
+ $ mkdir -p src/cmd/gc
+ $ touch src/cmd/gc/mksys.bash
+ $ hg ci -Am init
+ adding src/cmd/gc/mksys.bash
+ $ hg import - <<EOF
+ > # HG changeset patch
+ > # User Rob Pike
+ > # Date 1216685449 25200
+ > # Node ID 03aa2b206f499ad6eb50e6e207b9e710d6409c98
+ > # Parent 93d10138ad8df586827ca90b4ddb5033e21a3a84
+ > help management of empty pkg and lib directories in perforce
+ >
+ > R=gri
+ > DELTA=4 (4 added, 0 deleted, 0 changed)
+ > OCL=13328
+ > CL=13328
+ >
+ > diff --git a/lib/place-holder b/lib/place-holder
+ > new file mode 100644
+ > --- /dev/null
+ > +++ b/lib/place-holder
+ > @@ -0,0 +1,2 @@
+ > +perforce does not maintain empty directories.
+ > +this file helps.
+ > diff --git a/pkg/place-holder b/pkg/place-holder
+ > new file mode 100644
+ > --- /dev/null
+ > +++ b/pkg/place-holder
+ > @@ -0,0 +1,2 @@
+ > +perforce does not maintain empty directories.
+ > +this file helps.
+ > diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
+ > old mode 100644
+ > new mode 100755
+ > EOF
+ applying patch from stdin
+
+#if execbit
+
+ $ hg sum
+ parent: 1:d59915696727 tip
+ help management of empty pkg and lib directories in perforce
+ branch: default
+ commit: (clean)
+ update: (current)
+
+ $ hg diff --git -c tip
+ diff --git a/lib/place-holder b/lib/place-holder
+ new file mode 100644
+ --- /dev/null
+ +++ b/lib/place-holder
+ @@ -0,0 +1,2 @@
+ +perforce does not maintain empty directories.
+ +this file helps.
+ diff --git a/pkg/place-holder b/pkg/place-holder
+ new file mode 100644
+ --- /dev/null
+ +++ b/pkg/place-holder
+ @@ -0,0 +1,2 @@
+ +perforce does not maintain empty directories.
+ +this file helps.
+ diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
+ old mode 100644
+ new mode 100755
+
+#else
+
+ $ hg sum
+ parent: 1:28f089cc9ccc tip
+ help management of empty pkg and lib directories in perforce
+ branch: default
+ commit: (clean)
+ update: (current)
+
+ $ hg diff --git -c tip
+ diff --git a/lib/place-holder b/lib/place-holder
+ new file mode 100644
+ --- /dev/null
+ +++ b/lib/place-holder
+ @@ -0,0 +1,2 @@
+ +perforce does not maintain empty directories.
+ +this file helps.
+ diff --git a/pkg/place-holder b/pkg/place-holder
+ new file mode 100644
+ --- /dev/null
+ +++ b/pkg/place-holder
+ @@ -0,0 +1,2 @@
+ +perforce does not maintain empty directories.
+ +this file helps.
+
+/* The mode change for mksys.bash is missing here, because on platforms */
+/* that don't support execbits, mode changes in patches are ignored when */
+/* they are imported. This is obviously also the reason for why the hash */
+/* in the created changeset is different to the one you see above the */
+/* #else clause */
+
+#endif
+ $ cd ..
+
+
+diff lines looking like headers
+
+ $ hg init difflineslikeheaders
+ $ cd difflineslikeheaders
+ $ echo a >a
+ $ echo b >b
+ $ echo c >c
+ $ hg ci -Am1
+ adding a
+ adding b
+ adding c
+
+ $ echo "key: value" >>a
+ $ echo "key: value" >>b
+ $ echo "foo" >>c
+ $ hg ci -m2
+
+ $ hg up -C 0
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg diff --git -c1 >want
+ $ hg diff -c1 | hg import --no-commit -
+ applying patch from stdin
+ $ hg diff --git >have
+ $ diff want have
+ $ cd ..
+
+import a unified diff with no lines of context (diff -U0)
+
+ $ hg init diffzero
+ $ cd diffzero
+ $ cat > f << EOF
+ > c2
+ > c4
+ > c5
+ > EOF
+ $ hg commit -Am0
+ adding f
+
+ $ hg import --no-commit - << EOF
+ > # HG changeset patch
+ > # User test
+ > # Date 0 0
+ > # Node ID f4974ab632f3dee767567b0576c0ec9a4508575c
+ > # Parent 8679a12a975b819fae5f7ad3853a2886d143d794
+ > 1
+ > diff -r 8679a12a975b -r f4974ab632f3 f
+ > --- a/f Thu Jan 01 00:00:00 1970 +0000
+ > +++ b/f Thu Jan 01 00:00:00 1970 +0000
+ > @@ -0,0 +1,1 @@
+ > +c1
+ > @@ -1,0 +3,1 @@
+ > +c3
+ > @@ -3,1 +4,0 @@
+ > -c5
+ > EOF
+ applying patch from stdin
+
+ $ cat f
+ c1
+ c2
+ c3
+ c4
+
+ $ cd ..
+
+no segfault while importing a unified diff which start line is zero but chunk
+size is non-zero
+
+ $ hg init startlinezero
+ $ cd startlinezero
+ $ echo foo > foo
+ $ hg commit -Amfoo
+ adding foo
+
+ $ hg import --no-commit - << EOF
+ > diff a/foo b/foo
+ > --- a/foo
+ > +++ b/foo
+ > @@ -0,1 +0,1 @@
+ > foo
+ > EOF
+ applying patch from stdin
+
+ $ cd ..
+
+Test corner case involving fuzz and skew
+
+ $ hg init morecornercases
+ $ cd morecornercases
+
+ $ cat > 01-no-context-beginning-of-file.diff <<EOF
+ > diff --git a/a b/a
+ > --- a/a
+ > +++ b/a
+ > @@ -1,0 +1,1 @@
+ > +line
+ > EOF
+
+ $ cat > 02-no-context-middle-of-file.diff <<EOF
+ > diff --git a/a b/a
+ > --- a/a
+ > +++ b/a
+ > @@ -1,1 +1,1 @@
+ > -2
+ > +add some skew
+ > @@ -2,0 +2,1 @@
+ > +line
+ > EOF
+
+ $ cat > 03-no-context-end-of-file.diff <<EOF
+ > diff --git a/a b/a
+ > --- a/a
+ > +++ b/a
+ > @@ -10,0 +10,1 @@
+ > +line
+ > EOF
+
+ $ cat > 04-middle-of-file-completely-fuzzed.diff <<EOF
+ > diff --git a/a b/a
+ > --- a/a
+ > +++ b/a
+ > @@ -1,1 +1,1 @@
+ > -2
+ > +add some skew
+ > @@ -2,2 +2,3 @@
+ > not matching, should fuzz
+ > ... a bit
+ > +line
+ > EOF
+
+ $ cat > a <<EOF
+ > 1
+ > 2
+ > 3
+ > 4
+ > EOF
+ $ hg ci -Am adda a
+ $ for p in *.diff; do
+ > hg import -v --no-commit $p
+ > cat a
+ > hg revert -aqC a
+ > # patch -p1 < $p
+ > # cat a
+ > # hg revert -aC a
+ > done
+ applying 01-no-context-beginning-of-file.diff
+ patching file a
+ applied to working directory
+ 1
+ line
+ 2
+ 3
+ 4
+ applying 02-no-context-middle-of-file.diff
+ patching file a
+ Hunk #1 succeeded at 2 (offset 1 lines).
+ Hunk #2 succeeded at 4 (offset 1 lines).
+ applied to working directory
+ 1
+ add some skew
+ 3
+ line
+ 4
+ applying 03-no-context-end-of-file.diff
+ patching file a
+ Hunk #1 succeeded at 5 (offset -6 lines).
+ applied to working directory
+ 1
+ 2
+ 3
+ 4
+ line
+ applying 04-middle-of-file-completely-fuzzed.diff
+ patching file a
+ Hunk #1 succeeded at 2 (offset 1 lines).
+ Hunk #2 succeeded at 5 with fuzz 2 (offset 1 lines).
+ applied to working directory
+ 1
+ add some skew
+ 3
+ 4
+ line
+
+ $ cd ..
diff --git a/tests/test-incoming-outgoing.t b/tests/test-incoming-outgoing.t
new file mode 100644
index 0000000..03deeac
--- /dev/null
+++ b/tests/test-incoming-outgoing.t
@@ -0,0 +1,491 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ hg init test
+ $ cd test
+ $ for i in 0 1 2 3 4 5 6 7 8; do
+ > echo $i >> foo
+ > hg commit -A -m $i
+ > done
+ adding foo
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 9 changesets, 9 total revisions
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ cd ..
+
+ $ hg init new
+
+http incoming
+
+ $ hg -R new incoming http://localhost:$HGPORT/
+ comparing with http://localhost:$HGPORT/
+ changeset: 0:00a43fa82f62
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ changeset: 1:5460a410df01
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ changeset: 2:d9f42cd1a1ec
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 3:376476025137
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3
+
+ changeset: 4:70d7eb252d49
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 4
+
+ changeset: 5:ad284ee3b5ee
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 5
+
+ changeset: 6:e9229f2de384
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 6
+
+ changeset: 7:d152815bb8db
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 7
+
+ changeset: 8:e4feb4ac9035
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 8
+
+ $ hg -R new incoming -r 4 http://localhost:$HGPORT/
+ comparing with http://localhost:$HGPORT/
+ changeset: 0:00a43fa82f62
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ changeset: 1:5460a410df01
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ changeset: 2:d9f42cd1a1ec
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 3:376476025137
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3
+
+ changeset: 4:70d7eb252d49
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 4
+
+
+local incoming
+
+ $ hg -R new incoming test
+ comparing with test
+ changeset: 0:00a43fa82f62
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ changeset: 1:5460a410df01
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ changeset: 2:d9f42cd1a1ec
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 3:376476025137
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3
+
+ changeset: 4:70d7eb252d49
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 4
+
+ changeset: 5:ad284ee3b5ee
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 5
+
+ changeset: 6:e9229f2de384
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 6
+
+ changeset: 7:d152815bb8db
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 7
+
+ changeset: 8:e4feb4ac9035
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 8
+
+ $ hg -R new incoming -r 4 test
+ comparing with test
+ changeset: 0:00a43fa82f62
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ changeset: 1:5460a410df01
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ changeset: 2:d9f42cd1a1ec
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 3:376476025137
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3
+
+ changeset: 4:70d7eb252d49
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 4
+
+
+limit to 2 changesets
+
+ $ hg -R new incoming -l 2 test
+ comparing with test
+ changeset: 0:00a43fa82f62
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ changeset: 1:5460a410df01
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+
+limit to 2 changesets, test with -p --git
+
+ $ hg -R new incoming -l 2 -p --git test
+ comparing with test
+ changeset: 0:00a43fa82f62
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ diff --git a/foo b/foo
+ new file mode 100644
+ --- /dev/null
+ +++ b/foo
+ @@ -0,0 +1,1 @@
+ +0
+
+ changeset: 1:5460a410df01
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ diff --git a/foo b/foo
+ --- a/foo
+ +++ b/foo
+ @@ -1,1 +1,2 @@
+ 0
+ +1
+
+
+test with --bundle
+
+ $ hg -R new incoming --bundle test.hg http://localhost:$HGPORT/
+ comparing with http://localhost:$HGPORT/
+ changeset: 0:00a43fa82f62
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ changeset: 1:5460a410df01
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ changeset: 2:d9f42cd1a1ec
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 3:376476025137
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3
+
+ changeset: 4:70d7eb252d49
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 4
+
+ changeset: 5:ad284ee3b5ee
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 5
+
+ changeset: 6:e9229f2de384
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 6
+
+ changeset: 7:d152815bb8db
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 7
+
+ changeset: 8:e4feb4ac9035
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 8
+
+ $ hg -R new incoming --bundle test2.hg test
+ comparing with test
+ changeset: 0:00a43fa82f62
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0
+
+ changeset: 1:5460a410df01
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ changeset: 2:d9f42cd1a1ec
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 3:376476025137
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3
+
+ changeset: 4:70d7eb252d49
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 4
+
+ changeset: 5:ad284ee3b5ee
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 5
+
+ changeset: 6:e9229f2de384
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 6
+
+ changeset: 7:d152815bb8db
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 7
+
+ changeset: 8:e4feb4ac9035
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 8
+
+
+
+test the resulting bundles
+
+ $ hg init temp
+ $ hg init temp2
+ $ hg -R temp unbundle test.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 9 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg -R temp2 unbundle test2.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 9 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg -R temp tip
+ changeset: 8:e4feb4ac9035
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 8
+
+ $ hg -R temp2 tip
+ changeset: 8:e4feb4ac9035
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 8
+
+
+ $ rm -r temp temp2 new
+
+test outgoing
+
+ $ hg clone test test-dev
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd test-dev
+ $ for i in 9 10 11 12 13; do
+ > echo $i >> foo
+ > hg commit -A -m $i
+ > done
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 14 changesets, 14 total revisions
+ $ cd ..
+ $ hg -R test-dev outgoing test
+ comparing with test
+ searching for changes
+ changeset: 9:d89d4abea5bc
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 9
+
+ changeset: 10:820095aa7158
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 10
+
+ changeset: 11:09ede2f3a638
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 11
+
+ changeset: 12:e576b1bed305
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 12
+
+ changeset: 13:96bbff09a7cc
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 13
+
+test outgoing with secret changesets
+
+ $ hg -R test-dev phase --force --secret 9
+ $ hg -R test-dev outgoing test
+ comparing with test
+ searching for changes
+ no changes found (ignored 5 secret changesets)
+ [1]
+ $ hg -R test-dev phase --draft -r 'head()'
+
+limit to 3 changesets
+
+ $ hg -R test-dev outgoing -l 3 test
+ comparing with test
+ searching for changes
+ changeset: 9:d89d4abea5bc
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 9
+
+ changeset: 10:820095aa7158
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 10
+
+ changeset: 11:09ede2f3a638
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 11
+
+ $ hg -R test-dev outgoing http://localhost:$HGPORT/
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ changeset: 9:d89d4abea5bc
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 9
+
+ changeset: 10:820095aa7158
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 10
+
+ changeset: 11:09ede2f3a638
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 11
+
+ changeset: 12:e576b1bed305
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 12
+
+ changeset: 13:96bbff09a7cc
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 13
+
+ $ hg -R test-dev outgoing -r 11 http://localhost:$HGPORT/
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ changeset: 9:d89d4abea5bc
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 9
+
+ changeset: 10:820095aa7158
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 10
+
+ changeset: 11:09ede2f3a638
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 11
+
+
+incoming from empty remote repository
+
+ $ hg init r1
+ $ hg init r2
+ $ echo a > r1/foo
+ $ hg -R r1 ci -Ama
+ adding foo
+ $ hg -R r1 incoming r2 --bundle x.hg
+ comparing with r2
+ searching for changes
+ no changes found
+ [1]
diff --git a/tests/test-inherit-mode.t b/tests/test-inherit-mode.t
new file mode 100644
index 0000000..cf6c9e5
--- /dev/null
+++ b/tests/test-inherit-mode.t
@@ -0,0 +1,152 @@
+test that new files created in .hg inherit the permissions from .hg/store
+
+
+ $ "$TESTDIR/hghave" unix-permissions || exit 80
+
+ $ mkdir dir
+
+just in case somebody has a strange $TMPDIR
+
+ $ chmod g-s dir
+ $ cd dir
+
+ $ cat >printmodes.py <<EOF
+ > import os, sys
+ >
+ > allnames = []
+ > isdir = {}
+ > for root, dirs, files in os.walk(sys.argv[1]):
+ > for d in dirs:
+ > name = os.path.join(root, d)
+ > isdir[name] = 1
+ > allnames.append(name)
+ > for f in files:
+ > name = os.path.join(root, f)
+ > allnames.append(name)
+ > allnames.sort()
+ > for name in allnames:
+ > suffix = name in isdir and '/' or ''
+ > print '%05o %s%s' % (os.lstat(name).st_mode & 07777, name, suffix)
+ > EOF
+
+ $ cat >mode.py <<EOF
+ > import sys
+ > import os
+ > print '%05o' % os.lstat(sys.argv[1]).st_mode
+ > EOF
+
+ $ umask 077
+
+ $ hg init repo
+ $ cd repo
+
+ $ chmod 0770 .hg/store
+
+before commit
+store can be written by the group, other files cannot
+store is setgid
+
+ $ python ../printmodes.py .
+ 00700 ./.hg/
+ 00600 ./.hg/00changelog.i
+ 00600 ./.hg/requires
+ 00770 ./.hg/store/
+
+ $ mkdir dir
+ $ touch foo dir/bar
+ $ hg ci -qAm 'add files'
+
+after commit
+working dir files can only be written by the owner
+files created in .hg can be written by the group
+(in particular, store/**, dirstate, branch cache file, undo files)
+new directories are setgid
+
+ $ python ../printmodes.py .
+ 00700 ./.hg/
+ 00600 ./.hg/00changelog.i
+ 00770 ./.hg/cache/
+ 00660 ./.hg/cache/branchheads
+ 00660 ./.hg/dirstate
+ 00660 ./.hg/last-message.txt
+ 00600 ./.hg/requires
+ 00770 ./.hg/store/
+ 00660 ./.hg/store/00changelog.i
+ 00660 ./.hg/store/00manifest.i
+ 00770 ./.hg/store/data/
+ 00770 ./.hg/store/data/dir/
+ 00660 ./.hg/store/data/dir/bar.i
+ 00660 ./.hg/store/data/foo.i
+ 00660 ./.hg/store/fncache
+ 00660 ./.hg/store/phaseroots
+ 00660 ./.hg/store/undo
+ 00660 ./.hg/store/undo.phaseroots
+ 00660 ./.hg/undo.bookmarks
+ 00660 ./.hg/undo.branch
+ 00660 ./.hg/undo.desc
+ 00660 ./.hg/undo.dirstate
+ 00700 ./dir/
+ 00600 ./dir/bar
+ 00600 ./foo
+
+ $ umask 007
+ $ hg init ../push
+
+before push
+group can write everything
+
+ $ python ../printmodes.py ../push
+ 00770 ../push/.hg/
+ 00660 ../push/.hg/00changelog.i
+ 00660 ../push/.hg/requires
+ 00770 ../push/.hg/store/
+
+ $ umask 077
+ $ hg -q push ../push
+
+after push
+group can still write everything
+
+ $ python ../printmodes.py ../push
+ 00770 ../push/.hg/
+ 00660 ../push/.hg/00changelog.i
+ 00770 ../push/.hg/cache/
+ 00660 ../push/.hg/cache/branchheads
+ 00660 ../push/.hg/requires
+ 00770 ../push/.hg/store/
+ 00660 ../push/.hg/store/00changelog.i
+ 00660 ../push/.hg/store/00manifest.i
+ 00770 ../push/.hg/store/data/
+ 00770 ../push/.hg/store/data/dir/
+ 00660 ../push/.hg/store/data/dir/bar.i
+ 00660 ../push/.hg/store/data/foo.i
+ 00660 ../push/.hg/store/fncache
+ 00660 ../push/.hg/store/phaseroots
+ 00660 ../push/.hg/store/undo
+ 00660 ../push/.hg/store/undo.phaseroots
+ 00660 ../push/.hg/undo.bookmarks
+ 00660 ../push/.hg/undo.branch
+ 00660 ../push/.hg/undo.desc
+ 00660 ../push/.hg/undo.dirstate
+
+
+Test that we don't lose the setgid bit when we call chmod.
+Not all systems support setgid directories (e.g. HFS+), so
+just check that directories have the same mode.
+
+ $ cd ..
+ $ hg init setgid
+ $ cd setgid
+ $ chmod g+rwx .hg/store
+ $ chmod g+s .hg/store 2> /dev/null || true
+ $ mkdir dir
+ $ touch dir/file
+ $ hg ci -qAm 'add dir/file'
+ $ storemode=`python ../mode.py .hg/store`
+ $ dirmode=`python ../mode.py .hg/store/data/dir`
+ $ if [ "$storemode" != "$dirmode" ]; then
+ > echo "$storemode != $dirmode"
+ > fi
+ $ cd ..
+
+ $ cd .. # g-s dir
diff --git a/tests/test-init.t b/tests/test-init.t
new file mode 100644
index 0000000..aa4610b
--- /dev/null
+++ b/tests/test-init.t
@@ -0,0 +1,199 @@
+This test tries to exercise the ssh functionality with a dummy script
+
+ $ checknewrepo()
+ > {
+ > name=$1
+ > if [ -d "$name"/.hg/store ]; then
+ > echo store created
+ > fi
+ > if [ -f "$name"/.hg/00changelog.i ]; then
+ > echo 00changelog.i created
+ > fi
+ > cat "$name"/.hg/requires
+ > }
+
+creating 'local'
+
+ $ hg init local
+ $ checknewrepo local
+ store created
+ 00changelog.i created
+ revlogv1
+ fncache
+ store
+ dotencode
+ $ echo this > local/foo
+ $ hg ci --cwd local -A -m "init"
+ adding foo
+
+creating repo with format.usestore=false
+
+ $ hg --config format.usestore=false init old
+ $ checknewrepo old
+ revlogv1
+
+creating repo with format.usefncache=false
+
+ $ hg --config format.usefncache=false init old2
+ $ checknewrepo old2
+ store created
+ 00changelog.i created
+ revlogv1
+ store
+
+creating repo with format.dotencode=false
+
+ $ hg --config format.dotencode=false init old3
+ $ checknewrepo old3
+ store created
+ 00changelog.i created
+ revlogv1
+ fncache
+ store
+
+test failure
+
+ $ hg init local
+ abort: repository local already exists!
+ [255]
+
+init+push to remote2
+
+ $ hg init -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote2
+ $ hg incoming -R remote2 local
+ comparing with local
+ changeset: 0:08b9e9f63b32
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: init
+
+
+ $ hg push -R local -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote2
+ pushing to ssh://user@dummy/remote2
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+
+clone to remote1
+
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" local ssh://user@dummy/remote1
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+
+init to existing repo
+
+ $ hg init -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote1
+ abort: repository remote1 already exists!
+ abort: could not create remote repo!
+ [255]
+
+clone to existing repo
+
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" local ssh://user@dummy/remote1
+ abort: repository remote1 already exists!
+ abort: could not create remote repo!
+ [255]
+
+output of dummyssh
+
+ $ cat dummylog
+ Got arguments 1:user@dummy 2:hg init remote2
+ Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio
+ Got arguments 1:user@dummy 2:hg init remote1
+ Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio
+ Got arguments 1:user@dummy 2:hg init remote1
+ Got arguments 1:user@dummy 2:hg init remote1
+
+comparing repositories
+
+ $ hg tip -q -R local
+ 0:08b9e9f63b32
+ $ hg tip -q -R remote1
+ 0:08b9e9f63b32
+ $ hg tip -q -R remote2
+ 0:08b9e9f63b32
+
+check names for repositories (clashes with URL schemes, special chars)
+
+ $ for i in bundle file hg http https old-http ssh static-http "with space"; do
+ > printf "hg init \"$i\"... "
+ > hg init "$i"
+ > test -d "$i" -a -d "$i/.hg" && echo "ok" || echo "failed"
+ > done
+ hg init "bundle"... ok
+ hg init "file"... ok
+ hg init "hg"... ok
+ hg init "http"... ok
+ hg init "https"... ok
+ hg init "old-http"... ok
+ hg init "ssh"... ok
+ hg init "static-http"... ok
+ hg init "with space"... ok
+#if eol-in-paths
+/* " " is not a valid name for a directory on Windows */
+ $ hg init " "
+ $ test -d " "
+ $ test -d " /.hg"
+#endif
+
+creating 'local/sub/repo'
+
+ $ hg init local/sub/repo
+ $ checknewrepo local/sub/repo
+ store created
+ 00changelog.i created
+ revlogv1
+ fncache
+ store
+ dotencode
+
+prepare test of init of url configured from paths
+
+ $ echo '[paths]' >> $HGRCPATH
+ $ echo "somewhere = `pwd`/url from paths" >> $HGRCPATH
+ $ echo "elsewhere = `pwd`/another paths url" >> $HGRCPATH
+
+init should (for consistency with clone) expand the url
+
+ $ hg init somewhere
+ $ checknewrepo "url from paths"
+ store created
+ 00changelog.i created
+ revlogv1
+ fncache
+ store
+ dotencode
+
+verify that clone also expand urls
+
+ $ hg clone somewhere elsewhere
+ updating to branch default
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ checknewrepo "another paths url"
+ store created
+ 00changelog.i created
+ revlogv1
+ fncache
+ store
+ dotencode
+
+clone bookmarks
+
+ $ hg -R local bookmark test
+ $ hg -R local bookmarks
+ * test 0:08b9e9f63b32
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" local ssh://user@dummy/remote-bookmarks
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ $ hg -R remote-bookmarks bookmarks
+ test 0:08b9e9f63b32
diff --git a/tests/test-inotify-debuginotify.t b/tests/test-inotify-debuginotify.t
new file mode 100644
index 0000000..f0118f6
--- /dev/null
+++ b/tests/test-inotify-debuginotify.t
@@ -0,0 +1,41 @@
+
+ $ "$TESTDIR/hghave" inotify || exit 80
+ $ hg init
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "inotify=" >> $HGRCPATH
+
+inserve
+
+ $ hg inserve -d --pid-file=hg.pid
+ $ cat hg.pid >> "$DAEMON_PIDS"
+
+let the daemon finish its stuff
+
+ $ sleep 1
+
+empty
+
+ $ hg debuginotify
+ directories being watched:
+ /
+ .hg/
+ $ mkdir a
+ $ sleep 1
+
+only 'a
+
+ $ hg debuginotify
+ directories being watched:
+ /
+ .hg/
+ a/
+ $ rmdir a
+ $ sleep 1
+
+empty again
+
+ $ hg debuginotify
+ directories being watched:
+ /
+ .hg/
+ $ kill `cat hg.pid`
diff --git a/tests/test-inotify-dirty-dirstate.t b/tests/test-inotify-dirty-dirstate.t
new file mode 100644
index 0000000..af9bd8e
--- /dev/null
+++ b/tests/test-inotify-dirty-dirstate.t
@@ -0,0 +1,72 @@
+issues when status queries are issued when dirstate is dirty
+
+ $ "$TESTDIR/hghave" inotify || exit 80
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "inotify=" >> $HGRCPATH
+ $ echo "fetch=" >> $HGRCPATH
+
+issue1810: inotify and fetch
+
+ $ hg init test; cd test
+ $ hg inserve -d --pid-file=../hg.pid
+ $ cat ../hg.pid >> "$DAEMON_PIDS"
+ $ echo foo > foo
+ $ hg add
+ adding foo
+ $ hg ci -m foo
+ $ cd ..
+ $ hg --config "inotify.pidfile=../hg2.pid" clone test test2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat ../hg2.pid >> "$DAEMON_PIDS"
+ $ cd test2
+ $ echo bar > bar
+ $ hg add
+ adding bar
+ $ hg ci -m bar
+ $ cd ../test
+ $ echo spam > spam
+ $ hg add
+ adding spam
+ $ hg ci -m spam
+ $ cd ../test2
+ $ hg st
+
+abort, outstanding changes
+
+ $ hg fetch -q
+ $ hg st
+ $ cd ..
+
+issue1719: inotify and mq
+
+ $ echo "mq=" >> $HGRCPATH
+ $ hg init test-1719
+ $ cd test-1719
+
+inserve
+
+ $ hg inserve -d --pid-file=../hg-test-1719.pid
+ $ cat ../hg-test-1719.pid >> "$DAEMON_PIDS"
+ $ echo content > file
+ $ hg add file
+ $ hg qnew -f test.patch
+ $ hg status
+ $ hg qpop
+ popping test.patch
+ patch queue now empty
+
+st should not output anything
+
+ $ hg status
+ $ hg qpush
+ applying test.patch
+ now at: test.patch
+
+st should not output anything
+
+ $ hg status
+ $ hg qrefresh
+ $ hg status
+
+ $ cd ..
diff --git a/tests/test-inotify-issue1208.t b/tests/test-inotify-issue1208.t
new file mode 100644
index 0000000..e8e5237
--- /dev/null
+++ b/tests/test-inotify-issue1208.t
@@ -0,0 +1,38 @@
+
+ $ "$TESTDIR/hghave" inotify || exit 80
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "inotify=" >> $HGRCPATH
+ $ p="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ $ hg init $p
+ $ cd $p
+
+fail
+
+ $ ln -sf doesnotexist .hg/inotify.sock
+ $ hg st
+ abort: inotify-server: cannot start: .hg/inotify.sock is a broken symlink
+ inotify-client: could not start inotify server: child process failed to start
+ $ hg inserve
+ abort: inotify-server: cannot start: .hg/inotify.sock is a broken symlink
+ [255]
+ $ rm .hg/inotify.sock
+
+inserve
+
+ $ hg inserve -d --pid-file=hg.pid
+ $ cat hg.pid >> "$DAEMON_PIDS"
+
+status
+
+ $ hg status
+ ? hg.pid
+
+if we try to start twice the server, make sure we get a correct error
+
+ $ hg inserve -d --pid-file=hg2.pid
+ abort: inotify-server: cannot start: socket is already bound
+ abort: child process failed to start
+ [255]
+ $ kill `cat hg.pid`
+
+ $ cd ..
diff --git a/tests/test-inotify-issue1371.t b/tests/test-inotify-issue1371.t
new file mode 100644
index 0000000..2a12757
--- /dev/null
+++ b/tests/test-inotify-issue1371.t
@@ -0,0 +1,44 @@
+
+ $ "$TESTDIR/hghave" inotify || exit 80
+ $ hg init
+ $ touch a b c d e f
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "inotify=" >> $HGRCPATH
+
+inserve
+
+ $ hg inserve -d --pid-file=hg.pid 2>&1
+ $ cat hg.pid >> "$DAEMON_PIDS"
+ $ hg ci -Am m
+ adding a
+ adding b
+ adding c
+ adding d
+ adding e
+ adding f
+ adding hg.pid
+
+let the daemon finish its stuff
+
+ $ sleep 1
+
+eed to test all file opperations
+
+ $ hg rm a
+ $ rm b
+ $ echo c >> c
+ $ touch g
+ $ hg add g
+ $ hg mv e h
+ $ hg status
+ M c
+ A g
+ A h
+ R a
+ R e
+ ! b
+ $ sleep 1
+
+Are we able to kill the service? if not, the service died on some error
+
+ $ kill `cat hg.pid`
diff --git a/tests/test-inotify-issue1542.t b/tests/test-inotify-issue1542.t
new file mode 100644
index 0000000..fa3d5cd
--- /dev/null
+++ b/tests/test-inotify-issue1542.t
@@ -0,0 +1,36 @@
+
+ $ "$TESTDIR/hghave" inotify || exit 80
+ $ hg init
+ $ touch a
+ $ mkdir dir
+ $ touch dir/b
+ $ touch dir/c
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "inotify=" >> $HGRCPATH
+ $ hg add dir/c
+
+inserve
+
+ $ hg inserve -d --pid-file=hg.pid 2>&1
+ $ cat hg.pid >> "$DAEMON_PIDS"
+ $ hg st
+ A dir/c
+ ? a
+ ? dir/b
+ ? hg.pid
+
+moving dir out
+
+ $ mv dir ../tmp-test-inotify-issue1542
+
+status
+
+ $ hg st
+ ! dir/c
+ ? a
+ ? hg.pid
+ $ sleep 1
+
+Are we able to kill the service? if not, the service died on some error
+
+ $ kill `cat hg.pid`
diff --git a/tests/test-inotify-issue1556.t b/tests/test-inotify-issue1556.t
new file mode 100644
index 0000000..ade628f
--- /dev/null
+++ b/tests/test-inotify-issue1556.t
@@ -0,0 +1,31 @@
+
+ $ "$TESTDIR/hghave" inotify || exit 80
+ $ hg init
+ $ touch a b
+ $ hg add a b
+ $ rm b
+
+status without inotify
+
+ $ hg st
+ A a
+ ! b
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "inotify=" >> $HGRCPATH
+
+inserve
+
+ $ hg inserve -d --pid-file=hg.pid 2>&1
+ $ cat hg.pid >> "$DAEMON_PIDS"
+
+status
+
+ $ hg st
+ A a
+ ! b
+ ? hg.pid
+ $ sleep 1
+
+Are we able to kill the service? if not, the service died on some error
+
+ $ kill `cat hg.pid`
diff --git a/tests/test-inotify-lookup.t b/tests/test-inotify-lookup.t
new file mode 100644
index 0000000..c5fca69
--- /dev/null
+++ b/tests/test-inotify-lookup.t
@@ -0,0 +1,14 @@
+
+ $ "$TESTDIR/hghave" inotify || exit 80
+ $ hg init
+ $ echo "[extensions]" > .hg/hgrc
+ $ echo "inotify=" >> .hg/hgrc
+ $ hg inserve -d --pid-file .hg/inotify.pid
+ $ echo a > a
+ $ hg ci -Aqm0
+ $ hg co -q null
+ $ hg co -q
+ $ hg st
+ $ cat a
+ a
+ $ kill `cat .hg/inotify.pid`
diff --git a/tests/test-inotify.t b/tests/test-inotify.t
new file mode 100644
index 0000000..34be779
--- /dev/null
+++ b/tests/test-inotify.t
@@ -0,0 +1,162 @@
+
+ $ "$TESTDIR/hghave" inotify || exit 80
+ $ hg init repo1
+ $ cd repo1
+ $ touch a b c d e
+ $ mkdir dir
+ $ mkdir dir/bar
+ $ touch dir/x dir/y dir/bar/foo
+ $ hg ci -Am m
+ adding a
+ adding b
+ adding c
+ adding d
+ adding dir/bar/foo
+ adding dir/x
+ adding dir/y
+ adding e
+ $ cd ..
+ $ hg clone repo1 repo2
+ updating to branch default
+ 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "inotify=" >> $HGRCPATH
+ $ cd repo2
+ $ echo b >> a
+
+check that daemon started automatically works correctly
+and make sure that inotify.pidfile works
+
+ $ hg --config "inotify.pidfile=../hg2.pid" status
+ M a
+
+make sure that pidfile worked. Output should be silent.
+
+ $ kill `cat ../hg2.pid`
+ $ cd ../repo1
+
+inserve
+
+ $ hg inserve -d --pid-file=hg.pid
+ $ cat hg.pid >> "$DAEMON_PIDS"
+
+let the daemon finish its stuff
+
+ $ sleep 1
+
+cannot start, already bound
+
+ $ hg inserve
+ abort: inotify-server: cannot start: socket is already bound
+ [255]
+
+issue907
+
+ $ hg status
+ ? hg.pid
+
+clean
+
+ $ hg status -c
+ C a
+ C b
+ C c
+ C d
+ C dir/bar/foo
+ C dir/x
+ C dir/y
+ C e
+
+all
+
+ $ hg status -A
+ ? hg.pid
+ C a
+ C b
+ C c
+ C d
+ C dir/bar/foo
+ C dir/x
+ C dir/y
+ C e
+
+path patterns
+
+ $ echo x > dir/x
+ $ hg status .
+ M dir/x
+ ? hg.pid
+ $ hg status dir
+ M dir/x
+ $ cd dir
+ $ hg status .
+ M x
+ $ cd ..
+
+issue 1375
+testing that we can remove a folder and then add a file with the same name
+issue 1375
+
+ $ mkdir h
+ $ echo h > h/h
+ $ hg ci -Am t
+ adding h/h
+ adding hg.pid
+ $ hg rm h
+ removing h/h
+ $ echo h >h
+ $ hg add h
+ $ hg status
+ A h
+ R h/h
+ $ hg ci -m0
+
+Test for issue1735: inotify watches files in .hg/merge
+
+ $ hg st
+ $ echo a > a
+ $ hg ci -Am a
+ $ hg st
+ $ echo b >> a
+ $ hg ci -m ab
+ $ hg st
+ $ echo c >> a
+ $ hg st
+ M a
+ $ HGMERGE=internal:local hg up 0
+ 1 files updated, 1 files merged, 2 files removed, 0 files unresolved
+ $ hg st
+ M a
+ $ HGMERGE=internal:local hg up
+ 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ $ hg st
+ M a
+
+Test for 1844: "hg ci folder" will not commit all changes beneath "folder"
+
+ $ mkdir 1844
+ $ echo a > 1844/foo
+ $ hg add 1844
+ adding 1844/foo
+ $ hg ci -m 'working'
+ $ echo b >> 1844/foo
+ $ hg ci 1844 -m 'broken'
+
+Test for issue884: "Build products not ignored until .hgignore is touched"
+
+ $ echo '^build$' > .hgignore
+ $ hg add .hgignore
+ $ hg ci .hgignore -m 'ignorelist'
+
+Now, lets add some build products...
+
+ $ mkdir build
+ $ touch build/x
+ $ touch build/y
+
+build/x & build/y shouldn't appear in "hg st"
+
+ $ hg st
+ $ kill `cat hg.pid`
+
+ $ cd ..
diff --git a/tests/test-install.t b/tests/test-install.t
new file mode 100644
index 0000000..5d7741d
--- /dev/null
+++ b/tests/test-install.t
@@ -0,0 +1,20 @@
+hg debuginstall
+ $ hg debuginstall
+ checking encoding (ascii)...
+ checking installed modules (*mercurial)... (glob)
+ checking templates (*mercurial?templates)... (glob)
+ checking commit editor...
+ checking username...
+ no problems detected
+
+hg debuginstall with no username
+ $ HGUSER= hg debuginstall
+ checking encoding (ascii)...
+ checking installed modules (*mercurial)... (glob)
+ checking templates (*mercurial?templates)... (glob)
+ checking commit editor...
+ checking username...
+ no username supplied (see "hg help config")
+ (specify a username in your configuration file)
+ 1 problems detected, please check your install!
+ [1]
diff --git a/tests/test-interhg.t b/tests/test-interhg.t
new file mode 100644
index 0000000..ee08846
--- /dev/null
+++ b/tests/test-interhg.t
@@ -0,0 +1,33 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ hg init test
+ $ cd test
+
+ $ cat > .hg/hgrc <<EOF
+ > [extensions]
+ > interhg =
+ >
+ > [interhg]
+ > issues = s|Issue(\d+)|<a href="http://bts.example.org/issue\1">Issue\1</a>|
+ >
+ > # yes, 'x' is a weird delimiter...
+ > markbugs = sxbugx<i class="\x">bug</i>x
+ > EOF
+
+ $ touch foo
+ $ hg add foo
+ $ hg commit -d '1 0' -m 'Issue123: fixed the bug!'
+
+ $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+log
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '' | grep bts
+ <td class="description"><a href="/rev/1b0e7ece6bd6"><a href="http://bts.example.org/issue123">Issue123</a>: fixed the <i class="x">bug</i>!</a><span class="branchhead">default</span> <span class="tag">tip</span> </td>
+
+errors
+
+ $ cat errors.log
+
+ $ cd ..
diff --git a/tests/test-issue1089.t b/tests/test-issue1089.t
new file mode 100644
index 0000000..2bdd3d0
--- /dev/null
+++ b/tests/test-issue1089.t
@@ -0,0 +1,26 @@
+http://mercurial.selenic.com/bts/issue1089
+
+ $ hg init
+ $ mkdir a
+ $ echo a > a/b
+ $ hg ci -Am m
+ adding a/b
+
+ $ hg rm a
+ removing a/b (glob)
+ $ hg ci -m m a
+
+ $ mkdir a b
+ $ echo a > a/b
+ $ hg ci -Am m
+ adding a/b
+
+ $ hg rm a
+ removing a/b (glob)
+ $ cd b
+
+Relative delete:
+
+ $ hg ci -m m ../a
+
+ $ cd ..
diff --git a/tests/test-issue1175.t b/tests/test-issue1175.t
new file mode 100644
index 0000000..563c2df
--- /dev/null
+++ b/tests/test-issue1175.t
@@ -0,0 +1,53 @@
+http://mercurial.selenic.com/bts/issue1175
+
+ $ hg init
+ $ touch a
+ $ hg ci -Am0
+ adding a
+
+ $ hg mv a a1
+ $ hg ci -m1
+
+ $ hg co 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ hg mv a a2
+ $ hg up
+ note: possible conflict - a was renamed multiple times to:
+ a2
+ a1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg ci -m2
+
+ $ touch a
+ $ hg ci -Am3
+ adding a
+
+ $ hg mv a b
+ $ hg ci -Am4 a
+
+ $ hg ci --debug --traceback -Am5 b
+ b
+ b: searching for copy revision for a
+ b: copy a:b80de5d138758541c5f05265ad144ab9fa86d1db
+ committed changeset 5:89e8e4be0de296fa3d6dd7825ccc44d7dc0f1f3b
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 6 changesets, 4 total revisions
+
+ $ hg export --git tip
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Node ID 89e8e4be0de296fa3d6dd7825ccc44d7dc0f1f3b
+ # Parent 7fc86ba705e717a721dbc361bf8c9bc05a18ca2f
+ 5
+
+ diff --git a/b b/b
+ new file mode 100644
+
diff --git a/tests/test-issue1306.t b/tests/test-issue1306.t
new file mode 100644
index 0000000..a176284
--- /dev/null
+++ b/tests/test-issue1306.t
@@ -0,0 +1,96 @@
+http://mercurial.selenic.com/bts/issue1306
+
+Initialize remote repo with branches:
+
+ $ hg init remote
+ $ cd remote
+
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+
+ $ hg branch br
+ marked working directory as branch br
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Amb
+
+ $ echo c > c
+ $ hg ci -Amc
+ adding c
+
+ $ hg log
+ changeset: 2:ae3d9c30ec50
+ branch: br
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: c
+
+ changeset: 1:3f7f930ca414
+ branch: br
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+ changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+ $ cd ..
+
+Try cloning -r branch:
+
+ $ hg clone -rbr remote local1
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 2 changes to 2 files
+ updating to branch br
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg -R local1 parents
+ changeset: 2:ae3d9c30ec50
+ branch: br
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: c
+
+
+Try cloning -rother clone#branch:
+
+ $ hg clone -r0 remote#br local2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 2 changes to 2 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg -R local2 parents
+ changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+Try cloning -r1 clone#branch:
+
+ $ hg clone -r1 remote#br local3
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 2 changes to 2 files
+ updating to branch br
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg -R local3 parents
+ changeset: 1:3f7f930ca414
+ branch: br
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+
diff --git a/tests/test-issue1438.t b/tests/test-issue1438.t
new file mode 100644
index 0000000..3832625
--- /dev/null
+++ b/tests/test-issue1438.t
@@ -0,0 +1,23 @@
+http://mercurial.selenic.com/bts/issue1438
+
+ $ "$TESTDIR/hghave" symlink || exit 80
+
+ $ hg init
+
+ $ ln -s foo link
+ $ hg add link
+ $ hg ci -mbad link
+ $ hg rm link
+ $ hg ci -mok
+ $ hg diff -g -r 0:1 > bad.patch
+
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg import --no-commit bad.patch
+ applying bad.patch
+
+ $ hg status
+ R link
+ ? bad.patch
+
diff --git a/tests/test-issue1502.t b/tests/test-issue1502.t
new file mode 100644
index 0000000..4963502
--- /dev/null
+++ b/tests/test-issue1502.t
@@ -0,0 +1,41 @@
+http://mercurial.selenic.com/bts/issue1502
+
+Initialize repository
+
+ $ hg init foo
+ $ touch foo/a && hg -R foo commit -A -m "added a"
+ adding a
+
+ $ hg clone foo foo1
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo "bar" > foo1/a && hg -R foo1 commit -m "edit a in foo1"
+ $ echo "hi" > foo/a && hg -R foo commit -m "edited a foo"
+ $ hg -R foo1 pull -u
+ pulling from $TESTTMP/foo (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ not updating: crosses branches (merge branches or update --check to force update)
+
+ $ hg -R foo1 book branchy
+ $ hg -R foo1 book
+ * branchy 1:e3e522925eff
+
+Pull. Bookmark should not jump to new head.
+
+ $ echo "there" >> foo/a && hg -R foo commit -m "edited a again"
+ $ hg -R foo1 pull
+ pulling from $TESTTMP/foo (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+
+ $ hg -R foo1 book
+ * branchy 1:e3e522925eff
diff --git a/tests/test-issue1802.t b/tests/test-issue1802.t
new file mode 100644
index 0000000..9b3268a
--- /dev/null
+++ b/tests/test-issue1802.t
@@ -0,0 +1,73 @@
+ $ "$TESTDIR/hghave" execbit || exit 80
+
+Create extension that can disable exec checks:
+
+ $ cat > noexec.py <<EOF
+ > from mercurial import extensions, util
+ > def setflags(orig, f, l, x):
+ > pass
+ > def checkexec(orig, path):
+ > return False
+ > def extsetup(ui):
+ > extensions.wrapfunction(util, 'setflags', setflags)
+ > extensions.wrapfunction(util, 'checkexec', checkexec)
+ > EOF
+
+ $ hg init unix-repo
+ $ cd unix-repo
+ $ touch a
+ $ hg add a
+ $ hg commit -m 'unix: add a'
+ $ hg clone . ../win-repo
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ chmod +x a
+ $ hg commit -m 'unix: chmod a'
+ $ hg manifest -v
+ 755 * a
+
+ $ cd ../win-repo
+
+ $ touch b
+ $ hg add b
+ $ hg commit -m 'win: add b'
+
+ $ hg manifest -v
+ 644 a
+ 644 b
+
+ $ hg pull
+ pulling from $TESTTMP/unix-repo
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 0 changes to 0 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ $ hg manifest -v -r tip
+ 755 * a
+
+Simulate a Windows merge:
+
+ $ hg --config extensions.n=$TESTTMP/noexec.py merge --debug
+ searching for copies back to rev 1
+ unmatched files in local:
+ b
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: a03b0deabf2b, local: d6fa54f68ae1+, remote: 2d8bcf2dda39
+ a: update permissions -> e
+ updating: a 1/1 files (100.00%)
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+Simulate a Windows commit:
+
+ $ hg --config extensions.n=$TESTTMP/noexec.py commit -m 'win: merge'
+
+ $ hg manifest -v
+ 755 * a
+ 644 b
+
+ $ cd ..
diff --git a/tests/test-issue1877.t b/tests/test-issue1877.t
new file mode 100644
index 0000000..aa3083a
--- /dev/null
+++ b/tests/test-issue1877.t
@@ -0,0 +1,46 @@
+http://mercurial.selenic.com/bts/issue1877
+
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg add a
+ $ hg ci -m 'a'
+ $ echo b > a
+ $ hg ci -m'b'
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg book main
+ $ hg book
+ * main 0:cb9a9f314b8b
+ $ echo c > c
+ $ hg add c
+ $ hg ci -m'c'
+ created new head
+ $ hg book
+ * main 2:d36c0562f908
+ $ hg heads
+ changeset: 2:d36c0562f908
+ bookmark: main
+ tag: tip
+ parent: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: c
+
+ changeset: 1:1e6c11564562
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+ $ hg up 1e6c11564562
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge main
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg book
+ main 2:d36c0562f908
+ $ hg ci -m'merge'
+ $ hg book
+ main 2:d36c0562f908
+
+ $ cd ..
diff --git a/tests/test-issue2137.t b/tests/test-issue2137.t
new file mode 100644
index 0000000..99b41f4
--- /dev/null
+++ b/tests/test-issue2137.t
@@ -0,0 +1,56 @@
+http://mercurial.selenic.com/bts/issue2137
+
+Setup:
+
+create a little extension that has 3 side-effects:
+1) ensure changelog data is not inlined
+2) make revlog to use lazyparser
+3) test that repo.lookup() works
+1 and 2 are preconditions for the bug; 3 is the bug.
+
+ $ cat > commitwrapper.py <<EOF
+ > from mercurial import extensions, node, revlog
+ >
+ > def reposetup(ui, repo):
+ > def wrapcommit(orig, *args, **kwargs):
+ > result = orig(*args, **kwargs)
+ > tip1 = node.short(repo.changelog.tip())
+ > tip2 = node.short(repo.lookup(tip1))
+ > assert tip1 == tip2
+ > ui.write('new tip: %s\n' % tip1)
+ > return result
+ >
+ > extensions.wrapfunction(repo, 'commit', wrapcommit)
+ >
+ > def extsetup(ui):
+ > revlog._maxinline = 8 # split out 00changelog.d early
+ > revlog._prereadsize = 8 # use revlog.lazyparser
+ > EOF
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > commitwrapper = `pwd`/commitwrapper.py
+ > EOF
+
+ $ hg init repo1
+ $ cd repo1
+ $ echo a > a
+ $ hg commit -A -m'add a with a long commit message to make the changelog a bit bigger'
+ adding a
+ new tip: 553596fad57b
+
+Test that new changesets are visible to repo.lookup():
+
+ $ echo a >> a
+ $ hg commit -m'one more commit to demonstrate the bug'
+ new tip: 799ae3599e0e
+
+ $ hg tip
+ changeset: 1:799ae3599e0e
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: one more commit to demonstrate the bug
+
+
+ $ cd ..
diff --git a/tests/test-issue3084.t b/tests/test-issue3084.t
new file mode 100644
index 0000000..43945b1
--- /dev/null
+++ b/tests/test-issue3084.t
@@ -0,0 +1,110 @@
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "largefiles =" >> $HGRCPATH
+
+Create the repository outside $HOME since largefiles write to
+$HOME/.cache/largefiles.
+
+ $ hg init test
+ $ cd test
+ $ echo "root" > root
+ $ hg add root
+ $ hg commit -m "Root commit"
+
+ $ echo "large" > foo
+ $ hg add --large foo
+ $ hg commit -m "Add foo as a largefile"
+
+ $ hg update -r 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ getting changed largefiles
+ 0 largefiles updated, 1 removed
+
+ $ echo "normal" > foo
+ $ hg add foo
+ $ hg commit -m "Add foo as normal file"
+ created new head
+
+Normal file in the working copy, keeping the normal version:
+
+ $ echo "n" | hg merge --config ui.interactive=Yes
+ foo has been turned into a largefile
+ use (l)argefile or keep as (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg status
+ $ cat foo
+ normal
+
+Normal file in the working copy, keeping the largefile version:
+
+ $ hg update -q -C
+ $ echo "l" | hg merge --config ui.interactive=Yes
+ foo has been turned into a largefile
+ use (l)argefile or keep as (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+
+ $ hg status
+ M foo
+
+ $ hg diff --nodates
+ diff -r fa129ab6b5a7 .hglf/foo
+ --- /dev/null
+ +++ b/.hglf/foo
+ @@ -0,0 +1,1 @@
+ +7f7097b041ccf68cc5561e9600da4655d21c6d18
+ diff -r fa129ab6b5a7 foo
+ --- a/foo
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -normal
+
+ $ cat foo
+ large
+
+Largefile in the working copy, keeping the normal version:
+
+ $ hg update -q -C -r 1
+ $ echo "n" | hg merge --config ui.interactive=Yes
+ foo has been turned into a normal file
+ keep as (l)argefile or use (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ getting changed largefiles
+ 0 largefiles updated, 0 removed
+
+ $ hg status
+ M foo
+
+ $ hg diff --nodates
+ diff -r ff521236428a .hglf/foo
+ --- a/.hglf/foo
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -7f7097b041ccf68cc5561e9600da4655d21c6d18
+ diff -r ff521236428a foo
+ --- /dev/null
+ +++ b/foo
+ @@ -0,0 +1,1 @@
+ +normal
+
+ $ cat foo
+ normal
+
+Largefile in the working copy, keeping the largefile version:
+
+ $ hg update -q -C -r 1
+ $ echo "l" | hg merge --config ui.interactive=Yes
+ foo has been turned into a normal file
+ keep as (l)argefile or use (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+
+ $ hg status
+
+ $ cat foo
+ large
+
+ $ cd ..
diff --git a/tests/test-issue522.t b/tests/test-issue522.t
new file mode 100644
index 0000000..a21f23b
--- /dev/null
+++ b/tests/test-issue522.t
@@ -0,0 +1,56 @@
+http://mercurial.selenic.com/bts/issue522
+
+In the merge below, the file "foo" has the same contents in both
+parents, but if we look at the file-level history, we'll notice that
+the version in p1 is an ancestor of the version in p2. This test makes
+sure that we'll use the version from p2 in the manifest of the merge
+revision.
+
+ $ hg init
+
+ $ echo foo > foo
+ $ hg ci -qAm 'add foo'
+
+ $ echo bar >> foo
+ $ hg ci -m 'change foo'
+
+ $ hg backout -r tip -m 'backout changed foo'
+ reverting foo
+ changeset 2:4d9e78aaceee backs out changeset 1:b515023e500e
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ touch bar
+ $ hg ci -qAm 'add bar'
+
+ $ hg merge --debug
+ searching for copies back to rev 1
+ unmatched files in local:
+ bar
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: bbd179dfa0a7, local: 71766447bdbb+, remote: 4d9e78aaceee
+ foo: remote is newer -> g
+ updating: foo 1/1 files (100.00%)
+ getting foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg debugstate | grep foo
+ n 0 -2 unset foo
+
+ $ hg st -A foo
+ M foo
+
+ $ hg ci -m 'merge'
+
+ $ hg manifest --debug | grep foo
+ c6fc755d7e68f49f880599da29f15add41f42f5a 644 foo
+
+ $ hg debugindex foo
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 5 ..... 0 2ed2a3912a0b 000000000000 000000000000 (re)
+ 1 5 9 ..... 1 6f4310b00b9a 2ed2a3912a0b 000000000000 (re)
+ 2 14 5 ..... 2 c6fc755d7e68 6f4310b00b9a 000000000000 (re)
+
diff --git a/tests/test-issue612.t b/tests/test-issue612.t
new file mode 100644
index 0000000..2985abb
--- /dev/null
+++ b/tests/test-issue612.t
@@ -0,0 +1,34 @@
+http://mercurial.selenic.com/bts/issue612
+
+ $ hg init
+ $ mkdir src
+ $ echo a > src/a.c
+ $ hg ci -Ama
+ adding src/a.c
+
+ $ hg mv src source
+ moving src/a.c to source/a.c (glob)
+
+ $ hg ci -Ammove
+
+ $ hg co -C 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ echo new > src/a.c
+ $ echo compiled > src/a.o
+ $ hg ci -mupdate
+ created new head
+
+ $ hg status
+ ? src/a.o
+
+ $ hg merge
+ merging src/a.c and source/a.c to source/a.c
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg status
+ M source/a.c
+ R src/a.c
+ ? src/a.o
+
diff --git a/tests/test-issue619.t b/tests/test-issue619.t
new file mode 100644
index 0000000..e53e4df
--- /dev/null
+++ b/tests/test-issue619.t
@@ -0,0 +1,30 @@
+http://mercurial.selenic.com/bts/issue619
+
+ $ hg init
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+
+ $ echo b > b
+ $ hg branch b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Amb
+ adding b
+
+ $ hg co -C 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+Fast-forward:
+
+ $ hg merge b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -Ammerge
+
+Bogus fast-forward should fail:
+
+ $ hg merge b
+ abort: merging with a working directory ancestor has no effect
+ [255]
+
diff --git a/tests/test-issue660.t b/tests/test-issue660.t
new file mode 100644
index 0000000..850eb3f
--- /dev/null
+++ b/tests/test-issue660.t
@@ -0,0 +1,145 @@
+http://mercurial.selenic.com/bts/issue660 and:
+http://mercurial.selenic.com/bts/issue322
+
+ $ hg init
+ $ echo a > a
+ $ mkdir b
+ $ echo b > b/b
+ $ hg commit -A -m "a is file, b is dir"
+ adding a
+ adding b/b
+
+File replaced with directory:
+
+ $ rm a
+ $ mkdir a
+ $ echo a > a/a
+
+Should fail - would corrupt dirstate:
+
+ $ hg add a/a
+ abort: file 'a' in dirstate clashes with 'a/a'
+ [255]
+
+Removing shadow:
+
+ $ hg rm --after a
+
+Should succeed - shadow removed:
+
+ $ hg add a/a
+
+Directory replaced with file:
+
+ $ rm -r b
+ $ echo b > b
+
+Should fail - would corrupt dirstate:
+
+ $ hg add b
+ abort: directory 'b' already in dirstate
+ [255]
+
+Removing shadow:
+
+ $ hg rm --after b/b
+
+Should succeed - shadow removed:
+
+ $ hg add b
+
+Look what we got:
+
+ $ hg st
+ A a/a
+ A b
+ R a
+ R b/b
+
+Revert reintroducing shadow - should fail:
+
+ $ rm -r a b
+ $ hg revert b/b
+ abort: file 'b' in dirstate clashes with 'b/b'
+ [255]
+
+Revert all - should succeed:
+
+ $ hg revert --all
+ undeleting a
+ forgetting a/a (glob)
+ forgetting b
+ undeleting b/b (glob)
+
+ $ hg st
+
+addremove:
+
+ $ rm -r a b
+ $ mkdir a
+ $ echo a > a/a
+ $ echo b > b
+
+ $ hg addremove -s 0
+ removing a
+ adding a/a
+ adding b
+ removing b/b
+
+ $ hg st
+ A a/a
+ A b
+ R a
+ R b/b
+
+commit:
+
+ $ hg ci -A -m "a is dir, b is file"
+ $ hg st --all
+ C a/a
+ C b
+
+Long directory replaced with file:
+
+ $ mkdir d
+ $ mkdir d/d
+ $ echo d > d/d/d
+ $ hg commit -A -m "d is long directory"
+ adding d/d/d
+
+ $ rm -r d
+ $ echo d > d
+
+Should fail - would corrupt dirstate:
+
+ $ hg add d
+ abort: directory 'd' already in dirstate
+ [255]
+
+Removing shadow:
+
+ $ hg rm --after d/d/d
+
+Should succeed - shadow removed:
+
+ $ hg add d
+ $ hg ci -md
+
+Update should work at least with clean working directory:
+
+ $ rm -r a b d
+ $ hg up -r 0
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg st --all
+ C a
+ C b/b
+
+ $ rm -r a b
+ $ hg up -r 1
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg st --all
+ C a/a
+ C b
+
diff --git a/tests/test-issue672.t b/tests/test-issue672.t
new file mode 100644
index 0000000..a6e4fcb
--- /dev/null
+++ b/tests/test-issue672.t
@@ -0,0 +1,101 @@
+http://mercurial.selenic.com/bts/issue672
+
+# 0-2-4
+# \ \ \
+# 1-3-5
+#
+# rename in #1, content change in #4.
+
+ $ hg init
+
+ $ touch 1
+ $ touch 2
+ $ hg commit -Am init # 0
+ adding 1
+ adding 2
+
+ $ hg rename 1 1a
+ $ hg commit -m rename # 1
+
+ $ hg co -C 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ echo unrelated >> 2
+ $ hg ci -m unrelated1 # 2
+ created new head
+
+ $ hg merge --debug 1
+ searching for copies back to rev 1
+ unmatched files in other:
+ 1a
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ 1a -> 1
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 81f4b099af3d, local: c64f439569a9+, remote: c12dcd37c90a
+ 1: other deleted -> r
+ 1a: remote created -> g
+ updating: 1 1/2 files (50.00%)
+ removing 1
+ updating: 1a 2/2 files (100.00%)
+ getting 1a
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg ci -m merge1 # 3
+
+ $ hg co -C 2
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ echo hello >> 1
+ $ hg ci -m unrelated2 # 4
+ created new head
+
+ $ hg co -C 3
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ hg merge -y --debug 4
+ searching for copies back to rev 1
+ unmatched files in local:
+ 1a
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ 1a -> 1 *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: c64f439569a9, local: e327dca35ac8+, remote: 746e9549ea96
+ 1a: local copied/moved to 1 -> m
+ preserving 1a for resolve of 1a
+ updating: 1a 1/1 files (100.00%)
+ picked tool 'internal:merge' for 1a (binary False symlink False)
+ merging 1a and 1 to 1a
+ my 1a@e327dca35ac8+ other 1@746e9549ea96 ancestor 1@81f4b099af3d
+ premerge successful
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg co -C 4
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ hg merge -y --debug 3
+ searching for copies back to rev 1
+ unmatched files in other:
+ 1a
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ 1a -> 1 *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: c64f439569a9, local: 746e9549ea96+, remote: e327dca35ac8
+ 1: remote moved to 1a -> m
+ preserving 1 for resolve of 1a
+ removing 1
+ updating: 1 1/1 files (100.00%)
+ picked tool 'internal:merge' for 1a (binary False symlink False)
+ merging 1 and 1a to 1a
+ my 1a@746e9549ea96+ other 1a@e327dca35ac8 ancestor 1@81f4b099af3d
+ premerge successful
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
diff --git a/tests/test-issue842.t b/tests/test-issue842.t
new file mode 100644
index 0000000..6cf9b9d
--- /dev/null
+++ b/tests/test-issue842.t
@@ -0,0 +1,39 @@
+http://mercurial.selenic.com/bts/issue842
+
+ $ hg init
+ $ echo foo > a
+ $ hg ci -Ama
+ adding a
+
+ $ hg up -r0000
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ echo bar > a
+
+Should issue new head warning:
+
+ $ hg ci -Amb
+ adding a
+ created new head
+
+ $ hg up -r0000
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ echo stuffy > a
+
+Should not issue new head warning:
+
+ $ hg ci -q -Amc
+
+ $ hg up -r0000
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ echo crap > a
+ $ hg branch testing
+ marked working directory as branch testing
+ (branches are permanent and global, did you want a bookmark?)
+
+Should not issue warning:
+
+ $ hg ci -q -Amd
+
diff --git a/tests/test-journal-exists.t b/tests/test-journal-exists.t
new file mode 100644
index 0000000..4cc908f
--- /dev/null
+++ b/tests/test-journal-exists.t
@@ -0,0 +1,36 @@
+ $ hg init
+ $ echo a > a
+ $ hg ci -Am0
+ adding a
+
+ $ hg -q clone . foo
+
+ $ touch .hg/store/journal
+
+ $ echo foo > a
+ $ hg ci -Am0
+ abort: abandoned transaction found - run hg recover!
+ [255]
+
+ $ hg recover
+ rolling back interrupted transaction
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+
+Check that zero-size journals are correctly aborted:
+
+#if unix-permissions
+ $ hg bundle -qa repo.hg
+ $ chmod -w foo/.hg/store/00changelog.i
+
+ $ hg -R foo unbundle repo.hg
+ adding changesets
+ abort: Permission denied: $TESTTMP/foo/.hg/store/.00changelog.i-* (glob)
+ [255]
+
+ $ if test -f foo/.hg/store/journal; then echo 'journal exists :-('; fi
+#endif
+
diff --git a/tests/test-keyword.t b/tests/test-keyword.t
new file mode 100644
index 0000000..56fb4ba
--- /dev/null
+++ b/tests/test-keyword.t
@@ -0,0 +1,1139 @@
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > keyword =
+ > mq =
+ > notify =
+ > record =
+ > transplant =
+ > [ui]
+ > interactive = true
+ > EOF
+
+hide outer repo
+ $ hg init
+
+Run kwdemo before [keyword] files are set up
+as it would succeed without uisetup otherwise
+
+ $ hg --quiet kwdemo
+ [extensions]
+ keyword =
+ [keyword]
+ demo.txt =
+ [keywordset]
+ svn = False
+ [keywordmaps]
+ Author = {author|user}
+ Date = {date|utcdate}
+ Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
+ Id = {file|basename},v {node|short} {date|utcdate} {author|user}
+ RCSFile = {file|basename},v
+ RCSfile = {file|basename},v
+ Revision = {node|short}
+ Source = {root}/{file},v
+ $Author: test $
+ $Date: ????/??/?? ??:??:?? $ (glob)
+ $Header: */demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
+ $Id: demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
+ $RCSFile: demo.txt,v $
+ $RCSfile: demo.txt,v $
+ $Revision: ???????????? $ (glob)
+ $Source: */demo.txt,v $ (glob)
+
+ $ hg --quiet kwdemo "Branch = {branches}"
+ [extensions]
+ keyword =
+ [keyword]
+ demo.txt =
+ [keywordset]
+ svn = False
+ [keywordmaps]
+ Branch = {branches}
+ $Branch: demobranch $
+
+ $ cat <<EOF >> $HGRCPATH
+ > [keyword]
+ > ** =
+ > b = ignore
+ > i = ignore
+ > [hooks]
+ > EOF
+ $ cp $HGRCPATH $HGRCPATH.nohooks
+ > cat <<EOF >> $HGRCPATH
+ > commit=
+ > commit.test=cp a hooktest
+ > EOF
+
+ $ hg init Test-bndl
+ $ cd Test-bndl
+
+kwshrink should exit silently in empty/invalid repo
+
+ $ hg kwshrink
+
+Symlinks cannot be created on Windows.
+A bundle to test this was made with:
+ hg init t
+ cd t
+ echo a > a
+ ln -s a sym
+ hg add sym
+ hg ci -m addsym -u mercurial
+ hg bundle --base null ../test-keyword.hg
+
+ $ hg pull -u "$TESTDIR"/bundles/test-keyword.hg
+ pulling from *test-keyword.hg (glob)
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo 'expand $Id$' > a
+ $ echo 'do not process $Id:' >> a
+ $ echo 'xxx $' >> a
+ $ echo 'ignore $Id$' > b
+
+Output files as they were created
+
+ $ cat a b
+ expand $Id$
+ do not process $Id:
+ xxx $
+ ignore $Id$
+
+no kwfiles
+
+ $ hg kwfiles
+
+untracked candidates
+
+ $ hg -v kwfiles --unknown
+ k a
+
+Add files and check status
+
+ $ hg addremove
+ adding a
+ adding b
+ $ hg status
+ A a
+ A b
+
+
+Default keyword expansion including commit hook
+Interrupted commit should not change state or run commit hook
+
+ $ hg --debug commit
+ abort: empty commit message
+ [255]
+ $ hg status
+ A a
+ A b
+
+Commit with several checks
+
+ $ hg --debug commit -mabsym -u 'User Name <user@example.com>'
+ a
+ b
+ overwriting a expanding keywords
+ running hook commit.test: cp a hooktest
+ committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
+ $ hg status
+ ? hooktest
+ $ hg debugrebuildstate
+ $ hg --quiet identify
+ ef63ca68695b
+
+cat files in working directory with keywords expanded
+
+ $ cat a b
+ expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
+ do not process $Id:
+ xxx $
+ ignore $Id$
+
+hg cat files and symlink, no expansion
+
+ $ hg cat sym a b && echo
+ expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
+ do not process $Id:
+ xxx $
+ ignore $Id$
+ a
+
+ $ diff a hooktest
+
+ $ cp $HGRCPATH.nohooks $HGRCPATH
+ $ rm hooktest
+
+hg status of kw-ignored binary file starting with '\1\n'
+
+ >>> open("i", "wb").write("\1\nfoo")
+ $ hg -q commit -Am metasep i
+ $ hg status
+ >>> open("i", "wb").write("\1\nbar")
+ $ hg status
+ M i
+ $ hg -q commit -m "modify metasep" i
+ $ hg status --rev 2:3
+ M i
+ $ touch empty
+ $ hg -q commit -A -m "another file"
+ $ hg status -A --rev 3:4 i
+ C i
+
+ $ hg -q strip -n 2
+
+Test hook execution
+
+bundle
+
+ $ hg bundle --base null ../kw.hg
+ 2 changesets found
+ $ cd ..
+ $ hg init Test
+ $ cd Test
+
+Notify on pull to check whether keywords stay as is in email
+ie. if patch.diff wrapper acts as it should
+
+ $ cat <<EOF >> $HGRCPATH
+ > [hooks]
+ > incoming.notify = python:hgext.notify.hook
+ > [notify]
+ > sources = pull
+ > diffstat = False
+ > maxsubject = 15
+ > [reposubs]
+ > * = Test
+ > EOF
+
+Pull from bundle and trigger notify
+
+ $ hg pull -u ../kw.hg
+ pulling from ../kw.hg
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 3 changes to 3 files
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Date: * (glob)
+ Subject: changeset in...
+ From: mercurial
+ X-Hg-Notification: changeset a2392c293916
+ Message-Id: <hg.a2392c293916*> (glob)
+ To: Test
+
+ changeset a2392c293916 in $TESTTMP/Test (glob)
+ details: $TESTTMP/Test?cmd=changeset;node=a2392c293916
+ description:
+ addsym
+
+ diffs (6 lines):
+
+ diff -r 000000000000 -r a2392c293916 sym
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/sym Sat Feb 09 20:25:47 2008 +0100
+ @@ -0,0 +1,1 @@
+ +a
+ \ No newline at end of file
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Date:* (glob)
+ Subject: changeset in...
+ From: User Name <user@example.com>
+ X-Hg-Notification: changeset ef63ca68695b
+ Message-Id: <hg.ef63ca68695b*> (glob)
+ To: Test
+
+ changeset ef63ca68695b in $TESTTMP/Test (glob)
+ details: $TESTTMP/Test?cmd=changeset;node=ef63ca68695b
+ description:
+ absym
+
+ diffs (12 lines):
+
+ diff -r a2392c293916 -r ef63ca68695b a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,3 @@
+ +expand $Id$
+ +do not process $Id:
+ +xxx $
+ diff -r a2392c293916 -r ef63ca68695b b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +ignore $Id$
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cp $HGRCPATH.nohooks $HGRCPATH
+
+Touch files and check with status
+
+ $ touch a b
+ $ hg status
+
+Update and expand
+
+ $ rm sym a b
+ $ hg update -C
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat a b
+ expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
+ do not process $Id:
+ xxx $
+ ignore $Id$
+
+Check whether expansion is filewise and file mode is preserved
+
+ $ echo '$Id$' > c
+ $ echo 'tests for different changenodes' >> c
+#if unix-permissions
+ $ chmod 600 c
+ $ ls -l c | cut -b 1-10
+ -rw-------
+#endif
+
+commit file c
+
+ $ hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
+ adding c
+#if unix-permissions
+ $ ls -l c | cut -b 1-10
+ -rw-------
+#endif
+
+force expansion
+
+ $ hg -v kwexpand
+ overwriting a expanding keywords
+ overwriting c expanding keywords
+
+compare changenodes in a and c
+
+ $ cat a c
+ expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
+ do not process $Id:
+ xxx $
+ $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
+ tests for different changenodes
+
+record
+
+ $ echo '$Id$' > r
+ $ hg add r
+
+record chunk
+
+ >>> lines = open('a', 'rb').readlines()
+ >>> lines.insert(1, 'foo\n')
+ >>> lines.append('bar\n')
+ >>> open('a', 'wb').writelines(lines)
+ $ hg record -d '10 1' -m rectest a<<EOF
+ > y
+ > y
+ > n
+ > EOF
+ diff --git a/a b/a
+ 2 hunks, 2 lines changed
+ examine changes to 'a'? [Ynesfdaq?]
+ @@ -1,3 +1,4 @@
+ expand $Id$
+ +foo
+ do not process $Id:
+ xxx $
+ record change 1/2 to 'a'? [Ynesfdaq?]
+ @@ -2,2 +3,3 @@
+ do not process $Id:
+ xxx $
+ +bar
+ record change 2/2 to 'a'? [Ynesfdaq?]
+
+ $ hg identify
+ 5f5eb23505c3+ tip
+ $ hg status
+ M a
+ A r
+
+Cat modified file a
+
+ $ cat a
+ expand $Id: a,v 5f5eb23505c3 1970/01/01 00:00:10 test $
+ foo
+ do not process $Id:
+ xxx $
+ bar
+
+Diff remaining chunk
+
+ $ hg diff a
+ diff -r 5f5eb23505c3 a
+ --- a/a Thu Jan 01 00:00:09 1970 -0000
+ +++ b/a * (glob)
+ @@ -2,3 +2,4 @@
+ foo
+ do not process $Id:
+ xxx $
+ +bar
+
+ $ hg rollback
+ repository tip rolled back to revision 2 (undo commit)
+ working directory now based on revision 2
+
+Record all chunks in file a
+
+ $ echo foo > msg
+
+ - do not use "hg record -m" here!
+
+ $ hg record -l msg -d '11 1' a<<EOF
+ > y
+ > y
+ > y
+ > EOF
+ diff --git a/a b/a
+ 2 hunks, 2 lines changed
+ examine changes to 'a'? [Ynesfdaq?]
+ @@ -1,3 +1,4 @@
+ expand $Id$
+ +foo
+ do not process $Id:
+ xxx $
+ record change 1/2 to 'a'? [Ynesfdaq?]
+ @@ -2,2 +3,3 @@
+ do not process $Id:
+ xxx $
+ +bar
+ record change 2/2 to 'a'? [Ynesfdaq?]
+
+File a should be clean
+
+ $ hg status -A a
+ C a
+
+rollback and revert expansion
+
+ $ cat a
+ expand $Id: a,v 78e0a02d76aa 1970/01/01 00:00:11 test $
+ foo
+ do not process $Id:
+ xxx $
+ bar
+ $ hg --verbose rollback
+ repository tip rolled back to revision 2 (undo commit)
+ working directory now based on revision 2
+ overwriting a expanding keywords
+ $ hg status a
+ M a
+ $ cat a
+ expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
+ foo
+ do not process $Id:
+ xxx $
+ bar
+ $ echo '$Id$' > y
+ $ echo '$Id$' > z
+ $ hg add y
+ $ hg commit -Am "rollback only" z
+ $ cat z
+ $Id: z,v 45a5d3adce53 1970/01/01 00:00:00 test $
+ $ hg --verbose rollback
+ repository tip rolled back to revision 2 (undo commit)
+ working directory now based on revision 2
+ overwriting z shrinking keywords
+
+Only z should be overwritten
+
+ $ hg status a y z
+ M a
+ A y
+ A z
+ $ cat z
+ $Id$
+ $ hg forget y z
+ $ rm y z
+
+record added file alone
+
+ $ hg -v record -l msg -d '12 2' r<<EOF
+ > y
+ > EOF
+ diff --git a/r b/r
+ new file mode 100644
+ examine changes to 'r'? [Ynesfdaq?]
+ r
+ committed changeset 3:82a2f715724d
+ overwriting r expanding keywords
+ - status call required for dirstate.normallookup() check
+ $ hg status r
+ $ hg --verbose rollback
+ repository tip rolled back to revision 2 (undo commit)
+ working directory now based on revision 2
+ overwriting r shrinking keywords
+ $ hg forget r
+ $ rm msg r
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+record added keyword ignored file
+
+ $ echo '$Id$' > i
+ $ hg add i
+ $ hg --verbose record -d '13 1' -m recignored<<EOF
+ > y
+ > EOF
+ diff --git a/i b/i
+ new file mode 100644
+ examine changes to 'i'? [Ynesfdaq?]
+ i
+ committed changeset 3:9f40ceb5a072
+ $ cat i
+ $Id$
+ $ hg -q rollback
+ $ hg forget i
+ $ rm i
+
+amend
+
+ $ echo amend >> a
+ $ echo amend >> b
+ $ hg -q commit -d '14 1' -m 'prepare amend'
+
+ $ hg --debug commit --amend -d '15 1' -m 'amend without changes' | grep keywords
+ overwriting a expanding keywords
+ $ hg -q id
+ 577e60613a88
+ $ head -1 a
+ expand $Id: a,v 577e60613a88 1970/01/01 00:00:15 test $
+
+ $ hg -q strip -n tip
+
+Test patch queue repo
+
+ $ hg init --mq
+ $ hg qimport -r tip -n mqtest.diff
+ $ hg commit --mq -m mqtest
+
+Keywords should not be expanded in patch
+
+ $ cat .hg/patches/mqtest.diff
+ # HG changeset patch
+ # User User Name <user@example.com>
+ # Date 1 0
+ # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
+ # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
+ cndiff
+
+ diff -r ef63ca68695b -r 40a904bbbe4c c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,2 @@
+ +$Id$
+ +tests for different changenodes
+
+ $ hg qpop
+ popping mqtest.diff
+ patch queue now empty
+
+qgoto, implying qpush, should expand
+
+ $ hg qgoto mqtest.diff
+ applying mqtest.diff
+ now at: mqtest.diff
+ $ cat c
+ $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
+ tests for different changenodes
+ $ hg cat c
+ $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
+ tests for different changenodes
+
+Keywords should not be expanded in filelog
+
+ $ hg --config 'extensions.keyword=!' cat c
+ $Id$
+ tests for different changenodes
+
+qpop and move on
+
+ $ hg qpop
+ popping mqtest.diff
+ patch queue now empty
+
+Copy and show added kwfiles
+
+ $ hg cp a c
+ $ hg kwfiles
+ a
+ c
+
+Commit and show expansion in original and copy
+
+ $ hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
+ c
+ c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
+ removing unknown node 40a904bbbe4c from 1-phase boundary
+ overwriting c expanding keywords
+ committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
+ $ cat a c
+ expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
+ do not process $Id:
+ xxx $
+ expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
+ do not process $Id:
+ xxx $
+
+Touch copied c and check its status
+
+ $ touch c
+ $ hg status
+
+Copy kwfile to keyword ignored file unexpanding keywords
+
+ $ hg --verbose copy a i
+ copying a to i
+ overwriting i shrinking keywords
+ $ head -n 1 i
+ expand $Id$
+ $ hg forget i
+ $ rm i
+
+Copy ignored file to ignored file: no overwriting
+
+ $ hg --verbose copy b i
+ copying b to i
+ $ hg forget i
+ $ rm i
+
+cp symlink file; hg cp -A symlink file (part1)
+- copied symlink points to kwfile: overwrite
+
+#if symlink
+ $ cp sym i
+ $ ls -l i
+ -rw-r--r--* (glob)
+ $ head -1 i
+ expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
+ $ hg copy --after --verbose sym i
+ copying sym to i
+ overwriting i shrinking keywords
+ $ head -1 i
+ expand $Id$
+ $ hg forget i
+ $ rm i
+#endif
+
+Test different options of hg kwfiles
+
+ $ hg kwfiles
+ a
+ c
+ $ hg -v kwfiles --ignore
+ I b
+ I sym
+ $ hg kwfiles --all
+ K a
+ K c
+ I b
+ I sym
+
+Diff specific revision
+
+ $ hg diff --rev 1
+ diff -r ef63ca68695b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c * (glob)
+ @@ -0,0 +1,3 @@
+ +expand $Id$
+ +do not process $Id:
+ +xxx $
+
+Status after rollback:
+
+ $ hg rollback
+ repository tip rolled back to revision 1 (undo commit)
+ working directory now based on revision 1
+ $ hg status
+ A c
+ $ hg update --clean
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+#if symlink
+
+cp symlink file; hg cp -A symlink file (part2)
+- copied symlink points to kw ignored file: do not overwrite
+
+ $ cat a > i
+ $ ln -s i symignored
+ $ hg commit -Am 'fake expansion in ignored and symlink' i symignored
+ $ cp symignored x
+ $ hg copy --after --verbose symignored x
+ copying symignored to x
+ $ head -n 1 x
+ expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
+ $ hg forget x
+ $ rm x
+
+ $ hg rollback
+ repository tip rolled back to revision 1 (undo commit)
+ working directory now based on revision 1
+ $ hg update --clean
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm i symignored
+
+#endif
+
+Custom keywordmaps as argument to kwdemo
+
+ $ hg --quiet kwdemo "Xinfo = {author}: {desc}"
+ [extensions]
+ keyword =
+ [keyword]
+ ** =
+ b = ignore
+ demo.txt =
+ i = ignore
+ [keywordset]
+ svn = False
+ [keywordmaps]
+ Xinfo = {author}: {desc}
+ $Xinfo: test: hg keyword configuration and expansion example $
+
+Configure custom keywordmaps
+
+ $ cat <<EOF >>$HGRCPATH
+ > [keywordmaps]
+ > Id = {file} {node|short} {date|rfc822date} {author|user}
+ > Xinfo = {author}: {desc}
+ > EOF
+
+Cat and hg cat files before custom expansion
+
+ $ cat a b
+ expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
+ do not process $Id:
+ xxx $
+ ignore $Id$
+ $ hg cat sym a b && echo
+ expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
+ do not process $Id:
+ xxx $
+ ignore $Id$
+ a
+
+Write custom keyword and prepare multiline commit message
+
+ $ echo '$Xinfo$' >> a
+ $ cat <<EOF >> log
+ > firstline
+ > secondline
+ > EOF
+
+Interrupted commit should not change state
+
+ $ hg commit
+ abort: empty commit message
+ [255]
+ $ hg status
+ M a
+ ? c
+ ? log
+
+Commit with multiline message and custom expansion
+
+ $ hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
+ a
+ removing unknown node 40a904bbbe4c from 1-phase boundary
+ overwriting a expanding keywords
+ committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
+ $ rm log
+
+Stat, verify and show custom expansion (firstline)
+
+ $ hg status
+ ? c
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 3 changesets, 4 total revisions
+ $ cat a b
+ expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
+ do not process $Id:
+ xxx $
+ $Xinfo: User Name <user@example.com>: firstline $
+ ignore $Id$
+ $ hg cat sym a b && echo
+ expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
+ do not process $Id:
+ xxx $
+ $Xinfo: User Name <user@example.com>: firstline $
+ ignore $Id$
+ a
+
+annotate
+
+ $ hg annotate a
+ 1: expand $Id$
+ 1: do not process $Id:
+ 1: xxx $
+ 2: $Xinfo$
+
+remove with status checks
+
+ $ hg debugrebuildstate
+ $ hg remove a
+ $ hg --debug commit -m rma
+ committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
+ $ hg status
+ ? c
+
+Rollback, revert, and check expansion
+
+ $ hg rollback
+ repository tip rolled back to revision 2 (undo commit)
+ working directory now based on revision 2
+ $ hg status
+ R a
+ ? c
+ $ hg revert --no-backup --rev tip a
+ $ cat a
+ expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
+ do not process $Id:
+ xxx $
+ $Xinfo: User Name <user@example.com>: firstline $
+
+Clone to test global and local configurations
+
+ $ cd ..
+
+Expansion in destinaton with global configuration
+
+ $ hg --quiet clone Test globalconf
+ $ cat globalconf/a
+ expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
+ do not process $Id:
+ xxx $
+ $Xinfo: User Name <user@example.com>: firstline $
+
+No expansion in destination with local configuration in origin only
+
+ $ hg --quiet --config 'keyword.**=ignore' clone Test localconf
+ $ cat localconf/a
+ expand $Id$
+ do not process $Id:
+ xxx $
+ $Xinfo$
+
+Clone to test incoming
+
+ $ hg clone -r1 Test Test-a
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 3 changes to 3 files
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd Test-a
+ $ cat <<EOF >> .hg/hgrc
+ > [paths]
+ > default = ../Test
+ > EOF
+ $ hg incoming
+ comparing with $TESTTMP/Test (glob)
+ searching for changes
+ changeset: 2:bb948857c743
+ tag: tip
+ user: User Name <user@example.com>
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: firstline
+
+Imported patch should not be rejected
+
+ >>> import re
+ >>> text = re.sub(r'(Id.*)', r'\1 rejecttest', open('a').read())
+ >>> open('a', 'wb').write(text)
+ $ hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
+ a
+ overwriting a expanding keywords
+ committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
+ $ hg export -o ../rejecttest.diff tip
+ $ cd ../Test
+ $ hg import ../rejecttest.diff
+ applying ../rejecttest.diff
+ $ cat a b
+ expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
+ do not process $Id: rejecttest
+ xxx $
+ $Xinfo: User Name <user@example.com>: rejects? $
+ ignore $Id$
+
+ $ hg rollback
+ repository tip rolled back to revision 2 (undo import)
+ working directory now based on revision 2
+ $ hg update --clean
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+kwexpand/kwshrink on selected files
+
+ $ mkdir x
+ $ hg copy a x/a
+ $ hg --verbose kwshrink a
+ overwriting a shrinking keywords
+ - sleep required for dirstate.normal() check
+ $ sleep 1
+ $ hg status a
+ $ hg --verbose kwexpand a
+ overwriting a expanding keywords
+ $ hg status a
+
+kwexpand x/a should abort
+
+ $ hg --verbose kwexpand x/a
+ abort: outstanding uncommitted changes
+ [255]
+ $ cd x
+ $ hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
+ x/a
+ x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
+ overwriting x/a expanding keywords
+ committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
+ $ cat a
+ expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
+ do not process $Id:
+ xxx $
+ $Xinfo: User Name <user@example.com>: xa $
+
+kwshrink a inside directory x
+
+ $ hg --verbose kwshrink a
+ overwriting x/a shrinking keywords
+ $ cat a
+ expand $Id$
+ do not process $Id:
+ xxx $
+ $Xinfo$
+ $ cd ..
+
+kwexpand nonexistent
+
+ $ hg kwexpand nonexistent
+ nonexistent:* (glob)
+
+
+#if serve
+hg serve
+ - expand with hgweb file
+ - no expansion with hgweb annotate/changeset/filediff
+ - check errors
+
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/a/?style=raw'
+ 200 Script output follows
+
+ expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
+ do not process $Id:
+ xxx $
+ $Xinfo: User Name <user@example.com>: firstline $
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/a/?style=raw'
+ 200 Script output follows
+
+
+ user@1: expand $Id$
+ user@1: do not process $Id:
+ user@1: xxx $
+ user@2: $Xinfo$
+
+
+
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip/?style=raw'
+ 200 Script output follows
+
+
+ # HG changeset patch
+ # User User Name <user@example.com>
+ # Date 3 0
+ # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
+ # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
+ xa
+
+ diff -r bb948857c743 -r b4560182a3f9 x/a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,4 @@
+ +expand $Id$
+ +do not process $Id:
+ +xxx $
+ +$Xinfo$
+
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/bb948857c743/a?style=raw'
+ 200 Script output follows
+
+
+ diff -r ef63ca68695b -r bb948857c743 a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:02 1970 +0000
+ @@ -1,3 +1,4 @@
+ expand $Id$
+ do not process $Id:
+ xxx $
+ +$Xinfo$
+
+
+
+
+ $ cat errors.log
+#endif
+
+Prepare merge and resolve tests
+
+ $ echo '$Id$' > m
+ $ hg add m
+ $ hg commit -m 4kw
+ $ echo foo >> m
+ $ hg commit -m 5foo
+
+simplemerge
+
+ $ hg update 4
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo foo >> m
+ $ hg commit -m 6foo
+ created new head
+ $ hg merge
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -m simplemerge
+ $ cat m
+ $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
+ foo
+
+conflict: keyword should stay outside conflict zone
+
+ $ hg update 4
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo bar >> m
+ $ hg commit -m 8bar
+ created new head
+ $ hg merge
+ merging m
+ warning: conflicts during merge.
+ merging m incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ cat m
+ $Id$
+ <<<<<<< local
+ bar
+ =======
+ foo
+ >>>>>>> other
+
+resolve to local
+
+ $ HGMERGE=internal:local hg resolve -a
+ $ hg commit -m localresolve
+ $ cat m
+ $Id: m 800511b3a22d Thu, 01 Jan 1970 00:00:00 +0000 test $
+ bar
+
+Test restricted mode with transplant -b
+
+ $ hg update 6
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch foo
+ marked working directory as branch foo
+ (branches are permanent and global, did you want a bookmark?)
+ $ mv a a.bak
+ $ echo foobranch > a
+ $ cat a.bak >> a
+ $ rm a.bak
+ $ hg commit -m 9foobranch
+ $ hg update default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -y transplant -b foo tip
+ applying 4aa30d025d50
+ 4aa30d025d50 transplanted to e00abbf63521
+
+Expansion in changeset but not in file
+
+ $ hg tip -p
+ changeset: 11:e00abbf63521
+ tag: tip
+ parent: 9:800511b3a22d
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 9foobranch
+
+ diff -r 800511b3a22d -r e00abbf63521 a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,3 +1,4 @@
+ +foobranch
+ expand $Id$
+ do not process $Id:
+ xxx $
+
+ $ head -n 2 a
+ foobranch
+ expand $Id: a e00abbf63521 Thu, 01 Jan 1970 00:00:00 +0000 test $
+
+Turn off expansion
+
+ $ hg -q rollback
+ $ hg -q update -C
+
+kwshrink with unknown file u
+
+ $ cp a u
+ $ hg --verbose kwshrink
+ overwriting a shrinking keywords
+ overwriting m shrinking keywords
+ overwriting x/a shrinking keywords
+
+Keywords shrunk in working directory, but not yet disabled
+ - cat shows unexpanded keywords
+ - hg cat shows expanded keywords
+
+ $ cat a b
+ expand $Id$
+ do not process $Id:
+ xxx $
+ $Xinfo$
+ ignore $Id$
+ $ hg cat sym a b && echo
+ expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
+ do not process $Id:
+ xxx $
+ $Xinfo: User Name <user@example.com>: firstline $
+ ignore $Id$
+ a
+
+Now disable keyword expansion
+
+ $ rm "$HGRCPATH"
+ $ cat a b
+ expand $Id$
+ do not process $Id:
+ xxx $
+ $Xinfo$
+ ignore $Id$
+ $ hg cat sym a b && echo
+ expand $Id$
+ do not process $Id:
+ xxx $
+ $Xinfo$
+ ignore $Id$
+ a
+
+ $ cd ..
diff --git a/tests/test-known.t b/tests/test-known.t
new file mode 100644
index 0000000..3c19ebe
--- /dev/null
+++ b/tests/test-known.t
@@ -0,0 +1,38 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+= Test the known() protocol function =
+
+Create a test repository:
+
+ $ hg init repo
+ $ cd repo
+ $ touch a ; hg add a ; hg ci -ma
+ $ touch b ; hg add b ; hg ci -mb
+ $ touch c ; hg add c ; hg ci -mc
+ $ hg log --template '{node}\n'
+ 991a3460af53952d10ec8a295d3d2cc2e5fa9690
+ 0e067c57feba1a5694ca4844f05588bb1bf82342
+ 3903775176ed42b1458a6281db4a0ccf4d9f287a
+ $ cd ..
+
+Test locally:
+
+ $ hg debugknown repo 991a3460af53952d10ec8a295d3d2cc2e5fa9690 0e067c57feba1a5694ca4844f05588bb1bf82342 3903775176ed42b1458a6281db4a0ccf4d9f287a
+ 111
+ $ hg debugknown repo 000a3460af53952d10ec8a295d3d2cc2e5fa9690 0e067c57feba1a5694ca4844f05588bb1bf82342 0003775176ed42b1458a6281db4a0ccf4d9f287a
+ 010
+ $ hg debugknown repo
+
+
+Test via HTTP:
+
+ $ hg serve -R repo -p $HGPORT -d --pid-file=hg.pid -E error.log -A access.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg debugknown http://localhost:$HGPORT/ 991a3460af53952d10ec8a295d3d2cc2e5fa9690 0e067c57feba1a5694ca4844f05588bb1bf82342 3903775176ed42b1458a6281db4a0ccf4d9f287a
+ 111
+ $ hg debugknown http://localhost:$HGPORT/ 000a3460af53952d10ec8a295d3d2cc2e5fa9690 0e067c57feba1a5694ca4844f05588bb1bf82342 0003775176ed42b1458a6281db4a0ccf4d9f287a
+ 010
+ $ hg debugknown http://localhost:$HGPORT/
+
+ $ cat error.log
+
diff --git a/tests/test-largefiles-cache.t b/tests/test-largefiles-cache.t
new file mode 100644
index 0000000..ae6631c
--- /dev/null
+++ b/tests/test-largefiles-cache.t
@@ -0,0 +1,125 @@
+Create user cache directory
+
+ $ USERCACHE=`pwd`/cache; export USERCACHE
+ $ cat <<EOF >> ${HGRCPATH}
+ > [extensions]
+ > hgext.largefiles=
+ > [largefiles]
+ > usercache=${USERCACHE}
+ > EOF
+ $ mkdir -p ${USERCACHE}
+
+Create source repo, and commit adding largefile.
+
+ $ hg init src
+ $ cd src
+ $ echo large > large
+ $ hg add --large large
+ $ hg commit -m 'add largefile'
+ $ cd ..
+
+Discard all cached largefiles in USERCACHE
+
+ $ rm -rf ${USERCACHE}
+
+Create mirror repo, and pull from source without largefile:
+"pull" is used instead of "clone" for suppression of (1) updating to
+tip (= cahcing largefile from source repo), and (2) recording source
+repo as "default" path in .hg/hgrc.
+
+ $ hg init mirror
+ $ cd mirror
+ $ hg pull ../src
+ pulling from ../src
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ caching new largefiles
+ 0 largefiles cached
+
+Update working directory to "tip", which requires largefile("large"),
+but there is no cache file for it. So, hg must treat it as
+"missing"(!) file.
+
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ large: can't get file locally
+ (no default or default-push path set in hgrc)
+ 0 largefiles updated, 0 removed
+ $ hg status
+ ! large
+
+Update working directory to null: this cleanup .hg/largefiles/dirstate
+
+ $ hg update null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ getting changed largefiles
+ 0 largefiles updated, 0 removed
+
+Update working directory to tip, again.
+
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ large: can't get file locally
+ (no default or default-push path set in hgrc)
+ 0 largefiles updated, 0 removed
+ $ hg status
+ ! large
+ $ cd ..
+
+#if unix-permissions
+
+Portable way to print file permissions:
+
+ $ cat > ls-l.py <<EOF
+ > #!/usr/bin/env python
+ > import sys, os
+ > path = sys.argv[1]
+ > print '%03o' % (os.lstat(path).st_mode & 0777)
+ > EOF
+ $ chmod +x ls-l.py
+
+Test that files in .hg/largefiles inherit mode from .hg/store, not
+from file in working copy:
+
+ $ cd src
+ $ chmod 750 .hg/store
+ $ chmod 660 large
+ $ echo change >> large
+ $ hg commit -m change
+ $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
+ 640
+
+Test permission of with files in .hg/largefiles created by update:
+
+ $ cd ../mirror
+ $ rm -r "$USERCACHE" .hg/largefiles # avoid links
+ $ chmod 750 .hg/store
+ $ hg pull ../src --update -q
+ $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
+ 640
+
+Test permission of files created by push:
+
+ $ hg serve -R ../src -d -p $HGPORT --pid-file hg.pid \
+ > --config "web.allow_push=*" --config web.push_ssl=no
+ $ cat hg.pid >> $DAEMON_PIDS
+
+ $ echo change >> large
+ $ hg commit -m change
+
+ $ rm -r "$USERCACHE"
+
+ $ hg push -q http://localhost:$HGPORT/
+
+ $ ../ls-l.py ../src/.hg/largefiles/b734e14a0971e370408ab9bce8d56d8485e368a9
+ 640
+
+ $ cd ..
+
+#endif
diff --git a/tests/test-largefiles-small-disk.t b/tests/test-largefiles-small-disk.t
new file mode 100644
index 0000000..feb11e3
--- /dev/null
+++ b/tests/test-largefiles-small-disk.t
@@ -0,0 +1,67 @@
+Test how largefiles abort in case the disk runs full
+
+ $ cat > criple.py <<EOF
+ > import os, errno, shutil
+ > from mercurial import util
+ > #
+ > # this makes the original largefiles code abort:
+ > def copyfileobj(fsrc, fdst, length=16*1024):
+ > fdst.write(fsrc.read(4))
+ > raise IOError(errno.ENOSPC, os.strerror(errno.ENOSPC))
+ > shutil.copyfileobj = copyfileobj
+ > #
+ > # this makes the rewritten code abort:
+ > def filechunkiter(f, size=65536, limit=None):
+ > yield f.read(4)
+ > raise IOError(errno.ENOSPC, os.strerror(errno.ENOSPC))
+ > util.filechunkiter = filechunkiter
+ > #
+ > def oslink(src, dest):
+ > raise OSError("no hardlinks, try copying instead")
+ > util.oslink = oslink
+ > EOF
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "largefiles =" >> $HGRCPATH
+
+ $ hg init alice
+ $ cd alice
+ $ echo "this is a very big file" > big
+ $ hg add --large big
+ $ hg commit --config extensions.criple=$TESTTMP/criple.py -m big
+ abort: No space left on device
+ [255]
+
+The largefile is not created in .hg/largefiles:
+
+ $ ls .hg/largefiles
+ dirstate
+
+The user cache is not even created:
+
+ >>> import os; os.path.exists("$HOME/.cache/largefiles/")
+ False
+
+Make the commit with space on the device:
+
+ $ hg commit -m big
+
+Now make a clone with a full disk, and make sure lfutil.link function
+makes copies instead of hardlinks:
+
+ $ cd ..
+ $ hg --config extensions.criple=$TESTTMP/criple.py clone --pull alice bob
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ abort: No space left on device
+ [255]
+
+The largefile is not created in .hg/largefiles:
+
+ $ ls bob/.hg/largefiles
diff --git a/tests/test-largefiles.t b/tests/test-largefiles.t
new file mode 100644
index 0000000..c64dd73
--- /dev/null
+++ b/tests/test-largefiles.t
@@ -0,0 +1,1447 @@
+ $ USERCACHE="$TESTTMP/cache"; export USERCACHE
+ $ mkdir "${USERCACHE}"
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > largefiles=
+ > purge=
+ > rebase=
+ > transplant=
+ > [phases]
+ > publish=False
+ > [largefiles]
+ > minsize=2
+ > patterns=glob:**.dat
+ > usercache=${USERCACHE}
+ > [hooks]
+ > precommit=sh -c "echo \"Invoking status precommit hook\"; hg status"
+ > EOF
+
+Create the repo with a couple of revisions of both large and normal
+files, testing that status correctly shows largefiles and that summary output
+is correct.
+
+ $ hg init a
+ $ cd a
+ $ mkdir sub
+ $ echo normal1 > normal1
+ $ echo normal2 > sub/normal2
+ $ echo large1 > large1
+ $ echo large2 > sub/large2
+ $ hg add normal1 sub/normal2
+ $ hg add --large large1 sub/large2
+ $ hg commit -m "add files"
+ Invoking status precommit hook
+ A large1
+ A normal1
+ A sub/large2
+ A sub/normal2
+ $ echo normal11 > normal1
+ $ echo normal22 > sub/normal2
+ $ echo large11 > large1
+ $ echo large22 > sub/large2
+ $ hg commit -m "edit files"
+ Invoking status precommit hook
+ M large1
+ M normal1
+ M sub/large2
+ M sub/normal2
+ $ hg sum --large
+ parent: 1:ce8896473775 tip
+ edit files
+ branch: default
+ commit: (clean)
+ update: (current)
+ largefiles: No remote repo
+
+Commit preserved largefile contents.
+
+ $ cat normal1
+ normal11
+ $ cat large1
+ large11
+ $ cat sub/normal2
+ normal22
+ $ cat sub/large2
+ large22
+
+Test status, subdir and unknown files
+
+ $ echo unknown > sub/unknown
+ $ hg st --all
+ ? sub/unknown
+ C large1
+ C normal1
+ C sub/large2
+ C sub/normal2
+ $ hg st --all sub
+ ? sub/unknown
+ C sub/large2
+ C sub/normal2
+ $ rm sub/unknown
+
+Remove both largefiles and normal files.
+
+ $ hg remove normal1 large1
+ $ hg status large1
+ R large1
+ $ hg commit -m "remove files"
+ Invoking status precommit hook
+ R large1
+ R normal1
+ $ ls
+ sub
+ $ echo "testlargefile" > large1-test
+ $ hg add --large large1-test
+ $ hg st
+ A large1-test
+ $ hg rm large1-test
+ not removing large1-test: file has been marked for add (use forget to undo)
+ $ hg st
+ A large1-test
+ $ hg forget large1-test
+ $ hg st
+ ? large1-test
+ $ rm large1-test
+
+Copy both largefiles and normal files (testing that status output is correct).
+
+ $ hg cp sub/normal2 normal1
+ $ hg cp sub/large2 large1
+ $ hg commit -m "copy files"
+ Invoking status precommit hook
+ A large1
+ A normal1
+ $ cat normal1
+ normal22
+ $ cat large1
+ large22
+
+Test moving largefiles and verify that normal files are also unaffected.
+
+ $ hg mv normal1 normal3
+ $ hg mv large1 large3
+ $ hg mv sub/normal2 sub/normal4
+ $ hg mv sub/large2 sub/large4
+ $ hg commit -m "move files"
+ Invoking status precommit hook
+ A large3
+ A normal3
+ A sub/large4
+ A sub/normal4
+ R large1
+ R normal1
+ R sub/large2
+ R sub/normal2
+ $ cat normal3
+ normal22
+ $ cat large3
+ large22
+ $ cat sub/normal4
+ normal22
+ $ cat sub/large4
+ large22
+
+Test copies and moves from a directory other than root (issue3516)
+
+ $ cd ..
+ $ hg init lf_cpmv
+ $ cd lf_cpmv
+ $ mkdir dira
+ $ mkdir dira/dirb
+ $ touch dira/dirb/largefile
+ $ hg add --large dira/dirb/largefile
+ $ hg commit -m "added"
+ Invoking status precommit hook
+ A dira/dirb/largefile
+ $ cd dira
+ $ hg cp dirb/largefile foo/largefile
+ $ hg ci -m "deep copy"
+ Invoking status precommit hook
+ A dira/foo/largefile
+ $ find . | sort
+ .
+ ./dirb
+ ./dirb/largefile
+ ./foo
+ ./foo/largefile
+ $ hg mv foo/largefile baz/largefile
+ $ hg ci -m "moved"
+ Invoking status precommit hook
+ A dira/baz/largefile
+ R dira/foo/largefile
+ $ find . | sort
+ .
+ ./baz
+ ./baz/largefile
+ ./dirb
+ ./dirb/largefile
+ ./foo
+ $ cd ../../a
+
+#if hgweb
+Test display of largefiles in hgweb
+
+ $ hg serve -d -p $HGPORT --pid-file ../hg.pid
+ $ cat ../hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/?style=raw'
+ 200 Script output follows
+
+
+ drwxr-xr-x sub
+ -rw-r--r-- 41 large3
+ -rw-r--r-- 9 normal3
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/sub/?style=raw'
+ 200 Script output follows
+
+
+ -rw-r--r-- 41 large4
+ -rw-r--r-- 9 normal4
+
+
+ $ "$TESTDIR/killdaemons.py"
+#endif
+
+Test archiving the various revisions. These hit corner cases known with
+archiving.
+
+ $ hg archive -r 0 ../archive0
+ $ hg archive -r 1 ../archive1
+ $ hg archive -r 2 ../archive2
+ $ hg archive -r 3 ../archive3
+ $ hg archive -r 4 ../archive4
+ $ cd ../archive0
+ $ cat normal1
+ normal1
+ $ cat large1
+ large1
+ $ cat sub/normal2
+ normal2
+ $ cat sub/large2
+ large2
+ $ cd ../archive1
+ $ cat normal1
+ normal11
+ $ cat large1
+ large11
+ $ cat sub/normal2
+ normal22
+ $ cat sub/large2
+ large22
+ $ cd ../archive2
+ $ ls
+ sub
+ $ cat sub/normal2
+ normal22
+ $ cat sub/large2
+ large22
+ $ cd ../archive3
+ $ cat normal1
+ normal22
+ $ cat large1
+ large22
+ $ cat sub/normal2
+ normal22
+ $ cat sub/large2
+ large22
+ $ cd ../archive4
+ $ cat normal3
+ normal22
+ $ cat large3
+ large22
+ $ cat sub/normal4
+ normal22
+ $ cat sub/large4
+ large22
+
+Commit corner case: specify files to commit.
+
+ $ cd ../a
+ $ echo normal3 > normal3
+ $ echo large3 > large3
+ $ echo normal4 > sub/normal4
+ $ echo large4 > sub/large4
+ $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
+ Invoking status precommit hook
+ M large3
+ M normal3
+ M sub/large4
+ M sub/normal4
+ $ cat normal3
+ normal3
+ $ cat large3
+ large3
+ $ cat sub/normal4
+ normal4
+ $ cat sub/large4
+ large4
+
+One more commit corner case: commit from a subdirectory.
+
+ $ cd ../a
+ $ echo normal33 > normal3
+ $ echo large33 > large3
+ $ echo normal44 > sub/normal4
+ $ echo large44 > sub/large4
+ $ cd sub
+ $ hg commit -m "edit files yet again"
+ Invoking status precommit hook
+ M large3
+ M normal3
+ M sub/large4
+ M sub/normal4
+ $ cat ../normal3
+ normal33
+ $ cat ../large3
+ large33
+ $ cat normal4
+ normal44
+ $ cat large4
+ large44
+
+Committing standins is not allowed.
+
+ $ cd ..
+ $ echo large3 > large3
+ $ hg commit .hglf/large3 -m "try to commit standin"
+ abort: file ".hglf/large3" is a largefile standin
+ (commit the largefile itself instead)
+ [255]
+
+Corner cases for adding largefiles.
+
+ $ echo large5 > large5
+ $ hg add --large large5
+ $ hg add --large large5
+ large5 already a largefile
+ $ mkdir sub2
+ $ echo large6 > sub2/large6
+ $ echo large7 > sub2/large7
+ $ hg add --large sub2
+ adding sub2/large6 as a largefile (glob)
+ adding sub2/large7 as a largefile (glob)
+ $ hg st
+ M large3
+ A large5
+ A sub2/large6
+ A sub2/large7
+
+Test "hg status" with combination of 'file pattern' and 'directory
+pattern' for largefiles:
+
+ $ hg status sub2/large6 sub2
+ A sub2/large6
+ A sub2/large7
+
+Config settings (pattern **.dat, minsize 2 MB) are respected.
+
+ $ echo testdata > test.dat
+ $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
+ $ hg add
+ adding reallylarge as a largefile
+ adding test.dat as a largefile
+
+Test that minsize and --lfsize handle float values;
+also tests that --lfsize overrides largefiles.minsize.
+(0.250 MB = 256 kB = 262144 B)
+
+ $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
+ $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
+ $ hg --config largefiles.minsize=.25 add
+ adding ratherlarge as a largefile
+ adding medium
+ $ hg forget medium
+ $ hg --config largefiles.minsize=.25 add --lfsize=.125
+ adding medium as a largefile
+ $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
+ $ hg --config largefiles.minsize=.25 add --lfsize=.125
+ adding notlarge
+ $ hg forget notlarge
+
+Test forget on largefiles.
+
+ $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
+ $ hg commit -m "add/edit more largefiles"
+ Invoking status precommit hook
+ A sub2/large6
+ A sub2/large7
+ R large3
+ ? large5
+ ? medium
+ ? notlarge
+ ? ratherlarge
+ ? reallylarge
+ ? test.dat
+ $ hg st
+ ? large3
+ ? large5
+ ? medium
+ ? notlarge
+ ? ratherlarge
+ ? reallylarge
+ ? test.dat
+
+Purge with largefiles: verify that largefiles are still in the working
+dir after a purge.
+
+ $ hg purge --all
+ $ cat sub/large4
+ large44
+ $ cat sub2/large6
+ large6
+ $ cat sub2/large7
+ large7
+
+Test addremove: verify that files that should be added as largfiles are added as
+such and that already-existing largfiles are not added as normal files by
+accident.
+
+ $ rm normal3
+ $ rm sub/large4
+ $ echo "testing addremove with patterns" > testaddremove.dat
+ $ echo "normaladdremove" > normaladdremove
+ $ hg addremove
+ removing sub/large4
+ adding testaddremove.dat as a largefile
+ removing normal3
+ adding normaladdremove
+
+Test addremove with -R
+
+ $ hg up -C
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+ $ rm normal3
+ $ rm sub/large4
+ $ echo "testing addremove with patterns" > testaddremove.dat
+ $ echo "normaladdremove" > normaladdremove
+ $ cd ..
+ $ hg -R a addremove
+ removing sub/large4
+ adding a/testaddremove.dat as a largefile (glob)
+ removing normal3
+ adding normaladdremove
+ $ cd a
+
+Test 3364
+ $ hg clone . ../addrm
+ updating to branch default
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 3 largefiles updated, 0 removed
+ $ cd ../addrm
+ $ cat >> .hg/hgrc <<EOF
+ > [hooks]
+ > post-commit.stat=sh -c "echo \"Invoking status postcommit hook\"; hg status -A"
+ > EOF
+ $ touch foo
+ $ hg add --large foo
+ $ hg ci -m "add foo"
+ Invoking status precommit hook
+ A foo
+ Invoking status postcommit hook
+ C foo
+ C normal3
+ C sub/large4
+ C sub/normal4
+ C sub2/large6
+ C sub2/large7
+ $ rm foo
+ $ hg st
+ ! foo
+hmm.. no precommit invoked, but there is a postcommit??
+ $ hg ci -m "will not checkin"
+ nothing changed
+ Invoking status postcommit hook
+ ! foo
+ C normal3
+ C sub/large4
+ C sub/normal4
+ C sub2/large6
+ C sub2/large7
+ [1]
+ $ hg addremove
+ removing foo
+ $ hg st
+ R foo
+ $ hg ci -m "used to say nothing changed"
+ Invoking status precommit hook
+ R foo
+ Invoking status postcommit hook
+ C normal3
+ C sub/large4
+ C sub/normal4
+ C sub2/large6
+ C sub2/large7
+ $ hg st
+
+Test 3507 (both normal files and largefiles were a problem)
+
+ $ touch normal
+ $ touch large
+ $ hg add normal
+ $ hg add --large large
+ $ hg ci -m "added"
+ Invoking status precommit hook
+ A large
+ A normal
+ Invoking status postcommit hook
+ C large
+ C normal
+ C normal3
+ C sub/large4
+ C sub/normal4
+ C sub2/large6
+ C sub2/large7
+ $ hg remove normal
+ $ hg addremove --traceback
+ $ hg ci -m "addremoved normal"
+ Invoking status precommit hook
+ R normal
+ Invoking status postcommit hook
+ C large
+ C normal3
+ C sub/large4
+ C sub/normal4
+ C sub2/large6
+ C sub2/large7
+ $ hg up -C '.^'
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 0 largefiles updated, 0 removed
+ $ hg remove large
+ $ hg addremove --traceback
+ $ hg ci -m "removed large"
+ Invoking status precommit hook
+ R large
+ created new head
+ Invoking status postcommit hook
+ C normal
+ C normal3
+ C sub/large4
+ C sub/normal4
+ C sub2/large6
+ C sub2/large7
+
+Test that a standin can't be added as a large file
+
+ $ touch large
+ $ hg add --large large
+ $ hg ci -m "add"
+ Invoking status precommit hook
+ A large
+ Invoking status postcommit hook
+ C large
+ C normal
+ C normal3
+ C sub/large4
+ C sub/normal4
+ C sub2/large6
+ C sub2/large7
+ $ hg remove large
+ $ touch large
+ $ hg addremove --config largefiles.patterns=**large --traceback
+ adding large as a largefile
+
+Test that outgoing --large works (with revsets too)
+ $ hg outgoing --rev '.^' --large
+ comparing with $TESTTMP/a (glob)
+ searching for changes
+ changeset: 8:c02fd3b77ec4
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo
+
+ changeset: 9:289dd08c9bbb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: used to say nothing changed
+
+ changeset: 10:34f23ac6ac12
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: added
+
+ changeset: 12:710c1b2f523c
+ parent: 10:34f23ac6ac12
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: removed large
+
+ searching for changes
+ largefiles to upload:
+ large
+ foo
+
+ $ cd ../a
+
+Clone a largefiles repo.
+
+ $ hg clone . ../b
+ updating to branch default
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 3 largefiles updated, 0 removed
+ $ cd ../b
+ $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
+ 7:daea875e9014 add/edit more largefiles
+ 6:4355d653f84f edit files yet again
+ 5:9d5af5072dbd edit files again
+ 4:74c02385b94c move files
+ 3:9e8fbc4bce62 copy files
+ 2:51a0ae4d5864 remove files
+ 1:ce8896473775 edit files
+ 0:30d30fe6a5be add files
+ $ cat normal3
+ normal33
+ $ cat sub/normal4
+ normal44
+ $ cat sub/large4
+ large44
+ $ cat sub2/large6
+ large6
+ $ cat sub2/large7
+ large7
+ $ cd ..
+ $ hg clone a -r 3 c
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 10 changes to 4 files
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 2 largefiles updated, 0 removed
+ $ cd c
+ $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
+ 3:9e8fbc4bce62 copy files
+ 2:51a0ae4d5864 remove files
+ 1:ce8896473775 edit files
+ 0:30d30fe6a5be add files
+ $ cat normal1
+ normal22
+ $ cat large1
+ large22
+ $ cat sub/normal2
+ normal22
+ $ cat sub/large2
+ large22
+
+Old revisions of a clone have correct largefiles content (this also
+tests update).
+
+ $ hg update -r 1
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+ $ cat large1
+ large11
+ $ cat sub/large2
+ large22
+ $ cd ..
+
+Test cloning with --all-largefiles flag
+
+ $ rm "${USERCACHE}"/*
+ $ hg clone --all-largefiles a a-backup
+ updating to branch default
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 3 largefiles updated, 0 removed
+ 8 additional largefiles cached
+
+ $ hg clone --all-largefiles a ssh://localhost/a
+ abort: --all-largefiles is incompatible with non-local destination ssh://localhost/a
+ [255]
+
+Test pulling with --all-largefiles flag
+
+ $ rm -Rf a-backup
+ $ hg clone -r 1 a a-backup
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 8 changes to 4 files
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 2 largefiles updated, 0 removed
+ $ rm "${USERCACHE}"/*
+ $ cd a-backup
+ $ hg pull --all-largefiles
+ pulling from $TESTTMP/a (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 16 changes to 8 files
+ (run 'hg update' to get a working copy)
+ caching new largefiles
+ 3 largefiles cached
+ 3 additional largefiles cached
+ $ cd ..
+
+Rebasing between two repositories does not revert largefiles to old
+revisions (this was a very bad bug that took a lot of work to fix).
+
+ $ hg clone a d
+ updating to branch default
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 3 largefiles updated, 0 removed
+ $ cd b
+ $ echo large4-modified > sub/large4
+ $ echo normal3-modified > normal3
+ $ hg commit -m "modify normal file and largefile in repo b"
+ Invoking status precommit hook
+ M normal3
+ M sub/large4
+ $ cd ../d
+ $ echo large6-modified > sub2/large6
+ $ echo normal4-modified > sub/normal4
+ $ hg commit -m "modify normal file largefile in repo d"
+ Invoking status precommit hook
+ M sub/normal4
+ M sub2/large6
+ $ cd ..
+ $ hg clone d e
+ updating to branch default
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 3 largefiles updated, 0 removed
+ $ cd d
+ $ hg pull --rebase ../b
+ pulling from ../b
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files (+1 heads)
+ Invoking status precommit hook
+ M sub/normal4
+ M sub2/large6
+ saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
+ nothing to rebase
+ $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
+ 9:598410d3eb9a modify normal file largefile in repo d
+ 8:a381d2c8c80e modify normal file and largefile in repo b
+ 7:daea875e9014 add/edit more largefiles
+ 6:4355d653f84f edit files yet again
+ 5:9d5af5072dbd edit files again
+ 4:74c02385b94c move files
+ 3:9e8fbc4bce62 copy files
+ 2:51a0ae4d5864 remove files
+ 1:ce8896473775 edit files
+ 0:30d30fe6a5be add files
+ $ cat normal3
+ normal3-modified
+ $ cat sub/normal4
+ normal4-modified
+ $ cat sub/large4
+ large4-modified
+ $ cat sub2/large6
+ large6-modified
+ $ cat sub2/large7
+ large7
+ $ cd ../e
+ $ hg pull ../b
+ pulling from ../b
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ caching new largefiles
+ 0 largefiles cached
+ $ hg rebase
+ Invoking status precommit hook
+ M sub/normal4
+ M sub2/large6
+ saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
+ $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
+ 9:598410d3eb9a modify normal file largefile in repo d
+ 8:a381d2c8c80e modify normal file and largefile in repo b
+ 7:daea875e9014 add/edit more largefiles
+ 6:4355d653f84f edit files yet again
+ 5:9d5af5072dbd edit files again
+ 4:74c02385b94c move files
+ 3:9e8fbc4bce62 copy files
+ 2:51a0ae4d5864 remove files
+ 1:ce8896473775 edit files
+ 0:30d30fe6a5be add files
+ $ cat normal3
+ normal3-modified
+ $ cat sub/normal4
+ normal4-modified
+ $ cat sub/large4
+ large4-modified
+ $ cat sub2/large6
+ large6-modified
+ $ cat sub2/large7
+ large7
+
+Rollback on largefiles.
+
+ $ echo large4-modified-again > sub/large4
+ $ hg commit -m "Modify large4 again"
+ Invoking status precommit hook
+ M sub/large4
+ $ hg rollback
+ repository tip rolled back to revision 9 (undo commit)
+ working directory now based on revision 9
+ $ hg st
+ M sub/large4
+ $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
+ 9:598410d3eb9a modify normal file largefile in repo d
+ 8:a381d2c8c80e modify normal file and largefile in repo b
+ 7:daea875e9014 add/edit more largefiles
+ 6:4355d653f84f edit files yet again
+ 5:9d5af5072dbd edit files again
+ 4:74c02385b94c move files
+ 3:9e8fbc4bce62 copy files
+ 2:51a0ae4d5864 remove files
+ 1:ce8896473775 edit files
+ 0:30d30fe6a5be add files
+ $ cat sub/large4
+ large4-modified-again
+
+"update --check" refuses to update with uncommitted changes.
+ $ hg update --check 8
+ abort: uncommitted local changes
+ [255]
+
+"update --clean" leaves correct largefiles in working copy.
+
+ $ hg update --clean
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+ $ cat normal3
+ normal3-modified
+ $ cat sub/normal4
+ normal4-modified
+ $ cat sub/large4
+ large4-modified
+ $ cat sub2/large6
+ large6-modified
+ $ cat sub2/large7
+ large7
+
+Now "update check" is happy.
+ $ hg update --check 8
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+ $ hg update --check
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+
+Test removing empty largefiles directories on update
+ $ test -d sub2 && echo "sub2 exists"
+ sub2 exists
+ $ hg update -q null
+ $ test -d sub2 && echo "error: sub2 should not exist anymore"
+ [1]
+ $ hg update -q
+
+Test hg remove removes empty largefiles directories
+ $ test -d sub2 && echo "sub2 exists"
+ sub2 exists
+ $ hg remove sub2/*
+ $ test -d sub2 && echo "error: sub2 should not exist anymore"
+ [1]
+ $ hg revert sub2/large6 sub2/large7
+
+"revert" works on largefiles (and normal files too).
+ $ echo hack3 >> normal3
+ $ echo hack4 >> sub/normal4
+ $ echo hack4 >> sub/large4
+ $ rm sub2/large6
+ $ hg revert sub2/large6
+ $ hg rm sub2/large6
+ $ echo new >> sub2/large8
+ $ hg add --large sub2/large8
+# XXX we don't really want to report that we're reverting the standin;
+# that's just an implementation detail. But I don't see an obvious fix. ;-(
+ $ hg revert sub
+ reverting .hglf/sub/large4 (glob)
+ reverting sub/normal4 (glob)
+ $ hg status
+ M normal3
+ A sub2/large8
+ R sub2/large6
+ ? sub/large4.orig
+ ? sub/normal4.orig
+ $ cat sub/normal4
+ normal4-modified
+ $ cat sub/large4
+ large4-modified
+ $ hg revert -a --no-backup
+ undeleting .hglf/sub2/large6 (glob)
+ forgetting .hglf/sub2/large8 (glob)
+ reverting normal3
+ $ hg status
+ ? sub/large4.orig
+ ? sub/normal4.orig
+ ? sub2/large8
+ $ cat normal3
+ normal3-modified
+ $ cat sub2/large6
+ large6-modified
+ $ rm sub/*.orig sub2/large8
+
+revert some files to an older revision
+ $ hg revert --no-backup -r 8 sub2
+ reverting .hglf/sub2/large6 (glob)
+ $ cat sub2/large6
+ large6
+ $ hg revert --no-backup -C -r '.^' sub2
+ reverting .hglf/sub2/large6 (glob)
+ $ hg revert --no-backup sub2
+ reverting .hglf/sub2/large6 (glob)
+ $ hg status
+
+"verify --large" actually verifies largefiles
+
+ $ hg verify --large
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 10 files, 10 changesets, 28 total revisions
+ searching 1 changesets for largefiles
+ verified existence of 3 revisions of 3 largefiles
+
+Merging does not revert to old versions of largefiles and also check
+that merging after having pulled from a non-default remote works
+correctly.
+
+ $ cd ..
+ $ hg clone -r 7 e temp
+ adding changesets
+ adding manifests
+ adding file changes
+ added 8 changesets with 24 changes to 10 files
+ updating to branch default
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 3 largefiles updated, 0 removed
+ $ hg clone temp f
+ updating to branch default
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 3 largefiles updated, 0 removed
+# Delete the largefiles in the largefiles system cache so that we have an
+# opportunity to test that caching after a pull works.
+ $ rm "${USERCACHE}"/*
+ $ cd f
+ $ echo "large4-merge-test" > sub/large4
+ $ hg commit -m "Modify large4 to test merge"
+ Invoking status precommit hook
+ M sub/large4
+ $ hg pull ../e
+ pulling from ../e
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 4 changes to 4 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ caching new largefiles
+ 2 largefiles cached
+ $ hg merge
+ merging sub/large4
+ largefile sub/large4 has a merge conflict
+ keep (l)ocal or take (o)ther? l
+ 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+ $ hg commit -m "Merge repos e and f"
+ Invoking status precommit hook
+ M normal3
+ M sub/normal4
+ M sub2/large6
+ $ cat normal3
+ normal3-modified
+ $ cat sub/normal4
+ normal4-modified
+ $ cat sub/large4
+ large4-merge-test
+ $ cat sub2/large6
+ large6-modified
+ $ cat sub2/large7
+ large7
+
+Test status after merging with a branch that introduces a new largefile:
+
+ $ echo large > large
+ $ hg add --large large
+ $ hg commit -m 'add largefile'
+ Invoking status precommit hook
+ A large
+ $ hg update -q ".^"
+ $ echo change >> normal3
+ $ hg commit -m 'some change'
+ Invoking status precommit hook
+ M normal3
+ created new head
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+ $ hg status
+ M large
+
+Test that a normal file and a largefile with the same name and path cannot
+coexist.
+
+ $ rm sub2/large7
+ $ echo "largeasnormal" > sub2/large7
+ $ hg add sub2/large7
+ sub2/large7 already a largefile
+
+Test that transplanting a largefile change works correctly.
+
+ $ cd ..
+ $ hg clone -r 8 d g
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 26 changes to 10 files
+ updating to branch default
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 3 largefiles updated, 0 removed
+ $ cd g
+ $ hg transplant -s ../d 598410d3eb9a
+ searching for changes
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+ $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
+ 9:598410d3eb9a modify normal file largefile in repo d
+ 8:a381d2c8c80e modify normal file and largefile in repo b
+ 7:daea875e9014 add/edit more largefiles
+ 6:4355d653f84f edit files yet again
+ 5:9d5af5072dbd edit files again
+ 4:74c02385b94c move files
+ 3:9e8fbc4bce62 copy files
+ 2:51a0ae4d5864 remove files
+ 1:ce8896473775 edit files
+ 0:30d30fe6a5be add files
+ $ cat normal3
+ normal3-modified
+ $ cat sub/normal4
+ normal4-modified
+ $ cat sub/large4
+ large4-modified
+ $ cat sub2/large6
+ large6-modified
+ $ cat sub2/large7
+ large7
+
+Cat a largefile
+ $ hg cat normal3
+ normal3-modified
+ $ hg cat sub/large4
+ large4-modified
+ $ rm "${USERCACHE}"/*
+ $ hg cat -r a381d2c8c80e -o cat.out sub/large4
+ $ cat cat.out
+ large4-modified
+ $ rm cat.out
+ $ hg cat -r a381d2c8c80e normal3
+ normal3-modified
+ $ hg cat -r '.^' normal3
+ normal3-modified
+ $ hg cat -r '.^' sub/large4
+ large4-modified
+
+Test that renaming a largefile results in correct output for status
+
+ $ hg rename sub/large4 large4-renamed
+ $ hg commit -m "test rename output"
+ Invoking status precommit hook
+ A large4-renamed
+ R sub/large4
+ $ cat large4-renamed
+ large4-modified
+ $ cd sub2
+ $ hg rename large6 large6-renamed
+ $ hg st
+ A sub2/large6-renamed
+ R sub2/large6
+ $ cd ..
+
+Test --normal flag
+
+ $ dd if=/dev/zero bs=2k count=11k > new-largefile 2> /dev/null
+ $ hg add --normal --large new-largefile
+ abort: --normal cannot be used with --large
+ [255]
+ $ hg add --normal new-largefile
+ new-largefile: up to 69 MB of RAM may be required to manage this file
+ (use 'hg revert new-largefile' to cancel the pending addition)
+ $ cd ..
+
+#if serve
+vanilla clients not locked out from largefiles servers on vanilla repos
+ $ mkdir r1
+ $ cd r1
+ $ hg init
+ $ echo c1 > f1
+ $ hg add f1
+ $ hg commit -m "m1"
+ Invoking status precommit hook
+ A f1
+ $ cd ..
+ $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+largefiles clients still work with vanilla servers
+ $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg clone http://localhost:$HGPORT1 r3
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+#endif
+
+
+vanilla clients locked out from largefiles http repos
+ $ mkdir r4
+ $ cd r4
+ $ hg init
+ $ echo c1 > f1
+ $ hg add --large f1
+ $ hg commit -m "m1"
+ Invoking status precommit hook
+ A f1
+ $ cd ..
+
+#if serve
+ $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
+ abort: remote error:
+
+ This repository uses the largefiles extension.
+
+ Please enable it in your Mercurial config file.
+ [255]
+
+used all HGPORTs, kill all daemons
+ $ "$TESTDIR/killdaemons.py"
+#endif
+
+vanilla clients locked out from largefiles ssh repos
+ $ hg --config extensions.largefiles=! clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/r4 r5
+ abort: remote error:
+
+ This repository uses the largefiles extension.
+
+ Please enable it in your Mercurial config file.
+ [255]
+
+#if serve
+
+largefiles clients refuse to push largefiles repos to vanilla servers
+ $ mkdir r6
+ $ cd r6
+ $ hg init
+ $ echo c1 > f1
+ $ hg add f1
+ $ hg commit -m "m1"
+ Invoking status precommit hook
+ A f1
+ $ cat >> .hg/hgrc <<!
+ > [web]
+ > push_ssl = false
+ > allow_push = *
+ > !
+ $ cd ..
+ $ hg clone r6 r7
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd r7
+ $ echo c2 > f2
+ $ hg add --large f2
+ $ hg commit -m "m2"
+ Invoking status precommit hook
+ A f2
+ $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
+ $ cat ../hg.pid >> $DAEMON_PIDS
+ $ hg push http://localhost:$HGPORT
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: http://localhost:$HGPORT/ does not appear to be a largefile store
+ [255]
+ $ cd ..
+
+putlfile errors are shown (issue3123)
+Corrupt the cached largefile in r7 and in the usercache (required for testing on vfat)
+ $ echo corruption > "$TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8"
+ $ echo corruption > "$USERCACHE/4cdac4d8b084d0b599525cf732437fb337d422a8"
+ $ hg init empty
+ $ hg serve -R empty -d -p $HGPORT1 --pid-file hg.pid \
+ > --config 'web.allow_push=*' --config web.push_ssl=False
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg push -R r7 http://localhost:$HGPORT1
+ pushing to http://localhost:$HGPORT1/
+ searching for changes
+ remote: largefiles: failed to put 4cdac4d8b084d0b599525cf732437fb337d422a8 into store: largefile contents do not match hash
+ abort: remotestore: could not put $TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 to remote store http://localhost:$HGPORT1/ (glob)
+ [255]
+ $ rm -rf empty
+
+Push a largefiles repository to a served empty repository
+ $ hg init r8
+ $ echo c3 > r8/f1
+ $ hg add --large r8/f1 -R r8
+ $ hg commit -m "m1" -R r8
+ Invoking status precommit hook
+ A f1
+ $ hg init empty
+ $ hg serve -R empty -d -p $HGPORT2 --pid-file hg.pid \
+ > --config 'web.allow_push=*' --config web.push_ssl=False
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ rm "${USERCACHE}"/*
+ $ hg push -R r8 http://localhost:$HGPORT2
+ pushing to http://localhost:$HGPORT2/
+ searching for changes
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ $ rm -rf empty
+
+used all HGPORTs, kill all daemons
+ $ "$TESTDIR/killdaemons.py"
+
+#endif
+
+
+#if unix-permissions
+
+Clone a local repository owned by another user
+We have to simulate that here by setting $HOME and removing write permissions
+ $ ORIGHOME="$HOME"
+ $ mkdir alice
+ $ HOME="`pwd`/alice"
+ $ cd alice
+ $ hg init pubrepo
+ $ cd pubrepo
+ $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
+ $ hg add --large a-large-file
+ $ hg commit -m "Add a large file"
+ Invoking status precommit hook
+ A a-large-file
+ $ cd ..
+ $ chmod -R a-w pubrepo
+ $ cd ..
+ $ mkdir bob
+ $ HOME="`pwd`/bob"
+ $ cd bob
+ $ hg clone --pull ../alice/pubrepo pubrepo
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+ $ cd ..
+ $ chmod -R u+w alice/pubrepo
+ $ HOME="$ORIGHOME"
+
+#endif
+
+#if symlink
+
+Symlink to a large largefile should behave the same as a symlink to a normal file
+ $ hg init largesymlink
+ $ cd largesymlink
+ $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
+ $ hg add --large largefile
+ $ hg commit -m "commit a large file"
+ Invoking status precommit hook
+ A largefile
+ $ ln -s largefile largelink
+ $ hg add largelink
+ $ hg commit -m "commit a large symlink"
+ Invoking status precommit hook
+ A largelink
+ $ rm -f largelink
+ $ hg up >/dev/null
+ $ test -f largelink
+ [1]
+ $ test -L largelink
+ [1]
+ $ rm -f largelink # make next part of the test independent of the previous
+ $ hg up -C >/dev/null
+ $ test -f largelink
+ $ test -L largelink
+ $ cd ..
+
+#endif
+
+test for pattern matching on 'hg status':
+to boost performance, largefiles checks whether specified patterns are
+related to largefiles in working directory (NOT to STANDIN) or not.
+
+ $ hg init statusmatch
+ $ cd statusmatch
+
+ $ mkdir -p a/b/c/d
+ $ echo normal > a/b/c/d/e.normal.txt
+ $ hg add a/b/c/d/e.normal.txt
+ $ echo large > a/b/c/d/e.large.txt
+ $ hg add --large a/b/c/d/e.large.txt
+ $ mkdir -p a/b/c/x
+ $ echo normal > a/b/c/x/y.normal.txt
+ $ hg add a/b/c/x/y.normal.txt
+ $ hg commit -m 'add files'
+ Invoking status precommit hook
+ A a/b/c/d/e.large.txt
+ A a/b/c/d/e.normal.txt
+ A a/b/c/x/y.normal.txt
+
+(1) no pattern: no performance boost
+ $ hg status -A
+ C a/b/c/d/e.large.txt
+ C a/b/c/d/e.normal.txt
+ C a/b/c/x/y.normal.txt
+
+(2) pattern not related to largefiles: performance boost
+ $ hg status -A a/b/c/x
+ C a/b/c/x/y.normal.txt
+
+(3) pattern related to largefiles: no performance boost
+ $ hg status -A a/b/c/d
+ C a/b/c/d/e.large.txt
+ C a/b/c/d/e.normal.txt
+
+(4) pattern related to STANDIN (not to largefiles): performance boost
+ $ hg status -A .hglf/a
+ C .hglf/a/b/c/d/e.large.txt
+
+(5) mixed case: no performance boost
+ $ hg status -A a/b/c/x a/b/c/d
+ C a/b/c/d/e.large.txt
+ C a/b/c/d/e.normal.txt
+ C a/b/c/x/y.normal.txt
+
+verify that largefiles doesn't break filesets
+
+ $ hg log --rev . --exclude "set:binary()"
+ changeset: 0:41bd42f10efa
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add files
+
+verify that large files in subrepos handled properly
+ $ hg init subrepo
+ $ echo "subrepo = subrepo" > .hgsub
+ $ hg add .hgsub
+ $ hg ci -m "add subrepo"
+ Invoking status precommit hook
+ A .hgsub
+ ? .hgsubstate
+ $ echo "rev 1" > subrepo/large.txt
+ $ hg -R subrepo add --large subrepo/large.txt
+ $ hg sum
+ parent: 1:8ee150ea2e9c tip
+ add subrepo
+ branch: default
+ commit: 1 subrepos
+ update: (current)
+ $ hg st
+ $ hg st -S
+ A subrepo/large.txt
+ $ hg ci -S -m "commit top repo"
+ committing subrepository subrepo
+ Invoking status precommit hook
+ A large.txt
+ Invoking status precommit hook
+ M .hgsubstate
+# No differences
+ $ hg st -S
+ $ hg sum
+ parent: 2:ce4cd0c527a6 tip
+ commit top repo
+ branch: default
+ commit: (clean)
+ update: (current)
+ $ echo "rev 2" > subrepo/large.txt
+ $ hg st -S
+ M subrepo/large.txt
+ $ hg sum
+ parent: 2:ce4cd0c527a6 tip
+ commit top repo
+ branch: default
+ commit: 1 subrepos
+ update: (current)
+ $ hg ci -m "this commit should fail without -S"
+ abort: uncommitted changes in subrepo subrepo
+ (use --subrepos for recursive commit)
+ [255]
+
+Add a normal file to the subrepo, then test archiving
+
+ $ echo 'normal file' > subrepo/normal.txt
+ $ hg -R subrepo add subrepo/normal.txt
+
+Lock in subrepo, otherwise the change isn't archived
+
+ $ hg ci -S -m "add normal file to top level"
+ committing subrepository subrepo
+ Invoking status precommit hook
+ M large.txt
+ A normal.txt
+ Invoking status precommit hook
+ M .hgsubstate
+ $ hg archive -S lf_subrepo_archive
+ $ find lf_subrepo_archive | sort
+ lf_subrepo_archive
+ lf_subrepo_archive/.hg_archival.txt
+ lf_subrepo_archive/.hgsub
+ lf_subrepo_archive/.hgsubstate
+ lf_subrepo_archive/a
+ lf_subrepo_archive/a/b
+ lf_subrepo_archive/a/b/c
+ lf_subrepo_archive/a/b/c/d
+ lf_subrepo_archive/a/b/c/d/e.large.txt
+ lf_subrepo_archive/a/b/c/d/e.normal.txt
+ lf_subrepo_archive/a/b/c/x
+ lf_subrepo_archive/a/b/c/x/y.normal.txt
+ lf_subrepo_archive/subrepo
+ lf_subrepo_archive/subrepo/large.txt
+ lf_subrepo_archive/subrepo/normal.txt
+
+ $ cd ..
diff --git a/tests/test-lfconvert.t b/tests/test-lfconvert.t
new file mode 100644
index 0000000..50330eb
--- /dev/null
+++ b/tests/test-lfconvert.t
@@ -0,0 +1,272 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > largefiles =
+ > share =
+ > graphlog =
+ > mq =
+ > [largefiles]
+ > minsize = 0.5
+ > patterns = **.other
+ > **.dat
+ > EOF
+
+"lfconvert" works
+ $ hg init bigfile-repo
+ $ cd bigfile-repo
+ $ cat >> .hg/hgrc <<EOF
+ > [extensions]
+ > largefiles = !
+ > EOF
+ $ mkdir sub
+ $ dd if=/dev/zero bs=1k count=256 > large 2> /dev/null
+ $ dd if=/dev/zero bs=1k count=256 > large2 2> /dev/null
+ $ echo normal > normal1
+ $ echo alsonormal > sub/normal2
+ $ dd if=/dev/zero bs=1k count=10 > sub/maybelarge.dat 2> /dev/null
+ $ hg addremove
+ adding large
+ adding large2
+ adding normal1
+ adding sub/maybelarge.dat
+ adding sub/normal2
+ $ hg commit -m"add large, normal1" large normal1
+ $ hg commit -m"add sub/*" sub
+
+Test tag parsing
+ $ cat >> .hgtags <<EOF
+ > IncorrectlyFormattedTag!
+ > invalidhash sometag
+ > 0123456789abcdef anothertag
+ > EOF
+ $ hg add .hgtags
+ $ hg commit -m"add large2" large2 .hgtags
+
+Test link+rename largefile codepath
+ $ [ -d .hg/largefiles ] && echo fail || echo pass
+ pass
+ $ cd ..
+ $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
+ initializing destination largefiles-repo
+ skipping incorrectly formatted tag IncorrectlyFormattedTag!
+ skipping incorrectly formatted id invalidhash
+ no mapping for id 0123456789abcdef
+#if symlink
+ $ hg --cwd bigfile-repo rename large2 large3
+ $ ln -sf large bigfile-repo/large3
+ $ hg --cwd bigfile-repo commit -m"make large2 a symlink" large2 large3
+ $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo-symlink
+ initializing destination largefiles-repo-symlink
+ skipping incorrectly formatted tag IncorrectlyFormattedTag!
+ skipping incorrectly formatted id invalidhash
+ no mapping for id 0123456789abcdef
+ abort: renamed/copied largefile large3 becomes symlink
+ [255]
+#endif
+ $ cd bigfile-repo
+ $ hg strip --no-backup 2
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ cd ..
+ $ rm -rf largefiles-repo largefiles-repo-symlink
+
+ $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
+ initializing destination largefiles-repo
+
+"lfconvert" converts content correctly
+ $ cd largefiles-repo
+ $ hg up
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 2 largefiles updated, 0 removed
+ $ hg locate
+ .hglf/large
+ .hglf/sub/maybelarge.dat
+ normal1
+ sub/normal2
+ $ cat normal1
+ normal
+ $ cat sub/normal2
+ alsonormal
+ $ "$TESTDIR/md5sum.py" large sub/maybelarge.dat
+ ec87a838931d4d5d2e94a04644788a55 large
+ 1276481102f218c981e0324180bafd9f sub/maybelarge.dat
+
+"lfconvert" adds 'largefiles' to .hg/requires.
+ $ cat .hg/requires
+ largefiles
+ revlogv1
+ fncache
+ store
+ dotencode
+
+"lfconvert" includes a newline at the end of the standin files.
+ $ cat .hglf/large .hglf/sub/maybelarge.dat
+ 2e000fa7e85759c7f4c254d4d9c33ef481e459a7
+ 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c
+ $ cd ..
+
+add some changesets to rename/remove/merge
+ $ cd bigfile-repo
+ $ hg mv -q sub stuff
+ $ hg commit -m"rename sub/ to stuff/"
+ $ hg update -q 1
+ $ echo blah >> normal3
+ $ echo blah >> sub/normal2
+ $ echo blah >> sub/maybelarge.dat
+ $ "$TESTDIR/md5sum.py" sub/maybelarge.dat
+ 1dd0b99ff80e19cff409702a1d3f5e15 sub/maybelarge.dat
+ $ hg commit -A -m"add normal3, modify sub/*"
+ adding normal3
+ created new head
+ $ hg rm large normal3
+ $ hg commit -q -m"remove large, normal3"
+ $ hg merge
+ merging sub/maybelarge.dat and stuff/maybelarge.dat to stuff/maybelarge.dat
+ warning: $TESTTMP/bigfile-repo/stuff/maybelarge.dat looks like a binary file. (glob)
+ merging stuff/maybelarge.dat incomplete! (edit conflicts, then use 'hg resolve --mark')
+ merging sub/normal2 and stuff/normal2 to stuff/normal2
+ 0 files updated, 1 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ hg cat -r . sub/maybelarge.dat > stuff/maybelarge.dat
+ $ hg resolve -m stuff/maybelarge.dat
+ $ hg commit -m"merge"
+ $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
+ @ 5:4884f215abda merge
+ |\
+ | o 4:7285f817b77e remove large, normal3
+ | |
+ | o 3:67e3892e3534 add normal3, modify sub/*
+ | |
+ o | 2:c96c8beb5d56 rename sub/ to stuff/
+ |/
+ o 1:020c65d24e11 add sub/*
+ |
+ o 0:117b8328f97a add large, normal1
+
+ $ cd ..
+
+lfconvert with rename, merge, and remove
+ $ rm -rf largefiles-repo
+ $ hg lfconvert --size 0.2 bigfile-repo largefiles-repo
+ initializing destination largefiles-repo
+ $ cd largefiles-repo
+ $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
+ o 5:8e05f5f2b77e merge
+ |\
+ | o 4:a5a02de7a8e4 remove large, normal3
+ | |
+ | o 3:55759520c76f add normal3, modify sub/*
+ | |
+ o | 2:261ad3f3f037 rename sub/ to stuff/
+ |/
+ o 1:334e5237836d add sub/*
+ |
+ o 0:d4892ec57ce2 add large, normal1
+
+ $ hg locate -r 2
+ .hglf/large
+ .hglf/stuff/maybelarge.dat
+ normal1
+ stuff/normal2
+ $ hg locate -r 3
+ .hglf/large
+ .hglf/sub/maybelarge.dat
+ normal1
+ normal3
+ sub/normal2
+ $ hg locate -r 4
+ .hglf/sub/maybelarge.dat
+ normal1
+ sub/normal2
+ $ hg locate -r 5
+ .hglf/stuff/maybelarge.dat
+ normal1
+ stuff/normal2
+ $ hg update
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ 1 largefiles updated, 0 removed
+ $ cat stuff/normal2
+ alsonormal
+ blah
+ $ "$TESTDIR/md5sum.py" stuff/maybelarge.dat
+ 1dd0b99ff80e19cff409702a1d3f5e15 stuff/maybelarge.dat
+ $ cat .hglf/stuff/maybelarge.dat
+ 76236b6a2c6102826c61af4297dd738fb3b1de38
+ $ cd ..
+
+"lfconvert" error cases
+ $ hg lfconvert http://localhost/foo foo
+ abort: http://localhost/foo is not a local Mercurial repo
+ [255]
+ $ hg lfconvert foo ssh://localhost/foo
+ abort: ssh://localhost/foo is not a local Mercurial repo
+ [255]
+ $ hg lfconvert nosuchrepo foo
+ abort: repository nosuchrepo not found!
+ [255]
+ $ hg share -q -U bigfile-repo shared
+ $ printf 'bogus' > shared/.hg/sharedpath
+ $ hg lfconvert shared foo
+ abort: .hg/sharedpath points to nonexistent directory $TESTTMP/bogus! (glob)
+ [255]
+ $ hg lfconvert bigfile-repo largefiles-repo
+ initializing destination largefiles-repo
+ abort: repository largefiles-repo already exists!
+ [255]
+
+add another largefile to the new largefiles repo
+ $ cd largefiles-repo
+ $ dd if=/dev/zero bs=1k count=1k > anotherlarge 2> /dev/null
+ $ hg add --lfsize=1 anotherlarge
+ $ hg commit -m "add anotherlarge (should be a largefile)"
+ $ cat .hglf/anotherlarge
+ 3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3
+ $ cd ..
+
+round-trip: converting back to a normal (non-largefiles) repo with
+"lfconvert --to-normal" should give the same as ../bigfile-repo
+ $ cd largefiles-repo
+ $ hg lfconvert --to-normal . ../normal-repo
+ initializing destination ../normal-repo
+ $ cd ../normal-repo
+ $ cat >> .hg/hgrc <<EOF
+ > [extensions]
+ > largefiles = !
+ > EOF
+
+# Hmmm: the changeset ID for rev 5 is different from the original
+# normal repo (../bigfile-repo), because the changelog filelist
+# differs between the two incarnations of rev 5: this repo includes
+# 'large' in the list, but ../bigfile-repo does not. Since rev 5
+# removes 'large' relative to the first parent in both repos, it seems
+# to me that lfconvert is doing a *better* job than
+# "hg remove" + "hg merge" + "hg commit".
+# $ hg -R ../bigfile-repo debugdata -c 5
+# $ hg debugdata -c 5
+ $ hg glog --template "{rev}:{node|short} {desc|firstline}\n"
+ o 6:1635824e6f59 add anotherlarge (should be a largefile)
+ |
+ o 5:7215f8deeaaf merge
+ |\
+ | o 4:7285f817b77e remove large, normal3
+ | |
+ | o 3:67e3892e3534 add normal3, modify sub/*
+ | |
+ o | 2:c96c8beb5d56 rename sub/ to stuff/
+ |/
+ o 1:020c65d24e11 add sub/*
+ |
+ o 0:117b8328f97a add large, normal1
+
+ $ hg update
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg locate
+ anotherlarge
+ normal1
+ stuff/maybelarge.dat
+ stuff/normal2
+ $ [ -d .hg/largefiles ] && echo fail || echo pass
+ pass
+
+ $ cd ..
diff --git a/tests/test-locate.t b/tests/test-locate.t
new file mode 100644
index 0000000..9d18a3e
--- /dev/null
+++ b/tests/test-locate.t
@@ -0,0 +1,121 @@
+ $ hg init repo
+ $ cd repo
+ $ echo 0 > a
+ $ echo 0 > b
+ $ echo 0 > t.h
+ $ mkdir t
+ $ echo 0 > t/x
+ $ echo 0 > t/b
+ $ echo 0 > t/e.h
+ $ mkdir dir.h
+ $ echo 0 > dir.h/foo
+
+ $ hg ci -A -m m
+ adding a
+ adding b
+ adding dir.h/foo
+ adding t.h
+ adding t/b
+ adding t/e.h
+ adding t/x
+
+ $ touch nottracked
+
+ $ hg locate a
+ a
+
+ $ hg locate NONEXISTENT
+ [1]
+
+ $ hg locate
+ a
+ b
+ dir.h/foo
+ t.h
+ t/b
+ t/e.h
+ t/x
+
+ $ hg rm a
+ $ hg ci -m m
+
+ $ hg locate a
+ [1]
+ $ hg locate NONEXISTENT
+ [1]
+ $ hg locate relpath:NONEXISTENT
+ [1]
+ $ hg locate
+ b
+ dir.h/foo
+ t.h
+ t/b
+ t/e.h
+ t/x
+ $ hg locate -r 0 a
+ a
+ $ hg locate -r 0 NONEXISTENT
+ [1]
+ $ hg locate -r 0 relpath:NONEXISTENT
+ [1]
+ $ hg locate -r 0
+ a
+ b
+ dir.h/foo
+ t.h
+ t/b
+ t/e.h
+ t/x
+
+-I/-X with relative path should work:
+
+ $ cd t
+ $ hg locate
+ b
+ dir.h/foo
+ t.h
+ t/b
+ t/e.h
+ t/x
+ $ hg locate -I ../t
+ t/b
+ t/e.h
+ t/x
+
+Issue294: hg remove --after dir fails when dir.* also exists
+
+ $ cd ..
+ $ rm -r t
+
+ $ hg locate 't/**'
+ t/b (glob)
+ t/e.h (glob)
+ t/x (glob)
+
+ $ mkdir otherdir
+ $ cd otherdir
+
+ $ hg locate b
+ ../b (glob)
+ ../t/b (glob)
+ $ hg locate '*.h'
+ ../t.h (glob)
+ ../t/e.h (glob)
+ $ hg locate path:t/x
+ ../t/x (glob)
+ $ hg locate 're:.*\.h$'
+ ../t.h (glob)
+ ../t/e.h (glob)
+ $ hg locate -r 0 b
+ ../b (glob)
+ ../t/b (glob)
+ $ hg locate -r 0 '*.h'
+ ../t.h (glob)
+ ../t/e.h (glob)
+ $ hg locate -r 0 path:t/x
+ ../t/x (glob)
+ $ hg locate -r 0 're:.*\.h$'
+ ../t.h (glob)
+ ../t/e.h (glob)
+
+ $ cd ../..
diff --git a/tests/test-lock-badness.t b/tests/test-lock-badness.t
new file mode 100644
index 0000000..9c3319c
--- /dev/null
+++ b/tests/test-lock-badness.t
@@ -0,0 +1,24 @@
+ $ "$TESTDIR/hghave" unix-permissions || exit 80
+
+ $ hg init a
+ $ echo a > a/a
+ $ hg -R a ci -A -m a
+ adding a
+
+ $ hg clone a b
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo b > b/b
+ $ hg -R b ci -A -m b
+ adding b
+
+ $ chmod 100 a/.hg/store
+
+ $ hg -R b push a
+ pushing to a
+ abort: could not lock repository a: Permission denied
+ [255]
+
+ $ chmod 700 a/.hg/store
+
diff --git a/tests/test-log.t b/tests/test-log.t
new file mode 100644
index 0000000..0a4248e
--- /dev/null
+++ b/tests/test-log.t
@@ -0,0 +1,1215 @@
+The g is crafted to have 2 filelog topological heads in a linear
+changeset graph
+
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ echo f > f
+ $ hg ci -Ama -d '1 0'
+ adding a
+ adding f
+
+ $ hg cp a b
+ $ hg cp f g
+ $ hg ci -mb -d '2 0'
+
+ $ mkdir dir
+ $ hg mv b dir
+ $ echo g >> g
+ $ echo f >> f
+ $ hg ci -mc -d '3 0'
+
+ $ hg mv a b
+ $ hg cp -f f g
+ $ echo a > d
+ $ hg add d
+ $ hg ci -md -d '4 0'
+
+ $ hg mv dir/b e
+ $ hg ci -me -d '5 0'
+
+ $ hg log a
+ changeset: 0:9161b9aeaf16
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: a
+
+
+-f, directory
+
+ $ hg log -f dir
+ abort: cannot follow file not in parent revision: "dir"
+ [255]
+
+-f, but no args
+
+ $ hg log -f
+ changeset: 4:7e4639b4691b
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ summary: e
+
+ changeset: 3:2ca5ba701980
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: d
+
+ changeset: 2:f8954cd4dc1f
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: c
+
+ changeset: 1:d89b0a12d229
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: b
+
+ changeset: 0:9161b9aeaf16
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: a
+
+
+one rename
+
+ $ hg up -q 2
+ $ hg log -vf a
+ changeset: 0:9161b9aeaf16
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ files: a f
+ description:
+ a
+
+
+
+many renames
+
+ $ hg up -q tip
+ $ hg log -vf e
+ changeset: 4:7e4639b4691b
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ files: dir/b e
+ description:
+ e
+
+
+ changeset: 2:f8954cd4dc1f
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ files: b dir/b f g
+ description:
+ c
+
+
+ changeset: 1:d89b0a12d229
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ files: b g
+ description:
+ b
+
+
+ changeset: 0:9161b9aeaf16
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ files: a f
+ description:
+ a
+
+
+
+
+log -pf dir/b
+
+ $ hg up -q 3
+ $ hg log -pf dir/b
+ changeset: 2:f8954cd4dc1f
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: c
+
+ diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ changeset: 1:d89b0a12d229
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: b
+
+ diff -r 9161b9aeaf16 -r d89b0a12d229 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:02 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ changeset: 0:9161b9aeaf16
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: a
+
+ diff -r 000000000000 -r 9161b9aeaf16 a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+
+log -vf dir/b
+
+ $ hg log -vf dir/b
+ changeset: 2:f8954cd4dc1f
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ files: b dir/b f g
+ description:
+ c
+
+
+ changeset: 1:d89b0a12d229
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ files: b g
+ description:
+ b
+
+
+ changeset: 0:9161b9aeaf16
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ files: a f
+ description:
+ a
+
+
+
+
+-f and multiple filelog heads
+
+ $ hg up -q 2
+ $ hg log -f g --template '{rev}\n'
+ 2
+ 1
+ 0
+ $ hg up -q tip
+ $ hg log -f g --template '{rev}\n'
+ 3
+ 2
+ 0
+
+
+log copies with --copies
+
+ $ hg log -vC --template '{rev} {file_copies}\n'
+ 4 e (dir/b)
+ 3 b (a)g (f)
+ 2 dir/b (b)
+ 1 b (a)g (f)
+ 0
+
+log copies switch without --copies, with old filecopy template
+
+ $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
+ 4
+ 3
+ 2
+ 1
+ 0
+
+log copies switch with --copies
+
+ $ hg log -vC --template '{rev} {file_copies_switch}\n'
+ 4 e (dir/b)
+ 3 b (a)g (f)
+ 2 dir/b (b)
+ 1 b (a)g (f)
+ 0
+
+
+log copies with hardcoded style and with --style=default
+
+ $ hg log -vC -r4
+ changeset: 4:7e4639b4691b
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ files: dir/b e
+ copies: e (dir/b)
+ description:
+ e
+
+
+ $ hg log -vC -r4 --style=default
+ changeset: 4:7e4639b4691b
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ files: dir/b e
+ copies: e (dir/b)
+ description:
+ e
+
+
+
+
+log copies, non-linear manifest
+
+ $ hg up -C 3
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg mv dir/b e
+ $ echo foo > foo
+ $ hg ci -Ame2 -d '6 0'
+ adding foo
+ created new head
+ $ hg log -v --template '{rev} {file_copies}\n' -r 5
+ 5 e (dir/b)
+
+
+log copies, execute bit set
+
+#if execbit
+ $ chmod +x e
+ $ hg ci -me3 -d '7 0'
+ $ hg log -v --template '{rev} {file_copies}\n' -r 6
+ 6
+#endif
+
+
+log -p d
+
+ $ hg log -pv d
+ changeset: 3:2ca5ba701980
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ files: a b d g
+ description:
+ d
+
+
+ diff -r f8954cd4dc1f -r 2ca5ba701980 d
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/d Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+
+
+log --removed file
+
+ $ hg log --removed -v a
+ changeset: 3:2ca5ba701980
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ files: a b d g
+ description:
+ d
+
+
+ changeset: 0:9161b9aeaf16
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ files: a f
+ description:
+ a
+
+
+
+log --removed revrange file
+
+ $ hg log --removed -v -r0:2 a
+ changeset: 0:9161b9aeaf16
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ files: a f
+ description:
+ a
+
+
+ $ cd ..
+
+log --follow tests
+
+ $ hg init follow
+ $ cd follow
+
+ $ echo base > base
+ $ hg ci -Ambase -d '1 0'
+ adding base
+
+ $ echo r1 >> base
+ $ hg ci -Amr1 -d '1 0'
+ $ echo r2 >> base
+ $ hg ci -Amr2 -d '1 0'
+
+ $ hg up -C 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b1 > b1
+ $ hg ci -Amb1 -d '1 0'
+ adding b1
+ created new head
+
+
+log -f
+
+ $ hg log -f
+ changeset: 3:e62f78d544b4
+ tag: tip
+ parent: 1:3d5bf5654eda
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b1
+
+ changeset: 1:3d5bf5654eda
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: r1
+
+ changeset: 0:67e992f2c4f3
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: base
+
+
+
+log -f -r 1:tip
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo b2 > b2
+ $ hg ci -Amb2 -d '1 0'
+ adding b2
+ created new head
+ $ hg log -f -r 1:tip
+ changeset: 1:3d5bf5654eda
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: r1
+
+ changeset: 2:60c670bf5b30
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: r2
+
+ changeset: 3:e62f78d544b4
+ parent: 1:3d5bf5654eda
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b1
+
+
+
+log -r . with two parents
+
+ $ hg up -C 3
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg log -r .
+ changeset: 3:e62f78d544b4
+ parent: 1:3d5bf5654eda
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b1
+
+
+
+log -r . with one parent
+
+ $ hg ci -mm12 -d '1 0'
+ $ hg log -r .
+ changeset: 5:302e9dd6890d
+ tag: tip
+ parent: 3:e62f78d544b4
+ parent: 4:ddb82e70d1a1
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: m12
+
+
+ $ echo postm >> b1
+ $ hg ci -Amb1.1 -d'1 0'
+
+
+log --follow-first
+
+ $ hg log --follow-first
+ changeset: 6:2404bbcab562
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b1.1
+
+ changeset: 5:302e9dd6890d
+ parent: 3:e62f78d544b4
+ parent: 4:ddb82e70d1a1
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: m12
+
+ changeset: 3:e62f78d544b4
+ parent: 1:3d5bf5654eda
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b1
+
+ changeset: 1:3d5bf5654eda
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: r1
+
+ changeset: 0:67e992f2c4f3
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: base
+
+
+
+log -P 2
+
+ $ hg log -P 2
+ changeset: 6:2404bbcab562
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b1.1
+
+ changeset: 5:302e9dd6890d
+ parent: 3:e62f78d544b4
+ parent: 4:ddb82e70d1a1
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: m12
+
+ changeset: 4:ddb82e70d1a1
+ parent: 0:67e992f2c4f3
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b2
+
+ changeset: 3:e62f78d544b4
+ parent: 1:3d5bf5654eda
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b1
+
+
+
+log -r tip -p --git
+
+ $ hg log -r tip -p --git
+ changeset: 6:2404bbcab562
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b1.1
+
+ diff --git a/b1 b/b1
+ --- a/b1
+ +++ b/b1
+ @@ -1,1 +1,2 @@
+ b1
+ +postm
+
+
+
+log -r ""
+
+ $ hg log -r ''
+ hg: parse error: empty query
+ [255]
+
+log -r <some unknown node id>
+
+ $ hg log -r 1000000000000000000000000000000000000000
+ abort: unknown revision '1000000000000000000000000000000000000000'!
+ [255]
+
+log -k r1
+
+ $ hg log -k r1
+ changeset: 1:3d5bf5654eda
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: r1
+
+log -p -l2 --color=always
+
+ $ hg --config extensions.color= --config color.mode=ansi \
+ > log -p -l2 --color=always
+ \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b1.1
+
+ \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
+ \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
+ \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
+ \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
+ b1
+ \x1b[0;32m+postm\x1b[0m (esc)
+
+ \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
+ parent: 3:e62f78d544b4
+ parent: 4:ddb82e70d1a1
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: m12
+
+ \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
+ \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
+ \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
+ \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
+ \x1b[0;32m+b2\x1b[0m (esc)
+
+
+
+log -r tip --stat
+
+ $ hg log -r tip --stat
+ changeset: 6:2404bbcab562
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b1.1
+
+ b1 | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+
+ $ cd ..
+
+
+User
+
+ $ hg init usertest
+ $ cd usertest
+
+ $ echo a > a
+ $ hg ci -A -m "a" -u "User One <user1@example.org>"
+ adding a
+ $ echo b > b
+ $ hg ci -A -m "b" -u "User Two <user2@example.org>"
+ adding b
+
+ $ hg log -u "User One <user1@example.org>"
+ changeset: 0:29a4c94f1924
+ user: User One <user1@example.org>
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ hg log -u "user1" -u "user2"
+ changeset: 1:e834b5e69c0e
+ tag: tip
+ user: User Two <user2@example.org>
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+ changeset: 0:29a4c94f1924
+ user: User One <user1@example.org>
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ hg log -u "user3"
+
+ $ cd ..
+
+ $ hg init branches
+ $ cd branches
+
+ $ echo a > a
+ $ hg ci -A -m "commit on default"
+ adding a
+ $ hg branch test
+ marked working directory as branch test
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b > b
+ $ hg ci -A -m "commit on test"
+ adding b
+
+ $ hg up default
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo c > c
+ $ hg ci -A -m "commit on default"
+ adding c
+ $ hg up test
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo c > c
+ $ hg ci -A -m "commit on test"
+ adding c
+
+
+log -b default
+
+ $ hg log -b default
+ changeset: 2:c3a4f03cc9a7
+ parent: 0:24427303d56f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on default
+
+ changeset: 0:24427303d56f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on default
+
+
+
+log -b test
+
+ $ hg log -b test
+ changeset: 3:f5d8de11c2e2
+ branch: test
+ tag: tip
+ parent: 1:d32277701ccb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+ changeset: 1:d32277701ccb
+ branch: test
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+
+
+log -b dummy
+
+ $ hg log -b dummy
+ abort: unknown revision 'dummy'!
+ [255]
+
+
+log -b .
+
+ $ hg log -b .
+ changeset: 3:f5d8de11c2e2
+ branch: test
+ tag: tip
+ parent: 1:d32277701ccb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+ changeset: 1:d32277701ccb
+ branch: test
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+
+
+log -b default -b test
+
+ $ hg log -b default -b test
+ changeset: 3:f5d8de11c2e2
+ branch: test
+ tag: tip
+ parent: 1:d32277701ccb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+ changeset: 2:c3a4f03cc9a7
+ parent: 0:24427303d56f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on default
+
+ changeset: 1:d32277701ccb
+ branch: test
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+ changeset: 0:24427303d56f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on default
+
+
+
+log -b default -b .
+
+ $ hg log -b default -b .
+ changeset: 3:f5d8de11c2e2
+ branch: test
+ tag: tip
+ parent: 1:d32277701ccb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+ changeset: 2:c3a4f03cc9a7
+ parent: 0:24427303d56f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on default
+
+ changeset: 1:d32277701ccb
+ branch: test
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+ changeset: 0:24427303d56f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on default
+
+
+
+log -b . -b test
+
+ $ hg log -b . -b test
+ changeset: 3:f5d8de11c2e2
+ branch: test
+ tag: tip
+ parent: 1:d32277701ccb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+ changeset: 1:d32277701ccb
+ branch: test
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+
+
+log -b 2
+
+ $ hg log -b 2
+ changeset: 2:c3a4f03cc9a7
+ parent: 0:24427303d56f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on default
+
+ changeset: 0:24427303d56f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on default
+
+
+
+log -p --cwd dir (in subdir)
+
+ $ mkdir dir
+ $ hg log -p --cwd dir
+ changeset: 3:f5d8de11c2e2
+ branch: test
+ tag: tip
+ parent: 1:d32277701ccb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+ diff -r d32277701ccb -r f5d8de11c2e2 c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+ changeset: 2:c3a4f03cc9a7
+ parent: 0:24427303d56f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on default
+
+ diff -r 24427303d56f -r c3a4f03cc9a7 c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+ changeset: 1:d32277701ccb
+ branch: test
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on test
+
+ diff -r 24427303d56f -r d32277701ccb b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+ changeset: 0:24427303d56f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on default
+
+ diff -r 000000000000 -r 24427303d56f a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+
+
+log -p -R repo
+
+ $ cd dir
+ $ hg log -p -R .. ../a
+ changeset: 0:24427303d56f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit on default
+
+ diff -r 000000000000 -r 24427303d56f a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+
+ $ cd ../..
+
+ $ hg init follow2
+ $ cd follow2
+
+# Build the following history:
+# tip - o - x - o - x - x
+# \ /
+# o - o - o - x
+# \ /
+# o
+#
+# Where "o" is a revision containing "foo" and
+# "x" is a revision without "foo"
+
+ $ touch init
+ $ hg ci -A -m "init, unrelated"
+ adding init
+ $ echo 'foo' > init
+ $ hg ci -m "change, unrelated"
+ $ echo 'foo' > foo
+ $ hg ci -A -m "add unrelated old foo"
+ adding foo
+ $ hg rm foo
+ $ hg ci -m "delete foo, unrelated"
+ $ echo 'related' > foo
+ $ hg ci -A -m "add foo, related"
+ adding foo
+
+ $ hg up 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ touch branch
+ $ hg ci -A -m "first branch, unrelated"
+ adding branch
+ created new head
+ $ touch foo
+ $ hg ci -A -m "create foo, related"
+ adding foo
+ $ echo 'change' > foo
+ $ hg ci -m "change foo, related"
+
+ $ hg up 6
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo 'change foo in branch' > foo
+ $ hg ci -m "change foo in branch, related"
+ created new head
+ $ hg merge 7
+ merging foo
+ warning: conflicts during merge.
+ merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ echo 'merge 1' > foo
+ $ hg resolve -m foo
+ $ hg ci -m "First merge, related"
+
+ $ hg merge 4
+ merging foo
+ warning: conflicts during merge.
+ merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ echo 'merge 2' > foo
+ $ hg resolve -m foo
+ $ hg ci -m "Last merge, related"
+
+ $ hg log --graph
+ @ changeset: 10:4dae8563d2c5
+ |\ tag: tip
+ | | parent: 9:7b35701b003e
+ | | parent: 4:88176d361b69
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: Last merge, related
+ | |
+ | o changeset: 9:7b35701b003e
+ | |\ parent: 8:e5416ad8a855
+ | | | parent: 7:87fe3144dcfa
+ | | | user: test
+ | | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | | summary: First merge, related
+ | | |
+ | | o changeset: 8:e5416ad8a855
+ | | | parent: 6:dc6c325fe5ee
+ | | | user: test
+ | | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | | summary: change foo in branch, related
+ | | |
+ | o | changeset: 7:87fe3144dcfa
+ | |/ user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: change foo, related
+ | |
+ | o changeset: 6:dc6c325fe5ee
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: create foo, related
+ | |
+ | o changeset: 5:73db34516eb9
+ | | parent: 0:e87515fd044a
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: first branch, unrelated
+ | |
+ o | changeset: 4:88176d361b69
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: add foo, related
+ | |
+ o | changeset: 3:dd78ae4afb56
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: delete foo, unrelated
+ | |
+ o | changeset: 2:c4c64aedf0f7
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: add unrelated old foo
+ | |
+ o | changeset: 1:e5faa7440653
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: change, unrelated
+ |
+ o changeset: 0:e87515fd044a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: init, unrelated
+
+
+ $ hg --traceback log -f foo
+ changeset: 10:4dae8563d2c5
+ tag: tip
+ parent: 9:7b35701b003e
+ parent: 4:88176d361b69
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Last merge, related
+
+ changeset: 9:7b35701b003e
+ parent: 8:e5416ad8a855
+ parent: 7:87fe3144dcfa
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: First merge, related
+
+ changeset: 8:e5416ad8a855
+ parent: 6:dc6c325fe5ee
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change foo in branch, related
+
+ changeset: 7:87fe3144dcfa
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change foo, related
+
+ changeset: 6:dc6c325fe5ee
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: create foo, related
+
+ changeset: 4:88176d361b69
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo, related
+
+
+Also check when maxrev < lastrevfilelog
+
+ $ hg --traceback log -f -r4 foo
+ changeset: 4:88176d361b69
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo, related
+
+ $ cd ..
+
+Issue2383: hg log showing _less_ differences than hg diff
+
+ $ hg init issue2383
+ $ cd issue2383
+
+Create a test repo:
+
+ $ echo a > a
+ $ hg ci -Am0
+ adding a
+ $ echo b > b
+ $ hg ci -Am1
+ adding b
+ $ hg co 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo b > a
+ $ hg ci -m2
+ created new head
+
+Merge:
+
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+Make sure there's a file listed in the merge to trigger the bug:
+
+ $ echo c > a
+ $ hg ci -m3
+
+Two files shown here in diff:
+
+ $ hg diff --rev 2:3
+ diff -r b09be438c43a -r 8e07aafe1edc a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,1 @@
+ -b
+ +c
+ diff -r b09be438c43a -r 8e07aafe1edc b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+Diff here should be the same:
+
+ $ hg log -vpr 3
+ changeset: 3:8e07aafe1edc
+ tag: tip
+ parent: 2:b09be438c43a
+ parent: 1:925d80f479bb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: a
+ description:
+ 3
+
+
+ diff -r b09be438c43a -r 8e07aafe1edc a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,1 @@
+ -b
+ +c
+ diff -r b09be438c43a -r 8e07aafe1edc b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+ $ cd ..
+
+'hg log -r rev fn' when last(filelog(fn)) != rev
+
+ $ hg init simplelog
+ $ cd simplelog
+ $ echo f > a
+ $ hg ci -Am'a' -d '0 0'
+ adding a
+ $ echo f >> a
+ $ hg ci -Am'a bis' -d '1 0'
+
+ $ hg log -r0 a
+ changeset: 0:9f758d63dcde
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ cat > $HGTMP/testhidden.py << EOF
+ > def reposetup(ui, repo):
+ > for line in repo.opener('hidden'):
+ > ctx = repo[line.strip()]
+ > repo.hiddenrevs.add(ctx.rev())
+ > EOF
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo "hidden=$HGTMP/testhidden.py" >> $HGRCPATH
+ $ touch .hg/hidden
+ $ hg log --template='{rev}:{node}\n'
+ 1:a765632148dc55d38c35c4f247c618701886cb2f
+ 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
+ $ echo a765632148dc55d38c35c4f247c618701886cb2f > .hg/hidden
+ $ hg log --template='{rev}:{node}\n'
+ 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
+ $ hg log --template='{rev}:{node}\n' --hidden
+ 1:a765632148dc55d38c35c4f247c618701886cb2f
+ 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
+
+clear extensions configuration
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo "hidden=!" >> $HGRCPATH
+ $ cd ..
+
+test -u/-k for problematic encoding
+# unicode: cp932:
+# u30A2 0x83 0x41(= 'A')
+# u30C2 0x83 0x61(= 'a')
+
+ $ hg init problematicencoding
+ $ cd problematicencoding
+
+ $ python > setup.sh <<EOF
+ > print u'''
+ > echo a > text
+ > hg add text
+ > hg --encoding utf-8 commit -u '\u30A2' -m none
+ > echo b > text
+ > hg --encoding utf-8 commit -u '\u30C2' -m none
+ > echo c > text
+ > hg --encoding utf-8 commit -u none -m '\u30A2'
+ > echo d > text
+ > hg --encoding utf-8 commit -u none -m '\u30C2'
+ > '''.encode('utf-8')
+ > EOF
+ $ sh < setup.sh
+
+test in problematic encoding
+ $ python > test.sh <<EOF
+ > print u'''
+ > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
+ > echo ====
+ > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
+ > echo ====
+ > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
+ > echo ====
+ > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
+ > '''.encode('cp932')
+ > EOF
+ $ sh < test.sh
+ 0
+ ====
+ 1
+ ====
+ 2
+ 0
+ ====
+ 3
+ 1
+
+ $ cd ..
diff --git a/tests/test-mactext.t b/tests/test-mactext.t
new file mode 100644
index 0000000..efbd4d2
--- /dev/null
+++ b/tests/test-mactext.t
@@ -0,0 +1,38 @@
+
+ $ cat > unix2mac.py <<EOF
+ > import sys
+ >
+ > for path in sys.argv[1:]:
+ > data = file(path, 'rb').read()
+ > data = data.replace('\n', '\r')
+ > file(path, 'wb').write(data)
+ > EOF
+ $ cat > print.py <<EOF
+ > import sys
+ > print(sys.stdin.read().replace('\n', '<LF>').replace('\r', '<CR>').replace('\0', '<NUL>'))
+ > EOF
+ $ hg init
+ $ echo '[hooks]' >> .hg/hgrc
+ $ echo 'pretxncommit.cr = python:hgext.win32text.forbidcr' >> .hg/hgrc
+ $ echo 'pretxnchangegroup.cr = python:hgext.win32text.forbidcr' >> .hg/hgrc
+ $ cat .hg/hgrc
+ [hooks]
+ pretxncommit.cr = python:hgext.win32text.forbidcr
+ pretxnchangegroup.cr = python:hgext.win32text.forbidcr
+
+ $ echo hello > f
+ $ hg add f
+ $ hg ci -m 1
+
+ $ python unix2mac.py f
+ $ hg ci -m 2
+ attempt to commit or push text file(s) using CR line endings
+ in dea860dc51ec: f
+ transaction abort!
+ rollback completed
+ abort: pretxncommit.cr hook failed
+ [255]
+ $ hg cat f | python print.py
+ hello<LF>
+ $ cat f | python print.py
+ hello<CR>
diff --git a/tests/test-manifest-merging.t b/tests/test-manifest-merging.t
new file mode 100644
index 0000000..aa91cf0
--- /dev/null
+++ b/tests/test-manifest-merging.t
@@ -0,0 +1,37 @@
+ $ hg init base
+
+ $ cd base
+ $ echo 'alpha' > alpha
+ $ hg ci -A -m 'add alpha'
+ adding alpha
+ $ cd ..
+
+ $ hg clone base work
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd work
+ $ echo 'beta' > beta
+ $ hg ci -A -m 'add beta'
+ adding beta
+ $ cd ..
+
+ $ cd base
+ $ echo 'gamma' > gamma
+ $ hg ci -A -m 'add gamma'
+ adding gamma
+ $ cd ..
+
+ $ cd work
+ $ hg pull -q
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+Update --clean to revision 1 to simulate a failed merge:
+
+ $ rm alpha beta gamma
+ $ hg update --clean 1
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd ..
diff --git a/tests/test-manifest.t b/tests/test-manifest.t
new file mode 100644
index 0000000..f334b23
--- /dev/null
+++ b/tests/test-manifest.t
@@ -0,0 +1,69 @@
+Source bundle was generated with the following script:
+
+# hg init
+# echo a > a
+# ln -s a l
+# hg ci -Ama -d'0 0'
+# mkdir b
+# echo a > b/a
+# chmod +x b/a
+# hg ci -Amb -d'1 0'
+
+ $ hg init
+ $ hg -q pull "$TESTDIR/bundles/test-manifest.hg"
+
+The next call is expected to return nothing:
+
+ $ hg manifest
+
+ $ hg co
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg manifest
+ a
+ b/a
+ l
+
+ $ hg manifest -v
+ 644 a
+ 755 * b/a
+ 644 @ l
+
+ $ hg manifest --debug
+ b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 a
+ b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 755 * b/a
+ 047b75c6d7a3ef6a2243bd0e99f94f6ea6683597 644 @ l
+
+ $ hg manifest -r 0
+ a
+ l
+
+ $ hg manifest -r 1
+ a
+ b/a
+ l
+
+ $ hg manifest -r tip
+ a
+ b/a
+ l
+
+ $ hg manifest tip
+ a
+ b/a
+ l
+
+ $ hg manifest --all
+ a
+ b/a
+ l
+
+The next two calls are expected to abort:
+
+ $ hg manifest -r 2
+ abort: unknown revision '2'!
+ [255]
+
+ $ hg manifest -r tip tip
+ abort: please specify just one revision
+ [255]
diff --git a/tests/test-merge-closedheads.t b/tests/test-merge-closedheads.t
new file mode 100644
index 0000000..ad78c1e
--- /dev/null
+++ b/tests/test-merge-closedheads.t
@@ -0,0 +1,87 @@
+ $ hgcommit() {
+ > hg commit -u user "$@"
+ > }
+
+ $ hg init clhead
+ $ cd clhead
+
+ $ touch foo && hg add && hgcommit -m 'foo'
+ adding foo
+ $ touch bar && hg add && hgcommit -m 'bar'
+ adding bar
+ $ touch baz && hg add && hgcommit -m 'baz'
+ adding baz
+
+ $ echo "flub" > foo
+ $ hgcommit -m "flub"
+ $ echo "nub" > foo
+ $ hgcommit -m "nub"
+
+ $ hg up -C 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo "c1" > c1
+ $ hg add c1
+ $ hgcommit -m "c1"
+ created new head
+ $ echo "c2" > c1
+ $ hgcommit -m "c2"
+
+ $ hg up -C 2
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ echo "d1" > d1
+ $ hg add d1
+ $ hgcommit -m "d1"
+ created new head
+ $ echo "d2" > d1
+ $ hgcommit -m "d2"
+ $ hg tag -l good
+
+fail with three heads
+ $ hg up -C good
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge
+ abort: branch 'default' has 3 heads - please merge with an explicit rev
+ (run 'hg heads .' to see heads)
+ [255]
+
+close one of the heads
+ $ hg up -C 6
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hgcommit -m 'close this head' --close-branch
+
+succeed with two open heads
+ $ hg up -C good
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg up -C good
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hgcommit -m 'merged heads'
+
+hg update -C 8
+ $ hg update -C 8
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+hg branch some-branch
+ $ hg branch some-branch
+ marked working directory as branch some-branch
+ (branches are permanent and global, did you want a bookmark?)
+hg commit
+ $ hgcommit -m 'started some-branch'
+hg commit --close-branch
+ $ hgcommit --close-branch -m 'closed some-branch'
+
+hg update default
+ $ hg update default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+hg merge some-branch
+ $ hg merge some-branch
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+hg commit (no reopening of some-branch)
+ $ hgcommit -m 'merge with closed branch'
+
+ $ cd ..
diff --git a/tests/test-merge-commit.t b/tests/test-merge-commit.t
new file mode 100644
index 0000000..23a6e16
--- /dev/null
+++ b/tests/test-merge-commit.t
@@ -0,0 +1,184 @@
+Check that renames are correctly saved by a commit after a merge
+
+Test with the merge on 3 having the rename on the local parent
+
+ $ hg init a
+ $ cd a
+
+ $ echo line1 > foo
+ $ hg add foo
+ $ hg ci -m '0: add foo'
+
+ $ echo line2 >> foo
+ $ hg ci -m '1: change foo'
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg mv foo bar
+ $ rm bar
+ $ echo line0 > bar
+ $ echo line1 >> bar
+ $ hg ci -m '2: mv foo bar; change bar'
+ created new head
+
+ $ hg merge 1
+ merging bar and foo to bar
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cat bar
+ line0
+ line1
+ line2
+
+ $ hg ci -m '3: merge with local rename'
+
+ $ hg debugindex bar
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 77 ..... 2 d35118874825 000000000000 000000000000 (re)
+ 1 77 76 ..... 3 5345f5ab8abd 000000000000 d35118874825 (re)
+
+ $ hg debugrename bar
+ bar renamed from foo:9e25c27b87571a1edee5ae4dddee5687746cc8e2
+
+ $ hg debugindex foo
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 7 ..... 0 690b295714ae 000000000000 000000000000 (re)
+ 1 7 13 ..... 1 9e25c27b8757 690b295714ae 000000000000 (re)
+
+
+Revert the content change from rev 2:
+
+ $ hg up -C 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm bar
+ $ echo line1 > bar
+ $ hg ci -m '4: revert content change from rev 2'
+ created new head
+
+ $ hg log --template '{rev}:{node|short} {parents}\n'
+ 4:2263c1be0967 2:0f2ff26688b9
+ 3:0555950ead28 2:0f2ff26688b9 1:5cd961e4045d
+ 2:0f2ff26688b9 0:2665aaee66e9
+ 1:5cd961e4045d
+ 0:2665aaee66e9
+
+This should use bar@rev2 as the ancestor:
+
+ $ hg --debug merge 3
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 0f2ff26688b9, local: 2263c1be0967+, remote: 0555950ead28
+ bar: versions differ -> m
+ preserving bar for resolve of bar
+ updating: bar 1/1 files (100.00%)
+ picked tool 'internal:merge' for bar (binary False symlink False)
+ merging bar
+ my bar@2263c1be0967+ other bar@0555950ead28 ancestor bar@0f2ff26688b9
+ premerge successful
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cat bar
+ line1
+ line2
+
+ $ hg ci -m '5: merge'
+
+ $ hg debugindex bar
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 77 ..... 2 d35118874825 000000000000 000000000000 (re)
+ 1 77 76 ..... 3 5345f5ab8abd 000000000000 d35118874825 (re)
+ 2 153 7 ..... 4 ff4b45017382 d35118874825 000000000000 (re)
+ 3 160 13 ..... 5 3701b4893544 ff4b45017382 5345f5ab8abd (re)
+
+
+Same thing, but with the merge on 3 having the rename
+on the remote parent:
+
+ $ cd ..
+ $ hg clone -U -r 1 -r 2 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 2 files (+1 heads)
+ $ cd b
+
+ $ hg up -C 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg merge 2
+ merging foo and bar to bar
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cat bar
+ line0
+ line1
+ line2
+
+ $ hg ci -m '3: merge with remote rename'
+
+ $ hg debugindex bar
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 77 ..... 2 d35118874825 000000000000 000000000000 (re)
+ 1 77 76 ..... 3 5345f5ab8abd 000000000000 d35118874825 (re)
+
+ $ hg debugrename bar
+ bar renamed from foo:9e25c27b87571a1edee5ae4dddee5687746cc8e2
+
+ $ hg debugindex foo
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 7 ..... 0 690b295714ae 000000000000 000000000000 (re)
+ 1 7 13 ..... 1 9e25c27b8757 690b295714ae 000000000000 (re)
+
+
+Revert the content change from rev 2:
+
+ $ hg up -C 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm bar
+ $ echo line1 > bar
+ $ hg ci -m '4: revert content change from rev 2'
+ created new head
+
+ $ hg log --template '{rev}:{node|short} {parents}\n'
+ 4:2263c1be0967 2:0f2ff26688b9
+ 3:3ffa6b9e35f0 1:5cd961e4045d 2:0f2ff26688b9
+ 2:0f2ff26688b9 0:2665aaee66e9
+ 1:5cd961e4045d
+ 0:2665aaee66e9
+
+This should use bar@rev2 as the ancestor:
+
+ $ hg --debug merge 3
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 0f2ff26688b9, local: 2263c1be0967+, remote: 3ffa6b9e35f0
+ bar: versions differ -> m
+ preserving bar for resolve of bar
+ updating: bar 1/1 files (100.00%)
+ picked tool 'internal:merge' for bar (binary False symlink False)
+ merging bar
+ my bar@2263c1be0967+ other bar@3ffa6b9e35f0 ancestor bar@0f2ff26688b9
+ premerge successful
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cat bar
+ line1
+ line2
+
+ $ hg ci -m '5: merge'
+
+ $ hg debugindex bar
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 77 ..... 2 d35118874825 000000000000 000000000000 (re)
+ 1 77 76 ..... 3 5345f5ab8abd 000000000000 d35118874825 (re)
+ 2 153 7 ..... 4 ff4b45017382 d35118874825 000000000000 (re)
+ 3 160 13 ..... 5 3701b4893544 ff4b45017382 5345f5ab8abd (re)
+
+ $ cd ..
diff --git a/tests/test-merge-default.t b/tests/test-merge-default.t
new file mode 100644
index 0000000..64f64d3
--- /dev/null
+++ b/tests/test-merge-default.t
@@ -0,0 +1,111 @@
+ $ hg init
+ $ echo a > a
+ $ hg commit -A -ma
+ adding a
+
+ $ echo b >> a
+ $ hg commit -mb
+
+ $ echo c >> a
+ $ hg commit -mc
+
+ $ hg up 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo d >> a
+ $ hg commit -md
+ created new head
+
+ $ hg up 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo e >> a
+ $ hg commit -me
+ created new head
+
+ $ hg up 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Should fail because not at a head:
+
+ $ hg merge
+ abort: branch 'default' has 3 heads - please merge with an explicit rev
+ (run 'hg heads .' to see heads)
+ [255]
+
+ $ hg up
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Should fail because > 2 heads:
+
+ $ HGMERGE=internal:other; export HGMERGE
+ $ hg merge
+ abort: branch 'default' has 3 heads - please merge with an explicit rev
+ (run 'hg heads .' to see heads)
+ [255]
+
+Should succeed:
+
+ $ hg merge 2
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -mm1
+
+Should succeed - 2 heads:
+
+ $ hg merge -P
+ changeset: 3:ea9ff125ff88
+ parent: 1:1846eede8b68
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: d
+
+ $ hg merge
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -mm2
+
+Should fail because at tip:
+
+ $ hg merge
+ abort: nothing to merge
+ [255]
+
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Should fail because there is only one head:
+
+ $ hg merge
+ abort: nothing to merge
+ (use 'hg update' instead)
+ [255]
+
+ $ hg up 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo f >> a
+ $ hg branch foobranch
+ marked working directory as branch foobranch
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg commit -mf
+
+Should fail because merge with other branch:
+
+ $ hg merge
+ abort: branch 'foobranch' has one head - please merge with an explicit rev
+ (run 'hg heads' to see all heads)
+ [255]
+
+
+Test for issue2043: ensure that 'merge -P' shows ancestors of 6 that
+are not ancestors of 7, regardless of where their least common
+ancestor is.
+
+Merge preview not affected by common ancestor:
+
+ $ hg up -q 7
+ $ hg merge -q -P 6
+ 2:2d95304fed5d
+ 4:f25cbe84d8b3
+ 5:a431fabd6039
+ 6:e88e33f3bf62
+
diff --git a/tests/test-merge-force.t b/tests/test-merge-force.t
new file mode 100644
index 0000000..7a13f66
--- /dev/null
+++ b/tests/test-merge-force.t
@@ -0,0 +1,45 @@
+ $ hg init
+
+ $ echo a > a
+ $ hg ci -qAm 'add a'
+
+ $ echo b > b
+ $ hg ci -qAm 'add b'
+
+ $ hg up -qC 0
+ $ hg rm a
+ $ hg ci -m 'rm a'
+ created new head
+
+ $ hg up -qC 1
+ $ rm a
+
+Local deleted a file, remote removed
+
+Should fail, since there are deleted files:
+
+ $ hg merge
+ abort: outstanding uncommitted changes
+ (use 'hg status' to list changes)
+ [255]
+
+Should succeed with --force:
+
+ $ hg -v merge --force
+ resolving manifests
+ removing a
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+Should show 'a' as removed:
+
+ $ hg status
+ R a
+
+ $ hg ci -m merge
+
+Should not show 'a':
+
+ $ hg manifest
+ b
+
diff --git a/tests/test-merge-internal-tools-pattern.t b/tests/test-merge-internal-tools-pattern.t
new file mode 100644
index 0000000..ee4a359
--- /dev/null
+++ b/tests/test-merge-internal-tools-pattern.t
@@ -0,0 +1,112 @@
+Make sure that the internal merge tools (internal:fail, internal:local, and
+internal:other) are used when matched by a merge-pattern in hgrc
+
+Make sure HGMERGE doesn't interfere with the test:
+
+ $ unset HGMERGE
+
+ $ hg init
+
+Initial file contents:
+
+ $ echo "line 1" > f
+ $ echo "line 2" >> f
+ $ echo "line 3" >> f
+ $ hg ci -Am "revision 0"
+ adding f
+
+ $ cat f
+ line 1
+ line 2
+ line 3
+
+Branch 1: editing line 1:
+
+ $ sed 's/line 1/first line/' f > f.new
+ $ mv f.new f
+ $ hg ci -Am "edited first line"
+
+Branch 2: editing line 3:
+
+ $ hg update 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ sed 's/line 3/third line/' f > f.new
+ $ mv f.new f
+ $ hg ci -Am "edited third line"
+ created new head
+
+Merge using internal:fail tool:
+
+ $ echo "[merge-patterns]" > .hg/hgrc
+ $ echo "* = internal:fail" >> .hg/hgrc
+
+ $ hg merge
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+
+ $ cat f
+ line 1
+ line 2
+ third line
+
+ $ hg stat
+ M f
+
+Merge using internal:local tool:
+
+ $ hg update -C 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ sed 's/internal:fail/internal:local/' .hg/hgrc > .hg/hgrc.new
+ $ mv .hg/hgrc.new .hg/hgrc
+
+ $ hg merge
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cat f
+ line 1
+ line 2
+ third line
+
+ $ hg stat
+ M f
+
+Merge using internal:other tool:
+
+ $ hg update -C 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ sed 's/internal:local/internal:other/' .hg/hgrc > .hg/hgrc.new
+ $ mv .hg/hgrc.new .hg/hgrc
+
+ $ hg merge
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cat f
+ first line
+ line 2
+ line 3
+
+ $ hg stat
+ M f
+
+Merge using default tool:
+
+ $ hg update -C 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm .hg/hgrc
+
+ $ hg merge
+ merging f
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cat f
+ first line
+ line 2
+ third line
+
+ $ hg stat
+ M f
+
diff --git a/tests/test-merge-local.t b/tests/test-merge-local.t
new file mode 100644
index 0000000..8e1e5b1
--- /dev/null
+++ b/tests/test-merge-local.t
@@ -0,0 +1,138 @@
+ $ hg init
+
+Revision 0:
+
+ $ echo "unchanged" > unchanged
+ $ echo "remove me" > remove
+ $ echo "copy me" > copy
+ $ echo "move me" > move
+ $ for i in 1 2 3 4 5 6 7 8 9; do
+ > echo "merge ok $i" >> zzz1_merge_ok
+ > done
+ $ echo "merge bad" > zzz2_merge_bad
+ $ hg ci -Am "revision 0"
+ adding copy
+ adding move
+ adding remove
+ adding unchanged
+ adding zzz1_merge_ok
+ adding zzz2_merge_bad
+
+Revision 1:
+
+ $ hg rm remove
+ $ hg mv move moved
+ $ hg cp copy copied
+ $ echo "added" > added
+ $ hg add added
+ $ echo "new first line" > zzz1_merge_ok
+ $ hg cat zzz1_merge_ok >> zzz1_merge_ok
+ $ echo "new last line" >> zzz2_merge_bad
+ $ hg ci -m "revision 1"
+
+Local changes to revision 0:
+
+ $ hg co 0
+ 4 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ echo "new last line" >> zzz1_merge_ok
+ $ echo "another last line" >> zzz2_merge_bad
+
+ $ hg diff --nodates | grep "^[+-][^<>]"
+ --- a/zzz1_merge_ok
+ +++ b/zzz1_merge_ok
+ +new last line
+ --- a/zzz2_merge_bad
+ +++ b/zzz2_merge_bad
+ +another last line
+
+ $ hg st
+ M zzz1_merge_ok
+ M zzz2_merge_bad
+
+Local merge with bad merge tool:
+
+ $ HGMERGE=false hg co
+ merging zzz1_merge_ok
+ merging zzz2_merge_bad
+ merging zzz2_merge_bad failed!
+ 3 files updated, 1 files merged, 2 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges
+ [1]
+
+ $ hg co 0
+ merging zzz1_merge_ok
+ merging zzz2_merge_bad
+ warning: conflicts during merge.
+ merging zzz2_merge_bad incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 2 files updated, 1 files merged, 3 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges
+ [1]
+
+ $ hg diff --nodates | grep "^[+-][^<>]"
+ --- a/zzz1_merge_ok
+ +++ b/zzz1_merge_ok
+ +new last line
+ --- a/zzz2_merge_bad
+ +++ b/zzz2_merge_bad
+ +another last line
+ +=======
+
+ $ hg st
+ M zzz1_merge_ok
+ M zzz2_merge_bad
+ ? zzz2_merge_bad.orig
+
+Local merge with conflicts:
+
+ $ hg co
+ merging zzz1_merge_ok
+ merging zzz2_merge_bad
+ warning: conflicts during merge.
+ merging zzz2_merge_bad incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 3 files updated, 1 files merged, 2 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges
+ [1]
+
+ $ hg co 0
+ merging zzz1_merge_ok
+ merging zzz2_merge_bad
+ warning: conflicts during merge.
+ merging zzz2_merge_bad incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 2 files updated, 1 files merged, 3 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges
+ [1]
+
+ $ hg diff --nodates | grep "^[+-][^<>]"
+ --- a/zzz1_merge_ok
+ +++ b/zzz1_merge_ok
+ +new last line
+ --- a/zzz2_merge_bad
+ +++ b/zzz2_merge_bad
+ +another last line
+ +=======
+ +=======
+ +new last line
+ +=======
+
+ $ hg st
+ M zzz1_merge_ok
+ M zzz2_merge_bad
+ ? zzz2_merge_bad.orig
+
+Local merge without conflicts:
+
+ $ hg revert zzz2_merge_bad
+
+ $ hg co
+ merging zzz1_merge_ok
+ 4 files updated, 1 files merged, 2 files removed, 0 files unresolved
+
+ $ hg diff --nodates | grep "^[+-][^<>]"
+ --- a/zzz1_merge_ok
+ +++ b/zzz1_merge_ok
+ +new last line
+
+ $ hg st
+ M zzz1_merge_ok
+ ? zzz2_merge_bad.orig
+
diff --git a/tests/test-merge-prompt.t b/tests/test-merge-prompt.t
new file mode 100644
index 0000000..43f39c2
--- /dev/null
+++ b/tests/test-merge-prompt.t
@@ -0,0 +1,142 @@
+Test for
+b5605d88dc27: Make ui.prompt repeat on "unrecognized response" again
+ (issue897)
+
+840e2b315c1f: Fix misleading error and prompts during update/merge
+ (issue556)
+
+ $ status() {
+ > echo "--- status ---"
+ > hg st -A file1 file2
+ > for file in file1 file2; do
+ > if [ -f $file ]; then
+ > echo "--- $file ---"
+ > cat $file
+ > else
+ > echo "*** $file does not exist"
+ > fi
+ > done
+ > }
+
+ $ hg init
+
+ $ echo 1 > file1
+ $ echo 2 > file2
+ $ hg ci -Am 'added file1 and file2'
+ adding file1
+ adding file2
+
+ $ hg rm file1
+ $ echo changed >> file2
+ $ hg ci -m 'removed file1, changed file2'
+
+ $ hg co 0
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo changed >> file1
+ $ hg rm file2
+ $ hg ci -m 'changed file1, removed file2'
+ created new head
+
+
+Non-interactive merge:
+
+ $ hg merge -y
+ local changed file1 which remote deleted
+ use (c)hanged version or (d)elete? c
+ remote changed file2 which local deleted
+ use (c)hanged version or leave (d)eleted? c
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ status
+ --- status ---
+ M file2
+ C file1
+ --- file1 ---
+ 1
+ changed
+ --- file2 ---
+ 2
+ changed
+
+
+Interactive merge:
+
+ $ hg co -C
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ hg merge --config ui.interactive=true <<EOF
+ > c
+ > d
+ > EOF
+ local changed file1 which remote deleted
+ use (c)hanged version or (d)elete? remote changed file2 which local deleted
+ use (c)hanged version or leave (d)eleted? 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ status
+ --- status ---
+ file2: * (glob)
+ C file1
+ --- file1 ---
+ 1
+ changed
+ *** file2 does not exist
+
+
+Interactive merge with bad input:
+
+ $ hg co -C
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg merge --config ui.interactive=true <<EOF
+ > foo
+ > bar
+ > d
+ > baz
+ > c
+ > EOF
+ local changed file1 which remote deleted
+ use (c)hanged version or (d)elete? unrecognized response
+ local changed file1 which remote deleted
+ use (c)hanged version or (d)elete? unrecognized response
+ local changed file1 which remote deleted
+ use (c)hanged version or (d)elete? remote changed file2 which local deleted
+ use (c)hanged version or leave (d)eleted? unrecognized response
+ remote changed file2 which local deleted
+ use (c)hanged version or leave (d)eleted? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ status
+ --- status ---
+ M file2
+ R file1
+ *** file1 does not exist
+ --- file2 ---
+ 2
+ changed
+
+
+Interactive merge with not enough input:
+
+ $ hg co -C
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ hg merge --config ui.interactive=true <<EOF
+ > d
+ > EOF
+ local changed file1 which remote deleted
+ use (c)hanged version or (d)elete? remote changed file2 which local deleted
+ use (c)hanged version or leave (d)eleted? abort: response expected
+ [255]
+
+ $ status
+ --- status ---
+ file2: * (glob)
+ C file1
+ --- file1 ---
+ 1
+ changed
+ *** file2 does not exist
+
diff --git a/tests/test-merge-remove.t b/tests/test-merge-remove.t
new file mode 100644
index 0000000..d30f86f
--- /dev/null
+++ b/tests/test-merge-remove.t
@@ -0,0 +1,87 @@
+ $ hg init
+
+ $ echo foo > foo
+ $ echo bar > bar
+ $ hg ci -qAm 'add foo bar'
+
+ $ echo foo2 >> foo
+ $ echo bleh > bar
+ $ hg ci -m 'change foo bar'
+
+ $ hg up -qC 0
+ $ hg mv foo foo1
+ $ echo foo1 > foo1
+ $ hg cat foo >> foo1
+ $ hg ci -m 'mv foo foo1'
+ created new head
+
+ $ hg merge
+ merging foo1 and foo to foo1
+ 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg debugstate --nodates
+ n 0 -2 bar
+ m 644 14 foo1
+ copy: foo -> foo1
+
+ $ hg st -q
+ M bar
+ M foo1
+
+
+Removing foo1 and bar:
+
+ $ cp foo1 F
+ $ cp bar B
+ $ hg rm -f foo1 bar
+
+ $ hg debugstate --nodates
+ r 0 -2 bar
+ r 0 -1 foo1
+ copy: foo -> foo1
+
+ $ hg st -qC
+ R bar
+ R foo1
+
+
+Re-adding foo1 and bar:
+
+ $ cp F foo1
+ $ cp B bar
+ $ hg add -v foo1 bar
+ adding bar
+ adding foo1
+
+ $ hg debugstate --nodates
+ n 0 -2 bar
+ m 644 14 foo1
+ copy: foo -> foo1
+
+ $ hg st -qC
+ M bar
+ M foo1
+ foo
+
+
+Reverting foo1 and bar:
+
+ $ hg revert -vr . foo1 bar
+ saving current version of bar as bar.orig
+ reverting bar
+ saving current version of foo1 as foo1.orig
+ reverting foo1
+
+ $ hg debugstate --nodates
+ n 0 -2 bar
+ m 644 14 foo1
+ copy: foo -> foo1
+
+ $ hg st -qC
+ M bar
+ M foo1
+ foo
+
+ $ hg diff
+
diff --git a/tests/test-merge-revert.t b/tests/test-merge-revert.t
new file mode 100644
index 0000000..991699b
--- /dev/null
+++ b/tests/test-merge-revert.t
@@ -0,0 +1,74 @@
+ $ hg init
+
+ $ echo "added file1" > file1
+ $ echo "added file2" > file2
+ $ hg add file1 file2
+ $ hg commit -m "added file1 and file2"
+
+ $ echo "changed file1" >> file1
+ $ hg commit -m "changed file1"
+
+ $ hg -q log
+ 1:08a16e8e4408
+ 0:d29c767a4b52
+ $ hg id
+ 08a16e8e4408 tip
+
+ $ hg update -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ d29c767a4b52
+ $ echo "changed file1" >> file1
+ $ hg id
+ d29c767a4b52+
+
+ $ hg revert --all
+ reverting file1
+ $ hg diff
+ $ hg status
+ ? file1.orig
+ $ hg id
+ d29c767a4b52
+
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg diff
+ $ hg status
+ ? file1.orig
+ $ hg id
+ 08a16e8e4408 tip
+
+ $ hg update -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo "changed file1" >> file1
+
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg diff
+ $ hg status
+ ? file1.orig
+ $ hg id
+ 08a16e8e4408 tip
+
+ $ hg revert --all
+ $ hg diff
+ $ hg status
+ ? file1.orig
+ $ hg id
+ 08a16e8e4408 tip
+
+ $ hg revert -r tip --all
+ $ hg diff
+ $ hg status
+ ? file1.orig
+ $ hg id
+ 08a16e8e4408 tip
+
+ $ hg update -C
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg diff
+ $ hg status
+ ? file1.orig
+ $ hg id
+ 08a16e8e4408 tip
+
diff --git a/tests/test-merge-revert2.t b/tests/test-merge-revert2.t
new file mode 100644
index 0000000..4025e56
--- /dev/null
+++ b/tests/test-merge-revert2.t
@@ -0,0 +1,94 @@
+ $ hg init
+
+ $ echo "added file1" > file1
+ $ echo "another line of text" >> file1
+ $ echo "added file2" > file2
+ $ hg add file1 file2
+ $ hg commit -m "added file1 and file2"
+
+ $ echo "changed file1" >> file1
+ $ hg commit -m "changed file1"
+
+ $ hg -q log
+ 1:dfab7f3c2efb
+ 0:c3fa057dd86f
+ $ hg id
+ dfab7f3c2efb tip
+
+ $ hg update -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ c3fa057dd86f
+
+ $ echo "changed file1" >> file1
+ $ hg id
+ c3fa057dd86f+
+
+ $ hg revert --no-backup --all
+ reverting file1
+ $ hg diff
+ $ hg status
+ $ hg id
+ c3fa057dd86f
+
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg diff
+ $ hg status
+ $ hg id
+ dfab7f3c2efb tip
+
+ $ hg update -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo "changed file1 different" >> file1
+
+ $ hg update
+ merging file1
+ warning: conflicts during merge.
+ merging file1 incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges
+ [1]
+
+ $ hg diff --nodates
+ diff -r dfab7f3c2efb file1
+ --- a/file1
+ +++ b/file1
+ @@ -1,3 +1,7 @@
+ added file1
+ another line of text
+ +<<<<<<< local
+ +changed file1 different
+ +=======
+ changed file1
+ +>>>>>>> other
+
+ $ hg status
+ M file1
+ ? file1.orig
+ $ hg id
+ dfab7f3c2efb+ tip
+
+ $ hg revert --no-backup --all
+ reverting file1
+ $ hg diff
+ $ hg status
+ ? file1.orig
+ $ hg id
+ dfab7f3c2efb tip
+
+ $ hg revert -r tip --no-backup --all
+ $ hg diff
+ $ hg status
+ ? file1.orig
+ $ hg id
+ dfab7f3c2efb tip
+
+ $ hg update -C
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg diff
+ $ hg status
+ ? file1.orig
+ $ hg id
+ dfab7f3c2efb tip
+
diff --git a/tests/test-merge-subrepos.t b/tests/test-merge-subrepos.t
new file mode 100644
index 0000000..2bff401
--- /dev/null
+++ b/tests/test-merge-subrepos.t
@@ -0,0 +1,25 @@
+ $ hg init
+
+ $ echo a > a
+ $ hg ci -qAm 'add a'
+
+ $ hg init subrepo
+ $ echo 'subrepo = http://example.net/libfoo' > .hgsub
+ $ hg ci -qAm 'added subrepo'
+
+ $ hg up -qC 0
+ $ echo ax > a
+ $ hg ci -m 'changed a'
+ created new head
+
+ $ hg up -qC 1
+ $ cd subrepo
+ $ echo b > b
+ $ hg add b
+ $ cd ..
+
+Should fail, since there are added files to subrepo:
+
+ $ hg merge
+ abort: outstanding uncommitted changes in subrepository 'subrepo'
+ [255]
diff --git a/tests/test-merge-symlinks.t b/tests/test-merge-symlinks.t
new file mode 100644
index 0000000..9d50146
--- /dev/null
+++ b/tests/test-merge-symlinks.t
@@ -0,0 +1,63 @@
+ $ cat > echo.py <<EOF
+ > #!/usr/bin/env python
+ > import os, sys
+ > try:
+ > import msvcrt
+ > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+ > msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
+ > except ImportError:
+ > pass
+ >
+ > for k in ('HG_FILE', 'HG_MY_ISLINK', 'HG_OTHER_ISLINK', 'HG_BASE_ISLINK'):
+ > print k, os.environ[k]
+ > EOF
+
+Create 2 heads containing the same file, once as
+a file, once as a link. Bundle was generated with:
+
+# hg init t
+# cd t
+# echo a > a
+# hg ci -qAm t0 -d '0 0'
+# echo l > l
+# hg ci -qAm t1 -d '1 0'
+# hg up -C 0
+# ln -s a l
+# hg ci -qAm t2 -d '2 0'
+# echo l2 > l2
+# hg ci -qAm t3 -d '3 0'
+
+ $ hg init t
+ $ cd t
+ $ hg -q pull "$TESTDIR/bundles/test-merge-symlinks.hg"
+ $ hg up -C 3
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Merge them and display *_ISLINK vars
+merge heads
+
+ $ hg merge --tool="python ../echo.py"
+ merging l
+ HG_FILE l
+ HG_MY_ISLINK 1
+ HG_OTHER_ISLINK 0
+ HG_BASE_ISLINK 0
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+Test working directory symlink bit calculation wrt copies,
+especially on non-supporting systems.
+merge working directory
+
+ $ hg up -C 2
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg copy l l2
+ $ HGMERGE="python ../echo.py" hg up 3
+ merging l2
+ HG_FILE l2
+ HG_MY_ISLINK 1
+ HG_OTHER_ISLINK 0
+ HG_BASE_ISLINK 0
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+
+ $ cd ..
diff --git a/tests/test-merge-tools.t b/tests/test-merge-tools.t
new file mode 100644
index 0000000..cee56cd
--- /dev/null
+++ b/tests/test-merge-tools.t
@@ -0,0 +1,806 @@
+test merge-tools configuration - mostly exercising filemerge.py
+
+ $ unset HGMERGE # make sure HGMERGE doesn't interfere with the test
+ $ hg init
+
+revision 0
+
+ $ echo "revision 0" > f
+ $ echo "space" >> f
+ $ hg commit -Am "revision 0"
+ adding f
+
+revision 1
+
+ $ echo "revision 1" > f
+ $ echo "space" >> f
+ $ hg commit -Am "revision 1"
+ $ hg update 0 > /dev/null
+
+revision 2
+
+ $ echo "revision 2" > f
+ $ echo "space" >> f
+ $ hg commit -Am "revision 2"
+ created new head
+ $ hg update 0 > /dev/null
+
+revision 3 - simple to merge
+
+ $ echo "revision 3" >> f
+ $ hg commit -Am "revision 3"
+ created new head
+ $ echo "[merge-tools]" > .hg/hgrc
+
+ $ beforemerge() {
+ > cat .hg/hgrc
+ > echo "# hg update -C 1"
+ > hg update -C 1 > /dev/null
+ > }
+ $ aftermerge() {
+ > echo "# cat f"
+ > cat f
+ > echo "# hg stat"
+ > hg stat
+ > rm -f f.orig
+ > }
+
+Tool selection
+
+default is internal merge:
+
+ $ beforemerge
+ [merge-tools]
+ # hg update -C 1
+
+hg merge -r 2
+override $PATH to ensure hgmerge not visible; use $PYTHON in case we're
+running from a devel copy, not a temp installation
+
+ $ PATH="$BINDIR" $PYTHON "$BINDIR"/hg merge -r 2
+ merging f
+ warning: conflicts during merge.
+ merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ <<<<<<< local
+ revision 1
+ =======
+ revision 2
+ >>>>>>> other
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+simplest hgrc using false for merge:
+
+ $ echo "false.whatever=" >> .hg/hgrc
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ # hg update -C 1
+ $ hg merge -r 2
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+unexecutable file in $PATH shouldn't be found:
+
+ $ touch false
+ $ hg up -qC 1
+ $ PATH="`pwd`:$BINDIR" $PYTHON "$BINDIR"/hg merge -r 2
+ merging f
+ warning: conflicts during merge.
+ merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ rm false
+
+executable directory in $PATH shouldn't be found:
+
+ $ mkdir false
+ $ hg up -qC 1
+ $ PATH="`pwd`:$BINDIR" $PYTHON "$BINDIR"/hg merge -r 2
+ merging f
+ warning: conflicts during merge.
+ merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ rmdir false
+
+true with higher .priority gets precedence:
+
+ $ echo "true.priority=1" >> .hg/hgrc
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ # hg update -C 1
+ $ hg merge -r 2
+ merging f
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+
+unless lowered on command line:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-tools.true.priority=-7
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+or false set higher on command line:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-tools.false.priority=117
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+or true.executable not found in PATH:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-tools.true.executable=nonexistingmergetool
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+or true.executable with bogus path:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-tools.true.executable=/nonexisting/mergetool
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+but true.executable set to cat found in PATH works:
+
+ $ echo "true.executable=cat" >> .hg/hgrc
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2
+ merging f
+ revision 1
+ space
+ revision 0
+ space
+ revision 2
+ space
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+
+and true.executable set to cat with path works:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-tools.true.executable=cat
+ merging f
+ revision 1
+ space
+ revision 0
+ space
+ revision 2
+ space
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+
+#if unix-permissions
+
+environment variables in true.executable are handled:
+
+ $ echo 'echo "custom merge tool"' > "$HGTMP/merge.sh"
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg --config merge-tools.true.executable='sh' \
+ > --config merge-tools.true.args="$HGTMP/merge.sh" \
+ > merge -r 2
+ merging f
+ custom merge tool
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+
+#endif
+
+Tool selection and merge-patterns
+
+merge-patterns specifies new tool false:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-patterns.f=false
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+merge-patterns specifies executable not found in PATH and gets warning:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-patterns.f=true --config merge-tools.true.executable=nonexistingmergetool
+ couldn't find merge tool true specified for f
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+merge-patterns specifies executable with bogus path and gets warning:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-patterns.f=true --config merge-tools.true.executable=/nonexisting/mergetool
+ couldn't find merge tool true specified for f
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+ui.merge overrules priority
+
+ui.merge specifies false:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config ui.merge=false
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+ui.merge specifies internal:fail:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config ui.merge=internal:fail
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+
+ui.merge specifies internal:local:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config ui.merge=internal:local
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+
+ui.merge specifies internal:other:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config ui.merge=internal:other
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ revision 2
+ space
+ # hg stat
+ M f
+
+ui.merge specifies internal:prompt:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config ui.merge=internal:prompt
+ no tool found to merge f
+ keep (l)ocal or take (o)ther? l
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+
+ui.merge specifies internal:dump:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config ui.merge=internal:dump
+ merging f
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.base
+ ? f.local
+ ? f.orig
+ ? f.other
+
+f.base:
+
+ $ cat f.base
+ revision 0
+ space
+
+f.local:
+
+ $ cat f.local
+ revision 1
+ space
+
+f.other:
+
+ $ cat f.other
+ revision 2
+ space
+ $ rm f.base f.local f.other
+
+ui.merge specifies internal:other but is overruled by pattern for false:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config ui.merge=internal:other --config merge-patterns.f=false
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+Premerge
+
+ui.merge specifies internal:other but is overruled by --tool=false
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config ui.merge=internal:other --tool=false
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+HGMERGE specifies internal:other but is overruled by --tool=false
+
+ $ HGMERGE=internal:other ; export HGMERGE
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --tool=false
+ merging f
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
+
+ $ unset HGMERGE # make sure HGMERGE doesn't interfere with remaining tests
+
+Default is silent simplemerge:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 3
+ merging f
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ revision 3
+ # hg stat
+ M f
+
+.premerge=True is same:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 3 --config merge-tools.true.premerge=True
+ merging f
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ revision 3
+ # hg stat
+ M f
+
+.premerge=False executes merge-tool:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 3 --config merge-tools.true.premerge=False
+ merging f
+ revision 1
+ space
+ revision 0
+ space
+ revision 0
+ space
+ revision 3
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+
+Tool execution
+
+set tools.args explicit to include $base $local $other $output:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-tools.true.executable=head --config merge-tools.true.args='$base $local $other $output' \
+ > | sed 's,==> .* <==,==> ... <==,g'
+ merging f
+ ==> ... <==
+ revision 0
+ space
+
+ ==> ... <==
+ revision 1
+ space
+
+ ==> ... <==
+ revision 2
+ space
+
+ ==> ... <==
+ revision 1
+ space
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+
+Merge with "echo mergeresult > $local":
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-tools.true.executable=echo --config merge-tools.true.args='mergeresult > $local'
+ merging f
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ mergeresult
+ # hg stat
+ M f
+
+- and $local is the file f:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-tools.true.executable=echo --config merge-tools.true.args='mergeresult > f'
+ merging f
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ mergeresult
+ # hg stat
+ M f
+
+Merge with "echo mergeresult > $output" - the variable is a bit magic:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -r 2 --config merge-tools.true.executable=echo --config merge-tools.true.args='mergeresult > $output'
+ merging f
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ aftermerge
+ # cat f
+ mergeresult
+ # hg stat
+ M f
+
+Merge using tool with a path that must be quoted:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ cat <<EOF > 'my merge tool'
+ > cat "\$1" "\$2" "\$3" > "\$4"
+ > EOF
+ $ hg --config merge-tools.true.executable='sh' \
+ > --config merge-tools.true.args='"./my merge tool" $base $local $other $output' \
+ > merge -r 2
+ merging f
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ rm -f 'my merge tool'
+ $ aftermerge
+ # cat f
+ revision 0
+ space
+ revision 1
+ space
+ revision 2
+ space
+ # hg stat
+ M f
+
+Merge post-processing
+
+cat is a bad merge-tool and doesn't change:
+
+ $ beforemerge
+ [merge-tools]
+ false.whatever=
+ true.priority=1
+ true.executable=cat
+ # hg update -C 1
+ $ hg merge -y -r 2 --config merge-tools.true.checkchanged=1
+ merging f
+ revision 1
+ space
+ revision 0
+ space
+ revision 2
+ space
+ output file f appears unchanged
+ was merge successful (yn)? n
+ merging f failed!
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ aftermerge
+ # cat f
+ revision 1
+ space
+ # hg stat
+ M f
+ ? f.orig
diff --git a/tests/test-merge-types.t b/tests/test-merge-types.t
new file mode 100644
index 0000000..c51a029
--- /dev/null
+++ b/tests/test-merge-types.t
@@ -0,0 +1,110 @@
+ $ "$TESTDIR/hghave" symlink execbit || exit 80
+
+ $ hg init
+
+ $ echo a > a
+ $ hg ci -Amadd
+ adding a
+
+ $ chmod +x a
+ $ hg ci -mexecutable
+
+ $ hg up 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm a
+ $ ln -s symlink a
+ $ hg ci -msymlink
+ created new head
+
+ $ hg merge --debug
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: c334dc3be0da, local: 521a1e40188f+, remote: 3574f3e69b1c
+ conflicting flags for a
+ (n)one, e(x)ec or sym(l)ink? n
+ a: update permissions -> e
+ updating: a 1/1 files (100.00%)
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+
+Symlink is local parent, executable is other:
+
+ $ if [ -h a ]; then
+ > echo a is a symlink
+ > $TESTDIR/readlink.py a
+ > elif [ -x a ]; then
+ > echo a is executable
+ > else
+ > echo "a has no flags (default for conflicts)"
+ > fi
+ a has no flags (default for conflicts)
+
+ $ hg update -C 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg merge --debug
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: c334dc3be0da, local: 3574f3e69b1c+, remote: 521a1e40188f
+ conflicting flags for a
+ (n)one, e(x)ec or sym(l)ink? n
+ a: remote is newer -> g
+ updating: a 1/1 files (100.00%)
+ getting a
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+
+Symlink is other parent, executable is local:
+
+ $ if [ -h a ]; then
+ > echo a is a symlink
+ > $TESTDIR/readlink.py a
+ > elif [ -x a ]; then
+ > echo a is executable
+ > else
+ > echo "a has no flags (default for conflicts)"
+ > fi
+ a has no flags (default for conflicts)
+
+Update to link without local change should get us a symlink (issue3316):
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg up
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg st
+
+Update to link with local change should cause a merge prompt (issue3200):
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo data > a
+ $ HGMERGE= hg up -y --debug
+ searching for copies back to rev 2
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: c334dc3be0da, local: c334dc3be0da+, remote: 521a1e40188f
+ a: versions differ -> m
+ preserving a for resolve of a
+ updating: a 1/1 files (100.00%)
+ (couldn't find merge tool hgmerge|tool hgmerge can't handle symlinks) (re)
+ picked tool 'internal:prompt' for a (binary False symlink True)
+ no tool found to merge a
+ keep (l)ocal or take (o)ther? l
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ $ hg diff --git
+ diff --git a/a b/a
+ old mode 120000
+ new mode 100644
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,1 @@
+ -symlink
+ \ No newline at end of file
+ +data
+
+
diff --git a/tests/test-merge1.t b/tests/test-merge1.t
new file mode 100644
index 0000000..e0303c9
--- /dev/null
+++ b/tests/test-merge1.t
@@ -0,0 +1,176 @@
+ $ cat <<EOF > merge
+ > import sys, os
+ >
+ > try:
+ > import msvcrt
+ > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+ > msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
+ > except ImportError:
+ > pass
+ >
+ > print "merging for", os.path.basename(sys.argv[1])
+ > EOF
+ $ HGMERGE="python ../merge"; export HGMERGE
+
+ $ hg init t
+ $ cd t
+ $ echo This is file a1 > a
+ $ hg add a
+ $ hg commit -m "commit #0"
+ $ echo This is file b1 > b
+ $ hg add b
+ $ hg commit -m "commit #1"
+
+ $ hg update 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo This is file c1 > c
+ $ hg add c
+ $ hg commit -m "commit #2"
+ created new head
+ $ echo This is file b1 > b
+no merges expected
+ $ hg merge -P 1
+ changeset: 1:b8bb4a988f25
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: commit #1
+
+ $ hg merge 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg diff --nodates
+ diff -r 49035e18a8e6 b
+ --- /dev/null
+ +++ b/b
+ @@ -0,0 +1,1 @@
+ +This is file b1
+ $ hg status
+ M b
+ $ cd ..; rm -r t
+
+ $ hg init t
+ $ cd t
+ $ echo This is file a1 > a
+ $ hg add a
+ $ hg commit -m "commit #0"
+ $ echo This is file b1 > b
+ $ hg add b
+ $ hg commit -m "commit #1"
+
+ $ hg update 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo This is file c1 > c
+ $ hg add c
+ $ hg commit -m "commit #2"
+ created new head
+ $ echo This is file b2 > b
+merge should fail
+ $ hg merge 1
+ b: untracked file differs
+ abort: untracked files in working directory differ from files in requested revision
+ [255]
+merge of b expected
+ $ hg merge -f 1
+ merging b
+ merging for b
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg diff --nodates
+ diff -r 49035e18a8e6 b
+ --- /dev/null
+ +++ b/b
+ @@ -0,0 +1,1 @@
+ +This is file b2
+ $ hg status
+ M b
+ $ cd ..; rm -r t
+
+ $ hg init t
+ $ cd t
+ $ echo This is file a1 > a
+ $ hg add a
+ $ hg commit -m "commit #0"
+ $ echo This is file b1 > b
+ $ hg add b
+ $ hg commit -m "commit #1"
+ $ echo This is file b22 > b
+ $ hg commit -m "commit #2"
+ $ hg update 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo This is file c1 > c
+ $ hg add c
+ $ hg commit -m "commit #3"
+ created new head
+
+Contents of b should be "this is file b1"
+ $ cat b
+ This is file b1
+
+ $ echo This is file b22 > b
+merge fails
+ $ hg merge 2
+ abort: outstanding uncommitted changes
+ (use 'hg status' to list changes)
+ [255]
+merge expected!
+ $ hg merge -f 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg diff --nodates
+ diff -r 85de557015a8 b
+ --- a/b
+ +++ b/b
+ @@ -1,1 +1,1 @@
+ -This is file b1
+ +This is file b22
+ $ hg status
+ M b
+ $ cd ..; rm -r t
+
+ $ hg init t
+ $ cd t
+ $ echo This is file a1 > a
+ $ hg add a
+ $ hg commit -m "commit #0"
+ $ echo This is file b1 > b
+ $ hg add b
+ $ hg commit -m "commit #1"
+ $ echo This is file b22 > b
+ $ hg commit -m "commit #2"
+ $ hg update 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo This is file c1 > c
+ $ hg add c
+ $ hg commit -m "commit #3"
+ created new head
+ $ echo This is file b33 > b
+merge of b should fail
+ $ hg merge 2
+ abort: outstanding uncommitted changes
+ (use 'hg status' to list changes)
+ [255]
+merge of b expected
+ $ hg merge -f 2
+ merging b
+ merging for b
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg diff --nodates
+ diff -r 85de557015a8 b
+ --- a/b
+ +++ b/b
+ @@ -1,1 +1,1 @@
+ -This is file b1
+ +This is file b33
+ $ hg status
+ M b
+
+Test for issue2364
+
+ $ hg up -qC .
+ $ hg rm b
+ $ hg ci -md
+ $ hg revert -r -2 b
+ $ hg up -q -- -2
+
+ $ cd ..
diff --git a/tests/test-merge10.t b/tests/test-merge10.t
new file mode 100644
index 0000000..0ac57f4
--- /dev/null
+++ b/tests/test-merge10.t
@@ -0,0 +1,53 @@
+Test for changeset 9fe267f77f56ff127cf7e65dc15dd9de71ce8ceb
+(merge correctly when all the files in a directory are moved
+but then local changes are added in the same directory)
+
+ $ hg init a
+ $ cd a
+ $ mkdir -p testdir
+ $ echo a > testdir/a
+ $ hg add testdir/a
+ $ hg commit -m a
+ $ cd ..
+
+ $ hg clone a b
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd a
+ $ echo alpha > testdir/a
+ $ hg commit -m remote-change
+ $ cd ..
+
+ $ cd b
+ $ mkdir testdir/subdir
+ $ hg mv testdir/a testdir/subdir/a
+ $ hg commit -m move
+ $ mkdir newdir
+ $ echo beta > newdir/beta
+ $ hg add newdir/beta
+ $ hg commit -m local-addition
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up -C 2
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge
+ merging testdir/subdir/a and testdir/a to testdir/subdir/a
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg stat
+ M testdir/subdir/a
+ $ hg diff --nodates
+ diff -r bc21c9773bfa testdir/subdir/a
+ --- a/testdir/subdir/a
+ +++ b/testdir/subdir/a
+ @@ -1,1 +1,1 @@
+ -a
+ +alpha
+
+ $ cd ..
diff --git a/tests/test-merge2.t b/tests/test-merge2.t
new file mode 100644
index 0000000..4b6d566
--- /dev/null
+++ b/tests/test-merge2.t
@@ -0,0 +1,53 @@
+ $ hg init t
+ $ cd t
+ $ echo This is file a1 > a
+ $ hg add a
+ $ hg commit -m "commit #0"
+ $ echo This is file b1 > b
+ $ hg add b
+ $ hg commit -m "commit #1"
+ $ rm b
+ $ hg update 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo This is file b2 > b
+ $ hg add b
+ $ hg commit -m "commit #2"
+ created new head
+ $ cd ..; rm -r t
+
+ $ mkdir t
+ $ cd t
+ $ hg init
+ $ echo This is file a1 > a
+ $ hg add a
+ $ hg commit -m "commit #0"
+ $ echo This is file b1 > b
+ $ hg add b
+ $ hg commit -m "commit #1"
+ $ rm b
+ $ hg update 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo This is file b2 > b
+ $ hg commit -A -m "commit #2"
+ adding b
+ created new head
+ $ cd ..; rm -r t
+
+ $ hg init t
+ $ cd t
+ $ echo This is file a1 > a
+ $ hg add a
+ $ hg commit -m "commit #0"
+ $ echo This is file b1 > b
+ $ hg add b
+ $ hg commit -m "commit #1"
+ $ rm b
+ $ hg remove b
+ $ hg update 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo This is file b2 > b
+ $ hg commit -A -m "commit #2"
+ adding b
+ created new head
+
+ $ cd ..
diff --git a/tests/test-merge4.t b/tests/test-merge4.t
new file mode 100644
index 0000000..d0c27d1
--- /dev/null
+++ b/tests/test-merge4.t
@@ -0,0 +1,25 @@
+ $ hg init
+ $ echo This is file a1 > a
+ $ hg add a
+ $ hg commit -m "commit #0"
+ $ echo This is file b1 > b
+ $ hg add b
+ $ hg commit -m "commit #1"
+ $ hg update 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo This is file c1 > c
+ $ hg add c
+ $ hg commit -m "commit #2"
+ created new head
+ $ hg merge 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ rm b
+ $ echo This is file c22 > c
+
+Test hg behaves when committing with a missing file added by a merge
+
+ $ hg commit -m "commit #3"
+ abort: cannot commit merge with missing files
+ [255]
+
diff --git a/tests/test-merge5.t b/tests/test-merge5.t
new file mode 100644
index 0000000..fbc89b6
--- /dev/null
+++ b/tests/test-merge5.t
@@ -0,0 +1,37 @@
+ $ hg init
+ $ echo This is file a1 > a
+ $ echo This is file b1 > b
+ $ hg add a b
+ $ hg commit -m "commit #0"
+ $ echo This is file b22 > b
+ $ hg commit -m "comment #1"
+ $ hg update 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm b
+ $ hg commit -A -m "comment #2"
+ removing b
+ created new head
+ $ hg update 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg update
+ abort: crosses branches (merge branches or update --check to force update)
+ [255]
+ $ hg update -c
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mv a c
+
+In theory, we shouldn't need the "-y" below, but it prevents this test
+from hanging when "hg update" erroneously prompts the user for "keep
+or delete".
+
+Should abort:
+
+ $ hg update -y 1
+ abort: crosses branches (merge branches or use --clean to discard changes)
+ [255]
+ $ mv c a
+
+Should succeed:
+
+ $ hg update -y 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
diff --git a/tests/test-merge6.t b/tests/test-merge6.t
new file mode 100644
index 0000000..8aee05e
--- /dev/null
+++ b/tests/test-merge6.t
@@ -0,0 +1,70 @@
+ $ cat <<EOF > merge
+ > import sys, os
+ > print "merging for", os.path.basename(sys.argv[1])
+ > EOF
+ $ HGMERGE="python ../merge"; export HGMERGE
+
+ $ hg init A1
+ $ cd A1
+ $ echo This is file foo1 > foo
+ $ echo This is file bar1 > bar
+ $ hg add foo bar
+ $ hg commit -m "commit text"
+
+ $ cd ..
+ $ hg clone A1 B1
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd A1
+ $ rm bar
+ $ hg remove bar
+ $ hg commit -m "commit test"
+
+ $ cd ../B1
+ $ echo This is file foo22 > foo
+ $ hg commit -m "commit test"
+
+ $ cd ..
+ $ hg clone A1 A2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg clone B1 B2
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd A1
+ $ hg pull ../B1
+ pulling from ../B1
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -m "commit test"
+bar should remain deleted.
+ $ hg manifest --debug
+ f9b0e817f6a48de3564c6b2957687c5e7297c5a0 644 foo
+
+ $ cd ../B2
+ $ hg pull ../A2
+ pulling from ../A2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 0 changes to 0 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg merge
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -m "commit test"
+bar should remain deleted.
+ $ hg manifest --debug
+ f9b0e817f6a48de3564c6b2957687c5e7297c5a0 644 foo
+
+ $ cd ..
diff --git a/tests/test-merge7.t b/tests/test-merge7.t
new file mode 100644
index 0000000..10eed9a
--- /dev/null
+++ b/tests/test-merge7.t
@@ -0,0 +1,147 @@
+initial
+ $ hg init test-a
+ $ cd test-a
+ $ cat >test.txt <<"EOF"
+ > 1
+ > 2
+ > 3
+ > EOF
+ $ hg add test.txt
+ $ hg commit -m "Initial"
+
+clone
+ $ cd ..
+ $ hg clone test-a test-b
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+change test-a
+ $ cd test-a
+ $ cat >test.txt <<"EOF"
+ > one
+ > two
+ > three
+ > EOF
+ $ hg commit -m "Numbers as words"
+
+change test-b
+ $ cd ../test-b
+ $ cat >test.txt <<"EOF"
+ > 1
+ > 2.5
+ > 3
+ > EOF
+ $ hg commit -m "2 -> 2.5"
+
+now pull and merge from test-a
+ $ hg pull ../test-a
+ pulling from ../test-a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg merge
+ merging test.txt
+ warning: conflicts during merge.
+ merging test.txt incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+resolve conflict
+ $ cat >test.txt <<"EOF"
+ > one
+ > two-point-five
+ > three
+ > EOF
+ $ rm -f *.orig
+ $ hg resolve -m test.txt
+ $ hg commit -m "Merge 1"
+
+change test-a again
+ $ cd ../test-a
+ $ cat >test.txt <<"EOF"
+ > one
+ > two-point-one
+ > three
+ > EOF
+ $ hg commit -m "two -> two-point-one"
+
+pull and merge from test-a again
+ $ cd ../test-b
+ $ hg pull ../test-a
+ pulling from ../test-a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg merge --debug
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 96b70246a118, local: 50c3a7e29886+, remote: 40d11a4173a8
+ test.txt: versions differ -> m
+ preserving test.txt for resolve of test.txt
+ updating: test.txt 1/1 files (100.00%)
+ picked tool 'internal:merge' for test.txt (binary False symlink False)
+ merging test.txt
+ my test.txt@50c3a7e29886+ other test.txt@40d11a4173a8 ancestor test.txt@96b70246a118
+ warning: conflicts during merge.
+ merging test.txt incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+
+ $ cat test.txt
+ one
+ <<<<<<< local
+ two-point-five
+ =======
+ two-point-one
+ >>>>>>> other
+ three
+
+ $ hg debugindex test.txt
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 7 ..... 0 01365c4cca56 000000000000 000000000000 (re)
+ 1 7 9 ..... 1 7b013192566a 01365c4cca56 000000000000 (re)
+ 2 16 15 ..... 2 8fe46a3eb557 01365c4cca56 000000000000 (re)
+ 3 31 2. ..... 3 fc3148072371 7b013192566a 8fe46a3eb557 (re)
+ 4 5. 25 ..... 4 d40249267ae3 8fe46a3eb557 000000000000 (re)
+
+ $ hg log
+ changeset: 4:40d11a4173a8
+ tag: tip
+ parent: 2:96b70246a118
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: two -> two-point-one
+
+ changeset: 3:50c3a7e29886
+ parent: 1:d1e159716d41
+ parent: 2:96b70246a118
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Merge 1
+
+ changeset: 2:96b70246a118
+ parent: 0:b1832b9d912a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Numbers as words
+
+ changeset: 1:d1e159716d41
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2 -> 2.5
+
+ changeset: 0:b1832b9d912a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Initial
+
+
+ $ cd ..
diff --git a/tests/test-merge8.t b/tests/test-merge8.t
new file mode 100644
index 0000000..9a3a2cd
--- /dev/null
+++ b/tests/test-merge8.t
@@ -0,0 +1,29 @@
+Test for changeset ba7c74081861
+(update dirstate correctly for non-branchmerge updates)
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m a
+ $ cd ..
+ $ hg clone a b
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd a
+ $ hg mv a b
+ $ hg commit -m move
+ $ echo b >> b
+ $ hg commit -m b
+ $ cd ../b
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg update
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ cd ..
diff --git a/tests/test-merge9.t b/tests/test-merge9.t
new file mode 100644
index 0000000..85e06f0
--- /dev/null
+++ b/tests/test-merge9.t
@@ -0,0 +1,94 @@
+test that we don't interrupt the merge session if
+a file-level merge failed
+
+ $ hg init repo
+ $ cd repo
+
+ $ echo foo > foo
+ $ echo a > bar
+ $ hg ci -Am 'add foo'
+ adding bar
+ adding foo
+
+ $ hg mv foo baz
+ $ echo b >> bar
+ $ echo quux > quux1
+ $ hg ci -Am 'mv foo baz'
+ adding quux1
+
+ $ hg up -qC 0
+ $ echo >> foo
+ $ echo c >> bar
+ $ echo quux > quux2
+ $ hg ci -Am 'change foo'
+ adding quux2
+ created new head
+
+test with the rename on the remote side
+ $ HGMERGE=false hg merge
+ merging bar
+ merging bar failed!
+ merging foo and baz to baz
+ 1 files updated, 1 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ hg resolve -l
+ U bar
+ R baz
+
+test with the rename on the local side
+ $ hg up -C 1
+ 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ HGMERGE=false hg merge
+ merging bar
+ merging bar failed!
+ merging baz and foo to baz
+ 1 files updated, 1 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+
+show unresolved
+ $ hg resolve -l
+ U bar
+ R baz
+
+unmark baz
+ $ hg resolve -u baz
+
+show
+ $ hg resolve -l
+ U bar
+ U baz
+ $ hg st
+ M bar
+ M baz
+ M quux2
+ ? bar.orig
+
+re-resolve baz
+ $ hg resolve baz
+ merging baz and foo to baz
+
+after resolve
+ $ hg resolve -l
+ U bar
+ R baz
+
+resolve all warning
+ $ hg resolve
+ abort: no files or directories specified; use --all to remerge all files
+ [255]
+
+resolve all
+ $ hg resolve -a
+ merging bar
+ warning: conflicts during merge.
+ merging bar incomplete! (edit conflicts, then use 'hg resolve --mark')
+ [1]
+
+after
+ $ hg resolve -l
+ U bar
+ R baz
+
+ $ cd ..
diff --git a/tests/test-minirst.py b/tests/test-minirst.py
new file mode 100644
index 0000000..df5fbb6
--- /dev/null
+++ b/tests/test-minirst.py
@@ -0,0 +1,245 @@
+from pprint import pprint
+from mercurial import minirst
+
+def debugformat(text, form, **kwargs):
+ if form == 'html':
+ print "html format:"
+ out = minirst.format(text, style=form, **kwargs)
+ else:
+ print "%d column format:" % form
+ out = minirst.format(text, width=form, **kwargs)
+
+ print "-" * 70
+ if type(out) == tuple:
+ print out[0][:-1]
+ print "-" * 70
+ pprint(out[1])
+ else:
+ print out[:-1]
+ print "-" * 70
+ print
+
+def debugformats(title, text, **kwargs):
+ print "== %s ==" % title
+ debugformat(text, 60, **kwargs)
+ debugformat(text, 30, **kwargs)
+ debugformat(text, 'html', **kwargs)
+
+paragraphs = """
+This is some text in the first paragraph.
+
+ A small indented paragraph.
+ It is followed by some lines
+ containing random whitespace.
+ \n \n \nThe third and final paragraph.
+"""
+
+debugformats('paragraphs', paragraphs)
+
+definitions = """
+A Term
+ Definition. The indented
+ lines make up the definition.
+Another Term
+ Another definition. The final line in the
+ definition determines the indentation, so
+ this will be indented with four spaces.
+
+ A Nested/Indented Term
+ Definition.
+"""
+
+debugformats('definitions', definitions)
+
+literals = r"""
+The fully minimized form is the most
+convenient form::
+
+ Hello
+ literal
+ world
+
+In the partially minimized form a paragraph
+simply ends with space-double-colon. ::
+
+ ////////////////////////////////////////
+ long un-wrapped line in a literal block
+ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
+
+::
+
+ This literal block is started with '::',
+ the so-called expanded form. The paragraph
+ with '::' disappears in the final output.
+"""
+
+debugformats('literals', literals)
+
+lists = """
+- This is the first list item.
+
+ Second paragraph in the first list item.
+
+- List items need not be separated
+ by a blank line.
+- And will be rendered without
+ one in any case.
+
+We can have indented lists:
+
+ - This is an indented list item
+
+ - Another indented list item::
+
+ - A literal block in the middle
+ of an indented list.
+
+ (The above is not a list item since we are in the literal block.)
+
+::
+
+ Literal block with no indentation (apart from
+ the two spaces added to all literal blocks).
+
+1. This is an enumerated list (first item).
+2. Continuing with the second item.
+
+(1) foo
+(2) bar
+
+1) Another
+2) List
+
+Line blocks are also a form of list:
+
+| This is the first line.
+ The line continues here.
+| This is the second line.
+"""
+
+debugformats('lists', lists)
+
+options = """
+There is support for simple option lists,
+but only with long options:
+
+-X, --exclude filter an option with a short and long option with an argument
+-I, --include an option with both a short option and a long option
+--all Output all.
+--both Output both (this description is
+ quite long).
+--long Output all day long.
+
+--par This option has two paragraphs in its description.
+ This is the first.
+
+ This is the second. Blank lines may be omitted between
+ options (as above) or left in (as here).
+
+
+The next paragraph looks like an option list, but lacks the two-space
+marker after the option. It is treated as a normal paragraph:
+
+--foo bar baz
+"""
+
+debugformats('options', options)
+
+fields = """
+:a: First item.
+:ab: Second item. Indentation and wrapping
+ is handled automatically.
+
+Next list:
+
+:small: The larger key below triggers full indentation here.
+:much too large: This key is big enough to get its own line.
+"""
+
+debugformats('fields', fields)
+
+containers = """
+Normal output.
+
+.. container:: debug
+
+ Initial debug output.
+
+.. container:: verbose
+
+ Verbose output.
+
+ .. container:: debug
+
+ Debug output.
+"""
+
+debugformats('containers (normal)', containers)
+debugformats('containers (verbose)', containers, keep=['verbose'])
+debugformats('containers (debug)', containers, keep=['debug'])
+debugformats('containers (verbose debug)', containers,
+ keep=['verbose', 'debug'])
+
+roles = """Please see :hg:`add`."""
+debugformats('roles', roles)
+
+
+sections = """
+Title
+=====
+
+Section
+-------
+
+Subsection
+''''''''''
+
+Markup: ``foo`` and :hg:`help`
+------------------------------
+"""
+debugformats('sections', sections)
+
+
+admonitions = """
+.. note::
+ This is a note
+
+ - Bullet 1
+ - Bullet 2
+
+ .. warning:: This is a warning Second
+ input line of warning
+
+.. danger::
+ This is danger
+"""
+
+debugformats('admonitions', admonitions)
+
+comments = """
+Some text.
+
+.. A comment
+
+ .. An indented comment
+
+ Some indented text.
+
+..
+
+Empty comment above
+"""
+
+debugformats('comments', comments)
+
+
+data = [['a', 'b', 'c'],
+ ['1', '2', '3'],
+ ['foo', 'bar', 'baz this list is very very very long man']]
+
+rst = minirst.maketable(data, 2, True)
+table = ''.join(rst)
+
+print table
+
+debugformats('table', table)
diff --git a/tests/test-minirst.py.out b/tests/test-minirst.py.out
new file mode 100644
index 0000000..c2562ac
--- /dev/null
+++ b/tests/test-minirst.py.out
@@ -0,0 +1,766 @@
+== paragraphs ==
+60 column format:
+----------------------------------------------------------------------
+This is some text in the first paragraph.
+
+ A small indented paragraph. It is followed by some lines
+ containing random whitespace.
+
+The third and final paragraph.
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+This is some text in the first
+paragraph.
+
+ A small indented paragraph.
+ It is followed by some lines
+ containing random
+ whitespace.
+
+The third and final paragraph.
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<p>
+This is some text in the first paragraph.
+</p>
+<p>
+A small indented paragraph.
+It is followed by some lines
+containing random whitespace.
+</p>
+<p>
+The third and final paragraph.
+</p>
+----------------------------------------------------------------------
+
+== definitions ==
+60 column format:
+----------------------------------------------------------------------
+A Term
+ Definition. The indented lines make up the definition.
+
+Another Term
+ Another definition. The final line in the definition
+ determines the indentation, so this will be indented
+ with four spaces.
+
+ A Nested/Indented Term
+ Definition.
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+A Term
+ Definition. The indented
+ lines make up the
+ definition.
+
+Another Term
+ Another definition. The
+ final line in the
+ definition determines the
+ indentation, so this will
+ be indented with four
+ spaces.
+
+ A Nested/Indented Term
+ Definition.
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<dl>
+ <dt>A Term
+ <dd>Definition. The indented lines make up the definition.
+ <dt>Another Term
+ <dd>Another definition. The final line in the definition determines the indentation, so this will be indented with four spaces.
+ <dt>A Nested/Indented Term
+ <dd>Definition.
+</dl>
+----------------------------------------------------------------------
+
+== literals ==
+60 column format:
+----------------------------------------------------------------------
+The fully minimized form is the most convenient form:
+
+ Hello
+ literal
+ world
+
+In the partially minimized form a paragraph simply ends with
+space-double-colon.
+
+ ////////////////////////////////////////
+ long un-wrapped line in a literal block
+ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
+
+ This literal block is started with '::',
+ the so-called expanded form. The paragraph
+ with '::' disappears in the final output.
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+The fully minimized form is
+the most convenient form:
+
+ Hello
+ literal
+ world
+
+In the partially minimized
+form a paragraph simply ends
+with space-double-colon.
+
+ ////////////////////////////////////////
+ long un-wrapped line in a literal block
+ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
+
+ This literal block is started with '::',
+ the so-called expanded form. The paragraph
+ with '::' disappears in the final output.
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<p>
+The fully minimized form is the most
+convenient form:
+</p>
+<pre>
+Hello
+ literal
+ world
+</pre>
+<p>
+In the partially minimized form a paragraph
+simply ends with space-double-colon.
+</p>
+<pre>
+////////////////////////////////////////
+long un-wrapped line in a literal block
+\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
+</pre>
+<pre>
+This literal block is started with '::',
+ the so-called expanded form. The paragraph
+ with '::' disappears in the final output.
+</pre>
+----------------------------------------------------------------------
+
+== lists ==
+60 column format:
+----------------------------------------------------------------------
+- This is the first list item.
+
+ Second paragraph in the first list item.
+
+- List items need not be separated by a blank line.
+- And will be rendered without one in any case.
+
+We can have indented lists:
+
+ - This is an indented list item
+ - Another indented list item:
+
+ - A literal block in the middle
+ of an indented list.
+
+ (The above is not a list item since we are in the literal block.)
+
+ Literal block with no indentation (apart from
+ the two spaces added to all literal blocks).
+
+1. This is an enumerated list (first item).
+2. Continuing with the second item.
+(1) foo
+(2) bar
+1) Another
+2) List
+
+Line blocks are also a form of list:
+
+This is the first line. The line continues here.
+This is the second line.
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+- This is the first list item.
+
+ Second paragraph in the
+ first list item.
+
+- List items need not be
+ separated by a blank line.
+- And will be rendered without
+ one in any case.
+
+We can have indented lists:
+
+ - This is an indented list
+ item
+ - Another indented list
+ item:
+
+ - A literal block in the middle
+ of an indented list.
+
+ (The above is not a list item since we are in the literal block.)
+
+ Literal block with no indentation (apart from
+ the two spaces added to all literal blocks).
+
+1. This is an enumerated list
+ (first item).
+2. Continuing with the second
+ item.
+(1) foo
+(2) bar
+1) Another
+2) List
+
+Line blocks are also a form of
+list:
+
+This is the first line. The
+line continues here.
+This is the second line.
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<ul>
+ <li> This is the first list item.
+<p>
+Second paragraph in the first list item.
+</p>
+ <li> List items need not be separated by a blank line.
+ <li> And will be rendered without one in any case.
+</ul>
+<p>
+We can have indented lists:
+</p>
+<ul>
+ <li> This is an indented list item
+ <li> Another indented list item:
+<pre>
+- A literal block in the middle
+ of an indented list.
+</pre>
+<pre>
+(The above is not a list item since we are in the literal block.)
+</pre>
+</ul>
+<pre>
+Literal block with no indentation (apart from
+the two spaces added to all literal blocks).
+</pre>
+<ol>
+ <li> This is an enumerated list (first item).
+ <li> Continuing with the second item.
+ <li> foo
+ <li> bar
+ <li> Another
+ <li> List
+</ol>
+<p>
+Line blocks are also a form of list:
+</p>
+<ol>
+ <li> This is the first line. The line continues here.
+ <li> This is the second line.
+</ol>
+----------------------------------------------------------------------
+
+== options ==
+60 column format:
+----------------------------------------------------------------------
+There is support for simple option lists, but only with long
+options:
+
+ -X --exclude filter an option with a short and long option
+ with an argument
+ -I --include an option with both a short option and
+ a long option
+ --all Output all.
+ --both Output both (this description is quite
+ long).
+ --long Output all day long.
+ --par This option has two paragraphs in its
+ description. This is the first.
+
+ This is the second. Blank lines may
+ be omitted between options (as above)
+ or left in (as here).
+
+The next paragraph looks like an option list, but lacks the
+two-space marker after the option. It is treated as a normal
+paragraph:
+
+--foo bar baz
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+There is support for simple
+option lists, but only with
+long options:
+
+ -X --exclude filter an
+ option
+ with a
+ short
+ and
+ long
+ option
+ with an
+ argumen
+ t
+ -I --include an
+ option
+ with
+ both a
+ short
+ option
+ and a
+ long
+ option
+ --all Output
+ all.
+ --both Output
+ both
+ (this d
+ escript
+ ion is
+ quite
+ long).
+ --long Output
+ all day
+ long.
+ --par This
+ option
+ has two
+ paragra
+ phs in
+ its des
+ criptio
+ n. This
+ is the
+ first.
+
+ This is
+ the
+ second.
+ Blank
+ lines
+ may be
+ omitted
+ between
+ options
+ (as
+ above)
+ or left
+ in (as
+ here).
+
+The next paragraph looks like
+an option list, but lacks the
+two-space marker after the
+option. It is treated as a
+normal paragraph:
+
+--foo bar baz
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<p>
+There is support for simple option lists,
+but only with long options:
+</p>
+<dl>
+ <dt>-X --exclude filter
+ <dd>an option with a short and long option with an argument
+ <dt>-I --include
+ <dd>an option with both a short option and a long option
+ <dt> --all
+ <dd>Output all.
+ <dt> --both
+ <dd>Output both (this description is quite long).
+ <dt> --long
+ <dd>Output all day long.
+ <dt> --par
+ <dd>This option has two paragraphs in its description. This is the first.
+<p>
+This is the second. Blank lines may be omitted between
+options (as above) or left in (as here).
+</p>
+</dl>
+<p>
+The next paragraph looks like an option list, but lacks the two-space
+marker after the option. It is treated as a normal paragraph:
+</p>
+<p>
+--foo bar baz
+</p>
+----------------------------------------------------------------------
+
+== fields ==
+60 column format:
+----------------------------------------------------------------------
+a First item.
+ab Second item. Indentation and wrapping is
+ handled automatically.
+
+Next list:
+
+small The larger key below triggers full indentation
+ here.
+much too large
+ This key is big enough to get its own line.
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+a First item.
+ab Second item.
+ Indentation and
+ wrapping is
+ handled
+ automatically.
+
+Next list:
+
+small The larger key
+ below triggers
+ full indentation
+ here.
+much too large
+ This key is big
+ enough to get
+ its own line.
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<dl>
+ <dt>a
+ <dd>First item.
+ <dt>ab
+ <dd>Second item. Indentation and wrapping is handled automatically.
+</dl>
+<p>
+Next list:
+</p>
+<dl>
+ <dt>small
+ <dd>The larger key below triggers full indentation here.
+ <dt>much too large
+ <dd>This key is big enough to get its own line.
+</dl>
+----------------------------------------------------------------------
+
+== containers (normal) ==
+60 column format:
+----------------------------------------------------------------------
+Normal output.
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+Normal output.
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<p>
+Normal output.
+</p>
+----------------------------------------------------------------------
+
+== containers (verbose) ==
+60 column format:
+----------------------------------------------------------------------
+Normal output.
+
+Verbose output.
+----------------------------------------------------------------------
+['debug', 'debug']
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+Normal output.
+
+Verbose output.
+----------------------------------------------------------------------
+['debug', 'debug']
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<p>
+Normal output.
+</p>
+<p>
+Verbose output.
+</p>
+----------------------------------------------------------------------
+['debug', 'debug']
+----------------------------------------------------------------------
+
+== containers (debug) ==
+60 column format:
+----------------------------------------------------------------------
+Normal output.
+
+Initial debug output.
+----------------------------------------------------------------------
+['verbose']
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+Normal output.
+
+Initial debug output.
+----------------------------------------------------------------------
+['verbose']
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<p>
+Normal output.
+</p>
+<p>
+Initial debug output.
+</p>
+----------------------------------------------------------------------
+['verbose']
+----------------------------------------------------------------------
+
+== containers (verbose debug) ==
+60 column format:
+----------------------------------------------------------------------
+Normal output.
+
+Initial debug output.
+
+Verbose output.
+
+Debug output.
+----------------------------------------------------------------------
+[]
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+Normal output.
+
+Initial debug output.
+
+Verbose output.
+
+Debug output.
+----------------------------------------------------------------------
+[]
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<p>
+Normal output.
+</p>
+<p>
+Initial debug output.
+</p>
+<p>
+Verbose output.
+</p>
+<p>
+Debug output.
+</p>
+----------------------------------------------------------------------
+[]
+----------------------------------------------------------------------
+
+== roles ==
+60 column format:
+----------------------------------------------------------------------
+Please see "hg add".
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+Please see "hg add".
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<p>
+Please see "hg add".
+</p>
+----------------------------------------------------------------------
+
+== sections ==
+60 column format:
+----------------------------------------------------------------------
+Title
+=====
+
+Section
+-------
+
+Subsection
+''''''''''
+
+Markup: "foo" and "hg help"
+---------------------------
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+Title
+=====
+
+Section
+-------
+
+Subsection
+''''''''''
+
+Markup: "foo" and "hg help"
+---------------------------
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<h1>Title</h1>
+<h2>Section</h2>
+<h3>Subsection</h3>
+<h2>Markup: "foo" and "hg help"</h2>
+----------------------------------------------------------------------
+
+== admonitions ==
+60 column format:
+----------------------------------------------------------------------
+Note:
+ This is a note
+
+ - Bullet 1
+ - Bullet 2
+
+ Warning!
+ This is a warning Second input line of warning
+
+!Danger!
+ This is danger
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+Note:
+ This is a note
+
+ - Bullet 1
+ - Bullet 2
+
+ Warning!
+ This is a warning Second
+ input line of warning
+
+!Danger!
+ This is danger
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<p>
+<b>Note:</b> This is a note
+</p>
+<ul>
+ <li> Bullet 1
+ <li> Bullet 2
+</ul>
+<p>
+<b>Warning!</b> This is a warning Second input line of warning
+</p>
+<p>
+<b>!Danger!</b> This is danger
+</p>
+----------------------------------------------------------------------
+
+== comments ==
+60 column format:
+----------------------------------------------------------------------
+Some text.
+
+ Some indented text.
+
+Empty comment above
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+Some text.
+
+ Some indented text.
+
+Empty comment above
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<p>
+Some text.
+</p>
+<p>
+Some indented text.
+</p>
+<p>
+Empty comment above
+</p>
+----------------------------------------------------------------------
+
+ === === ========================================
+ a b c
+ === === ========================================
+ 1 2 3
+ foo bar baz this list is very very very long man
+ === === ========================================
+
+== table ==
+60 column format:
+----------------------------------------------------------------------
+ a b c
+ ------------------------------------------------
+ 1 2 3
+ foo bar baz this list is very very very long man
+----------------------------------------------------------------------
+
+30 column format:
+----------------------------------------------------------------------
+ a b c
+ ------------------------------
+ 1 2 3
+ foo bar baz this list is
+ very very very long
+ man
+----------------------------------------------------------------------
+
+html format:
+----------------------------------------------------------------------
+<table>
+ <tr><th>a</th><th>b</th><th>c</th></tr>
+ <tr><td>1</td><td>2</td><td>3</td></tr>
+ <tr><td>foo</td><td>bar</td><td>baz this list is very very very long man</td></tr>
+</table>
+----------------------------------------------------------------------
+
diff --git a/tests/test-mq-caches.t b/tests/test-mq-caches.t
new file mode 100644
index 0000000..f74a528
--- /dev/null
+++ b/tests/test-mq-caches.t
@@ -0,0 +1,126 @@
+ $ branches=.hg/cache/branchheads
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo 'mq =' >> $HGRCPATH
+
+ $ show_branch_cache()
+ > {
+ > # force cache (re)generation
+ > hg log -r does-not-exist 2> /dev/null
+ > hg log -r tip --template 'tip: {rev}\n'
+ > if [ -f $branches ]; then
+ > sort $branches
+ > else
+ > echo No branch cache
+ > fi
+ > if [ "$1" = 1 ]; then
+ > for b in foo bar; do
+ > hg log -r $b --template "branch $b: "'{rev}\n'
+ > done
+ > fi
+ > }
+
+ $ hg init a
+ $ cd a
+ $ hg qinit -c
+
+
+mq patch on an empty repo
+
+ $ hg qnew -d '0 0' p1
+ $ show_branch_cache
+ tip: 0
+ No branch cache
+
+ $ echo > pfile
+ $ hg add pfile
+ $ hg qrefresh -m 'patch 1'
+ $ show_branch_cache
+ tip: 0
+ d986d5caac23a7d44a46efc0ddaf5eb9665844cf 0
+ d986d5caac23a7d44a46efc0ddaf5eb9665844cf default
+
+some regular revisions
+
+ $ hg qpop
+ popping p1
+ patch queue now empty
+ $ echo foo > foo
+ $ hg add foo
+ $ echo foo > .hg/branch
+ $ hg ci -m 'branch foo'
+
+ $ echo bar > bar
+ $ hg add bar
+ $ echo bar > .hg/branch
+ $ hg ci -m 'branch bar'
+ $ show_branch_cache
+ tip: 1
+ c229711f16da3d7591f89b1b8d963b79bda22714 1
+ c229711f16da3d7591f89b1b8d963b79bda22714 bar
+ dc25e3827021582e979f600811852e36cbe57341 foo
+
+add some mq patches
+
+ $ hg qpush
+ applying p1
+ now at: p1
+ $ show_branch_cache
+ tip: 2
+ c229711f16da3d7591f89b1b8d963b79bda22714 1
+ c229711f16da3d7591f89b1b8d963b79bda22714 bar
+ dc25e3827021582e979f600811852e36cbe57341 foo
+
+ $ hg qnew -d '0 0' p2
+ $ echo foo > .hg/branch
+ $ echo foo2 >> foo
+ $ hg qrefresh -m 'patch 2'
+ $ show_branch_cache 1
+ tip: 3
+ 982611f6955f9c48d3365decea203217c945ef0d 2
+ 982611f6955f9c48d3365decea203217c945ef0d bar
+ dc25e3827021582e979f600811852e36cbe57341 foo
+ branch foo: 3
+ branch bar: 2
+
+removing the cache
+
+ $ rm $branches
+ $ show_branch_cache 1
+ tip: 3
+ c229711f16da3d7591f89b1b8d963b79bda22714 1
+ c229711f16da3d7591f89b1b8d963b79bda22714 bar
+ dc25e3827021582e979f600811852e36cbe57341 foo
+ branch foo: 3
+ branch bar: 2
+
+importing rev 1 (the cache now ends in one of the patches)
+
+ $ hg qimport -r 1 -n p0
+ $ show_branch_cache 1
+ tip: 3
+ c229711f16da3d7591f89b1b8d963b79bda22714 1
+ c229711f16da3d7591f89b1b8d963b79bda22714 bar
+ dc25e3827021582e979f600811852e36cbe57341 foo
+ branch foo: 3
+ branch bar: 2
+ $ hg log -r qbase --template 'qbase: {rev}\n'
+ qbase: 1
+
+detect an invalid cache
+
+ $ hg qpop -a
+ popping p2
+ popping p1
+ popping p0
+ patch queue now empty
+ $ hg qpush -a
+ applying p0
+ applying p1
+ applying p2
+ now at: p2
+ $ show_branch_cache
+ tip: 3
+ dc25e3827021582e979f600811852e36cbe57341 0
+ dc25e3827021582e979f600811852e36cbe57341 foo
+
+ $ cd ..
diff --git a/tests/test-mq-eol.t b/tests/test-mq-eol.t
new file mode 100644
index 0000000..3566340
--- /dev/null
+++ b/tests/test-mq-eol.t
@@ -0,0 +1,207 @@
+
+Test interactions between mq and patch.eol
+
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "nodates=1" >> $HGRCPATH
+
+ $ cat > makepatch.py <<EOF
+ > f = file('eol.diff', 'wb')
+ > w = f.write
+ > w('test message\n')
+ > w('diff --git a/a b/a\n')
+ > w('--- a/a\n')
+ > w('+++ b/a\n')
+ > w('@@ -1,5 +1,5 @@\n')
+ > w(' a\n')
+ > w('-b\r\n')
+ > w('+y\r\n')
+ > w(' c\r\n')
+ > w(' d\n')
+ > w('-e\n')
+ > w('\ No newline at end of file\n')
+ > w('+z\r\n')
+ > w('\ No newline at end of file\r\n')
+ > EOF
+
+ $ cat > cateol.py <<EOF
+ > import sys
+ > for line in file(sys.argv[1], 'rb'):
+ > line = line.replace('\r', '<CR>')
+ > line = line.replace('\n', '<LF>')
+ > print line
+ > EOF
+
+ $ hg init repo
+ $ cd repo
+ $ echo '\.diff' > .hgignore
+ $ echo '\.rej' >> .hgignore
+
+
+Test different --eol values
+
+ $ python -c 'file("a", "wb").write("a\nb\nc\nd\ne")'
+ $ hg ci -Am adda
+ adding .hgignore
+ adding a
+ $ python ../makepatch.py
+ $ hg qimport eol.diff
+ adding eol.diff to series file
+
+should fail in strict mode
+
+ $ hg qpush
+ applying eol.diff
+ patching file a
+ Hunk #1 FAILED at 0
+ 1 out of 1 hunks FAILED -- saving rejects to file a.rej
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh eol.diff
+ [2]
+ $ hg qpop
+ popping eol.diff
+ patch queue now empty
+
+invalid eol
+
+ $ hg --config patch.eol='LFCR' qpush
+ applying eol.diff
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh eol.diff
+ [2]
+ $ hg qpop
+ popping eol.diff
+ patch queue now empty
+
+force LF
+
+ $ hg --config patch.eol='CRLF' qpush
+ applying eol.diff
+ now at: eol.diff
+ $ hg qrefresh
+ $ python ../cateol.py .hg/patches/eol.diff
+ test message<LF>
+ <LF>
+ diff -r 0d0bf99a8b7a a<LF>
+ --- a/a<LF>
+ +++ b/a<LF>
+ @@ -1,5 +1,5 @@<LF>
+ -a<LF>
+ -b<LF>
+ -c<LF>
+ -d<LF>
+ -e<LF>
+ \ No newline at end of file<LF>
+ +a<CR><LF>
+ +y<CR><LF>
+ +c<CR><LF>
+ +d<CR><LF>
+ +z<LF>
+ \ No newline at end of file<LF>
+ $ python ../cateol.py a
+ a<CR><LF>
+ y<CR><LF>
+ c<CR><LF>
+ d<CR><LF>
+ z
+ $ hg qpop
+ popping eol.diff
+ patch queue now empty
+
+push again forcing LF and compare revisions
+
+ $ hg --config patch.eol='CRLF' qpush
+ applying eol.diff
+ now at: eol.diff
+ $ python ../cateol.py a
+ a<CR><LF>
+ y<CR><LF>
+ c<CR><LF>
+ d<CR><LF>
+ z
+ $ hg qpop
+ popping eol.diff
+ patch queue now empty
+
+push again without LF and compare revisions
+
+ $ hg qpush
+ applying eol.diff
+ now at: eol.diff
+ $ python ../cateol.py a
+ a<CR><LF>
+ y<CR><LF>
+ c<CR><LF>
+ d<CR><LF>
+ z
+ $ hg qpop
+ popping eol.diff
+ patch queue now empty
+ $ cd ..
+
+
+Test .rej file EOL are left unchanged
+
+ $ hg init testeol
+ $ cd testeol
+ $ python -c "file('a', 'wb').write('1\r\n2\r\n3\r\n4')"
+ $ hg ci -Am adda
+ adding a
+ $ python -c "file('a', 'wb').write('1\r\n2\r\n33\r\n4')"
+ $ hg qnew patch1
+ $ hg qpop
+ popping patch1
+ patch queue now empty
+ $ python -c "file('a', 'wb').write('1\r\n22\r\n33\r\n4')"
+ $ hg ci -m changea
+
+ $ hg --config 'patch.eol=LF' qpush
+ applying patch1
+ patching file a
+ Hunk #1 FAILED at 0
+ 1 out of 1 hunks FAILED -- saving rejects to file a.rej
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh patch1
+ [2]
+ $ hg qpop
+ popping patch1
+ patch queue now empty
+ $ cat a.rej
+ --- a
+ +++ a
+ @@ -1,4 +1,4 @@
+ 1\r (esc)
+ 2\r (esc)
+ -3\r (esc)
+ +33\r (esc)
+ 4
+ \ No newline at end of file
+
+ $ hg --config 'patch.eol=auto' qpush
+ applying patch1
+ patching file a
+ Hunk #1 FAILED at 0
+ 1 out of 1 hunks FAILED -- saving rejects to file a.rej
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh patch1
+ [2]
+ $ hg qpop
+ popping patch1
+ patch queue now empty
+ $ cat a.rej
+ --- a
+ +++ a
+ @@ -1,4 +1,4 @@
+ 1\r (esc)
+ 2\r (esc)
+ -3\r (esc)
+ +33\r (esc)
+ 4
+ \ No newline at end of file
+ $ cd ..
diff --git a/tests/test-mq-git.t b/tests/test-mq-git.t
new file mode 100644
index 0000000..f5fcf79
--- /dev/null
+++ b/tests/test-mq-git.t
@@ -0,0 +1,210 @@
+# Test the plumbing of mq.git option
+# Automatic upgrade itself is tested elsewhere.
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "nodates=1" >> $HGRCPATH
+
+ $ hg init repo-auto
+ $ cd repo-auto
+
+git=auto: regular patch creation:
+
+ $ echo a > a
+ $ hg add a
+ $ hg qnew -d '0 0' -f adda
+
+ $ cat .hg/patches/adda
+ # HG changeset patch
+ # Parent 0000000000000000000000000000000000000000
+ # Date 0 0
+
+ diff -r 000000000000 -r ef8dafc9fa4c a
+ --- /dev/null
+ +++ b/a
+ @@ -0,0 +1,1 @@
+ +a
+
+git=auto: git patch creation with copy:
+
+ $ hg cp a b
+ $ hg qnew -d '0 0' -f copy
+
+ $ cat .hg/patches/copy
+ # HG changeset patch
+ # Parent ef8dafc9fa4caff80f6e243eb0171bcd60c455b4
+ # Date 0 0
+
+ diff --git a/a b/b
+ copy from a
+ copy to b
+
+git=auto: git patch when using --git:
+
+ $ echo regular > regular
+ $ hg add regular
+ $ hg qnew -d '0 0' --git -f git
+
+ $ cat .hg/patches/git
+ # HG changeset patch
+ # Parent 99586d5f048c399e20f81cee41fbb3809c0e735d
+ # Date 0 0
+
+ diff --git a/regular b/regular
+ new file mode 100644
+ --- /dev/null
+ +++ b/regular
+ @@ -0,0 +1,1 @@
+ +regular
+
+git=auto: regular patch after qrefresh without --git:
+
+ $ hg qrefresh -d '0 0'
+
+ $ cat .hg/patches/git
+ # HG changeset patch
+ # Parent 99586d5f048c399e20f81cee41fbb3809c0e735d
+ # Date 0 0
+
+ diff -r 99586d5f048c regular
+ --- /dev/null
+ +++ b/regular
+ @@ -0,0 +1,1 @@
+ +regular
+
+ $ cd ..
+
+ $ hg init repo-keep
+ $ cd repo-keep
+ $ echo '[mq]' > .hg/hgrc
+ $ echo 'git = KEEP' >> .hg/hgrc
+
+git=keep: git patch with --git:
+
+ $ echo a > a
+ $ hg add a
+ $ hg qnew -d '0 0' -f --git git
+
+ $ cat .hg/patches/git
+ # HG changeset patch
+ # Parent 0000000000000000000000000000000000000000
+ # Date 0 0
+
+ diff --git a/a b/a
+ new file mode 100644
+ --- /dev/null
+ +++ b/a
+ @@ -0,0 +1,1 @@
+ +a
+
+git=keep: git patch after qrefresh without --git:
+
+ $ echo a >> a
+ $ hg qrefresh -d '0 0'
+
+ $ cat .hg/patches/git
+ # HG changeset patch
+ # Parent 0000000000000000000000000000000000000000
+ # Date 0 0
+
+ diff --git a/a b/a
+ new file mode 100644
+ --- /dev/null
+ +++ b/a
+ @@ -0,0 +1,2 @@
+ +a
+ +a
+ $ cd ..
+
+ $ hg init repo-yes
+ $ cd repo-yes
+ $ echo '[mq]' > .hg/hgrc
+ $ echo 'git = yes' >> .hg/hgrc
+
+git=yes: git patch:
+
+ $ echo a > a
+ $ hg add a
+ $ hg qnew -d '0 0' -f git
+
+ $ cat .hg/patches/git
+ # HG changeset patch
+ # Parent 0000000000000000000000000000000000000000
+ # Date 0 0
+
+ diff --git a/a b/a
+ new file mode 100644
+ --- /dev/null
+ +++ b/a
+ @@ -0,0 +1,1 @@
+ +a
+
+git=yes: git patch after qrefresh:
+
+ $ echo a >> a
+ $ hg qrefresh -d '0 0'
+
+ $ cat .hg/patches/git
+ # HG changeset patch
+ # Parent 0000000000000000000000000000000000000000
+ # Date 0 0
+
+ diff --git a/a b/a
+ new file mode 100644
+ --- /dev/null
+ +++ b/a
+ @@ -0,0 +1,2 @@
+ +a
+ +a
+ $ cd ..
+
+ $ hg init repo-no
+ $ cd repo-no
+ $ echo '[diff]' > .hg/hgrc
+ $ echo 'git = True' >> .hg/hgrc
+ $ echo '[mq]' > .hg/hgrc
+ $ echo 'git = False' >> .hg/hgrc
+
+git=no: regular patch with copy:
+
+ $ echo a > a
+ $ hg add a
+ $ hg qnew -d '0 0' -f adda
+ $ hg cp a b
+ $ hg qnew -d '0 0' -f regular
+
+ $ cat .hg/patches/regular
+ # HG changeset patch
+ # Parent ef8dafc9fa4caff80f6e243eb0171bcd60c455b4
+ # Date 0 0
+
+ diff -r ef8dafc9fa4c -r a70404f79ba3 b
+ --- /dev/null
+ +++ b/b
+ @@ -0,0 +1,1 @@
+ +a
+
+git=no: regular patch after qrefresh with copy:
+
+ $ hg cp a c
+ $ hg qrefresh -d '0 0'
+
+ $ cat .hg/patches/regular
+ # HG changeset patch
+ # Parent ef8dafc9fa4caff80f6e243eb0171bcd60c455b4
+ # Date 0 0
+
+ diff -r ef8dafc9fa4c b
+ --- /dev/null
+ +++ b/b
+ @@ -0,0 +1,1 @@
+ +a
+ diff -r ef8dafc9fa4c c
+ --- /dev/null
+ +++ b/c
+ @@ -0,0 +1,1 @@
+ +a
+
+ $ cd ..
+
diff --git a/tests/test-mq-guards.t b/tests/test-mq-guards.t
new file mode 100644
index 0000000..4ab4ac9
--- /dev/null
+++ b/tests/test-mq-guards.t
@@ -0,0 +1,509 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init
+ $ hg qinit
+
+ $ echo x > x
+ $ hg ci -Ama
+ adding x
+
+ $ hg qnew a.patch
+ $ echo a > a
+ $ hg add a
+ $ hg qrefresh
+
+ $ hg qnew b.patch
+ $ echo b > b
+ $ hg add b
+ $ hg qrefresh
+
+ $ hg qnew c.patch
+ $ echo c > c
+ $ hg add c
+ $ hg qrefresh
+
+ $ hg qpop -a
+ popping c.patch
+ popping b.patch
+ popping a.patch
+ patch queue now empty
+
+
+should fail
+
+ $ hg qguard does-not-exist.patch +bleh
+ abort: no patch named does-not-exist.patch
+ [255]
+
+
+should fail
+
+ $ hg qguard +fail
+ abort: no patches applied
+ [255]
+
+ $ hg qpush
+ applying a.patch
+ now at: a.patch
+
+should guard a.patch
+
+ $ hg qguard +a
+
+should print +a
+
+ $ hg qguard
+ a.patch: +a
+ $ hg qpop
+ popping a.patch
+ patch queue now empty
+
+
+should fail
+
+ $ hg qpush a.patch
+ cannot push 'a.patch' - guarded by '+a'
+ [1]
+
+ $ hg qguard a.patch
+ a.patch: +a
+
+should push b.patch
+
+ $ hg qpush
+ applying b.patch
+ now at: b.patch
+
+ $ hg qpop
+ popping b.patch
+ patch queue now empty
+
+test selection of an empty guard
+
+ $ hg qselect ""
+ abort: guard cannot be an empty string
+ [255]
+ $ hg qselect a
+ number of unguarded, unapplied patches has changed from 2 to 3
+
+should push a.patch
+
+ $ hg qpush
+ applying a.patch
+ now at: a.patch
+
+ $ hg qguard -- c.patch -a
+
+should print -a
+
+ $ hg qguard c.patch
+ c.patch: -a
+
+
+should skip c.patch
+
+ $ hg qpush -a
+ applying b.patch
+ skipping c.patch - guarded by '-a'
+ now at: b.patch
+ $ hg qnext
+ all patches applied
+ [1]
+
+should display b.patch
+
+ $ hg qtop
+ b.patch
+
+ $ hg qguard -n c.patch
+
+should push c.patch
+
+ $ hg qpush -a
+ applying c.patch
+ now at: c.patch
+
+ $ hg qpop -a
+ popping c.patch
+ popping b.patch
+ popping a.patch
+ patch queue now empty
+ $ hg qselect -n
+ guards deactivated
+ number of unguarded, unapplied patches has changed from 3 to 2
+
+should push all
+
+ $ hg qpush -a
+ applying b.patch
+ applying c.patch
+ now at: c.patch
+
+ $ hg qpop -a
+ popping c.patch
+ popping b.patch
+ patch queue now empty
+ $ hg qguard a.patch +1
+ $ hg qguard b.patch +2
+ $ hg qselect 1
+ number of unguarded, unapplied patches has changed from 1 to 2
+
+should push a.patch, not b.patch
+
+ $ hg qpush
+ applying a.patch
+ now at: a.patch
+ $ hg qpush
+ applying c.patch
+ now at: c.patch
+ $ hg qpop -a
+ popping c.patch
+ popping a.patch
+ patch queue now empty
+
+ $ hg qselect 2
+
+should push b.patch
+
+ $ hg qpush
+ applying b.patch
+ now at: b.patch
+ $ hg qpush -a
+ applying c.patch
+ now at: c.patch
+ $ hg qprev
+ b.patch
+
+Used to be an issue with holes in the patch sequence
+So, put one hole on the base and ask for topmost patch.
+
+ $ hg qtop
+ c.patch
+ $ hg qpop -a
+ popping c.patch
+ popping b.patch
+ patch queue now empty
+
+ $ hg qselect 1 2
+ number of unguarded, unapplied patches has changed from 2 to 3
+
+should push a.patch, b.patch
+
+ $ hg qpush
+ applying a.patch
+ now at: a.patch
+ $ hg qpush
+ applying b.patch
+ now at: b.patch
+ $ hg qpop -a
+ popping b.patch
+ popping a.patch
+ patch queue now empty
+
+ $ hg qguard -- a.patch +1 +2 -3
+ $ hg qselect 1 2 3
+ number of unguarded, unapplied patches has changed from 3 to 2
+
+
+list patches and guards
+
+ $ hg qguard -l
+ a.patch: +1 +2 -3
+ b.patch: +2
+ c.patch: unguarded
+
+have at least one patch applied to test coloring
+
+ $ hg qpush
+ applying b.patch
+ now at: b.patch
+
+list patches and guards with color
+
+ $ hg --config extensions.color= qguard --config color.mode=ansi \
+ > -l --color=always
+ \x1b[0;30;1ma.patch\x1b[0m: \x1b[0;33m+1\x1b[0m \x1b[0;33m+2\x1b[0m \x1b[0;31m-3\x1b[0m (esc)
+ \x1b[0;34;1;4mb.patch\x1b[0m: \x1b[0;33m+2\x1b[0m (esc)
+ \x1b[0;30;1mc.patch\x1b[0m: \x1b[0;32munguarded\x1b[0m (esc)
+
+should pop b.patch
+
+ $ hg qpop
+ popping b.patch
+ patch queue now empty
+
+list series
+
+ $ hg qseries -v
+ 0 G a.patch
+ 1 U b.patch
+ 2 U c.patch
+
+list guards
+
+ $ hg qselect
+ 1
+ 2
+ 3
+
+should push b.patch
+
+ $ hg qpush
+ applying b.patch
+ now at: b.patch
+
+ $ hg qpush -a
+ applying c.patch
+ now at: c.patch
+ $ hg qselect -n --reapply
+ guards deactivated
+ popping guarded patches
+ popping c.patch
+ popping b.patch
+ patch queue now empty
+ reapplying unguarded patches
+ applying c.patch
+ now at: c.patch
+
+guards in series file: +1 +2 -3
+
+ $ hg qselect -s
+ +1
+ +2
+ -3
+
+should show c.patch
+
+ $ hg qapplied
+ c.patch
+
+ $ hg qrename a.patch new.patch
+
+should show :
+
+
+new.patch: +1 +2 -3
+
+
+b.patch: +2
+
+
+c.patch: unguarded
+
+ $ hg qguard -l
+ new.patch: +1 +2 -3
+ b.patch: +2
+ c.patch: unguarded
+
+ $ hg qnew d.patch
+ $ hg qpop
+ popping d.patch
+ now at: c.patch
+
+should show new.patch and b.patch as Guarded, c.patch as Applied
+
+
+and d.patch as Unapplied
+
+ $ hg qseries -v
+ 0 G new.patch
+ 1 G b.patch
+ 2 A c.patch
+ 3 U d.patch
+
+qseries again, but with color
+
+ $ hg --config extensions.color= --config color.mode=ansi qseries -v --color=always
+ 0 G \x1b[0;30;1mnew.patch\x1b[0m (esc)
+ 1 G \x1b[0;30;1mb.patch\x1b[0m (esc)
+ 2 A \x1b[0;34;1;4mc.patch\x1b[0m (esc)
+ 3 U \x1b[0;30;1md.patch\x1b[0m (esc)
+
+ $ hg qguard d.patch +2
+
+new.patch, b.patch: Guarded. c.patch: Applied. d.patch: Guarded.
+
+ $ hg qseries -v
+ 0 G new.patch
+ 1 G b.patch
+ 2 A c.patch
+ 3 G d.patch
+
+ $ qappunappv()
+ > {
+ > for command in qapplied "qapplied -v" qunapplied "qunapplied -v"; do
+ > echo % hg $command
+ > hg $command
+ > done
+ > }
+
+ $ hg qpop -a
+ popping c.patch
+ patch queue now empty
+ $ hg qguard -l
+ new.patch: +1 +2 -3
+ b.patch: +2
+ c.patch: unguarded
+ d.patch: +2
+ $ qappunappv
+ % hg qapplied
+ % hg qapplied -v
+ % hg qunapplied
+ c.patch
+ % hg qunapplied -v
+ 0 G new.patch
+ 1 G b.patch
+ 2 U c.patch
+ 3 G d.patch
+ $ hg qselect 1
+ number of unguarded, unapplied patches has changed from 1 to 2
+ $ qappunappv
+ % hg qapplied
+ % hg qapplied -v
+ % hg qunapplied
+ new.patch
+ c.patch
+ % hg qunapplied -v
+ 0 U new.patch
+ 1 G b.patch
+ 2 U c.patch
+ 3 G d.patch
+ $ hg qpush -a
+ applying new.patch
+ skipping b.patch - guarded by '+2'
+ applying c.patch
+ skipping d.patch - guarded by '+2'
+ now at: c.patch
+ $ qappunappv
+ % hg qapplied
+ new.patch
+ c.patch
+ % hg qapplied -v
+ 0 A new.patch
+ 1 G b.patch
+ 2 A c.patch
+ % hg qunapplied
+ % hg qunapplied -v
+ 3 G d.patch
+ $ hg qselect 2
+ number of unguarded, unapplied patches has changed from 0 to 1
+ number of guarded, applied patches has changed from 1 to 0
+ $ qappunappv
+ % hg qapplied
+ new.patch
+ c.patch
+ % hg qapplied -v
+ 0 A new.patch
+ 1 U b.patch
+ 2 A c.patch
+ % hg qunapplied
+ d.patch
+ % hg qunapplied -v
+ 3 U d.patch
+
+ $ for patch in `hg qseries`; do
+ > echo % hg qapplied $patch
+ > hg qapplied $patch
+ > echo % hg qunapplied $patch
+ > hg qunapplied $patch
+ > done
+ % hg qapplied new.patch
+ new.patch
+ % hg qunapplied new.patch
+ b.patch
+ d.patch
+ % hg qapplied b.patch
+ new.patch
+ % hg qunapplied b.patch
+ d.patch
+ % hg qapplied c.patch
+ new.patch
+ c.patch
+ % hg qunapplied c.patch
+ d.patch
+ % hg qapplied d.patch
+ new.patch
+ c.patch
+ % hg qunapplied d.patch
+
+
+hg qseries -m: only b.patch should be shown
+the guards file was not ignored in the past
+
+ $ hg qdelete -k b.patch
+ $ hg qseries -m
+ b.patch
+
+hg qseries -m with color
+
+ $ hg --config extensions.color= --config color.mode=ansi qseries -m --color=always
+ \x1b[0;31;1mb.patch\x1b[0m (esc)
+
+
+excercise cornercases in "qselect --reapply"
+
+ $ hg qpop -a
+ popping c.patch
+ popping new.patch
+ patch queue now empty
+ $ hg qguard -- new.patch -not-new
+ $ hg qguard -- c.patch -not-c
+ $ hg qguard -- d.patch -not-d
+ $ hg qpush -a
+ applying new.patch
+ applying c.patch
+ applying d.patch
+ patch d.patch is empty
+ now at: d.patch
+ $ hg qguard -l
+ new.patch: -not-new
+ c.patch: -not-c
+ d.patch: -not-d
+ $ hg qselect --reapply not-d
+ popping guarded patches
+ popping d.patch
+ now at: c.patch
+ reapplying unguarded patches
+ cannot push 'd.patch' - guarded by '-not-d'
+ $ hg qser -v
+ 0 A new.patch
+ 1 A c.patch
+ 2 G d.patch
+ $ hg qselect --reapply -n
+ guards deactivated
+ $ hg qpush
+ applying d.patch
+ patch d.patch is empty
+ now at: d.patch
+ $ hg qser -v
+ 0 A new.patch
+ 1 A c.patch
+ 2 A d.patch
+ $ hg qselect --reapply not-c
+ popping guarded patches
+ popping d.patch
+ popping c.patch
+ now at: new.patch
+ reapplying unguarded patches
+ applying d.patch
+ patch d.patch is empty
+ now at: d.patch
+ $ hg qser -v
+ 0 A new.patch
+ 1 G c.patch
+ 2 A d.patch
+ $ hg qselect --reapply not-new
+ popping guarded patches
+ popping d.patch
+ popping new.patch
+ patch queue now empty
+ reapplying unguarded patches
+ applying c.patch
+ applying d.patch
+ patch d.patch is empty
+ now at: d.patch
+ $ hg qser -v
+ 0 G new.patch
+ 1 A c.patch
+ 2 A d.patch
diff --git a/tests/test-mq-header-date.t b/tests/test-mq-header-date.t
new file mode 100644
index 0000000..820d511
--- /dev/null
+++ b/tests/test-mq-header-date.t
@@ -0,0 +1,902 @@
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "nodates=true" >> $HGRCPATH
+ $ catpatch() {
+ > cat .hg/patches/$1.patch | sed -e "s/^diff \-r [0-9a-f]* /diff -r ... /" \
+ > -e "s/^\(# Parent \).*/\1/"
+ > }
+ $ catlog() {
+ > catpatch $1
+ > hg log --template "{rev}: {desc} - {author}\n"
+ > }
+ $ catlogd() {
+ > catpatch $1
+ > hg log --template "{rev}: {desc} - {author} - {date}\n"
+ > }
+ $ drop() {
+ > hg qpop
+ > hg qdel $1.patch
+ > }
+ $ runtest() {
+ > echo ==== init
+ > hg init a
+ > cd a
+ > hg qinit
+ >
+ >
+ > echo ==== qnew -d
+ > hg qnew -d '3 0' 1.patch
+ > catlogd 1
+ >
+ > echo ==== qref
+ > echo "1" >1
+ > hg add
+ > hg qref
+ > catlogd 1
+ >
+ > echo ==== qref -d
+ > hg qref -d '4 0'
+ > catlogd 1
+ >
+ >
+ > echo ==== qnew
+ > hg qnew 2.patch
+ > echo "2" >2
+ > hg add
+ > hg qref
+ > catlog 2
+ >
+ > echo ==== qref -d
+ > hg qref -d '5 0'
+ > catlog 2
+ >
+ > drop 2
+ >
+ >
+ > echo ==== qnew -d -m
+ > hg qnew -d '6 0' -m "Three" 3.patch
+ > catlogd 3
+ >
+ > echo ==== qref
+ > echo "3" >3
+ > hg add
+ > hg qref
+ > catlogd 3
+ >
+ > echo ==== qref -m
+ > hg qref -m "Drei"
+ > catlogd 3
+ >
+ > echo ==== qref -d
+ > hg qref -d '7 0'
+ > catlogd 3
+ >
+ > echo ==== qref -d -m
+ > hg qref -d '8 0' -m "Three (again)"
+ > catlogd 3
+ >
+ >
+ > echo ==== qnew -m
+ > hg qnew -m "Four" 4.patch
+ > echo "4" >4
+ > hg add
+ > hg qref
+ > catlog 4
+ >
+ > echo ==== qref -d
+ > hg qref -d '9 0'
+ > catlog 4
+ >
+ > drop 4
+ >
+ >
+ > echo ==== qnew with HG header
+ > hg qnew --config 'mq.plain=true' 5.patch
+ > hg qpop
+ > echo "# HG changeset patch" >>.hg/patches/5.patch
+ > echo "# Date 10 0" >>.hg/patches/5.patch
+ > hg qpush 2>&1 | grep 'Now at'
+ > catlogd 5
+ >
+ > echo ==== hg qref
+ > echo "5" >5
+ > hg add
+ > hg qref
+ > catlogd 5
+ >
+ > echo ==== hg qref -d
+ > hg qref -d '11 0'
+ > catlogd 5
+ >
+ >
+ > echo ==== qnew with plain header
+ > hg qnew --config 'mq.plain=true' -d '12 0' 6.patch
+ > hg qpop
+ > hg qpush 2>&1 | grep 'now at'
+ > catlog 6
+ >
+ > echo ==== hg qref
+ > echo "6" >6
+ > hg add
+ > hg qref
+ > catlogd 6
+ >
+ > echo ==== hg qref -d
+ > hg qref -d '13 0'
+ > catlogd 6
+ >
+ > drop 6
+ >
+ >
+ > echo ==== qnew -u
+ > hg qnew -u jane 6.patch
+ > echo "6" >6
+ > hg add
+ > hg qref
+ > catlog 6
+ >
+ > echo ==== qref -d
+ > hg qref -d '12 0'
+ > catlog 6
+ >
+ > drop 6
+ >
+ >
+ > echo ==== qnew -d
+ > hg qnew -d '13 0' 7.patch
+ > echo "7" >7
+ > hg add
+ > hg qref
+ > catlog 7
+ >
+ > echo ==== qref -u
+ > hg qref -u john
+ > catlogd 7
+ >
+ >
+ > echo ==== qnew
+ > hg qnew 8.patch
+ > echo "8" >8
+ > hg add
+ > hg qref
+ > catlog 8
+ >
+ > echo ==== qref -u -d
+ > hg qref -u john -d '14 0'
+ > catlog 8
+ >
+ > drop 8
+ >
+ >
+ > echo ==== qnew -m
+ > hg qnew -m "Nine" 9.patch
+ > echo "9" >9
+ > hg add
+ > hg qref
+ > catlog 9
+ >
+ > echo ==== qref -u -d
+ > hg qref -u john -d '15 0'
+ > catlog 9
+ >
+ > drop 9
+ >
+ >
+ > echo ==== "qpop -a / qpush -a"
+ > hg qpop -a
+ > hg qpush -a
+ > hg log --template "{rev}: {desc} - {author} - {date}\n"
+ > }
+
+======= plain headers
+
+ $ echo "[mq]" >> $HGRCPATH
+ $ echo "plain=true" >> $HGRCPATH
+ $ mkdir sandbox
+ $ (cd sandbox ; runtest)
+ ==== init
+ ==== qnew -d
+ Date: 3 0
+
+ 0: [mq]: 1.patch - test - 3.00
+ ==== qref
+ adding 1
+ Date: 3 0
+
+ diff -r ... 1
+ --- /dev/null
+ +++ b/1
+ @@ -0,0 +1,1 @@
+ +1
+ 0: [mq]: 1.patch - test - 3.00
+ ==== qref -d
+ Date: 4 0
+
+ diff -r ... 1
+ --- /dev/null
+ +++ b/1
+ @@ -0,0 +1,1 @@
+ +1
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qnew
+ adding 2
+ diff -r ... 2
+ --- /dev/null
+ +++ b/2
+ @@ -0,0 +1,1 @@
+ +2
+ 1: [mq]: 2.patch - test
+ 0: [mq]: 1.patch - test
+ ==== qref -d
+ Date: 5 0
+
+ diff -r ... 2
+ --- /dev/null
+ +++ b/2
+ @@ -0,0 +1,1 @@
+ +2
+ 1: [mq]: 2.patch - test
+ 0: [mq]: 1.patch - test
+ popping 2.patch
+ now at: 1.patch
+ ==== qnew -d -m
+ Date: 6 0
+
+ Three
+
+ 1: Three - test - 6.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qref
+ adding 3
+ Date: 6 0
+
+ Three
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 1: Three - test - 6.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qref -m
+ Date: 6 0
+
+ Drei
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 1: Drei - test - 6.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qref -d
+ Date: 7 0
+
+ Drei
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 1: Drei - test - 7.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qref -d -m
+ Date: 8 0
+
+ Three (again)
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qnew -m
+ adding 4
+ Four
+
+ diff -r ... 4
+ --- /dev/null
+ +++ b/4
+ @@ -0,0 +1,1 @@
+ +4
+ 2: Four - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== qref -d
+ Date: 9 0
+ Four
+
+ diff -r ... 4
+ --- /dev/null
+ +++ b/4
+ @@ -0,0 +1,1 @@
+ +4
+ 2: Four - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ popping 4.patch
+ now at: 3.patch
+ ==== qnew with HG header
+ popping 5.patch
+ now at: 3.patch
+ # HG changeset patch
+ # Date 10 0
+ 2: imported patch 5.patch - test - 10.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== hg qref
+ adding 5
+ # HG changeset patch
+ # Parent
+ # Date 10 0
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 2: [mq]: 5.patch - test - 10.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== hg qref -d
+ # HG changeset patch
+ # Parent
+ # Date 11 0
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 2: [mq]: 5.patch - test - 11.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qnew with plain header
+ popping 6.patch
+ now at: 5.patch
+ now at: 6.patch
+ Date: 12 0
+
+ 3: imported patch 6.patch - test
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== hg qref
+ adding 6
+ Date: 12 0
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 3: [mq]: 6.patch - test - 12.00
+ 2: [mq]: 5.patch - test - 11.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== hg qref -d
+ Date: 13 0
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 3: [mq]: 6.patch - test - 13.00
+ 2: [mq]: 5.patch - test - 11.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ popping 6.patch
+ now at: 5.patch
+ ==== qnew -u
+ adding 6
+ From: jane
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 3: [mq]: 6.patch - jane
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== qref -d
+ Date: 12 0
+ From: jane
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 3: [mq]: 6.patch - jane
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ popping 6.patch
+ now at: 5.patch
+ ==== qnew -d
+ adding 7
+ Date: 13 0
+
+ diff -r ... 7
+ --- /dev/null
+ +++ b/7
+ @@ -0,0 +1,1 @@
+ +7
+ 3: [mq]: 7.patch - test
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== qref -u
+ From: john
+ Date: 13 0
+
+ diff -r ... 7
+ --- /dev/null
+ +++ b/7
+ @@ -0,0 +1,1 @@
+ +7
+ 3: [mq]: 7.patch - john - 13.00
+ 2: [mq]: 5.patch - test - 11.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qnew
+ adding 8
+ diff -r ... 8
+ --- /dev/null
+ +++ b/8
+ @@ -0,0 +1,1 @@
+ +8
+ 4: [mq]: 8.patch - test
+ 3: [mq]: 7.patch - john
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== qref -u -d
+ Date: 14 0
+ From: john
+
+ diff -r ... 8
+ --- /dev/null
+ +++ b/8
+ @@ -0,0 +1,1 @@
+ +8
+ 4: [mq]: 8.patch - john
+ 3: [mq]: 7.patch - john
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ popping 8.patch
+ now at: 7.patch
+ ==== qnew -m
+ adding 9
+ Nine
+
+ diff -r ... 9
+ --- /dev/null
+ +++ b/9
+ @@ -0,0 +1,1 @@
+ +9
+ 4: Nine - test
+ 3: [mq]: 7.patch - john
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== qref -u -d
+ Date: 15 0
+ From: john
+ Nine
+
+ diff -r ... 9
+ --- /dev/null
+ +++ b/9
+ @@ -0,0 +1,1 @@
+ +9
+ 4: Nine - john
+ 3: [mq]: 7.patch - john
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ popping 9.patch
+ now at: 7.patch
+ ==== qpop -a / qpush -a
+ popping 7.patch
+ popping 5.patch
+ popping 3.patch
+ popping 1.patch
+ patch queue now empty
+ applying 1.patch
+ applying 3.patch
+ applying 5.patch
+ applying 7.patch
+ now at: 7.patch
+ 3: imported patch 7.patch - john - 13.00
+ 2: imported patch 5.patch - test - 11.00
+ 1: Three (again) - test - 8.00
+ 0: imported patch 1.patch - test - 4.00
+ $ rm -r sandbox
+
+======= hg headers
+
+ $ echo "plain=false" >> $HGRCPATH
+ $ mkdir sandbox
+ $ (cd sandbox ; runtest)
+ ==== init
+ ==== qnew -d
+ # HG changeset patch
+ # Parent
+ # Date 3 0
+
+ 0: [mq]: 1.patch - test - 3.00
+ ==== qref
+ adding 1
+ # HG changeset patch
+ # Parent
+ # Date 3 0
+
+ diff -r ... 1
+ --- /dev/null
+ +++ b/1
+ @@ -0,0 +1,1 @@
+ +1
+ 0: [mq]: 1.patch - test - 3.00
+ ==== qref -d
+ # HG changeset patch
+ # Parent
+ # Date 4 0
+
+ diff -r ... 1
+ --- /dev/null
+ +++ b/1
+ @@ -0,0 +1,1 @@
+ +1
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qnew
+ adding 2
+ # HG changeset patch
+ # Parent
+
+ diff -r ... 2
+ --- /dev/null
+ +++ b/2
+ @@ -0,0 +1,1 @@
+ +2
+ 1: [mq]: 2.patch - test
+ 0: [mq]: 1.patch - test
+ ==== qref -d
+ # HG changeset patch
+ # Date 5 0
+ # Parent
+
+ diff -r ... 2
+ --- /dev/null
+ +++ b/2
+ @@ -0,0 +1,1 @@
+ +2
+ 1: [mq]: 2.patch - test
+ 0: [mq]: 1.patch - test
+ popping 2.patch
+ now at: 1.patch
+ ==== qnew -d -m
+ # HG changeset patch
+ # Parent
+ # Date 6 0
+
+ Three
+
+ 1: Three - test - 6.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qref
+ adding 3
+ # HG changeset patch
+ # Parent
+ # Date 6 0
+
+ Three
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 1: Three - test - 6.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qref -m
+ # HG changeset patch
+ # Parent
+ # Date 6 0
+
+ Drei
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 1: Drei - test - 6.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qref -d
+ # HG changeset patch
+ # Parent
+ # Date 7 0
+
+ Drei
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 1: Drei - test - 7.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qref -d -m
+ # HG changeset patch
+ # Parent
+ # Date 8 0
+
+ Three (again)
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qnew -m
+ adding 4
+ # HG changeset patch
+ # Parent
+ Four
+
+ diff -r ... 4
+ --- /dev/null
+ +++ b/4
+ @@ -0,0 +1,1 @@
+ +4
+ 2: Four - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== qref -d
+ # HG changeset patch
+ # Date 9 0
+ # Parent
+ Four
+
+ diff -r ... 4
+ --- /dev/null
+ +++ b/4
+ @@ -0,0 +1,1 @@
+ +4
+ 2: Four - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ popping 4.patch
+ now at: 3.patch
+ ==== qnew with HG header
+ popping 5.patch
+ now at: 3.patch
+ # HG changeset patch
+ # Date 10 0
+ 2: imported patch 5.patch - test - 10.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== hg qref
+ adding 5
+ # HG changeset patch
+ # Parent
+ # Date 10 0
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 2: [mq]: 5.patch - test - 10.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== hg qref -d
+ # HG changeset patch
+ # Parent
+ # Date 11 0
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 2: [mq]: 5.patch - test - 11.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qnew with plain header
+ popping 6.patch
+ now at: 5.patch
+ now at: 6.patch
+ Date: 12 0
+
+ 3: imported patch 6.patch - test
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== hg qref
+ adding 6
+ Date: 12 0
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 3: [mq]: 6.patch - test - 12.00
+ 2: [mq]: 5.patch - test - 11.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== hg qref -d
+ Date: 13 0
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 3: [mq]: 6.patch - test - 13.00
+ 2: [mq]: 5.patch - test - 11.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ popping 6.patch
+ now at: 5.patch
+ ==== qnew -u
+ adding 6
+ # HG changeset patch
+ # Parent
+ # User jane
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 3: [mq]: 6.patch - jane
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== qref -d
+ # HG changeset patch
+ # Date 12 0
+ # Parent
+ # User jane
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 3: [mq]: 6.patch - jane
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ popping 6.patch
+ now at: 5.patch
+ ==== qnew -d
+ adding 7
+ # HG changeset patch
+ # Parent
+ # Date 13 0
+
+ diff -r ... 7
+ --- /dev/null
+ +++ b/7
+ @@ -0,0 +1,1 @@
+ +7
+ 3: [mq]: 7.patch - test
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== qref -u
+ # HG changeset patch
+ # User john
+ # Parent
+ # Date 13 0
+
+ diff -r ... 7
+ --- /dev/null
+ +++ b/7
+ @@ -0,0 +1,1 @@
+ +7
+ 3: [mq]: 7.patch - john - 13.00
+ 2: [mq]: 5.patch - test - 11.00
+ 1: Three (again) - test - 8.00
+ 0: [mq]: 1.patch - test - 4.00
+ ==== qnew
+ adding 8
+ # HG changeset patch
+ # Parent
+
+ diff -r ... 8
+ --- /dev/null
+ +++ b/8
+ @@ -0,0 +1,1 @@
+ +8
+ 4: [mq]: 8.patch - test
+ 3: [mq]: 7.patch - john
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== qref -u -d
+ # HG changeset patch
+ # Date 14 0
+ # User john
+ # Parent
+
+ diff -r ... 8
+ --- /dev/null
+ +++ b/8
+ @@ -0,0 +1,1 @@
+ +8
+ 4: [mq]: 8.patch - john
+ 3: [mq]: 7.patch - john
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ popping 8.patch
+ now at: 7.patch
+ ==== qnew -m
+ adding 9
+ # HG changeset patch
+ # Parent
+ Nine
+
+ diff -r ... 9
+ --- /dev/null
+ +++ b/9
+ @@ -0,0 +1,1 @@
+ +9
+ 4: Nine - test
+ 3: [mq]: 7.patch - john
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ ==== qref -u -d
+ # HG changeset patch
+ # Date 15 0
+ # User john
+ # Parent
+ Nine
+
+ diff -r ... 9
+ --- /dev/null
+ +++ b/9
+ @@ -0,0 +1,1 @@
+ +9
+ 4: Nine - john
+ 3: [mq]: 7.patch - john
+ 2: [mq]: 5.patch - test
+ 1: Three (again) - test
+ 0: [mq]: 1.patch - test
+ popping 9.patch
+ now at: 7.patch
+ ==== qpop -a / qpush -a
+ popping 7.patch
+ popping 5.patch
+ popping 3.patch
+ popping 1.patch
+ patch queue now empty
+ applying 1.patch
+ applying 3.patch
+ applying 5.patch
+ applying 7.patch
+ now at: 7.patch
+ 3: imported patch 7.patch - john - 13.00
+ 2: imported patch 5.patch - test - 11.00
+ 1: Three (again) - test - 8.00
+ 0: imported patch 1.patch - test - 4.00
+ $ rm -r sandbox
diff --git a/tests/test-mq-header-from.t b/tests/test-mq-header-from.t
new file mode 100644
index 0000000..64668ec
--- /dev/null
+++ b/tests/test-mq-header-from.t
@@ -0,0 +1,971 @@
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "nodates=true" >> $HGRCPATH
+ $ catlog() {
+ > cat .hg/patches/$1.patch | sed -e "s/^diff \-r [0-9a-f]* /diff -r ... /" \
+ > -e "s/^\(# Parent \).*/\1/"
+ > hg log --template "{rev}: {desc} - {author}\n"
+ > }
+ $ runtest() {
+ > echo ==== init
+ > hg init a
+ > cd a
+ > hg qinit
+ >
+ >
+ > echo ==== qnew -U
+ > hg qnew -U 1.patch
+ > catlog 1
+ >
+ > echo ==== qref
+ > echo "1" >1
+ > hg add
+ > hg qref
+ > catlog 1
+ >
+ > echo ==== qref -u
+ > hg qref -u mary
+ > catlog 1
+ >
+ > echo ==== qnew
+ > hg qnew 2.patch
+ > echo "2" >2
+ > hg add
+ > hg qref
+ > catlog 2
+ >
+ > echo ==== qref -u
+ > hg qref -u jane
+ > catlog 2
+ >
+ >
+ > echo ==== qnew -U -m
+ > hg qnew -U -m "Three" 3.patch
+ > catlog 3
+ >
+ > echo ==== qref
+ > echo "3" >3
+ > hg add
+ > hg qref
+ > catlog 3
+ >
+ > echo ==== qref -m
+ > hg qref -m "Drei"
+ > catlog 3
+ >
+ > echo ==== qref -u
+ > hg qref -u mary
+ > catlog 3
+ >
+ > echo ==== qref -u -m
+ > hg qref -u maria -m "Three (again)"
+ > catlog 3
+ >
+ > echo ==== qnew -m
+ > hg qnew -m "Four" 4.patch
+ > echo "4" >4of t
+ > hg add
+ > hg qref
+ > catlog 4
+ >
+ > echo ==== qref -u
+ > hg qref -u jane
+ > catlog 4
+ >
+ >
+ > echo ==== qnew with HG header
+ > hg qnew --config 'mq.plain=true' 5.patch
+ > hg qpop
+ > echo "# HG changeset patch" >>.hg/patches/5.patch
+ > echo "# User johndoe" >>.hg/patches/5.patch
+ > hg qpush 2>&1 | grep 'now at'
+ > catlog 5
+ >
+ > echo ==== hg qref
+ > echo "5" >5
+ > hg add
+ > hg qref
+ > catlog 5
+ >
+ > echo ==== hg qref -U
+ > hg qref -U
+ > catlog 5
+ >
+ > echo ==== hg qref -u
+ > hg qref -u johndeere
+ > catlog 5
+ >
+ >
+ > echo ==== qnew with plain header
+ > hg qnew --config 'mq.plain=true' -U 6.patch
+ > hg qpop
+ > hg qpush 2>&1 | grep 'now at'
+ > catlog 6
+ >
+ > echo ==== hg qref
+ > echo "6" >6
+ > hg add
+ > hg qref
+ > catlog 6
+ >
+ > echo ==== hg qref -U
+ > hg qref -U
+ > catlog 6
+ >
+ > echo ==== hg qref -u
+ > hg qref -u johndeere
+ > catlog 6
+ >
+ >
+ > echo ==== "qpop -a / qpush -a"
+ > hg qpop -a
+ > hg qpush -a
+ > hg log --template "{rev}: {desc} - {author}\n"
+ > }
+
+======= plain headers
+
+ $ echo "[mq]" >> $HGRCPATH
+ $ echo "plain=true" >> $HGRCPATH
+ $ mkdir sandbox
+ $ (cd sandbox ; runtest)
+ ==== init
+ ==== qnew -U
+ From: test
+
+ 0: [mq]: 1.patch - test
+ ==== qref
+ adding 1
+ From: test
+
+ diff -r ... 1
+ --- /dev/null
+ +++ b/1
+ @@ -0,0 +1,1 @@
+ +1
+ 0: [mq]: 1.patch - test
+ ==== qref -u
+ From: mary
+
+ diff -r ... 1
+ --- /dev/null
+ +++ b/1
+ @@ -0,0 +1,1 @@
+ +1
+ 0: [mq]: 1.patch - mary
+ ==== qnew
+ adding 2
+ diff -r ... 2
+ --- /dev/null
+ +++ b/2
+ @@ -0,0 +1,1 @@
+ +2
+ 1: [mq]: 2.patch - test
+ 0: [mq]: 1.patch - mary
+ ==== qref -u
+ From: jane
+
+ diff -r ... 2
+ --- /dev/null
+ +++ b/2
+ @@ -0,0 +1,1 @@
+ +2
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew -U -m
+ From: test
+
+ Three
+
+ 2: Three - test
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref
+ adding 3
+ From: test
+
+ Three
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Three - test
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -m
+ From: test
+
+ Drei
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Drei - test
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -u
+ From: mary
+
+ Drei
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Drei - mary
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -u -m
+ From: maria
+
+ Three (again)
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew -m
+ adding 4of
+ Four
+
+ diff -r ... 4of
+ --- /dev/null
+ +++ b/4of
+ @@ -0,0 +1,1 @@
+ +4 t
+ 3: Four - test
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -u
+ From: jane
+ Four
+
+ diff -r ... 4of
+ --- /dev/null
+ +++ b/4of
+ @@ -0,0 +1,1 @@
+ +4 t
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew with HG header
+ popping 5.patch
+ now at: 4.patch
+ now at: 5.patch
+ # HG changeset patch
+ # User johndoe
+ 4: imported patch 5.patch - johndoe
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref
+ adding 5
+ # HG changeset patch
+ # Parent
+ # User johndoe
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 4: [mq]: 5.patch - johndoe
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -U
+ # HG changeset patch
+ # Parent
+ # User test
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 4: [mq]: 5.patch - test
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -u
+ # HG changeset patch
+ # Parent
+ # User johndeere
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew with plain header
+ popping 6.patch
+ now at: 5.patch
+ now at: 6.patch
+ From: test
+
+ 5: imported patch 6.patch - test
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref
+ adding 6
+ From: test
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 5: [mq]: 6.patch - test
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -U
+ From: test
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 5: [mq]: 6.patch - test
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -u
+ From: johndeere
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 5: [mq]: 6.patch - johndeere
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qpop -a / qpush -a
+ popping 6.patch
+ popping 5.patch
+ popping 4.patch
+ popping 3.patch
+ popping 2.patch
+ popping 1.patch
+ patch queue now empty
+ applying 1.patch
+ applying 2.patch
+ applying 3.patch
+ applying 4.patch
+ applying 5.patch
+ applying 6.patch
+ now at: 6.patch
+ 5: imported patch 6.patch - johndeere
+ 4: imported patch 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: imported patch 2.patch - jane
+ 0: imported patch 1.patch - mary
+ $ rm -r sandbox
+
+======= hg headers
+
+ $ echo "plain=false" >> $HGRCPATH
+ $ mkdir sandbox
+ $ (cd sandbox ; runtest)
+ ==== init
+ ==== qnew -U
+ # HG changeset patch
+ # Parent
+ # User test
+ 0: [mq]: 1.patch - test
+ ==== qref
+ adding 1
+ # HG changeset patch
+ # Parent
+ # User test
+
+ diff -r ... 1
+ --- /dev/null
+ +++ b/1
+ @@ -0,0 +1,1 @@
+ +1
+ 0: [mq]: 1.patch - test
+ ==== qref -u
+ # HG changeset patch
+ # Parent
+ # User mary
+
+ diff -r ... 1
+ --- /dev/null
+ +++ b/1
+ @@ -0,0 +1,1 @@
+ +1
+ 0: [mq]: 1.patch - mary
+ ==== qnew
+ adding 2
+ # HG changeset patch
+ # Parent
+
+ diff -r ... 2
+ --- /dev/null
+ +++ b/2
+ @@ -0,0 +1,1 @@
+ +2
+ 1: [mq]: 2.patch - test
+ 0: [mq]: 1.patch - mary
+ ==== qref -u
+ # HG changeset patch
+ # User jane
+ # Parent
+
+ diff -r ... 2
+ --- /dev/null
+ +++ b/2
+ @@ -0,0 +1,1 @@
+ +2
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew -U -m
+ # HG changeset patch
+ # Parent
+ # User test
+ Three
+
+ 2: Three - test
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref
+ adding 3
+ # HG changeset patch
+ # Parent
+ # User test
+ Three
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Three - test
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -m
+ # HG changeset patch
+ # Parent
+ # User test
+ Drei
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Drei - test
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -u
+ # HG changeset patch
+ # Parent
+ # User mary
+ Drei
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Drei - mary
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -u -m
+ # HG changeset patch
+ # Parent
+ # User maria
+ Three (again)
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew -m
+ adding 4of
+ # HG changeset patch
+ # Parent
+ Four
+
+ diff -r ... 4of
+ --- /dev/null
+ +++ b/4of
+ @@ -0,0 +1,1 @@
+ +4 t
+ 3: Four - test
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -u
+ # HG changeset patch
+ # User jane
+ # Parent
+ Four
+
+ diff -r ... 4of
+ --- /dev/null
+ +++ b/4of
+ @@ -0,0 +1,1 @@
+ +4 t
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew with HG header
+ popping 5.patch
+ now at: 4.patch
+ now at: 5.patch
+ # HG changeset patch
+ # User johndoe
+ 4: imported patch 5.patch - johndoe
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref
+ adding 5
+ # HG changeset patch
+ # Parent
+ # User johndoe
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 4: [mq]: 5.patch - johndoe
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -U
+ # HG changeset patch
+ # Parent
+ # User test
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 4: [mq]: 5.patch - test
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -u
+ # HG changeset patch
+ # Parent
+ # User johndeere
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew with plain header
+ popping 6.patch
+ now at: 5.patch
+ now at: 6.patch
+ From: test
+
+ 5: imported patch 6.patch - test
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref
+ adding 6
+ From: test
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 5: [mq]: 6.patch - test
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -U
+ From: test
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 5: [mq]: 6.patch - test
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -u
+ From: johndeere
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 5: [mq]: 6.patch - johndeere
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qpop -a / qpush -a
+ popping 6.patch
+ popping 5.patch
+ popping 4.patch
+ popping 3.patch
+ popping 2.patch
+ popping 1.patch
+ patch queue now empty
+ applying 1.patch
+ applying 2.patch
+ applying 3.patch
+ applying 4.patch
+ applying 5.patch
+ applying 6.patch
+ now at: 6.patch
+ 5: imported patch 6.patch - johndeere
+ 4: imported patch 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: imported patch 2.patch - jane
+ 0: imported patch 1.patch - mary
+ $ rm -r sandbox
+ $ runtest
+ ==== init
+ ==== qnew -U
+ # HG changeset patch
+ # Parent
+ # User test
+ 0: [mq]: 1.patch - test
+ ==== qref
+ adding 1
+ # HG changeset patch
+ # Parent
+ # User test
+
+ diff -r ... 1
+ --- /dev/null
+ +++ b/1
+ @@ -0,0 +1,1 @@
+ +1
+ 0: [mq]: 1.patch - test
+ ==== qref -u
+ # HG changeset patch
+ # Parent
+ # User mary
+
+ diff -r ... 1
+ --- /dev/null
+ +++ b/1
+ @@ -0,0 +1,1 @@
+ +1
+ 0: [mq]: 1.patch - mary
+ ==== qnew
+ adding 2
+ # HG changeset patch
+ # Parent
+
+ diff -r ... 2
+ --- /dev/null
+ +++ b/2
+ @@ -0,0 +1,1 @@
+ +2
+ 1: [mq]: 2.patch - test
+ 0: [mq]: 1.patch - mary
+ ==== qref -u
+ # HG changeset patch
+ # User jane
+ # Parent
+
+ diff -r ... 2
+ --- /dev/null
+ +++ b/2
+ @@ -0,0 +1,1 @@
+ +2
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew -U -m
+ # HG changeset patch
+ # Parent
+ # User test
+ Three
+
+ 2: Three - test
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref
+ adding 3
+ # HG changeset patch
+ # Parent
+ # User test
+ Three
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Three - test
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -m
+ # HG changeset patch
+ # Parent
+ # User test
+ Drei
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Drei - test
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -u
+ # HG changeset patch
+ # Parent
+ # User mary
+ Drei
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Drei - mary
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -u -m
+ # HG changeset patch
+ # Parent
+ # User maria
+ Three (again)
+
+ diff -r ... 3
+ --- /dev/null
+ +++ b/3
+ @@ -0,0 +1,1 @@
+ +3
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew -m
+ adding 4of
+ # HG changeset patch
+ # Parent
+ Four
+
+ diff -r ... 4of
+ --- /dev/null
+ +++ b/4of
+ @@ -0,0 +1,1 @@
+ +4 t
+ 3: Four - test
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qref -u
+ # HG changeset patch
+ # User jane
+ # Parent
+ Four
+
+ diff -r ... 4of
+ --- /dev/null
+ +++ b/4of
+ @@ -0,0 +1,1 @@
+ +4 t
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew with HG header
+ popping 5.patch
+ now at: 4.patch
+ now at: 5.patch
+ # HG changeset patch
+ # User johndoe
+ 4: imported patch 5.patch - johndoe
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref
+ adding 5
+ # HG changeset patch
+ # Parent
+ # User johndoe
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 4: [mq]: 5.patch - johndoe
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -U
+ # HG changeset patch
+ # Parent
+ # User test
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 4: [mq]: 5.patch - test
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -u
+ # HG changeset patch
+ # Parent
+ # User johndeere
+
+ diff -r ... 5
+ --- /dev/null
+ +++ b/5
+ @@ -0,0 +1,1 @@
+ +5
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qnew with plain header
+ popping 6.patch
+ now at: 5.patch
+ now at: 6.patch
+ From: test
+
+ 5: imported patch 6.patch - test
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref
+ adding 6
+ From: test
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 5: [mq]: 6.patch - test
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -U
+ From: test
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 5: [mq]: 6.patch - test
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== hg qref -u
+ From: johndeere
+
+ diff -r ... 6
+ --- /dev/null
+ +++ b/6
+ @@ -0,0 +1,1 @@
+ +6
+ 5: [mq]: 6.patch - johndeere
+ 4: [mq]: 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: [mq]: 2.patch - jane
+ 0: [mq]: 1.patch - mary
+ ==== qpop -a / qpush -a
+ popping 6.patch
+ popping 5.patch
+ popping 4.patch
+ popping 3.patch
+ popping 2.patch
+ popping 1.patch
+ patch queue now empty
+ applying 1.patch
+ applying 2.patch
+ applying 3.patch
+ applying 4.patch
+ applying 5.patch
+ applying 6.patch
+ now at: 6.patch
+ 5: imported patch 6.patch - johndeere
+ 4: imported patch 5.patch - johndeere
+ 3: Four - jane
+ 2: Three (again) - maria
+ 1: imported patch 2.patch - jane
+ 0: imported patch 1.patch - mary
+
+ $ cd ..
diff --git a/tests/test-mq-merge.t b/tests/test-mq-merge.t
new file mode 100644
index 0000000..955134a
--- /dev/null
+++ b/tests/test-mq-merge.t
@@ -0,0 +1,173 @@
+Setup extension:
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq =" >> $HGRCPATH
+ $ echo "[mq]" >> $HGRCPATH
+ $ echo "git = keep" >> $HGRCPATH
+
+Test merge with mq changeset as the second parent:
+
+ $ hg init m
+ $ cd m
+ $ touch a b c
+ $ hg add a
+ $ hg commit -m a
+ $ hg add b
+ $ hg qnew -d "0 0" b
+ $ hg update 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg add c
+ $ hg commit -m c
+ created new head
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -m merge
+ abort: cannot commit over an applied mq patch
+ [255]
+ $ cd ..
+
+Issue529: mq aborts when merging patch deleting files
+
+ $ checkundo()
+ > {
+ > if [ -f .hg/store/undo ]; then
+ > echo ".hg/store/undo still exists"
+ > fi
+ > }
+
+Commit two dummy files in "init" changeset:
+
+ $ hg init t
+ $ cd t
+ $ echo a > a
+ $ echo b > b
+ $ hg ci -Am init
+ adding a
+ adding b
+ $ hg tag -l init
+
+Create a patch removing a:
+
+ $ hg qnew rm_a
+ $ hg rm a
+ $ hg qrefresh -m "rm a"
+
+Save the patch queue so we can merge it later:
+
+ $ hg qsave -c -e
+ copy $TESTTMP/t/.hg/patches to $TESTTMP/t/.hg/patches.1 (glob)
+ $ checkundo
+
+Update b and commit in an "update" changeset:
+
+ $ hg up -C init
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b >> b
+ $ hg st
+ M b
+ $ hg ci -m update
+ created new head
+
+# Here, qpush used to abort with :
+# The system cannot find the file specified => a
+ $ hg manifest
+ a
+ b
+
+ $ hg qpush -a -m
+ merging with queue at: $TESTTMP/t/.hg/patches.1 (glob)
+ applying rm_a
+ now at: rm_a
+
+ $ checkundo
+ $ hg manifest
+ b
+
+Ensure status is correct after merge:
+
+ $ hg qpop -a
+ popping rm_a
+ popping .hg.patches.merge.marker
+ patch queue now empty
+
+ $ cd ..
+
+Classic MQ merge sequence *with an explicit named queue*:
+
+ $ hg init t2
+ $ cd t2
+ $ echo '[diff]' > .hg/hgrc
+ $ echo 'nodates = 1' >> .hg/hgrc
+ $ echo a > a
+ $ hg ci -Am init
+ adding a
+ $ echo b > a
+ $ hg ci -m changea
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg cp a aa
+ $ echo c >> a
+ $ hg qnew --git -f -e patcha
+ $ echo d >> a
+ $ hg qnew -d '0 0' -f -e patcha2
+
+Create the reference queue:
+
+ $ hg qsave -c -e -n refqueue
+ copy $TESTTMP/t2/.hg/patches to $TESTTMP/t2/.hg/refqueue (glob)
+ $ hg up -C 1
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+Merge:
+
+ $ HGMERGE=internal:other hg qpush -a -m -n refqueue
+ merging with queue at: $TESTTMP/t2/.hg/refqueue (glob)
+ applying patcha
+ patching file a
+ Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
+ fuzz found when applying patch, stopping
+ patch didn't work out, merging patcha
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ applying patcha2
+ now at: patcha2
+
+Check patcha is still a git patch:
+
+ $ cat .hg/patches/patcha
+ # HG changeset patch
+ # Parent d3873e73d99ef67873dac33fbcc66268d5d2b6f4
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,2 @@
+ -b
+ +a
+ +c
+ diff --git a/aa b/aa
+ new file mode 100644
+ --- /dev/null
+ +++ b/aa
+ @@ -0,0 +1,1 @@
+ +a
+
+Check patcha2 is still a regular patch:
+
+ $ cat .hg/patches/patcha2
+ # HG changeset patch
+ # Parent ???????????????????????????????????????? (glob)
+ # Date 0 0
+
+ diff -r ???????????? -r ???????????? a (glob)
+ --- a/a
+ +++ b/a
+ @@ -1,2 +1,3 @@
+ a
+ c
+ +d
+
+ $ cd ..
+
diff --git a/tests/test-mq-missingfiles.t b/tests/test-mq-missingfiles.t
new file mode 100644
index 0000000..6897ff0
--- /dev/null
+++ b/tests/test-mq-missingfiles.t
@@ -0,0 +1,195 @@
+
+Issue835: qpush fails immediately when patching a missing file, but
+remaining added files are still created empty which will trick a
+future qrefresh.
+
+ $ cat > writelines.py <<EOF
+ > import sys
+ > path = sys.argv[1]
+ > args = sys.argv[2:]
+ > assert (len(args) % 2) == 0
+ >
+ > f = file(path, 'wb')
+ > for i in xrange(len(args)/2):
+ > count, s = args[2*i:2*i+2]
+ > count = int(count)
+ > s = s.decode('string_escape')
+ > f.write(s*count)
+ > f.close()
+ > EOF
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init normal
+ $ cd normal
+ $ python ../writelines.py b 10 'a\n'
+ $ hg ci -Am addb
+ adding b
+ $ echo a > a
+ $ python ../writelines.py b 2 'b\n' 10 'a\n' 2 'c\n'
+ $ echo c > c
+ $ hg add a c
+ $ hg qnew -f changeb
+ $ hg qpop
+ popping changeb
+ patch queue now empty
+ $ hg rm b
+ $ hg ci -Am rmb
+
+Push patch with missing target:
+
+ $ hg qpush
+ applying changeb
+ unable to find 'b' for patching
+ 2 out of 2 hunks FAILED -- saving rejects to file b.rej
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh changeb
+ [2]
+
+Display added files:
+
+ $ cat a
+ a
+ $ cat c
+ c
+
+Display rejections:
+
+ $ cat b.rej
+ --- b
+ +++ b
+ @@ -1,3 +1,5 @@
+ +b
+ +b
+ a
+ a
+ a
+ @@ -8,3 +10,5 @@
+ a
+ a
+ a
+ +c
+ +c
+
+Test missing renamed file
+
+ $ hg qpop
+ popping changeb
+ patch queue now empty
+ $ hg up -qC 0
+ $ echo a > a
+ $ hg mv b bb
+ $ python ../writelines.py bb 2 'b\n' 10 'a\n' 2 'c\n'
+ $ echo c > c
+ $ hg add a c
+ $ hg qnew changebb
+ $ hg qpop
+ popping changebb
+ patch queue now empty
+ $ hg up -qC 1
+ $ hg qpush
+ applying changebb
+ patching file bb
+ Hunk #1 FAILED at 0
+ Hunk #2 FAILED at 7
+ 2 out of 2 hunks FAILED -- saving rejects to file bb.rej
+ b not tracked!
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh changebb
+ [2]
+ $ cat a
+ a
+ $ cat c
+ c
+ $ cat bb.rej
+ --- bb
+ +++ bb
+ @@ -1,3 +1,5 @@
+ +b
+ +b
+ a
+ a
+ a
+ @@ -8,3 +10,5 @@
+ a
+ a
+ a
+ +c
+ +c
+
+ $ cd ..
+
+
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "git=1" >> $HGRCPATH
+
+ $ hg init git
+ $ cd git
+ $ python ../writelines.py b 1 '\x00'
+ $ hg ci -Am addb
+ adding b
+ $ echo a > a
+ $ python ../writelines.py b 1 '\x01' 1 '\x00'
+ $ echo c > c
+ $ hg add a c
+ $ hg qnew -f changeb
+ $ hg qpop
+ popping changeb
+ patch queue now empty
+ $ hg rm b
+ $ hg ci -Am rmb
+
+Push git patch with missing target:
+
+ $ hg qpush
+ applying changeb
+ unable to find 'b' for patching
+ 1 out of 1 hunks FAILED -- saving rejects to file b.rej
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh changeb
+ [2]
+ $ hg st
+ ? b.rej
+
+Display added files:
+
+ $ cat a
+ a
+ $ cat c
+ c
+
+Display rejections:
+
+ $ cat b.rej
+ --- b
+ +++ b
+ GIT binary patch
+ literal 2
+ Jc${No0000400IC2
+
+ $ cd ..
+
+Test push creating directory during git copy or rename:
+
+ $ hg init missingdir
+ $ cd missingdir
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ mkdir d
+ $ hg copy a d/a2
+ $ hg mv a d/a
+ $ hg qnew -g -f patch
+ $ hg qpop
+ popping patch
+ patch queue now empty
+ $ hg qpush
+ applying patch
+ now at: patch
+
+ $ cd ..
+
diff --git a/tests/test-mq-pull-from-bundle.t b/tests/test-mq-pull-from-bundle.t
new file mode 100644
index 0000000..45fb076
--- /dev/null
+++ b/tests/test-mq-pull-from-bundle.t
@@ -0,0 +1,135 @@
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > mq=
+ > [alias]
+ > tlog = log --template "{rev}: {desc}\\n"
+ > theads = heads --template "{rev}: {desc}\\n"
+ > tincoming = incoming --template "{rev}: {desc}\\n"
+ > EOF
+
+Setup main:
+
+ $ hg init base
+ $ cd base
+ $ echo "One" > one
+ $ hg add
+ adding one
+ $ hg ci -m "main: one added"
+ $ echo "++" >> one
+ $ hg ci -m "main: one updated"
+
+Bundle main:
+
+ $ hg bundle --base=null ../main.hg
+ 2 changesets found
+
+ $ cd ..
+
+Incoming to fresh repo:
+
+ $ hg init fresh
+
+ $ hg -R fresh tincoming main.hg
+ comparing with main.hg
+ 0: main: one added
+ 1: main: one updated
+ $ test -f ./fresh/.hg/hg-bundle* && echo 'temp. bundle file remained' || true
+
+ $ hg -R fresh tincoming bundle:fresh+main.hg
+ comparing with bundle:fresh+main.hg
+ 0: main: one added
+ 1: main: one updated
+
+
+Setup queue:
+
+ $ cd base
+ $ hg qinit -c
+ $ hg qnew -m "patch: two added" two.patch
+ $ echo two > two
+ $ hg add
+ adding two
+ $ hg qrefresh
+ $ hg qcommit -m "queue: two.patch added"
+ $ hg qpop -a
+ popping two.patch
+ patch queue now empty
+
+Bundle queue:
+
+ $ hg -R .hg/patches bundle --base=null ../queue.hgq
+ 1 changesets found
+ $ test -f ./fresh/.hg/hg-bundle* && echo 'temp. bundle file remained' || true
+
+ $ cd ..
+
+
+Clone base:
+
+ $ hg clone base copy
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd copy
+ $ hg qinit -c
+
+Incoming queue bundle:
+
+ $ hg -R .hg/patches tincoming ../queue.hgq
+ comparing with ../queue.hgq
+ 0: queue: two.patch added
+ $ test -f .hg/hg-bundle* && echo 'temp. bundle file remained' || true
+
+Pull queue bundle:
+
+ $ hg -R .hg/patches pull --update ../queue.hgq
+ pulling from ../queue.hgq
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 3 changes to 3 files
+ merging series
+ 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ $ test -f .hg/patches/hg-bundle* && echo 'temp. bundle file remained' || true
+
+ $ hg -R .hg/patches theads
+ 0: queue: two.patch added
+
+ $ hg -R .hg/patches tlog
+ 0: queue: two.patch added
+
+ $ hg qseries
+ two.patch
+
+ $ cd ..
+
+
+Clone base again:
+
+ $ hg clone base copy2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd copy2
+ $ hg qinit -c
+
+Unbundle queue bundle:
+
+ $ hg -R .hg/patches unbundle --update ../queue.hgq
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 3 changes to 3 files
+ merging series
+ 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
+
+ $ hg -R .hg/patches theads
+ 0: queue: two.patch added
+
+ $ hg -R .hg/patches tlog
+ 0: queue: two.patch added
+
+ $ hg qseries
+ two.patch
+
+ $ cd ..
+
diff --git a/tests/test-mq-qclone-http.t b/tests/test-mq-qclone-http.t
new file mode 100644
index 0000000..4c92f4a
--- /dev/null
+++ b/tests/test-mq-qclone-http.t
@@ -0,0 +1,153 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+hide outer repo
+ $ hg init
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ mkdir webdir
+ $ cd webdir
+ $ hg init a
+ $ hg --cwd a qinit -c
+ $ echo a > a/a
+ $ hg --cwd a ci -A -m a
+ adding a
+ $ echo b > a/b
+ $ hg --cwd a addremove
+ adding b
+ $ hg --cwd a qnew -f b.patch
+ $ hg --cwd a qcommit -m b.patch
+ $ hg --cwd a log --template "{desc}\n"
+ [mq]: b.patch
+ a
+ $ hg --cwd a/.hg/patches log --template "{desc}\n"
+ b.patch
+ $ root=`pwd`
+ $ cd ..
+
+test with recursive collection
+
+ $ cat > collections.conf <<EOF
+ > [paths]
+ > /=$root/**
+ > EOF
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf collections.conf \
+ > -A access-paths.log -E error-paths-1.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '?style=raw'
+ 200 Script output follows
+
+
+ /a/
+ /a/.hg/patches/
+
+ $ hg qclone http://localhost:$HGPORT/a b
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 3 changes to 3 files
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd b log --template "{desc}\n"
+ a
+ $ hg --cwd b qpush -a
+ applying b.patch
+ now at: b.patch
+ $ hg --cwd b log --template "{desc}\n"
+ imported patch b.patch
+ a
+
+test with normal collection
+
+ $ cat > collections1.conf <<EOF
+ > [paths]
+ > /=$root/*
+ > EOF
+ $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf collections1.conf \
+ > -A access-paths.log -E error-paths-1.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
+ 200 Script output follows
+
+
+ /a/
+ /a/.hg/patches/
+
+ $ hg qclone http://localhost:$HGPORT1/a c
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 3 changes to 3 files
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd c log --template "{desc}\n"
+ a
+ $ hg --cwd c qpush -a
+ applying b.patch
+ now at: b.patch
+ $ hg --cwd c log --template "{desc}\n"
+ imported patch b.patch
+ a
+
+test with old-style collection
+
+ $ cat > collections2.conf <<EOF
+ > [collections]
+ > $root=$root
+ > EOF
+ $ hg serve -p $HGPORT2 -d --pid-file=hg.pid --webdir-conf collections2.conf \
+ > -A access-paths.log -E error-paths-1.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '?style=raw'
+ 200 Script output follows
+
+
+ /a/
+ /a/.hg/patches/
+
+ $ hg qclone http://localhost:$HGPORT2/a d
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 3 changes to 3 files
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg --cwd d log --template "{desc}\n"
+ a
+ $ hg --cwd d qpush -a
+ applying b.patch
+ now at: b.patch
+ $ hg --cwd d log --template "{desc}\n"
+ imported patch b.patch
+ a
+
+test --mq works and uses correct repository config
+
+ $ hg --cwd d outgoing --mq
+ comparing with http://localhost:$HGPORT2/a/.hg/patches
+ searching for changes
+ no changes found
+ [1]
+ $ hg --cwd d log --mq --template '{rev} {desc|firstline}\n'
+ 0 b.patch
diff --git a/tests/test-mq-qdelete.t b/tests/test-mq-qdelete.t
new file mode 100644
index 0000000..2729a4d
--- /dev/null
+++ b/tests/test-mq-qdelete.t
@@ -0,0 +1,197 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init a
+ $ cd a
+
+ $ echo 'base' > base
+ $ hg ci -Ambase -d '1 0'
+ adding base
+
+ $ hg qnew -d '1 0' pa
+ $ hg qnew -d '1 0' pb
+ $ hg qnew -d '1 0' pc
+
+ $ hg qdel
+ abort: qdelete requires at least one revision or patch name
+ [255]
+
+ $ hg qdel pc
+ abort: cannot delete applied patch pc
+ [255]
+
+ $ hg qpop
+ popping pc
+ now at: pb
+
+Delete the same patch twice in one command (issue2427)
+
+ $ hg qdel pc pc
+
+ $ hg qseries
+ pa
+ pb
+
+ $ ls .hg/patches
+ pa
+ pb
+ series
+ status
+
+ $ hg qpop
+ popping pb
+ now at: pa
+
+ $ hg qdel -k 1
+
+ $ ls .hg/patches
+ pa
+ pb
+ series
+ status
+
+ $ hg qdel -r pa
+ patch pa finalized without changeset message
+
+ $ hg qapplied
+
+ $ hg log --template '{rev} {desc}\n'
+ 1 [mq]: pa
+ 0 base
+
+ $ hg qnew pd
+ $ hg qnew pe
+ $ hg qnew pf
+
+ $ hg qdel -r pe
+ abort: cannot delete revision 3 above applied patches
+ [255]
+
+ $ hg qdel -r qbase:pe
+ patch pd finalized without changeset message
+ patch pe finalized without changeset message
+
+ $ hg qapplied
+ pf
+
+ $ hg log --template '{rev} {desc}\n'
+ 4 [mq]: pf
+ 3 [mq]: pe
+ 2 [mq]: pd
+ 1 [mq]: pa
+ 0 base
+
+ $ cd ..
+
+ $ hg init b
+ $ cd b
+
+ $ echo 'base' > base
+ $ hg ci -Ambase -d '1 0'
+ adding base
+
+ $ hg qfinish
+ abort: no revisions specified
+ [255]
+
+ $ hg qfinish -a
+ no patches applied
+
+ $ hg qnew -d '1 0' pa
+ $ hg qnew -d '1 0' pb
+ $ hg qnew pc # XXX fails to apply by /usr/bin/patch if we put a date
+
+ $ hg qfinish 0
+ abort: revision 0 is not managed
+ [255]
+
+ $ hg qfinish pb
+ abort: cannot delete revision 2 above applied patches
+ [255]
+
+ $ hg qpop
+ popping pc
+ now at: pb
+
+ $ hg qfinish -a pc
+ abort: unknown revision 'pc'!
+ [255]
+
+ $ hg qpush
+ applying pc
+ patch pc is empty
+ now at: pc
+
+ $ hg qfinish qbase:pb
+ patch pa finalized without changeset message
+ patch pb finalized without changeset message
+
+ $ hg qapplied
+ pc
+
+ $ hg log --template '{rev} {desc}\n'
+ 3 imported patch pc
+ 2 [mq]: pb
+ 1 [mq]: pa
+ 0 base
+
+ $ hg qfinish -a pc
+ patch pc finalized without changeset message
+
+ $ hg qapplied
+
+ $ hg log --template '{rev} {desc}\n'
+ 3 imported patch pc
+ 2 [mq]: pb
+ 1 [mq]: pa
+ 0 base
+
+ $ ls .hg/patches
+ series
+ status
+
+qdel -k X && hg qimp -e X used to trigger spurious output with versioned queues
+
+ $ hg init --mq
+ $ hg qimport -r 3
+ $ hg qpop
+ popping 3.diff
+ patch queue now empty
+ $ hg qdel -k 3.diff
+ $ hg qimp -e 3.diff
+ adding 3.diff to series file
+ $ hg qfinish -a
+ no patches applied
+
+
+resilience to inconsistency: qfinish -a with applied patches not in series
+
+ $ hg qser
+ 3.diff
+ $ hg qapplied
+ $ hg qpush
+ applying 3.diff
+ patch 3.diff is empty
+ now at: 3.diff
+ $ echo next >> base
+ $ hg qrefresh -d '1 0'
+ $ echo > .hg/patches/series # remove 3.diff from series to confuse mq
+ $ hg qfinish -a
+ revision 47dfa8501675 refers to unknown patches: 3.diff
+
+more complex state 'both known and unknown patches
+
+ $ echo hip >> base
+ $ hg qnew -f -d '1 0' -m 4 4.diff
+ $ echo hop >> base
+ $ hg qnew -f -d '1 0' -m 5 5.diff
+ $ echo > .hg/patches/series # remove 4.diff and 5.diff from series to confuse mq
+ $ echo hup >> base
+ $ hg qnew -f -d '1 0' -m 6 6.diff
+ $ echo pup > base
+ $ hg qfinish -a
+ warning: uncommitted changes in the working directory
+ revision 2b1c98802260 refers to unknown patches: 5.diff
+ revision 33a6861311c0 refers to unknown patches: 4.diff
+
+ $ cd ..
diff --git a/tests/test-mq-qdiff.t b/tests/test-mq-qdiff.t
new file mode 100644
index 0000000..905a970
--- /dev/null
+++ b/tests/test-mq-qdiff.t
@@ -0,0 +1,177 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "[mq]" >> $HGRCPATH
+ $ echo "git=keep" >> $HGRCPATH
+
+ $ hg init a
+ $ cd a
+
+ $ echo 'base' > base
+ $ hg ci -Ambase
+ adding base
+
+ $ hg qnew -mmqbase mqbase
+
+ $ echo 'patched' > base
+ $ hg qrefresh
+
+qdiff:
+
+ $ hg qdiff
+ diff -r d20a80d4def3 base
+ --- a/base Thu Jan 01 00:00:00 1970 +0000
+ +++ b/base* (glob)
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+qdiff dirname:
+
+ $ hg qdiff --nodates .
+ diff -r d20a80d4def3 base
+ --- a/base
+ +++ b/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+qdiff filename:
+
+ $ hg qdiff --nodates base
+ diff -r d20a80d4def3 base
+ --- a/base
+ +++ b/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ hg revert -a
+
+ $ hg qpop
+ popping mqbase
+ patch queue now empty
+
+ $ hg qdelete mqbase
+
+ $ printf '1\n2\n3\n4\nhello world\ngoodbye world\n7\n8\n9\n' > lines
+ $ hg ci -Amlines -d '2 0'
+ adding lines
+
+ $ hg qnew -mmqbase2 mqbase2
+ $ printf '\n\n1\n2\n3\n4\nhello world\n goodbye world\n7\n8\n9\n' > lines
+
+ $ hg qdiff --nodates -U 1
+ diff -r b0c220e1cf43 lines
+ --- a/lines
+ +++ b/lines
+ @@ -1,1 +1,3 @@
+ +
+ +
+ 1
+ @@ -4,4 +6,4 @@
+ 4
+ -hello world
+ -goodbye world
+ +hello world
+ + goodbye world
+ 7
+
+ $ hg qdiff --nodates -b
+ diff -r b0c220e1cf43 lines
+ --- a/lines
+ +++ b/lines
+ @@ -1,9 +1,11 @@
+ +
+ +
+ 1
+ 2
+ 3
+ 4
+ hello world
+ -goodbye world
+ + goodbye world
+ 7
+ 8
+ 9
+
+ $ hg qdiff --nodates -U 1 -B
+ diff -r b0c220e1cf43 lines
+ --- a/lines
+ +++ b/lines
+ @@ -4,4 +4,4 @@
+ 4
+ -hello world
+ -goodbye world
+ +hello world
+ + goodbye world
+ 7
+
+ $ hg qdiff --nodates -w
+ diff -r b0c220e1cf43 lines
+ --- a/lines
+ +++ b/lines
+ @@ -1,3 +1,5 @@
+ +
+ +
+ 1
+ 2
+ 3
+
+ $ hg qdiff --nodates --reverse
+ diff -r b0c220e1cf43 lines
+ --- a/lines
+ +++ b/lines
+ @@ -1,11 +1,9 @@
+ -
+ -
+ 1
+ 2
+ 3
+ 4
+ -hello world
+ - goodbye world
+ +hello world
+ +goodbye world
+ 7
+ 8
+ 9
+
+qdiff preserve existing git flag:
+
+ $ hg qrefresh --git
+ $ echo a >> lines
+ $ hg qdiff
+ diff --git a/lines b/lines
+ --- a/lines
+ +++ b/lines
+ @@ -1,9 +1,12 @@
+ +
+ +
+ 1
+ 2
+ 3
+ 4
+ -hello world
+ -goodbye world
+ +hello world
+ + goodbye world
+ 7
+ 8
+ 9
+ +a
+
+ $ hg qdiff --stat
+ lines | 7 +++++--
+ 1 files changed, 5 insertions(+), 2 deletions(-)
+ $ hg qrefresh
+
+qdiff when file deleted (but not removed) in working dir:
+
+ $ hg qnew deleted-file
+ $ echo a > newfile
+ $ hg add newfile
+ $ hg qrefresh
+ $ rm newfile
+ $ hg qdiff
+
+ $ cd ..
diff --git a/tests/test-mq-qfold.t b/tests/test-mq-qfold.t
new file mode 100644
index 0000000..1345ab5
--- /dev/null
+++ b/tests/test-mq-qfold.t
@@ -0,0 +1,144 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "[mq]" >> $HGRCPATH
+ $ echo "git=keep" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "nodates=1" >> $HGRCPATH
+
+init:
+
+ $ hg init repo
+ $ cd repo
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ echo a >> a
+ $ hg qnew -f p1
+ $ echo b >> a
+ $ hg qnew -f p2
+ $ echo c >> a
+ $ hg qnew -f p3
+
+Fold in the middle of the queue:
+
+ $ hg qpop p1
+ popping p3
+ popping p2
+ now at: p1
+
+ $ hg qdiff
+ diff -r 07f494440405 a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,2 @@
+ a
+ +a
+
+ $ hg qfold p2
+ $ grep git .hg/patches/p1 && echo 'git patch found!'
+ [1]
+
+ $ hg qser
+ p1
+ p3
+
+ $ hg qdiff
+ diff -r 07f494440405 a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,3 @@
+ a
+ +a
+ +b
+
+Fold with local changes:
+
+ $ echo d >> a
+ $ hg qfold p3
+ abort: local changes found, refresh first
+ [255]
+
+ $ hg diff -c .
+ diff -r 07f494440405 -r ???????????? a (glob)
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,3 @@
+ a
+ +a
+ +b
+
+ $ hg revert -a --no-backup
+ reverting a
+
+Fold git patch into a regular patch, expect git patch:
+
+ $ echo a >> a
+ $ hg qnew -f regular
+ $ hg cp a aa
+ $ hg qnew --git -f git
+
+ $ hg qpop
+ popping git
+ now at: regular
+
+ $ hg qfold git
+
+ $ cat .hg/patches/regular
+ # HG changeset patch
+ # Parent ???????????????????????????????????????? (glob)
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,3 +1,4 @@
+ a
+ a
+ b
+ +a
+ diff --git a/a b/aa
+ copy from a
+ copy to aa
+ --- a/a
+ +++ b/aa
+ @@ -1,3 +1,4 @@
+ a
+ a
+ b
+ +a
+
+ $ hg qpop
+ popping regular
+ now at: p1
+
+ $ hg qdel regular
+
+Fold regular patch into a git patch, expect git patch:
+
+ $ hg cp a aa
+ $ hg qnew --git -f git
+ $ echo b >> aa
+ $ hg qnew -f regular
+
+ $ hg qpop
+ popping regular
+ now at: git
+
+ $ hg qfold regular
+
+ $ cat .hg/patches/git
+ # HG changeset patch
+ # Parent ???????????????????????????????????????? (glob)
+
+ diff --git a/a b/aa
+ copy from a
+ copy to aa
+ --- a/a
+ +++ b/aa
+ @@ -1,3 +1,4 @@
+ a
+ a
+ b
+ +b
+
+ $ cd ..
+
diff --git a/tests/test-mq-qgoto.t b/tests/test-mq-qgoto.t
new file mode 100644
index 0000000..891b3dd
--- /dev/null
+++ b/tests/test-mq-qgoto.t
@@ -0,0 +1,78 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+
+ $ hg qnew a.patch
+ $ echo a >> a
+ $ hg qrefresh
+
+ $ hg qnew b.patch
+ $ echo b > b
+ $ hg add b
+ $ hg qrefresh
+
+ $ hg qnew c.patch
+ $ echo c > c
+ $ hg add c
+ $ hg qrefresh
+
+ $ hg qgoto a.patch
+ popping c.patch
+ popping b.patch
+ now at: a.patch
+
+ $ hg qgoto c.patch
+ applying b.patch
+ applying c.patch
+ now at: c.patch
+
+ $ hg qgoto b.patch
+ popping c.patch
+ now at: b.patch
+
+Using index:
+
+ $ hg qgoto 0
+ popping b.patch
+ now at: a.patch
+
+ $ hg qgoto 2
+ applying b.patch
+ applying c.patch
+ now at: c.patch
+
+No warnings when using index:
+
+ $ hg qnew bug314159
+ $ echo d >> c
+ $ hg qrefresh
+ $ hg qnew bug141421
+ $ echo e >> c
+ $ hg qrefresh
+
+ $ hg qgoto 1
+ popping bug141421
+ popping bug314159
+ popping c.patch
+ now at: b.patch
+
+ $ hg qgoto 3
+ applying c.patch
+ applying bug314159
+ now at: bug314159
+
+Detect ambiguous non-index:
+
+ $ hg qgoto 14
+ patch name "14" is ambiguous:
+ bug314159
+ bug141421
+ abort: patch 14 not in series
+ [255]
+
+ $ cd ..
diff --git a/tests/test-mq-qimport-fail-cleanup.t b/tests/test-mq-qimport-fail-cleanup.t
new file mode 100644
index 0000000..a4ae565
--- /dev/null
+++ b/tests/test-mq-qimport-fail-cleanup.t
@@ -0,0 +1,42 @@
+Failed qimport of patches from files should cleanup by recording successfully
+imported patches in series file.
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ hg init repo
+ $ cd repo
+ $ echo a > a
+ $ hg ci -Am'add a'
+ adding a
+ $ cat >b.patch<<EOF
+ > diff --git a/a b/a
+ > --- a/a
+ > +++ b/a
+ > @@ -1,1 +1,2 @@
+ > a
+ > +b
+ > EOF
+
+empty series
+
+ $ hg qseries
+
+qimport valid patch followed by invalid patch
+
+ $ hg qimport b.patch fakepatch
+ adding b.patch to series file
+ abort: unable to read file fakepatch
+ [255]
+
+valid patches before fail added to series
+
+ $ hg qseries
+ b.patch
+
+ $ hg pull -q -r 0 . # update phase
+ $ hg qimport -r 0
+ abort: revision 0 is not mutable
+ (see "hg help phases" for details)
+ [255]
+
+ $ cd ..
diff --git a/tests/test-mq-qimport.t b/tests/test-mq-qimport.t
new file mode 100644
index 0000000..52b3568
--- /dev/null
+++ b/tests/test-mq-qimport.t
@@ -0,0 +1,280 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ cat > writelines.py <<EOF
+ > import sys
+ > path = sys.argv[1]
+ > args = sys.argv[2:]
+ > assert (len(args) % 2) == 0
+ >
+ > f = file(path, 'wb')
+ > for i in xrange(len(args)/2):
+ > count, s = args[2*i:2*i+2]
+ > count = int(count)
+ > s = s.decode('string_escape')
+ > f.write(s*count)
+ > f.close()
+ >
+ > EOF
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "git=1" >> $HGRCPATH
+ $ hg init repo
+ $ cd repo
+
+qimport without file or revision
+
+ $ hg qimport
+ abort: no files or revisions specified
+ [255]
+
+qimport non-existing-file
+
+ $ hg qimport non-existing-file
+ abort: unable to read file non-existing-file
+ [255]
+
+qimport null revision
+
+ $ hg qimport -r null
+ abort: revision -1 is not mutable
+ (see "hg help phases" for details)
+ [255]
+ $ hg qseries
+
+import email
+
+ $ hg qimport --push -n email - <<EOF
+ > From: Username in email <test@example.net>
+ > Subject: [PATCH] Message in email
+ > Date: Fri, 02 Jan 1970 00:00:00 +0000
+ >
+ > Text before patch.
+ >
+ > # HG changeset patch
+ > # User Username in patch <test@example.net>
+ > # Date 0 0
+ > # Node ID 1a706973a7d84cb549823634a821d9bdf21c6220
+ > # Parent 0000000000000000000000000000000000000000
+ > First line of commit message.
+ >
+ > More text in commit message.
+ > --- confuse the diff detection
+ >
+ > diff --git a/x b/x
+ > new file mode 100644
+ > --- /dev/null
+ > +++ b/x
+ > @@ -0,0 +1,1 @@
+ > +new file
+ > Text after patch.
+ >
+ > EOF
+ adding email to series file
+ applying email
+ now at: email
+
+hg tip -v
+
+ $ hg tip -v
+ changeset: 0:1a706973a7d8
+ tag: email
+ tag: qbase
+ tag: qtip
+ tag: tip
+ user: Username in patch <test@example.net>
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: x
+ description:
+ First line of commit message.
+
+ More text in commit message.
+
+
+ $ hg qpop
+ popping email
+ patch queue now empty
+ $ hg qdelete email
+
+import URL
+
+ $ echo foo >> foo
+ $ hg add foo
+ $ hg diff > url.diff
+ $ hg revert --no-backup foo
+ $ rm foo
+
+Under unix: file:///foobar/blah
+Under windows: file:///c:/foobar/blah
+
+ $ patchurl=`pwd | tr '\\\\' /`/url.diff
+ $ expr "$patchurl" : "\/" > /dev/null || patchurl="/$patchurl"
+ $ hg qimport file://"$patchurl"
+ adding url.diff to series file
+ $ rm url.diff
+ $ hg qun
+ url.diff
+
+import patch that already exists
+
+ $ echo foo2 >> foo
+ $ hg add foo
+ $ hg diff > ../url.diff
+ $ hg revert --no-backup foo
+ $ rm foo
+ $ hg qimport ../url.diff
+ abort: patch "url.diff" already exists
+ [255]
+ $ hg qpush
+ applying url.diff
+ now at: url.diff
+ $ cat foo
+ foo
+ $ hg qpop
+ popping url.diff
+ patch queue now empty
+
+qimport -f
+
+ $ hg qimport -f ../url.diff
+ adding url.diff to series file
+ $ hg qpush
+ applying url.diff
+ now at: url.diff
+ $ cat foo
+ foo2
+ $ hg qpop
+ popping url.diff
+ patch queue now empty
+
+build diff with CRLF
+
+ $ python ../writelines.py b 5 'a\n' 5 'a\r\n'
+ $ hg ci -Am addb
+ adding b
+ $ python ../writelines.py b 2 'a\n' 10 'b\n' 2 'a\r\n'
+ $ hg diff > b.diff
+ $ hg up -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+qimport CRLF diff
+
+ $ hg qimport b.diff
+ adding b.diff to series file
+ $ hg qpush
+ applying b.diff
+ now at: b.diff
+
+try to import --push
+
+ $ cat > appendfoo.diff <<EOF
+ > append foo
+ >
+ > diff -r 07f494440405 -r 261500830e46 baz
+ > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ > +++ b/baz Thu Jan 01 00:00:00 1970 +0000
+ > @@ -0,0 +1,1 @@
+ > +foo
+ > EOF
+
+ $ cat > appendbar.diff <<EOF
+ > append bar
+ >
+ > diff -r 07f494440405 -r 261500830e46 baz
+ > --- a/baz Thu Jan 01 00:00:00 1970 +0000
+ > +++ b/baz Thu Jan 01 00:00:00 1970 +0000
+ > @@ -1,1 +1,2 @@
+ > foo
+ > +bar
+ > EOF
+
+ $ hg qimport --push appendfoo.diff appendbar.diff
+ adding appendfoo.diff to series file
+ adding appendbar.diff to series file
+ applying appendfoo.diff
+ applying appendbar.diff
+ now at: appendbar.diff
+ $ hg qfin -a
+ patch b.diff finalized without changeset message
+ $ hg qimport -r 'p1(.)::' -P
+ $ hg qpop -a
+ popping 3.diff
+ popping 2.diff
+ patch queue now empty
+ $ hg qdel 3.diff
+ $ hg qdel -k 2.diff
+
+qimport -e
+
+ $ hg qimport -e 2.diff
+ adding 2.diff to series file
+ $ hg qdel -k 2.diff
+
+qimport -e --name newname oldexisitingpatch
+
+ $ hg qimport -e --name this-name-is-better 2.diff
+ renaming 2.diff to this-name-is-better
+ adding this-name-is-better to series file
+ $ hg qser
+ this-name-is-better
+ url.diff
+
+qimport -e --name without --force
+
+ $ cp .hg/patches/this-name-is-better .hg/patches/3.diff
+ $ hg qimport -e --name this-name-is-better 3.diff
+ abort: patch "this-name-is-better" already exists
+ [255]
+ $ hg qser
+ this-name-is-better
+ url.diff
+
+qimport -e --name with --force
+
+ $ hg qimport --force -e --name this-name-is-better 3.diff
+ renaming 3.diff to this-name-is-better
+ adding this-name-is-better to series file
+ $ hg qser
+ this-name-is-better
+ url.diff
+
+qimport with bad name, should abort before reading file
+
+ $ hg qimport non-existant-file --name .hg
+ abort: patch name cannot begin with ".hg"
+ [255]
+
+qimport http:// patch with leading slashes in url
+
+set up hgweb
+
+ $ cd ..
+ $ hg init served
+ $ cd served
+ $ echo a > a
+ $ hg ci -Am patch
+ adding a
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+
+ $ cd ../repo
+ $ hg qimport http://localhost:$HGPORT/raw-rev/0///
+ adding 0 to series file
+
+check qimport phase:
+
+ $ hg -q qpush
+ now at: 0
+ $ hg phase qparent
+ 1: draft
+ $ hg qimport -r qparent
+ $ hg phase qbase
+ 1: draft
+ $ hg qfinish qbase
+ $ echo '[mq]' >> $HGRCPATH
+ $ echo 'secret=true' >> $HGRCPATH
+ $ hg qimport -r qparent
+ $ hg phase qbase
+ 1: secret
+
+ $ cd ..
diff --git a/tests/test-mq-qnew.t b/tests/test-mq-qnew.t
new file mode 100644
index 0000000..7400cad
--- /dev/null
+++ b/tests/test-mq-qnew.t
@@ -0,0 +1,235 @@
+
+ $ catpatch() {
+ > cat $1 | sed -e "s/^\(# Parent \).*/\1/"
+ > }
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ runtest() {
+ > hg init mq
+ > cd mq
+ >
+ > echo a > a
+ > hg ci -Ama
+ >
+ > echo '% qnew should refuse bad patch names'
+ > hg qnew series
+ > hg qnew status
+ > hg qnew guards
+ > hg qnew .
+ > hg qnew ..
+ > hg qnew .hgignore
+ > hg qnew .mqfoo
+ > hg qnew 'foo#bar'
+ > hg qnew 'foo:bar'
+ >
+ > hg qinit -c
+ >
+ > echo '% qnew with name containing slash'
+ > hg qnew foo/
+ > hg qnew foo/bar.patch
+ > hg qnew foo
+ > hg qseries
+ > hg qpop
+ > hg qdelete foo/bar.patch
+ >
+ > echo '% qnew with uncommitted changes'
+ > echo a > somefile
+ > hg add somefile
+ > hg qnew uncommitted.patch
+ > hg st
+ > hg qseries
+ >
+ > echo '% qnew implies add'
+ > hg -R .hg/patches st
+ >
+ > echo '% qnew missing'
+ > hg qnew missing.patch missing
+ >
+ > echo '% qnew -m'
+ > hg qnew -m 'foo bar' mtest.patch
+ > catpatch .hg/patches/mtest.patch
+ >
+ > echo '% qnew twice'
+ > hg qnew first.patch
+ > hg qnew first.patch
+ >
+ > touch ../first.patch
+ > hg qimport ../first.patch
+ >
+ > echo '% qnew -f from a subdirectory'
+ > hg qpop -a
+ > mkdir d
+ > cd d
+ > echo b > b
+ > hg ci -Am t
+ > echo b >> b
+ > hg st
+ > hg qnew -g -f p
+ > catpatch ../.hg/patches/p
+ >
+ > echo '% qnew -u with no username configured'
+ > HGUSER= hg qnew -u blue red
+ > catpatch ../.hg/patches/red
+ >
+ > echo '% qnew -e -u with no username configured'
+ > HGUSER= hg qnew -e -u chartreuse fucsia
+ > catpatch ../.hg/patches/fucsia
+ >
+ > echo '% fail when trying to import a merge'
+ > hg init merge
+ > cd merge
+ > touch a
+ > hg ci -Am null
+ > echo a >> a
+ > hg ci -m a
+ > hg up -r 0
+ > echo b >> a
+ > hg ci -m b
+ > hg merge -f 1
+ > hg resolve --mark a
+ > hg qnew -f merge
+ >
+ > cd ../../..
+ > rm -r mq
+ > }
+
+plain headers
+
+ $ echo "[mq]" >> $HGRCPATH
+ $ echo "plain=true" >> $HGRCPATH
+ $ mkdir sandbox
+ $ (cd sandbox ; runtest)
+ adding a
+ % qnew should refuse bad patch names
+ abort: "series" cannot be used as the name of a patch
+ abort: "status" cannot be used as the name of a patch
+ abort: "guards" cannot be used as the name of a patch
+ abort: "." cannot be used as the name of a patch
+ abort: ".." cannot be used as the name of a patch
+ abort: patch name cannot begin with ".hg"
+ abort: patch name cannot begin with ".mq"
+ abort: "#" cannot be used in the name of a patch
+ abort: ":" cannot be used in the name of a patch
+ % qnew with name containing slash
+ abort: path ends in directory separator: foo/ (glob)
+ abort: "foo" already exists as a directory
+ foo/bar.patch
+ popping foo/bar.patch
+ patch queue now empty
+ % qnew with uncommitted changes
+ uncommitted.patch
+ % qnew implies add
+ A .hgignore
+ A series
+ A uncommitted.patch
+ % qnew missing
+ abort: missing: * (glob)
+ % qnew -m
+ foo bar
+
+ % qnew twice
+ abort: patch "first.patch" already exists
+ abort: patch "first.patch" already exists
+ % qnew -f from a subdirectory
+ popping first.patch
+ popping mtest.patch
+ popping uncommitted.patch
+ patch queue now empty
+ adding d/b
+ M d/b
+ diff --git a/d/b b/d/b
+ --- a/d/b
+ +++ b/d/b
+ @@ -1,1 +1,2 @@
+ b
+ +b
+ % qnew -u with no username configured
+ From: blue
+
+ % qnew -e -u with no username configured
+ From: chartreuse
+
+ % fail when trying to import a merge
+ adding a
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+ merging a
+ warning: conflicts during merge.
+ merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ abort: cannot manage merge changesets
+ $ rm -r sandbox
+
+hg headers
+
+ $ echo "plain=false" >> $HGRCPATH
+ $ mkdir sandbox
+ $ (cd sandbox ; runtest)
+ adding a
+ % qnew should refuse bad patch names
+ abort: "series" cannot be used as the name of a patch
+ abort: "status" cannot be used as the name of a patch
+ abort: "guards" cannot be used as the name of a patch
+ abort: "." cannot be used as the name of a patch
+ abort: ".." cannot be used as the name of a patch
+ abort: patch name cannot begin with ".hg"
+ abort: patch name cannot begin with ".mq"
+ abort: "#" cannot be used in the name of a patch
+ abort: ":" cannot be used in the name of a patch
+ % qnew with name containing slash
+ abort: path ends in directory separator: foo/ (glob)
+ abort: "foo" already exists as a directory
+ foo/bar.patch
+ popping foo/bar.patch
+ patch queue now empty
+ % qnew with uncommitted changes
+ uncommitted.patch
+ % qnew implies add
+ A .hgignore
+ A series
+ A uncommitted.patch
+ % qnew missing
+ abort: missing: * (glob)
+ % qnew -m
+ # HG changeset patch
+ # Parent
+ foo bar
+
+ % qnew twice
+ abort: patch "first.patch" already exists
+ abort: patch "first.patch" already exists
+ % qnew -f from a subdirectory
+ popping first.patch
+ popping mtest.patch
+ popping uncommitted.patch
+ patch queue now empty
+ adding d/b
+ M d/b
+ # HG changeset patch
+ # Parent
+ diff --git a/d/b b/d/b
+ --- a/d/b
+ +++ b/d/b
+ @@ -1,1 +1,2 @@
+ b
+ +b
+ % qnew -u with no username configured
+ # HG changeset patch
+ # Parent
+ # User blue
+ % qnew -e -u with no username configured
+ # HG changeset patch
+ # Parent
+ # User chartreuse
+ % fail when trying to import a merge
+ adding a
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+ merging a
+ warning: conflicts during merge.
+ merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ abort: cannot manage merge changesets
+ $ rm -r sandbox
diff --git a/tests/test-mq-qpush-exact.t b/tests/test-mq-qpush-exact.t
new file mode 100644
index 0000000..99fb74e
--- /dev/null
+++ b/tests/test-mq-qpush-exact.t
@@ -0,0 +1,289 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "graphlog=" >> $HGRCPATH
+
+make a test repository that looks like this:
+
+o 2:28bc7b1afd6a
+|
+| @ 1:d7fe2034f71b
+|/
+o 0/62ecad8b70e5
+
+ $ hg init r0
+ $ cd r0
+ $ touch f0
+ $ hg ci -m0 -Aq
+ $ touch f1
+ $ hg ci -m1 -Aq
+
+ $ hg update 0 -q
+ $ touch f2
+ $ hg ci -m2 -Aq
+ $ hg update 1 -q
+
+make some patches with a parent: 1:d7fe2034f71b -> p0 -> p1
+
+ $ echo cp0 >> fp0
+ $ hg add fp0
+ $ hg ci -m p0 -d "0 0"
+ $ hg export -r. > p0
+ $ hg strip -qn .
+ $ hg qimport p0
+ adding p0 to series file
+ $ hg qpush
+ applying p0
+ now at: p0
+
+ $ echo cp1 >> fp1
+ $ hg add fp1
+ $ hg qnew p1 -d "0 0"
+
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact when at the parent
+
+ $ hg update 1 -q
+ $ hg qpush -e
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg qpush -e p0
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg qpush -e p1
+ applying p0
+ applying p1
+ now at: p1
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact when at another rev
+
+ $ hg update 0 -q
+ $ hg qpush -e
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 0 -q
+ $ hg qpush -e p0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 0 -q
+ $ hg qpush -e p1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ applying p0
+ applying p1
+ now at: p1
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 0 -q
+ $ hg qpush -ea
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ applying p0
+ applying p1
+ now at: p1
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact while crossing branches
+
+ $ hg update 2 -q
+ $ hg qpush -e
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 2 -q
+ $ hg qpush -e p0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 2 -q
+ $ hg qpush -e p1
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ applying p0
+ applying p1
+ now at: p1
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 2 -q
+ $ hg qpush -ea
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ applying p0
+ applying p1
+ now at: p1
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact --force with changes to an unpatched file
+
+ $ hg update 1 -q
+ $ echo c0 >> f0
+ $ hg qpush -e
+ abort: local changes found
+ [255]
+ $ hg qpush -ef
+ applying p0
+ now at: p0
+ $ cat f0
+ c0
+ $ rm f0
+ $ touch f0
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 1 -q
+ $ echo c0 >> f0
+ $ hg qpush -e p1
+ abort: local changes found
+ [255]
+ $ hg qpush -e p1 -f
+ applying p0
+ applying p1
+ now at: p1
+ $ cat f0
+ c0
+ $ rm f0
+ $ touch f0
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact --force with changes to a patched file
+
+ $ hg update 1 -q
+ $ echo cp0-bad >> fp0
+ $ hg add fp0
+ $ hg qpush -e
+ abort: local changes found
+ [255]
+ $ hg qpush -ef
+ applying p0
+ file fp0 already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file fp0.rej
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh p0
+ [2]
+ $ cat fp0
+ cp0-bad
+ $ cat fp0.rej
+ --- fp0
+ +++ fp0
+ @@ -0,0 +1,1 @@
+ +cp0
+ $ hg qpop -aqf
+ patch queue now empty
+ $ rm fp0
+ $ rm fp0.rej
+
+ $ hg update 1 -q
+ $ echo cp1-bad >> fp1
+ $ hg add fp1
+ $ hg qpush -e p1
+ abort: local changes found
+ [255]
+ $ hg qpush -e p1 -f
+ applying p0
+ applying p1
+ file fp1 already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file fp1.rej
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh p1
+ [2]
+ $ cat fp1
+ cp1-bad
+ $ cat fp1.rej
+ --- fp1
+ +++ fp1
+ @@ -0,0 +1,1 @@
+ +cp1
+ $ hg qpop -aqf
+ patch queue now empty
+ $ rm fp1
+ $ rm fp1.rej
+
+qpush --exact when already at a patch
+
+ $ hg update 1
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg qpush -e p0
+ applying p0
+ now at: p0
+ $ hg qpush -e p1
+ abort: cannot push --exact with applied patches
+ [255]
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact --move should fail
+
+ $ hg qpush -e --move p1
+ abort: cannot use --exact and --move together
+ [255]
+
+qpush --exact a patch without a parent recorded
+
+ $ hg qpush -q
+ now at: p0
+ $ grep -v '# Parent' .hg/patches/p0 > p0.new
+ $ mv p0.new .hg/patches/p0
+ $ hg qpop -aq
+ patch queue now empty
+ $ hg qpush -e
+ abort: p0 does not have a parent recorded
+ [255]
+ $ hg qpush -e p0
+ abort: p0 does not have a parent recorded
+ [255]
+ $ hg qpush -e p1
+ abort: p0 does not have a parent recorded
+ [255]
+ $ hg qpush -ea
+ abort: p0 does not have a parent recorded
+ [255]
+
+ $ cd ..
diff --git a/tests/test-mq-qpush-fail.t b/tests/test-mq-qpush-fail.t
new file mode 100644
index 0000000..44379cd
--- /dev/null
+++ b/tests/test-mq-qpush-fail.t
@@ -0,0 +1,426 @@
+Test that qpush cleans things up if it doesn't complete
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ hg init repo
+ $ cd repo
+ $ echo foo > foo
+ $ hg ci -Am 'add foo'
+ adding foo
+ $ touch untracked-file
+ $ echo 'syntax: glob' > .hgignore
+ $ echo '.hgignore' >> .hgignore
+ $ hg qinit
+
+test qpush on empty series
+
+ $ hg qpush
+ no patches in series
+ $ hg qnew patch1
+ $ echo >> foo
+ $ hg qrefresh -m 'patch 1'
+ $ hg qnew patch2
+ $ echo bar > bar
+ $ hg add bar
+ $ hg qrefresh -m 'patch 2'
+ $ hg qnew --config 'mq.plain=true' bad-patch
+ $ echo >> foo
+ $ hg qrefresh
+ $ hg qpop -a
+ popping bad-patch
+ popping patch2
+ popping patch1
+ patch queue now empty
+ $ python -c 'print "\xe9"' > message
+ $ cat .hg/patches/bad-patch >> message
+ $ mv message .hg/patches/bad-patch
+ $ hg qpush -a && echo 'qpush succeded?!'
+ applying patch1
+ applying patch2
+ applying bad-patch
+ transaction abort!
+ rollback completed
+ cleaning up working directory...done
+ abort: decoding near '\xe9': 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)! (esc)
+ [255]
+ $ hg parents
+ changeset: 0:bbd179dfa0a7
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo
+
+
+test corrupt status file
+ $ hg qpush
+ applying patch1
+ now at: patch1
+ $ cp .hg/patches/status .hg/patches/status.orig
+ $ hg qpop
+ popping patch1
+ patch queue now empty
+ $ cp .hg/patches/status.orig .hg/patches/status
+ $ hg qpush
+ mq status file refers to unknown node * (glob)
+ abort: working directory revision is not qtip
+ [255]
+ $ rm .hg/patches/status .hg/patches/status.orig
+
+
+bar should be gone; other unknown/ignored files should still be around
+
+ $ hg status -A
+ ? untracked-file
+ I .hgignore
+ C foo
+
+preparing qpush of a missing patch
+
+ $ hg qpop -a
+ no patches applied
+ $ hg qpush
+ applying patch1
+ now at: patch1
+ $ rm .hg/patches/patch2
+
+now we expect the push to fail, but it should NOT complain about patch1
+
+ $ hg qpush
+ applying patch2
+ unable to read patch2
+ now at: patch1
+ [1]
+
+preparing qpush of missing patch with no patch applied
+
+ $ hg qpop -a
+ popping patch1
+ patch queue now empty
+ $ rm .hg/patches/patch1
+
+qpush should fail the same way as below
+
+ $ hg qpush
+ applying patch1
+ unable to read patch1
+ [1]
+
+Test qpush to a patch below the currently applied patch.
+
+ $ hg qq -c guardedseriesorder
+ $ hg qnew a
+ $ hg qguard +block
+ $ hg qnew b
+ $ hg qnew c
+
+ $ hg qpop -a
+ popping c
+ popping b
+ popping a
+ patch queue now empty
+
+try to push and pop while a is guarded
+
+ $ hg qpush a
+ cannot push 'a' - guarded by '+block'
+ [1]
+ $ hg qpush -a
+ applying b
+ patch b is empty
+ applying c
+ patch c is empty
+ now at: c
+
+now try it when a is unguarded, and we're at the top of the queue
+ $ hg qsel block
+ number of guarded, applied patches has changed from 1 to 0
+ $ hg qpush b
+ abort: cannot push to a previous patch: b
+ [255]
+ $ hg qpush a
+ abort: cannot push to a previous patch: a
+ [255]
+
+and now we try it one more time with a unguarded, while we're not at the top of the queue
+
+ $ hg qpop b
+ popping c
+ now at: b
+ $ hg qpush a
+ abort: cannot push to a previous patch: a
+ [255]
+
+test qpop --force and backup files
+
+ $ hg qpop -a
+ popping b
+ patch queue now empty
+ $ hg qq --create force
+ $ echo a > a
+ $ echo b > b
+ $ echo c > c
+ $ hg ci -Am add a b c
+ $ echo a >> a
+ $ hg rm b
+ $ hg rm c
+ $ hg qnew p1
+ $ echo a >> a
+ $ echo bb > b
+ $ hg add b
+ $ echo cc > c
+ $ hg add c
+ $ hg qpop --force --verbose
+ saving current version of a as a.orig
+ saving current version of b as b.orig
+ saving current version of c as c.orig
+ popping p1
+ patch queue now empty
+ $ hg st
+ ? a.orig
+ ? b.orig
+ ? c.orig
+ ? untracked-file
+ $ cat a.orig
+ a
+ a
+ a
+ $ cat b.orig
+ bb
+ $ cat c.orig
+ cc
+
+test qpop --force --no-backup
+
+ $ hg qpush
+ applying p1
+ now at: p1
+ $ rm a.orig
+ $ echo a >> a
+ $ hg qpop --force --no-backup --verbose
+ popping p1
+ patch queue now empty
+ $ test -f a.orig && echo 'error: backup with --no-backup'
+ [1]
+
+test qpop --keep-changes
+
+ $ hg qpush
+ applying p1
+ now at: p1
+ $ hg qpop --keep-changes --force
+ abort: cannot use both --force and --keep-changes
+ [255]
+ $ echo a >> a
+ $ hg qpop --keep-changes
+ abort: local changes found, refresh first
+ [255]
+ $ hg revert -qa a
+ $ rm a
+ $ hg qpop --keep-changes
+ abort: local changes found, refresh first
+ [255]
+ $ hg rm -A a
+ $ hg qpop --keep-changes
+ abort: local changes found, refresh first
+ [255]
+ $ hg revert -qa a
+ $ echo b > b
+ $ hg add b
+ $ hg qpop --keep-changes
+ abort: local changes found, refresh first
+ [255]
+ $ hg forget b
+ $ echo d > d
+ $ hg add d
+ $ hg qpop --keep-changes
+ popping p1
+ patch queue now empty
+ $ hg forget d
+ $ rm d
+
+test qpush --force and backup files
+
+ $ echo a >> a
+ $ hg qnew p2
+ $ echo b >> b
+ $ echo d > d
+ $ echo e > e
+ $ hg add d e
+ $ hg rm c
+ $ hg qnew p3
+ $ hg qpop -a
+ popping p3
+ popping p2
+ patch queue now empty
+ $ echo a >> a
+ $ echo b1 >> b
+ $ echo d1 > d
+ $ hg add d
+ $ echo e1 > e
+ $ hg qpush -a --force --verbose
+ applying p2
+ saving current version of a as a.orig
+ patching file a
+ a
+ applying p3
+ saving current version of b as b.orig
+ saving current version of d as d.orig
+ patching file b
+ patching file c
+ patching file d
+ file d already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file d.rej
+ patching file e
+ file e already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file e.rej
+ patch failed to apply
+ b
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh p3
+ [2]
+ $ cat a.orig
+ a
+ a
+ $ cat b.orig
+ b
+ b1
+ $ cat d.orig
+ d1
+
+test qpush --force --no-backup
+
+ $ hg revert -qa
+ $ hg qpop -a
+ popping p3
+ popping p2
+ patch queue now empty
+ $ echo a >> a
+ $ rm a.orig
+ $ hg qpush --force --no-backup --verbose
+ applying p2
+ patching file a
+ a
+ now at: p2
+ $ test -f a.orig && echo 'error: backup with --no-backup'
+ [1]
+
+test qgoto --force --no-backup
+
+ $ hg qpop
+ popping p2
+ patch queue now empty
+ $ echo a >> a
+ $ hg qgoto --force --no-backup p2 --verbose
+ applying p2
+ patching file a
+ a
+ now at: p2
+ $ test -f a.orig && echo 'error: backup with --no-backup'
+ [1]
+
+test qpush --keep-changes
+
+ $ hg qpush --keep-changes --force
+ abort: cannot use both --force and --keep-changes
+ [255]
+ $ hg qpush --keep-changes --exact
+ abort: cannot use --exact and --keep-changes together
+ [255]
+ $ echo b >> b
+ $ hg qpush --keep-changes
+ applying p3
+ errors during apply, please fix and refresh p2
+ [2]
+ $ rm b
+ $ hg qpush --keep-changes
+ applying p3
+ errors during apply, please fix and refresh p2
+ [2]
+ $ hg rm -A b
+ $ hg qpush --keep-changes
+ applying p3
+ errors during apply, please fix and refresh p2
+ [2]
+ $ hg revert -aq b
+ $ echo d > d
+ $ hg add d
+ $ hg qpush --keep-changes
+ applying p3
+ errors during apply, please fix and refresh p2
+ [2]
+ $ hg forget d
+ $ rm d
+ $ hg qpop
+ popping p2
+ patch queue now empty
+ $ echo b >> b
+ $ hg qpush -a --keep-changes
+ applying p2
+ applying p3
+ errors during apply, please fix and refresh p2
+ [2]
+ $ hg qtop
+ p2
+ $ hg parents --template "{rev} {desc}\n"
+ 2 imported patch p2
+ $ hg st b
+ M b
+ $ cat b
+ b
+ b
+
+test qgoto --keep-changes
+
+ $ hg revert -aq b
+ $ rm e
+ $ hg qgoto --keep-changes --force p3
+ abort: cannot use both --force and --keep-changes
+ [255]
+ $ echo a >> a
+ $ hg qgoto --keep-changes p3
+ applying p3
+ now at: p3
+ $ hg st a
+ M a
+ $ hg qgoto --keep-changes p2
+ popping p3
+ now at: p2
+ $ hg st a
+ M a
+
+test mq.keepchanges setting
+
+ $ hg --config mq.keepchanges=1 qpush
+ applying p3
+ now at: p3
+ $ hg st a
+ M a
+ $ hg --config mq.keepchanges=1 qpop
+ popping p3
+ now at: p2
+ $ hg st a
+ M a
+ $ hg --config mq.keepchanges=1 qgoto p3
+ applying p3
+ now at: p3
+ $ hg st a
+ M a
+ $ echo b >> b
+ $ hg --config mq.keepchanges=1 qpop --force
+ popping p3
+ now at: p2
+ $ hg st b
+ $ hg --config mq.keepchanges=1 qpush --exact
+ abort: local changes found, refresh first
+ [255]
+ $ hg revert -qa a
+ $ hg qpop
+ popping p2
+ patch queue now empty
+ $ echo a >> a
+ $ hg --config mq.keepchanges=1 qpush --force
+ applying p2
+ now at: p2
+ $ hg st a
+
+ $ cd ..
diff --git a/tests/test-mq-qqueue.t b/tests/test-mq-qqueue.t
new file mode 100644
index 0000000..00d3299
--- /dev/null
+++ b/tests/test-mq-qqueue.t
@@ -0,0 +1,188 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init foo
+ $ cd foo
+ $ echo a > a
+ $ hg ci -qAm a
+
+Default queue:
+
+ $ hg qqueue
+ patches (active)
+
+ $ echo b > a
+ $ hg qnew -fgDU somestuff
+
+Applied patches in default queue:
+
+ $ hg qap
+ somestuff
+
+Try to change patch (create succeeds, switch fails):
+
+ $ hg qqueue foo --create
+ abort: patches applied - cannot set new queue active
+ [255]
+
+ $ hg qqueue
+ foo
+ patches (active)
+
+Empty default queue:
+
+ $ hg qpop
+ popping somestuff
+ patch queue now empty
+
+Switch queue:
+
+ $ hg qqueue foo
+ $ hg qqueue
+ foo (active)
+ patches
+
+List queues, quiet:
+
+ $ hg qqueue --quiet
+ foo
+ patches
+
+Fail creating queue with already existing name:
+
+ $ hg qqueue --create foo
+ abort: queue "foo" already exists
+ [255]
+
+ $ hg qqueue
+ foo (active)
+ patches
+
+Create new queue for rename:
+
+ $ hg qqueue --create bar
+
+ $ hg qqueue
+ bar (active)
+ foo
+ patches
+
+Rename queue, same name:
+
+ $ hg qqueue --rename bar
+ abort: can't rename "bar" to its current name
+ [255]
+
+Rename queue to existing:
+
+ $ hg qqueue --rename foo
+ abort: queue "foo" already exists
+ [255]
+
+Rename queue:
+
+ $ hg qqueue --rename buz
+
+ $ hg qqueue
+ buz (active)
+ foo
+ patches
+
+Switch back to previous queue:
+
+ $ hg qqueue foo
+ $ hg qqueue --delete buz
+
+ $ hg qqueue
+ foo (active)
+ patches
+
+Create queue for purge:
+
+ $ hg qqueue --create purge-me
+
+ $ hg qqueue
+ foo
+ patches
+ purge-me (active)
+
+Create patch for purge:
+
+ $ hg qnew patch-purge-me
+
+ $ ls -1d .hg/patches-purge-me 2>/dev/null || true
+ .hg/patches-purge-me
+
+ $ hg qpop -a
+ popping patch-purge-me
+ patch queue now empty
+
+Purge queue:
+
+ $ hg qqueue foo
+ $ hg qqueue --purge purge-me
+
+ $ hg qqueue
+ foo (active)
+ patches
+
+ $ ls -1d .hg/patches-purge-me 2>/dev/null || true
+
+Unapplied patches:
+
+ $ hg qun
+ $ echo c > a
+ $ hg qnew -fgDU otherstuff
+
+Fail switching back:
+
+ $ hg qqueue patches
+ abort: patches applied - cannot set new queue active
+ [255]
+
+Fail deleting current:
+
+ $ hg qqueue foo --delete
+ abort: cannot delete currently active queue
+ [255]
+
+Switch back and delete foo:
+
+ $ hg qpop -a
+ popping otherstuff
+ patch queue now empty
+
+ $ hg qqueue patches
+ $ hg qqueue foo --delete
+ $ hg qqueue
+ patches (active)
+
+Tricky cases:
+
+ $ hg qqueue store --create
+ $ hg qnew journal
+
+ $ hg qqueue
+ patches
+ store (active)
+
+ $ hg qpop -a
+ popping journal
+ patch queue now empty
+
+ $ hg qqueue patches
+ $ hg qun
+ somestuff
+
+Invalid names:
+
+ $ hg qqueue test/../../bar --create
+ abort: invalid queue name, may not contain the characters ":\/."
+ [255]
+
+ $ hg qqueue . --create
+ abort: invalid queue name, may not contain the characters ":\/."
+ [255]
+
+ $ cd ..
+
diff --git a/tests/test-mq-qrefresh-interactive.t b/tests/test-mq-qrefresh-interactive.t
new file mode 100644
index 0000000..41c27ce
--- /dev/null
+++ b/tests/test-mq-qrefresh-interactive.t
@@ -0,0 +1,350 @@
+Create configuration
+
+ $ echo "[ui]" >> $HGRCPATH
+ $ echo "interactive=true" >> $HGRCPATH
+
+help qrefresh (no record)
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ hg help qrefresh
+ hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...
+
+ update the current patch
+
+ If any file patterns are provided, the refreshed patch will contain only
+ the modifications that match those patterns; the remaining modifications
+ will remain in the working directory.
+
+ If -s/--short is specified, files currently included in the patch will be
+ refreshed just like matched files and remain in the patch.
+
+ If -e/--edit is specified, Mercurial will start your configured editor for
+ you to enter a message. In case qrefresh fails, you will find a backup of
+ your message in ".hg/last-message.txt".
+
+ hg add/remove/copy/rename work as usual, though you might want to use git-
+ style patches (-g/--git or [diff] git=1) to track copies and renames. See
+ the diffs help topic for more information on the git diff format.
+
+ Returns 0 on success.
+
+ options:
+
+ -e --edit edit commit message
+ -g --git use git extended diff format
+ -s --short refresh only files already in the patch and
+ specified files
+ -U --currentuser add/update author field in patch with current user
+ -u --user USER add/update author field in patch with given user
+ -D --currentdate add/update date field in patch with current date
+ -d --date DATE add/update date field in patch with given date
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+ -m --message TEXT use text as commit message
+ -l --logfile FILE read commit message from file
+
+ [+] marked option can be specified multiple times
+
+ use "hg -v help qrefresh" to show more info
+
+help qrefresh (record)
+
+ $ echo "record=" >> $HGRCPATH
+ $ hg help qrefresh
+ hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...
+
+ update the current patch
+
+ If any file patterns are provided, the refreshed patch will contain only
+ the modifications that match those patterns; the remaining modifications
+ will remain in the working directory.
+
+ If -s/--short is specified, files currently included in the patch will be
+ refreshed just like matched files and remain in the patch.
+
+ If -e/--edit is specified, Mercurial will start your configured editor for
+ you to enter a message. In case qrefresh fails, you will find a backup of
+ your message in ".hg/last-message.txt".
+
+ hg add/remove/copy/rename work as usual, though you might want to use git-
+ style patches (-g/--git or [diff] git=1) to track copies and renames. See
+ the diffs help topic for more information on the git diff format.
+
+ Returns 0 on success.
+
+ options:
+
+ -e --edit edit commit message
+ -g --git use git extended diff format
+ -s --short refresh only files already in the patch and
+ specified files
+ -U --currentuser add/update author field in patch with current user
+ -u --user USER add/update author field in patch with given user
+ -D --currentdate add/update date field in patch with current date
+ -d --date DATE add/update date field in patch with given date
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+ -m --message TEXT use text as commit message
+ -l --logfile FILE read commit message from file
+ -i --interactive interactively select changes to refresh
+
+ [+] marked option can be specified multiple times
+
+ use "hg -v help qrefresh" to show more info
+
+ $ hg init a
+ $ cd a
+
+Base commit
+
+ $ cat > 1.txt <<EOF
+ > 1
+ > 2
+ > 3
+ > 4
+ > 5
+ > EOF
+ $ cat > 2.txt <<EOF
+ > a
+ > b
+ > c
+ > d
+ > e
+ > f
+ > EOF
+
+ $ mkdir dir
+ $ cat > dir/a.txt <<EOF
+ > hello world
+ >
+ > someone
+ > up
+ > there
+ > loves
+ > me
+ > EOF
+
+ $ hg add 1.txt 2.txt dir/a.txt
+ $ hg commit -m aaa
+ $ hg qnew -d '0 0' patch
+
+Changing files
+
+ $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
+ $ sed -e 's/b/b b/' 2.txt > 2.txt.new
+ $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
+
+ $ mv -f 1.txt.new 1.txt
+ $ mv -f 2.txt.new 2.txt
+ $ mv -f dir/a.txt.new dir/a.txt
+
+Whole diff
+
+ $ hg diff --nodates
+ diff -r ed27675cb5df 1.txt
+ --- a/1.txt
+ +++ b/1.txt
+ @@ -1,5 +1,5 @@
+ 1
+ -2
+ +2 2
+ 3
+ -4
+ +4 4
+ 5
+ diff -r ed27675cb5df 2.txt
+ --- a/2.txt
+ +++ b/2.txt
+ @@ -1,5 +1,5 @@
+ a
+ -b
+ +b b
+ c
+ d
+ e
+ diff -r ed27675cb5df dir/a.txt
+ --- a/dir/a.txt
+ +++ b/dir/a.txt
+ @@ -1,4 +1,4 @@
+ -hello world
+ +hello world!
+
+ someone
+ up
+
+partial qrefresh
+
+ $ hg qrefresh -i -d '0 0' <<EOF
+ > y
+ > y
+ > n
+ > y
+ > y
+ > n
+ > EOF
+ diff --git a/1.txt b/1.txt
+ 2 hunks, 2 lines changed
+ examine changes to '1.txt'? [Ynesfdaq?]
+ @@ -1,3 +1,3 @@
+ 1
+ -2
+ +2 2
+ 3
+ record change 1/4 to '1.txt'? [Ynesfdaq?]
+ @@ -3,3 +3,3 @@
+ 3
+ -4
+ +4 4
+ 5
+ record change 2/4 to '1.txt'? [Ynesfdaq?]
+ diff --git a/2.txt b/2.txt
+ 1 hunks, 1 lines changed
+ examine changes to '2.txt'? [Ynesfdaq?]
+ @@ -1,5 +1,5 @@
+ a
+ -b
+ +b b
+ c
+ d
+ e
+ record change 3/4 to '2.txt'? [Ynesfdaq?]
+ diff --git a/dir/a.txt b/dir/a.txt
+ 1 hunks, 1 lines changed
+ examine changes to 'dir/a.txt'? [Ynesfdaq?]
+
+After partial qrefresh 'tip'
+
+ $ hg tip -p
+ changeset: 1:0738af1a8211
+ tag: patch
+ tag: qbase
+ tag: qtip
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: [mq]: patch
+
+ diff -r 1fd39ab63a33 -r 0738af1a8211 1.txt
+ --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,5 +1,5 @@
+ 1
+ -2
+ +2 2
+ 3
+ 4
+ 5
+ diff -r 1fd39ab63a33 -r 0738af1a8211 2.txt
+ --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,5 +1,5 @@
+ a
+ -b
+ +b b
+ c
+ d
+ e
+
+After partial qrefresh 'diff'
+
+ $ hg diff --nodates
+ diff -r 0738af1a8211 1.txt
+ --- a/1.txt
+ +++ b/1.txt
+ @@ -1,5 +1,5 @@
+ 1
+ 2 2
+ 3
+ -4
+ +4 4
+ 5
+ diff -r 0738af1a8211 dir/a.txt
+ --- a/dir/a.txt
+ +++ b/dir/a.txt
+ @@ -1,4 +1,4 @@
+ -hello world
+ +hello world!
+
+ someone
+ up
+
+qrefresh interactively everything else
+
+ $ hg qrefresh -i -d '0 0' <<EOF
+ > y
+ > y
+ > y
+ > y
+ > EOF
+ diff --git a/1.txt b/1.txt
+ 1 hunks, 1 lines changed
+ examine changes to '1.txt'? [Ynesfdaq?]
+ @@ -1,5 +1,5 @@
+ 1
+ 2 2
+ 3
+ -4
+ +4 4
+ 5
+ record change 1/2 to '1.txt'? [Ynesfdaq?]
+ diff --git a/dir/a.txt b/dir/a.txt
+ 1 hunks, 1 lines changed
+ examine changes to 'dir/a.txt'? [Ynesfdaq?]
+ @@ -1,4 +1,4 @@
+ -hello world
+ +hello world!
+
+ someone
+ up
+ record change 2/2 to 'dir/a.txt'? [Ynesfdaq?]
+
+After final qrefresh 'tip'
+
+ $ hg tip -p
+ changeset: 1:2c3f66afeed9
+ tag: patch
+ tag: qbase
+ tag: qtip
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: [mq]: patch
+
+ diff -r 1fd39ab63a33 -r 2c3f66afeed9 1.txt
+ --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,5 +1,5 @@
+ 1
+ -2
+ +2 2
+ 3
+ -4
+ +4 4
+ 5
+ diff -r 1fd39ab63a33 -r 2c3f66afeed9 2.txt
+ --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,5 +1,5 @@
+ a
+ -b
+ +b b
+ c
+ d
+ e
+ diff -r 1fd39ab63a33 -r 2c3f66afeed9 dir/a.txt
+ --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,4 +1,4 @@
+ -hello world
+ +hello world!
+
+ someone
+ up
+
+
+After qrefresh 'diff'
+
+ $ hg diff --nodates
+
+ $ cd ..
diff --git a/tests/test-mq-qrefresh-replace-log-message.t b/tests/test-mq-qrefresh-replace-log-message.t
new file mode 100644
index 0000000..40ffa29
--- /dev/null
+++ b/tests/test-mq-qrefresh-replace-log-message.t
@@ -0,0 +1,61 @@
+Environement setup for MQ
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ hg init
+ $ hg qinit
+
+Should fail if no patches applied
+
+ $ hg qrefresh
+ no patches applied
+ [1]
+ $ hg qrefresh -e
+ no patches applied
+ [1]
+ $ hg qnew -m "First commit message" first-patch
+ $ echo aaaa > file
+ $ hg add file
+ $ hg qrefresh
+
+Should display 'First commit message'
+
+ $ hg log -l1 --template "{desc}\n"
+ First commit message
+
+Testing changing message with -m
+
+ $ echo bbbb > file
+ $ hg qrefresh -m "Second commit message"
+
+Should display 'Second commit message'
+
+ $ hg log -l1 --template "{desc}\n"
+ Second commit message
+
+Testing changing message with -l
+
+ $ echo "Third commit message" > logfile
+ $ echo " This is the 3rd log message" >> logfile
+ $ echo bbbb > file
+ $ hg qrefresh -l logfile
+
+Should display 'Third commit message\\\n This is the 3rd log message'
+
+ $ hg log -l1 --template "{desc}\n"
+ Third commit message
+ This is the 3rd log message
+
+Testing changing message with -l-
+
+ $ hg qnew -m "First commit message" second-patch
+ $ echo aaaa > file2
+ $ hg add file2
+ $ echo bbbb > file2
+ $ (echo "Fifth commit message"; echo " This is the 5th log message") | hg qrefresh -l-
+
+Should display 'Fifth commit message\\\n This is the 5th log message'
+
+ $ hg log -l1 --template "{desc}\n"
+ Fifth commit message
+ This is the 5th log message
diff --git a/tests/test-mq-qrefresh.t b/tests/test-mq-qrefresh.t
new file mode 100644
index 0000000..700380e
--- /dev/null
+++ b/tests/test-mq-qrefresh.t
@@ -0,0 +1,546 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "nodates=1" >> $HGRCPATH
+
+ $ hg init a
+ $ cd a
+
+ $ mkdir 1 2
+ $ echo 'base' > 1/base
+ $ echo 'base' > 2/base
+ $ hg ci -Ambase
+ adding 1/base
+ adding 2/base
+
+ $ hg qnew -mmqbase mqbase
+
+ $ echo 'patched' > 1/base
+ $ echo 'patched' > 2/base
+ $ hg qrefresh
+
+ $ hg qdiff
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ hg qdiff .
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ cat .hg/patches/mqbase
+ # HG changeset patch
+ # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
+ mqbase
+
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ echo 'patched again' > base
+ $ hg qrefresh 1
+
+ $ hg qdiff
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ hg qdiff .
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ cat .hg/patches/mqbase
+ # HG changeset patch
+ # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
+ mqbase
+
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+qrefresh . in subdir:
+
+ $ ( cd 1 ; hg qrefresh . )
+
+ $ hg qdiff
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ hg qdiff .
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ cat .hg/patches/mqbase
+ # HG changeset patch
+ # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
+ mqbase
+
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+qrefresh in hg-root again:
+
+ $ hg qrefresh
+
+ $ hg qdiff
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ hg qdiff .
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ cat .hg/patches/mqbase
+ # HG changeset patch
+ # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
+ mqbase
+
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+
+qrefresh --short tests:
+
+ $ echo 'orphan' > orphanchild
+ $ hg add orphanchild
+ $ hg qrefresh nonexistingfilename # clear patch
+ $ hg qrefresh --short 1/base
+ $ hg qrefresh --short 2/base
+
+ $ hg qdiff
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 orphanchild
+ --- /dev/null
+ +++ b/orphanchild
+ @@ -0,0 +1,1 @@
+ +orphan
+
+ $ cat .hg/patches/mqbase
+ # HG changeset patch
+ # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
+ mqbase
+
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ hg st
+ A orphanchild
+ ? base
+
+diff shows what is not in patch:
+
+ $ hg diff
+ diff -r ???????????? orphanchild (glob)
+ --- /dev/null
+ +++ b/orphanchild
+ @@ -0,0 +1,1 @@
+ +orphan
+
+Before starting exclusive tests:
+
+ $ cat .hg/patches/mqbase
+ # HG changeset patch
+ # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
+ mqbase
+
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+Exclude 2/base:
+
+ $ hg qref -s -X 2/base
+
+ $ cat .hg/patches/mqbase
+ # HG changeset patch
+ # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
+ mqbase
+
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+status shows 2/base as dirty:
+
+ $ hg status
+ M 2/base
+ A orphanchild
+ ? base
+
+Remove 1/base and add 2/base again but not orphanchild:
+
+ $ hg qref -s -X orphanchild -X 1/base 2/base orphanchild
+
+ $ cat .hg/patches/mqbase
+ # HG changeset patch
+ # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
+ mqbase
+
+ diff -r e7af5904b465 2/base
+ --- a/2/base
+ +++ b/2/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+Add 1/base with include filter - and thus remove 2/base from patch:
+
+ $ hg qref -s -I 1/ o* */*
+
+ $ cat .hg/patches/mqbase
+ # HG changeset patch
+ # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
+ mqbase
+
+ diff -r e7af5904b465 1/base
+ --- a/1/base
+ +++ b/1/base
+ @@ -1,1 +1,1 @@
+ -base
+ +patched
+
+ $ cd ..
+
+
+Test qrefresh --git losing copy metadata:
+
+ $ hg init repo
+ $ cd repo
+
+ $ echo "[diff]" >> .hg/hgrc
+ $ echo "git=True" >> .hg/hgrc
+ $ echo a > a
+
+ $ hg ci -Am adda
+ adding a
+ $ hg copy a ab
+ $ echo b >> ab
+ $ hg copy a ac
+ $ echo c >> ac
+
+Capture changes:
+
+ $ hg qnew -f p1
+
+ $ hg qdiff
+ diff --git a/a b/ab
+ copy from a
+ copy to ab
+ --- a/a
+ +++ b/ab
+ @@ -1,1 +1,2 @@
+ a
+ +b
+ diff --git a/a b/ac
+ copy from a
+ copy to ac
+ --- a/a
+ +++ b/ac
+ @@ -1,1 +1,2 @@
+ a
+ +c
+
+Refresh and check changes again:
+
+ $ hg qrefresh
+
+ $ hg qdiff
+ diff --git a/a b/ab
+ copy from a
+ copy to ab
+ --- a/a
+ +++ b/ab
+ @@ -1,1 +1,2 @@
+ a
+ +b
+ diff --git a/a b/ac
+ copy from a
+ copy to ac
+ --- a/a
+ +++ b/ac
+ @@ -1,1 +1,2 @@
+ a
+ +c
+
+ $ cd ..
+
+
+Issue1441: qrefresh confused after hg rename:
+
+ $ hg init repo-1441
+ $ cd repo-1441
+ $ echo a > a
+ $ hg add a
+ $ hg qnew -f p
+ $ hg mv a b
+ $ hg qrefresh
+
+ $ hg qdiff
+ diff -r 000000000000 b
+ --- /dev/null
+ +++ b/b
+ @@ -0,0 +1,1 @@
+ +a
+
+ $ cd ..
+
+
+Issue2025: qrefresh does not honor filtering options when tip !=
+qtip:
+
+ $ hg init repo-2025
+ $ cd repo-2025
+ $ echo a > a
+ $ echo b > b
+ $ hg ci -qAm addab
+ $ echo a >> a
+ $ echo b >> b
+ $ hg qnew -f patch
+ $ hg up -qC 0
+ $ echo c > c
+ $ hg ci -qAm addc
+ $ hg up -qC 1
+
+refresh with tip != qtip:
+
+ $ hg --config diff.nodates=1 qrefresh -I b
+
+ $ hg st
+ M a
+
+ $ cat b
+ b
+ b
+
+ $ cat .hg/patches/patch
+ # HG changeset patch
+ # Parent 1a60229be7ac3e4a7f647508e99b87bef1f03593
+
+ diff -r 1a60229be7ac b
+ --- a/b
+ +++ b/b
+ @@ -1,1 +1,2 @@
+ b
+ +b
+
+ $ cd ..
+
+
+Issue1441 with git patches:
+
+ $ hg init repo-1441-git
+ $ cd repo-1441-git
+
+ $ echo "[diff]" >> .hg/hgrc
+ $ echo "git=True" >> .hg/hgrc
+
+ $ echo a > a
+ $ hg add a
+ $ hg qnew -f p
+ $ hg mv a b
+ $ hg qrefresh
+
+ $ hg qdiff --nodates
+ diff --git a/b b/b
+ new file mode 100644
+ --- /dev/null
+ +++ b/b
+ @@ -0,0 +1,1 @@
+ +a
+
+ $ cd ..
+
+Refresh with bad usernames. Mercurial used to abort on bad usernames,
+but only after writing the bad name into the patch.
+
+ $ hg init bad-usernames
+ $ cd bad-usernames
+ $ touch a
+ $ hg add a
+ $ hg qnew a
+ $ hg qrefresh -u 'foo
+ > bar'
+ transaction abort!
+ rollback completed
+ refresh interrupted while patch was popped! (revert --all, qpush to recover)
+ abort: username 'foo\nbar' contains a newline!
+ [255]
+ $ rm a
+ $ cat .hg/patches/a
+ # HG changeset patch
+ # Parent 0000000000000000000000000000000000000000
+ diff --git a/a b/a
+ new file mode 100644
+ $ hg qpush
+ applying a
+ now at: a
+ $ hg qrefresh -u ' '
+ transaction abort!
+ rollback completed
+ refresh interrupted while patch was popped! (revert --all, qpush to recover)
+ abort: empty username!
+ [255]
+ $ cat .hg/patches/a
+ # HG changeset patch
+ # Parent 0000000000000000000000000000000000000000
+ diff --git a/a b/a
+ new file mode 100644
+ $ cd ..
+
+Refresh with phase data:
+
+
+
+ $ cd repo
+ $ echo 'babar' >> a
+ $ hg qnew -m 'update a' p2.diff
+ $ hg phase p2.diff
+ 2: draft
+ $ echo 'beber' >> a
+ $ hg qref
+ $ hg phase p2.diff
+ 2: draft
+ $ hg phase --force --secret p2.diff
+ $ echo 'bibir' >> a
+ $ hg qref
+ $ hg phase p2.diff
+ 2: secret
+
+ $ cd ..
diff --git a/tests/test-mq-qrename.t b/tests/test-mq-qrename.t
new file mode 100644
index 0000000..6baf88c
--- /dev/null
+++ b/tests/test-mq-qrename.t
@@ -0,0 +1,125 @@
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init a
+ $ cd a
+
+ $ echo 'base' > base
+ $ hg ci -Ambase
+ adding base
+
+ $ hg qnew -mmqbase mqbase
+
+ $ hg qrename mqbase renamed
+ $ mkdir .hg/patches/foo
+ $ hg qrename renamed foo
+
+ $ hg qseries
+ foo/renamed
+
+ $ ls .hg/patches/foo
+ renamed
+
+ $ mkdir .hg/patches/bar
+ $ hg qrename foo/renamed bar
+
+ $ hg qseries
+ bar/renamed
+
+ $ ls .hg/patches/bar
+ renamed
+
+ $ hg qrename bar/renamed baz
+
+ $ hg qseries
+ baz
+
+ $ ls .hg/patches/baz
+ .hg/patches/baz
+
+ $ hg qrename baz new/dir
+
+ $ hg qseries
+ new/dir
+
+ $ ls .hg/patches/new/dir
+ .hg/patches/new/dir
+
+ $ cd ..
+
+Test patch being renamed before committed:
+
+ $ hg init b
+ $ cd b
+ $ hg qinit -c
+ $ hg qnew x
+ $ hg qrename y
+ $ hg qcommit -m rename
+
+ $ cd ..
+
+Test overlapping renames (issue2388)
+
+ $ hg init c
+ $ cd c
+ $ hg qinit -c
+ $ echo a > a
+ $ hg add
+ adding a
+ $ hg qnew patcha
+ $ echo b > b
+ $ hg add
+ adding b
+ $ hg qnew patchb
+ $ hg ci --mq -m c1
+ $ hg qrename patchb patchc
+ $ hg qrename patcha patchb
+ $ hg st --mq
+ M series
+ A patchb
+ A patchc
+ R patcha
+ $ cd ..
+
+Test renames with mq repo (issue2097)
+
+ $ hg init issue2097
+ $ cd issue2097
+ $ hg qnew p0
+ $ (cd .hg/patches && hg init)
+ $ hg qren p0 p1
+ $ hg debugstate --mq
+ $ hg ci --mq -mq0
+ nothing changed
+ [1]
+ $ cd ..
+
+Test renaming to a folded patch (issue3058)
+
+ $ hg init issue3058
+ $ cd issue3058
+ $ hg init --mq
+ $ echo a > a
+ $ hg add a
+ $ hg qnew adda
+ $ echo b >> a
+ $ hg qnew addb
+ $ hg qpop
+ popping addb
+ now at: adda
+ $ hg ci --mq -m "save mq"
+ $ hg qfold addb
+ $ hg qmv addb
+ $ cat .hg/patches/addb
+ # HG changeset patch
+ # Parent 0000000000000000000000000000000000000000
+
+ diff -r 000000000000 a
+ --- /dev/null * (glob)
+ +++ b/a * (glob)
+ @@ -0,0 +1,2 @@
+ +a
+ +b
+ $ cd ..
+
diff --git a/tests/test-mq-qsave.t b/tests/test-mq-qsave.t
new file mode 100644
index 0000000..9754de1
--- /dev/null
+++ b/tests/test-mq-qsave.t
@@ -0,0 +1,15 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init
+
+ $ echo 'base' > base
+ $ hg ci -Ambase
+ adding base
+
+ $ hg qnew -mmqbase mqbase
+
+ $ hg qsave
+ $ hg qrestore 2
+ restoring status: hg patches saved state
+
diff --git a/tests/test-mq-safety.t b/tests/test-mq-safety.t
new file mode 100644
index 0000000..d6fe35d
--- /dev/null
+++ b/tests/test-mq-safety.t
@@ -0,0 +1,216 @@
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo 'hgext.mq =' >> $HGRCPATH
+ $ echo 'hgext.graphlog =' >> $HGRCPATH
+
+ $ hg init repo
+ $ cd repo
+
+ $ echo foo > foo
+ $ hg ci -qAm 'add a file'
+
+ $ hg qinit
+
+ $ hg qnew foo
+ $ echo foo >> foo
+ $ hg qrefresh -m 'append foo'
+
+ $ hg qnew bar
+ $ echo bar >> foo
+ $ hg qrefresh -m 'append bar'
+
+Try to operate on public mq changeset
+
+ $ hg qpop
+ popping bar
+ now at: foo
+ $ hg phase --public qbase
+ $ echo babar >> foo
+ $ hg qref
+ abort: cannot refresh immutable revision
+ (see "hg help phases" for details)
+ [255]
+ $ hg revert -a
+ reverting foo
+ $ hg qpop
+ abort: popping would remove an immutable revision
+ (see "hg help phases" for details)
+ [255]
+ $ hg qfold bar
+ abort: cannot refresh immutable revision
+ (see "hg help phases" for details)
+ [255]
+ $ hg revert -a
+ reverting foo
+
+restore state for remaining test
+
+ $ hg qpush
+ applying bar
+ now at: bar
+
+try to commit on top of a patch
+
+ $ echo quux >> foo
+ $ hg ci -m 'append quux'
+ abort: cannot commit over an applied mq patch
+ [255]
+
+
+cheat a bit...
+
+ $ mv .hg/patches .hg/patches2
+ $ hg ci -m 'append quux'
+ $ mv .hg/patches2 .hg/patches
+
+
+qpop/qrefresh on the wrong revision
+
+ $ hg qpop
+ abort: popping would remove a revision not managed by this patch queue
+ [255]
+ $ hg qpop -n patches
+ using patch queue: $TESTTMP/repo/.hg/patches (glob)
+ abort: popping would remove a revision not managed by this patch queue
+ [255]
+ $ hg qrefresh
+ abort: working directory revision is not qtip
+ [255]
+
+ $ hg up -C qtip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg qpop
+ abort: popping would remove a revision not managed by this patch queue
+ [255]
+ $ hg qrefresh
+ abort: cannot refresh a revision with children
+ [255]
+ $ hg tip --template '{rev} {desc}\n'
+ 3 append quux
+
+
+qpush warning branchheads
+
+ $ cd ..
+ $ hg init branchy
+ $ cd branchy
+ $ echo q > q
+ $ hg add q
+ $ hg qnew -f qp
+ $ hg qpop
+ popping qp
+ patch queue now empty
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+ $ hg up null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg branch b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo c > c
+ $ hg ci -Amc
+ adding c
+ $ hg merge default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -mmerge
+ $ hg up default
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg log
+ changeset: 2:65309210bf4e
+ branch: b
+ tag: tip
+ parent: 1:707adb4c8ae1
+ parent: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: merge
+
+ changeset: 1:707adb4c8ae1
+ branch: b
+ parent: -1:000000000000
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: c
+
+ changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ hg qpush
+ applying qp
+ now at: qp
+
+Testing applied patches, push and --force
+
+ $ cd ..
+ $ hg init forcepush
+ $ cd forcepush
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ echo a >> a
+ $ hg ci -m changea
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch branch
+ marked working directory as branch branch
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b > b
+ $ hg ci -Am addb
+ adding b
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg --cwd .. clone -r 0 forcepush forcepush2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a >> a
+ $ hg qnew patch
+
+Pushing applied patch with --rev without --force
+
+ $ hg push -r . ../forcepush2
+ pushing to ../forcepush2
+ abort: source has mq patches applied
+ [255]
+
+Pushing applied patch with branchhash, without --force
+
+ $ hg push ../forcepush2#default
+ pushing to ../forcepush2
+ abort: source has mq patches applied
+ [255]
+
+Pushing revs excluding applied patch
+
+ $ hg push --new-branch -r 'branch(branch)' -r 2 ../forcepush2
+ pushing to ../forcepush2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+Pushing applied patch with --force
+
+ $ hg phase --force --secret 'mq()'
+ $ hg push --force -r default ../forcepush2
+ pushing to ../forcepush2
+ searching for changes
+ no changes found (ignored 1 secret changesets)
+ [1]
+ $ hg phase --draft 'mq()'
+ $ hg push --force -r default ../forcepush2
+ pushing to ../forcepush2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+
+ $ cd ..
diff --git a/tests/test-mq-strip.t b/tests/test-mq-strip.t
new file mode 100644
index 0000000..70fffb1
--- /dev/null
+++ b/tests/test-mq-strip.t
@@ -0,0 +1,468 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "graphlog=" >> $HGRCPATH
+
+ $ restore() {
+ > hg unbundle -q .hg/strip-backup/*
+ > rm .hg/strip-backup/*
+ > }
+ $ teststrip() {
+ > hg up -C $1
+ > echo % before update $1, strip $2
+ > hg parents
+ > hg --traceback strip $2
+ > echo % after update $1, strip $2
+ > hg parents
+ > restore
+ > }
+
+ $ hg init test
+ $ cd test
+
+ $ echo foo > bar
+ $ hg ci -Ama
+ adding bar
+
+ $ echo more >> bar
+ $ hg ci -Amb
+
+ $ echo blah >> bar
+ $ hg ci -Amc
+
+ $ hg up 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo blah >> bar
+ $ hg ci -Amd
+ created new head
+
+ $ echo final >> bar
+ $ hg ci -Ame
+
+ $ hg log
+ changeset: 4:443431ffac4f
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: e
+
+ changeset: 3:65bd5f99a4a3
+ parent: 1:ef3a871183d7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: d
+
+ changeset: 2:264128213d29
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: c
+
+ changeset: 1:ef3a871183d7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+ changeset: 0:9ab35a2d17cb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+ $ teststrip 4 4
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % before update 4, strip 4
+ changeset: 4:443431ffac4f
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: e
+
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+ % after update 4, strip 4
+ changeset: 3:65bd5f99a4a3
+ tag: tip
+ parent: 1:ef3a871183d7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: d
+
+ $ teststrip 4 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % before update 4, strip 3
+ changeset: 4:443431ffac4f
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: e
+
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+ % after update 4, strip 3
+ changeset: 1:ef3a871183d7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+ $ teststrip 1 4
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % before update 1, strip 4
+ changeset: 1:ef3a871183d7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+ % after update 1, strip 4
+ changeset: 1:ef3a871183d7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+ $ teststrip 4 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % before update 4, strip 2
+ changeset: 4:443431ffac4f
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: e
+
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+ % after update 4, strip 2
+ changeset: 3:443431ffac4f
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: e
+
+ $ teststrip 4 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ % before update 4, strip 1
+ changeset: 4:264128213d29
+ tag: tip
+ parent: 1:ef3a871183d7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: c
+
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+ % after update 4, strip 1
+ changeset: 0:9ab35a2d17cb
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ teststrip null 4
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ % before update null, strip 4
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+ % after update null, strip 4
+
+ $ hg log
+ changeset: 4:264128213d29
+ tag: tip
+ parent: 1:ef3a871183d7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: c
+
+ changeset: 3:443431ffac4f
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: e
+
+ changeset: 2:65bd5f99a4a3
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: d
+
+ changeset: 1:ef3a871183d7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+ changeset: 0:9ab35a2d17cb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+ $ hg up -C 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge 4
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+before strip of merge parent
+
+ $ hg parents
+ changeset: 2:65bd5f99a4a3
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: d
+
+ changeset: 4:264128213d29
+ tag: tip
+ parent: 1:ef3a871183d7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: c
+
+ $ hg strip 4
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+
+after strip of merge parent
+
+ $ hg parents
+ changeset: 1:ef3a871183d7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+ $ restore
+
+ $ hg up
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg glog
+ @ changeset: 4:264128213d29
+ | tag: tip
+ | parent: 1:ef3a871183d7
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ | o changeset: 3:443431ffac4f
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: e
+ | |
+ | o changeset: 2:65bd5f99a4a3
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 1:ef3a871183d7
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:9ab35a2d17cb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+2 is parent of 3, only one strip should happen
+
+ $ hg strip "roots(2)" 3
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+ $ hg glog
+ @ changeset: 2:264128213d29
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:ef3a871183d7
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:9ab35a2d17cb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ restore
+ $ hg glog
+ o changeset: 4:443431ffac4f
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: e
+ |
+ o changeset: 3:65bd5f99a4a3
+ | parent: 1:ef3a871183d7
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ | @ changeset: 2:264128213d29
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c
+ |
+ o changeset: 1:ef3a871183d7
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:9ab35a2d17cb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+2 different branches: 2 strips
+
+ $ hg strip 2 4
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+ $ hg glog
+ @ changeset: 2:65bd5f99a4a3
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: d
+ |
+ o changeset: 1:ef3a871183d7
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:9ab35a2d17cb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ restore
+
+2 different branches and a common ancestor: 1 strip
+
+ $ hg strip 1 "2|4"
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+ $ restore
+
+stripping an empty revset
+
+ $ hg strip "1 and not 1"
+ abort: empty revision set
+ [255]
+
+remove branchy history for qimport tests
+
+ $ hg strip 3
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+
+
+strip of applied mq should cleanup status file
+
+ $ hg up -C 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo fooagain >> bar
+ $ hg ci -mf
+ $ hg qimport -r tip:2
+
+applied patches before strip
+
+ $ hg qapplied
+ 2.diff
+ 3.diff
+ 4.diff
+
+stripping revision in queue
+
+ $ hg strip 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+
+applied patches after stripping rev in queue
+
+ $ hg qapplied
+ 2.diff
+
+stripping ancestor of queue
+
+ $ hg strip 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+
+applied patches after stripping ancestor of queue
+
+ $ hg qapplied
+
+Verify strip protects against stripping wc parent when there are uncommited mods
+
+ $ echo b > b
+ $ hg add b
+ $ hg ci -m 'b'
+ $ hg log --graph
+ @ changeset: 1:7519abd79d14
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b
+ |
+ o changeset: 0:9ab35a2d17cb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+
+ $ echo c > b
+ $ echo c > bar
+ $ hg strip tip
+ abort: local changes found
+ [255]
+ $ hg strip tip --keep
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+ $ hg log --graph
+ @ changeset: 0:9ab35a2d17cb
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ hg status
+ M bar
+ ? b
+ $ cd ..
+
+stripping many nodes on a complex graph (issue3299)
+
+ $ hg init issue3299
+ $ cd issue3299
+ $ hg debugbuilddag '@a.:a@b.:b.:x<a@a.:a<b@b.:b<a@a.:a'
+ $ hg strip 'not ancestors(x)'
+ saved backup bundle to $TESTTMP/issue3299/.hg/strip-backup/*-backup.hg (glob)
+
+test hg strip -B bookmark
+
+ $ cd ..
+ $ hg init bookmarks
+ $ cd bookmarks
+ $ hg debugbuilddag '..<2.*1/2:m<2+3:c<m+3:a<2.:b'
+ $ hg bookmark -r 'a' 'todelete'
+ $ hg bookmark -r 'b' 'B'
+ $ hg bookmark -r 'b' 'nostrip'
+ $ hg bookmark -r 'c' 'delete'
+ $ hg up -C todelete
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg strip -B nostrip
+ bookmark 'nostrip' deleted
+ abort: empty revision set
+ [255]
+ $ hg strip -B todelete
+ bookmark 'todelete' deleted
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob)
+ $ hg id -ir dcbb326fdec2
+ abort: unknown revision 'dcbb326fdec2'!
+ [255]
+ $ hg id -ir d62d843c9a01
+ d62d843c9a01
+ $ hg bookmarks
+ B 9:ff43616e5d0f
+ delete 6:2702dd0c91e7
+ $ hg strip -B delete
+ bookmark 'delete' deleted
+ saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob)
+ $ hg id -ir 6:2702dd0c91e7
+ abort: unknown revision '2702dd0c91e7'!
+ [255]
+
+ $ cd ..
diff --git a/tests/test-mq-subrepo-svn.t b/tests/test-mq-subrepo-svn.t
new file mode 100644
index 0000000..39e5c0b
--- /dev/null
+++ b/tests/test-mq-subrepo-svn.t
@@ -0,0 +1,54 @@
+ $ "$TESTDIR/hghave" svn13 || exit 80
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "nodates=1" >> $HGRCPATH
+
+fn to create new repository, and cd into it
+ $ mkrepo() {
+ > hg init $1
+ > cd $1
+ > hg qinit
+ > }
+
+
+handle svn subrepos safely
+
+ $ svnadmin create svn-repo-2499
+
+ $ SVNREPOPATH=`pwd`/svn-repo-2499/project
+#if windows
+ $ SVNREPOURL=file:///`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
+#else
+ $ SVNREPOURL=file://`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
+#endif
+
+ $ mkdir -p svn-project-2499/trunk
+ $ svn import -m 'init project' svn-project-2499 "$SVNREPOURL"
+ Adding svn-project-2499/trunk (glob)
+
+ Committed revision 1.
+
+qnew on repo w/svn subrepo
+ $ mkrepo repo-2499-svn-subrepo
+ $ svn co "$SVNREPOURL"/trunk sub
+ Checked out revision 1.
+ $ echo 'sub = [svn]sub' >> .hgsub
+ $ hg add .hgsub
+ $ hg status -S -X '**/format'
+ A .hgsub
+ $ hg qnew -m0 0.diff
+ $ cd sub
+ $ echo a > a
+ $ svn add a
+ A a
+ $ svn st
+ A* a (glob)
+ $ cd ..
+ $ hg status -S # doesn't show status for svn subrepos (yet)
+ $ hg qnew -m1 1.diff
+ abort: uncommitted changes in subrepository sub
+ [255]
+
+ $ cd ..
diff --git a/tests/test-mq-subrepo.t b/tests/test-mq-subrepo.t
new file mode 100644
index 0000000..948006a
--- /dev/null
+++ b/tests/test-mq-subrepo.t
@@ -0,0 +1,514 @@
+ $ echo "[ui]" >> $HGRCPATH
+ $ echo "commitsubrepos = Yes" >> $HGRCPATH
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "record=" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "nodates=1" >> $HGRCPATH
+
+ $ stdin=`pwd`/stdin.tmp
+
+fn to create new repository w/dirty subrepo, and cd into it
+ $ mkrepo() {
+ > hg init $1
+ > cd $1
+ > hg qinit
+ > }
+
+fn to create dirty subrepo
+ $ mksubrepo() {
+ > hg init $1
+ > cd $1
+ > echo a > a
+ > hg add
+ > cd ..
+ > }
+
+ $ testadd() {
+ > cat - > "$stdin"
+ > mksubrepo sub
+ > echo sub = sub >> .hgsub
+ > hg add .hgsub
+ > echo % abort when adding .hgsub w/dirty subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > echo [$?]
+ > hg -R sub ci -m0sub
+ > echo % update substate when adding .hgsub w/clean updated subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > hg debugsub
+ > }
+
+ $ testmod() {
+ > cat - > "$stdin"
+ > mksubrepo sub2
+ > echo sub2 = sub2 >> .hgsub
+ > echo % abort when modifying .hgsub w/dirty subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > echo [$?]
+ > hg -R sub2 ci -m0sub2
+ > echo % update substate when modifying .hgsub w/clean updated subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > hg debugsub
+ > }
+
+ $ testrm1() {
+ > cat - > "$stdin"
+ > mksubrepo sub3
+ > echo sub3 = sub3 >> .hgsub
+ > hg ci -Aqmsub3
+ > $EXTRA
+ > echo b >> sub3/a
+ > hg rm .hgsub
+ > echo % update substate when removing .hgsub w/dirty subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > echo % debugsub should be empty
+ > hg debugsub
+ > }
+
+ $ testrm2() {
+ > cat - > "$stdin"
+ > mksubrepo sub4
+ > echo sub4 = sub4 >> .hgsub
+ > hg ci -Aqmsub4
+ > $EXTRA
+ > hg rm .hgsub
+ > echo % update substate when removing .hgsub w/clean updated subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > echo % debugsub should be empty
+ > hg debugsub
+ > }
+
+
+handle subrepos safely on qnew
+
+ $ mkrepo repo-2499-qnew
+ $ testadd qnew -m0 0.diff
+ adding a
+ % abort when adding .hgsub w/dirty subrepo
+ A .hgsub
+ A sub/a
+ % qnew -m0 0.diff
+ abort: uncommitted changes in subrepository sub
+ [255]
+ % update substate when adding .hgsub w/clean updated subrepo
+ A .hgsub
+ % qnew -m0 0.diff
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+
+ $ testmod qnew -m1 1.diff
+ adding a
+ % abort when modifying .hgsub w/dirty subrepo
+ M .hgsub
+ A sub2/a
+ % qnew -m1 1.diff
+ abort: uncommitted changes in subrepository sub2
+ [255]
+ % update substate when modifying .hgsub w/clean updated subrepo
+ M .hgsub
+ % qnew -m1 1.diff
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+ path sub2
+ source sub2
+ revision 1f94c7611cc6b74f5a17b16121a1170d44776845
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ testrm1 qnew -m2 2.diff
+ adding a
+ % update substate when removing .hgsub w/dirty subrepo
+ M sub3/a
+ R .hgsub
+ % qnew -m2 2.diff
+ % debugsub should be empty
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ testrm2 qnew -m3 3.diff
+ adding a
+ % update substate when removing .hgsub w/clean updated subrepo
+ R .hgsub
+ % qnew -m3 3.diff
+ % debugsub should be empty
+
+ $ cd ..
+
+
+handle subrepos safely on qrefresh
+
+ $ mkrepo repo-2499-qrefresh
+ $ hg qnew -m0 0.diff
+ $ testadd qrefresh
+ adding a
+ % abort when adding .hgsub w/dirty subrepo
+ A .hgsub
+ A sub/a
+ % qrefresh
+ abort: uncommitted changes in subrepository sub
+ [255]
+ % update substate when adding .hgsub w/clean updated subrepo
+ A .hgsub
+ % qrefresh
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+
+ $ hg qnew -m1 1.diff
+ $ testmod qrefresh
+ adding a
+ % abort when modifying .hgsub w/dirty subrepo
+ M .hgsub
+ A sub2/a
+ % qrefresh
+ abort: uncommitted changes in subrepository sub2
+ [255]
+ % update substate when modifying .hgsub w/clean updated subrepo
+ M .hgsub
+ % qrefresh
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+ path sub2
+ source sub2
+ revision 1f94c7611cc6b74f5a17b16121a1170d44776845
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ EXTRA='hg qnew -m2 2.diff'
+ $ testrm1 qrefresh
+ adding a
+ % update substate when removing .hgsub w/dirty subrepo
+ M sub3/a
+ R .hgsub
+ % qrefresh
+ % debugsub should be empty
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ EXTRA='hg qnew -m3 3.diff'
+ $ testrm2 qrefresh
+ adding a
+ % update substate when removing .hgsub w/clean updated subrepo
+ R .hgsub
+ % qrefresh
+ % debugsub should be empty
+ $ EXTRA=
+
+ $ cd ..
+
+
+handle subrepos safely on qpush/qpop
+
+ $ mkrepo repo-2499-qpush
+ $ mksubrepo sub
+ adding a
+ $ hg -R sub ci -m0sub
+ $ echo sub = sub > .hgsub
+ $ hg add .hgsub
+ $ hg qnew -m0 0.diff
+ $ hg debugsub
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+
+qpop
+ $ hg qpop
+ popping 0.diff
+ patch queue now empty
+ $ hg status -AS
+ $ hg debugsub
+
+qpush
+ $ hg qpush
+ applying 0.diff
+ now at: 0.diff
+ $ hg status -AS
+ C .hgsub
+ C .hgsubstate
+ C sub/a
+ $ hg debugsub
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+
+ $ cd ..
+
+
+handle subrepos safely on qrecord
+
+ $ mkrepo repo-2499-qrecord
+ $ testadd qrecord --config ui.interactive=1 -m0 0.diff <<EOF
+ > y
+ > y
+ > EOF
+ adding a
+ % abort when adding .hgsub w/dirty subrepo
+ A .hgsub
+ A sub/a
+ % qrecord --config ui.interactive=1 -m0 0.diff
+ diff --git a/.hgsub b/.hgsub
+ new file mode 100644
+ examine changes to '.hgsub'? [Ynesfdaq?]
+ abort: uncommitted changes in subrepository sub
+ [255]
+ % update substate when adding .hgsub w/clean updated subrepo
+ A .hgsub
+ % qrecord --config ui.interactive=1 -m0 0.diff
+ diff --git a/.hgsub b/.hgsub
+ new file mode 100644
+ examine changes to '.hgsub'? [Ynesfdaq?]
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+
+ $ testmod qrecord --config ui.interactive=1 -m1 1.diff <<EOF
+ > y
+ > y
+ > EOF
+ adding a
+ % abort when modifying .hgsub w/dirty subrepo
+ M .hgsub
+ A sub2/a
+ % qrecord --config ui.interactive=1 -m1 1.diff
+ diff --git a/.hgsub b/.hgsub
+ 1 hunks, 1 lines changed
+ examine changes to '.hgsub'? [Ynesfdaq?]
+ @@ -1,1 +1,2 @@
+ sub = sub
+ +sub2 = sub2
+ record this change to '.hgsub'? [Ynesfdaq?]
+ abort: uncommitted changes in subrepository sub2
+ [255]
+ % update substate when modifying .hgsub w/clean updated subrepo
+ M .hgsub
+ % qrecord --config ui.interactive=1 -m1 1.diff
+ diff --git a/.hgsub b/.hgsub
+ 1 hunks, 1 lines changed
+ examine changes to '.hgsub'? [Ynesfdaq?]
+ @@ -1,1 +1,2 @@
+ sub = sub
+ +sub2 = sub2
+ record this change to '.hgsub'? [Ynesfdaq?]
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+ path sub2
+ source sub2
+ revision 1f94c7611cc6b74f5a17b16121a1170d44776845
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ testrm1 qrecord --config ui.interactive=1 -m2 2.diff <<EOF
+ > y
+ > y
+ > EOF
+ adding a
+ % update substate when removing .hgsub w/dirty subrepo
+ M sub3/a
+ R .hgsub
+ % qrecord --config ui.interactive=1 -m2 2.diff
+ diff --git a/.hgsub b/.hgsub
+ deleted file mode 100644
+ examine changes to '.hgsub'? [Ynesfdaq?]
+ % debugsub should be empty
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ testrm2 qrecord --config ui.interactive=1 -m3 3.diff <<EOF
+ > y
+ > y
+ > EOF
+ adding a
+ % update substate when removing .hgsub w/clean updated subrepo
+ R .hgsub
+ % qrecord --config ui.interactive=1 -m3 3.diff
+ diff --git a/.hgsub b/.hgsub
+ deleted file mode 100644
+ examine changes to '.hgsub'? [Ynesfdaq?]
+ % debugsub should be empty
+
+ $ cd ..
+
+
+correctly handle subrepos with patch queues
+ $ mkrepo repo-subrepo-with-queue
+ $ mksubrepo sub
+ adding a
+ $ hg -R sub qnew sub0.diff
+ $ echo sub = sub >> .hgsub
+ $ hg add .hgsub
+ $ hg qnew 0.diff
+
+ $ cd ..
+
+check whether MQ operations can import updated .hgsubstate correctly
+both into 'revision' and 'patch file under .hg/patches':
+
+ $ hg init importing-hgsubstate
+ $ cd importing-hgsubstate
+
+ $ echo a > a
+ $ hg commit -u test -d '0 0' -Am '#0 in parent'
+ adding a
+ $ hg init sub
+ $ echo sa > sub/sa
+ $ hg -R sub commit -u test -d '0 0' -Am '#0 in sub'
+ adding sa
+ $ echo 'sub = sub' > .hgsub
+ $ touch .hgsubstate
+ $ hg add .hgsub .hgsubstate
+
+ $ hg qnew -u test -d '0 0' import-at-qnew
+ $ hg -R sub parents --template '{node} sub\n'
+ b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
+ $ cat .hgsubstate
+ b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
+ $ hg diff -c tip
+ diff -r f499373e340c -r b20ffac88564 .hgsub
+ --- /dev/null
+ +++ b/.hgsub
+ @@ -0,0 +1,1 @@
+ +sub = sub
+ diff -r f499373e340c -r b20ffac88564 .hgsubstate
+ --- /dev/null
+ +++ b/.hgsubstate
+ @@ -0,0 +1,1 @@
+ +b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
+ $ cat .hg/patches/import-at-qnew
+ # HG changeset patch
+ # Parent f499373e340cdca5d01dee904aeb42dd2a325e71
+ # User test
+ # Date 0 0
+
+ diff -r f499373e340c -r b20ffac88564 .hgsub
+ --- /dev/null
+ +++ b/.hgsub
+ @@ -0,0 +1,1 @@
+ +sub = sub
+ diff -r f499373e340c -r b20ffac88564 .hgsubstate
+ --- /dev/null
+ +++ b/.hgsubstate
+ @@ -0,0 +1,1 @@
+ +b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
+ $ hg qpop
+ popping import-at-qnew
+ patch queue now empty
+ $ hg qpush
+ applying import-at-qnew
+ now at: import-at-qnew
+
+ $ hg qnew import-at-qrefresh
+ $ echo sb > sub/sb
+ $ hg -R sub commit -u test -d '0 0' -Am '#1 in sub'
+ adding sb
+ $ hg qrefresh -u test -d '0 0'
+ $ hg -R sub parents --template '{node} sub\n'
+ 88ac1bef5ed43b689d1d200b59886b675dec474b sub
+ $ cat .hgsubstate
+ 88ac1bef5ed43b689d1d200b59886b675dec474b sub
+ $ hg diff -c tip
+ diff -r 44f846335325 -r b3e8c5fa3aaa .hgsubstate
+ --- a/.hgsubstate
+ +++ b/.hgsubstate
+ @@ -1,1 +1,1 @@
+ -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
+ +88ac1bef5ed43b689d1d200b59886b675dec474b sub
+ $ cat .hg/patches/import-at-qrefresh
+ # HG changeset patch
+ # Date 0 0
+ # User test
+ # Parent 44f846335325209be6be35dc2c9a4be107278c09
+
+ diff -r 44f846335325 .hgsubstate
+ --- a/.hgsubstate
+ +++ b/.hgsubstate
+ @@ -1,1 +1,1 @@
+ -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
+ +88ac1bef5ed43b689d1d200b59886b675dec474b sub
+
+ $ hg qrefresh -u test -d '0 0'
+ $ cat .hgsubstate
+ 88ac1bef5ed43b689d1d200b59886b675dec474b sub
+ $ hg diff -c tip
+ diff -r 44f846335325 -r b3e8c5fa3aaa .hgsubstate
+ --- a/.hgsubstate
+ +++ b/.hgsubstate
+ @@ -1,1 +1,1 @@
+ -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
+ +88ac1bef5ed43b689d1d200b59886b675dec474b sub
+ $ cat .hg/patches/import-at-qrefresh
+ # HG changeset patch
+ # Date 0 0
+ # User test
+ # Parent 44f846335325209be6be35dc2c9a4be107278c09
+
+ diff -r 44f846335325 .hgsubstate
+ --- a/.hgsubstate
+ +++ b/.hgsubstate
+ @@ -1,1 +1,1 @@
+ -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
+ +88ac1bef5ed43b689d1d200b59886b675dec474b sub
+
+ $ hg update -C tip
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg qpop -a
+ popping import-at-qrefresh
+ popping import-at-qnew
+ patch queue now empty
+
+ $ hg -R sub update -C 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo 'sub = sub' > .hgsub
+ $ hg commit -Am '#1 in parent'
+ adding .hgsub
+ $ hg -R sub update -C 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg commit -Am '#2 in parent (but be rollbacked soon)'
+ $ hg rollback
+ repository tip rolled back to revision 1 (undo commit)
+ working directory now based on revision 1
+ $ hg status
+ M .hgsubstate
+ $ hg qnew -u test -d '0 0' checkstate-at-qnew
+ $ hg -R sub parents --template '{node} sub\n'
+ 88ac1bef5ed43b689d1d200b59886b675dec474b sub
+ $ cat .hgsubstate
+ 88ac1bef5ed43b689d1d200b59886b675dec474b sub
+ $ hg diff -c tip
+ diff -r 4d91eb2fa1d1 -r 1259c112d884 .hgsubstate
+ --- a/.hgsubstate
+ +++ b/.hgsubstate
+ @@ -1,1 +1,1 @@
+ -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
+ +88ac1bef5ed43b689d1d200b59886b675dec474b sub
+ $ cat .hg/patches/checkstate-at-qnew
+ # HG changeset patch
+ # Parent 4d91eb2fa1d1b22ec513347b9cd06f6b49d470fa
+ # User test
+ # Date 0 0
+
+ diff -r 4d91eb2fa1d1 -r 1259c112d884 .hgsubstate
+ --- a/.hgsubstate
+ +++ b/.hgsubstate
+ @@ -1,1 +1,1 @@
+ -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
+ +88ac1bef5ed43b689d1d200b59886b675dec474b sub
+
+ $ cd ..
+
+ $ cd ..
diff --git a/tests/test-mq-symlinks.t b/tests/test-mq-symlinks.t
new file mode 100644
index 0000000..ffbc790
--- /dev/null
+++ b/tests/test-mq-symlinks.t
@@ -0,0 +1,108 @@
+ $ "$TESTDIR/hghave" symlink || exit 80
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init
+ $ hg qinit
+ $ hg qnew base.patch
+ $ echo aaa > a
+ $ echo bbb > b
+ $ echo ccc > c
+ $ hg add a b c
+ $ hg qrefresh
+ $ "$TESTDIR/readlink.py" a
+ a -> a not a symlink
+
+
+test replacing a file with a symlink
+
+ $ hg qnew symlink.patch
+ $ rm a
+ $ ln -s b a
+ $ hg qrefresh --git
+ $ "$TESTDIR/readlink.py" a
+ a -> b
+
+ $ hg qpop
+ popping symlink.patch
+ now at: base.patch
+ $ hg qpush
+ applying symlink.patch
+ now at: symlink.patch
+ $ "$TESTDIR/readlink.py" a
+ a -> b
+
+
+test updating a symlink
+
+ $ rm a
+ $ ln -s c a
+ $ hg qnew --git -f updatelink
+ $ "$TESTDIR/readlink.py" a
+ a -> c
+ $ hg qpop
+ popping updatelink
+ now at: symlink.patch
+ $ hg qpush --debug
+ applying updatelink
+ patching file a
+ a
+ now at: updatelink
+ $ "$TESTDIR/readlink.py" a
+ a -> c
+ $ hg st
+
+
+test replacing a symlink with a file
+
+ $ ln -s c s
+ $ hg add s
+ $ hg qnew --git -f addlink
+ $ rm s
+ $ echo sss > s
+ $ hg qnew --git -f replacelinkwithfile
+ $ hg qpop
+ popping replacelinkwithfile
+ now at: addlink
+ $ hg qpush
+ applying replacelinkwithfile
+ now at: replacelinkwithfile
+ $ cat s
+ sss
+ $ hg st
+
+
+test symlink removal
+
+ $ hg qnew removesl.patch
+ $ hg rm a
+ $ hg qrefresh --git
+ $ hg qpop
+ popping removesl.patch
+ now at: replacelinkwithfile
+ $ hg qpush
+ applying removesl.patch
+ now at: removesl.patch
+ $ hg st -c
+ C b
+ C c
+ C s
+
+replace broken symlink with another broken symlink
+
+ $ ln -s linka linka
+ $ hg add linka
+ $ hg qnew link
+ $ hg mv linka linkb
+ $ rm linkb
+ $ ln -s linkb linkb
+ $ hg qnew movelink
+ $ hg qpop
+ popping movelink
+ now at: link
+ $ hg qpush
+ applying movelink
+ now at: movelink
+ $ "$TESTDIR/readlink.py" linkb
+ linkb -> linkb
diff --git a/tests/test-mq.t b/tests/test-mq.t
new file mode 100644
index 0000000..7e31845
--- /dev/null
+++ b/tests/test-mq.t
@@ -0,0 +1,1552 @@
+ $ checkundo()
+ > {
+ > if [ -f .hg/store/undo ]; then
+ > echo ".hg/store/undo still exists after $1"
+ > fi
+ > }
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ echo "[mq]" >> $HGRCPATH
+ $ echo "plain=true" >> $HGRCPATH
+
+
+help
+
+ $ hg help mq
+ mq extension - manage a stack of patches
+
+ This extension lets you work with a stack of patches in a Mercurial
+ repository. It manages two stacks of patches - all known patches, and applied
+ patches (subset of known patches).
+
+ Known patches are represented as patch files in the .hg/patches directory.
+ Applied patches are both patch files and changesets.
+
+ Common tasks (use "hg help command" for more details):
+
+ create new patch qnew
+ import existing patch qimport
+
+ print patch series qseries
+ print applied patches qapplied
+
+ add known patch to applied stack qpush
+ remove patch from applied stack qpop
+ refresh contents of top applied patch qrefresh
+
+ By default, mq will automatically use git patches when required to avoid
+ losing file mode changes, copy records, binary files or empty files creations
+ or deletions. This behaviour can be configured with:
+
+ [mq]
+ git = auto/keep/yes/no
+
+ If set to 'keep', mq will obey the [diff] section configuration while
+ preserving existing git patches upon qrefresh. If set to 'yes' or 'no', mq
+ will override the [diff] section and always generate git or regular patches,
+ possibly losing data in the second case.
+
+ It may be desirable for mq changesets to be kept in the secret phase (see "hg
+ help phases"), which can be enabled with the following setting:
+
+ [mq]
+ secret = True
+
+ You will by default be managing a patch queue named "patches". You can create
+ other, independent patch queues with the "hg qqueue" command.
+
+ If the working directory contains uncommitted files, qpush, qpop and qgoto
+ abort immediately. If -f/--force is used, the changes are discarded. Setting:
+
+ [mq]
+ keepchanges = True
+
+ make them behave as if --keep-changes were passed, and non-conflicting local
+ changes will be tolerated and preserved. If incompatible options such as
+ -f/--force or --exact are passed, this setting is ignored.
+
+ list of commands:
+
+ qapplied print the patches already applied
+ qclone clone main and patch repository at same time
+ qdelete remove patches from queue
+ qdiff diff of the current patch and subsequent modifications
+ qfinish move applied patches into repository history
+ qfold fold the named patches into the current patch
+ qgoto push or pop patches until named patch is at top of stack
+ qguard set or print guards for a patch
+ qheader print the header of the topmost or specified patch
+ qimport import a patch or existing changeset
+ qnew create a new patch
+ qnext print the name of the next pushable patch
+ qpop pop the current patch off the stack
+ qprev print the name of the preceding applied patch
+ qpush push the next patch onto the stack
+ qqueue manage multiple patch queues
+ qrefresh update the current patch
+ qrename rename a patch
+ qselect set or print guarded patches to push
+ qseries print the entire series file
+ qtop print the name of the current patch
+ qunapplied print the patches not yet applied
+ strip strip changesets and all their descendants from the repository
+
+ use "hg -v help mq" to show builtin aliases and global options
+
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+
+ $ hg clone . ../k
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ mkdir b
+ $ echo z > b/z
+ $ hg ci -Ama
+ adding b/z
+
+
+qinit
+
+ $ hg qinit
+
+ $ cd ..
+ $ hg init b
+
+
+-R qinit
+
+ $ hg -R b qinit
+
+ $ hg init c
+
+
+qinit -c
+
+ $ hg --cwd c qinit -c
+ $ hg -R c/.hg/patches st
+ A .hgignore
+ A series
+
+
+qinit; qinit -c
+
+ $ hg init d
+ $ cd d
+ $ hg qinit
+ $ hg qinit -c
+
+qinit -c should create both files if they don't exist
+
+ $ cat .hg/patches/.hgignore
+ ^\.hg
+ ^\.mq
+ syntax: glob
+ status
+ guards
+ $ cat .hg/patches/series
+ $ hg qinit -c
+ abort: repository $TESTTMP/d/.hg/patches already exists! (glob)
+ [255]
+ $ cd ..
+
+ $ echo '% qinit; <stuff>; qinit -c'
+ % qinit; <stuff>; qinit -c
+ $ hg init e
+ $ cd e
+ $ hg qnew A
+ $ checkundo qnew
+ $ echo foo > foo
+ $ hg phase -r qbase
+ 0: draft
+ $ hg add foo
+ $ hg qrefresh
+ $ hg phase -r qbase
+ 0: draft
+ $ hg qnew B
+ $ echo >> foo
+ $ hg qrefresh
+ $ echo status >> .hg/patches/.hgignore
+ $ echo bleh >> .hg/patches/.hgignore
+ $ hg qinit -c
+ adding .hg/patches/A (glob)
+ adding .hg/patches/B (glob)
+ $ hg -R .hg/patches status
+ A .hgignore
+ A A
+ A B
+ A series
+
+qinit -c shouldn't touch these files if they already exist
+
+ $ cat .hg/patches/.hgignore
+ status
+ bleh
+ $ cat .hg/patches/series
+ A
+ B
+
+add an untracked file
+
+ $ echo >> .hg/patches/flaf
+
+status --mq with color (issue2096)
+
+ $ hg status --mq --config extensions.color= --config color.mode=ansi --color=always
+ \x1b[0;32;1mA .hgignore\x1b[0m (esc)
+ \x1b[0;32;1mA A\x1b[0m (esc)
+ \x1b[0;32;1mA B\x1b[0m (esc)
+ \x1b[0;32;1mA series\x1b[0m (esc)
+ \x1b[0;35;1;4m? flaf\x1b[0m (esc)
+
+try the --mq option on a command provided by an extension
+
+ $ hg purge --mq --verbose --config extensions.purge=
+ removing file flaf
+
+ $ cd ..
+
+#if no-outer-repo
+
+init --mq without repo
+
+ $ mkdir f
+ $ cd f
+ $ hg init --mq
+ abort: there is no Mercurial repository here (.hg not found)
+ [255]
+ $ cd ..
+
+#endif
+
+init --mq with repo path
+
+ $ hg init g
+ $ hg init --mq g
+ $ test -d g/.hg/patches/.hg
+
+init --mq with nonexistent directory
+
+ $ hg init --mq nonexistentdir
+ abort: repository nonexistentdir not found!
+ [255]
+
+
+init --mq with bundle (non "local")
+
+ $ hg -R a bundle --all a.bundle >/dev/null
+ $ hg init --mq a.bundle
+ abort: only a local queue repository may be initialized
+ [255]
+
+ $ cd a
+
+ $ hg qnew -m 'foo bar' test.patch
+
+ $ echo '# comment' > .hg/patches/series.tmp
+ $ echo >> .hg/patches/series.tmp # empty line
+ $ cat .hg/patches/series >> .hg/patches/series.tmp
+ $ mv .hg/patches/series.tmp .hg/patches/series
+
+
+qrefresh
+
+ $ echo a >> a
+ $ hg qrefresh
+ $ cat .hg/patches/test.patch
+ foo bar
+
+ diff -r [a-f0-9]* a (re)
+ --- a/a\t(?P<date>.*) (re)
+ \+\+\+ b/a\t(?P<date2>.*) (re)
+ @@ -1,1 +1,2 @@
+ a
+ +a
+
+empty qrefresh
+
+ $ hg qrefresh -X a
+
+revision:
+
+ $ hg diff -r -2 -r -1
+
+patch:
+
+ $ cat .hg/patches/test.patch
+ foo bar
+
+
+working dir diff:
+
+ $ hg diff --nodates -q
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,2 @@
+ a
+ +a
+
+restore things
+
+ $ hg qrefresh
+ $ checkundo qrefresh
+
+
+qpop
+
+ $ hg qpop
+ popping test.patch
+ patch queue now empty
+ $ checkundo qpop
+
+
+qpush with dump of tag cache
+Dump the tag cache to ensure that it has exactly one head after qpush.
+
+ $ rm -f .hg/cache/tags
+ $ hg tags > /dev/null
+
+.hg/cache/tags (pre qpush):
+
+ $ cat .hg/cache/tags
+ 1 [\da-f]{40} (re)
+
+ $ hg qpush
+ applying test.patch
+ now at: test.patch
+ $ hg phase -r qbase
+ 2: draft
+ $ hg tags > /dev/null
+
+.hg/cache/tags (post qpush):
+
+ $ cat .hg/cache/tags
+ 2 [\da-f]{40} (re)
+
+ $ checkundo qpush
+ $ cd ..
+
+
+pop/push outside repo
+ $ hg -R a qpop
+ popping test.patch
+ patch queue now empty
+ $ hg -R a qpush
+ applying test.patch
+ now at: test.patch
+
+ $ cd a
+ $ hg qnew test2.patch
+
+qrefresh in subdir
+
+ $ cd b
+ $ echo a > a
+ $ hg add a
+ $ hg qrefresh
+
+pop/push -a in subdir
+
+ $ hg qpop -a
+ popping test2.patch
+ popping test.patch
+ patch queue now empty
+ $ hg --traceback qpush -a
+ applying test.patch
+ applying test2.patch
+ now at: test2.patch
+
+
+setting columns & formatted tests truncating (issue1912)
+
+ $ COLUMNS=4 hg qseries --config ui.formatted=true
+ test.patch
+ test2.patch
+ $ COLUMNS=20 hg qseries --config ui.formatted=true -vs
+ 0 A test.patch: f...
+ 1 A test2.patch:
+ $ hg qpop
+ popping test2.patch
+ now at: test.patch
+ $ hg qseries -vs
+ 0 A test.patch: foo bar
+ 1 U test2.patch:
+ $ hg sum | grep mq
+ mq: 1 applied, 1 unapplied
+ $ hg qpush
+ applying test2.patch
+ now at: test2.patch
+ $ hg sum | grep mq
+ mq: 2 applied
+ $ hg qapplied
+ test.patch
+ test2.patch
+ $ hg qtop
+ test2.patch
+
+
+prev
+
+ $ hg qapp -1
+ test.patch
+
+next
+
+ $ hg qunapp -1
+ all patches applied
+ [1]
+
+ $ hg qpop
+ popping test2.patch
+ now at: test.patch
+
+commit should fail
+
+ $ hg commit
+ abort: cannot commit over an applied mq patch
+ [255]
+
+push should fail if draft
+
+ $ hg push ../../k
+ pushing to ../../k
+ abort: source has mq patches applied
+ [255]
+
+
+import should fail
+
+ $ hg st .
+ $ echo foo >> ../a
+ $ hg diff > ../../import.diff
+ $ hg revert --no-backup ../a
+ $ hg import ../../import.diff
+ abort: cannot import over an applied patch
+ [255]
+ $ hg st
+
+import --no-commit should succeed
+
+ $ hg import --no-commit ../../import.diff
+ applying ../../import.diff
+ $ hg st
+ M a
+ $ hg revert --no-backup ../a
+
+
+qunapplied
+
+ $ hg qunapplied
+ test2.patch
+
+
+qpush/qpop with index
+
+ $ hg qnew test1b.patch
+ $ echo 1b > 1b
+ $ hg add 1b
+ $ hg qrefresh
+ $ hg qpush 2
+ applying test2.patch
+ now at: test2.patch
+ $ hg qpop 0
+ popping test2.patch
+ popping test1b.patch
+ now at: test.patch
+ $ hg qpush test.patch+1
+ applying test1b.patch
+ now at: test1b.patch
+ $ hg qpush test.patch+2
+ applying test2.patch
+ now at: test2.patch
+ $ hg qpop test2.patch-1
+ popping test2.patch
+ now at: test1b.patch
+ $ hg qpop test2.patch-2
+ popping test1b.patch
+ now at: test.patch
+ $ hg qpush test1b.patch+1
+ applying test1b.patch
+ applying test2.patch
+ now at: test2.patch
+
+
+qpush --move
+
+ $ hg qpop -a
+ popping test2.patch
+ popping test1b.patch
+ popping test.patch
+ patch queue now empty
+ $ hg qguard test1b.patch -- -negguard
+ $ hg qguard test2.patch -- +posguard
+ $ hg qpush --move test2.patch # can't move guarded patch
+ cannot push 'test2.patch' - guarded by '+posguard'
+ [1]
+ $ hg qselect posguard
+ number of unguarded, unapplied patches has changed from 2 to 3
+ $ hg qpush --move test2.patch # move to front
+ applying test2.patch
+ now at: test2.patch
+ $ hg qpush --move test1b.patch # negative guard unselected
+ applying test1b.patch
+ now at: test1b.patch
+ $ hg qpush --move test.patch # noop move
+ applying test.patch
+ now at: test.patch
+ $ hg qseries -v
+ 0 A test2.patch
+ 1 A test1b.patch
+ 2 A test.patch
+ $ hg qpop -a
+ popping test.patch
+ popping test1b.patch
+ popping test2.patch
+ patch queue now empty
+
+cleaning up
+
+ $ hg qselect --none
+ guards deactivated
+ number of unguarded, unapplied patches has changed from 3 to 2
+ $ hg qguard --none test1b.patch
+ $ hg qguard --none test2.patch
+ $ hg qpush --move test.patch
+ applying test.patch
+ now at: test.patch
+ $ hg qpush --move test1b.patch
+ applying test1b.patch
+ now at: test1b.patch
+ $ hg qpush --move bogus # nonexistent patch
+ abort: patch bogus not in series
+ [255]
+ $ hg qpush --move # no patch
+ abort: please specify the patch to move
+ [255]
+ $ hg qpush --move test.patch # already applied
+ abort: cannot push to a previous patch: test.patch
+ [255]
+ $ sed '2i\
+ > # make qtip index different in series and fullseries
+ > ' `hg root`/.hg/patches/series > $TESTTMP/sedtmp
+ $ cp $TESTTMP/sedtmp `hg root`/.hg/patches/series
+ $ cat `hg root`/.hg/patches/series
+ # comment
+ # make qtip index different in series and fullseries
+
+ test.patch
+ test1b.patch
+ test2.patch
+ $ hg qpush --move test2.patch
+ applying test2.patch
+ now at: test2.patch
+
+
+series after move
+
+ $ cat `hg root`/.hg/patches/series
+ # comment
+ # make qtip index different in series and fullseries
+
+ test.patch
+ test1b.patch
+ test2.patch
+
+
+pop, qapplied, qunapplied
+
+ $ hg qseries -v
+ 0 A test.patch
+ 1 A test1b.patch
+ 2 A test2.patch
+
+qapplied -1 test.patch
+
+ $ hg qapplied -1 test.patch
+ only one patch applied
+ [1]
+
+qapplied -1 test1b.patch
+
+ $ hg qapplied -1 test1b.patch
+ test.patch
+
+qapplied -1 test2.patch
+
+ $ hg qapplied -1 test2.patch
+ test1b.patch
+
+qapplied -1
+
+ $ hg qapplied -1
+ test1b.patch
+
+qapplied
+
+ $ hg qapplied
+ test.patch
+ test1b.patch
+ test2.patch
+
+qapplied test1b.patch
+
+ $ hg qapplied test1b.patch
+ test.patch
+ test1b.patch
+
+qunapplied -1
+
+ $ hg qunapplied -1
+ all patches applied
+ [1]
+
+qunapplied
+
+ $ hg qunapplied
+
+popping
+
+ $ hg qpop
+ popping test2.patch
+ now at: test1b.patch
+
+qunapplied -1
+
+ $ hg qunapplied -1
+ test2.patch
+
+qunapplied
+
+ $ hg qunapplied
+ test2.patch
+
+qunapplied test2.patch
+
+ $ hg qunapplied test2.patch
+
+qunapplied -1 test2.patch
+
+ $ hg qunapplied -1 test2.patch
+ all patches applied
+ [1]
+
+popping -a
+
+ $ hg qpop -a
+ popping test1b.patch
+ popping test.patch
+ patch queue now empty
+
+qapplied
+
+ $ hg qapplied
+
+qapplied -1
+
+ $ hg qapplied -1
+ no patches applied
+ [1]
+ $ hg qpush
+ applying test.patch
+ now at: test.patch
+
+
+push should succeed
+
+ $ hg qpop -a
+ popping test.patch
+ patch queue now empty
+ $ hg push ../../k
+ pushing to ../../k
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+
+we want to start with some patches applied
+
+ $ hg qpush -a
+ applying test.patch
+ applying test1b.patch
+ applying test2.patch
+ now at: test2.patch
+
+% pops all patches and succeeds
+
+ $ hg qpop -a
+ popping test2.patch
+ popping test1b.patch
+ popping test.patch
+ patch queue now empty
+
+% does nothing and succeeds
+
+ $ hg qpop -a
+ no patches applied
+
+% fails - nothing else to pop
+
+ $ hg qpop
+ no patches applied
+ [1]
+
+% pushes a patch and succeeds
+
+ $ hg qpush
+ applying test.patch
+ now at: test.patch
+
+% pops a patch and succeeds
+
+ $ hg qpop
+ popping test.patch
+ patch queue now empty
+
+% pushes up to test1b.patch and succeeds
+
+ $ hg qpush test1b.patch
+ applying test.patch
+ applying test1b.patch
+ now at: test1b.patch
+
+% does nothing and succeeds
+
+ $ hg qpush test1b.patch
+ qpush: test1b.patch is already at the top
+
+% does nothing and succeeds
+
+ $ hg qpop test1b.patch
+ qpop: test1b.patch is already at the top
+
+% fails - can't push to this patch
+
+ $ hg qpush test.patch
+ abort: cannot push to a previous patch: test.patch
+ [255]
+
+% fails - can't pop to this patch
+
+ $ hg qpop test2.patch
+ abort: patch test2.patch is not applied
+ [255]
+
+% pops up to test.patch and succeeds
+
+ $ hg qpop test.patch
+ popping test1b.patch
+ now at: test.patch
+
+% pushes all patches and succeeds
+
+ $ hg qpush -a
+ applying test1b.patch
+ applying test2.patch
+ now at: test2.patch
+
+% does nothing and succeeds
+
+ $ hg qpush -a
+ all patches are currently applied
+
+% fails - nothing else to push
+
+ $ hg qpush
+ patch series already fully applied
+ [1]
+
+% does nothing and succeeds
+
+ $ hg qpush test2.patch
+ qpush: test2.patch is already at the top
+
+strip
+
+ $ cd ../../b
+ $ echo x>x
+ $ hg ci -Ama
+ adding x
+ $ hg strip tip
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
+ $ hg unbundle .hg/strip-backup/*
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+
+
+strip with local changes, should complain
+
+ $ hg up
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo y>y
+ $ hg add y
+ $ hg strip tip
+ abort: local changes found
+ [255]
+
+--force strip with local changes
+
+ $ hg strip -f tip
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
+ $ cd ..
+
+
+cd b; hg qrefresh
+
+ $ hg init refresh
+ $ cd refresh
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+ $ hg qnew -mfoo foo
+ $ echo a >> a
+ $ hg qrefresh
+ $ mkdir b
+ $ cd b
+ $ echo f > f
+ $ hg add f
+ $ hg qrefresh
+ $ cat ../.hg/patches/foo
+ foo
+
+ diff -r cb9a9f314b8b a
+ --- a/a\t(?P<date>.*) (re)
+ \+\+\+ b/a\t(?P<date>.*) (re)
+ @@ -1,1 +1,2 @@
+ a
+ +a
+ diff -r cb9a9f314b8b b/f
+ --- /dev/null\t(?P<date>.*) (re)
+ \+\+\+ b/b/f\t(?P<date>.*) (re)
+ @@ -0,0 +1,1 @@
+ +f
+
+hg qrefresh .
+
+ $ hg qrefresh .
+ $ cat ../.hg/patches/foo
+ foo
+
+ diff -r cb9a9f314b8b b/f
+ --- /dev/null\t(?P<date>.*) (re)
+ \+\+\+ b/b/f\t(?P<date>.*) (re)
+ @@ -0,0 +1,1 @@
+ +f
+ $ hg status
+ M a
+
+
+qpush failure
+
+ $ cd ..
+ $ hg qrefresh
+ $ hg qnew -mbar bar
+ $ echo foo > foo
+ $ echo bar > bar
+ $ hg add foo bar
+ $ hg qrefresh
+ $ hg qpop -a
+ popping bar
+ popping foo
+ patch queue now empty
+ $ echo bar > foo
+ $ hg qpush -a
+ applying foo
+ applying bar
+ file foo already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh bar
+ [2]
+ $ hg st
+ ? foo
+ ? foo.rej
+
+
+mq tags
+
+ $ hg log --template '{rev} {tags}\n' -r qparent:qtip
+ 0 qparent
+ 1 foo qbase
+ 2 bar qtip tip
+
+mq revset
+
+ $ hg log -r 'mq()' --template '{rev}\n'
+ 1
+ 2
+ $ hg help revsets | grep -i mq
+ "mq()"
+ Changesets managed by MQ.
+
+bad node in status
+
+ $ hg qpop
+ popping bar
+ now at: foo
+ $ hg strip -qn tip
+ $ hg tip
+ changeset: 0:cb9a9f314b8b
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ hg branches
+ default 0:cb9a9f314b8b
+ $ hg qpop
+ no patches applied
+ [1]
+
+ $ cd ..
+
+
+git patches
+
+ $ cat >>$HGRCPATH <<EOF
+ > [diff]
+ > git = True
+ > EOF
+ $ hg init git
+ $ cd git
+ $ hg qinit
+
+ $ hg qnew -m'new file' new
+ $ echo foo > new
+#if execbit
+ $ chmod +x new
+#endif
+ $ hg add new
+ $ hg qrefresh
+#if execbit
+ $ cat .hg/patches/new
+ new file
+
+ diff --git a/new b/new
+ new file mode 100755
+ --- /dev/null
+ +++ b/new
+ @@ -0,0 +1,1 @@
+ +foo
+#else
+ $ cat .hg/patches/new
+ new file
+
+ diff --git a/new b/new
+ new file mode 100644
+ --- /dev/null
+ +++ b/new
+ @@ -0,0 +1,1 @@
+ +foo
+#endif
+
+ $ hg qnew -m'copy file' copy
+ $ hg cp new copy
+ $ hg qrefresh
+ $ cat .hg/patches/copy
+ copy file
+
+ diff --git a/new b/copy
+ copy from new
+ copy to copy
+
+ $ hg qpop
+ popping copy
+ now at: new
+ $ hg qpush
+ applying copy
+ now at: copy
+ $ hg qdiff
+ diff --git a/new b/copy
+ copy from new
+ copy to copy
+ $ cat >>$HGRCPATH <<EOF
+ > [diff]
+ > git = False
+ > EOF
+ $ hg qdiff --git
+ diff --git a/new b/copy
+ copy from new
+ copy to copy
+ $ cd ..
+
+empty lines in status
+
+ $ hg init emptystatus
+ $ cd emptystatus
+ $ hg qinit
+ $ printf '\n\n' > .hg/patches/status
+ $ hg qser
+ $ cd ..
+
+bad line in status (without ":")
+
+ $ hg init badstatus
+ $ cd badstatus
+ $ hg qinit
+ $ printf 'babar has no colon in this line\n' > .hg/patches/status
+ $ hg qser
+ malformated mq status line: ['babar has no colon in this line']
+ $ cd ..
+
+
+test file addition in slow path
+
+ $ hg init slow
+ $ cd slow
+ $ hg qinit
+ $ echo foo > foo
+ $ hg add foo
+ $ hg ci -m 'add foo'
+ $ hg qnew bar
+ $ echo bar > bar
+ $ hg add bar
+ $ hg mv foo baz
+ $ hg qrefresh --git
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo >> foo
+ $ hg ci -m 'change foo'
+ created new head
+ $ hg up -C 1
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg qrefresh --git
+ $ cat .hg/patches/bar
+ diff --git a/bar b/bar
+ new file mode 100644
+ --- /dev/null
+ +++ b/bar
+ @@ -0,0 +1,1 @@
+ +bar
+ diff --git a/foo b/baz
+ rename from foo
+ rename to baz
+ $ hg log -v --template '{rev} {file_copies}\n' -r .
+ 2 baz (foo)
+ $ hg qrefresh --git
+ $ cat .hg/patches/bar
+ diff --git a/bar b/bar
+ new file mode 100644
+ --- /dev/null
+ +++ b/bar
+ @@ -0,0 +1,1 @@
+ +bar
+ diff --git a/foo b/baz
+ rename from foo
+ rename to baz
+ $ hg log -v --template '{rev} {file_copies}\n' -r .
+ 2 baz (foo)
+ $ hg qrefresh
+ $ grep 'diff --git' .hg/patches/bar
+ diff --git a/bar b/bar
+ diff --git a/foo b/baz
+
+
+test file move chains in the slow path
+
+ $ hg up -C 1
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo >> foo
+ $ hg ci -m 'change foo again'
+ $ hg up -C 2
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg mv bar quux
+ $ hg mv baz bleh
+ $ hg qrefresh --git
+ $ cat .hg/patches/bar
+ diff --git a/foo b/bleh
+ rename from foo
+ rename to bleh
+ diff --git a/quux b/quux
+ new file mode 100644
+ --- /dev/null
+ +++ b/quux
+ @@ -0,0 +1,1 @@
+ +bar
+ $ hg log -v --template '{rev} {file_copies}\n' -r .
+ 3 bleh (foo)
+ $ hg mv quux fred
+ $ hg mv bleh barney
+ $ hg qrefresh --git
+ $ cat .hg/patches/bar
+ diff --git a/foo b/barney
+ rename from foo
+ rename to barney
+ diff --git a/fred b/fred
+ new file mode 100644
+ --- /dev/null
+ +++ b/fred
+ @@ -0,0 +1,1 @@
+ +bar
+ $ hg log -v --template '{rev} {file_copies}\n' -r .
+ 3 barney (foo)
+
+
+refresh omitting an added file
+
+ $ hg qnew baz
+ $ echo newfile > newfile
+ $ hg add newfile
+ $ hg qrefresh
+ $ hg st -A newfile
+ C newfile
+ $ hg qrefresh -X newfile
+ $ hg st -A newfile
+ A newfile
+ $ hg revert newfile
+ $ rm newfile
+ $ hg qpop
+ popping baz
+ now at: bar
+ $ hg qdel baz
+
+
+create a git patch
+
+ $ echo a > alexander
+ $ hg add alexander
+ $ hg qnew -f --git addalexander
+ $ grep diff .hg/patches/addalexander
+ diff --git a/alexander b/alexander
+
+
+create a git binary patch
+
+ $ cat > writebin.py <<EOF
+ > import sys
+ > path = sys.argv[1]
+ > open(path, 'wb').write('BIN\x00ARY')
+ > EOF
+ $ python writebin.py bucephalus
+
+ $ python "$TESTDIR/md5sum.py" bucephalus
+ 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
+ $ hg add bucephalus
+ $ hg qnew -f --git addbucephalus
+ $ grep diff .hg/patches/addbucephalus
+ diff --git a/bucephalus b/bucephalus
+
+
+check binary patches can be popped and pushed
+
+ $ hg qpop
+ popping addbucephalus
+ now at: addalexander
+ $ test -f bucephalus && echo % bucephalus should not be there
+ [1]
+ $ hg qpush
+ applying addbucephalus
+ now at: addbucephalus
+ $ test -f bucephalus
+ $ python "$TESTDIR/md5sum.py" bucephalus
+ 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
+
+
+
+strip again
+
+ $ cd ..
+ $ hg init strip
+ $ cd strip
+ $ touch foo
+ $ hg add foo
+ $ hg ci -m 'add foo'
+ $ echo >> foo
+ $ hg ci -m 'change foo 1'
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo 1 >> foo
+ $ hg ci -m 'change foo 2'
+ created new head
+ $ HGMERGE=true hg merge
+ merging foo
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m merge
+ $ hg log
+ changeset: 3:99615015637b
+ tag: tip
+ parent: 2:20cbbe65cff7
+ parent: 1:d2871fc282d4
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: merge
+
+ changeset: 2:20cbbe65cff7
+ parent: 0:53245c60e682
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change foo 2
+
+ changeset: 1:d2871fc282d4
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change foo 1
+
+ changeset: 0:53245c60e682
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo
+
+ $ hg strip 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/strip/.hg/strip-backup/*-backup.hg (glob)
+ $ checkundo strip
+ $ hg log
+ changeset: 1:20cbbe65cff7
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change foo 2
+
+ changeset: 0:53245c60e682
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo
+
+ $ cd ..
+
+
+qclone
+
+ $ qlog()
+ > {
+ > echo 'main repo:'
+ > hg log --template ' rev {rev}: {desc}\n'
+ > echo 'patch repo:'
+ > hg -R .hg/patches log --template ' rev {rev}: {desc}\n'
+ > }
+ $ hg init qclonesource
+ $ cd qclonesource
+ $ echo foo > foo
+ $ hg add foo
+ $ hg ci -m 'add foo'
+ $ hg qinit
+ $ hg qnew patch1
+ $ echo bar >> foo
+ $ hg qrefresh -m 'change foo'
+ $ cd ..
+
+
+repo with unversioned patch dir
+
+ $ hg qclone qclonesource failure
+ abort: versioned patch repository not found (see init --mq)
+ [255]
+
+ $ cd qclonesource
+ $ hg qinit -c
+ adding .hg/patches/patch1 (glob)
+ $ hg qci -m checkpoint
+ $ qlog
+ main repo:
+ rev 1: change foo
+ rev 0: add foo
+ patch repo:
+ rev 0: checkpoint
+ $ cd ..
+
+
+repo with patches applied
+
+ $ hg qclone qclonesource qclonedest
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd qclonedest
+ $ qlog
+ main repo:
+ rev 0: add foo
+ patch repo:
+ rev 0: checkpoint
+ $ cd ..
+
+
+repo with patches unapplied
+
+ $ cd qclonesource
+ $ hg qpop -a
+ popping patch1
+ patch queue now empty
+ $ qlog
+ main repo:
+ rev 0: add foo
+ patch repo:
+ rev 0: checkpoint
+ $ cd ..
+ $ hg qclone qclonesource qclonedest2
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd qclonedest2
+ $ qlog
+ main repo:
+ rev 0: add foo
+ patch repo:
+ rev 0: checkpoint
+ $ cd ..
+
+
+Issue1033: test applying on an empty file
+
+ $ hg init empty
+ $ cd empty
+ $ touch a
+ $ hg ci -Am addempty
+ adding a
+ $ echo a > a
+ $ hg qnew -f -e changea
+ $ hg qpop
+ popping changea
+ patch queue now empty
+ $ hg qpush
+ applying changea
+ now at: changea
+ $ cd ..
+
+test qpush with --force, issue1087
+
+ $ hg init forcepush
+ $ cd forcepush
+ $ echo hello > hello.txt
+ $ echo bye > bye.txt
+ $ hg ci -Ama
+ adding bye.txt
+ adding hello.txt
+ $ hg qnew -d '0 0' empty
+ $ hg qpop
+ popping empty
+ patch queue now empty
+ $ echo world >> hello.txt
+
+
+qpush should fail, local changes
+
+ $ hg qpush
+ abort: local changes found
+ [255]
+
+
+apply force, should not discard changes with empty patch
+
+ $ hg qpush -f
+ applying empty
+ patch empty is empty
+ now at: empty
+ $ hg diff --config diff.nodates=True
+ diff -r d58265112590 hello.txt
+ --- a/hello.txt
+ +++ b/hello.txt
+ @@ -1,1 +1,2 @@
+ hello
+ +world
+ $ hg qdiff --config diff.nodates=True
+ diff -r 9ecee4f634e3 hello.txt
+ --- a/hello.txt
+ +++ b/hello.txt
+ @@ -1,1 +1,2 @@
+ hello
+ +world
+ $ hg log -l1 -p
+ changeset: 1:d58265112590
+ tag: empty
+ tag: qbase
+ tag: qtip
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: imported patch empty
+
+
+ $ hg qref -d '0 0'
+ $ hg qpop
+ popping empty
+ patch queue now empty
+ $ echo universe >> hello.txt
+ $ echo universe >> bye.txt
+
+
+qpush should fail, local changes
+
+ $ hg qpush
+ abort: local changes found
+ [255]
+
+
+apply force, should discard changes in hello, but not bye
+
+ $ hg qpush -f --verbose
+ applying empty
+ saving current version of hello.txt as hello.txt.orig
+ patching file hello.txt
+ hello.txt
+ now at: empty
+ $ hg st
+ M bye.txt
+ ? hello.txt.orig
+ $ hg diff --config diff.nodates=True
+ diff -r ba252371dbc1 bye.txt
+ --- a/bye.txt
+ +++ b/bye.txt
+ @@ -1,1 +1,2 @@
+ bye
+ +universe
+ $ hg qdiff --config diff.nodates=True
+ diff -r 9ecee4f634e3 bye.txt
+ --- a/bye.txt
+ +++ b/bye.txt
+ @@ -1,1 +1,2 @@
+ bye
+ +universe
+ diff -r 9ecee4f634e3 hello.txt
+ --- a/hello.txt
+ +++ b/hello.txt
+ @@ -1,1 +1,3 @@
+ hello
+ +world
+ +universe
+
+
+test popping revisions not in working dir ancestry
+
+ $ hg qseries -v
+ 0 A empty
+ $ hg up qparent
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg qpop
+ popping empty
+ patch queue now empty
+
+ $ cd ..
+ $ hg init deletion-order
+ $ cd deletion-order
+
+ $ touch a
+ $ hg ci -Aqm0
+
+ $ hg qnew rename-dir
+ $ hg rm a
+ $ hg qrefresh
+
+ $ mkdir a b
+ $ touch a/a b/b
+ $ hg add -q a b
+ $ hg qrefresh
+
+
+test popping must remove files added in subdirectories first
+
+ $ hg qpop
+ popping rename-dir
+ patch queue now empty
+ $ cd ..
+
+
+test case preservation through patch pushing especially on case
+insensitive filesystem
+
+ $ hg init casepreserve
+ $ cd casepreserve
+
+ $ hg qnew add-file1
+ $ echo a > TeXtFiLe.TxT
+ $ hg add TeXtFiLe.TxT
+ $ hg qrefresh
+
+ $ hg qnew add-file2
+ $ echo b > AnOtHeRFiLe.TxT
+ $ hg add AnOtHeRFiLe.TxT
+ $ hg qrefresh
+
+ $ hg qnew modify-file
+ $ echo c >> AnOtHeRFiLe.TxT
+ $ hg qrefresh
+
+ $ hg qapplied
+ add-file1
+ add-file2
+ modify-file
+ $ hg qpop -a
+ popping modify-file
+ popping add-file2
+ popping add-file1
+ patch queue now empty
+
+this qpush causes problems below, if case preservation on case
+insensitive filesystem is not enough:
+(1) unexpected "adding ..." messages are shown
+(2) patching fails in modification of (1) files
+
+ $ hg qpush -a
+ applying add-file1
+ applying add-file2
+ applying modify-file
+ now at: modify-file
+
+Proper phase default with mq:
+
+1. mq.secret=false
+
+ $ rm .hg/store/phaseroots
+ $ hg phase 'qparent::'
+ 0: draft
+ 1: draft
+ 2: draft
+ $ echo '[mq]' >> $HGRCPATH
+ $ echo 'secret=true' >> $HGRCPATH
+ $ rm -f .hg/store/phaseroots
+ $ hg phase 'qparent::'
+ 0: secret
+ 1: secret
+ 2: secret
+
+Test that qfinish change phase when mq.secret=true
+
+ $ hg qfinish qbase
+ patch add-file1 finalized without changeset message
+ $ hg phase 'all()'
+ 0: draft
+ 1: secret
+ 2: secret
+
+Test that qfinish respect phases.new-commit setting
+
+ $ echo '[phases]' >> $HGRCPATH
+ $ echo 'new-commit=secret' >> $HGRCPATH
+ $ hg qfinish qbase
+ patch add-file2 finalized without changeset message
+ $ hg phase 'all()'
+ 0: draft
+ 1: secret
+ 2: secret
+
+(restore env for next test)
+
+ $ sed -e 's/new-commit=secret//' $HGRCPATH > $TESTTMP/sedtmp
+ $ cp $TESTTMP/sedtmp $HGRCPATH
+ $ hg qimport -r 1 --name add-file2
+
+Test that qfinish preserve phase when mq.secret=false
+
+ $ sed -e 's/secret=true/secret=false/' $HGRCPATH > $TESTTMP/sedtmp
+ $ cp $TESTTMP/sedtmp $HGRCPATH
+ $ hg qfinish qbase
+ patch add-file2 finalized without changeset message
+ $ hg phase 'all()'
+ 0: draft
+ 1: secret
+ 2: secret
+
+ $ cd ..
diff --git a/tests/test-mv-cp-st-diff.t b/tests/test-mv-cp-st-diff.t
new file mode 100644
index 0000000..5342fea
--- /dev/null
+++ b/tests/test-mv-cp-st-diff.t
@@ -0,0 +1,1348 @@
+
+ $ add()
+ > {
+ > echo $2 >> $1
+ > }
+ $ hg init t
+ $ cd t
+
+set up a boring main branch
+
+ $ add a a
+ $ hg add a
+ $ mkdir x
+ $ add x/x x
+ $ hg add x/x
+ $ hg ci -m0
+ $ add a m1
+ $ hg ci -m1
+ $ add a m2
+ $ add x/y y1
+ $ hg add x/y
+ $ hg ci -m2
+ $ cd ..
+ $ show()
+ > {
+ > echo "- $2: $1"
+ > hg st -C $1
+ > echo
+ > hg diff --git $1
+ > echo
+ > }
+ $ count=0
+
+make a new branch and get diff/status output
+$1 - first commit
+$2 - second commit
+$3 - working dir action
+$4 - test description
+
+ $ tb()
+ > {
+ > hg clone t t2 ; cd t2
+ > hg co -q -C 0
+ >
+ > add a $count
+ > count=`expr $count + 1`
+ > hg ci -m "t0"
+ > $1
+ > hg ci -m "t1"
+ > $2
+ > hg ci -m "t2"
+ > $3
+ >
+ > echo "** $4 **"
+ > echo "** $1 / $2 / $3"
+ > show "" "working to parent"
+ > show "--rev 0" "working to root"
+ > show "--rev 2" "working to branch"
+ > show "--rev 0 --rev ." "root to parent"
+ > show "--rev . --rev 0" "parent to root"
+ > show "--rev 2 --rev ." "branch to parent"
+ > show "--rev . --rev 2" "parent to branch"
+ > echo
+ > cd ..
+ > rm -rf t2
+ > }
+ $ tb "add a a1" "add a a2" "hg mv a b" "rename in working dir"
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+ ** rename in working dir **
+ ** add a a1 / add a a2 / hg mv a b
+ - working to parent:
+ A b
+ a
+ R a
+
+ diff --git a/a b/b
+ rename from a
+ rename to b
+
+ - working to root: --rev 0
+ A b
+ a
+ R a
+
+ diff --git a/a b/b
+ rename from a
+ rename to b
+ --- a/a
+ +++ b/b
+ @@ -1,1 +1,4 @@
+ a
+ +0
+ +a1
+ +a2
+
+ - working to branch: --rev 2
+ A b
+ a
+ R a
+ R x/y
+
+ diff --git a/a b/b
+ rename from a
+ rename to b
+ --- a/a
+ +++ b/b
+ @@ -1,3 +1,4 @@
+ a
+ -m1
+ -m2
+ +0
+ +a1
+ +a2
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - root to parent: --rev 0 --rev .
+ M a
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,4 @@
+ a
+ +0
+ +a1
+ +a2
+
+ - parent to root: --rev . --rev 0
+ M a
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,4 +1,1 @@
+ a
+ -0
+ -a1
+ -a2
+
+ - branch to parent: --rev 2 --rev .
+ M a
+ R x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,3 +1,4 @@
+ a
+ -m1
+ -m2
+ +0
+ +a1
+ +a2
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - parent to branch: --rev . --rev 2
+ M a
+ A x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,4 +1,3 @@
+ a
+ -0
+ -a1
+ -a2
+ +m1
+ +m2
+ diff --git a/x/y b/x/y
+ new file mode 100644
+ --- /dev/null
+ +++ b/x/y
+ @@ -0,0 +1,1 @@
+ +y1
+
+
+ $ tb "add a a1" "add a a2" "hg cp a b" "copy in working dir"
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+ ** copy in working dir **
+ ** add a a1 / add a a2 / hg cp a b
+ - working to parent:
+ A b
+ a
+
+ diff --git a/a b/b
+ copy from a
+ copy to b
+
+ - working to root: --rev 0
+ M a
+ A b
+ a
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,4 @@
+ a
+ +1
+ +a1
+ +a2
+ diff --git a/a b/b
+ copy from a
+ copy to b
+ --- a/a
+ +++ b/b
+ @@ -1,1 +1,4 @@
+ a
+ +1
+ +a1
+ +a2
+
+ - working to branch: --rev 2
+ M a
+ A b
+ a
+ R x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,3 +1,4 @@
+ a
+ -m1
+ -m2
+ +1
+ +a1
+ +a2
+ diff --git a/a b/b
+ copy from a
+ copy to b
+ --- a/a
+ +++ b/b
+ @@ -1,3 +1,4 @@
+ a
+ -m1
+ -m2
+ +1
+ +a1
+ +a2
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - root to parent: --rev 0 --rev .
+ M a
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,4 @@
+ a
+ +1
+ +a1
+ +a2
+
+ - parent to root: --rev . --rev 0
+ M a
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,4 +1,1 @@
+ a
+ -1
+ -a1
+ -a2
+
+ - branch to parent: --rev 2 --rev .
+ M a
+ R x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,3 +1,4 @@
+ a
+ -m1
+ -m2
+ +1
+ +a1
+ +a2
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - parent to branch: --rev . --rev 2
+ M a
+ A x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,4 +1,3 @@
+ a
+ -1
+ -a1
+ -a2
+ +m1
+ +m2
+ diff --git a/x/y b/x/y
+ new file mode 100644
+ --- /dev/null
+ +++ b/x/y
+ @@ -0,0 +1,1 @@
+ +y1
+
+
+ $ tb "hg mv a b" "add b b1" "add b w" "single rename"
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+ ** single rename **
+ ** hg mv a b / add b b1 / add b w
+ - working to parent:
+ M b
+
+ diff --git a/b b/b
+ --- a/b
+ +++ b/b
+ @@ -1,3 +1,4 @@
+ a
+ 2
+ b1
+ +w
+
+ - working to root: --rev 0
+ A b
+ a
+ R a
+
+ diff --git a/a b/b
+ rename from a
+ rename to b
+ --- a/a
+ +++ b/b
+ @@ -1,1 +1,4 @@
+ a
+ +2
+ +b1
+ +w
+
+ - working to branch: --rev 2
+ A b
+ a
+ R a
+ R x/y
+
+ diff --git a/a b/b
+ rename from a
+ rename to b
+ --- a/a
+ +++ b/b
+ @@ -1,3 +1,4 @@
+ a
+ -m1
+ -m2
+ +2
+ +b1
+ +w
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - root to parent: --rev 0 --rev .
+ A b
+ a
+ R a
+
+ diff --git a/a b/b
+ rename from a
+ rename to b
+ --- a/a
+ +++ b/b
+ @@ -1,1 +1,3 @@
+ a
+ +2
+ +b1
+
+ - parent to root: --rev . --rev 0
+ A a
+ b
+ R b
+
+ diff --git a/b b/a
+ rename from b
+ rename to a
+ --- a/b
+ +++ b/a
+ @@ -1,3 +1,1 @@
+ a
+ -2
+ -b1
+
+ - branch to parent: --rev 2 --rev .
+ A b
+ a
+ R a
+ R x/y
+
+ diff --git a/a b/b
+ rename from a
+ rename to b
+ --- a/a
+ +++ b/b
+ @@ -1,3 +1,3 @@
+ a
+ -m1
+ -m2
+ +2
+ +b1
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - parent to branch: --rev . --rev 2
+ A a
+ b
+ A x/y
+ R b
+
+ diff --git a/b b/a
+ rename from b
+ rename to a
+ --- a/b
+ +++ b/a
+ @@ -1,3 +1,3 @@
+ a
+ -2
+ -b1
+ +m1
+ +m2
+ diff --git a/x/y b/x/y
+ new file mode 100644
+ --- /dev/null
+ +++ b/x/y
+ @@ -0,0 +1,1 @@
+ +y1
+
+
+ $ tb "hg cp a b" "add b b1" "add a w" "single copy"
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+ ** single copy **
+ ** hg cp a b / add b b1 / add a w
+ - working to parent:
+ M a
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,2 +1,3 @@
+ a
+ 3
+ +w
+
+ - working to root: --rev 0
+ M a
+ A b
+ a
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,3 @@
+ a
+ +3
+ +w
+ diff --git a/a b/b
+ copy from a
+ copy to b
+ --- a/a
+ +++ b/b
+ @@ -1,1 +1,3 @@
+ a
+ +3
+ +b1
+
+ - working to branch: --rev 2
+ M a
+ A b
+ a
+ R x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,3 +1,3 @@
+ a
+ -m1
+ -m2
+ +3
+ +w
+ diff --git a/a b/b
+ copy from a
+ copy to b
+ --- a/a
+ +++ b/b
+ @@ -1,3 +1,3 @@
+ a
+ -m1
+ -m2
+ +3
+ +b1
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - root to parent: --rev 0 --rev .
+ M a
+ A b
+ a
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,2 @@
+ a
+ +3
+ diff --git a/a b/b
+ copy from a
+ copy to b
+ --- a/a
+ +++ b/b
+ @@ -1,1 +1,3 @@
+ a
+ +3
+ +b1
+
+ - parent to root: --rev . --rev 0
+ M a
+ b
+ R b
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,2 +1,1 @@
+ a
+ -3
+ diff --git a/b b/b
+ deleted file mode 100644
+ --- a/b
+ +++ /dev/null
+ @@ -1,3 +0,0 @@
+ -a
+ -3
+ -b1
+
+ - branch to parent: --rev 2 --rev .
+ M a
+ A b
+ a
+ R x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +3
+ diff --git a/a b/b
+ copy from a
+ copy to b
+ --- a/a
+ +++ b/b
+ @@ -1,3 +1,3 @@
+ a
+ -m1
+ -m2
+ +3
+ +b1
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - parent to branch: --rev . --rev 2
+ M a
+ b
+ A x/y
+ R b
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,2 +1,3 @@
+ a
+ -3
+ +m1
+ +m2
+ diff --git a/b b/b
+ deleted file mode 100644
+ --- a/b
+ +++ /dev/null
+ @@ -1,3 +0,0 @@
+ -a
+ -3
+ -b1
+ diff --git a/x/y b/x/y
+ new file mode 100644
+ --- /dev/null
+ +++ b/x/y
+ @@ -0,0 +1,1 @@
+ +y1
+
+
+ $ tb "hg mv a b" "hg mv b c" "hg mv c d" "rename chain"
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+ ** rename chain **
+ ** hg mv a b / hg mv b c / hg mv c d
+ - working to parent:
+ A d
+ c
+ R c
+
+ diff --git a/c b/d
+ rename from c
+ rename to d
+
+ - working to root: --rev 0
+ A d
+ a
+ R a
+
+ diff --git a/a b/d
+ rename from a
+ rename to d
+ --- a/a
+ +++ b/d
+ @@ -1,1 +1,2 @@
+ a
+ +4
+
+ - working to branch: --rev 2
+ A d
+ a
+ R a
+ R x/y
+
+ diff --git a/a b/d
+ rename from a
+ rename to d
+ --- a/a
+ +++ b/d
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +4
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - root to parent: --rev 0 --rev .
+ A c
+ a
+ R a
+
+ diff --git a/a b/c
+ rename from a
+ rename to c
+ --- a/a
+ +++ b/c
+ @@ -1,1 +1,2 @@
+ a
+ +4
+
+ - parent to root: --rev . --rev 0
+ A a
+ c
+ R c
+
+ diff --git a/c b/a
+ rename from c
+ rename to a
+ --- a/c
+ +++ b/a
+ @@ -1,2 +1,1 @@
+ a
+ -4
+
+ - branch to parent: --rev 2 --rev .
+ A c
+ a
+ R a
+ R x/y
+
+ diff --git a/a b/c
+ rename from a
+ rename to c
+ --- a/a
+ +++ b/c
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +4
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - parent to branch: --rev . --rev 2
+ A a
+ c
+ A x/y
+ R c
+
+ diff --git a/c b/a
+ rename from c
+ rename to a
+ --- a/c
+ +++ b/a
+ @@ -1,2 +1,3 @@
+ a
+ -4
+ +m1
+ +m2
+ diff --git a/x/y b/x/y
+ new file mode 100644
+ --- /dev/null
+ +++ b/x/y
+ @@ -0,0 +1,1 @@
+ +y1
+
+
+ $ tb "hg cp a b" "hg cp b c" "hg cp c d" "copy chain"
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+ ** copy chain **
+ ** hg cp a b / hg cp b c / hg cp c d
+ - working to parent:
+ A d
+ c
+
+ diff --git a/c b/d
+ copy from c
+ copy to d
+
+ - working to root: --rev 0
+ M a
+ A b
+ a
+ A c
+ a
+ A d
+ a
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,2 @@
+ a
+ +5
+ diff --git a/a b/b
+ copy from a
+ copy to b
+ --- a/a
+ +++ b/b
+ @@ -1,1 +1,2 @@
+ a
+ +5
+ diff --git a/a b/c
+ copy from a
+ copy to c
+ --- a/a
+ +++ b/c
+ @@ -1,1 +1,2 @@
+ a
+ +5
+ diff --git a/a b/d
+ copy from a
+ copy to d
+ --- a/a
+ +++ b/d
+ @@ -1,1 +1,2 @@
+ a
+ +5
+
+ - working to branch: --rev 2
+ M a
+ A b
+ a
+ A c
+ a
+ A d
+ a
+ R x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +5
+ diff --git a/a b/b
+ copy from a
+ copy to b
+ --- a/a
+ +++ b/b
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +5
+ diff --git a/a b/c
+ copy from a
+ copy to c
+ --- a/a
+ +++ b/c
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +5
+ diff --git a/a b/d
+ copy from a
+ copy to d
+ --- a/a
+ +++ b/d
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +5
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - root to parent: --rev 0 --rev .
+ M a
+ A b
+ a
+ A c
+ a
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,2 @@
+ a
+ +5
+ diff --git a/a b/b
+ copy from a
+ copy to b
+ --- a/a
+ +++ b/b
+ @@ -1,1 +1,2 @@
+ a
+ +5
+ diff --git a/a b/c
+ copy from a
+ copy to c
+ --- a/a
+ +++ b/c
+ @@ -1,1 +1,2 @@
+ a
+ +5
+
+ - parent to root: --rev . --rev 0
+ M a
+ b
+ R b
+ R c
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,2 +1,1 @@
+ a
+ -5
+ diff --git a/b b/b
+ deleted file mode 100644
+ --- a/b
+ +++ /dev/null
+ @@ -1,2 +0,0 @@
+ -a
+ -5
+ diff --git a/c b/c
+ deleted file mode 100644
+ --- a/c
+ +++ /dev/null
+ @@ -1,2 +0,0 @@
+ -a
+ -5
+
+ - branch to parent: --rev 2 --rev .
+ M a
+ A b
+ a
+ A c
+ a
+ R x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +5
+ diff --git a/a b/b
+ copy from a
+ copy to b
+ --- a/a
+ +++ b/b
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +5
+ diff --git a/a b/c
+ copy from a
+ copy to c
+ --- a/a
+ +++ b/c
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +5
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - parent to branch: --rev . --rev 2
+ M a
+ b
+ A x/y
+ R b
+ R c
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,2 +1,3 @@
+ a
+ -5
+ +m1
+ +m2
+ diff --git a/b b/b
+ deleted file mode 100644
+ --- a/b
+ +++ /dev/null
+ @@ -1,2 +0,0 @@
+ -a
+ -5
+ diff --git a/c b/c
+ deleted file mode 100644
+ --- a/c
+ +++ /dev/null
+ @@ -1,2 +0,0 @@
+ -a
+ -5
+ diff --git a/x/y b/x/y
+ new file mode 100644
+ --- /dev/null
+ +++ b/x/y
+ @@ -0,0 +1,1 @@
+ +y1
+
+
+ $ tb "add a a1" "hg mv a b" "hg mv b a" "circular rename"
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+ ** circular rename **
+ ** add a a1 / hg mv a b / hg mv b a
+ - working to parent:
+ A a
+ b
+ R b
+
+ diff --git a/b b/a
+ rename from b
+ rename to a
+
+ - working to root: --rev 0
+ M a
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,3 @@
+ a
+ +6
+ +a1
+
+ - working to branch: --rev 2
+ M a
+ R x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,3 +1,3 @@
+ a
+ -m1
+ -m2
+ +6
+ +a1
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - root to parent: --rev 0 --rev .
+ A b
+ a
+ R a
+
+ diff --git a/a b/b
+ rename from a
+ rename to b
+ --- a/a
+ +++ b/b
+ @@ -1,1 +1,3 @@
+ a
+ +6
+ +a1
+
+ - parent to root: --rev . --rev 0
+ A a
+ b
+ R b
+
+ diff --git a/b b/a
+ rename from b
+ rename to a
+ --- a/b
+ +++ b/a
+ @@ -1,3 +1,1 @@
+ a
+ -6
+ -a1
+
+ - branch to parent: --rev 2 --rev .
+ A b
+ a
+ R a
+ R x/y
+
+ diff --git a/a b/b
+ rename from a
+ rename to b
+ --- a/a
+ +++ b/b
+ @@ -1,3 +1,3 @@
+ a
+ -m1
+ -m2
+ +6
+ +a1
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+
+ - parent to branch: --rev . --rev 2
+ A a
+ b
+ A x/y
+ R b
+
+ diff --git a/b b/a
+ rename from b
+ rename to a
+ --- a/b
+ +++ b/a
+ @@ -1,3 +1,3 @@
+ a
+ -6
+ -a1
+ +m1
+ +m2
+ diff --git a/x/y b/x/y
+ new file mode 100644
+ --- /dev/null
+ +++ b/x/y
+ @@ -0,0 +1,1 @@
+ +y1
+
+
+ $ tb "hg mv x y" "add y/x x1" "add y/x x2" "directory move"
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+ moving x/x to y/x (glob)
+ ** directory move **
+ ** hg mv x y / add y/x x1 / add y/x x2
+ - working to parent:
+ M y/x
+
+ diff --git a/y/x b/y/x
+ --- a/y/x
+ +++ b/y/x
+ @@ -1,2 +1,3 @@
+ x
+ x1
+ +x2
+
+ - working to root: --rev 0
+ M a
+ A y/x
+ x/x
+ R x/x
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,2 @@
+ a
+ +7
+ diff --git a/x/x b/y/x
+ rename from x/x
+ rename to y/x
+ --- a/x/x
+ +++ b/y/x
+ @@ -1,1 +1,3 @@
+ x
+ +x1
+ +x2
+
+ - working to branch: --rev 2
+ M a
+ A y/x
+ x/x
+ R x/x
+ R x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +7
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+ diff --git a/x/x b/y/x
+ rename from x/x
+ rename to y/x
+ --- a/x/x
+ +++ b/y/x
+ @@ -1,1 +1,3 @@
+ x
+ +x1
+ +x2
+
+ - root to parent: --rev 0 --rev .
+ M a
+ A y/x
+ x/x
+ R x/x
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,2 @@
+ a
+ +7
+ diff --git a/x/x b/y/x
+ rename from x/x
+ rename to y/x
+ --- a/x/x
+ +++ b/y/x
+ @@ -1,1 +1,2 @@
+ x
+ +x1
+
+ - parent to root: --rev . --rev 0
+ M a
+ A x/x
+ y/x
+ R y/x
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,2 +1,1 @@
+ a
+ -7
+ diff --git a/y/x b/x/x
+ rename from y/x
+ rename to x/x
+ --- a/y/x
+ +++ b/x/x
+ @@ -1,2 +1,1 @@
+ x
+ -x1
+
+ - branch to parent: --rev 2 --rev .
+ M a
+ A y/x
+ x/x
+ R x/x
+ R x/y
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,3 +1,2 @@
+ a
+ -m1
+ -m2
+ +7
+ diff --git a/x/y b/x/y
+ deleted file mode 100644
+ --- a/x/y
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -y1
+ diff --git a/x/x b/y/x
+ rename from x/x
+ rename to y/x
+ --- a/x/x
+ +++ b/y/x
+ @@ -1,1 +1,2 @@
+ x
+ +x1
+
+ - parent to branch: --rev . --rev 2
+ M a
+ A x/x
+ y/x
+ A x/y
+ R y/x
+
+ diff --git a/a b/a
+ --- a/a
+ +++ b/a
+ @@ -1,2 +1,3 @@
+ a
+ -7
+ +m1
+ +m2
+ diff --git a/y/x b/x/x
+ rename from y/x
+ rename to x/x
+ --- a/y/x
+ +++ b/x/x
+ @@ -1,2 +1,1 @@
+ x
+ -x1
+ diff --git a/x/y b/x/y
+ new file mode 100644
+ --- /dev/null
+ +++ b/x/y
+ @@ -0,0 +1,1 @@
+ +y1
+
+
+
+Cannot implement unrelated branch with tb
+testing copies with unrelated branch
+
+ $ hg init unrelated
+ $ cd unrelated
+ $ add a a
+ $ hg ci -Am adda
+ adding a
+ $ hg mv a b
+ $ hg ci -m movea
+ $ hg up -C null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ add a a
+ $ hg ci -Am addunrelateda
+ adding a
+ created new head
+
+unrelated branch diff
+
+ $ hg diff --git -r 2 -r 1
+ diff --git a/a b/a
+ deleted file mode 100644
+ --- a/a
+ +++ /dev/null
+ @@ -1,1 +0,0 @@
+ -a
+ diff --git a/b b/b
+ new file mode 100644
+ --- /dev/null
+ +++ b/b
+ @@ -0,0 +1,1 @@
+ +a
+ $ cd ..
diff --git a/tests/test-nested-repo.t b/tests/test-nested-repo.t
new file mode 100644
index 0000000..ddea413
--- /dev/null
+++ b/tests/test-nested-repo.t
@@ -0,0 +1,41 @@
+ $ hg init a
+ $ cd a
+ $ hg init b
+ $ echo x > b/x
+
+Should print nothing:
+
+ $ hg add b
+ $ hg st
+
+Should fail:
+
+ $ hg st b/x
+ abort: path 'b/x' is inside nested repo 'b' (glob)
+ [255]
+ $ hg add b/x
+ abort: path 'b/x' is inside nested repo 'b' (glob)
+ [255]
+
+Should fail:
+
+ $ hg add b b/x
+ abort: path 'b/x' is inside nested repo 'b' (glob)
+ [255]
+ $ hg st
+
+Should arguably print nothing:
+
+ $ hg st b
+
+ $ echo a > a
+ $ hg ci -Ama a
+
+Should fail:
+
+ $ hg mv a b
+ abort: path 'b/a' is inside nested repo 'b' (glob)
+ [255]
+ $ hg st
+
+ $ cd ..
diff --git a/tests/test-newbranch.t b/tests/test-newbranch.t
new file mode 100644
index 0000000..f1099b8
--- /dev/null
+++ b/tests/test-newbranch.t
@@ -0,0 +1,330 @@
+ $ branchcache=.hg/cache/branchheads
+
+ $ hg init t
+ $ cd t
+
+ $ hg branches
+ $ echo foo > a
+ $ hg add a
+ $ hg ci -m "initial"
+ $ hg branch foo
+ marked working directory as branch foo
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg branch
+ foo
+ $ hg ci -m "add branch name"
+ $ hg branch bar
+ marked working directory as branch bar
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m "change branch name"
+
+Branch shadowing:
+
+ $ hg branch default
+ abort: a branch of the same name already exists
+ (use 'hg update' to switch to it)
+ [255]
+
+ $ hg branch -f default
+ marked working directory as branch default
+ (branches are permanent and global, did you want a bookmark?)
+
+ $ hg ci -m "clear branch name"
+ created new head
+
+There should be only one default branch head
+
+ $ hg heads .
+ changeset: 3:1c28f494dae6
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: clear branch name
+
+
+ $ hg co foo
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch
+ foo
+ $ echo bleah > a
+ $ hg ci -m "modify a branch"
+
+ $ hg merge default
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg branch
+ foo
+ $ hg ci -m "merge"
+
+ $ hg log
+ changeset: 5:530046499edf
+ branch: foo
+ tag: tip
+ parent: 4:adf1a74a7f7b
+ parent: 3:1c28f494dae6
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: merge
+
+ changeset: 4:adf1a74a7f7b
+ branch: foo
+ parent: 1:6c0e42da283a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: modify a branch
+
+ changeset: 3:1c28f494dae6
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: clear branch name
+
+ changeset: 2:c21617b13b22
+ branch: bar
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change branch name
+
+ changeset: 1:6c0e42da283a
+ branch: foo
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add branch name
+
+ changeset: 0:db01e8ea3388
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: initial
+
+ $ hg branches
+ foo 5:530046499edf
+ default 3:1c28f494dae6 (inactive)
+ bar 2:c21617b13b22 (inactive)
+
+ $ hg branches -q
+ foo
+ default
+ bar
+
+Test for invalid branch cache:
+
+ $ hg rollback
+ repository tip rolled back to revision 4 (undo commit)
+ working directory now based on revisions 4 and 3
+
+ $ cp $branchcache .hg/bc-invalid
+
+ $ hg log -r foo
+ changeset: 4:adf1a74a7f7b
+ branch: foo
+ tag: tip
+ parent: 1:6c0e42da283a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: modify a branch
+
+ $ cp .hg/bc-invalid $branchcache
+
+ $ hg --debug log -r foo
+ invalidating branch cache (tip differs)
+ changeset: 4:adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6
+ branch: foo
+ tag: tip
+ phase: draft
+ parent: 1:6c0e42da283a56b5edc5b4fadb491365ec7f5fa8
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 1:8c342a37dfba0b3d3ce073562a00d8a813c54ffe
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: a
+ extra: branch=foo
+ description:
+ modify a branch
+
+
+ $ rm $branchcache
+ $ echo corrupted > $branchcache
+
+ $ hg log -qr foo
+ 4:adf1a74a7f7b
+
+ $ cat $branchcache
+ adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 4
+ 1c28f494dae69a2f8fc815059d257eccf3fcfe75 default
+ adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 foo
+ c21617b13b220988e7a2e26290fbe4325ffa7139 bar
+
+Push should update the branch cache:
+
+ $ hg init ../target
+
+Pushing just rev 0:
+
+ $ hg push -qr 0 ../target
+
+ $ cat ../target/$branchcache
+ db01e8ea3388fd3c7c94e1436ea2bd6a53d581c5 0
+ db01e8ea3388fd3c7c94e1436ea2bd6a53d581c5 default
+
+Pushing everything:
+
+ $ hg push -qf ../target
+
+ $ cat ../target/$branchcache
+ adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 4
+ 1c28f494dae69a2f8fc815059d257eccf3fcfe75 default
+ adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 foo
+ c21617b13b220988e7a2e26290fbe4325ffa7139 bar
+
+Update with no arguments: tipmost revision of the current branch:
+
+ $ hg up -q -C 0
+ $ hg up -q
+ $ hg id
+ 1c28f494dae6
+
+ $ hg up -q 1
+ $ hg up -q
+ $ hg id
+ adf1a74a7f7b (foo) tip
+
+ $ hg branch foobar
+ marked working directory as branch foobar
+ (branches are permanent and global, did you want a bookmark?)
+
+ $ hg up
+ abort: branch foobar not found
+ [255]
+
+Fastforward merge:
+
+ $ hg branch ff
+ marked working directory as branch ff
+ (branches are permanent and global, did you want a bookmark?)
+
+ $ echo ff > ff
+ $ hg ci -Am'fast forward'
+ adding ff
+
+ $ hg up foo
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ hg merge ff
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg branch
+ foo
+ $ hg commit -m'Merge ff into foo'
+ $ hg parents
+ changeset: 6:185ffbfefa30
+ branch: foo
+ tag: tip
+ parent: 4:adf1a74a7f7b
+ parent: 5:1a3c27dc5e11
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Merge ff into foo
+
+ $ hg manifest
+ a
+ ff
+
+
+Test merging, add 3 default heads and one test head:
+
+ $ cd ..
+ $ hg init merges
+ $ cd merges
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+
+ $ echo b > b
+ $ hg ci -Amb
+ adding b
+
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo c > c
+ $ hg ci -Amc
+ adding c
+ created new head
+
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo d > d
+ $ hg ci -Amd
+ adding d
+ created new head
+
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg branch test
+ marked working directory as branch test
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo e >> e
+ $ hg ci -Ame
+ adding e
+
+ $ hg log
+ changeset: 4:3a1e01ed1df4
+ branch: test
+ tag: tip
+ parent: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: e
+
+ changeset: 3:980f7dc84c29
+ parent: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: d
+
+ changeset: 2:d36c0562f908
+ parent: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: c
+
+ changeset: 1:d2ae7f538514
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+ changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+Implicit merge with test branch as parent:
+
+ $ hg merge
+ abort: branch 'test' has one head - please merge with an explicit rev
+ (run 'hg heads' to see all heads)
+ [255]
+ $ hg up -C default
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+Implicit merge with default branch as parent:
+
+ $ hg merge
+ abort: branch 'default' has 3 heads - please merge with an explicit rev
+ (run 'hg heads .' to see heads)
+ [255]
+
+3 branch heads, explicit merge required:
+
+ $ hg merge 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m merge
+
+2 branch heads, implicit merge works:
+
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cd ..
diff --git a/tests/test-newcgi.t b/tests/test-newcgi.t
new file mode 100644
index 0000000..fb4f541
--- /dev/null
+++ b/tests/test-newcgi.t
@@ -0,0 +1,66 @@
+ $ "$TESTDIR/hghave" no-msys || exit 80 # MSYS will translate web paths as if they were file paths
+
+This tests if CGI files from after d0db3462d568 but
+before d74fc8dec2b4 still work.
+
+ $ hg init test
+ $ cat >hgweb.cgi <<HGWEB
+ > #!/usr/bin/env python
+ > #
+ > # An example CGI script to use hgweb, edit as necessary
+ >
+ > import cgitb
+ > cgitb.enable()
+ >
+ > from mercurial import demandimport; demandimport.enable()
+ > from mercurial.hgweb import hgweb
+ > from mercurial.hgweb import wsgicgi
+ > from mercurial.hgweb.request import wsgiapplication
+ >
+ > def make_web_app():
+ > return hgweb("test", "Empty test repository")
+ >
+ > wsgicgi.launch(wsgiapplication(make_web_app))
+ > HGWEB
+
+ $ chmod 755 hgweb.cgi
+
+ $ cat >hgweb.config <<HGWEBDIRCONF
+ > [paths]
+ > test = test
+ > HGWEBDIRCONF
+
+ $ cat >hgwebdir.cgi <<HGWEBDIR
+ > #!/usr/bin/env python
+ > #
+ > # An example CGI script to export multiple hgweb repos, edit as necessary
+ >
+ > import cgitb
+ > cgitb.enable()
+ >
+ > from mercurial import demandimport; demandimport.enable()
+ > from mercurial.hgweb import hgwebdir
+ > from mercurial.hgweb import wsgicgi
+ > from mercurial.hgweb.request import wsgiapplication
+ >
+ > def make_web_app():
+ > return hgwebdir("hgweb.config")
+ >
+ > wsgicgi.launch(wsgiapplication(make_web_app))
+ > HGWEBDIR
+
+ $ chmod 755 hgwebdir.cgi
+
+ $ . "$TESTDIR/cgienv"
+ $ python hgweb.cgi > page1
+ $ python hgwebdir.cgi > page2
+
+ $ PATH_INFO="/test/"
+ $ PATH_TRANSLATED="/var/something/test.cgi"
+ $ REQUEST_URI="/test/test/"
+ $ SCRIPT_URI="http://hg.omnifarious.org/test/test/"
+ $ SCRIPT_URL="/test/test/"
+ $ python hgwebdir.cgi > page3
+
+ $ grep -i error page1 page2 page3
+ [1]
diff --git a/tests/test-newercgi.t b/tests/test-newercgi.t
new file mode 100644
index 0000000..b6771fc
--- /dev/null
+++ b/tests/test-newercgi.t
@@ -0,0 +1,60 @@
+ $ "$TESTDIR/hghave" no-msys || exit 80 # MSYS will translate web paths as if they were file paths
+
+This is a rudimentary test of the CGI files as of d74fc8dec2b4.
+
+ $ hg init test
+
+ $ cat >hgweb.cgi <<HGWEB
+ > #!/usr/bin/env python
+ > #
+ > # An example CGI script to use hgweb, edit as necessary
+ >
+ > import cgitb
+ > cgitb.enable()
+ >
+ > from mercurial import demandimport; demandimport.enable()
+ > from mercurial.hgweb import hgweb
+ > from mercurial.hgweb import wsgicgi
+ >
+ > application = hgweb("test", "Empty test repository")
+ > wsgicgi.launch(application)
+ > HGWEB
+
+ $ chmod 755 hgweb.cgi
+
+ $ cat >hgweb.config <<HGWEBDIRCONF
+ > [paths]
+ > test = test
+ > HGWEBDIRCONF
+
+ $ cat >hgwebdir.cgi <<HGWEBDIR
+ > #!/usr/bin/env python
+ > #
+ > # An example CGI script to export multiple hgweb repos, edit as necessary
+ >
+ > import cgitb
+ > cgitb.enable()
+ >
+ > from mercurial import demandimport; demandimport.enable()
+ > from mercurial.hgweb import hgwebdir
+ > from mercurial.hgweb import wsgicgi
+ >
+ > application = hgwebdir("hgweb.config")
+ > wsgicgi.launch(application)
+ > HGWEBDIR
+
+ $ chmod 755 hgwebdir.cgi
+
+ $ . "$TESTDIR/cgienv"
+ $ python hgweb.cgi > page1
+ $ python hgwebdir.cgi > page2
+
+ $ PATH_INFO="/test/"
+ $ PATH_TRANSLATED="/var/something/test.cgi"
+ $ REQUEST_URI="/test/test/"
+ $ SCRIPT_URI="http://hg.omnifarious.org/test/test/"
+ $ SCRIPT_URL="/test/test/"
+ $ python hgwebdir.cgi > page3
+
+ $ grep -i error page1 page2 page3
+ [1]
diff --git a/tests/test-no-symlinks.t b/tests/test-no-symlinks.t
new file mode 100644
index 0000000..e569067
--- /dev/null
+++ b/tests/test-no-symlinks.t
@@ -0,0 +1,59 @@
+ $ "$TESTDIR/hghave" no-symlink || exit 80
+
+# The following script was used to create the bundle:
+#
+# hg init symlinks
+# cd symlinks
+# echo a > a
+# mkdir d
+# echo b > d/b
+# ln -s a a.lnk
+# ln -s d/b d/b.lnk
+# hg ci -Am t
+# hg bundle --base null ../test-no-symlinks.hg
+
+Extract a symlink on a platform not supporting them
+
+ $ hg init t
+ $ cd t
+ $ hg pull -q "$TESTDIR/bundles/test-no-symlinks.hg"
+ $ hg update
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat a.lnk && echo
+ a
+ $ cat d/b.lnk && echo
+ d/b
+
+Copy a symlink and move another
+
+ $ hg copy a.lnk d/a2.lnk
+ $ hg mv d/b.lnk b2.lnk
+ $ hg ci -Am copy
+ $ cat d/a2.lnk && echo
+ a
+ $ cat b2.lnk && echo
+ d/b
+
+Bundle and extract again
+
+ $ hg bundle --base null ../symlinks.hg
+ 2 changesets found
+ $ cd ..
+ $ hg init t2
+ $ cd t2
+ $ hg pull ../symlinks.hg
+ pulling from ../symlinks.hg
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 6 changes to 6 files
+ (run 'hg update' to get a working copy)
+ $ hg update
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat a.lnk && echo
+ a
+ $ cat d/a2.lnk && echo
+ a
+ $ cat b2.lnk && echo
+ d/b
diff --git a/tests/test-notify-changegroup.t b/tests/test-notify-changegroup.t
new file mode 100644
index 0000000..d317adb
--- /dev/null
+++ b/tests/test-notify-changegroup.t
@@ -0,0 +1,214 @@
+
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > notify=
+ >
+ > [hooks]
+ > changegroup.notify = python:hgext.notify.hook
+ >
+ > [notify]
+ > sources = push
+ > diffstat = False
+ > maxsubject = 10
+ >
+ > [usersubs]
+ > foo@bar = *
+ >
+ > [reposubs]
+ > * = baz
+ > EOF
+ $ hg init a
+
+clone
+
+ $ hg --traceback clone a b
+ updating to branch default
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a > b/a
+
+commit
+
+ $ hg --traceback --cwd b commit -Ama
+ adding a
+ $ echo a >> b/a
+
+commit
+
+ $ hg --traceback --cwd b commit -Amb
+
+push
+
+ $ hg --traceback --cwd b push ../a 2>&1 |
+ > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
+ pushing to ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Date: * (glob)
+ Subject: * (glob)
+ From: test
+ X-Hg-Notification: changeset cb9a9f314b8b
+ Message-Id: <*> (glob)
+ To: baz, foo@bar
+
+ changeset cb9a9f314b8b in $TESTTMP/a (glob)
+ details: $TESTTMP/a?cmd=changeset;node=cb9a9f314b8b
+ summary: a
+
+ changeset ba677d0156c1 in $TESTTMP/a (glob)
+ details: $TESTTMP/a?cmd=changeset;node=ba677d0156c1
+ summary: b
+
+ diffs (6 lines):
+
+ diff -r 000000000000 -r ba677d0156c1 a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,2 @@
+ +a
+ +a
+ $ hg --cwd a rollback
+ repository tip rolled back to revision -1 (undo push)
+
+unbundle with unrelated source
+
+ $ hg --cwd b bundle ../test.hg ../a
+ searching for changes
+ 2 changesets found
+ $ hg --cwd a unbundle ../test.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg --cwd a rollback
+ repository tip rolled back to revision -1 (undo unbundle)
+
+unbundle with correct source
+
+ $ hg --config notify.sources=unbundle --cwd a unbundle ../test.hg 2>&1 |
+ > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Date: * (glob)
+ Subject: * (glob)
+ From: test
+ X-Hg-Notification: changeset cb9a9f314b8b
+ Message-Id: <*> (glob)
+ To: baz, foo@bar
+
+ changeset cb9a9f314b8b in $TESTTMP/a (glob)
+ details: $TESTTMP/a?cmd=changeset;node=cb9a9f314b8b
+ summary: a
+
+ changeset ba677d0156c1 in $TESTTMP/a (glob)
+ details: $TESTTMP/a?cmd=changeset;node=ba677d0156c1
+ summary: b
+
+ diffs (6 lines):
+
+ diff -r 000000000000 -r ba677d0156c1 a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,2 @@
+ +a
+ +a
+ (run 'hg update' to get a working copy)
+
+Check that using the first committer as the author of a changeset works:
+Check that the config option works.
+Check that the first committer is indeed used for "From:".
+Check that the merge user is NOT used for "From:"
+
+Create new file
+
+ $ echo a > b/b
+ $ echo b >> b/b
+ $ echo c >> b/b
+ $ hg --traceback --cwd b commit -Amnewfile -u committer_1
+ adding b
+
+commit as one user
+
+ $ echo x > b/b
+ $ echo b >> b/b
+ $ echo c >> b/b
+ $ hg --traceback --cwd b commit -Amx -u committer_2
+
+commit as other user, change file so we can do an (automatic) merge
+
+ $ hg --cwd b up 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a > b/b
+ $ echo b >> b/b
+ $ echo y >> b/b
+ $ hg --traceback --cwd b commit -Amy -u committer_3
+ created new head
+
+merge as a different user
+
+ $ hg --cwd b merge --config notify.fromauthor=True
+ merging b
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg --traceback --cwd b commit -Am "merged"
+
+push
+
+ $ hg --traceback --cwd b --config notify.fromauthor=True push ../a 2>&1 |
+ > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
+ pushing to ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 1 files
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Date: * (glob)
+ Subject: * (glob)
+ From: committer_1
+ X-Hg-Notification: changeset 84e487dddc58
+ Message-Id: <*> (glob)
+ To: baz, foo@bar
+
+ changeset 84e487dddc58 in $TESTTMP/a (glob)
+ details: $TESTTMP/a?cmd=changeset;node=84e487dddc58
+ summary: newfile
+
+ changeset b29c7a2b6b0c in $TESTTMP/a (glob)
+ details: $TESTTMP/a?cmd=changeset;node=b29c7a2b6b0c
+ summary: x
+
+ changeset 0957c7d64886 in $TESTTMP/a (glob)
+ details: $TESTTMP/a?cmd=changeset;node=0957c7d64886
+ summary: y
+
+ changeset 485b4e6b0249 in $TESTTMP/a (glob)
+ details: $TESTTMP/a?cmd=changeset;node=485b4e6b0249
+ summary: merged
+
+ diffs (7 lines):
+
+ diff -r ba677d0156c1 -r 485b4e6b0249 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,3 @@
+ +x
+ +b
+ +y
+ $ hg --cwd a rollback
+ repository tip rolled back to revision 1 (undo push)
+
diff --git a/tests/test-notify.t b/tests/test-notify.t
new file mode 100644
index 0000000..543ceba
--- /dev/null
+++ b/tests/test-notify.t
@@ -0,0 +1,475 @@
+
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > notify=
+ >
+ > [hooks]
+ > incoming.notify = python:hgext.notify.hook
+ >
+ > [notify]
+ > sources = pull
+ > diffstat = False
+ >
+ > [usersubs]
+ > foo@bar = *
+ >
+ > [reposubs]
+ > * = baz
+ > EOF
+ $ hg help notify
+ notify extension - hooks for sending email push notifications
+
+ This extension implements hooks to send email notifications when changesets
+ are sent from or received by the local repository.
+
+ First, enable the extension as explained in "hg help extensions", and register
+ the hook you want to run. "incoming" and "changegroup" hooks are run when
+ changesets are received, while "outgoing" hooks are for changesets sent to
+ another repository:
+
+ [hooks]
+ # one email for each incoming changeset
+ incoming.notify = python:hgext.notify.hook
+ # one email for all incoming changesets
+ changegroup.notify = python:hgext.notify.hook
+
+ # one email for all outgoing changesets
+ outgoing.notify = python:hgext.notify.hook
+
+ This registers the hooks. To enable notification, subscribers must be assigned
+ to repositories. The "[usersubs]" section maps multiple repositories to a
+ given recipient. The "[reposubs]" section maps multiple recipients to a single
+ repository:
+
+ [usersubs]
+ # key is subscriber email, value is a comma-separated list of repo glob
+ # patterns
+ user@host = pattern
+
+ [reposubs]
+ # key is glob pattern, value is a comma-separated list of subscriber
+ # emails
+ pattern = user@host
+
+ Glob patterns are matched against absolute path to repository root.
+
+ In order to place them under direct user management, "[usersubs]" and
+ "[reposubs]" sections may be placed in a separate "hgrc" file and incorporated
+ by reference:
+
+ [notify]
+ config = /path/to/subscriptionsfile
+
+ Notifications will not be sent until the "notify.test" value is set to
+ "False"; see below.
+
+ Notifications content can be tweaked with the following configuration entries:
+
+ notify.test
+ If "True", print messages to stdout instead of sending them. Default: True.
+
+ notify.sources
+ Space-separated list of change sources. Notifications are activated only
+ when a changeset's source is in this list. Sources may be:
+
+ "serve" changesets received via http or ssh
+ "pull" changesets received via "hg pull"
+ "unbundle" changesets received via "hg unbundle"
+ "push" changesets sent or received via "hg push"
+ "bundle" changesets sent via "hg unbundle"
+
+ Default: serve.
+
+ notify.strip
+ Number of leading slashes to strip from url paths. By default, notifications
+ reference repositories with their absolute path. "notify.strip" lets you
+ turn them into relative paths. For example, "notify.strip=3" will change
+ "/long/path/repository" into "repository". Default: 0.
+
+ notify.domain
+ Default email domain for sender or recipients with no explicit domain.
+
+ notify.style
+ Style file to use when formatting emails.
+
+ notify.template
+ Template to use when formatting emails.
+
+ notify.incoming
+ Template to use when run as an incoming hook, overriding "notify.template".
+
+ notify.outgoing
+ Template to use when run as an outgoing hook, overriding "notify.template".
+
+ notify.changegroup
+ Template to use when running as a changegroup hook, overriding
+ "notify.template".
+
+ notify.maxdiff
+ Maximum number of diff lines to include in notification email. Set to 0 to
+ disable the diff, or -1 to include all of it. Default: 300.
+
+ notify.maxsubject
+ Maximum number of characters in email's subject line. Default: 67.
+
+ notify.diffstat
+ Set to True to include a diffstat before diff content. Default: True.
+
+ notify.merge
+ If True, send notifications for merge changesets. Default: True.
+
+ notify.mbox
+ If set, append mails to this mbox file instead of sending. Default: None.
+
+ notify.fromauthor
+ If set, use the committer of the first changeset in a changegroup for the
+ "From" field of the notification mail. If not set, take the user from the
+ pushing repo. Default: False.
+
+ If set, the following entries will also be used to customize the
+ notifications:
+
+ email.from
+ Email "From" address to use if none can be found in the generated email
+ content.
+
+ web.baseurl
+ Root repository URL to combine with repository paths when making references.
+ See also "notify.strip".
+
+ no commands defined
+ $ hg init a
+ $ echo a > a/a
+
+commit
+
+ $ hg --cwd a commit -Ama -d '0 0'
+ adding a
+
+
+clone
+
+ $ hg --traceback clone a b
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a >> a/a
+
+commit
+
+ $ hg --traceback --cwd a commit -Amb -d '1 0'
+
+on Mac OS X 10.5 the tmp path is very long so would get stripped in the subject line
+
+ $ cat <<EOF >> $HGRCPATH
+ > [notify]
+ > maxsubject = 200
+ > EOF
+
+the python call below wraps continuation lines, which appear on Mac OS X 10.5 because
+of the very long subject line
+pull (minimal config)
+
+ $ hg --traceback --cwd b pull ../a | \
+ > python -c 'import sys,re; print re.sub("\n[\t ]", " ", sys.stdin.read()),'
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Date: * (glob)
+ Subject: changeset in $TESTTMP/b: b
+ From: test
+ X-Hg-Notification: changeset 0647d048b600
+ Message-Id: <*> (glob)
+ To: baz, foo@bar
+
+ changeset 0647d048b600 in $TESTTMP/b (glob)
+ details: $TESTTMP/b?cmd=changeset;node=0647d048b600
+ description: b
+
+ diffs (6 lines):
+
+ diff -r cb9a9f314b8b -r 0647d048b600 a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -1,1 +1,2 @@ a
+ +a
+ (run 'hg update' to get a working copy)
+ $ cat <<EOF >> $HGRCPATH
+ > [notify]
+ > config = `pwd`/.notify.conf
+ > domain = test.com
+ > strip = 42
+ > template = Subject: {desc|firstline|strip}\nFrom: {author}\nX-Test: foo\n\nchangeset {node|short} in {webroot}\ndescription:\n\t{desc|tabindent|strip}
+ >
+ > [web]
+ > baseurl = http://test/
+ > EOF
+
+fail for config file is missing
+
+ $ hg --cwd b rollback
+ repository tip rolled back to revision 0 (undo pull)
+ $ hg --cwd b pull ../a 2>&1 | grep 'error.*\.notify\.conf' > /dev/null && echo pull failed
+ pull failed
+ $ touch ".notify.conf"
+
+pull
+
+ $ hg --cwd b rollback
+ repository tip rolled back to revision 0 (undo pull)
+ $ hg --traceback --cwd b pull ../a | \
+ > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ X-Test: foo
+ Date: * (glob)
+ Subject: b
+ From: test@test.com
+ X-Hg-Notification: changeset 0647d048b600
+ Message-Id: <*> (glob)
+ To: baz@test.com, foo@bar
+
+ changeset 0647d048b600 in b
+ description: b
+ diffs (6 lines):
+
+ diff -r cb9a9f314b8b -r 0647d048b600 a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -1,1 +1,2 @@
+ a
+ +a
+ (run 'hg update' to get a working copy)
+
+ $ cat << EOF >> $HGRCPATH
+ > [hooks]
+ > incoming.notify = python:hgext.notify.hook
+ >
+ > [notify]
+ > sources = pull
+ > diffstat = True
+ > EOF
+
+pull
+
+ $ hg --cwd b rollback
+ repository tip rolled back to revision 0 (undo pull)
+ $ hg --traceback --cwd b pull ../a | \
+ > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ X-Test: foo
+ Date: * (glob)
+ Subject: b
+ From: test@test.com
+ X-Hg-Notification: changeset 0647d048b600
+ Message-Id: <*> (glob)
+ To: baz@test.com, foo@bar
+
+ changeset 0647d048b600 in b
+ description: b
+ diffstat:
+
+ a | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+ diffs (6 lines):
+
+ diff -r cb9a9f314b8b -r 0647d048b600 a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -1,1 +1,2 @@
+ a
+ +a
+ (run 'hg update' to get a working copy)
+
+test merge
+
+ $ cd a
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a >> a
+ $ hg ci -Am adda2 -d '2 0'
+ created new head
+ $ hg merge
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m merge -d '3 0'
+ $ cd ..
+ $ hg --traceback --cwd b pull ../a | \
+ > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 0 changes to 0 files
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ X-Test: foo
+ Date: * (glob)
+ Subject: adda2
+ From: test@test.com
+ X-Hg-Notification: changeset 0a184ce6067f
+ Message-Id: <*> (glob)
+ To: baz@test.com, foo@bar
+
+ changeset 0a184ce6067f in b
+ description: adda2
+ diffstat:
+
+ a | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+ diffs (6 lines):
+
+ diff -r cb9a9f314b8b -r 0a184ce6067f a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:02 1970 +0000
+ @@ -1,1 +1,2 @@
+ a
+ +a
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ X-Test: foo
+ Date: * (glob)
+ Subject: merge
+ From: test@test.com
+ X-Hg-Notification: changeset 6a0cf76b2701
+ Message-Id: <*> (glob)
+ To: baz@test.com, foo@bar
+
+ changeset 6a0cf76b2701 in b
+ description: merge
+ (run 'hg update' to get a working copy)
+
+non-ascii content and truncation of multi-byte subject
+
+ $ cat <<EOF >> $HGRCPATH
+ > [notify]
+ > maxsubject = 4
+ > EOF
+ $ echo a >> a/a
+ $ hg --cwd a --encoding utf-8 commit -A -d '0 0' \
+ > -m `python -c 'print "\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4"'`
+ $ hg --traceback --cwd b --encoding utf-8 pull ../a | \
+ > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 8bit
+ X-Test: foo
+ Date: * (glob)
+ Subject: \xc3\xa0... (esc)
+ From: test@test.com
+ X-Hg-Notification: changeset 7ea05ad269dc
+ Message-Id: <*> (glob)
+ To: baz@test.com, foo@bar
+
+ changeset 7ea05ad269dc in b
+ description: \xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4 (esc)
+ diffstat:
+
+ a | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+ diffs (7 lines):
+
+ diff -r 6a0cf76b2701 -r 7ea05ad269dc a
+ --- a/a Thu Jan 01 00:00:03 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,2 +1,3 @@
+ a
+ a
+ +a
+ (run 'hg update' to get a working copy)
+
+long lines
+
+ $ cat <<EOF >> $HGRCPATH
+ > [notify]
+ > maxsubject = 67
+ > test = False
+ > mbox = mbox
+ > EOF
+ $ python -c 'file("a/a", "ab").write("no" * 500 + "\n")'
+ $ hg --cwd a commit -A -m "long line"
+ $ hg --traceback --cwd b pull ../a
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ notify: sending 2 subscribers 1 changes
+ (run 'hg update' to get a working copy)
+ $ python -c 'import sys,re; print re.sub("\n\t", " ", file("b/mbox").read()),'
+ From test@test.com ... ... .. ..:..:.. .... (re)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: quoted-printable
+ X-Test: foo
+ Date: * (glob)
+ Subject: long line
+ From: test@test.com
+ X-Hg-Notification: changeset e0be44cf638b
+ Message-Id: <hg.e0be44cf638b.*.*@*> (glob)
+ To: baz@test.com, foo@bar
+
+ changeset e0be44cf638b in b
+ description: long line
+ diffstat:
+
+ a | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+ diffs (8 lines):
+
+ diff -r 7ea05ad269dc -r e0be44cf638b a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,3 +1,4 @@
+ a
+ a
+ a
+ +nonononononononononononononononononononononononononononononononononononono=
+ nononononononononononononononononononononononononononononononononononononon=
+ ononononononononononononononononononononononononononononononononononononono=
+ nononononononononononononononononononononononononononononononononononononon=
+ ononononononononononononononononononononononononononononononononononononono=
+ nononononononononononononononononononononononononononononononononononononon=
+ ononononononononononononononononononononononononononononononononononononono=
+ nononononononononononononononononononononononononononononononononononononon=
+ ononononononononononononononononononononononononononononononononononononono=
+ nononononononononononononononononononononononononononononononononononononon=
+ ononononononononononononononononononononononononononononononononononononono=
+ nononononononononononononononononononononononononononononononononononononon=
+ ononononononononononononononononononononononononononononononononononononono=
+ nonononononononononononono
+
diff --git a/tests/test-obsolete-changeset-exchange.t b/tests/test-obsolete-changeset-exchange.t
new file mode 100644
index 0000000..861556e
--- /dev/null
+++ b/tests/test-obsolete-changeset-exchange.t
@@ -0,0 +1,55 @@
+Test changesets filtering during exchanges (some tests are still in
+test-obsolete.t)
+
+ $ cat > obs.py << EOF
+ > import mercurial.obsolete
+ > mercurial.obsolete._enabled = True
+ > EOF
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
+
+Push does not corrupt remote
+----------------------------
+
+Create a DAG where a changeset reuses a revision from a file first used in an
+extinct changeset.
+
+ $ hg init local
+ $ cd local
+ $ echo 'base' > base
+ $ hg commit -Am base
+ adding base
+ $ echo 'A' > A
+ $ hg commit -Am A
+ adding A
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg revert -ar 1
+ adding A
+ $ hg commit -Am "A'"
+ created new head
+ $ hg log -G --template='{desc} {node}'
+ @ A' f89bcc95eba5174b1ccc3e33a82e84c96e8338ee
+ |
+ | o A 9d73aac1b2ed7d53835eaeec212ed41ea47da53a
+ |/
+ o base d20a80d4def38df63a4b330b7fb688f3d4cae1e3
+
+ $ hg debugobsolete 9d73aac1b2ed7d53835eaeec212ed41ea47da53a f89bcc95eba5174b1ccc3e33a82e84c96e8338ee
+
+Push it. The bundle should not refer to the extinct changeset.
+
+ $ hg init ../other
+ $ hg push ../other
+ pushing to ../other
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ $ hg -R ../other verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 2 changesets, 2 total revisions
diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t
new file mode 100644
index 0000000..40abaca
--- /dev/null
+++ b/tests/test-obsolete.t
@@ -0,0 +1,508 @@
+ $ cat >> $HGRCPATH << EOF
+ > [extensions]
+ > graphlog=
+ > [phases]
+ > # public changeset are not obsolete
+ > publish=false
+ > EOF
+ $ mkcommit() {
+ > echo "$1" > "$1"
+ > hg add "$1"
+ > hg ci -m "add $1"
+ > }
+ $ getid() {
+ > hg id --debug -ir "desc('$1')"
+ > }
+
+ $ cat > debugkeys.py <<EOF
+ > def reposetup(ui, repo):
+ > class debugkeysrepo(repo.__class__):
+ > def listkeys(self, namespace):
+ > ui.write('listkeys %s\n' % (namespace,))
+ > return super(debugkeysrepo, self).listkeys(namespace)
+ >
+ > if repo.local():
+ > repo.__class__ = debugkeysrepo
+ > EOF
+
+ $ hg init tmpa
+ $ cd tmpa
+ $ mkcommit kill_me
+
+Checking that the feature is properly disabled
+
+ $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
+ abort: obsolete feature is not enabled on this repo
+ [255]
+
+Enabling it
+
+ $ cat > ../obs.py << EOF
+ > import mercurial.obsolete
+ > mercurial.obsolete._enabled = True
+ > EOF
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
+
+Killing a single changeset without replacement
+
+ $ hg debugobsolete 0
+ abort: changeset references must be full hexadecimal node identifiers
+ [255]
+ $ hg debugobsolete '00'
+ abort: changeset references must be full hexadecimal node identifiers
+ [255]
+ $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
+ $ hg debugobsolete
+ 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 {'date': '0 0', 'user': 'babar'}
+ $ cd ..
+
+Killing a single changeset with replacement
+
+ $ hg init tmpb
+ $ cd tmpb
+ $ mkcommit a
+ $ mkcommit b
+ $ mkcommit original_c
+ $ hg up "desc('b')"
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit new_c
+ created new head
+ $ hg debugobsolete `getid original_c` `getid new_c` -d '56 12'
+ $ hg debugobsolete
+ 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
+
+do it again (it read the obsstore before adding new changeset)
+
+ $ hg up '.^'
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit new_2_c
+ created new head
+ $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
+ $ hg debugobsolete
+ 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
+
+Register two markers with a missing node
+
+ $ hg up '.^'
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit new_3_c
+ created new head
+ $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
+ $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
+ $ hg debugobsolete
+ 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
+ ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
+
+Check that graphlog detect that a changeset is obsolete:
+
+ $ hg glog
+ @ changeset: 5:5601fb93a350
+ | tag: tip
+ | parent: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add new_3_c
+ |
+ o changeset: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add b
+ |
+ o changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+
+Check that public changeset are not accounted as obsolete:
+
+ $ hg phase --public 2
+ $ hg --config 'extensions.graphlog=' glog
+ @ changeset: 5:5601fb93a350
+ | tag: tip
+ | parent: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add new_3_c
+ |
+ | o changeset: 2:245bde4270cd
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add original_c
+ |
+ o changeset: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add b
+ |
+ o changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+
+ $ cd ..
+
+Exchange Test
+============================
+
+Destination repo does not have any data
+---------------------------------------
+
+Try to pull markers
+(extinct changeset are excluded but marker are pushed)
+
+ $ hg init tmpc
+ $ cd tmpc
+ $ hg pull ../tmpb
+ pulling from ../tmpb
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg debugobsolete
+ 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
+ ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
+
+Rollback//Transaction support
+
+ $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+ $ hg debugobsolete
+ 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
+ ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '1340 0', 'user': 'test'}
+ $ hg rollback -n
+ repository tip rolled back to revision 3 (undo debugobsolete)
+ $ hg rollback
+ repository tip rolled back to revision 3 (undo debugobsolete)
+ $ hg debugobsolete
+ 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
+ ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
+
+ $ cd ..
+
+Try to pull markers
+
+ $ hg init tmpd
+ $ hg -R tmpb push tmpd
+ pushing to tmpd
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ $ hg -R tmpd debugobsolete
+ 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
+ ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
+
+Check obsolete keys are exchanged only if source has an obsolete store
+
+ $ hg init empty
+ $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
+ pushing to tmpd
+ no changes found
+ listkeys phases
+ listkeys bookmarks
+ [1]
+
+clone support
+(markers are copied and extinct changesets are included to allow hardlinks)
+
+ $ hg clone tmpb clone-dest
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R clone-dest log -G --hidden
+ @ changeset: 5:5601fb93a350
+ | tag: tip
+ | parent: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add new_3_c
+ |
+ | x changeset: 4:ca819180edb9
+ |/ parent: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add new_2_c
+ |
+ | x changeset: 3:cdbce2fbb163
+ |/ parent: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add new_c
+ |
+ | o changeset: 2:245bde4270cd
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add original_c
+ |
+ o changeset: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add b
+ |
+ o changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+ $ hg -R clone-dest debugobsolete
+ 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
+ ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
+
+
+Destination repo have existing data
+---------------------------------------
+
+On pull
+
+ $ hg init tmpe
+ $ cd tmpe
+ $ hg debugobsolete -d '1339 0' 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339
+ $ hg pull ../tmpb
+ pulling from ../tmpb
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 4 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg debugobsolete
+ 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
+ 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
+ ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
+
+
+On push
+
+ $ hg push ../tmpc
+ pushing to ../tmpc
+ searching for changes
+ no changes found
+ [1]
+ $ hg -R ../tmpc debugobsolete
+ 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
+ ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
+ 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
+
+detect outgoing obsolete and unstable
+---------------------------------------
+
+
+ $ hg glog
+ o changeset: 3:5601fb93a350
+ | tag: tip
+ | parent: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add new_3_c
+ |
+ | o changeset: 2:245bde4270cd
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add original_c
+ |
+ o changeset: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add b
+ |
+ o changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+ $ hg up 'desc("new_3_c")'
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mkcommit original_d
+ $ mkcommit original_e
+ $ hg debugobsolete `getid original_d` -d '0 0'
+ $ hg log -r 'obsolete()'
+ changeset: 4:7c694bff0650
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add original_d
+
+ $ hg glog -r '::unstable()'
+ @ changeset: 5:6e572121998e
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add original_e
+ |
+ x changeset: 4:7c694bff0650
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add original_d
+ |
+ o changeset: 3:5601fb93a350
+ | parent: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add new_3_c
+ |
+ o changeset: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add b
+ |
+ o changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+
+refuse to push obsolete changeset
+
+ $ hg push ../tmpc/ -r 'desc("original_d")'
+ pushing to ../tmpc/
+ searching for changes
+ abort: push includes an obsolete changeset: 7c694bff0650!
+ [255]
+
+refuse to push unstable changeset
+
+ $ hg push ../tmpc/
+ pushing to ../tmpc/
+ searching for changes
+ abort: push includes an unstable changeset: 6e572121998e!
+ [255]
+
+Test that extinct changeset are properly detected
+
+ $ hg log -r 'extinct()'
+
+Don't try to push extinct changeset
+
+ $ hg init ../tmpf
+ $ hg out ../tmpf
+ comparing with ../tmpf
+ searching for changes
+ changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+ changeset: 1:7c3bad9141dc
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add b
+
+ changeset: 2:245bde4270cd
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add original_c
+
+ changeset: 3:5601fb93a350
+ parent: 1:7c3bad9141dc
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add new_3_c
+
+ changeset: 4:7c694bff0650
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add original_d
+
+ changeset: 5:6e572121998e
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add original_e
+
+ $ hg push ../tmpf -f # -f because be push unstable too
+ pushing to ../tmpf
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 6 changes to 6 files (+1 heads)
+
+no warning displayed
+
+ $ hg push ../tmpf
+ pushing to ../tmpf
+ searching for changes
+ no changes found
+ [1]
+
+Do not warn about new head when the new head is a successors of a remote one
+
+ $ hg glog
+ @ changeset: 5:6e572121998e
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add original_e
+ |
+ x changeset: 4:7c694bff0650
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add original_d
+ |
+ o changeset: 3:5601fb93a350
+ | parent: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add new_3_c
+ |
+ | o changeset: 2:245bde4270cd
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add original_c
+ |
+ o changeset: 1:7c3bad9141dc
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: add b
+ |
+ o changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+ $ hg up -q 'desc(new_3_c)'
+ $ mkcommit obsolete_e
+ created new head
+ $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'`
+ $ hg push ../tmpf
+ pushing to ../tmpf
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+
+Checking _enable=False warning if obsolete marker exists
+
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo "obs=!" >> $HGRCPATH
+ $ hg log -r tip
+ obsolete feature not enabled but 7 markers found!
+ changeset: 6:d6a026544050
+ tag: tip
+ parent: 3:5601fb93a350
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add obsolete_e
+
diff --git a/tests/test-oldcgi.t b/tests/test-oldcgi.t
new file mode 100644
index 0000000..2651a9c
--- /dev/null
+++ b/tests/test-oldcgi.t
@@ -0,0 +1,76 @@
+ $ "$TESTDIR/hghave" no-msys || exit 80 # MSYS will translate web paths as if they were file paths
+
+This tests if CGI files from before d0db3462d568 still work.
+
+ $ hg init test
+ $ cat >hgweb.cgi <<HGWEB
+ > #!/usr/bin/env python
+ > #
+ > # An example CGI script to use hgweb, edit as necessary
+ >
+ > import cgitb, os, sys
+ > cgitb.enable()
+ >
+ > # sys.path.insert(0, "/path/to/python/lib") # if not a system-wide install
+ > from mercurial import hgweb
+ >
+ > h = hgweb.hgweb("test", "Empty test repository")
+ > h.run()
+ > HGWEB
+
+ $ chmod 755 hgweb.cgi
+
+ $ cat >hgweb.config <<HGWEBDIRCONF
+ > [paths]
+ > test = test
+ > HGWEBDIRCONF
+
+ $ cat >hgwebdir.cgi <<HGWEBDIR
+ > #!/usr/bin/env python
+ > #
+ > # An example CGI script to export multiple hgweb repos, edit as necessary
+ >
+ > import cgitb, sys
+ > cgitb.enable()
+ >
+ > # sys.path.insert(0, "/path/to/python/lib") # if not a system-wide install
+ > from mercurial import hgweb
+ >
+ > # The config file looks like this. You can have paths to individual
+ > # repos, collections of repos in a directory tree, or both.
+ > #
+ > # [paths]
+ > # virtual/path = /real/path
+ > # virtual/path = /real/path
+ > #
+ > # [collections]
+ > # /prefix/to/strip/off = /root/of/tree/full/of/repos
+ > #
+ > # collections example: say directory tree /foo contains repos /foo/bar,
+ > # /foo/quux/baz. Give this config section:
+ > # [collections]
+ > # /foo = /foo
+ > # Then repos will list as bar and quux/baz.
+ >
+ > # Alternatively you can pass a list of ('virtual/path', '/real/path') tuples
+ > # or use a dictionary with entries like 'virtual/path': '/real/path'
+ >
+ > h = hgweb.hgwebdir("hgweb.config")
+ > h.run()
+ > HGWEBDIR
+
+ $ chmod 755 hgwebdir.cgi
+
+ $ . "$TESTDIR/cgienv"
+ $ python hgweb.cgi > page1
+ $ python hgwebdir.cgi > page2
+
+ $ PATH_INFO="/test/"
+ $ PATH_TRANSLATED="/var/something/test.cgi"
+ $ REQUEST_URI="/test/test/"
+ $ SCRIPT_URI="http://hg.omnifarious.org/test/test/"
+ $ SCRIPT_URL="/test/test/"
+ $ python hgwebdir.cgi > page3
+
+ $ grep -i error page1 page2 page3
+ [1]
diff --git a/tests/test-parents.t b/tests/test-parents.t
new file mode 100644
index 0000000..36f7c65
--- /dev/null
+++ b/tests/test-parents.t
@@ -0,0 +1,154 @@
+test parents command
+
+ $ hg init repo
+ $ cd repo
+
+no working directory
+
+ $ hg parents
+
+ $ echo a > a
+ $ echo b > b
+ $ hg ci -Amab -d '0 0'
+ adding a
+ adding b
+ $ echo a >> a
+ $ hg ci -Ama -d '1 0'
+ $ echo b >> b
+ $ hg ci -Amb -d '2 0'
+ $ echo c > c
+ $ hg ci -Amc -d '3 0'
+ adding c
+ $ hg up -C 1
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo d > c
+ $ hg ci -Amc2 -d '4 0'
+ adding c
+ created new head
+ $ hg up -C 3
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+
+ $ hg parents
+ changeset: 3:02d851b7e549
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: c
+
+
+ $ hg parents a
+ changeset: 1:d786049f033a
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: a
+
+
+hg parents c, single revision
+
+ $ hg parents c
+ changeset: 3:02d851b7e549
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: c
+
+
+ $ hg parents -r 3 c
+ abort: 'c' not found in manifest!
+ [255]
+
+ $ hg parents -r 2
+ changeset: 1:d786049f033a
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: a
+
+
+ $ hg parents -r 2 a
+ changeset: 1:d786049f033a
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: a
+
+
+ $ hg parents -r 2 ../a
+ abort: ../a not under root
+ [255]
+
+
+cd dir; hg parents -r 2 ../a
+
+ $ mkdir dir
+ $ cd dir
+ $ hg parents -r 2 ../a
+ changeset: 1:d786049f033a
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: a
+
+ $ hg parents -r 2 path:a
+ changeset: 1:d786049f033a
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: a
+
+ $ cd ..
+
+ $ hg parents -r 2 glob:a
+ abort: can only specify an explicit filename
+ [255]
+
+
+merge working dir with 2 parents, hg parents c
+
+ $ HGMERGE=true hg merge
+ merging c
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg parents c
+ changeset: 3:02d851b7e549
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: c
+
+ changeset: 4:48cee28d4b4e
+ tag: tip
+ parent: 1:d786049f033a
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: c2
+
+
+
+merge working dir with 1 parent, hg parents
+
+ $ hg up -C 2
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ HGMERGE=true hg merge -r 4
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg parents
+ changeset: 2:6cfac479f009
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: b
+
+ changeset: 4:48cee28d4b4e
+ tag: tip
+ parent: 1:d786049f033a
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: c2
+
+
+merge working dir with 1 parent, hg parents c
+
+ $ hg parents c
+ changeset: 4:48cee28d4b4e
+ tag: tip
+ parent: 1:d786049f033a
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: c2
+
+
+ $ cd ..
diff --git a/tests/test-parse-date.t b/tests/test-parse-date.t
new file mode 100644
index 0000000..c08b27c
--- /dev/null
+++ b/tests/test-parse-date.t
@@ -0,0 +1,236 @@
+This runs with TZ="GMT"
+
+ $ hg init
+ $ echo "test-parse-date" > a
+ $ hg add a
+ $ hg ci -d "2006-02-01 13:00:30" -m "rev 0"
+ $ echo "hi!" >> a
+ $ hg ci -d "2006-02-01 13:00:30 -0500" -m "rev 1"
+ $ hg tag -d "2006-04-15 13:30" "Hi"
+ $ hg backout --merge -d "2006-04-15 13:30 +0200" -m "rev 3" 1
+ reverting a
+ created new head
+ changeset 3:107ce1ee2b43 backs out changeset 1:25a1420a55f8
+ merging with changeset 3:107ce1ee2b43
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -d "1150000000 14400" -m "rev 4 (merge)"
+ $ echo "fail" >> a
+ $ hg ci -d "should fail" -m "fail"
+ abort: invalid date: 'should fail'
+ [255]
+ $ hg ci -d "100000000000000000 1400" -m "fail"
+ abort: date exceeds 32 bits: 100000000000000000
+ [255]
+ $ hg ci -d "100000 1400000" -m "fail"
+ abort: impossible time zone offset: 1400000
+ [255]
+
+Check with local timezone other than GMT and with DST
+
+ $ TZ="PST+8PDT"
+ $ export TZ
+
+PST=UTC-8 / PDT=UTC-7
+
+ $ hg debugrebuildstate
+ $ echo "a" > a
+ $ hg ci -d "2006-07-15 13:30" -m "summer@UTC-7"
+ $ hg debugrebuildstate
+ $ echo "b" > a
+ $ hg ci -d "2006-07-15 13:30 +0500" -m "summer@UTC+5"
+ $ hg debugrebuildstate
+ $ echo "c" > a
+ $ hg ci -d "2006-01-15 13:30" -m "winter@UTC-8"
+ $ hg debugrebuildstate
+ $ echo "d" > a
+ $ hg ci -d "2006-01-15 13:30 +0500" -m "winter@UTC+5"
+ $ hg log --template '{date|date}\n'
+ Sun Jan 15 13:30:00 2006 +0500
+ Sun Jan 15 13:30:00 2006 -0800
+ Sat Jul 15 13:30:00 2006 +0500
+ Sat Jul 15 13:30:00 2006 -0700
+ Sun Jun 11 00:26:40 2006 -0400
+ Sat Apr 15 13:30:00 2006 +0200
+ Sat Apr 15 13:30:00 2006 +0000
+ Wed Feb 01 13:00:30 2006 -0500
+ Wed Feb 01 13:00:30 2006 +0000
+
+Test issue1014 (fractional timezones)
+
+ $ hg debugdate "1000000000 -16200" # 0430
+ internal: 1000000000 -16200
+ standard: Sun Sep 09 06:16:40 2001 +0430
+ $ hg debugdate "1000000000 -15300" # 0415
+ internal: 1000000000 -15300
+ standard: Sun Sep 09 06:01:40 2001 +0415
+ $ hg debugdate "1000000000 -14400" # 0400
+ internal: 1000000000 -14400
+ standard: Sun Sep 09 05:46:40 2001 +0400
+ $ hg debugdate "1000000000 0" # GMT
+ internal: 1000000000 0
+ standard: Sun Sep 09 01:46:40 2001 +0000
+ $ hg debugdate "1000000000 14400" # -0400
+ internal: 1000000000 14400
+ standard: Sat Sep 08 21:46:40 2001 -0400
+ $ hg debugdate "1000000000 15300" # -0415
+ internal: 1000000000 15300
+ standard: Sat Sep 08 21:31:40 2001 -0415
+ $ hg debugdate "1000000000 16200" # -0430
+ internal: 1000000000 16200
+ standard: Sat Sep 08 21:16:40 2001 -0430
+ $ hg debugdate "Sat Sep 08 21:16:40 2001 +0430"
+ internal: 999967600 -16200
+ standard: Sat Sep 08 21:16:40 2001 +0430
+ $ hg debugdate "Sat Sep 08 21:16:40 2001 -0430"
+ internal: 1000000000 16200
+ standard: Sat Sep 08 21:16:40 2001 -0430
+
+Test 12-hours times
+
+ $ hg debugdate "2006-02-01 1:00:30PM +0000"
+ internal: 1138798830 0
+ standard: Wed Feb 01 13:00:30 2006 +0000
+ $ hg debugdate "1:00:30PM" > /dev/null
+
+Normal range
+
+ $ hg log -d -1
+
+Negative range
+
+ $ hg log -d "--2"
+ abort: -2 must be nonnegative (see 'hg help dates')
+ [255]
+
+Whitespace only
+
+ $ hg log -d " "
+ abort: dates cannot consist entirely of whitespace
+ [255]
+
+Test date formats with '>' or '<' accompanied by space characters
+
+ $ hg log -d '>' --template '{date|date}\n'
+ abort: invalid day spec, use '>DATE'
+ [255]
+ $ hg log -d '<' --template '{date|date}\n'
+ abort: invalid day spec, use '<DATE'
+ [255]
+
+ $ hg log -d ' >' --template '{date|date}\n'
+ abort: invalid day spec, use '>DATE'
+ [255]
+ $ hg log -d ' <' --template '{date|date}\n'
+ abort: invalid day spec, use '<DATE'
+ [255]
+
+ $ hg log -d '> ' --template '{date|date}\n'
+ abort: invalid day spec, use '>DATE'
+ [255]
+ $ hg log -d '< ' --template '{date|date}\n'
+ abort: invalid day spec, use '<DATE'
+ [255]
+
+ $ hg log -d ' > ' --template '{date|date}\n'
+ abort: invalid day spec, use '>DATE'
+ [255]
+ $ hg log -d ' < ' --template '{date|date}\n'
+ abort: invalid day spec, use '<DATE'
+ [255]
+
+ $ hg log -d '>02/01' --template '{date|date}\n'
+ $ hg log -d '<02/01' --template '{date|date}\n'
+ Sun Jan 15 13:30:00 2006 +0500
+ Sun Jan 15 13:30:00 2006 -0800
+ Sat Jul 15 13:30:00 2006 +0500
+ Sat Jul 15 13:30:00 2006 -0700
+ Sun Jun 11 00:26:40 2006 -0400
+ Sat Apr 15 13:30:00 2006 +0200
+ Sat Apr 15 13:30:00 2006 +0000
+ Wed Feb 01 13:00:30 2006 -0500
+ Wed Feb 01 13:00:30 2006 +0000
+
+ $ hg log -d ' >02/01' --template '{date|date}\n'
+ $ hg log -d ' <02/01' --template '{date|date}\n'
+ Sun Jan 15 13:30:00 2006 +0500
+ Sun Jan 15 13:30:00 2006 -0800
+ Sat Jul 15 13:30:00 2006 +0500
+ Sat Jul 15 13:30:00 2006 -0700
+ Sun Jun 11 00:26:40 2006 -0400
+ Sat Apr 15 13:30:00 2006 +0200
+ Sat Apr 15 13:30:00 2006 +0000
+ Wed Feb 01 13:00:30 2006 -0500
+ Wed Feb 01 13:00:30 2006 +0000
+
+ $ hg log -d '> 02/01' --template '{date|date}\n'
+ $ hg log -d '< 02/01' --template '{date|date}\n'
+ Sun Jan 15 13:30:00 2006 +0500
+ Sun Jan 15 13:30:00 2006 -0800
+ Sat Jul 15 13:30:00 2006 +0500
+ Sat Jul 15 13:30:00 2006 -0700
+ Sun Jun 11 00:26:40 2006 -0400
+ Sat Apr 15 13:30:00 2006 +0200
+ Sat Apr 15 13:30:00 2006 +0000
+ Wed Feb 01 13:00:30 2006 -0500
+ Wed Feb 01 13:00:30 2006 +0000
+
+ $ hg log -d ' > 02/01' --template '{date|date}\n'
+ $ hg log -d ' < 02/01' --template '{date|date}\n'
+ Sun Jan 15 13:30:00 2006 +0500
+ Sun Jan 15 13:30:00 2006 -0800
+ Sat Jul 15 13:30:00 2006 +0500
+ Sat Jul 15 13:30:00 2006 -0700
+ Sun Jun 11 00:26:40 2006 -0400
+ Sat Apr 15 13:30:00 2006 +0200
+ Sat Apr 15 13:30:00 2006 +0000
+ Wed Feb 01 13:00:30 2006 -0500
+ Wed Feb 01 13:00:30 2006 +0000
+
+ $ hg log -d '>02/01 ' --template '{date|date}\n'
+ $ hg log -d '<02/01 ' --template '{date|date}\n'
+ Sun Jan 15 13:30:00 2006 +0500
+ Sun Jan 15 13:30:00 2006 -0800
+ Sat Jul 15 13:30:00 2006 +0500
+ Sat Jul 15 13:30:00 2006 -0700
+ Sun Jun 11 00:26:40 2006 -0400
+ Sat Apr 15 13:30:00 2006 +0200
+ Sat Apr 15 13:30:00 2006 +0000
+ Wed Feb 01 13:00:30 2006 -0500
+ Wed Feb 01 13:00:30 2006 +0000
+
+ $ hg log -d ' >02/01 ' --template '{date|date}\n'
+ $ hg log -d ' <02/01 ' --template '{date|date}\n'
+ Sun Jan 15 13:30:00 2006 +0500
+ Sun Jan 15 13:30:00 2006 -0800
+ Sat Jul 15 13:30:00 2006 +0500
+ Sat Jul 15 13:30:00 2006 -0700
+ Sun Jun 11 00:26:40 2006 -0400
+ Sat Apr 15 13:30:00 2006 +0200
+ Sat Apr 15 13:30:00 2006 +0000
+ Wed Feb 01 13:00:30 2006 -0500
+ Wed Feb 01 13:00:30 2006 +0000
+
+ $ hg log -d '> 02/01 ' --template '{date|date}\n'
+ $ hg log -d '< 02/01 ' --template '{date|date}\n'
+ Sun Jan 15 13:30:00 2006 +0500
+ Sun Jan 15 13:30:00 2006 -0800
+ Sat Jul 15 13:30:00 2006 +0500
+ Sat Jul 15 13:30:00 2006 -0700
+ Sun Jun 11 00:26:40 2006 -0400
+ Sat Apr 15 13:30:00 2006 +0200
+ Sat Apr 15 13:30:00 2006 +0000
+ Wed Feb 01 13:00:30 2006 -0500
+ Wed Feb 01 13:00:30 2006 +0000
+
+ $ hg log -d ' > 02/01 ' --template '{date|date}\n'
+ $ hg log -d ' < 02/01 ' --template '{date|date}\n'
+ Sun Jan 15 13:30:00 2006 +0500
+ Sun Jan 15 13:30:00 2006 -0800
+ Sat Jul 15 13:30:00 2006 +0500
+ Sat Jul 15 13:30:00 2006 -0700
+ Sun Jun 11 00:26:40 2006 -0400
+ Sat Apr 15 13:30:00 2006 +0200
+ Sat Apr 15 13:30:00 2006 +0000
+ Wed Feb 01 13:00:30 2006 -0500
+ Wed Feb 01 13:00:30 2006 +0000
diff --git a/tests/test-parseindex.t b/tests/test-parseindex.t
new file mode 100644
index 0000000..6807f50
--- /dev/null
+++ b/tests/test-parseindex.t
@@ -0,0 +1,61 @@
+revlog.parseindex must be able to parse the index file even if
+an index entry is split between two 64k blocks. The ideal test
+would be to create an index file with inline data where
+64k < size < 64k + 64 (64k is the size of the read buffer, 64 is
+the size of an index entry) and with an index entry starting right
+before the 64k block boundary, and try to read it.
+We approximate that by reducing the read buffer to 1 byte.
+
+ $ hg init a
+ $ cd a
+ $ echo abc > foo
+ $ hg add foo
+ $ hg commit -m 'add foo'
+ $ echo >> foo
+ $ hg commit -m 'change foo'
+ $ hg log -r 0:
+ changeset: 0:7c31755bf9b5
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo
+
+ changeset: 1:26333235a41c
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change foo
+
+ $ cat >> test.py << EOF
+ > from mercurial import changelog, scmutil
+ > from mercurial.node import *
+ >
+ > class singlebyteread(object):
+ > def __init__(self, real):
+ > self.real = real
+ >
+ > def read(self, size=-1):
+ > if size == 65536:
+ > size = 1
+ > return self.real.read(size)
+ >
+ > def __getattr__(self, key):
+ > return getattr(self.real, key)
+ >
+ > def opener(*args):
+ > o = scmutil.opener(*args)
+ > def wrapper(*a):
+ > f = o(*a)
+ > return singlebyteread(f)
+ > return wrapper
+ >
+ > cl = changelog.changelog(opener('.hg/store'))
+ > print len(cl), 'revisions:'
+ > for r in cl:
+ > print short(cl.node(r))
+ > EOF
+ $ python test.py
+ 2 revisions:
+ 7c31755bf9b5
+ 26333235a41c
+
+ $ cd ..
diff --git a/tests/test-parseindex2.py b/tests/test-parseindex2.py
new file mode 100644
index 0000000..1098226
--- /dev/null
+++ b/tests/test-parseindex2.py
@@ -0,0 +1,126 @@
+from mercurial import parsers
+from mercurial.node import nullid, nullrev
+import struct
+
+# This unit test compares the return value of the original Python
+# implementation of parseindex and the new C implementation for
+# an index file with and without inlined data
+
+# original python implementation
+def gettype(q):
+ return int(q & 0xFFFF)
+
+def offset_type(offset, type):
+ return long(long(offset) << 16 | type)
+
+indexformatng = ">Qiiiiii20s12x"
+
+def py_parseindex(data, inline) :
+ s = 64
+ cache = None
+ index = []
+ nodemap = {nullid: nullrev}
+ n = off = 0
+
+ l = len(data) - s
+ append = index.append
+ if inline:
+ cache = (0, data)
+ while off <= l:
+ e = struct.unpack(indexformatng, data[off:off + s])
+ nodemap[e[7]] = n
+ append(e)
+ n += 1
+ if e[1] < 0:
+ break
+ off += e[1] + s
+ else:
+ while off <= l:
+ e = struct.unpack(indexformatng, data[off:off + s])
+ nodemap[e[7]] = n
+ append(e)
+ n += 1
+ off += s
+
+ e = list(index[0])
+ type = gettype(e[0])
+ e[0] = offset_type(0, type)
+ index[0] = tuple(e)
+
+ # add the magic null revision at -1
+ index.append((0, 0, 0, -1, -1, -1, -1, nullid))
+
+ return index, cache
+
+data_inlined = '\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x01\x8c' \
+ '\x00\x00\x04\x07\x00\x00\x00\x00\x00\x00\x15\x15\xff\xff\xff' \
+ '\xff\xff\xff\xff\xff\xebG\x97\xb7\x1fB\x04\xcf\x13V\x81\tw\x1b' \
+ 'w\xdduR\xda\xc6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \
+ 'x\x9c\x9d\x93?O\xc30\x10\xc5\xf7|\x8a\xdb\x9a\xa8m\x06\xd8*\x95' \
+ '\x81B\xa1\xa2\xa2R\xcb\x86Pd\x9a\x0b5$vd_\x04\xfd\xf6\x9c\xff@' \
+ '\x11!\x0b\xd9\xec\xf7\xbbw\xe7gG6\xad6\x04\xdaN\xc0\x92\xa0$)' \
+ '\xb1\x82\xa2\xd1%\x16\xa4\x8b7\xa9\xca\xd4-\xb2Y\x02\xfc\xc9' \
+ '\xcaS\xf9\xaeX\xed\xb6\xd77Q\x02\x83\xd4\x19\xf5--Y\xea\xe1W' \
+ '\xab\xed\x10\xceR\x0f_\xdf\xdf\r\xe1,\xf5\xf0\xcb\xf5 \xceR\x0f' \
+ '_\xdc\x0e\x0e\xc3R\x0f_\xae\x96\x9b!\x9e\xa5\x1e\xbf\xdb,\x06' \
+ '\xc7q\x9a/\x88\x82\xc3B\xea\xb5\xb4TJ\x93\xb6\x82\x0e\xe16\xe6' \
+ 'KQ\xdb\xaf\xecG\xa3\xd1 \x01\xd3\x0b_^\xe8\xaa\xa0\xae\xad\xd1' \
+ '&\xbef\x1bz\x08\xb0|\xc9Xz\x06\xf6Z\x91\x90J\xaa\x17\x90\xaa' \
+ '\xd2\xa6\x11$5C\xcf\xba#\xa0\x03\x02*2\x92-\xfc\xb1\x94\xdf\xe2' \
+ '\xae\xb8\'m\x8ey0^\x85\xd3\x82\xb4\xf0`:\x9c\x00\x8a\xfd\x01' \
+ '\xb0\xc6\x86\x8b\xdd\xae\x80\xf3\xa9\x9fd\x16\n\x00R%\x1a\x06' \
+ '\xe9\xd8b\x98\x1d\xf4\xf3+\x9bf\x01\xd8p\x1b\xf3.\xed\x9f^g\xc3' \
+ '^\xd9W81T\xdb\xd5\x04sx|\xf2\xeb\xd6`%?x\xed"\x831\xbf\xf3\xdc' \
+ 'b\xeb%gaY\xe1\xad\x9f\xb9f\'1w\xa9\xa5a\x83s\x82J\xb98\xbc4\x8b' \
+ '\x83\x00\x9f$z\xb8#\xa5\xb1\xdf\x98\xd9\xec\x1b\x89O\xe3Ts\x9a4' \
+ '\x17m\x8b\xfc\x8f\xa5\x95\x9a\xfc\xfa\xed,\xe5|\xa1\xfe\x15\xb9' \
+ '\xbc\xb2\x93\x1f\xf2\x95\xff\xdf,\x1a\xc5\xe7\x17*\x93Oz:>\x0e'
+
+data_non_inlined = '\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01D\x19' \
+ '\x00\x07e\x12\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff' \
+ '\xff\xff\xff\xff\xd1\xf4\xbb\xb0\xbe\xfc\x13\xbd\x8c\xd3\x9d' \
+ '\x0f\xcd\xd9;\x8c\x07\x8cJ/\x00\x00\x00\x00\x00\x00\x00\x00\x00' \
+ '\x00\x00\x00\x00\x00\x00\x01D\x19\x00\x00\x00\x00\x00\xdf\x00' \
+ '\x00\x01q\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\xff' \
+ '\xff\xff\xff\xc1\x12\xb9\x04\x96\xa4Z1t\x91\xdfsJ\x90\xf0\x9bh' \
+ '\x07l&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \
+ '\x00\x01D\xf8\x00\x00\x00\x00\x01\x1b\x00\x00\x01\xb8\x00\x00' \
+ '\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\x02\n' \
+ '\x0e\xc6&\xa1\x92\xae6\x0b\x02i\xfe-\xe5\xbao\x05\xd1\xe7\x00' \
+ '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01F' \
+ '\x13\x00\x00\x00\x00\x01\xec\x00\x00\x03\x06\x00\x00\x00\x01' \
+ '\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x12\xcb\xeby1' \
+ '\xb6\r\x98B\xcb\x07\xbd`\x8f\x92\xd9\xc4\x84\xbdK\x00\x00\x00' \
+ '\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+
+def parse_index2(data, inline):
+ index, chunkcache = parsers.parse_index2(data, inline)
+ return list(index), chunkcache
+
+def runtest() :
+ py_res_1 = py_parseindex(data_inlined, True)
+ c_res_1 = parse_index2(data_inlined, True)
+
+ py_res_2 = py_parseindex(data_non_inlined, False)
+ c_res_2 = parse_index2(data_non_inlined, False)
+
+ if py_res_1 != c_res_1:
+ print "Parse index result (with inlined data) differs!"
+
+ if py_res_2 != c_res_2:
+ print "Parse index result (no inlined data) differs!"
+
+ ix = parsers.parse_index2(data_inlined, True)[0]
+ for i, r in enumerate(ix):
+ if r[7] == nullid:
+ i = -1
+ try:
+ if ix[r[7]] != i:
+ print 'Reverse lookup inconsistent for %r' % r[7].encode('hex')
+ except TypeError:
+ # pure version doesn't support this
+ break
+
+ print "done"
+
+runtest()
diff --git a/tests/test-parseindex2.py.out b/tests/test-parseindex2.py.out
new file mode 100644
index 0000000..19f86f4
--- /dev/null
+++ b/tests/test-parseindex2.py.out
@@ -0,0 +1 @@
+done
diff --git a/tests/test-patch-offset.t b/tests/test-patch-offset.t
new file mode 100644
index 0000000..02508c5
--- /dev/null
+++ b/tests/test-patch-offset.t
@@ -0,0 +1,79 @@
+
+ $ cat > writepatterns.py <<EOF
+ > import sys
+ >
+ > path = sys.argv[1]
+ > patterns = sys.argv[2:]
+ >
+ > fp = file(path, 'wb')
+ > for pattern in patterns:
+ > count = int(pattern[0:-1])
+ > char = pattern[-1] + '\n'
+ > fp.write(char*count)
+ > fp.close()
+ > EOF
+
+prepare repo
+
+ $ hg init a
+ $ cd a
+
+These initial lines of Xs were not in the original file used to generate
+the patch. So all the patch hunks need to be applied to a constant offset
+within this file. If the offset isn't tracked then the hunks can be
+applied to the wrong lines of this file.
+
+ $ python ../writepatterns.py a 34X 10A 1B 10A 1C 10A 1B 10A 1D 10A 1B 10A 1E 10A 1B 10A
+ $ hg commit -Am adda
+ adding a
+
+This is a cleaner patch generated via diff
+In this case it reproduces the problem when
+the output of hg export does not
+import patch
+
+ $ hg import -v -m 'b' -d '2 0' - <<EOF
+ > --- a/a 2009-12-08 19:26:17.000000000 -0800
+ > +++ b/a 2009-12-08 19:26:17.000000000 -0800
+ > @@ -9,7 +9,7 @@
+ > A
+ > A
+ > B
+ > -A
+ > +a
+ > A
+ > A
+ > A
+ > @@ -53,7 +53,7 @@
+ > A
+ > A
+ > B
+ > -A
+ > +a
+ > A
+ > A
+ > A
+ > @@ -75,7 +75,7 @@
+ > A
+ > A
+ > B
+ > -A
+ > +a
+ > A
+ > A
+ > A
+ > EOF
+ applying patch from stdin
+ patching file a
+ Hunk #1 succeeded at 43 (offset 34 lines).
+ Hunk #2 succeeded at 87 (offset 34 lines).
+ Hunk #3 succeeded at 109 (offset 34 lines).
+ a
+ created 189885cecb41
+
+compare imported changes against reference file
+
+ $ python ../writepatterns.py aref 34X 10A 1B 1a 9A 1C 10A 1B 10A 1D 10A 1B 1a 9A 1E 10A 1B 1a 9A
+ $ diff aref a
+
+ $ cd ..
diff --git a/tests/test-patch.t b/tests/test-patch.t
new file mode 100644
index 0000000..6528ce0
--- /dev/null
+++ b/tests/test-patch.t
@@ -0,0 +1,89 @@
+ $ cat > patchtool.py <<EOF
+ > import sys
+ > print 'Using custom patch'
+ > if '--binary' in sys.argv:
+ > print '--binary found !'
+ > EOF
+
+ $ echo "[ui]" >> $HGRCPATH
+ $ echo "patch=python ../patchtool.py" >> $HGRCPATH
+
+ $ hg init a
+ $ cd a
+ $ echo a > a
+ $ hg commit -Ama -d '1 0'
+ adding a
+ $ echo b >> a
+ $ hg commit -Amb -d '2 0'
+ $ cd ..
+
+This test checks that:
+ - custom patch commands with arguments actually work
+ - patch code does not try to add weird arguments like
+ --binary when custom patch commands are used. For instance
+ --binary is added by default under win32.
+
+check custom patch options are honored
+
+ $ hg --cwd a export -o ../a.diff tip
+ $ hg clone -r 0 a b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg --cwd b import -v ../a.diff
+ applying ../a.diff
+ Using custom patch
+ applied to working directory
+
+Issue2417: hg import with # comments in description
+
+Prepare source repo and patch:
+
+ $ rm $HGRCPATH
+ $ hg init c
+ $ cd c
+ $ printf "a\rc" > a
+ $ hg ci -A -m 0 a -d '0 0'
+ $ printf "a\rb\rc" > a
+ $ cat << eof > log
+ > first line which can't start with '# '
+ > # second line is a comment but that shouldn't be a problem.
+ > A patch marker like this was more problematic even after d7452292f9d3:
+ > # HG changeset patch
+ > # User lines looks like this - but it _is_ just a comment
+ > eof
+ $ hg ci -l log -d '0 0'
+ $ hg export -o p 1
+ $ cd ..
+
+Clone and apply patch:
+
+ $ hg clone -r 0 c d
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd d
+ $ hg import ../c/p
+ applying ../c/p
+ $ hg log -v -r 1
+ changeset: 1:cd0bde79c428
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: a
+ description:
+ first line which can't start with '# '
+ # second line is a comment but that shouldn't be a problem.
+ A patch marker like this was more problematic even after d7452292f9d3:
+ # HG changeset patch
+ # User lines looks like this - but it _is_ just a comment
+
+
+ $ cd ..
diff --git a/tests/test-patchbomb.t b/tests/test-patchbomb.t
new file mode 100644
index 0000000..3ce7407
--- /dev/null
+++ b/tests/test-patchbomb.t
@@ -0,0 +1,2351 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "patchbomb=" >> $HGRCPATH
+
+ $ hg init t
+ $ cd t
+ $ echo a > a
+ $ hg commit -Ama -d '1 0'
+ adding a
+
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -r tip
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] a ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH] a
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+
+ $ hg --config ui.interactive=1 email --confirm -n -f quux -t foo -c bar -r tip<<EOF
+ > n
+ > EOF
+ this patch series consists of 1 patches.
+
+
+ Final summary:
+
+ From: quux
+ To: foo
+ Cc: bar
+ Subject: [PATCH] a
+ a | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+ are you sure you want to send (yn)? abort: patchbomb canceled
+ [255]
+
+ $ echo b > b
+ $ hg commit -Amb -d '2 0'
+ adding b
+
+ $ hg email --date '1970-1-1 0:2' -n -f quux -t foo -c bar -s test -r 0:tip
+ this patch series consists of 2 patches.
+
+
+ Write the introductory message for the patch series.
+
+
+ displaying [PATCH 0 of 2] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 2] test
+ Message-Id: <patchbomb.120@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:02:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+
+ displaying [PATCH 1 of 2] a ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 1 of 2] a
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.121@*> (glob)
+ In-Reply-To: <patchbomb.120@*> (glob)
+ References: <patchbomb.120@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:02:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ displaying [PATCH 2 of 2] b ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 2 of 2] b
+ X-Mercurial-Node: 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ Message-Id: <97d72e5f12c7e84f8506.122@*> (glob)
+ In-Reply-To: <patchbomb.120@*> (glob)
+ References: <patchbomb.120@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:02:02 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 2 0
+ # Node ID 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ # Parent 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ b
+
+ diff -r 8580ff50825a -r 97d72e5f12c7 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:02 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+
+.hg/last-email.txt
+
+ $ cat > editor.sh << '__EOF__'
+ > echo "a precious introductory message" > "$1"
+ > __EOF__
+ $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg email -n -t foo -s test -r 0:tip > /dev/null
+ $ cat .hg/last-email.txt
+ a precious introductory message
+
+ $ hg email -m test.mbox -f quux -t foo -c bar -s test 0:tip \
+ > --config extensions.progress= --config progress.assume-tty=1 \
+ > --config progress.delay=0 --config progress.refresh=0 \
+ > --config progress.width=60 2>&1 | \
+ > python "$TESTDIR/filtercr.py"
+ this patch series consists of 2 patches.
+
+
+ Write the introductory message for the patch series.
+
+
+ sending [ ] 0/3
+ sending [ ] 0/3
+
+
+ sending [==============> ] 1/3
+ sending [==============> ] 1/3
+
+
+ sending [=============================> ] 2/3
+ sending [=============================> ] 2/3
+ \r (esc)
+ sending [PATCH 0 of 2] test ...
+ sending [PATCH 1 of 2] a ...
+ sending [PATCH 2 of 2] b ...
+
+
+ $ cd ..
+
+ $ hg clone -q t t2
+ $ cd t2
+ $ echo c > c
+ $ hg commit -Amc -d '3 0'
+ adding c
+
+ $ cat > description <<EOF
+ > a multiline
+ >
+ > description
+ > EOF
+
+
+test bundle and description:
+ $ hg email --date '1970-1-1 0:3' -n -f quux -t foo \
+ > -c bar -s test -r tip -b --desc description
+ searching for changes
+ 1 changesets found
+
+ displaying test ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: test
+ Message-Id: <patchbomb.180@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:03:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+
+ a multiline
+
+ description
+
+ --===* (glob)
+ Content-Type: application/x-mercurial-bundle
+ MIME-Version: 1.0
+ Content-Disposition: attachment; filename="bundle.hg"
+ Content-Transfer-Encoding: base64
+
+ SEcxMEJaaDkxQVkmU1nvR7I3AAAN////lFYQWj1/4HwRkdC/AywIAk0E4pfoSIIIgQCgGEQOcLAA
+ 2tA1VPyp4mkeoG0EaaPU0GTT1GjRiNPIg9CZGBqZ6UbU9J+KFU09DNUaGgAAAAAANAGgAAAAA1U8
+ oGgAADQGgAANNANAAAAAAZipFLz3XoakCEQB3PVPyHJVi1iYkAAKQAZQGpQGZESInRnCFMqLDla2
+ Bx3qfRQeA2N4lnzKkAmP8kR2asievLLXXebVU8Vg4iEBqcJNJAxIapSU6SM4888ZAciRG6MYAIEE
+ SlIBpFisgGkyRjX//TMtfcUAEsGu56+YnE1OlTZmzKm8BSu2rvo4rHAYYaadIFFuTy0LYgIkgLVD
+ sgVa2F19D1tx9+hgbAygLgQwaIqcDdgA4BjQgIiz/AEP72++llgDKhKducqodGE4B0ETqF3JFOFC
+ Q70eyNw=
+ --===*-- (glob)
+
+utf-8 patch:
+ $ python -c 'fp = open("utf", "wb"); fp.write("h\xC3\xB6mma!\n"); fp.close();'
+ $ hg commit -A -d '4 0' -m 'utf-8 content'
+ adding description
+ adding utf
+
+no mime encoding for email --test:
+ $ hg email --date '1970-1-1 0:4' -f quux -t foo -c bar -r tip -n
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] utf-8 content ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 8bit
+ Subject: [PATCH] utf-8 content
+ X-Mercurial-Node: 909a00e13e9d78b575aeee23dddbada46d5a143f
+ Message-Id: <909a00e13e9d78b575ae.240@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:04:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Node ID 909a00e13e9d78b575aeee23dddbada46d5a143f
+ # Parent ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ utf-8 content
+
+ diff -r ff2c9fa2018b -r 909a00e13e9d description
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/description Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,3 @@
+ +a multiline
+ +
+ +description
+ diff -r ff2c9fa2018b -r 909a00e13e9d utf
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/utf Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,1 @@
+ +h\xc3\xb6mma! (esc)
+
+
+mime encoded mbox (base64):
+ $ hg email --date '1970-1-1 0:4' -f 'Q <quux>' -t foo -c bar -r tip -m mbox
+ this patch series consists of 1 patches.
+
+
+ sending [PATCH] utf-8 content ...
+
+ $ cat mbox
+ From quux ... ... .. ..:..:.. .... (re)
+ Content-Type: text/plain; charset="utf-8"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: base64
+ Subject: [PATCH] utf-8 content
+ X-Mercurial-Node: 909a00e13e9d78b575aeee23dddbada46d5a143f
+ Message-Id: <909a00e13e9d78b575ae.240@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:04:00 +0000
+ From: Q <quux>
+ To: foo
+ Cc: bar
+
+ IyBIRyBjaGFuZ2VzZXQgcGF0Y2gKIyBVc2VyIHRlc3QKIyBEYXRlIDQgMAojIE5vZGUgSUQgOTA5
+ YTAwZTEzZTlkNzhiNTc1YWVlZTIzZGRkYmFkYTQ2ZDVhMTQzZgojIFBhcmVudCAgZmYyYzlmYTIw
+ MThiMTVmYTc0YjMzMzYzYmRhOTUyNzMyM2UyYTk5Zgp1dGYtOCBjb250ZW50CgpkaWZmIC1yIGZm
+ MmM5ZmEyMDE4YiAtciA5MDlhMDBlMTNlOWQgZGVzY3JpcHRpb24KLS0tIC9kZXYvbnVsbAlUaHUg
+ SmFuIDAxIDAwOjAwOjAwIDE5NzAgKzAwMDAKKysrIGIvZGVzY3JpcHRpb24JVGh1IEphbiAwMSAw
+ MDowMDowNCAxOTcwICswMDAwCkBAIC0wLDAgKzEsMyBAQAorYSBtdWx0aWxpbmUKKworZGVzY3Jp
+ cHRpb24KZGlmZiAtciBmZjJjOWZhMjAxOGIgLXIgOTA5YTAwZTEzZTlkIHV0ZgotLS0gL2Rldi9u
+ dWxsCVRodSBKYW4gMDEgMDA6MDA6MDAgMTk3MCArMDAwMAorKysgYi91dGYJVGh1IEphbiAwMSAw
+ MDowMDowNCAxOTcwICswMDAwCkBAIC0wLDAgKzEsMSBAQAoraMO2bW1hIQo=
+
+
+ $ python -c 'print open("mbox").read().split("\n\n")[1].decode("base64")'
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Node ID 909a00e13e9d78b575aeee23dddbada46d5a143f
+ # Parent ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ utf-8 content
+
+ diff -r ff2c9fa2018b -r 909a00e13e9d description
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/description Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,3 @@
+ +a multiline
+ +
+ +description
+ diff -r ff2c9fa2018b -r 909a00e13e9d utf
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/utf Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,1 @@
+ +h\xc3\xb6mma! (esc)
+
+ $ rm mbox
+
+mime encoded mbox (quoted-printable):
+ $ python -c 'fp = open("long", "wb"); fp.write("%s\nfoo\n\nbar\n" % ("x" * 1024)); fp.close();'
+ $ hg commit -A -d '4 0' -m 'long line'
+ adding long
+
+no mime encoding for email --test:
+ $ hg email --date '1970-1-1 0:4' -f quux -t foo -c bar -r tip -n
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] long line ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: quoted-printable
+ Subject: [PATCH] long line
+ X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ Message-Id: <a2ea8fc83dd8b93cfd86.240@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:04:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
+ long line
+
+ diff -r 909a00e13e9d -r a2ea8fc83dd8 long
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/long Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,4 @@
+ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ +foo
+ +
+ +bar
+
+
+mime encoded mbox (quoted-printable):
+ $ hg email --date '1970-1-1 0:4' -f quux -t foo -c bar -r tip -m mbox
+ this patch series consists of 1 patches.
+
+
+ sending [PATCH] long line ...
+ $ cat mbox
+ From quux ... ... .. ..:..:.. .... (re)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: quoted-printable
+ Subject: [PATCH] long line
+ X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ Message-Id: <a2ea8fc83dd8b93cfd86.240@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:04:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
+ long line
+
+ diff -r 909a00e13e9d -r a2ea8fc83dd8 long
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/long Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,4 @@
+ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ +foo
+ +
+ +bar
+
+
+
+ $ rm mbox
+
+iso-8859-1 patch:
+ $ python -c 'fp = open("isolatin", "wb"); fp.write("h\xF6mma!\n"); fp.close();'
+ $ hg commit -A -d '5 0' -m 'isolatin 8-bit encoding'
+ adding isolatin
+
+fake ascii mbox:
+ $ hg email --date '1970-1-1 0:5' -f quux -t foo -c bar -r tip -m mbox
+ this patch series consists of 1 patches.
+
+
+ sending [PATCH] isolatin 8-bit encoding ...
+ $ cat mbox
+ From quux ... ... .. ..:..:.. .... (re)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 8bit
+ Subject: [PATCH] isolatin 8-bit encoding
+ X-Mercurial-Node: 240fb913fc1b7ff15ddb9f33e73d82bf5277c720
+ Message-Id: <240fb913fc1b7ff15ddb.300@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:05:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 5 0
+ # Node ID 240fb913fc1b7ff15ddb9f33e73d82bf5277c720
+ # Parent a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ isolatin 8-bit encoding
+
+ diff -r a2ea8fc83dd8 -r 240fb913fc1b isolatin
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/isolatin Thu Jan 01 00:00:05 1970 +0000
+ @@ -0,0 +1,1 @@
+ +h\xf6mma! (esc)
+
+
+
+test diffstat for single patch:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -d -y -r 2
+ this patch series consists of 1 patches.
+
+
+ Final summary:
+
+ From: quux
+ To: foo
+ Cc: bar
+ Subject: [PATCH] test
+ c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+ are you sure you want to send (yn)? y
+
+ displaying [PATCH] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH] test
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+
+test diffstat for multiple patches:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -d -y \
+ > -r 0:1
+ this patch series consists of 2 patches.
+
+
+ Write the introductory message for the patch series.
+
+
+ Final summary:
+
+ From: quux
+ To: foo
+ Cc: bar
+ Subject: [PATCH 0 of 2] test
+ a | 1 +
+ b | 1 +
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+ Subject: [PATCH 1 of 2] a
+ a | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+ Subject: [PATCH 2 of 2] b
+ b | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+ are you sure you want to send (yn)? y
+
+ displaying [PATCH 0 of 2] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 2] test
+ Message-Id: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+
+ a | 1 +
+ b | 1 +
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+
+ displaying [PATCH 1 of 2] a ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 1 of 2] a
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.61@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ a | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ displaying [PATCH 2 of 2] b ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 2 of 2] b
+ X-Mercurial-Node: 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ Message-Id: <97d72e5f12c7e84f8506.62@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:02 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ b | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+
+ # HG changeset patch
+ # User test
+ # Date 2 0
+ # Node ID 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ # Parent 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ b
+
+ diff -r 8580ff50825a -r 97d72e5f12c7 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:02 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+
+test inline for single patch:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i -r 2
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] test ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH] test
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Content-Disposition: inline; filename=t2.patch
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+ --===*-- (glob)
+
+
+test inline for single patch (quoted-printable):
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i -r 4
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] test ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH] test
+ X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ Message-Id: <a2ea8fc83dd8b93cfd86.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: quoted-printable
+ Content-Disposition: inline; filename=t2.patch
+
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
+ long line
+
+ diff -r 909a00e13e9d -r a2ea8fc83dd8 long
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/long Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,4 @@
+ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ +foo
+ +
+ +bar
+
+ --===*-- (glob)
+
+test inline for multiple patches:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i \
+ > -r 0:1 -r 4
+ this patch series consists of 3 patches.
+
+
+ Write the introductory message for the patch series.
+
+
+ displaying [PATCH 0 of 3] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 3] test
+ Message-Id: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+
+ displaying [PATCH 1 of 3] a ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH 1 of 3] a
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.61@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Content-Disposition: inline; filename=t2-1.patch
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ --===*-- (glob)
+ displaying [PATCH 2 of 3] b ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH 2 of 3] b
+ X-Mercurial-Node: 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ Message-Id: <97d72e5f12c7e84f8506.62@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:02 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Content-Disposition: inline; filename=t2-2.patch
+
+ # HG changeset patch
+ # User test
+ # Date 2 0
+ # Node ID 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ # Parent 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ b
+
+ diff -r 8580ff50825a -r 97d72e5f12c7 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:02 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+ --===*-- (glob)
+ displaying [PATCH 3 of 3] long line ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH 3 of 3] long line
+ X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ Message-Id: <a2ea8fc83dd8b93cfd86.63@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:03 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: quoted-printable
+ Content-Disposition: inline; filename=t2-3.patch
+
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
+ long line
+
+ diff -r 909a00e13e9d -r a2ea8fc83dd8 long
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/long Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,4 @@
+ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ +foo
+ +
+ +bar
+
+ --===*-- (glob)
+
+test attach for single patch:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -a -r 2
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] test ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH] test
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+
+ Patch subject is complete summary.
+
+
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Content-Disposition: attachment; filename=t2.patch
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+ --===*-- (glob)
+
+test attach for single patch (quoted-printable):
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -a -r 4
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] test ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH] test
+ X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ Message-Id: <a2ea8fc83dd8b93cfd86.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+
+ Patch subject is complete summary.
+
+
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: quoted-printable
+ Content-Disposition: attachment; filename=t2.patch
+
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
+ long line
+
+ diff -r 909a00e13e9d -r a2ea8fc83dd8 long
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/long Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,4 @@
+ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ +foo
+ +
+ +bar
+
+ --===*-- (glob)
+
+test attach and body for single patch:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -a --body -r 2
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] test ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH] test
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Content-Disposition: attachment; filename=t2.patch
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+ --===*-- (glob)
+
+test attach for multiple patches:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -a \
+ > -r 0:1 -r 4
+ this patch series consists of 3 patches.
+
+
+ Write the introductory message for the patch series.
+
+
+ displaying [PATCH 0 of 3] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 3] test
+ Message-Id: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+
+ displaying [PATCH 1 of 3] a ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH 1 of 3] a
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.61@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+
+ Patch subject is complete summary.
+
+
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Content-Disposition: attachment; filename=t2-1.patch
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ --===*-- (glob)
+ displaying [PATCH 2 of 3] b ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH 2 of 3] b
+ X-Mercurial-Node: 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ Message-Id: <97d72e5f12c7e84f8506.62@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:02 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+
+ Patch subject is complete summary.
+
+
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Content-Disposition: attachment; filename=t2-2.patch
+
+ # HG changeset patch
+ # User test
+ # Date 2 0
+ # Node ID 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ # Parent 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ b
+
+ diff -r 8580ff50825a -r 97d72e5f12c7 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:02 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+ --===*-- (glob)
+ displaying [PATCH 3 of 3] long line ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH 3 of 3] long line
+ X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ Message-Id: <a2ea8fc83dd8b93cfd86.63@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:03 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+
+ Patch subject is complete summary.
+
+
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: quoted-printable
+ Content-Disposition: attachment; filename=t2-3.patch
+
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
+ long line
+
+ diff -r 909a00e13e9d -r a2ea8fc83dd8 long
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/long Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,4 @@
+ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ +foo
+ +
+ +bar
+
+ --===*-- (glob)
+
+test intro for single patch:
+ $ hg email --date '1970-1-1 0:1' -n --intro -f quux -t foo -c bar -s test \
+ > -r 2
+ this patch series consists of 1 patches.
+
+
+ Write the introductory message for the patch series.
+
+
+ displaying [PATCH 0 of 1] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 1] test
+ Message-Id: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+
+ displaying [PATCH 1 of 1] c ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 1 of 1] c
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.61@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+
+test --desc without --intro for a single patch:
+ $ echo foo > intro.text
+ $ hg email --date '1970-1-1 0:1' -n --desc intro.text -f quux -t foo -c bar \
+ > -s test -r 2
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH 0 of 1] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 1] test
+ Message-Id: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ foo
+
+ displaying [PATCH 1 of 1] c ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 1 of 1] c
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.61@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+
+test intro for multiple patches:
+ $ hg email --date '1970-1-1 0:1' -n --intro -f quux -t foo -c bar -s test \
+ > -r 0:1
+ this patch series consists of 2 patches.
+
+
+ Write the introductory message for the patch series.
+
+
+ displaying [PATCH 0 of 2] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 2] test
+ Message-Id: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+
+ displaying [PATCH 1 of 2] a ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 1 of 2] a
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.61@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ displaying [PATCH 2 of 2] b ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 2 of 2] b
+ X-Mercurial-Node: 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ Message-Id: <97d72e5f12c7e84f8506.62@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:02 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 2 0
+ # Node ID 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ # Parent 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ b
+
+ diff -r 8580ff50825a -r 97d72e5f12c7 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:02 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+
+test reply-to via config:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -r 2 \
+ > --config patchbomb.reply-to='baz@example.com'
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH] test
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+ Reply-To: baz@example.com
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+
+test reply-to via command line:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -r 2 \
+ > --reply-to baz --reply-to fred
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH] test
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+ Reply-To: baz, fred
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+
+tagging csets:
+ $ hg tag -r0 zero zero.foo
+ $ hg tag -r1 one one.patch
+ $ hg tag -r2 two two.diff
+
+test inline for single named patch:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i -r 2
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] test ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH] test
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Content-Disposition: inline; filename=two.diff
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+ --===*-- (glob)
+
+test inline for multiple named/unnamed patches:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i -r 0:1
+ this patch series consists of 2 patches.
+
+
+ Write the introductory message for the patch series.
+
+
+ displaying [PATCH 0 of 2] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 2] test
+ Message-Id: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+
+ displaying [PATCH 1 of 2] a ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH 1 of 2] a
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.61@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Content-Disposition: inline; filename=t2-1.patch
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ --===*-- (glob)
+ displaying [PATCH 2 of 2] b ...
+ Content-Type: multipart/mixed; boundary="===*" (glob)
+ MIME-Version: 1.0
+ Subject: [PATCH 2 of 2] b
+ X-Mercurial-Node: 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ Message-Id: <97d72e5f12c7e84f8506.62@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:02 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ --===* (glob)
+ Content-Type: text/x-patch; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Content-Disposition: inline; filename=one.patch
+
+ # HG changeset patch
+ # User test
+ # Date 2 0
+ # Node ID 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ # Parent 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ b
+
+ diff -r 8580ff50825a -r 97d72e5f12c7 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:02 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+ --===*-- (glob)
+
+
+test inreplyto:
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar --in-reply-to baz \
+ > -r tip
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH] Added tag two, two.diff for changeset ff2c9fa2018b ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH] Added tag two, two.diff for changeset ff2c9fa2018b
+ X-Mercurial-Node: 7aead2484924c445ad8ce2613df91f52f9e502ed
+ Message-Id: <7aead2484924c445ad8c.60@*> (glob)
+ In-Reply-To: <baz>
+ References: <baz>
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Node ID 7aead2484924c445ad8ce2613df91f52f9e502ed
+ # Parent 045ca29b1ea20e4940411e695e20e521f2f0f98e
+ Added tag two, two.diff for changeset ff2c9fa2018b
+
+ diff -r 045ca29b1ea2 -r 7aead2484924 .hgtags
+ --- a/.hgtags Thu Jan 01 00:00:00 1970 +0000
+ +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
+ @@ -2,3 +2,5 @@
+ 8580ff50825a50c8f716709acdf8de0deddcd6ab zero.foo
+ 97d72e5f12c7e84f85064aa72e5a297142c36ed9 one
+ 97d72e5f12c7e84f85064aa72e5a297142c36ed9 one.patch
+ +ff2c9fa2018b15fa74b33363bda9527323e2a99f two
+ +ff2c9fa2018b15fa74b33363bda9527323e2a99f two.diff
+
+no intro message in non-interactive mode
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar --in-reply-to baz \
+ > -r 0:1
+ this patch series consists of 2 patches.
+
+ (optional) Subject: [PATCH 0 of 2]
+
+ displaying [PATCH 1 of 2] a ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 1 of 2] a
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.60@*> (glob)
+ In-Reply-To: <baz>
+ References: <baz>
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ displaying [PATCH 2 of 2] b ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 2 of 2] b
+ X-Mercurial-Node: 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ Message-Id: <97d72e5f12c7e84f8506.61@*> (glob)
+ In-Reply-To: <8580ff50825a50c8f716.60@*> (glob)
+ References: <8580ff50825a50c8f716.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 2 0
+ # Node ID 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ # Parent 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ b
+
+ diff -r 8580ff50825a -r 97d72e5f12c7 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:02 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+
+
+
+ $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar --in-reply-to baz \
+ > -s test -r 0:1
+ this patch series consists of 2 patches.
+
+
+ Write the introductory message for the patch series.
+
+
+ displaying [PATCH 0 of 2] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 2] test
+ Message-Id: <patchbomb.60@*> (glob)
+ In-Reply-To: <baz>
+ References: <baz>
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+
+ displaying [PATCH 1 of 2] a ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 1 of 2] a
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.61@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ displaying [PATCH 2 of 2] b ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 2 of 2] b
+ X-Mercurial-Node: 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ Message-Id: <97d72e5f12c7e84f8506.62@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:02 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 2 0
+ # Node ID 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ # Parent 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ b
+
+ diff -r 8580ff50825a -r 97d72e5f12c7 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:02 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+
+test single flag for single patch:
+ $ hg email --date '1970-1-1 0:1' -n --flag fooFlag -f quux -t foo -c bar -s test \
+ > -r 2
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH fooFlag] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH fooFlag] test
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+
+test single flag for multiple patches:
+ $ hg email --date '1970-1-1 0:1' -n --flag fooFlag -f quux -t foo -c bar -s test \
+ > -r 0:1
+ this patch series consists of 2 patches.
+
+
+ Write the introductory message for the patch series.
+
+
+ displaying [PATCH 0 of 2 fooFlag] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 2 fooFlag] test
+ Message-Id: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+
+ displaying [PATCH 1 of 2 fooFlag] a ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 1 of 2 fooFlag] a
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.61@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ displaying [PATCH 2 of 2 fooFlag] b ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 2 of 2 fooFlag] b
+ X-Mercurial-Node: 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ Message-Id: <97d72e5f12c7e84f8506.62@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:02 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 2 0
+ # Node ID 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ # Parent 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ b
+
+ diff -r 8580ff50825a -r 97d72e5f12c7 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:02 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+
+test mutiple flags for single patch:
+ $ hg email --date '1970-1-1 0:1' -n --flag fooFlag --flag barFlag -f quux -t foo \
+ > -c bar -s test -r 2
+ this patch series consists of 1 patches.
+
+
+ displaying [PATCH fooFlag barFlag] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH fooFlag barFlag] test
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+
+test multiple flags for multiple patches:
+ $ hg email --date '1970-1-1 0:1' -n --flag fooFlag --flag barFlag -f quux -t foo \
+ > -c bar -s test -r 0:1
+ this patch series consists of 2 patches.
+
+
+ Write the introductory message for the patch series.
+
+
+ displaying [PATCH 0 of 2 fooFlag barFlag] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 2 fooFlag barFlag] test
+ Message-Id: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:00 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+
+ displaying [PATCH 1 of 2 fooFlag barFlag] a ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 1 of 2 fooFlag barFlag] a
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.61@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:01 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ displaying [PATCH 2 of 2 fooFlag barFlag] b ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 2 of 2 fooFlag barFlag] b
+ X-Mercurial-Node: 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ Message-Id: <97d72e5f12c7e84f8506.62@*> (glob)
+ In-Reply-To: <patchbomb.60@*> (glob)
+ References: <patchbomb.60@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Thu, 01 Jan 1970 00:01:02 +0000
+ From: quux
+ To: foo
+ Cc: bar
+
+ # HG changeset patch
+ # User test
+ # Date 2 0
+ # Node ID 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ # Parent 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ b
+
+ diff -r 8580ff50825a -r 97d72e5f12c7 b
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:02 1970 +0000
+ @@ -0,0 +1,1 @@
+ +b
+
+
+test multi-address parsing:
+ $ hg email --date '1980-1-1 0:1' -m tmp.mbox -f quux -t 'spam<spam><eggs>' \
+ > -t toast -c 'foo,bar@example.com' -c '"A, B <>" <a@example.com>' -s test -r 0 \
+ > --config email.bcc='"Quux, A." <quux>'
+ this patch series consists of 1 patches.
+
+
+ sending [PATCH] test ...
+ $ cat < tmp.mbox
+ From quux ... ... .. ..:..:.. .... (re)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH] test
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.315532860@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Tue, 01 Jan 1980 00:01:00 +0000
+ From: quux
+ To: spam <spam>, eggs, toast
+ Cc: foo, bar@example.com, "A, B <>" <a@example.com>
+ Bcc: "Quux, A." <quux>
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+
+
+test multi-byte domain parsing:
+ $ UUML=`python -c 'import sys; sys.stdout.write("\374")'`
+ $ HGENCODING=iso-8859-1
+ $ export HGENCODING
+ $ hg email --date '1980-1-1 0:1' -m tmp.mbox -f quux -t "bar@${UUML}nicode.com" -s test -r 0
+ this patch series consists of 1 patches.
+
+ Cc:
+
+ sending [PATCH] test ...
+
+ $ cat tmp.mbox
+ From quux ... ... .. ..:..:.. .... (re)
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH] test
+ X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ Message-Id: <8580ff50825a50c8f716.315532860@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Tue, 01 Jan 1980 00:01:00 +0000
+ From: quux
+ To: bar@xn--nicode-2ya.com
+
+ # HG changeset patch
+ # User test
+ # Date 1 0
+ # Node ID 8580ff50825a50c8f716709acdf8de0deddcd6ab
+ # Parent 0000000000000000000000000000000000000000
+ a
+
+ diff -r 000000000000 -r 8580ff50825a a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:01 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+
+
+test outgoing:
+ $ hg up 1
+ 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
+
+ $ hg branch test
+ marked working directory as branch test
+ (branches are permanent and global, did you want a bookmark?)
+
+ $ echo d > d
+ $ hg add d
+ $ hg ci -md -d '4 0'
+ $ echo d >> d
+ $ hg ci -mdd -d '5 0'
+ $ hg --config extensions.graphlog= glog --template "{rev}:{node|short} {desc|firstline}\n"
+ @ 10:3b6f1ec9dde9 dd
+ |
+ o 9:2f9fa9b998c5 d
+ |
+ | o 8:7aead2484924 Added tag two, two.diff for changeset ff2c9fa2018b
+ | |
+ | o 7:045ca29b1ea2 Added tag one, one.patch for changeset 97d72e5f12c7
+ | |
+ | o 6:5d5ef15dfe5e Added tag zero, zero.foo for changeset 8580ff50825a
+ | |
+ | o 5:240fb913fc1b isolatin 8-bit encoding
+ | |
+ | o 4:a2ea8fc83dd8 long line
+ | |
+ | o 3:909a00e13e9d utf-8 content
+ | |
+ | o 2:ff2c9fa2018b c
+ |/
+ o 1:97d72e5f12c7 b
+ |
+ o 0:8580ff50825a a
+
+ $ hg phase --force --secret -r 10
+ $ hg email --date '1980-1-1 0:1' -n -t foo -s test -o ../t -r 'rev(10) or rev(6)'
+ comparing with ../t
+ From [test]: test
+ this patch series consists of 6 patches.
+
+
+ Write the introductory message for the patch series.
+
+ Cc:
+
+ displaying [PATCH 0 of 6] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 0 of 6] test
+ Message-Id: <patchbomb.315532860@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Tue, 01 Jan 1980 00:01:00 +0000
+ From: test
+ To: foo
+
+
+ displaying [PATCH 1 of 6] c ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 1 of 6] c
+ X-Mercurial-Node: ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ Message-Id: <ff2c9fa2018b15fa74b3.315532861@*> (glob)
+ In-Reply-To: <patchbomb.315532860@*> (glob)
+ References: <patchbomb.315532860@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Tue, 01 Jan 1980 00:01:01 +0000
+ From: test
+ To: foo
+
+ # HG changeset patch
+ # User test
+ # Date 3 0
+ # Node ID ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ c
+
+ diff -r 97d72e5f12c7 -r ff2c9fa2018b c
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/c Thu Jan 01 00:00:03 1970 +0000
+ @@ -0,0 +1,1 @@
+ +c
+
+ displaying [PATCH 2 of 6] utf-8 content ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 8bit
+ Subject: [PATCH 2 of 6] utf-8 content
+ X-Mercurial-Node: 909a00e13e9d78b575aeee23dddbada46d5a143f
+ Message-Id: <909a00e13e9d78b575ae.315532862@*> (glob)
+ In-Reply-To: <patchbomb.315532860@*> (glob)
+ References: <patchbomb.315532860@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Tue, 01 Jan 1980 00:01:02 +0000
+ From: test
+ To: foo
+
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Node ID 909a00e13e9d78b575aeee23dddbada46d5a143f
+ # Parent ff2c9fa2018b15fa74b33363bda9527323e2a99f
+ utf-8 content
+
+ diff -r ff2c9fa2018b -r 909a00e13e9d description
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/description Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,3 @@
+ +a multiline
+ +
+ +description
+ diff -r ff2c9fa2018b -r 909a00e13e9d utf
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/utf Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,1 @@
+ +h\xc3\xb6mma! (esc)
+
+ displaying [PATCH 3 of 6] long line ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: quoted-printable
+ Subject: [PATCH 3 of 6] long line
+ X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ Message-Id: <a2ea8fc83dd8b93cfd86.315532863@*> (glob)
+ In-Reply-To: <patchbomb.315532860@*> (glob)
+ References: <patchbomb.315532860@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Tue, 01 Jan 1980 00:01:03 +0000
+ From: test
+ To: foo
+
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
+ long line
+
+ diff -r 909a00e13e9d -r a2ea8fc83dd8 long
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/long Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,4 @@
+ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ +foo
+ +
+ +bar
+
+ displaying [PATCH 4 of 6] isolatin 8-bit encoding ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 8bit
+ Subject: [PATCH 4 of 6] isolatin 8-bit encoding
+ X-Mercurial-Node: 240fb913fc1b7ff15ddb9f33e73d82bf5277c720
+ Message-Id: <240fb913fc1b7ff15ddb.315532864@*> (glob)
+ In-Reply-To: <patchbomb.315532860@*> (glob)
+ References: <patchbomb.315532860@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Tue, 01 Jan 1980 00:01:04 +0000
+ From: test
+ To: foo
+
+ # HG changeset patch
+ # User test
+ # Date 5 0
+ # Node ID 240fb913fc1b7ff15ddb9f33e73d82bf5277c720
+ # Parent a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
+ isolatin 8-bit encoding
+
+ diff -r a2ea8fc83dd8 -r 240fb913fc1b isolatin
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/isolatin Thu Jan 01 00:00:05 1970 +0000
+ @@ -0,0 +1,1 @@
+ +h\xf6mma! (esc)
+
+ displaying [PATCH 5 of 6] Added tag zero, zero.foo for changeset 8580ff50825a ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 5 of 6] Added tag zero, zero.foo for changeset 8580ff50825a
+ X-Mercurial-Node: 5d5ef15dfe5e7bd3a4ee154b5fff76c7945ec433
+ Message-Id: <5d5ef15dfe5e7bd3a4ee.315532865@*> (glob)
+ In-Reply-To: <patchbomb.315532860@*> (glob)
+ References: <patchbomb.315532860@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Tue, 01 Jan 1980 00:01:05 +0000
+ From: test
+ To: foo
+
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Node ID 5d5ef15dfe5e7bd3a4ee154b5fff76c7945ec433
+ # Parent 240fb913fc1b7ff15ddb9f33e73d82bf5277c720
+ Added tag zero, zero.foo for changeset 8580ff50825a
+
+ diff -r 240fb913fc1b -r 5d5ef15dfe5e .hgtags
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,2 @@
+ +8580ff50825a50c8f716709acdf8de0deddcd6ab zero
+ +8580ff50825a50c8f716709acdf8de0deddcd6ab zero.foo
+
+ displaying [PATCH 6 of 6] d ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH 6 of 6] d
+ X-Mercurial-Node: 2f9fa9b998c5fe3ac2bd9a2b14bfcbeecbc7c268
+ Message-Id: <2f9fa9b998c5fe3ac2bd.315532866@*> (glob)
+ In-Reply-To: <patchbomb.315532860@*> (glob)
+ References: <patchbomb.315532860@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Tue, 01 Jan 1980 00:01:06 +0000
+ From: test
+ To: foo
+
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Branch test
+ # Node ID 2f9fa9b998c5fe3ac2bd9a2b14bfcbeecbc7c268
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ d
+
+ diff -r 97d72e5f12c7 -r 2f9fa9b998c5 d
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/d Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,1 @@
+ +d
+
+
+dest#branch URIs:
+ $ hg email --date '1980-1-1 0:1' -n -t foo -s test -o ../t#test
+ comparing with ../t
+ From [test]: test
+ this patch series consists of 1 patches.
+
+ Cc:
+
+ displaying [PATCH] test ...
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: [PATCH] test
+ X-Mercurial-Node: 2f9fa9b998c5fe3ac2bd9a2b14bfcbeecbc7c268
+ Message-Id: <2f9fa9b998c5fe3ac2bd.315532860@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
+ Date: Tue, 01 Jan 1980 00:01:00 +0000
+ From: test
+ To: foo
+
+ # HG changeset patch
+ # User test
+ # Date 4 0
+ # Branch test
+ # Node ID 2f9fa9b998c5fe3ac2bd9a2b14bfcbeecbc7c268
+ # Parent 97d72e5f12c7e84f85064aa72e5a297142c36ed9
+ d
+
+ diff -r 97d72e5f12c7 -r 2f9fa9b998c5 d
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/d Thu Jan 01 00:00:04 1970 +0000
+ @@ -0,0 +1,1 @@
+ +d
+
+
+ $ cd ..
diff --git a/tests/test-paths.t b/tests/test-paths.t
new file mode 100644
index 0000000..99a45aa
--- /dev/null
+++ b/tests/test-paths.t
@@ -0,0 +1,65 @@
+ $ hg init a
+ $ hg clone a b
+ updating to branch default
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd a
+ $ echo '[paths]' >> .hg/hgrc
+ $ echo 'dupe = ../b' >> .hg/hgrc
+ $ echo 'expand = $SOMETHING/bar' >> .hg/hgrc
+ $ hg in dupe
+ comparing with $TESTTMP/b (glob)
+ no changes found
+ [1]
+ $ cd ..
+ $ hg -R a in dupe
+ comparing with $TESTTMP/b (glob)
+ no changes found
+ [1]
+ $ cd a
+ $ hg paths
+ dupe = $TESTTMP/b (glob)
+ expand = $TESTTMP/a/$SOMETHING/bar (glob)
+ $ SOMETHING=foo hg paths
+ dupe = $TESTTMP/b (glob)
+ expand = $TESTTMP/a/foo/bar (glob)
+#if msys
+ $ SOMETHING=//foo hg paths
+ dupe = $TESTTMP/b (glob)
+ expand = /foo/bar
+#else
+ $ SOMETHING=/foo hg paths
+ dupe = $TESTTMP/b (glob)
+ expand = /foo/bar
+#endif
+ $ hg paths -q
+ dupe
+ expand
+ $ hg paths dupe
+ $TESTTMP/b (glob)
+ $ hg paths -q dupe
+ $ hg paths unknown
+ not found!
+ [1]
+ $ hg paths -q unknown
+ [1]
+ $ cd ..
+
+'file:' disables [paths] entries for clone destination
+
+ $ cat >> $HGRCPATH <<EOF
+ > [paths]
+ > gpath1 = http://hg.example.com
+ > EOF
+
+ $ hg clone a gpath1
+ abort: cannot create new http repository
+ [255]
+
+ $ hg clone a file:gpath1
+ updating to branch default
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd gpath1
+ $ hg -q id
+ 000000000000
+
+ $ cd ..
diff --git a/tests/test-pending.t b/tests/test-pending.t
new file mode 100644
index 0000000..d449d29
--- /dev/null
+++ b/tests/test-pending.t
@@ -0,0 +1,115 @@
+Verify that pending changesets are seen by pretxn* hooks but not by other
+processes that access the destination repo while the hooks are running.
+
+The hooks (python and external) both reject changesets after some think time,
+during which another process runs pull. Each hook creates a file ('notify') to
+indicate to the controlling process that it is running; the process removes the
+file to indicate the hook can terminate.
+
+init env vars
+
+ $ d=`pwd`
+ $ maxwait=20
+
+utility to run the test - start a push in the background and run pull
+
+ $ dotest() {
+ > rm -f notify
+ > printf 'push '; hg -R child-push tip --template '{node}\n'
+ > hg -R child-push -q push > push.out 2>&1 &
+ >
+ > # wait for hook to create the notify file
+ > i=$maxwait
+ > while [ ! -f notify -a $i != 0 ]; do
+ > sleep 1
+ > i=`expr $i - 1`
+ > done
+ >
+ > # run pull
+ > hg -R child-pull -q pull
+ > rc=$?
+ >
+ > # tell hook to finish; notify should exist.
+ > rm notify
+ > wait
+ >
+ > cat push.out
+ > printf 'pull '; hg -R child-pull tip --template '{node}\n'
+ > return $rc
+ > }
+
+python hook
+
+ $ cat <<EOF > reject.py
+ > import os, time
+ > from mercurial import ui, localrepo
+ > def rejecthook(ui, repo, hooktype, node, **opts):
+ > ui.write('hook %s\\n' % repo['tip'].hex())
+ > # create the notify file so caller knows we're running
+ > fpath = os.path.join('$d', 'notify')
+ > f = open(fpath, 'w')
+ > f.close()
+ > # wait for ack - caller should delete the notify file
+ > i = $maxwait
+ > while os.path.exists(fpath) and i > 0:
+ > time.sleep(1)
+ > i -= 1
+ > return True # reject the changesets
+ > EOF
+
+external hook
+
+ $ cat <<EOF > reject.sh
+ > printf 'hook '; hg tip --template '{node}\\n'
+ > # create the notify file so caller knows we're running
+ > fpath=$d/notify
+ > touch \$fpath
+ > # wait for ack - caller should delete the notify file
+ > i=$maxwait
+ > while [ -f \$fpath -a \$i != 0 ]; do
+ > sleep 1
+ > i=\`expr \$i - 1\`
+ > done
+ > exit 1 # reject the changesets
+ > EOF
+
+create repos
+
+ $ hg init parent
+ $ hg clone -q parent child-push
+ $ hg clone -q parent child-pull
+ $ echo a > child-push/a
+ $ hg -R child-push add child-push/a
+ $ hg -R child-push commit -m a -d '1000000 0'
+
+test python hook
+
+ $ cat <<EOF > parent/.hg/hgrc
+ > [extensions]
+ > reject = $d/reject.py
+ > [hooks]
+ > pretxnchangegroup = python:reject.rejecthook
+ > EOF
+
+ $ dotest
+ push 29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
+ hook 29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
+ transaction abort!
+ rollback completed
+ abort: pretxnchangegroup hook failed
+ pull 0000000000000000000000000000000000000000
+
+test external hook
+
+ $ cat <<EOF > parent/.hg/hgrc
+ > [hooks]
+ > pretxnchangegroup = sh $d/reject.sh
+ > EOF
+
+ $ dotest
+ push 29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
+ hook 29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
+ transaction abort!
+ rollback completed
+ abort: pretxnchangegroup hook exited with status 1
+ pull 0000000000000000000000000000000000000000
diff --git a/tests/test-permissions.t b/tests/test-permissions.t
new file mode 100644
index 0000000..88f0637
--- /dev/null
+++ b/tests/test-permissions.t
@@ -0,0 +1,72 @@
+ $ "$TESTDIR/hghave" unix-permissions || exit 80
+
+ $ hg init t
+ $ cd t
+
+ $ echo foo > a
+ $ hg add a
+
+ $ hg commit -m "1"
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+
+ $ chmod -r .hg/store/data/a.i
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ abort: Permission denied: $TESTTMP/t/.hg/store/data/a.i
+ [255]
+
+ $ chmod +r .hg/store/data/a.i
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+
+ $ chmod -w .hg/store/data/a.i
+
+ $ echo barber > a
+ $ hg commit -m "2"
+ trouble committing a!
+ abort: Permission denied: $TESTTMP/t/.hg/store/data/a.i
+ [255]
+
+ $ chmod -w .
+
+ $ hg diff --nodates
+ diff -r 2a18120dc1c9 a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,1 @@
+ -foo
+ +barber
+
+ $ chmod +w .
+
+ $ chmod +w .hg/store/data/a.i
+ $ mkdir dir
+ $ touch dir/a
+ $ hg status
+ M a
+ ? dir/a
+ $ chmod -rx dir
+ $ hg status
+ dir: Permission denied
+ M a
+
+Reenable perm to allow deletion:
+
+ $ chmod +rx dir
+
+ $ cd ..
diff --git a/tests/test-phases-exchange.t b/tests/test-phases-exchange.t
new file mode 100644
index 0000000..a8a4483
--- /dev/null
+++ b/tests/test-phases-exchange.t
@@ -0,0 +1,1065 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > EOF
+ $ hgph() { hg log -G --template "{rev} {phase} {desc} - {node|short}\n" $*; }
+
+ $ mkcommit() {
+ > echo "$1" > "$1"
+ > hg add "$1"
+ > message="$1"
+ > shift
+ > hg ci -m "$message" $*
+ > }
+
+ $ hg init alpha
+ $ cd alpha
+ $ mkcommit a-A
+ $ mkcommit a-B
+ $ mkcommit a-C
+ $ mkcommit a-D
+ $ hgph
+ @ 3 draft a-D - b555f63b6063
+ |
+ o 2 draft a-C - 54acac6f23ab
+ |
+ o 1 draft a-B - 548a3d25dbf0
+ |
+ o 0 draft a-A - 054250a37db4
+
+
+ $ hg init ../beta
+ $ hg push -r 1 ../beta
+ pushing to ../beta
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ $ hgph
+ @ 3 draft a-D - b555f63b6063
+ |
+ o 2 draft a-C - 54acac6f23ab
+ |
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+ $ cd ../beta
+ $ hgph
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ hg up -q
+ $ mkcommit b-A
+ $ hgph
+ @ 2 draft b-A - f54f1bb90ff3
+ |
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ hg pull ../alpha
+ pulling from ../alpha
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hgph
+ o 4 public a-D - b555f63b6063
+ |
+ o 3 public a-C - 54acac6f23ab
+ |
+ | @ 2 draft b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+pull did not updated ../alpha state.
+push from alpha to beta should update phase even if nothing is transfered
+
+ $ cd ../alpha
+ $ hgph # not updated by remote pull
+ @ 3 draft a-D - b555f63b6063
+ |
+ o 2 draft a-C - 54acac6f23ab
+ |
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ hg push ../beta
+ pushing to ../beta
+ searching for changes
+ no changes found
+ [1]
+ $ hgph
+ @ 3 public a-D - b555f63b6063
+ |
+ o 2 public a-C - 54acac6f23ab
+ |
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+update must update phase of common changeset too
+
+ $ hg pull ../beta # getting b-A
+ pulling from ../beta
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ $ cd ../beta
+ $ hgph # not updated by remote pull
+ o 4 public a-D - b555f63b6063
+ |
+ o 3 public a-C - 54acac6f23ab
+ |
+ | @ 2 draft b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ hg pull ../alpha
+ pulling from ../alpha
+ searching for changes
+ no changes found
+ $ hgph
+ o 4 public a-D - b555f63b6063
+ |
+ o 3 public a-C - 54acac6f23ab
+ |
+ | @ 2 public b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+Publish configuration option
+----------------------------
+
+Pull
+````
+
+changegroup are added without phase movement
+
+ $ hg bundle -a ../base.bundle
+ 5 changesets found
+ $ cd ..
+ $ hg init mu
+ $ cd mu
+ $ cat > .hg/hgrc << EOF
+ > [phases]
+ > publish=0
+ > EOF
+ $ hg unbundle ../base.bundle
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 5 changes to 5 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hgph
+ o 4 draft a-D - b555f63b6063
+ |
+ o 3 draft a-C - 54acac6f23ab
+ |
+ | o 2 draft b-A - f54f1bb90ff3
+ |/
+ o 1 draft a-B - 548a3d25dbf0
+ |
+ o 0 draft a-A - 054250a37db4
+
+ $ cd ..
+
+Pulling from publish=False to publish=False does not move boundary.
+
+ $ hg init nu
+ $ cd nu
+ $ cat > .hg/hgrc << EOF
+ > [phases]
+ > publish=0
+ > EOF
+ $ hg pull ../mu -r 54acac6f23ab
+ pulling from ../mu
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 3 files
+ (run 'hg update' to get a working copy)
+ $ hgph
+ o 2 draft a-C - 54acac6f23ab
+ |
+ o 1 draft a-B - 548a3d25dbf0
+ |
+ o 0 draft a-A - 054250a37db4
+
+
+Even for common
+
+ $ hg pull ../mu -r f54f1bb90ff3
+ pulling from ../mu
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hgph
+ o 3 draft b-A - f54f1bb90ff3
+ |
+ | o 2 draft a-C - 54acac6f23ab
+ |/
+ o 1 draft a-B - 548a3d25dbf0
+ |
+ o 0 draft a-A - 054250a37db4
+
+
+
+Pulling from Publish=True to Publish=False move boundary in common set.
+we are in nu
+
+ $ hg pull ../alpha -r b555f63b6063
+ pulling from ../alpha
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hgph # f54f1bb90ff3 stay draft, not ancestor of -r
+ o 4 public a-D - b555f63b6063
+ |
+ | o 3 draft b-A - f54f1bb90ff3
+ | |
+ o | 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+pulling from Publish=False to publish=False with some public
+
+ $ hg up -q f54f1bb90ff3
+ $ mkcommit n-A
+ $ mkcommit n-B
+ $ hgph
+ @ 6 draft n-B - 145e75495359
+ |
+ o 5 draft n-A - d6bcb4f74035
+ |
+ | o 4 public a-D - b555f63b6063
+ | |
+ o | 3 draft b-A - f54f1bb90ff3
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ cd ../mu
+ $ hg pull ../nu
+ pulling from ../nu
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hgph
+ o 6 draft n-B - 145e75495359
+ |
+ o 5 draft n-A - d6bcb4f74035
+ |
+ | o 4 public a-D - b555f63b6063
+ | |
+ | o 3 public a-C - 54acac6f23ab
+ | |
+ o | 2 draft b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ cd ..
+
+pulling into publish=True
+
+ $ cd alpha
+ $ hgph
+ o 4 public b-A - f54f1bb90ff3
+ |
+ | @ 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ hg pull ../mu
+ pulling from ../mu
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hgph
+ o 6 draft n-B - 145e75495359
+ |
+ o 5 draft n-A - d6bcb4f74035
+ |
+ o 4 public b-A - f54f1bb90ff3
+ |
+ | @ 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ cd ..
+
+pulling back into original repo
+
+ $ cd nu
+ $ hg pull ../alpha
+ pulling from ../alpha
+ searching for changes
+ no changes found
+ $ hgph
+ @ 6 public n-B - 145e75495359
+ |
+ o 5 public n-A - d6bcb4f74035
+ |
+ | o 4 public a-D - b555f63b6063
+ | |
+ o | 3 public b-A - f54f1bb90ff3
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+Push
+````
+
+(inserted)
+
+Test that phase are pushed even when they are nothing to pus
+(this might be tested later bu are very convenient to not alter too much test)
+
+Push back to alpha
+
+ $ hg push ../alpha # from nu
+ pushing to ../alpha
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+ $ cd alpha
+ $ hgph
+ o 6 public n-B - 145e75495359
+ |
+ o 5 public n-A - d6bcb4f74035
+ |
+ o 4 public b-A - f54f1bb90ff3
+ |
+ | @ 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+(end insertion)
+
+
+initial setup
+
+ $ hg glog # of alpha
+ o changeset: 6:145e75495359
+ | tag: tip
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: n-B
+ |
+ o changeset: 5:d6bcb4f74035
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: n-A
+ |
+ o changeset: 4:f54f1bb90ff3
+ | parent: 1:548a3d25dbf0
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: b-A
+ |
+ | @ changeset: 3:b555f63b6063
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: a-D
+ | |
+ | o changeset: 2:54acac6f23ab
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: a-C
+ |
+ o changeset: 1:548a3d25dbf0
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: a-B
+ |
+ o changeset: 0:054250a37db4
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a-A
+
+ $ mkcommit a-E
+ $ mkcommit a-F
+ $ mkcommit a-G
+ $ hg up d6bcb4f74035 -q
+ $ mkcommit a-H
+ created new head
+ $ hgph
+ @ 10 draft a-H - 967b449fbc94
+ |
+ | o 9 draft a-G - 3e27b6f1eee1
+ | |
+ | o 8 draft a-F - b740e3e5c05d
+ | |
+ | o 7 draft a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ o | 4 public b-A - f54f1bb90ff3
+ | |
+ | o 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+Pulling from bundle does not alter phases of changeset not present in the bundle
+
+ $ hg bundle --base 1 -r 6 -r 3 ../partial-bundle.hg
+ 5 changesets found
+ $ hg pull ../partial-bundle.hg
+ pulling from ../partial-bundle.hg
+ searching for changes
+ no changes found
+ $ hgph
+ @ 10 draft a-H - 967b449fbc94
+ |
+ | o 9 draft a-G - 3e27b6f1eee1
+ | |
+ | o 8 draft a-F - b740e3e5c05d
+ | |
+ | o 7 draft a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ o | 4 public b-A - f54f1bb90ff3
+ | |
+ | o 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+Pushing to Publish=False (unknown changeset)
+
+ $ hg push ../mu -r b740e3e5c05d # a-F
+ pushing to ../mu
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ $ hgph
+ @ 10 draft a-H - 967b449fbc94
+ |
+ | o 9 draft a-G - 3e27b6f1eee1
+ | |
+ | o 8 draft a-F - b740e3e5c05d
+ | |
+ | o 7 draft a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ o | 4 public b-A - f54f1bb90ff3
+ | |
+ | o 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+ $ cd ../mu
+ $ hgph # again f54f1bb90ff3, d6bcb4f74035 and 145e75495359 stay draft,
+ > # not ancestor of -r
+ o 8 draft a-F - b740e3e5c05d
+ |
+ o 7 draft a-E - e9f537e46dea
+ |
+ | o 6 draft n-B - 145e75495359
+ | |
+ | o 5 draft n-A - d6bcb4f74035
+ | |
+ o | 4 public a-D - b555f63b6063
+ | |
+ o | 3 public a-C - 54acac6f23ab
+ | |
+ | o 2 draft b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+Pushing to Publish=True (unknown changeset)
+
+ $ hg push ../beta -r b740e3e5c05d
+ pushing to ../beta
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ $ hgph # again f54f1bb90ff3, d6bcb4f74035 and 145e75495359 stay draft,
+ > # not ancestor of -r
+ o 8 public a-F - b740e3e5c05d
+ |
+ o 7 public a-E - e9f537e46dea
+ |
+ | o 6 draft n-B - 145e75495359
+ | |
+ | o 5 draft n-A - d6bcb4f74035
+ | |
+ o | 4 public a-D - b555f63b6063
+ | |
+ o | 3 public a-C - 54acac6f23ab
+ | |
+ | o 2 draft b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+Pushing to Publish=True (common changeset)
+
+ $ cd ../beta
+ $ hg push ../alpha
+ pushing to ../alpha
+ searching for changes
+ no changes found
+ [1]
+ $ hgph
+ o 6 public a-F - b740e3e5c05d
+ |
+ o 5 public a-E - e9f537e46dea
+ |
+ o 4 public a-D - b555f63b6063
+ |
+ o 3 public a-C - 54acac6f23ab
+ |
+ | @ 2 public b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ cd ../alpha
+ $ hgph
+ @ 10 draft a-H - 967b449fbc94
+ |
+ | o 9 draft a-G - 3e27b6f1eee1
+ | |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ o | 4 public b-A - f54f1bb90ff3
+ | |
+ | o 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+Pushing to Publish=False (common changeset that change phase + unknown one)
+
+ $ hg push ../mu -r 967b449fbc94 -f
+ pushing to ../mu
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ $ hgph
+ @ 10 draft a-H - 967b449fbc94
+ |
+ | o 9 draft a-G - 3e27b6f1eee1
+ | |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ o | 4 public b-A - f54f1bb90ff3
+ | |
+ | o 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ cd ../mu
+ $ hgph # d6bcb4f74035 should have changed phase
+ > # 145e75495359 is still draft. not ancestor of -r
+ o 9 draft a-H - 967b449fbc94
+ |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 draft n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ | o 4 public a-D - b555f63b6063
+ | |
+ | o 3 public a-C - 54acac6f23ab
+ | |
+ o | 2 public b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+
+Pushing to Publish=True (common changeset from publish=False)
+
+(in mu)
+ $ hg push ../alpha
+ pushing to ../alpha
+ searching for changes
+ no changes found
+ [1]
+ $ hgph
+ o 9 public a-H - 967b449fbc94
+ |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ | o 4 public a-D - b555f63b6063
+ | |
+ | o 3 public a-C - 54acac6f23ab
+ | |
+ o | 2 public b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ hgph -R ../alpha # a-H should have been synced to 0
+ @ 10 public a-H - 967b449fbc94
+ |
+ | o 9 draft a-G - 3e27b6f1eee1
+ | |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ o | 4 public b-A - f54f1bb90ff3
+ | |
+ | o 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+
+Discovery locally secret changeset on a remote repository:
+
+- should make it non-secret
+
+ $ cd ../alpha
+ $ mkcommit A-secret --config phases.new-commit=2
+ $ hgph
+ @ 11 secret A-secret - 435b5d83910c
+ |
+ o 10 public a-H - 967b449fbc94
+ |
+ | o 9 draft a-G - 3e27b6f1eee1
+ | |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ o | 4 public b-A - f54f1bb90ff3
+ | |
+ | o 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ hg bundle --base 'parents(.)' -r . ../secret-bundle.hg
+ 1 changesets found
+ $ hg -R ../mu unbundle ../secret-bundle.hg
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hgph -R ../mu
+ o 10 draft A-secret - 435b5d83910c
+ |
+ o 9 public a-H - 967b449fbc94
+ |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ | o 4 public a-D - b555f63b6063
+ | |
+ | o 3 public a-C - 54acac6f23ab
+ | |
+ o | 2 public b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+ $ hg pull ../mu
+ pulling from ../mu
+ searching for changes
+ no changes found
+ $ hgph
+ @ 11 draft A-secret - 435b5d83910c
+ |
+ o 10 public a-H - 967b449fbc94
+ |
+ | o 9 draft a-G - 3e27b6f1eee1
+ | |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ o | 4 public b-A - f54f1bb90ff3
+ | |
+ | o 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+pushing a locally public and draft changesets remotly secret should make them
+appear on the remote side.
+
+
+ $ hg -R ../mu phase --secret --force 967b449fbc94
+ $ hg push -r 435b5d83910c ../mu
+ pushing to ../mu
+ searching for changes
+ abort: push creates new remote head 435b5d83910c!
+ (did you forget to merge? use push -f to force)
+ [255]
+ $ hg push -fr 435b5d83910c ../mu # because the push will create new visible head
+ pushing to ../mu
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 0 changesets with 0 changes to 2 files
+ $ hgph -R ../mu
+ o 10 draft A-secret - 435b5d83910c
+ |
+ o 9 public a-H - 967b449fbc94
+ |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ | o 4 public a-D - b555f63b6063
+ | |
+ | o 3 public a-C - 54acac6f23ab
+ | |
+ o | 2 public b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+pull new changeset with common draft locally
+
+ $ hg up -q 967b449fbc94 # create a new root for draft
+ $ mkcommit 'alpha-more'
+ created new head
+ $ hg push -fr . ../mu
+ pushing to ../mu
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ $ cd ../mu
+ $ hg phase --secret --force 1c5cfd894796
+ $ hg up -q 435b5d83910c
+ $ mkcommit 'mu-more'
+ $ cd ../alpha
+ $ hg pull ../mu
+ pulling from ../mu
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hgph
+ o 13 draft mu-more - 5237fb433fc8
+ |
+ | @ 12 draft alpha-more - 1c5cfd894796
+ | |
+ o | 11 draft A-secret - 435b5d83910c
+ |/
+ o 10 public a-H - 967b449fbc94
+ |
+ | o 9 draft a-G - 3e27b6f1eee1
+ | |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ o | 4 public b-A - f54f1bb90ff3
+ | |
+ | o 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+Test that test are properly ignored on remote event when existing locally
+
+ $ cd ..
+ $ hg clone -qU -r b555f63b6063 -r f54f1bb90ff3 beta gamma
+
+# pathological case are
+#
+# * secret remotely
+# * known locally
+# * repo have uncommon changeset
+
+ $ hg -R beta phase --secret --force f54f1bb90ff3
+ $ hg -R gamma phase --draft --force f54f1bb90ff3
+
+ $ cd gamma
+ $ hg pull ../beta
+ pulling from ../beta
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hg phase f54f1bb90ff3
+ 2: draft
+
+same over the wire
+
+ $ cd ../beta
+ $ hg serve -p $HGPORT -d --pid-file=../beta.pid -E ../beta-error.log
+ $ cat ../beta.pid >> $DAEMON_PIDS
+ $ cd ../gamma
+
+ $ hg pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ hg phase f54f1bb90ff3
+ 2: draft
+
+check that secret local on both side are not synced to public
+
+ $ hg push -r b555f63b6063 http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg phase f54f1bb90ff3
+ 2: draft
+
+put the changeset in the draft state again
+(first test after this one expect to be able to copy)
+
+ $ cd ..
+
+
+Test Clone behavior
+
+A. Clone without secret changeset
+
+1. cloning non-publishing repository
+(Phase should be preserved)
+
+# make sure there is no secret so we can use a copy clone
+
+ $ hg -R mu phase --draft 'secret()'
+
+ $ hg clone -U mu Tau
+ $ hgph -R Tau
+ o 12 draft mu-more - 5237fb433fc8
+ |
+ | o 11 draft alpha-more - 1c5cfd894796
+ | |
+ o | 10 draft A-secret - 435b5d83910c
+ |/
+ o 9 public a-H - 967b449fbc94
+ |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ | o 4 public a-D - b555f63b6063
+ | |
+ | o 3 public a-C - 54acac6f23ab
+ | |
+ o | 2 public b-A - f54f1bb90ff3
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
+2. cloning publishing repository
+
+(everything should be public)
+
+ $ hg clone -U alpha Upsilon
+ $ hgph -R Upsilon
+ o 13 public mu-more - 5237fb433fc8
+ |
+ | o 12 public alpha-more - 1c5cfd894796
+ | |
+ o | 11 public A-secret - 435b5d83910c
+ |/
+ o 10 public a-H - 967b449fbc94
+ |
+ | o 9 public a-G - 3e27b6f1eee1
+ | |
+ | o 8 public a-F - b740e3e5c05d
+ | |
+ | o 7 public a-E - e9f537e46dea
+ | |
+ +---o 6 public n-B - 145e75495359
+ | |
+ o | 5 public n-A - d6bcb4f74035
+ | |
+ o | 4 public b-A - f54f1bb90ff3
+ | |
+ | o 3 public a-D - b555f63b6063
+ | |
+ | o 2 public a-C - 54acac6f23ab
+ |/
+ o 1 public a-B - 548a3d25dbf0
+ |
+ o 0 public a-A - 054250a37db4
+
+
diff --git a/tests/test-phases.t b/tests/test-phases.t
new file mode 100644
index 0000000..28e7dab
--- /dev/null
+++ b/tests/test-phases.t
@@ -0,0 +1,479 @@
+ $ hglog() { hg log --template "{rev} {phaseidx} {desc}\n" $*; }
+ $ mkcommit() {
+ > echo "$1" > "$1"
+ > hg add "$1"
+ > message="$1"
+ > shift
+ > hg ci -m "$message" $*
+ > }
+
+ $ hg init initialrepo
+ $ cd initialrepo
+
+Cannot change null revision phase
+
+ $ hg phase --force --secret null
+ abort: cannot change null revision phase
+ [255]
+ $ hg phase null
+ -1: public
+
+ $ mkcommit A
+
+New commit are draft by default
+
+ $ hglog
+ 0 1 A
+
+Following commit are draft too
+
+ $ mkcommit B
+
+ $ hglog
+ 1 1 B
+ 0 1 A
+
+Draft commit are properly created over public one:
+
+ $ hg phase --public .
+ $ hglog
+ 1 0 B
+ 0 0 A
+
+ $ mkcommit C
+ $ mkcommit D
+
+ $ hglog
+ 3 1 D
+ 2 1 C
+ 1 0 B
+ 0 0 A
+
+Test creating changeset as secret
+
+ $ mkcommit E --config phases.new-commit='secret'
+ $ hglog
+ 4 2 E
+ 3 1 D
+ 2 1 C
+ 1 0 B
+ 0 0 A
+
+Test the secret property is inherited
+
+ $ mkcommit H
+ $ hglog
+ 5 2 H
+ 4 2 E
+ 3 1 D
+ 2 1 C
+ 1 0 B
+ 0 0 A
+
+Even on merge
+
+ $ hg up -q 1
+ $ mkcommit "B'"
+ created new head
+ $ hglog
+ 6 1 B'
+ 5 2 H
+ 4 2 E
+ 3 1 D
+ 2 1 C
+ 1 0 B
+ 0 0 A
+ $ hg merge 4 # E
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m "merge B' and E"
+ $ hglog
+ 7 2 merge B' and E
+ 6 1 B'
+ 5 2 H
+ 4 2 E
+ 3 1 D
+ 2 1 C
+ 1 0 B
+ 0 0 A
+
+Test secret changeset are not pushed
+
+ $ hg init ../push-dest
+ $ cat > ../push-dest/.hg/hgrc << EOF
+ > [phases]
+ > publish=False
+ > EOF
+ $ hg outgoing ../push-dest --template='{rev} {phase} {desc|firstline}\n'
+ comparing with ../push-dest
+ searching for changes
+ 0 public A
+ 1 public B
+ 2 draft C
+ 3 draft D
+ 6 draft B'
+ $ hg outgoing -r 'branch(default)' ../push-dest --template='{rev} {phase} {desc|firstline}\n'
+ comparing with ../push-dest
+ searching for changes
+ 0 public A
+ 1 public B
+ 2 draft C
+ 3 draft D
+ 6 draft B'
+
+ $ hg push ../push-dest -f # force because we push multiple heads
+ pushing to ../push-dest
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 5 changes to 5 files (+1 heads)
+ $ hglog
+ 7 2 merge B' and E
+ 6 1 B'
+ 5 2 H
+ 4 2 E
+ 3 1 D
+ 2 1 C
+ 1 0 B
+ 0 0 A
+ $ cd ../push-dest
+ $ hglog
+ 4 1 B'
+ 3 1 D
+ 2 1 C
+ 1 0 B
+ 0 0 A
+
+(Issue3303)
+Check that remote secret changeset are ignore when checking creation of remote heads
+
+We add a secret head into the push destination. This secreat head shadow a
+visible shared between the initial repo and the push destination.
+
+ $ hg up -q 4 # B'
+ $ mkcommit Z --config phases.new-commit=secret
+ $ hg phase .
+ 5: secret
+
+# We now try to push a new public changeset that descend from the common public
+# head shadowed by the remote secret head.
+
+ $ cd ../initialrepo
+ $ hg up -q 6 #B'
+ $ mkcommit I
+ created new head
+ $ hg push ../push-dest
+ pushing to ../push-dest
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+
+:note: The "(+1 heads)" is wrong as we do not had any visible head
+
+
+Restore condition prior extra insertion.
+ $ hg -q --config extensions.mq= strip .
+ $ hg up -q 7
+ $ cd ..
+
+Test secret changeset are not pull
+
+ $ hg init pull-dest
+ $ cd pull-dest
+ $ hg pull ../initialrepo
+ pulling from ../initialrepo
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 5 changes to 5 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hglog
+ 4 0 B'
+ 3 0 D
+ 2 0 C
+ 1 0 B
+ 0 0 A
+ $ cd ..
+
+But secret can still be bundled explicitly
+
+ $ cd initialrepo
+ $ hg bundle --base '4^' -r 'children(4)' ../secret-bundle.hg
+ 4 changesets found
+ $ cd ..
+
+Test secret changeset are not cloned
+(during local clone)
+
+ $ hg clone -qU initialrepo clone-dest
+ $ hglog -R clone-dest
+ 4 0 B'
+ 3 0 D
+ 2 0 C
+ 1 0 B
+ 0 0 A
+
+Test revset
+
+ $ cd initialrepo
+ $ hglog -r 'public()'
+ 0 0 A
+ 1 0 B
+ $ hglog -r 'draft()'
+ 2 1 C
+ 3 1 D
+ 6 1 B'
+ $ hglog -r 'secret()'
+ 4 2 E
+ 5 2 H
+ 7 2 merge B' and E
+
+test that phase are displayed in log at debug level
+
+ $ hg log --debug
+ changeset: 7:17a481b3bccb796c0521ae97903d81c52bfee4af
+ tag: tip
+ phase: secret
+ parent: 6:cf9fe039dfd67e829edf6522a45de057b5c86519
+ parent: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
+ manifest: 7:5e724ffacba267b2ab726c91fc8b650710deaaa8
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files+: C D E
+ extra: branch=default
+ description:
+ merge B' and E
+
+
+ changeset: 6:cf9fe039dfd67e829edf6522a45de057b5c86519
+ phase: draft
+ parent: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 6:ab8bfef2392903058bf4ebb9e7746e8d7026b27a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files+: B'
+ extra: branch=default
+ description:
+ B'
+
+
+ changeset: 5:a030c6be5127abc010fcbff1851536552e6951a8
+ phase: secret
+ parent: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 5:5c710aa854874fe3d5fa7192e77bdb314cc08b5a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files+: H
+ extra: branch=default
+ description:
+ H
+
+
+ changeset: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
+ phase: secret
+ parent: 3:b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 4:7173fd1c27119750b959e3a0f47ed78abe75d6dc
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files+: E
+ extra: branch=default
+ description:
+ E
+
+
+ changeset: 3:b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
+ phase: draft
+ parent: 2:f838bfaca5c7226600ebcfd84f3c3c13a28d3757
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 3:6e1f4c47ecb533ffd0c8e52cdc88afb6cd39e20c
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files+: D
+ extra: branch=default
+ description:
+ D
+
+
+ changeset: 2:f838bfaca5c7226600ebcfd84f3c3c13a28d3757
+ phase: draft
+ parent: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 2:66a5a01817fdf5239c273802b5b7618d051c89e4
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files+: C
+ extra: branch=default
+ description:
+ C
+
+
+ changeset: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
+ parent: 0:4a2df7238c3b48766b5e22fafbb8a2f506ec8256
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 1:cb5cbbc1bfbf24cc34b9e8c16914e9caa2d2a7fd
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files+: B
+ extra: branch=default
+ description:
+ B
+
+
+ changeset: 0:4a2df7238c3b48766b5e22fafbb8a2f506ec8256
+ parent: -1:0000000000000000000000000000000000000000
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 0:007d8c9d88841325f5c6b06371b35b4e8a2b1a83
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files+: A
+ extra: branch=default
+ description:
+ A
+
+
+
+Test phase command
+===================
+
+initial picture
+
+ $ cat >> $HGRCPATH << EOF
+ > [extensions]
+ > hgext.graphlog=
+ > EOF
+ $ hg log -G --template "{rev} {phase} {desc}\n"
+ @ 7 secret merge B' and E
+ |\
+ | o 6 draft B'
+ | |
+ +---o 5 secret H
+ | |
+ o | 4 secret E
+ | |
+ o | 3 draft D
+ | |
+ o | 2 draft C
+ |/
+ o 1 public B
+ |
+ o 0 public A
+
+
+display changesets phase
+
+(mixing -r and plain rev specification)
+
+ $ hg phase 1::4 -r 7
+ 1: public
+ 2: draft
+ 3: draft
+ 4: secret
+ 7: secret
+
+
+move changeset forward
+
+(with -r option)
+
+ $ hg phase --public -r 2
+ $ hg log -G --template "{rev} {phase} {desc}\n"
+ @ 7 secret merge B' and E
+ |\
+ | o 6 draft B'
+ | |
+ +---o 5 secret H
+ | |
+ o | 4 secret E
+ | |
+ o | 3 draft D
+ | |
+ o | 2 public C
+ |/
+ o 1 public B
+ |
+ o 0 public A
+
+
+move changeset backward
+
+(without -r option)
+
+ $ hg phase --draft --force 2
+ $ hg log -G --template "{rev} {phase} {desc}\n"
+ @ 7 secret merge B' and E
+ |\
+ | o 6 draft B'
+ | |
+ +---o 5 secret H
+ | |
+ o | 4 secret E
+ | |
+ o | 3 draft D
+ | |
+ o | 2 draft C
+ |/
+ o 1 public B
+ |
+ o 0 public A
+
+
+move changeset forward and backward
+
+ $ hg phase --draft --force 1::4
+ $ hg log -G --template "{rev} {phase} {desc}\n"
+ @ 7 secret merge B' and E
+ |\
+ | o 6 draft B'
+ | |
+ +---o 5 secret H
+ | |
+ o | 4 draft E
+ | |
+ o | 3 draft D
+ | |
+ o | 2 draft C
+ |/
+ o 1 draft B
+ |
+ o 0 public A
+
+test partial failure
+
+ $ hg phase --public 7
+ $ hg phase --draft '5 or 7'
+ cannot move 1 changesets to a more permissive phase, use --force
+ phase changed for 1 changesets
+ [1]
+ $ hg log -G --template "{rev} {phase} {desc}\n"
+ @ 7 public merge B' and E
+ |\
+ | o 6 public B'
+ | |
+ +---o 5 draft H
+ | |
+ o | 4 public E
+ | |
+ o | 3 public D
+ | |
+ o | 2 public C
+ |/
+ o 1 public B
+ |
+ o 0 public A
+
+
+test complete failure
+
+ $ hg phase --draft 7
+ cannot move 1 changesets to a more permissive phase, use --force
+ no phases changed
+ [1]
+
+ $ cd ..
diff --git a/tests/test-profile.t b/tests/test-profile.t
new file mode 100644
index 0000000..f05a8dd
--- /dev/null
+++ b/tests/test-profile.t
@@ -0,0 +1,31 @@
+test --time
+
+ $ hg --time help -q help 2>&1 | grep time > /dev/null
+ $ hg init a
+ $ cd a
+
+#if lsprof
+
+test --profile
+
+ $ hg --profile st 2>../out
+ $ grep CallCount ../out > /dev/null || cat ../out
+
+ $ hg --profile --config profiling.output=../out st
+ $ grep CallCount ../out > /dev/null || cat ../out
+
+ $ hg --profile --config profiling.format=text st 2>../out
+ $ grep CallCount ../out > /dev/null || cat ../out
+
+ $ echo "[profiling]" >> $HGRCPATH
+ $ echo "format=kcachegrind" >> $HGRCPATH
+
+ $ hg --profile st 2>../out
+ $ grep 'events: Ticks' ../out > /dev/null || cat ../out
+
+ $ hg --profile --config profiling.output=../out st
+ $ grep 'events: Ticks' ../out > /dev/null || cat ../out
+
+#endif
+
+ $ cd ..
diff --git a/tests/test-progress.t b/tests/test-progress.t
new file mode 100644
index 0000000..5fa0a62
--- /dev/null
+++ b/tests/test-progress.t
@@ -0,0 +1,216 @@
+
+ $ cat > loop.py <<EOF
+ > from mercurial import commands
+ >
+ > def loop(ui, loops, **opts):
+ > loops = int(loops)
+ > total = None
+ > if loops >= 0:
+ > total = loops
+ > if opts.get('total', None):
+ > total = int(opts.get('total'))
+ > nested = False
+ > if opts.get('nested', None):
+ > nested = True
+ > loops = abs(loops)
+ >
+ > for i in range(loops):
+ > ui.progress('loop', i, 'loop.%d' % i, 'loopnum', total)
+ > if opts.get('parallel'):
+ > ui.progress('other', i, 'other.%d' % i, 'othernum', total)
+ > if nested:
+ > for j in range(2):
+ > ui.progress('nested', j, 'nested.%d' % j, 'nestnum', 2)
+ > ui.progress('nested', None, 'nested.done', 'nestnum', 2)
+ > ui.progress('loop', None, 'loop.done', 'loopnum', total)
+ >
+ > commands.norepo += " loop"
+ >
+ > cmdtable = {
+ > "loop": (loop, [('', 'total', '', 'override for total'),
+ > ('', 'nested', False, 'show nested results'),
+ > ('', 'parallel', False, 'show parallel sets of results'),
+ > ],
+ > 'hg loop LOOPS'),
+ > }
+ > EOF
+
+ $ cp $HGRCPATH $HGRCPATH.orig
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "progress=" >> $HGRCPATH
+ $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
+ $ echo "[progress]" >> $HGRCPATH
+ $ echo "format = topic bar number" >> $HGRCPATH
+ $ echo "assume-tty=1" >> $HGRCPATH
+ $ echo "width=60" >> $HGRCPATH
+
+test default params, display nothing because of delay
+
+ $ hg -y loop 3 2>&1 | "$TESTDIR/filtercr.py"
+
+ $ echo "delay=0" >> $HGRCPATH
+ $ echo "refresh=0" >> $HGRCPATH
+
+test with delay=0, refresh=0
+
+ $ hg -y loop 3 2>&1 | "$TESTDIR/filtercr.py"
+
+ loop [ ] 0/3
+ loop [===============> ] 1/3
+ loop [===============================> ] 2/3
+ \r (esc)
+
+
+test nested short-lived topics (which shouldn't display with nestdelay):
+
+ $ hg -y loop 3 --nested 2>&1 | \
+ > python "$TESTDIR/filtercr.py"
+
+ loop [ ] 0/3
+ loop [===============> ] 1/3
+ loop [===============================> ] 2/3
+ \r (esc)
+
+
+ $ hg --config progress.changedelay=0 -y loop 3 --nested 2>&1 | \
+ > python "$TESTDIR/filtercr.py"
+
+ loop [ ] 0/3
+ nested [ ] 0/2
+ nested [======================> ] 1/2
+ loop [===============> ] 1/3
+ nested [ ] 0/2
+ nested [======================> ] 1/2
+ loop [===============================> ] 2/3
+ nested [ ] 0/2
+ nested [======================> ] 1/2
+ \r (esc)
+
+
+test two topics being printed in parallel (as when we're doing a local
+--pull clone, where you get the unbundle and bundle progress at the
+same time):
+ $ hg loop 3 --parallel 2>&1 | python "$TESTDIR/filtercr.py"
+
+ loop [ ] 0/3
+ loop [===============> ] 1/3
+ loop [===============================> ] 2/3
+ \r (esc)
+test refresh is taken in account
+
+ $ hg -y --config progress.refresh=100 loop 3 2>&1 | "$TESTDIR/filtercr.py"
+
+
+test format options 1
+
+ $ hg -y --config 'progress.format=number topic item+2' loop 2 2>&1 \
+ > | "$TESTDIR/filtercr.py"
+
+ 0/2 loop lo
+ 1/2 loop lo
+ \r (esc)
+
+test format options 2
+
+ $ hg -y --config 'progress.format=number item-3 bar' loop 2 2>&1 \
+ > | "$TESTDIR/filtercr.py"
+
+ 0/2 p.0 [ ]
+ 1/2 p.1 [=======================> ]
+ \r (esc)
+
+test format options and indeterminate progress
+
+ $ hg -y --config 'progress.format=number item bar' loop -- -2 2>&1 \
+ > | "$TESTDIR/filtercr.py"
+
+ 0 loop.0 [ <=> ]
+ 1 loop.1 [ <=> ]
+ \r (esc)
+
+make sure things don't fall over if count > total
+
+ $ hg -y loop --total 4 6 2>&1 | "$TESTDIR/filtercr.py"
+
+ loop [ ] 0/4
+ loop [===========> ] 1/4
+ loop [=======================> ] 2/4
+ loop [===================================> ] 3/4
+ loop [===============================================>] 4/4
+ loop [ <=> ] 5/4
+ \r (esc)
+
+test immediate progress completion
+
+ $ hg -y loop 0 2>&1 | "$TESTDIR/filtercr.py"
+
+
+test delay time estimates
+
+ $ cat > mocktime.py <<EOF
+ > import os
+ > import time
+ >
+ > class mocktime(object):
+ > def __init__(self, increment):
+ > self.time = 0
+ > self.increment = increment
+ > def __call__(self):
+ > self.time += self.increment
+ > return self.time
+ >
+ > def uisetup(ui):
+ > time.time = mocktime(int(os.environ.get('MOCKTIME', '11')))
+ > EOF
+
+ $ cp $HGRCPATH.orig $HGRCPATH
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mocktime=`pwd`/mocktime.py" >> $HGRCPATH
+ $ echo "progress=" >> $HGRCPATH
+ $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
+ $ echo "[progress]" >> $HGRCPATH
+ $ echo "assume-tty=1" >> $HGRCPATH
+ $ echo "delay=25" >> $HGRCPATH
+ $ echo "width=60" >> $HGRCPATH
+
+ $ hg -y loop 8 2>&1 | python "$TESTDIR/filtercr.py"
+
+ loop [=========> ] 2/8 1m07s
+ loop [===============> ] 3/8 56s
+ loop [=====================> ] 4/8 45s
+ loop [==========================> ] 5/8 34s
+ loop [================================> ] 6/8 23s
+ loop [=====================================> ] 7/8 12s
+ \r (esc)
+
+ $ MOCKTIME=10000 hg -y loop 4 2>&1 | python "$TESTDIR/filtercr.py"
+
+ loop [ ] 0/4
+ loop [=========> ] 1/4 8h21m
+ loop [====================> ] 2/4 5h34m
+ loop [==============================> ] 3/4 2h47m
+ \r (esc)
+
+ $ MOCKTIME=1000000 hg -y loop 4 2>&1 | python "$TESTDIR/filtercr.py"
+
+ loop [ ] 0/4
+ loop [=========> ] 1/4 5w00d
+ loop [====================> ] 2/4 3w03d
+ loop [=============================> ] 3/4 11d14h
+ \r (esc)
+
+
+ $ MOCKTIME=14000000 hg -y loop 4 2>&1 | python "$TESTDIR/filtercr.py"
+
+ loop [ ] 0/4
+ loop [=========> ] 1/4 1y18w
+ loop [===================> ] 2/4 46w03d
+ loop [=============================> ] 3/4 23w02d
+ \r (esc)
+
+Time estimates should not fail when there's no end point:
+ $ hg -y loop -- -4 2>&1 | python "$TESTDIR/filtercr.py"
+
+ loop [ <=> ] 2
+ loop [ <=> ] 3
+ \r (esc)
diff --git a/tests/test-pull-branch.t b/tests/test-pull-branch.t
new file mode 100644
index 0000000..a9545cf
--- /dev/null
+++ b/tests/test-pull-branch.t
@@ -0,0 +1,216 @@
+ $ hg init t
+ $ cd t
+ $ echo 1 > foo
+ $ hg ci -Am1 # 0
+ adding foo
+ $ hg branch branchA
+ marked working directory as branch branchA
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a1 > foo
+ $ hg ci -ma1 # 1
+
+ $ cd ..
+ $ hg init tt
+ $ cd tt
+ $ hg pull ../t
+ pulling from ../t
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up branchA
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd ../t
+ $ echo a2 > foo
+ $ hg ci -ma2 # 2
+
+Create branch B:
+
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch branchB
+ marked working directory as branch branchB
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b1 > foo
+ $ hg ci -mb1 # 3
+
+ $ cd ../tt
+
+A new branch is there
+
+ $ hg pull -u ../t
+ pulling from ../t
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files (+1 heads)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Develop both branches:
+
+ $ cd ../t
+ $ hg up branchA
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a3 > foo
+ $ hg ci -ma3 # 4
+ $ hg up branchB
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b2 > foo
+ $ hg ci -mb2 # 5
+
+ $ cd ../tt
+
+Should succeed, no new heads:
+
+ $ hg pull -u ../t
+ pulling from ../t
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Add a head on other branch:
+
+ $ cd ../t
+ $ hg up branchA
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a4 > foo
+ $ hg ci -ma4 # 6
+ $ hg up branchB
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b3.1 > foo
+ $ hg ci -m b3.1 # 7
+ $ hg up 5
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b3.2 > foo
+ $ hg ci -m b3.2 # 8
+ created new head
+
+ $ cd ../tt
+
+Should succeed because there is only one head on our branch:
+
+ $ hg pull -u ../t
+ pulling from ../t
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files (+1 heads)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd ../t
+ $ hg up -C branchA
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a5.1 > foo
+ $ hg ci -ma5.1 # 9
+ $ hg up 6
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a5.2 > foo
+ $ hg ci -ma5.2 # 10
+ created new head
+ $ hg up 7
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b4.1 > foo
+ $ hg ci -m b4.1 # 11
+ $ hg up -C 8
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b4.2 > foo
+ $ hg ci -m b4.2 # 12
+
+ $ cd ../tt
+
+ $ hg pull -u ../t
+ pulling from ../t
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 1 files (+1 heads)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Make changes on new branch on tt
+
+ $ hg up 6
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch branchC
+ marked working directory as branch branchC
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b1 > bar
+ $ hg ci -Am "commit on branchC on tt"
+ adding bar
+
+Make changes on default branch on t
+
+ $ cd ../t
+ $ hg up -C default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a1 > bar
+ $ hg ci -Am "commit on default on t"
+ adding bar
+
+Pull branchC from tt
+
+ $ hg pull ../tt
+ pulling from ../tt
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads)
+
+Make changes on default and branchC on tt
+
+ $ cd ../tt
+ $ hg pull ../t
+ pulling from ../t
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads)
+ $ hg up -C default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a1 > bar1
+ $ hg ci -Am "commit on default on tt"
+ adding bar1
+ $ hg up branchC
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo a1 > bar2
+ $ hg ci -Am "commit on branchC on tt"
+ adding bar2
+
+Make changes on default and branchC on t
+
+ $ cd ../t
+ $ hg up default
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a1 > bar3
+ $ hg ci -Am "commit on default on t"
+ adding bar3
+ $ hg up branchC
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo a1 > bar4
+ $ hg ci -Am "commit on branchC on tt"
+ adding bar4
+
+Pull from tt
+
+ $ hg pull ../tt
+ pulling from ../tt
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+2 heads)
+ (run 'hg heads .' to see heads, 'hg merge' to merge)
+
+ $ cd ..
diff --git a/tests/test-pull-http.t b/tests/test-pull-http.t
new file mode 100644
index 0000000..7c53682
--- /dev/null
+++ b/tests/test-pull-http.t
@@ -0,0 +1,65 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ hg init test
+ $ cd test
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+ $ cd ..
+ $ hg clone test test2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd test2
+ $ echo a >> a
+ $ hg ci -mb
+
+Cloning with a password in the URL should not save the password in .hg/hgrc:
+
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg clone http://foo:xyzzy@localhost:$HGPORT/ test3
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat test3/.hg/hgrc
+ [paths]
+ default = http://foo@localhost:$HGPORT/
+ $ "$TESTDIR/killdaemons.py"
+
+expect error, cloning not allowed
+
+ $ echo '[web]' > .hg/hgrc
+ $ echo 'allowpull = false' >> .hg/hgrc
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg clone http://localhost:$HGPORT/ test4
+ requesting all changes
+ abort: authorization failed
+ [255]
+ $ "$TESTDIR/killdaemons.py"
+
+serve errors
+
+ $ cat errors.log
+ $ req() {
+ > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ > cat hg.pid >> $DAEMON_PIDS
+ > hg --cwd ../test pull http://localhost:$HGPORT/
+ > kill `cat hg.pid`
+ > echo % serve errors
+ > cat errors.log
+ > }
+
+expect error, pulling not allowed
+
+ $ req
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ % serve errors
+
+ $ cd ..
diff --git a/tests/test-pull-permission.t b/tests/test-pull-permission.t
new file mode 100644
index 0000000..8df5527
--- /dev/null
+++ b/tests/test-pull-permission.t
@@ -0,0 +1,32 @@
+ $ "$TESTDIR/hghave" unix-permissions || exit 80
+
+ $ hg init a
+ $ cd a
+ $ echo foo > b
+ $ hg add b
+ $ hg ci -m "b"
+
+ $ chmod -w .hg/store
+
+ $ cd ..
+
+ $ hg clone a b
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ chmod +w a/.hg/store # let test clean up
+
+ $ cd b
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+
+ $ cd ..
diff --git a/tests/test-pull-pull-corruption.t b/tests/test-pull-pull-corruption.t
new file mode 100644
index 0000000..4df2984
--- /dev/null
+++ b/tests/test-pull-pull-corruption.t
@@ -0,0 +1,72 @@
+Corrupt an hg repo with two pulls.
+create one repo with a long history
+
+ $ hg init source1
+ $ cd source1
+ $ touch foo
+ $ hg add foo
+ $ for i in 1 2 3 4 5 6 7 8 9 10; do
+ > echo $i >> foo
+ > hg ci -m $i
+ > done
+ $ cd ..
+
+create one repo with a shorter history
+
+ $ hg clone -r 0 source1 source2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd source2
+ $ echo a >> foo
+ $ hg ci -m a
+ $ cd ..
+
+create a third repo to pull both other repos into it
+
+ $ hg init corrupted
+ $ cd corrupted
+
+use a hook to make the second pull start while the first one is still running
+
+ $ echo '[hooks]' >> .hg/hgrc
+ $ echo 'prechangegroup = sleep 5' >> .hg/hgrc
+
+start a pull...
+
+ $ hg pull ../source1 > pull.out 2>&1 &
+
+... and start another pull before the first one has finished
+
+ $ sleep 1
+ $ hg pull ../source2 2>/dev/null
+ pulling from ../source2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ cat pull.out
+ pulling from ../source1
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 10 changesets with 10 changes to 1 files
+ (run 'hg update' to get a working copy)
+
+see the result
+
+ $ wait
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 11 changesets, 11 total revisions
+
+ $ cd ..
diff --git a/tests/test-pull-r.t b/tests/test-pull-r.t
new file mode 100644
index 0000000..af91b6d
--- /dev/null
+++ b/tests/test-pull-r.t
@@ -0,0 +1,104 @@
+ $ hg init repo
+ $ cd repo
+ $ echo foo > foo
+ $ hg ci -qAm 'add foo'
+ $ echo >> foo
+ $ hg ci -m 'change foo'
+ $ hg up -qC 0
+ $ echo bar > bar
+ $ hg ci -qAm 'add bar'
+
+ $ hg log
+ changeset: 2:effea6de0384
+ tag: tip
+ parent: 0:bbd179dfa0a7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add bar
+
+ changeset: 1:ed1b79f46b9a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change foo
+
+ changeset: 0:bbd179dfa0a7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo
+
+ $ cd ..
+
+don't show "(+1 heads)" message when pulling closed head
+
+ $ hg clone -q repo repo2
+ $ hg clone -q repo2 repo3
+ $ cd repo2
+ $ hg up -q 0
+ $ echo hello >> foo
+ $ hg ci -mx1
+ created new head
+ $ hg ci -mx2 --close-branch
+ $ cd ../repo3
+ $ hg heads -q --closed
+ 2:effea6de0384
+ 1:ed1b79f46b9a
+ $ hg pull
+ pulling from $TESTTMP/repo2 (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg heads -q --closed
+ 4:00cfe9073916
+ 2:effea6de0384
+ 1:ed1b79f46b9a
+
+ $ cd ..
+
+ $ hg init copy
+ $ cd copy
+
+Pull a missing revision:
+
+ $ hg pull -qr missing ../repo
+ abort: unknown revision 'missing'!
+ [255]
+
+Pull multiple revisions with update:
+
+ $ hg pull -qu -r 0 -r 1 ../repo
+ $ hg -q parents
+ 0:bbd179dfa0a7
+ $ hg rollback
+ repository tip rolled back to revision -1 (undo pull)
+ working directory now based on revision -1
+
+ $ hg pull -qr 0 ../repo
+ $ hg log
+ changeset: 0:bbd179dfa0a7
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo
+
+ $ hg pull -qr 1 ../repo
+ $ hg log
+ changeset: 1:ed1b79f46b9a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change foo
+
+ changeset: 0:bbd179dfa0a7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add foo
+
+
+This used to abort: received changelog group is empty:
+
+ $ hg pull -qr 1 ../repo
+
+ $ cd ..
diff --git a/tests/test-pull-update.t b/tests/test-pull-update.t
new file mode 100644
index 0000000..3aa5a49
--- /dev/null
+++ b/tests/test-pull-update.t
@@ -0,0 +1,62 @@
+ $ hg init t
+ $ cd t
+ $ echo 1 > foo
+ $ hg ci -Am m
+ adding foo
+
+ $ cd ..
+ $ hg clone t tt
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd tt
+ $ echo 1.1 > foo
+ $ hg ci -Am m
+
+ $ cd ../t
+ $ echo 1.2 > foo
+ $ hg ci -Am m
+
+Should not update:
+
+ $ hg pull -u ../tt
+ pulling from ../tt
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ not updating: crosses branches (merge branches or update --check to force update)
+
+ $ cd ../tt
+
+Should not update:
+
+ $ hg pull -u ../t
+ pulling from ../t
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ not updating: crosses branches (merge branches or update --check to force update)
+
+ $ HGMERGE=true hg merge
+ merging foo
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -mm
+
+ $ cd ../t
+
+Should work:
+
+ $ hg pull -u ../tt
+ pulling from ../tt
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (-1 heads)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd ..
diff --git a/tests/test-pull.t b/tests/test-pull.t
new file mode 100644
index 0000000..b14d7f7
--- /dev/null
+++ b/tests/test-pull.t
@@ -0,0 +1,92 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ hg init test
+ $ cd test
+
+ $ echo foo>foo
+ $ hg addremove
+ adding foo
+ $ hg commit -m 1
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ cd ..
+
+ $ hg clone --pull http://foo:bar@localhost:$HGPORT/ copy
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd copy
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+
+ $ hg co
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat foo
+ foo
+
+ $ hg manifest --debug
+ 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo
+
+ $ hg pull
+ pulling from http://foo@localhost:$HGPORT/
+ searching for changes
+ no changes found
+
+ $ hg rollback --dry-run --verbose
+ repository tip rolled back to revision -1 (undo pull: http://foo:***@localhost:$HGPORT/)
+
+Issue622: hg init && hg pull -u URL doesn't checkout default branch
+
+ $ cd ..
+ $ hg init empty
+ $ cd empty
+ $ hg pull -u ../test
+ pulling from ../test
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Test 'file:' uri handling:
+
+ $ hg pull -q file://../test-doesnt-exist
+ abort: file:// URLs can only refer to localhost
+ [255]
+
+ $ hg pull -q file://../test
+ abort: file:// URLs can only refer to localhost
+ [255]
+
+ $ hg pull -q file:../test
+
+It's tricky to make file:// URLs working on every platform with
+regular shell commands.
+
+ $ URL=`python -c "import os; print 'file://foobar' + ('/' + os.getcwd().replace(os.sep, '/')).replace('//', '/') + '/../test'"`
+ $ hg pull -q "$URL"
+ abort: file:// URLs can only refer to localhost
+ [255]
+
+ $ URL=`python -c "import os; print 'file://localhost' + ('/' + os.getcwd().replace(os.sep, '/')).replace('//', '/') + '/../test'"`
+ $ hg pull -q "$URL"
+
+ $ cd ..
diff --git a/tests/test-purge.t b/tests/test-purge.t
new file mode 100644
index 0000000..75f9f90
--- /dev/null
+++ b/tests/test-purge.t
@@ -0,0 +1,218 @@
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > purge =
+ > EOF
+
+init
+
+ $ hg init t
+ $ cd t
+
+setup
+
+ $ echo r1 > r1
+ $ hg ci -qAmr1 -d'0 0'
+ $ mkdir directory
+ $ echo r2 > directory/r2
+ $ hg ci -qAmr2 -d'1 0'
+ $ echo 'ignored' > .hgignore
+ $ hg ci -qAmr3 -d'2 0'
+
+delete an empty directory
+
+ $ mkdir empty_dir
+ $ hg purge -p
+ empty_dir
+ $ hg purge -v
+ removing directory empty_dir
+ $ ls
+ directory
+ r1
+
+delete an untracked directory
+
+ $ mkdir untracked_dir
+ $ touch untracked_dir/untracked_file1
+ $ touch untracked_dir/untracked_file2
+ $ hg purge -p
+ untracked_dir/untracked_file1
+ untracked_dir/untracked_file2
+ $ hg purge -v
+ removing file untracked_dir/untracked_file1
+ removing file untracked_dir/untracked_file2
+ removing directory untracked_dir
+ $ ls
+ directory
+ r1
+
+delete an untracked file
+
+ $ touch untracked_file
+ $ touch untracked_file_readonly
+ $ python <<EOF
+ > import os, stat
+ > f= 'untracked_file_readonly'
+ > os.chmod(f, stat.S_IMODE(os.stat(f).st_mode) & ~stat.S_IWRITE)
+ > EOF
+ $ hg purge -p
+ untracked_file
+ untracked_file_readonly
+ $ hg purge -v
+ removing file untracked_file
+ removing file untracked_file_readonly
+ $ ls
+ directory
+ r1
+
+delete an untracked file in a tracked directory
+
+ $ touch directory/untracked_file
+ $ hg purge -p
+ directory/untracked_file
+ $ hg purge -v
+ removing file directory/untracked_file
+ $ ls
+ directory
+ r1
+
+delete nested directories
+
+ $ mkdir -p untracked_directory/nested_directory
+ $ hg purge -p
+ untracked_directory/nested_directory
+ $ hg purge -v
+ removing directory untracked_directory/nested_directory
+ removing directory untracked_directory
+ $ ls
+ directory
+ r1
+
+delete nested directories from a subdir
+
+ $ mkdir -p untracked_directory/nested_directory
+ $ cd directory
+ $ hg purge -p
+ untracked_directory/nested_directory
+ $ hg purge -v
+ removing directory untracked_directory/nested_directory
+ removing directory untracked_directory
+ $ cd ..
+ $ ls
+ directory
+ r1
+
+delete only part of the tree
+
+ $ mkdir -p untracked_directory/nested_directory
+ $ touch directory/untracked_file
+ $ cd directory
+ $ hg purge -p ../untracked_directory
+ untracked_directory/nested_directory
+ $ hg purge -v ../untracked_directory
+ removing directory untracked_directory/nested_directory
+ removing directory untracked_directory
+ $ cd ..
+ $ ls
+ directory
+ r1
+ $ ls directory/untracked_file
+ directory/untracked_file
+ $ rm directory/untracked_file
+
+skip ignored files if --all not specified
+
+ $ touch ignored
+ $ hg purge -p
+ $ hg purge -v
+ $ ls
+ directory
+ ignored
+ r1
+ $ hg purge -p --all
+ ignored
+ $ hg purge -v --all
+ removing file ignored
+ $ ls
+ directory
+ r1
+
+abort with missing files until we support name mangling filesystems
+
+ $ touch untracked_file
+ $ rm r1
+
+hide error messages to avoid changing the output when the text changes
+
+ $ hg purge -p 2> /dev/null
+ untracked_file
+ $ hg st
+ ! r1
+ ? untracked_file
+
+ $ hg purge -p
+ untracked_file
+ $ hg purge -v 2> /dev/null
+ removing file untracked_file
+ $ hg st
+ ! r1
+
+ $ hg purge -v
+ $ hg revert --all --quiet
+ $ hg st -a
+
+tracked file in ignored directory (issue621)
+
+ $ echo directory >> .hgignore
+ $ hg ci -m 'ignore directory'
+ $ touch untracked_file
+ $ hg purge -p
+ untracked_file
+ $ hg purge -v
+ removing file untracked_file
+
+skip excluded files
+
+ $ touch excluded_file
+ $ hg purge -p -X excluded_file
+ $ hg purge -v -X excluded_file
+ $ ls
+ directory
+ excluded_file
+ r1
+ $ rm excluded_file
+
+skip files in excluded dirs
+
+ $ mkdir excluded_dir
+ $ touch excluded_dir/file
+ $ hg purge -p -X excluded_dir
+ $ hg purge -v -X excluded_dir
+ $ ls
+ directory
+ excluded_dir
+ r1
+ $ ls excluded_dir
+ file
+ $ rm -R excluded_dir
+
+skip excluded empty dirs
+
+ $ mkdir excluded_dir
+ $ hg purge -p -X excluded_dir
+ $ hg purge -v -X excluded_dir
+ $ ls
+ directory
+ excluded_dir
+ r1
+ $ rmdir excluded_dir
+
+skip patterns
+
+ $ mkdir .svn
+ $ touch .svn/foo
+ $ mkdir directory/.svn
+ $ touch directory/.svn/foo
+ $ hg purge -p -X .svn -X '*/.svn'
+ $ hg purge -p -X re:.*.svn
+
+ $ cd ..
diff --git a/tests/test-push-cgi.t b/tests/test-push-cgi.t
new file mode 100644
index 0000000..365a73a
--- /dev/null
+++ b/tests/test-push-cgi.t
@@ -0,0 +1,92 @@
+ $ "$TESTDIR/hghave" no-msys || exit 80 # MSYS will translate web paths as if they were file paths
+
+This is a test of the push wire protocol over CGI-based hgweb.
+
+initialize repository
+
+ $ hg init r
+ $ cd r
+ $ echo a > a
+ $ hg ci -A -m "0"
+ adding a
+ $ echo '[web]' > .hg/hgrc
+ $ echo 'allow_push = *' >> .hg/hgrc
+ $ echo 'push_ssl = false' >> .hg/hgrc
+
+create hgweb invocation script
+
+ $ cat >hgweb.cgi <<HGWEB
+ > import cgitb
+ > cgitb.enable()
+ > from mercurial import demandimport; demandimport.enable()
+ > from mercurial.hgweb import hgweb
+ > from mercurial.hgweb import wsgicgi
+ > application = hgweb('.', 'test repository')
+ > wsgicgi.launch(application)
+ > HGWEB
+ $ chmod 755 hgweb.cgi
+
+test preparation
+
+ $ . "$TESTDIR/cgienv"
+ $ REQUEST_METHOD="POST"; export REQUEST_METHOD
+ $ CONTENT_TYPE="application/octet-stream"; export CONTENT_TYPE
+ $ hg bundle --all bundle.hg
+ 1 changesets found
+ $ CONTENT_LENGTH=279; export CONTENT_LENGTH;
+
+expect unsynced changes
+
+ $ QUERY_STRING="cmd=unbundle&heads=0000000000000000000000000000000000000000"; export QUERY_STRING
+ $ python hgweb.cgi <bundle.hg >page1 2>&1
+ $ cat page1
+ Status: 200 Script output follows\r (esc)
+ Content-Type: application/mercurial-0.1\r (esc)
+ Content-Length: 19\r (esc)
+ \r (esc)
+ 0
+ unsynced changes
+
+successful force push
+
+ $ QUERY_STRING="cmd=unbundle&heads=666f726365"; export QUERY_STRING
+ $ python hgweb.cgi <bundle.hg >page2 2>&1
+ $ cat page2
+ Status: 200 Script output follows\r (esc)
+ Content-Type: application/mercurial-0.1\r (esc)
+ \r (esc)
+ 1
+ adding changesets
+ adding manifests
+ adding file changes
+ added 0 changesets with 0 changes to 1 files
+
+successful push, list of heads
+
+ $ QUERY_STRING="cmd=unbundle&heads=f7b1eb17ad24730a1651fccd46c43826d1bbc2ac"; export QUERY_STRING
+ $ python hgweb.cgi <bundle.hg >page3 2>&1
+ $ cat page3
+ Status: 200 Script output follows\r (esc)
+ Content-Type: application/mercurial-0.1\r (esc)
+ \r (esc)
+ 1
+ adding changesets
+ adding manifests
+ adding file changes
+ added 0 changesets with 0 changes to 1 files
+
+successful push, SHA1 hash of heads (unbundlehash capability)
+
+ $ QUERY_STRING="cmd=unbundle&heads=686173686564 5a785a5f9e0d433b88ed862b206b011b0c3a9d13"; export QUERY_STRING
+ $ python hgweb.cgi <bundle.hg >page4 2>&1
+ $ cat page4
+ Status: 200 Script output follows\r (esc)
+ Content-Type: application/mercurial-0.1\r (esc)
+ \r (esc)
+ 1
+ adding changesets
+ adding manifests
+ adding file changes
+ added 0 changesets with 0 changes to 1 files
+
+ $ cd ..
diff --git a/tests/test-push-hook-lock.t b/tests/test-push-hook-lock.t
new file mode 100644
index 0000000..0a5ec47
--- /dev/null
+++ b/tests/test-push-hook-lock.t
@@ -0,0 +1,31 @@
+ $ hg init 1
+
+ $ echo '[ui]' >> 1/.hg/hgrc
+ $ echo 'timeout = 10' >> 1/.hg/hgrc
+
+ $ echo foo > 1/foo
+ $ hg --cwd 1 ci -A -m foo
+ adding foo
+
+ $ hg clone 1 2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg clone 2 3
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo '[hooks]' >> 2/.hg/hgrc
+ $ echo 'changegroup.push = hg push -qf ../1' >> 2/.hg/hgrc
+
+ $ echo bar >> 3/foo
+ $ hg --cwd 3 ci -m bar
+
+ $ hg --cwd 3 push ../2
+ pushing to ../2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
diff --git a/tests/test-push-http.t b/tests/test-push-http.t
new file mode 100644
index 0000000..7f3c6d6
--- /dev/null
+++ b/tests/test-push-http.t
@@ -0,0 +1,123 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ hg init test
+ $ cd test
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+ $ cd ..
+ $ hg clone test test2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd test2
+ $ echo a >> a
+ $ hg ci -mb
+ $ req() {
+ > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ > cat hg.pid >> $DAEMON_PIDS
+ > hg --cwd ../test2 push http://localhost:$HGPORT/
+ > "$TESTDIR/killdaemons.py"
+ > echo % serve errors
+ > cat errors.log
+ > }
+ $ cd ../test
+
+expect ssl error
+
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: ssl required
+ remote: ssl required
+ updating cb9a9f314b8b to public failed!
+ % serve errors
+
+expect authorization error
+
+ $ echo '[web]' > .hg/hgrc
+ $ echo 'push_ssl = false' >> .hg/hgrc
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ % serve errors
+
+expect authorization error: must have authorized user
+
+ $ echo 'allow_push = unperson' >> .hg/hgrc
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ % serve errors
+
+expect success
+
+ $ echo 'allow_push = *' >> .hg/hgrc
+ $ echo '[hooks]' >> .hg/hgrc
+ $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup 0" >> .hg/hgrc
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
+ % serve errors
+ $ hg rollback
+ repository tip rolled back to revision 0 (undo serve)
+
+expect success, server lacks the httpheader capability
+
+ $ CAP=httpheader
+ $ . "$TESTDIR/notcapable"
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
+ % serve errors
+ $ hg rollback
+ repository tip rolled back to revision 0 (undo serve)
+
+expect success, server lacks the unbundlehash capability
+
+ $ CAP=unbundlehash
+ $ . "$TESTDIR/notcapable"
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
+ % serve errors
+ $ hg rollback
+ repository tip rolled back to revision 0 (undo serve)
+
+expect authorization error: all users denied
+
+ $ echo '[web]' > .hg/hgrc
+ $ echo 'push_ssl = false' >> .hg/hgrc
+ $ echo 'deny_push = *' >> .hg/hgrc
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ % serve errors
+
+expect authorization error: some users denied, users must be authenticated
+
+ $ echo 'deny_push = unperson' >> .hg/hgrc
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ % serve errors
+
+ $ cd ..
diff --git a/tests/test-push-r.t b/tests/test-push-r.t
new file mode 100644
index 0000000..d6e541b
--- /dev/null
+++ b/tests/test-push-r.t
@@ -0,0 +1,149 @@
+ $ hg init test
+ $ cd test
+ $ hg unbundle "$TESTDIR/bundles/remote.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 7 changes to 4 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+
+ $ for i in 0 1 2 3 4 5 6 7 8; do
+ > echo
+ > mkdir test-"$i"
+ > hg --cwd test-"$i" init
+ > hg -R test push -r "$i" test-"$i"
+ > cd test-"$i"
+ > hg verify
+ > cd ..
+ > done
+
+ pushing to test-0
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+
+ pushing to test-1
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+
+ pushing to test-2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+
+ pushing to test-3
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 1 files
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 4 changesets, 4 total revisions
+
+ pushing to test-4
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+
+ pushing to test-5
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+
+ pushing to test-6
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 5 changes to 2 files
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 4 changesets, 5 total revisions
+
+ pushing to test-7
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 6 changes to 3 files
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 5 changesets, 6 total revisions
+
+ pushing to test-8
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 5 changes to 2 files
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 5 changesets, 5 total revisions
+
+ $ cd test-8
+
+ $ hg pull ../test-7
+ pulling from ../test-7
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 2 changes to 3 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 9 changesets, 7 total revisions
+
+ $ cd ..
diff --git a/tests/test-push-validation.t b/tests/test-push-validation.t
new file mode 100644
index 0000000..a4b49de
--- /dev/null
+++ b/tests/test-push-validation.t
@@ -0,0 +1,53 @@
+ $ hg init test
+ $ cd test
+
+ $ cat > .hg/hgrc <<EOF
+ > [server]
+ > validate=1
+ > EOF
+
+ $ echo alpha > alpha
+ $ echo beta > beta
+ $ hg addr
+ adding alpha
+ adding beta
+ $ hg ci -m 1
+
+ $ cd ..
+ $ hg clone test test-clone
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd test-clone
+ $ cp .hg/store/data/beta.i tmp
+ $ echo blah >> beta
+ $ hg ci -m '2 (corrupt)'
+ $ mv tmp .hg/store/data/beta.i
+
+Expected to fail:
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ beta@1: dddc47b3ba30 in manifests not found
+ 2 files, 2 changesets, 2 total revisions
+ 1 integrity errors encountered!
+ (first damaged changeset appears to be 1)
+ [1]
+
+Expected to fail:
+
+ $ hg push
+ pushing to $TESTTMP/test (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ transaction abort!
+ rollback completed
+ abort: missing file data for beta:dddc47b3ba30e54484720ce0f4f768a0f4b6efb9 - run hg verify
+ [255]
+
+ $ cd ..
diff --git a/tests/test-push-warn.t b/tests/test-push-warn.t
new file mode 100644
index 0000000..37c1589
--- /dev/null
+++ b/tests/test-push-warn.t
@@ -0,0 +1,732 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "graphlog=" >> $HGRCPATH
+
+ $ hg init a
+ $ cd a
+ $ echo foo > t1
+ $ hg add t1
+ $ hg commit -m "1"
+
+ $ cd ..
+ $ hg clone a b
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd a
+ $ echo foo > t2
+ $ hg add t2
+ $ hg commit -m "2"
+
+ $ cd ../b
+ $ echo foo > t3
+ $ hg add t3
+ $ hg commit -m "3"
+
+ $ hg push ../a
+ pushing to ../a
+ searching for changes
+ abort: push creates new remote head 1e108cc5548c!
+ (you should pull and merge or use push -f to force)
+ [255]
+
+ $ hg push --debug ../a
+ pushing to ../a
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 1, sample size is: 1
+ 2 total queries
+ listing keys for "bookmarks"
+ new remote heads on branch 'default'
+ new remote head 1e108cc5548c
+ abort: push creates new remote head 1e108cc5548c!
+ (you should pull and merge or use push -f to force)
+ [255]
+
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ $ hg push ../a
+ pushing to ../a
+ searching for changes
+ abort: push creates new remote head 1e108cc5548c!
+ (did you forget to merge? use push -f to force)
+ [255]
+
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg commit -m "4"
+ $ hg push ../a
+ pushing to ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 1 changes to 1 files
+
+ $ cd ..
+
+ $ hg init c
+ $ cd c
+ $ for i in 0 1 2; do
+ > echo $i >> foo
+ > hg ci -Am $i
+ > done
+ adding foo
+ $ cd ..
+
+ $ hg clone c d
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd d
+ $ for i in 0 1; do
+ > hg co -C $i
+ > echo d-$i >> foo
+ > hg ci -m d-$i
+ > done
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ created new head
+
+ $ HGMERGE=true hg merge 3
+ merging foo
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg ci -m c-d
+
+ $ hg push ../c
+ pushing to ../c
+ searching for changes
+ abort: push creates new remote head 6346d66eb9f5!
+ (did you forget to merge? use push -f to force)
+ [255]
+
+ $ hg push -r 2 ../c
+ pushing to ../c
+ searching for changes
+ no changes found
+ [1]
+
+ $ hg push -r 3 ../c
+ pushing to ../c
+ searching for changes
+ abort: push creates new remote head a5dda829a167!
+ (did you forget to merge? use push -f to force)
+ [255]
+
+ $ hg push -v -r 3 -r 4 ../c
+ pushing to ../c
+ searching for changes
+ new remote heads on branch 'default'
+ new remote head a5dda829a167
+ new remote head ee8fbc7a0295
+ abort: push creates new remote head a5dda829a167!
+ (did you forget to merge? use push -f to force)
+ [255]
+
+ $ hg push -v -f -r 3 -r 4 ../c
+ pushing to ../c
+ searching for changes
+ 2 changesets found
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files (+2 heads)
+
+ $ hg push -r 5 ../c
+ pushing to ../c
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (-1 heads)
+
+ $ hg in ../c
+ comparing with ../c
+ searching for changes
+ no changes found
+ [1]
+
+
+Issue450: push -r warns about remote head creation even if no heads
+will be created
+
+ $ hg init ../e
+ $ hg push -r 0 ../e
+ pushing to ../e
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+ $ hg push -r 1 ../e
+ pushing to ../e
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+ $ cd ..
+
+
+Issue736: named branches are not considered for detection of
+unmerged heads in "hg push"
+
+ $ hg init f
+ $ cd f
+ $ hg -q branch a
+ $ echo 0 > foo
+ $ hg -q ci -Am 0
+ $ echo 1 > foo
+ $ hg -q ci -m 1
+ $ hg -q up 0
+ $ echo 2 > foo
+ $ hg -q ci -m 2
+ $ hg -q up 0
+ $ hg -q branch b
+ $ echo 3 > foo
+ $ hg -q ci -m 3
+ $ cd ..
+
+ $ hg -q clone f g
+ $ cd g
+
+Push on existing branch and new branch:
+
+ $ hg -q up 1
+ $ echo 4 > foo
+ $ hg -q ci -m 4
+ $ hg -q up 0
+ $ echo 5 > foo
+ $ hg -q branch c
+ $ hg -q ci -m 5
+
+ $ hg push ../f
+ pushing to ../f
+ searching for changes
+ abort: push creates new remote branches: c!
+ (use 'hg push --new-branch' to create new remote branches)
+ [255]
+
+ $ hg push -r 4 -r 5 ../f
+ pushing to ../f
+ searching for changes
+ abort: push creates new remote branches: c!
+ (use 'hg push --new-branch' to create new remote branches)
+ [255]
+
+
+Multiple new branches:
+
+ $ hg -q branch d
+ $ echo 6 > foo
+ $ hg -q ci -m 6
+
+ $ hg push ../f
+ pushing to ../f
+ searching for changes
+ abort: push creates new remote branches: c, d!
+ (use 'hg push --new-branch' to create new remote branches)
+ [255]
+
+ $ hg push -r 4 -r 6 ../f
+ pushing to ../f
+ searching for changes
+ abort: push creates new remote branches: c, d!
+ (use 'hg push --new-branch' to create new remote branches)
+ [255]
+
+ $ cd ../g
+
+
+Fail on multiple head push:
+
+ $ hg -q up 1
+ $ echo 7 > foo
+ $ hg -q ci -m 7
+
+ $ hg push -r 4 -r 7 ../f
+ pushing to ../f
+ searching for changes
+ abort: push creates new remote head 0b715ef6ff8f on branch 'a'!
+ (did you forget to merge? use push -f to force)
+ [255]
+
+Push replacement head on existing branches:
+
+ $ hg -q up 3
+ $ echo 8 > foo
+ $ hg -q ci -m 8
+
+ $ hg push -r 7 -r 8 ../f
+ pushing to ../f
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+
+
+Merge of branch a to other branch b followed by unrelated push
+on branch a:
+
+ $ hg -q up 7
+ $ HGMERGE=true hg -q merge 8
+ $ hg -q ci -m 9
+ $ hg -q up 8
+ $ echo 10 > foo
+ $ hg -q ci -m 10
+
+ $ hg push -r 9 ../f
+ pushing to ../f
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (-1 heads)
+
+ $ hg push -r 10 ../f
+ pushing to ../f
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+
+
+Cheating the counting algorithm:
+
+ $ hg -q up 9
+ $ HGMERGE=true hg -q merge 2
+ $ hg -q ci -m 11
+ $ hg -q up 1
+ $ echo 12 > foo
+ $ hg -q ci -m 12
+
+ $ hg push -r 11 -r 12 ../f
+ pushing to ../f
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+
+
+Failed push of new named branch:
+
+ $ echo 12 > foo
+ $ hg -q ci -m 12a
+ [1]
+ $ hg -q up 11
+ $ echo 13 > foo
+ $ hg -q branch e
+ $ hg -q ci -m 13d
+
+ $ hg push -r 12 -r 13 ../f
+ pushing to ../f
+ searching for changes
+ abort: push creates new remote branches: e!
+ (use 'hg push --new-branch' to create new remote branches)
+ [255]
+
+
+Using --new-branch to push new named branch:
+
+ $ hg push --new-branch -r 12 -r 13 ../f
+ pushing to ../f
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+
+Checking prepush logic does not allow silently pushing
+multiple new heads:
+
+ $ cd ..
+ $ hg init h
+ $ echo init > h/init
+ $ hg -R h ci -Am init
+ adding init
+ $ echo a > h/a
+ $ hg -R h ci -Am a
+ adding a
+ $ hg clone h i
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R h up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo b > h/b
+ $ hg -R h ci -Am b
+ adding b
+ created new head
+ $ hg -R i up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo c > i/c
+ $ hg -R i ci -Am c
+ adding c
+ created new head
+
+ $ hg -R i push h
+ pushing to h
+ searching for changes
+ abort: push creates new remote head 97bd0c84d346!
+ (you should pull and merge or use push -f to force)
+ [255]
+
+
+Check prepush logic with merged branches:
+
+ $ hg init j
+ $ hg -R j branch a
+ marked working directory as branch a
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo init > j/foo
+ $ hg -R j ci -Am init
+ adding foo
+ $ hg clone j k
+ updating to branch a
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a1 > j/foo
+ $ hg -R j ci -m a1
+ $ hg -R k branch b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b > k/foo
+ $ hg -R k ci -m b
+ $ hg -R k up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg -R k merge b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg -R k ci -m merge
+
+ $ hg -R k push -r a j
+ pushing to j
+ searching for changes
+ abort: push creates new remote branches: b!
+ (use 'hg push --new-branch' to create new remote branches)
+ [255]
+
+
+Prepush -r should not allow you to sneak in new heads:
+
+ $ hg init l
+ $ cd l
+ $ echo a >> foo
+ $ hg -q add foo
+ $ hg -q branch a
+ $ hg -q ci -ma
+ $ hg -q up null
+ $ echo a >> foo
+ $ hg -q add foo
+ $ hg -q branch b
+ $ hg -q ci -mb
+ $ cd ..
+ $ hg -q clone l m -u a
+ $ cd m
+ $ hg -q merge b
+ $ hg -q ci -mmb
+ $ hg -q up 0
+ $ echo a >> foo
+ $ hg -q ci -ma2
+ $ hg -q up 2
+ $ echo a >> foo
+ $ hg -q branch -f b
+ $ hg -q ci -mb2
+ $ hg -q merge 3
+ $ hg -q ci -mma
+
+ $ hg push ../l -b b
+ pushing to ../l
+ searching for changes
+ abort: push creates new remote head e7e31d71180f on branch 'a'!
+ (did you forget to merge? use push -f to force)
+ [255]
+
+ $ cd ..
+
+
+Check prepush with new branch head on former topo non-head:
+
+ $ hg init n
+ $ cd n
+ $ hg branch A
+ marked working directory as branch A
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a >a
+ $ hg ci -Ama
+ adding a
+ $ hg branch B
+ marked working directory as branch B
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b >b
+ $ hg ci -Amb
+ adding b
+
+b is now branch head of B, and a topological head
+a is now branch head of A, but not a topological head
+
+ $ hg clone . inner
+ updating to branch B
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd inner
+ $ hg up B
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b1 >b1
+ $ hg ci -Amb1
+ adding b1
+
+in the clone b1 is now the head of B
+
+ $ cd ..
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo a2 >a2
+ $ hg ci -Ama2
+ adding a2
+
+a2 is now the new branch head of A, and a new topological head
+it replaces a former inner branch head, so it should at most warn about
+A, not B
+
+glog of local:
+
+ $ hg glog --template "{rev}: {branches} {desc}\n"
+ @ 2: A a2
+ |
+ | o 1: B b
+ |/
+ o 0: A a
+
+glog of remote:
+
+ $ hg glog -R inner --template "{rev}: {branches} {desc}\n"
+ @ 2: B b1
+ |
+ o 1: B b
+ |
+ o 0: A a
+
+outgoing:
+
+ $ hg out inner --template "{rev}: {branches} {desc}\n"
+ comparing with inner
+ searching for changes
+ 2: A a2
+
+ $ hg push inner
+ pushing to inner
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+
+ $ cd ..
+
+
+Check prepush with new branch head on former topo head:
+
+ $ hg init o
+ $ cd o
+ $ hg branch A
+ marked working directory as branch A
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a >a
+ $ hg ci -Ama
+ adding a
+ $ hg branch B
+ marked working directory as branch B
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b >b
+ $ hg ci -Amb
+ adding b
+
+b is now branch head of B, and a topological head
+
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo a1 >a1
+ $ hg ci -Ama1
+ adding a1
+
+a1 is now branch head of A, and a topological head
+
+ $ hg clone . inner
+ updating to branch A
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd inner
+ $ hg up B
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo b1 >b1
+ $ hg ci -Amb1
+ adding b1
+
+in the clone b1 is now the head of B
+
+ $ cd ..
+ $ echo a2 >a2
+ $ hg ci -Ama2
+ adding a2
+
+a2 is now the new branch head of A, and a topological head
+it replaces a former topological and branch head, so this should not warn
+
+glog of local:
+
+ $ hg glog --template "{rev}: {branches} {desc}\n"
+ @ 3: A a2
+ |
+ o 2: A a1
+ |
+ | o 1: B b
+ |/
+ o 0: A a
+
+glog of remote:
+
+ $ hg glog -R inner --template "{rev}: {branches} {desc}\n"
+ @ 3: B b1
+ |
+ | o 2: A a1
+ | |
+ o | 1: B b
+ |/
+ o 0: A a
+
+outgoing:
+
+ $ hg out inner --template "{rev}: {branches} {desc}\n"
+ comparing with inner
+ searching for changes
+ 3: A a2
+
+ $ hg push inner
+ pushing to inner
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+ $ cd ..
+
+
+Check prepush with new branch head and new child of former branch head
+but child is on different branch:
+
+ $ hg init p
+ $ cd p
+ $ hg branch A
+ marked working directory as branch A
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a0 >a
+ $ hg ci -Ama0
+ adding a
+ $ echo a1 >a
+ $ hg ci -ma1
+ $ hg up null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg branch B
+ marked working directory as branch B
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b0 >b
+ $ hg ci -Amb0
+ adding b
+ $ echo b1 >b
+ $ hg ci -mb1
+
+ $ hg clone . inner
+ updating to branch B
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg up A
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg branch -f B
+ marked working directory as branch B
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a3 >a
+ $ hg ci -ma3
+ created new head
+ $ hg up 3
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg branch -f A
+ marked working directory as branch A
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b3 >b
+ $ hg ci -mb3
+ created new head
+
+glog of local:
+
+ $ hg glog --template "{rev}: {branches} {desc}\n"
+ @ 5: A b3
+ |
+ | o 4: B a3
+ | |
+ o | 3: B b1
+ | |
+ o | 2: B b0
+ /
+ o 1: A a1
+ |
+ o 0: A a0
+
+glog of remote:
+
+ $ hg glog -R inner --template "{rev}: {branches} {desc}\n"
+ @ 3: B b1
+ |
+ o 2: B b0
+
+ o 1: A a1
+ |
+ o 0: A a0
+
+outgoing:
+
+ $ hg out inner --template "{rev}: {branches} {desc}\n"
+ comparing with inner
+ searching for changes
+ 4: B a3
+ 5: A b3
+
+ $ hg push inner
+ pushing to inner
+ searching for changes
+ abort: push creates new remote head 7d0f4fb6cf04 on branch 'A'!
+ (did you forget to merge? use push -f to force)
+ [255]
+
+ $ hg push inner -r4 -r5
+ pushing to inner
+ searching for changes
+ abort: push creates new remote head 7d0f4fb6cf04 on branch 'A'!
+ (did you forget to merge? use push -f to force)
+ [255]
+
+ $ hg in inner
+ comparing with inner
+ searching for changes
+ no changes found
+ [1]
+
+ $ cd ..
diff --git a/tests/test-qrecord.t b/tests/test-qrecord.t
new file mode 100644
index 0000000..ca218f3
--- /dev/null
+++ b/tests/test-qrecord.t
@@ -0,0 +1,402 @@
+Create configuration
+
+ $ echo "[ui]" >> $HGRCPATH
+ $ echo "interactive=true" >> $HGRCPATH
+
+help record (no record)
+
+ $ hg help record
+ record extension - commands to interactively select changes for
+ commit/qrefresh
+
+ use "hg help extensions" for information on enabling extensions
+
+help qrecord (no record)
+
+ $ hg help qrecord
+ 'qrecord' is provided by the following extension:
+
+ record commands to interactively select changes for commit/qrefresh
+
+ use "hg help extensions" for information on enabling extensions
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "record=" >> $HGRCPATH
+
+help record (record)
+
+ $ hg help record
+ hg record [OPTION]... [FILE]...
+
+ interactively select changes to commit
+
+ If a list of files is omitted, all changes reported by "hg status" will be
+ candidates for recording.
+
+ See "hg help dates" for a list of formats valid for -d/--date.
+
+ You will be prompted for whether to record changes to each modified file,
+ and for files with multiple changes, for each change to use. For each
+ query, the following responses are possible:
+
+ y - record this change
+ n - skip this change
+ e - edit this change manually
+
+ s - skip remaining changes to this file
+ f - record remaining changes to this file
+
+ d - done, skip remaining changes and files
+ a - record all changes to all remaining files
+ q - quit, recording no changes
+
+ ? - display help
+
+ This command is not available when committing a merge.
+
+ options:
+
+ -A --addremove mark new/missing files as added/removed before
+ committing
+ --close-branch mark a branch as closed, hiding it from the branch
+ list
+ --amend amend the parent of the working dir
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+ -m --message TEXT use text as commit message
+ -l --logfile FILE read commit message from file
+ -d --date DATE record the specified date as commit date
+ -u --user USER record the specified user as committer
+ -S --subrepos recurse into subrepositories
+ -w --ignore-all-space ignore white space when comparing lines
+ -b --ignore-space-change ignore changes in the amount of white space
+ -B --ignore-blank-lines ignore changes whose lines are all blank
+
+ [+] marked option can be specified multiple times
+
+ use "hg -v help record" to show more info
+
+help (no mq, so no qrecord)
+
+ $ hg help qrecord
+ hg qrecord [OPTION]... PATCH [FILE]...
+
+ interactively record a new patch
+
+ See "hg help qnew" & "hg help record" for more information and usage.
+
+ use "hg -v help qrecord" to show more info
+
+ $ hg init a
+
+qrecord (mq not present)
+
+ $ hg -R a qrecord
+ hg qrecord: invalid arguments
+ hg qrecord [OPTION]... PATCH [FILE]...
+
+ interactively record a new patch
+
+ use "hg help qrecord" to show the full help text
+ [255]
+
+qrecord patch (mq not present)
+
+ $ hg -R a qrecord patch
+ abort: 'mq' extension not loaded
+ [255]
+
+help (bad mq)
+
+ $ echo "mq=nonexistant" >> $HGRCPATH
+ $ hg help qrecord
+ *** failed to import extension mq from nonexistant: [Errno 2] * (glob)
+ hg qrecord [OPTION]... PATCH [FILE]...
+
+ interactively record a new patch
+
+ See "hg help qnew" & "hg help record" for more information and usage.
+
+ use "hg -v help qrecord" to show more info
+
+help (mq present)
+
+ $ sed 's/mq=nonexistant/mq=/' $HGRCPATH > hgrc.tmp
+ $ mv hgrc.tmp $HGRCPATH
+
+ $ hg help qrecord
+ hg qrecord [OPTION]... PATCH [FILE]...
+
+ interactively record a new patch
+
+ See "hg help qnew" & "hg help record" for more information and usage.
+
+ options:
+
+ -e --edit edit commit message
+ -g --git use git extended diff format
+ -U --currentuser add "From: <current user>" to patch
+ -u --user USER add "From: <USER>" to patch
+ -D --currentdate add "Date: <current date>" to patch
+ -d --date DATE add "Date: <DATE>" to patch
+ -I --include PATTERN [+] include names matching the given patterns
+ -X --exclude PATTERN [+] exclude names matching the given patterns
+ -m --message TEXT use text as commit message
+ -l --logfile FILE read commit message from file
+ -w --ignore-all-space ignore white space when comparing lines
+ -b --ignore-space-change ignore changes in the amount of white space
+ -B --ignore-blank-lines ignore changes whose lines are all blank
+ --mq operate on patch repository
+
+ [+] marked option can be specified multiple times
+
+ use "hg -v help qrecord" to show more info
+
+ $ cd a
+
+Base commit
+
+ $ cat > 1.txt <<EOF
+ > 1
+ > 2
+ > 3
+ > 4
+ > 5
+ > EOF
+ $ cat > 2.txt <<EOF
+ > a
+ > b
+ > c
+ > d
+ > e
+ > f
+ > EOF
+
+ $ mkdir dir
+ $ cat > dir/a.txt <<EOF
+ > hello world
+ >
+ > someone
+ > up
+ > there
+ > loves
+ > me
+ > EOF
+
+ $ hg add 1.txt 2.txt dir/a.txt
+ $ hg commit -m 'initial checkin'
+
+Changing files
+
+ $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
+ $ sed -e 's/b/b b/' 2.txt > 2.txt.new
+ $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
+
+ $ mv -f 1.txt.new 1.txt
+ $ mv -f 2.txt.new 2.txt
+ $ mv -f dir/a.txt.new dir/a.txt
+
+Whole diff
+
+ $ hg diff --nodates
+ diff -r 1057167b20ef 1.txt
+ --- a/1.txt
+ +++ b/1.txt
+ @@ -1,5 +1,5 @@
+ 1
+ -2
+ +2 2
+ 3
+ -4
+ +4 4
+ 5
+ diff -r 1057167b20ef 2.txt
+ --- a/2.txt
+ +++ b/2.txt
+ @@ -1,5 +1,5 @@
+ a
+ -b
+ +b b
+ c
+ d
+ e
+ diff -r 1057167b20ef dir/a.txt
+ --- a/dir/a.txt
+ +++ b/dir/a.txt
+ @@ -1,4 +1,4 @@
+ -hello world
+ +hello world!
+
+ someone
+ up
+
+qrecord with bad patch name, should abort before prompting
+
+ $ hg qrecord .hg
+ abort: patch name cannot begin with ".hg"
+ [255]
+
+qrecord a.patch
+
+ $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
+ > y
+ > y
+ > n
+ > y
+ > y
+ > n
+ > EOF
+ diff --git a/1.txt b/1.txt
+ 2 hunks, 2 lines changed
+ examine changes to '1.txt'? [Ynesfdaq?]
+ @@ -1,3 +1,3 @@
+ 1
+ -2
+ +2 2
+ 3
+ record change 1/4 to '1.txt'? [Ynesfdaq?]
+ @@ -3,3 +3,3 @@
+ 3
+ -4
+ +4 4
+ 5
+ record change 2/4 to '1.txt'? [Ynesfdaq?]
+ diff --git a/2.txt b/2.txt
+ 1 hunks, 1 lines changed
+ examine changes to '2.txt'? [Ynesfdaq?]
+ @@ -1,5 +1,5 @@
+ a
+ -b
+ +b b
+ c
+ d
+ e
+ record change 3/4 to '2.txt'? [Ynesfdaq?]
+ diff --git a/dir/a.txt b/dir/a.txt
+ 1 hunks, 1 lines changed
+ examine changes to 'dir/a.txt'? [Ynesfdaq?]
+
+After qrecord a.patch 'tip'"
+
+ $ hg tip -p
+ changeset: 1:5d1ca63427ee
+ tag: a.patch
+ tag: qbase
+ tag: qtip
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: aaa
+
+ diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
+ --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,5 +1,5 @@
+ 1
+ -2
+ +2 2
+ 3
+ 4
+ 5
+ diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
+ --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,5 +1,5 @@
+ a
+ -b
+ +b b
+ c
+ d
+ e
+
+
+After qrecord a.patch 'diff'"
+
+ $ hg diff --nodates
+ diff -r 5d1ca63427ee 1.txt
+ --- a/1.txt
+ +++ b/1.txt
+ @@ -1,5 +1,5 @@
+ 1
+ 2 2
+ 3
+ -4
+ +4 4
+ 5
+ diff -r 5d1ca63427ee dir/a.txt
+ --- a/dir/a.txt
+ +++ b/dir/a.txt
+ @@ -1,4 +1,4 @@
+ -hello world
+ +hello world!
+
+ someone
+ up
+
+qrecord b.patch
+
+ $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
+ > y
+ > y
+ > y
+ > y
+ > EOF
+ diff --git a/1.txt b/1.txt
+ 1 hunks, 1 lines changed
+ examine changes to '1.txt'? [Ynesfdaq?]
+ @@ -1,5 +1,5 @@
+ 1
+ 2 2
+ 3
+ -4
+ +4 4
+ 5
+ record change 1/2 to '1.txt'? [Ynesfdaq?]
+ diff --git a/dir/a.txt b/dir/a.txt
+ 1 hunks, 1 lines changed
+ examine changes to 'dir/a.txt'? [Ynesfdaq?]
+ @@ -1,4 +1,4 @@
+ -hello world
+ +hello world!
+
+ someone
+ up
+ record change 2/2 to 'dir/a.txt'? [Ynesfdaq?]
+
+After qrecord b.patch 'tip'
+
+ $ hg tip -p
+ changeset: 2:b056198bf878
+ tag: b.patch
+ tag: qtip
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: bbb
+
+ diff -r 5d1ca63427ee -r b056198bf878 1.txt
+ --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,5 +1,5 @@
+ 1
+ 2 2
+ 3
+ -4
+ +4 4
+ 5
+ diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
+ --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
+ +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,4 +1,4 @@
+ -hello world
+ +hello world!
+
+ someone
+ up
+
+
+After qrecord b.patch 'diff'
+
+ $ hg diff --nodates
+
+ $ cd ..
diff --git a/tests/test-rebase-abort.t b/tests/test-rebase-abort.t
new file mode 100644
index 0000000..3be364e
--- /dev/null
+++ b/tests/test-rebase-abort.t
@@ -0,0 +1,158 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}:{phase} '{desc}' {branches}\n"
+ > EOF
+
+
+ $ hg init a
+ $ cd a
+
+ $ echo c1 > common
+ $ hg add common
+ $ hg ci -m C1
+
+ $ echo c2 >> common
+ $ hg ci -m C2
+
+ $ echo c3 >> common
+ $ hg ci -m C3
+
+ $ hg up -q -C 1
+
+ $ echo l1 >> extra
+ $ hg add extra
+ $ hg ci -m L1
+ created new head
+
+ $ sed -e 's/c2/l2/' common > common.new
+ $ mv common.new common
+ $ hg ci -m L2
+
+ $ hg phase --force --secret 2
+
+ $ hg tglog
+ @ 4:draft 'L2'
+ |
+ o 3:draft 'L1'
+ |
+ | o 2:secret 'C3'
+ |/
+ o 1:draft 'C2'
+ |
+ o 0:draft 'C1'
+
+
+Conflicting rebase:
+
+ $ hg rebase -s 3 -d 2
+ merging common
+ warning: conflicts during merge.
+ merging common incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+Abort:
+
+ $ hg rebase --abort
+ saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
+ rebase aborted
+
+ $ hg tglog
+ @ 4:draft 'L2'
+ |
+ o 3:draft 'L1'
+ |
+ | o 2:secret 'C3'
+ |/
+ o 1:draft 'C2'
+ |
+ o 0:draft 'C1'
+
+ $ cd ..
+
+
+Constrcut new repo:
+
+ $ hg init b
+ $ cd b
+
+ $ echo a > a
+ $ hg ci -Am A
+ adding a
+
+ $ echo b > b
+ $ hg ci -Am B
+ adding b
+
+ $ echo c > c
+ $ hg ci -Am C
+ adding c
+
+ $ hg up -q 0
+
+ $ echo b > b
+ $ hg ci -Am 'B bis'
+ adding b
+ created new head
+
+ $ echo c1 > c
+ $ hg ci -Am C1
+ adding c
+
+ $ hg phase --force --secret 1
+ $ hg phase --public 1
+
+Rebase and abort without generating new changesets:
+
+ $ hg tglog
+ @ 4:draft 'C1'
+ |
+ o 3:draft 'B bis'
+ |
+ | o 2:secret 'C'
+ | |
+ | o 1:public 'B'
+ |/
+ o 0:public 'A'
+
+ $ hg rebase -b 4 -d 2
+ merging c
+ warning: conflicts during merge.
+ merging c incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+ $ hg tglog
+ @ 4:draft 'C1'
+ |
+ o 3:draft 'B bis'
+ |
+ | @ 2:secret 'C'
+ | |
+ | o 1:public 'B'
+ |/
+ o 0:public 'A'
+
+ $ hg rebase -a
+ rebase aborted
+
+ $ hg tglog
+ @ 4:draft 'C1'
+ |
+ o 3:draft 'B bis'
+ |
+ | o 2:secret 'C'
+ | |
+ | o 1:public 'B'
+ |/
+ o 0:public 'A'
+
+
+ $ cd ..
diff --git a/tests/test-rebase-bookmarks.t b/tests/test-rebase-bookmarks.t
new file mode 100644
index 0000000..fe5a251
--- /dev/null
+++ b/tests/test-rebase-bookmarks.t
@@ -0,0 +1,113 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' bookmarks: {bookmarks}\n"
+ > EOF
+
+Create a repo with several bookmarks
+ $ hg init a
+ $ cd a
+
+ $ echo a > a
+ $ hg ci -Am A
+ adding a
+
+ $ echo b > b
+ $ hg ci -Am B
+ adding b
+ $ hg book 'X'
+ $ hg book 'Y'
+
+ $ echo c > c
+ $ hg ci -Am C
+ adding c
+ $ hg book 'Z'
+
+ $ hg up -q 0
+
+ $ echo d > d
+ $ hg ci -Am D
+ adding d
+ created new head
+
+ $ hg book W
+
+ $ hg tglog
+ @ 3: 'D' bookmarks: W
+ |
+ | o 2: 'C' bookmarks: Y Z
+ | |
+ | o 1: 'B' bookmarks: X
+ |/
+ o 0: 'A' bookmarks:
+
+
+Move only rebased bookmarks
+
+ $ cd ..
+ $ hg clone -q a a1
+
+ $ cd a1
+ $ hg up -q Z
+
+ $ hg rebase -s Y -d 3
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 3: 'C' bookmarks: Y Z
+ |
+ o 2: 'D' bookmarks: W
+ |
+ | o 1: 'B' bookmarks: X
+ |/
+ o 0: 'A' bookmarks:
+
+Keep bookmarks to the correct rebased changeset
+
+ $ cd ..
+ $ hg clone -q a a2
+
+ $ cd a2
+ $ hg up -q Z
+
+ $ hg rebase -s 1 -d 3
+ saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 3: 'C' bookmarks: Y Z
+ |
+ o 2: 'B' bookmarks: X
+ |
+ o 1: 'D' bookmarks: W
+ |
+ o 0: 'A' bookmarks:
+
+
+Keep active bookmark on the correct changeset
+
+ $ cd ..
+ $ hg clone -q a a3
+
+ $ cd a3
+ $ hg up -q X
+
+ $ hg rebase -d W
+ saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 3: 'C' bookmarks: Y Z
+ |
+ o 2: 'B' bookmarks: X
+ |
+ o 1: 'D' bookmarks: W
+ |
+ o 0: 'A' bookmarks:
+
+
+ $ cd ..
diff --git a/tests/test-rebase-cache.t b/tests/test-rebase-cache.t
new file mode 100644
index 0000000..81fa012
--- /dev/null
+++ b/tests/test-rebase-cache.t
@@ -0,0 +1,387 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ > mq=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
+ > theads = heads --template "{rev}: '{desc}' {branches}\n"
+ > EOF
+
+ $ hg init a
+ $ cd a
+
+ $ echo a > a
+ $ hg ci -Am A
+ adding a
+
+ $ hg branch branch1
+ marked working directory as branch branch1
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m 'branch1'
+
+ $ echo b > b
+ $ hg ci -Am B
+ adding b
+
+ $ hg up -q 0
+
+ $ hg branch branch2
+ marked working directory as branch branch2
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m 'branch2'
+
+ $ echo c > C
+ $ hg ci -Am C
+ adding C
+
+ $ hg up -q 2
+
+ $ hg branch -f branch2
+ marked working directory as branch branch2
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo d > d
+ $ hg ci -Am D
+ adding d
+ created new head
+
+ $ echo e > e
+ $ hg ci -Am E
+ adding e
+
+ $ hg update default
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+
+ $ hg branch branch3
+ marked working directory as branch branch3
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m 'branch3'
+
+ $ echo f > f
+ $ hg ci -Am F
+ adding f
+
+ $ cd ..
+
+
+Rebase part of branch2 (5-6) onto branch3 (8):
+
+ $ hg clone -q -u . a a1
+ $ cd a1
+
+ $ hg tglog
+ @ 8: 'F' branch3
+ |
+ o 7: 'branch3' branch3
+ |
+ | o 6: 'E' branch2
+ | |
+ | o 5: 'D' branch2
+ | |
+ | | o 4: 'C' branch2
+ | | |
+ +---o 3: 'branch2' branch2
+ | |
+ | o 2: 'B' branch1
+ | |
+ | o 1: 'branch1' branch1
+ |/
+ o 0: 'A'
+
+ $ hg branches
+ branch3 8:4666b71e8e32
+ branch2 6:5097051d331d
+ branch1 2:0a03079c47fd (inactive)
+ default 0:1994f17a630e (inactive)
+
+ $ hg theads
+ 8: 'F' branch3
+ 6: 'E' branch2
+ 4: 'C' branch2
+ 2: 'B' branch1
+ 0: 'A'
+
+ $ hg rebase -s 5 -d 8
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg branches
+ branch3 8:466cdfb14b62
+ branch2 4:e4fdb121d036
+ branch1 2:0a03079c47fd
+ default 0:1994f17a630e (inactive)
+
+ $ hg theads
+ 8: 'E' branch3
+ 4: 'C' branch2
+ 2: 'B' branch1
+ 0: 'A'
+
+ $ hg tglog
+ @ 8: 'E' branch3
+ |
+ o 7: 'D' branch3
+ |
+ o 6: 'F' branch3
+ |
+ o 5: 'branch3' branch3
+ |
+ | o 4: 'C' branch2
+ | |
+ | o 3: 'branch2' branch2
+ |/
+ | o 2: 'B' branch1
+ | |
+ | o 1: 'branch1' branch1
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Rebase head of branch3 (8) onto branch2 (6):
+
+ $ hg clone -q -u . a a2
+ $ cd a2
+
+ $ hg tglog
+ @ 8: 'F' branch3
+ |
+ o 7: 'branch3' branch3
+ |
+ | o 6: 'E' branch2
+ | |
+ | o 5: 'D' branch2
+ | |
+ | | o 4: 'C' branch2
+ | | |
+ +---o 3: 'branch2' branch2
+ | |
+ | o 2: 'B' branch1
+ | |
+ | o 1: 'branch1' branch1
+ |/
+ o 0: 'A'
+
+ $ hg rebase -s 8 -d 6
+ saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg branches
+ branch2 8:6b4bdc1b5ac0
+ branch3 7:653b9feb4616
+ branch1 2:0a03079c47fd (inactive)
+ default 0:1994f17a630e (inactive)
+
+ $ hg theads
+ 8: 'F' branch2
+ 7: 'branch3' branch3
+ 4: 'C' branch2
+ 2: 'B' branch1
+ 0: 'A'
+
+ $ hg tglog
+ @ 8: 'F' branch2
+ |
+ | o 7: 'branch3' branch3
+ | |
+ o | 6: 'E' branch2
+ | |
+ o | 5: 'D' branch2
+ | |
+ | | o 4: 'C' branch2
+ | | |
+ | | o 3: 'branch2' branch2
+ | |/
+ o | 2: 'B' branch1
+ | |
+ o | 1: 'branch1' branch1
+ |/
+ o 0: 'A'
+
+ $ hg verify -q
+
+ $ cd ..
+
+
+Rebase entire branch3 (7-8) onto branch2 (6):
+
+ $ hg clone -q -u . a a3
+ $ cd a3
+
+ $ hg tglog
+ @ 8: 'F' branch3
+ |
+ o 7: 'branch3' branch3
+ |
+ | o 6: 'E' branch2
+ | |
+ | o 5: 'D' branch2
+ | |
+ | | o 4: 'C' branch2
+ | | |
+ +---o 3: 'branch2' branch2
+ | |
+ | o 2: 'B' branch1
+ | |
+ | o 1: 'branch1' branch1
+ |/
+ o 0: 'A'
+
+ $ hg rebase -s 7 -d 6
+ saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg branches
+ branch2 7:6b4bdc1b5ac0
+ branch1 2:0a03079c47fd (inactive)
+ default 0:1994f17a630e (inactive)
+
+ $ hg theads
+ 7: 'F' branch2
+ 4: 'C' branch2
+ 2: 'B' branch1
+ 0: 'A'
+
+ $ hg tglog
+ @ 7: 'F' branch2
+ |
+ o 6: 'E' branch2
+ |
+ o 5: 'D' branch2
+ |
+ | o 4: 'C' branch2
+ | |
+ | o 3: 'branch2' branch2
+ | |
+ o | 2: 'B' branch1
+ | |
+ o | 1: 'branch1' branch1
+ |/
+ o 0: 'A'
+
+ $ hg verify -q
+
+Stripping multiple branches in one go bypasses the fast-case code to
+update the branch cache.
+
+ $ hg strip 2
+ 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ o 3: 'C' branch2
+ |
+ o 2: 'branch2' branch2
+ |
+ | @ 1: 'branch1' branch1
+ |/
+ o 0: 'A'
+
+
+ $ hg branches
+ branch2 3:e4fdb121d036
+ branch1 1:63379ac49655
+ default 0:1994f17a630e (inactive)
+
+ $ hg theads
+ 3: 'C' branch2
+ 1: 'branch1' branch1
+ 0: 'A'
+
+Fast path branchcache code should not be invoked if branches stripped is not
+the same as branches remaining.
+
+ $ hg init b
+ $ cd b
+
+ $ hg branch branch1
+ marked working directory as branch branch1
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m 'branch1'
+
+ $ hg branch branch2
+ marked working directory as branch branch2
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m 'branch2'
+
+ $ hg branch -f branch1
+ marked working directory as branch branch1
+ (branches are permanent and global, did you want a bookmark?)
+
+ $ echo a > A
+ $ hg ci -Am A
+ adding A
+ created new head
+
+ $ hg tglog
+ @ 2: 'A' branch1
+ |
+ o 1: 'branch2' branch2
+ |
+ o 0: 'branch1' branch1
+
+
+ $ hg theads
+ 2: 'A' branch1
+ 1: 'branch2' branch2
+
+ $ hg strip 2
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/a3/b/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg theads
+ 1: 'branch2' branch2
+ 0: 'branch1' branch1
+
+
+Make sure requesting to strip a revision already stripped does not confuse things.
+Try both orders.
+
+ $ cd ..
+
+ $ hg init c
+ $ cd c
+
+ $ echo a > a
+ $ hg ci -Am A
+ adding a
+ $ echo b > b
+ $ hg ci -Am B
+ adding b
+ $ echo c > c
+ $ hg ci -Am C
+ adding c
+ $ echo d > d
+ $ hg ci -Am D
+ adding d
+ $ echo e > e
+ $ hg ci -Am E
+ adding e
+
+ $ hg tglog
+ @ 4: 'E'
+ |
+ o 3: 'D'
+ |
+ o 2: 'C'
+ |
+ o 1: 'B'
+ |
+ o 0: 'A'
+
+
+ $ hg strip 3 4
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/a3/c/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg theads
+ 2: 'C'
+
+ $ hg strip 2 1
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/a3/c/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg theads
+ 0: 'A'
diff --git a/tests/test-rebase-check-restore.t b/tests/test-rebase-check-restore.t
new file mode 100644
index 0000000..c664725
--- /dev/null
+++ b/tests/test-rebase-check-restore.t
@@ -0,0 +1,150 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}:{phase} '{desc}' {branches}\n"
+ > EOF
+
+
+ $ hg init a
+ $ cd a
+
+ $ echo A > A
+ $ hg add A
+ $ hg ci -m A
+
+ $ echo 'B' > B
+ $ hg add B
+ $ hg ci -m B
+
+ $ echo C >> A
+ $ hg ci -m C
+
+ $ hg up -q -C 0
+
+ $ echo D >> A
+ $ hg ci -m D
+ created new head
+
+ $ echo E > E
+ $ hg add E
+ $ hg ci -m E
+
+ $ hg up -q -C 0
+
+ $ hg branch 'notdefault'
+ marked working directory as branch notdefault
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo F >> A
+ $ hg ci -m F
+
+ $ cd ..
+
+
+Rebasing B onto E - check keep: and phases
+
+ $ hg clone -q -u . a a1
+ $ cd a1
+ $ hg phase --force --secret 2
+
+ $ hg tglog
+ @ 5:draft 'F' notdefault
+ |
+ | o 4:draft 'E'
+ | |
+ | o 3:draft 'D'
+ |/
+ | o 2:secret 'C'
+ | |
+ | o 1:draft 'B'
+ |/
+ o 0:draft 'A'
+
+ $ hg rebase -s 1 -d 4 --keep
+ merging A
+ warning: conflicts during merge.
+ merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+Solve the conflict and go on:
+
+ $ echo 'conflict solved' > A
+ $ rm A.orig
+ $ hg resolve -m A
+ $ hg rebase --continue
+
+ $ hg tglog
+ @ 7:secret 'C'
+ |
+ o 6:draft 'B'
+ |
+ | o 5:draft 'F' notdefault
+ | |
+ o | 4:draft 'E'
+ | |
+ o | 3:draft 'D'
+ |/
+ | o 2:secret 'C'
+ | |
+ | o 1:draft 'B'
+ |/
+ o 0:draft 'A'
+
+ $ cd ..
+
+
+Rebase F onto E - check keepbranches:
+
+ $ hg clone -q -u . a a2
+ $ cd a2
+ $ hg phase --force --secret 2
+
+ $ hg tglog
+ @ 5:draft 'F' notdefault
+ |
+ | o 4:draft 'E'
+ | |
+ | o 3:draft 'D'
+ |/
+ | o 2:secret 'C'
+ | |
+ | o 1:draft 'B'
+ |/
+ o 0:draft 'A'
+
+ $ hg rebase -s 5 -d 4 --keepbranches
+ merging A
+ warning: conflicts during merge.
+ merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+Solve the conflict and go on:
+
+ $ echo 'conflict solved' > A
+ $ rm A.orig
+ $ hg resolve -m A
+ $ hg rebase --continue
+ saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 5:draft 'F' notdefault
+ |
+ o 4:draft 'E'
+ |
+ o 3:draft 'D'
+ |
+ | o 2:secret 'C'
+ | |
+ | o 1:draft 'B'
+ |/
+ o 0:draft 'A'
+
+
+ $ cd ..
diff --git a/tests/test-rebase-collapse.t b/tests/test-rebase-collapse.t
new file mode 100644
index 0000000..a89b8fe
--- /dev/null
+++ b/tests/test-rebase-collapse.t
@@ -0,0 +1,722 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ > mq=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
+ > tglogp = log -G --template "{rev}:{phase} '{desc}' {branches}\n"
+ > EOF
+
+Create repo a:
+
+ $ hg init a
+ $ cd a
+ $ hg unbundle "$TESTDIR/bundles/rebase.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 8 changesets with 7 changes to 7 files (+2 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up tip
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg tglog
+ @ 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Rebasing B onto H and collapsing changesets with different phases:
+
+
+ $ hg clone -q -u 3 a a1
+ $ cd a1
+
+ $ hg phase --force --secret 3
+
+ $ hg rebase --collapse --keepbranches
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglogp
+ @ 5:secret 'Collapsed revision
+ | * B
+ | * C
+ | * D'
+ o 4:draft 'H'
+ |
+ | o 3:draft 'G'
+ |/|
+ o | 2:draft 'F'
+ | |
+ | o 1:draft 'E'
+ |/
+ o 0:draft 'A'
+
+ $ hg manifest
+ A
+ B
+ C
+ D
+ F
+ H
+
+ $ cd ..
+
+
+Rebasing E onto H:
+
+ $ hg clone -q -u . a a2
+ $ cd a2
+
+ $ hg phase --force --secret 6
+ $ hg rebase --source 4 --collapse
+ saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 6: 'Collapsed revision
+ | * E
+ | * G'
+ o 5: 'H'
+ |
+ o 4: 'F'
+ |
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg manifest
+ A
+ E
+ F
+ H
+
+ $ cd ..
+
+Rebasing G onto H with custom message:
+
+ $ hg clone -q -u . a a3
+ $ cd a3
+
+ $ hg rebase --base 6 -m 'custom message'
+ abort: message can only be specified with collapse
+ [255]
+
+ $ hg rebase --source 4 --collapse -m 'custom message'
+ saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 6: 'custom message'
+ |
+ o 5: 'H'
+ |
+ o 4: 'F'
+ |
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg manifest
+ A
+ E
+ F
+ H
+
+ $ cd ..
+
+Create repo b:
+
+ $ hg init b
+ $ cd b
+
+ $ echo A > A
+ $ hg ci -Am A
+ adding A
+ $ echo B > B
+ $ hg ci -Am B
+ adding B
+
+ $ hg up -q 0
+
+ $ echo C > C
+ $ hg ci -Am C
+ adding C
+ created new head
+
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ echo D > D
+ $ hg ci -Am D
+ adding D
+
+ $ hg up -q 1
+
+ $ echo E > E
+ $ hg ci -Am E
+ adding E
+ created new head
+
+ $ echo F > F
+ $ hg ci -Am F
+ adding F
+
+ $ hg merge
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m G
+
+ $ hg up -q 0
+
+ $ echo H > H
+ $ hg ci -Am H
+ adding H
+ created new head
+
+ $ hg tglog
+ @ 7: 'H'
+ |
+ | o 6: 'G'
+ | |\
+ | | o 5: 'F'
+ | | |
+ | | o 4: 'E'
+ | | |
+ | o | 3: 'D'
+ | |\|
+ | o | 2: 'C'
+ |/ /
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Rebase and collapse - more than one external (fail):
+
+ $ hg clone -q -u . b b1
+ $ cd b1
+
+ $ hg rebase -s 2 --collapse
+ abort: unable to collapse, there is more than one external parent
+ [255]
+
+Rebase and collapse - E onto H:
+
+ $ hg rebase -s 4 --collapse # root (4) is not a merge
+ saved backup bundle to $TESTTMP/b1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 5: 'Collapsed revision
+ |\ * E
+ | | * F
+ | | * G'
+ | o 4: 'H'
+ | |
+ o | 3: 'D'
+ |\ \
+ | o | 2: 'C'
+ | |/
+ o / 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg manifest
+ A
+ C
+ D
+ E
+ F
+ H
+
+ $ cd ..
+
+
+
+
+Test that branchheads cache is updated correctly when doing a strip in which
+the parent of the ancestor node to be stripped does not become a head and
+also, the parent of a node that is a child of the node stripped becomes a head
+(node 3).
+
+ $ hg clone -q -u . b b2
+ $ cd b2
+
+ $ hg heads --template="{rev}:{node} {branch}\n"
+ 7:c65502d4178782309ce0574c5ae6ee9485a9bafa default
+ 6:c772a8b2dc17629cec88a19d09c926c4814b12c7 default
+
+ $ cat $TESTTMP/b2/.hg/cache/branchheads
+ c65502d4178782309ce0574c5ae6ee9485a9bafa 7
+ c772a8b2dc17629cec88a19d09c926c4814b12c7 default
+ c65502d4178782309ce0574c5ae6ee9485a9bafa default
+
+ $ hg strip 4
+ saved backup bundle to $TESTTMP/b2/.hg/strip-backup/8a5212ebc852-backup.hg (glob)
+
+ $ cat $TESTTMP/b2/.hg/cache/branchheads
+ c65502d4178782309ce0574c5ae6ee9485a9bafa 4
+ 2870ad076e541e714f3c2bc32826b5c6a6e5b040 default
+ c65502d4178782309ce0574c5ae6ee9485a9bafa default
+
+ $ hg heads --template="{rev}:{node} {branch}\n"
+ 4:c65502d4178782309ce0574c5ae6ee9485a9bafa default
+ 3:2870ad076e541e714f3c2bc32826b5c6a6e5b040 default
+
+ $ cd ..
+
+
+
+
+
+
+Create repo c:
+
+ $ hg init c
+ $ cd c
+
+ $ echo A > A
+ $ hg ci -Am A
+ adding A
+ $ echo B > B
+ $ hg ci -Am B
+ adding B
+
+ $ hg up -q 0
+
+ $ echo C > C
+ $ hg ci -Am C
+ adding C
+ created new head
+
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ echo D > D
+ $ hg ci -Am D
+ adding D
+
+ $ hg up -q 1
+
+ $ echo E > E
+ $ hg ci -Am E
+ adding E
+ created new head
+ $ echo F > E
+ $ hg ci -m 'F'
+
+ $ echo G > G
+ $ hg ci -Am G
+ adding G
+
+ $ hg merge
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg ci -m H
+
+ $ hg up -q 0
+
+ $ echo I > I
+ $ hg ci -Am I
+ adding I
+ created new head
+
+ $ hg tglog
+ @ 8: 'I'
+ |
+ | o 7: 'H'
+ | |\
+ | | o 6: 'G'
+ | | |
+ | | o 5: 'F'
+ | | |
+ | | o 4: 'E'
+ | | |
+ | o | 3: 'D'
+ | |\|
+ | o | 2: 'C'
+ |/ /
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Rebase and collapse - E onto I:
+
+ $ hg clone -q -u . c c1
+ $ cd c1
+
+ $ hg rebase -s 4 --collapse # root (4) is not a merge
+ merging E
+ saved backup bundle to $TESTTMP/c1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 5: 'Collapsed revision
+ |\ * E
+ | | * F
+ | | * G
+ | | * H'
+ | o 4: 'I'
+ | |
+ o | 3: 'D'
+ |\ \
+ | o | 2: 'C'
+ | |/
+ o / 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg manifest
+ A
+ C
+ D
+ E
+ G
+ I
+
+ $ cat E
+ F
+
+ $ cd ..
+
+
+Create repo d:
+
+ $ hg init d
+ $ cd d
+
+ $ echo A > A
+ $ hg ci -Am A
+ adding A
+ $ echo B > B
+ $ hg ci -Am B
+ adding B
+ $ echo C > C
+ $ hg ci -Am C
+ adding C
+
+ $ hg up -q 1
+
+ $ echo D > D
+ $ hg ci -Am D
+ adding D
+ created new head
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg ci -m E
+
+ $ hg up -q 0
+
+ $ echo F > F
+ $ hg ci -Am F
+ adding F
+ created new head
+
+ $ hg tglog
+ @ 5: 'F'
+ |
+ | o 4: 'E'
+ | |\
+ | | o 3: 'D'
+ | | |
+ | o | 2: 'C'
+ | |/
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Rebase and collapse - B onto F:
+
+ $ hg clone -q -u . d d1
+ $ cd d1
+
+ $ hg rebase -s 1 --collapse
+ saved backup bundle to $TESTTMP/d1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 2: 'Collapsed revision
+ | * B
+ | * C
+ | * D
+ | * E'
+ o 1: 'F'
+ |
+ o 0: 'A'
+
+ $ hg manifest
+ A
+ B
+ C
+ D
+ F
+
+Interactions between collapse and keepbranches
+ $ cd ..
+ $ hg init e
+ $ cd e
+ $ echo 'a' > a
+ $ hg ci -Am 'A'
+ adding a
+
+ $ hg branch '1'
+ marked working directory as branch 1
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo 'b' > b
+ $ hg ci -Am 'B'
+ adding b
+
+ $ hg branch '2'
+ marked working directory as branch 2
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo 'c' > c
+ $ hg ci -Am 'C'
+ adding c
+
+ $ hg up -q 0
+ $ echo 'd' > d
+ $ hg ci -Am 'D'
+ adding d
+
+ $ hg tglog
+ @ 3: 'D'
+ |
+ | o 2: 'C' 2
+ | |
+ | o 1: 'B' 1
+ |/
+ o 0: 'A'
+
+ $ hg rebase --keepbranches --collapse -s 1 -d 3
+ abort: cannot collapse multiple named branches
+ [255]
+
+ $ repeatchange() {
+ > hg checkout $1
+ > hg cp d z
+ > echo blah >> z
+ > hg commit -Am "$2" --user "$3"
+ > }
+ $ repeatchange 3 "E" "user1"
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ repeatchange 3 "E" "user2"
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ created new head
+ $ hg tglog
+ @ 5: 'E'
+ |
+ | o 4: 'E'
+ |/
+ o 3: 'D'
+ |
+ | o 2: 'C' 2
+ | |
+ | o 1: 'B' 1
+ |/
+ o 0: 'A'
+
+ $ hg rebase -s 5 -d 4
+ saved backup bundle to $TESTTMP/e/.hg/strip-backup/*-backup.hg (glob)
+ $ hg tglog
+ @ 4: 'E'
+ |
+ o 3: 'D'
+ |
+ | o 2: 'C' 2
+ | |
+ | o 1: 'B' 1
+ |/
+ o 0: 'A'
+
+ $ hg export tip
+ # HG changeset patch
+ # User user1
+ # Date 0 0
+ # Node ID f338eb3c2c7cc5b5915676a2376ba7ac558c5213
+ # Parent 41acb9dca9eb976e84cd21fcb756b4afa5a35c09
+ E
+
+ diff -r 41acb9dca9eb -r f338eb3c2c7c z
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/z Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,2 @@
+ +d
+ +blah
+
+ $ cd ..
+
+Rebase, collapse and copies
+
+ $ hg init copies
+ $ cd copies
+ $ hg unbundle "$TESTDIR/bundles/renames.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 11 changes to 7 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up -q tip
+ $ hg tglog
+ @ 3: 'move2'
+ |
+ o 2: 'move1'
+ |
+ | o 1: 'change'
+ |/
+ o 0: 'add'
+
+ $ hg rebase --collapse -d 1
+ merging a and d to d
+ merging b and e to e
+ merging c and f to f
+ merging e and g to g
+ merging f and c to c
+ saved backup bundle to $TESTTMP/copies/.hg/strip-backup/*-backup.hg (glob)
+ $ hg st
+ $ hg st --copies --change .
+ A d
+ a
+ A g
+ b
+ R b
+ $ cat c
+ c
+ c
+ $ cat d
+ a
+ a
+ $ cat g
+ b
+ b
+ $ hg log -r . --template "{file_copies}\n"
+ d (a)g (b)
+
+Test collapsing a middle revision in-place
+
+ $ hg tglog
+ @ 2: 'Collapsed revision
+ | * move1
+ | * move2'
+ o 1: 'change'
+ |
+ o 0: 'add'
+
+ $ hg rebase --collapse -r 1 -d 0
+ abort: can't remove original changesets with unrebased descendants
+ (use --keep to keep original changesets)
+ [255]
+
+Test collapsing in place
+
+ $ hg rebase --collapse -b . -d 0
+ saved backup bundle to $TESTTMP/copies/.hg/strip-backup/*-backup.hg (glob)
+ $ hg st --change . --copies
+ M a
+ M c
+ A d
+ a
+ A g
+ b
+ R b
+ $ cat a
+ a
+ a
+ $ cat c
+ c
+ c
+ $ cat d
+ a
+ a
+ $ cat g
+ b
+ b
+ $ cd ..
+
+
+Test stripping a revision with another child
+
+ $ hg init f
+ $ cd f
+
+ $ echo A > A
+ $ hg ci -Am A
+ adding A
+ $ echo B > B
+ $ hg ci -Am B
+ adding B
+
+ $ hg up -q 0
+
+ $ echo C > C
+ $ hg ci -Am C
+ adding C
+ created new head
+
+ $ hg tglog
+ @ 2: 'C'
+ |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+
+
+ $ hg heads --template="{rev}:{node} {branch}: {desc}\n"
+ 2:c5cefa58fd557f84b72b87f970135984337acbc5 default: C
+ 1:27547f69f25460a52fff66ad004e58da7ad3fb56 default: B
+
+ $ hg strip 2
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/f/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ o 1: 'B'
+ |
+ @ 0: 'A'
+
+
+
+ $ hg heads --template="{rev}:{node} {branch}: {desc}\n"
+ 1:27547f69f25460a52fff66ad004e58da7ad3fb56 default: B
+
+ $ cd ..
+
+
+
+
diff --git a/tests/test-rebase-conflicts.t b/tests/test-rebase-conflicts.t
new file mode 100644
index 0000000..9d0a156
--- /dev/null
+++ b/tests/test-rebase-conflicts.t
@@ -0,0 +1,121 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}:{phase} '{desc}' {branches}\n"
+ > EOF
+
+ $ hg init a
+ $ cd a
+ $ echo c1 >common
+ $ hg add common
+ $ hg ci -m C1
+
+ $ echo c2 >>common
+ $ hg ci -m C2
+
+ $ echo c3 >>common
+ $ hg ci -m C3
+
+ $ hg up -q -C 1
+
+ $ echo l1 >>extra
+ $ hg add extra
+ $ hg ci -m L1
+ created new head
+
+ $ sed -e 's/c2/l2/' common > common.new
+ $ mv common.new common
+ $ hg ci -m L2
+
+ $ echo l3 >> extra2
+ $ hg add extra2
+ $ hg ci -m L3
+
+ $ hg phase --force --secret 4
+
+ $ hg tglog
+ @ 5:secret 'L3'
+ |
+ o 4:secret 'L2'
+ |
+ o 3:draft 'L1'
+ |
+ | o 2:draft 'C3'
+ |/
+ o 1:draft 'C2'
+ |
+ o 0:draft 'C1'
+
+Try to call --continue:
+
+ $ hg rebase --continue
+ abort: no rebase in progress
+ [255]
+
+Conflicting rebase:
+
+ $ hg rebase -s 3 -d 2
+ merging common
+ warning: conflicts during merge.
+ merging common incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+Try to continue without solving the conflict:
+
+ $ hg rebase --continue
+ abort: unresolved merge conflicts (see hg help resolve)
+ [255]
+
+Conclude rebase:
+
+ $ echo 'resolved merge' >common
+ $ hg resolve -m common
+ $ hg rebase --continue
+ saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 5:secret 'L3'
+ |
+ o 4:secret 'L2'
+ |
+ o 3:draft 'L1'
+ |
+ o 2:draft 'C3'
+ |
+ o 1:draft 'C2'
+ |
+ o 0:draft 'C1'
+
+Check correctness:
+
+ $ hg cat -r 0 common
+ c1
+
+ $ hg cat -r 1 common
+ c1
+ c2
+
+ $ hg cat -r 2 common
+ c1
+ c2
+ c3
+
+ $ hg cat -r 3 common
+ c1
+ c2
+ c3
+
+ $ hg cat -r 4 common
+ resolved merge
+
+ $ hg cat -r 5 common
+ resolved merge
+
+ $ cd ..
diff --git a/tests/test-rebase-detach.t b/tests/test-rebase-detach.t
new file mode 100644
index 0000000..cacc754
--- /dev/null
+++ b/tests/test-rebase-detach.t
@@ -0,0 +1,400 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
+ > EOF
+
+
+ $ hg init a
+ $ cd a
+ $ hg unbundle "$TESTDIR/bundles/rebase.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 8 changesets with 7 changes to 7 files (+2 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up tip
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd ..
+
+
+Rebasing D onto H detaching from C:
+
+ $ hg clone -q -u . a a1
+ $ cd a1
+
+ $ hg tglog
+ @ 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg phase --force --secret 3
+ $ hg rebase -s 3 -d 7
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
+ @ 7:secret 'D'
+ |
+ o 6:draft 'H'
+ |
+ | o 5:draft 'G'
+ |/|
+ o | 4:draft 'F'
+ | |
+ | o 3:draft 'E'
+ |/
+ | o 2:draft 'C'
+ | |
+ | o 1:draft 'B'
+ |/
+ o 0:draft 'A'
+
+ $ hg manifest
+ A
+ D
+ F
+ H
+
+ $ cd ..
+
+
+Rebasing C onto H detaching from B:
+
+ $ hg clone -q -u . a a2
+ $ cd a2
+
+ $ hg tglog
+ @ 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg rebase -s 2 -d 7
+ saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 7: 'D'
+ |
+ o 6: 'C'
+ |
+ o 5: 'H'
+ |
+ | o 4: 'G'
+ |/|
+ o | 3: 'F'
+ | |
+ | o 2: 'E'
+ |/
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg manifest
+ A
+ C
+ D
+ F
+ H
+
+ $ cd ..
+
+
+Rebasing B onto H using detach (same as not using it):
+
+ $ hg clone -q -u . a a3
+ $ cd a3
+
+ $ hg tglog
+ @ 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg rebase -s 1 -d 7
+ saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 7: 'D'
+ |
+ o 6: 'C'
+ |
+ o 5: 'B'
+ |
+ o 4: 'H'
+ |
+ | o 3: 'G'
+ |/|
+ o | 2: 'F'
+ | |
+ | o 1: 'E'
+ |/
+ o 0: 'A'
+
+ $ hg manifest
+ A
+ B
+ C
+ D
+ F
+ H
+
+ $ cd ..
+
+
+Rebasing C onto H detaching from B and collapsing:
+
+ $ hg clone -q -u . a a4
+ $ cd a4
+ $ hg phase --force --secret 3
+
+ $ hg tglog
+ @ 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg rebase --collapse -s 2 -d 7
+ saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
+ @ 6:secret 'Collapsed revision
+ | * C
+ | * D'
+ o 5:draft 'H'
+ |
+ | o 4:draft 'G'
+ |/|
+ o | 3:draft 'F'
+ | |
+ | o 2:draft 'E'
+ |/
+ | o 1:draft 'B'
+ |/
+ o 0:draft 'A'
+
+ $ hg manifest
+ A
+ C
+ D
+ F
+ H
+
+ $ cd ..
+
+Rebasing across null as ancestor
+ $ hg clone -q -U a a5
+
+ $ cd a5
+
+ $ echo x > x
+
+ $ hg add x
+
+ $ hg ci -m "extra branch"
+ created new head
+
+ $ hg tglog
+ @ 8: 'extra branch'
+
+ o 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg rebase -s 1 -d tip
+ saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ o 6: 'B'
+ |
+ o 5: 'extra branch'
+
+ o 4: 'H'
+ |
+ | o 3: 'G'
+ |/|
+ o | 2: 'F'
+ | |
+ | o 1: 'E'
+ |/
+ o 0: 'A'
+
+
+ $ hg rebase -d 5 -s 7
+ saved backup bundle to $TESTTMP/a5/.hg/strip-backup/13547172c9c0-backup.hg (glob)
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ | o 6: 'B'
+ |/
+ o 5: 'extra branch'
+
+ o 4: 'H'
+ |
+ | o 3: 'G'
+ |/|
+ o | 2: 'F'
+ | |
+ | o 1: 'E'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+Verify that target is not selected as external rev (issue3085)
+
+ $ hg clone -q -U a a6
+ $ cd a6
+ $ hg up -q 6
+
+ $ echo "I" >> E
+ $ hg ci -m "I"
+ $ hg merge 7
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m "Merge"
+ $ echo "J" >> F
+ $ hg ci -m "J"
+
+ $ hg rebase -s 8 -d 7 --collapse --config ui.merge=internal:other
+ remote changed E which local deleted
+ use (c)hanged version or leave (d)eleted? c
+ saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'Collapsed revision
+ | * I
+ | * Merge
+ | * J'
+ o 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+
+ $ hg parents
+ changeset: 8:9472f4b1d736
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Collapsed revision
+
+
+ $ cd ..
+
+Ensure --continue restores a correct state (issue3046) and phase:
+ $ hg clone -q a a7
+ $ cd a7
+ $ hg up -q 3
+ $ echo 'H2' > H
+ $ hg ci -A -m 'H2'
+ adding H
+ $ hg phase --force --secret 8
+ $ hg rebase -s 8 -d 7 --config ui.merge=internal:fail
+ merging H
+ warning: conflicts during merge.
+ merging H incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+ $ hg resolve --all -t internal:local
+ $ hg rebase -c
+ saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6215fafa5447-backup.hg (glob)
+ $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
+ @ 7:draft 'H'
+ |
+ | o 6:draft 'G'
+ |/|
+ o | 5:draft 'F'
+ | |
+ | o 4:draft 'E'
+ |/
+ | o 3:draft 'D'
+ | |
+ | o 2:draft 'C'
+ | |
+ | o 1:draft 'B'
+ |/
+ o 0:draft 'A'
+
+
+ $ cd ..
diff --git a/tests/test-rebase-interruptions.t b/tests/test-rebase-interruptions.t
new file mode 100644
index 0000000..28fd76e
--- /dev/null
+++ b/tests/test-rebase-interruptions.t
@@ -0,0 +1,268 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
+ > tglogp = log -G --template "{rev}:{phase} '{desc}' {branches}\n"
+ > EOF
+
+
+ $ hg init a
+ $ cd a
+
+ $ echo A > A
+ $ hg ci -Am A
+ adding A
+
+ $ echo B > B
+ $ hg ci -Am B
+ adding B
+
+ $ echo C >> A
+ $ hg ci -m C
+
+ $ hg up -q -C 0
+
+ $ echo D >> A
+ $ hg ci -m D
+ created new head
+
+ $ echo E > E
+ $ hg ci -Am E
+ adding E
+
+ $ cd ..
+
+
+Changes during an interruption - continue:
+
+ $ hg clone -q -u . a a1
+ $ cd a1
+
+ $ hg tglog
+ @ 4: 'E'
+ |
+ o 3: 'D'
+ |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+Rebasing B onto E:
+
+ $ hg rebase -s 1 -d 4
+ merging A
+ warning: conflicts during merge.
+ merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+Force a commit on C during the interruption:
+
+ $ hg up -q -C 2
+
+ $ echo 'Extra' > Extra
+ $ hg add Extra
+ $ hg ci -m 'Extra'
+
+Force this commit onto secret phase
+
+ $ hg phase --force --secret 6
+
+ $ hg tglogp
+ @ 6:secret 'Extra'
+ |
+ | o 5:draft 'B'
+ | |
+ | o 4:draft 'E'
+ | |
+ | o 3:draft 'D'
+ | |
+ o | 2:draft 'C'
+ | |
+ o | 1:draft 'B'
+ |/
+ o 0:draft 'A'
+
+Resume the rebasing:
+
+ $ hg rebase --continue
+ merging A
+ warning: conflicts during merge.
+ merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+Solve the conflict and go on:
+
+ $ echo 'conflict solved' > A
+ $ rm A.orig
+ $ hg resolve -m A
+
+ $ hg rebase --continue
+ warning: new changesets detected on source branch, not stripping
+
+ $ hg tglogp
+ @ 7:draft 'C'
+ |
+ | o 6:secret 'Extra'
+ | |
+ o | 5:draft 'B'
+ | |
+ o | 4:draft 'E'
+ | |
+ o | 3:draft 'D'
+ | |
+ | o 2:draft 'C'
+ | |
+ | o 1:draft 'B'
+ |/
+ o 0:draft 'A'
+
+ $ cd ..
+
+
+Changes during an interruption - abort:
+
+ $ hg clone -q -u . a a2
+ $ cd a2
+
+ $ hg tglog
+ @ 4: 'E'
+ |
+ o 3: 'D'
+ |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+Rebasing B onto E:
+
+ $ hg rebase -s 1 -d 4
+ merging A
+ warning: conflicts during merge.
+ merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+Force a commit on B' during the interruption:
+
+ $ hg up -q -C 5
+
+ $ echo 'Extra' > Extra
+ $ hg add Extra
+ $ hg ci -m 'Extra'
+
+ $ hg tglog
+ @ 6: 'Extra'
+ |
+ o 5: 'B'
+ |
+ o 4: 'E'
+ |
+ o 3: 'D'
+ |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+Abort the rebasing:
+
+ $ hg rebase --abort
+ warning: new changesets detected on target branch, can't abort
+ [255]
+
+ $ hg tglog
+ @ 6: 'Extra'
+ |
+ o 5: 'B'
+ |
+ o 4: 'E'
+ |
+ o 3: 'D'
+ |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+Changes during an interruption - abort (again):
+
+ $ hg clone -q -u . a a3
+ $ cd a3
+
+ $ hg tglogp
+ @ 4:draft 'E'
+ |
+ o 3:draft 'D'
+ |
+ | o 2:draft 'C'
+ | |
+ | o 1:draft 'B'
+ |/
+ o 0:draft 'A'
+
+Rebasing B onto E:
+
+ $ hg rebase -s 1 -d 4
+ merging A
+ warning: conflicts during merge.
+ merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+Change phase on B and B'
+
+ $ hg up -q -C 5
+ $ hg phase --public 1
+ $ hg phase --public 5
+ $ hg phase --secret -f 2
+
+ $ hg tglogp
+ @ 5:public 'B'
+ |
+ o 4:public 'E'
+ |
+ o 3:public 'D'
+ |
+ | o 2:secret 'C'
+ | |
+ | o 1:public 'B'
+ |/
+ o 0:public 'A'
+
+Abort the rebasing:
+
+ $ hg rebase --abort
+ abort: can't abort rebase due to immutable changesets 45396c49d53b
+ (see hg help phases for details)
+ [255]
+
+ $ hg tglogp
+ @ 5:public 'B'
+ |
+ o 4:public 'E'
+ |
+ o 3:public 'D'
+ |
+ | o 2:secret 'C'
+ | |
+ | o 1:public 'B'
+ |/
+ o 0:public 'A'
+
+ $ cd ..
diff --git a/tests/test-rebase-issue-noparam-single-rev.t b/tests/test-rebase-issue-noparam-single-rev.t
new file mode 100644
index 0000000..6e96ee7
--- /dev/null
+++ b/tests/test-rebase-issue-noparam-single-rev.t
@@ -0,0 +1,128 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
+ > EOF
+
+
+ $ hg init a
+ $ cd a
+
+ $ echo c1 > c1
+ $ hg ci -Am c1
+ adding c1
+
+ $ echo c2 > c2
+ $ hg ci -Am c2
+ adding c2
+
+ $ echo l1 > l1
+ $ hg ci -Am l1
+ adding l1
+
+ $ hg up -q -C 1
+
+ $ echo r1 > r1
+ $ hg ci -Am r1
+ adding r1
+ created new head
+
+ $ echo r2 > r2
+ $ hg ci -Am r2
+ adding r2
+
+ $ hg tglog
+ @ 4: 'r2'
+ |
+ o 3: 'r1'
+ |
+ | o 2: 'l1'
+ |/
+ o 1: 'c2'
+ |
+ o 0: 'c1'
+
+Rebase with no arguments - single revision in source branch:
+
+ $ hg up -q -C 2
+
+ $ hg rebase
+ saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 4: 'l1'
+ |
+ o 3: 'r2'
+ |
+ o 2: 'r1'
+ |
+ o 1: 'c2'
+ |
+ o 0: 'c1'
+
+ $ cd ..
+
+
+ $ hg init b
+ $ cd b
+
+ $ echo c1 > c1
+ $ hg ci -Am c1
+ adding c1
+
+ $ echo c2 > c2
+ $ hg ci -Am c2
+ adding c2
+
+ $ echo l1 > l1
+ $ hg ci -Am l1
+ adding l1
+
+ $ echo l2 > l2
+ $ hg ci -Am l2
+ adding l2
+
+ $ hg up -q -C 1
+
+ $ echo r1 > r1
+ $ hg ci -Am r1
+ adding r1
+ created new head
+
+ $ hg tglog
+ @ 4: 'r1'
+ |
+ | o 3: 'l2'
+ | |
+ | o 2: 'l1'
+ |/
+ o 1: 'c2'
+ |
+ o 0: 'c1'
+
+Rebase with no arguments - single revision in target branch:
+
+ $ hg up -q -C 3
+
+ $ hg rebase
+ saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 4: 'l2'
+ |
+ o 3: 'l1'
+ |
+ o 2: 'r1'
+ |
+ o 1: 'c2'
+ |
+ o 0: 'c1'
+
+
+ $ cd ..
diff --git a/tests/test-rebase-mq-skip.t b/tests/test-rebase-mq-skip.t
new file mode 100644
index 0000000..8d70458
--- /dev/null
+++ b/tests/test-rebase-mq-skip.t
@@ -0,0 +1,139 @@
+This emulates the effects of an hg pull --rebase in which the remote repo
+already has one local mq patch
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ > mq=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' tags: {tags}\n"
+ > EOF
+
+
+ $ hg init a
+ $ cd a
+ $ hg qinit -c
+
+ $ echo c1 > c1
+ $ hg add c1
+ $ hg ci -m C1
+
+ $ echo r1 > r1
+ $ hg add r1
+ $ hg ci -m R1
+
+ $ hg up -q 0
+
+ $ hg qnew p0.patch
+ $ echo p0 > p0
+ $ hg add p0
+ $ hg qref -m P0
+
+ $ hg qnew p1.patch
+ $ echo p1 > p1
+ $ hg add p1
+ $ hg qref -m P1
+
+ $ hg export qtip > p1.patch
+
+ $ hg up -q -C 1
+
+ $ hg import p1.patch
+ applying p1.patch
+
+ $ rm p1.patch
+
+ $ hg up -q -C qtip
+
+ $ hg rebase
+ saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 3: 'P0' tags: p0.patch qbase qtip tip
+ |
+ o 2: 'P1' tags: qparent
+ |
+ o 1: 'R1' tags:
+ |
+ o 0: 'C1' tags:
+
+ $ cd ..
+
+
+ $ hg init b
+ $ cd b
+ $ hg qinit -c
+
+ $ for i in r0 r1 r2 r3 r4 r5 r6;
+ > do
+ > echo $i > $i
+ > hg ci -Am $i
+ > done
+ adding r0
+ adding r1
+ adding r2
+ adding r3
+ adding r4
+ adding r5
+ adding r6
+
+ $ hg qimport -r 1:tip
+
+ $ hg up -q 0
+
+ $ for i in r1 r3 r7 r8;
+ > do
+ > echo $i > $i
+ > hg ci -Am branch2-$i
+ > done
+ adding r1
+ created new head
+ adding r3
+ adding r7
+ adding r8
+
+ $ echo somethingelse > r4
+ $ hg ci -Am branch2-r4
+ adding r4
+
+ $ echo r6 > r6
+ $ hg ci -Am branch2-r6
+ adding r6
+
+ $ hg up -q qtip
+
+ $ HGMERGE=internal:fail hg rebase
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+ $ HGMERGE=internal:local hg resolve --all
+
+ $ hg rebase --continue
+ saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'r5' tags: 5.diff qtip tip
+ |
+ o 7: 'r2' tags: 2.diff qbase
+ |
+ o 6: 'branch2-r6' tags: qparent
+ |
+ o 5: 'branch2-r4' tags:
+ |
+ o 4: 'branch2-r8' tags:
+ |
+ o 3: 'branch2-r7' tags:
+ |
+ o 2: 'branch2-r3' tags:
+ |
+ o 1: 'branch2-r1' tags:
+ |
+ o 0: 'r0' tags:
+
+
+ $ cd ..
diff --git a/tests/test-rebase-mq.t b/tests/test-rebase-mq.t
new file mode 100644
index 0000000..7301ebe
--- /dev/null
+++ b/tests/test-rebase-mq.t
@@ -0,0 +1,343 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ > mq=
+ >
+ > [mq]
+ > plain=true
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' tags: {tags}\n"
+ > EOF
+
+
+ $ hg init a
+ $ cd a
+ $ hg qinit -c
+
+ $ echo c1 > f
+ $ hg add f
+ $ hg ci -m C1
+
+ $ echo r1 > f
+ $ hg ci -m R1
+
+ $ hg up -q 0
+
+ $ hg qnew f.patch
+ $ echo mq1 > f
+ $ hg qref -m P0
+
+ $ hg qnew f2.patch
+ $ echo mq2 > f
+ $ hg qref -m P1
+
+ $ hg tglog
+ @ 3: 'P1' tags: f2.patch qtip tip
+ |
+ o 2: 'P0' tags: f.patch qbase
+ |
+ | o 1: 'R1' tags:
+ |/
+ o 0: 'C1' tags: qparent
+
+
+Rebase - try to rebase on an applied mq patch:
+
+ $ hg rebase -s 1 -d 3
+ abort: cannot rebase onto an applied mq patch
+ [255]
+
+Rebase - same thing, but mq patch is default dest:
+
+ $ hg up -q 1
+ $ hg rebase
+ abort: cannot rebase onto an applied mq patch
+ [255]
+ $ hg up -q qtip
+
+Rebase - generate a conflict:
+
+ $ hg rebase -s 2 -d 1
+ merging f
+ warning: conflicts during merge.
+ merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+Fix the 1st conflict:
+
+ $ echo mq1r1 > f
+ $ hg resolve -m f
+ $ hg rebase -c
+ merging f
+ warning: conflicts during merge.
+ merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+Fix the 2nd conflict:
+
+ $ echo mq1r1mq2 > f
+ $ hg resolve -m f
+ $ hg rebase -c
+ saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 3: 'P1' tags: f2.patch qtip tip
+ |
+ o 2: 'P0' tags: f.patch qbase
+ |
+ o 1: 'R1' tags: qparent
+ |
+ o 0: 'C1' tags:
+
+ $ hg up -q qbase
+
+ $ cat f
+ mq1r1
+
+ $ cat .hg/patches/f.patch
+ # HG changeset patch
+ # User test
+ # Date ?????????? ? (glob)
+ # Node ID ???????????????????????????????????????? (glob)
+ # Parent bac9ed9960d8992bcad75864a879fa76cadaf1b0
+ P0
+
+ diff -r bac9ed9960d8 -r ???????????? f (glob)
+ --- a/f Thu Jan 01 00:00:00 1970 +0000
+ +++ b/f ??? ??? ?? ??:??:?? ???? ????? (glob)
+ @@ -1,1 +1,1 @@
+ -r1
+ +mq1r1
+
+Update to qtip:
+
+ $ hg up -q qtip
+
+ $ cat f
+ mq1r1mq2
+
+ $ cat .hg/patches/f2.patch
+ # HG changeset patch
+ # User test
+ # Date ?????????? ? (glob)
+ # Node ID ???????????????????????????????????????? (glob)
+ # Parent ???????????????????????????????????????? (glob)
+ P1
+
+ diff -r ???????????? -r ???????????? f (glob)
+ --- a/f ??? ??? ?? ??:??:?? ???? ????? (glob)
+ +++ b/f ??? ??? ?? ??:??:?? ???? ????? (glob)
+ @@ -1,1 +1,1 @@
+ -mq1r1
+ +mq1r1mq2
+
+Adding one git-style patch and one normal:
+
+ $ hg qpop -a
+ popping f2.patch
+ popping f.patch
+ patch queue now empty
+
+ $ rm -fr .hg/patches
+ $ hg qinit -c
+
+ $ hg up -q 0
+
+ $ hg qnew --git f_git.patch
+ $ echo mq1 > p
+ $ hg add p
+ $ hg qref --git -m 'P0 (git)'
+
+ $ hg qnew f.patch
+ $ echo mq2 > p
+ $ hg qref -m P1
+ $ hg qci -m 'save patch state'
+
+ $ hg qseries -s
+ f_git.patch: P0 (git)
+ f.patch: P1
+
+ $ hg -R .hg/patches manifest
+ .hgignore
+ f.patch
+ f_git.patch
+ series
+
+ $ cat .hg/patches/f_git.patch
+ P0 (git)
+
+ diff --git a/p b/p
+ new file mode 100644
+ --- /dev/null
+ +++ b/p
+ @@ -0,0 +1,1 @@
+ +mq1
+
+ $ cat .hg/patches/f.patch
+ P1
+
+ diff -r ???????????? p (glob)
+ --- a/p ??? ??? ?? ??:??:?? ???? ????? (glob)
+ +++ b/p ??? ??? ?? ??:??:?? ???? ????? (glob)
+ @@ -1,1 +1,1 @@
+ -mq1
+ +mq2
+
+
+Rebase the applied mq patches:
+
+ $ hg rebase -s 2 -d 1
+ saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg qci -m 'save patch state'
+
+ $ hg qseries -s
+ f_git.patch: P0 (git)
+ f.patch: P1
+
+ $ hg -R .hg/patches manifest
+ .hgignore
+ f.patch
+ f_git.patch
+ series
+
+ $ cat .hg/patches/f_git.patch
+ # HG changeset patch
+ # User test
+ # Date ?????????? ? (glob)
+ # Node ID ???????????????????????????????????????? (glob)
+ # Parent bac9ed9960d8992bcad75864a879fa76cadaf1b0
+ P0 (git)
+
+ diff --git a/p b/p
+ new file mode 100644
+ --- /dev/null
+ +++ b/p
+ @@ -0,0 +1,1 @@
+ +mq1
+
+ $ cat .hg/patches/f.patch
+ # HG changeset patch
+ # User test
+ # Date ?????????? ? (glob)
+ # Node ID ???????????????????????????????????????? (glob)
+ # Parent ???????????????????????????????????????? (glob)
+ P1
+
+ diff -r ???????????? -r ???????????? p (glob)
+ --- a/p ??? ??? ?? ??:??:?? ???? ????? (glob)
+ +++ b/p ??? ??? ?? ??:??:?? ???? ????? (glob)
+ @@ -1,1 +1,1 @@
+ -mq1
+ +mq2
+
+ $ cd ..
+
+Rebase with guards
+
+ $ hg init foo
+ $ cd foo
+ $ echo a > a
+ $ hg ci -Am a
+ adding a
+
+Create mq repo with guarded patches foo and bar and empty patch:
+
+ $ hg qinit
+ $ echo guarded > guarded
+ $ hg add guarded
+ $ hg qnew guarded
+ $ hg qnew empty-important -m 'important commit message'
+ $ echo bar > bar
+ $ hg add bar
+ $ hg qnew bar
+ $ echo foo > foo
+ $ hg add foo
+ $ hg qnew foo
+ $ hg qpop -a
+ popping foo
+ popping bar
+ popping empty-important
+ popping guarded
+ patch queue now empty
+ $ hg qguard guarded +guarded
+ $ hg qguard bar +baz
+ $ hg qguard foo +baz
+ $ hg qselect baz
+ number of unguarded, unapplied patches has changed from 1 to 3
+ $ hg qpush bar
+ applying empty-important
+ patch empty-important is empty
+ applying bar
+ now at: bar
+
+ $ hg qguard -l
+ guarded: +guarded
+ empty-important: unguarded
+ bar: +baz
+ foo: +baz
+
+ $ hg tglog
+ @ 2: 'imported patch bar' tags: bar qtip tip
+ |
+ o 1: 'important commit message' tags: empty-important qbase
+ |
+ o 0: 'a' tags: qparent
+
+Create new head to rebase bar onto:
+
+ $ hg up -C 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo b > b
+ $ hg add b
+ $ hg ci -m b
+ created new head
+ $ hg up -C 2
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo a >> a
+ $ hg qref
+
+ $ hg tglog
+ @ 3: '[mq]: bar' tags: bar qtip tip
+ |
+ | o 2: 'b' tags:
+ | |
+ o | 1: 'important commit message' tags: empty-important qbase
+ |/
+ o 0: 'a' tags: qparent
+
+
+Rebase bar (make sure series order is preserved and empty-important also is
+removed from the series):
+
+ $ hg qseries
+ guarded
+ empty-important
+ bar
+ foo
+ $ [ -f .hg/patches/empty-important ]
+ $ hg -q rebase -d 2
+ $ hg qseries
+ guarded
+ bar
+ foo
+ $ [ -f .hg/patches/empty-important ]
+ [1]
+
+ $ hg qguard -l
+ guarded: +guarded
+ bar: +baz
+ foo: +baz
+
+ $ hg tglog
+ @ 2:* '[mq]: bar' tags: bar qbase qtip tip (glob)
+ |
+ o 1:* 'b' tags: qparent (glob)
+ |
+ o 0:* 'a' tags: (glob)
+
+ $ cd ..
diff --git a/tests/test-rebase-named-branches.t b/tests/test-rebase-named-branches.t
new file mode 100644
index 0000000..0f2f904
--- /dev/null
+++ b/tests/test-rebase-named-branches.t
@@ -0,0 +1,243 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
+ > EOF
+
+ $ hg init a
+ $ cd a
+ $ hg unbundle "$TESTDIR/bundles/rebase.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 8 changesets with 7 changes to 7 files (+2 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up tip
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+
+ $ hg clone -q -u . a a1
+
+ $ cd a1
+
+ $ hg update 3
+ 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg branch dev-one
+ marked working directory as branch dev-one
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m 'dev-one named branch'
+
+ $ hg update 7
+ 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ hg branch dev-two
+ marked working directory as branch dev-two
+ (branches are permanent and global, did you want a bookmark?)
+
+ $ echo x > x
+
+ $ hg add x
+
+ $ hg ci -m 'dev-two named branch'
+
+ $ hg tglog
+ @ 9: 'dev-two named branch' dev-two
+ |
+ | o 8: 'dev-one named branch' dev-one
+ | |
+ o | 7: 'H'
+ | |
+ +---o 6: 'G'
+ | | |
+ o | | 5: 'F'
+ | | |
+ +---o 4: 'E'
+ | |
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+
+Branch name containing a dash (issue3181)
+
+ $ hg rebase -b dev-two -d dev-one --keepbranches
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 9: 'dev-two named branch' dev-two
+ |
+ o 8: 'H'
+ |
+ | o 7: 'G'
+ |/|
+ o | 6: 'F'
+ | |
+ o | 5: 'dev-one named branch' dev-one
+ | |
+ | o 4: 'E'
+ | |
+ o | 3: 'D'
+ | |
+ o | 2: 'C'
+ | |
+ o | 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg rebase -s dev-one -d 0 --keepbranches
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'dev-two named branch' dev-two
+ |
+ o 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg update 3
+ 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ hg branch dev-one
+ marked working directory as branch dev-one
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m 'dev-one named branch'
+
+ $ hg tglog
+ @ 9: 'dev-one named branch' dev-one
+ |
+ | o 8: 'dev-two named branch' dev-two
+ | |
+ | o 7: 'H'
+ | |
+ | | o 6: 'G'
+ | |/|
+ | o | 5: 'F'
+ | | |
+ | | o 4: 'E'
+ | |/
+ o | 3: 'D'
+ | |
+ o | 2: 'C'
+ | |
+ o | 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg rebase -b 'max(branch("dev-two"))' -d dev-one --keepbranches
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 9: 'dev-two named branch' dev-two
+ |
+ o 8: 'H'
+ |
+ | o 7: 'G'
+ |/|
+ o | 6: 'F'
+ | |
+ o | 5: 'dev-one named branch' dev-one
+ | |
+ | o 4: 'E'
+ | |
+ o | 3: 'D'
+ | |
+ o | 2: 'C'
+ | |
+ o | 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg rebase -s 'max(branch("dev-one"))' -d 0 --keepbranches
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'dev-two named branch' dev-two
+ |
+ o 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+
+Rebasing descendant onto ancestor across different named branches
+
+ $ hg rebase -s 1 -d 8 --keepbranches
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ o 6: 'B'
+ |
+ o 5: 'dev-two named branch' dev-two
+ |
+ o 4: 'H'
+ |
+ | o 3: 'G'
+ |/|
+ o | 2: 'F'
+ | |
+ | o 1: 'E'
+ |/
+ o 0: 'A'
+
+ $ hg rebase -s 4 -d 5
+ abort: source is ancestor of destination
+ [255]
+
+ $ hg rebase -s 5 -d 4
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ o 6: 'B'
+ |
+ o 5: 'dev-two named branch'
+ |
+ o 4: 'H'
+ |
+ | o 3: 'G'
+ |/|
+ o | 2: 'F'
+ | |
+ | o 1: 'E'
+ |/
+ o 0: 'A'
+
+ $ cd ..
diff --git a/tests/test-rebase-newancestor.t b/tests/test-rebase-newancestor.t
new file mode 100644
index 0000000..949c5d2
--- /dev/null
+++ b/tests/test-rebase-newancestor.t
@@ -0,0 +1,56 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
+ > EOF
+
+ $ hg init repo
+ $ cd repo
+
+ $ echo A > a
+ $ echo >> a
+ $ hg ci -Am A
+ adding a
+
+ $ echo B > a
+ $ echo >> a
+ $ hg ci -m B
+
+ $ echo C > a
+ $ echo >> a
+ $ hg ci -m C
+
+ $ hg up -q -C 0
+
+ $ echo D >> a
+ $ hg ci -Am AD
+ created new head
+
+ $ hg tglog
+ @ 3: 'AD'
+ |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ hg rebase -s 1 -d 3
+ merging a
+ merging a
+ saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 3: 'C'
+ |
+ o 2: 'B'
+ |
+ o 1: 'AD'
+ |
+ o 0: 'A'
+
+
+ $ cd ..
diff --git a/tests/test-rebase-parameters.t b/tests/test-rebase-parameters.t
new file mode 100644
index 0000000..6597f75
--- /dev/null
+++ b/tests/test-rebase-parameters.t
@@ -0,0 +1,430 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
+ > EOF
+
+
+ $ hg init a
+ $ cd a
+ $ hg unbundle "$TESTDIR/bundles/rebase.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 8 changesets with 7 changes to 7 files (+2 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up tip
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ echo I > I
+ $ hg ci -AmI
+ adding I
+
+ $ hg tglog
+ @ 8: 'I'
+ |
+ o 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+These fail:
+
+ $ hg clone -q -u . a a1
+ $ cd a1
+
+ $ hg rebase -s 8 -d 7
+ nothing to rebase
+ [1]
+
+ $ hg rebase --continue --abort
+ abort: cannot use both abort and continue
+ [255]
+
+ $ hg rebase --continue --collapse
+ abort: cannot use collapse with continue or abort
+ [255]
+
+ $ hg rebase --continue --dest 4
+ abort: abort and continue do not allow specifying revisions
+ [255]
+
+ $ hg rebase --base 5 --source 4
+ abort: cannot specify both a source and a base
+ [255]
+
+ $ hg rebase --rev 5 --source 4
+ abort: cannot specify both a revision and a source
+ [255]
+ $ hg rebase --base 5 --rev 4
+ abort: cannot specify both a revision and a base
+ [255]
+
+ $ hg rebase
+ nothing to rebase
+ [1]
+
+ $ hg up -q 7
+
+ $ hg rebase --traceback
+ nothing to rebase
+ [1]
+
+
+These work:
+
+Rebase with no arguments (from 3 onto 8):
+
+ $ hg up -q -C 3
+
+ $ hg rebase
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ o 6: 'B'
+ |
+ o 5: 'I'
+ |
+ o 4: 'H'
+ |
+ | o 3: 'G'
+ |/|
+ o | 2: 'F'
+ | |
+ | o 1: 'E'
+ |/
+ o 0: 'A'
+
+Try to rollback after a rebase (fail):
+
+ $ hg rollback
+ no rollback information available
+ [1]
+
+ $ cd ..
+
+
+Rebase with base == '.' => same as no arguments (from 3 onto 8):
+
+ $ hg clone -q -u 3 a a2
+ $ cd a2
+
+ $ hg rebase --base .
+ saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ o 6: 'B'
+ |
+ o 5: 'I'
+ |
+ o 4: 'H'
+ |
+ | o 3: 'G'
+ |/|
+ o | 2: 'F'
+ | |
+ | o 1: 'E'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Rebase with dest == branch(.) => same as no arguments (from 3 onto 8):
+
+ $ hg clone -q -u 3 a a3
+ $ cd a3
+
+ $ hg rebase --dest 'branch(.)'
+ saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ o 6: 'B'
+ |
+ o 5: 'I'
+ |
+ o 4: 'H'
+ |
+ | o 3: 'G'
+ |/|
+ o | 2: 'F'
+ | |
+ | o 1: 'E'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Specify only source (from 2 onto 8):
+
+ $ hg clone -q -u . a a4
+ $ cd a4
+
+ $ hg rebase --source 'desc("C")'
+ saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ o 6: 'I'
+ |
+ o 5: 'H'
+ |
+ | o 4: 'G'
+ |/|
+ o | 3: 'F'
+ | |
+ | o 2: 'E'
+ |/
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Specify only dest (from 3 onto 6):
+
+ $ hg clone -q -u 3 a a5
+ $ cd a5
+
+ $ hg rebase --dest 6
+ saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ o 6: 'B'
+ |
+ | o 5: 'I'
+ | |
+ | o 4: 'H'
+ | |
+ o | 3: 'G'
+ |\|
+ | o 2: 'F'
+ | |
+ o | 1: 'E'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Specify only base (from 1 onto 8):
+
+ $ hg clone -q -u . a a6
+ $ cd a6
+
+ $ hg rebase --base 'desc("D")'
+ saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ o 6: 'B'
+ |
+ o 5: 'I'
+ |
+ o 4: 'H'
+ |
+ | o 3: 'G'
+ |/|
+ o | 2: 'F'
+ | |
+ | o 1: 'E'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Specify source and dest (from 2 onto 7):
+
+ $ hg clone -q -u . a a7
+ $ cd a7
+
+ $ hg rebase --source 2 --dest 7
+ saved backup bundle to $TESTTMP/a7/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ | o 6: 'I'
+ |/
+ o 5: 'H'
+ |
+ | o 4: 'G'
+ |/|
+ o | 3: 'F'
+ | |
+ | o 2: 'E'
+ |/
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Specify base and dest (from 1 onto 7):
+
+ $ hg clone -q -u . a a8
+ $ cd a8
+
+ $ hg rebase --base 3 --dest 7
+ saved backup bundle to $TESTTMP/a8/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ o 6: 'B'
+ |
+ | o 5: 'I'
+ |/
+ o 4: 'H'
+ |
+ | o 3: 'G'
+ |/|
+ o | 2: 'F'
+ | |
+ | o 1: 'E'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Specify only revs (from 2 onto 8)
+
+ $ hg clone -q -u . a a9
+ $ cd a9
+
+ $ hg rebase --rev 'desc("C")::'
+ saved backup bundle to $TESTTMP/a9/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 8: 'D'
+ |
+ o 7: 'C'
+ |
+ o 6: 'I'
+ |
+ o 5: 'H'
+ |
+ | o 4: 'G'
+ |/|
+ o | 3: 'F'
+ | |
+ | o 2: 'E'
+ |/
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+Test --tool parameter:
+
+ $ hg init b
+ $ cd b
+
+ $ echo c1 > c1
+ $ hg ci -Am c1
+ adding c1
+
+ $ echo c2 > c2
+ $ hg ci -Am c2
+ adding c2
+
+ $ hg up -q 0
+ $ echo c2b > c2
+ $ hg ci -Am c2b
+ adding c2
+ created new head
+
+ $ cd ..
+
+ $ hg clone -q -u . b b1
+ $ cd b1
+
+ $ hg rebase -s 2 -d 1 --tool internal:local
+ saved backup bundle to $TESTTMP/b1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg cat c2
+ c2
+
+ $ cd ..
+
+
+ $ hg clone -q -u . b b2
+ $ cd b2
+
+ $ hg rebase -s 2 -d 1 --tool internal:other
+ saved backup bundle to $TESTTMP/b2/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg cat c2
+ c2b
+
+ $ cd ..
+
+
+ $ hg clone -q -u . b b3
+ $ cd b3
+
+ $ hg rebase -s 2 -d 1 --tool internal:fail
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+
+ $ hg resolve -l
+ U c2
+
+ $ hg resolve -m c2
+ $ hg rebase -c --tool internal:fail
+ tool option will be ignored
+ saved backup bundle to $TESTTMP/b3/.hg/strip-backup/*-backup.hg (glob)
+
+ $ cd ..
diff --git a/tests/test-rebase-pull.t b/tests/test-rebase-pull.t
new file mode 100644
index 0000000..07388d5
--- /dev/null
+++ b/tests/test-rebase-pull.t
@@ -0,0 +1,116 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
+ > EOF
+
+
+ $ hg init a
+ $ cd a
+
+ $ echo C1 > C1
+ $ hg ci -Am C1
+ adding C1
+
+ $ echo C2 > C2
+ $ hg ci -Am C2
+ adding C2
+
+ $ cd ..
+
+ $ hg clone a b
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg clone a c
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd b
+
+ $ echo L1 > L1
+ $ hg ci -Am L1
+ adding L1
+
+
+ $ cd ../a
+
+ $ echo R1 > R1
+ $ hg ci -Am R1
+ adding R1
+
+
+ $ cd ../b
+
+Now b has one revision to be pulled from a:
+
+ $ hg pull --rebase
+ pulling from $TESTTMP/a (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 3: 'L1'
+ |
+ o 2: 'R1'
+ |
+ o 1: 'C2'
+ |
+ o 0: 'C1'
+
+Re-run:
+
+ $ hg pull --rebase
+ pulling from $TESTTMP/a (glob)
+ searching for changes
+ no changes found
+
+
+Invoke pull --rebase and nothing to rebase:
+
+ $ cd ../c
+
+ $ hg book norebase
+ $ hg pull --rebase
+ pulling from $TESTTMP/a (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ nothing to rebase
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ updating bookmark norebase
+
+ $ hg tglog -l 1
+ @ 2: 'R1'
+ |
+
+pull --rebase --update should ignore --update:
+
+ $ hg pull --rebase --update
+ pulling from $TESTTMP/a (glob)
+ searching for changes
+ no changes found
+
+pull --rebase doesn't update if nothing has been pulled:
+
+ $ hg up -q 1
+
+ $ hg pull --rebase
+ pulling from $TESTTMP/a (glob)
+ searching for changes
+ no changes found
+
+ $ hg tglog -l 1
+ o 2: 'R1'
+ |
+
+ $ cd ..
diff --git a/tests/test-rebase-rename.t b/tests/test-rebase-rename.t
new file mode 100644
index 0000000..c46f7c7
--- /dev/null
+++ b/tests/test-rebase-rename.t
@@ -0,0 +1,171 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [alias]
+ > tlog = log --template "{rev}: '{desc}' {branches}\n"
+ > tglog = tlog --graph
+ > EOF
+
+
+ $ hg init a
+ $ cd a
+
+ $ echo a > a
+ $ hg ci -Am A
+ adding a
+
+ $ echo b > b
+ $ hg ci -Am B
+ adding b
+
+ $ hg up -q -C 0
+
+ $ hg mv a a-renamed
+
+ $ hg ci -m 'rename A'
+ created new head
+
+ $ hg tglog
+ @ 2: 'rename A'
+ |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+
+Rename is tracked:
+
+ $ hg tlog -p --git -r tip
+ 2: 'rename A'
+ diff --git a/a b/a-renamed
+ rename from a
+ rename to a-renamed
+
+Rebase the revision containing the rename:
+
+ $ hg rebase -s 2 -d 1
+ saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 2: 'rename A'
+ |
+ o 1: 'B'
+ |
+ o 0: 'A'
+
+
+Rename is not lost:
+
+ $ hg tlog -p --git -r tip
+ 2: 'rename A'
+ diff --git a/a b/a-renamed
+ rename from a
+ rename to a-renamed
+
+ $ cd ..
+
+
+ $ hg init b
+ $ cd b
+
+ $ echo a > a
+ $ hg ci -Am A
+ adding a
+
+ $ echo b > b
+ $ hg ci -Am B
+ adding b
+
+ $ hg up -q -C 0
+
+ $ hg cp a a-copied
+ $ hg ci -m 'copy A'
+ created new head
+
+ $ hg tglog
+ @ 2: 'copy A'
+ |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+Copy is tracked:
+
+ $ hg tlog -p --git -r tip
+ 2: 'copy A'
+ diff --git a/a b/a-copied
+ copy from a
+ copy to a-copied
+
+Rebase the revision containing the copy:
+
+ $ hg rebase -s 2 -d 1
+ saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 2: 'copy A'
+ |
+ o 1: 'B'
+ |
+ o 0: 'A'
+
+Copy is not lost:
+
+ $ hg tlog -p --git -r tip
+ 2: 'copy A'
+ diff --git a/a b/a-copied
+ copy from a
+ copy to a-copied
+
+ $ cd ..
+
+
+Test rebase across repeating renames:
+
+ $ hg init repo
+
+ $ cd repo
+
+ $ echo testing > file1.txt
+ $ hg add file1.txt
+ $ hg ci -m "Adding file1"
+
+ $ hg rename file1.txt file2.txt
+ $ hg ci -m "Rename file1 to file2"
+
+ $ echo Unrelated change > unrelated.txt
+ $ hg add unrelated.txt
+ $ hg ci -m "Unrelated change"
+
+ $ hg rename file2.txt file1.txt
+ $ hg ci -m "Rename file2 back to file1"
+
+ $ hg update -r -2
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ echo Another unrelated change >> unrelated.txt
+ $ hg ci -m "Another unrelated change"
+ created new head
+
+ $ hg tglog
+ @ 4: 'Another unrelated change'
+ |
+ | o 3: 'Rename file2 back to file1'
+ |/
+ o 2: 'Unrelated change'
+ |
+ o 1: 'Rename file1 to file2'
+ |
+ o 0: 'Adding file1'
+
+
+ $ hg rebase -s 4 -d 3
+ saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg diff --stat -c .
+ unrelated.txt | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+ $ cd ..
diff --git a/tests/test-rebase-scenario-global.t b/tests/test-rebase-scenario-global.t
new file mode 100644
index 0000000..7cb6e8d
--- /dev/null
+++ b/tests/test-rebase-scenario-global.t
@@ -0,0 +1,547 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ > rebase=
+ >
+ > [phases]
+ > publish=False
+ >
+ > [alias]
+ > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
+ > EOF
+
+
+ $ hg init a
+ $ cd a
+ $ hg unbundle "$TESTDIR/bundles/rebase.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 8 changesets with 7 changes to 7 files (+2 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up tip
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+
+
+Rebasing
+D onto H - simple rebase:
+
+ $ hg clone -q -u . a a1
+ $ cd a1
+
+ $ hg tglog
+ @ 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+
+ $ hg rebase -s 3 -d 7
+ saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 7: 'D'
+ |
+ o 6: 'H'
+ |
+ | o 5: 'G'
+ |/|
+ o | 4: 'F'
+ | |
+ | o 3: 'E'
+ |/
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+D onto F - intermediate point:
+
+ $ hg clone -q -u . a a2
+ $ cd a2
+
+ $ hg rebase -s 3 -d 5
+ saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 7: 'D'
+ |
+ | o 6: 'H'
+ |/
+ | o 5: 'G'
+ |/|
+ o | 4: 'F'
+ | |
+ | o 3: 'E'
+ |/
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+E onto H - skip of G:
+
+ $ hg clone -q -u . a a3
+ $ cd a3
+
+ $ hg rebase -s 4 -d 7
+ saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 6: 'E'
+ |
+ o 5: 'H'
+ |
+ o 4: 'F'
+ |
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+F onto E - rebase of a branching point (skip G):
+
+ $ hg clone -q -u . a a4
+ $ cd a4
+
+ $ hg rebase -s 5 -d 4
+ saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 6: 'H'
+ |
+ o 5: 'F'
+ |
+ o 4: 'E'
+ |
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+G onto H - merged revision having a parent in ancestors of target:
+
+ $ hg clone -q -u . a a5
+ $ cd a5
+
+ $ hg rebase -s 6 -d 7
+ saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 7: 'G'
+ |\
+ | o 6: 'H'
+ | |
+ | o 5: 'F'
+ | |
+ o | 4: 'E'
+ |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+F onto B - G maintains E as parent:
+
+ $ hg clone -q -u . a a6
+ $ cd a6
+
+ $ hg rebase -s 5 -d 1
+ saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
+
+ $ hg tglog
+ @ 7: 'H'
+ |
+ | o 6: 'G'
+ |/|
+ o | 5: 'F'
+ | |
+ | o 4: 'E'
+ | |
+ | | o 3: 'D'
+ | | |
+ +---o 2: 'C'
+ | |
+ o | 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+These will fail (using --source):
+
+G onto F - rebase onto an ancestor:
+
+ $ hg clone -q -u . a a7
+ $ cd a7
+
+ $ hg rebase -s 6 -d 5
+ nothing to rebase
+ [1]
+
+F onto G - rebase onto a descendant:
+
+ $ hg rebase -s 5 -d 6
+ abort: source is ancestor of destination
+ [255]
+
+G onto B - merge revision with both parents not in ancestors of target:
+
+ $ hg rebase -s 6 -d 1
+ abort: cannot use revision 6 as base, result would have 3 parents
+ [255]
+
+
+These will abort gracefully (using --base):
+
+G onto G - rebase onto same changeset:
+
+ $ hg rebase -b 6 -d 6
+ nothing to rebase
+ [1]
+
+G onto F - rebase onto an ancestor:
+
+ $ hg rebase -b 6 -d 5
+ nothing to rebase
+ [1]
+
+F onto G - rebase onto a descendant:
+
+ $ hg rebase -b 5 -d 6
+ nothing to rebase
+ [1]
+
+C onto A - rebase onto an ancestor:
+
+ $ hg rebase -d 0 -s 2
+ saved backup bundle to $TESTTMP/a7/.hg/strip-backup/5fddd98957c8-backup.hg (glob)
+ $ hg tglog
+ @ 7: 'D'
+ |
+ o 6: 'C'
+ |
+ | o 5: 'H'
+ | |
+ | | o 4: 'G'
+ | |/|
+ | o | 3: 'F'
+ |/ /
+ | o 2: 'E'
+ |/
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+
+Check rebasing public changeset
+
+ $ hg pull --config phases.publish=True -q -r 6 . # update phase of 6
+ $ hg rebase -d 5 -b 6
+ abort: can't rebase immutable changeset e1c4361dd923
+ (see hg help phases for details)
+ [255]
+
+ $ hg rebase -d 5 -b 6 --keep
+
+Check rebasing mutable changeset
+Source phase greater or equal to destination phase: new changeset get the phase of source:
+ $ hg rebase -s9 -d0
+ saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2b23e52411f4-backup.hg (glob)
+ $ hg log --template "{phase}\n" -r 9
+ draft
+ $ hg rebase -s9 -d1
+ saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2cb10d0cfc6c-backup.hg (glob)
+ $ hg log --template "{phase}\n" -r 9
+ draft
+ $ hg phase --force --secret 9
+ $ hg rebase -s9 -d0
+ saved backup bundle to $TESTTMP/a7/.hg/strip-backup/c5b12b67163a-backup.hg (glob)
+ $ hg log --template "{phase}\n" -r 9
+ secret
+ $ hg rebase -s9 -d1
+ saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2a0524f868ac-backup.hg (glob)
+ $ hg log --template "{phase}\n" -r 9
+ secret
+Source phase lower than destination phase: new changeset get the phase of destination:
+ $ hg rebase -s8 -d9
+ saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6d4f22462821-backup.hg (glob)
+ $ hg log --template "{phase}\n" -r 'rev(9)'
+ secret
+
+ $ cd ..
+
+Test for revset
+
+We need a bit different graph
+All destination are B
+
+ $ hg init ah
+ $ cd ah
+ $ hg unbundle "$TESTDIR/bundles/rebase-revset.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 9 changes to 9 files (+2 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg tglog
+ o 8: 'I'
+ |
+ o 7: 'H'
+ |
+ o 6: 'G'
+ |
+ | o 5: 'F'
+ | |
+ | o 4: 'E'
+ |/
+ o 3: 'D'
+ |
+ o 2: 'C'
+ |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+Simple case with keep:
+
+Source on have two descendant heads but ask for one
+
+ $ hg clone -q -u . ah ah1
+ $ cd ah1
+ $ hg rebase -r '2::8' -d 1
+ abort: can't remove original changesets with unrebased descendants
+ (use --keep to keep original changesets)
+ [255]
+ $ hg rebase -r '2::8' -d 1 --keep
+ $ hg tglog
+ @ 13: 'I'
+ |
+ o 12: 'H'
+ |
+ o 11: 'G'
+ |
+ o 10: 'D'
+ |
+ o 9: 'C'
+ |
+ | o 8: 'I'
+ | |
+ | o 7: 'H'
+ | |
+ | o 6: 'G'
+ | |
+ | | o 5: 'F'
+ | | |
+ | | o 4: 'E'
+ | |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ o | 1: 'B'
+ |/
+ o 0: 'A'
+
+
+ $ cd ..
+
+Base on have one descendant heads we ask for but common ancestor have two
+
+ $ hg clone -q -u . ah ah2
+ $ cd ah2
+ $ hg rebase -r '3::8' -d 1
+ abort: can't remove original changesets with unrebased descendants
+ (use --keep to keep original changesets)
+ [255]
+ $ hg rebase -r '3::8' -d 1 --keep
+ $ hg tglog
+ @ 12: 'I'
+ |
+ o 11: 'H'
+ |
+ o 10: 'G'
+ |
+ o 9: 'D'
+ |
+ | o 8: 'I'
+ | |
+ | o 7: 'H'
+ | |
+ | o 6: 'G'
+ | |
+ | | o 5: 'F'
+ | | |
+ | | o 4: 'E'
+ | |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ o | 1: 'B'
+ |/
+ o 0: 'A'
+
+
+ $ cd ..
+
+rebase subset
+
+ $ hg clone -q -u . ah ah3
+ $ cd ah3
+ $ hg rebase -r '3::7' -d 1
+ abort: can't remove original changesets with unrebased descendants
+ (use --keep to keep original changesets)
+ [255]
+ $ hg rebase -r '3::7' -d 1 --keep
+ $ hg tglog
+ @ 11: 'H'
+ |
+ o 10: 'G'
+ |
+ o 9: 'D'
+ |
+ | o 8: 'I'
+ | |
+ | o 7: 'H'
+ | |
+ | o 6: 'G'
+ | |
+ | | o 5: 'F'
+ | | |
+ | | o 4: 'E'
+ | |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ o | 1: 'B'
+ |/
+ o 0: 'A'
+
+
+ $ cd ..
+
+rebase subset with multiple head
+
+ $ hg clone -q -u . ah ah4
+ $ cd ah4
+ $ hg rebase -r '3::(7+5)' -d 1
+ abort: can't remove original changesets with unrebased descendants
+ (use --keep to keep original changesets)
+ [255]
+ $ hg rebase -r '3::(7+5)' -d 1 --keep
+ $ hg tglog
+ @ 13: 'H'
+ |
+ o 12: 'G'
+ |
+ | o 11: 'F'
+ | |
+ | o 10: 'E'
+ |/
+ o 9: 'D'
+ |
+ | o 8: 'I'
+ | |
+ | o 7: 'H'
+ | |
+ | o 6: 'G'
+ | |
+ | | o 5: 'F'
+ | | |
+ | | o 4: 'E'
+ | |/
+ | o 3: 'D'
+ | |
+ | o 2: 'C'
+ | |
+ o | 1: 'B'
+ |/
+ o 0: 'A'
+
+
+ $ cd ..
+
+More advanced tests
+
+rebase on ancestor with revset
+
+ $ hg clone -q -u . ah ah5
+ $ cd ah5
+ $ hg rebase -r '6::' -d 2
+ saved backup bundle to $TESTTMP/ah5/.hg/strip-backup/3d8a618087a7-backup.hg (glob)
+ $ hg tglog
+ @ 8: 'I'
+ |
+ o 7: 'H'
+ |
+ o 6: 'G'
+ |
+ | o 5: 'F'
+ | |
+ | o 4: 'E'
+ | |
+ | o 3: 'D'
+ |/
+ o 2: 'C'
+ |
+ | o 1: 'B'
+ |/
+ o 0: 'A'
+
+ $ cd ..
+
+
+rebase with multiple root.
+We rebase E and G on B
+We would expect heads are I, F if it was supported
+
+ $ hg clone -q -u . ah ah6
+ $ cd ah6
+ $ hg rebase -r '(4+6)::' -d 1
+ abort: can't rebase multiple roots
+ [255]
+ $ cd ..
diff --git a/tests/test-rebuildstate.t b/tests/test-rebuildstate.t
new file mode 100644
index 0000000..954d343
--- /dev/null
+++ b/tests/test-rebuildstate.t
@@ -0,0 +1,30 @@
+basic test for hg debugrebuildstate
+
+ $ hg init repo
+ $ cd repo
+
+ $ touch foo bar
+ $ hg ci -Am 'add foo bar'
+ adding bar
+ adding foo
+
+ $ touch baz
+ $ hg add baz
+ $ hg rm bar
+
+ $ hg debugrebuildstate
+
+state dump after
+
+ $ hg debugstate --nodates | sort
+ n 644 -1 bar
+ n 644 -1 foo
+
+status
+
+ $ hg st -A
+ ! bar
+ ? baz
+ C foo
+
+ $ cd ..
diff --git a/tests/test-record.t b/tests/test-record.t
new file mode 100644
index 0000000..833b290
--- /dev/null
+++ b/tests/test-record.t
@@ -0,0 +1,1221 @@
+Set up a repo
+
+ $ echo "[ui]" >> $HGRCPATH
+ $ echo "interactive=true" >> $HGRCPATH
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "record=" >> $HGRCPATH
+
+ $ hg init a
+ $ cd a
+
+Select no files
+
+ $ touch empty-rw
+ $ hg add empty-rw
+
+ $ hg record empty-rw<<EOF
+ > n
+ > EOF
+ diff --git a/empty-rw b/empty-rw
+ new file mode 100644
+ examine changes to 'empty-rw'? [Ynesfdaq?]
+ no changes to record
+
+ $ hg tip -p
+ changeset: -1:000000000000
+ tag: tip
+ user:
+ date: Thu Jan 01 00:00:00 1970 +0000
+
+
+
+Select files but no hunks
+
+ $ hg record empty-rw<<EOF
+ > y
+ > n
+ > EOF
+ diff --git a/empty-rw b/empty-rw
+ new file mode 100644
+ examine changes to 'empty-rw'? [Ynesfdaq?]
+ abort: empty commit message
+ [255]
+
+ $ hg tip -p
+ changeset: -1:000000000000
+ tag: tip
+ user:
+ date: Thu Jan 01 00:00:00 1970 +0000
+
+
+
+Record empty file
+
+ $ hg record -d '0 0' -m empty empty-rw<<EOF
+ > y
+ > y
+ > EOF
+ diff --git a/empty-rw b/empty-rw
+ new file mode 100644
+ examine changes to 'empty-rw'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 0:c0708cf4e46e
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: empty
+
+
+
+Summary shows we updated to the new cset
+
+ $ hg summary
+ parent: 0:c0708cf4e46e tip
+ empty
+ branch: default
+ commit: (clean)
+ update: (current)
+
+Rename empty file
+
+ $ hg mv empty-rw empty-rename
+ $ hg record -d '1 0' -m rename<<EOF
+ > y
+ > EOF
+ diff --git a/empty-rw b/empty-rename
+ rename from empty-rw
+ rename to empty-rename
+ examine changes to 'empty-rw' and 'empty-rename'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 1:d695e8dcb197
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: rename
+
+
+
+Copy empty file
+
+ $ hg cp empty-rename empty-copy
+ $ hg record -d '2 0' -m copy<<EOF
+ > y
+ > EOF
+ diff --git a/empty-rename b/empty-copy
+ copy from empty-rename
+ copy to empty-copy
+ examine changes to 'empty-rename' and 'empty-copy'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 2:1d4b90bea524
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: copy
+
+
+
+Delete empty file
+
+ $ hg rm empty-copy
+ $ hg record -d '3 0' -m delete<<EOF
+ > y
+ > EOF
+ diff --git a/empty-copy b/empty-copy
+ deleted file mode 100644
+ examine changes to 'empty-copy'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 3:b39a238f01a1
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:03 1970 +0000
+ summary: delete
+
+
+
+Add binary file
+
+ $ hg bundle --base -2 tip.bundle
+ 1 changesets found
+ $ hg add tip.bundle
+ $ hg record -d '4 0' -m binary<<EOF
+ > y
+ > EOF
+ diff --git a/tip.bundle b/tip.bundle
+ new file mode 100644
+ this is a binary file
+ examine changes to 'tip.bundle'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 4:ad816da3711e
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:04 1970 +0000
+ summary: binary
+
+ diff -r b39a238f01a1 -r ad816da3711e tip.bundle
+ Binary file tip.bundle has changed
+
+
+Change binary file
+
+ $ hg bundle --base -2 tip.bundle
+ 1 changesets found
+ $ hg record -d '5 0' -m binary-change<<EOF
+ > y
+ > EOF
+ diff --git a/tip.bundle b/tip.bundle
+ this modifies a binary file (all or nothing)
+ examine changes to 'tip.bundle'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 5:dccd6f3eb485
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ summary: binary-change
+
+ diff -r ad816da3711e -r dccd6f3eb485 tip.bundle
+ Binary file tip.bundle has changed
+
+
+Rename and change binary file
+
+ $ hg mv tip.bundle top.bundle
+ $ hg bundle --base -2 top.bundle
+ 1 changesets found
+ $ hg record -d '6 0' -m binary-change-rename<<EOF
+ > y
+ > EOF
+ diff --git a/tip.bundle b/top.bundle
+ rename from tip.bundle
+ rename to top.bundle
+ this modifies a binary file (all or nothing)
+ examine changes to 'tip.bundle' and 'top.bundle'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 6:7fa44105f5b3
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: binary-change-rename
+
+ diff -r dccd6f3eb485 -r 7fa44105f5b3 tip.bundle
+ Binary file tip.bundle has changed
+ diff -r dccd6f3eb485 -r 7fa44105f5b3 top.bundle
+ Binary file top.bundle has changed
+
+
+Add plain file
+
+ $ for i in 1 2 3 4 5 6 7 8 9 10; do
+ > echo $i >> plain
+ > done
+
+ $ hg add plain
+ $ hg record -d '7 0' -m plain plain<<EOF
+ > y
+ > y
+ > EOF
+ diff --git a/plain b/plain
+ new file mode 100644
+ examine changes to 'plain'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 7:11fb457c1be4
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:07 1970 +0000
+ summary: plain
+
+ diff -r 7fa44105f5b3 -r 11fb457c1be4 plain
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/plain Thu Jan 01 00:00:07 1970 +0000
+ @@ -0,0 +1,10 @@
+ +1
+ +2
+ +3
+ +4
+ +5
+ +6
+ +7
+ +8
+ +9
+ +10
+
+
+Modify end of plain file
+
+ $ echo 11 >> plain
+ $ hg record -d '8 0' -m end plain <<EOF
+ > y
+ > y
+ > EOF
+ diff --git a/plain b/plain
+ 1 hunks, 1 lines changed
+ examine changes to 'plain'? [Ynesfdaq?]
+ @@ -8,3 +8,4 @@
+ 8
+ 9
+ 10
+ +11
+ record this change to 'plain'? [Ynesfdaq?]
+
+Modify end of plain file, no EOL
+
+ $ hg tip --template '{node}' >> plain
+ $ hg record -d '9 0' -m noeol plain <<EOF
+ > y
+ > y
+ > EOF
+ diff --git a/plain b/plain
+ 1 hunks, 1 lines changed
+ examine changes to 'plain'? [Ynesfdaq?]
+ @@ -9,3 +9,4 @@
+ 9
+ 10
+ 11
+ +7264f99c5f5ff3261504828afa4fb4d406c3af54
+ \ No newline at end of file
+ record this change to 'plain'? [Ynesfdaq?]
+
+Modify end of plain file, add EOL
+
+ $ echo >> plain
+ $ echo 1 > plain2
+ $ hg add plain2
+ $ hg record -d '10 0' -m eol plain plain2 <<EOF
+ > y
+ > y
+ > y
+ > EOF
+ diff --git a/plain b/plain
+ 1 hunks, 1 lines changed
+ examine changes to 'plain'? [Ynesfdaq?]
+ @@ -9,4 +9,4 @@
+ 9
+ 10
+ 11
+ -7264f99c5f5ff3261504828afa4fb4d406c3af54
+ \ No newline at end of file
+ +7264f99c5f5ff3261504828afa4fb4d406c3af54
+ record change 1/2 to 'plain'? [Ynesfdaq?]
+ diff --git a/plain2 b/plain2
+ new file mode 100644
+ examine changes to 'plain2'? [Ynesfdaq?]
+
+Modify beginning, trim end, record both, add another file to test
+changes numbering
+
+ $ rm plain
+ $ for i in 2 2 3 4 5 6 7 8 9 10; do
+ > echo $i >> plain
+ > done
+ $ echo 2 >> plain2
+
+ $ hg record -d '10 0' -m begin-and-end plain plain2 <<EOF
+ > y
+ > y
+ > y
+ > y
+ > y
+ > EOF
+ diff --git a/plain b/plain
+ 2 hunks, 3 lines changed
+ examine changes to 'plain'? [Ynesfdaq?]
+ @@ -1,4 +1,4 @@
+ -1
+ +2
+ 2
+ 3
+ 4
+ record change 1/3 to 'plain'? [Ynesfdaq?]
+ @@ -8,5 +8,3 @@
+ 8
+ 9
+ 10
+ -11
+ -7264f99c5f5ff3261504828afa4fb4d406c3af54
+ record change 2/3 to 'plain'? [Ynesfdaq?]
+ diff --git a/plain2 b/plain2
+ 1 hunks, 1 lines changed
+ examine changes to 'plain2'? [Ynesfdaq?]
+ @@ -1,1 +1,2 @@
+ 1
+ +2
+ record change 3/3 to 'plain2'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 11:21df83db12b8
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:10 1970 +0000
+ summary: begin-and-end
+
+ diff -r ddb8b281c3ff -r 21df83db12b8 plain
+ --- a/plain Thu Jan 01 00:00:10 1970 +0000
+ +++ b/plain Thu Jan 01 00:00:10 1970 +0000
+ @@ -1,4 +1,4 @@
+ -1
+ +2
+ 2
+ 3
+ 4
+ @@ -8,5 +8,3 @@
+ 8
+ 9
+ 10
+ -11
+ -7264f99c5f5ff3261504828afa4fb4d406c3af54
+ diff -r ddb8b281c3ff -r 21df83db12b8 plain2
+ --- a/plain2 Thu Jan 01 00:00:10 1970 +0000
+ +++ b/plain2 Thu Jan 01 00:00:10 1970 +0000
+ @@ -1,1 +1,2 @@
+ 1
+ +2
+
+
+Trim beginning, modify end
+
+ $ rm plain
+ > for i in 4 5 6 7 8 9 10.new; do
+ > echo $i >> plain
+ > done
+
+Record end
+
+ $ hg record -d '11 0' -m end-only plain <<EOF
+ > y
+ > n
+ > y
+ > EOF
+ diff --git a/plain b/plain
+ 2 hunks, 4 lines changed
+ examine changes to 'plain'? [Ynesfdaq?]
+ @@ -1,9 +1,6 @@
+ -2
+ -2
+ -3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ record change 1/2 to 'plain'? [Ynesfdaq?]
+ @@ -4,7 +1,7 @@
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ -10
+ +10.new
+ record change 2/2 to 'plain'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 12:99337501826f
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:11 1970 +0000
+ summary: end-only
+
+ diff -r 21df83db12b8 -r 99337501826f plain
+ --- a/plain Thu Jan 01 00:00:10 1970 +0000
+ +++ b/plain Thu Jan 01 00:00:11 1970 +0000
+ @@ -7,4 +7,4 @@
+ 7
+ 8
+ 9
+ -10
+ +10.new
+
+
+Record beginning
+
+ $ hg record -d '12 0' -m begin-only plain <<EOF
+ > y
+ > y
+ > EOF
+ diff --git a/plain b/plain
+ 1 hunks, 3 lines changed
+ examine changes to 'plain'? [Ynesfdaq?]
+ @@ -1,6 +1,3 @@
+ -2
+ -2
+ -3
+ 4
+ 5
+ 6
+ record this change to 'plain'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 13:bbd45465d540
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:12 1970 +0000
+ summary: begin-only
+
+ diff -r 99337501826f -r bbd45465d540 plain
+ --- a/plain Thu Jan 01 00:00:11 1970 +0000
+ +++ b/plain Thu Jan 01 00:00:12 1970 +0000
+ @@ -1,6 +1,3 @@
+ -2
+ -2
+ -3
+ 4
+ 5
+ 6
+
+
+Add to beginning, trim from end
+
+ $ rm plain
+ $ for i in 1 2 3 4 5 6 7 8 9; do
+ > echo $i >> plain
+ > done
+
+Record end
+
+ $ hg record --traceback -d '13 0' -m end-again plain<<EOF
+ > y
+ > n
+ > y
+ > EOF
+ diff --git a/plain b/plain
+ 2 hunks, 4 lines changed
+ examine changes to 'plain'? [Ynesfdaq?]
+ @@ -1,6 +1,9 @@
+ +1
+ +2
+ +3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ record change 1/2 to 'plain'? [Ynesfdaq?]
+ @@ -1,7 +4,6 @@
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ -10.new
+ record change 2/2 to 'plain'? [Ynesfdaq?]
+
+Add to beginning, middle, end
+
+ $ rm plain
+ $ for i in 1 2 3 4 5 5.new 5.reallynew 6 7 8 9 10 11; do
+ > echo $i >> plain
+ > done
+
+Record beginning, middle
+
+ $ hg record -d '14 0' -m middle-only plain <<EOF
+ > y
+ > y
+ > y
+ > n
+ > EOF
+ diff --git a/plain b/plain
+ 3 hunks, 7 lines changed
+ examine changes to 'plain'? [Ynesfdaq?]
+ @@ -1,2 +1,5 @@
+ +1
+ +2
+ +3
+ 4
+ 5
+ record change 1/3 to 'plain'? [Ynesfdaq?]
+ @@ -1,6 +4,8 @@
+ 4
+ 5
+ +5.new
+ +5.reallynew
+ 6
+ 7
+ 8
+ 9
+ record change 2/3 to 'plain'? [Ynesfdaq?]
+ @@ -3,4 +8,6 @@
+ 6
+ 7
+ 8
+ 9
+ +10
+ +11
+ record change 3/3 to 'plain'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 15:f34a7937ec33
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:14 1970 +0000
+ summary: middle-only
+
+ diff -r 82c065d0b850 -r f34a7937ec33 plain
+ --- a/plain Thu Jan 01 00:00:13 1970 +0000
+ +++ b/plain Thu Jan 01 00:00:14 1970 +0000
+ @@ -1,5 +1,10 @@
+ +1
+ +2
+ +3
+ 4
+ 5
+ +5.new
+ +5.reallynew
+ 6
+ 7
+ 8
+
+
+Record end
+
+ $ hg record -d '15 0' -m end-only plain <<EOF
+ > y
+ > y
+ > EOF
+ diff --git a/plain b/plain
+ 1 hunks, 2 lines changed
+ examine changes to 'plain'? [Ynesfdaq?]
+ @@ -9,3 +9,5 @@
+ 7
+ 8
+ 9
+ +10
+ +11
+ record this change to 'plain'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 16:f9900b71a04c
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:15 1970 +0000
+ summary: end-only
+
+ diff -r f34a7937ec33 -r f9900b71a04c plain
+ --- a/plain Thu Jan 01 00:00:14 1970 +0000
+ +++ b/plain Thu Jan 01 00:00:15 1970 +0000
+ @@ -9,3 +9,5 @@
+ 7
+ 8
+ 9
+ +10
+ +11
+
+
+ $ mkdir subdir
+ $ cd subdir
+ $ echo a > a
+ $ hg ci -d '16 0' -Amsubdir
+ adding subdir/a
+
+ $ echo a >> a
+ $ hg record -d '16 0' -m subdir-change a <<EOF
+ > y
+ > y
+ > EOF
+ diff --git a/subdir/a b/subdir/a
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/a'? [Ynesfdaq?]
+ @@ -1,1 +1,2 @@
+ a
+ +a
+ record this change to 'subdir/a'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 18:61be427a9deb
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:16 1970 +0000
+ summary: subdir-change
+
+ diff -r a7ffae4d61cb -r 61be427a9deb subdir/a
+ --- a/subdir/a Thu Jan 01 00:00:16 1970 +0000
+ +++ b/subdir/a Thu Jan 01 00:00:16 1970 +0000
+ @@ -1,1 +1,2 @@
+ a
+ +a
+
+
+ $ echo a > f1
+ $ echo b > f2
+ $ hg add f1 f2
+
+ $ hg ci -mz -d '17 0'
+
+ $ echo a >> f1
+ $ echo b >> f2
+
+Help, quit
+
+ $ hg record <<EOF
+ > ?
+ > q
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ y - record this change
+ n - skip this change
+ e - edit this change manually
+ s - skip remaining changes to this file
+ f - record remaining changes to this file
+ d - done, skip remaining changes and files
+ a - record all changes to all remaining files
+ q - quit, recording no changes
+ ? - display help
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ abort: user quit
+ [255]
+
+Skip
+
+ $ hg record <<EOF
+ > s
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ diff --git a/subdir/f2 b/subdir/f2
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f2'? [Ynesfdaq?] abort: response expected
+ [255]
+
+No
+
+ $ hg record <<EOF
+ > n
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ diff --git a/subdir/f2 b/subdir/f2
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f2'? [Ynesfdaq?] abort: response expected
+ [255]
+
+f, quit
+
+ $ hg record <<EOF
+ > f
+ > q
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ diff --git a/subdir/f2 b/subdir/f2
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f2'? [Ynesfdaq?]
+ abort: user quit
+ [255]
+
+s, all
+
+ $ hg record -d '18 0' -mx <<EOF
+ > s
+ > a
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ diff --git a/subdir/f2 b/subdir/f2
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f2'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 20:b3df3dda369a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:18 1970 +0000
+ summary: x
+
+ diff -r 6e02d6c9906d -r b3df3dda369a subdir/f2
+ --- a/subdir/f2 Thu Jan 01 00:00:17 1970 +0000
+ +++ b/subdir/f2 Thu Jan 01 00:00:18 1970 +0000
+ @@ -1,1 +1,2 @@
+ b
+ +b
+
+
+f
+
+ $ hg record -d '19 0' -my <<EOF
+ > f
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 21:38ec577f126b
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:19 1970 +0000
+ summary: y
+
+ diff -r b3df3dda369a -r 38ec577f126b subdir/f1
+ --- a/subdir/f1 Thu Jan 01 00:00:18 1970 +0000
+ +++ b/subdir/f1 Thu Jan 01 00:00:19 1970 +0000
+ @@ -1,1 +1,2 @@
+ a
+ +a
+
+
+#if execbit
+
+Preserve chmod +x
+
+ $ chmod +x f1
+ $ echo a >> f1
+ $ hg record -d '20 0' -mz <<EOF
+ > y
+ > y
+ > y
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ old mode 100644
+ new mode 100755
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ @@ -1,2 +1,3 @@
+ a
+ a
+ +a
+ record this change to 'subdir/f1'? [Ynesfdaq?]
+
+ $ hg tip --config diff.git=True -p
+ changeset: 22:3261adceb075
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:20 1970 +0000
+ summary: z
+
+ diff --git a/subdir/f1 b/subdir/f1
+ old mode 100644
+ new mode 100755
+ --- a/subdir/f1
+ +++ b/subdir/f1
+ @@ -1,2 +1,3 @@
+ a
+ a
+ +a
+
+
+Preserve execute permission on original
+
+ $ echo b >> f1
+ $ hg record -d '21 0' -maa <<EOF
+ > y
+ > y
+ > y
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ @@ -1,3 +1,4 @@
+ a
+ a
+ a
+ +b
+ record this change to 'subdir/f1'? [Ynesfdaq?]
+
+ $ hg tip --config diff.git=True -p
+ changeset: 23:b429867550db
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:21 1970 +0000
+ summary: aa
+
+ diff --git a/subdir/f1 b/subdir/f1
+ --- a/subdir/f1
+ +++ b/subdir/f1
+ @@ -1,3 +1,4 @@
+ a
+ a
+ a
+ +b
+
+
+Preserve chmod -x
+
+ $ chmod -x f1
+ $ echo c >> f1
+ $ hg record -d '22 0' -mab <<EOF
+ > y
+ > y
+ > y
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ old mode 100755
+ new mode 100644
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ @@ -2,3 +2,4 @@
+ a
+ a
+ b
+ +c
+ record this change to 'subdir/f1'? [Ynesfdaq?]
+
+ $ hg tip --config diff.git=True -p
+ changeset: 24:0b082130c20a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:22 1970 +0000
+ summary: ab
+
+ diff --git a/subdir/f1 b/subdir/f1
+ old mode 100755
+ new mode 100644
+ --- a/subdir/f1
+ +++ b/subdir/f1
+ @@ -2,3 +2,4 @@
+ a
+ a
+ b
+ +c
+
+
+#else
+
+Slightly bogus tests to get almost same repo structure as when x bit is used
+- but with different hashes.
+
+Mock "Preserve chmod +x"
+
+ $ echo a >> f1
+ $ hg record -d '20 0' -mz <<EOF
+ > y
+ > y
+ > y
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ @@ -1,2 +1,3 @@
+ a
+ a
+ +a
+ record this change to 'subdir/f1'? [Ynesfdaq?]
+
+ $ hg tip --config diff.git=True -p
+ changeset: 22:0d463bd428f5
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:20 1970 +0000
+ summary: z
+
+ diff --git a/subdir/f1 b/subdir/f1
+ --- a/subdir/f1
+ +++ b/subdir/f1
+ @@ -1,2 +1,3 @@
+ a
+ a
+ +a
+
+
+Mock "Preserve execute permission on original"
+
+ $ echo b >> f1
+ $ hg record -d '21 0' -maa <<EOF
+ > y
+ > y
+ > y
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ @@ -1,3 +1,4 @@
+ a
+ a
+ a
+ +b
+ record this change to 'subdir/f1'? [Ynesfdaq?]
+
+ $ hg tip --config diff.git=True -p
+ changeset: 23:0eab41a3e524
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:21 1970 +0000
+ summary: aa
+
+ diff --git a/subdir/f1 b/subdir/f1
+ --- a/subdir/f1
+ +++ b/subdir/f1
+ @@ -1,3 +1,4 @@
+ a
+ a
+ a
+ +b
+
+
+Mock "Preserve chmod -x"
+
+ $ chmod -x f1
+ $ echo c >> f1
+ $ hg record -d '22 0' -mab <<EOF
+ > y
+ > y
+ > y
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ @@ -2,3 +2,4 @@
+ a
+ a
+ b
+ +c
+ record this change to 'subdir/f1'? [Ynesfdaq?]
+
+ $ hg tip --config diff.git=True -p
+ changeset: 24:f4f718f27b7c
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:22 1970 +0000
+ summary: ab
+
+ diff --git a/subdir/f1 b/subdir/f1
+ --- a/subdir/f1
+ +++ b/subdir/f1
+ @@ -2,3 +2,4 @@
+ a
+ a
+ b
+ +c
+
+
+#endif
+
+ $ cd ..
+
+
+Abort early when a merge is in progress
+
+ $ hg up 4
+ 1 files updated, 0 files merged, 6 files removed, 0 files unresolved
+
+ $ touch iwillmergethat
+ $ hg add iwillmergethat
+
+ $ hg branch thatbranch
+ marked working directory as branch thatbranch
+ (branches are permanent and global, did you want a bookmark?)
+
+ $ hg ci -m'new head'
+
+ $ hg up default
+ 6 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+ $ hg merge thatbranch
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg record -m'will abort'
+ abort: cannot partially commit a merge (use "hg commit" instead)
+ [255]
+
+ $ hg up -C
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+Editing patch
+
+ $ cat > editor.sh << '__EOF__'
+ > sed -e 7d -e '5s/^-/ /' "$1" > tmp
+ > mv tmp "$1"
+ > __EOF__
+ $ cat > editedfile << '__EOF__'
+ > This is the first line
+ > This is the second line
+ > This is the third line
+ > __EOF__
+ $ hg add editedfile
+ $ hg commit -medit-patch-1
+ $ cat > editedfile << '__EOF__'
+ > This line has changed
+ > This change will be committed
+ > This is the third line
+ > __EOF__
+ $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg record -d '23 0' -medit-patch-2 <<EOF
+ > y
+ > e
+ > EOF
+ diff --git a/editedfile b/editedfile
+ 1 hunks, 2 lines changed
+ examine changes to 'editedfile'? [Ynesfdaq?]
+ @@ -1,3 +1,3 @@
+ -This is the first line
+ -This is the second line
+ +This line has changed
+ +This change will be committed
+ This is the third line
+ record this change to 'editedfile'? [Ynesfdaq?]
+ $ cat editedfile
+ This line has changed
+ This change will be committed
+ This is the third line
+ $ hg cat -r tip editedfile
+ This is the first line
+ This change will be committed
+ This is the third line
+ $ hg revert editedfile
+
+Trying to edit patch for whole file
+
+ $ echo "This is the fourth line" >> editedfile
+ $ hg record <<EOF
+ > e
+ > q
+ > EOF
+ diff --git a/editedfile b/editedfile
+ 1 hunks, 1 lines changed
+ examine changes to 'editedfile'? [Ynesfdaq?]
+ cannot edit patch for whole file
+ examine changes to 'editedfile'? [Ynesfdaq?]
+ abort: user quit
+ [255]
+ $ hg revert editedfile
+
+Removing changes from patch
+
+ $ sed -e '3s/third/second/' -e '2s/will/will not/' -e 1d editedfile > tmp
+ $ mv tmp editedfile
+ $ echo "This line has been added" >> editedfile
+ $ cat > editor.sh << '__EOF__'
+ > sed -e 's/^[-+]/ /' "$1" > tmp
+ > mv tmp "$1"
+ > __EOF__
+ $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg record <<EOF
+ > y
+ > e
+ > EOF
+ diff --git a/editedfile b/editedfile
+ 1 hunks, 3 lines changed
+ examine changes to 'editedfile'? [Ynesfdaq?]
+ @@ -1,3 +1,3 @@
+ -This is the first line
+ -This change will be committed
+ -This is the third line
+ +This change will not be committed
+ +This is the second line
+ +This line has been added
+ record this change to 'editedfile'? [Ynesfdaq?]
+ no changes to record
+ $ cat editedfile
+ This change will not be committed
+ This is the second line
+ This line has been added
+ $ hg cat -r tip editedfile
+ This is the first line
+ This change will be committed
+ This is the third line
+ $ hg revert editedfile
+
+Invalid patch
+
+ $ sed -e '3s/third/second/' -e '2s/will/will not/' -e 1d editedfile > tmp
+ $ mv tmp editedfile
+ $ echo "This line has been added" >> editedfile
+ $ cat > editor.sh << '__EOF__'
+ > sed s/This/That/ "$1" > tmp
+ > mv tmp "$1"
+ > __EOF__
+ $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg record <<EOF
+ > y
+ > e
+ > EOF
+ diff --git a/editedfile b/editedfile
+ 1 hunks, 3 lines changed
+ examine changes to 'editedfile'? [Ynesfdaq?]
+ @@ -1,3 +1,3 @@
+ -This is the first line
+ -This change will be committed
+ -This is the third line
+ +This change will not be committed
+ +This is the second line
+ +This line has been added
+ record this change to 'editedfile'? [Ynesfdaq?]
+ patching file editedfile
+ Hunk #1 FAILED at 0
+ 1 out of 1 hunks FAILED -- saving rejects to file editedfile.rej
+ abort: patch failed to apply
+ [255]
+ $ cat editedfile
+ This change will not be committed
+ This is the second line
+ This line has been added
+ $ hg cat -r tip editedfile
+ This is the first line
+ This change will be committed
+ This is the third line
+ $ cat editedfile.rej
+ --- editedfile
+ +++ editedfile
+ @@ -1,3 +1,3 @@
+ -That is the first line
+ -That change will be committed
+ -That is the third line
+ +That change will not be committed
+ +That is the second line
+ +That line has been added
+ $ hg up -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+With win32text
+
+ $ echo '[extensions]' >> .hg/hgrc
+ $ echo 'win32text = ' >> .hg/hgrc
+ $ echo '[decode]' >> .hg/hgrc
+ $ echo '** = cleverdecode:' >> .hg/hgrc
+ $ echo '[encode]' >> .hg/hgrc
+ $ echo '** = cleverencode:' >> .hg/hgrc
+ $ echo '[patch]' >> .hg/hgrc
+ $ echo 'eol = crlf' >> .hg/hgrc
+
+Ignore win32text deprecation warning for now:
+
+ $ echo '[win32text]' >> .hg/hgrc
+ $ echo 'warn = no' >> .hg/hgrc
+
+ $ echo d >> subdir/f1
+ $ hg record -d '24 0' -mw1 <<EOF
+ > y
+ > y
+ > EOF
+ diff --git a/subdir/f1 b/subdir/f1
+ 1 hunks, 1 lines changed
+ examine changes to 'subdir/f1'? [Ynesfdaq?]
+ @@ -3,3 +3,4 @@
+ a
+ b
+ c
+ +d
+ record this change to 'subdir/f1'? [Ynesfdaq?]
+
+ $ hg tip -p
+ changeset: 28:* (glob)
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:24 1970 +0000
+ summary: w1
+
+ diff -r ???????????? -r ???????????? subdir/f1 (glob)
+ --- a/subdir/f1 Thu Jan 01 00:00:23 1970 +0000
+ +++ b/subdir/f1 Thu Jan 01 00:00:24 1970 +0000
+ @@ -3,3 +3,4 @@
+ a
+ b
+ c
+ +d
+
+
+ $ cd ..
diff --git a/tests/test-relink.t b/tests/test-relink.t
new file mode 100644
index 0000000..2b0bc2b
--- /dev/null
+++ b/tests/test-relink.t
@@ -0,0 +1,100 @@
+ $ "$TESTDIR/hghave" hardlink || exit 80
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "relink=" >> $HGRCPATH
+
+ $ fix_path() {
+ > tr '\\' /
+ > }
+
+ $ cat > arelinked.py <<EOF
+ > import sys, os
+ > from mercurial import util
+ > path1, path2 = sys.argv[1:3]
+ > if util.samefile(path1, path2):
+ > print '%s == %s' % (path1, path2)
+ > else:
+ > print '%s != %s' % (path1, path2)
+ > EOF
+
+
+create source repository
+
+ $ hg init repo
+ $ cd repo
+ $ echo a > a
+ $ echo b > b
+ $ hg ci -Am addfile
+ adding a
+ adding b
+ $ cat "$TESTDIR/binfile.bin" >> a
+ $ cat "$TESTDIR/binfile.bin" >> b
+ $ hg ci -Am changefiles
+
+make another commit to create files larger than 1 KB to test
+formatting of final byte count
+
+ $ cat "$TESTDIR/binfile.bin" >> a
+ $ cat "$TESTDIR/binfile.bin" >> b
+ $ hg ci -m anotherchange
+
+don't sit forever trying to double-lock the source repo
+
+ $ hg relink .
+ relinking $TESTTMP/repo/.hg/store to $TESTTMP/repo/.hg/store (glob)
+ there is nothing to relink
+
+
+Test files are read in binary mode
+
+ $ python -c "file('.hg/store/data/dummy.i', 'wb').write('a\r\nb\n')"
+ $ cd ..
+
+
+clone and pull to break links
+
+ $ hg clone --pull -r0 repo clone
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd clone
+ $ hg pull -q
+ $ echo b >> b
+ $ hg ci -m changeb
+ created new head
+ $ python -c "file('.hg/store/data/dummy.i', 'wb').write('a\nb\r\n')"
+
+
+relink
+
+ $ hg relink --debug | fix_path
+ relinking $TESTTMP/repo/.hg/store to $TESTTMP/clone/.hg/store
+ tip has 2 files, estimated total number of files: 3
+ collecting: 00changelog.i 1/3 files (33.33%)
+ collecting: 00manifest.i 2/3 files (66.67%)
+ collecting: a.i 3/3 files (100.00%)
+ collecting: b.i 4/3 files (133.33%)
+ collecting: dummy.i 5/3 files (166.67%)
+ collected 5 candidate storage files
+ not linkable: 00changelog.i
+ not linkable: 00manifest.i
+ pruning: data/a.i 3/5 files (60.00%)
+ not linkable: data/b.i
+ pruning: data/dummy.i 5/5 files (100.00%)
+ pruned down to 2 probably relinkable files
+ relinking: data/a.i 1/2 files (50.00%)
+ not linkable: data/dummy.i
+ relinked 1 files (1.37 KB reclaimed)
+ $ cd ..
+
+
+check hardlinks
+
+ $ python arelinked.py repo/.hg/store/data/a.i clone/.hg/store/data/a.i
+ repo/.hg/store/data/a.i == clone/.hg/store/data/a.i
+ $ python arelinked.py repo/.hg/store/data/b.i clone/.hg/store/data/b.i
+ repo/.hg/store/data/b.i != clone/.hg/store/data/b.i
+
diff --git a/tests/test-remove.t b/tests/test-remove.t
new file mode 100644
index 0000000..f67146e
--- /dev/null
+++ b/tests/test-remove.t
@@ -0,0 +1,268 @@
+ $ remove() {
+ > hg rm $@
+ > echo "exit code: $?" # no-check-code
+ > hg st
+ > # do not use ls -R, which recurses in .hg subdirs on Mac OS X 10.5
+ > find . -name .hg -prune -o -type f -print | sort
+ > hg up -C
+ > }
+
+ $ hg init a
+ $ cd a
+ $ echo a > foo
+
+file not managed
+
+ $ remove foo
+ not removing foo: file is untracked
+ exit code: 1
+ ? foo
+ ./foo
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg add foo
+ $ hg commit -m1
+
+the table cases
+00 state added, options none
+
+ $ echo b > bar
+ $ hg add bar
+ $ remove bar
+ not removing bar: file has been marked for add (use forget to undo)
+ exit code: 1
+ A bar
+ ./bar
+ ./foo
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+01 state clean, options none
+
+ $ remove foo
+ exit code: 0
+ R foo
+ ? bar
+ ./bar
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+02 state modified, options none
+
+ $ echo b >> foo
+ $ remove foo
+ not removing foo: file is modified (use -f to force removal)
+ exit code: 1
+ M foo
+ ? bar
+ ./bar
+ ./foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+03 state missing, options none
+
+ $ rm foo
+ $ remove foo
+ exit code: 0
+ R foo
+ ? bar
+ ./bar
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+10 state added, options -f
+
+ $ echo b > bar
+ $ hg add bar
+ $ remove -f bar
+ exit code: 0
+ ? bar
+ ./bar
+ ./foo
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm bar
+
+11 state clean, options -f
+
+ $ remove -f foo
+ exit code: 0
+ R foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+12 state modified, options -f
+
+ $ echo b >> foo
+ $ remove -f foo
+ exit code: 0
+ R foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+13 state missing, options -f
+
+ $ rm foo
+ $ remove -f foo
+ exit code: 0
+ R foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+20 state added, options -A
+
+ $ echo b > bar
+ $ hg add bar
+ $ remove -A bar
+ not removing bar: file still exists (use -f to force removal)
+ exit code: 1
+ A bar
+ ./bar
+ ./foo
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+21 state clean, options -A
+
+ $ remove -A foo
+ not removing foo: file still exists (use -f to force removal)
+ exit code: 1
+ ? bar
+ ./bar
+ ./foo
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+22 state modified, options -A
+
+ $ echo b >> foo
+ $ remove -A foo
+ not removing foo: file still exists (use -f to force removal)
+ exit code: 1
+ M foo
+ ? bar
+ ./bar
+ ./foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+23 state missing, options -A
+
+ $ rm foo
+ $ remove -A foo
+ exit code: 0
+ R foo
+ ? bar
+ ./bar
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+30 state added, options -Af
+
+ $ echo b > bar
+ $ hg add bar
+ $ remove -Af bar
+ exit code: 0
+ ? bar
+ ./bar
+ ./foo
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm bar
+
+31 state clean, options -Af
+
+ $ remove -Af foo
+ exit code: 0
+ R foo
+ ./foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+32 state modified, options -Af
+
+ $ echo b >> foo
+ $ remove -Af foo
+ exit code: 0
+ R foo
+ ./foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+33 state missing, options -Af
+
+ $ rm foo
+ $ remove -Af foo
+ exit code: 0
+ R foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+test some directory stuff
+
+ $ mkdir test
+ $ echo a > test/foo
+ $ echo b > test/bar
+ $ hg ci -Am2
+ adding test/bar
+ adding test/foo
+
+dir, options none
+
+ $ rm test/bar
+ $ remove test
+ removing test/bar (glob)
+ removing test/foo (glob)
+ exit code: 0
+ R test/bar
+ R test/foo
+ ./foo
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+dir, options -f
+
+ $ rm test/bar
+ $ remove -f test
+ removing test/bar (glob)
+ removing test/foo (glob)
+ exit code: 0
+ R test/bar
+ R test/foo
+ ./foo
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+dir, options -A
+
+ $ rm test/bar
+ $ remove -A test
+ not removing test/foo: file still exists (use -f to force removal) (glob)
+ removing test/bar (glob)
+ exit code: 1
+ R test/bar
+ ./foo
+ ./test/foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+dir, options -Af
+
+ $ rm test/bar
+ $ remove -Af test
+ removing test/bar (glob)
+ removing test/foo (glob)
+ exit code: 0
+ R test/bar
+ R test/foo
+ ./foo
+ ./test/foo
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+test remove dropping empty trees (issue1861)
+
+ $ mkdir -p issue1861/b/c
+ $ echo x > issue1861/x
+ $ echo y > issue1861/b/c/y
+ $ hg ci -Am add
+ adding issue1861/b/c/y
+ adding issue1861/x
+ $ hg rm issue1861/b
+ removing issue1861/b/c/y (glob)
+ $ hg ci -m remove
+ $ ls issue1861
+ x
+
+test that commit does not crash if the user removes a newly added file
+
+ $ touch f1
+ $ hg add f1
+ $ rm f1
+ $ hg ci -A -mx
+ removing f1
+ nothing changed
+ [1]
+
+ $ cd ..
diff --git a/tests/test-rename-after-merge.t b/tests/test-rename-after-merge.t
new file mode 100644
index 0000000..8c6bd49
--- /dev/null
+++ b/tests/test-rename-after-merge.t
@@ -0,0 +1,121 @@
+Issue746: renaming files brought by the second parent of a merge was
+broken.
+
+Create source repository:
+
+ $ hg init t
+ $ cd t
+ $ echo a > a
+ $ hg ci -Am a
+ adding a
+ $ cd ..
+
+Fork source repository:
+
+ $ hg clone t t2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd t2
+ $ echo b > b
+ $ hg ci -Am b
+ adding b
+
+Update source repository:
+
+ $ cd ../t
+ $ echo a >> a
+ $ hg ci -m a2
+
+Merge repositories:
+
+ $ hg pull ../t2
+ pulling from ../t2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg st
+ M b
+
+Rename b as c:
+
+ $ hg mv b c
+ $ hg st
+ A c
+ R b
+
+Rename back c as b:
+
+ $ hg mv c b
+ $ hg st
+ M b
+
+ $ cd ..
+
+Issue 1476: renaming a first parent file into another first parent
+file while none of them belong to the second parent was broken
+
+ $ hg init repo1476
+ $ cd repo1476
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ echo b1 > b1
+ $ echo b2 > b2
+ $ hg ci -Am changea
+ adding b1
+ adding b2
+ $ hg up -C 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo c1 > c1
+ $ echo c2 > c2
+ $ hg ci -Am addcandd
+ adding c1
+ adding c2
+ created new head
+
+Merge heads:
+
+ $ hg merge
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg mv -Af c1 c2
+
+Commit issue 1476:
+
+ $ hg ci -m merge
+
+ $ hg log -r tip -C -v | grep copies
+ copies: c2 (c1)
+
+ $ hg rollback
+ repository tip rolled back to revision 2 (undo commit)
+ working directory now based on revisions 2 and 1
+
+ $ hg up -C .
+ 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+Merge heads again:
+
+ $ hg merge
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg mv -Af b1 b2
+
+Commit issue 1476 with a rename on the other side:
+
+ $ hg ci -m merge
+
+ $ hg log -r tip -C -v | grep copies
+ copies: b2 (b1)
+
+ $ cd ..
diff --git a/tests/test-rename-dir-merge.t b/tests/test-rename-dir-merge.t
new file mode 100644
index 0000000..b115c26
--- /dev/null
+++ b/tests/test-rename-dir-merge.t
@@ -0,0 +1,159 @@
+ $ hg init t
+ $ cd t
+
+ $ mkdir a
+ $ echo foo > a/a
+ $ echo bar > a/b
+ $ hg ci -Am "0"
+ adding a/a
+ adding a/b
+
+ $ hg co -C 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg mv a b
+ moving a/a to b/a (glob)
+ moving a/b to b/b (glob)
+ $ hg ci -m "1 mv a/ b/"
+
+ $ hg co -C 0
+ 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo baz > a/c
+ $ echo quux > a/d
+ $ hg add a/c
+ $ hg ci -m "2 add a/c"
+ created new head
+
+ $ hg merge --debug 1
+ searching for copies back to rev 1
+ unmatched files in local:
+ a/c
+ unmatched files in other:
+ b/a
+ b/b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b/a -> a/a
+ b/b -> a/b
+ checking for directory renames
+ dir a/ -> b/
+ file a/c -> b/c
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: f9b20c0d4c51, local: ce36d17b18fb+, remote: 397f8b00a740
+ a/c: remote renamed directory to b/c -> d
+ a/b: other deleted -> r
+ a/a: other deleted -> r
+ b/a: remote created -> g
+ b/b: remote created -> g
+ updating: a/a 1/5 files (20.00%)
+ removing a/a
+ updating: a/b 2/5 files (40.00%)
+ removing a/b
+ updating: a/c 3/5 files (60.00%)
+ moving a/c to b/c
+ updating: b/a 4/5 files (80.00%)
+ getting b/a
+ updating: b/b 5/5 files (100.00%)
+ getting b/b
+ 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ echo a/* b/*
+ a/d b/a b/b b/c
+ $ hg st -C
+ M b/a
+ M b/b
+ A b/c
+ a/c
+ R a/a
+ R a/b
+ R a/c
+ ? a/d
+ $ hg ci -m "3 merge 2+1"
+ $ hg debugrename b/c
+ b/c renamed from a/c:354ae8da6e890359ef49ade27b68bbc361f3ca88 (glob)
+
+ $ hg co -C 1
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge --debug 2
+ searching for copies back to rev 1
+ unmatched files in local:
+ b/a
+ b/b
+ unmatched files in other:
+ a/c
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b/a -> a/a
+ b/b -> a/b
+ checking for directory renames
+ dir a/ -> b/
+ file a/c -> b/c
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: f9b20c0d4c51, local: 397f8b00a740+, remote: ce36d17b18fb
+ None: local renamed directory to b/c -> d
+ updating:None 1/1 files (100.00%)
+ getting a/c to b/c
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ echo a/* b/*
+ a/d b/a b/b b/c
+ $ hg st -C
+ A b/c
+ a/c
+ ? a/d
+ $ hg ci -m "4 merge 1+2"
+ created new head
+ $ hg debugrename b/c
+ b/c renamed from a/c:354ae8da6e890359ef49ade27b68bbc361f3ca88 (glob)
+
+
+Second scenario with two repos:
+
+ $ cd ..
+ $ hg init r1
+ $ cd r1
+ $ mkdir a
+ $ echo foo > a/f
+ $ hg add a
+ adding a/f (glob)
+ $ hg ci -m "a/f == foo"
+ $ cd ..
+
+ $ hg clone r1 r2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd r2
+ $ hg mv a b
+ moving a/f to b/f (glob)
+ $ echo foo1 > b/f
+ $ hg ci -m" a -> b, b/f == foo1"
+ $ cd ..
+
+ $ cd r1
+ $ mkdir a/aa
+ $ echo bar > a/aa/g
+ $ hg add a/aa
+ adding a/aa/g (glob)
+ $ hg ci -m "a/aa/g"
+ $ hg pull ../r2
+ pulling from ../r2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ $ hg merge
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg st -C
+ M b/f
+ A b/aa/g
+ a/aa/g
+ R a/aa/g
+ R a/f
+
+ $ cd ..
diff --git a/tests/test-rename-merge1.t b/tests/test-rename-merge1.t
new file mode 100644
index 0000000..f6b5f52
--- /dev/null
+++ b/tests/test-rename-merge1.t
@@ -0,0 +1,195 @@
+ $ hg init
+
+ $ echo "[merge]" >> .hg/hgrc
+ $ echo "followcopies = 1" >> .hg/hgrc
+
+ $ echo foo > a
+ $ echo foo > a2
+ $ hg add a a2
+ $ hg ci -m "start"
+
+ $ hg mv a b
+ $ hg mv a2 b2
+ $ hg ci -m "rename"
+
+ $ hg co 0
+ 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+ $ echo blahblah > a
+ $ echo blahblah > a2
+ $ hg mv a2 c2
+ $ hg ci -m "modify"
+ created new head
+
+ $ hg merge -y --debug
+ searching for copies back to rev 1
+ unmatched files in local:
+ c2
+ unmatched files in other:
+ b
+ b2
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ c2 -> a2 !
+ b -> a *
+ b2 -> a2 !
+ checking for directory renames
+ a2: divergent renames -> dr
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: af1939970a1c, local: 044f8520aeeb+, remote: 85c198ef2f6c
+ a: remote moved to b -> m
+ b2: remote created -> g
+ preserving a for resolve of b
+ removing a
+ updating: a 1/3 files (33.33%)
+ picked tool 'internal:merge' for b (binary False symlink False)
+ merging a and b to b
+ my b@044f8520aeeb+ other b@85c198ef2f6c ancestor a@af1939970a1c
+ premerge successful
+ updating: a2 2/3 files (66.67%)
+ note: possible conflict - a2 was renamed multiple times to:
+ c2
+ b2
+ updating: b2 3/3 files (100.00%)
+ getting b2
+ 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg status -AC
+ M b
+ a
+ M b2
+ R a
+ C c2
+
+ $ cat b
+ blahblah
+
+ $ hg ci -m "merge"
+
+ $ hg debugindex b
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 67 ..... 1 57eacc201a7f 000000000000 000000000000 (re)
+ 1 67 72 ..... 3 4727ba907962 000000000000 57eacc201a7f (re)
+
+ $ hg debugrename b
+ b renamed from a:dd03b83622e78778b403775d0d074b9ac7387a66
+
+This used to trigger a "divergent renames" warning, despite no renames
+
+ $ hg cp b b3
+ $ hg cp b b4
+ $ hg ci -A -m 'copy b twice'
+ $ hg up eb92d88a9712
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg up
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg rm b3 b4
+ $ hg ci -m 'clean up a bit of our mess'
+
+We'd rather not warn on divergent renames done in the same changeset (issue2113)
+
+ $ hg cp b b3
+ $ hg mv b b4
+ $ hg ci -A -m 'divergent renames in same changeset'
+ $ hg up c761c6948de0
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg up
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+Check for issue2642
+
+ $ hg init t
+ $ cd t
+
+ $ echo c0 > f1
+ $ hg ci -Aqm0
+
+ $ hg up null -q
+ $ echo c1 > f1 # backport
+ $ hg ci -Aqm1
+ $ hg mv f1 f2
+ $ hg ci -qm2
+
+ $ hg up 0 -q
+ $ hg merge 1 -q --tool internal:local
+ $ hg ci -qm3
+
+ $ hg merge 2
+ merging f1 and f2 to f2
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cat f2
+ c0
+
+ $ cd ..
+
+Check for issue2089
+
+ $ hg init repo2089
+ $ cd repo2089
+
+ $ echo c0 > f1
+ $ hg ci -Aqm0
+
+ $ hg up null -q
+ $ echo c1 > f1
+ $ hg ci -Aqm1
+
+ $ hg up 0 -q
+ $ hg merge 1 -q --tool internal:local
+ $ echo c2 > f1
+ $ hg ci -qm2
+
+ $ hg up 1 -q
+ $ hg mv f1 f2
+ $ hg ci -Aqm3
+
+ $ hg up 2 -q
+ $ hg merge 3
+ merging f1 and f2 to f2
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cat f2
+ c2
+
+ $ cd ..
+
+Check for issue3074
+
+ $ hg init repo3074
+ $ cd repo3074
+ $ echo foo > file
+ $ hg add file
+ $ hg commit -m "added file"
+ $ hg mv file newfile
+ $ hg commit -m "renamed file"
+ $ hg update 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg rm file
+ $ hg commit -m "deleted file"
+ created new head
+ $ hg merge --debug
+ searching for copies back to rev 1
+ unmatched files in other:
+ newfile
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ newfile -> file %
+ checking for directory renames
+ file: rename and delete -> rd
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 19d7f95df299, local: 0084274f6b67+, remote: 5d32493049f0
+ newfile: remote created -> g
+ updating: file 1/2 files (50.00%)
+ note: possible conflict - file was deleted and renamed to:
+ newfile
+ updating: newfile 2/2 files (100.00%)
+ getting newfile
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg status
+ M newfile
+ $ cd ..
diff --git a/tests/test-rename-merge2.t b/tests/test-rename-merge2.t
new file mode 100644
index 0000000..e5ba1d5
--- /dev/null
+++ b/tests/test-rename-merge2.t
@@ -0,0 +1,754 @@
+
+ $ mkdir -p t
+ $ cd t
+ $ cat <<EOF > merge
+ > import sys, os
+ > f = open(sys.argv[1], "wb")
+ > f.write("merge %s %s %s" % (sys.argv[1], sys.argv[2], sys.argv[3]))
+ > f.close()
+ > EOF
+
+perform a test merge with possible renaming
+args:
+$1 = action in local branch
+$2 = action in remote branch
+$3 = action in working dir
+$4 = expected result
+
+ $ tm()
+ > {
+ > hg init t
+ > cd t
+ > echo "[merge]" >> .hg/hgrc
+ > echo "followcopies = 1" >> .hg/hgrc
+ >
+ > # base
+ > echo base > a
+ > echo base > rev # used to force commits
+ > hg add a rev
+ > hg ci -m "base"
+ >
+ > # remote
+ > echo remote > rev
+ > if [ "$2" != "" ] ; then $2 ; fi
+ > hg ci -m "remote"
+ >
+ > # local
+ > hg co -q 0
+ > echo local > rev
+ > if [ "$1" != "" ] ; then $1 ; fi
+ > hg ci -m "local"
+ >
+ > # working dir
+ > echo local > rev
+ > if [ "$3" != "" ] ; then $3 ; fi
+ >
+ > # merge
+ > echo "--------------"
+ > echo "test L:$1 R:$2 W:$3 - $4"
+ > echo "--------------"
+ > hg merge -y --debug --traceback --tool="python ../merge"
+ >
+ > echo "--------------"
+ > hg status -camC -X rev
+ >
+ > hg ci -m "merge"
+ >
+ > echo "--------------"
+ > echo
+ >
+ > cd ..
+ > rm -r t
+ > }
+ $ up() {
+ > cp rev $1
+ > hg add $1 2> /dev/null
+ > if [ "$2" != "" ] ; then
+ > cp rev $2
+ > hg add $2 2> /dev/null
+ > fi
+ > }
+ $ uc() { up $1; hg cp $1 $2; } # update + copy
+ $ um() { up $1; hg mv $1 $2; }
+ $ nc() { hg cp $1 $2; } # just copy
+ $ nm() { hg mv $1 $2; } # just move
+ $ tm "up a " "nc a b" " " "1 get local a to b"
+ created new head
+ --------------
+ test L:up a R:nc a b W: - 1 get local a to b
+ --------------
+ searching for copies back to rev 1
+ unmatched files in other:
+ b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: e300d1c794ec+, remote: 4ce40f5aca24
+ rev: versions differ -> m
+ a: remote copied to b -> m
+ preserving a for resolve of b
+ preserving rev for resolve of rev
+ updating: a 1/2 files (50.00%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging a and b to b
+ my b@e300d1c794ec+ other b@4ce40f5aca24 ancestor a@924404dff337
+ premerge successful
+ updating: rev 2/2 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@e300d1c794ec+ other rev@4ce40f5aca24 ancestor rev@924404dff337
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ a
+ C a
+ --------------
+
+ $ tm "nc a b" "up a " " " "2 get rem change to a and b"
+ created new head
+ --------------
+ test L:nc a b R:up a W: - 2 get rem change to a and b
+ --------------
+ searching for copies back to rev 1
+ unmatched files in local:
+ b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 86a2aa42fc76+, remote: f4db7e329e71
+ a: remote is newer -> g
+ b: local copied/moved to a -> m
+ rev: versions differ -> m
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: a 1/3 files (33.33%)
+ getting a
+ updating: b 2/3 files (66.67%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b and a to b
+ my b@86a2aa42fc76+ other a@f4db7e329e71 ancestor a@924404dff337
+ premerge successful
+ updating: rev 3/3 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@86a2aa42fc76+ other rev@f4db7e329e71 ancestor rev@924404dff337
+ 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M a
+ M b
+ a
+ --------------
+
+ $ tm "up a " "nm a b" " " "3 get local a change to b, remove a"
+ created new head
+ --------------
+ test L:up a R:nm a b W: - 3 get local a change to b, remove a
+ --------------
+ searching for copies back to rev 1
+ unmatched files in other:
+ b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: e300d1c794ec+, remote: bdb19105162a
+ rev: versions differ -> m
+ a: remote moved to b -> m
+ preserving a for resolve of b
+ preserving rev for resolve of rev
+ removing a
+ updating: a 1/2 files (50.00%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging a and b to b
+ my b@e300d1c794ec+ other b@bdb19105162a ancestor a@924404dff337
+ premerge successful
+ updating: rev 2/2 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@e300d1c794ec+ other rev@bdb19105162a ancestor rev@924404dff337
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ a
+ --------------
+
+ $ tm "nm a b" "up a " " " "4 get remote change to b"
+ created new head
+ --------------
+ test L:nm a b R:up a W: - 4 get remote change to b
+ --------------
+ searching for copies back to rev 1
+ unmatched files in local:
+ b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 02963e448370+, remote: f4db7e329e71
+ b: local copied/moved to a -> m
+ rev: versions differ -> m
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: b 1/2 files (50.00%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b and a to b
+ my b@02963e448370+ other a@f4db7e329e71 ancestor a@924404dff337
+ premerge successful
+ updating: rev 2/2 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@02963e448370+ other rev@f4db7e329e71 ancestor rev@924404dff337
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ a
+ --------------
+
+ $ tm " " "nc a b" " " "5 get b"
+ created new head
+ --------------
+ test L: R:nc a b W: - 5 get b
+ --------------
+ searching for copies back to rev 1
+ unmatched files in other:
+ b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: 4ce40f5aca24
+ rev: versions differ -> m
+ b: remote created -> g
+ preserving rev for resolve of rev
+ updating: b 1/2 files (50.00%)
+ getting b
+ updating: rev 2/2 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@94b33a1b7f2d+ other rev@4ce40f5aca24 ancestor rev@924404dff337
+ 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ C a
+ --------------
+
+ $ tm "nc a b" " " " " "6 nothing"
+ created new head
+ --------------
+ test L:nc a b R: W: - 6 nothing
+ --------------
+ searching for copies back to rev 1
+ unmatched files in local:
+ b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 97c705ade336
+ rev: versions differ -> m
+ preserving rev for resolve of rev
+ updating: rev 1/1 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@86a2aa42fc76+ other rev@97c705ade336 ancestor rev@924404dff337
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ C a
+ C b
+ --------------
+
+ $ tm " " "nm a b" " " "7 get b"
+ created new head
+ --------------
+ test L: R:nm a b W: - 7 get b
+ --------------
+ searching for copies back to rev 1
+ unmatched files in other:
+ b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: bdb19105162a
+ a: other deleted -> r
+ rev: versions differ -> m
+ b: remote created -> g
+ preserving rev for resolve of rev
+ updating: a 1/3 files (33.33%)
+ removing a
+ updating: b 2/3 files (66.67%)
+ getting b
+ updating: rev 3/3 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@94b33a1b7f2d+ other rev@bdb19105162a ancestor rev@924404dff337
+ 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ --------------
+
+ $ tm "nm a b" " " " " "8 nothing"
+ created new head
+ --------------
+ test L:nm a b R: W: - 8 nothing
+ --------------
+ searching for copies back to rev 1
+ unmatched files in local:
+ b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 02963e448370+, remote: 97c705ade336
+ rev: versions differ -> m
+ preserving rev for resolve of rev
+ updating: rev 1/1 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@02963e448370+ other rev@97c705ade336 ancestor rev@924404dff337
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ C b
+ --------------
+
+ $ tm "um a b" "um a b" " " "9 do merge with ancestor in a"
+ created new head
+ --------------
+ test L:um a b R:um a b W: - 9 do merge with ancestor in a
+ --------------
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 62e7bf090eba+, remote: 49b6d8032493
+ b: versions differ -> m
+ rev: versions differ -> m
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: b 1/2 files (50.00%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b
+ my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
+ updating: rev 2/2 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@62e7bf090eba+ other rev@49b6d8032493 ancestor rev@924404dff337
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ --------------
+
+
+m "um a c" "um x c" " " "10 do merge with no ancestor"
+
+ $ tm "nm a b" "nm a c" " " "11 get c, keep b"
+ created new head
+ --------------
+ test L:nm a b R:nm a c W: - 11 get c, keep b
+ --------------
+ searching for copies back to rev 1
+ unmatched files in local:
+ b
+ unmatched files in other:
+ c
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ c -> a !
+ b -> a !
+ checking for directory renames
+ a: divergent renames -> dr
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 02963e448370+, remote: fe905ef2c33e
+ rev: versions differ -> m
+ c: remote created -> g
+ preserving rev for resolve of rev
+ updating: a 1/3 files (33.33%)
+ note: possible conflict - a was renamed multiple times to:
+ b
+ c
+ updating: c 2/3 files (66.67%)
+ getting c
+ updating: rev 3/3 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
+ 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M c
+ C b
+ --------------
+
+ $ tm "nc a b" "up b " " " "12 merge b no ancestor"
+ created new head
+ --------------
+ test L:nc a b R:up b W: - 12 merge b no ancestor
+ --------------
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 86a2aa42fc76+, remote: af30c7647fc7
+ b: versions differ -> m
+ rev: versions differ -> m
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: b 1/2 files (50.00%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b
+ my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
+ updating: rev 2/2 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@86a2aa42fc76+ other rev@af30c7647fc7 ancestor rev@924404dff337
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ C a
+ --------------
+
+ $ tm "up b " "nm a b" " " "13 merge b no ancestor"
+ created new head
+ --------------
+ test L:up b R:nm a b W: - 13 merge b no ancestor
+ --------------
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
+ a: other deleted -> r
+ b: versions differ -> m
+ rev: versions differ -> m
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: a 1/3 files (33.33%)
+ removing a
+ updating: b 2/3 files (66.67%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b
+ my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
+ updating: rev 3/3 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
+ 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ --------------
+
+ $ tm "nc a b" "up a b" " " "14 merge b no ancestor"
+ created new head
+ --------------
+ test L:nc a b R:up a b W: - 14 merge b no ancestor
+ --------------
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
+ a: remote is newer -> g
+ b: versions differ -> m
+ rev: versions differ -> m
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: a 1/3 files (33.33%)
+ getting a
+ updating: b 2/3 files (66.67%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b
+ my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
+ updating: rev 3/3 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
+ 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M a
+ M b
+ --------------
+
+ $ tm "up b " "nm a b" " " "15 merge b no ancestor, remove a"
+ created new head
+ --------------
+ test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
+ --------------
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
+ a: other deleted -> r
+ b: versions differ -> m
+ rev: versions differ -> m
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: a 1/3 files (33.33%)
+ removing a
+ updating: b 2/3 files (66.67%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b
+ my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
+ updating: rev 3/3 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
+ 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ --------------
+
+ $ tm "nc a b" "up a b" " " "16 get a, merge b no ancestor"
+ created new head
+ --------------
+ test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
+ --------------
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
+ a: remote is newer -> g
+ b: versions differ -> m
+ rev: versions differ -> m
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: a 1/3 files (33.33%)
+ getting a
+ updating: b 2/3 files (66.67%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b
+ my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
+ updating: rev 3/3 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
+ 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M a
+ M b
+ --------------
+
+ $ tm "up a b" "nc a b" " " "17 keep a, merge b no ancestor"
+ created new head
+ --------------
+ test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
+ --------------
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 0b76e65c8289+, remote: 4ce40f5aca24
+ b: versions differ -> m
+ rev: versions differ -> m
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: b 1/2 files (50.00%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b
+ my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
+ updating: rev 2/2 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@0b76e65c8289+ other rev@4ce40f5aca24 ancestor rev@924404dff337
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ C a
+ --------------
+
+ $ tm "nm a b" "up a b" " " "18 merge b no ancestor"
+ created new head
+ --------------
+ test L:nm a b R:up a b W: - 18 merge b no ancestor
+ --------------
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 02963e448370+, remote: 8dbce441892a
+ b: versions differ -> m
+ rev: versions differ -> m
+ remote changed a which local deleted
+ use (c)hanged version or leave (d)eleted? c
+ a: prompt recreating -> g
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: a 1/3 files (33.33%)
+ getting a
+ updating: b 2/3 files (66.67%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b
+ my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
+ updating: rev 3/3 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@02963e448370+ other rev@8dbce441892a ancestor rev@924404dff337
+ 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M a
+ M b
+ --------------
+
+ $ tm "up a b" "nm a b" " " "19 merge b no ancestor, prompt remove a"
+ created new head
+ --------------
+ test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
+ --------------
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 0b76e65c8289+, remote: bdb19105162a
+ local changed a which remote deleted
+ use (c)hanged version or (d)elete? c
+ a: prompt keep -> a
+ b: versions differ -> m
+ rev: versions differ -> m
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: a 1/3 files (33.33%)
+ updating: b 2/3 files (66.67%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b
+ my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
+ updating: rev 3/3 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ C a
+ --------------
+
+ $ tm "up a " "um a b" " " "20 merge a and b to b, remove a"
+ created new head
+ --------------
+ test L:up a R:um a b W: - 20 merge a and b to b, remove a
+ --------------
+ searching for copies back to rev 1
+ unmatched files in other:
+ b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: e300d1c794ec+, remote: 49b6d8032493
+ rev: versions differ -> m
+ a: remote moved to b -> m
+ preserving a for resolve of b
+ preserving rev for resolve of rev
+ removing a
+ updating: a 1/2 files (50.00%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging a and b to b
+ my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
+ updating: rev 2/2 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@e300d1c794ec+ other rev@49b6d8032493 ancestor rev@924404dff337
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ a
+ --------------
+
+ $ tm "um a b" "up a " " " "21 merge a and b to b"
+ created new head
+ --------------
+ test L:um a b R:up a W: - 21 merge a and b to b
+ --------------
+ searching for copies back to rev 1
+ unmatched files in local:
+ b
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 62e7bf090eba+, remote: f4db7e329e71
+ b: local copied/moved to a -> m
+ rev: versions differ -> m
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: b 1/2 files (50.00%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b and a to b
+ my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
+ updating: rev 2/2 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@62e7bf090eba+ other rev@f4db7e329e71 ancestor rev@924404dff337
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ a
+ --------------
+
+
+m "nm a b" "um x a" " " "22 get a, keep b"
+
+ $ tm "nm a b" "up a c" " " "23 get c, keep b"
+ created new head
+ --------------
+ test L:nm a b R:up a c W: - 23 get c, keep b
+ --------------
+ searching for copies back to rev 1
+ unmatched files in local:
+ b
+ unmatched files in other:
+ c
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ b -> a *
+ checking for directory renames
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 924404dff337, local: 02963e448370+, remote: 2b958612230f
+ b: local copied/moved to a -> m
+ rev: versions differ -> m
+ c: remote created -> g
+ preserving b for resolve of b
+ preserving rev for resolve of rev
+ updating: b 1/3 files (33.33%)
+ picked tool 'python ../merge' for b (binary False symlink False)
+ merging b and a to b
+ my b@02963e448370+ other a@2b958612230f ancestor a@924404dff337
+ premerge successful
+ updating: c 2/3 files (66.67%)
+ getting c
+ updating: rev 3/3 files (100.00%)
+ picked tool 'python ../merge' for rev (binary False symlink False)
+ merging rev
+ my rev@02963e448370+ other rev@2b958612230f ancestor rev@924404dff337
+ 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ --------------
+ M b
+ a
+ M c
+ --------------
+
+
+ $ cd ..
diff --git a/tests/test-rename.t b/tests/test-rename.t
new file mode 100644
index 0000000..059f569
--- /dev/null
+++ b/tests/test-rename.t
@@ -0,0 +1,637 @@
+ $ hg init
+ $ mkdir d1 d1/d11 d2
+ $ echo d1/a > d1/a
+ $ echo d1/ba > d1/ba
+ $ echo d1/a1 > d1/d11/a1
+ $ echo d1/b > d1/b
+ $ echo d2/b > d2/b
+ $ hg add d1/a d1/b d1/ba d1/d11/a1 d2/b
+ $ hg commit -m "1"
+
+rename a single file
+
+ $ hg rename d1/d11/a1 d2/c
+ $ hg --config ui.portablefilenames=abort rename d1/a d1/con.xml
+ abort: filename contains 'con', which is reserved on Windows: 'd1/con.xml'
+ [255]
+ $ hg sum
+ parent: 0:9b4b6e7b2c26 tip
+ 1
+ branch: default
+ commit: 1 renamed
+ update: (current)
+ $ hg status -C
+ A d2/c
+ d1/d11/a1
+ R d1/d11/a1
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d2/c
+
+rename a single file using absolute paths
+
+ $ hg rename `pwd`/d1/d11/a1 `pwd`/d2/c
+ $ hg status -C
+ A d2/c
+ d1/d11/a1
+ R d1/d11/a1
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d2/c
+
+rename --after a single file
+
+ $ mv d1/d11/a1 d2/c
+ $ hg rename --after d1/d11/a1 d2/c
+ $ hg status -C
+ A d2/c
+ d1/d11/a1
+ R d1/d11/a1
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d2/c
+
+rename --after a single file when src and tgt already tracked
+
+ $ mv d1/d11/a1 d2/c
+ $ hg addrem -s 0
+ removing d1/d11/a1
+ adding d2/c
+ $ hg rename --after d1/d11/a1 d2/c
+ $ hg status -C
+ A d2/c
+ d1/d11/a1
+ R d1/d11/a1
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d2/c
+
+rename --after a single file to a nonexistant target filename
+
+ $ hg rename --after d1/a dummy
+ d1/a: not recording move - dummy does not exist (glob)
+
+move a single file to an existing directory
+
+ $ hg rename d1/d11/a1 d2
+ $ hg status -C
+ A d2/a1
+ d1/d11/a1
+ R d1/d11/a1
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d2/a1
+
+move --after a single file to an existing directory
+
+ $ mv d1/d11/a1 d2
+ $ hg rename --after d1/d11/a1 d2
+ $ hg status -C
+ A d2/a1
+ d1/d11/a1
+ R d1/d11/a1
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d2/a1
+
+rename a file using a relative path
+
+ $ (cd d1/d11; hg rename ../../d2/b e)
+ $ hg status -C
+ A d1/d11/e
+ d2/b
+ R d2/b
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d1/d11/e
+
+rename --after a file using a relative path
+
+ $ (cd d1/d11; mv ../../d2/b e; hg rename --after ../../d2/b e)
+ $ hg status -C
+ A d1/d11/e
+ d2/b
+ R d2/b
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d1/d11/e
+
+rename directory d1 as d3
+
+ $ hg rename d1/ d3
+ moving d1/a to d3/a (glob)
+ moving d1/b to d3/b (glob)
+ moving d1/ba to d3/ba (glob)
+ moving d1/d11/a1 to d3/d11/a1 (glob)
+ $ hg status -C
+ A d3/a
+ d1/a
+ A d3/b
+ d1/b
+ A d3/ba
+ d1/ba
+ A d3/d11/a1
+ d1/d11/a1
+ R d1/a
+ R d1/b
+ R d1/ba
+ R d1/d11/a1
+ $ hg update -C
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d3
+
+rename --after directory d1 as d3
+
+ $ mv d1 d3
+ $ hg rename --after d1 d3
+ moving d1/a to d3/a (glob)
+ moving d1/b to d3/b (glob)
+ moving d1/ba to d3/ba (glob)
+ moving d1/d11/a1 to d3/d11/a1 (glob)
+ $ hg status -C
+ A d3/a
+ d1/a
+ A d3/b
+ d1/b
+ A d3/ba
+ d1/ba
+ A d3/d11/a1
+ d1/d11/a1
+ R d1/a
+ R d1/b
+ R d1/ba
+ R d1/d11/a1
+ $ hg update -C
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d3
+
+move a directory using a relative path
+
+ $ (cd d2; mkdir d3; hg rename ../d1/d11 d3)
+ moving ../d1/d11/a1 to d3/d11/a1 (glob)
+ $ hg status -C
+ A d2/d3/d11/a1
+ d1/d11/a1
+ R d1/d11/a1
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d2/d3
+
+move --after a directory using a relative path
+
+ $ (cd d2; mkdir d3; mv ../d1/d11 d3; hg rename --after ../d1/d11 d3)
+ moving ../d1/d11/a1 to d3/d11/a1 (glob)
+ $ hg status -C
+ A d2/d3/d11/a1
+ d1/d11/a1
+ R d1/d11/a1
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d2/d3
+
+move directory d1/d11 to an existing directory d2 (removes empty d1)
+
+ $ hg rename d1/d11/ d2
+ moving d1/d11/a1 to d2/d11/a1 (glob)
+ $ hg status -C
+ A d2/d11/a1
+ d1/d11/a1
+ R d1/d11/a1
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d2/d11
+
+move directories d1 and d2 to a new directory d3
+
+ $ mkdir d3
+ $ hg rename d1 d2 d3
+ moving d1/a to d3/d1/a (glob)
+ moving d1/b to d3/d1/b (glob)
+ moving d1/ba to d3/d1/ba (glob)
+ moving d1/d11/a1 to d3/d1/d11/a1 (glob)
+ moving d2/b to d3/d2/b (glob)
+ $ hg status -C
+ A d3/d1/a
+ d1/a
+ A d3/d1/b
+ d1/b
+ A d3/d1/ba
+ d1/ba
+ A d3/d1/d11/a1
+ d1/d11/a1
+ A d3/d2/b
+ d2/b
+ R d1/a
+ R d1/b
+ R d1/ba
+ R d1/d11/a1
+ R d2/b
+ $ hg update -C
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d3
+
+move --after directories d1 and d2 to a new directory d3
+
+ $ mkdir d3
+ $ mv d1 d2 d3
+ $ hg rename --after d1 d2 d3
+ moving d1/a to d3/d1/a (glob)
+ moving d1/b to d3/d1/b (glob)
+ moving d1/ba to d3/d1/ba (glob)
+ moving d1/d11/a1 to d3/d1/d11/a1 (glob)
+ moving d2/b to d3/d2/b (glob)
+ $ hg status -C
+ A d3/d1/a
+ d1/a
+ A d3/d1/b
+ d1/b
+ A d3/d1/ba
+ d1/ba
+ A d3/d1/d11/a1
+ d1/d11/a1
+ A d3/d2/b
+ d2/b
+ R d1/a
+ R d1/b
+ R d1/ba
+ R d1/d11/a1
+ R d2/b
+ $ hg update -C
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d3
+
+move everything under directory d1 to existing directory d2, do not
+overwrite existing files (d2/b)
+
+ $ hg rename d1/* d2
+ d2/b: not overwriting - file exists
+ moving d1/d11/a1 to d2/d11/a1 (glob)
+ $ hg status -C
+ A d2/a
+ d1/a
+ A d2/ba
+ d1/ba
+ A d2/d11/a1
+ d1/d11/a1
+ R d1/a
+ R d1/ba
+ R d1/d11/a1
+ $ diff -u d1/b d2/b
+ --- d1/b * (glob)
+ +++ d2/b * (glob)
+ @@ * (glob)
+ -d1/b
+ +d2/b
+ [1]
+ $ hg update -C
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d2/a d2/ba d2/d11/a1
+
+attempt to move one file into a non-existent directory
+
+ $ hg rename d1/a dx/
+ abort: destination dx/ is not a directory
+ [255]
+ $ hg status -C
+ $ hg update -C
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+attempt to move potentially more than one file into a non-existent directory
+
+ $ hg rename 'glob:d1/**' dx
+ abort: with multiple sources, destination must be an existing directory
+ [255]
+
+move every file under d1 to d2/d21 (glob)
+
+ $ mkdir d2/d21
+ $ hg rename 'glob:d1/**' d2/d21
+ moving d1/a to d2/d21/a (glob)
+ moving d1/b to d2/d21/b (glob)
+ moving d1/ba to d2/d21/ba (glob)
+ moving d1/d11/a1 to d2/d21/a1 (glob)
+ $ hg status -C
+ A d2/d21/a
+ d1/a
+ A d2/d21/a1
+ d1/d11/a1
+ A d2/d21/b
+ d1/b
+ A d2/d21/ba
+ d1/ba
+ R d1/a
+ R d1/b
+ R d1/ba
+ R d1/d11/a1
+ $ hg update -C
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d2/d21
+
+move --after some files under d1 to d2/d21 (glob)
+
+ $ mkdir d2/d21
+ $ mv d1/a d1/d11/a1 d2/d21
+ $ hg rename --after 'glob:d1/**' d2/d21
+ moving d1/a to d2/d21/a (glob)
+ d1/b: not recording move - d2/d21/b does not exist (glob)
+ d1/ba: not recording move - d2/d21/ba does not exist (glob)
+ moving d1/d11/a1 to d2/d21/a1 (glob)
+ $ hg status -C
+ A d2/d21/a
+ d1/a
+ A d2/d21/a1
+ d1/d11/a1
+ R d1/a
+ R d1/d11/a1
+ $ hg update -C
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d2/d21
+
+move every file under d1 starting with an 'a' to d2/d21 (regexp)
+
+ $ mkdir d2/d21
+ $ hg rename 're:d1/([^a][^/]*/)*a.*' d2/d21
+ moving d1/a to d2/d21/a (glob)
+ moving d1/d11/a1 to d2/d21/a1 (glob)
+ $ hg status -C
+ A d2/d21/a
+ d1/a
+ A d2/d21/a1
+ d1/d11/a1
+ R d1/a
+ R d1/d11/a1
+ $ hg update -C
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d2/d21
+
+attempt to overwrite an existing file
+
+ $ echo "ca" > d1/ca
+ $ hg rename d1/ba d1/ca
+ d1/ca: not overwriting - file exists
+ $ hg status -C
+ ? d1/ca
+ $ hg update -C
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+forced overwrite of an existing file
+
+ $ echo "ca" > d1/ca
+ $ hg rename --force d1/ba d1/ca
+ $ hg status -C
+ A d1/ca
+ d1/ba
+ R d1/ba
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d1/ca
+
+attempt to overwrite an existing broken symlink
+
+#if symlink
+ $ ln -s ba d1/ca
+ $ hg rename --traceback d1/ba d1/ca
+ d1/ca: not overwriting - file exists
+ $ hg status -C
+ ? d1/ca
+ $ hg update -C
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d1/ca
+
+replace a symlink with a file
+
+ $ ln -s ba d1/ca
+ $ hg rename --force d1/ba d1/ca
+ $ hg status -C
+ A d1/ca
+ d1/ba
+ R d1/ba
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d1/ca
+#endif
+
+do not copy more than one source file to the same destination file
+
+ $ mkdir d3
+ $ hg rename d1/* d2/* d3
+ moving d1/d11/a1 to d3/d11/a1 (glob)
+ d3/b: not overwriting - d2/b collides with d1/b
+ $ hg status -C
+ A d3/a
+ d1/a
+ A d3/b
+ d1/b
+ A d3/ba
+ d1/ba
+ A d3/d11/a1
+ d1/d11/a1
+ R d1/a
+ R d1/b
+ R d1/ba
+ R d1/d11/a1
+ $ hg update -C
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d3
+
+move a whole subtree with "hg rename ."
+
+ $ mkdir d3
+ $ (cd d1; hg rename . ../d3)
+ moving a to ../d3/d1/a
+ moving b to ../d3/d1/b
+ moving ba to ../d3/d1/ba
+ moving d11/a1 to ../d3/d1/d11/a1 (glob)
+ $ hg status -C
+ A d3/d1/a
+ d1/a
+ A d3/d1/b
+ d1/b
+ A d3/d1/ba
+ d1/ba
+ A d3/d1/d11/a1
+ d1/d11/a1
+ R d1/a
+ R d1/b
+ R d1/ba
+ R d1/d11/a1
+ $ hg update -C
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d3
+
+move a whole subtree with "hg rename --after ."
+
+ $ mkdir d3
+ $ mv d1/* d3
+ $ (cd d1; hg rename --after . ../d3)
+ moving a to ../d3/a
+ moving b to ../d3/b
+ moving ba to ../d3/ba
+ moving d11/a1 to ../d3/d11/a1 (glob)
+ $ hg status -C
+ A d3/a
+ d1/a
+ A d3/b
+ d1/b
+ A d3/ba
+ d1/ba
+ A d3/d11/a1
+ d1/d11/a1
+ R d1/a
+ R d1/b
+ R d1/ba
+ R d1/d11/a1
+ $ hg update -C
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d3
+
+move the parent tree with "hg rename .."
+
+ $ (cd d1/d11; hg rename .. ../../d3)
+ moving ../a to ../../d3/a (glob)
+ moving ../b to ../../d3/b (glob)
+ moving ../ba to ../../d3/ba (glob)
+ moving a1 to ../../d3/d11/a1
+ $ hg status -C
+ A d3/a
+ d1/a
+ A d3/b
+ d1/b
+ A d3/ba
+ d1/ba
+ A d3/d11/a1
+ d1/d11/a1
+ R d1/a
+ R d1/b
+ R d1/ba
+ R d1/d11/a1
+ $ hg update -C
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d3
+
+skip removed files
+
+ $ hg remove d1/b
+ $ hg rename d1 d3
+ moving d1/a to d3/a (glob)
+ moving d1/ba to d3/ba (glob)
+ moving d1/d11/a1 to d3/d11/a1 (glob)
+ $ hg status -C
+ A d3/a
+ d1/a
+ A d3/ba
+ d1/ba
+ A d3/d11/a1
+ d1/d11/a1
+ R d1/a
+ R d1/b
+ R d1/ba
+ R d1/d11/a1
+ $ hg update -C
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf d3
+
+transitive rename
+
+ $ hg rename d1/b d1/bb
+ $ hg rename d1/bb d1/bc
+ $ hg status -C
+ A d1/bc
+ d1/b
+ R d1/b
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d1/bc
+
+transitive rename --after
+
+ $ hg rename d1/b d1/bb
+ $ mv d1/bb d1/bc
+ $ hg rename --after d1/bb d1/bc
+ $ hg status -C
+ A d1/bc
+ d1/b
+ R d1/b
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm d1/bc
+
+ $ echo "# idempotent renames (d1/b -> d1/bb followed by d1/bb -> d1/b)"
+ # idempotent renames (d1/b -> d1/bb followed by d1/bb -> d1/b)
+ $ hg rename d1/b d1/bb
+ $ echo "some stuff added to d1/bb" >> d1/bb
+ $ hg rename d1/bb d1/b
+ $ hg status -C
+ M d1/b
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+overwriting with renames (issue1959)
+
+ $ hg rename d1/a d1/c
+ $ hg rename d1/b d1/a
+ $ hg status -C
+ A d1/a
+ d1/b
+ A d1/c
+ d1/a
+ R d1/b
+ $ hg diff --git
+ diff --git a/d1/b b/d1/a
+ rename from d1/b
+ rename to d1/a
+ diff --git a/d1/a b/d1/c
+ copy from d1/a
+ copy to d1/c
+ $ hg update -C
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+check illegal path components
+
+ $ hg rename d1/d11/a1 .hg/foo
+ abort: path contains illegal component: .hg/foo (glob)
+ [255]
+ $ hg status -C
+ $ hg rename d1/d11/a1 ../foo
+ abort: ../foo not under root
+ [255]
+ $ hg status -C
+
+ $ mv d1/d11/a1 .hg/foo
+ $ hg rename --after d1/d11/a1 .hg/foo
+ abort: path contains illegal component: .hg/foo (glob)
+ [255]
+ $ hg status -C
+ ! d1/d11/a1
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm .hg/foo
+
+ $ hg rename d1/d11/a1 .hg
+ abort: path contains illegal component: .hg/a1 (glob)
+ [255]
+ $ hg status -C
+ $ hg rename d1/d11/a1 ..
+ abort: ../a1 not under root (glob)
+ [255]
+ $ hg status -C
+
+ $ mv d1/d11/a1 .hg
+ $ hg rename --after d1/d11/a1 .hg
+ abort: path contains illegal component: .hg/a1 (glob)
+ [255]
+ $ hg status -C
+ ! d1/d11/a1
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm .hg/a1
+
+ $ (cd d1/d11; hg rename ../../d2/b ../../.hg/foo)
+ abort: path contains illegal component: .hg/foo (glob)
+ [255]
+ $ hg status -C
+ $ (cd d1/d11; hg rename ../../d2/b ../../../foo)
+ abort: ../../../foo not under root
+ [255]
+ $ hg status -C
+
diff --git a/tests/test-repair-strip.t b/tests/test-repair-strip.t
new file mode 100644
index 0000000..6393ea2
--- /dev/null
+++ b/tests/test-repair-strip.t
@@ -0,0 +1,132 @@
+ $ "$TESTDIR/hghave" unix-permissions || exit 80
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=">> $HGRCPATH
+
+ $ teststrip() {
+ > hg -q up -C $1
+ > echo % before update $1, strip $2
+ > hg parents
+ > chmod -$3 $4
+ > hg strip $2 2>&1 | sed 's/\(bundle\).*/\1/' | sed 's/Permission denied.*\.hg\/store\/\(.*\)/Permission denied \.hg\/store\/\1/'
+ > echo % after update $1, strip $2
+ > chmod +$3 $4
+ > hg verify
+ > echo % journal contents
+ > if [ -f .hg/store/journal ]; then
+ > sed -e 's/\.i[^\n]*/\.i/' .hg/store/journal
+ > else
+ > echo "(no journal)"
+ > fi
+ > ls .hg/store/journal >/dev/null 2>&1 && hg recover
+ > ls .hg/strip-backup/* >/dev/null 2>&1 && hg unbundle -q .hg/strip-backup/*
+ > rm -rf .hg/strip-backup
+ > }
+
+ $ hg init test
+ $ cd test
+ $ echo a > a
+ $ hg -q ci -m "a" -A
+ $ echo b > b
+ $ hg -q ci -m "b" -A
+ $ echo b2 >> b
+ $ hg -q ci -m "b2" -A
+ $ echo c > c
+ $ hg -q ci -m "c" -A
+ $ teststrip 0 2 w .hg/store/data/b.i
+ % before update 0, strip 2
+ changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ saved backup bundle
+ transaction abort!
+ failed to truncate data/b.i
+ rollback failed - please run hg recover
+ strip failed, full bundle
+ abort: Permission denied .hg/store/data/b.i
+ % after update 0, strip 2
+ abandoned transaction found - run hg recover
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ b@?: rev 1 points to nonexistent changeset 2
+ (expected 1)
+ b@?: 736c29771fba not in manifests
+ warning: orphan revlog 'data/c.i'
+ 2 files, 2 changesets, 3 total revisions
+ 2 warnings encountered!
+ 2 integrity errors encountered!
+ % journal contents
+ 00changelog.i
+ 00manifest.i
+ data/b.i
+ data/c.i
+ rolling back interrupted transaction
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 2 changesets, 2 total revisions
+ $ teststrip 0 2 r .hg/store/data/b.i
+ % before update 0, strip 2
+ changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ abort: Permission denied .hg/store/data/b.i
+ % after update 0, strip 2
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 4 changesets, 4 total revisions
+ % journal contents
+ (no journal)
+ $ teststrip 0 2 w .hg/store/00manifest.i
+ % before update 0, strip 2
+ changeset: 0:cb9a9f314b8b
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ saved backup bundle
+ transaction abort!
+ failed to truncate 00manifest.i
+ rollback failed - please run hg recover
+ strip failed, full bundle
+ abort: Permission denied .hg/store/00manifest.i
+ % after update 0, strip 2
+ abandoned transaction found - run hg recover
+ checking changesets
+ checking manifests
+ manifest@?: rev 2 points to nonexistent changeset 2
+ manifest@?: 3362547cdf64 not in changesets
+ manifest@?: rev 3 points to nonexistent changeset 3
+ manifest@?: 265a85892ecb not in changesets
+ crosschecking files in changesets and manifests
+ c@3: in manifest but not in changeset
+ checking files
+ b@?: rev 1 points to nonexistent changeset 2
+ (expected 1)
+ c@?: rev 0 points to nonexistent changeset 3
+ 3 files, 2 changesets, 4 total revisions
+ 1 warnings encountered!
+ 7 integrity errors encountered!
+ (first damaged changeset appears to be 3)
+ % journal contents
+ 00changelog.i
+ 00manifest.i
+ data/b.i
+ data/c.i
+ rolling back interrupted transaction
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 2 changesets, 2 total revisions
+
+ $ cd ..
diff --git a/tests/test-requires.t b/tests/test-requires.t
new file mode 100644
index 0000000..ff3427d
--- /dev/null
+++ b/tests/test-requires.t
@@ -0,0 +1,19 @@
+ $ hg init t
+ $ cd t
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m test
+ $ rm .hg/requires
+ $ hg tip
+ abort: index 00changelog.i unknown format 2!
+ [255]
+ $ echo indoor-pool > .hg/requires
+ $ hg tip
+ abort: unknown repository format: requires features 'indoor-pool' (upgrade Mercurial)!
+ [255]
+ $ echo outdoor-pool >> .hg/requires
+ $ hg tip
+ abort: unknown repository format: requires features 'indoor-pool', 'outdoor-pool' (upgrade Mercurial)!
+ [255]
+
+ $ cd ..
diff --git a/tests/test-resolve.t b/tests/test-resolve.t
new file mode 100644
index 0000000..86dc9ea
--- /dev/null
+++ b/tests/test-resolve.t
@@ -0,0 +1,46 @@
+test that a commit clears the merge state.
+
+ $ hg init repo
+ $ cd repo
+
+ $ echo foo > file
+ $ hg commit -Am 'add file'
+ adding file
+
+ $ echo bar >> file
+ $ hg commit -Am 'append bar'
+
+
+create a second head
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo baz >> file
+ $ hg commit -Am 'append baz'
+ created new head
+
+failing merge
+
+ $ hg merge --tool=internal:fail
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+
+ $ echo resolved > file
+ $ hg resolve -m file
+ $ hg commit -m 'resolved'
+
+resolve -l, should be empty
+
+ $ hg resolve -l
+
+test crashed merge with empty mergestate
+
+ $ mkdir .hg/merge
+ $ touch .hg/merge/state
+
+resolve -l, should be empty
+
+ $ hg resolve -l
+
+ $ cd ..
diff --git a/tests/test-revert-flags.t b/tests/test-revert-flags.t
new file mode 100644
index 0000000..890e590
--- /dev/null
+++ b/tests/test-revert-flags.t
@@ -0,0 +1,23 @@
+ $ "$TESTDIR/hghave" execbit || exit 80
+
+ $ hg init repo
+ $ cd repo
+ $ echo foo > foo
+ $ chmod 644 foo
+ $ hg ci -qAm '644'
+
+ $ chmod 755 foo
+ $ hg ci -qAm '755'
+
+reverting to rev 0
+
+ $ hg revert -a -r 0
+ reverting foo
+ $ hg st
+ M foo
+ $ hg diff --git
+ diff --git a/foo b/foo
+ old mode 100755
+ new mode 100644
+
+ $ cd ..
diff --git a/tests/test-revert-unknown.t b/tests/test-revert-unknown.t
new file mode 100644
index 0000000..67eb717
--- /dev/null
+++ b/tests/test-revert-unknown.t
@@ -0,0 +1,29 @@
+ $ hg init
+ $ touch unknown
+
+ $ touch a
+ $ hg add a
+ $ hg ci -m "1"
+
+ $ touch b
+ $ hg add b
+ $ hg ci -m "2"
+
+Should show unknown
+
+ $ hg status
+ ? unknown
+ $ hg revert -r 0 --all
+ removing b
+
+Should show unknown and b removed
+
+ $ hg status
+ R b
+ ? unknown
+
+Should show a and unknown
+
+ $ ls
+ a
+ unknown
diff --git a/tests/test-revert.t b/tests/test-revert.t
new file mode 100644
index 0000000..c2b085f
--- /dev/null
+++ b/tests/test-revert.t
@@ -0,0 +1,278 @@
+ $ hg init repo
+ $ cd repo
+ $ echo 123 > a
+ $ echo 123 > c
+ $ echo 123 > e
+ $ hg add a c e
+ $ hg commit -m "first" a c e
+
+nothing changed
+
+ $ hg revert
+ abort: no files or directories specified
+ (use --all to revert all files)
+ [255]
+ $ hg revert --all
+
+ $ echo 123 > b
+
+should show b unknown
+
+ $ hg status
+ ? b
+ $ echo 12 > c
+
+should show b unknown and c modified
+
+ $ hg status
+ M c
+ ? b
+ $ hg add b
+
+should show b added and c modified
+
+ $ hg status
+ M c
+ A b
+ $ hg rm a
+
+should show a removed, b added and c modified
+
+ $ hg status
+ M c
+ A b
+ R a
+ $ hg revert a
+
+should show b added, copy saved, and c modified
+
+ $ hg status
+ M c
+ A b
+ $ hg revert b
+
+should show b unknown, and c modified
+
+ $ hg status
+ M c
+ ? b
+ $ hg revert --no-backup c
+
+should show unknown: b
+
+ $ hg status
+ ? b
+ $ hg add b
+
+should show b added
+
+ $ hg status b
+ A b
+ $ rm b
+
+should show b deleted
+
+ $ hg status b
+ ! b
+ $ hg revert -v b
+ forgetting b
+
+should not find b
+
+ $ hg status b
+ b: * (glob)
+
+should show a c e
+
+ $ ls
+ a
+ c
+ e
+
+should verbosely save backup to e.orig
+
+ $ echo z > e
+ $ hg revert --all -v
+ saving current version of e as e.orig
+ reverting e
+
+should say no changes needed
+
+ $ hg revert a
+ no changes needed to a
+
+should say file not managed
+
+ $ echo q > q
+ $ hg revert q
+ file not managed: q
+ $ rm q
+
+should say file not found
+
+ $ hg revert notfound
+ notfound: no such file in rev 334a9e57682c
+ $ touch d
+ $ hg add d
+ $ hg rm a
+ $ hg commit -m "second"
+ $ echo z > z
+ $ hg add z
+ $ hg st
+ A z
+ ? e.orig
+
+should add a, remove d, forget z
+
+ $ hg revert --all -r0
+ adding a
+ removing d
+ forgetting z
+
+should forget a, undelete d
+
+ $ hg revert --all -rtip
+ forgetting a
+ undeleting d
+ $ rm a *.orig
+
+should silently add a
+
+ $ hg revert -r0 a
+ $ hg st a
+ A a
+ $ hg rm d
+ $ hg st d
+ R d
+
+should silently keep d removed
+
+ $ hg revert -r0 d
+ $ hg st d
+ R d
+
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+#if execbit
+ $ chmod +x c
+ $ hg revert --all
+ reverting c
+
+should print non-executable
+
+ $ test -x c || echo non-executable
+ non-executable
+
+ $ chmod +x c
+ $ hg commit -m exe
+
+ $ chmod -x c
+ $ hg revert --all
+ reverting c
+
+should print executable
+
+ $ test -x c && echo executable
+ executable
+#endif
+
+ $ cd ..
+
+
+Issue241: update and revert produces inconsistent repositories
+
+ $ hg init a
+ $ cd a
+ $ echo a >> a
+ $ hg commit -A -d '1 0' -m a
+ adding a
+ $ echo a >> a
+ $ hg commit -d '2 0' -m a
+ $ hg update 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mkdir b
+ $ echo b > b/b
+
+should fail - no arguments
+
+ $ hg revert -rtip
+ abort: no files or directories specified
+ (use --all to revert all files, or 'hg update 1' to update)
+ [255]
+
+should succeed
+
+ $ hg revert --all -rtip
+ reverting a
+
+
+Issue332: confusing message when reverting directory
+
+ $ hg ci -A -m b
+ adding b/b
+ created new head
+ $ echo foobar > b/b
+ $ mkdir newdir
+ $ echo foo > newdir/newfile
+ $ hg add newdir/newfile
+ $ hg revert b newdir
+ reverting b/b (glob)
+ forgetting newdir/newfile (glob)
+ $ echo foobar > b/b
+ $ hg revert .
+ reverting b/b (glob)
+
+
+reverting a rename target should revert the source
+
+ $ hg mv a newa
+ $ hg revert newa
+ $ hg st a newa
+ ? newa
+
+ $ cd ..
+
+ $ hg init ignored
+ $ cd ignored
+ $ echo '^ignored$' > .hgignore
+ $ echo '^ignoreddir$' >> .hgignore
+ $ echo '^removed$' >> .hgignore
+
+ $ mkdir ignoreddir
+ $ touch ignoreddir/file
+ $ touch ignoreddir/removed
+ $ touch ignored
+ $ touch removed
+
+4 ignored files (we will add/commit everything)
+
+ $ hg st -A -X .hgignore
+ I ignored
+ I ignoreddir/file
+ I ignoreddir/removed
+ I removed
+ $ hg ci -qAm 'add files' ignored ignoreddir/file ignoreddir/removed removed
+
+ $ echo >> ignored
+ $ echo >> ignoreddir/file
+ $ hg rm removed ignoreddir/removed
+
+should revert ignored* and undelete *removed
+
+ $ hg revert -a --no-backup
+ reverting ignored
+ reverting ignoreddir/file (glob)
+ undeleting ignoreddir/removed (glob)
+ undeleting removed
+ $ hg st -mardi
+
+ $ hg up -qC
+ $ echo >> ignored
+ $ hg rm removed
+
+should silently revert the named files
+
+ $ hg revert --no-backup ignored removed
+ $ hg st -mardi
+
+ $ cd ..
diff --git a/tests/test-revlog-ancestry.py b/tests/test-revlog-ancestry.py
new file mode 100644
index 0000000..0834646
--- /dev/null
+++ b/tests/test-revlog-ancestry.py
@@ -0,0 +1,77 @@
+import os
+from mercurial import hg, ui, merge
+
+u = ui.ui()
+
+repo = hg.repository(u, 'test1', create=1)
+os.chdir('test1')
+
+def commit(text, time):
+ repo.commit(text=text, date="%d 0" % time)
+
+def addcommit(name, time):
+ f = open(name, 'w')
+ f.write('%s\n' % name)
+ f.close()
+ repo[None].add([name])
+ commit(name, time)
+
+def update(rev):
+ merge.update(repo, rev, False, True, False)
+
+def merge_(rev):
+ merge.update(repo, rev, True, False, False)
+
+if __name__ == '__main__':
+ addcommit("A", 0)
+ addcommit("B", 1)
+
+ update(0)
+ addcommit("C", 2)
+
+ merge_(1)
+ commit("D", 3)
+
+ update(2)
+ addcommit("E", 4)
+ addcommit("F", 5)
+
+ update(3)
+ addcommit("G", 6)
+
+ merge_(5)
+ commit("H", 7)
+
+ update(5)
+ addcommit("I", 8)
+
+ # Ancestors
+ print 'Ancestors of 5'
+ for r in repo.changelog.ancestors([5]):
+ print r,
+
+ print '\nAncestors of 6 and 5'
+ for r in repo.changelog.ancestors([6, 5]):
+ print r,
+
+ print '\nAncestors of 5 and 4'
+ for r in repo.changelog.ancestors([5, 4]):
+ print r,
+
+ print '\nAncestors of 7, stop at 6'
+ for r in repo.changelog.ancestors([7], 6):
+ print r,
+
+ # Descendants
+ print '\n\nDescendants of 5'
+ for r in repo.changelog.descendants([5]):
+ print r,
+
+ print '\nDescendants of 5 and 3'
+ for r in repo.changelog.descendants([5, 3]):
+ print r,
+
+ print '\nDescendants of 5 and 4'
+ for r in repo.changelog.descendants([5, 4]):
+ print r,
+
diff --git a/tests/test-revlog-ancestry.py.out b/tests/test-revlog-ancestry.py.out
new file mode 100644
index 0000000..d5c167a
--- /dev/null
+++ b/tests/test-revlog-ancestry.py.out
@@ -0,0 +1,15 @@
+Ancestors of 5
+4 2 0
+Ancestors of 6 and 5
+3 4 2 1 0
+Ancestors of 5 and 4
+4 2 0
+Ancestors of 7, stop at 6
+6
+
+Descendants of 5
+7 8
+Descendants of 5 and 3
+6 7 8
+Descendants of 5 and 4
+5 7 8
diff --git a/tests/test-revlog-group-emptyiter.t b/tests/test-revlog-group-emptyiter.t
new file mode 100644
index 0000000..905a6e0
--- /dev/null
+++ b/tests/test-revlog-group-emptyiter.t
@@ -0,0 +1,35 @@
+Issue1678: IndexError when pushing
+
+setting up base repo
+ $ hg init a
+ $ cd a
+ $ touch a
+ $ hg ci -Am a
+ adding a
+ $ cd ..
+
+cloning base repo
+ $ hg clone a b
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd b
+
+setting up cset to push
+ $ hg up null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ touch a
+different msg so we get a clog new entry
+ $ hg ci -Am b
+ adding a
+ created new head
+
+pushing
+ $ hg push -f ../a
+ pushing to ../a
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 0 changes to 0 files (+1 heads)
+
+ $ cd ..
diff --git a/tests/test-revlog-packentry.t b/tests/test-revlog-packentry.t
new file mode 100644
index 0000000..4bcb3f9
--- /dev/null
+++ b/tests/test-revlog-packentry.t
@@ -0,0 +1,23 @@
+ $ hg init repo
+ $ cd repo
+
+ $ touch foo
+ $ hg ci -Am 'add foo'
+ adding foo
+
+ $ hg up -C null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+this should be stored as a delta against rev 0
+
+ $ echo foo bar baz > foo
+ $ hg ci -Am 'add foo again'
+ adding foo
+ created new head
+
+ $ hg debugindex foo
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 0 ..... 0 b80de5d13875 000000000000 000000000000 (re)
+ 1 0 24 ..... 1 0376abec49b8 000000000000 000000000000 (re)
+
+ $ cd ..
diff --git a/tests/test-revset-dirstate-parents.t b/tests/test-revset-dirstate-parents.t
new file mode 100644
index 0000000..0582bc7
--- /dev/null
+++ b/tests/test-revset-dirstate-parents.t
@@ -0,0 +1,60 @@
+ $ HGENCODING=utf-8
+ $ export HGENCODING
+
+ $ try() {
+ > hg debugrevspec --debug $@
+ > }
+
+ $ log() {
+ > hg log --template '{rev}\n' -r "$1"
+ > }
+
+ $ hg init repo
+ $ cd repo
+
+ $ try 'p1()'
+ (func
+ ('symbol', 'p1')
+ None)
+ $ try 'p2()'
+ (func
+ ('symbol', 'p2')
+ None)
+ $ try 'parents()'
+ (func
+ ('symbol', 'parents')
+ None)
+
+null revision
+ $ log 'p1()'
+ $ log 'p2()'
+ $ log 'parents()'
+
+working dir with a single parent
+ $ echo a > a
+ $ hg ci -Aqm0
+ $ log 'p1()'
+ 0
+ $ log 'tag() and p1()'
+ $ log 'p2()'
+ $ log 'parents()'
+ 0
+ $ log 'tag() and parents()'
+
+merge in progress
+ $ echo b > b
+ $ hg ci -Aqm1
+ $ hg up -q 0
+ $ echo c > c
+ $ hg ci -Aqm2
+ $ hg merge -q
+ $ log 'p1()'
+ 2
+ $ log 'p2()'
+ 1
+ $ log 'tag() and p2()'
+ $ log 'parents()'
+ 1
+ 2
+
+ $ cd ..
diff --git a/tests/test-revset-outgoing.t b/tests/test-revset-outgoing.t
new file mode 100644
index 0000000..18d36f2
--- /dev/null
+++ b/tests/test-revset-outgoing.t
@@ -0,0 +1,94 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > graphlog=
+ >
+ > [alias]
+ > tlog = log --template "{rev}:{node|short}: '{desc}' {branches}\n"
+ > tglog = tlog -G
+ > tout = out --template "{rev}:{node|short}: '{desc}' {branches}\n"
+ > EOF
+
+ $ hg init a
+ $ cd a
+
+ $ echo a > a
+ $ hg ci -Aqm0
+
+ $ echo foo >> a
+ $ hg ci -Aqm1
+
+ $ hg up -q 0
+
+ $ hg branch stable
+ marked working directory as branch stable
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo bar >> a
+ $ hg ci -qm2
+
+ $ hg tglog
+ @ 2:7bee6c3bea3a: '2' stable
+ |
+ | o 1:3560197d8331: '1'
+ |/
+ o 0:f7b1eb17ad24: '0'
+
+
+ $ cd ..
+
+ $ hg clone -q a#stable b
+
+ $ cd b
+ $ cat .hg/hgrc
+ [paths]
+ default = $TESTTMP/a#stable (glob)
+
+ $ echo red >> a
+ $ hg ci -qm3
+
+ $ hg up -q default
+
+ $ echo blue >> a
+ $ hg ci -qm4
+
+ $ hg tglog
+ @ 3:f0461977a3db: '4'
+ |
+ | o 2:1d4099801a4e: '3' stable
+ | |
+ | o 1:7bee6c3bea3a: '2' stable
+ |/
+ o 0:f7b1eb17ad24: '0'
+
+
+ $ hg tout
+ comparing with $TESTTMP/a (glob)
+ searching for changes
+ 2:1d4099801a4e: '3' stable
+
+ $ hg tlog -r 'outgoing()'
+ 2:1d4099801a4e: '3' stable
+
+ $ hg tout ../a#default
+ comparing with ../a
+ searching for changes
+ 3:f0461977a3db: '4'
+
+ $ hg tlog -r 'outgoing("../a#default")'
+ 3:f0461977a3db: '4'
+
+ $ echo "green = ../a#default" >> .hg/hgrc
+
+ $ cat .hg/hgrc
+ [paths]
+ default = $TESTTMP/a#stable (glob)
+ green = ../a#default
+
+ $ hg tout green
+ comparing with $TESTTMP/a (glob)
+ searching for changes
+ 3:f0461977a3db: '4'
+
+ $ hg tlog -r 'outgoing("green")'
+ 3:f0461977a3db: '4'
+
+ $ cd ..
diff --git a/tests/test-revset.t b/tests/test-revset.t
new file mode 100644
index 0000000..2a41901
--- /dev/null
+++ b/tests/test-revset.t
@@ -0,0 +1,817 @@
+ $ HGENCODING=utf-8
+ $ export HGENCODING
+
+ $ try() {
+ > hg debugrevspec --debug "$@"
+ > }
+
+ $ log() {
+ > hg log --template '{rev}\n' -r "$1"
+ > }
+
+ $ hg init repo
+ $ cd repo
+
+ $ echo a > a
+ $ hg branch a
+ marked working directory as branch a
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Aqm0
+
+ $ echo b > b
+ $ hg branch b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Aqm1
+
+ $ rm a
+ $ hg branch a-b-c-
+ marked working directory as branch a-b-c-
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Aqm2 -u Bob
+
+ $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
+ 2
+ $ hg log -r "extra('branch')" --template '{rev}\n'
+ 0
+ 1
+ 2
+ $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
+ 0 a
+ 2 a-b-c-
+
+ $ hg co 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch +a+b+c+
+ marked working directory as branch +a+b+c+
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Aqm3
+
+ $ hg co 2 # interleave
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo bb > b
+ $ hg branch -- -a-b-c-
+ marked working directory as branch -a-b-c-
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Aqm4 -d "May 12 2005"
+
+ $ hg co 3
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch !a/b/c/
+ marked working directory as branch !a/b/c/
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Aqm"5 bug"
+
+ $ hg merge 4
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg branch _a_b_c_
+ marked working directory as branch _a_b_c_
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Aqm"6 issue619"
+
+ $ hg branch .a.b.c.
+ marked working directory as branch .a.b.c.
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Aqm7
+
+ $ hg branch all
+ marked working directory as branch all
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci --close-branch -Aqm8
+ abort: can only close branch heads
+ [255]
+
+ $ hg co 4
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg branch é
+ marked working directory as branch \xc3\xa9 (esc)
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -Aqm9
+
+ $ hg tag -r6 1.0
+
+ $ hg clone --quiet -U -r 7 . ../remote1
+ $ hg clone --quiet -U -r 8 . ../remote2
+ $ echo "[paths]" >> .hg/hgrc
+ $ echo "default = ../remote1" >> .hg/hgrc
+
+names that should work without quoting
+
+ $ try a
+ ('symbol', 'a')
+ 0
+ $ try b-a
+ (minus
+ ('symbol', 'b')
+ ('symbol', 'a'))
+ 1
+ $ try _a_b_c_
+ ('symbol', '_a_b_c_')
+ 6
+ $ try _a_b_c_-a
+ (minus
+ ('symbol', '_a_b_c_')
+ ('symbol', 'a'))
+ 6
+ $ try .a.b.c.
+ ('symbol', '.a.b.c.')
+ 7
+ $ try .a.b.c.-a
+ (minus
+ ('symbol', '.a.b.c.')
+ ('symbol', 'a'))
+ 7
+ $ try -- '-a-b-c-' # complains
+ hg: parse error at 7: not a prefix: end
+ [255]
+ $ log -a-b-c- # succeeds with fallback
+ 4
+ $ try -- -a-b-c--a # complains
+ (minus
+ (minus
+ (minus
+ (negate
+ ('symbol', 'a'))
+ ('symbol', 'b'))
+ ('symbol', 'c'))
+ (negate
+ ('symbol', 'a')))
+ abort: unknown revision '-a'!
+ [255]
+ $ try é
+ ('symbol', '\xc3\xa9')
+ 9
+
+quoting needed
+
+ $ try '"-a-b-c-"-a'
+ (minus
+ ('string', '-a-b-c-')
+ ('symbol', 'a'))
+ 4
+
+ $ log '1 or 2'
+ 1
+ 2
+ $ log '1|2'
+ 1
+ 2
+ $ log '1 and 2'
+ $ log '1&2'
+ $ try '1&2|3' # precedence - and is higher
+ (or
+ (and
+ ('symbol', '1')
+ ('symbol', '2'))
+ ('symbol', '3'))
+ 3
+ $ try '1|2&3'
+ (or
+ ('symbol', '1')
+ (and
+ ('symbol', '2')
+ ('symbol', '3')))
+ 1
+ $ try '1&2&3' # associativity
+ (and
+ (and
+ ('symbol', '1')
+ ('symbol', '2'))
+ ('symbol', '3'))
+ $ try '1|(2|3)'
+ (or
+ ('symbol', '1')
+ (group
+ (or
+ ('symbol', '2')
+ ('symbol', '3'))))
+ 1
+ 2
+ 3
+ $ log '1.0' # tag
+ 6
+ $ log 'a' # branch
+ 0
+ $ log '2785f51ee'
+ 0
+ $ log 'date(2005)'
+ 4
+ $ log 'date(this is a test)'
+ hg: parse error at 10: unexpected token: symbol
+ [255]
+ $ log 'date()'
+ hg: parse error: date requires a string
+ [255]
+ $ log 'date'
+ hg: parse error: can't use date here
+ [255]
+ $ log 'date('
+ hg: parse error at 5: not a prefix: end
+ [255]
+ $ log 'date(tip)'
+ abort: invalid date: 'tip'
+ [255]
+ $ log '"date"'
+ abort: unknown revision 'date'!
+ [255]
+ $ log 'date(2005) and 1::'
+ 4
+
+ $ log 'ancestor(1)'
+ hg: parse error: ancestor requires two arguments
+ [255]
+ $ log 'ancestor(4,5)'
+ 1
+ $ log 'ancestor(4,5) and 4'
+ $ log 'ancestors(5)'
+ 0
+ 1
+ 3
+ 5
+ $ log 'author(bob)'
+ 2
+ $ log 'author("re:bob|test")'
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ $ log 'branch(é)'
+ 8
+ 9
+ $ log 'branch(a)'
+ 0
+ $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
+ 0 a
+ 2 a-b-c-
+ 3 +a+b+c+
+ 4 -a-b-c-
+ 5 !a/b/c/
+ 6 _a_b_c_
+ 7 .a.b.c.
+ $ log 'children(ancestor(4,5))'
+ 2
+ 3
+ $ log 'closed()'
+ $ log 'contains(a)'
+ 0
+ 1
+ 3
+ 5
+ $ log 'desc(B)'
+ 5
+ $ log 'descendants(2 or 3)'
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ $ log 'file("b*")'
+ 1
+ 4
+ $ log 'follow()'
+ 0
+ 1
+ 2
+ 4
+ 8
+ 9
+ $ log 'grep("issue\d+")'
+ 6
+ $ try 'grep("(")' # invalid regular expression
+ (func
+ ('symbol', 'grep')
+ ('string', '('))
+ hg: parse error: invalid match pattern: unbalanced parenthesis
+ [255]
+ $ try 'grep("\bissue\d+")'
+ (func
+ ('symbol', 'grep')
+ ('string', '\x08issue\\d+'))
+ $ try 'grep(r"\bissue\d+")'
+ (func
+ ('symbol', 'grep')
+ ('string', '\\bissue\\d+'))
+ 6
+ $ try 'grep(r"\")'
+ hg: parse error at 7: unterminated string
+ [255]
+ $ log 'head()'
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 9
+ $ log 'heads(6::)'
+ 7
+ $ log 'keyword(issue)'
+ 6
+ $ log 'limit(head(), 1)'
+ 0
+ $ log 'matching(6)'
+ 6
+ $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
+ 6
+ 7
+ $ log 'max(contains(a))'
+ 5
+ $ log 'min(contains(a))'
+ 0
+ $ log 'merge()'
+ 6
+ $ log 'modifies(b)'
+ 4
+ $ log 'modifies("path:b")'
+ 4
+ $ log 'modifies("*")'
+ 4
+ 6
+ $ log 'modifies("set:modified()")'
+ 4
+ $ log 'id(5)'
+ 2
+ $ log 'outgoing()'
+ 8
+ 9
+ $ log 'outgoing("../remote1")'
+ 8
+ 9
+ $ log 'outgoing("../remote2")'
+ 3
+ 5
+ 6
+ 7
+ 9
+ $ log 'p1(merge())'
+ 5
+ $ log 'p2(merge())'
+ 4
+ $ log 'parents(merge())'
+ 4
+ 5
+ $ log 'removes(a)'
+ 2
+ 6
+ $ log 'roots(all())'
+ 0
+ $ log 'reverse(2 or 3 or 4 or 5)'
+ 5
+ 4
+ 3
+ 2
+ $ log 'reverse(all())'
+ 9
+ 8
+ 7
+ 6
+ 5
+ 4
+ 3
+ 2
+ 1
+ 0
+ $ log 'rev(5)'
+ 5
+ $ log 'sort(limit(reverse(all()), 3))'
+ 7
+ 8
+ 9
+ $ log 'sort(2 or 3 or 4 or 5, date)'
+ 2
+ 3
+ 5
+ 4
+ $ log 'tagged()'
+ 6
+ $ log 'tag()'
+ 6
+ $ log 'tag(1.0)'
+ 6
+ $ log 'tag(tip)'
+ 9
+
+we can use patterns when searching for tags
+
+ $ log 'tag("1..*")'
+ abort: tag '1..*' does not exist
+ [255]
+ $ log 'tag("re:1..*")'
+ 6
+ $ log 'tag("re:[0-9].[0-9]")'
+ 6
+ $ log 'tag("literal:1.0")'
+ 6
+ $ log 'tag("re:0..*")'
+ abort: no tags exist that match '0..*'
+ [255]
+
+ $ log 'tag(unknown)'
+ abort: tag 'unknown' does not exist
+ [255]
+ $ log 'branch(unknown)'
+ abort: unknown revision 'unknown'!
+ [255]
+ $ log 'user(bob)'
+ 2
+
+ $ log '4::8'
+ 4
+ 8
+ $ log '4:8'
+ 4
+ 5
+ 6
+ 7
+ 8
+
+ $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
+ 4
+ 2
+ 5
+
+ $ log 'not 0 and 0:2'
+ 1
+ 2
+ $ log 'not 1 and 0:2'
+ 0
+ 2
+ $ log 'not 2 and 0:2'
+ 0
+ 1
+ $ log '(1 and 2)::'
+ $ log '(1 and 2):'
+ $ log '(1 and 2):3'
+ $ log 'sort(head(), -rev)'
+ 9
+ 7
+ 6
+ 5
+ 4
+ 3
+ 2
+ 1
+ 0
+ $ log '4::8 - 8'
+ 4
+ $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
+ 2
+ 3
+ 1
+
+issue2437
+
+ $ log '3 and p1(5)'
+ 3
+ $ log '4 and p2(6)'
+ 4
+ $ log '1 and parents(:2)'
+ 1
+ $ log '2 and children(1:)'
+ 2
+ $ log 'roots(all()) or roots(all())'
+ 0
+ $ hg debugrevspec 'roots(all()) or roots(all())'
+ 0
+ $ log 'heads(branch(é)) or heads(branch(é))'
+ 9
+ $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(é)))'
+ 4
+
+issue2654: report a parse error if the revset was not completely parsed
+
+ $ log '1 OR 2'
+ hg: parse error at 2: invalid token
+ [255]
+
+or operator should preserve ordering:
+ $ log 'reverse(2::4) or tip'
+ 4
+ 2
+ 9
+
+parentrevspec
+
+ $ log 'merge()^0'
+ 6
+ $ log 'merge()^'
+ 5
+ $ log 'merge()^1'
+ 5
+ $ log 'merge()^2'
+ 4
+ $ log 'merge()^^'
+ 3
+ $ log 'merge()^1^'
+ 3
+ $ log 'merge()^^^'
+ 1
+
+ $ log 'merge()~0'
+ 6
+ $ log 'merge()~1'
+ 5
+ $ log 'merge()~2'
+ 3
+ $ log 'merge()~2^1'
+ 1
+ $ log 'merge()~3'
+ 1
+
+ $ log '(-3:tip)^'
+ 4
+ 6
+ 8
+
+ $ log 'tip^foo'
+ hg: parse error: ^ expects a number 0, 1, or 2
+ [255]
+
+aliases:
+
+ $ echo '[revsetalias]' >> .hg/hgrc
+ $ echo 'm = merge()' >> .hg/hgrc
+ $ echo 'sincem = descendants(m)' >> .hg/hgrc
+ $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
+ $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
+ $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
+
+ $ try m
+ ('symbol', 'm')
+ (func
+ ('symbol', 'merge')
+ None)
+ 6
+
+test alias recursion
+
+ $ try sincem
+ ('symbol', 'sincem')
+ (func
+ ('symbol', 'descendants')
+ (func
+ ('symbol', 'merge')
+ None))
+ 6
+ 7
+
+test infinite recursion
+
+ $ echo 'recurse1 = recurse2' >> .hg/hgrc
+ $ echo 'recurse2 = recurse1' >> .hg/hgrc
+ $ try recurse1
+ ('symbol', 'recurse1')
+ hg: parse error: infinite expansion of revset alias "recurse1" detected
+ [255]
+
+ $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
+ $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
+ $ try "level2(level1(1, 2), 3)"
+ (func
+ ('symbol', 'level2')
+ (list
+ (func
+ ('symbol', 'level1')
+ (list
+ ('symbol', '1')
+ ('symbol', '2')))
+ ('symbol', '3')))
+ (or
+ ('symbol', '3')
+ (or
+ ('symbol', '1')
+ ('symbol', '2')))
+ 3
+ 1
+ 2
+
+test nesting and variable passing
+
+ $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
+ $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
+ $ echo 'nested3($1) = max($1)' >> .hg/hgrc
+ $ try 'nested(2:5)'
+ (func
+ ('symbol', 'nested')
+ (range
+ ('symbol', '2')
+ ('symbol', '5')))
+ (func
+ ('symbol', 'max')
+ (range
+ ('symbol', '2')
+ ('symbol', '5')))
+ 5
+
+test variable isolation, variable placeholders are rewritten as string
+then parsed and matched again as string. Check they do not leak too
+far away.
+
+ $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
+ $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
+ $ try 'callinjection(2:5)'
+ (func
+ ('symbol', 'callinjection')
+ (range
+ ('symbol', '2')
+ ('symbol', '5')))
+ (func
+ ('symbol', 'descendants')
+ (func
+ ('symbol', 'max')
+ ('string', '$1')))
+ abort: unknown revision '$1'!
+ [255]
+
+ $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
+ $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
+ $ try 'callinjection2(2:5)'
+ (func
+ ('symbol', 'callinjection2')
+ (range
+ ('symbol', '2')
+ ('symbol', '5')))
+ hg: parse error: not a function: _aliasarg
+ [255]
+ >>> data = file('.hg/hgrc', 'rb').read()
+ >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
+
+ $ try 'd(2:5)'
+ (func
+ ('symbol', 'd')
+ (range
+ ('symbol', '2')
+ ('symbol', '5')))
+ (func
+ ('symbol', 'reverse')
+ (func
+ ('symbol', 'sort')
+ (list
+ (range
+ ('symbol', '2')
+ ('symbol', '5'))
+ ('symbol', 'date'))))
+ 4
+ 5
+ 3
+ 2
+ $ try 'rs(2 or 3, date)'
+ (func
+ ('symbol', 'rs')
+ (list
+ (or
+ ('symbol', '2')
+ ('symbol', '3'))
+ ('symbol', 'date')))
+ (func
+ ('symbol', 'reverse')
+ (func
+ ('symbol', 'sort')
+ (list
+ (or
+ ('symbol', '2')
+ ('symbol', '3'))
+ ('symbol', 'date'))))
+ 3
+ 2
+ $ try 'rs()'
+ (func
+ ('symbol', 'rs')
+ None)
+ hg: parse error: invalid number of arguments: 0
+ [255]
+ $ try 'rs(2)'
+ (func
+ ('symbol', 'rs')
+ ('symbol', '2'))
+ hg: parse error: invalid number of arguments: 1
+ [255]
+ $ try 'rs(2, data, 7)'
+ (func
+ ('symbol', 'rs')
+ (list
+ (list
+ ('symbol', '2')
+ ('symbol', 'data'))
+ ('symbol', '7')))
+ hg: parse error: invalid number of arguments: 3
+ [255]
+ $ try 'rs4(2 or 3, x, x, date)'
+ (func
+ ('symbol', 'rs4')
+ (list
+ (list
+ (list
+ (or
+ ('symbol', '2')
+ ('symbol', '3'))
+ ('symbol', 'x'))
+ ('symbol', 'x'))
+ ('symbol', 'date')))
+ (func
+ ('symbol', 'reverse')
+ (func
+ ('symbol', 'sort')
+ (list
+ (or
+ ('symbol', '2')
+ ('symbol', '3'))
+ ('symbol', 'date'))))
+ 3
+ 2
+
+issue2549 - correct optimizations
+
+ $ log 'limit(1 or 2 or 3, 2) and not 2'
+ 1
+ $ log 'max(1 or 2) and not 2'
+ $ log 'min(1 or 2) and not 1'
+ $ log 'last(1 or 2, 1) and not 2'
+
+tests for 'remote()' predicate:
+#. (csets in remote) (id) (remote)
+1. less than local current branch "default"
+2. same with local specified "default"
+3. more than local specified specified
+
+ $ hg clone --quiet -U . ../remote3
+ $ cd ../remote3
+ $ hg update -q 7
+ $ echo r > r
+ $ hg ci -Aqm 10
+ $ log 'remote()'
+ 7
+ $ log 'remote("a-b-c-")'
+ 2
+ $ cd ../repo
+ $ log 'remote(".a.b.c.", "../remote3")'
+
+ $ cd ..
+
+test author/desc/keyword in problematic encoding
+# unicode: cp932:
+# u30A2 0x83 0x41(= 'A')
+# u30C2 0x83 0x61(= 'a')
+
+ $ hg init problematicencoding
+ $ cd problematicencoding
+
+ $ python > setup.sh <<EOF
+ > print u'''
+ > echo a > text
+ > hg add text
+ > hg --encoding utf-8 commit -u '\u30A2' -m none
+ > echo b > text
+ > hg --encoding utf-8 commit -u '\u30C2' -m none
+ > echo c > text
+ > hg --encoding utf-8 commit -u none -m '\u30A2'
+ > echo d > text
+ > hg --encoding utf-8 commit -u none -m '\u30C2'
+ > '''.encode('utf-8')
+ > EOF
+ $ sh < setup.sh
+
+test in problematic encoding
+ $ python > test.sh <<EOF
+ > print u'''
+ > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
+ > echo ====
+ > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
+ > echo ====
+ > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
+ > echo ====
+ > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
+ > echo ====
+ > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
+ > echo ====
+ > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
+ > '''.encode('cp932')
+ > EOF
+ $ sh < test.sh
+ 0
+ ====
+ 1
+ ====
+ 2
+ ====
+ 3
+ ====
+ 0
+ 2
+ ====
+ 1
+ 3
+
+ $ cd ..
diff --git a/tests/test-rollback.t b/tests/test-rollback.t
new file mode 100644
index 0000000..305555b
--- /dev/null
+++ b/tests/test-rollback.t
@@ -0,0 +1,187 @@
+setup repo
+ $ hg init t
+ $ cd t
+ $ echo a > a
+ $ hg commit -Am'add a'
+ adding a
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+ $ hg parents
+ changeset: 0:1f0dee641bb7
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+
+rollback to null revision
+ $ hg status
+ $ hg rollback
+ repository tip rolled back to revision -1 (undo commit)
+ working directory now based on revision -1
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 0 files, 0 changesets, 0 total revisions
+ $ hg parents
+ $ hg status
+ A a
+
+Two changesets this time so we rollback to a real changeset
+ $ hg commit -m'add a again'
+ $ echo a >> a
+ $ hg commit -m'modify a'
+
+Test issue 902 (current branch is preserved)
+ $ hg branch test
+ marked working directory as branch test
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg rollback
+ repository tip rolled back to revision 0 (undo commit)
+ working directory now based on revision 0
+ $ hg branch
+ default
+
+Test issue 1635 (commit message saved)
+ $ cat .hg/last-message.txt ; echo
+ modify a
+
+Test rollback of hg before issue 902 was fixed
+
+ $ hg commit -m "test3"
+ $ hg branch test
+ marked working directory as branch test
+ (branches are permanent and global, did you want a bookmark?)
+ $ rm .hg/undo.branch
+ $ hg rollback
+ repository tip rolled back to revision 0 (undo commit)
+ named branch could not be reset: current branch is still 'test'
+ working directory now based on revision 0
+ $ hg branch
+ test
+
+working dir unaffected by rollback: do not restore dirstate et. al.
+ $ hg log --template '{rev} {branch} {desc|firstline}\n'
+ 0 default add a again
+ $ hg status
+ M a
+ $ hg bookmark foo
+ $ hg commit -m'modify a again'
+ $ echo b > b
+ $ hg commit -Am'add b'
+ adding b
+ $ hg log --template '{rev} {branch} {desc|firstline}\n'
+ 2 test add b
+ 1 test modify a again
+ 0 default add a again
+ $ hg update default
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg bookmark bar
+ $ cat .hg/undo.branch ; echo
+ test
+ $ hg rollback -f
+ repository tip rolled back to revision 1 (undo commit)
+ $ hg id -n
+ 0
+ $ hg branch
+ default
+ $ cat .hg/bookmarks.current ; echo
+ bar
+ $ hg bookmark --delete foo
+
+rollback by pretxncommit saves commit message (issue 1635)
+
+ $ echo a >> a
+ $ hg --config hooks.pretxncommit=false commit -m"precious commit message"
+ transaction abort!
+ rollback completed
+ abort: pretxncommit hook exited with status * (glob)
+ [255]
+ $ cat .hg/last-message.txt ; echo
+ precious commit message
+
+same thing, but run $EDITOR
+
+ $ cat > editor.sh << '__EOF__'
+ > echo "another precious commit message" > "$1"
+ > __EOF__
+ $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg --config hooks.pretxncommit=false commit 2>&1
+ transaction abort!
+ rollback completed
+ note: commit message saved in .hg/last-message.txt
+ abort: pretxncommit hook exited with status * (glob)
+ [255]
+ $ cat .hg/last-message.txt
+ another precious commit message
+
+test rollback on served repository
+
+#if serve
+ $ hg commit -m "precious commit message"
+ $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ cd ..
+ $ hg clone http://localhost:$HGPORT u
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 2 changes to 1 files (+1 heads)
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd u
+ $ hg id default
+ 068774709090
+
+now rollback and observe that 'hg serve' reloads the repository and
+presents the correct tip changeset:
+
+ $ hg -R ../t rollback
+ repository tip rolled back to revision 1 (undo commit)
+ working directory now based on revision 0
+ $ hg id default
+ 791dd2169706
+#endif
+
+update to older changeset and then refuse rollback, because
+that would lose data (issue2998)
+ $ cd ../t
+ $ hg -q update
+ $ rm `hg status -un`
+ $ template='{rev}:{node|short} [{branch}] {desc|firstline}\n'
+ $ echo 'valuable new file' > b
+ $ echo 'valuable modification' >> a
+ $ hg commit -A -m'a valuable change'
+ adding b
+ $ hg update 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg rollback
+ abort: rollback of last commit while not checked out may lose data
+ (use -f to force)
+ [255]
+ $ hg tip -q
+ 2:4d9cd3795eea
+ $ hg rollback -f
+ repository tip rolled back to revision 1 (undo commit)
+ $ hg status
+ $ hg log --removed b # yep, it's gone
+
+same again, but emulate an old client that doesn't write undo.desc
+ $ hg -q update
+ $ echo 'valuable modification redux' >> a
+ $ hg commit -m'a valuable change redux'
+ $ rm .hg/undo.desc
+ $ hg update 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg rollback
+ rolling back unknown transaction
+ $ cat a
+ a
+
+ $ cd ..
diff --git a/tests/test-run-tests.t b/tests/test-run-tests.t
new file mode 100644
index 0000000..68b60cf
--- /dev/null
+++ b/tests/test-run-tests.t
@@ -0,0 +1,99 @@
+Simple commands:
+
+ $ echo foo
+ foo
+ $ printf 'oh no'
+ oh no (no-eol)
+ $ printf 'bar\nbaz\n' | cat
+ bar
+ baz
+
+Multi-line command:
+
+ $ foo() {
+ > echo bar
+ > }
+ $ foo
+ bar
+
+Return codes before inline python:
+
+ $ sh -c 'exit 1'
+ [1]
+
+Doctest commands:
+
+ >>> print 'foo'
+ foo
+ $ echo interleaved
+ interleaved
+ >>> for c in 'xyz':
+ ... print c
+ x
+ y
+ z
+ >>> print
+
+
+Regular expressions:
+
+ $ echo foobarbaz
+ foobar.* (re)
+ $ echo barbazquux
+ .*quux.* (re)
+
+Globs:
+
+ $ printf '* \\foobarbaz {10}\n'
+ \* \\fo?bar* {10} (glob)
+
+Literal match ending in " (re)":
+
+ $ echo 'foo (re)'
+ foo (re)
+
+testing hghave
+
+ $ "$TESTDIR/hghave" true
+ $ "$TESTDIR/hghave" false
+ skipped: missing feature: nail clipper
+ [1]
+ $ "$TESTDIR/hghave" no-true
+ skipped: system supports yak shaving
+ [1]
+ $ "$TESTDIR/hghave" no-false
+
+Conditional sections based on hghave:
+
+#if true
+ $ echo tested
+ tested
+#else
+ $ echo skipped
+#endif
+
+#if false
+ $ echo skipped
+#else
+ $ echo tested
+ tested
+#endif
+
+#if no-false
+ $ echo tested
+ tested
+#else
+ $ echo skipped
+#endif
+
+#if no-true
+ $ echo skipped
+#else
+ $ echo tested
+ tested
+#endif
+
+Exit code:
+
+ $ (exit 1)
+ [1]
diff --git a/tests/test-schemes.t b/tests/test-schemes.t
new file mode 100644
index 0000000..a31ae80
--- /dev/null
+++ b/tests/test-schemes.t
@@ -0,0 +1,50 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > schemes=
+ >
+ > [schemes]
+ > l = http://localhost:$HGPORT/
+ > parts = http://{1}:$HGPORT/
+ > z = file:\$PWD/
+ > EOF
+ $ hg init test
+ $ cd test
+ $ echo a > a
+ $ hg ci -Am initial
+ adding a
+ $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ hg incoming l://
+ comparing with l://
+ searching for changes
+ no changes found
+ [1]
+
+check that {1} syntax works
+
+ $ hg incoming --debug parts://localhost
+ using http://localhost:$HGPORT/
+ sending capabilities command
+ comparing with parts://localhost/
+ query 1; heads
+ sending batch command
+ searching for changes
+ all remote heads known locally
+ no changes found
+ [1]
+
+check that paths are expanded
+
+ $ PWD=`pwd` hg incoming z://
+ comparing with z://
+ searching for changes
+ no changes found
+ [1]
+
+errors
+
+ $ cat errors.log
+
+ $ cd ..
diff --git a/tests/test-serve.t b/tests/test-serve.t
new file mode 100644
index 0000000..8ae4a86
--- /dev/null
+++ b/tests/test-serve.t
@@ -0,0 +1,84 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ hgserve()
+ > {
+ > hg serve -a localhost -d --pid-file=hg.pid -E errors.log -v $@ \
+ > | sed -e "s/:$HGPORT1\\([^0-9]\\)/:HGPORT1\1/g" \
+ > -e "s/:$HGPORT2\\([^0-9]\\)/:HGPORT2\1/g" \
+ > -e 's/http:\/\/[^/]*\//http:\/\/localhost\//'
+ > cat hg.pid >> "$DAEMON_PIDS"
+ > echo % errors
+ > cat errors.log
+ > if [ "$KILLQUIETLY" = "Y" ]; then
+ > kill `cat hg.pid` 2>/dev/null
+ > else
+ > kill `cat hg.pid`
+ > fi
+ > while kill -0 `cat hg.pid` 2>/dev/null; do sleep 0; done
+ > }
+
+ $ hg init test
+ $ cd test
+ $ echo '[web]' > .hg/hgrc
+ $ echo 'accesslog = access.log' >> .hg/hgrc
+ $ echo "port = $HGPORT1" >> .hg/hgrc
+
+Without -v
+
+ $ hg serve -a localhost -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ $ cat hg.pid >> "$DAEMON_PIDS"
+ $ if [ -f access.log ]; then
+ > echo 'access log created - .hg/hgrc respected'
+ > fi
+ access log created - .hg/hgrc respected
+
+errors
+
+ $ cat errors.log
+
+With -v
+
+ $ hgserve
+ listening at http://localhost/ (bound to 127.0.0.1:HGPORT1)
+ % errors
+
+With -v and -p HGPORT2
+
+ $ hgserve -p "$HGPORT2"
+ listening at http://localhost/ (bound to 127.0.0.1:HGPORT2)
+ % errors
+
+With -v and -p daytime (should fail because low port)
+
+ $ KILLQUIETLY=Y
+ $ hgserve -p daytime
+ abort: cannot start server at 'localhost:13': Permission denied
+ abort: child process failed to start
+ % errors
+ $ KILLQUIETLY=N
+
+With --prefix foo
+
+ $ hgserve --prefix foo
+ listening at http://localhost/foo/ (bound to 127.0.0.1:HGPORT1)
+ % errors
+
+With --prefix /foo
+
+ $ hgserve --prefix /foo
+ listening at http://localhost/foo/ (bound to 127.0.0.1:HGPORT1)
+ % errors
+
+With --prefix foo/
+
+ $ hgserve --prefix foo/
+ listening at http://localhost/foo/ (bound to 127.0.0.1:HGPORT1)
+ % errors
+
+With --prefix /foo/
+
+ $ hgserve --prefix /foo/
+ listening at http://localhost/foo/ (bound to 127.0.0.1:HGPORT1)
+ % errors
+
+ $ cd ..
diff --git a/tests/test-setdiscovery.t b/tests/test-setdiscovery.t
new file mode 100644
index 0000000..cca197d
--- /dev/null
+++ b/tests/test-setdiscovery.t
@@ -0,0 +1,327 @@
+
+Function to test discovery between two repos in both directions, using both the local shortcut
+(which is currently not activated by default) and the full remotable protocol:
+
+ $ testdesc() { # revs_a, revs_b, dagdesc
+ > if [ -d foo ]; then rm -rf foo; fi
+ > hg init foo
+ > cd foo
+ > hg debugbuilddag "$3"
+ > hg clone . a $1 --quiet
+ > hg clone . b $2 --quiet
+ > echo
+ > echo "% -- a -> b tree"
+ > hg -R a debugdiscovery b --verbose --old
+ > echo
+ > echo "% -- a -> b set"
+ > hg -R a debugdiscovery b --verbose --debug
+ > echo
+ > echo "% -- b -> a tree"
+ > hg -R b debugdiscovery a --verbose --old
+ > echo
+ > echo "% -- b -> a set"
+ > hg -R b debugdiscovery a --verbose --debug
+ > cd ..
+ > }
+
+
+Small superset:
+
+ $ testdesc '-ra1 -ra2' '-rb1 -rb2 -rb3' '
+ > +2:f +1:a1:b1
+ > <f +4 :a2
+ > +5 :b2
+ > <f +3 :b3'
+
+ % -- a -> b tree
+ comparing with b
+ searching for changes
+ unpruned common: b5714e113bc0 66f7d451a68b 01241442b3c2
+ common heads: b5714e113bc0 01241442b3c2
+ local is subset
+
+ % -- a -> b set
+ comparing with b
+ query 1; heads
+ searching for changes
+ all local heads known remotely
+ common heads: b5714e113bc0 01241442b3c2
+ local is subset
+
+ % -- b -> a tree
+ comparing with a
+ searching for changes
+ unpruned common: b5714e113bc0 01241442b3c2
+ common heads: b5714e113bc0 01241442b3c2
+ remote is subset
+
+ % -- b -> a set
+ comparing with a
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ common heads: b5714e113bc0 01241442b3c2
+ remote is subset
+
+
+Many new:
+
+ $ testdesc '-ra1 -ra2' '-rb' '
+ > +2:f +3:a1 +3:b
+ > <f +30 :a2'
+
+ % -- a -> b tree
+ comparing with b
+ searching for changes
+ unpruned common: bebd167eb94d
+ common heads: bebd167eb94d
+
+ % -- a -> b set
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking initial sample
+ searching: 2 queries
+ query 2; still undecided: 29, sample size is: 29
+ 2 total queries
+ common heads: bebd167eb94d
+
+ % -- b -> a tree
+ comparing with a
+ searching for changes
+ unpruned common: bebd167eb94d 66f7d451a68b
+ common heads: bebd167eb94d
+
+ % -- b -> a set
+ comparing with a
+ query 1; heads
+ searching for changes
+ taking initial sample
+ searching: 2 queries
+ query 2; still undecided: 2, sample size is: 2
+ 2 total queries
+ common heads: bebd167eb94d
+
+
+Both sides many new with stub:
+
+ $ testdesc '-ra1 -ra2' '-rb' '
+ > +2:f +2:a1 +30 :b
+ > <f +30 :a2'
+
+ % -- a -> b tree
+ comparing with b
+ searching for changes
+ unpruned common: 2dc09a01254d
+ common heads: 2dc09a01254d
+
+ % -- a -> b set
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking initial sample
+ searching: 2 queries
+ query 2; still undecided: 29, sample size is: 29
+ 2 total queries
+ common heads: 2dc09a01254d
+
+ % -- b -> a tree
+ comparing with a
+ searching for changes
+ unpruned common: 66f7d451a68b 2dc09a01254d
+ common heads: 2dc09a01254d
+
+ % -- b -> a set
+ comparing with a
+ query 1; heads
+ searching for changes
+ taking initial sample
+ searching: 2 queries
+ query 2; still undecided: 29, sample size is: 29
+ 2 total queries
+ common heads: 2dc09a01254d
+
+
+Both many new:
+
+ $ testdesc '-ra' '-rb' '
+ > +2:f +30 :b
+ > <f +30 :a'
+
+ % -- a -> b tree
+ comparing with b
+ searching for changes
+ unpruned common: 66f7d451a68b
+ common heads: 66f7d451a68b
+
+ % -- a -> b set
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 31, sample size is: 31
+ 2 total queries
+ common heads: 66f7d451a68b
+
+ % -- b -> a tree
+ comparing with a
+ searching for changes
+ unpruned common: 66f7d451a68b
+ common heads: 66f7d451a68b
+
+ % -- b -> a set
+ comparing with a
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 31, sample size is: 31
+ 2 total queries
+ common heads: 66f7d451a68b
+
+
+Both many new skewed:
+
+ $ testdesc '-ra' '-rb' '
+ > +2:f +30 :b
+ > <f +50 :a'
+
+ % -- a -> b tree
+ comparing with b
+ searching for changes
+ unpruned common: 66f7d451a68b
+ common heads: 66f7d451a68b
+
+ % -- a -> b set
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 51, sample size is: 51
+ 2 total queries
+ common heads: 66f7d451a68b
+
+ % -- b -> a tree
+ comparing with a
+ searching for changes
+ unpruned common: 66f7d451a68b
+ common heads: 66f7d451a68b
+
+ % -- b -> a set
+ comparing with a
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 31, sample size is: 31
+ 2 total queries
+ common heads: 66f7d451a68b
+
+
+Both many new on top of long history:
+
+ $ testdesc '-ra' '-rb' '
+ > +1000:f +30 :b
+ > <f +50 :a'
+
+ % -- a -> b tree
+ comparing with b
+ searching for changes
+ unpruned common: 7ead0cba2838
+ common heads: 7ead0cba2838
+
+ % -- a -> b set
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 1049, sample size is: 11
+ sampling from both directions
+ searching: 3 queries
+ query 3; still undecided: 31, sample size is: 31
+ 3 total queries
+ common heads: 7ead0cba2838
+
+ % -- b -> a tree
+ comparing with a
+ searching for changes
+ unpruned common: 7ead0cba2838
+ common heads: 7ead0cba2838
+
+ % -- b -> a set
+ comparing with a
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 1029, sample size is: 11
+ sampling from both directions
+ searching: 3 queries
+ query 3; still undecided: 15, sample size is: 15
+ 3 total queries
+ common heads: 7ead0cba2838
+
+
+One with >200 heads, which used to use up all of the sample:
+
+ $ hg init manyheads
+ $ cd manyheads
+ $ echo "+300:r @a" >dagdesc
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
+ $ echo "@b *r+3" >>dagdesc # one more head
+ $ hg debugbuilddag <dagdesc
+ reading DAG from stdin
+
+ $ hg heads -t --template . | wc -c
+ \s*261 (re)
+
+ $ hg clone -b a . a
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1340 changesets with 0 changes to 0 files (+259 heads)
+ updating to branch a
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg clone -b b . b
+ adding changesets
+ adding manifests
+ adding file changes
+ added 304 changesets with 0 changes to 0 files
+ updating to branch b
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg -R a debugdiscovery b --debug --verbose
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 1080, sample size is: 260
+ sampling from both directions
+ searching: 3 queries
+ query 3; still undecided: 820, sample size is: 260
+ sampling from both directions
+ searching: 4 queries
+ query 4; still undecided: 560, sample size is: 260
+ sampling from both directions
+ searching: 5 queries
+ query 5; still undecided: 300, sample size is: 200
+ 5 total queries
+ common heads: 3ee37d65064a
+
+ $ cd ..
diff --git a/tests/test-share.t b/tests/test-share.t
new file mode 100644
index 0000000..0eb755f
--- /dev/null
+++ b/tests/test-share.t
@@ -0,0 +1,129 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "share = " >> $HGRCPATH
+
+prepare repo1
+
+ $ hg init repo1
+ $ cd repo1
+ $ echo a > a
+ $ hg commit -A -m'init'
+ adding a
+
+share it
+
+ $ cd ..
+ $ hg share repo1 repo2
+ updating working directory
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+share shouldn't have a store dir
+
+ $ cd repo2
+ $ test -d .hg/store
+ [1]
+
+Some sed versions appends newline, some don't, and some just fails
+
+ $ cat .hg/sharedpath; echo
+ $TESTTMP/repo1/.hg (glob)
+
+trailing newline on .hg/sharedpath is ok
+ $ hg tip -q
+ 0:d3873e73d99e
+ $ echo '' >> .hg/sharedpath
+ $ cat .hg/sharedpath
+ $TESTTMP/repo1/.hg (glob)
+ $ hg tip -q
+ 0:d3873e73d99e
+
+commit in shared clone
+
+ $ echo a >> a
+ $ hg commit -m'change in shared clone'
+
+check original
+
+ $ cd ../repo1
+ $ hg log
+ changeset: 1:8af4dc49db9e
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change in shared clone
+
+ changeset: 0:d3873e73d99e
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: init
+
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat a # should be two lines of "a"
+ a
+ a
+
+commit in original
+
+ $ echo b > b
+ $ hg commit -A -m'another file'
+ adding b
+
+check in shared clone
+
+ $ cd ../repo2
+ $ hg log
+ changeset: 2:c2e0ac586386
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: another file
+
+ changeset: 1:8af4dc49db9e
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change in shared clone
+
+ changeset: 0:d3873e73d99e
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: init
+
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat b # should exist with one "b"
+ b
+
+hg serve shared clone
+
+ $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid
+ $ cat hg.pid >> $DAEMON_PIDS
+ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-file/'
+ 200 Script output follows
+
+
+ -rw-r--r-- 4 a
+ -rw-r--r-- 2 b
+
+
+
+test unshare command
+
+ $ hg unshare
+ $ test -d .hg/store
+ $ test -f .hg/sharedpath
+ [1]
+ $ hg unshare
+ abort: this is not a shared repo
+ [255]
+
+check that a change does not propagate
+
+ $ echo b >> b
+ $ hg commit -m'change in unshared'
+ $ cd ../repo1
+ $ hg id -r tip
+ c2e0ac586386 tip
+
+ $ cd ..
diff --git a/tests/test-simple-update.t b/tests/test-simple-update.t
new file mode 100644
index 0000000..080bdc7
--- /dev/null
+++ b/tests/test-simple-update.t
@@ -0,0 +1,58 @@
+ $ hg init test
+ $ cd test
+ $ echo foo>foo
+ $ hg addremove
+ adding foo
+ $ hg commit -m "1"
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+
+ $ hg clone . ../branch
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../branch
+ $ hg co
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo bar>>foo
+ $ hg commit -m "2"
+
+ $ cd ../test
+
+ $ hg pull ../branch
+ pulling from ../branch
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+
+ $ hg co
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cat foo
+ foo
+ bar
+
+ $ hg manifest --debug
+ 6f4310b00b9a147241b071a60c28a650827fb03d 644 foo
+
+update to rev 0 with a date
+
+ $ hg upd -d foo 0
+ abort: you can't specify a revision and a date
+ [255]
+
+ $ cd ..
diff --git a/tests/test-simplemerge.py b/tests/test-simplemerge.py
new file mode 100644
index 0000000..fb6add0
--- /dev/null
+++ b/tests/test-simplemerge.py
@@ -0,0 +1,415 @@
+# Copyright (C) 2004, 2005 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+from unittest import TestCase
+from mercurial import util, simplemerge
+
+# bzr compatible interface, for the tests
+class Merge3(simplemerge.Merge3Text):
+ """3-way merge of texts.
+
+ Given BASE, OTHER, THIS, tries to produce a combined text
+ incorporating the changes from both BASE->OTHER and BASE->THIS.
+ All three will typically be sequences of lines."""
+ def __init__(self, base, a, b):
+ basetext = '\n'.join([i.strip('\n') for i in base] + [''])
+ atext = '\n'.join([i.strip('\n') for i in a] + [''])
+ btext = '\n'.join([i.strip('\n') for i in b] + [''])
+ if util.binary(basetext) or util.binary(atext) or util.binary(btext):
+ raise util.Abort("don't know how to merge binary files")
+ simplemerge.Merge3Text.__init__(self, basetext, atext, btext,
+ base, a, b)
+
+CantReprocessAndShowBase = simplemerge.CantReprocessAndShowBase
+
+def split_lines(t):
+ from cStringIO import StringIO
+ return StringIO(t).readlines()
+
+############################################################
+# test case data from the gnu diffutils manual
+# common base
+TZU = split_lines(""" The Nameless is the origin of Heaven and Earth;
+ The named is the mother of all things.
+
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+ so we may see their outcome.
+ The two are the same,
+ But after they are produced,
+ they have different names.
+ They both may be called deep and profound.
+ Deeper and more profound,
+ The door of all subtleties!
+""")
+
+LAO = split_lines(""" The Way that can be told of is not the eternal Way;
+ The name that can be named is not the eternal name.
+ The Nameless is the origin of Heaven and Earth;
+ The Named is the mother of all things.
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+ so we may see their outcome.
+ The two are the same,
+ But after they are produced,
+ they have different names.
+""")
+
+
+TAO = split_lines(""" The Way that can be told of is not the eternal Way;
+ The name that can be named is not the eternal name.
+ The Nameless is the origin of Heaven and Earth;
+ The named is the mother of all things.
+
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+ so we may see their result.
+ The two are the same,
+ But after they are produced,
+ they have different names.
+
+ -- The Way of Lao-Tzu, tr. Wing-tsit Chan
+
+""")
+
+MERGED_RESULT = split_lines("""\
+ The Way that can be told of is not the eternal Way;
+ The name that can be named is not the eternal name.
+ The Nameless is the origin of Heaven and Earth;
+ The Named is the mother of all things.
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+ so we may see their result.
+ The two are the same,
+ But after they are produced,
+ they have different names.
+<<<<<<< LAO
+=======
+
+ -- The Way of Lao-Tzu, tr. Wing-tsit Chan
+
+>>>>>>> TAO
+""")
+
+class TestMerge3(TestCase):
+ def log(self, msg):
+ pass
+
+ def test_no_changes(self):
+ """No conflicts because nothing changed"""
+ m3 = Merge3(['aaa', 'bbb'],
+ ['aaa', 'bbb'],
+ ['aaa', 'bbb'])
+
+ self.assertEquals(m3.find_unconflicted(),
+ [(0, 2)])
+
+ self.assertEquals(list(m3.find_sync_regions()),
+ [(0, 2,
+ 0, 2,
+ 0, 2),
+ (2, 2, 2, 2, 2, 2)])
+
+ self.assertEquals(list(m3.merge_regions()),
+ [('unchanged', 0, 2)])
+
+ self.assertEquals(list(m3.merge_groups()),
+ [('unchanged', ['aaa', 'bbb'])])
+
+ def test_front_insert(self):
+ m3 = Merge3(['zz'],
+ ['aaa', 'bbb', 'zz'],
+ ['zz'])
+
+ # todo: should use a sentinal at end as from get_matching_blocks
+ # to match without zz
+ self.assertEquals(list(m3.find_sync_regions()),
+ [(0, 1, 2, 3, 0, 1),
+ (1, 1, 3, 3, 1, 1)])
+
+ self.assertEquals(list(m3.merge_regions()),
+ [('a', 0, 2),
+ ('unchanged', 0, 1)])
+
+ self.assertEquals(list(m3.merge_groups()),
+ [('a', ['aaa', 'bbb']),
+ ('unchanged', ['zz'])])
+
+ def test_null_insert(self):
+ m3 = Merge3([],
+ ['aaa', 'bbb'],
+ [])
+ # todo: should use a sentinal at end as from get_matching_blocks
+ # to match without zz
+ self.assertEquals(list(m3.find_sync_regions()),
+ [(0, 0, 2, 2, 0, 0)])
+
+ self.assertEquals(list(m3.merge_regions()),
+ [('a', 0, 2)])
+
+ self.assertEquals(list(m3.merge_lines()),
+ ['aaa', 'bbb'])
+
+ def test_no_conflicts(self):
+ """No conflicts because only one side changed"""
+ m3 = Merge3(['aaa', 'bbb'],
+ ['aaa', '111', 'bbb'],
+ ['aaa', 'bbb'])
+
+ self.assertEquals(m3.find_unconflicted(),
+ [(0, 1), (1, 2)])
+
+ self.assertEquals(list(m3.find_sync_regions()),
+ [(0, 1, 0, 1, 0, 1),
+ (1, 2, 2, 3, 1, 2),
+ (2, 2, 3, 3, 2, 2)])
+
+ self.assertEquals(list(m3.merge_regions()),
+ [('unchanged', 0, 1),
+ ('a', 1, 2),
+ ('unchanged', 1, 2)])
+
+ def test_append_a(self):
+ m3 = Merge3(['aaa\n', 'bbb\n'],
+ ['aaa\n', 'bbb\n', '222\n'],
+ ['aaa\n', 'bbb\n'])
+
+ self.assertEquals(''.join(m3.merge_lines()),
+ 'aaa\nbbb\n222\n')
+
+ def test_append_b(self):
+ m3 = Merge3(['aaa\n', 'bbb\n'],
+ ['aaa\n', 'bbb\n'],
+ ['aaa\n', 'bbb\n', '222\n'])
+
+ self.assertEquals(''.join(m3.merge_lines()),
+ 'aaa\nbbb\n222\n')
+
+ def test_append_agreement(self):
+ m3 = Merge3(['aaa\n', 'bbb\n'],
+ ['aaa\n', 'bbb\n', '222\n'],
+ ['aaa\n', 'bbb\n', '222\n'])
+
+ self.assertEquals(''.join(m3.merge_lines()),
+ 'aaa\nbbb\n222\n')
+
+ def test_append_clash(self):
+ m3 = Merge3(['aaa\n', 'bbb\n'],
+ ['aaa\n', 'bbb\n', '222\n'],
+ ['aaa\n', 'bbb\n', '333\n'])
+
+ ml = m3.merge_lines(name_a='a',
+ name_b='b',
+ start_marker='<<',
+ mid_marker='--',
+ end_marker='>>')
+ self.assertEquals(''.join(ml),
+ 'aaa\n'
+ 'bbb\n'
+ '<< a\n'
+ '222\n'
+ '--\n'
+ '333\n'
+ '>> b\n'
+ )
+
+ def test_insert_agreement(self):
+ m3 = Merge3(['aaa\n', 'bbb\n'],
+ ['aaa\n', '222\n', 'bbb\n'],
+ ['aaa\n', '222\n', 'bbb\n'])
+
+ ml = m3.merge_lines(name_a='a',
+ name_b='b',
+ start_marker='<<',
+ mid_marker='--',
+ end_marker='>>')
+ self.assertEquals(''.join(ml), 'aaa\n222\nbbb\n')
+
+
+ def test_insert_clash(self):
+ """Both try to insert lines in the same place."""
+ m3 = Merge3(['aaa\n', 'bbb\n'],
+ ['aaa\n', '111\n', 'bbb\n'],
+ ['aaa\n', '222\n', 'bbb\n'])
+
+ self.assertEquals(m3.find_unconflicted(),
+ [(0, 1), (1, 2)])
+
+ self.assertEquals(list(m3.find_sync_regions()),
+ [(0, 1, 0, 1, 0, 1),
+ (1, 2, 2, 3, 2, 3),
+ (2, 2, 3, 3, 3, 3)])
+
+ self.assertEquals(list(m3.merge_regions()),
+ [('unchanged', 0, 1),
+ ('conflict', 1, 1, 1, 2, 1, 2),
+ ('unchanged', 1, 2)])
+
+ self.assertEquals(list(m3.merge_groups()),
+ [('unchanged', ['aaa\n']),
+ ('conflict', [], ['111\n'], ['222\n']),
+ ('unchanged', ['bbb\n']),
+ ])
+
+ ml = m3.merge_lines(name_a='a',
+ name_b='b',
+ start_marker='<<',
+ mid_marker='--',
+ end_marker='>>')
+ self.assertEquals(''.join(ml),
+'''aaa
+<< a
+111
+--
+222
+>> b
+bbb
+''')
+
+ def test_replace_clash(self):
+ """Both try to insert lines in the same place."""
+ m3 = Merge3(['aaa', '000', 'bbb'],
+ ['aaa', '111', 'bbb'],
+ ['aaa', '222', 'bbb'])
+
+ self.assertEquals(m3.find_unconflicted(),
+ [(0, 1), (2, 3)])
+
+ self.assertEquals(list(m3.find_sync_regions()),
+ [(0, 1, 0, 1, 0, 1),
+ (2, 3, 2, 3, 2, 3),
+ (3, 3, 3, 3, 3, 3)])
+
+ def test_replace_multi(self):
+ """Replacement with regions of different size."""
+ m3 = Merge3(['aaa', '000', '000', 'bbb'],
+ ['aaa', '111', '111', '111', 'bbb'],
+ ['aaa', '222', '222', '222', '222', 'bbb'])
+
+ self.assertEquals(m3.find_unconflicted(),
+ [(0, 1), (3, 4)])
+
+
+ self.assertEquals(list(m3.find_sync_regions()),
+ [(0, 1, 0, 1, 0, 1),
+ (3, 4, 4, 5, 5, 6),
+ (4, 4, 5, 5, 6, 6)])
+
+ def test_merge_poem(self):
+ """Test case from diff3 manual"""
+ m3 = Merge3(TZU, LAO, TAO)
+ ml = list(m3.merge_lines('LAO', 'TAO'))
+ self.log('merge result:')
+ self.log(''.join(ml))
+ self.assertEquals(ml, MERGED_RESULT)
+
+ def test_minimal_conflicts_common(self):
+ """Reprocessing"""
+ base_text = ("a\n" * 20).splitlines(True)
+ this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
+ other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True)
+ m3 = Merge3(base_text, other_text, this_text)
+ m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
+ merged_text = "".join(list(m_lines))
+ optimal_text = ("a\n" * 10 + "<<<<<<< OTHER\nc\n=======\n"
+ + ">>>>>>> THIS\n"
+ + 8* "b\n" + "<<<<<<< OTHER\nc\n=======\n"
+ + 2* "b\n" + ">>>>>>> THIS\n")
+ self.assertEquals(optimal_text, merged_text)
+
+ def test_minimal_conflicts_unique(self):
+ def add_newline(s):
+ """Add a newline to each entry in the string"""
+ return [(x+'\n') for x in s]
+
+ base_text = add_newline("abcdefghijklm")
+ this_text = add_newline("abcdefghijklmNOPQRSTUVWXYZ")
+ other_text = add_newline("abcdefghijklm1OPQRSTUVWXY2")
+ m3 = Merge3(base_text, other_text, this_text)
+ m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
+ merged_text = "".join(list(m_lines))
+ optimal_text = ''.join(add_newline("abcdefghijklm")
+ + ["<<<<<<< OTHER\n1\n=======\nN\n>>>>>>> THIS\n"]
+ + add_newline('OPQRSTUVWXY')
+ + ["<<<<<<< OTHER\n2\n=======\nZ\n>>>>>>> THIS\n"]
+ )
+ self.assertEquals(optimal_text, merged_text)
+
+ def test_minimal_conflicts_nonunique(self):
+ def add_newline(s):
+ """Add a newline to each entry in the string"""
+ return [(x+'\n') for x in s]
+
+ base_text = add_newline("abacddefgghij")
+ this_text = add_newline("abacddefgghijkalmontfprz")
+ other_text = add_newline("abacddefgghijknlmontfprd")
+ m3 = Merge3(base_text, other_text, this_text)
+ m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
+ merged_text = "".join(list(m_lines))
+ optimal_text = ''.join(add_newline("abacddefgghijk")
+ + ["<<<<<<< OTHER\nn\n=======\na\n>>>>>>> THIS\n"]
+ + add_newline('lmontfpr')
+ + ["<<<<<<< OTHER\nd\n=======\nz\n>>>>>>> THIS\n"]
+ )
+ self.assertEquals(optimal_text, merged_text)
+
+ def test_reprocess_and_base(self):
+ """Reprocessing and showing base breaks correctly"""
+ base_text = ("a\n" * 20).splitlines(True)
+ this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
+ other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True)
+ m3 = Merge3(base_text, other_text, this_text)
+ m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True,
+ base_marker='|||||||')
+ self.assertRaises(CantReprocessAndShowBase, list, m_lines)
+
+ def test_binary(self):
+ self.assertRaises(util.Abort, Merge3, ['\x00'], ['a'], ['b'])
+
+ def test_dos_text(self):
+ base_text = 'a\r\n'
+ this_text = 'b\r\n'
+ other_text = 'c\r\n'
+ m3 = Merge3(base_text.splitlines(True), other_text.splitlines(True),
+ this_text.splitlines(True))
+ m_lines = m3.merge_lines('OTHER', 'THIS')
+ self.assertEqual('<<<<<<< OTHER\r\nc\r\n=======\r\nb\r\n'
+ '>>>>>>> THIS\r\n'.splitlines(True), list(m_lines))
+
+ def test_mac_text(self):
+ base_text = 'a\r'
+ this_text = 'b\r'
+ other_text = 'c\r'
+ m3 = Merge3(base_text.splitlines(True), other_text.splitlines(True),
+ this_text.splitlines(True))
+ m_lines = m3.merge_lines('OTHER', 'THIS')
+ self.assertEqual('<<<<<<< OTHER\rc\r=======\rb\r'
+ '>>>>>>> THIS\r'.splitlines(True), list(m_lines))
+
+if __name__ == '__main__':
+ # hide the timer
+ import time
+ orig = time.time
+ try:
+ time.time = lambda: 0
+ unittest.main()
+ finally:
+ time.time = orig
+
diff --git a/tests/test-simplemerge.py.out b/tests/test-simplemerge.py.out
new file mode 100644
index 0000000..953572f
--- /dev/null
+++ b/tests/test-simplemerge.py.out
@@ -0,0 +1,5 @@
+....................
+----------------------------------------------------------------------
+Ran 20 tests in 0.000s
+
+OK
diff --git a/tests/test-ssh-clone-r.t b/tests/test-ssh-clone-r.t
new file mode 100644
index 0000000..4c1dff2
--- /dev/null
+++ b/tests/test-ssh-clone-r.t
@@ -0,0 +1,195 @@
+This test tries to exercise the ssh functionality with a dummy script
+
+creating 'remote' repo
+
+ $ hg init remote
+ $ cd remote
+ $ hg unbundle "$TESTDIR/bundles/remote.hg"
+ adding changesets
+ adding manifests
+ adding file changes
+ added 9 changesets with 7 changes to 4 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+
+clone remote via stream
+
+ $ for i in 0 1 2 3 4 5 6 7 8; do
+ > hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed -r "$i" ssh://user@dummy/remote test-"$i"
+ > if cd test-"$i"; then
+ > hg verify
+ > cd ..
+ > fi
+ > done
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 4 changesets, 4 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 2 changesets, 2 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 3 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 5 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 4 changesets, 5 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 6 changes to 3 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 5 changesets, 6 total revisions
+ adding changesets
+ adding manifests
+ adding file changes
+ added 5 changesets with 5 changes to 2 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 5 changesets, 5 total revisions
+ $ cd test-8
+ $ hg pull ../test-7
+ pulling from ../test-7
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 2 changes to 3 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 9 changesets, 7 total revisions
+ $ cd ..
+ $ cd test-1
+ $ hg pull -e "python \"$TESTDIR/dummyssh\"" -r 4 ssh://user@dummy/remote
+ pulling from ssh://user@dummy/remote
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 0 changes to 0 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 3 changesets, 2 total revisions
+ $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote
+ pulling from ssh://user@dummy/remote
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 5 changes to 4 files
+ (run 'hg update' to get a working copy)
+ $ cd ..
+ $ cd test-2
+ $ hg pull -e "python \"$TESTDIR/dummyssh\"" -r 5 ssh://user@dummy/remote
+ pulling from ssh://user@dummy/remote
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 0 changes to 0 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 5 changesets, 3 total revisions
+ $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote
+ pulling from ssh://user@dummy/remote
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 4 files
+ (run 'hg update' to get a working copy)
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 9 changesets, 7 total revisions
+
+ $ cd ..
diff --git a/tests/test-ssh.t b/tests/test-ssh.t
new file mode 100644
index 0000000..169473d
--- /dev/null
+++ b/tests/test-ssh.t
@@ -0,0 +1,376 @@
+
+
+This test tries to exercise the ssh functionality with a dummy script
+
+creating 'remote' repo
+
+ $ hg init remote
+ $ cd remote
+ $ echo this > foo
+ $ echo this > fooO
+ $ hg ci -A -m "init" foo fooO
+ $ cat <<EOF > .hg/hgrc
+ > [server]
+ > uncompressed = True
+ >
+ > [hooks]
+ > changegroup = python "$TESTDIR/printenv.py" changegroup-in-remote 0 ../dummylog
+ > EOF
+ $ cd ..
+
+repo not found error
+
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
+ remote: abort: there is no Mercurial repository here (.hg not found)!
+ abort: no suitable response from remote hg!
+ [255]
+
+non-existent absolute path
+
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
+ remote: abort: there is no Mercurial repository here (.hg not found)!
+ abort: no suitable response from remote hg!
+ [255]
+
+clone remote via stream
+
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
+ streaming all changes
+ 4 files to transfer, 392 bytes of data
+ transferred 392 bytes in * seconds (*/sec) (glob)
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd local-stream
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 1 changesets, 2 total revisions
+ $ cd ..
+
+clone remote via pull
+
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+verify
+
+ $ cd local
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 1 changesets, 2 total revisions
+ $ echo '[hooks]' >> .hg/hgrc
+ $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup-in-local 0 ../dummylog" >> .hg/hgrc
+
+empty default pull
+
+ $ hg paths
+ default = ssh://user@dummy/remote
+ $ hg pull -e "python \"$TESTDIR/dummyssh\""
+ pulling from ssh://user@dummy/remote
+ searching for changes
+ no changes found
+
+local change
+
+ $ echo bleah > foo
+ $ hg ci -m "add"
+
+updating rc
+
+ $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
+ $ echo "[ui]" >> .hg/hgrc
+ $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
+
+find outgoing
+
+ $ hg out ssh://user@dummy/remote
+ comparing with ssh://user@dummy/remote
+ searching for changes
+ changeset: 1:a28a9d1a809c
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add
+
+
+find incoming on the remote side
+
+ $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
+ comparing with ssh://user@dummy/local
+ searching for changes
+ changeset: 1:a28a9d1a809c
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add
+
+
+find incoming on the remote side (using absolute path)
+
+ $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
+ comparing with ssh://user@dummy/$TESTTMP/local
+ searching for changes
+ changeset: 1:a28a9d1a809c
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add
+
+
+push
+
+ $ hg push
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ $ cd ../remote
+
+check remote tip
+
+ $ hg tip
+ changeset: 1:a28a9d1a809c
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 2 changesets, 3 total revisions
+ $ hg cat -r tip foo
+ bleah
+ $ echo z > z
+ $ hg ci -A -m z z
+ created new head
+
+test pushkeys and bookmarks
+
+ $ cd ../local
+ $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
+ bookmarks
+ phases
+ namespaces
+ $ hg book foo -r 0
+ $ hg out -B
+ comparing with ssh://user@dummy/remote
+ searching for changed bookmarks
+ foo 1160648e36ce
+ $ hg push -B foo
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ no changes found
+ exporting bookmark foo
+ [1]
+ $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
+ foo 1160648e36cec0054048a7edc4110c6f84fde594
+ $ hg book -f foo
+ $ hg push --traceback
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ no changes found
+ updating bookmark foo
+ [1]
+ $ hg book -d foo
+ $ hg in -B
+ comparing with ssh://user@dummy/remote
+ searching for changed bookmarks
+ foo a28a9d1a809c
+ $ hg book -f -r 0 foo
+ $ hg pull -B foo
+ pulling from ssh://user@dummy/remote
+ no changes found
+ updating bookmark foo
+ importing bookmark foo
+ $ hg book -d foo
+ $ hg push -B foo
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ no changes found
+ deleting remote bookmark foo
+ [1]
+
+a bad, evil hook that prints to stdout
+
+ $ cat <<EOF > $TESTTMP/badhook
+ > import sys
+ > sys.stdout.write("KABOOM\n")
+ > EOF
+
+ $ echo '[hooks]' >> ../remote/.hg/hgrc
+ $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
+ $ echo r > r
+ $ hg ci -A -m z r
+
+push should succeed even though it has an unexpected response
+
+ $ hg push
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ note: unsynced remote changes!
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: KABOOM
+ $ hg -R ../remote heads
+ changeset: 3:1383141674ec
+ tag: tip
+ parent: 1:a28a9d1a809c
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: z
+
+ changeset: 2:6c0482d977a3
+ parent: 0:1160648e36ce
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: z
+
+
+clone bookmarks
+
+ $ hg -R ../remote bookmark test
+ $ hg -R ../remote bookmarks
+ * test 2:6c0482d977a3
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 5 changes to 4 files (+1 heads)
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R local-bookmarks bookmarks
+ test 2:6c0482d977a3
+
+passwords in ssh urls are not supported
+(we use a glob here because different Python versions give different
+results here)
+
+ $ hg push ssh://user:erroneouspwd@dummy/remote
+ pushing to ssh://user:*@dummy/remote (glob)
+ abort: password in URL not supported!
+ [255]
+
+ $ cd ..
+
+hide outer repo
+ $ hg init
+
+Test remote paths with spaces (issue2983):
+
+ $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
+ $ touch "$TESTTMP/a repo/test"
+ $ hg -R 'a repo' commit -A -m "test"
+ adding test
+ $ hg -R 'a repo' tag tag
+ $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
+ 73649e48688a
+
+Test hg-ssh using a helper script that will restore PYTHONPATH (which might
+have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
+parameters:
+
+ $ cat > ssh.sh << EOF
+ > userhost="\$1"
+ > SSH_ORIGINAL_COMMAND="\$2"
+ > export SSH_ORIGINAL_COMMAND
+ > PYTHONPATH="$PYTHONPATH"
+ > export PYTHONPATH
+ > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
+ > EOF
+
+ $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
+ 73649e48688a
+
+ $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
+ remote: Illegal repository "$TESTTMP/a'repo" (glob)
+ abort: no suitable response from remote hg!
+ [255]
+
+ $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
+ remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
+ abort: no suitable response from remote hg!
+ [255]
+
+ $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
+ Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
+ [255]
+
+Test hg-ssh in read-only mode:
+
+ $ cat > ssh.sh << EOF
+ > userhost="\$1"
+ > SSH_ORIGINAL_COMMAND="\$2"
+ > export SSH_ORIGINAL_COMMAND
+ > PYTHONPATH="$PYTHONPATH"
+ > export PYTHONPATH
+ > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
+ > EOF
+
+ $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 5 changes to 4 files (+1 heads)
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd read-only-local
+ $ echo "baz" > bar
+ $ hg ci -A -m "unpushable commit" bar
+ $ hg push --ssh "sh ../ssh.sh"
+ pushing to ssh://user@dummy/*/remote (glob)
+ searching for changes
+ remote: Permission denied
+ remote: abort: prechangegroup.hg-ssh hook failed
+ remote: Permission denied
+ remote: abort: prepushkey.hg-ssh hook failed
+ abort: unexpected response: empty string
+ [255]
+
+ $ cd ..
+
+ $ cat dummylog
+ Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
+ Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R local serve --stdio
+ Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg init 'a repo'
+ Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
+ Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
diff --git a/tests/test-static-http.t b/tests/test-static-http.t
new file mode 100644
index 0000000..ed9ab54
--- /dev/null
+++ b/tests/test-static-http.t
@@ -0,0 +1,174 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+#if windows
+ $ hg clone http://localhost:$HGPORT/ copy
+ abort: * (glob)
+ [255]
+#else
+ $ hg clone http://localhost:$HGPORT/ copy
+ abort: error: Connection refused
+ [255]
+#endif
+ $ test -d copy
+ [1]
+
+This server doesn't do range requests so it's basically only good for
+one pull
+
+ $ cat > dumb.py <<EOF
+ > import BaseHTTPServer, SimpleHTTPServer, os, signal, sys
+ >
+ > def run(server_class=BaseHTTPServer.HTTPServer,
+ > handler_class=SimpleHTTPServer.SimpleHTTPRequestHandler):
+ > server_address = ('localhost', int(os.environ['HGPORT']))
+ > httpd = server_class(server_address, handler_class)
+ > httpd.serve_forever()
+ >
+ > signal.signal(signal.SIGTERM, lambda x, y: sys.exit(0))
+ > run()
+ > EOF
+ $ python dumb.py 2>/dev/null &
+ $ echo $! >> $DAEMON_PIDS
+ $ hg init remote
+ $ cd remote
+ $ echo foo > bar
+ $ echo c2 > '.dotfile with spaces'
+ $ hg add
+ adding .dotfile with spaces
+ adding bar
+ $ hg commit -m"test"
+ $ hg tip
+ changeset: 0:02770d679fb8
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: test
+
+ $ cd ..
+ $ hg clone static-http://localhost:$HGPORT/remote local
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd local
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 1 changesets, 2 total revisions
+ $ cat bar
+ foo
+ $ cd ../remote
+ $ echo baz > quux
+ $ hg commit -A -mtest2
+ adding quux
+
+check for HTTP opener failures when cachefile does not exist
+
+ $ rm .hg/cache/*
+ $ cd ../local
+ $ echo '[hooks]' >> .hg/hgrc
+ $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
+ $ hg pull
+ pulling from static-http://localhost:$HGPORT/remote
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ changegroup hook: HG_NODE=4ac2e3648604439c580c69b09ec9d93a88d93432 HG_SOURCE=pull HG_URL=http://localhost:$HGPORT/remote
+ (run 'hg update' to get a working copy)
+
+trying to push
+
+ $ hg update
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo more foo >> bar
+ $ hg commit -m"test"
+ $ hg push
+ pushing to static-http://localhost:$HGPORT/remote
+ abort: destination does not support push
+ [255]
+
+trying clone -r
+
+ $ cd ..
+ $ hg clone -r donotexist static-http://localhost:$HGPORT/remote local0
+ abort: unknown revision 'donotexist'!
+ [255]
+ $ hg clone -r 0 static-http://localhost:$HGPORT/remote local0
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+test with "/" URI (issue 747) and subrepo
+
+ $ hg init
+ $ hg init sub
+ $ touch sub/test
+ $ hg -R sub commit -A -m "test"
+ adding test
+ $ hg -R sub tag not-empty
+ $ echo sub=sub > .hgsub
+ $ echo a > a
+ $ hg add a .hgsub
+ $ hg -q ci -ma
+ $ hg clone static-http://localhost:$HGPORT/ local2
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 3 changes to 3 files
+ updating to branch default
+ cloning subrepo sub from static-http://localhost:$HGPORT/sub
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd local2
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 1 changesets, 3 total revisions
+ $ cat a
+ a
+ $ hg paths
+ default = static-http://localhost:$HGPORT/
+
+test with empty repo (issue965)
+
+ $ cd ..
+ $ hg init remotempty
+ $ hg clone static-http://localhost:$HGPORT/remotempty local3
+ no changes found
+ updating to branch default
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd local3
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 0 files, 0 changesets, 0 total revisions
+ $ hg paths
+ default = static-http://localhost:$HGPORT/remotempty
+
+test with non-repo
+
+ $ cd ..
+ $ mkdir notarepo
+ $ hg clone static-http://localhost:$HGPORT/notarepo local3
+ abort: 'http://localhost:$HGPORT/notarepo' does not appear to be an hg repository!
+ [255]
+ $ kill $!
diff --git a/tests/test-status-color.t b/tests/test-status-color.t
new file mode 100644
index 0000000..f7917f7
--- /dev/null
+++ b/tests/test-status-color.t
@@ -0,0 +1,300 @@
+ $ "$TESTDIR/hghave" tic || exit 80
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "color=" >> $HGRCPATH
+ $ echo "[color]" >> $HGRCPATH
+ $ echo "mode=ansi" >> $HGRCPATH
+Terminfo codes compatibility fix
+ $ echo "color.none=0" >> $HGRCPATH
+
+ $ hg init repo1
+ $ cd repo1
+ $ mkdir a b a/1 b/1 b/2
+ $ touch in_root a/in_a b/in_b a/1/in_a_1 b/1/in_b_1 b/2/in_b_2
+
+hg status in repo root:
+
+ $ hg status --color=always
+ \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+
+hg status . in repo root:
+
+ $ hg status --color=always .
+ \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+
+ $ hg status --color=always --cwd a
+ \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ $ hg status --color=always --cwd a .
+ \x1b[0;35;1;4m? 1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_a\x1b[0m (esc)
+ $ hg status --color=always --cwd a ..
+ \x1b[0;35;1;4m? 1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? ../b/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? ../b/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? ../b/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? ../in_root\x1b[0m (esc)
+
+ $ hg status --color=always --cwd b
+ \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ $ hg status --color=always --cwd b .
+ \x1b[0;35;1;4m? 1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? 2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_b\x1b[0m (esc)
+ $ hg status --color=always --cwd b ..
+ \x1b[0;35;1;4m? ../a/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? ../a/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? 1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? 2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? ../in_root\x1b[0m (esc)
+
+ $ hg status --color=always --cwd a/1
+ \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ $ hg status --color=always --cwd a/1 .
+ \x1b[0;35;1;4m? in_a_1\x1b[0m (esc)
+ $ hg status --color=always --cwd a/1 ..
+ \x1b[0;35;1;4m? in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? ../in_a\x1b[0m (esc)
+
+ $ hg status --color=always --cwd b/1
+ \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ $ hg status --color=always --cwd b/1 .
+ \x1b[0;35;1;4m? in_b_1\x1b[0m (esc)
+ $ hg status --color=always --cwd b/1 ..
+ \x1b[0;35;1;4m? in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? ../2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? ../in_b\x1b[0m (esc)
+
+ $ hg status --color=always --cwd b/2
+ \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ $ hg status --color=always --cwd b/2 .
+ \x1b[0;35;1;4m? in_b_2\x1b[0m (esc)
+ $ hg status --color=always --cwd b/2 ..
+ \x1b[0;35;1;4m? ../1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? ../in_b\x1b[0m (esc)
+ $ cd ..
+
+ $ hg init repo2
+ $ cd repo2
+ $ touch modified removed deleted ignored
+ $ echo "^ignored$" > .hgignore
+ $ hg ci -A -m 'initial checkin'
+ adding .hgignore
+ adding deleted
+ adding modified
+ adding removed
+ $ touch modified added unknown ignored
+ $ hg add added
+ $ hg remove removed
+ $ rm deleted
+
+hg status:
+
+ $ hg status --color=always
+ \x1b[0;32;1mA added\x1b[0m (esc)
+ \x1b[0;31;1mR removed\x1b[0m (esc)
+ \x1b[0;36;1;4m! deleted\x1b[0m (esc)
+ \x1b[0;35;1;4m? unknown\x1b[0m (esc)
+
+hg status modified added removed deleted unknown never-existed ignored:
+
+ $ hg status --color=always modified added removed deleted unknown never-existed ignored
+ never-existed: * (glob)
+ \x1b[0;32;1mA added\x1b[0m (esc)
+ \x1b[0;31;1mR removed\x1b[0m (esc)
+ \x1b[0;36;1;4m! deleted\x1b[0m (esc)
+ \x1b[0;35;1;4m? unknown\x1b[0m (esc)
+
+ $ hg copy modified copied
+
+hg status -C:
+
+ $ hg status --color=always -C
+ \x1b[0;32;1mA added\x1b[0m (esc)
+ \x1b[0;32;1mA copied\x1b[0m (esc)
+ \x1b[0;0m modified\x1b[0m (esc)
+ \x1b[0;31;1mR removed\x1b[0m (esc)
+ \x1b[0;36;1;4m! deleted\x1b[0m (esc)
+ \x1b[0;35;1;4m? unknown\x1b[0m (esc)
+
+hg status -A:
+
+ $ hg status --color=always -A
+ \x1b[0;32;1mA added\x1b[0m (esc)
+ \x1b[0;32;1mA copied\x1b[0m (esc)
+ \x1b[0;0m modified\x1b[0m (esc)
+ \x1b[0;31;1mR removed\x1b[0m (esc)
+ \x1b[0;36;1;4m! deleted\x1b[0m (esc)
+ \x1b[0;35;1;4m? unknown\x1b[0m (esc)
+ \x1b[0;30;1mI ignored\x1b[0m (esc)
+ \x1b[0;0mC .hgignore\x1b[0m (esc)
+ \x1b[0;0mC modified\x1b[0m (esc)
+
+hg status -A (with terminfo color):
+
+ $ mkdir "$TESTTMP/terminfo"
+ $ TERMINFO="$TESTTMP/terminfo" tic "$TESTDIR/hgterm.ti"
+ $ TERM=hgterm TERMINFO="$TESTTMP/terminfo" hg status --config color.mode=terminfo --color=always -A
+ \x1b[30m\x1b[32m\x1b[1mA added\x1b[30m (esc)
+ \x1b[30m\x1b[32m\x1b[1mA copied\x1b[30m (esc)
+ \x1b[30m\x1b[30m modified\x1b[30m (esc)
+ \x1b[30m\x1b[31m\x1b[1mR removed\x1b[30m (esc)
+ \x1b[30m\x1b[36m\x1b[1m\x1b[4m! deleted\x1b[30m (esc)
+ \x1b[30m\x1b[35m\x1b[1m\x1b[4m? unknown\x1b[30m (esc)
+ \x1b[30m\x1b[30m\x1b[1mI ignored\x1b[30m (esc)
+ \x1b[30m\x1b[30mC .hgignore\x1b[30m (esc)
+ \x1b[30m\x1b[30mC modified\x1b[30m (esc)
+
+
+ $ echo "^ignoreddir$" > .hgignore
+ $ mkdir ignoreddir
+ $ touch ignoreddir/file
+
+hg status ignoreddir/file:
+
+ $ hg status --color=always ignoreddir/file
+
+hg status -i ignoreddir/file:
+
+ $ hg status --color=always -i ignoreddir/file
+ \x1b[0;30;1mI ignoreddir/file\x1b[0m (esc)
+ $ cd ..
+
+check 'status -q' and some combinations
+
+ $ hg init repo3
+ $ cd repo3
+ $ touch modified removed deleted ignored
+ $ echo "^ignored$" > .hgignore
+ $ hg commit -A -m 'initial checkin'
+ adding .hgignore
+ adding deleted
+ adding modified
+ adding removed
+ $ touch added unknown ignored
+ $ hg add added
+ $ echo "test" >> modified
+ $ hg remove removed
+ $ rm deleted
+ $ hg copy modified copied
+
+test unknown color
+
+ $ hg --config color.status.modified=periwinkle status --color=always
+ ignoring unknown color/effect 'periwinkle' (configured in color.status.modified)
+ M modified
+ \x1b[0;32;1mA added\x1b[0m (esc)
+ \x1b[0;32;1mA copied\x1b[0m (esc)
+ \x1b[0;31;1mR removed\x1b[0m (esc)
+ \x1b[0;36;1;4m! deleted\x1b[0m (esc)
+ \x1b[0;35;1;4m? unknown\x1b[0m (esc)
+
+Run status with 2 different flags.
+Check if result is the same or different.
+If result is not as expected, raise error
+
+ $ assert() {
+ > hg status --color=always $1 > ../a
+ > hg status --color=always $2 > ../b
+ > if diff ../a ../b > /dev/null; then
+ > out=0
+ > else
+ > out=1
+ > fi
+ > if [ $3 -eq 0 ]; then
+ > df="same"
+ > else
+ > df="different"
+ > fi
+ > if [ $out -ne $3 ]; then
+ > echo "Error on $1 and $2, should be $df."
+ > fi
+ > }
+
+assert flag1 flag2 [0-same | 1-different]
+
+ $ assert "-q" "-mard" 0
+ $ assert "-A" "-marduicC" 0
+ $ assert "-qA" "-mardcC" 0
+ $ assert "-qAui" "-A" 0
+ $ assert "-qAu" "-marducC" 0
+ $ assert "-qAi" "-mardicC" 0
+ $ assert "-qu" "-u" 0
+ $ assert "-q" "-u" 1
+ $ assert "-m" "-a" 1
+ $ assert "-r" "-d" 1
+ $ cd ..
+
+test 'resolve -l'
+
+ $ hg init repo4
+ $ cd repo4
+ $ echo "file a" > a
+ $ echo "file b" > b
+ $ hg add a b
+ $ hg commit -m "initial"
+ $ echo "file a change 1" > a
+ $ echo "file b change 1" > b
+ $ hg commit -m "head 1"
+ $ hg update 0
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo "file a change 2" > a
+ $ echo "file b change 2" > b
+ $ hg commit -m "head 2"
+ created new head
+ $ hg merge
+ merging a
+ warning: conflicts during merge.
+ merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
+ merging b
+ warning: conflicts during merge.
+ merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ [1]
+ $ hg resolve -m b
+
+hg resolve with one unresolved, one resolved:
+
+ $ hg resolve --color=always -l
+ \x1b[0;31;1mU a\x1b[0m (esc)
+ \x1b[0;32;1mR b\x1b[0m (esc)
+
+ $ cd ..
diff --git a/tests/test-status-inprocess.py b/tests/test-status-inprocess.py
new file mode 100755
index 0000000..8aadaa2
--- /dev/null
+++ b/tests/test-status-inprocess.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+from mercurial.ui import ui
+from mercurial.localrepo import localrepository
+from mercurial.commands import add, commit, status
+
+u = ui()
+
+print '% creating repo'
+repo = localrepository(u, '.', create=True)
+
+f = open('test.py', 'w')
+try:
+ f.write('foo\n')
+finally:
+ f.close
+
+print '% add and commit'
+add(u, repo, 'test.py')
+commit(u, repo, message='*')
+status(u, repo, clean=True)
+
+
+print '% change'
+f = open('test.py', 'w')
+try:
+ f.write('bar\n')
+finally:
+ f.close()
+
+# this would return clean instead of changed before the fix
+status(u, repo, clean=True, modified=True)
diff --git a/tests/test-status-inprocess.py.out b/tests/test-status-inprocess.py.out
new file mode 100644
index 0000000..f94bd06
--- /dev/null
+++ b/tests/test-status-inprocess.py.out
@@ -0,0 +1,5 @@
+% creating repo
+% add and commit
+C test.py
+% change
+M test.py
diff --git a/tests/test-status.t b/tests/test-status.t
new file mode 100644
index 0000000..8de94a1
--- /dev/null
+++ b/tests/test-status.t
@@ -0,0 +1,333 @@
+ $ hg init repo1
+ $ cd repo1
+ $ mkdir a b a/1 b/1 b/2
+ $ touch in_root a/in_a b/in_b a/1/in_a_1 b/1/in_b_1 b/2/in_b_2
+
+hg status in repo root:
+
+ $ hg status
+ ? a/1/in_a_1
+ ? a/in_a
+ ? b/1/in_b_1
+ ? b/2/in_b_2
+ ? b/in_b
+ ? in_root
+
+hg status . in repo root:
+
+ $ hg status .
+ ? a/1/in_a_1
+ ? a/in_a
+ ? b/1/in_b_1
+ ? b/2/in_b_2
+ ? b/in_b
+ ? in_root
+
+ $ hg status --cwd a
+ ? a/1/in_a_1
+ ? a/in_a
+ ? b/1/in_b_1
+ ? b/2/in_b_2
+ ? b/in_b
+ ? in_root
+ $ hg status --cwd a .
+ ? 1/in_a_1
+ ? in_a
+ $ hg status --cwd a ..
+ ? 1/in_a_1
+ ? in_a
+ ? ../b/1/in_b_1
+ ? ../b/2/in_b_2
+ ? ../b/in_b
+ ? ../in_root
+
+ $ hg status --cwd b
+ ? a/1/in_a_1
+ ? a/in_a
+ ? b/1/in_b_1
+ ? b/2/in_b_2
+ ? b/in_b
+ ? in_root
+ $ hg status --cwd b .
+ ? 1/in_b_1
+ ? 2/in_b_2
+ ? in_b
+ $ hg status --cwd b ..
+ ? ../a/1/in_a_1
+ ? ../a/in_a
+ ? 1/in_b_1
+ ? 2/in_b_2
+ ? in_b
+ ? ../in_root
+
+ $ hg status --cwd a/1
+ ? a/1/in_a_1
+ ? a/in_a
+ ? b/1/in_b_1
+ ? b/2/in_b_2
+ ? b/in_b
+ ? in_root
+ $ hg status --cwd a/1 .
+ ? in_a_1
+ $ hg status --cwd a/1 ..
+ ? in_a_1
+ ? ../in_a
+
+ $ hg status --cwd b/1
+ ? a/1/in_a_1
+ ? a/in_a
+ ? b/1/in_b_1
+ ? b/2/in_b_2
+ ? b/in_b
+ ? in_root
+ $ hg status --cwd b/1 .
+ ? in_b_1
+ $ hg status --cwd b/1 ..
+ ? in_b_1
+ ? ../2/in_b_2
+ ? ../in_b
+
+ $ hg status --cwd b/2
+ ? a/1/in_a_1
+ ? a/in_a
+ ? b/1/in_b_1
+ ? b/2/in_b_2
+ ? b/in_b
+ ? in_root
+ $ hg status --cwd b/2 .
+ ? in_b_2
+ $ hg status --cwd b/2 ..
+ ? ../1/in_b_1
+ ? in_b_2
+ ? ../in_b
+ $ cd ..
+
+ $ hg init repo2
+ $ cd repo2
+ $ touch modified removed deleted ignored
+ $ echo "^ignored$" > .hgignore
+ $ hg ci -A -m 'initial checkin'
+ adding .hgignore
+ adding deleted
+ adding modified
+ adding removed
+ $ touch modified added unknown ignored
+ $ hg add added
+ $ hg remove removed
+ $ rm deleted
+
+hg status:
+
+ $ hg status
+ A added
+ R removed
+ ! deleted
+ ? unknown
+
+hg status modified added removed deleted unknown never-existed ignored:
+
+ $ hg status modified added removed deleted unknown never-existed ignored
+ never-existed: * (glob)
+ A added
+ R removed
+ ! deleted
+ ? unknown
+
+ $ hg copy modified copied
+
+hg status -C:
+
+ $ hg status -C
+ A added
+ A copied
+ modified
+ R removed
+ ! deleted
+ ? unknown
+
+hg status -A:
+
+ $ hg status -A
+ A added
+ A copied
+ modified
+ R removed
+ ! deleted
+ ? unknown
+ I ignored
+ C .hgignore
+ C modified
+
+
+ $ echo "^ignoreddir$" > .hgignore
+ $ mkdir ignoreddir
+ $ touch ignoreddir/file
+
+hg status ignoreddir/file:
+
+ $ hg status ignoreddir/file
+
+hg status -i ignoreddir/file:
+
+ $ hg status -i ignoreddir/file
+ I ignoreddir/file
+ $ cd ..
+
+Check 'status -q' and some combinations
+
+ $ hg init repo3
+ $ cd repo3
+ $ touch modified removed deleted ignored
+ $ echo "^ignored$" > .hgignore
+ $ hg commit -A -m 'initial checkin'
+ adding .hgignore
+ adding deleted
+ adding modified
+ adding removed
+ $ touch added unknown ignored
+ $ hg add added
+ $ echo "test" >> modified
+ $ hg remove removed
+ $ rm deleted
+ $ hg copy modified copied
+
+Run status with 2 different flags.
+Check if result is the same or different.
+If result is not as expected, raise error
+
+ $ assert() {
+ > hg status $1 > ../a
+ > hg status $2 > ../b
+ > if diff ../a ../b > /dev/null; then
+ > out=0
+ > else
+ > out=1
+ > fi
+ > if [ $3 -eq 0 ]; then
+ > df="same"
+ > else
+ > df="different"
+ > fi
+ > if [ $out -ne $3 ]; then
+ > echo "Error on $1 and $2, should be $df."
+ > fi
+ > }
+
+Assert flag1 flag2 [0-same | 1-different]
+
+ $ assert "-q" "-mard" 0
+ $ assert "-A" "-marduicC" 0
+ $ assert "-qA" "-mardcC" 0
+ $ assert "-qAui" "-A" 0
+ $ assert "-qAu" "-marducC" 0
+ $ assert "-qAi" "-mardicC" 0
+ $ assert "-qu" "-u" 0
+ $ assert "-q" "-u" 1
+ $ assert "-m" "-a" 1
+ $ assert "-r" "-d" 1
+ $ cd ..
+
+ $ hg init repo4
+ $ cd repo4
+ $ touch modified removed deleted
+ $ hg ci -q -A -m 'initial checkin'
+ $ touch added unknown
+ $ hg add added
+ $ hg remove removed
+ $ rm deleted
+ $ echo x > modified
+ $ hg copy modified copied
+ $ hg ci -m 'test checkin' -d "1000001 0"
+ $ rm *
+ $ touch unrelated
+ $ hg ci -q -A -m 'unrelated checkin' -d "1000002 0"
+
+hg status --change 1:
+
+ $ hg status --change 1
+ M modified
+ A added
+ A copied
+ R removed
+
+hg status --change 1 unrelated:
+
+ $ hg status --change 1 unrelated
+
+hg status -C --change 1 added modified copied removed deleted:
+
+ $ hg status -C --change 1 added modified copied removed deleted
+ M modified
+ A added
+ A copied
+ modified
+ R removed
+
+hg status -A --change 1 and revset:
+
+ $ hg status -A --change '1|1'
+ M modified
+ A added
+ A copied
+ modified
+ R removed
+ C deleted
+
+ $ cd ..
+
+hg status of binary file starting with '\1\n', a separator for metadata:
+
+ $ hg init repo5
+ $ cd repo5
+ >>> open("010a", "wb").write("\1\nfoo")
+ $ hg ci -q -A -m 'initial checkin'
+ $ hg status -A
+ C 010a
+
+ >>> open("010a", "wb").write("\1\nbar")
+ $ hg status -A
+ M 010a
+ $ hg ci -q -m 'modify 010a'
+ $ hg status -A --rev 0:1
+ M 010a
+
+ $ touch empty
+ $ hg ci -q -A -m 'add another file'
+ $ hg status -A --rev 1:2 010a
+ C 010a
+
+ $ cd ..
+
+test "hg status" with "directory pattern" which matches against files
+only known on target revision.
+
+ $ hg init repo6
+ $ cd repo6
+
+ $ echo a > a.txt
+ $ hg add a.txt
+ $ hg commit -m '#0'
+ $ mkdir -p 1/2/3/4/5
+ $ echo b > 1/2/3/4/5/b.txt
+ $ hg add 1/2/3/4/5/b.txt
+ $ hg commit -m '#1'
+
+ $ hg update -C 0 > /dev/null
+ $ hg status -A
+ C a.txt
+
+the directory matching against specified pattern should be removed,
+because directory existence prevents 'dirstate.walk()' from showing
+warning message about such pattern.
+
+ $ test ! -d 1
+ $ hg status -A --rev 1 1/2/3/4/5/b.txt
+ R 1/2/3/4/5/b.txt
+ $ hg status -A --rev 1 1/2/3/4/5
+ R 1/2/3/4/5/b.txt
+ $ hg status -A --rev 1 1/2/3
+ R 1/2/3/4/5/b.txt
+ $ hg status -A --rev 1 1
+ R 1/2/3/4/5/b.txt
+
+ $ cd ..
diff --git a/tests/test-strict.t b/tests/test-strict.t
new file mode 100644
index 0000000..0e108cb
--- /dev/null
+++ b/tests/test-strict.t
@@ -0,0 +1,49 @@
+ $ hg init
+
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+
+ $ hg an a
+ 0: a
+
+ $ hg --config ui.strict=False an a
+ 0: a
+
+ $ echo "[ui]" >> $HGRCPATH
+ $ echo "strict=True" >> $HGRCPATH
+
+ $ hg an a
+ hg: unknown command 'an'
+ Mercurial Distributed SCM
+
+ basic commands:
+
+ add add the specified files on the next commit
+ annotate show changeset information by line for each file
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ forget forget the specified files on the next commit
+ init create a new repository in the given directory
+ log show revision history of entire repository or files
+ merge merge working directory with another revision
+ phase set or show the current phase name
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ remove remove the specified files on the next commit
+ serve start stand-alone webserver
+ status show changed files in the working directory
+ summary summarize working directory state
+ update update working directory (or switch revisions)
+
+ use "hg help" for the full list of commands or "hg -v" for details
+ [255]
+ $ hg annotate a
+ 0: a
+
+should succeed - up is an alias, not an abbreviation
+
+ $ hg up
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
diff --git a/tests/test-strip-cross.t b/tests/test-strip-cross.t
new file mode 100644
index 0000000..95bc17b
--- /dev/null
+++ b/tests/test-strip-cross.t
@@ -0,0 +1,143 @@
+test stripping of filelogs where the linkrev doesn't always increase
+
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo 'hgext.mq =' >> $HGRCPATH
+ $ hg init orig
+ $ cd orig
+ $ commit()
+ > {
+ > hg up -qC null
+ > count=1
+ > for i in "$@"; do
+ > for f in $i; do
+ > echo $count > $f
+ > done
+ > count=`expr $count + 1`
+ > done
+ > hg commit -qAm "$*"
+ > }
+
+2 1 0 2 0 1 2
+
+ $ commit '201 210'
+ $ commit '102 120' '210'
+ $ commit '021'
+ $ commit '201' '021 120'
+ $ commit '012 021' '102 201' '120 210'
+ $ commit 'manifest-file'
+ $ commit '102 120' '012 210' '021 201'
+ $ commit '201 210' '021 120' '012 102'
+ $ HGUSER=another-user; export HGUSER
+ $ commit 'manifest-file'
+ $ commit '012' 'manifest-file'
+ $ cd ..
+ $ hg clone -q -U -r -1 -r -2 -r -3 -r -4 -r -6 orig crossed
+ $ cd crossed
+ $ hg debugindex --manifest
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 112 ..... 0 6f105cbb914d 000000000000 000000000000 (re)
+ 1 112 56 ..... 3 1b55917b3699 000000000000 000000000000 (re)
+ 2 168 123 ..... 1 8f3d04e263e5 000000000000 000000000000 (re)
+ 3 291 122 ..... 2 f0ef8726ac4f 000000000000 000000000000 (re)
+ 4 413 87 ..... 4 0b76e38b4070 000000000000 000000000000 (re)
+
+ $ for i in 012 021 102 120 201 210 manifest-file; do
+ > echo $i
+ > hg debugindex $i
+ > echo
+ > done
+ 012
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 0 b8e02f643373 000000000000 000000000000 (re)
+ 1 3 3 ..... 1 5d9299349fc0 000000000000 000000000000 (re)
+ 2 6 3 ..... 2 2661d26c6496 000000000000 000000000000 (re)
+
+ 021
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 0 b8e02f643373 000000000000 000000000000 (re)
+ 1 3 3 ..... 2 5d9299349fc0 000000000000 000000000000 (re)
+ 2 6 3 ..... 1 2661d26c6496 000000000000 000000000000 (re)
+
+ 102
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 1 b8e02f643373 000000000000 000000000000 (re)
+ 1 3 3 ..... 0 5d9299349fc0 000000000000 000000000000 (re)
+ 2 6 3 ..... 2 2661d26c6496 000000000000 000000000000 (re)
+
+ 120
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 1 b8e02f643373 000000000000 000000000000 (re)
+ 1 3 3 ..... 2 5d9299349fc0 000000000000 000000000000 (re)
+ 2 6 3 ..... 0 2661d26c6496 000000000000 000000000000 (re)
+
+ 201
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 2 b8e02f643373 000000000000 000000000000 (re)
+ 1 3 3 ..... 0 5d9299349fc0 000000000000 000000000000 (re)
+ 2 6 3 ..... 1 2661d26c6496 000000000000 000000000000 (re)
+
+ 210
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 2 b8e02f643373 000000000000 000000000000 (re)
+ 1 3 3 ..... 1 5d9299349fc0 000000000000 000000000000 (re)
+ 2 6 3 ..... 0 2661d26c6496 000000000000 000000000000 (re)
+
+ manifest-file
+ rev offset length ..... linkrev nodeid p1 p2 (re)
+ 0 0 3 ..... 3 b8e02f643373 000000000000 000000000000 (re)
+ 1 3 3 ..... 4 5d9299349fc0 000000000000 000000000000 (re)
+
+ $ cd ..
+ $ for i in 0 1 2 3 4; do
+ > hg clone -q -U --pull crossed $i
+ > echo "% Trying to strip revision $i"
+ > hg --cwd $i strip $i
+ > echo "% Verifying"
+ > hg --cwd $i verify
+ > echo
+ > done
+ % Trying to strip revision 0
+ saved backup bundle to $TESTTMP/0/.hg/strip-backup/*-backup.hg (glob)
+ % Verifying
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 7 files, 4 changesets, 15 total revisions
+
+ % Trying to strip revision 1
+ saved backup bundle to $TESTTMP/1/.hg/strip-backup/*-backup.hg (glob)
+ % Verifying
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 7 files, 4 changesets, 14 total revisions
+
+ % Trying to strip revision 2
+ saved backup bundle to $TESTTMP/2/.hg/strip-backup/*-backup.hg (glob)
+ % Verifying
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 7 files, 4 changesets, 14 total revisions
+
+ % Trying to strip revision 3
+ saved backup bundle to $TESTTMP/3/.hg/strip-backup/*-backup.hg (glob)
+ % Verifying
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 7 files, 4 changesets, 19 total revisions
+
+ % Trying to strip revision 4
+ saved backup bundle to $TESTTMP/4/.hg/strip-backup/*-backup.hg (glob)
+ % Verifying
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 7 files, 4 changesets, 19 total revisions
+
diff --git a/tests/test-subrepo-deep-nested-change.t b/tests/test-subrepo-deep-nested-change.t
new file mode 100644
index 0000000..aa79c87
--- /dev/null
+++ b/tests/test-subrepo-deep-nested-change.t
@@ -0,0 +1,264 @@
+Preparing the subrepository 'sub2'
+
+ $ hg init sub2
+ $ echo sub2 > sub2/sub2
+ $ hg add -R sub2
+ adding sub2/sub2 (glob)
+ $ hg commit -R sub2 -m "sub2 import"
+
+Preparing the 'sub1' repo which depends on the subrepo 'sub2'
+
+ $ hg init sub1
+ $ echo sub1 > sub1/sub1
+ $ echo "sub2 = ../sub2" > sub1/.hgsub
+ $ hg clone sub2 sub1/sub2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg add -R sub1
+ adding sub1/.hgsub (glob)
+ adding sub1/sub1 (glob)
+ $ hg commit -R sub1 -m "sub1 import"
+
+Preparing the 'main' repo which depends on the subrepo 'sub1'
+
+ $ hg init main
+ $ echo main > main/main
+ $ echo "sub1 = ../sub1" > main/.hgsub
+ $ hg clone sub1 main/sub1
+ updating to branch default
+ cloning subrepo sub2 from $TESTTMP/sub2
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg add -R main
+ adding main/.hgsub (glob)
+ adding main/main (glob)
+ $ hg commit -R main -m "main import"
+
+Cleaning both repositories, just as a clone -U
+
+ $ hg up -C -R sub2 null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg up -C -R sub1 null
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ hg up -C -R main null
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ rm -rf main/sub1
+ $ rm -rf sub1/sub2
+
+Clone main
+
+ $ hg clone main cloned
+ updating to branch default
+ cloning subrepo sub1 from $TESTTMP/sub1
+ cloning subrepo sub1/sub2 from $TESTTMP/sub2 (glob)
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Checking cloned repo ids
+
+ $ printf "cloned " ; hg id -R cloned
+ cloned 7f491f53a367 tip
+ $ printf "cloned/sub1 " ; hg id -R cloned/sub1
+ cloned/sub1 fc3b4ce2696f tip
+ $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
+ cloned/sub1/sub2 c57a0840e3ba tip
+
+debugsub output for main and sub1
+
+ $ hg debugsub -R cloned
+ path sub1
+ source ../sub1
+ revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
+ $ hg debugsub -R cloned/sub1
+ path sub2
+ source ../sub2
+ revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
+
+Modifying deeply nested 'sub2'
+
+ $ echo modified > cloned/sub1/sub2/sub2
+ $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
+ committing subrepository sub1
+ committing subrepository sub1/sub2 (glob)
+
+Checking modified node ids
+
+ $ printf "cloned " ; hg id -R cloned
+ cloned ffe6649062fe tip
+ $ printf "cloned/sub1 " ; hg id -R cloned/sub1
+ cloned/sub1 2ecb03bf44a9 tip
+ $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
+ cloned/sub1/sub2 53dd3430bcaf tip
+
+debugsub output for main and sub1
+
+ $ hg debugsub -R cloned
+ path sub1
+ source ../sub1
+ revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
+ $ hg debugsub -R cloned/sub1
+ path sub2
+ source ../sub2
+ revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
+
+Check that deep archiving works
+
+ $ cd cloned
+ $ echo 'test' > sub1/sub2/test.txt
+ $ hg --config extensions.largefiles=! add sub1/sub2/test.txt
+ $ mkdir sub1/sub2/folder
+ $ echo 'subfolder' > sub1/sub2/folder/test.txt
+ $ hg --config extensions.largefiles=! add sub1/sub2/folder/test.txt
+ $ hg ci -Sm "add test.txt"
+ committing subrepository sub1
+ committing subrepository sub1/sub2 (glob)
+ $ hg --config extensions.largefiles=! archive -S ../archive_all
+ $ find ../archive_all | sort
+ ../archive_all
+ ../archive_all/.hg_archival.txt
+ ../archive_all/.hgsub
+ ../archive_all/.hgsubstate
+ ../archive_all/main
+ ../archive_all/sub1
+ ../archive_all/sub1/.hgsub
+ ../archive_all/sub1/.hgsubstate
+ ../archive_all/sub1/sub1
+ ../archive_all/sub1/sub2
+ ../archive_all/sub1/sub2/folder
+ ../archive_all/sub1/sub2/folder/test.txt
+ ../archive_all/sub1/sub2/sub2
+ ../archive_all/sub1/sub2/test.txt
+
+Check that archive -X works in deep subrepos
+
+ $ hg --config extensions.largefiles=! archive -S -X '**test*' ../archive_exclude
+ $ find ../archive_exclude | sort
+ ../archive_exclude
+ ../archive_exclude/.hg_archival.txt
+ ../archive_exclude/.hgsub
+ ../archive_exclude/.hgsubstate
+ ../archive_exclude/main
+ ../archive_exclude/sub1
+ ../archive_exclude/sub1/.hgsub
+ ../archive_exclude/sub1/.hgsubstate
+ ../archive_exclude/sub1/sub1
+ ../archive_exclude/sub1/sub2
+ ../archive_exclude/sub1/sub2/sub2
+
+ $ hg --config extensions.largefiles=! archive -S -I '**test*' ../archive_include
+ $ find ../archive_include | sort
+ ../archive_include
+ ../archive_include/sub1
+ ../archive_include/sub1/sub2
+ ../archive_include/sub1/sub2/folder
+ ../archive_include/sub1/sub2/folder/test.txt
+ ../archive_include/sub1/sub2/test.txt
+
+Check that deep archive works with largefiles (which overrides hgsubrepo impl)
+This also tests the repo.ui regression in 43fb170a23bd, and that lf subrepo
+subrepos are archived properly.
+Note that add --large through a subrepo currently adds the file as a normal file
+
+ $ echo "large" > sub1/sub2/large.bin
+ $ hg --config extensions.largefiles= add --large -R sub1/sub2 sub1/sub2/large.bin
+ $ echo "large" > large.bin
+ $ hg --config extensions.largefiles= add --large large.bin
+ $ hg --config extensions.largefiles= ci -S -m "add large files"
+ committing subrepository sub1
+ committing subrepository sub1/sub2 (glob)
+
+ $ hg --config extensions.largefiles= archive -S ../archive_lf
+ $ find ../archive_lf | sort
+ ../archive_lf
+ ../archive_lf/.hg_archival.txt
+ ../archive_lf/.hgsub
+ ../archive_lf/.hgsubstate
+ ../archive_lf/large.bin
+ ../archive_lf/main
+ ../archive_lf/sub1
+ ../archive_lf/sub1/.hgsub
+ ../archive_lf/sub1/.hgsubstate
+ ../archive_lf/sub1/sub1
+ ../archive_lf/sub1/sub2
+ ../archive_lf/sub1/sub2/folder
+ ../archive_lf/sub1/sub2/folder/test.txt
+ ../archive_lf/sub1/sub2/large.bin
+ ../archive_lf/sub1/sub2/sub2
+ ../archive_lf/sub1/sub2/test.txt
+ $ rm -rf ../archive_lf
+
+Exclude large files from main and sub-sub repo
+
+ $ hg --config extensions.largefiles= archive -S -X '**.bin' ../archive_lf
+ $ find ../archive_lf | sort
+ ../archive_lf
+ ../archive_lf/.hg_archival.txt
+ ../archive_lf/.hgsub
+ ../archive_lf/.hgsubstate
+ ../archive_lf/main
+ ../archive_lf/sub1
+ ../archive_lf/sub1/.hgsub
+ ../archive_lf/sub1/.hgsubstate
+ ../archive_lf/sub1/sub1
+ ../archive_lf/sub1/sub2
+ ../archive_lf/sub1/sub2/folder
+ ../archive_lf/sub1/sub2/folder/test.txt
+ ../archive_lf/sub1/sub2/sub2
+ ../archive_lf/sub1/sub2/test.txt
+ $ rm -rf ../archive_lf
+
+Exclude normal files from main and sub-sub repo
+
+ $ hg --config extensions.largefiles= archive -S -X '**.txt' ../archive_lf
+ $ find ../archive_lf | sort
+ ../archive_lf
+ ../archive_lf/.hgsub
+ ../archive_lf/.hgsubstate
+ ../archive_lf/large.bin
+ ../archive_lf/main
+ ../archive_lf/sub1
+ ../archive_lf/sub1/.hgsub
+ ../archive_lf/sub1/.hgsubstate
+ ../archive_lf/sub1/sub1
+ ../archive_lf/sub1/sub2
+ ../archive_lf/sub1/sub2/large.bin
+ ../archive_lf/sub1/sub2/sub2
+ $ rm -rf ../archive_lf
+
+Include normal files from within a largefiles subrepo
+
+ $ hg --config extensions.largefiles= archive -S -I '**.txt' ../archive_lf
+ $ find ../archive_lf | sort
+ ../archive_lf
+ ../archive_lf/.hg_archival.txt
+ ../archive_lf/sub1
+ ../archive_lf/sub1/sub2
+ ../archive_lf/sub1/sub2/folder
+ ../archive_lf/sub1/sub2/folder/test.txt
+ ../archive_lf/sub1/sub2/test.txt
+ $ rm -rf ../archive_lf
+
+Include large files from within a largefiles subrepo
+
+ $ hg --config extensions.largefiles= archive -S -I '**.bin' ../archive_lf
+ $ find ../archive_lf | sort
+ ../archive_lf
+ ../archive_lf/large.bin
+ ../archive_lf/sub1
+ ../archive_lf/sub1/sub2
+ ../archive_lf/sub1/sub2/large.bin
+ $ rm -rf ../archive_lf
+
+Find an exact largefile match in a largefiles subrepo
+
+ $ hg --config extensions.largefiles= archive -S -I 'sub1/sub2/large.bin' ../archive_lf
+ $ find ../archive_lf | sort
+ ../archive_lf
+ ../archive_lf/sub1
+ ../archive_lf/sub1/sub2
+ ../archive_lf/sub1/sub2/large.bin
+ $ rm -rf ../archive_lf
+
+Find an exact match to a standin (should archive nothing)
+ $ hg --config extensions.largefiles= archive -S -I 'sub/sub2/.hglf/large.bin' ../archive_lf
+ $ find ../archive_lf 2> /dev/null | sort
+
+ $ cd ..
diff --git a/tests/test-subrepo-git.t b/tests/test-subrepo-git.t
new file mode 100644
index 0000000..3f06a46
--- /dev/null
+++ b/tests/test-subrepo-git.t
@@ -0,0 +1,534 @@
+ $ "$TESTDIR/hghave" git || exit 80
+
+make git commits repeatable
+
+ $ echo "[core]" >> $HOME/.gitconfig
+ $ echo "autocrlf = false" >> $HOME/.gitconfig
+ $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
+ $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
+ $ GIT_AUTHOR_DATE='1234567891 +0000'; export GIT_AUTHOR_DATE
+ $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
+ $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
+ $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
+
+root hg repo
+
+ $ hg init t
+ $ cd t
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m a
+ $ cd ..
+
+new external git repo
+
+ $ mkdir gitroot
+ $ cd gitroot
+ $ git init -q
+ $ echo g > g
+ $ git add g
+ $ git commit -q -m g
+
+add subrepo clone
+
+ $ cd ../t
+ $ echo 's = [git]../gitroot' > .hgsub
+ $ git clone -q ../gitroot s
+ $ hg add .hgsub
+ $ hg commit -m 'new git subrepo'
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+
+record a new commit from upstream from a different branch
+
+ $ cd ../gitroot
+ $ git checkout -q -b testing
+ $ echo gg >> g
+ $ git commit -q -a -m gg
+
+ $ cd ../t/s
+ $ git pull -q >/dev/null 2>/dev/null
+ $ git checkout -q -b testing origin/testing >/dev/null
+
+ $ cd ..
+ $ hg status --subrepos
+ M s/g
+ $ hg commit -m 'update git subrepo'
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
+
+make $GITROOT pushable, by replacing it with a clone with nothing checked out
+
+ $ cd ..
+ $ git clone gitroot gitrootbare --bare -q
+ $ rm -rf gitroot
+ $ mv gitrootbare gitroot
+
+clone root
+
+ $ cd t
+ $ hg clone . ../tc
+ updating to branch default
+ cloning subrepo s from $TESTTMP/gitroot
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../tc
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
+
+update to previous substate
+
+ $ hg update 1 -q
+ $ cat s/g
+ g
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+
+clone root, make local change
+
+ $ cd ../t
+ $ hg clone . ../ta
+ updating to branch default
+ cloning subrepo s from $TESTTMP/gitroot
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd ../ta
+ $ echo ggg >> s/g
+ $ hg status --subrepos
+ M s/g
+ $ hg commit --subrepos -m ggg
+ committing subrepository s
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision 79695940086840c99328513acbe35f90fcd55e57
+
+clone root separately, make different local change
+
+ $ cd ../t
+ $ hg clone . ../tb
+ updating to branch default
+ cloning subrepo s from $TESTTMP/gitroot
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd ../tb/s
+ $ echo f > f
+ $ git add f
+ $ cd ..
+
+ $ hg status --subrepos
+ A s/f
+ $ hg commit --subrepos -m f
+ committing subrepository s
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+
+user b push changes
+
+ $ hg push 2>/dev/null
+ pushing to $TESTTMP/t (glob)
+ pushing branch testing of subrepo s
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+user a pulls, merges, commits
+
+ $ cd ../ta
+ $ hg pull
+ pulling from $TESTTMP/t (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg merge 2>/dev/null
+ pulling subrepo s from $TESTTMP/gitroot
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ cat s/f
+ f
+ $ cat s/g
+ g
+ gg
+ ggg
+ $ hg commit --subrepos -m 'merge'
+ committing subrepository s
+ $ hg status --subrepos --rev 1:5
+ M .hgsubstate
+ M s/g
+ A s/f
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision f47b465e1bce645dbf37232a00574aa1546ca8d3
+ $ hg push 2>/dev/null
+ pushing to $TESTTMP/t (glob)
+ pushing branch testing of subrepo s
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+
+make upstream git changes
+
+ $ cd ..
+ $ git clone -q gitroot gitclone
+ $ cd gitclone
+ $ echo ff >> f
+ $ git commit -q -a -m ff
+ $ echo fff >> f
+ $ git commit -q -a -m fff
+ $ git push origin testing 2>/dev/null
+
+make and push changes to hg without updating the subrepo
+
+ $ cd ../t
+ $ hg clone . ../td
+ updating to branch default
+ cloning subrepo s from $TESTTMP/gitroot
+ checking out detached HEAD in subrepo s
+ check out a git branch if you intend to make changes
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../td
+ $ echo aa >> a
+ $ hg commit -m aa
+ $ hg push
+ pushing to $TESTTMP/t (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+sync to upstream git, distribute changes
+
+ $ cd ../ta
+ $ hg pull -u -q
+ $ cd s
+ $ git pull -q >/dev/null 2>/dev/null
+ $ cd ..
+ $ hg commit -m 'git upstream sync'
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ $ hg push -q
+
+ $ cd ../tb
+ $ hg pull -q
+ $ hg update 2>/dev/null
+ pulling subrepo s from $TESTTMP/gitroot
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+
+update to a revision without the subrepo, keeping the local git repository
+
+ $ cd ../t
+ $ hg up 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ ls -a s
+ .
+ ..
+ .git
+
+ $ hg up 2
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ ls -a s
+ .
+ ..
+ .git
+ g
+
+archive subrepos
+
+ $ cd ../tc
+ $ hg pull -q
+ $ hg archive --subrepos -r 5 ../archive 2>/dev/null
+ pulling subrepo s from $TESTTMP/gitroot
+ $ cd ../archive
+ $ cat s/f
+ f
+ $ cat s/g
+ g
+ gg
+ ggg
+
+ $ hg -R ../tc archive --subrepo -r 5 -X ../tc/**f ../archive_x 2>/dev/null
+ $ find ../archive_x | sort | grep -v pax_global_header
+ ../archive_x
+ ../archive_x/.hg_archival.txt
+ ../archive_x/.hgsub
+ ../archive_x/.hgsubstate
+ ../archive_x/a
+ ../archive_x/s
+ ../archive_x/s/g
+
+create nested repo
+
+ $ cd ..
+ $ hg init outer
+ $ cd outer
+ $ echo b>b
+ $ hg add b
+ $ hg commit -m b
+
+ $ hg clone ../t inner
+ updating to branch default
+ cloning subrepo s from $TESTTMP/gitroot
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo inner = inner > .hgsub
+ $ hg add .hgsub
+ $ hg commit -m 'nested sub'
+
+nested commit
+
+ $ echo ffff >> inner/s/f
+ $ hg status --subrepos
+ M inner/s/f
+ $ hg commit --subrepos -m nested
+ committing subrepository inner
+ committing subrepository inner/s (glob)
+
+nested archive
+
+ $ hg archive --subrepos ../narchive
+ $ ls ../narchive/inner/s | grep -v pax_global_header
+ f
+ g
+
+relative source expansion
+
+ $ cd ..
+ $ mkdir d
+ $ hg clone t d/t
+ updating to branch default
+ cloning subrepo s from $TESTTMP/gitroot
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Don't crash if the subrepo is missing
+
+ $ hg clone t missing -q
+ $ cd missing
+ $ rm -rf s
+ $ hg status -S
+ $ hg sum | grep commit
+ commit: 1 subrepos
+ $ hg push -q
+ abort: subrepo s is missing
+ [255]
+ $ hg commit --subrepos -qm missing
+ abort: subrepo s is missing
+ [255]
+ $ hg update -C
+ cloning subrepo s from $TESTTMP/gitroot
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg sum | grep commit
+ commit: (clean)
+
+Don't crash if the .hgsubstate entry is missing
+
+ $ hg update 1 -q
+ $ hg rm .hgsubstate
+ $ hg commit .hgsubstate -m 'no substate'
+ nothing changed
+ [1]
+ $ hg tag -l nosubstate
+ $ hg manifest
+ .hgsub
+ .hgsubstate
+ a
+
+ $ hg status -S
+ R .hgsubstate
+ $ hg sum | grep commit
+ commit: 1 removed, 1 subrepos (new branch head)
+
+ $ hg commit -m 'restore substate'
+ nothing changed
+ [1]
+ $ hg manifest
+ .hgsub
+ .hgsubstate
+ a
+ $ hg sum | grep commit
+ commit: 1 removed, 1 subrepos (new branch head)
+
+ $ hg update -qC nosubstate
+ $ ls s
+ g
+
+issue3109: false positives in git diff-index
+
+ $ hg update -q
+ $ touch -t 200001010000 s/g
+ $ hg status --subrepos
+ $ touch -t 200001010000 s/g
+ $ hg sum | grep commit
+ commit: (clean)
+
+Check hg update --clean
+ $ cd $TESTTMP/ta
+ $ echo > s/g
+ $ cd s
+ $ echo c1 > f1
+ $ echo c1 > f2
+ $ git add f1
+ $ cd ..
+ $ hg status -S
+ M s/g
+ A s/f1
+ $ ls s
+ f
+ f1
+ f2
+ g
+ $ hg update --clean
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg status -S
+ $ ls s
+ f
+ f1
+ f2
+ g
+
+Sticky subrepositories, no changes
+ $ cd $TESTTMP/ta
+ $ hg id -n
+ 7
+ $ cd s
+ $ git rev-parse HEAD
+ 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ $ cd ..
+ $ hg update 1 > /dev/null 2>&1
+ $ hg id -n
+ 1
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+
+Sticky subrepositorys, file changes
+ $ touch s/f1
+ $ cd s
+ $ git add f1
+ $ cd ..
+ $ hg id -n
+ 1+
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+ $ hg update 4
+ subrepository sources for s differ
+ use (l)ocal source (da5f5b1) or (r)emote source (aa84837)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 4+
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+ $ hg update --clean tip > /dev/null 2>&1
+
+Sticky subrepository, revision updates
+ $ hg id -n
+ 7
+ $ cd s
+ $ git rev-parse HEAD
+ 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ $ cd ..
+ $ cd s
+ $ git checkout aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ Previous HEAD position was 32a3438... fff
+ HEAD is now at aa84837... f
+ $ cd ..
+ $ hg update 1
+ subrepository sources for s differ (in checked out version)
+ use (l)ocal source (32a3438) or (r)emote source (da5f5b1)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1+
+ $ cd s
+ $ git rev-parse HEAD
+ aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ $ cd ..
+
+Sticky subrepository, file changes and revision updates
+ $ touch s/f1
+ $ cd s
+ $ git add f1
+ $ git rev-parse HEAD
+ aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ $ cd ..
+ $ hg id -n
+ 1+
+ $ hg update 7
+ subrepository sources for s differ
+ use (l)ocal source (32a3438) or (r)emote source (32a3438)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 7+
+ $ cd s
+ $ git rev-parse HEAD
+ aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ $ cd ..
+
+Sticky repository, update --clean
+ $ hg update --clean tip 2>/dev/null
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 7
+ $ cd s
+ $ git rev-parse HEAD
+ 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ $ cd ..
+
+Test subrepo already at intended revision:
+ $ cd s
+ $ git checkout 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ HEAD is now at 32a3438... fff
+ $ cd ..
+ $ hg update 1
+ Previous HEAD position was 32a3438... fff
+ HEAD is now at da5f5b1... g
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+
+Test forgetting files, not implemented in git subrepo, used to
+traceback
+#if no-windows
+ $ hg forget 'notafile*'
+ notafile*: No such file or directory
+ [1]
+#else
+ $ hg forget 'notafile'
+ notafile: * (glob)
+ [1]
+#endif
+
+ $ cd ..
diff --git a/tests/test-subrepo-missing.t b/tests/test-subrepo-missing.t
new file mode 100644
index 0000000..fb6bca9
--- /dev/null
+++ b/tests/test-subrepo-missing.t
@@ -0,0 +1,71 @@
+ $ hg init repo
+ $ cd repo
+ $ hg init subrepo
+ $ echo a > subrepo/a
+ $ hg -R subrepo ci -Am adda
+ adding a
+ $ echo 'subrepo = subrepo' > .hgsub
+ $ hg ci -Am addsubrepo
+ adding .hgsub
+ $ echo b > subrepo/b
+ $ hg -R subrepo ci -Am addb
+ adding b
+ $ hg ci -m updatedsub
+
+ignore blanklines in .hgsubstate
+
+ >>> file('.hgsubstate', 'wb').write('\n\n \t \n \n')
+ $ hg st --subrepos
+ M .hgsubstate
+ $ hg revert -qC .hgsubstate
+
+abort more gracefully on .hgsubstate parsing error
+
+ $ cp .hgsubstate .hgsubstate.old
+ >>> file('.hgsubstate', 'wb').write('\ninvalid')
+ $ hg st --subrepos
+ abort: invalid subrepository revision specifier in .hgsubstate line 2
+ [255]
+ $ mv .hgsubstate.old .hgsubstate
+
+delete .hgsub and revert it
+
+ $ rm .hgsub
+ $ hg revert .hgsub
+ warning: subrepo spec file .hgsub not found
+ warning: subrepo spec file .hgsub not found
+
+delete .hgsubstate and revert it
+
+ $ rm .hgsubstate
+ $ hg revert .hgsubstate
+
+delete .hgsub and update
+
+ $ rm .hgsub
+ $ hg up 0
+ warning: subrepo spec file .hgsub not found
+ warning: subrepo spec file .hgsub not found
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg st
+ warning: subrepo spec file .hgsub not found
+ ! .hgsub
+ $ ls subrepo
+ a
+
+delete .hgsubstate and update
+
+ $ hg up -C
+ warning: subrepo spec file .hgsub not found
+ warning: subrepo spec file .hgsub not found
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm .hgsubstate
+ $ hg up 0
+ remote changed .hgsubstate which local deleted
+ use (c)hanged version or leave (d)eleted? c
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg st
+ $ ls subrepo
+ a
+
+ $ cd ..
diff --git a/tests/test-subrepo-paths.t b/tests/test-subrepo-paths.t
new file mode 100644
index 0000000..fd5c9c9
--- /dev/null
+++ b/tests/test-subrepo-paths.t
@@ -0,0 +1,61 @@
+ $ hg init outer
+ $ cd outer
+
+ $ echo '[paths]' >> .hg/hgrc
+ $ echo 'default = http://example.net/' >> .hg/hgrc
+
+hg debugsub with no remapping
+
+ $ echo 'sub = libfoo' > .hgsub
+ $ hg add .hgsub
+
+ $ hg debugsub
+ path sub
+ source libfoo
+ revision
+
+hg debugsub with remapping
+
+ $ echo '[subpaths]' >> .hg/hgrc
+ $ printf 'http://example.net/lib(.*) = C:\\libs\\\\1-lib\\\n' >> .hg/hgrc # no-check-code
+
+ $ hg debugsub
+ path sub
+ source C:\libs\foo-lib\
+ revision
+
+test cumulative remapping, the $HGRCPATH file is loaded first
+
+ $ echo '[subpaths]' >> $HGRCPATH
+ $ echo 'libfoo = libbar' >> $HGRCPATH
+ $ hg debugsub
+ path sub
+ source C:\libs\bar-lib\
+ revision
+
+test absolute source path -- testing with a URL is important since
+standard os.path.join wont treat that as an absolute path
+
+ $ echo 'abs = http://example.net/abs' > .hgsub
+ $ hg debugsub
+ path abs
+ source http://example.net/abs
+ revision
+
+ $ echo 'abs = /abs' > .hgsub
+ $ hg debugsub
+ path abs
+ source /abs
+ revision
+
+test bad subpaths pattern
+
+ $ cat > .hg/hgrc <<EOF
+ > [subpaths]
+ > .* = \1
+ > EOF
+ $ hg debugsub
+ abort: bad subrepository pattern in $TESTTMP/outer/.hg/hgrc:2: invalid group reference (glob)
+ [255]
+
+ $ cd ..
diff --git a/tests/test-subrepo-recursion.t b/tests/test-subrepo-recursion.t
new file mode 100644
index 0000000..fa419b3
--- /dev/null
+++ b/tests/test-subrepo-recursion.t
@@ -0,0 +1,494 @@
+Create test repository:
+
+ $ hg init repo
+ $ cd repo
+ $ echo x1 > x.txt
+
+ $ hg init foo
+ $ cd foo
+ $ echo y1 > y.txt
+
+ $ hg init bar
+ $ cd bar
+ $ echo z1 > z.txt
+
+ $ cd ..
+ $ echo 'bar = bar' > .hgsub
+
+ $ cd ..
+ $ echo 'foo = foo' > .hgsub
+
+Add files --- .hgsub files must go first to trigger subrepos:
+
+ $ hg add -S .hgsub
+ $ hg add -S foo/.hgsub
+ $ hg add -S foo/bar
+ adding foo/bar/z.txt (glob)
+ $ hg add -S
+ adding x.txt
+ adding foo/y.txt (glob)
+
+Test recursive status without committing anything:
+
+ $ hg status -S
+ A .hgsub
+ A foo/.hgsub
+ A foo/bar/z.txt
+ A foo/y.txt
+ A x.txt
+
+Test recursive diff without committing anything:
+
+ $ hg diff --nodates -S foo
+ diff -r 000000000000 foo/.hgsub
+ --- /dev/null
+ +++ b/foo/.hgsub
+ @@ -0,0 +1,1 @@
+ +bar = bar
+ diff -r 000000000000 foo/y.txt
+ --- /dev/null
+ +++ b/foo/y.txt
+ @@ -0,0 +1,1 @@
+ +y1
+ diff -r 000000000000 foo/bar/z.txt
+ --- /dev/null
+ +++ b/foo/bar/z.txt
+ @@ -0,0 +1,1 @@
+ +z1
+
+Commits:
+
+ $ hg commit -m fails
+ abort: uncommitted changes in subrepo foo
+ (use --subrepos for recursive commit)
+ [255]
+
+The --subrepos flag overwrite the config setting:
+
+ $ hg commit -m 0-0-0 --config ui.commitsubrepos=No --subrepos
+ committing subrepository foo
+ committing subrepository foo/bar (glob)
+
+ $ cd foo
+ $ echo y2 >> y.txt
+ $ hg commit -m 0-1-0
+
+ $ cd bar
+ $ echo z2 >> z.txt
+ $ hg commit -m 0-1-1
+
+ $ cd ..
+ $ hg commit -m 0-2-1
+
+ $ cd ..
+ $ hg commit -m 1-2-1
+
+Change working directory:
+
+ $ echo y3 >> foo/y.txt
+ $ echo z3 >> foo/bar/z.txt
+ $ hg status -S
+ M foo/bar/z.txt
+ M foo/y.txt
+ $ hg diff --nodates -S
+ diff -r d254738c5f5e foo/y.txt
+ --- a/foo/y.txt
+ +++ b/foo/y.txt
+ @@ -1,2 +1,3 @@
+ y1
+ y2
+ +y3
+ diff -r 9647f22de499 foo/bar/z.txt
+ --- a/foo/bar/z.txt
+ +++ b/foo/bar/z.txt
+ @@ -1,2 +1,3 @@
+ z1
+ z2
+ +z3
+
+Status call crossing repository boundaries:
+
+ $ hg status -S foo/bar/z.txt
+ M foo/bar/z.txt
+ $ hg status -S -I 'foo/?.txt'
+ M foo/y.txt
+ $ hg status -S -I '**/?.txt'
+ M foo/bar/z.txt
+ M foo/y.txt
+ $ hg diff --nodates -S -I '**/?.txt'
+ diff -r d254738c5f5e foo/y.txt
+ --- a/foo/y.txt
+ +++ b/foo/y.txt
+ @@ -1,2 +1,3 @@
+ y1
+ y2
+ +y3
+ diff -r 9647f22de499 foo/bar/z.txt
+ --- a/foo/bar/z.txt
+ +++ b/foo/bar/z.txt
+ @@ -1,2 +1,3 @@
+ z1
+ z2
+ +z3
+
+Status from within a subdirectory:
+
+ $ mkdir dir
+ $ cd dir
+ $ echo a1 > a.txt
+ $ hg status -S
+ M foo/bar/z.txt
+ M foo/y.txt
+ ? dir/a.txt
+ $ hg diff --nodates -S
+ diff -r d254738c5f5e foo/y.txt
+ --- a/foo/y.txt
+ +++ b/foo/y.txt
+ @@ -1,2 +1,3 @@
+ y1
+ y2
+ +y3
+ diff -r 9647f22de499 foo/bar/z.txt
+ --- a/foo/bar/z.txt
+ +++ b/foo/bar/z.txt
+ @@ -1,2 +1,3 @@
+ z1
+ z2
+ +z3
+
+Status with relative path:
+
+ $ hg status -S ..
+ M ../foo/bar/z.txt
+ M ../foo/y.txt
+ ? a.txt
+ $ hg diff --nodates -S ..
+ diff -r d254738c5f5e foo/y.txt
+ --- a/foo/y.txt
+ +++ b/foo/y.txt
+ @@ -1,2 +1,3 @@
+ y1
+ y2
+ +y3
+ diff -r 9647f22de499 foo/bar/z.txt
+ --- a/foo/bar/z.txt
+ +++ b/foo/bar/z.txt
+ @@ -1,2 +1,3 @@
+ z1
+ z2
+ +z3
+ $ cd ..
+
+Cleanup and final commit:
+
+ $ rm -r dir
+ $ hg commit --subrepos -m 2-3-2
+ committing subrepository foo
+ committing subrepository foo/bar (glob)
+
+Test explicit path commands within subrepos: add/forget
+ $ echo z1 > foo/bar/z2.txt
+ $ hg status -S
+ ? foo/bar/z2.txt
+ $ hg add foo/bar/z2.txt
+ $ hg status -S
+ A foo/bar/z2.txt
+ $ hg forget foo/bar/z2.txt
+ $ hg status -S
+ ? foo/bar/z2.txt
+ $ hg forget foo/bar/z2.txt
+ not removing foo/bar/z2.txt: file is already untracked (glob)
+ [1]
+ $ hg status -S
+ ? foo/bar/z2.txt
+ $ rm foo/bar/z2.txt
+
+Log with the relationships between repo and its subrepo:
+
+ $ hg log --template '{rev}:{node|short} {desc}\n'
+ 2:1326fa26d0c0 2-3-2
+ 1:4b3c9ff4f66b 1-2-1
+ 0:23376cbba0d8 0-0-0
+
+ $ hg -R foo log --template '{rev}:{node|short} {desc}\n'
+ 3:65903cebad86 2-3-2
+ 2:d254738c5f5e 0-2-1
+ 1:8629ce7dcc39 0-1-0
+ 0:af048e97ade2 0-0-0
+
+ $ hg -R foo/bar log --template '{rev}:{node|short} {desc}\n'
+ 2:31ecbdafd357 2-3-2
+ 1:9647f22de499 0-1-1
+ 0:4904098473f9 0-0-0
+
+Status between revisions:
+
+ $ hg status -S
+ $ hg status -S --rev 0:1
+ M .hgsubstate
+ M foo/.hgsubstate
+ M foo/bar/z.txt
+ M foo/y.txt
+ $ hg diff --nodates -S -I '**/?.txt' --rev 0:1
+ diff -r af048e97ade2 -r d254738c5f5e foo/y.txt
+ --- a/foo/y.txt
+ +++ b/foo/y.txt
+ @@ -1,1 +1,2 @@
+ y1
+ +y2
+ diff -r 4904098473f9 -r 9647f22de499 foo/bar/z.txt
+ --- a/foo/bar/z.txt
+ +++ b/foo/bar/z.txt
+ @@ -1,1 +1,2 @@
+ z1
+ +z2
+
+Enable progress extension for archive tests:
+
+ $ cp $HGRCPATH $HGRCPATH.no-progress
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > progress =
+ > [progress]
+ > assume-tty = 1
+ > delay = 0
+ > format = topic bar number
+ > refresh = 0
+ > width = 60
+ > EOF
+
+Test archiving to a directory tree (the doubled lines in the output
+only show up in the test output, not in real usage):
+
+ $ hg archive --subrepos ../archive 2>&1 | "$TESTDIR/filtercr.py"
+
+ archiving [ ] 0/3
+ archiving [ ] 0/3
+ archiving [=============> ] 1/3
+ archiving [=============> ] 1/3
+ archiving [===========================> ] 2/3
+ archiving [===========================> ] 2/3
+ archiving [==========================================>] 3/3
+ archiving [==========================================>] 3/3
+
+ archiving (foo) [ ] 0/3
+ archiving (foo) [ ] 0/3
+ archiving (foo) [===========> ] 1/3
+ archiving (foo) [===========> ] 1/3
+ archiving (foo) [=======================> ] 2/3
+ archiving (foo) [=======================> ] 2/3
+ archiving (foo) [====================================>] 3/3
+ archiving (foo) [====================================>] 3/3
+
+ archiving (foo/bar) [ ] 0/1 (glob)
+ archiving (foo/bar) [ ] 0/1 (glob)
+ archiving (foo/bar) [================================>] 1/1 (glob)
+ archiving (foo/bar) [================================>] 1/1 (glob)
+ \r (esc)
+ $ find ../archive | sort
+ ../archive
+ ../archive/.hg_archival.txt
+ ../archive/.hgsub
+ ../archive/.hgsubstate
+ ../archive/foo
+ ../archive/foo/.hgsub
+ ../archive/foo/.hgsubstate
+ ../archive/foo/bar
+ ../archive/foo/bar/z.txt
+ ../archive/foo/y.txt
+ ../archive/x.txt
+
+Test archiving to zip file (unzip output is unstable):
+
+ $ hg archive --subrepos ../archive.zip 2>&1 | "$TESTDIR/filtercr.py"
+
+ archiving [ ] 0/3
+ archiving [ ] 0/3
+ archiving [=============> ] 1/3
+ archiving [=============> ] 1/3
+ archiving [===========================> ] 2/3
+ archiving [===========================> ] 2/3
+ archiving [==========================================>] 3/3
+ archiving [==========================================>] 3/3
+
+ archiving (foo) [ ] 0/3
+ archiving (foo) [ ] 0/3
+ archiving (foo) [===========> ] 1/3
+ archiving (foo) [===========> ] 1/3
+ archiving (foo) [=======================> ] 2/3
+ archiving (foo) [=======================> ] 2/3
+ archiving (foo) [====================================>] 3/3
+ archiving (foo) [====================================>] 3/3
+
+ archiving (foo/bar) [ ] 0/1 (glob)
+ archiving (foo/bar) [ ] 0/1 (glob)
+ archiving (foo/bar) [================================>] 1/1 (glob)
+ archiving (foo/bar) [================================>] 1/1 (glob)
+ \r (esc)
+
+Test archiving a revision that references a subrepo that is not yet
+cloned:
+
+ $ hg clone -U . ../empty
+ $ cd ../empty
+ $ hg archive --subrepos -r tip ../archive.tar.gz 2>&1 | "$TESTDIR/filtercr.py"
+
+ archiving [ ] 0/3
+ archiving [ ] 0/3
+ archiving [=============> ] 1/3
+ archiving [=============> ] 1/3
+ archiving [===========================> ] 2/3
+ archiving [===========================> ] 2/3
+ archiving [==========================================>] 3/3
+ archiving [==========================================>] 3/3
+
+ archiving (foo) [ ] 0/3
+ archiving (foo) [ ] 0/3
+ archiving (foo) [===========> ] 1/3
+ archiving (foo) [===========> ] 1/3
+ archiving (foo) [=======================> ] 2/3
+ archiving (foo) [=======================> ] 2/3
+ archiving (foo) [====================================>] 3/3
+ archiving (foo) [====================================>] 3/3
+
+ archiving (foo/bar) [ ] 0/1 (glob)
+ archiving (foo/bar) [ ] 0/1 (glob)
+ archiving (foo/bar) [================================>] 1/1 (glob)
+ archiving (foo/bar) [================================>] 1/1 (glob)
+
+ cloning subrepo foo from $TESTTMP/repo/foo
+ cloning subrepo foo/bar from $TESTTMP/repo/foo/bar (glob)
+
+The newly cloned subrepos contain no working copy:
+
+ $ hg -R foo summary
+ parent: -1:000000000000 (no revision checked out)
+ branch: default
+ commit: (clean)
+ update: 4 new changesets (update)
+
+Disable progress extension and cleanup:
+
+ $ mv $HGRCPATH.no-progress $HGRCPATH
+
+Test archiving when there is a directory in the way for a subrepo
+created by archive:
+
+ $ hg clone -U . ../almost-empty
+ $ cd ../almost-empty
+ $ mkdir foo
+ $ echo f > foo/f
+ $ hg archive --subrepos -r tip archive
+ cloning subrepo foo from $TESTTMP/empty/foo
+ abort: destination '$TESTTMP/almost-empty/foo' is not empty (glob)
+ [255]
+
+Clone and test outgoing:
+
+ $ cd ..
+ $ hg clone repo repo2
+ updating to branch default
+ cloning subrepo foo from $TESTTMP/repo/foo
+ cloning subrepo foo/bar from $TESTTMP/repo/foo/bar (glob)
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd repo2
+ $ hg outgoing -S
+ comparing with $TESTTMP/repo (glob)
+ searching for changes
+ no changes found
+ comparing with $TESTTMP/repo/foo
+ searching for changes
+ no changes found
+ comparing with $TESTTMP/repo/foo/bar
+ searching for changes
+ no changes found
+ [1]
+
+Make nested change:
+
+ $ echo y4 >> foo/y.txt
+ $ hg diff --nodates -S
+ diff -r 65903cebad86 foo/y.txt
+ --- a/foo/y.txt
+ +++ b/foo/y.txt
+ @@ -1,3 +1,4 @@
+ y1
+ y2
+ y3
+ +y4
+ $ hg commit --subrepos -m 3-4-2
+ committing subrepository foo
+ $ hg outgoing -S
+ comparing with $TESTTMP/repo (glob)
+ searching for changes
+ changeset: 3:2655b8ecc4ee
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3-4-2
+
+ comparing with $TESTTMP/repo/foo
+ searching for changes
+ changeset: 4:e96193d6cb36
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3-4-2
+
+ comparing with $TESTTMP/repo/foo/bar
+ searching for changes
+ no changes found
+
+
+Switch to original repo and setup default path:
+
+ $ cd ../repo
+ $ echo '[paths]' >> .hg/hgrc
+ $ echo 'default = ../repo2' >> .hg/hgrc
+
+Test incoming:
+
+ $ hg incoming -S
+ comparing with $TESTTMP/repo2 (glob)
+ searching for changes
+ changeset: 3:2655b8ecc4ee
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3-4-2
+
+ comparing with $TESTTMP/repo2/foo
+ searching for changes
+ changeset: 4:e96193d6cb36
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3-4-2
+
+ comparing with $TESTTMP/repo2/foo/bar
+ searching for changes
+ no changes found
+
+ $ hg incoming -S --bundle incoming.hg
+ abort: cannot combine --bundle and --subrepos
+ [255]
+
+Test missing subrepo:
+
+ $ rm -r foo
+ $ hg status -S
+ warning: error "unknown revision '65903cebad86f1a84bd4f1134f62fa7dcb7a1c98'" in subrepository "foo"
+
+Issue2619: IndexError: list index out of range on hg add with subrepos
+The subrepo must sorts after the explicit filename.
+
+ $ cd ..
+ $ hg init test
+ $ cd test
+ $ hg init x
+ $ echo "x = x" >> .hgsub
+ $ hg add .hgsub
+ $ touch a x/a
+ $ hg add a x/a
+
+ $ cd ..
diff --git a/tests/test-subrepo-relative-path.t b/tests/test-subrepo-relative-path.t
new file mode 100644
index 0000000..e101511
--- /dev/null
+++ b/tests/test-subrepo-relative-path.t
@@ -0,0 +1,105 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+Preparing the subrepository 'sub'
+
+ $ hg init sub
+ $ echo sub > sub/sub
+ $ hg add -R sub
+ adding sub/sub (glob)
+ $ hg commit -R sub -m "sub import"
+
+Preparing the 'main' repo which depends on the subrepo 'sub'
+
+ $ hg init main
+ $ echo main > main/main
+ $ echo "sub = ../sub" > main/.hgsub
+ $ hg clone sub main/sub
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg add -R main
+ adding main/.hgsub (glob)
+ adding main/main (glob)
+ $ hg commit -R main -m "main import"
+
+Cleaning both repositories, just as a clone -U
+
+ $ hg up -C -R sub null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg up -C -R main null
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ rm -rf main/sub
+
+hide outer repo
+ $ hg init
+
+Serving them both using hgweb
+
+ $ printf '[paths]\n/main = main\nsub = sub\n' > webdir.conf
+ $ hg serve --webdir-conf webdir.conf -a localhost -p $HGPORT \
+ > -A /dev/null -E /dev/null --pid-file hg.pid -d
+ $ cat hg.pid >> $DAEMON_PIDS
+
+Clone main from hgweb
+
+ $ hg clone "http://localhost:$HGPORT/main" cloned
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 3 changes to 3 files
+ updating to branch default
+ cloning subrepo sub from http://localhost:$HGPORT/sub
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Checking cloned repo ids
+
+ $ hg id -R cloned
+ fdfeeb3e979e tip
+ $ hg id -R cloned/sub
+ 863c1745b441 tip
+
+subrepo debug for 'main' clone
+
+ $ hg debugsub -R cloned
+ path sub
+ source ../sub
+ revision 863c1745b441bd97a8c4a096e87793073f4fb215
+
+ $ "$TESTDIR/killdaemons.py"
+
+subrepo paths with ssh urls
+
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/cloned sshclone
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 3 changes to 3 files
+ updating to branch default
+ cloning subrepo sub from ssh://user@dummy/sub
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg -R sshclone push -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/`pwd`/cloned
+ pushing to ssh://user@dummy/$TESTTMP/cloned
+ pushing subrepo sub to ssh://user@dummy/$TESTTMP/sub
+ searching for changes
+ no changes found
+ searching for changes
+ no changes found
+ [1]
+
+ $ cat dummylog
+ Got arguments 1:user@dummy 2:hg -R cloned serve --stdio
+ Got arguments 1:user@dummy 2:hg -R sub serve --stdio
+ Got arguments 1:user@dummy 2:hg -R $TESTTMP/cloned serve --stdio
+ Got arguments 1:user@dummy 2:hg -R $TESTTMP/sub serve --stdio
diff --git a/tests/test-subrepo-svn.t b/tests/test-subrepo-svn.t
new file mode 100644
index 0000000..ba9611d
--- /dev/null
+++ b/tests/test-subrepo-svn.t
@@ -0,0 +1,625 @@
+ $ "$TESTDIR/hghave" svn15 || exit 80
+
+ $ SVNREPOPATH=`pwd`/svn-repo
+#if windows
+ $ SVNREPOURL=file:///`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
+#else
+ $ SVNREPOURL=file://`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
+#endif
+
+create subversion repo
+
+ $ WCROOT="`pwd`/svn-wc"
+ $ svnadmin create svn-repo
+ $ svn co "$SVNREPOURL" svn-wc
+ Checked out revision 0.
+ $ cd svn-wc
+ $ mkdir src
+ $ echo alpha > src/alpha
+ $ svn add src
+ A src
+ A src/alpha (glob)
+ $ mkdir externals
+ $ echo other > externals/other
+ $ svn add externals
+ A externals
+ A externals/other (glob)
+ $ svn ci -m 'Add alpha'
+ Adding externals
+ Adding externals/other (glob)
+ Adding src
+ Adding src/alpha (glob)
+ Transmitting file data ..
+ Committed revision 1.
+ $ svn up -q
+ $ echo "externals -r1 $SVNREPOURL/externals" > extdef
+ $ svn propset -F extdef svn:externals src
+ property 'svn:externals' set on 'src'
+ $ svn ci -m 'Setting externals'
+ Sending src
+
+ Committed revision 2.
+ $ cd ..
+
+create hg repo
+
+ $ mkdir sub
+ $ cd sub
+ $ hg init t
+ $ cd t
+
+first revision, no sub
+
+ $ echo a > a
+ $ hg ci -Am0
+ adding a
+
+add first svn sub with leading whitespaces
+
+ $ echo "s = [svn] $SVNREPOURL/src" >> .hgsub
+ $ echo "subdir/s = [svn] $SVNREPOURL/src" >> .hgsub
+ $ svn co --quiet "$SVNREPOURL"/src s
+ $ mkdir subdir
+ $ svn co --quiet "$SVNREPOURL"/src subdir/s
+ $ hg add .hgsub
+ $ hg ci -m1
+
+make sure we avoid empty commits (issue2445)
+
+ $ hg sum
+ parent: 1:* tip (glob)
+ 1
+ branch: default
+ commit: (clean)
+ update: (current)
+ $ hg ci -moops
+ nothing changed
+ [1]
+
+debugsub
+
+ $ hg debugsub
+ path s
+ source file://*/svn-repo/src (glob)
+ revision 2
+ path subdir/s
+ source file://*/svn-repo/src (glob)
+ revision 2
+
+change file in svn and hg, commit
+
+ $ echo a >> a
+ $ echo alpha >> s/alpha
+ $ hg sum
+ parent: 1:* tip (glob)
+ 1
+ branch: default
+ commit: 1 modified, 1 subrepos
+ update: (current)
+ $ hg commit --subrepos -m 'Message!' | grep -v Updating
+ committing subrepository s
+ Sending*s/alpha (glob)
+ Transmitting file data .
+ Committed revision 3.
+
+ Fetching external item into '*s/externals'* (glob)
+ External at revision 1.
+
+ At revision 3.
+ $ hg debugsub
+ path s
+ source file://*/svn-repo/src (glob)
+ revision 3
+ path subdir/s
+ source file://*/svn-repo/src (glob)
+ revision 2
+
+missing svn file, commit should fail
+
+ $ rm s/alpha
+ $ hg commit --subrepos -m 'abort on missing file'
+ committing subrepository s
+ abort: cannot commit missing svn entries
+ [255]
+ $ svn revert s/alpha > /dev/null
+
+add an unrelated revision in svn and update the subrepo to without
+bringing any changes.
+
+ $ svn mkdir "$SVNREPOURL/unrelated" -m 'create unrelated'
+
+ Committed revision 4.
+ $ svn up -q s
+ $ hg sum
+ parent: 2:* tip (glob)
+ Message!
+ branch: default
+ commit: (clean)
+ update: (current)
+
+ $ echo a > s/a
+
+should be empty despite change to s/a
+
+ $ hg st
+
+add a commit from svn
+
+ $ cd "$WCROOT/src"
+ $ svn up -q
+ $ echo xyz >> alpha
+ $ svn propset svn:mime-type 'text/xml' alpha
+ property 'svn:mime-type' set on 'alpha'
+ $ svn ci -m 'amend a from svn'
+ Sending *alpha (glob)
+ Transmitting file data .
+ Committed revision 5.
+ $ cd ../../sub/t
+
+this commit from hg will fail
+
+ $ echo zzz >> s/alpha
+ $ (hg ci --subrepos -m 'amend alpha from hg' 2>&1; echo "[$?]") | grep -vi 'out of date'
+ committing subrepository s
+ abort: svn:*Commit failed (details follow): (glob)
+ [255]
+ $ svn revert -q s/alpha
+
+this commit fails because of meta changes
+
+ $ svn propset svn:mime-type 'text/html' s/alpha
+ property 'svn:mime-type' set on 's/alpha' (glob)
+ $ (hg ci --subrepos -m 'amend alpha from hg' 2>&1; echo "[$?]") | grep -vi 'out of date'
+ committing subrepository s
+ abort: svn:*Commit failed (details follow): (glob)
+ [255]
+ $ svn revert -q s/alpha
+
+this commit fails because of externals changes
+
+ $ echo zzz > s/externals/other
+ $ hg ci --subrepos -m 'amend externals from hg'
+ committing subrepository s
+ abort: cannot commit svn externals
+ [255]
+ $ hg diff --subrepos -r 1:2 | grep -v diff
+ --- a/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
+ +++ b/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,2 +1,2 @@
+ -2 s
+ +3 s
+ 2 subdir/s
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,2 @@
+ a
+ +a
+ $ svn revert -q s/externals/other
+
+this commit fails because of externals meta changes
+
+ $ svn propset svn:mime-type 'text/html' s/externals/other
+ property 'svn:mime-type' set on 's/externals/other' (glob)
+ $ hg ci --subrepos -m 'amend externals from hg'
+ committing subrepository s
+ abort: cannot commit svn externals
+ [255]
+ $ svn revert -q s/externals/other
+
+clone
+
+ $ cd ..
+ $ hg clone t tc
+ updating to branch default
+ A tc/s/alpha (glob)
+ U tc/s (glob)
+
+ Fetching external item into 'tc/s/externals'* (glob)
+ A tc/s/externals/other (glob)
+ Checked out external at revision 1.
+
+ Checked out revision 3.
+ A tc/subdir/s/alpha (glob)
+ U tc/subdir/s (glob)
+
+ Fetching external item into 'tc/subdir/s/externals'* (glob)
+ A tc/subdir/s/externals/other (glob)
+ Checked out external at revision 1.
+
+ Checked out revision 2.
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd tc
+
+debugsub in clone
+
+ $ hg debugsub
+ path s
+ source file://*/svn-repo/src (glob)
+ revision 3
+ path subdir/s
+ source file://*/svn-repo/src (glob)
+ revision 2
+
+verify subrepo is contained within the repo directory
+
+ $ python -c "import os.path; print os.path.exists('s')"
+ True
+
+update to nullrev (must delete the subrepo)
+
+ $ hg up null
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ ls
+
+Check hg update --clean
+ $ cd "$TESTTMP/sub/t"
+ $ cd s
+ $ echo c0 > alpha
+ $ echo c1 > f1
+ $ echo c1 > f2
+ $ svn add f1 -q
+ $ svn status | sort
+
+ ? * a (glob)
+ ? * f2 (glob)
+ A * f1 (glob)
+ M * alpha (glob)
+ Performing status on external item at 'externals'* (glob)
+ X * externals (glob)
+ $ cd ../..
+ $ hg -R t update -C
+
+ Fetching external item into 't/s/externals'* (glob)
+ Checked out external at revision 1.
+
+ Checked out revision 3.
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd t/s
+ $ svn status | sort
+
+ ? * a (glob)
+ ? * f1 (glob)
+ ? * f2 (glob)
+ Performing status on external item at 'externals'* (glob)
+ X * externals (glob)
+
+Sticky subrepositories, no changes
+ $ cd "$TESTTMP/sub/t"
+ $ hg id -n
+ 2
+ $ cd s
+ $ svnversion
+ 3
+ $ cd ..
+ $ hg update 1
+ U *s/alpha (glob)
+
+ Fetching external item into '*s/externals'* (glob)
+ Checked out external at revision 1.
+
+ Checked out revision 2.
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1
+ $ cd s
+ $ svnversion
+ 2
+ $ cd ..
+
+Sticky subrepositorys, file changes
+ $ touch s/f1
+ $ cd s
+ $ svn add f1
+ A f1
+ $ cd ..
+ $ hg id -n
+ 1+
+ $ cd s
+ $ svnversion
+ 2M
+ $ cd ..
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (2) or (r)emote source (3)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 2+
+ $ cd s
+ $ svnversion
+ 2M
+ $ cd ..
+ $ hg update --clean tip
+ U *s/alpha (glob)
+
+ Fetching external item into '*s/externals'* (glob)
+ Checked out external at revision 1.
+
+ Checked out revision 3.
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Sticky subrepository, revision updates
+ $ hg id -n
+ 2
+ $ cd s
+ $ svnversion
+ 3
+ $ cd ..
+ $ cd s
+ $ svn update -qr 1
+ $ cd ..
+ $ hg update 1
+ subrepository sources for s differ (in checked out version)
+ use (l)ocal source (1) or (r)emote source (2)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1+
+ $ cd s
+ $ svnversion
+ 1
+ $ cd ..
+
+Sticky subrepository, file changes and revision updates
+ $ touch s/f1
+ $ cd s
+ $ svn add f1
+ A f1
+ $ svnversion
+ 1M
+ $ cd ..
+ $ hg id -n
+ 1+
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (1) or (r)emote source (3)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 2+
+ $ cd s
+ $ svnversion
+ 1M
+ $ cd ..
+
+Sticky repository, update --clean
+ $ hg update --clean tip | grep -v 's[/\]externals[/\]other'
+ U *s/alpha (glob)
+ U *s (glob)
+
+ Fetching external item into '*s/externals'* (glob)
+ Checked out external at revision 1.
+
+ Checked out revision 3.
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 2
+ $ cd s
+ $ svnversion
+ 3
+ $ cd ..
+
+Test subrepo already at intended revision:
+ $ cd s
+ $ svn update -qr 2
+ $ cd ..
+ $ hg update 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1+
+ $ cd s
+ $ svnversion
+ 2
+ $ cd ..
+
+Test case where subversion would fail to update the subrepo because there
+are unknown directories being replaced by tracked ones (happens with rebase).
+
+ $ cd "$WCROOT/src"
+ $ mkdir dir
+ $ echo epsilon.py > dir/epsilon.py
+ $ svn add dir
+ A dir
+ A dir/epsilon.py (glob)
+ $ svn ci -m 'Add dir/epsilon.py'
+ Adding *dir (glob)
+ Adding *dir/epsilon.py (glob)
+ Transmitting file data .
+ Committed revision 6.
+ $ cd ../..
+ $ hg init rebaserepo
+ $ cd rebaserepo
+ $ svn co -r5 --quiet "$SVNREPOURL"/src s
+ $ echo "s = [svn] $SVNREPOURL/src" >> .hgsub
+ $ hg add .hgsub
+ $ hg ci -m addsub
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ svn up -qr6 s
+ $ hg ci -m updatesub
+ created new head
+ $ echo pyc > s/dir/epsilon.pyc
+ $ hg up 1
+ D *s/dir (glob)
+
+ Fetching external item into '*s/externals'* (glob)
+ Checked out external at revision 1.
+
+ Checked out revision 5.
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg up -q 2
+
+Modify one of the externals to point to a different path so we can
+test having obstructions when switching branches on checkout:
+ $ hg checkout tip
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo "obstruct = [svn] $SVNREPOURL/externals" >> .hgsub
+ $ svn co -r5 --quiet "$SVNREPOURL"/externals obstruct
+ $ hg commit -m 'Start making obstructed working copy'
+ $ hg book other
+ $ hg co -r 'p1(tip)'
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo "obstruct = [svn] $SVNREPOURL/src" >> .hgsub
+ $ svn co -r5 --quiet "$SVNREPOURL"/src obstruct
+ $ hg commit -m 'Other branch which will be obstructed'
+ created new head
+
+Switching back to the head where we have another path mapped to the
+same subrepo should work if the subrepo is clean.
+ $ hg co other
+ A *obstruct/other (glob)
+ Checked out revision 1.
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+This is surprising, but is also correct based on the current code:
+ $ echo "updating should (maybe) fail" > obstruct/other
+ $ hg co tip
+ abort: crosses branches (merge branches or use --clean to discard changes)
+ [255]
+
+Point to a Subversion branch which has since been deleted and recreated
+First, create that condition in the repository.
+
+ $ hg ci --subrepos -m cleanup | grep -v Updating
+ committing subrepository obstruct
+ Sending obstruct/other (glob)
+ Transmitting file data .
+ Committed revision 7.
+ At revision 7.
+ $ svn mkdir -m "baseline" $SVNREPOURL/trunk
+
+ Committed revision 8.
+ $ svn copy -m "initial branch" $SVNREPOURL/trunk $SVNREPOURL/branch
+
+ Committed revision 9.
+ $ svn co --quiet "$SVNREPOURL"/branch tempwc
+ $ cd tempwc
+ $ echo "something old" > somethingold
+ $ svn add somethingold
+ A somethingold
+ $ svn ci -m 'Something old'
+ Adding somethingold
+ Transmitting file data .
+ Committed revision 10.
+ $ svn rm -m "remove branch" $SVNREPOURL/branch
+
+ Committed revision 11.
+ $ svn copy -m "recreate branch" $SVNREPOURL/trunk $SVNREPOURL/branch
+
+ Committed revision 12.
+ $ svn up -q
+ $ echo "something new" > somethingnew
+ $ svn add somethingnew
+ A somethingnew
+ $ svn ci -m 'Something new'
+ Adding somethingnew
+ Transmitting file data .
+ Committed revision 13.
+ $ cd ..
+ $ rm -rf tempwc
+ $ svn co "$SVNREPOURL/branch"@10 recreated
+ A recreated/somethingold (glob)
+ Checked out revision 10.
+ $ echo "recreated = [svn] $SVNREPOURL/branch" >> .hgsub
+ $ hg ci -m addsub
+ $ cd recreated
+ $ svn up -q
+ $ cd ..
+ $ hg ci -m updatesub
+ $ hg up -r-2
+ D *recreated/somethingnew (glob)
+ A *recreated/somethingold (glob)
+ Checked out revision 10.
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ test -f recreated/somethingold
+
+Test archive
+
+ $ hg archive -S ../archive-all --debug
+ archiving: 0/2 files (0.00%)
+ archiving: .hgsub 1/2 files (50.00%)
+ archiving: .hgsubstate 2/2 files (100.00%)
+ archiving (obstruct): 0/1 files (0.00%)
+ archiving (obstruct): 1/1 files (100.00%)
+ archiving (s): 0/2 files (0.00%)
+ archiving (s): 1/2 files (50.00%)
+ archiving (s): 2/2 files (100.00%)
+ archiving (recreated): 0/1 files (0.00%)
+ archiving (recreated): 1/1 files (100.00%)
+
+ $ hg archive -S ../archive-exclude --debug -X **old
+ archiving: 0/2 files (0.00%)
+ archiving: .hgsub 1/2 files (50.00%)
+ archiving: .hgsubstate 2/2 files (100.00%)
+ archiving (obstruct): 0/1 files (0.00%)
+ archiving (obstruct): 1/1 files (100.00%)
+ archiving (s): 0/2 files (0.00%)
+ archiving (s): 1/2 files (50.00%)
+ archiving (s): 2/2 files (100.00%)
+ archiving (recreated): 0 files
+ $ find ../archive-exclude | sort
+ ../archive-exclude
+ ../archive-exclude/.hg_archival.txt
+ ../archive-exclude/.hgsub
+ ../archive-exclude/.hgsubstate
+ ../archive-exclude/obstruct
+ ../archive-exclude/obstruct/other
+ ../archive-exclude/s
+ ../archive-exclude/s/alpha
+ ../archive-exclude/s/dir
+ ../archive-exclude/s/dir/epsilon.py
+
+Test forgetting files, not implemented in svn subrepo, used to
+traceback
+
+#if no-windows
+ $ hg forget 'notafile*'
+ notafile*: No such file or directory
+ [1]
+#else
+ $ hg forget 'notafile'
+ notafile: * (glob)
+ [1]
+#endif
+
+Test a subrepo referencing a just moved svn path. Last commit rev will
+be different from the revision, and the path will be different as
+well.
+
+ $ cd "$WCROOT"
+ $ svn up > /dev/null
+ $ mkdir trunk/subdir branches
+ $ echo a > trunk/subdir/a
+ $ svn add trunk/subdir branches
+ A trunk/subdir (glob)
+ A trunk/subdir/a (glob)
+ A branches
+ $ svn ci -m addsubdir
+ Adding branches
+ Adding trunk/subdir (glob)
+ Adding trunk/subdir/a (glob)
+ Transmitting file data .
+ Committed revision 14.
+ $ svn cp -m branchtrunk $SVNREPOURL/trunk $SVNREPOURL/branches/somebranch
+
+ Committed revision 15.
+ $ cd ..
+
+ $ hg init repo2
+ $ cd repo2
+ $ svn co $SVNREPOURL/branches/somebranch/subdir
+ A subdir/a (glob)
+ Checked out revision 15.
+ $ echo "subdir = [svn] $SVNREPOURL/branches/somebranch/subdir" > .hgsub
+ $ hg add .hgsub
+ $ hg ci -m addsub
+ $ hg up null
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg up
+ A *subdir/a (glob)
+ Checked out revision 15.
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
diff --git a/tests/test-subrepo.t b/tests/test-subrepo.t
new file mode 100644
index 0000000..bb58c2f
--- /dev/null
+++ b/tests/test-subrepo.t
@@ -0,0 +1,1023 @@
+Let commit recurse into subrepos by default to match pre-2.0 behavior:
+
+ $ echo "[ui]" >> $HGRCPATH
+ $ echo "commitsubrepos = Yes" >> $HGRCPATH
+
+ $ hg init t
+ $ cd t
+
+first revision, no sub
+
+ $ echo a > a
+ $ hg ci -Am0
+ adding a
+
+add first sub
+
+ $ echo s = s > .hgsub
+ $ hg add .hgsub
+ $ hg init s
+ $ echo a > s/a
+
+Issue2232: committing a subrepo without .hgsub
+
+ $ hg ci -mbad s
+ abort: can't commit subrepos without .hgsub
+ [255]
+
+ $ hg -R s ci -Ams0
+ adding a
+ $ hg sum
+ parent: 0:f7b1eb17ad24 tip
+ 0
+ branch: default
+ commit: 1 added, 1 subrepos
+ update: (current)
+ $ hg ci -m1
+
+Revert subrepo and test subrepo fileset keyword:
+
+ $ echo b > s/a
+ $ hg revert "set:subrepo('glob:s*')"
+ reverting subrepo s
+ reverting s/a (glob)
+ $ rm s/a.orig
+
+Revert subrepo with no backup. The "reverting s/a" line is gone since
+we're really running 'hg update' in the subrepo:
+
+ $ echo b > s/a
+ $ hg revert --no-backup s
+ reverting subrepo s
+
+Issue2022: update -C
+
+ $ echo b > s/a
+ $ hg sum
+ parent: 1:7cf8cfea66e4 tip
+ 1
+ branch: default
+ commit: 1 subrepos
+ update: (current)
+ $ hg co -C 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg sum
+ parent: 1:7cf8cfea66e4 tip
+ 1
+ branch: default
+ commit: (clean)
+ update: (current)
+
+commands that require a clean repo should respect subrepos
+
+ $ echo b >> s/a
+ $ hg backout tip
+ abort: uncommitted changes in subrepo s
+ [255]
+ $ hg revert -C -R s s/a
+
+add sub sub
+
+ $ echo ss = ss > s/.hgsub
+ $ hg init s/ss
+ $ echo a > s/ss/a
+ $ hg -R s add s/.hgsub
+ $ hg -R s/ss add s/ss/a
+ $ hg sum
+ parent: 1:7cf8cfea66e4 tip
+ 1
+ branch: default
+ commit: 1 subrepos
+ update: (current)
+ $ hg ci -m2
+ committing subrepository s
+ committing subrepository s/ss (glob)
+ $ hg sum
+ parent: 2:df30734270ae tip
+ 2
+ branch: default
+ commit: (clean)
+ update: (current)
+
+bump sub rev (and check it is ignored by ui.commitsubrepos)
+
+ $ echo b > s/a
+ $ hg -R s ci -ms1
+ $ hg --config ui.commitsubrepos=no ci -m3
+
+leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
+
+ $ echo c > s/a
+ $ hg --config ui.commitsubrepos=no ci -m4
+ abort: uncommitted changes in subrepo s
+ (use --subrepos for recursive commit)
+ [255]
+ $ hg id
+ f6affe3fbfaa+ tip
+ $ hg -R s ci -mc
+ $ hg id
+ f6affe3fbfaa+ tip
+ $ echo d > s/a
+ $ hg ci -m4
+ committing subrepository s
+ $ hg tip -R s
+ changeset: 4:02dcf1d70411
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 4
+
+
+check caching
+
+ $ hg co 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg debugsub
+
+restore
+
+ $ hg co
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg debugsub
+ path s
+ source s
+ revision 02dcf1d704118aee3ee306ccfa1910850d5b05ef
+
+new branch for merge tests
+
+ $ hg co 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo t = t >> .hgsub
+ $ hg init t
+ $ echo t > t/t
+ $ hg -R t add t
+ adding t/t (glob)
+
+5
+
+ $ hg ci -m5 # add sub
+ committing subrepository t
+ created new head
+ $ echo t2 > t/t
+
+6
+
+ $ hg st -R s
+ $ hg ci -m6 # change sub
+ committing subrepository t
+ $ hg debugsub
+ path s
+ source s
+ revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
+ path t
+ source t
+ revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
+ $ echo t3 > t/t
+
+7
+
+ $ hg ci -m7 # change sub again for conflict test
+ committing subrepository t
+ $ hg rm .hgsub
+
+8
+
+ $ hg ci -m8 # remove sub
+
+merge tests
+
+ $ hg co -C 3
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge 5 # test adding
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg debugsub
+ path s
+ source s
+ revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
+ path t
+ source t
+ revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
+ $ hg ci -m9
+ created new head
+ $ hg merge 6 --debug # test change
+ searching for copies back to rev 2
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
+ .hgsubstate: versions differ -> m
+ updating: .hgsubstate 1/1 files (100.00%)
+ subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
+ subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
+ getting subrepo t
+ resolving manifests
+ overwrite: True, partial: False
+ ancestor: 60ca1237c194+, local: 60ca1237c194+, remote: 6747d179aa9a
+ t: remote is newer -> g
+ updating: t 1/1 files (100.00%)
+ getting t
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg debugsub
+ path s
+ source s
+ revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
+ path t
+ source t
+ revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
+ $ echo conflict > t/t
+ $ hg ci -m10
+ committing subrepository t
+ $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
+ searching for copies back to rev 2
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
+ .hgsubstate: versions differ -> m
+ updating: .hgsubstate 1/1 files (100.00%)
+ subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
+ subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
+ merging subrepo t
+ searching for copies back to rev 2
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
+ t: versions differ -> m
+ preserving t for resolve of t
+ updating: t 1/1 files (100.00%)
+ picked tool 'internal:merge' for t (binary False symlink False)
+ merging t
+ my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
+ warning: conflicts during merge.
+ merging t incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+should conflict
+
+ $ cat t/t
+ <<<<<<< local
+ conflict
+ =======
+ t3
+ >>>>>>> other
+
+clone
+
+ $ cd ..
+ $ hg clone t tc
+ updating to branch default
+ cloning subrepo s from $TESTTMP/t/s (glob)
+ cloning subrepo s/ss from $TESTTMP/t/s/ss (glob)
+ cloning subrepo t from $TESTTMP/t/t (glob)
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd tc
+ $ hg debugsub
+ path s
+ source s
+ revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
+ path t
+ source t
+ revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
+
+push
+
+ $ echo bah > t/t
+ $ hg ci -m11
+ committing subrepository t
+ $ hg push
+ pushing to $TESTTMP/t (glob)
+ pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
+ searching for changes
+ no changes found
+ pushing subrepo s to $TESTTMP/t/s (glob)
+ searching for changes
+ no changes found
+ pushing subrepo t to $TESTTMP/t/t (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+push -f
+
+ $ echo bah > s/a
+ $ hg ci -m12
+ committing subrepository s
+ $ hg push
+ pushing to $TESTTMP/t (glob)
+ pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
+ searching for changes
+ no changes found
+ pushing subrepo s to $TESTTMP/t/s (glob)
+ searching for changes
+ abort: push creates new remote head 12a213df6fa9!
+ (did you forget to merge? use push -f to force)
+ [255]
+ $ hg push -f
+ pushing to $TESTTMP/t (glob)
+ pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
+ searching for changes
+ no changes found
+ pushing subrepo s to $TESTTMP/t/s (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ pushing subrepo t to $TESTTMP/t/t (glob)
+ searching for changes
+ no changes found
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+update
+
+ $ cd ../t
+ $ hg up -C # discard our earlier merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo blah > t/t
+ $ hg ci -m13
+ committing subrepository t
+
+pull
+
+ $ cd ../tc
+ $ hg pull
+ pulling from $TESTTMP/t (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+
+should pull t
+
+ $ hg up
+ pulling subrepo t from $TESTTMP/t/t (glob)
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat t/t
+ blah
+
+bogus subrepo path aborts
+
+ $ echo 'bogus=[boguspath' >> .hgsub
+ $ hg ci -m 'bogus subrepo path'
+ abort: missing ] in subrepo source
+ [255]
+
+Issue1986: merge aborts when trying to merge a subrepo that
+shouldn't need merging
+
+# subrepo layout
+#
+# o 5 br
+# /|
+# o | 4 default
+# | |
+# | o 3 br
+# |/|
+# o | 2 default
+# | |
+# | o 1 br
+# |/
+# o 0 default
+
+ $ cd ..
+ $ rm -rf sub
+ $ hg init main
+ $ cd main
+ $ hg init s
+ $ cd s
+ $ echo a > a
+ $ hg ci -Am1
+ adding a
+ $ hg branch br
+ marked working directory as branch br
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a >> a
+ $ hg ci -m1
+ $ hg up default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b > b
+ $ hg ci -Am1
+ adding b
+ $ hg up br
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m1
+ $ hg up 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo c > c
+ $ hg ci -Am1
+ adding c
+ $ hg up 3
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge 4
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m1
+
+# main repo layout:
+#
+# * <-- try to merge default into br again
+# .`|
+# . o 5 br --> substate = 5
+# . |
+# o | 4 default --> substate = 4
+# | |
+# | o 3 br --> substate = 2
+# |/|
+# o | 2 default --> substate = 2
+# | |
+# | o 1 br --> substate = 3
+# |/
+# o 0 default --> substate = 2
+
+ $ cd ..
+ $ echo 's = s' > .hgsub
+ $ hg -R s up 2
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg ci -Am1
+ adding .hgsub
+ $ hg branch br
+ marked working directory as branch br
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo b > b
+ $ hg -R s up 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg ci -Am1
+ adding b
+ $ hg up default
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo c > c
+ $ hg ci -Am1
+ adding c
+ $ hg up 1
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m1
+ $ hg up 2
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg -R s up 4
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo d > d
+ $ hg ci -Am1
+ adding d
+ $ hg up 3
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg -R s up 5
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo e > e
+ $ hg ci -Am1
+ adding e
+
+ $ hg up 5
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge 4 # try to merge default into br again
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ cd ..
+
+test subrepo delete from .hgsubstate
+
+ $ hg init testdelete
+ $ mkdir testdelete/nested testdelete/nested2
+ $ hg init testdelete/nested
+ $ hg init testdelete/nested2
+ $ echo test > testdelete/nested/foo
+ $ echo test > testdelete/nested2/foo
+ $ hg -R testdelete/nested add
+ adding testdelete/nested/foo (glob)
+ $ hg -R testdelete/nested2 add
+ adding testdelete/nested2/foo (glob)
+ $ hg -R testdelete/nested ci -m test
+ $ hg -R testdelete/nested2 ci -m test
+ $ echo nested = nested > testdelete/.hgsub
+ $ echo nested2 = nested2 >> testdelete/.hgsub
+ $ hg -R testdelete add
+ adding testdelete/.hgsub (glob)
+ $ hg -R testdelete ci -m "nested 1 & 2 added"
+ $ echo nested = nested > testdelete/.hgsub
+ $ hg -R testdelete ci -m "nested 2 deleted"
+ $ cat testdelete/.hgsubstate
+ bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
+ $ hg -R testdelete remove testdelete/.hgsub
+ $ hg -R testdelete ci -m ".hgsub deleted"
+ $ cat testdelete/.hgsubstate
+ bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
+
+test repository cloning
+
+ $ mkdir mercurial mercurial2
+ $ hg init nested_absolute
+ $ echo test > nested_absolute/foo
+ $ hg -R nested_absolute add
+ adding nested_absolute/foo (glob)
+ $ hg -R nested_absolute ci -mtest
+ $ cd mercurial
+ $ hg init nested_relative
+ $ echo test2 > nested_relative/foo2
+ $ hg -R nested_relative add
+ adding nested_relative/foo2 (glob)
+ $ hg -R nested_relative ci -mtest2
+ $ hg init main
+ $ echo "nested_relative = ../nested_relative" > main/.hgsub
+ $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
+ $ hg -R main add
+ adding main/.hgsub (glob)
+ $ hg -R main ci -m "add subrepos"
+ $ cd ..
+ $ hg clone mercurial/main mercurial2/main
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat mercurial2/main/nested_absolute/.hg/hgrc \
+ > mercurial2/main/nested_relative/.hg/hgrc
+ [paths]
+ default = $TESTTMP/mercurial/nested_absolute
+ [paths]
+ default = $TESTTMP/mercurial/nested_relative
+ $ rm -rf mercurial mercurial2
+
+Issue1977: multirepo push should fail if subrepo push fails
+
+ $ hg init repo
+ $ hg init repo/s
+ $ echo a > repo/s/a
+ $ hg -R repo/s ci -Am0
+ adding a
+ $ echo s = s > repo/.hgsub
+ $ hg -R repo ci -Am1
+ adding .hgsub
+ $ hg clone repo repo2
+ updating to branch default
+ cloning subrepo s from $TESTTMP/repo/s (glob)
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -q -R repo2 pull -u
+ $ echo 1 > repo2/s/a
+ $ hg -R repo2/s ci -m2
+ $ hg -q -R repo2/s push
+ $ hg -R repo2/s up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo 2 > repo2/s/a
+ $ hg -R repo2/s ci -m3
+ created new head
+ $ hg -R repo2 ci -m3
+ $ hg -q -R repo2 push
+ abort: push creates new remote head 9d66565e64e1!
+ (did you forget to merge? use push -f to force)
+ [255]
+ $ hg -R repo update
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm -rf repo2 repo
+
+
+Issue1852 subrepos with relative paths always push/pull relative to default
+
+Prepare a repo with subrepo
+
+ $ hg init issue1852a
+ $ cd issue1852a
+ $ hg init sub/repo
+ $ echo test > sub/repo/foo
+ $ hg -R sub/repo add sub/repo/foo
+ $ echo sub/repo = sub/repo > .hgsub
+ $ hg add .hgsub
+ $ hg ci -mtest
+ committing subrepository sub/repo (glob)
+ $ echo test >> sub/repo/foo
+ $ hg ci -mtest
+ committing subrepository sub/repo (glob)
+ $ cd ..
+
+Create repo without default path, pull top repo, and see what happens on update
+
+ $ hg init issue1852b
+ $ hg -R issue1852b pull issue1852a
+ pulling from issue1852a
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 3 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hg -R issue1852b update
+ abort: default path for subrepository sub/repo not found (glob)
+ [255]
+
+Pull -u now doesn't help
+
+ $ hg -R issue1852b pull -u issue1852a
+ pulling from issue1852a
+ searching for changes
+ no changes found
+
+Try the same, but with pull -u
+
+ $ hg init issue1852c
+ $ hg -R issue1852c pull -r0 -u issue1852a
+ pulling from issue1852a
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ cloning subrepo sub/repo from issue1852a/sub/repo (glob)
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Try to push from the other side
+
+ $ hg -R issue1852a push `pwd`/issue1852c
+ pushing to $TESTTMP/issue1852c
+ pushing subrepo sub/repo to $TESTTMP/issue1852c/sub/repo (glob)
+ searching for changes
+ no changes found
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+Incoming and outgoing should not use the default path:
+
+ $ hg clone -q issue1852a issue1852d
+ $ hg -R issue1852d outgoing --subrepos issue1852c
+ comparing with issue1852c
+ searching for changes
+ no changes found
+ comparing with issue1852c/sub/repo
+ searching for changes
+ no changes found
+ [1]
+ $ hg -R issue1852d incoming --subrepos issue1852c
+ comparing with issue1852c
+ searching for changes
+ no changes found
+ comparing with issue1852c/sub/repo
+ searching for changes
+ no changes found
+ [1]
+
+Check status of files when none of them belong to the first
+subrepository:
+
+ $ hg init subrepo-status
+ $ cd subrepo-status
+ $ hg init subrepo-1
+ $ hg init subrepo-2
+ $ cd subrepo-2
+ $ touch file
+ $ hg add file
+ $ cd ..
+ $ echo subrepo-1 = subrepo-1 > .hgsub
+ $ echo subrepo-2 = subrepo-2 >> .hgsub
+ $ hg add .hgsub
+ $ hg ci -m 'Added subrepos'
+ committing subrepository subrepo-2
+ $ hg st subrepo-2/file
+
+Check hg update --clean
+ $ cd $TESTTMP/t
+ $ rm -r t/t.orig
+ $ hg status -S --all
+ C .hgsub
+ C .hgsubstate
+ C a
+ C s/.hgsub
+ C s/.hgsubstate
+ C s/a
+ C s/ss/a
+ C t/t
+ $ echo c1 > s/a
+ $ cd s
+ $ echo c1 > b
+ $ echo c1 > c
+ $ hg add b
+ $ cd ..
+ $ hg status -S
+ M s/a
+ A s/b
+ ? s/c
+ $ hg update -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg status -S
+ ? s/b
+ ? s/c
+
+Sticky subrepositories, no changes
+ $ cd $TESTTMP/t
+ $ hg id
+ 925c17564ef8 tip
+ $ hg -R s id
+ 12a213df6fa9 tip
+ $ hg -R t id
+ 52c0adc0515a tip
+ $ hg update 11
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 365661e5936a
+ $ hg -R s id
+ fc627a69481f
+ $ hg -R t id
+ e95bcfa18a35
+
+Sticky subrepositorys, file changes
+ $ touch s/f1
+ $ touch t/f1
+ $ hg add -S s/f1
+ $ hg add -S t/f1
+ $ hg id
+ 365661e5936a+
+ $ hg -R s id
+ fc627a69481f+
+ $ hg -R t id
+ e95bcfa18a35+
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
+ l
+ subrepository sources for t differ
+ use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 925c17564ef8+ tip
+ $ hg -R s id
+ fc627a69481f+
+ $ hg -R t id
+ e95bcfa18a35+
+ $ hg update --clean tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Sticky subrepository, revision updates
+ $ hg id
+ 925c17564ef8 tip
+ $ hg -R s id
+ 12a213df6fa9 tip
+ $ hg -R t id
+ 52c0adc0515a tip
+ $ cd s
+ $ hg update -r -2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../t
+ $ hg update -r 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+ $ hg update 10
+ subrepository sources for t differ (in checked out version)
+ use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ e45c8b14af55+
+ $ hg -R s id
+ 02dcf1d70411
+ $ hg -R t id
+ 7af322bc1198
+
+Sticky subrepository, file changes and revision updates
+ $ touch s/f1
+ $ touch t/f1
+ $ hg add -S s/f1
+ $ hg add -S t/f1
+ $ hg id
+ e45c8b14af55+
+ $ hg -R s id
+ 02dcf1d70411+
+ $ hg -R t id
+ 7af322bc1198+
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)?
+ l
+ subrepository sources for t differ
+ use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 925c17564ef8+ tip
+ $ hg -R s id
+ 02dcf1d70411+
+ $ hg -R t id
+ 7af322bc1198+
+
+Sticky repository, update --clean
+ $ hg update --clean tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 925c17564ef8 tip
+ $ hg -R s id
+ 12a213df6fa9 tip
+ $ hg -R t id
+ 52c0adc0515a tip
+
+Test subrepo already at intended revision:
+ $ cd s
+ $ hg update fc627a69481f
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+ $ hg update 11
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 11+
+ $ hg -R s id
+ fc627a69481f
+ $ hg -R t id
+ e95bcfa18a35
+
+Test that removing .hgsubstate doesn't break anything:
+
+ $ hg rm -f .hgsubstate
+ $ hg ci -mrm
+ nothing changed
+ [1]
+ $ hg log -vr tip
+ changeset: 13:925c17564ef8
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: .hgsubstate
+ description:
+ 13
+
+
+
+Test that removing .hgsub removes .hgsubstate:
+
+ $ hg rm .hgsub
+ $ hg ci -mrm2
+ created new head
+ $ hg log -vr tip
+ changeset: 14:2400bccd50af
+ tag: tip
+ parent: 11:365661e5936a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: .hgsub .hgsubstate
+ description:
+ rm2
+
+
+Test issue3153: diff -S with deleted subrepos
+
+ $ hg diff --nodates -S -c .
+ diff -r 365661e5936a -r 2400bccd50af .hgsub
+ --- a/.hgsub
+ +++ /dev/null
+ @@ -1,2 +0,0 @@
+ -s = s
+ -t = t
+ diff -r 365661e5936a -r 2400bccd50af .hgsubstate
+ --- a/.hgsubstate
+ +++ /dev/null
+ @@ -1,2 +0,0 @@
+ -fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
+ -e95bcfa18a358dc4936da981ebf4147b4cad1362 t
+
+Test behavior of add for explicit path in subrepo:
+ $ cd ..
+ $ hg init explicit
+ $ cd explicit
+ $ echo s = s > .hgsub
+ $ hg add .hgsub
+ $ hg init s
+ $ hg ci -m0
+Adding with an explicit path in a subrepo adds the file
+ $ echo c1 > f1
+ $ echo c2 > s/f2
+ $ hg st -S
+ ? f1
+ ? s/f2
+ $ hg add s/f2
+ $ hg st -S
+ A s/f2
+ ? f1
+ $ hg ci -R s -m0
+ $ hg ci -Am1
+ adding f1
+Adding with an explicit path in a subrepo with -S has the same behavior
+ $ echo c3 > f3
+ $ echo c4 > s/f4
+ $ hg st -S
+ ? f3
+ ? s/f4
+ $ hg add -S s/f4
+ $ hg st -S
+ A s/f4
+ ? f3
+ $ hg ci -R s -m1
+ $ hg ci -Ama2
+ adding f3
+Adding without a path or pattern silently ignores subrepos
+ $ echo c5 > f5
+ $ echo c6 > s/f6
+ $ echo c7 > s/f7
+ $ hg st -S
+ ? f5
+ ? s/f6
+ ? s/f7
+ $ hg add
+ adding f5
+ $ hg st -S
+ A f5
+ ? s/f6
+ ? s/f7
+ $ hg ci -R s -Am2
+ adding f6
+ adding f7
+ $ hg ci -m3
+Adding without a path or pattern with -S also adds files in subrepos
+ $ echo c8 > f8
+ $ echo c9 > s/f9
+ $ echo c10 > s/f10
+ $ hg st -S
+ ? f8
+ ? s/f10
+ ? s/f9
+ $ hg add -S
+ adding f8
+ adding s/f10 (glob)
+ adding s/f9 (glob)
+ $ hg st -S
+ A f8
+ A s/f10
+ A s/f9
+ $ hg ci -R s -m3
+ $ hg ci -m4
+Adding with a pattern silently ignores subrepos
+ $ echo c11 > fm11
+ $ echo c12 > fn12
+ $ echo c13 > s/fm13
+ $ echo c14 > s/fn14
+ $ hg st -S
+ ? fm11
+ ? fn12
+ ? s/fm13
+ ? s/fn14
+ $ hg add 'glob:**fm*'
+ adding fm11
+ $ hg st -S
+ A fm11
+ ? fn12
+ ? s/fm13
+ ? s/fn14
+ $ hg ci -R s -Am4
+ adding fm13
+ adding fn14
+ $ hg ci -Am5
+ adding fn12
+Adding with a pattern with -S also adds matches in subrepos
+ $ echo c15 > fm15
+ $ echo c16 > fn16
+ $ echo c17 > s/fm17
+ $ echo c18 > s/fn18
+ $ hg st -S
+ ? fm15
+ ? fn16
+ ? s/fm17
+ ? s/fn18
+ $ hg add -S 'glob:**fm*'
+ adding fm15
+ adding s/fm17 (glob)
+ $ hg st -S
+ A fm15
+ A s/fm17
+ ? fn16
+ ? s/fn18
+ $ hg ci -R s -Am5
+ adding fn18
+ $ hg ci -Am6
+ adding fn16
+
+Test behavior of forget for explicit path in subrepo:
+Forgetting an explicit path in a subrepo untracks the file
+ $ echo c19 > s/f19
+ $ hg add s/f19
+ $ hg st -S
+ A s/f19
+ $ hg forget s/f19
+ $ hg st -S
+ ? s/f19
+ $ rm s/f19
+ $ cd ..
diff --git a/tests/test-symlink-os-yes-fs-no.py b/tests/test-symlink-os-yes-fs-no.py
new file mode 100644
index 0000000..e122d60
--- /dev/null
+++ b/tests/test-symlink-os-yes-fs-no.py
@@ -0,0 +1,45 @@
+import os, sys, time
+from mercurial import hg, ui, commands, util
+
+TESTDIR = os.environ["TESTDIR"]
+BUNDLEPATH = os.path.join(TESTDIR, 'bundles', 'test-no-symlinks.hg')
+
+# only makes sense to test on os which supports symlinks
+if not getattr(os, "symlink", False):
+ sys.exit(80) # SKIPPED_STATUS defined in run-tests.py
+
+u = ui.ui()
+# hide outer repo
+hg.peer(u, {}, '.', create=True)
+
+# clone with symlink support
+hg.clone(u, {}, BUNDLEPATH, 'test0')
+
+repo = hg.repository(u, 'test0')
+
+# wait a bit, or the status call wont update the dirstate
+time.sleep(1)
+commands.status(u, repo)
+
+# now disable symlink support -- this is what os.symlink would do on a
+# non-symlink file system
+def symlink_failure(src, dst):
+ raise OSError, (1, "Operation not permitted")
+os.symlink = symlink_failure
+
+# dereference links as if a Samba server has exported this to a
+# Windows client
+for f in 'test0/a.lnk', 'test0/d/b.lnk':
+ os.unlink(f)
+ fp = open(f, 'wb')
+ fp.write(util.readfile(f[:-4]))
+ fp.close()
+
+# reload repository
+u = ui.ui()
+repo = hg.repository(u, 'test0')
+commands.status(u, repo)
+
+# try cloning a repo which contains symlinks
+u = ui.ui()
+hg.clone(u, {}, BUNDLEPATH, 'test1')
diff --git a/tests/test-symlink-os-yes-fs-no.py.out b/tests/test-symlink-os-yes-fs-no.py.out
new file mode 100644
index 0000000..700d56c
--- /dev/null
+++ b/tests/test-symlink-os-yes-fs-no.py.out
@@ -0,0 +1,14 @@
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 4 changes to 4 files
+updating to branch default
+4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 4 changes to 4 files
+updating to branch default
+4 files updated, 0 files merged, 0 files removed, 0 files unresolved
diff --git a/tests/test-symlink-placeholder.t b/tests/test-symlink-placeholder.t
new file mode 100644
index 0000000..501b62b
--- /dev/null
+++ b/tests/test-symlink-placeholder.t
@@ -0,0 +1,72 @@
+ $ "$TESTDIR/hghave" symlink || exit 80
+
+Create extension that can disable symlink support:
+
+ $ cat > nolink.py <<EOF
+ > from mercurial import extensions, util
+ > def setflags(orig, f, l, x):
+ > pass
+ > def checklink(orig, path):
+ > return False
+ > def extsetup(ui):
+ > extensions.wrapfunction(util, 'setflags', setflags)
+ > extensions.wrapfunction(util, 'checklink', checklink)
+ > EOF
+
+ $ hg init unix-repo
+ $ cd unix-repo
+ $ echo foo > a
+ $ ln -s a b
+ $ hg ci -Am0
+ adding a
+ adding b
+ $ cd ..
+
+Simulate a checkout shared on NFS/Samba:
+
+ $ hg clone -q unix-repo shared
+ $ cd shared
+ $ rm b
+ $ echo foo > b
+ $ hg --config extensions.n=$TESTTMP/nolink.py status --debug
+ ignoring suspect symlink placeholder "b"
+
+Make a clone using placeholders:
+
+ $ hg --config extensions.n=$TESTTMP/nolink.py clone . ../win-repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../win-repo
+ $ cat b
+ a (no-eol)
+ $ hg --config extensions.n=$TESTTMP/nolink.py st --debug
+
+Write binary data to the placeholder:
+
+ >>> open('b', 'w').write('this is a binary\0')
+ $ hg --config extensions.n=$TESTTMP/nolink.py st --debug
+ ignoring suspect symlink placeholder "b"
+
+Write a long string to the placeholder:
+
+ >>> open('b', 'w').write('this' * 1000)
+ $ hg --config extensions.n=$TESTTMP/nolink.py st --debug
+ ignoring suspect symlink placeholder "b"
+
+Commit shouldn't succeed:
+
+ $ hg --config extensions.n=$TESTTMP/nolink.py ci -m1
+ nothing changed
+ [1]
+
+Write a valid string to the placeholder:
+
+ >>> open('b', 'w').write('this')
+ $ hg --config extensions.n=$TESTTMP/nolink.py st --debug
+ M b
+ $ hg --config extensions.n=$TESTTMP/nolink.py ci -m1
+ $ hg manifest tip --verbose
+ 644 a
+ 644 @ b
+
+ $ cd ..
diff --git a/tests/test-symlinks.t b/tests/test-symlinks.t
new file mode 100644
index 0000000..660ab91
--- /dev/null
+++ b/tests/test-symlinks.t
@@ -0,0 +1,256 @@
+ $ "$TESTDIR/hghave" symlink || exit 80
+
+== tests added in 0.7 ==
+
+ $ hg init test-symlinks-0.7; cd test-symlinks-0.7;
+ $ touch foo; ln -s foo bar;
+
+import with addremove -- symlink walking should _not_ screwup.
+
+ $ hg addremove
+ adding bar
+ adding foo
+
+commit -- the symlink should _not_ appear added to dir state
+
+ $ hg commit -m 'initial'
+
+ $ touch bomb
+
+again, symlink should _not_ show up on dir state
+
+ $ hg addremove
+ adding bomb
+
+Assert screamed here before, should go by without consequence
+
+ $ hg commit -m 'is there a bug?'
+ $ cd ..
+
+
+== fifo & ignore ==
+
+ $ hg init test; cd test;
+
+ $ mkdir dir
+ $ touch a.c dir/a.o dir/b.o
+
+test what happens if we want to trick hg
+
+ $ hg commit -A -m 0
+ adding a.c
+ adding dir/a.o
+ adding dir/b.o
+ $ echo "relglob:*.o" > .hgignore
+ $ rm a.c
+ $ rm dir/a.o
+ $ rm dir/b.o
+ $ mkdir dir/a.o
+ $ ln -s nonexist dir/b.o
+ $ mkfifo a.c
+
+it should show a.c, dir/a.o and dir/b.o deleted
+
+ $ hg status
+ M dir/b.o
+ ! a.c
+ ! dir/a.o
+ ? .hgignore
+ $ hg status a.c
+ a.c: unsupported file type (type is fifo)
+ ! a.c
+ $ cd ..
+
+
+== symlinks from outside the tree ==
+
+test absolute path through symlink outside repo
+
+ $ p=`pwd`
+ $ hg init x
+ $ ln -s x y
+ $ cd x
+ $ touch f
+ $ hg add f
+ $ hg status "$p"/y/f
+ A f
+
+try symlink outside repo to file inside
+
+ $ ln -s x/f ../z
+
+this should fail
+
+ $ hg status ../z && { echo hg mistakenly exited with status 0; exit 1; } || :
+ abort: ../z not under root
+ $ cd ..
+
+
+== cloning symlinks ==
+ $ hg init clone; cd clone;
+
+try cloning symlink in a subdir
+1. commit a symlink
+
+ $ mkdir -p a/b/c
+ $ cd a/b/c
+ $ ln -s /path/to/symlink/source demo
+ $ cd ../../..
+ $ hg stat
+ ? a/b/c/demo
+ $ hg commit -A -m 'add symlink in a/b/c subdir'
+ adding a/b/c/demo
+
+2. clone it
+
+ $ cd ..
+ $ hg clone clone clonedest
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+
+== symlink and git diffs ==
+
+git symlink diff
+
+ $ cd clonedest
+ $ hg diff --git -r null:tip
+ diff --git a/a/b/c/demo b/a/b/c/demo
+ new file mode 120000
+ --- /dev/null
+ +++ b/a/b/c/demo
+ @@ -0,0 +1,1 @@
+ +/path/to/symlink/source
+ \ No newline at end of file
+ $ hg export --git tip > ../sl.diff
+
+import git symlink diff
+
+ $ hg rm a/b/c/demo
+ $ hg commit -m'remove link'
+ $ hg import ../sl.diff
+ applying ../sl.diff
+ $ hg diff --git -r 1:tip
+ diff --git a/a/b/c/demo b/a/b/c/demo
+ new file mode 120000
+ --- /dev/null
+ +++ b/a/b/c/demo
+ @@ -0,0 +1,1 @@
+ +/path/to/symlink/source
+ \ No newline at end of file
+
+== symlinks and addremove ==
+
+directory moved and symlinked
+
+ $ mkdir foo
+ $ touch foo/a
+ $ hg ci -Ama
+ adding foo/a
+ $ mv foo bar
+ $ ln -s bar foo
+
+now addremove should remove old files
+
+ $ hg addremove
+ adding bar/a
+ adding foo
+ removing foo/a
+ $ cd ..
+
+== root of repository is symlinked ==
+
+ $ hg init root
+ $ ln -s root link
+ $ cd root
+ $ echo foo > foo
+ $ hg status
+ ? foo
+ $ hg status ../link
+ ? foo
+ $ hg add foo
+ $ hg cp foo "$TESTTMP/link/bar"
+ foo has not been committed yet, so no copy data will be stored for bar.
+ $ cd ..
+
+
+ $ hg init b
+ $ cd b
+ $ ln -s nothing dangling
+ $ hg commit -m 'commit symlink without adding' dangling
+ abort: dangling: file not tracked!
+ [255]
+ $ hg add dangling
+ $ hg commit -m 'add symlink'
+
+ $ hg tip -v
+ changeset: 0:cabd88b706fc
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: dangling
+ description:
+ add symlink
+
+
+ $ hg manifest --debug
+ 2564acbe54bbbedfbf608479340b359f04597f80 644 @ dangling
+ $ "$TESTDIR/readlink.py" dangling
+ dangling -> nothing
+
+ $ rm dangling
+ $ ln -s void dangling
+ $ hg commit -m 'change symlink'
+ $ "$TESTDIR/readlink.py" dangling
+ dangling -> void
+
+
+modifying link
+
+ $ rm dangling
+ $ ln -s empty dangling
+ $ "$TESTDIR/readlink.py" dangling
+ dangling -> empty
+
+
+reverting to rev 0:
+
+ $ hg revert -r 0 -a
+ reverting dangling
+ $ "$TESTDIR/readlink.py" dangling
+ dangling -> nothing
+
+
+backups:
+
+ $ "$TESTDIR/readlink.py" *.orig
+ dangling.orig -> empty
+ $ rm *.orig
+ $ hg up -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+copies
+
+ $ hg cp -v dangling dangling2
+ copying dangling to dangling2
+ $ hg st -Cmard
+ A dangling2
+ dangling
+ $ "$TESTDIR/readlink.py" dangling dangling2
+ dangling -> void
+ dangling2 -> void
+
+
+Issue995: hg copy -A incorrectly handles symbolic links
+
+ $ hg up -C
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mkdir dir
+ $ ln -s dir dirlink
+ $ hg ci -qAm 'add dirlink'
+ $ mkdir newdir
+ $ mv dir newdir/dir
+ $ mv dirlink newdir/dirlink
+ $ hg mv -A dirlink newdir/dirlink
+
+ $ cd ..
diff --git a/tests/test-tag.t b/tests/test-tag.t
new file mode 100644
index 0000000..3731802
--- /dev/null
+++ b/tests/test-tag.t
@@ -0,0 +1,319 @@
+ $ hg init test
+ $ cd test
+
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m "test"
+ $ hg history
+ changeset: 0:acb14030fe0a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: test
+
+
+ $ hg tag ' '
+ abort: tag names cannot consist entirely of whitespace
+ [255]
+
+ $ hg tag "bleah"
+ $ hg history
+ changeset: 1:d4f0d2909abc
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag bleah for changeset acb14030fe0a
+
+ changeset: 0:acb14030fe0a
+ tag: bleah
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: test
+
+
+ $ echo foo >> .hgtags
+ $ hg tag "bleah2"
+ abort: working copy of .hgtags is changed (please commit .hgtags manually)
+ [255]
+
+ $ hg revert .hgtags
+ $ hg tag -r 0 x y z y y z
+ abort: tag names must be unique
+ [255]
+ $ hg tag tap nada dot tip null .
+ abort: the name 'tip' is reserved
+ [255]
+ $ hg tag "bleah"
+ abort: tag 'bleah' already exists (use -f to force)
+ [255]
+ $ hg tag "blecch" "bleah"
+ abort: tag 'bleah' already exists (use -f to force)
+ [255]
+
+ $ hg tag --remove "blecch"
+ abort: tag 'blecch' does not exist
+ [255]
+ $ hg tag --remove "bleah" "blecch" "blough"
+ abort: tag 'blecch' does not exist
+ [255]
+
+ $ hg tag -r 0 "bleah0"
+ $ hg tag -l -r 1 "bleah1"
+ $ hg tag gack gawk gorp
+ $ hg tag -f gack
+ $ hg tag --remove gack gorp
+
+ $ hg tag "bleah "
+ abort: tag 'bleah' already exists (use -f to force)
+ [255]
+ $ hg tag " bleah"
+ abort: tag 'bleah' already exists (use -f to force)
+ [255]
+ $ hg tag " bleah"
+ abort: tag 'bleah' already exists (use -f to force)
+ [255]
+ $ hg tag -r 0 " bleahbleah "
+ $ hg tag -r 0 " bleah bleah "
+
+ $ cat .hgtags
+ acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
+ acb14030fe0a21b60322c440ad2d20cf7685a376 bleah0
+ 336fccc858a4eb69609a291105009e484a6b6b8d gack
+ 336fccc858a4eb69609a291105009e484a6b6b8d gawk
+ 336fccc858a4eb69609a291105009e484a6b6b8d gorp
+ 336fccc858a4eb69609a291105009e484a6b6b8d gack
+ 799667b6f2d9b957f73fa644a918c2df22bab58f gack
+ 799667b6f2d9b957f73fa644a918c2df22bab58f gack
+ 0000000000000000000000000000000000000000 gack
+ 336fccc858a4eb69609a291105009e484a6b6b8d gorp
+ 0000000000000000000000000000000000000000 gorp
+ acb14030fe0a21b60322c440ad2d20cf7685a376 bleahbleah
+ acb14030fe0a21b60322c440ad2d20cf7685a376 bleah bleah
+
+ $ cat .hg/localtags
+ d4f0d2909abc9290e2773c08837d70c1794e3f5a bleah1
+
+tagging on a non-head revision
+
+ $ hg update 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg tag -l localblah
+ $ hg tag "foobar"
+ abort: not at a branch head (use -f to force)
+ [255]
+ $ hg tag -f "foobar"
+ $ cat .hgtags
+ acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
+ $ cat .hg/localtags
+ d4f0d2909abc9290e2773c08837d70c1794e3f5a bleah1
+ acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
+
+ $ hg tag -l 'xx
+ > newline'
+ abort: '\n' cannot be used in a tag name
+ [255]
+ $ hg tag -l 'xx:xx'
+ abort: ':' cannot be used in a tag name
+ [255]
+
+cloning local tags
+
+ $ cd ..
+ $ hg -R test log -r0:5
+ changeset: 0:acb14030fe0a
+ tag: bleah
+ tag: bleah bleah
+ tag: bleah0
+ tag: bleahbleah
+ tag: foobar
+ tag: localblah
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: test
+
+ changeset: 1:d4f0d2909abc
+ tag: bleah1
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag bleah for changeset acb14030fe0a
+
+ changeset: 2:336fccc858a4
+ tag: gawk
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag bleah0 for changeset acb14030fe0a
+
+ changeset: 3:799667b6f2d9
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag gack, gawk, gorp for changeset 336fccc858a4
+
+ changeset: 4:154eeb7c0138
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag gack for changeset 799667b6f2d9
+
+ changeset: 5:b4bb47aaff09
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Removed tag gack, gorp
+
+ $ hg clone -q -rbleah1 test test1
+ $ hg -R test1 parents --style=compact
+ 1[tip] d4f0d2909abc 1970-01-01 00:00 +0000 test
+ Added tag bleah for changeset acb14030fe0a
+
+ $ hg clone -q -r5 test#bleah1 test2
+ $ hg -R test2 parents --style=compact
+ 5[tip] b4bb47aaff09 1970-01-01 00:00 +0000 test
+ Removed tag gack, gorp
+
+ $ hg clone -q -U test#bleah1 test3
+ $ hg -R test3 parents --style=compact
+
+ $ cd test
+
+Issue601: hg tag doesn't do the right thing if .hgtags or localtags
+doesn't end with EOL
+
+ $ python << EOF
+ > f = file('.hg/localtags'); last = f.readlines()[-1][:-1]; f.close()
+ > f = file('.hg/localtags', 'w'); f.write(last); f.close()
+ > EOF
+ $ cat .hg/localtags; echo
+ acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
+ $ hg tag -l localnewline
+ $ cat .hg/localtags; echo
+ acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
+ c2899151f4e76890c602a2597a650a72666681bf localnewline
+
+
+ $ python << EOF
+ > f = file('.hgtags'); last = f.readlines()[-1][:-1]; f.close()
+ > f = file('.hgtags', 'w'); f.write(last); f.close()
+ > EOF
+ $ hg ci -m'broken manual edit of .hgtags'
+ $ cat .hgtags; echo
+ acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
+ $ hg tag newline
+ $ cat .hgtags; echo
+ acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
+ a0eea09de1eeec777b46f2085260a373b2fbc293 newline
+
+
+tag and branch using same name
+
+ $ hg branch tag-and-branch-same-name
+ marked working directory as branch tag-and-branch-same-name
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m"discouraged"
+ $ hg tag tag-and-branch-same-name
+ warning: tag tag-and-branch-same-name conflicts with existing branch name
+
+test custom commit messages
+
+ $ cat > editor.sh << '__EOF__'
+ > echo "custom tag message" > "$1"
+ > echo "second line" >> "$1"
+ > __EOF__
+ $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e
+ $ hg log -l1 --template "{desc}\n"
+ custom tag message
+ second line
+
+
+local tag with .hgtags modified
+
+ $ hg tag hgtags-modified
+ $ hg rollback
+ repository tip rolled back to revision 13 (undo commit)
+ working directory now based on revision 13
+ $ hg st
+ M .hgtags
+ ? .hgtags.orig
+ ? editor.sh
+ $ hg tag --local baz
+ $ hg revert --no-backup .hgtags
+
+
+tagging when at named-branch-head that's not a topo-head
+
+ $ hg up default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge -t internal:local
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m 'merge named branch'
+ $ hg up 13
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg tag new-topo-head
+
+tagging on null rev
+
+ $ hg up null
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg tag nullrev
+ abort: not at a branch head (use -f to force)
+ [255]
+
+ $ hg init empty
+ $ hg tag -R empty nullrev
+ abort: null revision specified
+ [255]
+
+ $ hg tag -R empty -r 00000000000 -f nulltag
+ abort: null revision specified
+ [255]
+
+ $ cd ..
+
+tagging on an uncommitted merge (issue2542)
+
+ $ hg init repo-tag-uncommitted-merge
+ $ cd repo-tag-uncommitted-merge
+ $ echo c1 > f1
+ $ hg ci -Am0
+ adding f1
+ $ echo c2 > f2
+ $ hg ci -Am1
+ adding f2
+ $ hg co -q 0
+ $ hg branch b1
+ marked working directory as branch b1
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m2
+ $ hg up default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge b1
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ hg tag t1
+ abort: uncommitted merge
+ [255]
+ $ hg status
+ $ hg tag --rev 1 t2
+ abort: uncommitted merge
+ [255]
+ $ hg tag --rev 1 --local t3
+ $ hg tags -v
+ tip 2:2a156e8887cc
+ t3 1:c3adabd1a5f4 local
+
+ $ cd ..
+
+commit hook on tag used to be run without write lock - issue3344
+
+ $ hg init repo-tag
+ $ touch repo-tag/test
+ $ hg -R repo-tag commit -A -m "test"
+ adding test
+ $ hg init repo-tag-target
+ $ hg -R repo-tag --config hooks.commit="\"hg\" push \"`pwd`/repo-tag-target\"" tag tag
+ pushing to $TESTTMP/repo-tag-target
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+
diff --git a/tests/test-tags.t b/tests/test-tags.t
new file mode 100644
index 0000000..557c076
--- /dev/null
+++ b/tests/test-tags.t
@@ -0,0 +1,384 @@
+Helper functions:
+
+ $ cacheexists() {
+ > [ -f .hg/cache/tags ] && echo "tag cache exists" || echo "no tag cache"
+ > }
+
+ $ dumptags() {
+ > rev=$1
+ > echo "rev $rev: .hgtags:"
+ > hg cat -r$rev .hgtags
+ > }
+
+# XXX need to test that the tag cache works when we strip an old head
+# and add a new one rooted off non-tip: i.e. node and rev of tip are the
+# same, but stuff has changed behind tip.
+
+Setup:
+
+ $ hg init t
+ $ cd t
+ $ cacheexists
+ no tag cache
+ $ hg id
+ 000000000000 tip
+ $ cacheexists
+ no tag cache
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m "test"
+ $ hg co
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg identify
+ acb14030fe0a tip
+ $ cacheexists
+ tag cache exists
+
+Try corrupting the cache
+
+ $ printf 'a b' > .hg/cache/tags
+ $ hg identify
+ .hg/cache/tags is corrupt, rebuilding it
+ acb14030fe0a tip
+ $ cacheexists
+ tag cache exists
+ $ hg identify
+ acb14030fe0a tip
+
+Create local tag with long name:
+
+ $ T=`hg identify --debug --id`
+ $ hg tag -l "This is a local tag with a really long name!"
+ $ hg tags
+ tip 0:acb14030fe0a
+ This is a local tag with a really long name! 0:acb14030fe0a
+ $ rm .hg/localtags
+
+Create a tag behind hg's back:
+
+ $ echo "$T first" > .hgtags
+ $ cat .hgtags
+ acb14030fe0a21b60322c440ad2d20cf7685a376 first
+ $ hg add .hgtags
+ $ hg commit -m "add tags"
+ $ hg tags
+ tip 1:b9154636be93
+ first 0:acb14030fe0a
+ $ hg identify
+ b9154636be93 tip
+
+Repeat with cold tag cache:
+
+ $ rm -f .hg/cache/tags
+ $ hg identify
+ b9154636be93 tip
+
+And again, but now unable to write tag cache:
+
+#if unix-permissions
+ $ rm -f .hg/cache/tags
+ $ chmod 555 .hg
+ $ hg identify
+ b9154636be93 tip
+ $ chmod 755 .hg
+#endif
+
+Create a branch:
+
+ $ echo bb > a
+ $ hg status
+ M a
+ $ hg identify
+ b9154636be93+ tip
+ $ hg co first
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg id
+ acb14030fe0a+ first
+ $ hg -v id
+ acb14030fe0a+ first
+ $ hg status
+ M a
+ $ echo 1 > b
+ $ hg add b
+ $ hg commit -m "branch"
+ created new head
+ $ hg id
+ c8edf04160c7 tip
+
+Merge the two heads:
+
+ $ hg merge 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg id
+ c8edf04160c7+b9154636be93+ tip
+ $ hg status
+ M .hgtags
+ $ hg commit -m "merge"
+
+Create a fake head, make sure tag not visible afterwards:
+
+ $ cp .hgtags tags
+ $ hg tag last
+ $ hg rm .hgtags
+ $ hg commit -m "remove"
+
+ $ mv tags .hgtags
+ $ hg add .hgtags
+ $ hg commit -m "readd"
+ $
+ $ hg tags
+ tip 6:35ff301afafe
+ first 0:acb14030fe0a
+
+Add invalid tags:
+
+ $ echo "spam" >> .hgtags
+ $ echo >> .hgtags
+ $ echo "foo bar" >> .hgtags
+ $ echo "a5a5 invalid" >> .hg/localtags
+ $ cat .hgtags
+ acb14030fe0a21b60322c440ad2d20cf7685a376 first
+ spam
+
+ foo bar
+ $ hg commit -m "tags"
+
+Report tag parse error on other head:
+
+ $ hg up 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo 'x y' >> .hgtags
+ $ hg commit -m "head"
+ created new head
+
+ $ hg tags
+ .hgtags@75d9f02dfe28, line 2: cannot parse entry
+ .hgtags@75d9f02dfe28, line 4: node 'foo' is not well formed
+ .hgtags@c4be69a18c11, line 2: node 'x' is not well formed
+ tip 8:c4be69a18c11
+ first 0:acb14030fe0a
+ $ hg tip
+ changeset: 8:c4be69a18c11
+ tag: tip
+ parent: 3:ac5e980c4dc0
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: head
+
+
+Test tag precedence rules:
+
+ $ cd ..
+ $ hg init t2
+ $ cd t2
+ $ echo foo > foo
+ $ hg add foo
+ $ hg ci -m 'add foo' # rev 0
+ $ hg tag bar # rev 1
+ $ echo >> foo
+ $ hg ci -m 'change foo 1' # rev 2
+ $ hg up -C 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg tag -r 1 -f bar # rev 3
+ $ hg up -C 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo >> foo
+ $ hg ci -m 'change foo 2' # rev 4
+ created new head
+ $ hg tags
+ tip 4:0c192d7d5e6b
+ bar 1:78391a272241
+
+Repeat in case of cache effects:
+
+ $ hg tags
+ tip 4:0c192d7d5e6b
+ bar 1:78391a272241
+
+Detailed dump of tag info:
+
+ $ hg heads -q # expect 4, 3, 2
+ 4:0c192d7d5e6b
+ 3:6fa450212aeb
+ 2:7a94127795a3
+ $ dumptags 2
+ rev 2: .hgtags:
+ bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
+ $ dumptags 3
+ rev 3: .hgtags:
+ bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
+ bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
+ 78391a272241d70354aa14c874552cad6b51bb42 bar
+ $ dumptags 4
+ rev 4: .hgtags:
+ bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
+
+Dump cache:
+
+ $ cat .hg/cache/tags
+ 4 0c192d7d5e6b78a714de54a2e9627952a877e25a 0c04f2a8af31de17fab7422878ee5a2dadbc943d
+ 3 6fa450212aeb2a21ed616a54aea39a4a27894cd7 7d3b718c964ef37b89e550ebdafd5789e76ce1b0
+ 2 7a94127795a33c10a370c93f731fd9fea0b79af6 0c04f2a8af31de17fab7422878ee5a2dadbc943d
+
+ 78391a272241d70354aa14c874552cad6b51bb42 bar
+
+Test tag removal:
+
+ $ hg tag --remove bar # rev 5
+ $ hg tip -vp
+ changeset: 5:5f6e8655b1c7
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: .hgtags
+ description:
+ Removed tag bar
+
+
+ diff -r 0c192d7d5e6b -r 5f6e8655b1c7 .hgtags
+ --- a/.hgtags Thu Jan 01 00:00:00 1970 +0000
+ +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,3 @@
+ bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
+ +78391a272241d70354aa14c874552cad6b51bb42 bar
+ +0000000000000000000000000000000000000000 bar
+
+ $ hg tags
+ tip 5:5f6e8655b1c7
+ $ hg tags # again, try to expose cache bugs
+ tip 5:5f6e8655b1c7
+
+Remove nonexistent tag:
+
+ $ hg tag --remove foobar
+ abort: tag 'foobar' does not exist
+ [255]
+ $ hg tip
+ changeset: 5:5f6e8655b1c7
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Removed tag bar
+
+
+Undo a tag with rollback:
+
+ $ hg rollback # destroy rev 5 (restore bar)
+ repository tip rolled back to revision 4 (undo commit)
+ working directory now based on revision 4
+ $ hg tags
+ tip 4:0c192d7d5e6b
+ bar 1:78391a272241
+ $ hg tags
+ tip 4:0c192d7d5e6b
+ bar 1:78391a272241
+
+Test tag rank:
+
+ $ cd ..
+ $ hg init t3
+ $ cd t3
+ $ echo foo > foo
+ $ hg add foo
+ $ hg ci -m 'add foo' # rev 0
+ $ hg tag -f bar # rev 1 bar -> 0
+ $ hg tag -f bar # rev 2 bar -> 1
+ $ hg tag -fr 0 bar # rev 3 bar -> 0
+ $ hg tag -fr 1 bar # rev 4 bar -> 1
+ $ hg tag -fr 0 bar # rev 5 bar -> 0
+ $ hg tags
+ tip 5:85f05169d91d
+ bar 0:bbd179dfa0a7
+ $ hg co 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo barbar > foo
+ $ hg ci -m 'change foo' # rev 6
+ created new head
+ $ hg tags
+ tip 6:735c3ca72986
+ bar 0:bbd179dfa0a7
+
+Don't allow moving tag without -f:
+
+ $ hg tag -r 3 bar
+ abort: tag 'bar' already exists (use -f to force)
+ [255]
+ $ hg tags
+ tip 6:735c3ca72986
+ bar 0:bbd179dfa0a7
+
+Strip 1: expose an old head:
+
+ $ hg --config extensions.mq= strip 5
+ saved backup bundle to $TESTTMP/t3/.hg/strip-backup/*-backup.hg (glob)
+ $ hg tags # partly stale cache
+ tip 5:735c3ca72986
+ bar 1:78391a272241
+ $ hg tags # up-to-date cache
+ tip 5:735c3ca72986
+ bar 1:78391a272241
+
+Strip 2: destroy whole branch, no old head exposed
+
+ $ hg --config extensions.mq= strip 4
+ saved backup bundle to $TESTTMP/t3/.hg/strip-backup/*-backup.hg (glob)
+ $ hg tags # partly stale
+ tip 4:735c3ca72986
+ bar 0:bbd179dfa0a7
+ $ rm -f .hg/cache/tags
+ $ hg tags # cold cache
+ tip 4:735c3ca72986
+ bar 0:bbd179dfa0a7
+
+Test tag rank with 3 heads:
+
+ $ cd ..
+ $ hg init t4
+ $ cd t4
+ $ echo foo > foo
+ $ hg add
+ adding foo
+ $ hg ci -m 'add foo' # rev 0
+ $ hg tag bar # rev 1 bar -> 0
+ $ hg tag -f bar # rev 2 bar -> 1
+ $ hg up -qC 0
+ $ hg tag -fr 2 bar # rev 3 bar -> 2
+ $ hg tags
+ tip 3:197c21bbbf2c
+ bar 2:6fa450212aeb
+ $ hg up -qC 0
+ $ hg tag -m 'retag rev 0' -fr 0 bar # rev 4 bar -> 0, but bar stays at 2
+
+Bar should still point to rev 2:
+
+ $ hg tags
+ tip 4:3b4b14ed0202
+ bar 2:6fa450212aeb
+
+Test that removing global/local tags does not get confused when trying
+to remove a tag of type X which actually only exists as a type Y:
+
+ $ cd ..
+ $ hg init t5
+ $ cd t5
+ $ echo foo > foo
+ $ hg add
+ adding foo
+ $ hg ci -m 'add foo' # rev 0
+
+ $ hg tag -r 0 -l localtag
+ $ hg tag --remove localtag
+ abort: tag 'localtag' is not a global tag
+ [255]
+ $
+ $ hg tag -r 0 globaltag
+ $ hg tag --remove -l globaltag
+ abort: tag 'globaltag' is not a local tag
+ [255]
+ $ hg tags -v
+ tip 1:a0b6fe111088
+ localtag 0:bbd179dfa0a7 local
+ globaltag 0:bbd179dfa0a7
+
+ $ cd ..
diff --git a/tests/test-template-engine.t b/tests/test-template-engine.t
new file mode 100644
index 0000000..9dafebf
--- /dev/null
+++ b/tests/test-template-engine.t
@@ -0,0 +1,39 @@
+
+ $ cat > engine.py << EOF
+ >
+ > from mercurial import templater
+ >
+ > class mytemplater(object):
+ > def __init__(self, loader, filters, defaults):
+ > self.loader = loader
+ >
+ > def process(self, t, map):
+ > tmpl = self.loader(t)
+ > for k, v in map.iteritems():
+ > if k in ('templ', 'ctx', 'repo', 'revcache', 'cache'):
+ > continue
+ > if hasattr(v, '__call__'):
+ > v = v(**map)
+ > v = templater.stringify(v)
+ > tmpl = tmpl.replace('{{%s}}' % k, v)
+ > yield tmpl
+ >
+ > templater.engines['my'] = mytemplater
+ > EOF
+ $ hg init test
+ $ echo '[extensions]' > test/.hg/hgrc
+ $ echo "engine = `pwd`/engine.py" >> test/.hg/hgrc
+ $ cd test
+ $ cat > mymap << EOF
+ > changeset = my:changeset.txt
+ > EOF
+ $ cat > changeset.txt << EOF
+ > {{rev}} {{node}} {{author}}
+ > EOF
+ $ hg ci -Ama
+ adding changeset.txt
+ adding mymap
+ $ hg log --style=./mymap
+ 0 97e5f848f0936960273bbf75be6388cd0350a32b test
+
+ $ cd ..
diff --git a/tests/test-transplant.t b/tests/test-transplant.t
new file mode 100644
index 0000000..36a61f7
--- /dev/null
+++ b/tests/test-transplant.t
@@ -0,0 +1,634 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > transplant=
+ > EOF
+
+ $ hg init t
+ $ cd t
+ $ echo r1 > r1
+ $ hg ci -Amr1 -d'0 0'
+ adding r1
+ $ echo r2 > r2
+ $ hg ci -Amr2 -d'1 0'
+ adding r2
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+ $ echo b1 > b1
+ $ hg ci -Amb1 -d '0 0'
+ adding b1
+ created new head
+ $ echo b2 > b2
+ $ hg ci -Amb2 -d '1 0'
+ adding b2
+ $ echo b3 > b3
+ $ hg ci -Amb3 -d '2 0'
+ adding b3
+
+ $ hg log --template '{rev} {parents} {desc}\n'
+ 4 b3
+ 3 b2
+ 2 0:17ab29e464c6 b1
+ 1 r2
+ 0 r1
+
+ $ hg clone . ../rebase
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../rebase
+
+ $ hg up -C 1
+ 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
+
+rebase b onto r1
+
+ $ hg transplant -a -b tip
+ applying 37a1297eb21b
+ 37a1297eb21b transplanted to e234d668f844
+ applying 722f4667af76
+ 722f4667af76 transplanted to 539f377d78df
+ applying a53251cdf717
+ a53251cdf717 transplanted to ffd6818a3975
+ $ hg log --template '{rev} {parents} {desc}\n'
+ 7 b3
+ 6 b2
+ 5 1:d11e3596cc1a b1
+ 4 b3
+ 3 b2
+ 2 0:17ab29e464c6 b1
+ 1 r2
+ 0 r1
+
+test transplanted revset
+
+ $ hg log -r 'transplanted()' --template '{rev} {parents} {desc}\n'
+ 5 1:d11e3596cc1a b1
+ 6 b2
+ 7 b3
+ $ hg help revsets | grep transplanted
+ "transplanted([set])"
+ Transplanted changesets in set, or all transplanted changesets.
+
+test tranplanted keyword
+
+ $ hg log --template '{rev} {transplanted}\n'
+ 7 a53251cdf717679d1907b289f991534be05c997a
+ 6 722f4667af767100cb15b6a79324bf8abbfe1ef4
+ 5 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21
+ 4
+ 3
+ 2
+ 1
+ 0
+
+test destination() revset predicate with a transplant of a transplant; new
+clone so subsequent rollback isn't affected
+ $ hg clone -q . ../destination
+ $ cd ../destination
+ $ hg up -Cq 0
+ $ hg branch -q b4
+ $ hg ci -qm "b4"
+ $ hg transplant 7
+ applying ffd6818a3975
+ ffd6818a3975 transplanted to 502236fa76bb
+
+
+ $ hg log -r 'destination()'
+ changeset: 5:e234d668f844
+ parent: 1:d11e3596cc1a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b1
+
+ changeset: 6:539f377d78df
+ user: test
+ date: Thu Jan 01 00:00:01 1970 +0000
+ summary: b2
+
+ changeset: 7:ffd6818a3975
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: b3
+
+ changeset: 9:502236fa76bb
+ branch: b4
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: b3
+
+ $ hg log -r 'destination(a53251cdf717)'
+ changeset: 7:ffd6818a3975
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: b3
+
+ changeset: 9:502236fa76bb
+ branch: b4
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: b3
+
+
+test subset parameter in reverse order
+ $ hg log -r 'reverse(all()) and destination(a53251cdf717)'
+ changeset: 9:502236fa76bb
+ branch: b4
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: b3
+
+ changeset: 7:ffd6818a3975
+ user: test
+ date: Thu Jan 01 00:00:02 1970 +0000
+ summary: b3
+
+
+back to the original dir
+ $ cd ../rebase
+
+rollback the transplant
+ $ hg rollback
+ repository tip rolled back to revision 4 (undo transplant)
+ working directory now based on revision 1
+ $ hg tip -q
+ 4:a53251cdf717
+ $ hg parents -q
+ 1:d11e3596cc1a
+ $ hg status
+ ? b1
+ ? b2
+ ? b3
+
+ $ hg clone ../t ../prune
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../prune
+
+ $ hg up -C 1
+ 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
+
+rebase b onto r1, skipping b2
+
+ $ hg transplant -a -b tip -p 3
+ applying 37a1297eb21b
+ 37a1297eb21b transplanted to e234d668f844
+ applying a53251cdf717
+ a53251cdf717 transplanted to 7275fda4d04f
+ $ hg log --template '{rev} {parents} {desc}\n'
+ 6 b3
+ 5 1:d11e3596cc1a b1
+ 4 b3
+ 3 b2
+ 2 0:17ab29e464c6 b1
+ 1 r2
+ 0 r1
+
+test same-parent transplant with --log
+
+ $ hg clone -r 1 ../t ../sameparent
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../sameparent
+ $ hg transplant --log -s ../prune 5
+ searching for changes
+ applying e234d668f844
+ e234d668f844 transplanted to e07aea8ecf9c
+ $ hg log --template '{rev} {parents} {desc}\n'
+ 2 b1
+ (transplanted from e234d668f844e1b1a765f01db83a32c0c7bfa170)
+ 1 r2
+ 0 r1
+remote transplant
+
+ $ hg clone -r 1 ../t ../remote
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../remote
+ $ hg transplant --log -s ../t 2 4
+ searching for changes
+ applying 37a1297eb21b
+ 37a1297eb21b transplanted to c19cf0ccb069
+ applying a53251cdf717
+ a53251cdf717 transplanted to f7fe5bf98525
+ $ hg log --template '{rev} {parents} {desc}\n'
+ 3 b3
+ (transplanted from a53251cdf717679d1907b289f991534be05c997a)
+ 2 b1
+ (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
+ 1 r2
+ 0 r1
+
+skip previous transplants
+
+ $ hg transplant -s ../t -a -b 4
+ searching for changes
+ applying 722f4667af76
+ 722f4667af76 transplanted to 47156cd86c0b
+ $ hg log --template '{rev} {parents} {desc}\n'
+ 4 b2
+ 3 b3
+ (transplanted from a53251cdf717679d1907b289f991534be05c997a)
+ 2 b1
+ (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
+ 1 r2
+ 0 r1
+
+skip local changes transplanted to the source
+
+ $ echo b4 > b4
+ $ hg ci -Amb4 -d '3 0'
+ adding b4
+ $ hg clone ../t ../pullback
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../pullback
+ $ hg transplant -s ../remote -a -b tip
+ searching for changes
+ applying 4333daefcb15
+ 4333daefcb15 transplanted to 5f42c04e07cc
+
+
+remote transplant with pull
+
+ $ hg -R ../t serve -p $HGPORT -d --pid-file=../t.pid
+ $ cat ../t.pid >> $DAEMON_PIDS
+
+ $ hg clone -r 0 ../t ../rp
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../rp
+ $ hg transplant -s http://localhost:$HGPORT/ 2 4
+ searching for changes
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ applying a53251cdf717
+ a53251cdf717 transplanted to 8d9279348abb
+ $ hg log --template '{rev} {parents} {desc}\n'
+ 2 b3
+ 1 b1
+ 0 r1
+
+transplant --continue
+
+ $ hg init ../tc
+ $ cd ../tc
+ $ cat <<EOF > foo
+ > foo
+ > bar
+ > baz
+ > EOF
+ $ echo toremove > toremove
+ $ echo baz > baz
+ $ hg ci -Amfoo
+ adding baz
+ adding foo
+ adding toremove
+ $ cat <<EOF > foo
+ > foo2
+ > bar2
+ > baz2
+ > EOF
+ $ rm toremove
+ $ echo added > added
+ $ hg ci -Amfoo2
+ adding added
+ removing toremove
+ $ echo bar > bar
+ $ cat > baz <<EOF
+ > before baz
+ > baz
+ > after baz
+ > EOF
+ $ hg ci -Ambar
+ adding bar
+ $ echo bar2 >> bar
+ $ hg ci -mbar2
+ $ hg up 0
+ 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo foobar > foo
+ $ hg ci -mfoobar
+ created new head
+ $ hg transplant 1:3
+ applying 46ae92138f3c
+ patching file foo
+ Hunk #1 FAILED at 0
+ 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
+ patch failed to apply
+ abort: fix up the merge and run hg transplant --continue
+ [255]
+
+transplant -c shouldn't use an old changeset
+
+ $ hg up -C
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ rm added
+ $ hg transplant 1
+ applying 46ae92138f3c
+ patching file foo
+ Hunk #1 FAILED at 0
+ 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
+ patch failed to apply
+ abort: fix up the merge and run hg transplant --continue
+ [255]
+ $ hg transplant --continue
+ 46ae92138f3c transplanted as 9159dada197d
+ $ hg transplant 1:3
+ skipping already applied revision 1:46ae92138f3c
+ applying 9d6d6b5a8275
+ 9d6d6b5a8275 transplanted to 2d17a10c922f
+ applying 1dab759070cf
+ 1dab759070cf transplanted to e06a69927eb0
+ $ hg locate
+ added
+ bar
+ baz
+ foo
+
+test multiple revisions and --continue
+
+ $ hg up -qC 0
+ $ echo bazbaz > baz
+ $ hg ci -Am anotherbaz baz
+ created new head
+ $ hg transplant 1:3
+ applying 46ae92138f3c
+ 46ae92138f3c transplanted to 1024233ea0ba
+ applying 9d6d6b5a8275
+ patching file baz
+ Hunk #1 FAILED at 0
+ 1 out of 1 hunks FAILED -- saving rejects to file baz.rej
+ patch failed to apply
+ abort: fix up the merge and run hg transplant --continue
+ [255]
+ $ echo fixed > baz
+ $ hg transplant --continue
+ 9d6d6b5a8275 transplanted as d80c49962290
+ applying 1dab759070cf
+ 1dab759070cf transplanted to aa0ffe6bd5ae
+
+ $ cd ..
+
+Issue1111: Test transplant --merge
+
+ $ hg init t1111
+ $ cd t1111
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ echo b >> a
+ $ hg ci -m appendb
+ $ echo c >> a
+ $ hg ci -m appendc
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo d >> a
+ $ hg ci -m appendd
+ created new head
+
+tranplant
+
+ $ hg transplant -m 1
+ applying 42dc4432fd35
+ 1:42dc4432fd35 merged at a9f4acbac129
+ $ cd ..
+
+test transplant into empty repository
+
+ $ hg init empty
+ $ cd empty
+ $ hg transplant -s ../t -b tip -a
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 4 files
+ $ cd ..
+
+
+#if unix-permissions system-sh
+
+test filter
+
+ $ hg init filter
+ $ cd filter
+ $ cat <<'EOF' >test-filter
+ > #!/bin/sh
+ > sed 's/r1/r2/' $1 > $1.new
+ > mv $1.new $1
+ > EOF
+ $ chmod +x test-filter
+ $ hg transplant -s ../t -b tip -a --filter ./test-filter
+ filtering * (glob)
+ applying 17ab29e464c6
+ 17ab29e464c6 transplanted to e9ffc54ea104
+ filtering * (glob)
+ applying 37a1297eb21b
+ 37a1297eb21b transplanted to 348b36d0b6a5
+ filtering * (glob)
+ applying 722f4667af76
+ 722f4667af76 transplanted to 0aa6979afb95
+ filtering * (glob)
+ applying a53251cdf717
+ a53251cdf717 transplanted to 14f8512272b5
+ $ hg log --template '{rev} {parents} {desc}\n'
+ 3 b3
+ 2 b2
+ 1 b1
+ 0 r2
+ $ cd ..
+
+
+test filter with failed patch
+
+ $ cd filter
+ $ hg up 0
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ echo foo > b1
+ $ hg ci -Am foo
+ adding b1
+ adding test-filter
+ created new head
+ $ hg transplant 1 --filter ./test-filter
+ filtering * (glob)
+ applying 348b36d0b6a5
+ file b1 already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file b1.rej
+ patch failed to apply
+ abort: fix up the merge and run hg transplant --continue
+ [255]
+ $ cd ..
+
+test environment passed to filter
+
+ $ hg init filter-environment
+ $ cd filter-environment
+ $ cat <<'EOF' >test-filter-environment
+ > #!/bin/sh
+ > echo "Transplant by $HGUSER" >> $1
+ > echo "Transplant from rev $HGREVISION" >> $1
+ > EOF
+ $ chmod +x test-filter-environment
+ $ hg transplant -s ../t --filter ./test-filter-environment 0
+ filtering * (glob)
+ applying 17ab29e464c6
+ 17ab29e464c6 transplanted to 5190e68026a0
+
+ $ hg log --template '{rev} {parents} {desc}\n'
+ 0 r1
+ Transplant by test
+ Transplant from rev 17ab29e464c6ca53e329470efe2a9918ac617a6f
+ $ cd ..
+
+test transplant with filter handles invalid changelog
+
+ $ hg init filter-invalid-log
+ $ cd filter-invalid-log
+ $ cat <<'EOF' >test-filter-invalid-log
+ > #!/bin/sh
+ > echo "" > $1
+ > EOF
+ $ chmod +x test-filter-invalid-log
+ $ hg transplant -s ../t --filter ./test-filter-invalid-log 0
+ filtering * (glob)
+ abort: filter corrupted changeset (no user or date)
+ [255]
+ $ cd ..
+
+#endif
+
+
+test with a win32ext like setup (differing EOLs)
+
+ $ hg init twin1
+ $ cd twin1
+ $ echo a > a
+ $ echo b > b
+ $ echo b >> b
+ $ hg ci -Am t
+ adding a
+ adding b
+ $ echo a > b
+ $ echo b >> b
+ $ hg ci -m changeb
+ $ cd ..
+
+ $ hg init twin2
+ $ cd twin2
+ $ echo '[patch]' >> .hg/hgrc
+ $ echo 'eol = crlf' >> .hg/hgrc
+ $ python -c "file('b', 'wb').write('b\r\nb\r\n')"
+ $ hg ci -Am addb
+ adding b
+ $ hg transplant -s ../twin1 tip
+ searching for changes
+ warning: repository is unrelated
+ applying 2e849d776c17
+ 2e849d776c17 transplanted to 8e65bebc063e
+ $ cat b
+ a\r (esc)
+ b\r (esc)
+ $ cd ..
+
+test transplant with merge changeset is skipped
+
+ $ hg init merge1a
+ $ cd merge1a
+ $ echo a > a
+ $ hg ci -Am a
+ adding a
+ $ hg branch b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m branchb
+ $ echo b > b
+ $ hg ci -Am b
+ adding b
+ $ hg update default
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m mergeb
+ $ cd ..
+
+ $ hg init merge1b
+ $ cd merge1b
+ $ hg transplant -s ../merge1a tip
+ $ cd ..
+
+test transplant with merge changeset accepts --parent
+
+ $ hg init merge2a
+ $ cd merge2a
+ $ echo a > a
+ $ hg ci -Am a
+ adding a
+ $ hg branch b
+ marked working directory as branch b
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -m branchb
+ $ echo b > b
+ $ hg ci -Am b
+ adding b
+ $ hg update default
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg merge b
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m mergeb
+ $ cd ..
+
+ $ hg init merge2b
+ $ cd merge2b
+ $ hg transplant -s ../merge2a --parent 0 tip
+ applying be9f9b39483f
+ be9f9b39483f transplanted to 9959e51f94d1
+ $ cd ..
+
+test transplanting a patch turning into a no-op
+
+ $ hg init binarysource
+ $ cd binarysource
+ $ echo a > a
+ $ hg ci -Am adda a
+ >>> file('b', 'wb').write('\0b1')
+ $ hg ci -Am addb b
+ >>> file('b', 'wb').write('\0b2')
+ $ hg ci -m changeb b
+ $ cd ..
+
+ $ hg clone -r0 binarysource binarydest
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd binarydest
+ $ cp ../binarysource/b b
+ $ hg ci -Am addb2 b
+ $ hg transplant -s ../binarysource 2
+ searching for changes
+ applying 7a7d57e15850
+ skipping emptied changeset 7a7d57e15850
+ $ cd ..
+
diff --git a/tests/test-treediscovery-legacy.t b/tests/test-treediscovery-legacy.t
new file mode 100644
index 0000000..bc3563c
--- /dev/null
+++ b/tests/test-treediscovery-legacy.t
@@ -0,0 +1,371 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+Tests discovery against servers without getbundle support:
+
+ $ cat >> $HGRCPATH <<EOF
+ > [ui]
+ > logtemplate="{rev} {node|short}: {desc} {branches}\n"
+ > [extensions]
+ > graphlog=
+ > EOF
+ $ cp $HGRCPATH $HGRCPATH-withcap
+
+ $ CAP="getbundle known changegroupsubset"
+ $ . "$TESTDIR/notcapable"
+ $ cp $HGRCPATH $HGRCPATH-nocap
+ $ cp $HGRCPATH-withcap $HGRCPATH
+
+Prep for test server without branchmap support
+
+ $ CAP="branchmap"
+ $ . "$TESTDIR/notcapable"
+ $ cp $HGRCPATH $HGRCPATH-nocap-branchmap
+ $ cp $HGRCPATH-withcap $HGRCPATH
+
+Setup HTTP server control:
+
+ $ remote=http://localhost:$HGPORT/
+ $ export remote
+ $ tstart() {
+ > echo '[web]' > $1/.hg/hgrc
+ > echo 'push_ssl = false' >> $1/.hg/hgrc
+ > echo 'allow_push = *' >> $1/.hg/hgrc
+ > cp $HGRCPATH-nocap $HGRCPATH
+ > hg serve -R $1 -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ > cat hg.pid >> $DAEMON_PIDS
+ > }
+ $ tstop() {
+ > "$TESTDIR/killdaemons.py"
+ > cp $HGRCPATH-withcap $HGRCPATH
+ > }
+
+Both are empty:
+
+ $ hg init empty1
+ $ hg init empty2
+ $ tstart empty2
+ $ hg incoming -R empty1 $remote
+ comparing with http://localhost:$HGPORT/
+ no changes found
+ [1]
+ $ hg outgoing -R empty1 $remote
+ comparing with http://localhost:$HGPORT/
+ no changes found
+ [1]
+ $ hg pull -R empty1 $remote
+ pulling from http://localhost:$HGPORT/
+ no changes found
+ $ hg push -R empty1 $remote
+ pushing to http://localhost:$HGPORT/
+ no changes found
+ [1]
+ $ tstop
+
+Base repo:
+
+ $ hg init main
+ $ cd main
+ $ hg debugbuilddag -mo '+2:tbase @name1 +3:thead1 <tbase @name2 +4:thead2 @both /thead1 +2:tmaintip'
+ $ hg glog
+ o 11 a19bfa7e7328: r11 both
+ |
+ o 10 8b6bad1512e1: r10 both
+ |
+ o 9 025829e08038: r9 both
+ |\
+ | o 8 d8f638ac69e9: r8 name2
+ | |
+ | o 7 b6b4d315a2ac: r7 name2
+ | |
+ | o 6 6c6f5d5f3c11: r6 name2
+ | |
+ | o 5 70314b29987d: r5 name2
+ | |
+ o | 4 e71dbbc70e03: r4 name1
+ | |
+ o | 3 2c8d5d5ec612: r3 name1
+ | |
+ o | 2 a7892891da29: r2 name1
+ |/
+ o 1 0019a3b924fd: r1
+ |
+ o 0 d57206cc072a: r0
+
+ $ cd ..
+ $ tstart main
+
+Full clone:
+
+ $ hg clone main full
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd full
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ hg push $remote
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+Local is empty:
+
+ $ cd empty1
+ $ hg incoming $remote --rev name1
+ comparing with http://localhost:$HGPORT/
+ abort: cannot look up remote changes; remote repository does not support the 'changegroupsubset' capability!
+ [255]
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ 0 d57206cc072a: r0
+ 1 0019a3b924fd: r1
+ 2 a7892891da29: r2 name1
+ 3 2c8d5d5ec612: r3 name1
+ 4 e71dbbc70e03: r4 name1
+ 5 70314b29987d: r5 name2
+ 6 6c6f5d5f3c11: r6 name2
+ 7 b6b4d315a2ac: r7 name2
+ 8 d8f638ac69e9: r8 name2
+ 9 025829e08038: r9 both
+ 10 8b6bad1512e1: r10 both
+ 11 a19bfa7e7328: r11 both
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ no changes found
+ [1]
+ $ hg push $remote
+ pushing to http://localhost:$HGPORT/
+ no changes found
+ [1]
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 12 changesets with 24 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+Local is subset:
+
+ $ cp $HGRCPATH-withcap $HGRCPATH
+ $ hg clone main subset --rev name2 ; cd subset
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 12 changes to 2 files
+ updating to branch name2
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cp $HGRCPATH-nocap $HGRCPATH
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 6 a7892891da29: r2 name1
+ 7 2c8d5d5ec612: r3 name1
+ 8 e71dbbc70e03: r4 name1
+ 9 025829e08038: r9 both
+ 10 8b6bad1512e1: r10 both
+ 11 a19bfa7e7328: r11 both
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg push $remote
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 12 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+Remote is empty:
+
+ $ tstop ; tstart empty2
+ $ cd main
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 0 d57206cc072a: r0
+ 1 0019a3b924fd: r1
+ 2 a7892891da29: r2 name1
+ 3 2c8d5d5ec612: r3 name1
+ 4 e71dbbc70e03: r4 name1
+ 5 70314b29987d: r5 name2
+ 6 6c6f5d5f3c11: r6 name2
+ 7 b6b4d315a2ac: r7 name2
+ 8 d8f638ac69e9: r8 name2
+ 9 025829e08038: r9 both
+ 10 8b6bad1512e1: r10 both
+ 11 a19bfa7e7328: r11 both
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ hg push $remote
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 12 changesets with 24 changes to 2 files
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+Local is superset:
+
+ $ tstop
+ $ hg clone main subset2 --rev name2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 12 changes to 2 files
+ updating to branch name2
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ tstart subset2
+ $ cd main
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 2 a7892891da29: r2 name1
+ 3 2c8d5d5ec612: r3 name1
+ 4 e71dbbc70e03: r4 name1
+ 9 025829e08038: r9 both
+ 10 8b6bad1512e1: r10 both
+ 11 a19bfa7e7328: r11 both
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ hg push $remote
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: push creates new remote branches: both, name1!
+ (use 'hg push --new-branch' to create new remote branches)
+ [255]
+ $ hg push $remote --new-branch
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 6 changesets with 12 changes to 2 files
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+Partial pull:
+
+ $ tstop ; tstart main
+ $ hg clone $remote partial --rev name2
+ abort: partial pull cannot be done because other repository doesn't support changegroupsubset.
+ [255]
+ $ hg init partial; cd partial
+ $ hg incoming $remote --rev name2
+ comparing with http://localhost:$HGPORT/
+ abort: cannot look up remote changes; remote repository does not support the 'changegroupsubset' capability!
+ [255]
+ $ hg pull $remote --rev name2
+ pulling from http://localhost:$HGPORT/
+ abort: partial pull cannot be done because other repository doesn't support changegroupsubset.
+ [255]
+ $ cd ..
+
+ $ tstop
+
+Exercise pushing to server without branchmap capability
+
+ $ cp $HGRCPATH-nocap-branchmap $HGRCPATH-nocap
+ $ hg init rlocal
+ $ cd rlocal
+ $ echo A > A
+ $ hg ci -Am A
+ adding A
+ $ cd ..
+ $ hg clone rlocal rremote
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd rlocal
+ $ echo B > B
+ $ hg ci -Am B
+ adding B
+ $ cd ..
+ $ tstart rremote
+
+ $ cd rlocal
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 1 27547f69f254: B
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ hg push $remote
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+ $ tstop
diff --git a/tests/test-treediscovery.t b/tests/test-treediscovery.t
new file mode 100644
index 0000000..1f59d0b
--- /dev/null
+++ b/tests/test-treediscovery.t
@@ -0,0 +1,504 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+Tests discovery against servers without getbundle support:
+
+ $ CAP=getbundle
+ $ . "$TESTDIR/notcapable"
+ $ cat >> $HGRCPATH <<EOF
+ > [ui]
+ > logtemplate="{rev} {node|short}: {desc} {branches}\n"
+ > [extensions]
+ > graphlog=
+ > EOF
+
+Setup HTTP server control:
+
+ $ remote=http://localhost:$HGPORT/
+ $ export remote
+ $ tstart() {
+ > echo '[web]' > $1/.hg/hgrc
+ > echo 'push_ssl = false' >> $1/.hg/hgrc
+ > echo 'allow_push = *' >> $1/.hg/hgrc
+ > hg serve -R $1 -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ > cat hg.pid >> $DAEMON_PIDS
+ > }
+ $ tstop() {
+ > "$TESTDIR/killdaemons.py"
+ > }
+
+Both are empty:
+
+ $ hg init empty1
+ $ hg init empty2
+ $ tstart empty2
+ $ hg incoming -R empty1 $remote
+ comparing with http://localhost:$HGPORT/
+ no changes found
+ [1]
+ $ hg outgoing -R empty1 $remote
+ comparing with http://localhost:$HGPORT/
+ no changes found
+ [1]
+ $ hg pull -R empty1 $remote
+ pulling from http://localhost:$HGPORT/
+ no changes found
+ $ hg push -R empty1 $remote
+ pushing to http://localhost:$HGPORT/
+ no changes found
+ [1]
+ $ tstop
+
+Base repo:
+
+ $ hg init main
+ $ cd main
+ $ hg debugbuilddag -mo '+2:tbase @name1 +3:thead1 <tbase @name2 +4:thead2 @both /thead1 +2:tmaintip'
+ $ hg glog
+ o 11 a19bfa7e7328: r11 both
+ |
+ o 10 8b6bad1512e1: r10 both
+ |
+ o 9 025829e08038: r9 both
+ |\
+ | o 8 d8f638ac69e9: r8 name2
+ | |
+ | o 7 b6b4d315a2ac: r7 name2
+ | |
+ | o 6 6c6f5d5f3c11: r6 name2
+ | |
+ | o 5 70314b29987d: r5 name2
+ | |
+ o | 4 e71dbbc70e03: r4 name1
+ | |
+ o | 3 2c8d5d5ec612: r3 name1
+ | |
+ o | 2 a7892891da29: r2 name1
+ |/
+ o 1 0019a3b924fd: r1
+ |
+ o 0 d57206cc072a: r0
+
+ $ cd ..
+ $ tstart main
+
+Full clone:
+
+ $ hg clone main full
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd full
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ hg push $remote
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+Local is empty:
+
+ $ cd empty1
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ 0 d57206cc072a: r0
+ 1 0019a3b924fd: r1
+ 2 a7892891da29: r2 name1
+ 3 2c8d5d5ec612: r3 name1
+ 4 e71dbbc70e03: r4 name1
+ 5 70314b29987d: r5 name2
+ 6 6c6f5d5f3c11: r6 name2
+ 7 b6b4d315a2ac: r7 name2
+ 8 d8f638ac69e9: r8 name2
+ 9 025829e08038: r9 both
+ 10 8b6bad1512e1: r10 both
+ 11 a19bfa7e7328: r11 both
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ no changes found
+ [1]
+ $ hg push $remote
+ pushing to http://localhost:$HGPORT/
+ no changes found
+ [1]
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 12 changesets with 24 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+Local is subset:
+
+ $ hg clone main subset --rev name2 ; cd subset
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 12 changes to 2 files
+ updating to branch name2
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 6 a7892891da29: r2 name1
+ 7 2c8d5d5ec612: r3 name1
+ 8 e71dbbc70e03: r4 name1
+ 9 025829e08038: r9 both
+ 10 8b6bad1512e1: r10 both
+ 11 a19bfa7e7328: r11 both
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg push $remote
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 12 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+Remote is empty:
+
+ $ tstop ; tstart empty2
+ $ cd main
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 0 d57206cc072a: r0
+ 1 0019a3b924fd: r1
+ 2 a7892891da29: r2 name1
+ 3 2c8d5d5ec612: r3 name1
+ 4 e71dbbc70e03: r4 name1
+ 5 70314b29987d: r5 name2
+ 6 6c6f5d5f3c11: r6 name2
+ 7 b6b4d315a2ac: r7 name2
+ 8 d8f638ac69e9: r8 name2
+ 9 025829e08038: r9 both
+ 10 8b6bad1512e1: r10 both
+ 11 a19bfa7e7328: r11 both
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ hg push $remote
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 12 changesets with 24 changes to 2 files
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+Local is superset:
+
+ $ tstop
+ $ hg clone main subset2 --rev name2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 12 changes to 2 files
+ updating to branch name2
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ tstart subset2
+ $ cd main
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 2 a7892891da29: r2 name1
+ 3 2c8d5d5ec612: r3 name1
+ 4 e71dbbc70e03: r4 name1
+ 9 025829e08038: r9 both
+ 10 8b6bad1512e1: r10 both
+ 11 a19bfa7e7328: r11 both
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ hg push $remote
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: push creates new remote branches: both, name1!
+ (use 'hg push --new-branch' to create new remote branches)
+ [255]
+ $ hg push $remote --new-branch
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 6 changesets with 12 changes to 2 files
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+Partial pull:
+
+ $ tstop ; tstart main
+ $ hg clone $remote partial --rev name2
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 12 changes to 2 files
+ updating to branch name2
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd partial
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 6 a7892891da29: r2 name1
+ 7 2c8d5d5ec612: r3 name1
+ 8 e71dbbc70e03: r4 name1
+ 9 025829e08038: r9 both
+ 10 8b6bad1512e1: r10 both
+ 11 a19bfa7e7328: r11 both
+ $ hg incoming $remote --rev name1
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 6 a7892891da29: r2 name1
+ 7 2c8d5d5ec612: r3 name1
+ 8 e71dbbc70e03: r4 name1
+ $ hg pull $remote --rev name1
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 6 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads)
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 9 025829e08038: r9 both
+ 10 8b6bad1512e1: r10 both
+ 11 a19bfa7e7328: r11 both
+ $ cd ..
+
+Both have new stuff in new named branches:
+
+ $ tstop
+ $ hg clone main repo1a --rev name1 -q
+ $ hg clone repo1a repo1b -q
+ $ hg clone main repo2a --rev name2 -q
+ $ hg clone repo2a repo2b -q
+ $ tstart repo1a
+
+ $ cd repo2a
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 6 a7892891da29: r2 name1
+ 7 2c8d5d5ec612: r3 name1
+ 8 e71dbbc70e03: r4 name1
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 2 70314b29987d: r5 name2
+ 3 6c6f5d5f3c11: r6 name2
+ 4 b6b4d315a2ac: r7 name2
+ 5 d8f638ac69e9: r8 name2
+ $ hg push $remote --new-branch
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 4 changesets with 8 changes to 2 files (+1 heads)
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 6 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads)
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+ $ tstop ; tstart repo1b
+ $ cd repo2b
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 6 a7892891da29: r2 name1
+ 7 2c8d5d5ec612: r3 name1
+ 8 e71dbbc70e03: r4 name1
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 2 70314b29987d: r5 name2
+ 3 6c6f5d5f3c11: r6 name2
+ 4 b6b4d315a2ac: r7 name2
+ 5 d8f638ac69e9: r8 name2
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 6 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads)
+ $ hg push $remote --new-branch
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 4 changesets with 8 changes to 2 files (+1 heads)
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+Both have new stuff in existing named branches:
+
+ $ tstop
+ $ rm -r repo1a repo1b repo2a repo2b
+ $ hg clone main repo1a --rev 3 --rev 8 -q
+ $ hg clone repo1a repo1b -q
+ $ hg clone main repo2a --rev 4 --rev 7 -q
+ $ hg clone repo2a repo2b -q
+ $ tstart repo1a
+
+ $ cd repo2a
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 8 d8f638ac69e9: r8 name2
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 4 e71dbbc70e03: r4 name1
+ $ hg push $remote --new-branch
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 2 changes to 2 files
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+ $ tstop ; tstart repo1b
+ $ cd repo2b
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 8 d8f638ac69e9: r8 name2
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ 4 e71dbbc70e03: r4 name1
+ $ hg pull $remote
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 2 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hg push $remote --new-branch
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 2 changes to 2 files
+ $ hg incoming $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ hg outgoing $remote
+ comparing with http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ [1]
+ $ cd ..
+
+ $ tstop
+
diff --git a/tests/test-trusted.py b/tests/test-trusted.py
new file mode 100644
index 0000000..3999a0b
--- /dev/null
+++ b/tests/test-trusted.py
@@ -0,0 +1,197 @@
+# Since it's not easy to write a test that portably deals
+# with files from different users/groups, we cheat a bit by
+# monkey-patching some functions in the util module
+
+import os
+from mercurial import ui, util, error
+
+hgrc = os.environ['HGRCPATH']
+f = open(hgrc)
+basehgrc = f.read()
+f.close()
+
+def testui(user='foo', group='bar', tusers=(), tgroups=(),
+ cuser='foo', cgroup='bar', debug=False, silent=False,
+ report=True):
+ # user, group => owners of the file
+ # tusers, tgroups => trusted users/groups
+ # cuser, cgroup => user/group of the current process
+
+ # write a global hgrc with the list of trusted users/groups and
+ # some setting so that we can be sure it was read
+ f = open(hgrc, 'w')
+ f.write(basehgrc)
+ f.write('\n[paths]\n')
+ f.write('global = /some/path\n\n')
+
+ if tusers or tgroups:
+ f.write('[trusted]\n')
+ if tusers:
+ f.write('users = %s\n' % ', '.join(tusers))
+ if tgroups:
+ f.write('groups = %s\n' % ', '.join(tgroups))
+ f.close()
+
+ # override the functions that give names to uids and gids
+ def username(uid=None):
+ if uid is None:
+ return cuser
+ return user
+ util.username = username
+
+ def groupname(gid=None):
+ if gid is None:
+ return 'bar'
+ return group
+ util.groupname = groupname
+
+ def isowner(st):
+ return user == cuser
+ util.isowner = isowner
+
+ # try to read everything
+ #print '# File belongs to user %s, group %s' % (user, group)
+ #print '# trusted users = %s; trusted groups = %s' % (tusers, tgroups)
+ kind = ('different', 'same')
+ who = ('', 'user', 'group', 'user and the group')
+ trusted = who[(user in tusers) + 2*(group in tgroups)]
+ if trusted:
+ trusted = ', but we trust the ' + trusted
+ print '# %s user, %s group%s' % (kind[user == cuser], kind[group == cgroup],
+ trusted)
+
+ u = ui.ui()
+ u.setconfig('ui', 'debug', str(bool(debug)))
+ u.setconfig('ui', 'report_untrusted', str(bool(report)))
+ u.readconfig('.hg/hgrc')
+ if silent:
+ return u
+ print 'trusted'
+ for name, path in u.configitems('paths'):
+ print ' ', name, '=', path
+ print 'untrusted'
+ for name, path in u.configitems('paths', untrusted=True):
+ print '.',
+ u.config('paths', name) # warning with debug=True
+ print '.',
+ u.config('paths', name, untrusted=True) # no warnings
+ print name, '=', path
+ print
+
+ return u
+
+os.mkdir('repo')
+os.chdir('repo')
+os.mkdir('.hg')
+f = open('.hg/hgrc', 'w')
+f.write('[paths]\n')
+f.write('local = /another/path\n\n')
+f.close()
+
+#print '# Everything is run by user foo, group bar\n'
+
+# same user, same group
+testui()
+# same user, different group
+testui(group='def')
+# different user, same group
+testui(user='abc')
+# ... but we trust the group
+testui(user='abc', tgroups=['bar'])
+# different user, different group
+testui(user='abc', group='def')
+# ... but we trust the user
+testui(user='abc', group='def', tusers=['abc'])
+# ... but we trust the group
+testui(user='abc', group='def', tgroups=['def'])
+# ... but we trust the user and the group
+testui(user='abc', group='def', tusers=['abc'], tgroups=['def'])
+# ... but we trust all users
+print '# we trust all users'
+testui(user='abc', group='def', tusers=['*'])
+# ... but we trust all groups
+print '# we trust all groups'
+testui(user='abc', group='def', tgroups=['*'])
+# ... but we trust the whole universe
+print '# we trust all users and groups'
+testui(user='abc', group='def', tusers=['*'], tgroups=['*'])
+# ... check that users and groups are in different namespaces
+print "# we don't get confused by users and groups with the same name"
+testui(user='abc', group='def', tusers=['def'], tgroups=['abc'])
+# ... lists of user names work
+print "# list of user names"
+testui(user='abc', group='def', tusers=['foo', 'xyz', 'abc', 'bleh'],
+ tgroups=['bar', 'baz', 'qux'])
+# ... lists of group names work
+print "# list of group names"
+testui(user='abc', group='def', tusers=['foo', 'xyz', 'bleh'],
+ tgroups=['bar', 'def', 'baz', 'qux'])
+
+print "# Can't figure out the name of the user running this process"
+testui(user='abc', group='def', cuser=None)
+
+print "# prints debug warnings"
+u = testui(user='abc', group='def', cuser='foo', debug=True)
+
+print "# report_untrusted enabled without debug hides warnings"
+u = testui(user='abc', group='def', cuser='foo', report=False)
+
+print "# report_untrusted enabled with debug shows warnings"
+u = testui(user='abc', group='def', cuser='foo', debug=True, report=False)
+
+print "# ui.readconfig sections"
+filename = 'foobar'
+f = open(filename, 'w')
+f.write('[foobar]\n')
+f.write('baz = quux\n')
+f.close()
+u.readconfig(filename, sections = ['foobar'])
+print u.config('foobar', 'baz')
+
+print
+print "# read trusted, untrusted, new ui, trusted"
+u = ui.ui()
+u.setconfig('ui', 'debug', 'on')
+u.readconfig(filename)
+u2 = u.copy()
+def username(uid=None):
+ return 'foo'
+util.username = username
+u2.readconfig('.hg/hgrc')
+print 'trusted:'
+print u2.config('foobar', 'baz')
+print 'untrusted:'
+print u2.config('foobar', 'baz', untrusted=True)
+
+print
+print "# error handling"
+
+def assertraises(f, exc=util.Abort):
+ try:
+ f()
+ except exc, inst:
+ print 'raised', inst.__class__.__name__
+ else:
+ print 'no exception?!'
+
+print "# file doesn't exist"
+os.unlink('.hg/hgrc')
+assert not os.path.exists('.hg/hgrc')
+testui(debug=True, silent=True)
+testui(user='abc', group='def', debug=True, silent=True)
+
+print
+print "# parse error"
+f = open('.hg/hgrc', 'w')
+f.write('foo')
+f.close()
+
+try:
+ testui(user='abc', group='def', silent=True)
+except error.ParseError, inst:
+ print inst
+
+try:
+ testui(debug=True, silent=True)
+except error.ParseError, inst:
+ print inst
diff --git a/tests/test-trusted.py.out b/tests/test-trusted.py.out
new file mode 100644
index 0000000..8774db3
--- /dev/null
+++ b/tests/test-trusted.py.out
@@ -0,0 +1,179 @@
+# same user, same group
+trusted
+ global = /some/path
+ local = /another/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# same user, different group
+trusted
+ global = /some/path
+ local = /another/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# different user, same group
+not trusting file .hg/hgrc from untrusted user abc, group bar
+trusted
+ global = /some/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# different user, same group, but we trust the group
+trusted
+ global = /some/path
+ local = /another/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# different user, different group
+not trusting file .hg/hgrc from untrusted user abc, group def
+trusted
+ global = /some/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# different user, different group, but we trust the user
+trusted
+ global = /some/path
+ local = /another/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# different user, different group, but we trust the group
+trusted
+ global = /some/path
+ local = /another/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# different user, different group, but we trust the user and the group
+trusted
+ global = /some/path
+ local = /another/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# we trust all users
+# different user, different group
+trusted
+ global = /some/path
+ local = /another/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# we trust all groups
+# different user, different group
+trusted
+ global = /some/path
+ local = /another/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# we trust all users and groups
+# different user, different group
+trusted
+ global = /some/path
+ local = /another/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# we don't get confused by users and groups with the same name
+# different user, different group
+not trusting file .hg/hgrc from untrusted user abc, group def
+trusted
+ global = /some/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# list of user names
+# different user, different group, but we trust the user
+trusted
+ global = /some/path
+ local = /another/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# list of group names
+# different user, different group, but we trust the group
+trusted
+ global = /some/path
+ local = /another/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# Can't figure out the name of the user running this process
+# different user, different group
+not trusting file .hg/hgrc from untrusted user abc, group def
+trusted
+ global = /some/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# prints debug warnings
+# different user, different group
+not trusting file .hg/hgrc from untrusted user abc, group def
+trusted
+ignoring untrusted configuration option paths.local = /another/path
+ global = /some/path
+untrusted
+. . global = /some/path
+.ignoring untrusted configuration option paths.local = /another/path
+. local = /another/path
+
+# report_untrusted enabled without debug hides warnings
+# different user, different group
+trusted
+ global = /some/path
+untrusted
+. . global = /some/path
+. . local = /another/path
+
+# report_untrusted enabled with debug shows warnings
+# different user, different group
+not trusting file .hg/hgrc from untrusted user abc, group def
+trusted
+ignoring untrusted configuration option paths.local = /another/path
+ global = /some/path
+untrusted
+. . global = /some/path
+.ignoring untrusted configuration option paths.local = /another/path
+. local = /another/path
+
+# ui.readconfig sections
+quux
+
+# read trusted, untrusted, new ui, trusted
+not trusting file foobar from untrusted user abc, group def
+trusted:
+ignoring untrusted configuration option foobar.baz = quux
+None
+untrusted:
+quux
+
+# error handling
+# file doesn't exist
+# same user, same group
+# different user, different group
+
+# parse error
+# different user, different group
+not trusting file .hg/hgrc from untrusted user abc, group def
+('foo', '.hg/hgrc:1')
+# same user, same group
+('foo', '.hg/hgrc:1')
diff --git a/tests/test-ui-color.py b/tests/test-ui-color.py
new file mode 100644
index 0000000..e20bcbc
--- /dev/null
+++ b/tests/test-ui-color.py
@@ -0,0 +1,33 @@
+import os, sys
+from hgext import color
+from mercurial import dispatch, ui
+
+# ensure errors aren't buffered
+testui = color.colorui()
+testui.pushbuffer()
+testui.write('buffered\n')
+testui.warn('warning\n')
+testui.write_err('error\n')
+print repr(testui.popbuffer())
+
+# test dispatch.dispatch with the same ui object
+hgrc = open(os.environ["HGRCPATH"], 'w')
+hgrc.write('[extensions]\n')
+hgrc.write('color=\n')
+hgrc.close()
+
+ui_ = ui.ui()
+ui_.setconfig('ui', 'formatted', 'True')
+
+# we're not interested in the output, so write that to devnull
+ui_.fout = open(os.devnull, 'w')
+
+# call some arbitrary command just so we go through
+# color's wrapped _runcommand twice.
+def runcmd():
+ dispatch.dispatch(dispatch.request(['version', '-q'], ui_))
+
+runcmd()
+print "colored? " + str(issubclass(ui_.__class__, color.colorui))
+runcmd()
+print "colored? " + str(issubclass(ui_.__class__, color.colorui))
diff --git a/tests/test-ui-color.py.out b/tests/test-ui-color.py.out
new file mode 100644
index 0000000..b4ea116
--- /dev/null
+++ b/tests/test-ui-color.py.out
@@ -0,0 +1,5 @@
+warning
+error
+'buffered\n'
+colored? True
+colored? True
diff --git a/tests/test-ui-config.py b/tests/test-ui-config.py
new file mode 100644
index 0000000..95dfc9d
--- /dev/null
+++ b/tests/test-ui-config.py
@@ -0,0 +1,98 @@
+from mercurial import ui, dispatch, error
+
+testui = ui.ui()
+parsed = dispatch._parseconfig(testui, [
+ 'values.string=string value',
+ 'values.bool1=true',
+ 'values.bool2=false',
+ 'values.boolinvalid=foo',
+ 'values.int1=42',
+ 'values.int2=-42',
+ 'values.intinvalid=foo',
+ 'lists.list1=foo',
+ 'lists.list2=foo bar baz',
+ 'lists.list3=alice, bob',
+ 'lists.list4=foo bar baz alice, bob',
+ 'lists.list5=abc d"ef"g "hij def"',
+ 'lists.list6="hello world", "how are you?"',
+ 'lists.list7=Do"Not"Separate',
+ 'lists.list8="Do"Separate',
+ 'lists.list9="Do\\"NotSeparate"',
+ 'lists.list10=string "with extraneous" quotation mark"',
+ 'lists.list11=x, y',
+ 'lists.list12="x", "y"',
+ 'lists.list13=""" key = "x", "y" """',
+ 'lists.list14=,,,, ',
+ 'lists.list15=" just with starting quotation',
+ 'lists.list16="longer quotation" with "no ending quotation',
+ 'lists.list17=this is \\" "not a quotation mark"',
+ 'lists.list18=\n \n\nding\ndong',
+ ])
+
+print repr(testui.configitems('values'))
+print repr(testui.configitems('lists'))
+print "---"
+print repr(testui.config('values', 'string'))
+print repr(testui.config('values', 'bool1'))
+print repr(testui.config('values', 'bool2'))
+print repr(testui.config('values', 'unknown'))
+print "---"
+try:
+ print repr(testui.configbool('values', 'string'))
+except error.ConfigError, inst:
+ print inst
+print repr(testui.configbool('values', 'bool1'))
+print repr(testui.configbool('values', 'bool2'))
+print repr(testui.configbool('values', 'bool2', True))
+print repr(testui.configbool('values', 'unknown'))
+print repr(testui.configbool('values', 'unknown', True))
+print "---"
+print repr(testui.configint('values', 'int1'))
+print repr(testui.configint('values', 'int2'))
+print "---"
+print repr(testui.configlist('lists', 'list1'))
+print repr(testui.configlist('lists', 'list2'))
+print repr(testui.configlist('lists', 'list3'))
+print repr(testui.configlist('lists', 'list4'))
+print repr(testui.configlist('lists', 'list4', ['foo']))
+print repr(testui.configlist('lists', 'list5'))
+print repr(testui.configlist('lists', 'list6'))
+print repr(testui.configlist('lists', 'list7'))
+print repr(testui.configlist('lists', 'list8'))
+print repr(testui.configlist('lists', 'list9'))
+print repr(testui.configlist('lists', 'list10'))
+print repr(testui.configlist('lists', 'list11'))
+print repr(testui.configlist('lists', 'list12'))
+print repr(testui.configlist('lists', 'list13'))
+print repr(testui.configlist('lists', 'list14'))
+print repr(testui.configlist('lists', 'list15'))
+print repr(testui.configlist('lists', 'list16'))
+print repr(testui.configlist('lists', 'list17'))
+print repr(testui.configlist('lists', 'list18'))
+print repr(testui.configlist('lists', 'unknown'))
+print repr(testui.configlist('lists', 'unknown', ''))
+print repr(testui.configlist('lists', 'unknown', 'foo'))
+print repr(testui.configlist('lists', 'unknown', ['foo']))
+print repr(testui.configlist('lists', 'unknown', 'foo bar'))
+print repr(testui.configlist('lists', 'unknown', 'foo, bar'))
+print repr(testui.configlist('lists', 'unknown', ['foo bar']))
+print repr(testui.configlist('lists', 'unknown', ['foo', 'bar']))
+
+print repr(testui.config('values', 'String'))
+
+def function():
+ pass
+
+# values that aren't strings should work
+testui.setconfig('hook', 'commit', function)
+print function == testui.config('hook', 'commit')
+
+# invalid values
+try:
+ testui.configbool('values', 'boolinvalid')
+except error.ConfigError:
+ print 'boolinvalid'
+try:
+ testui.configint('values', 'intinvalid')
+except error.ConfigError:
+ print 'intinvalid'
diff --git a/tests/test-ui-config.py.out b/tests/test-ui-config.py.out
new file mode 100644
index 0000000..6be87d1
--- /dev/null
+++ b/tests/test-ui-config.py.out
@@ -0,0 +1,49 @@
+[('string', 'string value'), ('bool1', 'true'), ('bool2', 'false'), ('boolinvalid', 'foo'), ('int1', '42'), ('int2', '-42'), ('intinvalid', 'foo')]
+[('list1', 'foo'), ('list2', 'foo bar baz'), ('list3', 'alice, bob'), ('list4', 'foo bar baz alice, bob'), ('list5', 'abc d"ef"g "hij def"'), ('list6', '"hello world", "how are you?"'), ('list7', 'Do"Not"Separate'), ('list8', '"Do"Separate'), ('list9', '"Do\\"NotSeparate"'), ('list10', 'string "with extraneous" quotation mark"'), ('list11', 'x, y'), ('list12', '"x", "y"'), ('list13', '""" key = "x", "y" """'), ('list14', ',,,, '), ('list15', '" just with starting quotation'), ('list16', '"longer quotation" with "no ending quotation'), ('list17', 'this is \\" "not a quotation mark"'), ('list18', '\n \n\nding\ndong')]
+---
+'string value'
+'true'
+'false'
+None
+---
+values.string is not a boolean ('string value')
+True
+False
+False
+False
+True
+---
+42
+-42
+---
+['foo']
+['foo', 'bar', 'baz']
+['alice', 'bob']
+['foo', 'bar', 'baz', 'alice', 'bob']
+['foo', 'bar', 'baz', 'alice', 'bob']
+['abc', 'd"ef"g', 'hij def']
+['hello world', 'how are you?']
+['Do"Not"Separate']
+['Do', 'Separate']
+['Do"NotSeparate']
+['string', 'with extraneous', 'quotation', 'mark"']
+['x', 'y']
+['x', 'y']
+['', ' key = ', 'x"', 'y', '', '"']
+[]
+['"', 'just', 'with', 'starting', 'quotation']
+['longer quotation', 'with', '"no', 'ending', 'quotation']
+['this', 'is', '"', 'not a quotation mark']
+['ding', 'dong']
+[]
+[]
+['foo']
+['foo']
+['foo', 'bar']
+['foo', 'bar']
+['foo bar']
+['foo', 'bar']
+None
+True
+boolinvalid
+intinvalid
diff --git a/tests/test-ui-verbosity.py b/tests/test-ui-verbosity.py
new file mode 100644
index 0000000..8daf7ab
--- /dev/null
+++ b/tests/test-ui-verbosity.py
@@ -0,0 +1,47 @@
+import os
+from mercurial import ui
+
+hgrc = os.environ['HGRCPATH']
+f = open(hgrc)
+basehgrc = f.read()
+f.close()
+
+print ' hgrc settings command line options final result '
+print ' quiet verbo debug quiet verbo debug quiet verbo debug'
+
+for i in xrange(64):
+ hgrc_quiet = bool(i & 1<<0)
+ hgrc_verbose = bool(i & 1<<1)
+ hgrc_debug = bool(i & 1<<2)
+ cmd_quiet = bool(i & 1<<3)
+ cmd_verbose = bool(i & 1<<4)
+ cmd_debug = bool(i & 1<<5)
+
+ f = open(hgrc, 'w')
+ f.write(basehgrc)
+ f.write('\n[ui]\n')
+ if hgrc_quiet:
+ f.write('quiet = True\n')
+ if hgrc_verbose:
+ f.write('verbose = True\n')
+ if hgrc_debug:
+ f.write('debug = True\n')
+ f.close()
+
+ u = ui.ui()
+ if cmd_quiet or cmd_debug or cmd_verbose:
+ u.setconfig('ui', 'quiet', str(bool(cmd_quiet)))
+ u.setconfig('ui', 'verbose', str(bool(cmd_verbose)))
+ u.setconfig('ui', 'debug', str(bool(cmd_debug)))
+
+ check = ''
+ if u.debugflag:
+ if not u.verbose or u.quiet:
+ check = ' *'
+ elif u.verbose and u.quiet:
+ check = ' +'
+
+ print ('%2d %5s %5s %5s %5s %5s %5s -> %5s %5s %5s%s'
+ % (i, hgrc_quiet, hgrc_verbose, hgrc_debug,
+ cmd_quiet, cmd_verbose, cmd_debug,
+ u.quiet, u.verbose, u.debugflag, check))
diff --git a/tests/test-ui-verbosity.py.out b/tests/test-ui-verbosity.py.out
new file mode 100644
index 0000000..960ac37
--- /dev/null
+++ b/tests/test-ui-verbosity.py.out
@@ -0,0 +1,66 @@
+ hgrc settings command line options final result
+ quiet verbo debug quiet verbo debug quiet verbo debug
+ 0 False False False False False False -> False False False
+ 1 True False False False False False -> True False False
+ 2 False True False False False False -> False True False
+ 3 True True False False False False -> False False False
+ 4 False False True False False False -> False True True
+ 5 True False True False False False -> False True True
+ 6 False True True False False False -> False True True
+ 7 True True True False False False -> False True True
+ 8 False False False True False False -> True False False
+ 9 True False False True False False -> True False False
+10 False True False True False False -> True False False
+11 True True False True False False -> True False False
+12 False False True True False False -> True False False
+13 True False True True False False -> True False False
+14 False True True True False False -> True False False
+15 True True True True False False -> True False False
+16 False False False False True False -> False True False
+17 True False False False True False -> False True False
+18 False True False False True False -> False True False
+19 True True False False True False -> False True False
+20 False False True False True False -> False True False
+21 True False True False True False -> False True False
+22 False True True False True False -> False True False
+23 True True True False True False -> False True False
+24 False False False True True False -> False False False
+25 True False False True True False -> False False False
+26 False True False True True False -> False False False
+27 True True False True True False -> False False False
+28 False False True True True False -> False False False
+29 True False True True True False -> False False False
+30 False True True True True False -> False False False
+31 True True True True True False -> False False False
+32 False False False False False True -> False True True
+33 True False False False False True -> False True True
+34 False True False False False True -> False True True
+35 True True False False False True -> False True True
+36 False False True False False True -> False True True
+37 True False True False False True -> False True True
+38 False True True False False True -> False True True
+39 True True True False False True -> False True True
+40 False False False True False True -> False True True
+41 True False False True False True -> False True True
+42 False True False True False True -> False True True
+43 True True False True False True -> False True True
+44 False False True True False True -> False True True
+45 True False True True False True -> False True True
+46 False True True True False True -> False True True
+47 True True True True False True -> False True True
+48 False False False False True True -> False True True
+49 True False False False True True -> False True True
+50 False True False False True True -> False True True
+51 True True False False True True -> False True True
+52 False False True False True True -> False True True
+53 True False True False True True -> False True True
+54 False True True False True True -> False True True
+55 True True True False True True -> False True True
+56 False False False True True True -> False True True
+57 True False False True True True -> False True True
+58 False True False True True True -> False True True
+59 True True False True True True -> False True True
+60 False False True True True True -> False True True
+61 True False True True True True -> False True True
+62 False True True True True True -> False True True
+63 True True True True True True -> False True True
diff --git a/tests/test-unbundlehash.t b/tests/test-unbundlehash.t
new file mode 100644
index 0000000..e55e1b7
--- /dev/null
+++ b/tests/test-unbundlehash.t
@@ -0,0 +1,32 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+Test wire protocol unbundle with hashed heads (capability: unbundlehash)
+
+Create a remote repository.
+
+ $ hg init remote
+ $ hg serve -R remote --config web.push_ssl=False --config web.allow_push=* -p $HGPORT -d --pid-file=hg1.pid -E error.log -A access.log
+ $ cat hg1.pid >> $DAEMON_PIDS
+
+Clone the repository and push a change.
+
+ $ hg clone http://localhost:$HGPORT/ local
+ no changes found
+ updating to branch default
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ touch local/README
+ $ hg ci -R local -A -m hoge
+ adding README
+ $ hg push -R local
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+
+Ensure hashed heads format is used.
+The hash here is always the same since the remote repository only has the null head.
+
+ $ cat access.log | grep unbundle
+ * - - [*] "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=686173686564+6768033e216468247bd031a0a2d9876d79818f8f (glob)
diff --git a/tests/test-unrelated-pull.t b/tests/test-unrelated-pull.t
new file mode 100644
index 0000000..5779905
--- /dev/null
+++ b/tests/test-unrelated-pull.t
@@ -0,0 +1,45 @@
+ $ hg init a
+ $ cd a
+ $ echo 123 > a
+ $ hg add a
+ $ hg commit -m "a" -u a
+
+ $ cd ..
+ $ hg init b
+ $ cd b
+ $ echo 321 > b
+ $ hg add b
+ $ hg commit -m "b" -u b
+
+ $ hg pull ../a
+ pulling from ../a
+ searching for changes
+ abort: repository is unrelated
+ [255]
+
+ $ hg pull -f ../a
+ pulling from ../a
+ searching for changes
+ warning: repository is unrelated
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ $ hg heads
+ changeset: 1:9a79c33a9db3
+ tag: tip
+ parent: -1:000000000000
+ user: a
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ changeset: 0:01f8062b2de5
+ user: b
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: b
+
+
+ $ cd ..
diff --git a/tests/test-up-local-change.t b/tests/test-up-local-change.t
new file mode 100644
index 0000000..815f9fb
--- /dev/null
+++ b/tests/test-up-local-change.t
@@ -0,0 +1,238 @@
+ $ HGMERGE=true; export HGMERGE
+
+ $ hg init r1
+ $ cd r1
+ $ echo a > a
+ $ hg addremove
+ adding a
+ $ hg commit -m "1"
+
+ $ hg clone . ../r2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../r2
+ $ hg up
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo abc > a
+ $ hg diff --nodates
+ diff -r c19d34741b0a a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,1 @@
+ -a
+ +abc
+
+ $ cd ../r1
+ $ echo b > b
+ $ echo a2 > a
+ $ hg addremove
+ adding b
+ $ hg commit -m "2"
+
+ $ cd ../r2
+ $ hg -q pull ../r1
+ $ hg status
+ M a
+ $ hg parents
+ changeset: 0:c19d34741b0a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ $ hg --debug up
+ searching for copies back to rev 1
+ unmatched files in other:
+ b
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
+ a: versions differ -> m
+ b: remote created -> g
+ preserving a for resolve of a
+ updating: a 1/2 files (50.00%)
+ picked tool 'true' for a (binary False symlink False)
+ merging a
+ my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
+ updating: b 2/2 files (100.00%)
+ getting b
+ 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ $ hg parents
+ changeset: 1:1e71731e6fbb
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ $ hg --debug up 0
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: 1e71731e6fbb, local: 1e71731e6fbb+, remote: c19d34741b0a
+ a: versions differ -> m
+ b: other deleted -> r
+ preserving a for resolve of a
+ updating: b 1/2 files (50.00%)
+ removing b
+ updating: a 2/2 files (100.00%)
+ picked tool 'true' for a (binary False symlink False)
+ merging a
+ my a@1e71731e6fbb+ other a@c19d34741b0a ancestor a@1e71731e6fbb
+ 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
+ $ hg parents
+ changeset: 0:c19d34741b0a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ $ hg --debug merge
+ abort: nothing to merge
+ (use 'hg update' instead)
+ [255]
+ $ hg parents
+ changeset: 0:c19d34741b0a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ $ hg --debug up
+ searching for copies back to rev 1
+ unmatched files in other:
+ b
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
+ a: versions differ -> m
+ b: remote created -> g
+ preserving a for resolve of a
+ updating: a 1/2 files (50.00%)
+ picked tool 'true' for a (binary False symlink False)
+ merging a
+ my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
+ updating: b 2/2 files (100.00%)
+ getting b
+ 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ $ hg parents
+ changeset: 1:1e71731e6fbb
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ $ hg -v history
+ changeset: 1:1e71731e6fbb
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: a b
+ description:
+ 2
+
+
+ changeset: 0:c19d34741b0a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: a
+ description:
+ 1
+
+
+ $ hg diff --nodates
+ diff -r 1e71731e6fbb a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,1 @@
+ -a2
+ +abc
+
+
+create a second head
+
+ $ cd ../r1
+ $ hg up 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo b2 > b
+ $ echo a3 > a
+ $ hg addremove
+ adding b
+ $ hg commit -m "3"
+ created new head
+
+ $ cd ../r2
+ $ hg -q pull ../r1
+ $ hg status
+ M a
+ $ hg parents
+ changeset: 1:1e71731e6fbb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ $ hg --debug up
+ abort: crosses branches (merge branches or use --clean to discard changes)
+ [255]
+ $ hg --debug merge
+ abort: outstanding uncommitted changes
+ (use 'hg status' to list changes)
+ [255]
+ $ hg --debug merge -f
+ searching for copies back to rev 1
+ resolving manifests
+ overwrite: False, partial: False
+ ancestor: c19d34741b0a, local: 1e71731e6fbb+, remote: 83c51d0caff4
+ a: versions differ -> m
+ b: versions differ -> m
+ preserving a for resolve of a
+ preserving b for resolve of b
+ updating: a 1/2 files (50.00%)
+ picked tool 'true' for a (binary False symlink False)
+ merging a
+ my a@1e71731e6fbb+ other a@83c51d0caff4 ancestor a@c19d34741b0a
+ updating: b 2/2 files (100.00%)
+ picked tool 'true' for b (binary False symlink False)
+ merging b
+ my b@1e71731e6fbb+ other b@83c51d0caff4 ancestor b@000000000000
+ 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg parents
+ changeset: 1:1e71731e6fbb
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 2
+
+ changeset: 2:83c51d0caff4
+ tag: tip
+ parent: 0:c19d34741b0a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 3
+
+ $ hg diff --nodates
+ diff -r 1e71731e6fbb a
+ --- a/a
+ +++ b/a
+ @@ -1,1 +1,1 @@
+ -a2
+ +abc
+
+
+test a local add
+
+ $ cd ..
+ $ hg init a
+ $ hg init b
+ $ echo a > a/a
+ $ echo a > b/a
+ $ hg --cwd a commit -A -m a
+ adding a
+ $ cd b
+ $ hg add a
+ $ hg pull -u ../a
+ pulling from ../a
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg st
+
+ $ cd ..
diff --git a/tests/test-update-branches.t b/tests/test-update-branches.t
new file mode 100644
index 0000000..e6a578e
--- /dev/null
+++ b/tests/test-update-branches.t
@@ -0,0 +1,156 @@
+# Construct the following history tree:
+#
+# @ 5:e1bb631146ca b1
+# |
+# o 4:a4fdb3b883c4 0:b608b9236435 b1
+# |
+# | o 3:4b57d2520816 1:44592833ba9f
+# | |
+# | | o 2:063f31070f65
+# | |/
+# | o 1:44592833ba9f
+# |/
+# o 0:b608b9236435
+
+ $ hg init
+ $ echo foo > foo
+ $ echo zero > a
+ $ hg init sub
+ $ echo suba > sub/suba
+ $ hg --cwd sub ci -Am addsuba
+ adding suba
+ $ echo 'sub = sub' > .hgsub
+ $ hg ci -qAm0
+ $ echo one > a ; hg ci -m1
+ $ echo two > a ; hg ci -m2
+ $ hg up -q 1
+ $ echo three > a ; hg ci -qm3
+ $ hg up -q 0
+ $ hg branch -q b1
+ $ echo four > a ; hg ci -qm4
+ $ echo five > a ; hg ci -qm5
+
+Initial repo state:
+
+ $ hg --config 'extensions.graphlog=' \
+ > glog --template '{rev}:{node|short} {parents} {branches}\n'
+ @ 5:ff252e8273df b1
+ |
+ o 4:d047485b3896 0:60829823a42a b1
+ |
+ | o 3:6efa171f091b 1:0786582aa4b1
+ | |
+ | | o 2:bd10386d478c
+ | |/
+ | o 1:0786582aa4b1
+ |/
+ o 0:60829823a42a
+
+
+Test helper functions:
+
+ $ revtest () {
+ > msg=$1
+ > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
+ > startrev=$3
+ > targetrev=$4
+ > opt=$5
+ > hg up -qC $startrev
+ > test $dirtyflag = dirty && echo dirty > foo
+ > test $dirtyflag = dirtysub && echo dirty > sub/suba
+ > hg up $opt $targetrev
+ > hg parent --template 'parent={rev}\n'
+ > hg stat -S
+ > }
+
+ $ norevtest () {
+ > msg=$1
+ > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
+ > startrev=$3
+ > opt=$4
+ > hg up -qC $startrev
+ > test $dirtyflag = dirty && echo dirty > foo
+ > test $dirtyflag = dirtysub && echo dirty > sub/suba
+ > hg up $opt
+ > hg parent --template 'parent={rev}\n'
+ > hg stat -S
+ > }
+
+Test cases are documented in a table in the update function of merge.py.
+Cases are run as shown in that table, row by row.
+
+ $ norevtest 'none clean linear' clean 4
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ parent=5
+
+ $ norevtest 'none clean same' clean 2
+ abort: crosses branches (merge branches or update --check to force update)
+ parent=2
+
+
+ $ revtest 'none clean linear' clean 1 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ parent=2
+
+ $ revtest 'none clean same' clean 2 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ parent=3
+
+ $ revtest 'none clean cross' clean 3 4
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ parent=4
+
+
+ $ revtest 'none dirty linear' dirty 1 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ parent=2
+ M foo
+
+ $ revtest 'none dirtysub linear' dirtysub 1 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ parent=2
+ M sub/suba
+
+ $ revtest 'none dirty same' dirty 2 3
+ abort: crosses branches (merge branches or use --clean to discard changes)
+ parent=2
+ M foo
+
+ $ revtest 'none dirtysub same' dirtysub 2 3
+ abort: crosses branches (merge branches or use --clean to discard changes)
+ parent=2
+ M sub/suba
+
+ $ revtest 'none dirty cross' dirty 3 4
+ abort: crosses branches (merge branches or use --clean to discard changes)
+ parent=3
+ M foo
+
+ $ revtest 'none dirtysub cross' dirtysub 3 4
+ abort: crosses branches (merge branches or use --clean to discard changes)
+ parent=3
+ M sub/suba
+
+ $ revtest '-C dirty linear' dirty 1 2 -C
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ parent=2
+
+ $ revtest '-c dirty linear' dirty 1 2 -c
+ abort: uncommitted local changes
+ parent=1
+ M foo
+
+ $ revtest '-c dirtysub linear' dirtysub 1 2 -c
+ abort: uncommitted local changes
+ parent=1
+ M sub/suba
+
+ $ norevtest '-c clean same' clean 2 -c
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ parent=3
+
+ $ revtest '-cC dirty linear' dirty 1 2 -cC
+ abort: cannot specify both -c/--check and -C/--clean
+ parent=1
+ M foo
+
diff --git a/tests/test-update-issue1456.t b/tests/test-update-issue1456.t
new file mode 100644
index 0000000..e6c8f23
--- /dev/null
+++ b/tests/test-update-issue1456.t
@@ -0,0 +1,36 @@
+ $ "$TESTDIR/hghave" execbit || exit 80
+
+ $ rm -rf a
+ $ hg init a
+ $ cd a
+
+ $ echo foo > foo
+ $ hg ci -qAm0
+ $ chmod +x foo
+ $ hg ci -m1
+ $ hg co -q 0
+ $ echo dirty > foo
+ $ hg up -c
+ abort: uncommitted local changes
+ [255]
+ $ hg up -q
+ $ cat foo
+ dirty
+ $ hg st -A
+ M foo
+
+Validate update of standalone execute bit change:
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ chmod -x foo
+ $ hg ci -m removeexec
+ nothing changed
+ [1]
+ $ hg up -C 0
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg up
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg st
+
+ $ cd ..
diff --git a/tests/test-update-renames.t b/tests/test-update-renames.t
new file mode 100644
index 0000000..829317a
--- /dev/null
+++ b/tests/test-update-renames.t
@@ -0,0 +1,27 @@
+Test update logic when there are renames
+
+Update with local changes across a file rename
+
+ $ hg init
+
+ $ echo a > a
+ $ hg add a
+ $ hg ci -m a
+
+ $ hg mv a b
+ $ hg ci -m rename
+
+ $ echo b > b
+ $ hg ci -m change
+
+ $ hg up -q 0
+
+ $ echo c > a
+
+ $ hg up
+ merging a and b to b
+ warning: conflicts during merge.
+ merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges
+ [1]
diff --git a/tests/test-update-reverse.t b/tests/test-update-reverse.t
new file mode 100644
index 0000000..4d1dd26
--- /dev/null
+++ b/tests/test-update-reverse.t
@@ -0,0 +1,85 @@
+ $ hg init
+
+ $ touch a
+ $ hg add a
+ $ hg commit -m "Added a"
+
+ $ touch main
+ $ hg add main
+ $ hg commit -m "Added main"
+ $ hg checkout 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+'main' should be gone:
+
+ $ ls
+ a
+
+ $ touch side1
+ $ hg add side1
+ $ hg commit -m "Added side1"
+ created new head
+ $ touch side2
+ $ hg add side2
+ $ hg commit -m "Added side2"
+
+ $ hg log
+ changeset: 3:91ebc10ed028
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added side2
+
+ changeset: 2:b932d7dbb1e1
+ parent: 0:c2eda428b523
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added side1
+
+ changeset: 1:71a760306caf
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added main
+
+ changeset: 0:c2eda428b523
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added a
+
+
+ $ hg heads
+ changeset: 3:91ebc10ed028
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added side2
+
+ changeset: 1:71a760306caf
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added main
+
+ $ ls
+ a
+ side1
+ side2
+
+ $ hg update --debug -C 1
+ resolving manifests
+ overwrite: True, partial: False
+ ancestor: 91ebc10ed028+, local: 91ebc10ed028+, remote: 71a760306caf
+ side2: other deleted -> r
+ side1: other deleted -> r
+ main: remote created -> g
+ updating: side1 1/3 files (33.33%)
+ removing side1
+ updating: side2 2/3 files (66.67%)
+ removing side2
+ updating: main 3/3 files (100.00%)
+ getting main
+ 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+ $ ls
+ a
+ main
+
diff --git a/tests/test-url-rev.t b/tests/test-url-rev.t
new file mode 100644
index 0000000..517b83b
--- /dev/null
+++ b/tests/test-url-rev.t
@@ -0,0 +1,210 @@
+Test basic functionality of url#rev syntax
+
+ $ hg init repo
+ $ cd repo
+ $ echo a > a
+ $ hg ci -qAm 'add a'
+ $ hg branch foo
+ marked working directory as branch foo
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo >> a
+ $ hg ci -m 'change a'
+ $ cd ..
+
+ $ hg clone 'repo#foo' clone
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+ updating to branch foo
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg --cwd clone heads
+ changeset: 1:cd2a86ecc814
+ branch: foo
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change a
+
+ changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+ $ hg --cwd clone parents
+ changeset: 1:cd2a86ecc814
+ branch: foo
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change a
+
+ $ cat clone/.hg/hgrc
+ [paths]
+ default = $TESTTMP/repo#foo (glob)
+
+Changing original repo:
+
+ $ cd repo
+
+ $ echo >> a
+ $ hg ci -m 'new head of branch foo'
+
+ $ hg up -qC default
+ $ echo bar > bar
+ $ hg ci -qAm 'add bar'
+
+ $ hg log
+ changeset: 3:4cd725637392
+ tag: tip
+ parent: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add bar
+
+ changeset: 2:faba9097cad4
+ branch: foo
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: new head of branch foo
+
+ changeset: 1:cd2a86ecc814
+ branch: foo
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: change a
+
+ changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+ $ hg -q outgoing '../clone#foo'
+ 2:faba9097cad4
+
+ $ hg -q push '../clone#foo'
+
+ $ hg --cwd ../clone heads
+ changeset: 2:faba9097cad4
+ branch: foo
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: new head of branch foo
+
+ changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+ $ cd ..
+
+ $ cd clone
+ $ hg rollback
+ repository tip rolled back to revision 1 (undo push)
+
+ $ hg -q incoming
+ 2:faba9097cad4
+
+ $ hg -q pull
+
+ $ hg heads
+ changeset: 2:faba9097cad4
+ branch: foo
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: new head of branch foo
+
+ changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+Pull should not have updated:
+
+ $ hg parents -q
+ 1:cd2a86ecc814
+
+Going back to the default branch:
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg parents
+ changeset: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add a
+
+No new revs, no update:
+
+ $ hg pull -qu
+
+ $ hg parents -q
+ 0:1f0dee641bb7
+
+ $ hg rollback
+ repository tip rolled back to revision 1 (undo pull)
+
+ $ hg parents -q
+ 0:1f0dee641bb7
+
+Pull -u takes us back to branch foo:
+
+ $ hg pull -qu
+
+ $ hg parents
+ changeset: 2:faba9097cad4
+ branch: foo
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: new head of branch foo
+
+ $ hg rollback
+ repository tip rolled back to revision 1 (undo pull)
+ working directory now based on revision 0
+
+ $ hg up -C 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg parents -q
+ 0:1f0dee641bb7
+
+ $ hg heads -q
+ 1:cd2a86ecc814
+ 0:1f0dee641bb7
+
+ $ hg pull -qur default default
+
+ $ hg parents
+ changeset: 3:4cd725637392
+ tag: tip
+ parent: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add bar
+
+ $ hg heads
+ changeset: 3:4cd725637392
+ tag: tip
+ parent: 0:1f0dee641bb7
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add bar
+
+ changeset: 2:faba9097cad4
+ branch: foo
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: new head of branch foo
+
+Test handling of invalid urls
+
+ $ hg id http://foo/?bar
+ abort: unsupported URL component: "bar"
+ [255]
+
+ $ cd ..
diff --git a/tests/test-url.py b/tests/test-url.py
new file mode 100644
index 0000000..0cf2ad6
--- /dev/null
+++ b/tests/test-url.py
@@ -0,0 +1,246 @@
+import os
+
+def check(a, b):
+ if a != b:
+ print (a, b)
+
+def cert(cn):
+ return dict(subject=((('commonName', cn),),))
+
+from mercurial.sslutil import _verifycert
+
+# Test non-wildcard certificates
+check(_verifycert(cert('example.com'), 'example.com'),
+ None)
+check(_verifycert(cert('example.com'), 'www.example.com'),
+ 'certificate is for example.com')
+check(_verifycert(cert('www.example.com'), 'example.com'),
+ 'certificate is for www.example.com')
+
+# Test wildcard certificates
+check(_verifycert(cert('*.example.com'), 'www.example.com'),
+ None)
+check(_verifycert(cert('*.example.com'), 'example.com'),
+ 'certificate is for *.example.com')
+check(_verifycert(cert('*.example.com'), 'w.w.example.com'),
+ 'certificate is for *.example.com')
+
+# Test subjectAltName
+san_cert = {'subject': ((('commonName', 'example.com'),),),
+ 'subjectAltName': (('DNS', '*.example.net'),
+ ('DNS', 'example.net'))}
+check(_verifycert(san_cert, 'example.net'),
+ None)
+check(_verifycert(san_cert, 'foo.example.net'),
+ None)
+# no fallback to subject commonName when subjectAltName has DNS
+check(_verifycert(san_cert, 'example.com'),
+ 'certificate is for *.example.net, example.net')
+# fallback to subject commonName when no DNS in subjectAltName
+san_cert = {'subject': ((('commonName', 'example.com'),),),
+ 'subjectAltName': (('IP Address', '8.8.8.8'),)}
+check(_verifycert(san_cert, 'example.com'), None)
+
+# Avoid some pitfalls
+check(_verifycert(cert('*.foo'), 'foo'),
+ 'certificate is for *.foo')
+check(_verifycert(cert('*o'), 'foo'),
+ 'certificate is for *o')
+
+check(_verifycert({'subject': ()},
+ 'example.com'),
+ 'no commonName or subjectAltName found in certificate')
+check(_verifycert(None, 'example.com'),
+ 'no certificate received')
+
+# Unicode (IDN) certname isn't supported
+check(_verifycert(cert(u'\u4f8b.jp'), 'example.jp'),
+ 'IDN in certificate not supported')
+
+import doctest
+
+def test_url():
+ """
+ >>> from mercurial.util import url
+
+ This tests for edge cases in url.URL's parsing algorithm. Most of
+ these aren't useful for documentation purposes, so they aren't
+ part of the class's doc tests.
+
+ Query strings and fragments:
+
+ >>> url('http://host/a?b#c')
+ <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'>
+ >>> url('http://host/a?')
+ <url scheme: 'http', host: 'host', path: 'a'>
+ >>> url('http://host/a#b#c')
+ <url scheme: 'http', host: 'host', path: 'a', fragment: 'b#c'>
+ >>> url('http://host/a#b?c')
+ <url scheme: 'http', host: 'host', path: 'a', fragment: 'b?c'>
+ >>> url('http://host/?a#b')
+ <url scheme: 'http', host: 'host', path: '', query: 'a', fragment: 'b'>
+ >>> url('http://host/?a#b', parsequery=False)
+ <url scheme: 'http', host: 'host', path: '?a', fragment: 'b'>
+ >>> url('http://host/?a#b', parsefragment=False)
+ <url scheme: 'http', host: 'host', path: '', query: 'a#b'>
+ >>> url('http://host/?a#b', parsequery=False, parsefragment=False)
+ <url scheme: 'http', host: 'host', path: '?a#b'>
+
+ IPv6 addresses:
+
+ >>> url('ldap://[2001:db8::7]/c=GB?objectClass?one')
+ <url scheme: 'ldap', host: '[2001:db8::7]', path: 'c=GB',
+ query: 'objectClass?one'>
+ >>> url('ldap://joe:xxx@[2001:db8::7]:80/c=GB?objectClass?one')
+ <url scheme: 'ldap', user: 'joe', passwd: 'xxx', host: '[2001:db8::7]',
+ port: '80', path: 'c=GB', query: 'objectClass?one'>
+
+ Missing scheme, host, etc.:
+
+ >>> url('://192.0.2.16:80/')
+ <url path: '://192.0.2.16:80/'>
+ >>> url('http://mercurial.selenic.com')
+ <url scheme: 'http', host: 'mercurial.selenic.com'>
+ >>> url('/foo')
+ <url path: '/foo'>
+ >>> url('bundle:/foo')
+ <url scheme: 'bundle', path: '/foo'>
+ >>> url('a?b#c')
+ <url path: 'a?b', fragment: 'c'>
+ >>> url('http://x.com?arg=/foo')
+ <url scheme: 'http', host: 'x.com', query: 'arg=/foo'>
+ >>> url('http://joe:xxx@/foo')
+ <url scheme: 'http', user: 'joe', passwd: 'xxx', path: 'foo'>
+
+ Just a scheme and a path:
+
+ >>> url('mailto:John.Doe@example.com')
+ <url scheme: 'mailto', path: 'John.Doe@example.com'>
+ >>> url('a:b:c:d')
+ <url path: 'a:b:c:d'>
+ >>> url('aa:bb:cc:dd')
+ <url scheme: 'aa', path: 'bb:cc:dd'>
+
+ SSH examples:
+
+ >>> url('ssh://joe@host//home/joe')
+ <url scheme: 'ssh', user: 'joe', host: 'host', path: '/home/joe'>
+ >>> url('ssh://joe:xxx@host/src')
+ <url scheme: 'ssh', user: 'joe', passwd: 'xxx', host: 'host', path: 'src'>
+ >>> url('ssh://joe:xxx@host')
+ <url scheme: 'ssh', user: 'joe', passwd: 'xxx', host: 'host'>
+ >>> url('ssh://joe@host')
+ <url scheme: 'ssh', user: 'joe', host: 'host'>
+ >>> url('ssh://host')
+ <url scheme: 'ssh', host: 'host'>
+ >>> url('ssh://')
+ <url scheme: 'ssh'>
+ >>> url('ssh:')
+ <url scheme: 'ssh'>
+
+ Non-numeric port:
+
+ >>> url('http://example.com:dd')
+ <url scheme: 'http', host: 'example.com', port: 'dd'>
+ >>> url('ssh://joe:xxx@host:ssh/foo')
+ <url scheme: 'ssh', user: 'joe', passwd: 'xxx', host: 'host', port: 'ssh',
+ path: 'foo'>
+
+ Bad authentication credentials:
+
+ >>> url('http://joe@joeville:123@4:@host/a?b#c')
+ <url scheme: 'http', user: 'joe@joeville', passwd: '123@4:',
+ host: 'host', path: 'a', query: 'b', fragment: 'c'>
+ >>> url('http://!*#?/@!*#?/:@host/a?b#c')
+ <url scheme: 'http', host: '!*', fragment: '?/@!*#?/:@host/a?b#c'>
+ >>> url('http://!*#?@!*#?:@host/a?b#c')
+ <url scheme: 'http', host: '!*', fragment: '?@!*#?:@host/a?b#c'>
+ >>> url('http://!*@:!*@@host/a?b#c')
+ <url scheme: 'http', user: '!*@', passwd: '!*@', host: 'host',
+ path: 'a', query: 'b', fragment: 'c'>
+
+ File paths:
+
+ >>> url('a/b/c/d.g.f')
+ <url path: 'a/b/c/d.g.f'>
+ >>> url('/x///z/y/')
+ <url path: '/x///z/y/'>
+ >>> url('/foo:bar')
+ <url path: '/foo:bar'>
+ >>> url('\\\\foo:bar')
+ <url path: '\\\\foo:bar'>
+ >>> url('./foo:bar')
+ <url path: './foo:bar'>
+
+ Non-localhost file URL:
+
+ >>> u = url('file://mercurial.selenic.com/foo')
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ Abort: file:// URLs can only refer to localhost
+
+ Empty URL:
+
+ >>> u = url('')
+ >>> u
+ <url path: ''>
+ >>> str(u)
+ ''
+
+ Empty path with query string:
+
+ >>> str(url('http://foo/?bar'))
+ 'http://foo/?bar'
+
+ Invalid path:
+
+ >>> u = url('http://foo/bar')
+ >>> u.path = 'bar'
+ >>> str(u)
+ 'http://foo/bar'
+
+ >>> u = url('file:/foo/bar/baz')
+ >>> u
+ <url scheme: 'file', path: '/foo/bar/baz'>
+ >>> str(u)
+ 'file:///foo/bar/baz'
+ >>> u.localpath()
+ '/foo/bar/baz'
+
+ >>> u = url('file:///foo/bar/baz')
+ >>> u
+ <url scheme: 'file', path: '/foo/bar/baz'>
+ >>> str(u)
+ 'file:///foo/bar/baz'
+ >>> u.localpath()
+ '/foo/bar/baz'
+
+ >>> u = url('file:///f:oo/bar/baz')
+ >>> u
+ <url scheme: 'file', path: 'f:oo/bar/baz'>
+ >>> str(u)
+ 'file:///f:oo/bar/baz'
+ >>> u.localpath()
+ 'f:oo/bar/baz'
+
+ >>> u = url('file://localhost/f:oo/bar/baz')
+ >>> u
+ <url scheme: 'file', host: 'localhost', path: 'f:oo/bar/baz'>
+ >>> str(u)
+ 'file://localhost/f:oo/bar/baz'
+ >>> u.localpath()
+ 'f:oo/bar/baz'
+
+ >>> u = url('file:foo/bar/baz')
+ >>> u
+ <url scheme: 'file', path: 'foo/bar/baz'>
+ >>> str(u)
+ 'file:foo/bar/baz'
+ >>> u.localpath()
+ 'foo/bar/baz'
+ """
+
+if 'TERM' in os.environ:
+ del os.environ['TERM']
+
+doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE)
diff --git a/tests/test-username-newline.t b/tests/test-username-newline.t
new file mode 100644
index 0000000..6f3bc5c
--- /dev/null
+++ b/tests/test-username-newline.t
@@ -0,0 +1,25 @@
+ $ hg init
+ $ touch a
+
+ $ unset HGUSER
+ $ echo "[ui]" >> .hg/hgrc
+ $ echo "username= foo" >> .hg/hgrc
+ $ echo " bar1" >> .hg/hgrc
+
+ $ hg ci -Am m
+ adding a
+ abort: username 'foo\nbar1' contains a newline
+
+ [255]
+ $ rm .hg/hgrc
+
+ $ HGUSER=`(echo foo; echo bar2)` hg ci -Am m
+ abort: username 'foo\nbar2' contains a newline
+
+ [255]
+ $ hg ci -Am m -u "`(echo foo; echo bar3)`"
+ transaction abort!
+ rollback completed
+ abort: username 'foo\nbar3' contains a newline!
+ [255]
+
diff --git a/tests/test-verify.t b/tests/test-verify.t
new file mode 100644
index 0000000..5f3d7a7
--- /dev/null
+++ b/tests/test-verify.t
@@ -0,0 +1,103 @@
+prepare repo
+
+ $ hg init a
+ $ cd a
+ $ echo "some text" > FOO.txt
+ $ echo "another text" > bar.txt
+ $ echo "more text" > QUICK.txt
+ $ hg add
+ adding FOO.txt
+ adding QUICK.txt
+ adding bar.txt
+ $ hg ci -mtest1
+
+verify
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 1 changesets, 3 total revisions
+
+verify with journal
+
+ $ touch .hg/store/journal
+ $ hg verify
+ abandoned transaction found - run hg recover
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 3 files, 1 changesets, 3 total revisions
+ $ rm .hg/store/journal
+
+introduce some bugs in repo
+
+ $ cd .hg/store/data
+ $ mv _f_o_o.txt.i X_f_o_o.txt.i
+ $ mv bar.txt.i xbar.txt.i
+ $ rm _q_u_i_c_k.txt.i
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ data/FOO.txt.i@0: missing revlog!
+ 0: empty or missing FOO.txt
+ FOO.txt@0: f62022d3d590 in manifests not found
+ data/QUICK.txt.i@0: missing revlog!
+ 0: empty or missing QUICK.txt
+ QUICK.txt@0: 88b857db8eba in manifests not found
+ data/bar.txt.i@0: missing revlog!
+ 0: empty or missing bar.txt
+ bar.txt@0: 256559129457 in manifests not found
+ 3 files, 1 changesets, 0 total revisions
+ 9 integrity errors encountered!
+ (first damaged changeset appears to be 0)
+ [1]
+
+ $ cd ../../..
+ $ cd ..
+
+test revlog corruption
+
+ $ hg init b
+ $ cd b
+
+ $ touch a
+ $ hg add a
+ $ hg ci -m a
+
+ $ echo 'corrupted' > b
+ $ dd if=.hg/store/data/a.i of=start bs=1 count=20 2>/dev/null
+ $ cat start b > .hg/store/data/a.i
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ a@0: broken revlog! (index data/a.i is corrupted)
+ warning: orphan revlog 'data/a.i'
+ 1 files, 1 changesets, 0 total revisions
+ 1 warnings encountered!
+ 1 integrity errors encountered!
+ (first damaged changeset appears to be 0)
+ [1]
+
+ $ cd ..
+
+test revlog format 0
+
+ $ "$TESTDIR/revlog-formatv0.py"
+ $ cd formatv0
+ $ hg verify
+ repository uses revlog format 0
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+ $ cd ..
diff --git a/tests/test-walk.t b/tests/test-walk.t
new file mode 100644
index 0000000..52de65e
--- /dev/null
+++ b/tests/test-walk.t
@@ -0,0 +1,333 @@
+ $ hg init t
+ $ cd t
+ $ mkdir -p beans
+ $ for b in kidney navy turtle borlotti black pinto; do
+ > echo $b > beans/$b
+ $ done
+ $ mkdir -p mammals/Procyonidae
+ $ for m in cacomistle coatimundi raccoon; do
+ > echo $m > mammals/Procyonidae/$m
+ $ done
+ $ echo skunk > mammals/skunk
+ $ echo fennel > fennel
+ $ echo fenugreek > fenugreek
+ $ echo fiddlehead > fiddlehead
+ $ hg addremove
+ adding beans/black
+ adding beans/borlotti
+ adding beans/kidney
+ adding beans/navy
+ adding beans/pinto
+ adding beans/turtle
+ adding fennel
+ adding fenugreek
+ adding fiddlehead
+ adding mammals/Procyonidae/cacomistle
+ adding mammals/Procyonidae/coatimundi
+ adding mammals/Procyonidae/raccoon
+ adding mammals/skunk
+ $ hg commit -m "commit #0"
+
+ $ hg debugwalk
+ f beans/black beans/black
+ f beans/borlotti beans/borlotti
+ f beans/kidney beans/kidney
+ f beans/navy beans/navy
+ f beans/pinto beans/pinto
+ f beans/turtle beans/turtle
+ f fennel fennel
+ f fenugreek fenugreek
+ f fiddlehead fiddlehead
+ f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
+ f mammals/skunk mammals/skunk
+ $ hg debugwalk -I.
+ f beans/black beans/black
+ f beans/borlotti beans/borlotti
+ f beans/kidney beans/kidney
+ f beans/navy beans/navy
+ f beans/pinto beans/pinto
+ f beans/turtle beans/turtle
+ f fennel fennel
+ f fenugreek fenugreek
+ f fiddlehead fiddlehead
+ f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
+ f mammals/skunk mammals/skunk
+
+ $ cd mammals
+ $ hg debugwalk
+ f beans/black ../beans/black
+ f beans/borlotti ../beans/borlotti
+ f beans/kidney ../beans/kidney
+ f beans/navy ../beans/navy
+ f beans/pinto ../beans/pinto
+ f beans/turtle ../beans/turtle
+ f fennel ../fennel
+ f fenugreek ../fenugreek
+ f fiddlehead ../fiddlehead
+ f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon Procyonidae/raccoon
+ f mammals/skunk skunk
+ $ hg debugwalk -X ../beans
+ f fennel ../fennel
+ f fenugreek ../fenugreek
+ f fiddlehead ../fiddlehead
+ f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon Procyonidae/raccoon
+ f mammals/skunk skunk
+ $ hg debugwalk -I '*k'
+ f mammals/skunk skunk
+ $ hg debugwalk -I 'glob:*k'
+ f mammals/skunk skunk
+ $ hg debugwalk -I 'relglob:*k'
+ f beans/black ../beans/black
+ f fenugreek ../fenugreek
+ f mammals/skunk skunk
+ $ hg debugwalk -I 'relglob:*k' .
+ f mammals/skunk skunk
+ $ hg debugwalk -I 're:.*k$'
+ f beans/black ../beans/black
+ f fenugreek ../fenugreek
+ f mammals/skunk skunk
+ $ hg debugwalk -I 'relre:.*k$'
+ f beans/black ../beans/black
+ f fenugreek ../fenugreek
+ f mammals/skunk skunk
+ $ hg debugwalk -I 'path:beans'
+ f beans/black ../beans/black
+ f beans/borlotti ../beans/borlotti
+ f beans/kidney ../beans/kidney
+ f beans/navy ../beans/navy
+ f beans/pinto ../beans/pinto
+ f beans/turtle ../beans/turtle
+ $ hg debugwalk -I 'relpath:detour/../../beans'
+ f beans/black ../beans/black
+ f beans/borlotti ../beans/borlotti
+ f beans/kidney ../beans/kidney
+ f beans/navy ../beans/navy
+ f beans/pinto ../beans/pinto
+ f beans/turtle ../beans/turtle
+ $ hg debugwalk .
+ f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon Procyonidae/raccoon
+ f mammals/skunk skunk
+ $ hg debugwalk -I.
+ f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon Procyonidae/raccoon
+ f mammals/skunk skunk
+ $ hg debugwalk Procyonidae
+ f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon Procyonidae/raccoon
+
+ $ cd Procyonidae
+ $ hg debugwalk .
+ f mammals/Procyonidae/cacomistle cacomistle
+ f mammals/Procyonidae/coatimundi coatimundi
+ f mammals/Procyonidae/raccoon raccoon
+ $ hg debugwalk ..
+ f mammals/Procyonidae/cacomistle cacomistle
+ f mammals/Procyonidae/coatimundi coatimundi
+ f mammals/Procyonidae/raccoon raccoon
+ f mammals/skunk ../skunk
+ $ cd ..
+
+ $ hg debugwalk ../beans
+ f beans/black ../beans/black
+ f beans/borlotti ../beans/borlotti
+ f beans/kidney ../beans/kidney
+ f beans/navy ../beans/navy
+ f beans/pinto ../beans/pinto
+ f beans/turtle ../beans/turtle
+ $ hg debugwalk .
+ f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon Procyonidae/raccoon
+ f mammals/skunk skunk
+ $ hg debugwalk .hg
+ abort: path 'mammals/.hg' is inside nested repo 'mammals' (glob)
+ [255]
+ $ hg debugwalk ../.hg
+ abort: path contains illegal component: .hg (glob)
+ [255]
+ $ cd ..
+
+ $ hg debugwalk -Ibeans
+ f beans/black beans/black
+ f beans/borlotti beans/borlotti
+ f beans/kidney beans/kidney
+ f beans/navy beans/navy
+ f beans/pinto beans/pinto
+ f beans/turtle beans/turtle
+ $ hg debugwalk -I '{*,{b,m}*/*}k'
+ f beans/black beans/black
+ f fenugreek fenugreek
+ f mammals/skunk mammals/skunk
+ $ hg debugwalk 'glob:mammals/../beans/b*'
+ f beans/black beans/black
+ f beans/borlotti beans/borlotti
+ $ hg debugwalk '-X*/Procyonidae' mammals
+ f mammals/skunk mammals/skunk
+ $ hg debugwalk path:mammals
+ f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
+ f mammals/skunk mammals/skunk
+ $ hg debugwalk ..
+ abort: .. not under root
+ [255]
+ $ hg debugwalk beans/../..
+ abort: beans/../.. not under root
+ [255]
+ $ hg debugwalk .hg
+ abort: path contains illegal component: .hg (glob)
+ [255]
+ $ hg debugwalk beans/../.hg
+ abort: path contains illegal component: .hg (glob)
+ [255]
+ $ hg debugwalk beans/../.hg/data
+ abort: path contains illegal component: .hg/data (glob)
+ [255]
+ $ hg debugwalk beans/.hg
+ abort: path 'beans/.hg' is inside nested repo 'beans' (glob)
+ [255]
+
+Test absolute paths:
+
+ $ hg debugwalk `pwd`/beans
+ f beans/black beans/black
+ f beans/borlotti beans/borlotti
+ f beans/kidney beans/kidney
+ f beans/navy beans/navy
+ f beans/pinto beans/pinto
+ f beans/turtle beans/turtle
+ $ hg debugwalk `pwd`/..
+ abort: $TESTTMP/t/.. not under root
+ [255]
+
+Test patterns:
+
+ $ hg debugwalk glob:\*
+ f fennel fennel
+ f fenugreek fenugreek
+ f fiddlehead fiddlehead
+#if eol-in-paths
+ $ echo glob:glob > glob:glob
+ $ hg addremove
+ adding glob:glob
+ warning: filename contains ':', which is reserved on Windows: 'glob:glob'
+ $ hg debugwalk glob:\*
+ f fennel fennel
+ f fenugreek fenugreek
+ f fiddlehead fiddlehead
+ f glob:glob glob:glob
+ $ hg debugwalk glob:glob
+ glob: No such file or directory
+ $ hg debugwalk glob:glob:glob
+ f glob:glob glob:glob exact
+ $ hg debugwalk path:glob:glob
+ f glob:glob glob:glob exact
+ $ rm glob:glob
+ $ hg addremove
+ removing glob:glob
+#endif
+
+ $ hg debugwalk 'glob:**e'
+ f beans/turtle beans/turtle
+ f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
+
+ $ hg debugwalk 're:.*[kb]$'
+ f beans/black beans/black
+ f fenugreek fenugreek
+ f mammals/skunk mammals/skunk
+
+ $ hg debugwalk path:beans/black
+ f beans/black beans/black exact
+ $ hg debugwalk path:beans//black
+ f beans/black beans/black exact
+
+ $ hg debugwalk relglob:Procyonidae
+ $ hg debugwalk 'relglob:Procyonidae/**'
+ f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
+ $ hg debugwalk 'relglob:Procyonidae/**' fennel
+ f fennel fennel exact
+ f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
+ $ hg debugwalk beans 'glob:beans/*'
+ f beans/black beans/black
+ f beans/borlotti beans/borlotti
+ f beans/kidney beans/kidney
+ f beans/navy beans/navy
+ f beans/pinto beans/pinto
+ f beans/turtle beans/turtle
+ $ hg debugwalk 'glob:mamm**'
+ f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
+ f mammals/skunk mammals/skunk
+ $ hg debugwalk 'glob:mamm**' fennel
+ f fennel fennel exact
+ f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
+ f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
+ f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
+ f mammals/skunk mammals/skunk
+ $ hg debugwalk 'glob:j*'
+ $ hg debugwalk NOEXIST
+ NOEXIST: * (glob)
+
+#if fifo
+ $ mkfifo fifo
+ $ hg debugwalk fifo
+ fifo: unsupported file type (type is fifo)
+#endif
+
+ $ rm fenugreek
+ $ hg debugwalk fenugreek
+ f fenugreek fenugreek exact
+ $ hg rm fenugreek
+ $ hg debugwalk fenugreek
+ f fenugreek fenugreek exact
+ $ touch new
+ $ hg debugwalk new
+ f new new exact
+
+ $ mkdir ignored
+ $ touch ignored/file
+ $ echo '^ignored$' > .hgignore
+ $ hg debugwalk ignored
+ $ hg debugwalk ignored/file
+ f ignored/file ignored/file exact
+
+Test listfile and listfile0
+
+ $ python -c "file('listfile0', 'wb').write('fenugreek\0new\0')"
+ $ hg debugwalk -I 'listfile0:listfile0'
+ f fenugreek fenugreek
+ f new new
+ $ python -c "file('listfile', 'wb').write('fenugreek\nnew\r\nmammals/skunk\n')"
+ $ hg debugwalk -I 'listfile:listfile'
+ f fenugreek fenugreek
+ f mammals/skunk mammals/skunk
+ f new new
+
+ $ cd ..
+ $ hg debugwalk -R t t/mammals/skunk
+ f mammals/skunk t/mammals/skunk exact
+ $ mkdir t2
+ $ cd t2
+ $ hg debugwalk -R ../t ../t/mammals/skunk
+ f mammals/skunk ../t/mammals/skunk exact
+ $ hg debugwalk --cwd ../t mammals/skunk
+ f mammals/skunk mammals/skunk exact
+
+ $ cd ..
diff --git a/tests/test-walkrepo.py b/tests/test-walkrepo.py
new file mode 100644
index 0000000..bbeebd4
--- /dev/null
+++ b/tests/test-walkrepo.py
@@ -0,0 +1,55 @@
+import os
+from mercurial import hg, ui
+from mercurial.scmutil import walkrepos
+from mercurial.util import checklink
+from os import mkdir, chdir
+from os.path import join as pjoin
+
+u = ui.ui()
+sym = checklink('.')
+
+hg.repository(u, 'top1', create=1)
+mkdir('subdir')
+chdir('subdir')
+hg.repository(u, 'sub1', create=1)
+mkdir('subsubdir')
+chdir('subsubdir')
+hg.repository(u, 'subsub1', create=1)
+chdir(os.path.pardir)
+if sym:
+ os.symlink(os.path.pardir, 'circle')
+ os.symlink(pjoin('subsubdir', 'subsub1'), 'subsub1')
+
+def runtest():
+ reposet = frozenset(walkrepos('.', followsym=True))
+ if sym and (len(reposet) != 3):
+ print "reposet = %r" % (reposet,)
+ print ("Found %d repositories when I should have found 3"
+ % (len(reposet),))
+ if (not sym) and (len(reposet) != 2):
+ print "reposet = %r" % (reposet,)
+ print ("Found %d repositories when I should have found 2"
+ % (len(reposet),))
+ sub1set = frozenset((pjoin('.', 'sub1'),
+ pjoin('.', 'circle', 'subdir', 'sub1')))
+ if len(sub1set & reposet) != 1:
+ print "sub1set = %r" % (sub1set,)
+ print "reposet = %r" % (reposet,)
+ print "sub1set and reposet should have exactly one path in common."
+ sub2set = frozenset((pjoin('.', 'subsub1'),
+ pjoin('.', 'subsubdir', 'subsub1')))
+ if len(sub2set & reposet) != 1:
+ print "sub2set = %r" % (sub2set,)
+ print "reposet = %r" % (reposet,)
+ print "sub1set and reposet should have exactly one path in common."
+ sub3 = pjoin('.', 'circle', 'top1')
+ if sym and sub3 not in reposet:
+ print "reposet = %r" % (reposet,)
+ print "Symbolic links are supported and %s is not in reposet" % (sub3,)
+
+runtest()
+if sym:
+ # Simulate not having symlinks.
+ del os.path.samestat
+ sym = False
+ runtest()
diff --git a/tests/test-win32text.t b/tests/test-win32text.t
new file mode 100644
index 0000000..edbe842
--- /dev/null
+++ b/tests/test-win32text.t
@@ -0,0 +1,426 @@
+
+ $ hg init t
+ $ cd t
+ $ cat > unix2dos.py <<EOF
+ > import sys
+ >
+ > for path in sys.argv[1:]:
+ > data = file(path, 'rb').read()
+ > data = data.replace('\n', '\r\n')
+ > file(path, 'wb').write(data)
+ > EOF
+ $ echo '[hooks]' >> .hg/hgrc
+ $ echo 'pretxncommit.crlf = python:hgext.win32text.forbidcrlf' >> .hg/hgrc
+ $ echo 'pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf' >> .hg/hgrc
+ $ cat .hg/hgrc
+ [hooks]
+ pretxncommit.crlf = python:hgext.win32text.forbidcrlf
+ pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf
+
+ $ echo hello > f
+ $ hg add f
+
+commit should succeed
+
+ $ hg ci -m 1
+
+ $ hg clone . ../zoz
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cp .hg/hgrc ../zoz/.hg
+ $ python unix2dos.py f
+
+commit should fail
+
+ $ hg ci -m 2.1
+ attempt to commit or push text file(s) using CRLF line endings
+ in f583ea08d42a: f
+ transaction abort!
+ rollback completed
+ abort: pretxncommit.crlf hook failed
+ [255]
+
+ $ mv .hg/hgrc .hg/hgrc.bak
+
+commits should succeed
+
+ $ hg ci -m 2
+ $ hg cp f g
+ $ hg ci -m 2.2
+
+push should fail
+
+ $ hg push ../zoz
+ pushing to ../zoz
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ attempt to commit or push text file(s) using CRLF line endings
+ in bc2d09796734: g
+ in b1aa5cde7ff4: f
+
+ To prevent this mistake in your local repository,
+ add to Mercurial.ini or .hg/hgrc:
+
+ [hooks]
+ pretxncommit.crlf = python:hgext.win32text.forbidcrlf
+
+ and also consider adding:
+
+ [extensions]
+ win32text =
+ [encode]
+ ** = cleverencode:
+ [decode]
+ ** = cleverdecode:
+ transaction abort!
+ rollback completed
+ abort: pretxnchangegroup.crlf hook failed
+ [255]
+
+ $ mv .hg/hgrc.bak .hg/hgrc
+ $ echo hello > f
+ $ hg rm g
+
+commit should succeed
+
+ $ hg ci -m 2.3
+
+push should succeed
+
+ $ hg push ../zoz
+ pushing to ../zoz
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 3 changes to 2 files
+
+and now for something completely different
+
+ $ mkdir d
+ $ echo hello > d/f2
+ $ python unix2dos.py d/f2
+ $ hg add d/f2
+ $ hg ci -m 3
+ attempt to commit or push text file(s) using CRLF line endings
+ in 053ba1a3035a: d/f2
+ transaction abort!
+ rollback completed
+ abort: pretxncommit.crlf hook failed
+ [255]
+ $ hg revert -a
+ forgetting d/f2 (glob)
+ $ rm d/f2
+
+ $ hg rem f
+ $ hg ci -m 4
+
+ $ python -c 'file("bin", "wb").write("hello\x00\x0D\x0A")'
+ $ hg add bin
+ $ hg ci -m 5
+ $ hg log -v
+ changeset: 5:f0b1c8d75fce
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: bin
+ description:
+ 5
+
+
+ changeset: 4:77796dbcd4ad
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f
+ description:
+ 4
+
+
+ changeset: 3:7c1b5430b350
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f g
+ description:
+ 2.3
+
+
+ changeset: 2:bc2d09796734
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: g
+ description:
+ 2.2
+
+
+ changeset: 1:b1aa5cde7ff4
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f
+ description:
+ 2
+
+
+ changeset: 0:fcf06d5c4e1d
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f
+ description:
+ 1
+
+
+ $ hg clone . dupe
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ for x in a b c d; do echo content > dupe/$x; done
+ $ hg -R dupe add
+ adding dupe/a (glob)
+ adding dupe/b (glob)
+ adding dupe/c (glob)
+ adding dupe/d (glob)
+ $ python unix2dos.py dupe/b dupe/c dupe/d
+ $ hg -R dupe ci -m a dupe/a
+ $ hg -R dupe ci -m b/c dupe/[bc]
+ $ hg -R dupe ci -m d dupe/d
+ $ hg -R dupe log -v
+ changeset: 8:67ac5962ab43
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: d
+ description:
+ d
+
+
+ changeset: 7:68c127d1834e
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: b c
+ description:
+ b/c
+
+
+ changeset: 6:adbf8bf7f31d
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: a
+ description:
+ a
+
+
+ changeset: 5:f0b1c8d75fce
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: bin
+ description:
+ 5
+
+
+ changeset: 4:77796dbcd4ad
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f
+ description:
+ 4
+
+
+ changeset: 3:7c1b5430b350
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f g
+ description:
+ 2.3
+
+
+ changeset: 2:bc2d09796734
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: g
+ description:
+ 2.2
+
+
+ changeset: 1:b1aa5cde7ff4
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f
+ description:
+ 2
+
+
+ changeset: 0:fcf06d5c4e1d
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f
+ description:
+ 1
+
+
+ $ hg pull dupe
+ pulling from dupe
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 4 changes to 4 files
+ attempt to commit or push text file(s) using CRLF line endings
+ in 67ac5962ab43: d
+ in 68c127d1834e: b
+ in 68c127d1834e: c
+
+ To prevent this mistake in your local repository,
+ add to Mercurial.ini or .hg/hgrc:
+
+ [hooks]
+ pretxncommit.crlf = python:hgext.win32text.forbidcrlf
+
+ and also consider adding:
+
+ [extensions]
+ win32text =
+ [encode]
+ ** = cleverencode:
+ [decode]
+ ** = cleverdecode:
+ transaction abort!
+ rollback completed
+ abort: pretxnchangegroup.crlf hook failed
+ [255]
+
+ $ hg log -v
+ changeset: 5:f0b1c8d75fce
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: bin
+ description:
+ 5
+
+
+ changeset: 4:77796dbcd4ad
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f
+ description:
+ 4
+
+
+ changeset: 3:7c1b5430b350
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f g
+ description:
+ 2.3
+
+
+ changeset: 2:bc2d09796734
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: g
+ description:
+ 2.2
+
+
+ changeset: 1:b1aa5cde7ff4
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f
+ description:
+ 2
+
+
+ changeset: 0:fcf06d5c4e1d
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ files: f
+ description:
+ 1
+
+
+ $ rm .hg/hgrc
+ $ (echo some; echo text) > f3
+ $ python -c 'file("f4.bat", "wb").write("rem empty\x0D\x0A")'
+ $ hg add f3 f4.bat
+ $ hg ci -m 6
+ $ cat bin
+ hello\x00\r (esc)
+ $ cat f3
+ some
+ text
+ $ cat f4.bat
+ rem empty\r (esc)
+
+ $ echo '[extensions]' >> .hg/hgrc
+ $ echo 'win32text = ' >> .hg/hgrc
+ $ echo '[decode]' >> .hg/hgrc
+ $ echo '** = cleverdecode:' >> .hg/hgrc
+ $ echo '[encode]' >> .hg/hgrc
+ $ echo '** = cleverencode:' >> .hg/hgrc
+ $ cat .hg/hgrc
+ [extensions]
+ win32text =
+ [decode]
+ ** = cleverdecode:
+ [encode]
+ ** = cleverencode:
+
+Trigger deprecation warning:
+
+ $ hg id -t
+ win32text is deprecated: http://mercurial.selenic.com/wiki/Win32TextExtension
+ tip
+
+Disable warning:
+
+ $ echo '[win32text]' >> .hg/hgrc
+ $ echo 'warn = no' >> .hg/hgrc
+ $ hg id -t
+ tip
+
+ $ rm f3 f4.bat bin
+ $ hg co -C
+ WARNING: f4.bat already has CRLF line endings
+ and does not need EOL conversion by the win32text plugin.
+ Before your next commit, please reconsider your encode/decode settings in
+ Mercurial.ini or $TESTTMP/t/.hg/hgrc. (glob)
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat bin
+ hello\x00\r (esc)
+ $ cat f3
+ some\r (esc)
+ text\r (esc)
+ $ cat f4.bat
+ rem empty\r (esc)
+
+ $ python -c 'file("f5.sh", "wb").write("# empty\x0D\x0A")'
+ $ hg add f5.sh
+ $ hg ci -m 7
+ $ cat f5.sh
+ # empty\r (esc)
+ $ hg cat f5.sh
+ # empty
+ $ echo '% just linefeed' > linefeed
+ $ hg ci -qAm 8 linefeed
+ $ cat linefeed
+ % just linefeed
+ $ hg cat linefeed
+ % just linefeed
+ $ hg st -q
+ $ hg revert -a linefeed
+ no changes needed to linefeed
+ $ cat linefeed
+ % just linefeed
+ $ hg st -q
+ $ echo modified >> linefeed
+ $ hg st -q
+ M linefeed
+ $ hg revert -a
+ reverting linefeed
+ $ hg st -q
+ $ cat linefeed
+ % just linefeed\r (esc)
+
+ $ cd ..
diff --git a/tests/test-wireproto.py b/tests/test-wireproto.py
new file mode 100644
index 0000000..82f7f0b
--- /dev/null
+++ b/tests/test-wireproto.py
@@ -0,0 +1,45 @@
+from mercurial import wireproto
+
+class proto(object):
+ def __init__(self, args):
+ self.args = args
+ def getargs(self, spec):
+ args = self.args
+ args.setdefault('*', {})
+ names = spec.split()
+ return [args[n] for n in names]
+
+class clientpeer(wireproto.wirepeer):
+ def __init__(self, serverrepo):
+ self.serverrepo = serverrepo
+ def _call(self, cmd, **args):
+ return wireproto.dispatch(self.serverrepo, proto(args), cmd)
+
+ @wireproto.batchable
+ def greet(self, name):
+ f = wireproto.future()
+ yield wireproto.todict(name=mangle(name)), f
+ yield unmangle(f.value)
+
+class serverrepo(object):
+ def greet(self, name):
+ return "Hello, " + name
+
+def mangle(s):
+ return ''.join(chr(ord(c) + 1) for c in s)
+def unmangle(s):
+ return ''.join(chr(ord(c) - 1) for c in s)
+
+def greet(repo, proto, name):
+ return mangle(repo.greet(unmangle(name)))
+
+wireproto.commands['greet'] = (greet, 'name',)
+
+srv = serverrepo()
+clt = clientpeer(srv)
+
+print clt.greet("Foobar")
+b = clt.batch()
+fs = [b.greet(s) for s in ["Fo, =;o", "Bar"]]
+b.submit()
+print [f.value for f in fs]
diff --git a/tests/test-wireproto.py.out b/tests/test-wireproto.py.out
new file mode 100644
index 0000000..348d247
--- /dev/null
+++ b/tests/test-wireproto.py.out
@@ -0,0 +1,2 @@
+Hello, Foobar
+['Hello, Fo, =;o', 'Hello, Bar']
diff --git a/tests/test-wireproto.t b/tests/test-wireproto.t
new file mode 100644
index 0000000..c8a81ea
--- /dev/null
+++ b/tests/test-wireproto.t
@@ -0,0 +1,114 @@
+ $ "$TESTDIR/hghave" serve || exit 80
+
+Test wire protocol argument passing
+
+Setup repo:
+
+ $ hg init repo
+
+Local:
+
+ $ hg debugwireargs repo eins zwei --three drei --four vier
+ eins zwei drei vier None
+ $ hg debugwireargs repo eins zwei --four vier
+ eins zwei None vier None
+ $ hg debugwireargs repo eins zwei
+ eins zwei None None None
+ $ hg debugwireargs repo eins zwei --five fuenf
+ eins zwei None None fuenf
+
+HTTP:
+
+ $ hg serve -R repo -p $HGPORT -d --pid-file=hg1.pid -E error.log -A access.log
+ $ cat hg1.pid >> $DAEMON_PIDS
+
+ $ hg debugwireargs http://localhost:$HGPORT/ un deux trois quatre
+ un deux trois quatre None
+ $ hg debugwireargs http://localhost:$HGPORT/ \ un deux trois\ qu\ \ atre
+ un deux trois qu atre None
+ $ hg debugwireargs http://localhost:$HGPORT/ eins zwei --four vier
+ eins zwei None vier None
+ $ hg debugwireargs http://localhost:$HGPORT/ eins zwei
+ eins zwei None None None
+ $ hg debugwireargs http://localhost:$HGPORT/ eins zwei --five fuenf
+ eins zwei None None None
+ $ hg debugwireargs http://localhost:$HGPORT/ un deux trois onethousandcharactersxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ un deux trois onethousandcharactersxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx None
+ $ cat error.log
+ $ cat access.log
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=quatre&one=un&three=trois&two=deux (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=quatre&one=un&three=trois&two=deux (glob)
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=qu++atre&one=+un&three=trois+&two=deux (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=qu++atre&one=+un&three=trois+&two=deux (glob)
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=vier&one=eins&two=zwei (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=vier&one=eins&two=zwei (glob)
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:one=eins&two=zwei (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:one=eins&two=zwei (glob)
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:one=eins&two=zwei (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:one=eins&two=zwei (glob)
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=onethousandcharactersxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&one x-hgarg-2:=un&three=trois&two=deux (glob)
+ * - - [*] "GET /?cmd=debugwireargs HTTP/1.1" 200 - x-hgarg-1:four=onethousandcharactersxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&one x-hgarg-2:=un&three=trois&two=deux (glob)
+
+HTTP without the httpheader capability:
+
+ $ HGRCPATH="`pwd`/repo/.hgrc"
+ $ export HGRCPATH
+ $ CAP=httpheader
+ $ . "$TESTDIR/notcapable"
+
+ $ hg serve -R repo -p $HGPORT2 -d --pid-file=hg2.pid -E error2.log -A access2.log
+ $ cat hg2.pid >> $DAEMON_PIDS
+
+ $ hg debugwireargs http://localhost:$HGPORT2/ un deux trois quatre
+ un deux trois quatre None
+ $ hg debugwireargs http://localhost:$HGPORT2/ eins zwei --four vier
+ eins zwei None vier None
+ $ hg debugwireargs http://localhost:$HGPORT2/ eins zwei
+ eins zwei None None None
+ $ hg debugwireargs http://localhost:$HGPORT2/ eins zwei --five fuenf
+ eins zwei None None None
+ $ cat error2.log
+ $ cat access2.log
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs&four=quatre&one=un&three=trois&two=deux HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs&four=quatre&one=un&three=trois&two=deux HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs&four=vier&one=eins&two=zwei HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs&four=vier&one=eins&two=zwei HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs&one=eins&two=zwei HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs&one=eins&two=zwei HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs&one=eins&two=zwei HTTP/1.1" 200 - (glob)
+ * - - [*] "GET /?cmd=debugwireargs&one=eins&two=zwei HTTP/1.1" 200 - (glob)
+
+SSH (try to exercise the ssh functionality with a dummy script):
+
+ $ cat <<EOF > dummyssh
+ > import sys
+ > import os
+ > os.chdir(os.path.dirname(sys.argv[0]))
+ > if sys.argv[1] != "user@dummy":
+ > sys.exit(-1)
+ > if not os.path.exists("dummyssh"):
+ > sys.exit(-1)
+ > os.environ["SSH_CLIENT"] = "127.0.0.1 1 2"
+ > r = os.system(sys.argv[2])
+ > sys.exit(bool(r))
+ > EOF
+
+ $ hg debugwireargs --ssh "python ./dummyssh" ssh://user@dummy/repo uno due tre quattro
+ uno due tre quattro None
+ $ hg debugwireargs --ssh "python ./dummyssh" ssh://user@dummy/repo eins zwei --four vier
+ eins zwei None vier None
+ $ hg debugwireargs --ssh "python ./dummyssh" ssh://user@dummy/repo eins zwei
+ eins zwei None None None
+ $ hg debugwireargs --ssh "python ./dummyssh" ssh://user@dummy/repo eins zwei --five fuenf
+ eins zwei None None None
+
diff --git a/tests/tinyproxy.py b/tests/tinyproxy.py
new file mode 100755
index 0000000..044eba2
--- /dev/null
+++ b/tests/tinyproxy.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+
+__doc__ = """Tiny HTTP Proxy.
+
+This module implements GET, HEAD, POST, PUT and DELETE methods
+on BaseHTTPServer, and behaves as an HTTP proxy. The CONNECT
+method is also implemented experimentally, but has not been
+tested yet.
+
+Any help will be greatly appreciated. SUZUKI Hisao
+"""
+
+__version__ = "0.2.1"
+
+import BaseHTTPServer, select, socket, SocketServer, urlparse, os
+
+class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler):
+ __base = BaseHTTPServer.BaseHTTPRequestHandler
+ __base_handle = __base.handle
+
+ server_version = "TinyHTTPProxy/" + __version__
+ rbufsize = 0 # self.rfile Be unbuffered
+
+ def handle(self):
+ (ip, port) = self.client_address
+ allowed = getattr(self, 'allowed_clients', None)
+ if allowed is not None and ip not in allowed:
+ self.raw_requestline = self.rfile.readline()
+ if self.parse_request():
+ self.send_error(403)
+ else:
+ self.__base_handle()
+
+ def log_request(self, code='-', size='-'):
+ xheaders = [h for h in self.headers.items() if h[0].startswith('x-')]
+ self.log_message('"%s" %s %s%s',
+ self.requestline, str(code), str(size),
+ ''.join([' %s:%s' % h for h in sorted(xheaders)]))
+
+ def _connect_to(self, netloc, soc):
+ i = netloc.find(':')
+ if i >= 0:
+ host_port = netloc[:i], int(netloc[i + 1:])
+ else:
+ host_port = netloc, 80
+ print "\t" "connect to %s:%d" % host_port
+ try: soc.connect(host_port)
+ except socket.error, arg:
+ try: msg = arg[1]
+ except (IndexError, TypeError): msg = arg
+ self.send_error(404, msg)
+ return 0
+ return 1
+
+ def do_CONNECT(self):
+ soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ if self._connect_to(self.path, soc):
+ self.log_request(200)
+ self.wfile.write(self.protocol_version +
+ " 200 Connection established\r\n")
+ self.wfile.write("Proxy-agent: %s\r\n" % self.version_string())
+ self.wfile.write("\r\n")
+ self._read_write(soc, 300)
+ finally:
+ print "\t" "bye"
+ soc.close()
+ self.connection.close()
+
+ def do_GET(self):
+ (scm, netloc, path, params, query, fragment) = urlparse.urlparse(
+ self.path, 'http')
+ if scm != 'http' or fragment or not netloc:
+ self.send_error(400, "bad url %s" % self.path)
+ return
+ soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ if self._connect_to(netloc, soc):
+ self.log_request()
+ soc.send("%s %s %s\r\n" % (
+ self.command,
+ urlparse.urlunparse(('', '', path, params, query, '')),
+ self.request_version))
+ self.headers['Connection'] = 'close'
+ del self.headers['Proxy-Connection']
+ for key_val in self.headers.items():
+ soc.send("%s: %s\r\n" % key_val)
+ soc.send("\r\n")
+ self._read_write(soc)
+ finally:
+ print "\t" "bye"
+ soc.close()
+ self.connection.close()
+
+ def _read_write(self, soc, max_idling=20):
+ iw = [self.connection, soc]
+ ow = []
+ count = 0
+ while True:
+ count += 1
+ (ins, _, exs) = select.select(iw, ow, iw, 3)
+ if exs:
+ break
+ if ins:
+ for i in ins:
+ if i is soc:
+ out = self.connection
+ else:
+ out = soc
+ data = i.recv(8192)
+ if data:
+ out.send(data)
+ count = 0
+ else:
+ print "\t" "idle", count
+ if count == max_idling:
+ break
+
+ do_HEAD = do_GET
+ do_POST = do_GET
+ do_PUT = do_GET
+ do_DELETE = do_GET
+
+class ThreadingHTTPServer (SocketServer.ThreadingMixIn,
+ BaseHTTPServer.HTTPServer):
+ def __init__(self, *args, **kwargs):
+ BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs)
+ a = open("proxy.pid", "w")
+ a.write(str(os.getpid()) + "\n")
+ a.close()
+
+if __name__ == '__main__':
+ from sys import argv
+ if argv[1:] and argv[1] in ('-h', '--help'):
+ print argv[0], "[port [allowed_client_name ...]]"
+ else:
+ if argv[2:]:
+ allowed = []
+ for name in argv[2:]:
+ client = socket.gethostbyname(name)
+ allowed.append(client)
+ print "Accept: %s (%s)" % (client, name)
+ ProxyHandler.allowed_clients = allowed
+ del argv[2:]
+ else:
+ print "Any clients will be served..."
+ BaseHTTPServer.test(ProxyHandler, ThreadingHTTPServer)