{"thread":{"id":"25141","subject":"Find out on which branch a commit was originally made","startedAt":"2010-09-18T09:19:53Z","lastAt":"2010-09-24T20:57:19Z","messageCount":33,"participants":["Stefan Haller","Ævar Arnfjörð Bjarmason","Tor Arntsen","Artur Skawina","Clemens Buchacher","Robin Rosenberg","Seth Robertson","Stephen Bash","Bryan Drewery"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"150937","messageId":"1jp0h7e.lgk0kp19qe5bbM%lists@haller-berlin.de","threadId":"25141","inReplyTo":null,"subject":"Find out on which branch a commit was originally made","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2010-09-18T09:19:53Z","receivedAt":"2010-09-18T09:19:53Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"I'm trying to pursuade my co-workers to switch from Subversion to Git;\nsome of them prefer Mercurial.\n\nOne concern that they are raising is that in Git there doesn't seem to\nbe an easy way to find out on which branch a given commit was originally\nmade, after the branch is merged back and deleted. They consider this a\nshow-stopper.  In Mercurial, branch information is meta data attached to\neach commit, so you can easily get this information even after a branch\nis closed.\n\nThree questions:\n\n1) Is this not something that Git users miss sometimes?  Why not?\n\n2) Is there an easy way to get this information that I might have\nmissed?  (Typical use-case: you blame a line of code with git gui blame,\nchoose \"Show history context\" to show the changeset in gitk, and from\nthere you want to go up to the next merge commit to see if the merge\ncommit message mentions the name of the branch. I can't seem to figure\nout how to find this merge commit in gitk, and besides, \"Show history\ncontext\" shows me only 7 days of context by default, so the merge commit\nis likely not to be in my current list anyway.)\n\n3) As a possible work-around, they suggest to require encoding the\nbranch information in some format in the commit messages, maybe\nautomatically with a commit-msg hook.  Does this sound like a feasible\nidea?  One drawback would be that it becomes awkward when you\naccidentally make a commit on the wrong branch, and want to rebase it\nonto the correct one.\n\nAny insights and thoughts about this are much appreciated.\n\nThanks,\n   Stefan\n\n\n-- \nStefan Haller\nBerlin, Germany\nhttp://www.haller-berlin.de/\n"},{"id":"150943","messageId":"AANLkTiknoBS7x2za3qzghfS0TD6UUL83eoZz7LFBPUuc@mail.gmail.com","threadId":"25141","inReplyTo":"1jp0h7e.lgk0kp19qe5bbM%lists@haller-berlin.de","subject":"Re: Find out on which branch a commit was originally made","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-09-18T09:58:40Z","receivedAt":"2010-09-18T09:58:40Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Sat, Sep 18, 2010 at 09:19, Stefan Haller <lists@haller-berlin.de> wrote:\n> I'm trying to pursuade my co-workers to switch from Subversion to Git;\n> some of them prefer Mercurial.\n>\n> One concern that they are raising is that in Git there doesn't seem to\n> be an easy way to find out on which branch a given commit was originally\n> made, after the branch is merged back and deleted. They consider this a\n> show-stopper.  In Mercurial, branch information is meta data attached to\n> each commit, so you can easily get this information even after a branch\n> is closed.\n>\n> Three questions:\n>\n> 1) Is this not something that Git users miss sometimes?  Why not?\n>\n> 2) Is there an easy way to get this information that I might have\n> missed?  (Typical use-case: you blame a line of code with git gui blame,\n> choose \"Show history context\" to show the changeset in gitk, and from\n> there you want to go up to the next merge commit to see if the merge\n> commit message mentions the name of the branch. I can't seem to figure\n> out how to find this merge commit in gitk, and besides, \"Show history\n> context\" shows me only 7 days of context by default, so the merge commit\n> is likely not to be in my current list anyway.)\n>\n> 3) As a possible work-around, they suggest to require encoding the\n> branch information in some format in the commit messages, maybe\n> automatically with a commit-msg hook.  Does this sound like a feasible\n> idea?  One drawback would be that it becomes awkward when you\n> accidentally make a commit on the wrong branch, and want to rebase it\n> onto the correct one.\n\n    You want to do X, and you think Y is the best way of doing so.\nInstead of asking about X, you ask about Y.\n    — from Re: sequencial file naming by Abigail\n\nYour Y is encoding the name of the current branch at commit-time, the\nyou haven't told us. Why do your co-workers think this is essential to\nthe point that they can't get by without it? What problem are they\ntrying to solve?\n\nBut to answer your question then no, Git doesn't track this\ninformation. Because we think it's irrelevant.\n\nAs an example of how irrelevant it is consider my huge ab/i18n series\n(you may have spotted it on the list). It's currently composed of 140\npatches.\n\nIf Git tracked the branch at commit time that series would contain a\nbunch of useless metadata. The series is currently composed of commits\nwhich were originally created on at least some of these branches:\n\n    $ git branch -l |grep -e gettext -e i18n\n    * ab/i18n\n      ab/i18n-add-translations\n      ab/i18n-all\n      ab/i18n-all-continue\n      ab/i18n-continue\n      ab/i18n-continue-hi.po\n      ab/i18n-continue-more\n      ab/i18n-continue-with-hindi\n      ab/i18n-for-junio\n      ab/i18n-for-junio-with-docs\n      ab/i18n-gettextize\n      ab/i18n-v2\n      debug-gettext-poison\n      disable-gettext-by-default-in-releases\n      gettext-remove-old-sanity-test\n      gettextize-git-in-german\n      gettextize-git-mainporcelain\n      gettextize-git-mainporcelain-even-more\n      gettextize-git-mainporcelain-more\n      gettextize-git-mainporcelain-v2\n      gettextize-git-mainporcelain-v3\n      gettextize-git-mainporcelain-with-perl\n      minor-gettext-infrastructure-fixes\n\nBut nobody will ever care what branch name I just happened to pick\nwhile I was hacking some patch, why should they? Why does it matter\nthan I commited some commit on a Solaris box on a branch called\n`ab/i18n-oh-man-i-hate-solaris-will-this-just-bloddy-work-already' ?\n\nWhat Git *does* track however when you do `git merge topic` is the\nname of the `topic` branch you're merging into some other branch,\ne.g. here (from git-merge(1)):\n\n                     A---B---C topic\n                    /         \\\n               D---E---F---G---H master\n\nEven though A B and C might have been commited on branches called\n`blah`, `bluh` and `blarghl` you'll never know. You'll just know that\nsomeone put them all together on a branch called `topic` and that\nsomeone later merged that into master in the main repository. E.g.:\n\n    Merge: A G\n    Author: Some Guy <some-guy@example.com>\n    Date:   <....>\n\n        Merge branch 'topic'\n\nFrom there you can *infer* that A-B-C came from the topic branch,\nbecause of that merge commit and that the DAG doesn't meet master\nuntil commit E.\n\nBut you can't ever get info about `blah`, `bluh` and `blarghl` back\nout of A-B and C again unless you track those branches down in\nsomeone's development repository.\n\nWhy? Because who cares about `blah`, `bluh` and `blarghl`, really?\n"},{"id":"150944","messageId":"AANLkTik50NTkA8DCzrQRR3Z+JO6++sseZqcfcCG4zQ5Z@mail.gmail.com","threadId":"25141","inReplyTo":"AANLkTiknoBS7x2za3qzghfS0TD6UUL83eoZz7LFBPUuc@mail.gmail.com","subject":"Re: Find out on which branch a commit was originally made","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-09-18T10:02:24Z","receivedAt":"2010-09-18T10:02:24Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Sat, Sep 18, 2010 at 09:58, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n>    You want to do X, and you think Y is the best way of doing so.\n> Instead of asking about X, you ask about Y.\n>    — from Re: sequencial file naming by Abigail\n>\n> Your Y is encoding the name of the current branch at commit-time, the\n> you haven't told us.\n\n\"the X you haven't told us\", damn PEBKAC problems.\n"},{"id":"150946","messageId":"AANLkTim4cqAhWPTY5tSsFq7S1A_f=9QFy=3Mrp9ZFwXT@mail.gmail.com","threadId":"25141","inReplyTo":"AANLkTiknoBS7x2za3qzghfS0TD6UUL83eoZz7LFBPUuc@mail.gmail.com","subject":"Re: Find out on which branch a commit was originally made","fromName":"Tor Arntsen","fromEmail":"tor@spacetec.no","sentAt":"2010-09-18T11:28:25Z","receivedAt":"2010-09-18T11:28:25Z","isPatch":false,"sender":{"key":"tor@spacetec.no","avatar":null},"body":"On Sat, Sep 18, 2010 at 11:58, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n[..]\n> What Git *does* track however when you do `git merge topic` is the\n> name of the `topic` branch you're merging into some other branch,\n> e.g. here (from git-merge(1)):\n>\n>                     A---B---C topic\n>                    /         \\\n>               D---E---F---G---H master\n>\n> Even though A B and C might have been commited on branches called\n> `blah`, `bluh` and `blarghl` you'll never know. You'll just know that\n> someone put them all together on a branch called `topic` and that\n> someone later merged that into master in the main repository. E.g.:\n>\n>    Merge: A G\n>    Author: Some Guy <some-guy@example.com>\n>    Date:   <....>\n>\n>        Merge branch 'topic'\n>\n> >From there you can *infer* that A-B-C came from the topic branch,\n> because of that merge commit and that the DAG doesn't meet master\n> until commit E.\n[..]\n\nHowever, you can see it explictly if you add --log when merging, i.e.\ngit merge --no-ff --log topic\n(you'll get a list of one-line commit messages from those commits\nmerged into master from topic).\nIt doesn't identify the commits, only the commit messages. Therefore I\nadd problem report IDs into my oneline-messages, and I get a shortlist\nof exactly what was fixed by a given merge. This is sufficient support\nfor me, I too don't care where a commit _originally_ came from, before\nit arrived into the branch that I at some point merge to the delivery\nbranch.\n\n-Tor\n"},{"id":"150955","messageId":"1jp0xnn.1gyr9a31jn4r7cM%lists@haller-berlin.de","threadId":"25141","inReplyTo":"AANLkTiknoBS7x2za3qzghfS0TD6UUL83eoZz7LFBPUuc@mail.gmail.com","subject":"Re: Find out on which branch a commit was originally made","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2010-09-18T15:26:08Z","receivedAt":"2010-09-18T15:26:08Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"Ævar Arnfjör? Bjarmason <avarab@gmail.com> wrote:\n\n>     You want to do X, and you think Y is the best way of doing so.\n> Instead of asking about X, you ask about Y.\n\nErm, not really; I explicitly mentioned Y as \"a possible workaround\"\nonly.  Anyway...\n\n> Why do your co-workers think this is essential to the point that they\n> can't get by without it? What problem are they trying to solve?\n\nIt's a common situation that you want to know why a certain piece of\ncode is written the way it is.  So you blame it, you eventually end up\nat a certain interesting changeset, and hopefully the commit message\ntells you enough about why the change was made.  If it doesn't, then it\ncan help a lot to know a bit more about the context of the change, i.e.\nwhat topic it was part of.\n\n> What Git *does* track however when you do `git merge topic` is the\n> name of the `topic` branch you're merging into some other branch,\n> e.g. here (from git-merge(1)):\n> \n>                      A---B---C topic\n>                     /         \\\n>                D---E---F---G---H master\n> \n> Even though A B and C might have been commited on branches called\n> `blah`, `bluh` and `blarghl` you'll never know. You'll just know that\n> someone put them all together on a branch called `topic` and that\n> someone later merged that into master in the main repository. E.g.:\n> \n>     Merge: A G\n>     Author: Some Guy <some-guy@example.com>\n>     Date:   <....>\n> \n>         Merge branch 'topic'\n> \n> From there you can *infer* that A-B-C came from the topic branch,\n\nOK, that's pretty much the same as what I had in mind.  (We're\nsimple-minded, so for us \"original branch\" and topic branch is the same\nmost of the time.)\n\nThe question is the same though: if I hit commit B while blaming, how do\nI know what topic it was a part of?  For that, I need to find commit H\nwhich will tell me, right?  How do I do that?\n\n-Stefan\n\n\n-- \nStefan Haller\nBerlin, Germany\nhttp://www.haller-berlin.de/\n"},{"id":"150957","messageId":"4C94EBBC.4080201@gmail.com","threadId":"25141","inReplyTo":"1jp0xnn.1gyr9a31jn4r7cM%lists@haller-berlin.de","subject":"Re: Find out on which branch a commit was originally made","fromName":"Artur Skawina","fromEmail":"art.08.09@gmail.com","sentAt":"2010-09-18T16:41:32Z","receivedAt":"2010-09-18T16:41:32Z","isPatch":false,"sender":{"key":"art.08.09@gmail.com","avatar":null},"body":"On 09/18/10 17:26, Stefan Haller wrote:\n> Ævar Arnfjör? Bjarmason <avarab@gmail.com> wrote:\n>>                      A---B---C topic\n>>                     /         \\\n>>                D---E---F---G---H master\n\n The question is the same though: if I hit commit B while blaming, how do\n> I know what topic it was a part of?  For that, I need to find commit H\n> which will tell me, right?  How do I do that?\n\ngit rev-list --ancestry-path --merges --reverse B..master --format=oneline\n\n> One concern that they are raising is that in Git there doesn't seem to\n> be an easy way to find out on which branch a given commit was originally\n> made, after the branch is merged back and deleted. They consider this a\n> show-stopper.  In Mercurial, branch information is meta data attached to\n> each commit, so you can easily get this information even after a branch\n> is closed.\n\nDon't do that, then. \nIOW if you know you could still need the old branch info, make an alias\nthat doesn't actually delete the branch after merging, but moves the ref\naway, eg 'topic-name' -> \"merged/topic-name\" or just adds a\n\"merged/topic-name\" tag. Then simply checking from which \"merged/*\"\nbranch/tag the offending commit is reachable would be enough.\nDeleting a merged branch does not do anything more than removing the\nreference (to 'C' in the above example), all the history stays around\nforever anyway...\n\nartur\n"},{"id":"150981","messageId":"1jp2d5s.1q4xl2w1f5ufljM%lists@haller-berlin.de","threadId":"25141","inReplyTo":"4C94EBBC.4080201@gmail.com","subject":"Re: Find out on which branch a commit was originally made","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2010-09-19T09:45:25Z","receivedAt":"2010-09-19T09:45:25Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"Artur Skawina <art.08.09@gmail.com> wrote:\n\n> On 09/18/10 17:26, Stefan Haller wrote:\n> > Ævar Arnfjör? Bjarmason <avarab@gmail.com> wrote:\n> >>                      A---B---C topic\n> >>                     /         \\\n> >>                D---E---F---G---H master\n> \n> > The question is the same though: if I hit commit B while blaming, how do\n> > I know what topic it was a part of?  For that, I need to find commit H\n> > which will tell me, right?  How do I do that?\n> \n> git rev-list --ancestry-path --merges --reverse B..master --format=oneline\n\nThanks, this is helpful.  (However, my co-workers will probably laugh at\nme if I suggest they remember a command such as this for what they think\nshould be a very simple operation.)\n\nThere's a problem though for commits that are far back in history:\n\n               A---B---C topic\n              /         \\\n         D---E---F---G---H---I---J---K---L---M---N master\n                                  \\         /\n                                   O---P---Q another-topic\n\nYour command also shows M, which is not interesting at all in this\ncontext.  Ideally it should stop at the first command that's common to\ntopic and master.  Is there an easy way to achieve that?\n\n> IOW if you know you could still need the old branch info, make an alias\n> that doesn't actually delete the branch after merging, but moves the ref\n> away, eg 'topic-name' -> \"merged/topic-name\" or just adds a\n> \"merged/topic-name\" tag. Then simply checking from which \"merged/*\"\n> branch/tag the offending commit is reachable would be enough.\n\nSame problem here: this also shows all branches that were created and\nmerged after the original topic was merged.  (In the example above, it\nwill also list another-topic.)  This makes it pretty much impossible to\nfind the one I'm interested in.\n\n\n-- \nStefan Haller\nBerlin, Germany\nhttp://www.haller-berlin.de/\n"},{"id":"150988","messageId":"20100919125438.GA4870@localhost","threadId":"25141","inReplyTo":"1jp2d5s.1q4xl2w1f5ufljM%lists@haller-berlin.de","subject":"Re: Find out on which branch a commit was originally made","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2010-09-19T12:54:38Z","receivedAt":"2010-09-19T12:54:38Z","isPatch":false,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Sun, Sep 19, 2010 at 11:45:25AM +0200, Stefan Haller wrote:\n> \n> Your command also shows M, which is not interesting at all in this\n> context.  Ideally it should stop at the first command that's common to\n> topic and master.  Is there an easy way to achieve that?\n\nhead -1?\n"},{"id":"150991","messageId":"4C96183E.7020208@gmail.com","threadId":"25141","inReplyTo":"1jp2d5s.1q4xl2w1f5ufljM%lists@haller-berlin.de","subject":"Re: Find out on which branch a commit was originally made","fromName":"Artur Skawina","fromEmail":"art.08.09@gmail.com","sentAt":"2010-09-19T14:03:42Z","receivedAt":"2010-09-19T14:03:42Z","isPatch":false,"sender":{"key":"art.08.09@gmail.com","avatar":null},"body":"On 09/19/10 11:45, Stefan Haller wrote:\n> Artur Skawina <art.08.09@gmail.com> wrote:\n> \n>> On 09/18/10 17:26, Stefan Haller wrote:\n>>> Ævar Arnfjör? Bjarmason <avarab@gmail.com> wrote:\n>>>>                      A---B---C topic\n>>>>                     /         \\\n>>>>                D---E---F---G---H master\n>>\n>>> The question is the same though: if I hit commit B while blaming, how do\n>>> I know what topic it was a part of?  For that, I need to find commit H\n>>> which will tell me, right?  How do I do that?\n>>\n>> git rev-list --ancestry-path --merges --reverse B..master --format=oneline\n> \n> Thanks, this is helpful.  (However, my co-workers will probably laugh at\n> me if I suggest they remember a command such as this for what they think\n> should be a very simple operation.)\n\nAn alias such as \"git show-merges-since B\" might help.\n\n> There's a problem though for commits that are far back in history:\n> \n>                A---B---C topic\n>               /         \\\n>          D---E---F---G---H---I---J---K---L---M---N master\n>                                   \\         /\n>                                    O---P---Q another-topic\n> \n> Your command also shows M, which is not interesting at all in this\n\nBut you're only interested in the name of the original topic branch,\nright? Then the first merge will tell you that; I omitted \"| head -1\"\nfrom the cmdline above, just in case the history isn't as simple as\nin this graph.\n\n> context.  Ideally it should stop at the first command that's common to\n> topic and master.  Is there an easy way to achieve that?\n\nWell, as you've explicitly deleted the 'topic' ref, how is git supposed\nto find it?\n\nThe above \"git rev-list\" will give you either the merge w/ the info you\nare looking for, or a list of merge commits that you'll have to filter\n(grep etc) to find the first one containing the answer.\n\n>> IOW if you know you could still need the old branch info, make an alias\n>> that doesn't actually delete the branch after merging, but moves the ref\n>> away, eg 'topic-name' -> \"merged/topic-name\" or just adds a\n>> \"merged/topic-name\" tag. Then simply checking from which \"merged/*\"\n>> branch/tag the offending commit is reachable would be enough.\n> \n> Same problem here: this also shows all branches that were created and\n> merged after the original topic was merged.  (In the example above, it\n> will also list another-topic.)  This makes it pretty much impossible to\n\nYes. \"git merge-base master another-topic\" would return 'J' and if 'B'\nis still reachable from 'J' then 'another-topic' isn't the answer and\nyou have to keep looking. So it's a bit more complicated.\n\nartur\n"},{"id":"150992","messageId":"1jp2pkw.1s4r5br1xvl05eM%lists@haller-berlin.de","threadId":"25141","inReplyTo":"1jp2d5s.1q4xl2w1f5ufljM%lists@haller-berlin.de","subject":"Re: Find out on which branch a commit was originally made","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2010-09-19T14:08:13Z","receivedAt":"2010-09-19T14:08:13Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"Stefan Haller <lists@haller-berlin.de> wrote:\n\n> Artur Skawina <art.08.09@gmail.com> wrote:\n> \n> > On 09/18/10 17:26, Stefan Haller wrote:\n> > > Ævar Arnfjör? Bjarmason <avarab@gmail.com> wrote:\n> > >>                      A---B---C topic\n> > >>                     /         \\\n> > >>                D---E---F---G---H master\n> > \n> > > The question is the same though: if I hit commit B while blaming, how do\n> > > I know what topic it was a part of?  For that, I need to find commit H\n> > > which will tell me, right?  How do I do that?\n> > \n> > git rev-list --ancestry-path --merges --reverse B..master --format=oneline\n> \n> Thanks, this is helpful.  (However, my co-workers will probably laugh at\n> me if I suggest they remember a command such as this for what they think\n> should be a very simple operation.)\n> \n> There's a problem though for commits that are far back in history:\n> \n>                A---B---C topic\n>               /         \\\n>          D---E---F---G---H---I---J---K---L---M---N master\n>                                   \\         /\n>                                    O---P---Q another-topic\n> \n> Your command also shows M, which is not interesting at all in this\n> context.  Ideally it should stop at the first command that's common to\n> topic and master.\n\nNo, that's not what I need either.  After thinking about it more, I\nthink what I want is \"of all merges in the ancestry path from B to\nmaster, show only those whose first parent can't reach B.\"  The result\nis the list of all merges that were involved in bringing B to master.\n\nHere's what I came up with:\n\n#!/bin/sh\n\ngit rev-list --ancestry-path --merges --reverse \"$1\"..\"${2-master}\" \\\n  | while read ref\ndo\n  if [ -z \"$(git rev-list --ancestry-path \"$1\"..\"$ref\"^)\" ]\n  then\n    git --no-pager log -1 --pretty=oneline \"$ref\"\n  fi\ndone\n\nIt's pretty inefficient, but seems to get the job done. Is there a\nsmarter way to achieve the same?\n\n-Stefan\n\n\n-- \nStefan Haller\nBerlin, Germany\nhttp://www.haller-berlin.de/\n"},{"id":"150996","messageId":"4C963C84.2050608@gmail.com","threadId":"25141","inReplyTo":"1jp2pkw.1s4r5br1xvl05eM%lists@haller-berlin.de","subject":"Re: Find out on which branch a commit was originally made","fromName":"Artur Skawina","fromEmail":"art.08.09@gmail.com","sentAt":"2010-09-19T16:38:28Z","receivedAt":"2010-09-19T16:38:28Z","isPatch":false,"sender":{"key":"art.08.09@gmail.com","avatar":null},"body":"On 09/19/10 16:08, Stefan Haller wrote:\n> Stefan Haller <lists@haller-berlin.de> wrote:\n> \n>> Artur Skawina <art.08.09@gmail.com> wrote:\n>>\n>>> On 09/18/10 17:26, Stefan Haller wrote:\n>>>> Ævar Arnfjör? Bjarmason <avarab@gmail.com> wrote:\n>>>>>                      A---B---C topic\n>>>>>                     /         \\\n>>>>>                D---E---F---G---H master\n>>>\n>>>> The question is the same though: if I hit commit B while blaming, how do\n>>>> I know what topic it was a part of?  For that, I need to find commit H\n>>>> which will tell me, right?  How do I do that?\n>>>\n>>> git rev-list --ancestry-path --merges --reverse B..master --format=oneline\n>>\n>> Thanks, this is helpful.  (However, my co-workers will probably laugh at\n>> me if I suggest they remember a command such as this for what they think\n>> should be a very simple operation.)\n>>\n>> There's a problem though for commits that are far back in history:\n>>\n>>                A---B---C topic\n>>               /         \\\n>>          D---E---F---G---H---I---J---K---L---M---N master\n>>                                   \\         /\n>>                                    O---P---Q another-topic\n>>\n>> Your command also shows M, which is not interesting at all in this\n>> context.  Ideally it should stop at the first command that's common to\n>> topic and master.\n> \n> No, that's not what I need either.  After thinking about it more, I\n> think what I want is \"of all merges in the ancestry path from B to\n> master, show only those whose first parent can't reach B.\"  The result\n> is the list of all merges that were involved in bringing B to master.\n> \n> Here's what I came up with:\n> \n> #!/bin/sh\n> \n> git rev-list --ancestry-path --merges --reverse \"$1\"..\"${2-master}\" \\\n>   | while read ref\n> do\n>   if [ -z \"$(git rev-list --ancestry-path \"$1\"..\"$ref\"^)\" ]\n>   then\n>     git --no-pager log -1 --pretty=oneline \"$ref\"\n>   fi\n> done\n> \n> It's pretty inefficient, but seems to get the job done. Is there a\n> smarter way to achieve the same?\n\nThis would work, and i don't see a way to optimize it in git-speak,\ngiven that you don't want to see any extra trailing merges. At least,\nnot if it's supposed to be generic; consider a case where the 'topic'\nmerges another 'subtopic' and is then merged into a 'supertopic', which\nis then merged to 'master'. Maybe somebody else has an idea?\n\nFor me, this seems like overkill, the merge list given by \"git rev-list\"\nshould be more than enough to figure out which branch the commit came\nfrom. And if not - either your shell script or walking the history\n(\"--parents\" option) w/ a script would do. But i can't even imagine how\nsuch a history would have to look like... \n\nartur\n"},{"id":"151000","messageId":"201009192030.21659.robin.rosenberg@dewire.com","threadId":"25141","inReplyTo":"1jp0xnn.1gyr9a31jn4r7cM%lists@haller-berlin.de","subject":"Re: Find out on which branch a commit was originally made","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2010-09-19T18:30:21Z","receivedAt":"2010-09-19T18:30:21Z","isPatch":false,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"lördagen den 18 september 2010 17.26.08 skrev  Stefan Haller:\n> Ævar Arnfjör? Bjarmason <avarab@gmail.com> wrote:\n> >     You want to do X, and you think Y is the best way of doing so.\n> > \n> > Instead of asking about X, you ask about Y.\n> \n> Erm, not really; I explicitly mentioned Y as \"a possible workaround\"\n> only.  Anyway...\n> \n> > Why do your co-workers think this is essential to the point that they\n> > can't get by without it? What problem are they trying to solve?\n> \n> It's a common situation that you want to know why a certain piece of\n> code is written the way it is.  So you blame it, you eventually end up\n> at a certain interesting changeset, and hopefully the commit message\n> tells you enough about why the change was made.  If it doesn't, then it\n> can help a lot to know a bit more about the context of the change, i.e.\n> what topic it was part of.\n\nWhat most people do (I think) is to include a reference to a ticket in a issue \ntracker. JGit/EGit adds Bug:-line in the footer. Others add the ticket number \nin the Subject. This much informative than a branch name.  It also allows\nyou to fix unrelated bugs on your branch. \n\n-- robin\n"},{"id":"151011","messageId":"201009192203.o8JM39PE011067@no.baka.org","threadId":"25141","inReplyTo":"201009192030.21659.robin.rosenberg@dewire.com","subject":"Re: Find out on which branch a commit was originally made","fromName":"Seth Robertson","fromEmail":"in-gitvger@baka.org","sentAt":"2010-09-19T22:03:09Z","receivedAt":"2010-09-19T22:03:09Z","isPatch":false,"sender":{"key":"in-gitvger@baka.org","avatar":null},"body":"\n>>>                A---B---C topic\n>>>               /         \\\n>>>          D---E---F---G---H---I---J---K---L---M---N master\n>>>                                   \\         /\n>>>                                    O---P---Q another-topic\n\n>> No, that's not what I need either.  After thinking about it more, I\n>> think what I want is \"of all merges in the ancestry path from B to\n>> master, show only those whose first parent can't reach B.\"  The result\n>> is the list of all merges that were involved in bringing B to master.\n\n\n> This would work, and i don't see a way to optimize it in git-speak,\n> given that you don't want to see any extra trailing merges. [...]\n\nThe provided command actually doesn't work for me for all cases.  It\nworks for the simple case of \"B\", but does not work for \"F\", because F\nsaw merge H & M.  I think we need --not --first-parent, except that\ndoesn't actually work in this case either.  However, if we get the\nfull --first-parent rev-list and look for our commit, that works.\nThis is incredibly painful, though.\n\n----------------------------------------------------------------------\n#!/bin/sh\nTARGET=`git rev-list -n 1 $1`\ngit branch -a --contains $1 | sed 's/^\\** *//' | grep -v ' -> ' |\nwhile read br; do\n if git rev-list --first-parent $br | grep -q \"$TARGET\"; then\n  echo $br\n fi\ndone\n----------------------------------------------------------------------\n\n\t\t\t\t\t-Seth Robertson\n"},{"id":"151014","messageId":"4C9698C5.70607@gmail.com","threadId":"25141","inReplyTo":"201009192203.o8JM39PE011067@no.baka.org","subject":"Re: Find out on which branch a commit was originally made","fromName":"Artur Skawina","fromEmail":"art.08.09@gmail.com","sentAt":"2010-09-19T23:12:05Z","receivedAt":"2010-09-19T23:12:05Z","isPatch":false,"sender":{"key":"art.08.09@gmail.com","avatar":null},"body":"On 09/20/10 00:03, Seth Robertson wrote:\n>>>>                A---B---C topic\n>>>>               /         \\\n>>>>          D---E---F---G---H---I---J---K---L---M---N master\n>>>>                                   \\         /\n>>>>                                    O---P---Q another-topic\n> \n>>> No, that's not what I need either.  After thinking about it more, I\n>>> think what I want is \"of all merges in the ancestry path from B to\n>>> master, show only those whose first parent can't reach B.\"  The result\n>>> is the list of all merges that were involved in bringing B to master.\n> \n> \n>> This would work, and i don't see a way to optimize it in git-speak,\n>> given that you don't want to see any extra trailing merges. [...]\n> \n> The provided command actually doesn't work for me for all cases.  It\n> works for the simple case of \"B\", but does not work for \"F\", because F\n> saw merge H & M.  I think we need --not --first-parent, except that\n\nWell, F was never on a separate branch, so the command returning \"\"\nis arguably the right thing.\nThe example I gave\n(B->[merge of subtopic]->[merged to supertopic]->[merged to master])\nwas the case where \"--not-first-parent\" wouldn't help, even if such\nan option would exist.\n\n> doesn't actually work in this case either.  However, if we get the\n> full --first-parent rev-list and look for our commit, that works.\n> This is incredibly painful, though.\n> ----------------------------------------------------------------------\n> #!/bin/sh\n> TARGET=`git rev-list -n 1 $1`\n> git branch -a --contains $1 | sed 's/^\\** *//' | grep -v ' -> ' |\n> while read br; do\n>  if git rev-list --first-parent $br | grep -q \"$TARGET\"; then\n>   echo $br\n>  fi\n> done\n> ----------------------------------------------------------------------\n\nAnd it does not work if you no longer have the branches around...\n\nBut even if you kept all the old refs, this would return\n\"another-topic\"+\"master\", which is hardly the right answer.\n\nartur\n"},{"id":"151032","messageId":"201009192354.o8JNsVLs018778@no.baka.org","threadId":"25141","inReplyTo":"4C9698C5.70607@gmail.com","subject":"Re: Find out on which branch a commit was originally made","fromName":"Seth Robertson","fromEmail":"in-gitvger@baka.org","sentAt":"2010-09-19T23:54:31Z","receivedAt":"2010-09-19T23:54:31Z","isPatch":false,"sender":{"key":"in-gitvger@baka.org","avatar":null},"body":"\nIn message <4C9698C5.70607@gmail.com>, Artur Skawina writes:\n\nOn 09/20/10 00:03, Seth Robertson wrote:\n>>>>>                A---B---C topic\n>>>>>               /         \\\n>>>>>          D---E---F---G---H---I---J---K---L---M---N master\n>>>>>                                   \\         /\n>>>>>                                    O---P---Q another-topic\n>>\n>>>> No, that's not what I need either.  After thinking about it more, I\n>>>> think what I want is \"of all merges in the ancestry path from B to\n>>>> master, show only those whose first parent can't reach B.\"  The result\n>>>> is the list of all merges that were involved in bringing B to master.\n>>\n>>\n>>> This would work, and i don't see a way to optimize it in git-speak,\n>>> given that you don't want to see any extra trailing merges. [...]\n>>\n>> The provided command actually doesn't work for me for all cases.  It\n>> works for the simple case of \"B\", but does not work for \"F\", because F\n>> saw merge H & M.  I think we need --not --first-parent, except that\n>\n> Well, F was never on a separate branch, so the command returning \"\"\n> is arguably the right thing.\n\nI'd like a command that would tell me the right branch something was\non whether it was on master or topic or whatever.  If instead of\n\"master\" the branch was named \"supertopic\" and master commit AA had\nchild D would that make a difference?\n\n>> doesn't actually work in this case either.  However, if we get the\n>> full --first-parent rev-list and look for our commit, that works.\n>> This is incredibly painful, though.\n>> ----------------------------------------------------------------------\n>> #!/bin/sh\n>> TARGET=`git rev-list -n 1 $1`\n>> git branch -a --contains $1 | sed 's/^\\** *//' | grep -v ' -> ' |\n>> while read br; do\n>>  if git rev-list --first-parent $br | grep -q \"$TARGET\"; then\n>>   echo $br\n>>  fi\n>> done\n>> ----------------------------------------------------------------------\n\n> And it does not work if you no longer have the branches around...\n\nIf something doesn't have a name I am not very interested in it (for\nmy purposes, your milage may vary).  Presumably the other code could be\ncombined with my inner loop.\n\n>But even if you kept all the old refs, this would return\n>\"another-topic\"+\"master\", which is hardly the right answer.\n\nI'm not sure how you can figure out when a branch was first created.\nWe might \"know\" that master is older than the others, but if this\ncommit was on another-topic and supertopic we cannot use that\nintuition..\n\nReturning all possible branch names at least gives the user somewhere\nto start and does not give them ones which are obviously insane.\n\n\t\t\t\t\t-Seth Robertson\n"},{"id":"151037","messageId":"4C96B97D.6030209@gmail.com","threadId":"25141","inReplyTo":"201009192354.o8JNsVLs018778@no.baka.org","subject":"Re: Find out on which branch a commit was originally made","fromName":"Artur Skawina","fromEmail":"art.08.09@gmail.com","sentAt":"2010-09-20T01:31:41Z","receivedAt":"2010-09-20T01:31:41Z","isPatch":false,"sender":{"key":"art.08.09@gmail.com","avatar":null},"body":"On 09/20/10 01:54, Seth Robertson wrote:\n> In message <4C9698C5.70607@gmail.com>, Artur Skawina writes:\n> \n> On 09/20/10 00:03, Seth Robertson wrote:\n>>>>>>                A---B---C topic\n>>>>>>               /         \\\n>>>>>>          D---E---F---G---H---I---J---K---L---M---N master\n>>>>>>                                   \\         /\n>>>>>>                                    O---P---Q another-topic\n>>>\n>>>>> No, that's not what I need either.  After thinking about it more, I\n>>>>> think what I want is \"of all merges in the ancestry path from B to\n>>>>> master, show only those whose first parent can't reach B.\"  The result\n>>>>> is the list of all merges that were involved in bringing B to master.\n>>>\n>>>\n>>>> This would work, and i don't see a way to optimize it in git-speak,\n>>>> given that you don't want to see any extra trailing merges. [...]\n>>>\n>>> The provided command actually doesn't work for me for all cases.  It\n>>> works for the simple case of \"B\", but does not work for \"F\", because F\n>>> saw merge H & M.  I think we need --not --first-parent, except that\n>>\n>> Well, F was never on a separate branch, so the command returning \"\"\n>> is arguably the right thing.\n> \n> I'd like a command that would tell me the right branch something was\n> on whether it was on master or topic or whatever.  If instead of\n> \"master\" the branch was named \"supertopic\" and master commit AA had\n> child D would that make a difference?\n\nLike i said, \"arguably\". In theory, no, there is no difference. In\npractice, some branches will be more long-lived than others -- and\ncertain conventions will apply. Hence, i think that answer /is/ the\nright one, in context -- that script was specifically looking for\ninfo on /another/ branch.\n\n>>> doesn't actually work in this case either.  However, if we get the\n>>> full --first-parent rev-list and look for our commit, that works.\n>>> This is incredibly painful, though.\n>>> ----------------------------------------------------------------------\n>>> #!/bin/sh\n>>> TARGET=`git rev-list -n 1 $1`\n>>> git branch -a --contains $1 | sed 's/^\\** *//' | grep -v ' -> ' |\n>>> while read br; do\n>>>  if git rev-list --first-parent $br | grep -q \"$TARGET\"; then\n>>>   echo $br\n>>>  fi\n>>> done\n>>> ----------------------------------------------------------------------\n> \n>> And it does not work if you no longer have the branches around...\n> \n> If something doesn't have a name I am not very interested in it (for\n> my purposes, your milage may vary).  Presumably the other code could be\n> combined with my inner loop.\n> \n>> But even if you kept all the old refs, this would return\n>> \"another-topic\"+\"master\", which is hardly the right answer.\n> \n> I'm not sure how you can figure out when a branch was first created.\n> We might \"know\" that master is older than the others, but if this\n> commit was on another-topic and supertopic we cannot use that\n> intuition..\n> \n> Returning all possible branch names at least gives the user somewhere\n> to start and does not give them ones which are obviously insane.\n\nIf you want to find out on which branch a change was committed and\n\"master\" is right for 'F', then the \"another-topic\" part of that\nanswer is problematic -- every commit on that branch is a descendant\nof 'F\", and so is everything in between $common_base ('J') and master.\nIf you /don't/ treat master as special (ie don't treat the first\nparent as special) what is then the difference vs a simple\n\"git branch -a --contains F\"?\nIOW, why would the right answer for 'F' be both 'master' and\n'another-topic', but for 'B' - just 'topic'?\n\nartur\n"},{"id":"151044","messageId":"201009200547.o8K5ldI7010683@no.baka.org","threadId":"25141","inReplyTo":"4C96B97D.6030209@gmail.com","subject":"Re: Find out on which branch a commit was originally made","fromName":"Seth Robertson","fromEmail":"in-gitvger@baka.org","sentAt":"2010-09-20T05:47:39Z","receivedAt":"2010-09-20T05:47:39Z","isPatch":false,"sender":{"key":"in-gitvger@baka.org","avatar":null},"body":"\nIn message <4C96B97D.6030209@gmail.com>, Artur Skawina writes:\n\n    On 09/20/10 01:54, Seth Robertson wrote:\n\n    > I'd like a command that would tell me the right branch something was\n    > on whether it was on master or topic or whatever.  If instead of\n    > \"master\" the branch was named \"supertopic\" and master commit AA had\n    > child D would that make a difference?\n\n    Like i said, \"arguably\". In theory, no, there is no difference. In\n    practice, some branches will be more long-lived than others -- and\n    certain conventions will apply. Hence, i think that answer /is/ the\n    right one, in context -- that script was specifically looking for\n    info on /another/ branch.\n\nOnly if the topic branch didn't have a merge on it.\n\n         -AA-- subtopic\n        /     \\\n       A---B---C topic\n      /         \\\n D---E---F---G---H---I---J---K---L---M---N master\n                          \\         /\n                           O---P---Q another-topic\n\n\nIn the above example, the subtopic branch merge from AA to C prevents\nyou from finding out what branch B is on using the original script.\n\n\n    > I'm not sure how you can figure out when a branch was first created.\n    > We might \"know\" that master is older than the others, but if this\n    > commit was on another-topic and supertopic we cannot use that\n    > intuition..\n\n    > Returning all possible branch names at least gives the user somewhere\n    > to start and does not give them ones which are obviously insane.\n\n    IOW, why would the right answer for 'F' be both 'master' and\n    'another-topic', but for 'B' - just 'topic'?\n\nI agree 100% that the right answer is topic for B and master for F.\n\nI know how to get topic for B.  Finding master (and not another-topic)\nfor F is difficult because we have to know something that I don't know\nhow to get git to tell me: when another-topic branch was created.\nUsing git-rev-parse another-topic....master we know what commit\nanother-topic and master diverged, but I cannot figure out a way to\ndiscover which branch was created at that point and which branch\npre-existed (obviously for master we know, but if this was a\nsupertopic branch we would not).  I thought about using merge\ndirection for subsequent merges as a hint, but we don't know if the\nsecond branch has been permanently been merged or not, if there was a\nK->P merge and Q-M did not happen (yet) then we would give the wrong\nbranch name.\n\nIf you (or anyone) can answer that question, I'll be happy to update\nthe script.  Otherwise getting both answers is as close as we can come.\n\n\t\t\t\t\t-Seth Robertson\n"},{"id":"151050","messageId":"1jp42v5.w5dez21d3nlciM%lists@haller-berlin.de","threadId":"25141","inReplyTo":"201009200547.o8K5ldI7010683@no.baka.org","subject":"Re: Find out on which branch a commit was originally made","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2010-09-20T08:12:06Z","receivedAt":"2010-09-20T08:12:06Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"Seth Robertson <in-gitvger@baka.org> wrote:\n\n> In message <4C96B97D.6030209@gmail.com>, Artur Skawina writes:\n> \n>     On 09/20/10 01:54, Seth Robertson wrote:\n> \n>     > I'd like a command that would tell me the right branch something was\n>     > on whether it was on master or topic or whatever.  If instead of\n>     > \"master\" the branch was named \"supertopic\" and master commit AA had\n>     > child D would that make a difference?\n> \n>     Like i said, \"arguably\". In theory, no, there is no difference. In\n>     practice, some branches will be more long-lived than others -- and\n>     certain conventions will apply. Hence, i think that answer /is/ the\n>     right one, in context -- that script was specifically looking for\n>     info on /another/ branch.\n> \n> Only if the topic branch didn't have a merge on it.\n> \n>          -AA-- subtopic\n>         /     \\\n>        A---B---C topic\n>       /         \\\n>  D---E---F---G---H---I---J---K---L---M---N master\n>                           \\         /\n>                            O---P---Q another-topic\n> \n> \n> In the above example, the subtopic branch merge from AA to C prevents\n> you from finding out what branch B is on using the original script.\n\nWhen you say \"the original script\", are you talking about Artur's\none-liner or my script?\n\nMy script gives me exactly the information I want in all cases.  For a\ngiven command $1 and a target branch $2, it shows you all merges that\nwere involved in bringing $1 into $2. For example:\n\n  Called with \"B\" \"master\", it returns H\n  Called with \"AA\" \"master\", it returns C, H\n    (and that's good, because for someone asking \"what was AA's original\n     branch?\" it's not clear if he will be more interested in topic or\n     sub-topic, so show him both)\n  Called with \"F\" \"master\", it returns nothing\n\nThe one limitation is that the result is empty both when $1 started on\n$2, and when $1 is not reachable from $2 at all, in which case it should\nprobably error out (like when you call it with \"F\" \"topic\").  That's\neasy to add as an additional check at the beginning of the script,\nthough.\n\n\nThe script works even in cases where you have a long-running topic\nbranch that is occasionally brought up to date with master, like this:\n\n\n         F---G---H---I---J---O---P  topic\n        /       /       /         \\\n   A---B---C---D---E---K---L---M---N---Q master\n\n\nWhen called with \"F\" \"master\", it returns only N, but not H or J.\nExactly what I need.  (We have this kind of history a lot in our code\nbase.)\n\nYou could even call the script with \"C\" \"topic\" if you wanted to (in\nwhich case it would return H, but not J).  It's not quite clear why you\nwould want to though.\n\n\n-- \nStefan Haller\nBerlin, Germany\nhttp://www.haller-berlin.de/\n"},{"id":"151107","messageId":"4C973E5B.4090201@gmail.com","threadId":"25141","inReplyTo":"1jp42v5.w5dez21d3nlciM%lists@haller-berlin.de","subject":"Re: Find out on which branch a commit was originally made","fromName":"Artur Skawina","fromEmail":"art.08.09@gmail.com","sentAt":"2010-09-20T10:58:35Z","receivedAt":"2010-09-20T10:58:35Z","isPatch":false,"sender":{"key":"art.08.09@gmail.com","avatar":null},"body":"On 09/20/10 10:12, Stefan Haller wrote:\n> Seth Robertson <in-gitvger@baka.org> wrote:\n\n>>          -AA-- subtopic\n>>         /     \\\n>>        A---B---C topic\n>>       /         \\\n>>  D---E---F---G---H---I---J---K---L---M---N master\n>>                           \\         /\n>>                            O---P---Q another-topic\n>>\n>>\n>> In the above example, the subtopic branch merge from AA to C prevents\n>> you from finding out what branch B is on using the original script.\n> \n> When you say \"the original script\", are you talking about Artur's\n> one-liner or my script?\n> \n> My script gives me exactly the information I want in all cases.  For a\n> given command $1 and a target branch $2, it shows you all merges that\n> were involved in bringing $1 into $2. For example:\n> \n>   Called with \"B\" \"master\", it returns H\n\nNo, it will return both C and H, just like my one-liner; this will be\nmisleading, the user won't be able to figure out where 'B\" came from\nw/o looking at the graph, from output like:\n\n$ git-show-merges-since B master\nC..... Merge branch 'subtopic' into topic\nH..... Merge branch 'topic'\n\nThe results for 'B' and 'AA' will be exactly the same.\n\nFor 'B', the 'C' merge should be omitted; skipping it because 'B'\ncomes in via first parent would probably work, but i can't turn that\ninto a one-liner right now...\n\n\nOn 09/20/10 07:47, Seth Robertson wrote:\n> I agree 100% that the right answer is topic for B and master for F.\n> \n> I know how to get topic for B.  Finding master (and not another-topic)\n> for F is difficult because we have to know something that I don't know\n> how to get git to tell me: when another-topic branch was created.\n> Using git-rev-parse another-topic....master we know what commit\n> another-topic and master diverged, but I cannot figure out a way to\n> discover which branch was created at that point and which branch\n> pre-existed (obviously for master we know, but if this was a\n> supertopic branch we would not).  I thought about using merge\n> direction for subsequent merges as a hint, but we don't know if the\n> second branch has been permanently been merged or not, if there was a\n> K->P merge and Q-M did not happen (yet) then we would give the wrong\n> branch name.\n\nOh, if there would be no 'Q->M' merge and both branches would still\nbe \"live\", 'both' is certainly the right answer.\n\nIf 'another-topic' was merged into another branch (like in the example\ngraph) and is dead at this point, i think skipping it is the correct\ndecision -- there could be many such branches and presenting a long\nlist of candidates won't really help the user.\n\nGiven history as in the graph and a /live/ 'another-topic' -- hmm, \nif there are just a few such refs maybe showing them would be ok.\n\nartur\n"},{"id":"151125","messageId":"4C9782A3.5010005@gmail.com","threadId":"25141","inReplyTo":"4C973E5B.4090201@gmail.com","subject":"Re: Find out on which branch a commit was originally made","fromName":"Artur Skawina","fromEmail":"art.08.09@gmail.com","sentAt":"2010-09-20T15:49:55Z","receivedAt":"2010-09-20T15:49:55Z","isPatch":false,"sender":{"key":"art.08.09@gmail.com","avatar":null},"body":"On 09/20/10 12:58, Artur Skawina wrote:\n> On 09/20/10 10:12, Stefan Haller wrote:\n>> Seth Robertson <in-gitvger@baka.org> wrote:\n> \n>>>          -AA-- subtopic\n>>>         /     \\\n>>>        A---B---C topic\n>>>       /         \\\n>>>  D---E---F---G---H---I---J---K---L---M---N master\n>>>                           \\         /\n>>>                            O---P---Q another-topic\n>>>\n>>>\n>>> In the above example, the subtopic branch merge from AA to C prevents\n>>> you from finding out what branch B is on using the original script.\n>>\n>> When you say \"the original script\", are you talking about Artur's\n>> one-liner or my script?\n>>\n>> My script gives me exactly the information I want in all cases.  For a\n>> given command $1 and a target branch $2, it shows you all merges that\n>> were involved in bringing $1 into $2. For example:\n>>\n>>   Called with \"B\" \"master\", it returns H\n> \n> No, it will return both C and H, just like my one-liner; this will be\n> misleading, the user won't be able to figure out where 'B\" came from\n> w/o looking at the graph, from output like:\n> \n> $ git-show-merges-since B master\n> C..... Merge branch 'subtopic' into topic\n> H..... Merge branch 'topic'\n> \n> The results for 'B' and 'AA' will be exactly the same.\n> \n> For 'B', the 'C' merge should be omitted; skipping it because 'B'\n> comes in via first parent would probably work, but i can't turn that\n> into a one-liner right now...\n\nYeah, that was it; the script below will correctly handle not only\nthe simple example above, but also some real cases. \n\nUsage: git-find-branch-for <rev> [long-lived-branch]\n\nReturns some merge commits, making it easier to find out from which\nbranch a change originated. Returns nothing if it did not find an\ninteresting merge all the way up to long-lived-branch (which defaults\nto \"master\")\n\nExample, using git.git:\n\n$ time ../../../stefans-script bac80370817\n4fa088209c81845e73756a4173a8c954e25958d2 Merge branch 'jk/run-command-use-shell'\n225f78c817755bebff91629cc525a258cf60eaea Merge branch 'master' of git://repo.or.cz/alt-git into jn/autodep\n037c43c68e220739e690540de89a6d5835fefe73 Merge remote branch 'ko/master' into jc/read-tree-cache-tree-fix\n1m23.271s user   0m2.173s system   1m26.389s elapsed   98.90% CPU\n\n$ time ../../../git-find-branch-for bac80370817                             \n4fa08820    Merge branch 'jk/run-command-use-shell'        * jk/run-command-use 1263743895\n225f78c8    Merge branch 'master' of git://repo.or.cz/alt-git into jn/autodep   1264500524\n037c43c6    Merge remote branch 'ko/master' into jc/read-tree-cache-tree-fix    1278615350\n0m0.270s user   0m0.017s system   0m0.287s elapsed   99.87% CPU\n$\n\nSo it's also a little bit faster.\nReceived very little testing, i only tried it on a few commits, other\nthan the example from this thread, but so far seems to do the right\nthing for all of them.\nUnpikifying is left as an exercise for the user. ;)\n\nartur\n\n------------------------------------------------------------------------------\n#! /usr/bin/env pike\n// git-find-branch-for <rev> [long-lived-branch]\n//    Probably needs pike7.8\n#define die(a...) exit(1, \"Aborting; %s\"+a)\n\nstring run(string ... cmdline) {\n   mapping r;\n   mixed e = catch { r = Process.run( ({@cmdline}) ); };\n   if (e || r[\"exitcode\"])\n      die(\"\", e?e:r[\"stderr\"]);\n   return r[\"stdout\"];\n}\n\nmapping commits = ([]);\n\narray parsecommits(string from, string to) {\n   array res = ({});\n   string id;\n   string gitout = run(\"git\", \"rev-list\", \"--format=raw\",  \"--ancestry-path\",\n                                          \"--date-order\", from+\"..\"+to);\n   array lines = gitout/\"\\n\";\n\n   foreach (lines, string line) {\n      array words = line/\" \";\n      if (words[0]==\"commit\") {\n         id = words[1][0]!='-' ? words[1] : words[1][1..];\n\t commits[id] = ([]);\n\t res += ({id});\n      }\n      commits[id][words[0]] += words[1..];\n   }\n   return res;\n}\n\nint ismerge(string id) {\n   return commits[id][\"parent\"] && sizeof(commits[id][\"parent\"])>1;\n}\n\nmapping desc = ([]);\n\nint main(int argc, array argv) {\n   argv[1] = (run(\"git\", \"rev-parse\", argv[1])/\"\\n\")[0];\n   if (argc==2)\n      argv += ({\"master\"});\n   argv[2] = (run(\"git\", \"rev-parse\", argv[2])/\"\\n\")[0];\n   array merges = parsecommits(argv[1], argv[2]);\n   merges = reverse(merges);\n   desc[argv[1]] = 1;\n   foreach (merges, string id) {\n      if (commits[id][\"parent\"])\n         foreach (commits[id][\"parent\"], string parent)\n            if (desc[parent])\n        \tdesc[id] = 1;\n      if (ismerge(id))\n         if (!desc[commits[id][\"parent\"][0]]) {\n\t    int comtime = (int)commits[id][\"committer\"][-2];\n\t    comtime += (int)commits[id][\"committer\"][-1]/100*60*60;\n            write(\"%.8s %.70s %d\\n\", id, commits[id][\"\"]*\" \", comtime );\n\t }\n   }\n}\n------------------------------------------------------------------------------\n"},{"id":"151139","messageId":"1jp4vak.uzmm6w190gd2rM%lists@haller-berlin.de","threadId":"25141","inReplyTo":"4C973E5B.4090201@gmail.com","subject":"Re: Find out on which branch a commit was originally made","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2010-09-20T18:20:27Z","receivedAt":"2010-09-20T18:20:27Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"Artur Skawina <art.08.09@gmail.com> wrote:\n\n> >>          -AA-- subtopic\n> >>         /     \\\n> >>        A---B---C topic\n> >>       /         \\\n> >>  D---E---F---G---H---I---J---K---L---M---N master\n> >>                           \\         /\n> >>                            O---P---Q another-topic\n> >>\n> >>\n> >> In the above example, the subtopic branch merge from AA to C prevents\n> >> you from finding out what branch B is on using the original script.\n> >\n> >   Called with \"B\" \"master\", it returns H\n> \n> No, it will return both C and H, just like my one-liner;\n\nRight, there was a bug in my script: it doesn't work if B is a direct\nparent of the next merge. (For A, it would correctly return only H.)  To\nfix that, you'd need this version:\n\n#!/bin/sh\n\ngit rev-list --ancestry-path --merges --reverse \"$1\"..\"${2-master}\" \\\n  | while read ref\ndo\n  if [ \"$1\" != \"$ref\"^ -a -z \"$(git rev-list --ancestry-path \"$1\"..\"$ref\"^)\" ]\n  then\n    git --no-pager log -1 --pretty=oneline \"$ref\"\n  fi\ndone\n\nBut of course, since your version is so much faster, I'll no longer\nbother with mine.  Thanks!\n\n-Stefan\n\n\n-- \nStefan Haller\nBerlin, Germany\nhttp://www.haller-berlin.de/\n"},{"id":"151174","messageId":"201009210015.o8L0FcJt020691@no.baka.org","threadId":"25141","inReplyTo":"4C9782A3.5010005@gmail.com","subject":"Re: Find out on which branch a commit was originally made","fromName":"Seth Robertson","fromEmail":"in-gitvger@baka.org","sentAt":"2010-09-21T00:15:38Z","receivedAt":"2010-09-21T00:15:38Z","isPatch":false,"sender":{"key":"in-gitvger@baka.org","avatar":null},"body":"\nIn message <4C9782A3.5010005@gmail.com>, Artur Skawina writes:\n\n    Received very little testing, i only tried it on a few commits, other\n    than the example from this thread, but so far seems to do the right\n    thing for all of them.\n\nI've discovered an error case in your pike script's logic (as and if I\nunderstand it).  If there are multiple children of the commit in\nquestion and those two children both merge onto the target branch, the\npath your program prints is incorrect (specifically, for reference B\nit prints D and then G--the correct answer is G only or a least D+H).\nIt does not check to see whether a specific reachable merge commit is\nreachable by the path you have started to print.\n\n----master-----------G------H\n                    /      /\n                    |     /\n --A-------D-----------F-\n          /         |\n ----B---C          |\n      \\             |\n       ----------E--/\n\n    Unpikifying is left as an exercise for the user. ;)\n\nI've converted it to perl and it now handles both your problem (which\nI now understand, I was distracted by the subject line) and mine\n(which I now better understand includes yours as well--we use --rebase\na lot so don't have many unnamed branches).  I'm also being annoyed at\ngit's default merge --ff option which causes the wrong branch to be\nlabeled with the branch name.\n\nOf course it still suffers from reporting branches created after the\nreference you are interested in was created.\n\n\t\t\t\t\t-Seth Robertson\n\ngit://github.com/SethRobertson/git-what-branch.git\n\n----------------------------------------------------------------------\n#!/usr/bin/perl\n#\n# Tell us what preferred branch a commit was made on and if has not\n# been made on any preferred branch, the earliest path the commit got\n# onto a named branch.\n#\n# Preferred meaning ignoring branches that are a descendant due to a\n# merge, close to the answer you would have gotten if you had asked\n# the question at the moment the commit/tag was made.\n#\n# If I am on a release branch and tag a commit, if I ask that question\n# I should be told the name of the release branch.  If I later merge\n# onto master and ask that question, being told that the tag was also\n# made on master is disingenious.  master is a descendant, but the tag\n# was not made on master.\n#\n# Thanks to Artur Skawina for his assistance in developing some\n# of the algorithms used by this script.\n#\n# License: GPL v2\n# Copyright (c) 2010 Seth Robertson\n#\nuse warnings;\nno warnings \"uninitialized\";\nuse Getopt::Long;\nuse strict;\n\nmy $USAGE=\"$0: [--allref] [--all] [--quiet] [--reference-branch=branchname] [--reference=reference] <commit-hash/tag>...\n\n--allref\n\tConsider even remote branches as candidates for the branch a\n\treference is on\n\n--all\n\tPrint all reachable branch names (and merge paths)\n\n--quiet\n\tPrint only the branch names, not the merge paths\n\n--reference-branch <branchname>\n\tThe command line arguments/reference are searched to see if\n\tthey can reach this branch.\n\n--reference <hash|tag>\n\tSpecify a particular commit you which you want to\n\tknow how the commit in question was reached\n\";\n\nmy(%OPTIONS);\nGetopt::Long::Configure(\"bundling\", \"no_ignore_case\", \"no_auto_abbrev\", \"no_getopt_compat\", \"require_order\");\nGetOptions(\\%OPTIONS, 'a|allref', 'all', 'quiet', 'debug', 'reference-branch=s', 'reference=s', 'verbose|v+') || die $USAGE;\n\nmy ($OPT_A);\n$OPT_A=\"-a\" if ($OPTIONS{'a'});\n\nif ( $#ARGV < 0 )\n{\n    print STDERR $USAGE;\n    exit(2);\n}\n\nmy ($MULTI);\n$MULTI=1 if ( $#ARGV > 0 );\n\n\n\n\n########################################\n#\n# Describe a hash if necessary\n#\nsub describep($)\n{\n  my ($ref) = @_;\n\n  if ($ref =~ /^[0-9a-f]{40}$/)\n  {\n    my $newref;\n    chomp($newref = `git describe $ref`);\n    $ref = $newref if ($newref && $? == 0);\n  }\n  $ref;\n}\n\n\n\n########################################\n#\n# Find shortest path through a dag\n# Return array of shortest path\n#\nsub find_shortest($$$$);\nsub find_shortest($$$$)\n{\n  my ($id,$target,$tree,$mark) = @_;\n\n  print STDERR \"Looking at node $id\\n\" if ($OPTIONS{'debug'});\n\n  while ($id ne $target)\n  {\n    # Is this a merge commit?\n    if ($#{$tree->{$id}->{'parent'}} > 0)\n    {\n      # Is the first parent not a descendant?\n      if (!$mark->{$tree->{$id}->{'parent'}->[0]})\n      {\n\tmy (@minp);\n\tmy ($mindef);\n\n\t# See which parent is the best connected\n\tforeach my $parent (@{$tree->{$id}->{'parent'}})\n\t{\n\t  next unless $mark->{$parent};\n\n\t  my (@tmp) = find_shortest($parent,$target,$tree,$mark);\n\n\t  if (!$mindef || $#minp > $#tmp)\n\t  {\n\t    @minp = @tmp;\n\t    $mindef = 1;\n\t  }\n\t}\n\tunshift(@minp,$id);\n\treturn(@minp);\n      }\n    }\n\n    $id = $tree->{$id}->{'parent'}->[0];\n  }\n  ();\n}\n\n\nforeach my $f (@ARGV)\n{\n  print \"Looking for $f\\n++++++++++++++++++++++++++++++++++++++++\\n\" if ($MULTI);\n\n  # Translate into a commit hash\n  my ($TARGET)=`git rev-list -n 1 $f 2>/dev/null`;\n  die \"Unknown reference $f\\n\" if ($?);\n  chomp($TARGET);\n\n  my (@first,@second);\n\n  if ($OPTIONS{'reference'})\n  {\n    my $tmp = `git rev-list -n 1 $OPTIONS{'reference'} 2>/dev/null`;\n    die \"Unknown --reference $OPTIONS{'reference'}\\n\" if ($?);\n    chomp($tmp);\n    @first = ($tmp);\n  }\n  else\n  {\n    # Generate first pass list of candidate branches\n    @first = grep(s/^\\*?\\s+// && s/\\n// && !/ -\\> / && (!$OPTIONS{'reference-branch'} || $OPTIONS{'reference-branch'} eq $_),`git branch $OPT_A --contains $f`);\n\n    if ($#first < 0)\n    {\n      my $msg = \"any named branch\";\n      $msg = \"any local named branch\" unless ($OPTIONS{'a'});\n      $msg = \"branch $OPTIONS{'reference-branch'}\" if ($OPTIONS{'reference-branch'});\n      die \"Commit $f has not merged onto $msg yet\\n\";\n    }\n  }\n\n  # Shortcut if we might only need direct commit branches\n  if (!$OPTIONS{'all'})\n  {\n    # Look for merge intos to exclude\n    foreach my $br (@first)\n    {\n      # Exclude branches that this commit was merged into\n      push(@second,$br) if (grep(/$TARGET/,`git rev-list --first-parent $br`));\n    }\n  }\n\n  if ($#second >= 0)\n  {\n    # If branch was subsequently forked via `git branch <old> <new>`\n    # we might have multiple answers.  Only one is right, but we\n    # cannot figure out which is the privledged branch because the\n    # branch creation information is not preserved.\n\n    print join(\"\\n\",@second).\"\\n\";\n  }\n  else\n  {\n    # Commit is on an anonymous branch, find out where it merged\n\n    my (%brtree,%min);\n    foreach my $br (@first)\n    {\n      my (%commits,@commits);\n      my $SOURCE = `git rev-list -n 1 $br 2>/dev/null`;\n      die \"Cannot find branch reference.  Huh?\\n\" if ($?);\n      chomp($SOURCE);\n      print STDERR \"Checking branch $br\\n\" if ($OPTIONS{'debug'});\n\n      # Discover all \"ancestry-path\" commits between target and branch\n      my $cmd = qq^git rev-list --ancestry-path --date-order --format=raw \"$TARGET\"..\"$br\"^;\n      my ($commit);\n      foreach my $line (`$cmd`)\n      {\n\tmy (@f) = split(/\\s+/,$line);\n\tif ($f[0] eq \"commit\")\n\t{\n\t  $commit = $f[1];\n\t  $commit =~ s/^-//;\t# I have never seen this myself, but Artur Skawina wrote code to defend against it\n\t  unshift(@commits,$commit);\n\t}\n\tif ($f[0] eq \"parent\")\n\t{\n\t  push(@{$commits{$commit}->{'parent'}},$f[1]);\n\t}\n\tif ($f[0] eq \"committer\")\n\t{\n\t  $commits{$commit}->{'committime'} = $f[$#f-1];\n\t}\n      }\n\n      print STDERR \"Found $#commits+1\\n\" if ($OPTIONS{'debug'});\n\n      my (@path);\n\n      # Go through commit list (in forward chonological order)\n      my (%mark,$cnt);\n      $mark{$TARGET} = ++$cnt;\n      foreach my $id (@commits)\n      {\n\tnext unless $commits{$id}->{'parent'};\n\n\t# Check to see if this commit is actually a descent of $TARGET\n\tif (grep($mark{$_},@{$commits{$id}->{'parent'}}))\n\t{\n\t  $mark{$id} = ++$cnt;\n\t}\n\n\t# Is this a merge commit?\n\tif ($#{$commits{$id}->{'parent'}} > 0)\n\t{\n\t  # Is the first parent not a descendant? (earliest merge)\n\t  if (!$mark{$commits{$id}->{'parent'}->[0]})\n\t  {\n\t    push(@path,$id);\n\t  }\n\t}\n      }\n\n      # Check to make sure we have gone from TARGET or SOURCE via parents\n      if (!$mark{$SOURCE})\n      {\n\t# Not connected\n\tnext;\n      }\n\n      print STDERR \"Found $#path+1 initial path entries\\n\" if ($OPTIONS{'debug'});\n\n      if ($#path >= 0)\n      {\n\tmy $id = $path[$#path];\n\t@path = find_shortest($id,$TARGET,\\%commits,\\%mark);\n\t$brtree{$br}->{'path'} = \\@path;\n\t$brtree{$br}->{'cnt'} = $#path;\n\t$brtree{$br}->{'tstamp'} = $commits{$id}->{'committime'};\n\n\tif ($OPTIONS{'all'})\n\t{\n\t  if ($OPTIONS{'quiet'})\n\t  {\n\t    print \"$br\\n\";\n\t  }\n\t  else\n\t  {\n\t    print \"* $TARGET first merged onto $br using the following path:\\n\";\n\t    my $last = describep($TARGET);\n\t    foreach my $mp (@{$brtree{$br}->{'path'}})\n\t    {\n\t      my $newm = describep($mp);\n\t      print \"  $last merged up at $newm (@{[scalar(localtime($commits{$mp}->{'committime'}))]})\\n\";\n\t      $last = $newm;\n\t    }\n\t    print \"  $last is on $br\\n\";\n\t  }\n\t}\n\telse\n\t{\n\t  if (!defined($min{'tstamp'}) || $min{'tstamp'} > $brtree{br}->{'tstamp'})\n\t  {\n\t    %min = %{$brtree{$br}};\n\t    $min{'br'} = $br;\n\t    $min{'commits'} = \\%commits;\n\t  }\n\t}\n      }\n      else\n      {\n\tif ($OPTIONS{'all'})\n\t{\n\t  print \"$TARGET is on $br\\n\";\n\t}\n\telse\n\t{\n\t  print \"$br\\n\";\n\t}\n\t$min{'tstamp'} = 0;\n\tdelete($min{'br'});\n      }\n    }\n\n    if (!$OPTIONS{'all'})\n    {\n      if ($min{'br'})\n      {\n\tif ($OPTIONS{'quiet'})\n\t{\n\t  print \"$min{'br'}\\n\";\n\t}\n\telse\n\t{\n\t  print \"$f first merged onto $min{'br'} using the following minimal path:\\n\";\n\t  my $last = describep($TARGET);\n\t  foreach my $br (@{$min{'path'}})\n\t  {\n\t    my $newm = describep($br);\n\t    print \"  $last merged up at $newm (@{[scalar(localtime($min{'commits'}->{$br}->{'committime'}))]})\\n\";\n\t    $last = $newm;\n\t  }\n\t  print \"  $last is on $min{'br'}\\n\";\n\t}\n      }\n      else\n      {\n\tprint \"Could not find $f connected anywhere\\n\" unless defined($min{'tstamp'});\n      }\n    }\n  }\n  print \"----------------------------------------\\n\" if ($MULTI);\n}\n"},{"id":"151180","messageId":"4C981475.10404@gmail.com","threadId":"25141","inReplyTo":"201009210015.o8L0FcJt020691@no.baka.org","subject":"Re: Find out on which branch a commit was originally made","fromName":"Artur Skawina","fromEmail":"art.08.09@gmail.com","sentAt":"2010-09-21T02:12:05Z","receivedAt":"2010-09-21T02:12:05Z","isPatch":false,"sender":{"key":"art.08.09@gmail.com","avatar":null},"body":"On 09/21/10 02:15, Seth Robertson wrote:\n> \n> I've discovered an error case in your pike script's logic (as and if I\n> understand it).  If there are multiple children of the commit in\n> question and those two children both merge onto the target branch, the\n> path your program prints is incorrect (specifically, for reference B\n> it prints D and then G--the correct answer is G only or a least D+H).\n> It does not check to see whether a specific reachable merge commit is\n> reachable by the path you have started to print.\n> \n> ----master-----------G------H\n>                     /      /\n>                     |     /\n>  --A-------D-----------F-\n>           /         |\n>  ----B---C          |\n>       \\             |\n>        ----------E--/\n\nI haven't checked, but I expect it to print exactly 'D' and 'G'.\n'H' isn't interesting, as both parents already contain 'B'.\nYes, 'D' could be omitted, but knowing where else 'B' also\nappeared /can/ be useful (and figuring out if it's safe to skip\n'D' would be more expensive).\n\n>     Unpikifying is left as an exercise for the user. ;)\n> \n> I've converted it to perl and it now handles both your problem (which\n\nI wasn't exactly thinking of perl when i wrote that... :)\n\n> Of course it still suffers from reporting branches created after the\n> reference you are interested in was created.\n\nWell, at least git-find-branch-for, shows (some) merges _to_ other\n(topic/remote) branches, but after browsing the kernel history\nfor a while i'm a bit surprised -- this causes significantly less\nproblems than i expected.\n\nI haven't looked at your script, so i'm not sure what exactly it\ntries to do, but i ran a quick test, using the kernel tree:\n\n$ time git-find-branch-for 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 \n84e48b6d64fd Merge of master.kernel.org:/home/rmk/linux-2.6-rmk.git   050503 22:27\nbfd4bda097f8 Merge with master.kernel.org:/pub/scm/linux/kernel/git/t 050505 12:59\n325a479c4c11 Merge with temp tree to get David's gdb inferior calls p 050517 22:53\nad34ea2cc384 merge by hand - fix up rejections in Documentation/DocBo 050520 20:27\n0m10.549s user   0m0.713s system   0m10.963s elapsed   102.74% CPU\n$\n$ time git-what-branch 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 \n1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 first merged onto v2.6.32.n using the following minimal path:\n  v2.6.12-rc3-450-g1f9c381 merged up at v2.6.12-rc4-39-gad34ea2 (Fri May 20 22:27:44 2005)\n  v2.6.12-rc4-39-gad34ea2 merged up at v2.6.12-rc3-590-gbfd4bda (Thu May  5 14:59:37 2005)\n  v2.6.12-rc3-590-gbfd4bda merged up at v2.6.12-rc3-461-g84e48b6 (Wed May  4 00:27:24 2005)\n  v2.6.12-rc3-461-g84e48b6 is on v2.6.32.n\n18m29.771s user   0m29.681s system   18m4.897s elapsed   105.03% CPU\n$\n\nResults are similar, that one extra merge i'll have to take a look at\nlater, but the cost difference...\n\nartur\n"},{"id":"151298","messageId":"201009221635.o8MGZnLD024629@no.baka.org","threadId":"25141","inReplyTo":"4C981475.10404@gmail.com","subject":"ANNOUNCE git-what-branch (was Re: Find out on which branch a commit was originally made)","fromName":"Seth Robertson","fromEmail":"in-gitvger@baka.org","sentAt":"2010-09-22T16:35:49Z","receivedAt":"2010-09-22T16:35:49Z","isPatch":false,"sender":{"key":"in-gitvger@baka.org","avatar":null},"body":"\nIn message <4C981475.10404@gmail.com>, Artur Skawina writes:\n\n    $ time git-what-branch 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4\n    1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 first merged onto v2.6.32.n using the following minimal path:\n      v2.6.12-rc3-450-g1f9c381 merged up at v2.6.12-rc4-39-gad34ea2 (Fri May 20 22:27:44 2005)\n      v2.6.12-rc4-39-gad34ea2 merged up at v2.6.12-rc3-590-gbfd4bda (Thu May  5 14:59:37 2005)\n      v2.6.12-rc3-590-gbfd4bda merged up at v2.6.12-rc3-461-g84e48b6 (Wed May  4 00:27:24 2005)\n      v2.6.12-rc3-461-g84e48b6 is on v2.6.32.n\n    18m29.771s user   0m29.681s system   18m4.897s elapsed   105.03% CPU\n\nI found two minor bugs in my script which caused it to return something\nother than the most optimal path in all cases.  I then got crazy and\nadded a --date-order and --topo-order -- the former orders paths by\ncommit date and the latter orders paths by the number of merges that\ntook place (and then by commit date) and then path summarization if\nmultiple branches were obtained through the same path.\n\n    Results are similar, that one extra merge i'll have to take a look at\n    later, but the cost difference...\n\nAs we discussed privately, the cost difference is because instead of\nlooking at just one branch, it is looking at 150+ branches.  If you\nuse --reference-branch to specify the one branch you are looking at,\nit takes a much more reasonable 15-20 seconds.  Likewise if you select\na commit more recent than 2005, the number of branches that it could\napply to goes down and the command runs faster.\n\nAlso in my most recent version I was able to find an even shorter path\n(two merges to master).\n\nI have cleaned everything up and made a formal release out of it.\n\nIt is available at:  http://github.com/SethRobertson/git-what-branch\n\n\t\t\t\t\t-Seth Robertson\n"},{"id":"151324","messageId":"4C9A66AF.5000302@gmail.com","threadId":"25141","inReplyTo":"201009221635.o8MGZnLD024629@no.baka.org","subject":"Re: ANNOUNCE git-what-branch (was Re: Find out on which branch a commit was originally made)","fromName":"Artur Skawina","fromEmail":"art.08.09@gmail.com","sentAt":"2010-09-22T20:27:27Z","receivedAt":"2010-09-22T20:27:27Z","isPatch":false,"sender":{"key":"art.08.09@gmail.com","avatar":null},"body":"On 09/22/10 18:35, Seth Robertson wrote:\n> looking at just one branch, it is looking at 150+ branches.  If you\n> use --reference-branch to specify the one branch you are looking at,\n> it takes a much more reasonable 15-20 seconds.  Likewise if you select\n\nThis started in a thread about locating dead topic branches, but what\nyou want is something slightly different, hence the confusion. \nAFAIUI it now, your case is basically this: you have several\nindependently developed topic (or side-) branches, which are\nperiodically merged into a master branch, the side branches\nthemselves are also merging 'master' to receive changes happening\nelsewhere. So the graph could look like this:\n\n m-> m -> m -> m -> m -> m -> m ->   master\n  \\        \\       /         /\n   b -> b -> b -> b -> b -> b ->    side-branch#1\n\nDitto for the other n side-branches. \n\nWhat you're asking for is: given commit C and a list of several side\nbranches, tell me where (ie on which branch) this commit originated.\n\nTwo things make the above trivial history a bit more complicated.\nA) one side-branch can merge another, and build on top of changes that\n   are not yet available on 'master'; the result can then appear in master\n   via either one or both paths. This is why showing when and how a change\n   became visible on every side branch can be interesting.\nB) when a side branch does not contain any new changes, but is made uptodate\n   wrt master, the resulting history could end up like this:\n\n m-> m -> m -> m -> m -> m -> m ->   master\n  \\           /      \\       /\n   b -> b -> b        c ->  c ->    side-branch#1\n    \n   What happened was -- git \"optimized\" the simple merge away, turning it\n   into a fast-forward, saving one merge commit, but loosing the link\n   connecting the 'c' and 'b' parts of 'side-branch#1'.   \n\nDo you (anybody) happen to know a public repo, w/ history as above, ie\nw/ more then one long-lived branch that has seen some fast-forwards? \nI wonder how reliable recovering the missing link would be...\n\nAnd there's no reason why this operation should take ~20 minutes, even\nfor the randomly chosen, but real, worst case. But finding a good repo\nto test w/ would take longer than writing the code...\n\nartur\n"},{"id":"151331","messageId":"201009222326.o8MNQJ2E022410@no.baka.org","threadId":"25141","inReplyTo":"4C9A66AF.5000302@gmail.com","subject":"Re: Find out on which branch a commit was originally made) (was ANNOUNCE git-what-branch)","fromName":"Seth Robertson","fromEmail":"in-gitvger@baka.org","sentAt":"2010-09-22T23:26:19Z","receivedAt":"2010-09-22T23:26:19Z","isPatch":false,"sender":{"key":"in-gitvger@baka.org","avatar":null},"body":"\nIn message <4C9A66AF.5000302@gmail.com>, Artur Skawina writes:\n\n    This started in a thread about locating dead topic branche\n\nIsn't that pretty easy to do?  `git fsck --unreachable master | grep\ncommits`?  Post-processing that to assemble branches would seem to be\nfairly simple.\n\nBut yes, I wanted something completely different.  Something more\nlike: if a bug was introduced in commit X, what releases or branches\nhas it contaminated (or more positively, if a feature was introduced,\nwhere was it made available).  The simple case is figuring out on\nwhich branch a commit was originally made.\n\nI was unhappy when I realized that another way code could get out was\nthrough cherry-picks, and that there doesn't seem any non-brute force\n(computing checksums of patches for every patch in the tree) method to\ndiscover them.\n\n    Two things make the above trivial history a bit more complicated.\n    A) one side-branch can merge another, and build on top of changes that\n       are not yet available on 'master'; the result can then appear in master\n       via either one or both paths. This is why showing when and how a change\n       became visible on every side branch can be interesting.\n\nQuite.  I encountered this a few different ways and even when I fixed\nit during the reverse parse, I failed to learn my lesson and it was a\nproblem during the forward parse.  I think the latest version is\nfairly bullet-proof.\n\n    B) when a side branch does not contain any new changes, but is\n       made uptodate wrt master, the resulting history could end up\n       like this:\n\n     m-> m -> m -> m -> m -> m -> m ->   master\n      \\           /      \\       /\n       b -> b -> b        c ->  c ->    side-branch#1\n\n       What happened was -- git \"optimized\" the simple merge away, turning it\n       into a fast-forward, saving one merge commit, but loosing the link\n       connecting the 'c' and 'b' parts of 'side-branch#1'.\n\n    Do you (anybody) happen to know a public repo, w/ history as above, ie\n    w/ more then one long-lived branch that has seen some fast-forwards?\n    I wonder how reliable recovering the missing link would be...\n\nI have a real (non-public, sorry) tree that did something approaching\nthis:\n\n->m->m->m->m->m---------m\n       /     /         /\nb->b->b->b->b------b->b->\n \\     \\     \\    /\n  t->t->t->t->t->t\n\nHowever, due to fast-forwarding, it was turned into something like this:\n\n->m->m->m->m->m---------m\n       /     /         /\nb->?->?->?->?------b->b->\n \\     \\     \\    /\n  t->t->t->t->t->t\n  b  b  b  b  b  b\n\nI don't think there is any way to figure out what happened given git's\navailable information.\n\nI was just saying on #git a few hours ago, though, that I think git\nneeded a tree anonymizing program.  As long as one does not go\noverboard, it doesn't seem too difficult.  That probably means I just\nhave not thought about the problem hard enough.  Of course, it would\nonly replicate what is, not how you got there.\n\n    And there's no reason why this operation should take ~20 minutes, even\n    for the randomly chosen, but real, worst case. But finding a good repo\n    to test w/ would take longer than writing the code...\n\nIt only takes 8 seconds per test on the linux kernel, which all things\nconsidered is rather fast.  The real problem is that each test is\ntreated independently.  If someone got the complete history of the\nproject and built a tree out of it, it would be extremely fast to run\nadditional tests even ignoring the obvious optimiziations of not\nresearching known paths.\n\nThe question is, will this functionality be needed often enough to\nspend the time necessary to optimize it?\n\n\n\t\t\t\t\t-Seth Robertson\n"},{"id":"151357","messageId":"32741263.335615.1285247653984.JavaMail.root@mail.hq.genarts.com","threadId":"25141","inReplyTo":"201009222326.o8MNQJ2E022410@no.baka.org","subject":"Re: Find out on which branch a commit was originally made) (was ANNOUNCE git-what-branch)","fromName":"Stephen Bash","fromEmail":"bash@genarts.com","sentAt":"2010-09-23T13:14:14Z","receivedAt":"2010-09-23T13:14:14Z","isPatch":false,"sender":{"key":"bash@genarts.com","avatar":null},"body":"----- Original Message -----\n> From: \"Seth Robertson\" <in-gitvger@baka.org>\n> To: \"Artur Skawina\" <art.08.09@gmail.com>\n> Cc: \"Stefan Haller\" <lists@haller-berlin.de>, git@vger.kernel.org\n> Sent: Wednesday, September 22, 2010 7:26:19 PM\n> Subject: Re: Find out on which branch a commit was originally made) (was ANNOUNCE git-what-branch)\n>\n> ... I wanted something completely different. Something more\n> like: if a bug was introduced in commit X, what releases or branches\n> has it contaminated (or more positively, if a feature was introduced,\n> where was it made available). The simple case is figuring out on\n> which branch a commit was originally made.\n\nWait... When you restate the problem that way, isn't git-{branch,tag} --contains the right answer?  I'm curious how you (and others) would differentiate the approaches...\n\nIf I were to frame this discussion, I think the value of git-what-branch is the ability to extract the branch name that a commit was created on.  In many environments the branch name may be useless (see the i18n example earlier in this discussion), but at least in our corporate environment, branches (especially those that are going to merge into mainline development) are named very consistently.  So in our situation the branch name can produce information that may not be captured in the standard reporting products (branch names transform into conventional tag names, branch names imply a lead developer, branch names spur developers' memories, ...).\n\nStephen\n"},{"id":"151358","messageId":"AANLkTinw2bWWYD7UcS8P=uDJm8p3TGuWA133+BsnZPGH@mail.gmail.com","threadId":"25141","inReplyTo":"32741263.335615.1285247653984.JavaMail.root@mail.hq.genarts.com","subject":"Re: Find out on which branch a commit was originally made) (was ANNOUNCE git-what-branch)","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-09-23T13:26:17Z","receivedAt":"2010-09-23T13:26:17Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Thu, Sep 23, 2010 at 13:14, Stephen Bash <bash@genarts.com> wrote:\n> ----- Original Message -----\n>> From: \"Seth Robertson\" <in-gitvger@baka.org>\n>> To: \"Artur Skawina\" <art.08.09@gmail.com>\n>> Cc: \"Stefan Haller\" <lists@haller-berlin.de>, git@vger.kernel.org\n>> Sent: Wednesday, September 22, 2010 7:26:19 PM\n>> Subject: Re: Find out on which branch a commit was originally made) (was ANNOUNCE git-what-branch)\n>>\n>> ... I wanted something completely different. Something more\n>> like: if a bug was introduced in commit X, what releases or branches\n>> has it contaminated (or more positively, if a feature was introduced,\n>> where was it made available). The simple case is figuring out on\n>> which branch a commit was originally made.\n\n> Wait... When you restate the problem that way, isn't\n> git-{branch,tag} --contains the right answer?  I'm curious how you\n> (and others) would differentiate the approaches...\n\ngit-{branch,tag} *is* the right answer, the problem here was that the\noriginal reporter wanted to *delete* the original branch, or otherwise\nnot make it available, but still find out what it was.\n\nThe workaround is to walk the tree from a merge commit, but I think a\nbetter solution is to just push the refs to your topic branches\nsomewhere and keep them in an archive/ namespace. Then if you need to\ngo digging you can always add the archive as a remote and go\ngit-{branch,tag} --contains.\n"},{"id":"151359","messageId":"201009231427.o8NERBqF019672@no.baka.org","threadId":"25141","inReplyTo":"32741263.335615.1285247653984.JavaMail.root@mail.hq.genarts.com","subject":"Re: Re: Find out on which branch a commit was originally made) (was ANNOUNCE git-what-branch)","fromName":"Seth Robertson","fromEmail":"in-gitvger@baka.org","sentAt":"2010-09-23T14:27:11Z","receivedAt":"2010-09-23T14:27:11Z","isPatch":false,"sender":{"key":"in-gitvger@baka.org","avatar":null},"body":"\nIn message <32741263.335615.1285247653984.JavaMail.root@mail.hq.genarts.com>, S\ntephen Bash writes:\n\n    ----- Original Message -----\n    > From: \"Seth Robertson\" <in-gitvger@baka.org>\n    > To: \"Artur Skawina\" <art.08.09@gmail.com>\n    > Cc: \"Stefan Haller\" <lists@haller-berlin.de>, git@vger.kernel.org\n    > Sent: Wednesday, September 22, 2010 7:26:19 PM\n    > Subject: Re: Find out on which branch a commit was originally made) (was ANNOUNCE git-what-branch)\n    >\n    > ... I wanted something completely different. Something more\n    > like: if a bug was introduced in commit X, what releases or branches\n    > has it contaminated (or more positively, if a feature was introduced,\n    > where was it made available). The simple case is figuring out on\n    > which branch a commit was originally made.\n\n    Wait... When you restate the problem that way, isn't\n    git-{branch,tag} --contains the right answer?  I'm curious how you\n    (and others) would differentiate the approaches...\n\nOh, it is, don't get me wrong.  I actually use `git-branch --contains`\nin the script to generate my candidate list. This doesn't solve the\ncherry-pick problem, but I don't solve that either (yet).  I found it\ndifficult to verbalize exactly why this was needed--I know I have\nneeded it in the past which was why I pounced on the thread and used\nthe ideas to write git-what-branch\nhttp://github.com/SethRobertson/git-what-branch\n\n    If I were to frame this discussion, I think the value of\n    git-what-branch is the ability to extract the branch name that a\n    commit was created on.  In many environments the branch name may\n    be useless (see the i18n example earlier in this discussion), but\n    at least in our corporate environment, branches (especially those\n    that are going to merge into mainline development) are named very\n    consistently.  So in our situation the branch name can produce\n    information that may not be captured in the standard reporting\n    products (branch names transform into conventional tag names,\n    branch names imply a lead developer, branch names spur developers'\n    memories, ...).\n\nExactly.  The ability to see if a commit was born on a branch or what\nbranch it was merged to first is what is most important (anonymous\nbranches do exist even if you try to use --rebase consistently) so the\nability to find which branch it merged into first is also important.\nThis is the default operating mode of git-what-branch.\n\nTo a lesser extent, fornensics to help understanding how a commit\nmerged into a specific target may also be interesting.  It would be\neven nicer if we could express a path of interest to gitk so that you\ncould have that specific path highlighted in a `gitk --all` output.\n\nHmm.  Path/commit highlighting would be a nice feature in gitk no\nmatter what.  --highlight-stdin to highlight specific commits (and\nideally an algorithm to allow the connecting arcs for adjancent\ncommits to be highlighted.  There is already an interestedin hammer\nAlso being able to highlight specific commits at runtime (probably a\ndifferent color) and potentially enter a commit note would be pretty\ncool as well.  Unfortunately I have a different skill-set.\n\n\t\t\t\t\t-Seth Robertson\n"},{"id":"151407","messageId":"4C9BC757.3050803@gmail.com","threadId":"25141","inReplyTo":"AANLkTinw2bWWYD7UcS8P=uDJm8p3TGuWA133+BsnZPGH@mail.gmail.com","subject":"Re: Find out on which branch a commit was originally made) (was ANNOUNCE git-what-branch)","fromName":"Artur Skawina","fromEmail":"art.08.09@gmail.com","sentAt":"2010-09-23T21:32:07Z","receivedAt":"2010-09-23T21:32:07Z","isPatch":false,"sender":{"key":"art.08.09@gmail.com","avatar":null},"body":"On 09/23/10 15:26, Ævar Arnfjörð Bjarmason wrote:\n> On Thu, Sep 23, 2010 at 13:14, Stephen Bash <bash@genarts.com> wrote:\n>>> From: \"Seth Robertson\" <in-gitvger@baka.org>\n>>> ... I wanted something completely different. Something more\n>>> like: if a bug was introduced in commit X, what releases or branches\n>>> has it contaminated (or more positively, if a feature was introduced,\n>>> where was it made available). The simple case is figuring out on\n>>> which branch a commit was originally made.\n> \n>> Wait... When you restate the problem that way, isn't\n>> git-{branch,tag} --contains the right answer?  I'm curious how you\n>> (and others) would differentiate the approaches...\n> \n> git-{branch,tag} *is* the right answer, the problem here was that the\n> original reporter wanted to *delete* the original branch, or otherwise\n> not make it available, but still find out what it was.\n> \n> The workaround is to walk the tree from a merge commit, but I think a\n> better solution is to just push the refs to your topic branches\n> somewhere and keep them in an archive/ namespace. Then if you need to\n> go digging you can always add the archive as a remote and go\n> git-{branch,tag} --contains.\n\nWhile this was my initial suggestion too, there are several valid reasons\nfor wanting such functionality. One is obviously to ease adaptation for \nusers switching from other vcses, where branches are much more \"special\".\nAnother is that maintaining fine enough granularity in tag/branch naming\nmay not be that easy, not to mention the namespace clutter that causes and\nthat large scale omissions are practically impossible to fix retroactively.\n\nBut that's not all, consider:\n\n$ time git-show-merge-path 0c357544b0d `git for-each-ref refs/remotes/origin --format='%(refname)'| sed -e 's,refs/remotes/,,'`\nf88bdb1c315a M: 'ab/test' => next                                     100818 21:07\n# Merged into origin/next\na2c6726417db M: 'ab/test-2'                                           100904 15:15\n# Merged into origin/master, origin/HEAD and origin/pu\n# Not reachable from origin/html, origin/man, origin/maint and origin/todo\n0m0.333s user   0m0.010s system   0m0.355s elapsed   96.82% CPU\n\n$ time git branch -r --contains 0c357544b0d\n  remotes/origin/HEAD -> origin/master\n  remotes/origin/master\n  remotes/origin/next\n  remotes/origin/pu\n0m0.283s user   0m0.013s system   0m0.303s elapsed   97.84% CPU\n$\n\nboth commands have approximately the same cost, except the first one gives you\nmuch more information.\n\nOr, using the kernel repo: [1]\n\n$ time git-show-merge-path 86ab04c8c1df51df master release  \nb1bc81a0ef86 M: 'master'@$KO/linville/wireless-next-2.6               090607 11:24\n36432dae73cf M: 'master'@$KO/davem/net-next-2.6                       090611 14:00\n2ed0e21b30b5 M: $KO/davem/net-next-2.6                                090615 16:40\n# Merged into release and master\n0m3.056s user   0m0.207s system   0m3.154s elapsed   103.46% CPU\n$\n\nScript below; w/ one or two args works like the previous git-find-branch-for,\nexcept it's ~two times faster for expensive queries and does that silly five \nold branch request in <13s, for *all* 150 heads; <10s for master alone; also\nthis one won't show extra merges that happened after the commit arrived on the\nbranch. When ran w/ more then one branch name, will print the merge points\nand/or unreachability info for all of them, as in the above git.git example.\n\nThere's still a bug in there somewhere; finding it before blindly transforming\nit into perl might be a good idea ;) I'll fix it when i'll encounter it in .rl,\nright now i don't remember the random commit (in git.git) which confused it...\nStill no ff-detection, mostly due to lack of (real) test case.\n\nartur\n\n[1] yes, 36432dae73cf could be omitted, but i can't convince myself that it\n/should/ be. Implementing the filtering would be simple and cheap, but i think\ni want to know that another path to master exists.\n\n\n---------------------------------------------------------------------------------\n#! /usr/bin/env pike\n// git-show-merge-path <rev> [long-lived-branch(es)]\n// v. 0.99\n// Will show all external merge commits starting at <rev> until\n// this commit appears on the specified branches. When that happens\n// \"# Merged into <branchlist>\" is printed. If <rev> is still\n// unreachable from some of the branches then the search continues.\n// If at least one of the branches does not contain <rev> then $0\n// can and will print *all* merges (ie it won't stop at the last\n// of the given branches containing this commit), followed by \n// \"# Not reachable from <branchlist>\". This is a feature (can be\n// used to find leaks outside of the given branches).\n//\n#define die(a...) exit(1, \"Aborting; %s\"+a)\n\nstring run(string ... cmdline) {\n#if __REAL_MAJOR__<7 || __REAL_MAJOR__==7 && __REAL_MINOR__<8\n   string s = Process.popen(cmdline*\" \");\n   if (s==\"\")\n      die(\"\\n\", cmdline*\" \");\n   return s;\n#else\n   mapping r;\n   mixed e = catch { r = Process.run( ({@cmdline}) ); };\n   if (e || r[\"exitcode\"])\n      die(\"\", e?e:r[\"stderr\"]);\n   return r[\"stdout\"];\n#endif\n}\n\nstatic mapping commits = ([]);\n\narray parsecommits(string ... delim) {\n   array res = ({});\n   string id;\n   array lines = run(\"git\", \"rev-list\", \"--format=raw\",  \"--ancestry-path\",\n                                        \"--topo-order\", @delim)/\"\\n\";\n   mapping branchkids = ([]);\n   foreach (lines, string line) {\n      array words = line/\" \";\n      string h = words[0];\n      if (h==\"commit\") {\n         id = words[1];\n\t commits[id] = ([]);\n\t res += ({id});\n\t if (mapping bs = m_delete(branchkids, id))\n\t    commits[id][\"Branch\"] += bs;\n\t if (mapping bs = livebranches[id])\n\t    commits[id][\"Branch\"] += bs;\n      } else if (h==\"\") {\n         if (commits[id])\n            commits[id][\"\"] += ({line});\n      }\n      else {\n         if (h==\"parent\" && !commits[id][\"parent\"] && commits[id][\"Branch\"]) {\n            if (branchkids[words[1]])\n               branchkids[words[1]] += commits[id][\"Branch\"];\n\t    else\n               branchkids[words[1]] = commits[id][\"Branch\"];\n         }\n         commits[id][h] += words[1..];\n      }\n   }\n   return res;\n}\n\nstatic mapping desc = ([]);\n\nstatic mapping livebranches = ([]); // id : array(name)\nstatic mapping branchnames = ([]);  // name : void\n\nint main(int argc, array argv) {\n   argv[1] = (run(\"git\", \"rev-parse\", argv[1])/\"\\n\")[0];\n   if (argc==2)\n      argv += ({\"master\"});\n   for (int i=2; i<sizeof(argv); i++) {\n      string ref = argv[i];\n      string refid = (run(\"git\", \"rev-parse\", argv[i])/\"\\n\")[0];\n      livebranches[refid] += ([ ref : refid ]);\n      branchnames[ref] = refid;\n      argv[i] = refid;\n   }\n   array commit_list = parsecommits(\"^\"+argv[1], @argv[2..]);\n   commit_list = reverse(commit_list);\n   desc[argv[1]] = 1;\n   foreach (commit_list, string id) {\n      if (commits[id][\"parent\"]) {\n         foreach (commits[id][\"parent\"], string parent)\n            if (desc[parent])\n        \tdesc[id] = 1;\n\t if (sizeof(commits[id][\"parent\"])>1)\n            if (!desc[commits[id][\"parent\"][0]]) {\n\t       mapping reached = ([]);\n\t       if (commits[id][\"Branch\"])\n\t          reached = commits[id][\"Branch\"]&branchnames;\n\t       int comtime = (int)commits[id][\"committer\"][-2];\n               write(\"%.12s %-56.56s %.12s\\n\", id, \n\t              squeeze_subject(commits[id][\"\"][1]),\n\t\t      cal->Second(comtime)->format_time_xshort() );\n               if (sizeof(reached)>0) {\n\t          branchnames -= reached;\n                  write(\"# Merged into %s\\n\", \n\t\t          String.implode_nicely(indices(reached)) );\n\t\t  if (sizeof(branchnames)==0)\n\t\t     exit(0);\n\t       }\n\t    }\n      }\n      m_delete(commits, id);\n   }\n   write(\"# Not reachable from %s\\n\",  String.implode_nicely(indices(branchnames)) );\n}\n\nstring squeeze_subject(string subject) {\n\n   subject = String.trim_all_whites(subject);\n   subject = String.expand_tabs(subject);\n   foreach (sub_from_to, mapping m)\n      subject = replace(subject, m);\n   return subject;\n}\n\nstatic array(mapping) sub_from_to =\n({\n   ([ \n      \"Merge branch \" : \"Merge \",\n      \"Merge remote branch \" : \"Merge \",\n      \"Merge branches \" : \"MM:\",\n   ]),\n   ([ \n      \"Merge \" : \"M: \",\n      \"' of git:\": \"'@git:\",\n      \"' into \": \"' => \",\n   ]),\n   ([ \n       \"git://git.kernel.org/pub/scm/linux/kernel/git/\" : \"$KO/\",\n       \"commit '\" : \"C'\"\n   ]),\n});\n\nstatic object cal = Calendar.ISO.set_timezone(Calendar.Timezone.UTC);\n\n---------------------------------------------------------------------------------\n"},{"id":"151421","messageId":"4C9BFFE0.5040406@gmail.com","threadId":"25141","inReplyTo":"4C9BC757.3050803@gmail.com","subject":"Re: Find out on which branch a commit was originally made) (was ANNOUNCE git-what-branch)","fromName":"Artur Skawina","fromEmail":"art.08.09@gmail.com","sentAt":"2010-09-24T01:33:20Z","receivedAt":"2010-09-24T01:33:20Z","isPatch":false,"sender":{"key":"art.08.09@gmail.com","avatar":null},"body":"> There's still a bug in there somewhere; \n\nJIC someone actually wants to use that script -- you'll need this:\n\n--- git-show-merge-path\t2010-09-23 20:13:59.000000000 +0000\n+++ git-show-merge-path\t2010-09-24 01:09:10.000000000 +0000\n@@ -90,21 +89,21 @@\n         \tdesc[id] = 1;\n \t if (sizeof(commits[id][\"parent\"])>1)\n             if (!desc[commits[id][\"parent\"][0]]) {\n-\t       mapping reached = ([]);\n-\t       if (commits[id][\"Branch\"])\n-\t          reached = commits[id][\"Branch\"]&branchnames;\n \t       int comtime = (int)commits[id][\"committer\"][-2];\n                write(\"%.12s %-56.56s %.12s\\n\", id, \n \t              squeeze_subject(commits[id][\"\"][1]),\n \t\t      cal->Second(comtime)->format_time_xshort() );\n-               if (sizeof(reached)>0) {\n-\t          branchnames -= reached;\n-                  write(\"# Merged into %s\\n\", \n-\t\t          String.implode_nicely(indices(reached)) );\n-\t\t  if (sizeof(branchnames)==0)\n-\t\t     exit(0);\n-\t       }\n \t    }\n+\t if (mapping reached = commits[id][\"Branch\"]) {\n+\t    reached = reached&branchnames;\n+            if (sizeof(reached)>0) {\n+               branchnames -= reached;\n+               write(\"# Merged into %s\\n\",\n+\t\t       String.implode_nicely(indices(reached)) );\n+\t       if (sizeof(branchnames)==0)\n+\t\t  exit(0);\n+\t    }\n+\t }\n       }\n       m_delete(commits, id);\n    }\n"},{"id":"151524","messageId":"4C9CED68.50203@shatow.net","threadId":"25141","inReplyTo":"1jp0h7e.lgk0kp19qe5bbM%lists@haller-berlin.de","subject":"Re: Find out on which branch a commit was originally made","fromName":"Bryan Drewery","fromEmail":"bryan@shatow.net","sentAt":"2010-09-24T18:26:48Z","receivedAt":"2010-09-24T18:26:48Z","isPatch":false,"sender":{"key":"bryan@shatow.net","avatar":"https://gravatar.com/avatar/97f2135497453f52d450b5cc8a09910e12efea7dc520a25107afcc666ab9a182?d=mp&s=160"},"body":"  On 9/18/2010 4:19 AM, Stefan Haller wrote:\n> I'm trying to pursuade my co-workers to switch from Subversion to Git;\n> some of them prefer Mercurial.\n>\n> One concern that they are raising is that in Git there doesn't seem to\n> be an easy way to find out on which branch a given commit was originally\n> made, after the branch is merged back and deleted. They consider this a\n> show-stopper.  In Mercurial, branch information is meta data attached to\n> each commit, so you can easily get this information even after a branch\n> is closed.\n>\nUse an issue tracker? Associate the commits with ticket numbers in the \ncommit msg.\n\ngit commit -m \"Blah Blah Blah (refs #someticket)\"\n\nBryan Drewery\n"},{"id":"151549","messageId":"201009242057.o8OKvJRE024995@no.baka.org","threadId":"25141","inReplyTo":"4C9BC757.3050803@gmail.com","subject":"Re: Find out on which branch a commit was originally made) (was ANNOUNCE git-what-branch)","fromName":"Seth Robertson","fromEmail":"in-gitvger@baka.org","sentAt":"2010-09-24T20:57:19Z","receivedAt":"2010-09-24T20:57:19Z","isPatch":false,"sender":{"key":"in-gitvger@baka.org","avatar":null},"body":"\nIn message <4C9BC757.3050803@gmail.com>, Artur Skawina writes:\n\n    $ time git-show-merge-path 86ab04c8c1df51df master release\n    b1bc81a0ef86 M: 'master'@$KO/linville/wireless-next-2.6        090607 11:24\n    36432dae73cf M: 'master'@$KO/davem/net-next-2.6                090611 14:00\n    2ed0e21b30b5 M: $KO/davem/net-next-2.6                         090615 16:40\n    # Merged into release and master\n    0m3.056s user   0m0.207s system   0m3.154s elapsed   103.46% CPU\n\n    Script below; w/ one or two args works like the previous\n    git-find-branch-for, except it's ~two times faster for expensive\n    queries and does that silly five old branch request in <13s, for\n    *all* 150 heads\n\nThanks to your suggestion about using git rev-list with more than two\nreferences I was able to massively increase the performance of my\nscript, from 26 minutes to 26 seconds, for the linux kernel search\ntest.\n\nI have updated http://github.com/SethRobertson/git-what-branch to\nrelease v0.2.1 with the performance boost and some display enhancements.\n\n--------------------------------------------------\ntime git-what-branch --reference master 86ab04c8c1df51df\n86ab04c8c1df51df used the following minimal temporal path:\n  merged to v2.6.30-rc6-1103-gb1bc81a @Sun Jun  7 07:24:21 2009\n  merged to v2.6.30-5398-g2ed0e21     @Mon Jun 15 12:40:05 2009\n  v2.6.30-5398-g2ed0e21 is on master\n5.97user 0.45system 0:06.08elapsed\n--------------------------------------------------\n\n    Still no ff-detection, mostly due to lack of (real) test case.\n\nHere are some fake test cases.  The question is which branch do tags\nmasterE and newbrBB appear on.\n\n# Demonstrates picking wrong branch for \"master\"\nMERGE=\"git merge\"\nmkdir foo; cd foo; git init; echo A > A; git add A; git commit -a -m \"initial\"\necho B >> A; git commit -a -m \"B\"; echo C >> A; git commit -a -m \"C\"\ngit branch newbr; echo AB > B; git add B; git commit -a -m \"newbr\"\ngit checkout master; echo D >> A; git commit -a -m \"D\"; git tag masterD;\ngit checkout newbr; $MERGE master; echo BB >> B; git commit -a -m \"BB\"; git tag newbrBB\ngit checkout master; echo E >> A; git commit -a -m \"E\"; git tag masterE;\ngit checkout newbr; $MERGE master; echo CB >> B; git commit -a -m \"CB\"\ngit checkout master; echo F >> A; git commit -a -m \"F\"\ngit checkout newbr; $MERGE master; echo DB >> B; git commit -a -m \"DB\"\ngit checkout master; $MERGE newbr; echo G >> A; git commit -a -m \"G\"\necho H >> A; git commit -a -m \"H\"; echo J >> A; git commit -a -m \"J\"; git tag masterJ\ngit checkout newbr; $MERGE master; echo eB >> B; git commit -a -m \"EB\"; git tag newbrEB\ngit checkout master; echo K >> A; git commit -a -m \"K\"; $MERGE newbr\nunset MERGE\n\n# Demonstrates picking the wrong branch for \"newbr\"\nMERGE=\"git merge\"\nmkdir foo; cd foo; git init; echo A > A; git add A; git commit -a -m \"initial\"\necho B >> A; git commit -a -m \"B\"; echo C >> A; git commit -a -m \"C\"\ngit branch newbr; echo AB > B; git add B; git commit -a -m \"newbr\"\ngit checkout master; echo D >> A; git commit -a -m \"D\"; git tag masterD;\ngit checkout newbr; $MERGE master; echo BB >> B; git commit -a -m \"BB\"; git tag newbrBB\ngit checkout master; echo E >> A; git commit -a -m \"E\"; git tag masterE;\ngit checkout newbr; $MERGE master; echo CB >> B; git commit -a -m \"CB\"\ngit checkout master; echo F >> A; git commit -a -m \"F\"\ngit checkout newbr; echo DB >> B; git commit -a -m \"DB\"\ngit checkout master; $MERGE newbr; echo G >> A; git commit -a -m \"G\"\necho H >> A; git commit -a -m \"H\"; echo J >> A; git commit -a -m \"J\"; git tag masterJ\ngit checkout newbr; $MERGE master; echo eB >> B; git commit -a -m \"EB\"; git tag newbrEB\ngit checkout master; echo K >> A; git commit -a -m \"K\"; $MERGE newbr\nunset MERGE\n\n\n\t\t\t\t\t-Seth Robertson\n"}]}