{"thread":{"id":"55576","subject":"[PATCH] git-p4: speed up search for branch parent","startedAt":"2021-04-28T20:07:19Z","lastAt":"2021-05-05T11:56:33Z","messageCount":10,"participants":["Joachim Kuebart via GitGitGadget","Junio C Hamano","Joachim Kuebart","Luke Diamand"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"423215","messageId":"pull.1013.git.git.1619640416533.gitgitgadget@gmail.com","threadId":"55576","inReplyTo":null,"subject":"[PATCH] git-p4: speed up search for branch parent","fromName":"Joachim Kuebart via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-04-28T20:06:56Z","receivedAt":"2021-04-28T20:07:19Z","isPatch":true,"sender":{"key":"joachim.kuebart@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24879979?v=4"},"body":"From: Joachim Kuebart <joachim.kuebart@gmail.com>\n\nPreviously, the code iterated through the parent branch commits and\ncompared each one to the target tree using diff-tree.\n\nThis patch outputs the revision's tree hash along with the commit hash,\nthereby saving the diff-tree invocation. This results in a considerable\nspeed-up, at least on Windows.\n\nSigned-off-by: Joachim Kuebart <joachim.kuebart@gmail.com>\n---\n    git-p4: speed up search for branch parent\n    \n    Previously, the code iterated through the parent branch commits and\n    compared each one to the target tree using diff-tree.\n    \n    This patch outputs the revision's tree hash along with the commit hash,\n    thereby saving the diff-tree invocation. This results in a considerable\n    speed-up, at least on Windows.\n    \n    Signed-off-by: Joachim Kuebart joachim.kuebart@gmail.com\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1013%2Fjkuebart%2Fp4-faster-parent-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1013/jkuebart/p4-faster-parent-v1\nPull-Request: https://github.com/git/git/pull/1013\n\n git-p4.py | 22 +++++++++++-----------\n 1 file changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/git-p4.py b/git-p4.py\nindex 09c9e93ac401..dbe94e6fb83b 100755\n--- a/git-p4.py\n+++ b/git-p4.py\n@@ -3600,19 +3600,19 @@ def importNewBranch(self, branch, maxChange):\n         return True\n \n     def searchParent(self, parent, branch, target):\n-        parentFound = False\n-        for blob in read_pipe_lines([\"git\", \"rev-list\", \"--reverse\",\n+        for tree in read_pipe_lines([\"git\", \"rev-parse\",\n+                                     \"{}^{{tree}}\".format(target)]):\n+            targetTree = tree.strip()\n+        for blob in read_pipe_lines([\"git\", \"rev-list\", \"--format=%H %T\",\n                                      \"--no-merges\", parent]):\n-            blob = blob.strip()\n-            if len(read_pipe([\"git\", \"diff-tree\", blob, target])) == 0:\n-                parentFound = True\n+            if blob[:7] == \"commit \":\n+                continue\n+            blob = blob.strip().split(\" \")\n+            if blob[1] == targetTree:\n                 if self.verbose:\n-                    print(\"Found parent of %s in commit %s\" % (branch, blob))\n-                break\n-        if parentFound:\n-            return blob\n-        else:\n-            return None\n+                    print(\"Found parent of %s in commit %s\" % (branch, blob[0]))\n+                return blob[0]\n+        return None\n \n     def importChanges(self, changes, origin_revision=0):\n         cnt = 1\n\nbase-commit: 311531c9de557d25ac087c1637818bd2aad6eb3a\n-- \ngitgitgadget\n"},{"id":"423229","messageId":"xmqq5z05akyf.fsf@gitster.g","threadId":"55576","inReplyTo":"pull.1013.git.git.1619640416533.gitgitgadget@gmail.com","subject":"Re: [PATCH] git-p4: speed up search for branch parent","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-29T02:22:32Z","receivedAt":"2021-04-29T02:22:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Joachim Kuebart via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: Joachim Kuebart <joachim.kuebart@gmail.com>\n\nThanks.  As git-p4 is not in my area of expertise, I'll make a style\ncritique first, while pinging Luke as an area expert (you can learn\nwho they are with \"git shortlog --no-merges --since=18.months.ago\ngit-p4.py\").\n\n> Previously, the code iterated through the parent branch commits and\n> compared each one to the target tree using diff-tree.\n\nIt is customary in this project to describe the problem in the\npresent tense.  In other words, whoever is writing the log message\nstill lives in the world without this patch applied to the system.\n\n    The code iterates through the parent commits and compares each of\n    them to the target tree using diff-tree.\n\nBut before that sentence, please prepare the reader with a bit\nlarger picture.  A reader may not know what purpose the comparison\nserves.  Do we know that the tree of one of the parents of the\ncommit must match the tree of the target, and trying to see which\nparent is the one with the same tree?  What is helped by learning\nwhich parent has the same tree?\n\nPerhaps\n\n    The method searchParent() is used to find a commit in the\n    history of the given 'parent' commit whose tree exactly matches\n    the tree of the given 'target commit.  The code iterates through\n    the commits in the history and compares each of them to the\n    target tree by invoking diff-tree.\n\nAnd then our log message would make observation, pointing out what\nis wrong with it (after all comparing with diff-tree is not giving\nus a wrong result---the point of this change is that spawning diff-tree\nfor each commit is wasteful when we only want to see exact matches).\n\n    Because we only are interested in finding a tree that is exactly\n    the same, and not interested in how other trees are different,\n    having to spawn diff-tree for each and every commit is wasteful. \n\n> This patch outputs the revision's tree hash along with the commit hash,\n> thereby saving the diff-tree invocation. This results in a considerable\n> speed-up, at least on Windows.\n\nAnd then our log message would order the codebase to \"become like\nso\", in order to resolve the issue(s) pointed out in the\nobservation.  Perhaps\n\n    Use the \"--format\" option of \"rev-list\" to find out the tree\n    object name of each commit in the history, and find the tree\n    whose name is exactly the same as the tree of the target commit\n    to optimize this.\n\nWhen making a claim on performance, it is helpful to our readers to\ngive some numbers, even in a limited test, e.g.\n\n    In a sample history where ~100 commits needed to be traversed to\n    find the fork point on my Windows box, the current code took\n    10.4 seconds to complete, while the new code yields the same\n    result in 1.8 seconds, which is a significant speed-up.\n\nor something along these lines.\n\n> Signed-off-by: Joachim Kuebart <joachim.kuebart@gmail.com>\n>  git-p4.py | 22 +++++++++++-----------\n>  1 file changed, 11 insertions(+), 11 deletions(-)\n>\n> diff --git a/git-p4.py b/git-p4.py\n> index 09c9e93ac401..dbe94e6fb83b 100755\n> --- a/git-p4.py\n> +++ b/git-p4.py\n> @@ -3600,19 +3600,19 @@ def importNewBranch(self, branch, maxChange):\n>          return True\n>  \n>      def searchParent(self, parent, branch, target):\n> +        for tree in read_pipe_lines([\"git\", \"rev-parse\",\n> +                                     \"{}^{{tree}}\".format(target)]):\n> +            targetTree = tree.strip()\n\nIt looks very strange to run a commit that you expect a single line\nof output, and read the result in a loop.  Doesn't git-p4.py supply\na more suitable helper to read a single line output from a command?\n\n> +        for blob in read_pipe_lines([\"git\", \"rev-list\", \"--format=%H %T\",\n>                                       \"--no-merges\", parent]):\n\nThis is not a new problem you introduced, but when we hear word\n\"blob\" in the context of this project, it reminds us of the \"blob\"\nobject, while the 'blob' variable used in this loop has nothing to\ndo with it.  Perhaps rename it to say 'line' or something?\n\n> +            if blob[:7] == \"commit \":\n> +                continue\n\nPerhaps blob.startswith(\"commit \") to avoid hardcoded string length?\n\n> +            blob = blob.strip().split(\" \")\n> +            if blob[1] == targetTree:\n>                  if self.verbose:\n> +                    print(\"Found parent of %s in commit %s\" % (branch, blob[0]))\n> +                return blob[0]\n> +        return None\n\n"},{"id":"423248","messageId":"CAJGkkrQJFaLPfCBTVn6k1v9cCwF4wEUxr+ZyzebUBQJB8qLaWg@mail.gmail.com","threadId":"55576","inReplyTo":"xmqq5z05akyf.fsf@gitster.g","subject":"Re: [PATCH] git-p4: speed up search for branch parent","fromName":"Joachim Kuebart","fromEmail":"joachim.kuebart@gmail.com","sentAt":"2021-04-29T07:48:34Z","receivedAt":"2021-04-29T07:49:17Z","isPatch":true,"sender":{"key":"joachim.kuebart@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24879979?v=4"},"body":"On Thu, 29 Apr 2021 at 04:22, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> \"Joachim Kuebart via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>\n> > From: Joachim Kuebart <joachim.kuebart@gmail.com>\n>\n> Thanks.  As git-p4 is not in my area of expertise, I'll make a style\n> critique first, while pinging Luke as an area expert (you can learn\n> who they are with \"git shortlog --no-merges --since=18.months.ago\n> git-p4.py\").\n\nHi Junio, thanks for your timely and thorough review and for putting\nup with my greenhorn mistakes ;-)\n\n> > Previously, the code iterated through the parent branch commits and\n> > compared each one to the target tree using diff-tree.\n>\n> It is customary in this project to describe the problem in the\n> present tense.  In other words, whoever is writing the log message\n> still lives in the world without this patch applied to the system.\n\nI will rephrase the commit message and give better details as you\nmentioned. Thanks a lot for your suggestions!\n\n> When making a claim on performance, it is helpful to our readers to\n> give some numbers, even in a limited test, e.g.\n>\n>     In a sample history where ~100 commits needed to be traversed to\n>     find the fork point on my Windows box, the current code took\n>     10.4 seconds to complete, while the new code yields the same\n>     result in 1.8 seconds, which is a significant speed-up.\n>\n> or something along these lines.\n\nI will add some measurements.\n\n> > Signed-off-by: Joachim Kuebart <joachim.kuebart@gmail.com>\n> >  git-p4.py | 22 +++++++++++-----------\n> >  1 file changed, 11 insertions(+), 11 deletions(-)\n> >\n> > diff --git a/git-p4.py b/git-p4.py\n> > index 09c9e93ac401..dbe94e6fb83b 100755\n> > --- a/git-p4.py\n> > +++ b/git-p4.py\n> > @@ -3600,19 +3600,19 @@ def importNewBranch(self, branch, maxChange):\n> >          return True\n> >\n> >      def searchParent(self, parent, branch, target):\n> > +        for tree in read_pipe_lines([\"git\", \"rev-parse\",\n> > +                                     \"{}^{{tree}}\".format(target)]):\n> > +            targetTree = tree.strip()\n>\n> It looks very strange to run a commit that you expect a single line\n> of output, and read the result in a loop.  Doesn't git-p4.py supply\n> a more suitable helper to read a single line output from a command?\n\nYou're absolutely right that this isn't very readable. I had a quick\nlook around for a function that reads a single-line response, but I'll\nlook again and come up with a clearer solution.\n\n> > +        for blob in read_pipe_lines([\"git\", \"rev-list\", \"--format=%H %T\",\n> >                                       \"--no-merges\", parent]):\n>\n> This is not a new problem you introduced, but when we hear word\n> \"blob\" in the context of this project, it reminds us of the \"blob\"\n> object, while the 'blob' variable used in this loop has nothing to\n> do with it.  Perhaps rename it to say 'line' or something?\n\nWill do, thanks!\n\n> > +            if blob[:7] == \"commit \":\n> > +                continue\n>\n> Perhaps blob.startswith(\"commit \") to avoid hardcoded string length?\n\nYes, that's the name of the function that I can never think of when I need it.\n\nThanks again for your comments,\n\nJoachim\n"},{"id":"423252","messageId":"b0befcf3-8d8a-f99f-d4f0-78b2cfe22505@diamand.org","threadId":"55576","inReplyTo":"CAJGkkrQJFaLPfCBTVn6k1v9cCwF4wEUxr+ZyzebUBQJB8qLaWg@mail.gmail.com","subject":"Re: [PATCH] git-p4: speed up search for branch parent","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2021-04-29T08:22:52Z","receivedAt":"2021-04-29T08:22:49Z","isPatch":true,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"\n\nOn 29/04/2021 07:48, Joachim Kuebart wrote:\n> On Thu, 29 Apr 2021 at 04:22, Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>> \"Joachim Kuebart via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>>\n>>> From: Joachim Kuebart <joachim.kuebart@gmail.com>\n>>\n>> Thanks.  As git-p4 is not in my area of expertise, I'll make a style\n>> critique first, while pinging Luke as an area expert (you can learn\n>> who they are with \"git shortlog --no-merges --since=18.months.ago\n>> git-p4.py\").\n> \n> Hi Junio, thanks for your timely and thorough review and for putting\n> up with my greenhorn mistakes ;-)\n> \n>>> Previously, the code iterated through the parent branch commits and\n>>> compared each one to the target tree using diff-tree.\n>>\n>> It is customary in this project to describe the problem in the\n>> present tense.  In other words, whoever is writing the log message\n>> still lives in the world without this patch applied to the system.\n> \n> I will rephrase the commit message and give better details as you\n> mentioned. Thanks a lot for your suggestions!\n> \n>> When making a claim on performance, it is helpful to our readers to\n>> give some numbers, even in a limited test, e.g.\n>>\n>>      In a sample history where ~100 commits needed to be traversed to\n>>      find the fork point on my Windows box, the current code took\n>>      10.4 seconds to complete, while the new code yields the same\n>>      result in 1.8 seconds, which is a significant speed-up.\n>>\n>> or something along these lines.\n> \n> I will add some measurements.\n> \n>>> Signed-off-by: Joachim Kuebart <joachim.kuebart@gmail.com>\n>>>   git-p4.py | 22 +++++++++++-----------\n>>>   1 file changed, 11 insertions(+), 11 deletions(-)\n>>>\n>>> diff --git a/git-p4.py b/git-p4.py\n>>> index 09c9e93ac401..dbe94e6fb83b 100755\n>>> --- a/git-p4.py\n>>> +++ b/git-p4.py\n>>> @@ -3600,19 +3600,19 @@ def importNewBranch(self, branch, maxChange):\n>>>           return True\n>>>\n>>>       def searchParent(self, parent, branch, target):\n>>> +        for tree in read_pipe_lines([\"git\", \"rev-parse\",\n>>> +                                     \"{}^{{tree}}\".format(target)]):\n>>> +            targetTree = tree.strip()\n>>\n>> It looks very strange to run a commit that you expect a single line\n>> of output, and read the result in a loop.  Doesn't git-p4.py supply\n>> a more suitable helper to read a single line output from a command?\n> \n> You're absolutely right that this isn't very readable. I had a quick\n> look around for a function that reads a single-line response, but I'll\n> look again and come up with a clearer solution.\n\nI don't think there is one - git-p4 has lots of functions for calling \n`p4', but for calling git, it just uses Python's Popen() API.\n\nA good question is whether we can start taking advantage of the newer \nfeatures in Python3 which will obviously break backward compatibility.\n\n> \n>>> +        for blob in read_pipe_lines([\"git\", \"rev-list\", \"--format=%H %T\",\n>>>                                        \"--no-merges\", parent]):\n>>\n>> This is not a new problem you introduced, but when we hear word\n>> \"blob\" in the context of this project, it reminds us of the \"blob\"\n>> object, while the 'blob' variable used in this loop has nothing to\n>> do with it.  Perhaps rename it to say 'line' or something? >\n> Will do, thanks!\n\nIt confused me as well.\n\n> \n>>> +            if blob[:7] == \"commit \":\n>>> +                continue\n>>\n>> Perhaps blob.startswith(\"commit \") to avoid hardcoded string length?\n> \n> Yes, that's the name of the function that I can never think of when I need it.\n> \n> Thanks again for your comments,\n> \n> Joachim\n> \n\nThere are existing tests for importing branches which should cover this. \nI don't know if they need to be extended or not, you might want to check.\n\nLooks good otherwise.\n\n\n"},{"id":"423253","messageId":"xmqqwnslfq4l.fsf@gitster.g","threadId":"55576","inReplyTo":"b0befcf3-8d8a-f99f-d4f0-78b2cfe22505@diamand.org","subject":"Re: [PATCH] git-p4: speed up search for branch parent","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-29T08:31:54Z","receivedAt":"2021-04-29T08:32:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Luke Diamand <luke@diamand.org> writes:\n\n>>>>       def searchParent(self, parent, branch, target):\n>>>> +        for tree in read_pipe_lines([\"git\", \"rev-parse\",\n>>>> +                                     \"{}^{{tree}}\".format(target)]):\n>>>> +            targetTree = tree.strip()\n>>>\n>>> It looks very strange to run a commit that you expect a single line\n>>> of output, and read the result in a loop.  Doesn't git-p4.py supply\n>>> a more suitable helper to read a single line output from a command?\n>> You're absolutely right that this isn't very readable. I had a quick\n>> look around for a function that reads a single-line response, but I'll\n>> look again and come up with a clearer solution.\n>\n> I don't think there is one - git-p4 has lots of functions for calling\n> `p4', but for calling git, it just uses Python's Popen() API.\n\nOK.  It just felt \"strange\", not \"wrong\", so I am OK with the\nconstruct at least for now.\n\n> There are existing tests for importing branches which should cover\n> this. I don't know if they need to be extended or not, you might want\n> to check.\n>\n> Looks good otherwise.\n\nThanks for a prompt review.\n\n\n"},{"id":"423260","messageId":"CAJGkkrS1Qg_Se=Bu5oE1K1G+NtWDTq2JErJNtvyRoQrRw74WQA@mail.gmail.com","threadId":"55576","inReplyTo":"b0befcf3-8d8a-f99f-d4f0-78b2cfe22505@diamand.org","subject":"Re: [PATCH] git-p4: speed up search for branch parent","fromName":"Joachim Kuebart","fromEmail":"joachim.kuebart@gmail.com","sentAt":"2021-04-29T11:30:57Z","receivedAt":"2021-04-29T11:31:37Z","isPatch":true,"sender":{"key":"joachim.kuebart@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24879979?v=4"},"body":"On Thu, 29 Apr 2021 at 10:22, Luke Diamand <luke@diamand.org> wrote:\n>\n> There are existing tests for importing branches which should cover this.\n> I don't know if they need to be extended or not, you might want to check.\n\nI enhanced t9801-git-p4-branch to check for this functionality, i.e.\nthat the branches are branched off at the correct commits from their\nparents. As far as I could see, there was no test for this before.\n\nThank you as well for your quick response!\n\nCheers,\n\nJoachim\n"},{"id":"423293","messageId":"CAJGkkrTzThckEuFr7abV7WwZg4FUw=y5Xt4uu6TuQzuhWcrSQw@mail.gmail.com","threadId":"55576","inReplyTo":"xmqqwnslfq4l.fsf@gitster.g","subject":"Re: [PATCH] git-p4: speed up search for branch parent","fromName":"Joachim Kuebart","fromEmail":"joachim.kuebart@gmail.com","sentAt":"2021-04-29T19:31:03Z","receivedAt":"2021-04-29T19:31:42Z","isPatch":true,"sender":{"key":"joachim.kuebart@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24879979?v=4"},"body":"On Thu, 29 Apr 2021 at 10:31, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Luke Diamand <luke@diamand.org> writes:\n> >\n> > Looks good otherwise.\n>\n> Thanks for a prompt review.\n\nI addressed your comments and updated my PR at\nhttps://github.com/git/git/pull/1013, but CI seems stuck and hasn't\nkicked off yet. I'd like to see it pass especially since I modified a\ntest. Is there anything else I need to do?\n\nJoachim\n"},{"id":"423653","messageId":"0ee0b7b55691a8923c7fd1610adfe8854163dcfc.1620215786.git.gitgitgadget@gmail.com","threadId":"55576","inReplyTo":"pull.1013.v2.git.git.1620215786.gitgitgadget@gmail.com","subject":"[PATCH v2 1/2] git-p4: ensure complex branches are cloned correctly","fromName":"Joachim Kuebart via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-05-05T11:56:25Z","receivedAt":"2021-05-05T11:56:31Z","isPatch":true,"sender":{"key":"joachim.kuebart@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24879979?v=4"},"body":"From: Joachim Kuebart <joachim.kuebart@gmail.com>\n\nWhen importing a branch from p4, git-p4 searches the history of the parent\nbranch for the branch point. The test for the complex branch structure\nensures all files have the expected contents, but doesn't examine the\nbranch structure.\n\nCheck for the correct branch structure by making sure that the initial\ncommit on each branch is empty. This ensures that the initial commit's\nparent is indeed the correct branch-off point.\n\nSigned-off-by: Joachim Kuebart <joachim.kuebart@gmail.com>\n---\n t/t9801-git-p4-branch.sh | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh\nindex ff94c3f17df1..50a6f8bad5c5 100755\n--- a/t/t9801-git-p4-branch.sh\n+++ b/t/t9801-git-p4-branch.sh\n@@ -294,11 +294,13 @@ test_expect_success 'git p4 clone complex branches' '\n \t\ttest_path_is_file file3 &&\n \t\tgrep update file2 &&\n \t\tgit reset --hard p4/depot/branch4 &&\n+\t\tgit diff-tree --quiet HEAD &&\n \t\ttest_path_is_file file1 &&\n \t\ttest_path_is_file file2 &&\n \t\ttest_path_is_missing file3 &&\n \t\t! grep update file2 &&\n \t\tgit reset --hard p4/depot/branch5 &&\n+\t\tgit diff-tree --quiet HEAD &&\n \t\ttest_path_is_file file1 &&\n \t\ttest_path_is_file file2 &&\n \t\ttest_path_is_file file3 &&\n-- \ngitgitgadget\n\n"},{"id":"423654","messageId":"pull.1013.v2.git.git.1620215786.gitgitgadget@gmail.com","threadId":"55576","inReplyTo":"pull.1013.git.git.1619640416533.gitgitgadget@gmail.com","subject":"[PATCH v2 0/2] git-p4: speed up search for branch parent","fromName":"Joachim Kuebart via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-05-05T11:56:24Z","receivedAt":"2021-05-05T11:56:32Z","isPatch":true,"sender":{"key":"joachim.kuebart@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24879979?v=4"},"body":"In this iteration, I have added more context and measurements to the commit\nmessage.\n\nI have also made small improvements to the code suggested by reviewers.\n\nI enhanced t9801-git-p4-branch.sh to test for the functionality, namely that\nbranches are branched off at the correct point in their parents' history.\n\nSigned-off-by: Joachim Kuebart joachim.kuebart@gmail.com\n\ncc: Joachim Kuebart joachim.kuebart@gmail.com\n\nJoachim Kuebart (2):\n  git-p4: ensure complex branches are cloned correctly\n  git-p4: speed up search for branch parent\n\n git-p4.py                | 21 ++++++++++-----------\n t/t9801-git-p4-branch.sh |  2 ++\n 2 files changed, 12 insertions(+), 11 deletions(-)\n\n\nbase-commit: 311531c9de557d25ac087c1637818bd2aad6eb3a\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1013%2Fjkuebart%2Fp4-faster-parent-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1013/jkuebart/p4-faster-parent-v2\nPull-Request: https://github.com/git/git/pull/1013\n\nRange-diff vs v1:\n\n -:  ------------ > 1:  0ee0b7b55691 git-p4: ensure complex branches are cloned correctly\n 1:  a171f7e6c023 ! 2:  41b3a23f682c git-p4: speed up search for branch parent\n     @@ Metadata\n       ## Commit message ##\n          git-p4: speed up search for branch parent\n      \n     -    Previously, the code iterated through the parent branch commits and\n     -    compared each one to the target tree using diff-tree.\n     +    For every new branch that git-p4 imports, it needs to find the commit\n     +    where it branched off its parent branch. While p4 doesn't record this\n     +    information explicitly, the first changelist on a branch is usually an\n     +    identical copy of the parent branch.\n      \n     -    This patch outputs the revision's tree hash along with the commit hash,\n     -    thereby saving the diff-tree invocation. This results in a considerable\n     -    speed-up, at least on Windows.\n     +    The method searchParent() tries to find a commit in the history of the\n     +    given \"parent\" branch whose tree exactly matches the initial changelist\n     +    of the new branch, \"target\". The code iterates through the parent\n     +    commits and compares each of them to this initial changelist using\n     +    diff-tree.\n     +\n     +    Since we already know the tree object name we are looking for, spawning\n     +    diff-tree for each commit is wasteful.\n     +\n     +    Use the \"--format\" option of \"rev-list\" to find out the tree object name\n     +    of each commit in the history, and find the tree whose name is exactly\n     +    the same as the tree of the target commit to optimize this.\n     +\n     +    This results in a considerable speed-up, at least on Windows. On one\n     +    Windows machine with a fairly large repository of about 16000 commits in\n     +    the parent branch, the current code takes over 7 minutes, while the new\n     +    code only takes just over 10 seconds for the same changelist:\n     +\n     +    Before:\n     +\n     +        $ time git p4 sync\n     +        Importing from/into multiple branches\n     +        Depot paths: //depot\n     +        Importing revision 31274 (100.0%)\n     +        Updated branches: b1\n     +\n     +        real    7m41.458s\n     +        user    0m0.000s\n     +        sys     0m0.077s\n     +\n     +    After:\n     +\n     +        $ time git p4 sync\n     +        Importing from/into multiple branches\n     +        Depot paths: //depot\n     +        Importing revision 31274 (100.0%)\n     +        Updated branches: b1\n     +\n     +        real    0m10.235s\n     +        user    0m0.000s\n     +        sys     0m0.062s\n      \n          Signed-off-by: Joachim Kuebart <joachim.kuebart@gmail.com>\n     +    Helped-by: Junio C Hamano <gitster@pobox.com>\n     +    Helped-by: Luke Diamand <luke@diamand.org>\n      \n       ## git-p4.py ##\n      @@ git-p4.py: def importNewBranch(self, branch, maxChange):\n     @@ git-p4.py: def importNewBranch(self, branch, maxChange):\n           def searchParent(self, parent, branch, target):\n      -        parentFound = False\n      -        for blob in read_pipe_lines([\"git\", \"rev-list\", \"--reverse\",\n     -+        for tree in read_pipe_lines([\"git\", \"rev-parse\",\n     -+                                     \"{}^{{tree}}\".format(target)]):\n     -+            targetTree = tree.strip()\n     -+        for blob in read_pipe_lines([\"git\", \"rev-list\", \"--format=%H %T\",\n     ++        targetTree = read_pipe([\"git\", \"rev-parse\",\n     ++                                \"{}^{{tree}}\".format(target)]).strip()\n     ++        for line in read_pipe_lines([\"git\", \"rev-list\", \"--format=%H %T\",\n                                            \"--no-merges\", parent]):\n      -            blob = blob.strip()\n      -            if len(read_pipe([\"git\", \"diff-tree\", blob, target])) == 0:\n      -                parentFound = True\n     -+            if blob[:7] == \"commit \":\n     ++            if line.startswith(\"commit \"):\n      +                continue\n     -+            blob = blob.strip().split(\" \")\n     -+            if blob[1] == targetTree:\n     ++            commit, tree = line.strip().split(\" \")\n     ++            if tree == targetTree:\n                       if self.verbose:\n      -                    print(\"Found parent of %s in commit %s\" % (branch, blob))\n      -                break\n     @@ git-p4.py: def importNewBranch(self, branch, maxChange):\n      -            return blob\n      -        else:\n      -            return None\n     -+                    print(\"Found parent of %s in commit %s\" % (branch, blob[0]))\n     -+                return blob[0]\n     ++                    print(\"Found parent of %s in commit %s\" % (branch, commit))\n     ++                return commit\n      +        return None\n       \n           def importChanges(self, changes, origin_revision=0):\n\n-- \ngitgitgadget\n"},{"id":"423655","messageId":"41b3a23f682cddb3720de14723854c5956f25704.1620215786.git.gitgitgadget@gmail.com","threadId":"55576","inReplyTo":"pull.1013.v2.git.git.1620215786.gitgitgadget@gmail.com","subject":"[PATCH v2 2/2] git-p4: speed up search for branch parent","fromName":"Joachim Kuebart via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-05-05T11:56:26Z","receivedAt":"2021-05-05T11:56:33Z","isPatch":true,"sender":{"key":"joachim.kuebart@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24879979?v=4"},"body":"From: Joachim Kuebart <joachim.kuebart@gmail.com>\n\nFor every new branch that git-p4 imports, it needs to find the commit\nwhere it branched off its parent branch. While p4 doesn't record this\ninformation explicitly, the first changelist on a branch is usually an\nidentical copy of the parent branch.\n\nThe method searchParent() tries to find a commit in the history of the\ngiven \"parent\" branch whose tree exactly matches the initial changelist\nof the new branch, \"target\". The code iterates through the parent\ncommits and compares each of them to this initial changelist using\ndiff-tree.\n\nSince we already know the tree object name we are looking for, spawning\ndiff-tree for each commit is wasteful.\n\nUse the \"--format\" option of \"rev-list\" to find out the tree object name\nof each commit in the history, and find the tree whose name is exactly\nthe same as the tree of the target commit to optimize this.\n\nThis results in a considerable speed-up, at least on Windows. On one\nWindows machine with a fairly large repository of about 16000 commits in\nthe parent branch, the current code takes over 7 minutes, while the new\ncode only takes just over 10 seconds for the same changelist:\n\nBefore:\n\n    $ time git p4 sync\n    Importing from/into multiple branches\n    Depot paths: //depot\n    Importing revision 31274 (100.0%)\n    Updated branches: b1\n\n    real    7m41.458s\n    user    0m0.000s\n    sys     0m0.077s\n\nAfter:\n\n    $ time git p4 sync\n    Importing from/into multiple branches\n    Depot paths: //depot\n    Importing revision 31274 (100.0%)\n    Updated branches: b1\n\n    real    0m10.235s\n    user    0m0.000s\n    sys     0m0.062s\n\nSigned-off-by: Joachim Kuebart <joachim.kuebart@gmail.com>\nHelped-by: Junio C Hamano <gitster@pobox.com>\nHelped-by: Luke Diamand <luke@diamand.org>\n---\n git-p4.py | 21 ++++++++++-----------\n 1 file changed, 10 insertions(+), 11 deletions(-)\n\ndiff --git a/git-p4.py b/git-p4.py\nindex 09c9e93ac401..d34a1946b754 100755\n--- a/git-p4.py\n+++ b/git-p4.py\n@@ -3600,19 +3600,18 @@ def importNewBranch(self, branch, maxChange):\n         return True\n \n     def searchParent(self, parent, branch, target):\n-        parentFound = False\n-        for blob in read_pipe_lines([\"git\", \"rev-list\", \"--reverse\",\n+        targetTree = read_pipe([\"git\", \"rev-parse\",\n+                                \"{}^{{tree}}\".format(target)]).strip()\n+        for line in read_pipe_lines([\"git\", \"rev-list\", \"--format=%H %T\",\n                                      \"--no-merges\", parent]):\n-            blob = blob.strip()\n-            if len(read_pipe([\"git\", \"diff-tree\", blob, target])) == 0:\n-                parentFound = True\n+            if line.startswith(\"commit \"):\n+                continue\n+            commit, tree = line.strip().split(\" \")\n+            if tree == targetTree:\n                 if self.verbose:\n-                    print(\"Found parent of %s in commit %s\" % (branch, blob))\n-                break\n-        if parentFound:\n-            return blob\n-        else:\n-            return None\n+                    print(\"Found parent of %s in commit %s\" % (branch, commit))\n+                return commit\n+        return None\n \n     def importChanges(self, changes, origin_revision=0):\n         cnt = 1\n-- \ngitgitgadget\n"}]}