{"thread":{"id":"14917","subject":"[RFC PATCH] Documentation: rev-list-options: clarify history simplification with paths","startedAt":"2008-08-10T13:44:00Z","lastAt":"2008-08-11T23:55:37Z","messageCount":12,"participants":["Thomas Rast","Junio C Hamano","Linus Torvalds"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"86671","messageId":"1218375840-4292-1-git-send-email-trast@student.ethz.ch","threadId":"14917","inReplyTo":null,"subject":"[RFC PATCH] Documentation: rev-list-options: clarify history simplification with paths","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-08-10T13:44:00Z","receivedAt":"2008-08-10T13:44:00Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"This is an attempt to rewrite the documentation for --full-history,\n--simplify-merges, and --sparse for clarity.\n\n--prune-merges does not exist yet, but would be intended to restore\nthe default behavior over possible earlier --full-history and\n--simplify-merges.\n\nWARNING: Does not match current code behavior.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nThis is fallout from my investigation of rev-list during the\nfilter-branch topic.  I found the descriptions quite unhelpful, and\ninvestigated commit logs and empiric behavior a bit.\n\nThe problem is, rev-list behaves quite erratically if one mixes\n--sparse, --full-history and --parents in combinations.\n\nWith the history from the patch, i.e.\n\n  $ git log --graph --pretty=oneline --abbrev-commit --decorate\n  *-.   e0083e6... (refs/heads/master) Merge branches 'side' and 'unrelated'\n  |\\ \\\n  | | * b3127f4... (refs/heads/unrelated) d: unrelated\n  | * | 984aa48... (refs/heads/side) C: dir=B\n  | |/\n  * | aad9982... B: dir\n  |/\n  * b60c459... A: dir\n  * ad7052b... initial\n\nwhere only commits with 'dir' touch the 'dir' subdirectory, and C=B in\nterms of diffs, a few unexpected things happen.  (I manually applied\n--abbrev-commit to rev-list output to make it fit in less columns.)\n\nAs noted in the patch, I would expect the default pruning to simplify\nthe history to 'o -- A -- B -- m' (drop parent 'd' because the entire\nsideline is non-touching; drop parent 'C' because it is the same as\n'B'), and then have --dense decide to drop 'o' and 'm' because they\nare not touching.  The output agrees:\n\n  $ git rev-list --pretty=oneline HEAD -- dir\n  aad9982... B: dir\n  b60c459... A: dir\n\nAlso, --sparse tends to support this two-pass simplification theory:\n\n  $ git rev-list --pretty=oneline --sparse HEAD -- dir\n  e0083e6... Merge branches 'side' and 'unrelated'\n  aad9982... B: dir\n  b60c459... A: dir\n  ad7052b... initial\n\nNow according to current docs, --full-history should turn off removing\n\"merges which didn't change anything at all at some child\", but still\n\"simplify away merges that didn't change anything at all into either\nchild.\"  How does being a merge have anything to do with it's\n_children_?  So I read this as saying that a merge is removed iff it\nagrees with all _parents_.  However, despite having a merge that is\ndifferent relative to its third parent, it is dropped:\n\n  $ g rev-list --pretty=oneline --full-history HEAD -- dir\n  984aa48... C: dir=B\n  aad9982... B: dir\n  b60c459... A: dir\n\nBut --parents --full-history magically revives the merge:\n\n  $ git rev-list --pretty=oneline --parents --full-history HEAD -- dir\n  e0083e6... aad9982... 984aa48... b60c459... Merge branches 'side' and 'unrelated'\n  984aa48... b60c459... C: dir=B\n  aad9982... b60c459... B: dir\n  b60c459... A: dir\n\nOne quickly verifies that --sparse --full-history shows everything, as\nit should.\n\nMore to the point, --simplify-merges actually shows the merge when\n--full-history does not, resulting in\n\n  $ git rev-list --pretty=oneline --simplify-merges HEAD -- dir\n  e0083e6... Merge branches 'side' and 'unrelated'\n  984aa48... C: dir=B\n  aad9982... B: dir\n  b60c459... A: dir\n\ndespite the commit message (90818fdc) claiming that it is an\nadditional simplification on top of --full-history, and should\ntherefore output at most as many commits.  --parents seems to agree\nthat the simplification is working right:\n\n  $ git rev-list --pretty=oneline --parents --simplify-merges HEAD -- dir\n  e0083e6... aad9982... 984aa48... Merge branches 'side' and 'unrelated'\n  984aa48... b60c459... C: dir=B\n  aad9982... b60c459... B: dir\n  b60c459... A: dir\n\n(Note that it dropped the third unrelated parent.)\n\nFurthermore, with --sparse the same turns into\n\n  $ git rev-list --pretty=oneline --sparse --parents --simplify-merges HEAD -- dir\n  e0083e6... aad9982... 984aa48... b3127f4... Merge branches 'side' and 'unrelated'\n  b3127f4... b60c459... d: unrelated\n  984aa48... b60c459... C: dir=B\n  aad9982... b60c459... B: dir\n  b60c459... ad7052b... A: dir\n  ad7052b... initial\n\nSo it didn't simplify away the parent 'd' after all, even though\n90818fdc (in the second * bullet) does not mention any criterion that\nwould make 'd' its own replacement.  (I would actually expect it to\nreplace 'd' with 'initial' on that ancestor line, and subsequently\nprune that parent because it is redundant.)\n\nSo if anyone read this mail up to this point:  Which of these are\nactual bugs?  Which of them are a misunderstanding on my part?\n\nThanks for your time,\n\nThomas\n\n\n Documentation/rev-list-options.txt |   97 ++++++++++++++++++++++++++++-------\n 1 files changed, 77 insertions(+), 20 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex ee6822a..0eaefd2 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -191,20 +191,6 @@ endif::git-rev-list[]\n \n \tStop when a given path disappears from the tree.\n \n---full-history::\n-\n-\tShow also parts of history irrelevant to current state of given\n-\tpaths. This turns off history simplification, which removed merges\n-\twhich didn't change anything at all at some child. It will still actually\n-\tsimplify away merges that didn't change anything at all into either\n-\tchild.\n-\n---simplify-merges::\n-\n-\tSimplify away commits that did not change the given paths, similar\n-\tto `--full-history`, and further remove merges none of whose\n-\tparent history changes the given paths.\n-\n --no-merges::\n \n \tDo not print commits with more than one parent.\n@@ -287,18 +273,89 @@ See also linkgit:git-reflog[1].\n \tOutput uninteresting commits at the boundary, which are usually\n \tnot shown.\n \n+--\n+\n+History Simplification\n+~~~~~~~~~~~~~~~~~~~~~~\n+\n+When optional paths are given, 'git-rev-list' simplifies merge and\n+non-merge commits separately.  First, all non-merge commits that do\n+not touch the given paths are marked as such.  We'll call them\n+'non-touching' commits, and all other commits 'touching'.\n+\n+Second, merges are simplified.  You can choose three levels.  We\n+illustrate the strategies with the following example history, where\n+touching commits are shown with capital letters and both B and C\n+contain the same changes:\n+\n+-----------------------------------------------------------------------\n+\to -- A -- B -- m\n+\t     |\\\t      /|\n+\t     | \\- C -/ |\n+\t     \\\t       /\n+\t      \\-- d --/\n+-----------------------------------------------------------------------\n+\n+--prune-merges::\n+\n+\tThis is the default.  A merge is has its parents rewritten as\n+\tfollows:\n++\n+\t* All parents that do not have any touching ancestors are\n+\t  removed.\n++\n+\t* Of a set of parents that agree on the path contents, only\n+\t  the first is kept.\n++\n+In our example, we get the following:\n++\n+-----------------------------------------------------------------------\n+\to -- A -- B -- m\n+-----------------------------------------------------------------------\n+\n+--simplify-merges::\n+\n+\tFor each commit C, compute its replacement in the final history:\n++\n+* First compute the replacements of all parents of C, and\n+  rewrite C to have these parents.  Then remove parents that\n+  are either identical to or ancestors of an existing parent.\n++\n+* If, after this simplification, the commit is touching, a root or\n+  merge commit, or marked as uninteresting, it remains.\n++\n+In the example, history is simplified as follows.  (Note that while\n+'o' remains, it will not be output with '\\--dense'.)\n++\n+-----------------------------------------------------------------------\n+\to -- A -- B -- m\n+\t      \\\t      /\n+\t       \\- C -/\n+-----------------------------------------------------------------------\n+\n+--full-history::\n+\n+\tDo not simplify merges at all.  Their ancestor lines are still\n+\tonly shown if they have any touching commits, but the merges\n+\tthemselves are always output.\n+\n+Finally the simplified history is output.  You can control which\n+commits are shown:\n+\n --dense::\n+\n+\tHide all non-touching non-merge commits.  This is the default.\n+\n --sparse::\n \n-When optional paths are given, the default behaviour ('--dense') is to\n-only output commits that changes at least one of them, and also ignore\n-merges that do not touch the given paths.\n+\tOutput all commits.  (Still subject to merge simplification\n+\tand count and age limitations.)\n \n-Use the '--sparse' flag to makes the command output all eligible commits\n-(still subject to count and age limitation), but apply merge\n-simplification nevertheless.\n \n ifdef::git-rev-list[]\n+Bisection Helpers\n+~~~~~~~~~~~~~~~~~\n+\n --bisect::\n \n Limit output to the one commit object which is roughly halfway between\n-- \n1.6.0.rc2.29.g7ec81\n"},{"id":"86710","messageId":"7vabfk3cge.fsf@gitster.siamese.dyndns.org","threadId":"14917","inReplyTo":"1218375840-4292-1-git-send-email-trast@student.ethz.ch","subject":"Re: [RFC PATCH] Documentation: rev-list-options: clarify history simplification with paths","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-10T19:19:13Z","receivedAt":"2008-08-10T19:19:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n>   $ g rev-list --pretty=oneline --full-history HEAD -- dir\n> ...\n> But --parents --full-history magically revives the merge:\n> ...\n\nPersonally I do not think --full-history without --parents is of much\nusefulness (I'd let Linus or somebody else defend this usage, or make it\nimply revs.rewrite_parents otherwise).  If you remove that case from your\nset of experiments in the equation, do the rest of the results make sense?\n\n> More to the point, --simplify-merges actually shows the merge when\n> --full-history does not, resulting in ...\n\nOne thing I forgot to mention (but the code of course does not forget to\ndo) in the series is that --simplify-merges implies revs.rewrite_parents\nwhich roughly translates to your experiments from the command line to\nalways have --parents option.\n\n>   $ git rev-list --pretty=oneline --sparse --parents --simplify-merges HEAD -- dir\n>   e0083e6... aad9982... 984aa48... b3127f4... Merge branches 'side' and 'unrelated'\n>   b3127f4... b60c459... d: unrelated\n>   984aa48... b60c459... C: dir=B\n>   aad9982... b60c459... B: dir\n>   b60c459... ad7052b... A: dir\n>   ad7052b... initial\n\nI am not sure what one should expect from combination between these two\noptions.  --sparse says do not drop commits that are of no interest with\nrespect to the paths specified, while --simplify-merges tells it to\nsimplify merges so that the remaining graph shows only the ones that have\nrelevance to !TREESAME (iow \"has some changes\") nodes.\n"},{"id":"86711","messageId":"alpine.LFD.1.10.0808101226130.3462@nehalem.linux-foundation.org","threadId":"14917","inReplyTo":"7vabfk3cge.fsf@gitster.siamese.dyndns.org","subject":"Re: [RFC PATCH] Documentation: rev-list-options: clarify history simplification with paths","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-10T19:27:58Z","receivedAt":"2008-08-10T19:27:58Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 10 Aug 2008, Junio C Hamano wrote:\n> \n> Personally I do not think --full-history without --parents is of much\n> usefulness (I'd let Linus or somebody else defend this usage, or make it\n> imply revs.rewrite_parents otherwise).  If you remove that case from your\n> set of experiments in the equation, do the rest of the results make sense?\n\nOh, it's _very_ useful.\n\nThe most common case is \"git whatchanged\". It's useful to find a commit \nthat did some change _without_ any graphical front-end. \n\nAnd then the merges and parenthood are totally pointless - no human can \ntry to tie things together in their head _anyway_, so why show them? You \njust want to find the change.\n\n\t\t\tLinus\n"},{"id":"86720","messageId":"200808102331.55385.trast@student.ethz.ch","threadId":"14917","inReplyTo":"7vabfk3cge.fsf@gitster.siamese.dyndns.org","subject":"Re: [RFC PATCH] Documentation: rev-list-options: clarify history simplification with paths","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-08-10T21:31:51Z","receivedAt":"2008-08-10T21:31:51Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano wrote:\n> Thomas Rast <trast@student.ethz.ch> writes:\n> \n> >   $ g rev-list --pretty=oneline --full-history HEAD -- dir\n> > ...\n> > But --parents --full-history magically revives the merge:\n> > ...\n> \n> Personally I do not think --full-history without --parents is of much\n> usefulness (I'd let Linus or somebody else defend this usage, or make it\n> imply revs.rewrite_parents otherwise).\n\nWell,\n\n  --parents::\n          Print the parents of the commit.\n\ndoes not mention any change in behaviour.  I find it very surprising\nthat a simple commit formatting option changes the way commits are\n_selected_.\n\n> One thing I forgot to mention (but the code of course does not forget to\n> do) in the series is that --simplify-merges implies revs.rewrite_parents\n> which roughly translates to your experiments from the command line to\n> always have --parents option.\n\nThen it makes sense of course.\n\n> >   $ git rev-list --pretty=oneline --sparse --parents --simplify-merges HEAD -- dir\n[...]\n> I am not sure what one should expect from combination between these two\n> options.  --sparse says do not drop commits that are of no interest with\n> respect to the paths specified, while --simplify-merges tells it to\n> simplify merges so that the remaining graph shows only the ones that have\n> relevance to !TREESAME (iow \"has some changes\") nodes.\n\nIt makes sense assuming a one-pass (plus simplify-merges) model.  It\ndid not fit into my two-pass model that I tried to come up with for an\neasier explanation.\n\nSo in my current (ahem, new) understanding, that means (assuming the\nside effect of --parents):\n\nThe simplification follows commits backwards into history according to\nthe following rules:\n\n--dense:\n\tNon-merges are included if TREESAME[1], otherwise they are\n\tskipped.\n--sparse:\n\tNon-merges are always included.\n\ndefault:\n\tMerges are included unless they are TREESAME with a parent, in\n\twhich case they are skipped and only that parent is followed.\n--full-history:\n\tMerges are always included.\n\nConceptually, that builds a subset of the history, although it is\nnot kept in memory unless absolutely required.  Then:\n\n--simplify-commits:\n\tImplies --full-history, then applies your algorithm on the\n\tresulting subset.\n\nWhich probably means that --sparse --simplify-commits makes no sense,\nbut explains the results.\n\nNote that --full-history makes no exceptions, not even for merges that\nare TREESAME w.r.t. all parents, unlike current docs state.  (This is\nempirically correct.)  If the above is correct, and you think that has\nsome merit, I'll rewrite my patch to reflect this (with examples) to\nupdate the docs.\n\n- Thomas\n\n\n[1] I still think \"touching\" was a pretty neat idea ;-)\n\n-- \nThomas Rast\ntrast@student.ethz.ch\n\n\n"},{"id":"86721","messageId":"7v63q8353m.fsf@gitster.siamese.dyndns.org","threadId":"14917","inReplyTo":"alpine.LFD.1.10.0808101226130.3462@nehalem.linux-foundation.org","subject":"Re: [RFC PATCH] Documentation: rev-list-options: clarify history simplification with paths","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-10T21:58:05Z","receivedAt":"2008-08-10T21:58:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@linux-foundation.org> writes:\n\n> On Sun, 10 Aug 2008, Junio C Hamano wrote:\n>> \n>> Personally I do not think --full-history without --parents is of much\n>> usefulness (I'd let Linus or somebody else defend this usage, or make it\n>> imply revs.rewrite_parents otherwise).  If you remove that case from your\n>> set of experiments in the equation, do the rest of the results make sense?\n>\n> Oh, it's _very_ useful.\n>\n> The most common case is \"git whatchanged\". It's useful to find a commit \n> that did some change _without_ any graphical front-end. \n>\n> And then the merges and parenthood are totally pointless - no human can \n> try to tie things together in their head _anyway_, so why show them? You \n> just want to find the change.\n\nOh, I was not talking about revs.print_parents part, but about\nrevs.rewrite_parents part.  What got Thomas puzzled about was exactly how\nthe set of commits _shown_ are different with and without --parents, which\nsets both of these internal flags.  Your \"pointless\" argument applies to\n\"print_parents\" part, but \"rewrite_parents\" affects the resulting set.\n"},{"id":"86723","messageId":"alpine.LFD.1.10.0808101507510.3462@nehalem.linux-foundation.org","threadId":"14917","inReplyTo":"7v63q8353m.fsf@gitster.siamese.dyndns.org","subject":"Re: [RFC PATCH] Documentation: rev-list-options: clarify history simplification with paths","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-10T22:16:43Z","receivedAt":"2008-08-10T22:16:43Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 10 Aug 2008, Junio C Hamano wrote:\n> \n> Oh, I was not talking about revs.print_parents part, but about\n> revs.rewrite_parents part.  What got Thomas puzzled about was exactly how\n> the set of commits _shown_ are different with and without --parents, which\n> sets both of these internal flags.  Your \"pointless\" argument applies to\n> \"print_parents\" part, but \"rewrite_parents\" affects the resulting set.\n\nUmm. Since --parents sets both, I don't see the point of that statement.\n\nThe fact is, --parents makes us show parenthood. That means that we need \nthe merges to show up, otherwise the parenthood is meaningless.\n\nSo without \"--parents\", there is absolutely no point in showing the merges \nthat don't have any other reason to be shown. And _with_ --parents, we \nneed to show them because they matter for parenthood.\n\nWhat's so confusing or hard to understand?\n\nAnd yes, we now have split that \"parents\" flag into two separate flags \ninternally, but that has absolutely _zero_ meaning for \"--parents\" itself, \nand it is totally irrelevant and meaningless to bring up that internal \nimplementation issue and mentioning \"print_parents\" and \"rewrite_parents\". \n\nThey are immaterial to the actual argument, and the split-up happened \nbecause of the \"--graph\" flag, where we actually *do* show parents too, \nbut we show them through the graph, not by printing the SHA1 of the \nparent. So the reason \"rewrite_parents\" is the one that affects the set of \ncommits that get output is a small _internal_ implementation detail, and I \nreally don't see what it has to do with anything at all.\n\nSo the fact is:\n\n - \"rewrite_parents\" is the flag that says that we are interested in \n   parenthood and keeping the graph consistent and dense.\n\n   This very much implies showing merges that would otherwise not be \n   relevant.\n\n - \"print_parents\" is just a flag whether we should print the parent SHA1 \n   or not. Nothing less, nothing more.\n\n   This one has absolutely no relevance to whether a merge should be shown \n   or not, since it only affects the output _format_. It's related to \n   pretty-printing, not to anything else!\n\nI really don't see what the confusion is all about. It's very \nstraightforward and obvious.\n\n\t\t\tLinus\n"},{"id":"86825","messageId":"7vprofwat0.fsf@gitster.siamese.dyndns.org","threadId":"14917","inReplyTo":"1218375840-4292-1-git-send-email-trast@student.ethz.ch","subject":"Re: [RFC PATCH] Documentation: rev-list-options: clarify history simplification with paths","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-11T20:34:19Z","receivedAt":"2008-08-11T20:34:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\n> index ee6822a..0eaefd2 100644\n> --- a/Documentation/rev-list-options.txt\n> +++ b/Documentation/rev-list-options.txt\n> @@ -191,20 +191,6 @@ endif::git-rev-list[]\n> ...\n> +--\n\nWhat was the meaning of the double-dash at the beginning of line in\nAsciiDoc markup?  I forgot.\n\n> +History Simplification\n> +~~~~~~~~~~~~~~~~~~~~~~\n> +\n> +When optional paths are given, 'git-rev-list' simplifies merge and\n> +non-merge commits separately.  First, all non-merge commits that do\n> +not touch the given paths are marked as such.  We'll call them\n> +'non-touching' commits, and all other commits 'touching'.\n> +\n> +Second, merges are simplified.  You can choose three levels.  We\n> +illustrate the strategies with the following example history, where\n> +touching commits are shown with capital letters and both B and C\n> +contain the same changes:\n> +\n> +-----------------------------------------------------------------------\n> +\to -- A -- B -- m\n> +\t     |\\\t      /|\n> +\t     | \\- C -/ |\n> +\t     \\\t       /\n> +\t      \\-- d --/\n> +-----------------------------------------------------------------------\n\nPlease draw it a bit more consistently with pictures in other existing\ndocumentation, perhaps like this:\n\n              d---.  \n             /     \\\n        o---A---B---m\n             \\     /\n              C---.\n\n> +--prune-merges::\n> +\n> +\tThis is the default.  A merge is has its parents rewritten as\n> +\tfollows:\n> ++\n> +\t* All parents that do not have any touching ancestors are\n> +\t  removed.\n> ++\n> +\t* Of a set of parents that agree on the path contents, only\n> +\t  the first is kept.\n> ++\n> +In our example, we get the following:\n> ++\n> +-----------------------------------------------------------------------\n> +\to -- A -- B -- m\n> +-----------------------------------------------------------------------\n\nI'd rather make this the part of the base text.  In other words, remove\nthe \"--prune-merges\" header, dedent the description and start the sentence\nwith \"By default, parents of a merge is rewritten with the following\nrules:\".\n\nThen before listing the options, say something like \"You can influence how\nsimplification works using the following options\".\n\n> +--simplify-merges::\n> +\n> +\tFor each commit C, compute its replacement in the final history:\n> ++\n> +* First compute the replacements of all parents of C, and\n> +  rewrite C to have these parents.  Then remove parents that\n> +  are either identical to or ancestors of an existing parent.\n> ++\n> +* If, after this simplification, the commit is touching, a root or\n> +  merge commit, or marked as uninteresting, it remains.\n> ++\n> +In the example, history is simplified as follows.  (Note that while\n> +'o' remains, it will not be output with '\\--dense'.)\n> ++\n\nAlso this option implies --full-history's true meaning \"do not cull side\nbranches even when they led to the same conclusion\", with --parent's\nmeaning \"do not drop merges that are necessary to keep the rewritten\nhistory still connected\".\n\n> +-----------------------------------------------------------------------\n> +\to -- A -- B -- m\n> +\t      \\\t      /\n> +\t       \\- C -/\n> +-----------------------------------------------------------------------\n\nSame comment on the way the picture is drawn.\n\n> +--full-history::\n> +\n> +\tDo not simplify merges at all.  Their ancestor lines are still\n> +\tonly shown if they have any touching commits, but the merges\n> +\tthemselves are always output.\n\nWith clarification from Linus yesterday, this would need rewording.  It is\nnot about \"simplifying merges\", but its main focus is \"do not cull side\nbranches\".  When --parents is in effect, merges need to be shown because\notherwise the resulting list of commits won't be connected, but otherwise\nyou are getting a flat list of commits and useless merges won't be shown.\n"},{"id":"86826","messageId":"7vljz3wako.fsf@gitster.siamese.dyndns.org","threadId":"14917","inReplyTo":"200808102331.55385.trast@student.ethz.ch","subject":"Re: [RFC PATCH] Documentation: rev-list-options: clarify history simplification with paths","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-11T20:39:19Z","receivedAt":"2008-08-11T20:39:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> [1] I still think \"touching\" was a pretty neat idea ;-)\n\nActually, I felt it was a horrible wording, because the first association\nI got from the word was with \"emotionally moved\", and not about !TREESAME\nwhich is \"Does the commit modify the specified paths?\" at all.\n"},{"id":"86858","messageId":"200808120151.56067.trast@student.ethz.ch","threadId":"14917","inReplyTo":"7vprofwat0.fsf@gitster.siamese.dyndns.org","subject":"Re: [RFC PATCH] Documentation: rev-list-options: clarify history simplification with paths","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-08-11T23:51:46Z","receivedAt":"2008-08-11T23:51:46Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n>\n\nThanks for taking the time to look into this!\n\n> What was the meaning of the double-dash at the beginning of line in\n> AsciiDoc markup?  I forgot.\n\nI wish I knew.  I simply copied that from elsewhere in the docs to\nmake it shut up about an error.  It would seem that it is required to\nend the list before a title, except if there's already an 'if' doing\nthe split, unless on a full moon, except if it's wednesday.  I've\ntried to make the patches compile with asciidoc (8.2.5 here), but\nthat's about as far as it goes.\n\nI haven't found any mention of the magic features of '^--' in the user\nmanual, though the cheat sheet\n\n  http://powerman.name/doc/asciidoc\n\nhas nice examples how to interrupt lists, which I used for the\nupcoming patch contents.\n\n> Please draw it a bit more consistently with pictures in other existing\n> documentation, perhaps like this:\n\nHmm.  I've tried to give the new examples a more compact and round\nappearance, like in your example.  Tell me if that works for you.\n\n> I'd rather make this the part of the base text.  In other words, remove\n> the \"--prune-merges\" header, dedent the description and start the sentence\n> with \"By default, parents of a merge is rewritten with the following\n> rules:\".\n> \n> Then before listing the options, say something like \"You can influence how\n> simplification works using the following options\".\n\nI dropped the \"--prune-merges\" since it would be a new option.\nHowever, I would like to keep some sort of \"Default mode\" header (not\nnecessarily as a list header, if you have better ideas).  Otherwise,\nupon encountering \"--full-history ... differs from the default\", the\nreader would have to (tediously) scan several paragraph breaks to\ndiscover where the default begins.\n\n\nI completely rewrote it along the outlines given in my own followup.\nI also devised a better example that shows the differences between\nall-TREESAME merges, one-TREESAME merges, and (!)TREESAME commits.  I\nam open for further suggestions of course.  (I'm also violating the\n\"no patches after midnight\" rule, so feel free to point out obvious\nmistakes too.)\n\nI furthermore split the patch into two halves:\n\n* 2/3 applies on top of master, so that it is independent of\n  --simplify-merges.\n\n* 3/3 replaces the docs coming with --simplify-merges with an extra\n  paragraph in 'History Simplification'.\n\nI hope that's the right way to proceed.  This does mean you will get a\nmerge conflict when merging jc/post-simplify, but it's a fairly\nobvious one.\n\n1/3 is just a one-character typo that I discovered along the way.\n\nFinally, I'm attaching a script that generates a repository with the\nhistory used in the example.\n\n- Thomas\n\n-- \nThomas Rast\ntrast@student.ethz.ch\n\n\n"},{"id":"86860","messageId":"ac1b3fe540b183acc8cdd87d36c55256cc56a204.1218498922.git.trast@student.ethz.ch","threadId":"14917","inReplyTo":"200808120151.56067.trast@student.ethz.ch","subject":"[PATCH 1/3] Documentation: rev-list-options: Fix a typo","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-08-11T23:55:35Z","receivedAt":"2008-08-11T23:55:35Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Signed-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n Documentation/rev-list-options.txt |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 3aa3809..83070ed 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -71,7 +71,7 @@ For example, if you have this topology:\n          o---x---a---a  branch A\n -----------------------------------------------------------------------\n +\n-you would get an output line this:\n+you would get an output like this:\n +\n -----------------------------------------------------------------------\n \t$ git rev-list --left-right --boundary --pretty=oneline A...B\n-- \n1.6.0.rc2.56.g86ca\n"},{"id":"86861","messageId":"eada6ecf77a858b2f1fe91c13c6a68b9d0351621.1218498923.git.trast@student.ethz.ch","threadId":"14917","inReplyTo":"ac1b3fe540b183acc8cdd87d36c55256cc56a204.1218498922.git.trast@student.ethz.ch","subject":"[PATCH 2/3] Documentation: rev-list-options: Rewrite simplification descriptions for clarity","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-08-11T23:55:36Z","receivedAt":"2008-08-11T23:55:36Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"This completely rewrites the documentation of --full-history with lots\nof examples.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n Documentation/rev-list-options.txt |  153 ++++++++++++++++++++++++++++++++----\n 1 files changed, 136 insertions(+), 17 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 83070ed..f8e5fb9 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -43,11 +43,13 @@ endif::git-rev-list[]\n \n --parents::\n \n-\tPrint the parents of the commit.\n+\tPrint the parents of the commit.  Also enables parent\n+\trewriting, see 'History Simplification' below.\n \n --children::\n \n-\tPrint the children of the commit.\n+\tPrint the children of the commit.  Also enables parent\n+\trewriting, see 'History Simplification' below.\n \n ifdef::git-rev-list[]\n --timestamp::\n@@ -191,14 +193,6 @@ endif::git-rev-list[]\n \n \tStop when a given path disappears from the tree.\n \n---full-history::\n-\n-\tShow also parts of history irrelevant to current state of a given\n-\tpath. This turns off history simplification, which removed merges\n-\twhich didn't change anything at all at some child. It will still actually\n-\tsimplify away merges that didn't change anything at all into either\n-\tchild.\n-\n --no-merges::\n \n \tDo not print commits with more than one parent.\n@@ -281,18 +275,144 @@ See also linkgit:git-reflog[1].\n \tOutput uninteresting commits at the boundary, which are usually\n \tnot shown.\n \n+--\n+\n+History Simplification\n+~~~~~~~~~~~~~~~~~~~~~~\n+\n+When optional paths are given, 'git-rev-list' simplifies commits with\n+various strategies, according to the options you have selected.\n+\n+Suppose you specified `foo` as the <paths>.  We shall call commits\n+that modify `foo` !TREESAME, and the rest TREESAME.  (In a diff\n+filtered for `foo`, they look different and equal, respectively.)\n+\n+In the following, we will always refer to the same example history to\n+illustrate the differences between simplification settings.  We assume\n+that you are filtering for a file `foo` in this commit graph:\n+-----------------------------------------------------------------------\n+\t  .-A---M---N---O---P\n+\t /     /   /   /   /\n+\tI     B   C   D   E\n+\t \\   /   /   /   /\n+\t  `-------------'\n+-----------------------------------------------------------------------\n+The horizontal line of history A--P is taken to be the first parent of\n+each merge.  The commits are:\n+\n+* `I` is the initial commit, in which `foo` exists with contents\n+  \"asdf\", and a file `quux` exists with contents \"quux\".  Initial\n+  commits are compared to an empty tree, so `I` is !TREESAME.\n+\n+* In `A`, `foo` contains just \"foo\".\n+\n+* `B` contains the same change as `A`.  Its merge `M` is trivial and\n+  hence TREESAME to all parents.\n+\n+* `C` does not change `foo`, but its merge `N` changes it to \"foobar\",\n+  so it is not TREESAME to any parent.\n+\n+* `D` sets `foo` to \"baz\".  Its merge `O` combines the strings from\n+  `N` and `D` to \"foobarbaz\"; i.e., it is not TREESAME to any parent.\n+\n+* `E` changes `quux` to \"xyzzy\", and its merge `P` combines the\n+  strings to \"quux xyzzy\".  Despite appearing interesting, `P` is\n+  TREESAME to all parents.\n+\n+'rev-list' walks backwards through history, including or excluding\n+commits based on whether '\\--full-history' and/or parent rewriting\n+(via '\\--parents' or '\\--children') are used.  The following settings\n+are available.\n+\n+Default mode::\n+\n+\tCommits are included if they are not TREESAME to any parent\n+\t(though this can be changed, see '\\--sparse' below).  If the\n+\tcommit was a merge, and it was TREESAME to one parent, follow\n+\tonly that parent.  (Even if there are several TREESAME\n+\tparents, follow only one of them.)  Otherwise, follow all\n+\tparents.\n++\n+This results in:\n++\n+-----------------------------------------------------------------------\n+\t  .-A---N---O\n+\t /         /\n+\tI---------D\n+-----------------------------------------------------------------------\n++\n+Note how the rule to only follow the TREESAME parent, if one is\n+available, removed `B` from consideration entirely.  `C` was\n+considered via `N`, but is TREESAME.  Root commits are compared to an\n+empty tree, so `I` is !TREESAME.\n++\n+Parent/child relations are only visible with --parents, but that does\n+not affect the commits selected in default mode, so we have shown the\n+parent lines.\n+\n+--full-history without parent rewriting::\n+\n+\tThis mode differs from the default in one point: always follow\n+\tall parents of a merge, even if it is TREESAME to one of them.\n+\tEven if more than one side of the merge has commits that are\n+\tincluded, this does not imply that the merge itself is!  In\n+\tthe example, we get\n++\n+-----------------------------------------------------------------------\n+\tI  A  B  N  D  O\n+-----------------------------------------------------------------------\n++\n+`P` and `M` were excluded because they are TREESAME to a parent.  `E`,\n+`C` and `B` were all walked, but only `B` was !TREESAME, so the others\n+do not appear.\n++\n+Note that without parent rewriting, it is not really possible to talk\n+about the parent/child relationships between the commits, so we show\n+them disconnected.\n+\n+--full-history with parent rewriting::\n+\n+\tOrdinary commits are only included if they are !TREESAME\n+\t(though this can be changed, see '\\--sparse' below).\n++\n+Merges are always included.  However, their parent list is rewritten:\n+Along each parent, prune away commits that are not included\n+themselves.  This results in\n++\n+-----------------------------------------------------------------------\n+\t  .-A---M---N---O---P\n+\t /     /   /   /   /\n+\tI     B   /   D   /\n+\t \\   /   /   /   /\n+\t  `-------------'\n+-----------------------------------------------------------------------\n++\n+Compare to '\\--full-history' without rewriting above.  Note that `E`\n+was pruned away because it is TREESAME, but the parent list of P was\n+rewritten to contain `E`'s parent `I`.  The same happened for `C` and\n+`N`.  Note also that `P` was included despite being TREESAME.\n+\n+In addition to the above settings, you can change whether TREESAME\n+affects inclusion:\n+\n --dense::\n+\n+\tCommits that are walked are included if they are not TREESAME\n+\tto any parent.\n+\n --sparse::\n \n-When optional paths are given, the default behaviour ('--dense') is to\n-only output commits that changes at least one of them, and also ignore\n-merges that do not touch the given paths.\n+\tAll commits that are walked are included.\n++\n+Note that without '\\--full-history', this still simplifies merges: if\n+one of the parents is TREESAME, we follow only that one, so the other\n+sides of the merge are never walked.\n \n-Use the '--sparse' flag to makes the command output all eligible commits\n-(still subject to count and age limitation), but apply merge\n-simplification nevertheless.\n \n ifdef::git-rev-list[]\n+Bisection Helpers\n+~~~~~~~~~~~~~~~~~\n+\n --bisect::\n \n Limit output to the one commit object which is roughly halfway between\n@@ -342,7 +462,6 @@ after all the sorted commit objects, there will be the same text as if\n `--bisect-vars` had been used alone.\n endif::git-rev-list[]\n \n---\n \n Commit Ordering\n ~~~~~~~~~~~~~~~\n-- \n1.6.0.rc2.56.g86ca\n"},{"id":"86862","messageId":"9c8cd2c95aba3ca921099a28b07b2b7f2e497b2f.1218498923.git.trast@student.ethz.ch","threadId":"14917","inReplyTo":"eada6ecf77a858b2f1fe91c13c6a68b9d0351621.1218498923.git.trast@student.ethz.ch","subject":"[PATCH 3/3] Documentation: rev-list-options: move --simplify-merges documentation","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-08-11T23:55:37Z","receivedAt":"2008-08-11T23:55:37Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Fits --simplify-merges documentation into the 'History Simplification'\nsection, including example.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n Documentation/rev-list-options.txt |   48 +++++++++++++++++++++++++++++++----\n 1 files changed, 42 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex c6b0bf1..1d0048e 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -193,12 +193,6 @@ endif::git-rev-list[]\n \n \tStop when a given path disappears from the tree.\n \n---simplify-merges::\n-\n-\tSimplify away commits that did not change the given paths, similar\n-\tto `--full-history`, and further remove merges none of whose\n-\tparent history changes the given paths.\n-\n --no-merges::\n \n \tDo not print commits with more than one parent.\n@@ -414,6 +408,48 @@ Note that without '\\--full-history', this still simplifies merges: if\n one of the parents is TREESAME, we follow only that one, so the other\n sides of the merge are never walked.\n \n+Finally, there is a fourth simplification mode available:\n+\n+--simplify-merges::\n+\n+\tFirst, build a history graph in the same way that\n+\t'\\--full-history' with parent rewriting does (see above).\n++\n+Then simplify each commit `C` to its replacement `C'` in the final\n+history according to the following rules:\n++\n+--\n+* Set `C'` to `C`.\n++\n+* Replace each parent `P` of `C'` with its simplification `P'`.  In\n+  the process, drop parents that are ancestors of other parents, and\n+  remove duplicates.\n++\n+* If after this parent rewriting, `C'` is a root or merge commit (has\n+  zero or >1 parents), a boundary commit, or !TREESAME, it remains.\n+  Otherwise, it is replaced with its only parent.\n+--\n++\n+The effect of this is best shown by way of comparing to\n+'\\--full-history' with parent rewriting.  The example turns into:\n++\n+-----------------------------------------------------------------------\n+\t  .-A---M---N---O\n+\t /     /       /\n+\tI     B       D\n+\t \\   /       /\n+\t  `---------'\n+-----------------------------------------------------------------------\n++\n+Note the major differences in `N` and `P` over '\\--full-history':\n++\n+--\n+* `N`'s parent list had `I` removed, because it is an ancestor of the\n+  other parent `M`.  Still, `N` remained because it is !TREESAME.\n++\n+* `P`'s parent list similarly had `I` removed.  `P` was then\n+  removed completely, because it had one parent and is TREESAME.\n+--\n \n ifdef::git-rev-list[]\n Bisection Helpers\n-- \n1.6.0.rc2.56.g86ca\n"}]}