{"thread":{"id":"34227","subject":"Splitting a rev list into 2 sets","startedAt":"2013-06-20T10:14:22Z","lastAt":"2013-06-25T08:09:45Z","messageCount":12,"participants":["Francis Moreau","Ramkumar Ramachandra","Phil Hord","Thomas Rast"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"221460","messageId":"CAC9WiBi-E+LN4hKGeu0mG7ihJWCaTg-W1Dx_PWmX_vsx-uLOaw@mail.gmail.com","threadId":"34227","inReplyTo":null,"subject":"Splitting a rev list into 2 sets","fromName":"Francis Moreau","fromEmail":"francis.moro@gmail.com","sentAt":"2013-06-20T10:14:22Z","receivedAt":"2013-06-20T10:14:22Z","isPatch":false,"sender":{"key":"francis.moro@gmail.com","avatar":null},"body":"Hello,\n\nI'd like to write a script that would parse commits in one of my repo.\nIdeally this script should accept any revision ranges that\ngit-rev-list would accept.\n\nThis script should consider commits in master differently than the\nones in others branches.\n\nTo get the commit set which can't be reached by master (ie commits\nwhich are specific to branches other than master) I would do:\n\n  # \"$@\" is the range spec passed to the script\n  git rev-list \"$@\" ^master | check_other_commit\n\nBut I don't know if it's possible to use a different git-rev-list\ncommand to get the rest of the commits, ie the ones that are reachable\nby the specified range and master.\n\nOne way to do that is to record the first commit set got by the first\nrev-list command and check that the ones returned by \"git rev-list $@\"\nare not in the record.\n\nBut I'm wondering if someone can see another solution more elegant ?\n\nThanks\n--\nFrancis\n"},{"id":"221464","messageId":"CALkWK0=6ZofURGvC-FtS81765yDsA9+0wW94riPZUPudc_nDyw@mail.gmail.com","threadId":"34227","inReplyTo":"CAC9WiBi-E+LN4hKGeu0mG7ihJWCaTg-W1Dx_PWmX_vsx-uLOaw@mail.gmail.com","subject":"Re: Splitting a rev list into 2 sets","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-06-20T11:26:26Z","receivedAt":"2013-06-20T11:26:26Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Francis Moreau wrote:\n> To get the commit set which can't be reached by master (ie commits\n> which are specific to branches other than master) I would do:\n>\n>   # \"$@\" is the range spec passed to the script\n>   git rev-list \"$@\" ^master | check_other_commit\n>\n> But I don't know if it's possible to use a different git-rev-list\n> command to get the rest of the commits, ie the ones that are reachable\n> by the specified range and master.\n>\n> One way to do that is to record the first commit set got by the first\n> rev-list command and check that the ones returned by \"git rev-list $@\"\n> are not in the record.\n\nI don't fully understand your query, because almost anything is\npossible with rev-list:\n\n  $ git rev-list foo..bar master # reachable from master, bar, not foo\n\nWhat I _suspect_ you're asking is for help when you can't construct\nthis \"foo..bar master\" programmatically (or when you cannot express\nyour criterion as arguments to rev-list).  You want an initial commit\nset, and filter it at various points in your program using various\ncriteria, right?  In that case, I'd suggest something like this:\n\n    # Returns a list of commits given a committish that `rev-list`\n    # accepts.\n    def self.list_commits(committish)\n        commits = []\n        revlist = execute(\"git\", \"rev-list\", \"--reverse\", \"--date-order\",\n                          \"--simplify-merges\", committish).chomp.split(\"\\n\")\n\n        # do it in batches of 1000 commits\n        while revlist\n            these_revs = revlist.first(1000).join(\"\\n\")\n            this_chunk = execute({ :in => these_revs }, \"git\",\n                               \"cat-file\", \"--batch\")\n\n            # parse_cat_file parses the chunk and updates @commit_index\n            parse_cat_file(this_chunk) { |struct| commits << struct }\n\n            revlist = revlist[1000 .. revlist.length - 1]\n        end\n        return commits\n    end\n\n    # Filters a list of commits with the precondition that it exists\n    # in the committish.  :sha1 is used to uniquely identify a commit.\n    def self.filter_commits(commits, committish)\n        revlist = execute(\"git\", \"rev-list\", \"--simplify-merges\",\n                                 committish).split(\"\\n\")\n        allowed_commits = revlist.map { |sha1| @commit_index[sha1.hex] }\n        return commits & allowed_commits\n    end\n\nIn essence, I use '&' to filter and it's extremely fast.  The trick is\nto shell out to git sparingly, store the data you get in a sensible\nmanner, and build fast custom filters based on what you want.  Here\nare a few more examples:\n\n    # Filters a list of commits with the precondition that it is a\n    # first-parent commit in a given committish.\n    def self.filter_fp_commits(commits, committish)\n        revlist = execute(\"git\", \"rev-list\", \"--first-parent\",\n                          \"--simplify-merges\", committish).split(\"\\n\")\n        allowed_commits = revlist.map { |sha1| @commit_index[sha1.hex] }\n        return commits & allowed_commits\n    end\n\n    # Slice a list of commits using a start_hex and end_hex, which\n    # may both be nil.\n    def self.slice_commits(commits, start_commit, end_commit)\n        start_idx = commits.index(start_commit)\n        end_idx = commits.index(end_commit)\n        start_idx = 0 if start_idx.nil?\n        end_idx = commits.size - 1 if end_idx.nil?\n        return commits[start_idx..end_idx]\n    end\n\n    def self.filter_commits_tree_path(commits, path)\n        commit_chunk = (commits.map { |commit| commit.sha1 }).join(\"\\n\")\n        commit_chunk = \"#{commit_chunk}\\n\"\n        diff_tree_chunk = execute({ :in => commit_chunk }, \"git\", \"diff-tree\", \\\n                                  \"-m\", \"-r\", \"-s\", \"--stdin\", path)\n        matching_sha1s = diff_tree_chunk.split(\"\\n\")\n        allowed_commits = matching_sha1s.map { |sha1| @commit_index[sha1.hex] }\n        return commits & allowed_commits\n    end\n\nDid that help?\n"},{"id":"221475","messageId":"CABURp0r+rzRqHv9vMX3Nsxn_p2R7zf8AsY=_Cg98xWRWn+7bkg@mail.gmail.com","threadId":"34227","inReplyTo":"CAC9WiBi-E+LN4hKGeu0mG7ihJWCaTg-W1Dx_PWmX_vsx-uLOaw@mail.gmail.com","subject":"Re: Splitting a rev list into 2 sets","fromName":"Phil Hord","fromEmail":"phil.hord@gmail.com","sentAt":"2013-06-20T13:04:19Z","receivedAt":"2013-06-20T13:04:19Z","isPatch":false,"sender":{"key":"phil.hord@gmail.com","avatar":"https://avatars.githubusercontent.com/u/123908?v=4"},"body":"On Thu, Jun 20, 2013 at 6:14 AM, Francis Moreau <francis.moro@gmail.com> wrote:\n> I'd like to write a script that would parse commits in one of my repo.\n> Ideally this script should accept any revision ranges that\n> git-rev-list would accept.\n>\n> This script should consider commits in master differently than the\n> ones in others branches.\n>\n> To get the commit set which can't be reached by master (ie commits\n> which are specific to branches other than master) I would do:\n>\n>   # \"$@\" is the range spec passed to the script\n>   git rev-list \"$@\" ^master | check_other_commit\n>\n> But I don't know if it's possible to use a different git-rev-list\n> command to get the rest of the commits, ie the ones that are reachable\n> by the specified range and master.\n>\n> One way to do that is to record the first commit set got by the first\n> rev-list command and check that the ones returned by \"git rev-list $@\"\n> are not in the record.\n>\n> But I'm wondering if someone can see another solution more elegant ?\n\nI do not know if I would call this elegant, but I think this\ncodification of your \"One way to do that\" is at least small and mostly\nreadable:\n\n   git rev-list \"$@\" |grep -v -f <(git rev-list \"$@\" ^master)\n\nPhil\n"},{"id":"221477","messageId":"CAC9WiBgmswSqDHS3XOubvkY6GhBqrQ3YdwgKR4npqHM-kLJuMA@mail.gmail.com","threadId":"34227","inReplyTo":"CALkWK0=6ZofURGvC-FtS81765yDsA9+0wW94riPZUPudc_nDyw@mail.gmail.com","subject":"Re: Splitting a rev list into 2 sets","fromName":"Francis Moreau","fromEmail":"francis.moro@gmail.com","sentAt":"2013-06-20T13:12:09Z","receivedAt":"2013-06-20T13:12:09Z","isPatch":false,"sender":{"key":"francis.moro@gmail.com","avatar":null},"body":"On Thu, Jun 20, 2013 at 1:26 PM, Ramkumar Ramachandra\n<artagnon@gmail.com> wrote:\n> Francis Moreau wrote:\n>> To get the commit set which can't be reached by master (ie commits\n>> which are specific to branches other than master) I would do:\n>>\n>>   # \"$@\" is the range spec passed to the script\n>>   git rev-list \"$@\" ^master | check_other_commit\n>>\n>> But I don't know if it's possible to use a different git-rev-list\n>> command to get the rest of the commits, ie the ones that are reachable\n>> by the specified range and master.\n>>\n>> One way to do that is to record the first commit set got by the first\n>> rev-list command and check that the ones returned by \"git rev-list $@\"\n>> are not in the record.\n>\n> I don't fully understand your query, because almost anything is\n> possible with rev-list:\n>\n>   $ git rev-list foo..bar master # reachable from master, bar, not foo\n>\n> What I _suspect_ you're asking is for help when you can't construct\n> this \"foo..bar master\" programmatically (or when you cannot express\n> your criterion as arguments to rev-list).  You want an initial commit\n> set, and filter it at various points in your program using various\n> criteria, right?\n\nYes, I would like to be sure that I haven't missed some magic syntax\nfor rev-list before going further in my poor man solution :)\n\nBasically I have an initial set (or can be several different sets)\nexpressed as a revision specification described by git-rev-list man\npage. I just want to find the common set of commit which are part of\nthe initial sets *and* is reachable by master.\n\nI would write it:\n\n     git rev-list \"$@\" --and master\n\n> In that case, I'd suggest something like this:\n\nThanks for the details example.\n\n--\nFrancis\n"},{"id":"221479","messageId":"CAC9WiBg2+ep2EMhcofh14TqG+eujbDg51UDLGm3OK=ntOFuRxw@mail.gmail.com","threadId":"34227","inReplyTo":"CABURp0r+rzRqHv9vMX3Nsxn_p2R7zf8AsY=_Cg98xWRWn+7bkg@mail.gmail.com","subject":"Re: Splitting a rev list into 2 sets","fromName":"Francis Moreau","fromEmail":"francis.moro@gmail.com","sentAt":"2013-06-20T13:17:08Z","receivedAt":"2013-06-20T13:17:08Z","isPatch":false,"sender":{"key":"francis.moro@gmail.com","avatar":null},"body":"Hi,\n\nOn Thu, Jun 20, 2013 at 3:04 PM, Phil Hord <phil.hord@gmail.com> wrote:\n> On Thu, Jun 20, 2013 at 6:14 AM, Francis Moreau <francis.moro@gmail.com> wrote:\n>> I'd like to write a script that would parse commits in one of my repo.\n>> Ideally this script should accept any revision ranges that\n>> git-rev-list would accept.\n>>\n>> This script should consider commits in master differently than the\n>> ones in others branches.\n>>\n>> To get the commit set which can't be reached by master (ie commits\n>> which are specific to branches other than master) I would do:\n>>\n>>   # \"$@\" is the range spec passed to the script\n>>   git rev-list \"$@\" ^master | check_other_commit\n>>\n>> But I don't know if it's possible to use a different git-rev-list\n>> command to get the rest of the commits, ie the ones that are reachable\n>> by the specified range and master.\n>>\n>> One way to do that is to record the first commit set got by the first\n>> rev-list command and check that the ones returned by \"git rev-list $@\"\n>> are not in the record.\n>>\n>> But I'm wondering if someone can see another solution more elegant ?\n>\n> I do not know if I would call this elegant, but I think this\n> codification of your \"One way to do that\" is at least small and mostly\n> readable:\n>\n>    git rev-list \"$@\" |grep -v -f <(git rev-list \"$@\" ^master)\n>\n\nYes, thanks.\n\nBut I wanted to be sure that git-rev-list can't display the\nintersection of several sets before going forward.\n\n--\nFrancis\n"},{"id":"221481","messageId":"8761x87wc8.fsf@linux-k42r.v.cablecom.net","threadId":"34227","inReplyTo":"CAC9WiBi-E+LN4hKGeu0mG7ihJWCaTg-W1Dx_PWmX_vsx-uLOaw@mail.gmail.com","subject":"Re: Splitting a rev list into 2 sets","fromName":"Thomas Rast","fromEmail":"trast@inf.ethz.ch","sentAt":"2013-06-20T13:20:07Z","receivedAt":"2013-06-20T13:20:07Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Francis Moreau <francis.moro@gmail.com> writes:\n\n> Hello,\n>\n> I'd like to write a script that would parse commits in one of my repo.\n> Ideally this script should accept any revision ranges that\n> git-rev-list would accept.\n>\n> This script should consider commits in master differently than the\n> ones in others branches.\n>\n> To get the commit set which can't be reached by master (ie commits\n> which are specific to branches other than master) I would do:\n>\n>   # \"$@\" is the range spec passed to the script\n>   git rev-list \"$@\" ^master | check_other_commit\n>\n> But I don't know if it's possible to use a different git-rev-list\n> command to get the rest of the commits, ie the ones that are reachable\n> by the specified range and master.\n>\n> One way to do that is to record the first commit set got by the first\n> rev-list command and check that the ones returned by \"git rev-list $@\"\n> are not in the record.\n>\n> But I'm wondering if someone can see another solution more elegant ?\n\nI think there's a cute way.  Suppose your arguments are of the form\n\n  p1 p2 ... --not n1 n2 ...\n\nthat is each pX is positive, and each nX is negative.  Then as you\nobserved, building the difference with master is easy: just add it to\nthe negative args.\n\nIntersecting with master is harder, because you don't know what parts of\nit (if any) are in the range.  But the --boundary option can help: these\nare the commits where the positive and negative ranges \"first\" met, and\nprevented the walk from continuing.\n\nSo the part of master reachable from p1, p2, etc. is exactly the set of\nboundary commits of 'p1 p2 ... ^master'.  And on top of that, excluding\nthe parts reachable from the n's is easy.  So you can do:\n\n  positive=$(git rev-parse \"$@\" | grep -v '^\\^')\n  negative=$(git rev-parse \"$@\" | grep '^\\^')\n  boundary=$(git rev-list --boundary $positive ^master | sed -n 's/^-//p')\n  # the intersection is\n  git rev-list $boundary $negative\n\nI haven't tested it much, however.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"221487","messageId":"CALkWK0k_2jzQNBjLKZ4SDc9vqoZuQ7937dnO6Z_Ye4Ha+FNcag@mail.gmail.com","threadId":"34227","inReplyTo":"CAC9WiBgmswSqDHS3XOubvkY6GhBqrQ3YdwgKR4npqHM-kLJuMA@mail.gmail.com","subject":"Re: Splitting a rev list into 2 sets","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-06-20T13:47:31Z","receivedAt":"2013-06-20T13:47:31Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Francis Moreau wrote:\n> Basically I have an initial set (or can be several different sets)\n> expressed as a revision specification described by git-rev-list man\n> page. I just want to find the common set of commit which are part of\n> the initial sets *and* is reachable by master.\n\nThat's just a generic list intersection between\n\n  [a, b, c] and [d, e, f]\n\nno?  [a, b, c] is a list you built up somehow, and [d, e, f] comes\nfrom $(git rev-list master), right?\n\nYou could go about determining the revision walk boundaries and\ncombine them to set up a revision walk to splice the master line, but\nwhat is the point of that?  You'll only be painting yourself into a\ndesign-corner (you won't be able to do other kinds of filtering), and\ngoing around your head to touch your nose.  You precisely want list\nintersection: so write an efficient list intersection in the language\nof your choice.  Why is it a poor man's solution?  If anything, your\nconvoluted rev-list solution will probably be more complicated,\nslower, and bug-ridden.\n"},{"id":"221493","messageId":"CAC9WiBgb18ZX0vr8V79tCEUStrDRhRiSh44nH6+3B_Kf8rypYg@mail.gmail.com","threadId":"34227","inReplyTo":"8761x87wc8.fsf@linux-k42r.v.cablecom.net","subject":"Re: Splitting a rev list into 2 sets","fromName":"Francis Moreau","fromEmail":"francis.moro@gmail.com","sentAt":"2013-06-20T16:24:10Z","receivedAt":"2013-06-20T16:24:10Z","isPatch":false,"sender":{"key":"francis.moro@gmail.com","avatar":null},"body":"Hi,\n\nOn Thu, Jun 20, 2013 at 3:20 PM, Thomas Rast <trast@inf.ethz.ch> wrote:\n> Francis Moreau <francis.moro@gmail.com> writes:\n>>\n>> But I'm wondering if someone can see another solution more elegant ?\n>\n> I think there's a cute way.  Suppose your arguments are of the form\n\nReally nice !\n\n>\n>   p1 p2 ... --not n1 n2 ...\n>\n> that is each pX is positive, and each nX is negative.  Then as you\n> observed, building the difference with master is easy: just add it to\n> the negative args.\n\nI didn't know that git-rev-parse could be used to transform any range\nspecification into that form (p1 p2 .. -not n1 n2..)\n\n>\n> Intersecting with master is harder, because you don't know what parts of\n> it (if any) are in the range.  But the --boundary option can help: these\n> are the commits where the positive and negative ranges \"first\" met, and\n> prevented the walk from continuing.\n>\n> So the part of master reachable from p1, p2, etc. is exactly the set of\n> boundary commits of 'p1 p2 ... ^master'.  And on top of that, excluding\n> the parts reachable from the n's is easy.  So you can do:\n\nReally clever.\n\n>\n>   positive=$(git rev-parse \"$@\" | grep -v '^\\^')\n>   negative=$(git rev-parse \"$@\" | grep '^\\^')\n>   boundary=$(git rev-list --boundary $positive ^master | sed -n 's/^-//p')\n>   # the intersection is\n>   git rev-list $boundary $negative\n\nI think there's a minor issue here, when boundary is empty. Please\ncorrect me if I'm wrong but I think it can only happen if positive is\nsimply master or a subset of master. In that case I think the solution\nis just make boundary equal to positive:\n\n     # the intersection is\n     git rev-list ${boundary:-$positive} $negative\n\nNow I'm going to see if that solution is faster than the initial one.\n\nGreat Thanks\n--\nFrancis\n"},{"id":"221563","messageId":"CAC9WiBieEG9zhiAqC+bwCAN8qutRr0L_-Fo19ORBqjecnBynhQ@mail.gmail.com","threadId":"34227","inReplyTo":"CALkWK0k_2jzQNBjLKZ4SDc9vqoZuQ7937dnO6Z_Ye4Ha+FNcag@mail.gmail.com","subject":"Re: Splitting a rev list into 2 sets","fromName":"Francis Moreau","fromEmail":"francis.moro@gmail.com","sentAt":"2013-06-21T07:15:13Z","receivedAt":"2013-06-21T07:15:13Z","isPatch":false,"sender":{"key":"francis.moro@gmail.com","avatar":null},"body":"Hi,\n\nOn Thu, Jun 20, 2013 at 3:47 PM, Ramkumar Ramachandra\n<artagnon@gmail.com> wrote:\n> Francis Moreau wrote:\n>> Basically I have an initial set (or can be several different sets)\n>> expressed as a revision specification described by git-rev-list man\n>> page. I just want to find the common set of commit which are part of\n>> the initial sets *and* is reachable by master.\n>\n> That's just a generic list intersection between\n>\n>   [a, b, c] and [d, e, f]\n>\n> no?  [a, b, c] is a list you built up somehow, and [d, e, f] comes\n> from $(git rev-list master), right?\n\nyes.\n\n>\n> You could go about determining the revision walk boundaries and\n> combine them to set up a revision walk to splice the master line, but\n> what is the point of that?\n\nWell, that seems to me a more elegant solution and I was curious about\ndoing this with git-rev-list only if possible.\n\n>  You'll only be painting yourself into a\n> design-corner (you won't be able to do other kinds of filtering), and\n> going around your head to touch your nose.\n\nI think what Thomas proposed is fine.\n\n>  You precisely want list\n> intersection: so write an efficient list intersection in the language\n> of your choice.  Why is it a poor man's solution?\n\nSorry my wording was poor. I just meant that it was the obvious\nsolution that I don't find nice. But your implementation was good.\n\n>  If anything, your\n> convoluted rev-list solution will probably be more complicated,\n> slower, and bug-ridden.\n\nSlower ? why do you think Thomas' solution is slower than the obvious one ?\n\nThanks\n--\nFrancis\n"},{"id":"221564","messageId":"CALkWK0=xL-o3tHLK8iqyB+KTt8S7QA=Ln8o8kwW+fisY7D_TeA@mail.gmail.com","threadId":"34227","inReplyTo":"CAC9WiBieEG9zhiAqC+bwCAN8qutRr0L_-Fo19ORBqjecnBynhQ@mail.gmail.com","subject":"Re: Splitting a rev list into 2 sets","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-06-21T07:19:26Z","receivedAt":"2013-06-21T07:19:26Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Francis Moreau wrote:\n> Slower ? why do you think Thomas' solution is slower than the obvious one ?\n\nThere's really only one way to find out: try it and see. YMMV\ndepending on your data.\n"},{"id":"221780","messageId":"87mwqf3k3n.fsf@linux-k42r.v.cablecom.net","threadId":"34227","inReplyTo":"CAC9WiBgb18ZX0vr8V79tCEUStrDRhRiSh44nH6+3B_Kf8rypYg@mail.gmail.com","subject":"Re: Splitting a rev list into 2 sets","fromName":"Thomas Rast","fromEmail":"trast@inf.ethz.ch","sentAt":"2013-06-24T09:59:24Z","receivedAt":"2013-06-24T09:59:24Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Francis Moreau <francis.moro@gmail.com> writes:\n\n> On Thu, Jun 20, 2013 at 3:20 PM, Thomas Rast <trast@inf.ethz.ch> wrote:\n>>   positive=$(git rev-parse \"$@\" | grep -v '^\\^')\n>>   negative=$(git rev-parse \"$@\" | grep '^\\^')\n>>   boundary=$(git rev-list --boundary $positive ^master | sed -n 's/^-//p')\n>>   # the intersection is\n>>   git rev-list $boundary $negative\n>\n> I think there's a minor issue here, when boundary is empty. Please\n> correct me if I'm wrong but I think it can only happen if positive is\n> simply master or a subset of master. In that case I think the solution\n> is just make boundary equal to positive:\n>\n>      # the intersection is\n>      git rev-list ${boundary:-$positive} $negative\n>\n> Now I'm going to see if that solution is faster than the initial one.\n\nJan \"jast\" Krüger pointed out on #git that\n\n  git log $(git merge-base --all A B)\n\nis exactly the set of commits reachable from both A and B; so there's\nyour intersection operator :-)\n\nSo it would seem that a much simpler approach is\n\n  git rev-list $(git merge-base --all master $positive) --not $negative\n\navoiding the boundary handling and special-case.  It relies on the\n(weird?) property that $(git merge-base --all A B1 B2 ...) shows the\nmerge bases of A with a hypothetical merge of B1, B2, ..., which is just\nwhat you need here.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"221925","messageId":"CAC9WiBiEtygQGB7JAo5mWuetFE_WTZOYDaTTKv_bkbWQs8xe8A@mail.gmail.com","threadId":"34227","inReplyTo":"87mwqf3k3n.fsf@linux-k42r.v.cablecom.net","subject":"Re: Splitting a rev list into 2 sets","fromName":"Francis Moreau","fromEmail":"francis.moro@gmail.com","sentAt":"2013-06-25T08:09:45Z","receivedAt":"2013-06-25T08:09:45Z","isPatch":false,"sender":{"key":"francis.moro@gmail.com","avatar":null},"body":"Hello Thomas,\n\nOn Mon, Jun 24, 2013 at 11:59 AM, Thomas Rast <trast@inf.ethz.ch> wrote:\n> Francis Moreau <francis.moro@gmail.com> writes:\n>\n>> On Thu, Jun 20, 2013 at 3:20 PM, Thomas Rast <trast@inf.ethz.ch> wrote:\n>>>   positive=$(git rev-parse \"$@\" | grep -v '^\\^')\n>>>   negative=$(git rev-parse \"$@\" | grep '^\\^')\n>>>   boundary=$(git rev-list --boundary $positive ^master | sed -n 's/^-//p')\n>>>   # the intersection is\n>>>   git rev-list $boundary $negative\n>>\n>> I think there's a minor issue here, when boundary is empty. Please\n>> correct me if I'm wrong but I think it can only happen if positive is\n>> simply master or a subset of master. In that case I think the solution\n>> is just make boundary equal to positive:\n>>\n>>      # the intersection is\n>>      git rev-list ${boundary:-$positive} $negative\n>>\n>> Now I'm going to see if that solution is faster than the initial one.\n>\n> Jan \"jast\" Krüger pointed out on #git that\n>\n>   git log $(git merge-base --all A B)\n>\n> is exactly the set of commits reachable from both A and B; so there's\n> your intersection operator :-)\n\nnice :)\n\n>\n> So it would seem that a much simpler approach is\n>\n>   git rev-list $(git merge-base --all master $positive) --not $negative\n>\n> avoiding the boundary handling and special-case.  It relies on the\n> (weird?) property that $(git merge-base --all A B1 B2 ...) shows the\n> merge bases of A with a hypothetical merge of B1, B2, ..., which is just\n> what you need here.\n\nThank you Thomas, that's exactly what I was asking for :)\n\n--\nFrancis\n"}]}