{"thread":{"id":"30523","subject":"cherry-pick is slow","startedAt":"2012-05-12T22:39:36Z","lastAt":"2012-05-19T00:54:24Z","messageCount":9,"participants":["Dmitry Risenberg","Junio C Hamano","Jeff King","Paweł Sikora"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"191461","messageId":"CAPZ_ugYojqTaWi0atr2ApOu9xmcwy4y8FduNC+TDhgWgSxXNPQ@mail.gmail.com","threadId":"30523","inReplyTo":null,"subject":"cherry-pick is slow","fromName":"Dmitry Risenberg","fromEmail":"dmitry.risenberg@gmail.com","sentAt":"2012-05-12T22:39:36Z","receivedAt":"2012-05-12T22:39:36Z","isPatch":false,"sender":{"key":"dmitry.risenberg@gmail.com","avatar":null},"body":"Hello.\n\nI have a very big git repository (the .git directory is about 5.3 Gb),\nwhich is a copy of an svn repository fetched via git-svn. In fact\nthere are a few repositories (\"working copies\") that share the same\n.git directory (via symlinks), in which I have different svn branches\nchecked out. Now I want to merge a commit from one svn branch to\nanother via git cherry-pick. The commit contains diff in only one\nfile. So I do\n\ngit cherry-pick <commit>\n\nAnd the operation takes tens of seconds to finish. In \"top\" output I\nsee that git process uses almost no CPU, but has hundreds of page\nfaults, so I assume that it is reading a lot of files from disk. I\nalso tried running git in gdb and interrupting it in random places,\nthe stacktrace I get is usually like this:\n\n#0  0x00000000004fb70c in experimental_loose_object (\n    map=0x3268e000\n\"x\\001+)JMU043g040031QpöMÌNõÉ,.)Ö+©(aøt*äãú½\\vÍ4\\236Yñ\\230¤&z¯ß<{º\\211\\001\\020(¤eV0\\024\\177ò\\177á$\\\\$\\034\\224\\036ö*÷vÂ\\216#3ºâ!²\\231)@Ù*íü»Ü7\\233BmÜ\\005^·\\034ñÏOä¨\\205Èæf\\227\\024e¦2¬fÐ\\tY¾}Ñ³\\212,û\\027î<ê\\236[³w\\234\\204*(Í)Éd0ø\\024\\030n\\233øìP\\210\\214üDSÆ?ó\\216½¹>\\a\")\nat sha1_file.c:1259\n#1  0x00000000004fb8df in unpack_sha1_header (stream=0x7fffffffc9f0,\n    map=0x3268e000\n\"x\\001+)JMU043g040031QpöMÌNõÉ,.)Ö+©(aøt*äãú½\\vÍ4\\236Yñ\\230¤&z¯ß<{º\\211\\001\\020(¤eV0\\024\\177ò\\177á$\\\\$\\034\\224\\036ö*÷vÂ\\216#3ºâ!²\\231)@Ù*íü»Ü7\\233BmÜ\\005^·\\034ñÏOä¨\\205Èæf\\227\\024e¦2¬fÐ\\tY¾}Ñ³\\212,û\\027î<ê\\236[³w\\234\\204*(Í)Éd0ø\\024\\030n\\233øìP\\210\\214üDSÆ?ó\\216½¹>\\a\",\nmapsize=173,\n    buffer=0x7fffffffa9f0, bufsiz=8192) at sha1_file.c:1308\n#2  0x00000000004fbc85 in unpack_sha1_file (map=0x3268e000,\nmapsize=173, type=0x7fffffffcbf0, size=0x7fffffffcbe8,\n    sha1=0x7fffffffcbd0 \"\\001/Ç4&ç®º\\036© wK`\\214\\\"Ë\\035H\\203\") at\nsha1_file.c:1435\n#3  0x00000000004fd96c in read_object (sha1=0x7fffffffcbd0\n\"\\001/Ç4&ç®º\\036© wK`\\214\\\"Ë\\035H\\203\", type=0x7fffffffcbf0,\nsize=0x7fffffffcbe8)\n    at sha1_file.c:2233\n#4  0x00000000004fda0d in read_sha1_file_extended (sha1=0x7fffffffcbd0\n\"\\001/Ç4&ç®º\\036© wK`\\214\\\"Ë\\035H\\203\", type=0x7fffffffcbf0,\nsize=0x7fffffffcbe8,\n    flag=1) at sha1_file.c:2258\n#5  0x00000000004fdcda in read_sha1_file (sha1=0x7fffffffcbd0\n\"\\001/Ç4&ç®º\\036© wK`\\214\\\"Ë\\035H\\203\", type=0x7fffffffcbf0,\nsize=0x7fffffffcbe8)\n    at cache.h:761\n#6  0x00000000004fdbb1 in read_object_with_reference (sha1=0x334a8130\n\"\\001/Ç4&ç®º\\036© wK`\\214\\\"Ë\\035H\\203\", required_type_name=0x55a1a0\n\"tree\",\n    size=0x7fffffffcc30, actual_sha1_return=0x0) at sha1_file.c:2299\n#7  0x0000000000510f50 in fill_tree_descriptor (desc=0x7fffffffcd10,\nsha1=0x334a8130 \"\\001/Ç4&ç®º\\036© wK`\\214\\\"Ë\\035H\\203\") at\ntree-walk.c:57\n#8  0x00000000005133dd in traverse_trees_recursive (n=1, dirmask=1,\ndf_conflicts=0, names=0x349d68a0, info=0x7fffffffd020) at\nunpack-trees.c:456\n#9  0x0000000000514239 in unpack_callback (n=1, mask=1, dirmask=1,\nnames=0x349d68a0, info=0x7fffffffd020) at unpack-trees.c:809\n#10 0x00000000005119c9 in traverse_trees (n=1, t=0x7fffffffd0b0,\ninfo=0x7fffffffd020) at tree-walk.c:407\n#11 0x000000000051342d in traverse_trees_recursive (n=1, dirmask=0,\ndf_conflicts=0, names=0x349d6860, info=0x7fffffffd3c0) at\nunpack-trees.c:460\n#12 0x0000000000514239 in unpack_callback (n=1, mask=1, dirmask=1,\nnames=0x349d6860, info=0x7fffffffd3c0) at unpack-trees.c:809\n#13 0x00000000005119c9 in traverse_trees (n=1, t=0x7fffffffd450,\ninfo=0x7fffffffd3c0) at tree-walk.c:407\n#14 0x000000000051342d in traverse_trees_recursive (n=1, dirmask=0,\ndf_conflicts=0, names=0x349d6840, info=0x7fffffffd760) at\nunpack-trees.c:460\n#15 0x0000000000514239 in unpack_callback (n=1, mask=1, dirmask=1,\nnames=0x349d6840, info=0x7fffffffd760) at unpack-trees.c:809\n#16 0x00000000005119c9 in traverse_trees (n=1, t=0x7fffffffda40,\ninfo=0x7fffffffd760) at tree-walk.c:407\n#17 0x0000000000514af5 in unpack_trees (len=1, t=0x7fffffffda40,\no=0x7fffffffd830) at unpack-trees.c:1063\n#18 0x000000000049f140 in diff_cache (revs=0x7fffffffdaf0,\ntree_sha1=0x32f3b094 \"ò\\032'\\023\\220U\", tree_name=0x546766 \"HEAD\",\ncached=1) at diff-lib.c:476\n#19 0x000000000049f18a in run_diff_index (revs=0x7fffffffdaf0,\ncached=1) at diff-lib.c:484\n#20 0x000000000049f34d in index_differs_from (def=0x546766 \"HEAD\",\ndiff_flags=0) at diff-lib.c:519\n#21 0x0000000000470288 in do_pick_commit (commit=0x32f3b000,\nopts=0x7fffffffe270) at builtin/revert.c:502\n#22 0x0000000000471d38 in single_pick (cmit=0x32f3b000,\nopts=0x7fffffffe270) at builtin/revert.c:1069\n#23 0x0000000000471ea9 in pick_revisions (opts=0x7fffffffe270) at\nbuiltin/revert.c:1113\n#24 0x0000000000472045 in cmd_cherry_pick (argc=2,\nargv=0x7fffffffe4c0, prefix=0x6a81c1 ) at builtin/revert.c:1161\n#25 0x0000000000405093 in run_builtin (p=0x65d190, argc=2,\nargv=0x7fffffffe4c0) at git.c:308\n#26 0x0000000000405288 in handle_internal_command (argc=2,\nargv=0x7fffffffe4c0) at git.c:467\n\nIt always interrupts inside experimental_loose_object, when reading\nmemory-mapped data from disk(?).\n\ngit diff <commit>^ <commit>\n\nworks blazingly fast, so I assume that cherry-picking should also be,\nbut it is not. What can I do to make the cherry-picking go quicker?\n\nI am using git 1.7.10 on FreeBSD 7.2.\n\n-- \nDmitry Risenberg\n"},{"id":"191462","messageId":"CAPc5daW6eBLUf55_Qk+4bA6Y16TehfOUGc1xFzhib9vm=8O2Yw@mail.gmail.com","threadId":"30523","inReplyTo":"CAPZ_ugYojqTaWi0atr2ApOu9xmcwy4y8FduNC+TDhgWgSxXNPQ@mail.gmail.com","subject":"Re: cherry-pick is slow","fromName":"Junio C Hamano","fromEmail":"gitster-vger@pobox.com","sentAt":"2012-05-13T01:11:11Z","receivedAt":"2012-05-13T01:11:11Z","isPatch":false,"sender":{"key":"gitster-vger@pobox.com","avatar":null},"body":"On Sat, May 12, 2012 at 3:39 PM, Dmitry Risenberg\n<dmitry.risenberg@gmail.com> wrote:\n>\n> Hello.\n>\n> I have a very big git repository (the .git directory is about 5.3 Gb),\n> which is a copy of an svn repository fetched via git-svn. In fact\n> there are a few repositories (\"working copies\") that share the same\n> .git directory (via symlinks), in which I have different svn branches\n> checked out. Now I want to merge a commit from one svn branch to\n> another via git cherry-pick. The commit contains diff in only one\n> file. So I do\n>\n> git cherry-pick <commit>\n>\n> And the operation takes tens of seconds to finish. In \"top\" output I\n> see that git process uses almost no CPU, but has hundreds of page\n> faults, so I assume that it is reading a lot of files from disk.\n\nWild guess: poorly (or worse yet, never) packed repository?\n"},{"id":"191467","messageId":"CAPZ_ugbV6hB+8z8UsQKdHhxGuHbLzC5WK19mK7M8k2tMz+mtXw@mail.gmail.com","threadId":"30523","inReplyTo":"CAPc5daW6eBLUf55_Qk+4bA6Y16TehfOUGc1xFzhib9vm=8O2Yw@mail.gmail.com","subject":"Re: cherry-pick is slow","fromName":"Dmitry Risenberg","fromEmail":"dmitry.risenberg@gmail.com","sentAt":"2012-05-13T15:39:49Z","receivedAt":"2012-05-13T15:39:49Z","isPatch":false,"sender":{"key":"dmitry.risenberg@gmail.com","avatar":null},"body":"2012/5/13 Junio C Hamano <gitster-vger@pobox.com>:\n> On Sat, May 12, 2012 at 3:39 PM, Dmitry Risenberg\n> <dmitry.risenberg@gmail.com> wrote:\n>>\n>> Hello.\n>>\n>> I have a very big git repository (the .git directory is about 5.3 Gb),\n>> which is a copy of an svn repository fetched via git-svn. In fact\n>> there are a few repositories (\"working copies\") that share the same\n>> .git directory (via symlinks), in which I have different svn branches\n>> checked out. Now I want to merge a commit from one svn branch to\n>> another via git cherry-pick. The commit contains diff in only one\n>> file. So I do\n>>\n>> git cherry-pick <commit>\n>>\n>> And the operation takes tens of seconds to finish. In \"top\" output I\n>> see that git process uses almost no CPU, but has hundreds of page\n>> faults, so I assume that it is reading a lot of files from disk.\n>\n> Wild guess: poorly (or worse yet, never) packed repository?\n\nYou were absolutely right.\nI set \"gc.auto = 0\" during the initial checkout of svn and forgot to\nturn it on afterwards. After running \"git gc\", my repo became two\ntimes smaller, and git operations are now running much faster.\n\nHowever, cherry-picking is still not as fast as I expected it to be -\ncherry-picking a single-file commit takes about 14-15 seconds, fully\nusing one CPU core. Anything else I can improve?\n\n-- \nDmitry Risenberg\n"},{"id":"191492","messageId":"20120514145412.GA1159@sigill.intra.peff.net","threadId":"30523","inReplyTo":"CAPZ_ugbV6hB+8z8UsQKdHhxGuHbLzC5WK19mK7M8k2tMz+mtXw@mail.gmail.com","subject":"Re: cherry-pick is slow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-05-14T14:54:12Z","receivedAt":"2012-05-14T14:54:12Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, May 13, 2012 at 07:39:49PM +0400, Dmitry Risenberg wrote:\n\n> However, cherry-picking is still not as fast as I expected it to be -\n> cherry-picking a single-file commit takes about 14-15 seconds, fully\n> using one CPU core. Anything else I can improve?\n\nIt's probably detecting renames as part of the merge, which can be\nexpensive if the thing you are cherry-picking is far away from HEAD. You\ncan try setting the merge.renamelimit config variable to something small\n(like 1; setting it to 0 means \"no limit\").\n\n-Peff\n"},{"id":"191547","messageId":"20120515132451.GA25378@sigill.intra.peff.net","threadId":"30523","inReplyTo":"CAPZ_ugbD=mOPBs6GyapWtv6NWuJ-=r2+bqBN9n+gdTPwGj3F0Q@mail.gmail.com","subject":"Re: cherry-pick is slow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-05-15T13:24:51Z","receivedAt":"2012-05-15T13:24:51Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"[let's keep this on-list so others can benefit from the discussion]\n\nOn Tue, May 15, 2012 at 12:38:59PM +0400, Dmitry Risenberg wrote:\n\n> > It's probably detecting renames as part of the merge, which can be\n> > expensive if the thing you are cherry-picking is far away from HEAD. You\n> > can try setting the merge.renamelimit config variable to something small\n> > (like 1; setting it to 0 means \"no limit\").\n> \n> I set it to 1, but it didn't help at all - cherry-pick time is still\n> about the same.\n\nOK, then my guess was probably wrong. You'll have to try profiling (if\nyou are on Linux, \"perf record git cherry-pick ...\"; perf report\" is the\nsimplest way). Or if the repository is publicly available, I can do a\nquick profile run.\n\n-Peff\n"},{"id":"191563","messageId":"29715654.5ciT9KkCQq@localhost","threadId":"30523","inReplyTo":"20120515132451.GA25378@sigill.intra.peff.net","subject":"Re: cherry-pick is slow","fromName":"Paweł Sikora","fromEmail":"pawel.sikora@agmk.net","sentAt":"2012-05-15T18:57:07Z","receivedAt":"2012-05-15T18:57:07Z","isPatch":false,"sender":{"key":"pawel.sikora@agmk.net","avatar":null},"body":"On Tuesday 15 of May 2012 09:24:51 Jeff King wrote:\n> [let's keep this on-list so others can benefit from the discussion]\n> \n> On Tue, May 15, 2012 at 12:38:59PM +0400, Dmitry Risenberg wrote:\n> \n> > > It's probably detecting renames as part of the merge, which can be\n> > > expensive if the thing you are cherry-picking is far away from HEAD. You\n> > > can try setting the merge.renamelimit config variable to something small\n> > > (like 1; setting it to 0 means \"no limit\").\n> > \n> > I set it to 1, but it didn't help at all - cherry-pick time is still\n> > about the same.\n> \n> OK, then my guess was probably wrong. You'll have to try profiling (if\n> you are on Linux, \"perf record git cherry-pick ...\"; perf report\" is the\n> simplest way). Or if the repository is publicly available, I can do a\n> quick profile run.\n\ni have two big repos (few GB) and cherry-pick utilizes i/o and cpu heavy.\ntiming varies from few seconds on raid-0 (2x500GB) to ~30 second\non linear lvm (few TB). here's perf report:\n\n 36,24%  git  libc-2.15.so        [.] __memmove_ssse3_back\n  7,04%  git  libz.so.1.2.7       [.] inflate_fast\n  6,17%  git  libz.so.1.2.7       [.] inflate\n  5,53%  git  git                 [.] xdl_recs_cmp\n  3,04%  git  libc-2.15.so        [.] __memcmp_sse4_1\n  2,54%  git  libz.so.1.2.7       [.] inflate_table\n  1,83%  git  libc-2.15.so        [.] __strcmp_sse42\n  1,52%  git  libc-2.15.so        [.] __memcpy_ssse3_back\n  1,49%  git  git                 [.] match_trees\n  1,39%  git  libc-2.15.so        [.] _int_malloc\n  1,18%  git  libz.so.1.2.7       [.] adler32\n  1,08%  git  git                 [.] do_head_ref\n  1,02%  git  git                 [.] splice_tree\n  0,83%  git  libc-2.15.so        [.] __strlen_sse2_pminub\n  0,71%  git  [kernel.kallsyms]   [k] _raw_spin_lock\n  0,68%  git  git                 [.] shift_tree_by\n  0,67%  git  libc-2.15.so        [.] _int_free\n  0,63%  git  [kernel.kallsyms]   [k] __d_lookup_rcu\n  0,60%  git  [kernel.kallsyms]   [k] link_path_walk\n  0,57%  git  git                 [.] get_shallow_commits\n(...)\n"},{"id":"191565","messageId":"7v1umldw3i.fsf@alter.siamese.dyndns.org","threadId":"30523","inReplyTo":"20120515132451.GA25378@sigill.intra.peff.net","subject":"Re: cherry-pick is slow","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-15T20:32:01Z","receivedAt":"2012-05-15T20:32:01Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> [let's keep this on-list so others can benefit from the discussion]\n>\n> On Tue, May 15, 2012 at 12:38:59PM +0400, Dmitry Risenberg wrote:\n>\n>> > It's probably detecting renames as part of the merge, which can be\n>> > expensive if the thing you are cherry-picking is far away from HEAD. You\n>> > can try setting the merge.renamelimit config variable to something small\n>> > (like 1; setting it to 0 means \"no limit\").\n>> \n>> I set it to 1, but it didn't help at all - cherry-pick time is still\n>> about the same.\n>\n> OK, then my guess was probably wrong. You'll have to try profiling (if\n> you are on Linux, \"perf record git cherry-pick ...\"; perf report\" is the\n> simplest way). Or if the repository is publicly available, I can do a\n> quick profile run.\n\nPerhaps the word \"cherry-pick\" invites an expectation that it must be\nfaster than a full-tree merge, i.e. something like \"format-patch | am -3\",\nespecially when the change introduced by the commit being cherry-picked\ntouch only a handful of paths.\n\nUnfortunately, I do not think that the actual implementation of\n\"cherry-pick\" matches that expectation, as it is a full three-way merge.\n\nI am somewhat curious to see what the performance characteristics would be\nif the same commit is replayed using\n\n\tgit format-patch -1 --stdout $commit | git apply --index --3way\n\npipeline.  Depending on the number of paths in the whole tree vs the\nnumber of paths the $commit touches, I wouldn't be surprised if it is\nfaster.\n"},{"id":"191566","messageId":"7vwr4dcg2b.fsf@alter.siamese.dyndns.org","threadId":"30523","inReplyTo":"7v1umldw3i.fsf@alter.siamese.dyndns.org","subject":"Re: cherry-pick is slow","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-15T21:03:40Z","receivedAt":"2012-05-15T21:03:40Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Unfortunately, I do not think that the actual implementation of\n> \"cherry-pick\" matches that expectation, as it is a full three-way merge.\n>\n> I am somewhat curious to see what the performance characteristics would be\n> if the same commit is replayed using\n>\n> \tgit format-patch -1 --stdout $commit | git apply --index --3way\n>\n> pipeline.  Depending on the number of paths in the whole tree vs the\n> number of paths the $commit touches, I wouldn't be surprised if it is\n> faster.\n\nAn unscientific datapoint shows that with a project as small as the kernel,\nthe difference is noticeable.\n\nFor example, v3.4-rc7-22-g3911ff3 (random tip of the day) touches two\npaths, and cherry-picking it on top of v3.3 goes like this:\n\n    $ git checkout v3.3 && EDITOR=: /usr/bin/time git cherry-pick 3911ff3\n     Author: Jiri Kosina <jkosina@suse.cz>\n     2 files changed, 2 insertions(+)\n    1.08user 0.20system 0:01.28elapsed 99%CPU (0avgtext+0avgdata 469728maxresident)k\n    0inputs+7536outputs (0major+52604minor)pagefaults 0swaps\n\nas opposed to an alternative that touches only these two paths:\n\n    $ git checkout v3.3 && EDITOR=: /usr/bin/time sh -c '\n\tgit format-patch --stdout -1 3911ff3 | git am -3'\n    Applying: genirq: export handle_edge_irq() and irq_to_desc()\n    0.36user 0.16system 0:00.46elapsed 112%CPU (0avgtext+0avgdata 254720maxresident)k\n    0inputs+14872outputs (0major+55145minor)pagefaults 0swaps\n\nOf course, there are vast differences between v3.3 and 3911ff3^1; 11k+\npaths touched, countless paths created and deleted.\n\nI _think_ most of the overhead comes from having to match the large trees\nin unpack_trees() even though none of the changes between the base\nversions matters for this\" cherry-pick\".\n\nBoth reads the flat index into the core in its entirety and futzing with\nthe index file format would not affect this comparison, even though it\ncould improve the performance of \"am\", if done right, as it could limit\nits updates to only two paths.  In the merge case, we pretty much rebuild\nthe resulting index from scratch by walking the entire tree in\nunpack_trees(), so there won't be much benefit.\n\nPerhaps we might want to rethink the way we run merges?\n"},{"id":"191709","messageId":"20120519005424.GF765@sigill.intra.peff.net","threadId":"30523","inReplyTo":"7vwr4dcg2b.fsf@alter.siamese.dyndns.org","subject":"Re: cherry-pick is slow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-05-19T00:54:24Z","receivedAt":"2012-05-19T00:54:24Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, May 15, 2012 at 02:03:40PM -0700, Junio C Hamano wrote:\n\n> > \tgit format-patch -1 --stdout $commit | git apply --index --3way\n> [...]\n> An unscientific datapoint shows that with a project as small as the kernel,\n> the difference is noticeable.\n>\n> For example, v3.4-rc7-22-g3911ff3 (random tip of the day) touches two\n> paths, and cherry-picking it on top of v3.3 goes like this:\n\nYeah that's what I would expect. And that's not even that far away.\nCherry-picking the same commit onto v3.0 should be even more noticeable.\n\n> I _think_ most of the overhead comes from having to match the large trees\n> in unpack_trees() even though none of the changes between the base\n> versions matters for this\" cherry-pick\".\n> \n> Both reads the flat index into the core in its entirety and futzing with\n> the index file format would not affect this comparison, even though it\n> could improve the performance of \"am\", if done right, as it could limit\n> its updates to only two paths.  In the merge case, we pretty much rebuild\n> the resulting index from scratch by walking the entire tree in\n> unpack_trees(), so there won't be much benefit.\n> \n> Perhaps we might want to rethink the way we run merges?\n\nFor merge-recursive, we would always want to compute the pair-wise\nrenames between each side and the ancestor. So that diff to the\ncherry-pick destination is always going to be an expensive O(# of\nchanges between source and dest) operation.\n\nWithout renames, you could do better on the actual merge with a\nthree-way tree walk. E.g., you see that some sub-tree is at tree A in\nthe \"ours\" and \"ancestor\" trees, but at tree B in \"theirs\". So you don't\nhave to descend further, and can just say \"take theirs\" (well, you have\nto descend \"theirs\" to get the values). But I expect it gets more\ncomplicated with the interactions with the index (and is probably not\nworth spending much effort on because of the rename issue, anyway).\n\n-Peff\n"}]}