The unified diff between revisions [b954a1fc..] and [dd2f27b8..] is displayed below. It can also be downloaded as a raw diff.

#
#
# add_file "tests/t_cvsimport_branch.at"
#  content [d5bcc9ee933be0f2711d9e81f005dfbd8d1ca3e8]
#
# add_file "tests/t_db_kill_rev_locally_2.at"
#  content [296391166304e8c739fcc7968ae5f58a36b91265]
#
# add_file "tests/t_log_nofiles_merges.at"
#  content [958b5e4229b1afd2c7ec131d0a239b28d792815f]
#
# add_file "tests/t_log_to_file.at"
#  content [4a9ad6b478915e87c07d13d7d15b8bdb6ae0a92c]
#
# add_file "tests/t_revert_new_project.at"
#  content [ac8b9497aa5d1a89d01be066365bddb8b3889baf]
#
# patch "ChangeLog"
#  from [36ddfbc60c098baecae82e3be37bb02055100506]
#    to [e130fcd32c009c5f7ad8b31d5736aed3e9f67c09]
#
# patch "Makefile.am"
#  from [d4ad27fc9fa7d8d2b82c512a67adbd237b7fcca1]
#    to [380383c22ef6bb6b1d7203b215dbed739c249c63]
#
# patch "app_state.cc"
#  from [18045740e735562c70e3a482927003729014844f]
#    to [d6bd147ff69418001cff7cfd08e7ec18deca23ab]
#
# patch "app_state.hh"
#  from [7fa51b357c748547e5d71dbc84fb35077c148177]
#    to [7fb16348486ca507f22a99d6aca9ba2dc4a658c0]
#
# patch "commands.cc"
#  from [dbf77e72442ab85b8b4390b8fb1316ca8145d507]
#    to [8d15447176db8827209c2feeaaf0b0eaa7e2e1fd]
#
# patch "contrib/monotone.bash_completion"
#  from [d942f24e3f430c7e12fceeb7a58e088e45211971]
#    to [c5fff50c3c591f9dd72f80c3812c506571e3ab74]
#
# patch "contrib/usher.cc"
#  from [cb295e80eb1af0bd7d55cde7da973c340a05deb2]
#    to [599b754c575694458973cf7ecd5be5fd5a03c06d]
#
# patch "cset.cc"
#  from [ac5f2a4848a4c5661496ec4f5af706de1fb6a454]
#    to [a8497f9a82330f842cda2f242e97ef48e3a6b9fb]
#
# patch "cset.hh"
#  from [f2d58803ea89b51b5029a349c30acc3c6c3cf580]
#    to [7bd817258ac15fa2b6e4c3473e9b97858721969d]
#
# patch "database.cc"
#  from [2fc44fac19123c10272d86d0295b91f58a8ad6b1]
#    to [70d4d8f0c43de5e18bb023fc2c87805c0cdfa659]
#
# patch "enumerator.cc"
#  from [33a06c9ebfb955efb197f5eafb2e8d9beaee8a1d]
#    to [05baab83e8b397403e54ed13a6c514c81feb7b4f]
#
# patch "enumerator.hh"
#  from [1880dae7a6147b0ddd8064bfc4679334b520aeab]
#    to [5cc476581aed97dd306843e60c057ab1053cf0da]
#
# patch "lua.cc"
#  from [8284c5010bee38f15141c3e60eeeeb7c288ee20c]
#    to [a9045fcf6d8283a12a96f422b79fb54ae2da727c]
#
# patch "lua.hh"
#  from [a682ec35ee70ef30fd080616f8f21d8ef2a1a6ea]
#    to [5691c7c116dc402741a8a9ba7f5ab7d2ebe7b2e0]
#
# patch "monotone.cc"
#  from [92399bda2cd0fba92739636d7b0955c1c43bea23]
#    to [6626e22d6ef4d9c8d3380a2f498599dd57bc6d3d]
#
# patch "monotone.texi"
#  from [355d07f84caee318dd69f37ff6274842ca2d2c70]
#    to [1fcc35f2ac3ca9ba692509cd29f6f5ff01b6616a]
#
# patch "netsync.cc"
#  from [8d4dc8e530af4fb0a6cca30ca600dd74f905b1aa]
#    to [0edebb049f6f44132b6c97be4663efc113efeee8]
#
# patch "options.hh"
#  from [6dc48543e2cb20ea82ded241dc5bb6088c3cb09c]
#    to [16194449c59ae0307ab9bbf15ae879f0f8063fdd]
#
# patch "po/sv.po"
#  from [754e90276863a8b1a53cad17c575bb93ffcdd5b4]
#    to [e065ecfd2c28c0ea89877c3c95ceeae23190b320]
#
# patch "roster.cc"
#  from [4547e72b235da17471b9781c3416e7eac2904027]
#    to [5313de9037e0af779b593f9f432155891a70374a]
#
# patch "roster.hh"
#  from [0f6d33d17d3d1c804be21f2e8025d86e47f087f9]
#    to [0647777b7cab5a2c17419998351f049eadc706d5]
#
# patch "roster_merge.cc"
#  from [4dec4aecf9c67f0ba369c9430bb492a3d93170bf]
#    to [aa38469bceafec9e94d2ba9c291cf08d6fc90e06]
#
# patch "roster_merge.hh"
#  from [e9c290f799091e5ecb70e291daae0bff72df2d48]
#    to [9227745f9aeb67c68ca363dc1df62537c8bcb873]
#
# patch "sanity.cc"
#  from [b31758131617cacbc373a95c25cab49e15ffedc3]
#    to [36f79a9ba2cf13f0f96eb85a36ee0ca1619c39df]
#
# patch "sanity.hh"
#  from [3d91a4abd21f2af06ea78724a922b3b52fa0838f]
#    to [88009f27365f17c86b8dd104021fbcc1cc08a497]
#
# patch "sqlite/alter.c"
#  from [faf98b04050d674d06df21bcf23ded5bbff7b5b7]
#    to [451b34fc4eb2475ca76a2e86b21e1030a9428091]
#
# patch "sqlite/btree.c"
#  from [f45f57e6cbd3b3db947cdd699db64e5215d20b2a]
#    to [23bbfb4745e549ca224f6c933a6e9bc106d77f56]
#
# patch "sqlite/btree.h"
#  from [5663c4f43e8521546ccebc8fc95acb013b8f3184]
#    to [40055cfc09defd1146bc5b922399c035f969e56d]
#
# patch "sqlite/build.c"
#  from [feaa61e769d7887ffeaa060d746638c7b3e994ef]
#    to [b46cd7d0e2daca775d9de0cba8abae1b1625caf4]
#
# patch "sqlite/date.c"
#  from [c70a4f88e495ae2c523f6ef3848c26a021c96de8]
#    to [cd2bd5d1ebc6fa12d6312f69789ae5b0a2766f2e]
#
# patch "sqlite/delete.c"
#  from [56ab34c3a384caa5d5ea06f5739944957e2e4213]
#    to [ca404d5fd5f678e32f2f46377ad802cd0219aa99]
#
# patch "sqlite/expr.c"
#  from [1149c3380bfce27703f5e9bec7dfb8e51baaf9d9]
#    to [9c957fabf95ef62288151eecd5c490a629470666]
#
# patch "sqlite/func.c"
#  from [96b26601c092b7b43a13e440e3f988b32a385f6a]
#    to [93d004b453a5d9aa754e673eef75d3c9527e0f54]
#
# patch "sqlite/insert.c"
#  from [7e931b7f06afbcefcbbaab175c02eff8268db33f]
#    to [67b3dc11831c58d8703eb502355ad3704ee18f66]
#
# patch "sqlite/main.c"
#  from [2693776249865dc69b97904205638e84a34a059c]
#    to [9a42464c44a6532003391486e802e65e88789cfc]
#
# patch "sqlite/os_common.h"
#  from [061fba8511a656b118551424f64e366ad0d4cb3b]
#    to [108cd719c96a2b714b64e02aeabbd40684274e6a]
#
# patch "sqlite/os_unix.c"
#  from [73c5e722a661ed98d8919f204911e4e34e51fa41]
#    to [378a89aaf15d83b901c1b73350e91ddecf743986]
#
# patch "sqlite/os_win.c"
#  from [566bf7b41b72556fd7dca390bceaa2769dc395e9]
#    to [c67a2c46d929cf54c8f80ec5e6079cf684a141a9]
#
# patch "sqlite/pager.c"
#  from [b5b380ea7a36f84e50c3adc1a414820a0eb3baa6]
#    to [c438aa5fc248e0523e80591eeae33a3993c47278]
#
# patch "sqlite/pager.h"
#  from [e0acb095b3ad0bca48f2ab00c87346665643f64f]
#    to [425a9e52d5404158de016799715cbc2c3d685178]
#
# patch "sqlite/parse.c"
#  from [a31a0cb5fd9be3781389e4b2784b197d03226dc4]
#    to [56d45a7fd03e7c499e1a0bacb81916956b9ec8d7]
#
# patch "sqlite/pragma.c"
#  from [4496cc77dc35824e1c978c3d1413b8a5a4c777d3]
#    to [31d3e1b74cab2172807894e70c674d6a577501fd]
#
# patch "sqlite/prepare.c"
#  from [40ae23c8aeb641dc7b9bb271eb5e295b815154a7]
#    to [cf0fc8ebaf94409955ecb09ffeb0099c9ef44693]
#
# patch "sqlite/select.c"
#  from [daee9b20702ba51cf3807fc1b130edd8846e3e48]
#    to [7d069e875d0eec05129c7e8b9c99422d7c9c6321]
#
# patch "sqlite/sqlite3.h"
#  from [6b9ed927e0a9a3c6051a372929c97c2ac87ab314]
#    to [d0605a62334179d9c38bf587ac38b777d6daee2b]
#
# patch "sqlite/sqliteInt.h"
#  from [0121298397ac14eb468ab1ba9d488ac7ed7d88a1]
#    to [f61b60f243f1709c943c62cfb6d7a50209080e38]
#
# patch "sqlite/table.c"
#  from [486dcfce532685b53b5a2b5da8bba0ded6fb2316]
#    to [f64ec4fbfe333f8df925bc6ba494f55e05b0e75e]
#
# patch "sqlite/tokenize.c"
#  from [9ae9a59238eb97fbc61baea280563b91100518fb]
#    to [382b3bb0ca26eb9153b5d20b246ef512a114a24f]
#
# patch "sqlite/update.c"
#  from [14be4ba2f438919b4217085c02feff569e6cf1f2]
#    to [050a7e0ddaac03dec5271712eee62f1a9e699049]
#
# patch "sqlite/util.c"
#  from [82ee598519b8193184bdeab06b51a4ffa05ad60b]
#    to [405f46fef062b476826d2c171ec21def29563b75]
#
# patch "sqlite/vdbe.c"
#  from [fee677e05236e483d6c75d1d4229955fc1b89193]
#    to [0a7fd81609429bae2b3c326687b02a60a9c01c49]
#
# patch "sqlite/vdbe.h"
#  from [8729a4ee16ff9aeab2af9667df3cf300ff978e13]
#    to [80ba1c391ec28180dd07a630577f50b22c2062da]
#
# patch "sqlite/vdbeapi.c"
#  from [dcb2636f49b4807e34960d52a2fc257b3a751140]
#    to [7dc662e7c905ce666bb506dced932e0307115cbf]
#
# patch "sqlite/vdbeaux.c"
#  from [9bf50cdb6a6c40b8c06ca9a8d87cf90120a16797]
#    to [95f4ed0bc8ed45f16823d84504310495b5dc587d]
#
# patch "sqlite/where.c"
#  from [8409e00fa2cb5fce873b4c911165cfed097e9c49]
#    to [c7d71d5e55c9c4c1e948089280fb0dec7c7d1ef6]
#
# patch "std_hooks.lua"
#  from [8f01e338e8056c62de500694210fd22dacac6122]
#    to [87a925a89f17ae312390049e28296bbb9f7ee170]
#
# patch "test_hooks.lua"
#  from [391ca756f0e4bd4325ffba83caf9a698b1713e23]
#    to [c8ca29aac8840285176dc56724352917a3b52bf2]
#
# patch "tests/t_netsync_permissions.at"
#  from [9a8356b76404d50e044f74e5f59d6e055ad64d1e]
#    to [14dc033954a1e36979893b0f9b4d5daf4be18b82]
#
# patch "testsuite.at"
#  from [7f433b14b3bd2a67eeacc49577a64e35d97ed02f]
#    to [c8be08d87b48f90c833c326e708aaa06423b1b75]
#
# patch "ui.cc"
#  from [f412b8a06dfed701085469c14e62e359369469cf]
#    to [7bef43275fba7bdf4c2dc03ee191776dc2a57834]
#
# patch "ui.hh"
#  from [496479433aee1e5ff51e96a22ae7cb662d71c4b8]
#    to [5a1e338407beeda0b373e5296d9106d4a6d9f35f]
#
# patch "unit_tests.cc"
#  from [cd6c9924afd3ab76ba8bfb91ff23990f3a1cc565]
#    to [5f4e6b96f89134edb6d35c799b26932587dc3679]
#
# patch "unit_tests.hh"
#  from [b2611fdb586f062e99b396dd5985db3b1f884360]
#    to [1f0dbf6a811b8bcb25b0a0071239cf7809867037]
#
# patch "work.cc"
#  from [265e6d058be85a58414c208164fbe9592b1d3e74]
#    to [39e5c9ecd7f5209dbcbb7e631d6fc044296a4a67]
#
# patch "work.hh"
#  from [723c827976adf80b589df8c0e2629ed7fafb907e]
#    to [2e87d93b08c16ef877483f69594636c480d0f97f]
#
============================================================
--- tests/t_cvsimport_branch.at	d5bcc9ee933be0f2711d9e81f005dfbd8d1ca3e8
+++ tests/t_cvsimport_branch.at	d5bcc9ee933be0f2711d9e81f005dfbd8d1ca3e8
@@ -0,0 +1,127 @@
+#  -*- Autoconf -*-
+
+AT_SETUP([importing CVS branches with correct ancestory])
+
+MONOTONE_SETUP
+
+AT_XFAIL_IF(true)
+
+AT_DATA(file1.0, [version 0 of test file1
+])
+
+AT_DATA(file1.1, [version 1 of test file1
+])
+
+AT_DATA(file1.2, [version 2 of test file1
+])
+
+AT_DATA(file2.0, [version 0 of test file2
+])
+
+AT_DATA(file2.1, [version 1 of test file2
+])
+
+AT_DATA(changelog.0, [first changelog entry
+])
+
+AT_DATA(changelog.1, [second changelog
+
+first changelog entry
+])
+
+AT_DATA(changelog.2, [third changelog -not on branch-
+
+second changelog
+
+first changelog entry
+])
+
+AT_DATA(changelog.3, [third changelog -on branch-
+
+second changelog
+
+first changelog entry
+])
+
+AT_DATA(branchlist, [test
+test.branched
+])
+
+F1SHA0=`SHA1(file1.0)`
+F1SHA1=`SHA1(file1.1)`
+F1SHA2=`SHA1(file1.2)`
+F2SHA0=`SHA1(file2.0)`
+T2SHA1=`SHA1(file2.1)`
+CSHA0=`SHA1(changelog.0)`
+CSHA1=`SHA1(changelog.1)`
+CSHA2=`SHA1(changelog.2)`
+CSHA3=`SHA1(changelog.3)`
+
+# build the cvs repository
+
+CVSROOT=`pwd`/cvs-repository
+AT_CHECK(cvs -q -d $CVSROOT init, [0], [ignore], [ignore])
+AT_CHECK(test -e $CVSROOT)
+AT_CHECK(test -e $CVSROOT/CVSROOT)
+AT_CHECK(test -e $CVSROOT/CVSROOT/modules)
+
+# checkout the empty repository and commit some files
+
+AT_CHECK(cvs -d $CVSROOT co ., [], [ignore], [ignore])
+AT_CHECK(mkdir testdir)
+AT_CHECK(cp file1.0 testdir/file1)
+AT_CHECK(cp file2.0 testdir/file2)
+AT_CHECK(cp changelog.0 testdir/changelog)
+AT_CHECK(cvs -d $CVSROOT add testdir, [], [ignore], [ignore])
+AT_CHECK(cvs -d $CVSROOT add testdir/file1, [], [ignore], [ignore])
+AT_CHECK(cvs -d $CVSROOT add testdir/file2, [], [ignore], [ignore])
+AT_CHECK(cvs -d $CVSROOT add testdir/changelog, [], [ignore], [ignore])
+AT_CHECK(cvs -d $CVSROOT commit -m 'initial import' testdir/file1 testdir/file2 testdir/changelog, [], [ignore], [ignore])
+
+# commit first changes
+AT_CHECK(cp file1.1 testdir/file1)
+AT_CHECK(cp changelog.1 testdir/changelog)
+AT_CHECK(cvs -d $CVSROOT commit -m 'first commit' testdir/file1 testdir/changelog, [], [ignore], [ignore])
+
+# now we create a branch
+AT_CHECK(cd testdir; cvs -d $CVSROOT tag -b branched, [], [ignore], [ignore])
+AT_CHECK(cd testdir; cvs -d $CVSROOT up -r branched, [], [ignore], [ignore])
+
+# alter the files on the branch
+AT_CHECK(cp file2.1 testdir/file2)
+AT_CHECK(cp changelog.3 testdir/changelog)
+AT_CHECK(cvs -d $CVSROOT commit -m 'commit on branch' testdir/file2 testdir/changelog, [], [ignore], [ignore])
+
+# and create some mainline changes after the branch
+AT_CHECK(cvs -d $CVSROOT up -A, [], [ignore], [ignore])
+AT_CHECK(cp file1.2 testdir/file1)
+AT_CHECK(cp changelog.2 testdir/changelog)
+AT_CHECK(cvs -d $CVSROOT commit -m 'commit on mainline after branch' testdir/file1 testdir/changelog, [], [ignore], [ignore])
+
+# import into monotone and check presence of files
+AT_CHECK(MONOTONE --branch=test cvs_import $CVSROOT/testdir, [], [ignore], [ignore])
+
+# check if all branches were imported
+AT_CHECK(MONOTONE list branches, [], [stdout], [ignore])
+AT_CHECK(cmp stdout branchlist)
+
+# checkout the imported repository into maindir and branchdir
+AT_CHECK(MONOTONE checkout --branch=test maindir, [], [ignore], [ignore])
+AT_CHECK(MONOTONE checkout --branch=test.branched branchdir, [], [ignore], [ignore])
+
+# check for correctness of the files in the main tree
+AT_CHECK(cmp file1.2 maindir/file1)
+AT_CHECK(cmp file2.0 maindir/file2)
+AT_CHECK(cmp changelog.2 maindir/changelog)
+
+# check for correctness of the files in the branch
+AT_CHECK(cmp file1.1 branchdir/file1)
+AT_CHECK(cmp file2.1 branchdir/file2)
+AT_CHECK(cmp changelog.3 branchdir/changelog)
+
+# get the log of the branch to check for correct branchpoint
+AT_CHECK(cd branchdir; MONOTONE log, [], [stdout], [ignore])
+AT_CHECK(grep "commit on branch" stdout, [], [ignore], [ignore])
+AT_CHECK(grep "initial import" stdout, [], [ignore], [ignore])
+
+AT_CLEANUP
============================================================
--- tests/t_db_kill_rev_locally_2.at	296391166304e8c739fcc7968ae5f58a36b91265
+++ tests/t_db_kill_rev_locally_2.at	296391166304e8c739fcc7968ae5f58a36b91265
@@ -0,0 +1,32 @@
+AT_SETUP([db kill_rev_locally command 2])
+MONOTONE_SETUP
+
+# start off with three revisions
+ADD_FILE(testfile, [blah blah
+])
+COMMIT(testbranch)
+ANCESTOR=`BASE_REVISION`
+
+SET_FILE(testfile, [stuff stuff
+])
+COMMIT(testbranch)
+CHILD1=`BASE_REVISION`
+
+SET_FILE(testfile, [blahdy blah blay
+])
+COMMIT(testbranch)
+CHILD2=`BASE_REVISION`
+
+# kill head revision
+AT_CHECK(MONOTONE automate get_revision $CHILD2, [], [ignore], [ignore])
+AT_CHECK(MONOTONE db kill_rev_locally $CHILD2, [], [ignore], [ignore])
+AT_CHECK(MONOTONE automate get_revision $CHILD2, [1], [ignore], [ignore])
+AT_CHECK(MONOTONE db check, [], ignore, ignore)
+
+# head is an older revision now, let's kill that too
+AT_CHECK(MONOTONE automate get_revision $CHILD1, [], [ignore], [ignore])
+AT_CHECK(MONOTONE db kill_rev_locally $CHILD1, [], [ignore], [ignore])
+AT_CHECK(MONOTONE automate get_revision $CHILD1, [1], [ignore], [ignore])
+AT_CHECK(MONOTONE db check, [], ignore, ignore)
+
+AT_CLEANUP
============================================================
--- tests/t_log_nofiles_merges.at	958b5e4229b1afd2c7ec131d0a239b28d792815f
+++ tests/t_log_nofiles_merges.at	958b5e4229b1afd2c7ec131d0a239b28d792815f
@@ -0,0 +1,41 @@
+AT_SETUP([log --no-files and --merges])
+MONOTONE_SETUP
+
+ADD_FILE(testfile, [blah blah
+])
+COMMIT(testbranch)
+R1=`BASE_REVISION`
+
+# check that changed (added) file is listed in the log output
+AT_CHECK(MONOTONE log, [], [stdout], [ignore])
+AT_CHECK(grep testfile stdout, [], [ignore])
+
+# and that it has been excluded by --no-files
+AT_CHECK(MONOTONE log --no-files, [], [stdout], [ignore])
+AT_CHECK(grep testfile stdout, [1], [ignore])
+
+# add create some divergence...
+SET_FILE(testfile, [stuff stuff
+])
+COMMIT(testbranch)
+
+REVERT_TO($R1)
+
+ADD_FILE(nufile, [moo moo
+])
+COMMIT(testbranch)
+
+# ...and now merge it cleanly
+AT_CHECK(MONOTONE merge, [], [ignore], [ignore])
+AT_CHECK(MONOTONE update, [], [ignore], [ignore])
+R2=`BASE_REVISION`
+
+# check that merge is excluded from log output
+AT_CHECK(MONOTONE log, [], [stdout], [ignore])
+AT_CHECK(grep '^Revision' stdout | grep $R2, [1], [ignore])
+
+# and that it has been included by --merges
+AT_CHECK(MONOTONE log --merges, [], [stdout], [ignore])
+AT_CHECK(grep '^Revision' stdout | grep $R2, [], [ignore])
+
+AT_CLEANUP
============================================================
--- tests/t_log_to_file.at	4a9ad6b478915e87c07d13d7d15b8bdb6ae0a92c
+++ tests/t_log_to_file.at	4a9ad6b478915e87c07d13d7d15b8bdb6ae0a92c
@@ -0,0 +1,17 @@
+# -*- Autoconf -*-
+
+AT_SETUP([check --log])
+
+MONOTONE_SETUP
+
+AT_DATA(input.txt, [random content
+])
+
+AT_CHECK(MONOTONE add input.txt, [], [ignore], [ignore])
+
+AT_CHECK(MONOTONE --branch=testbranch --log=log.log commit -m "test", [], [stdout], [ignore])
+
+AT_CHECK(QGREP('^monotone:' stdout), [1])
+AT_CHECK(QGREP('^monotone:' log.log), [0])
+
+AT_CLEANUP
============================================================
--- tests/t_revert_new_project.at	ac8b9497aa5d1a89d01be066365bddb8b3889baf
+++ tests/t_revert_new_project.at	ac8b9497aa5d1a89d01be066365bddb8b3889baf
@@ -0,0 +1,32 @@
+#  -*- Autoconf -*-
+
+AT_SETUP([revert file in new project])
+
+AT_XFAIL_IF(true)
+
+MONOTONE_SETUP
+
+
+# reverting one of one files
+AT_DATA(testfile0, [version 0 of first test file
+])
+
+AT_CHECK(MONOTONE add testfile0, [], [ignore], [ignore])
+AT_CHECK(MONOTONE revert testfile0, [], [ignore], [ignore])
+AT_CHECK(MONOTONE status, [], [stdout], [ignore])
+AT_CHECK(grep testfile0 stdout, [1], [ignore])
+
+
+# reverting one of two files
+AT_DATA(testfile0, [version 0 of first test file
+])
+AT_DATA(testfile1, [version 0 of second test file
+])
+
+AT_CHECK(MONOTONE add testfile0 testfile1, [], [ignore], [ignore])
+AT_CHECK(MONOTONE revert testfile0, [], [ignore], [ignore])
+AT_CHECK(MONOTONE status, [], [stdout], [ignore])
+AT_CHECK(grep testfile0 stdout, [1], [ignore])
+
+
+AT_CLEANUP
============================================================
--- ChangeLog	36ddfbc60c098baecae82e3be37bb02055100506
+++ ChangeLog	e130fcd32c009c5f7ad8b31d5736aed3e9f67c09
@@ -1,3 +1,224 @@
+2006-02-23  Matt Johnston  <matt@ucc.asn.au>
+
+	* enumerator.{cc,hh}: avoid transferring deltas on both sides of merge
+	revisions, and prefer deltas to data when both are available.
+	See
+	https://savannah.nongnu.org/bugs/?func=detailitem&item_id=15846
+
+2006-02-21  Nathaniel Smith  <njs@pobox.com>
+
+	* work.cc (detach_node): This time for sure!
+
+2006-02-21  Nathaniel Smith  <njs@pobox.com>
+
+	* work.cc (detach_node): Oops, x != y != !(x == y).
+
+2006-02-21  Nathaniel Smith  <njs@pobox.com>
+
+	* work.cc (detach_node): Check if we are passed the root dir, and
+	error out if so.
+
+2006-02-21  Matt Johnston  <matt@ucc.asn.au>
+
+	* commands.cc (pid_file): newline-terminate the pid
+
+2006-02-21  Richard Levitte  <richard@levitte.org>
+
+	* contrib/usher.cc (server::set_hosts): Erasing the list node that
+	we're iterating on, then trying to go to the next node doesn't
+	work.  Save the iterator, then increment it before erasing the
+	node using the saved value.  No more segfaults.
+
+2006-02-21  Matthew Gregan  <kinetik@orcon.net.nz>
+
+	* sanity.hh: Work around roster_merge.cc compilation failure with
+	GCC 3.4.
+
+2006-02-20  Richard Levitte  <richard@levitte.org>
+
+	* monotone.cc (cpp_main), options.hh, ui.cc (redirect_log_to),
+	ui.hh (struct user_interface): Add --log option, to redirect the
+	log lines to a file.
+
+	* monotone.texi (OPTIONS): Document it.
+
+	* po/sv.po: Translate help for this option to Swedish.
+
+	* testsuite.at, tests/t_log_to_file.at: Test it.
+
+2006-02-20  Matt Johnston  <matt@ucc.asn.au>
+
+	* database.cc (remove_version): get rid of dangling deltas,
+	don't try to put data or deltas if they already exist.
+	* tests/t_db_kill_rev_locally_2.at: un-XFAIL
+
+2006-02-20  Matthew Gregan  <kinetik@orcon.net.nz>
+
+	* testsuite.at: Add an ADD_FILE variant that allows use of
+	alternate databases.
+
+	* tests/t_netsync_permissions.at: Missed some cases of the
+	database locking race.
+
+2006-02-19  Nathaniel Smith  <njs@pobox.com>
+
+	* ChangeLog: Fixup after xxdiff lossage.
+
+2006-02-19  Nathaniel Smith  <njs@pobox.com>
+
+	* roster_merge.cc (make_lifecycle_objs): Fix test bug.
+
+2006-02-19  Matthew Gregan  <kinetik@orcon.net.nz>
+
+	* testsuite.at: Add a REVERT_TO variant that allows use of
+	alternate databases.
+
+	* tests/t_netsync_permissions.at: Attempt to avoid a database
+	locking race in this test that is causing spurious failures by
+	using the new REVERT_TO variant to cause revert to be performed
+	using the "client" database.
+
+2006-02-19  Nathaniel Smith  <njs@pobox.com>
+
+	* roster.cc (shallow_equal): Publically expose.
+	* roster.cc, roster_merge.cc: Various compile fixes.
+
+2006-02-19  Nathaniel Smith  <njs@pobox.com>
+
+	* roster_merge.{hh,cc}: Make terminology more consistent.
+	"marking_map" type -> "markings" name, "marking_t" type ->
+	"marking" name.
+
+2006-02-19  Nathaniel Smith  <njs@pobox.com>
+
+	* roster.{hh,cc} (testing_node_id_source): Make this node source
+	available to unit tests in other files.
+	* roster_merge.cc (test_roster_merge_node_lifecycle): New test.
+	Still quite ugly.
+
+2006-02-18  Nathaniel Smith  <njs@pobox.com>
+
+	* roster_merge.cc (roster_merge): Remove obsolete FIXME.
+
+2005-10-19  Matthew A. Nicholson  <matt@matt-land.com>
+
+	* contrib/monotone.bash_completion: Update for 0.25.
+
+2006-02-19  Matthew Gregan  <kinetik@orcon.net.nz>
+
+	* cset.hh (struct editable_tree): Add commit() member function to
+	editable_tree.
+
+	* cset.cc (cset::apply_to): Call editable_tree::commit() after
+	applying any other changes.
+
+	* roster.hh, roster.cc: Empty implementation of
+	editable_roster_base::commit().
+
+	* work.hh, work.cc: Implementation of
+	editable_working_tree::commit() that ensures all detached nodes
+	have been reattached.
+
+	* work.hh (struct editable_working_tree): Add map for tracking
+	path name mappings across node detach operations.
+
+	* work.cc (editable_working_tree::detach_node): Insert path name
+	mappings into map.
+	(editable_working_tree::drop_detached_node,
+	editable_working_tree::attach_node): Report add/drop/rename
+	operations during workspace updates.
+
+	* lua.cc: Use the safer luaL_check* rather than lua_to* in
+	monotone_*_for_lua functions.
+
+2006-02-18  Markus Schiltknecht  <markus@bluegap.ch>
+
+	* tests/t_cvsimport_branch.at, testsuite.at: New XFAIL test for
+	cvs_import branch reconstruction.
+
+2006-02-18  Matthew Gregan  <kinetik@orcon.net.nz>
+
+	* tests/t_log_nofiles_merges.at: Add test for the log options
+	--no-files and --merges.
+
+	* testsuite.at: Add t_log_nofiles_merges.at.
+
+2006-02-13  Nathaniel Smith  <njs@pobox.com>
+
+	* roster_merge.cc (log_conflicts): Tweak string.
+	Add list of tests needed.
+
+2006-02-13  Nathaniel Smith  <njs@pobox.com>
+
+	* roster_merge.cc (is_clean): Simplify.
+	(add_roster_merge_tests):
+	* unit_tests.cc (init_unit_test_suite):
+	* unit_tests.hh (add_roster_merge_tests): Add unit test
+	boilerplate.
+
+2006-02-18  Matthew Gregan  <kinetik@orcon.net.nz>
+
+	* tests/t_db_kill_rev_locally_2.at: Add an XFAIL test for a
+	kill_rev_locally bug reported by Daniel Carosone.
+
+	* testsuite.at: Add t_db_kill_rev_locally_2.at.
+
+	* sqlite/parse.h: Regenerated parse.h from pristine SQLite 3.3.4
+	source.  The version committed in the 3.3.4 import had a bunch of
+	duplicate entries.
+
+	* commands.cc (CMD(identify)): This isn't really a "workspace"
+	command--stick it under "debug" for lack of a better place.
+
+	* commands.cc (CMD(refresh_inodeprints)): Check for a valid
+	workspace rather than failing with an invariant when run outside
+	of a workspace.
+
+	* tests/t_revert_new_project.at: Add an XFAIL test for a bug where
+	reverting a file added in a new project will leave the workspace
+	in a bad state until MT/work is removed manually.
+
+	* testsuite.at: Add t_revert_new_project.at.
+
+	* app_state.cc, app_state.hh, commands.cc, monotone.cc,
+	options.hh: Add '--no-files' option to log to allow users to
+	exclude the list of files changed in each revision from the log
+	output.
+
+	* monotone.texi: Document '--no-files', and '--next' and '--diffs'
+	while there.
+
+2006-02-17  Matthew Gregan  <kinetik@orcon.net.nz>
+
+	* lua.cc, lua.hh, monotone.texi, std_hooks.lua, test_hooks.lua,
+	testsuite.at: Remove unused non_blocking_rng_ok hook.
+
+	* sqlite/*: Import SQLite 3.3.4.
+
+2006-02-16  Patrick Mauritz  <oxygene@studentenbude.ath.cx>
+
+	* netsync.cc (handle_new_connection): Netxx::Address.get_name()
+	returns NULL every now and then. if so, continue with "" instead
+
+	* sqlite/parse.c: move #line under all #include directives so
+	the compiler can't be confused by it.
+
+2006-02-14  Richard Levitte  <richard@levitte.org>
+
+	* Makefile.am (htmldir): Add variables so monotone.html is created
+	and installed automatically.
+	This is prompted by debian/monotone.html, which indicates
+	monotone.html should be available.
+
+	* netsync.cc (serve_connections): Correct spelling.
+
+2006-02-13  Matthew Gregan  <kinetik@orcon.net.nz>
+
+	* sanity.cc (sanity::dump_buffer): Fix a SEGV when we're in an
+	error unwind and about to ask the user to mail us the crash
+	log--we must use FL() rather than F() here, since by the time this
+	is called we can't rely on the i18n infrastructure being alive.
+
 2006-02-12  Nathaniel Smith  <njs@pobox.com>

 	* netsync.cc (serve_connections): Revert garbage that I
============================================================
--- Makefile.am	d4ad27fc9fa7d8d2b82c512a67adbd237b7fcca1
+++ Makefile.am	380383c22ef6bb6b1d7203b215dbed739c249c63
@@ -241,6 +241,9 @@ lib3rdparty_a_SOURCES = $(BOOST_SANDBOX_
 			$(LUA_SOURCES) \
 			$(SQLITE_SOURCES)

+htmldir = $(datadir)/doc/monotone
+html_DATA = monotone.html
+
 # flags

 if BUILD_PCH
============================================================
--- app_state.cc	18045740e735562c70e3a482927003729014844f
+++ app_state.cc	d6bd147ff69418001cff7cfd08e7ec18deca23ab
@@ -36,7 +36,7 @@ app_state::app_state()
     depth(-1), last(-1), next(-1), diff_format(unified_diff), diff_args_provided(false),
     use_lca(false), execute(false), bind_address(""), bind_port(""),
     missing(false), unknown(false),
-    confdir(get_default_confdir()), have_set_key_dir(false)
+    confdir(get_default_confdir()), have_set_key_dir(false), no_files(false)
 {
   db.set_app(this);
   lua.set_app(this);
============================================================
--- app_state.hh	7fa51b357c748547e5d71dbc84fb35077c148177
+++ app_state.hh	7fb16348486ca507f22a99d6aca9ba2dc4a658c0
@@ -73,6 +73,7 @@ public:
   system_path confdir;
   bool have_set_key_dir;
   std::set<std::string> attrs_to_drop;
+  bool no_files;

   std::map<int, bool> explicit_option_map;  // set if the value of the flag was explicitly given on the command line
   void set_is_explicit_option (int option_id);
============================================================
--- commands.cc	dbf77e72442ab85b8b4390b8fb1316ca8145d507
+++ commands.cc	8d15447176db8827209c2feeaaf0b0eaa7e2e1fd
@@ -300,7 +300,7 @@ struct pid_file
       return;
     require_path_is_nonexistent(path, F("pid file '%s' already exists") % path);
     file.open(path.as_external().c_str());
-    file << get_process_id();
+    file << get_process_id() << endl;
     file.flush();
   }

@@ -1339,7 +1339,7 @@ CMD(status, N_("informative"), N_("[PATH
 }


-CMD(identify, N_("workspace"), N_("[PATH]"),
+CMD(identify, N_("debug"), N_("[PATH]"),
     N_("calculate identity of PATH or stdin"),
     OPT_NONE)
 {
@@ -3219,6 +3219,7 @@ CMD(refresh_inodeprints, N_("tree"), "",
 CMD(refresh_inodeprints, N_("tree"), "", N_("refresh the inodeprint cache"),
     OPT_NONE)
 {
+  app.require_workspace();
   enable_inodeprints();
   maybe_update_inodeprints(app);
 }
@@ -3541,7 +3542,8 @@ CMD(log, N_("informative"), N_("[FILE] .
 CMD(log, N_("informative"), N_("[FILE] ..."),
     N_("print history in reverse order (filtering by 'FILE'). If one or more\n"
     "revisions are given, use them as a starting point."),
-    OPT_LAST % OPT_NEXT % OPT_REVISION % OPT_BRIEF % OPT_DIFFS % OPT_MERGES)
+    OPT_LAST % OPT_NEXT % OPT_REVISION % OPT_BRIEF % OPT_DIFFS % OPT_MERGES %
+    OPT_NO_FILES)
 {
   if (app.revision_selectors.size() == 0)
     app.require_workspace("try passing a --revision to start at");
@@ -3716,7 +3718,7 @@ CMD(log, N_("informative"), N_("[FILE] .
                 log_certs(app, rid, branch_name, "Branch: ", false);
                 log_certs(app, rid, tag_name,    "Tag: ",    false);

-                if (! csum.cs.empty())
+                if (!app.no_files && !csum.cs.empty())
                   {
                     cout << endl;
                     csum.print(cout, 70);
============================================================
--- contrib/monotone.bash_completion	d942f24e3f430c7e12fceeb7a58e088e45211971
+++ contrib/monotone.bash_completion	c5fff50c3c591f9dd72f80c3812c506571e3ab74
@@ -1,7 +1,9 @@
 # -*- shell-script -*-
+# vim: set ft=sh:

-# bash completion for monotone 0.18
+# bash completion for monotone 0.25
 # Author: Olivier Andrieu <oandrieu@nerim.net>
+# Contributions by Matthew A. Nicholson <matt@matt-land.com>

 # source this file from your .bashrc
 # If you use the bash completion package <http://www.caliban.org/bash/>,
@@ -42,6 +44,10 @@ _monotone_branches() {
   COMPREPLY=( $(compgen -W "$(monotone $mono_db list branches 2> /dev/null)" -- ${cur#*=} ) )
 }

+_monotone_tags() {
+  COMPREPLY=( $(compgen -W "$(monotone $mono_db list tags 2> /dev/null | awk '{print $1}')" -- ${cur#*=} ) )
+}
+
 _monotone() {
   local cur prev mono_db

@@ -68,6 +74,10 @@ _monotone() {
       cur="${cur#*=}"
       _filedir
       ;;
+    --root=* )
+      cur="${cur#*=}"
+      _filedir -d
+      ;;
     --branch=* )
       _monotone_branches
       ;;
@@ -76,19 +86,22 @@ _monotone() {
       ;;
     --ticker=* )
       cur="${cur#*=}"
-      COMPREPLY=( $(compgen -W 'count dot' -- $cur ) )
+      COMPREPLY=( $(compgen -W 'count dot none' -- $cur ) )
       ;;
     --revision=* )
       _monotone_complete revision
       ;;
     -* )
-      COMPREPLY=( $(compgen -W '--debug --dump --quiet --help --nostd --norc\
-                                --rcfile --key --db --branch --version --full-version\
-                                --ticker --revision --message' -- $cur) )
+      COMPREPLY=( $(compgen -W '--debug --dump --quiet --help --version
+                                --full-version --xargs --ticker --nostd --norc
+                                --rcfile --key --db --root --verbose -k -d -@
+                                -m -b -r --branch --message --date --author
+                                --depth --execute --keydir --confdir
+                                --key-to-push --bind' -- $cur) )
       ;;
     * )
       case $prev in
-        --db | -d | --rcfile | --dump )
+        --db | -d | --rcfile | --dump | --root )
           _filedir
           ;;
         --branch | -b )
@@ -103,105 +116,112 @@ _monotone() {
         --revision | -r )
           _monotone_complete revision
           ;;
-	db )
-	  COMPREPLY=( $(compgen -W 'init info version dump load migrate execute check changesetify rebuild' -- $cur ) )
-	  ;;
-	cdiff | diff | annotate )
+        db )
+          COMPREPLY=( $(compgen -W 'init info version dump load migrate execute kill_rev_locally kill_branch_certs_locally kill_tag_locally check changesetify rebuild set_epoch' -- $cur ) )
+          ;;
+        cdiff | diff | annotate )
           COMPREPLY=( $(compgen -W '--revision' -- $cur ) )
-	  _filedir
-	  ;;
-	log | approve | disapprove | comment | tag | testresult | cert | explicit_merge | trusted | update )
-	  _monotone_complete revision
-	  ;;
-	ls | list )
-	  COMPREPLY=( $(compgen -W 'certs keys branches epochs tags vars known unknown ignored missing' -- $cur ) )
-	  ;;
-	attr )
-	  COMPREPLY=( $(compgen -W 'get set drop' -- $cur ) )
-	  ;;
-	co | checkout )
-	  _filedir -d
-	  _monotone_complete revision
-	  ;;
-	status | cvs_import | add | drop | rename | revert | identify )
-	  _filedir
-	  ;;
-	cat )
-	  COMPREPLY=( $(compgen -W 'file manifest revision' -- $cur) )
-	  ;;
+          _filedir
+          ;;
+        log | approve | disapprove | comment | tag | testresult | cert | explicit_merge | trusted | update )
+          _monotone_complete revision
+          ;;
+        ls | list )
+          COMPREPLY=( $(compgen -W 'certs keys branches epochs tags vars known unknown ignored missing' -- $cur ) )
+          ;;
+        attr )
+          COMPREPLY=( $(compgen -W 'get set drop' -- $cur ) )
+          ;;
+        co | checkout )
+          _filedir -d
+          _monotone_complete revision
+          ;;
+        status | cvs_import | add | drop | rm | rename | mv | revert | identify )
+          _filedir
+          ;;
+        complete )
+          COMPREPLY=( $(compgen -W 'revision manifest file key' -- $cur) )
+          ;;
+        cat )
+          COMPREPLY=( $(compgen -W 'file manifest revision' -- $cur) )
+          ;;
         push | pull | serve | sync )
-	  COMPREPLY=( $(compgen -A hostname -- $cur) )
-	  ;;
-	pubkey | privkey )
-	  _monotone_keys $prev
-	  ;;
-	chkeypass | dropkey )
-	  _monotone_keys privkey
-	  ;;
-	propagate | reindex )
-	  _monotone_branches
-	  ;;
-	* )
-	  if (( $COMP_CWORD >= 2 )) ; then
-	    local prev2=${COMP_WORDS[COMP_CWORD-2]}
-	    case $prev2 in
-	      cdiff | diff | explicit_merge )
-		_monotone_complete revision
-		;;
-	      co | checkout | rename | annotate )
-		_filedir -d
-		;;
-	      cat )
-		_monotone_complete $prev
-		;;
-	      log | attr )
-		_filedir
-		;;
-	      list )
-		if [ $prev == certs ] ; then
-		    _monotone_complete revision
-		    _monotone_complete manifest
-		    _monotone_complete file
-		fi
-		;;
-	      push | pull | serve | sync | propagate )
+          COMPREPLY=( $(compgen -A hostname -- $cur) )
+          ;;
+        pubkey | privkey )
+          _monotone_keys $prev
+          ;;
+        chkeypass | dropkey )
+          _monotone_keys privkey
+          ;;
+        propagate | reindex )
+          _monotone_branches
+          ;;
+        * )
+          if (( $COMP_CWORD >= 2 )) ; then
+            local prev2=${COMP_WORDS[COMP_CWORD-2]}
+            case $prev2 in
+              cdiff | diff | explicit_merge )
+                _monotone_complete revision
+                ;;
+              co | checkout | rename | mv | annotate )
+                _filedir
+                ;;
+              cat )
+                _monotone_complete $prev
+                ;;
+              log | attr )
+                _filedir
+                ;;
+              list )
+                if [ $prev == certs ] ; then
+                    _monotone_complete revision
+                    _monotone_complete manifest
+                    _monotone_complete file
+                fi
+                ;;
+              push | pull | serve | sync | propagate )
                 _monotone_branches
-		;;
-	      * )
-		if (( $COMP_CWORD >= 3 )) ; then
-		    local prev3=${COMP_WORDS[COMP_CWORD-3]}
-		    case $prev3 in
-			explicit_merge )
-			    _monotone_complete revision
-			    _monotone_branches
-			    ;;
-			*)
-			    unset prev2
-			    unset prev3
-		    esac
-		else
-		    unset prev2
-		fi
-		;;
-	    esac
-	  fi
-	  if [ -z "$prev2" ] ; then
-	    COMPREPLY=( $(compgen -W 'db agraph \
-                                      annotate cat cdiff complete diff list log ls status \
-                                      cert chkeypass dropkey genkey trusted \
-                                      pull push reindex serve sync \
-                                      privkey pubkey read \
-                                      cvs_import \
-                                      approve comment disapprove tag testresult \
-                                      checkout co explicit_merge heads merge propagate refresh_inodeprints setup \
-                                      set unset \
-                                      add attr commit drop identify rename revert update' -- $cur) )
-	  fi
-	  ;;
+                ;;
+              * )
+                if (( $COMP_CWORD >= 3 )) ; then
+                    local prev3=${COMP_WORDS[COMP_CWORD-3]}
+                    case $prev3 in
+                        explicit_merge )
+                            _monotone_complete revision
+                            _monotone_branches
+                            ;;
+                        *)
+                            unset prev2
+                            unset prev3
+                    esac
+                else
+                    unset prev2
+                    _filedir
+                fi
+                ;;
+            esac
+          fi
+          if (( $COMP_CWORD < 2 )) ; then
+            COMPREPLY=( $(compgen -W 'automate db agraph fload fmerge lca lcad
+                                      rcs_import annotate cat complete diff
+                                      list log ls status cert chkeypass dropkey
+                                      genkey trusted pull push reindex serve
+                                      sync certs fdata fdelta mdata mdelta
+                                      privkey pubkey rdata read cvs_import
+                                      approve comment disapprove tag testresult
+                                      checkout co explicit_merge fcommit heads
+                                      merge propagate refresh_inodeprints setup
+                                      set unset add attr ci commit drop
+                                      identify mv rename revert rm update' -- $cur) )
+          else
+              _filedir
+          fi
+          ;;
       esac
       ;;
   esac
   return 0
 }

+complete -F _monotone -o filenames monotone
-complete -F _monotone -o default monotone
============================================================
--- contrib/usher.cc	cb295e80eb1af0bd7d55cde7da973c340a05deb2
+++ contrib/usher.cc	599b754c575694458973cf7ecd5be5fd5a03c06d
@@ -1,3 +1,4 @@
+// -*- mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil -*-
 // Timothy Brownawell  <tbrownaw@gmail.com>
 // GPL v2
 //
@@ -691,10 +692,16 @@ struct server
       c = servers_by_host.find(*i);
       if (c != servers_by_host.end()) {
         list<map<string, shared_ptr<server> >::iterator>::iterator j;
-        for (j = c->second->by_host.begin(); j != c->second->by_host.end(); ++j)
-          if ((*j)->first == *i) {
-            servers_by_host.erase(*j);
-            c->second->by_host.erase(j);
+        for (j = c->second->by_host.begin(); j != c->second->by_host.end();)
+          {
+            list<map<string, shared_ptr<server> >::iterator>::iterator j_saved
+              = j;
+            ++j;
+            if ((*j_saved)->first == *i)
+              {
+                servers_by_host.erase(*j_saved);
+                c->second->by_host.erase(j_saved);
+              }
           }
       }
       c = servers_by_host.insert(make_pair(*i, me)).first;
============================================================
--- cset.cc	ac5f2a4848a4c5661496ec4f5af706de1fb6a454
+++ cset.cc	a8497f9a82330f842cda2f242e97ef48e3a6b9fb
@@ -225,6 +225,8 @@ cset::apply_to(editable_tree & t) const
   for (map<pair<split_path, attr_key>, attr_value>::const_iterator i = attrs_set.begin();
        i != attrs_set.end(); ++i)
     t.set_attr(i->first.first, i->first.second, i->second);
+
+  t.commit();
 }

 ////////////////////////////////////////////////////////////////////
============================================================
--- cset.hh	f2d58803ea89b51b5029a349c30acc3c6c3cf580
+++ cset.hh	7bd817258ac15fa2b6e4c3473e9b97858721969d
@@ -46,6 +46,8 @@ struct editable_tree
                         attr_key const & name,
                         attr_value const & val) = 0;

+  virtual void commit() = 0;
+
   virtual ~editable_tree() {}
 };

============================================================
--- database.cc	2fc44fac19123c10272d86d0295b91f58a8ad6b1
+++ database.cc	70d4d8f0c43de5e18bb023fc2c87805c0cdfa659
@@ -1316,6 +1316,10 @@ database::remove_version(hexenc<id> cons
       }
   }

+  // no deltas are allowed to point to the target.
+  execute(query("DELETE from " + delta_table + " WHERE base = ?")
+          % text(target_id()));
+
   if (delta_exists(target_id, delta_table))
     {
       if (!older.empty())
@@ -1335,6 +1339,8 @@ database::remove_version(hexenc<id> cons
           for (map<hexenc<id>, data>::const_iterator i = older.begin();
                i != older.end(); ++i)
             {
+              if (delta_exists(i->first, delta_table))
+                continue;
               delta bypass_delta;
               diff(newer_data, i->second, bypass_delta);
               put_delta(i->first, newer_id, bypass_delta, delta_table);
@@ -1349,7 +1355,10 @@ database::remove_version(hexenc<id> cons
       I(exists(target_id, data_table));
       for (map<hexenc<id>, data>::const_iterator i = older.begin();
            i != older.end(); ++i)
-        put(i->first, i->second, data_table);
+        {
+          if (!exists(i->first, data_table))
+            put(i->first, i->second, data_table);
+        }
       execute(query("DELETE from " + data_table + " WHERE id = ?")
               % text(target_id()));
     }
============================================================
--- enumerator.cc	33a06c9ebfb955efb197f5eafb2e8d9beaee8a1d
+++ enumerator.cc	05baab83e8b397403e54ed13a6c514c81feb7b4f
@@ -68,6 +68,89 @@ void
 }

 void
+revision_enumerator::files_for_revision(revision_id const & r,
+                                        set<file_id> & full_files,
+                                        set<pair<file_id,file_id> > & del_files)
+{
+  // when we're sending a merge, we have to be careful if we
+  // want to send as little data as possible. see bug #15846
+  //
+  // njs's solution: "when sending the files for a revision,
+  // look at both csets. If a given hash is not listed as new
+  // in _both_ csets, throw it out. Now, for everything left
+  // over, if one side says "add" and the other says "delta",
+  // do a delta. If both sides say "add", do a data."
+
+  set<file_id> file_adds;
+  // map<dst, src>.  src is arbitrary.
+  map<file_id, file_id> file_deltas;
+  map<file_id, size_t> file_edge_counts;
+
+  revision_set rs;
+  MM(rs);
+  app.db.get_revision(r, rs);
+
+  for (edge_map::const_iterator i = rs.edges.begin();
+       i != rs.edges.end(); ++i)
+    {
+      set<file_id> file_dsts;
+      cset const & cs = edge_changes(i);
+
+      // Queue up all the file-adds
+      for (map<split_path, file_id>::const_iterator fa = cs.files_added.begin();
+           fa != cs.files_added.end(); ++fa)
+        {
+          file_adds.insert(fa->second);
+          file_dsts.insert(fa->second);
+        }
+
+      // Queue up all the file-deltas
+      for (map<split_path, std::pair<file_id, file_id> >::const_iterator fd
+             = cs.deltas_applied.begin();
+           fd != cs.deltas_applied.end(); ++fd)
+        {
+          file_deltas[fd->second.second] = fd->second.first;
+          file_dsts.insert(fd->second.second);
+        }
+
+      // we don't want to be counting files twice in a single edge
+      for (set<file_id>::const_iterator i = file_dsts.begin();
+           i != file_dsts.end(); i++)
+        file_edge_counts[*i]++;
+    }
+
+  del_files.clear();
+  full_files.clear();
+  size_t num_edges = rs.edges.size();
+
+  for (map<file_id, size_t>::const_iterator i = file_edge_counts.begin();
+       i != file_edge_counts.end(); i++)
+    {
+      MM(i->first);
+      if (i->second < num_edges)
+        continue;
+
+      // first preference is to send as a delta...
+      map<file_id, file_id>::const_iterator fd = file_deltas.find(i->first);
+      if (fd != file_deltas.end())
+        {
+          del_files.insert(make_pair(fd->second, fd->first));
+          continue;
+        }
+
+      // ... otherwise as a full file.
+      set<file_id>::const_iterator f = file_adds.find(i->first);
+      if (f != file_adds.end())
+        {
+          full_files.insert(*f);
+          continue;
+        }
+
+      I(false);
+    }
+}
+
+void
 revision_enumerator::process_bunch()
 {
   // we build up a set of files and revs to send
@@ -89,42 +172,31 @@ revision_enumerator::process_bunch()

       bunch_revs.push_back(r);

-      revision_set rs;
-      app.db.get_revision(r, rs);
-      for (edge_map::const_iterator i = rs.edges.begin();
-           i != rs.edges.end(); ++i)
+      set<file_id> full_files;
+      set<pair<file_id, file_id> > del_files;
+
+      files_for_revision(r, full_files, del_files);
+
+      set<file_id> top_files;
+      set<file_id> dst_files;
+
+      for (set<file_id>::const_iterator f = full_files.begin();
+           f != full_files.end(); f++)
         {
-          cset const & cs = edge_changes(i);
-
-          // Queue up all the file-adds
-          for (map<split_path, file_id>::const_iterator fa = cs.files_added.begin();
-               fa != cs.files_added.end(); ++fa)
-            {
-              if (cb.queue_this_file(fa->second.inner()))
-                {
-                  dst_files.insert(fa->second);
-                  top_files.insert(fa->second);
-                  bunch_files.insert(fa->second);
-                }
-            }
-
-          // Queue up all the file-deltas
-          for (map<split_path, std::pair<file_id, file_id> >::const_iterator fd
-                 = cs.deltas_applied.begin();
-               fd != cs.deltas_applied.end(); ++fd)
-            {
-              if (cb.queue_this_file(fd->second.second.inner()))
-                {
-                  if (dst_files.find(fd->second.first) == dst_files.end())
-                    {
-                      top_files.insert(fd->second.first);
-                    }
+          bunch_files.insert(*f);
+          top_files.insert(*f);
+          dst_files.insert(*f)
+        }

-                  bunch_file_deltas.insert(make_pair(fd->second.first,
-                                                     fd->second.second));
-                  dst_files.insert(fd->second.second);
-                }
-            }
+      for (set<pair<file_id,file_id> >::const_iterator fd = del_files.begin();
+           fd != del_files.end(); fd++)
+        {
+          file_id src(fd->second);
+          file_id dst(fd->first);
+          bunch_file_deltas.insert(make_pair(fd->second, fd->first));
+          if (dst_files.find(src) == dst_files.end())
+            top_files.insert(src);
+          dst_files.insert(dst);
         }
     }

============================================================
--- enumerator.hh	1880dae7a6147b0ddd8064bfc4679334b520aeab
+++ enumerator.hh	5cc476581aed97dd306843e60c057ab1053cf0da
@@ -60,6 +60,9 @@ revision_enumerator
   revision_enumerator(enumerator_callbacks & cb,
                       app_state & app);
   void load_revs();
+  void revision_enumerator::files_for_revision(revision_id const & r,
+                                               std::set<file_id> & full_files,
+                                               std::set<std::pair<file_id,file_id> > & del_files);
   void process_bunch();
   void step();
   bool done();
============================================================
--- lua.cc	8284c5010bee38f15141c3e60eeeeb7c288ee20c
+++ lua.cc	a9045fcf6d8283a12a96f422b79fb54ae2da727c
@@ -426,7 +426,7 @@ extern "C"
   {
     int fd = -1;
     FILE **pf = NULL;
-    char const *filename = lua_tostring (L, -1);
+    char const *filename = luaL_checkstring (L, -1);
     std::string dup(filename);

     fd = monotone_mkstemp(dup);
@@ -458,7 +458,7 @@ extern "C"
   static int
   monotone_existsonpath_for_lua(lua_State *L)
   {
-    const char *exe = lua_tostring(L, -1);
+    const char *exe = luaL_checkstring(L, -1);
     lua_pushnumber(L, existsonpath(exe));
     return 1;
   }
@@ -466,7 +466,7 @@ extern "C"
   static int
   monotone_is_executable_for_lua(lua_State *L)
   {
-    const char *path = lua_tostring(L, -1);
+    const char *path = luaL_checkstring(L, -1);
     lua_pushboolean(L, is_executable(path));
     return 1;
   }
@@ -474,7 +474,7 @@ extern "C"
   static int
   monotone_make_executable_for_lua(lua_State *L)
   {
-    const char *path = lua_tostring(L, -1);
+    const char *path = luaL_checkstring(L, -1);
     lua_pushnumber(L, make_executable(path));
     return 1;
   }
@@ -483,14 +483,14 @@ extern "C"
   monotone_spawn_for_lua(lua_State *L)
   {
     int n = lua_gettop(L);
-    const char *path = lua_tostring(L, -n);
+    const char *path = luaL_checkstring(L, -n);
     char **argv = (char**)malloc((n+1)*sizeof(char*));
     int i;
     pid_t ret;
     if (argv==NULL)
       return 0;
     argv[0] = (char*)path;
-    for (i=1; i<n; i++) argv[i] = (char*)lua_tostring(L, -(n - i));
+    for (i=1; i<n; i++) argv[i] = (char*)luaL_checkstring(L, -(n - i));
     argv[i] = NULL;
     ret = process_spawn(argv);
     free(argv);
@@ -501,7 +501,7 @@ extern "C"
   static int
   monotone_wait_for_lua(lua_State *L)
   {
-    pid_t pid = (pid_t)lua_tonumber(L, -1);
+    pid_t pid = static_cast<pid_t>(luaL_checknumber(L, -1));
     int res;
     int ret;
     ret = process_wait(pid, &res);
@@ -514,10 +514,10 @@ extern "C"
   monotone_kill_for_lua(lua_State *L)
   {
     int n = lua_gettop(L);
-    pid_t pid = (pid_t)lua_tonumber(L, -2);
+    pid_t pid = static_cast<pid_t>(luaL_checknumber(L, -2));
     int sig;
     if (n>1)
-      sig = (int)lua_tonumber(L, -1);
+      sig = static_cast<int>(luaL_checknumber(L, -1));
     else
       sig = SIGTERM;
     lua_pushnumber(L, process_kill(pid, sig));
@@ -527,7 +527,7 @@ extern "C"
   static int
   monotone_sleep_for_lua(lua_State *L)
   {
-    int seconds = (int)lua_tonumber(L, -1);
+    int seconds = static_cast<int>(luaL_checknumber(L, -1));
     lua_pushnumber(L, process_sleep(seconds));
     return 1;
   }
@@ -535,7 +535,7 @@ extern "C"
   static int
   monotone_guess_binary_file_contents_for_lua(lua_State *L)
   {
-    const char *path = lua_tostring(L, -1);
+    const char *path = luaL_checkstring(L, -1);
     N(path, F("%s called with an invalid parameter") % "guess_binary");

     std::ifstream file(path, ios_base::binary);
@@ -564,7 +564,7 @@ extern "C"
   static int
   monotone_include_for_lua(lua_State *L)
   {
-    const char *path = lua_tostring(L, -1);
+    const char *path = luaL_checkstring(L, -1);
     N(path, F("%s called with an invalid parameter") % "Include");

     bool res =Lua(L)
@@ -579,7 +579,7 @@ extern "C"
   static int
   monotone_includedir_for_lua(lua_State *L)
   {
-    const char *pathstr = lua_tostring(L, -1);
+    const char *pathstr = luaL_checkstring(L, -1);
     N(pathstr, F("%s called with an invalid parameter") % "IncludeDir");

     fs::path locpath(pathstr, fs::native);
@@ -613,8 +613,8 @@ extern "C"
   static int
   monotone_regex_search_for_lua(lua_State *L)
   {
-    const char *re = lua_tostring(L, -2);
-    const char *str = lua_tostring(L, -1);
+    const char *re = luaL_checkstring(L, -2);
+    const char *str = luaL_checkstring(L, -1);
     boost::cmatch what;

     bool result = false;
@@ -632,8 +632,8 @@ extern "C"
   static int
   monotone_globish_match_for_lua(lua_State *L)
   {
-    const char *re = lua_tostring(L, -2);
-    const char *str = lua_tostring(L, -1);
+    const char *re = luaL_checkstring(L, -2);
+    const char *str = luaL_checkstring(L, -1);

     bool result = false;
     try {
@@ -661,7 +661,7 @@ extern "C"
   static int
   monotone_gettext_for_lua(lua_State *L)
   {
-    const char *msgid = lua_tostring(L, -1);
+    const char *msgid = luaL_checkstring(L, -1);
     lua_pushstring(L, gettext(msgid));
     return 1;
   }
@@ -685,7 +685,7 @@ extern "C"
   monotone_parse_basic_io_for_lua(lua_State *L)
   {
     vector<pair<string, vector<string> > > res;
-    const string str(lua_tostring(L, -1), lua_strlen(L, -1));
+    const string str(luaL_checkstring(L, -1), lua_strlen(L, -1));
     basic_io::input_source in(str, "monotone_parse_basic_io_for_lua");
     basic_io::tokenizer tok(in);
     try
@@ -1049,18 +1049,6 @@ lua_hooks::hook_ignore_branch(std::strin
   return exec_ok && ignore_it;
 }

-bool
-lua_hooks::hook_non_blocking_rng_ok()
-{
-  bool ok = false;
-  bool exec_ok = Lua(st)
-    .func("non_blocking_rng_ok")
-    .call(0,1)
-    .extract_bool(ok)
-    .ok();
-  return exec_ok && ok;
-}
-
 static inline bool
 shared_trust_function_body(Lua & ll,
                            std::set<rsa_keypair_id> const & signers,
============================================================
--- lua.hh	a682ec35ee70ef30fd080616f8f21d8ef2a1a6ea
+++ lua.hh	5691c7c116dc402741a8a9ba7f5ab7d2ebe7b2e0
@@ -49,7 +49,6 @@ public:
                          std::string const & user_log_message,
                          std::string & result);
   bool hook_persist_phrase_ok();
-  bool hook_non_blocking_rng_ok();
   bool hook_get_revision_cert_trust(std::set<rsa_keypair_id> const & signers,
                                    hexenc<id> const & id,
                                    cert_name const & name,
============================================================
--- monotone.cc	92399bda2cd0fba92739636d7b0955c1c43bea23
+++ monotone.cc	6626e22d6ef4d9c8d3380a2f498599dd57bc6d3d
@@ -74,6 +74,7 @@ struct poptOption coptions[] =
     {"unknown", 0, POPT_ARG_NONE, NULL, OPT_UNKNOWN, gettext_noop("perform the operations for unknown files from workspace"), NULL},
     {"key-to-push", 0, POPT_ARG_STRING, &argstr, OPT_KEY_TO_PUSH, gettext_noop("push the specified key even if it hasn't signed anything"), NULL},
     {"drop-attr", 0, POPT_ARG_STRING, &argstr, OPT_DROP_ATTR, gettext_noop("when rosterifying, drop attrs entries with the given key"), NULL},
+    {"no-files", 0, POPT_ARG_NONE, NULL, OPT_NO_FILES, gettext_noop("exclude files when printing logs"), NULL},
     { NULL, 0, 0, NULL, 0, NULL, NULL }
   };

@@ -84,6 +85,7 @@ struct poptOption options[] =

     {"debug", 0, POPT_ARG_NONE, NULL, OPT_DEBUG, gettext_noop("print debug log to stderr while running"), NULL},
     {"dump", 0, POPT_ARG_STRING, &argstr, OPT_DUMP, gettext_noop("file to dump debugging log to, on failure"), NULL},
+    {"log", 0, POPT_ARG_STRING, &argstr, OPT_LOG, gettext_noop("file to write the log to"), NULL},
     {"quiet", 0, POPT_ARG_NONE, NULL, OPT_QUIET, gettext_noop("suppress log and progress messages"), NULL},
     {"help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, gettext_noop("display help message"), NULL},
     {"version", 0, POPT_ARG_NONE, NULL, OPT_VERSION, gettext_noop("print version number, then exit"), NULL},
@@ -332,6 +334,10 @@ cpp_main(int argc, char ** argv)
               global_sanity.filename = system_path(argstr);
               break;

+            case OPT_LOG:
+              ui.redirect_log_to(system_path(argstr));
+              break;
+
             case OPT_DB_NAME:
               app.set_database(system_path(argstr));
               break;
@@ -519,6 +525,10 @@ cpp_main(int argc, char ** argv)
               app.attrs_to_drop.insert(string(argstr));
               break;

+            case OPT_NO_FILES:
+              app.no_files = true;
+              break;
+
             case OPT_HELP:
             default:
               requested_help = true;
============================================================
--- monotone.texi	355d07f84caee318dd69f37ff6274842ca2d2c70
+++ monotone.texi	1fcc35f2ac3ca9ba692509cd29f6f5ff01b6616a
@@ -4139,26 +4139,37 @@ @section Informative
 to files changed within the current subdirectory of the workspace.

 @item monotone log
-@itemx monotone log [--last=@var{n}] [--revision=@var{id} [...]] [--brief] [--merges] [@var{file} [...]]
+@itemx monotone log [--last=@var{n}] [--next=@var{n}] [--revision=@var{id} [...]] [--brief] [--merges] [--no-files] [--diffs] [@var{file} [...]]

 This command prints out a log, in reverse-ancestry order, of small
 history summaries.  Each summary contains author, date, changelog and
-comment information associated with a revision.
+comment information associated with a revision.

 If @code{--brief} is given, the output consists of one line per revision
 with the revision ID, the author, the date and the branches (separated
 with commas).

-If @code{--last=}@var{n} is given, at most that many log entries will be
+If @code{--last=}@var{n} is given, at most @var{n} log entries will be
 given.

-By default, the log entries for merge nodes are not shown; usually they
-don't contain much interesting information. If @code{--merges} is given,
-the log entries for these nodes will be included.
+If @code{--next=}@var{n} is given, at most @var{n} log entries towards
+the current head revision will be given from the workspace's base
+revision in forward-ancestry order.  This is useful to review changes
+that will be applied to the workspace when @command{update} is run.

+By default, the log entries for merge nodes are not shown; usually
+they don't contain much interesting information. If @code{--merges} is
+given, the log entries for these nodes will be included.
+
+If @code{--no-files} is given, the log output excludes the list of
+files changed in each revision.
+
+Specifying @code{--diffs} causes the log output to include a unified
+diff of the changes in each revision.
+
 If one or more revision IDs are given, the command starts tracing back
-through history from these revisions, otherwise it starts from the base
-revision of your workspace.
+through history from these revisions, otherwise it starts from the
+base revision of your workspace.

 If one or more files are given, the command will only log the revisions
 where those files are changed.
@@ -4435,12 +4446,7 @@ @section Key and Cert

 This command generates an @sc{rsa} public/private key pair, using a
 system random number generator, and stores it in your keystore under
-the key name @var{keyid}. If the the hook
-@code{non_blocking_rng_ok()} returns @code{true}, the key
-generation will use an unlimited random number generator (such as
-@file{/dev/urandom}), otherwise it will use a higher quality random
-number generator (such as @file{/dev/random}) but might run slightly
-slower.
+the key name @var{keyid}.

 The private half of the key is stored in an encrypted form, so that anyone
 who can read your keystore cannot extract your private key and use it.
@@ -6157,25 +6163,6 @@ @subsection User Defaults

 For the default definition of this hook, see @ref{Default hooks}.

-@item non_blocking_rng_ok ()
-
-Returns @code{true} if you are willing to let monotone use the
-system's non-blocking random number generator, such as
-@file{/dev/urandom}, for generating random values during cryptographic
-operations. This diminishes the cryptographic strength of such
-operations, but speeds them up. Returns @code{false} if you want to
-force monotone to always use higher quality random numbers, such as
-those from @file{/dev/random}.
-
-The default definition of this hook is:
-@smallexample
-@group
-function non_blocking_rng_ok()
-        return true
-end
-@end group
-@end smallexample
-
 @item persist_phrase_ok ()

 Returns @code{true} if you want monotone to remember the passphrase of
@@ -7770,6 +7757,10 @@ @section OPTIONS
 Dump debugging log to @i{<file>} on failure.
 @comment TROFF INPUT: .TP

+@item @b{--log=}@i{<file>}
+Redirect the log lines to to @i{<file>}.
+@comment TROFF INPUT: .TP
+
 @item @b{--nostd}
 Do not evaluate "standard" Lua hooks compiled into @b{monotone}.
 @comment TROFF INPUT: .TP
============================================================
--- netsync.cc	8d4dc8e530af4fb0a6cca30ca600dd74f905b1aa
+++ netsync.cc	0edebb049f6f44132b6c97be4663efc113efeee8
@@ -2390,7 +2390,7 @@ handle_new_connection(Netxx::Address & a
                       app_state & app)
 {
   L(FL("accepting new connection on %s : %s\n")
-    % addr.get_name() % lexical_cast<string>(addr.get_port()));
+    % (addr.get_name()?addr.get_name():"") % lexical_cast<string>(addr.get_port()));
   Netxx::Peer client = server.accept_connection();

   if (!client)
@@ -2589,7 +2589,7 @@ serve_connections(protocol_role role,
           else
             addr.add_all_addresses (default_port);

-          // If se use IPv6 and the initiasation of server fails, we want
+          // If se use IPv6 and the initialisation of server fails, we want
           // to try again with IPv4.  The reason is that someone may have
           // downloaded a IPv6-enabled monotone on a system that doesn't
           // have IPv6, and which might fail therefore.
============================================================
--- options.hh	6dc48543e2cb20ea82ded241dc5bb6088c3cb09c
+++ options.hh	16194449c59ae0307ab9bbf15ae879f0f8063fdd
@@ -51,3 +51,5 @@
 #define OPT_KEY_TO_PUSH 42
 #define OPT_CONF_DIR 43
 #define OPT_DROP_ATTR 44
+#define OPT_NO_FILES 45
+#define OPT_LOG 46
============================================================
--- po/sv.po	754e90276863a8b1a53cad17c575bb93ffcdd5b4
+++ po/sv.po	e065ecfd2c28c0ea89877c3c95ceeae23190b320
@@ -144,8 +144,8 @@ msgstr ""
 msgstr ""
 "Project-Id-Version: monotone 0.26pre1\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-02-11 08:32+0100\n"
-"PO-Revision-Date: 2006-02-11 08:43+0100\n"
+"POT-Creation-Date: 2006-02-20 17:26+0100\n"
+"PO-Revision-Date: 2006-02-20 17:28+0100\n"
 "Last-Translator: Joel Rosdahl <joel@rosdahl.net>\n"
 "Language-Team: Richard Levitte <richard@levitte.org>\n"
 "MIME-Version: 1.0\n"
@@ -303,7 +303,7 @@ msgstr "pid-filen '%s' finns redan"
 msgstr "pid-filen '%s' finns redan"

 #: commands.cc:325 commands.cc:1295 commands.cc:1365 commands.cc:1801
-#: commands.cc:2722 commands.cc:3266 commands.cc:3497 commands.cc:3536
+#: commands.cc:2722 commands.cc:3267 commands.cc:3498 commands.cc:3537
 msgid "informative"
 msgstr "informativ"

@@ -343,7 +343,7 @@ msgstr ""

 #: commands.cc:481 commands.cc:737 commands.cc:1383 commands.cc:1460
 #: commands.cc:1888 commands.cc:2772 commands.cc:2800 commands.cc:2803
-#: commands.cc:2939 commands.cc:3519
+#: commands.cc:2939 commands.cc:3520
 #, c-format
 msgid "no such revision '%s'"
 msgstr "det finns ingen revision med identiteten '%s'"
@@ -618,13 +618,13 @@ msgstr "tom kommentar"
 msgid "empty comment"
 msgstr "tom kommentar"

-#: commands.cc:1168 commands.cc:1196 commands.cc:1221 commands.cc:1342
-#: commands.cc:2224 commands.cc:2342 commands.cc:2875 commands.cc:3314
+#: commands.cc:1168 commands.cc:1196 commands.cc:1221 commands.cc:2224
+#: commands.cc:2342 commands.cc:2875 commands.cc:3315
 msgid "workspace"
 msgstr "arbetskopia"

 #: commands.cc:1168 commands.cc:1196 commands.cc:1295 commands.cc:2342
-#: commands.cc:2722 commands.cc:3314
+#: commands.cc:2722 commands.cc:3315
 msgid "[PATH]..."
 msgstr "[SÖKVÄG]..."

@@ -651,7 +651,8 @@ msgstr "byt namn på filer i arbetskopia
 msgid "rename entries in the workspace"
 msgstr "byt namn på filer i arbetskopian"

-#: commands.cc:1249 commands.cc:1262 commands.cc:3417 commands.cc:3857
+#: commands.cc:1249 commands.cc:1262 commands.cc:1342 commands.cc:3418
+#: commands.cc:3859
 msgid "debug"
 msgstr "felsökning"

@@ -708,13 +709,13 @@ msgstr "skriv ut angiven fil från datab
 msgid "write file from database to stdout"
 msgstr "skriv ut angiven fil från databasen"

-#: commands.cc:1395 commands.cc:1397 commands.cc:3528
+#: commands.cc:1395 commands.cc:1397 commands.cc:3529
 #, c-format
 msgid "no file '%s' found in revision '%s'\n"
 msgstr "filen '%s' finns inte i revisionen '%s'\n"

 #: commands.cc:1409 commands.cc:1531 commands.cc:3076 commands.cc:3125
-#: commands.cc:3214 commands.cc:3221 commands.cc:3770
+#: commands.cc:3214 commands.cc:3222 commands.cc:3772
 msgid "tree"
 msgstr "träd"

@@ -1224,13 +1225,13 @@ msgstr "slår ihop med revision %d av %d
 msgid "merging with revision %d / %d\n"
 msgstr "slår ihop med revision %d av %d\n"

-#: commands.cc:3101 commands.cc:3102 commands.cc:3169 commands.cc:3244
-#: commands.cc:3245
+#: commands.cc:3101 commands.cc:3102 commands.cc:3169 commands.cc:3245
+#: commands.cc:3246
 #, c-format
 msgid "[source] %s\n"
 msgstr "[källa]      %s\n"

-#: commands.cc:3119 commands.cc:3210 commands.cc:3263
+#: commands.cc:3119 commands.cc:3210 commands.cc:3264
 #, c-format
 msgid "[merged] %s\n"
 msgstr "[ihopslagen] %s\n"
@@ -1282,58 +1283,58 @@ msgstr "uppdatera inodeprint-cachen"
 msgid "refresh the inodeprint cache"
 msgstr "uppdatera inodeprint-cachen"

-#: commands.cc:3222
+#: commands.cc:3223
 msgid "LEFT-REVISION RIGHT-REVISION DEST-BRANCH"
 msgstr "VÄNSTERREVISION HÖGERREVISION MÅLGREN"

-#: commands.cc:3223
+#: commands.cc:3224
 msgid "merge two explicitly given revisions, placing result in given branch"
 msgstr ""
 "slå ihop två explicit angivna revisioner, placera resultatet i angiven gren"

-#: commands.cc:3237
+#: commands.cc:3238
 #, c-format
 msgid "%s and %s are the same revision, aborting"
 msgstr "%s och %s är samma revision, avbryter"

-#: commands.cc:3239 commands.cc:3241
+#: commands.cc:3240 commands.cc:3242
 #, c-format
 msgid "%s is already an ancestor of %s"
 msgstr "%s är redan förfader till %s"

-#: commands.cc:3266
+#: commands.cc:3267
 msgid "(revision|file|key) PARTIAL-ID"
 msgstr "(revision|file|key) PARTIAL-ID"

-#: commands.cc:3267
+#: commands.cc:3268
 msgid "complete partial id"
 msgstr "utöka den partiella identiteten"

-#: commands.cc:3276
+#: commands.cc:3277
 #, c-format
 msgid "non-hex digits in partial id"
 msgstr "något tecken i den partiella identiteten är inte hexadecimalt"

-#: commands.cc:3315
+#: commands.cc:3316
 #, fuzzy
 msgid "revert file(s), dir(s) or entire workspace (\".\")"
 msgstr "återställ fil(er), katalog(er) eller hela arbetskopian (\".\")"

-#: commands.cc:3392
+#: commands.cc:3393
 #, c-format
 msgid "reverting %s"
 msgstr "återställer %s"

-#: commands.cc:3396
+#: commands.cc:3397
 #, c-format
 msgid "no file version %s found in database for %s"
 msgstr "filversionen %s finns inte i databasen för %s"

-#: commands.cc:3417
+#: commands.cc:3418
 msgid "RCSFILE..."
 msgstr "RCSFIL..."

-#: commands.cc:3418
+#: commands.cc:3419
 msgid ""
 "parse versions in RCS files\n"
 "this command doesn't reconstruct or import revisions.you probably want "
@@ -1343,36 +1344,36 @@ msgstr ""
 "detta kommando importerar inte revisioner; du vill antagligen använda\n"
 "cvs_import"

-#: commands.cc:3434
+#: commands.cc:3435
 msgid "rcs"
 msgstr "rcs"

-#: commands.cc:3434
+#: commands.cc:3435
 msgid "CVSROOT"
 msgstr "CVSROOT"

-#: commands.cc:3434
+#: commands.cc:3435
 msgid "import all versions in CVS repository"
 msgstr "importera alla revisioner i ett CVS-arkiv"

-#: commands.cc:3497
+#: commands.cc:3498
 msgid "PATH"
 msgstr "SÖKVÄG"

-#: commands.cc:3498
+#: commands.cc:3499
 msgid "print annotated copy of the file from REVISION"
 msgstr "skriv ut filen ur REVISION med extra detaljer"

-#: commands.cc:3518
+#: commands.cc:3519
 #, c-format
 msgid "no revision for file '%s' in database"
 msgstr "filen '%s' har ingen revision i databasen"

-#: commands.cc:3536
+#: commands.cc:3537
 msgid "[FILE] ..."
 msgstr "[FIL] ..."

-#: commands.cc:3537
+#: commands.cc:3538
 msgid ""
 "print history in reverse order (filtering by 'FILE'). If one or more\n"
 "revisions are given, use them as a starting point."
@@ -1381,35 +1382,35 @@ msgstr ""
 "arbetskatalogen om inga filer angivits. Om en eller flera revisioner\n"
 "har angivits används de som utgångspunkter."

-#: commands.cc:3584
+#: commands.cc:3586
 #, c-format
 msgid "Unknown file '%s' for log command"
 msgstr "Okänd fil '%s'"

-#: commands.cc:3602
+#: commands.cc:3604
 #, c-format
 msgid "only one of --last/--next allowed"
 msgstr "enbart en av --last eller --next tillåten"

-#: commands.cc:3770
+#: commands.cc:3772
 msgid "[DIRECTORY]"
 msgstr "[KATALOG]"

-#: commands.cc:3770
+#: commands.cc:3772
 #, fuzzy
 msgid "setup a new workspace directory, default to current"
 msgstr "initiera en ny arbetskatalog (nuvarande om katalog ej anges)"

-#: commands.cc:3776
+#: commands.cc:3778
 #, c-format
 msgid "need --branch argument for setup"
 msgstr "du måste ange en gren med --branch till kommandot \"setup\""

-#: commands.cc:3790
+#: commands.cc:3792
 msgid "automation"
 msgstr "automatisering"

-#: commands.cc:3791
+#: commands.cc:3793
 msgid ""
 "interface_version\n"
 "heads [BRANCH]\n"
@@ -1453,40 +1454,40 @@ msgstr ""
 "get_revision [REVID]\n"
 "keys\n"

-#: commands.cc:3811
+#: commands.cc:3813
 msgid "automation interface"
 msgstr "automatiseringsgränssnitt"

-#: commands.cc:3825 commands.cc:3841
+#: commands.cc:3827 commands.cc:3843
 msgid "vars"
 msgstr "variabler"

-#: commands.cc:3825
+#: commands.cc:3827
 msgid "DOMAIN NAME VALUE"
 msgstr "DOMÄN NAMN VÄRDE"

-#: commands.cc:3826
+#: commands.cc:3828
 msgid "set the database variable NAME to VALUE, in domain DOMAIN"
 msgstr "sätt databasvariabeln NAMN till VÄRDE i domänen DOMÄN"

-#: commands.cc:3841
+#: commands.cc:3843
 msgid "DOMAIN NAME"
 msgstr "DOMÄN NAMN"

-#: commands.cc:3842
+#: commands.cc:3844
 msgid "remove the database variable NAME in domain DOMAIN"
 msgstr "ta bort databasvariabeln NAMN från domänen DOMÄN"

-#: commands.cc:3853
+#: commands.cc:3855
 #, c-format
 msgid "no var with name %s in domain %s"
 msgstr "det finns inga variabler med namnet %s i domänen %s"

-#: commands.cc:3857
+#: commands.cc:3859
 msgid "REVID"
 msgstr "REVID"

-#: commands.cc:3858
+#: commands.cc:3860
 msgid "dump the roster associated with the given REVID"
 msgstr "skriv ut den roster som hör ihop med angivet REVID"

@@ -1502,7 +1503,7 @@ msgstr "markeringar"
 msgid "markings"
 msgstr "markeringar"

-#: database_check.cc:319 database_check.cc:507 netsync.cc:2719
+#: database_check.cc:319 database_check.cc:507 netsync.cc:2755
 #: rcs_import.cc:1226
 msgid "revisions"
 msgstr "revisioner"
@@ -1511,7 +1512,7 @@ msgstr "föräldraskap"
 msgid "ancestry"
 msgstr "föräldraskap"

-#: database_check.cc:451 netsync.cc:2723
+#: database_check.cc:451 netsync.cc:2759
 msgid "keys"
 msgstr "nycklar"

@@ -1780,7 +1781,7 @@ msgstr "databasen är i gott skick\n"
 msgid "database is good\n"
 msgstr "databasen är i gott skick\n"

-#: database.cc:134
+#: database.cc:144
 #, c-format
 msgid ""
 "layout of database %s doesn't match this version of monotone\n"
@@ -1794,7 +1795,7 @@ msgstr ""
 "(detta går inte att ångra; du vill nog ta en säkerhetskopia av databasen\n"
 "först)"

-#: database.cc:158
+#: database.cc:168
 #, c-format
 msgid ""
 "database %s contains revisions but no rosters\n"
@@ -1813,7 +1814,7 @@ msgstr ""
 "  sedan databasen på nytt.\n"
 "ursäkta besväret."

-#: database.cc:177
+#: database.cc:187
 #, c-format
 msgid ""
 "database %s contains manifests but no revisions\n"
@@ -1824,19 +1825,19 @@ msgstr ""
 "detta är en väldigt gammal databas; den behöver uppgraderas\n"
 "var god läs README.changesets för detaljer"

-#: database.cc:238
+#: database.cc:248
 #, c-format
 msgid "unable to probe database version in file %s"
 msgstr "kunde inte hitta någon databasversion i filen %s"

-#: database.cc:245
+#: database.cc:255
 #, c-format
 msgid "database %s is not an sqlite version 3 file, try dump and reload"
 msgstr ""
 "databasen %s är inte skapad med SQLite version 3; testa att dumpa och ladda "
 "på nytt"

-#: database.cc:272
+#: database.cc:282
 msgid ""
 "make sure database and containing directory are writeable\n"
 "and you have not run out of disk space"
@@ -1845,7 +1846,7 @@ msgstr ""
 "i\n"
 "samt att det finns tillräckligt med ledigt utrymme på disken"

-#: database.cc:278
+#: database.cc:288
 #, c-format
 msgid ""
 "sqlite error: %d: %s\n"
@@ -1854,12 +1855,12 @@ msgstr ""
 "sqlite-fel: %d: %s\n"
 "%s"

-#: database.cc:324
+#: database.cc:334
 #, c-format
 msgid "could not initialize database: %s: already exists"
 msgstr "kunde inte initiera databasen: %s: den finns redan"

-#: database.cc:329
+#: database.cc:339
 #, c-format
 msgid ""
 "existing (possibly stale) journal file '%s' has same stem as new database '%"
@@ -1870,12 +1871,12 @@ msgstr ""
 "databasen '%s'\n"
 "avbryter skapandet av databasen"

-#: database.cc:451
+#: database.cc:461
 #, c-format
 msgid "cannot create %s; it already exists"
 msgstr "kan inte skapa %s; den finns redan"

-#: database.cc:511
+#: database.cc:521
 #, c-format
 msgid ""
 "schema version    : %s\n"
@@ -1916,52 +1917,52 @@ msgstr ""
 "  cert                : %u\n"
 "  total               : %u\n"

-#: database.cc:565
+#: database.cc:575
 #, c-format
 msgid "database schema version: %s"
 msgstr "databasens schemaversion: %s"

-#: database.cc:642
+#: database.cc:652
 #, c-format
 msgid "multiple statements in query: %s\n"
 msgstr "multipla kommandon i databasfråga: %s\n"

-#: database.cc:648
+#: database.cc:658
 #, c-format
 msgid "wanted %d columns got %d in query: %s\n"
 msgstr "ville ha %d kolumner, fick %d i databasfråga: %s\n"

-#: database.cc:706
+#: database.cc:716
 #, c-format
 msgid "null result in query: %s\n"
 msgstr "inget resultat med databasfråga: %s\n"

-#: database.cc:724
+#: database.cc:734
 #, c-format
 msgid "wanted %d rows got %s in query: %s\n"
 msgstr "ville ha %d rader, fick %s i databasfråga: %s\n"

-#: database.cc:1771
+#: database.cc:1781
 #, c-format
 msgid "another key with name '%s' already exists"
 msgstr "det finns redan en annan nyckel med namnet '%s'"

-#: database.cc:2815
+#: database.cc:2825
 #, c-format
 msgid "no database specified"
 msgstr "ingen databas angiven"

-#: database.cc:2823
+#: database.cc:2833
 #, c-format
 msgid "database %s does not exist"
 msgstr "databasen %s finns inte"

-#: database.cc:2824
+#: database.cc:2834
 #, c-format
 msgid "%s is a directory, not a database"
 msgstr "%s är en katalog, inte en databas"

-#: database.cc:2849
+#: database.cc:2859
 #, c-format
 msgid "could not open database '%s': %s"
 msgstr "kunde inte öppna databasen '%s': %s"
@@ -2344,100 +2345,109 @@ msgstr "släng attribut med den givna ny
 msgid "when rosterifying, drop attrs entries with the given key"
 msgstr "släng attribut med den givna nyckeln vid konvertering till 'rosters'"

-#: monotone.cc:85
+#: monotone.cc:77
+#, fuzzy
+msgid "exclude files when printing logs"
+msgstr "ta med ihopslagningar i loggen"
+
+#: monotone.cc:86
 msgid "print debug log to stderr while running"
 msgstr "skriv ut felsökningslogg till stderr under körning"

-#: monotone.cc:86
+#: monotone.cc:87
 msgid "file to dump debugging log to, on failure"
 msgstr "fil att skriva ut felsökningsloggen till om något gick fel"

-#: monotone.cc:87
+#: monotone.cc:88
+msgid "file to write the log to"
+msgstr "fil att skriva ut loggen till"
+
+#: monotone.cc:89
 msgid "suppress log and progress messages"
 msgstr "skriv inte ut loggar eller förloppsmeddelanden"

-#: monotone.cc:88
+#: monotone.cc:90
 msgid "display help message"
 msgstr "skriv ut extra hjälptext"

-#: monotone.cc:89
+#: monotone.cc:91
 msgid "print version number, then exit"
 msgstr "skriv ut versionsnumret och avsluta sedan omedelbart"

-#: monotone.cc:90
+#: monotone.cc:92
 msgid "print detailed version number, then exit"
 msgstr "skriv ut detaljerad versionsinformation och avsluta sedan omedelbart"

-#: monotone.cc:91
+#: monotone.cc:93
 msgid "insert command line arguments taken from the given file"
 msgstr "använd kommandoradsargument ur denna fil"

-#: monotone.cc:92
+#: monotone.cc:94
 msgid "set ticker style (count|dot|none)"
 msgstr "sätt stilen för förloppsinformationen (count|dot|none)"

-#: monotone.cc:93
+#: monotone.cc:95
 msgid "do not load standard lua hooks"
 msgstr "använd inte standard-lua-rutinerna"

-#: monotone.cc:94
+#: monotone.cc:96
 msgid "do not load ~/.monotone/monotonerc or MT/monotonerc lua files"
 msgstr "använd inte ~/.monotone/monotonerc eller MT/monotonerc"

-#: monotone.cc:95
+#: monotone.cc:97
 msgid "load extra rc file"
 msgstr "använd denna lua-fil"

-#: monotone.cc:96
+#: monotone.cc:98
 msgid "set key for signatures"
 msgstr "ange nyckel att signera med"

-#: monotone.cc:97
+#: monotone.cc:99
 msgid "set name of database"
 msgstr "ange databasens filnamn"

-#: monotone.cc:98
+#: monotone.cc:100
 #, fuzzy
 msgid "limit search for workspace to specified root"
 msgstr "begränsa sökningen efter arbetskatalogen till denna katalog"

-#: monotone.cc:99
+#: monotone.cc:101
 msgid "verbose completion output"
 msgstr "ge utförlig information"

-#: monotone.cc:100
+#: monotone.cc:102
 msgid "set location of key store"
 msgstr "ange i vilken katalog nycklarna finns"

-#: monotone.cc:101
+#: monotone.cc:103
 msgid "set location of configuration directory"
 msgstr "ange i vilken katalog konfigurationsfilerna finns"

-#: monotone.cc:205
+#: monotone.cc:207
 #, c-format
 msgid "problem parsing arguments from file %s: %s"
 msgstr "problem att tyda argumenten i filen %s: %s"

-#: monotone.cc:214
+#: monotone.cc:216
 #, c-format
 msgid "weird error when stuffing arguments read from %s: %s\n"
 msgstr "underligt fel när argument lästa från %s stoppades in: %s\n"

-#: monotone.cc:294
+#: monotone.cc:296
 msgid "[OPTION...] command [ARGS...]\n"
 msgstr "[FLAGGOR...] kommando [ARGUMENT...]\n"

-#: monotone.cc:532
+#: monotone.cc:542
 #, c-format
 msgid "syntax error near the \"%s\" option: %s"
 msgstr "syntaxfel nära flaggan \"%s\": %s"

-#: monotone.cc:571
+#: monotone.cc:581
 #, c-format
 msgid "monotone %s doesn't use the option %s"
 msgstr "monotone %s använder inte flaggan %s"

-#: monotone.cc:606
+#: monotone.cc:616
 #, c-format
 msgid "Options specific to 'monotone %s':"
 msgstr "Specifika flaggor för 'monotone %s':"
@@ -2885,53 +2895,53 @@ msgstr "fd %d (%s) har varit inaktiv fö
 msgid "fd %d (peer %s) has been idle too long, disconnecting\n"
 msgstr "fd %d (%s) har varit inaktiv för länge, kopplar ifrån\n"

-#: netsync.cc:2588
+#: netsync.cc:2610
 #, c-format
 msgid "beginning service on %s : %s\n"
 msgstr "startar tjänst på %s : %s\n"

-#: netsync.cc:2603
+#: netsync.cc:2625
 #, c-format
 msgid "session limit %d reached, some connections will be refused\n"
 msgstr ""
 "gränsen för antalet sessioner, %d, är nådd, en del uppkopplingar kommer att "
 "nekas\n"

-#: netsync.cc:2658
+#: netsync.cc:2680
 #, c-format
 msgid "got OOB from peer %s, disconnecting\n"
 msgstr "fick OOB-data från %s, kopplar ifrån\n"

-#: netsync.cc:2713
+#: netsync.cc:2749
 #, c-format
 msgid "finding items to synchronize:\n"
 msgstr "letar efter saker att synkronisera:\n"

-#: netsync.cc:2721
+#: netsync.cc:2757
 msgid "certificates"
 msgstr "certifikat"

-#: netsync.cc:2830
+#: netsync.cc:2866
 #, c-format
 msgid "Cannot find key '%s'"
 msgstr "Kan inte hitta nyckeln '%s'"

-#: netsync.cc:2870
+#: netsync.cc:2906
 #, c-format
 msgid "include branch pattern contains a quote character:\n"
 msgstr "grenmönstret givet med --include innehåller ett citattecken\n"

-#: netsync.cc:2871 netsync.cc:2877
+#: netsync.cc:2907 netsync.cc:2913
 #, c-format
 msgid "%s\n"
 msgstr "%s\n"

-#: netsync.cc:2876
+#: netsync.cc:2912
 #, c-format
 msgid "exclude branch pattern contains a quote character:\n"
 msgstr "grenmönstret givet med --exclude innehåller ett citattecken\n"

-#: netsync.cc:2899 netsync.cc:2903
+#: netsync.cc:2935 netsync.cc:2939
 #, c-format
 msgid "network error: %s"
 msgstr "nätverksfel: %s"
@@ -3114,20 +3124,6 @@ msgstr "bygger om revisionsgrafen från
 msgid "rebuilding revision graph from manifest certs\n"
 msgstr "bygger om revisionsgrafen från manifestcert\n"

-#: sanity.cc:54
-#, c-format
-msgid ""
-"wrote debugging log to %s\n"
-"if reporting a bug, please include this file"
-msgstr ""
-"skrev felsökningslogg till %s\n"
-"om du rapporterar ett fel, var god bifoga den filen"
-
-#: sanity.cc:59
-#, c-format
-msgid "failed to write debugging log to %s\n"
-msgstr "misslyckades med att skriva felsökningsloggen till %s\n"
-
 #: sanity.cc:116
 #, c-format
 msgid "fatal: formatter failed on %s:%d: %s"
@@ -3238,7 +3234,7 @@ msgstr ""
 "Något gick fel när textredigeraren '%s' skulle användas för att skriva ett "
 "loggmeddelande\n"

-#: std_hooks.lua:501
+#: std_hooks.lua:496
 msgid "executing external 3-way merge command\n"
 msgstr "använder externt 3-vägs ihopslagningskommando\n"

@@ -3290,7 +3286,7 @@ msgstr ""
 "var god skicka detta felmeddelande, utskriften av 'monotone --full-version'\n"
 "och en beskrivning av det du gjorde till %s.\n"

-#: ui.cc:412
+#: ui.cc:422
 msgid "monotone: "
 msgstr "monotone: "

@@ -3429,36 +3425,58 @@ msgstr "grundrevisionen %s finns inte i
 msgid "base revision %s does not exist in database\n"
 msgstr "grundrevisionen %s finns inte i databasen\n"

-#: work.cc:776 work.cc:787
+#: work.cc:771
+#, fuzzy, c-format
+msgid "dropping %s"
+msgstr "slänger cert\n"
+
+#: work.cc:782 work.cc:793
 #, c-format
 msgid "path %s already exists"
 msgstr "sökvägen %s finns redan"

-#: work.cc:830
+#: work.cc:821 work.cc:853
 #, c-format
+msgid "adding %s"
+msgstr "lägger till %s"
+
+#: work.cc:837
+#, c-format
 msgid "renaming '%s' onto existing file: '%s'\n"
 msgstr "byter namn på '%s' till redan existerande fil: '%s'\n"

 #: work.cc:849
+#, fuzzy, c-format
+msgid "renaming %s to %s"
+msgstr "uppdaterar %s till %s"
+
+#: work.cc:865
 #, c-format
 msgid "file '%s' does not exist"
 msgstr "filen '%s' finns inte"

-#: work.cc:850
+#: work.cc:866
 #, c-format
 msgid "file '%s' is a directory"
 msgstr "filen '%s' är en katalog"

-#: work.cc:855
+#: work.cc:871
 #, c-format
 msgid "content of file '%s' has changed, not overwriting"
 msgstr "innehållet i filen '%s' har ändrats, skriver inte över"

-#: work.cc:856
+#: work.cc:872
 #, c-format
 msgid "updating %s to %s"
 msgstr "uppdaterar %s till %s"

+#~ msgid ""
+#~ "wrote debugging log to %s\n"
+#~ "if reporting a bug, please include this file"
+#~ msgstr ""
+#~ "skrev felsökningslogg till %s\n"
+#~ "om du rapporterar ett fel, var god bifoga den filen"
+
 #, fuzzy
 #~ msgid "adding %s to workspace delete set\n"
 #~ msgstr "lägger till %s i mängden borttagna filer i arbetskopian\n"
============================================================
--- roster.cc	4547e72b235da17471b9781c3416e7eac2904027
+++ roster.cc	5313de9037e0af779b593f9f432155891a70374a
@@ -982,6 +982,11 @@ editable_roster_base::set_attr(split_pat
   r.set_attr(pth, name, val);
 }

+void
+editable_roster_base::commit()
+{
+}
+
 namespace
 {
   struct true_node_id_source
@@ -2877,19 +2882,18 @@ change_automaton
   }
 };

-struct testing_node_id_source
-  : public node_id_source
+testing_node_id_source::testing_node_id_source()
+  : curr(first_node)
+{}
+
+node_id
+testing_node_id_source::next()
 {
-  testing_node_id_source() : curr(first_node) {}
-  virtual node_id next()
-  {
-    // L(FL("creating node %x\n") % curr);
-    node_id n = curr++;
-    I(!temp_node(n));
-    return n;
-  }
-  node_id curr;
-};
+  // L(FL("creating node %x\n") % curr);
+  node_id n = curr++;
+  I(!temp_node(n));
+  return n;
+}

 template <> void
 dump(int const & i, std::string & out)
============================================================
--- roster.hh	0f6d33d17d3d1c804be21f2e8025d86e47f087f9
+++ roster.hh	0647777b7cab5a2c17419998351f049eadc706d5
@@ -143,6 +143,9 @@ downcast_to_file_t(node_t const n)
   return f;
 }

+bool
+shallow_equal(node_t a, node_t b, bool shallow_compare_dir_children);
+
 template <> void dump(node_t const & n, std::string & out);

 struct marking_t
@@ -277,6 +280,7 @@ public:
   virtual void set_attr(split_path const & pth,
                         attr_key const & name,
                         attr_value const & val);
+  virtual void commit();
 protected:
   roster_t & r;
   node_id_source & nis;
@@ -343,5 +347,17 @@ write_manifest_of_roster(roster_t const
 write_manifest_of_roster(roster_t const & ros,
                          data & dat);

+#ifdef BUILD_UNIT_TESTS
+
+struct testing_node_id_source
+  : public node_id_source
+{
+  testing_node_id_source();
+  virtual node_id next();
+  node_id curr;
+};
+
+#endif // BUILD_UNIT_TESTS
+
 #endif

============================================================
--- roster_merge.cc	4dec4aecf9c67f0ba369c9430bb492a3d93170bf
+++ roster_merge.cc	aa38469bceafec9e94d2ba9c291cf08d6fc90e06
@@ -14,12 +14,8 @@ roster_merge_result::is_clean()
 bool
 roster_merge_result::is_clean()
 {
-  return node_name_conflicts.empty()
-    && file_content_conflicts.empty()
-    && node_attr_conflicts.empty()
-    && orphaned_node_conflicts.empty()
-    && rename_target_conflicts.empty()
-    && directory_loop_conflicts.empty();
+  return is_clean_except_for_content()
+    && file_content_conflicts.empty();
 }

 bool
@@ -35,7 +31,7 @@ roster_merge_result::log_conflicts()
 void
 roster_merge_result::log_conflicts()
 {
-  L(FL("unclean mark-merge: %d name conflicts, %d content conflicts, %d attr conflicts, "
+  L(FL("unclean roster_merge: %d name conflicts, %d content conflicts, %d attr conflicts, "
        "%d orphaned node conflicts, %d rename target conflicts, %d directory loop conflicts\n")
     % node_name_conflicts.size()
     % file_content_conflicts.size()
@@ -173,6 +169,10 @@ namespace
         result = left;
         return true;
       }
+    MM(left_marks);
+    MM(left_uncommon_ancestors);
+    MM(right_marks);
+    MM(right_uncommon_ancestors);
     bool left_wins = a_wins(right_marks, right_uncommon_ancestors);
     bool right_wins = a_wins(left_marks, left_uncommon_ancestors);
     // two bools means 4 cases:
@@ -214,11 +214,11 @@ namespace

   inline void
   insert_if_unborn(node_t const & n,
-                   marking_map const & marking,
+                   marking_map const & markings,
                    std::set<revision_id> const & uncommon_ancestors,
                    roster_t & new_roster)
   {
-    revision_id const & birth = safe_get(marking, n->self).birth_revision;
+    revision_id const & birth = safe_get(markings, n->self).birth_revision;
     if (uncommon_ancestors.find(birth) != uncommon_ancestors.end())
       create_node_for(n, new_roster);
   }
@@ -333,19 +333,18 @@ roster_merge(roster_t const & left_paren

 void
 roster_merge(roster_t const & left_parent,
-             marking_map const & left_marking,
+             marking_map const & left_markings,
              std::set<revision_id> const & left_uncommon_ancestors,
              roster_t const & right_parent,
-             marking_map const & right_marking,
+             marking_map const & right_markings,
              std::set<revision_id> const & right_uncommon_ancestors,
              roster_merge_result & result)
 {
-
   result.clear();
   MM(left_parent);
-  MM(left_marking);
+  MM(left_markings);
   MM(right_parent);
-  MM(right_marking);
+  MM(right_markings);
   MM(result.roster);

   // First handle lifecycles, by die-die-die merge -- our result will contain
@@ -362,13 +361,13 @@ roster_merge(roster_t const & left_paren

           case parallel::in_left:
             insert_if_unborn(i.left_data(),
-                             left_marking, left_uncommon_ancestors,
+                             left_markings, left_uncommon_ancestors,
                              result.roster);
             break;

           case parallel::in_right:
             insert_if_unborn(i.right_data(),
-                             right_marking, right_uncommon_ancestors,
+                             right_markings, right_uncommon_ancestors,
                              result.roster);
             break;

@@ -385,8 +384,8 @@ roster_merge(roster_t const & left_paren
     node_map::const_iterator left_i, right_i;
     parallel::iter<node_map> i(left_parent.all_nodes(), right_parent.all_nodes());
     node_map::const_iterator new_i = result.roster.all_nodes().begin();
-    marking_map::const_iterator left_mi = left_marking.begin();
-    marking_map::const_iterator right_mi = right_marking.begin();
+    marking_map::const_iterator left_mi = left_markings.begin();
+    marking_map::const_iterator right_mi = right_markings.begin();
     while (i.next())
       {
         switch (i.state())
@@ -530,11 +529,179 @@ roster_merge(roster_t const & left_paren
             break;
           }
       }
-    I(left_mi == left_marking.end());
-    I(right_mi == right_marking.end());
+    I(left_mi == left_markings.end());
+    I(right_mi == right_markings.end());
     I(new_i == result.roster.all_nodes().end());
   }
+}

-  // FIXME: looped nodes here
+#ifdef BUILD_UNIT_TESTS
+#include "unit_tests.hh"
+
+// cases for testing:
+//
+// lifecycle, file and dir
+//    alive in both
+//    alive in one and unborn in other (left vs. right)
+//    alive in one and dead in other (left vs. right)
+//
+// mark merge:
+//   same in both, same mark
+//   same in both, diff marks
+//   different, left wins with 1 mark
+//   different, right wins with 1 mark
+//   different, conflict with 1 mark
+//   different, left wins with 2 marks
+//   different, right wins with 2 marks
+//   different, conflict with 1 mark winning, 1 mark losing
+//   different, conflict with 2 marks both conflicting
+//
+// for:
+//   node name, name and parent, file and dir
+//   file content
+//   node attr, file and dir
+//
+// attr lifecycle:
+//   seen in both -- -->mark merge cases
+//   live in one and unseen in other
+//   dead in one and unseen in other
+//
+// two diff nodes with same name
+// directory loops
+// orphans
+// name collision on root dir
+//
+// interactions:
+//   in-node name conflict + possible between-node name conflict
+//   in-node name conflict + both possible names orphaned
+//   in-node name conflict + directory loop conflict
+//   between-node name conflict + both nodes orphaned
+//   between-node name conflict + both nodes cause loop
+
+// need roster, marking, birth revs, and uncommon ancestors for each side...
+
+namespace
+{
+  const revision_id a_uncommon1 = revision_id(std::string("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+  const revision_id a_uncommon2 = revision_id(std::string("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"));
+  const revision_id b_uncommon1 = revision_id(std::string("cccccccccccccccccccccccccccccccccccccccc"));
+  const revision_id b_uncommon2 = revision_id(std::string("dddddddddddddddddddddddddddddddddddddddd"));
+  const revision_id common1 = revision_id(std::string("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"));
+  const revision_id common2 = revision_id(std::string("ffffffffffffffffffffffffffffffffffffffff"));
+
+  const file_id fid1 = file_id(std::string("1111111111111111111111111111111111111111"));
+  const file_id fid2 = file_id(std::string("2222222222222222222222222222222222222222"));
+
+  split_path
+  split(std::string const & s)
+  {
+    split_path sp;
+    file_path_internal(s).split(sp);
+    return sp;
+  }
 }

+static void
+make_dir(roster_t & r, marking_map & markings,
+         revision_id const & birth_rid, revision_id const & parent_name_rid,
+         std::string const & name, node_id nid)
+{
+  r.create_dir_node(nid);
+  r.attach_node(nid, split(name));
+  marking_t marking;
+  marking.birth_revision = birth_rid;
+  marking.parent_name.insert(parent_name_rid);
+  safe_insert(markings, std::make_pair(nid, marking));
+}
+
+static void
+make_file(roster_t & r, marking_map & markings,
+          revision_id const & birth_rid, revision_id const & parent_name_rid,
+          revision_id const & file_content_rid,
+          std::string const & name, file_id const & content,
+          node_id nid)
+{
+  r.create_file_node(content, nid);
+  r.attach_node(nid, split(name));
+  marking_t marking;
+  marking.birth_revision = birth_rid;
+  marking.parent_name.insert(parent_name_rid);
+  marking.file_content.insert(file_content_rid);
+  safe_insert(markings, std::make_pair(nid, marking));
+}
+
+static void
+make_lifecycle_objs(roster_t & r, marking_map & markings, revision_id uncommon,
+                    std::string const & name, node_id common_dir_nid, node_id common_file_nid,
+                    node_id & safe_dir_nid, node_id & safe_file_nid, node_id_source & nis)
+{
+  make_dir(r, markings, common1, common1, "common_old_dir", common_dir_nid);
+  make_file(r, markings, common1, common1, common1, "common_old_file", fid1, common_file_nid);
+  safe_dir_nid = nis.next();
+  make_dir(r, markings, uncommon, uncommon, name + "_safe_dir", safe_dir_nid);
+  safe_file_nid = nis.next();
+  make_file(r, markings, uncommon, uncommon, uncommon, name + "_safe_file", fid1, safe_file_nid);
+  make_dir(r, markings, common1, common1, name + "_dead_dir", nis.next());
+  make_file(r, markings, common1, common1, common1, name + "_dead_file", fid1, nis.next());
+}
+
+
+static void
+test_roster_merge_node_lifecycle()
+{
+  roster_t a_roster, b_roster;
+  marking_map a_markings, b_markings;
+  std::set<revision_id> a_uncommon, b_uncommon;
+  // boilerplate to get uncommon revision sets...
+  a_uncommon.insert(a_uncommon1);
+  a_uncommon.insert(a_uncommon2);
+  b_uncommon.insert(b_uncommon1);
+  b_uncommon.insert(b_uncommon2);
+  testing_node_id_source nis;
+  // boilerplate to set up a root node...
+  {
+    node_id root_nid = nis.next();
+    make_dir(a_roster, a_markings, common1, common1, "", root_nid);
+    make_dir(b_roster, b_markings, common1, common1, "", root_nid);
+  }
+  // create some nodes on each side
+  node_id common_dir_nid = nis.next();
+  node_id common_file_nid = nis.next();
+  node_id a_safe_dir_nid, a_safe_file_nid, b_safe_dir_nid, b_safe_file_nid;
+  make_lifecycle_objs(a_roster, a_markings, a_uncommon1, "a", common_dir_nid, common_file_nid,
+                      a_safe_dir_nid, a_safe_file_nid, nis);
+  make_lifecycle_objs(b_roster, b_markings, b_uncommon1, "b", common_dir_nid, common_file_nid,
+                      b_safe_dir_nid, b_safe_file_nid, nis);
+  // do the merge
+  roster_merge_result result;
+  roster_merge(a_roster, a_markings, a_uncommon, b_roster, b_markings, b_uncommon, result);
+  I(result.is_clean());
+  // 7 = 1 root + 2 common + 2 safe a + 2 safe b
+  I(result.roster.all_nodes().size() == 7);
+  // check that they're the right ones...
+  I(shallow_equal(result.roster.get_node(common_dir_nid),
+                  a_roster.get_node(common_dir_nid), false));
+  I(shallow_equal(result.roster.get_node(common_file_nid),
+                  a_roster.get_node(common_file_nid), false));
+  I(shallow_equal(result.roster.get_node(common_dir_nid),
+                  b_roster.get_node(common_dir_nid), false));
+  I(shallow_equal(result.roster.get_node(common_file_nid),
+                  b_roster.get_node(common_file_nid), false));
+  I(shallow_equal(result.roster.get_node(a_safe_dir_nid),
+                  a_roster.get_node(a_safe_dir_nid), false));
+  I(shallow_equal(result.roster.get_node(a_safe_file_nid),
+                  a_roster.get_node(a_safe_file_nid), false));
+  I(shallow_equal(result.roster.get_node(b_safe_dir_nid),
+                  b_roster.get_node(b_safe_dir_nid), false));
+  I(shallow_equal(result.roster.get_node(b_safe_file_nid),
+                  b_roster.get_node(b_safe_file_nid), false));
+}
+
+void
+add_roster_merge_tests(test_suite * suite)
+{
+  I(suite);
+  suite->add(BOOST_TEST_CASE(&test_roster_merge_node_lifecycle));
+}
+
+#endif // BUILD_UNIT_TESTS
============================================================
--- roster_merge.hh	e9c290f799091e5ecb70e291daae0bff72df2d48
+++ roster_merge.hh	9227745f9aeb67c68ca363dc1df62537c8bcb873
@@ -116,10 +116,10 @@ roster_merge(roster_t const & left_paren

 void
 roster_merge(roster_t const & left_parent,
-             marking_map const & left_marking,
+             marking_map const & left_markings,
              std::set<revision_id> const & left_uncommon_ancestors,
              roster_t const & right_parent,
-             marking_map const & right_marking,
+             marking_map const & right_markings,
              std::set<revision_id> const & right_uncommon_ancestors,
              roster_merge_result & result);

============================================================
--- sanity.cc	b31758131617cacbc373a95c25cab49e15ffedc3
+++ sanity.cc	36f79a9ba2cf13f0f96eb85a36ee0ca1619c39df
@@ -51,12 +51,12 @@ sanity::dump_buffer()
         {
           copy(logbuf.begin(), logbuf.end(), ostream_iterator<char>(out));
           copy(gasp_dump.begin(), gasp_dump.end(), ostream_iterator<char>(out));
-          ui.inform((F("wrote debugging log to %s\n"
-                       "if reporting a bug, please include this file")
-                     % filename).str());
+          ui.inform((FL("wrote debugging log to %s\n"
+                        "if reporting a bug, please include this file")
+                       % filename).str());
         }
       else
-        ui.inform((F("failed to write debugging log to %s\n") % filename).str());
+        ui.inform((FL("failed to write debugging log to %s\n") % filename).str());
     }
   else
     ui.inform("discarding debug log (maybe you want --debug or --dump?)");
============================================================
--- sanity.hh	3d91a4abd21f2af06ea78724a922b3b52fa0838f
+++ sanity.hh	88009f27365f17c86b8dd104021fbcc1cc08a497
@@ -268,15 +268,27 @@ protected:
 };


+// remove_reference is a workaround for C++ defect #106.
 template <typename T>
+struct remove_reference {
+  typedef T type;
+};
+
+template <typename T>
+struct remove_reference <T &> {
+  typedef typename remove_reference<T>::type type;
+};
+
+
+template <typename T>
 class Musing : public MusingI, private MusingBase
 {
 public:
-  Musing(T const & obj, char const * name, char const * file, int line, char const * func)
+  Musing(typename remove_reference<T>::type const & obj, char const * name, char const * file, int line, char const * func)
     : MusingBase(name, file, line, func), obj(obj) {}
   virtual void gasp(std::string & out) const;
 private:
-  T const & obj;
+  typename remove_reference<T>::type const & obj;
 };

 // The header line must be printed into the "out" string before
============================================================
--- sqlite/alter.c	faf98b04050d674d06df21bcf23ded5bbff7b5b7
+++ sqlite/alter.c	451b34fc4eb2475ca76a2e86b21e1030a9428091
@@ -12,7 +12,7 @@
 ** This file contains C code routines that used to generate VDBE code
 ** that implements the ALTER TABLE command.
 **
-** $Id: alter.c,v 1.19 2006/01/31 14:28:45 drh Exp $
+** $Id: alter.c,v 1.20 2006/02/09 02:56:03 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -541,6 +541,7 @@ void sqlite3AlterBeginAddColumn(Parse *p
   for(i=0; i<pNew->nCol; i++){
     Column *pCol = &pNew->aCol[i];
     pCol->zName = sqliteStrDup(pCol->zName);
+    pCol->zColl = 0;
     pCol->zType = 0;
     pCol->pDflt = 0;
   }
============================================================
--- sqlite/btree.c	f45f57e6cbd3b3db947cdd699db64e5215d20b2a
+++ sqlite/btree.c	23bbfb4745e549ca224f6c933a6e9bc106d77f56
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.311 2006/01/24 16:37:58 danielk1977 Exp $
+** $Id: btree.c,v 1.314 2006/02/11 01:25:51 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -411,8 +411,8 @@ struct BtCursor {
 **   The table that this cursor was opened on still exists, but has been
 **   modified since the cursor was last used. The cursor position is saved
 **   in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
-**   this state, restoreOrClearCursorPosition() can be called to attempt to seek
-**   the cursor to the saved position.
+**   this state, restoreOrClearCursorPosition() can be called to attempt to
+**   seek the cursor to the saved position.
 */
 #define CURSOR_INVALID           0
 #define CURSOR_VALID             1
@@ -756,10 +756,20 @@ static void unlockAllTables(Btree *p){
 ** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
 ** this test.
 */
-#define PTRMAP_PAGENO(pgsz, pgno) (((pgno-2)/(pgsz/5+1))*(pgsz/5+1)+2)
-#define PTRMAP_PTROFFSET(pgsz, pgno) (((pgno-2)%(pgsz/5+1)-1)*5)
-#define PTRMAP_ISPAGE(pgsz, pgno) (PTRMAP_PAGENO(pgsz,pgno)==pgno)
+#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
+#define PTRMAP_PTROFFSET(pBt, pgno) (5*(pgno-ptrmapPageno(pBt, pgno)-1))
+#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))

+static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
+  int nPagesPerMapPage = (pBt->usableSize/5)+1;
+  int iPtrMap = (pgno-2)/nPagesPerMapPage;
+  int ret = (iPtrMap*nPagesPerMapPage) + 2;
+  if( ret==PENDING_BYTE_PAGE(pBt) ){
+    ret++;
+  }
+  return ret;
+}
+
 /*
 ** The pointer map is a lookup table that identifies the parent page for
 ** each child page in the database file.  The parent page is the page that
@@ -810,16 +820,19 @@ static int ptrmapPut(BtShared *pBt, Pgno
   int offset;     /* Offset in pointer map page */
   int rc;

+  /* The master-journal page number must never be used as a pointer map page */
+  assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) );
+
   assert( pBt->autoVacuum );
   if( key==0 ){
     return SQLITE_CORRUPT_BKPT;
   }
-  iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
+  iPtrmap = PTRMAP_PAGENO(pBt, key);
   rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
   if( rc!=SQLITE_OK ){
     return rc;
   }
-  offset = PTRMAP_PTROFFSET(pBt->usableSize, key);
+  offset = PTRMAP_PTROFFSET(pBt, key);

   if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
     TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
@@ -847,13 +860,13 @@ static int ptrmapGet(BtShared *pBt, Pgno
   int offset;        /* Offset of entry in pointer map */
   int rc;

-  iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
+  iPtrmap = PTRMAP_PAGENO(pBt, key);
   rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
   if( rc!=0 ){
     return rc;
   }

-  offset = PTRMAP_PTROFFSET(pBt->usableSize, key);
+  offset = PTRMAP_PTROFFSET(pBt, key);
   if( pEType ) *pEType = pPtrmap[offset];
   if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);

@@ -1790,9 +1803,9 @@ int sqlite3BtreeSetCacheSize(Btree *p, i
 ** probability of damage to near zero but with a write performance reduction.
 */
 #ifndef SQLITE_OMIT_PAGER_PRAGMAS
-int sqlite3BtreeSetSafetyLevel(Btree *p, int level){
+int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
   BtShared *pBt = p->pBt;
-  sqlite3pager_set_safety_level(pBt->pPager, level);
+  sqlite3pager_set_safety_level(pBt->pPager, level, fullSync);
   return SQLITE_OK;
 }
 #endif
@@ -2344,7 +2357,7 @@ static int autoVacuumCommit(BtShared *pB
 #endif

   assert( pBt->autoVacuum );
-  if( PTRMAP_ISPAGE(pgsz, sqlite3pager_pagecount(pPager)) ){
+  if( PTRMAP_ISPAGE(pBt, sqlite3pager_pagecount(pPager)) ){
     return SQLITE_CORRUPT_BKPT;
   }

@@ -2357,15 +2370,27 @@ static int autoVacuumCommit(BtShared *pB
     return SQLITE_OK;
   }

+  /* This block figures out how many pages there are in the database
+  ** now (variable origSize), and how many there will be after the
+  ** truncation (variable finSize).
+  **
+  ** The final size is the original size, less the number of free pages
+  ** in the database, less any pointer-map pages that will no longer
+  ** be required, less 1 if the pending-byte page was part of the database
+  ** but is not after the truncation.
+  **/
   origSize = sqlite3pager_pagecount(pPager);
-  nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5);
+  if( origSize==PENDING_BYTE_PAGE(pBt) ){
+    origSize--;
+  }
+  nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pBt, origSize)+pgsz/5)/(pgsz/5);
   finSize = origSize - nFreeList - nPtrMap;
-  if( origSize>=PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
+  if( origSize>PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
     finSize--;
-    if( PTRMAP_ISPAGE(pBt->usableSize, finSize) ){
-      finSize--;
-    }
   }
+  while( PTRMAP_ISPAGE(pBt, finSize) || finSize==PENDING_BYTE_PAGE(pBt) ){
+    finSize--;
+  }
   TRACE(("AUTOVACUUM: Begin (db size %d->%d)\n", origSize, finSize));

   /* Variable 'finSize' will be the size of the file in pages after
@@ -2376,7 +2401,7 @@ static int autoVacuumCommit(BtShared *pB
   */
   for( iDbPage=finSize+1; iDbPage<=origSize; iDbPage++ ){
     /* If iDbPage is a pointer map page, or the pending-byte page, skip it. */
-    if( PTRMAP_ISPAGE(pgsz, iDbPage) || iDbPage==PENDING_BYTE_PAGE(pBt) ){
+    if( PTRMAP_ISPAGE(pBt, iDbPage) || iDbPage==PENDING_BYTE_PAGE(pBt) ){
       continue;
     }

@@ -2434,6 +2459,7 @@ static int autoVacuumCommit(BtShared *pB
   put4byte(&pBt->pPage1->aData[36], 0);
   if( rc!=SQLITE_OK ) goto autovacuum_out;
   *nTrunc = finSize;
+  assert( finSize!=PENDING_BYTE_PAGE(pBt) );

 autovacuum_out:
   assert( nRef==*sqlite3pager_stats(pPager) );
@@ -3806,7 +3832,7 @@ static int allocatePage(
     *pPgno = sqlite3pager_pagecount(pBt->pPager) + 1;

 #ifndef SQLITE_OMIT_AUTOVACUUM
-    if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt->usableSize, *pPgno) ){
+    if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
       /* If *pPgno refers to a pointer-map page, allocate two new pages
       ** at the end of the file instead of one. The first allocated page
       ** becomes a new pointer-map page, the second is used by the caller.
@@ -5440,7 +5466,7 @@ int sqlite3BtreeCreateTable(Btree *p, in
     /* The new root-page may not be allocated on a pointer-map page, or the
     ** PENDING_BYTE page.
     */
-    if( pgnoRoot==PTRMAP_PAGENO(pBt->usableSize, pgnoRoot) ||
+    if( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) ||
         pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
       pgnoRoot++;
     }
@@ -5713,7 +5739,7 @@ int sqlite3BtreeDropTable(Btree *p, int
       if( maxRootPgno==PENDING_BYTE_PAGE(pBt) ){
         maxRootPgno--;
       }
-      if( maxRootPgno==PTRMAP_PAGENO(pBt->usableSize, maxRootPgno) ){
+      if( maxRootPgno==PTRMAP_PAGENO(pBt, maxRootPgno) ){
         maxRootPgno--;
       }
       assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
@@ -6390,11 +6416,11 @@ char *sqlite3BtreeIntegrityCheck(Btree *
     ** references to pointer-map pages.
     */
     if( sCheck.anRef[i]==0 &&
-       (PTRMAP_PAGENO(pBt->usableSize, i)!=i || !pBt->autoVacuum) ){
+       (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
       checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
     }
     if( sCheck.anRef[i]!=0 &&
-       (PTRMAP_PAGENO(pBt->usableSize, i)==i && pBt->autoVacuum) ){
+       (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
       checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
     }
 #endif
@@ -6522,19 +6548,21 @@ int sqlite3BtreeSync(Btree *p, const cha
 ** the write-transaction for this database file is to delete the journal.
 */
 int sqlite3BtreeSync(Btree *p, const char *zMaster){
+  int rc = SQLITE_OK;
   if( p->inTrans==TRANS_WRITE ){
     BtShared *pBt = p->pBt;
-#ifndef SQLITE_OMIT_AUTOVACUUM
     Pgno nTrunc = 0;
+#ifndef SQLITE_OMIT_AUTOVACUUM
     if( pBt->autoVacuum ){
-      int rc = autoVacuumCommit(pBt, &nTrunc);
-      if( rc!=SQLITE_OK ) return rc;
+      rc = autoVacuumCommit(pBt, &nTrunc);
+      if( rc!=SQLITE_OK ){
+        return rc;
+      }
     }
-    return sqlite3pager_sync(pBt->pPager, zMaster, nTrunc);
 #endif
-    return sqlite3pager_sync(pBt->pPager, zMaster, 0);
+    rc = sqlite3pager_sync(pBt->pPager, zMaster, nTrunc);
   }
-  return SQLITE_OK;
+  return rc;
 }

 /*
============================================================
--- sqlite/btree.h	5663c4f43e8521546ccebc8fc95acb013b8f3184
+++ sqlite/btree.h	40055cfc09defd1146bc5b922399c035f969e56d
@@ -13,7 +13,7 @@
 ** subsystem.  See comments in the source code for a detailed description
 ** of what each interface routine does.
 **
-** @(#) $Id: btree.h,v 1.69 2006/01/07 13:21:04 danielk1977 Exp $
+** @(#) $Id: btree.h,v 1.70 2006/02/11 01:25:51 drh Exp $
 */
 #ifndef _BTREE_H_
 #define _BTREE_H_
@@ -59,7 +59,7 @@ int sqlite3BtreeSetCacheSize(Btree*,int)
 int sqlite3BtreeClose(Btree*);
 int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
 int sqlite3BtreeSetCacheSize(Btree*,int);
-int sqlite3BtreeSetSafetyLevel(Btree*,int);
+int sqlite3BtreeSetSafetyLevel(Btree*,int,int);
 int sqlite3BtreeSyncDisabled(Btree*);
 int sqlite3BtreeSetPageSize(Btree*,int,int);
 int sqlite3BtreeGetPageSize(Btree*);
============================================================
--- sqlite/build.c	feaa61e769d7887ffeaa060d746638c7b3e994ef
+++ sqlite/build.c	b46cd7d0e2daca775d9de0cba8abae1b1625caf4
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.383 2006/01/24 12:09:19 danielk1977 Exp $
+** $Id: build.c,v 1.386 2006/02/10 18:08:09 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1662,12 +1662,10 @@ int sqlite3ViewGetColumnNames(Parse *pPa
   ** Actually, this error is caught previously and so the following test
   ** should always fail.  But we will leave it in place just to be safe.
   */
-#if 0
   if( pTable->nCol<0 ){
     sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName);
     return 1;
   }
-#endif
   assert( pTable->nCol>=0 );

   /* If we get this far, it means we need to compute the table names.
@@ -2364,10 +2362,10 @@ void sqlite3CreateIndex(
       nExtra                       /* Collation sequence names */
   );
   if( sqlite3MallocFailed() ) goto exit_create_index;
-  pIndex->aiColumn = (int *)(&pIndex[1]);
+  pIndex->azColl = (char**)(&pIndex[1]);
+  pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]);
   pIndex->aiRowEst = (unsigned *)(&pIndex->aiColumn[nCol]);
-  pIndex->azColl = (char **)(&pIndex->aiRowEst[nCol+1]);
-  pIndex->aSortOrder = (u8 *)(&pIndex->azColl[nCol]);
+  pIndex->aSortOrder = (u8 *)(&pIndex->aiRowEst[nCol+1]);
   pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]);
   zExtra = (char *)(&pIndex->zName[nName+1]);
   strcpy(pIndex->zName, zName);
@@ -2849,6 +2847,7 @@ SrcList *sqlite3SrcListAppend(SrcList *p
   pItem->zName = sqlite3NameFromToken(pTable);
   pItem->zDatabase = sqlite3NameFromToken(pDatabase);
   pItem->iCursor = -1;
+  pItem->isPopulated = 0;
   pList->nSrc++;
   return pList;
 }
============================================================
--- sqlite/date.c	c70a4f88e495ae2c523f6ef3848c26a021c96de8
+++ sqlite/date.c	cd2bd5d1ebc6fa12d6312f69789ae5b0a2766f2e
@@ -16,7 +16,7 @@
 ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
 ** All other code has file scope.
 **
-** $Id: date.c,v 1.53 2006/01/24 12:09:19 danielk1977 Exp $
+** $Id: date.c,v 1.54 2006/01/31 20:49:13 drh Exp $
 **
 ** NOTES:
 **
@@ -117,8 +117,8 @@ static int getDigits(const char *zDate,
     zDate++;
     cnt++;
   }while( nextC );
+end_getDigits:
   va_end(ap);
-end_getDigits:
   return cnt;
 }

============================================================
--- sqlite/delete.c	56ab34c3a384caa5d5ea06f5739944957e2e4213
+++ sqlite/delete.c	ca404d5fd5f678e32f2f46377ad802cd0219aa99
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** in order to generate code for DELETE FROM statements.
 **
-** $Id: delete.c,v 1.120 2006/01/24 12:09:19 danielk1977 Exp $
+** $Id: delete.c,v 1.121 2006/02/10 02:27:43 danielk1977 Exp $
 */
 #include "sqliteInt.h"

@@ -343,7 +343,7 @@ void sqlite3DeleteFrom(
   if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
     sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
     sqlite3VdbeSetNumCols(v, 1);
-    sqlite3VdbeSetColName(v, 0, "rows deleted", P3_STATIC);
+    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC);
   }

 delete_from_cleanup:
============================================================
--- sqlite/expr.c	1149c3380bfce27703f5e9bec7dfb8e51baaf9d9
+++ sqlite/expr.c	9c957fabf95ef62288151eecd5c490a629470666
@@ -12,7 +12,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions in SQLite.
 **
-** $Id: expr.c,v 1.253 2006/01/30 14:36:59 drh Exp $
+** $Id: expr.c,v 1.254 2006/02/10 07:07:15 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -495,6 +495,7 @@ SrcList *sqlite3SrcListDup(SrcList *p){
     pNewItem->zAlias = sqliteStrDup(pOldItem->zAlias);
     pNewItem->jointype = pOldItem->jointype;
     pNewItem->iCursor = pOldItem->iCursor;
+    pNewItem->isPopulated = pOldItem->isPopulated;
     pTab = pNewItem->pTab = pOldItem->pTab;
     if( pTab ){
       pTab->nRef++;
============================================================
--- sqlite/func.c	96b26601c092b7b43a13e440e3f988b32a385f6a
+++ sqlite/func.c	93d004b453a5d9aa754e673eef75d3c9527e0f54
@@ -16,7 +16,7 @@
 ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
 ** All other code has file scope.
 **
-** $Id: func.c,v 1.117 2006/01/17 13:21:40 danielk1977 Exp $
+** $Id: func.c,v 1.121 2006/02/09 22:13:42 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -817,9 +817,9 @@ struct SumCtx {
 */
 typedef struct SumCtx SumCtx;
 struct SumCtx {
-  double sum;     /* Sum of terms */
-  int cnt;        /* Number of elements summed */
-  u8 seenFloat;   /* True if there has been any floating point value */
+  LONGDOUBLE_TYPE sum;    /* Sum of terms */
+  i64 cnt;                /* Number of elements summed */
+  u8 approx;              /* True if sum is approximate */
 };

 /*
@@ -830,18 +830,33 @@ struct SumCtx {
 ** 0.0 in that case.  In addition, TOTAL always returns a float where
 ** SUM might return an integer if it never encounters a floating point
 ** value.
+**
+** I am told that SUM() should raise an exception if it encounters
+** a integer overflow.  But after pondering this, I decided that
+** behavior leads to brittle programs.  So instead, I have coded
+** SUM() to revert to using floating point if it encounters an
+** integer overflow.  The answer may not be exact, but it will be
+** close.  If the SUM() function returns an integer, the value is
+** exact.  If SUM() returns a floating point value, it means the
+** value might be approximated.
 */
 static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
   SumCtx *p;
   int type;
   assert( argc==1 );
   p = sqlite3_aggregate_context(context, sizeof(*p));
-  type = sqlite3_value_type(argv[0]);
+  type = sqlite3_value_numeric_type(argv[0]);
   if( p && type!=SQLITE_NULL ){
-    p->sum += sqlite3_value_double(argv[0]);
     p->cnt++;
-    if( type==SQLITE_FLOAT ){
-      p->seenFloat = 1;
+    if( type==SQLITE_INTEGER ){
+      p->sum += sqlite3_value_int64(argv[0]);
+      if( !p->approx ){
+        i64 iVal;
+        p->approx = p->sum!=(LONGDOUBLE_TYPE)(iVal = (i64)p->sum);
+      }
+    }else{
+      p->sum += sqlite3_value_double(argv[0]);
+      p->approx = 1;
     }
   }
 }
@@ -849,7 +864,7 @@ static void sumFinalize(sqlite3_context
   SumCtx *p;
   p = sqlite3_aggregate_context(context, 0);
   if( p && p->cnt>0 ){
-    if( p->seenFloat ){
+    if( p->approx ){
       sqlite3_result_double(context, p->sum);
     }else{
       sqlite3_result_int64(context, (i64)p->sum);
@@ -870,23 +885,12 @@ static void totalFinalize(sqlite3_contex
 }

 /*
-** An instance of the following structure holds the context of a
-** variance or standard deviation computation.
-*/
-typedef struct StdDevCtx StdDevCtx;
-struct StdDevCtx {
-  double sum;     /* Sum of terms */
-  double sum2;    /* Sum of the squares of terms */
-  int cnt;        /* Number of terms counted */
-};
-
-/*
 ** The following structure keeps track of state information for the
 ** count() aggregate function.
 */
 typedef struct CountCtx CountCtx;
 struct CountCtx {
-  int n;
+  i64 n;
 };

 /*
@@ -902,7 +906,7 @@ static void countFinalize(sqlite3_contex
 static void countFinalize(sqlite3_context *context){
   CountCtx *p;
   p = sqlite3_aggregate_context(context, 0);
-  sqlite3_result_int(context, p ? p->n : 0);
+  sqlite3_result_int64(context, p ? p->n : 0);
 }

 /*
============================================================
--- sqlite/insert.c	7e931b7f06afbcefcbbaab175c02eff8268db33f
+++ sqlite/insert.c	67b3dc11831c58d8703eb502355ad3704ee18f66
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.160 2006/01/24 12:09:19 danielk1977 Exp $
+** $Id: insert.c,v 1.161 2006/02/10 02:27:43 danielk1977 Exp $
 */
 #include "sqliteInt.h"

@@ -703,7 +703,7 @@ void sqlite3Insert(
     sqlite3VdbeAddOp(v, OP_MemLoad, iCntMem, 0);
     sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
     sqlite3VdbeSetNumCols(v, 1);
-    sqlite3VdbeSetColName(v, 0, "rows inserted", P3_STATIC);
+    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", P3_STATIC);
   }

 insert_cleanup:
============================================================
--- sqlite/main.c	2693776249865dc69b97904205638e84a34a059c
+++ sqlite/main.c	9a42464c44a6532003391486e802e65e88789cfc
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.331 2006/01/24 16:37:58 danielk1977 Exp $
+** $Id: main.c,v 1.334 2006/02/09 13:43:29 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -29,7 +29,6 @@ const int sqlite3one = 1;
 /*
 ** The version of the library
 */
-const char rcsid3[] = "@(#) \044Id: SQLite version " SQLITE_VERSION " $";
 const char sqlite3_version[] = SQLITE_VERSION;
 const char *sqlite3_libversion(void){ return sqlite3_version; }
 int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
@@ -732,6 +731,10 @@ int sqlite3_errcode(sqlite3 *db){
   return db->errCode;
 }

+/*
+** Create a new collating function for database "db".  The name is zName
+** and the encoding is enc.
+*/
 static int createCollation(
   sqlite3* db,
   const char *zName,
@@ -817,8 +820,9 @@ static int openDatabase(
   ** and UTF-16, so add a version for each to avoid any unnecessary
   ** conversions. The only error that can occur here is a malloc() failure.
   */
-  if( createCollation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) ||
-      createCollation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) ||
+  if( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc) ||
+      createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc) ||
+      createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc) ||
       (db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0
   ){
     assert( sqlite3MallocFailed() );
@@ -1113,3 +1117,117 @@ void sqlite3_thread_cleanup(void){
     sqlite3OsThreadSpecificData(-1);
   }
 }
+
+/*
+** Return meta information about a specific column of a database table.
+** See comment in sqlite3.h (sqlite.h.in) for details.
+*/
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
+int sqlite3_table_column_metadata(
+  sqlite3 *db,                /* Connection handle */
+  const char *zDbName,        /* Database name or NULL */
+  const char *zTableName,     /* Table name */
+  const char *zColumnName,    /* Column name */
+  char const **pzDataType,    /* OUTPUT: Declared data type */
+  char const **pzCollSeq,     /* OUTPUT: Collation sequence name */