{"thread":{"id":"16126","subject":"[RFC/PATCH 1/2] bisect: add \"git bisect replace\" subcommand","startedAt":"2008-11-02T01:19:10Z","lastAt":"2008-11-02T11:20:09Z","messageCount":3,"participants":["Christian Couder","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"94611","messageId":"20081102021910.fef1532e.chriscool@tuxfamily.org","threadId":"16126","inReplyTo":null,"subject":"[RFC/PATCH 1/2] bisect: add \"git bisect replace\" subcommand","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-11-02T01:19:10Z","receivedAt":"2008-11-02T01:19:10Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This new subcommand should be used when you have a branch or a part of\na branch that isn't easily bisectable because at some point, say A, a\nbug as been introduced. The bug has been fixed latter at another point,\nsay B, but between these points the code is not easily testable because\nof the bug, so it's not easy to bisect between these points.\n\nIn this case you can create a branch starting at the parent of A, say\nO, that has a fixed history. In this fixed history for example, there\ncould be first a commit C that is the result of squashing A and B\ntogether and then all the commit between A and B that have been\ncherry picked.\n\nFor example, let's say the commits between A and B are X1, X2, ... Xn\nand they have been cherry picked after C as Y1, Y2, ... Yn:\n\n        C--Y1--Y2--...--Yn\n      /\n...--O--A--X1--X2--...--Xn--B--...\n\nBy design, the last cherry picked commit (Yn) should point to the same\ntree as commit B.\n\nSo in this case you can say:\n\n$ git bisect replace B Yn\n\nand commit B will be tagged with a special name like:\n\n\"bisect-replace-with-Yn\"\n\nWhen bisecting, commit with those tags will be grafted so that their\nparents will be replaced by the commit specified in the tag.\n\nIn the example above that means that instead of the above graph, the\nfollowing graph will be bisected:\n\n        C--Y1--Y2--...--Yn\n      /                   \\\n...--O                     B--...\n\nThis means that the bisections on this branch will be much easier\nbecause the bug introduced by commit A and fixed by commit B will not\nannoy you anymore.\n---\n builtin-rev-list.c |   29 ++++++++++++++++++++++++++++-\n git-bisect.sh      |   40 +++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 67 insertions(+), 2 deletions(-)\n\n\tThank you Junio for your help in designing this during the GitTogether,\n\tespecially for the trick to change the parents of the commit fixing the\n\tbug.\n\n\tI know this is lacking documentation but I plan to work on it soon and\n\tsend a documentation patch. The tests (in the following patch) are also\n\ta bit lacking, so I will improve them too.\n\ndiff --git a/builtin-rev-list.c b/builtin-rev-list.c\nindex 06cdeb7..5569bb2 100644\n--- a/builtin-rev-list.c\n+++ b/builtin-rev-list.c\n@@ -529,6 +529,30 @@ static struct commit_list *do_find_bisection(struct commit_list *list,\n \t\treturn best_bisection_sorted(list, nr);\n }\n \n+static int bisect_replace(const char *refname, const unsigned char *sha1,\n+\t\t\t  int flag, void *cb_data)\n+{\n+\tstruct commit_graft *graft;\n+\n+\tif (prefixcmp(refname, \"bisect-replace-with-\"))\n+\t\treturn 0;\n+\n+\t/* Create a graft to replace current commit */\n+\n+\tgraft = xmalloc(sizeof(*graft) + 20);\n+\n+\thashcpy(graft->sha1, sha1);\n+\tgraft->nr_parent = 1;\n+\tif (get_sha1_hex(refname + 20, graft->parent[0])) {\n+\t\tfree(graft);\n+\t\treturn 0;\n+\t}\n+\n+\tregister_commit_graft(graft, 1);\n+\n+\treturn 0;\n+}\n+\n static struct commit_list *find_bisection(struct commit_list *list,\n \t\t\t\t\t  int *reaches, int *all,\n \t\t\t\t\t  int find_all)\n@@ -646,8 +670,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)\n \n \tsave_commit_buffer = revs.verbose_header ||\n \t\trevs.grep_filter.pattern_list;\n-\tif (bisect_list)\n+\n+\tif (bisect_list) {\n+\t\tfor_each_tag_ref(bisect_replace, NULL);\n \t\trevs.limited = 1;\n+\t}\n \n \tif (prepare_revision_walk(&revs))\n \t\tdie(\"revision walk setup failed\");\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 0d0e278..245435c 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -1,6 +1,6 @@\n #!/bin/sh\n \n-USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'\n+USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run|replace]'\n LONG_USAGE='git bisect help\n         print this long help message.\n git bisect start [<bad> [<good>...]] [--] [<pathspec>...]\n@@ -23,6 +23,8 @@ git bisect log\n         show bisect log.\n git bisect run <cmd>...\n         use <cmd>... to automatically bisect.\n+git bisect replace <rev> [<rev>]\n+        use another branch for bisection.\n \n Please use \"git help bisect\" to get the full man page.'\n \n@@ -618,6 +620,40 @@ bisect_run () {\n     done\n }\n \n+bisect_replace() {\n+    test \"$#\" -ge 1 -a \"$#\" -le 2 ||\n+        die \"'git bisect replace' accept one or two arguments\"\n+\n+    source=\"$1\"\n+    target=\"${2:-HEAD}\"\n+\n+    # Check arguments\n+    src_commit=$(git rev-parse --verify \"$source^{commit}\") ||\n+        die \"Bad rev input: $source\"\n+    tgt_commit=$(git rev-parse --verify \"$target^{commit}\") ||\n+        die \"Bad rev input: $target\"\n+\n+    test \"$src_commit\" != \"tgt_commit\" ||\n+        die \"source and target should be different commits\"\n+\n+    # Check that trees from source and target are identical\n+    src_tree=$(git rev-parse --verify \"$src_commit^{tree}\") ||\n+        die \"Could not get tree for source: $source\"\n+    tgt_tree=$(git rev-parse --verify \"$tgt_commit^{tree}\") ||\n+        die \"Could not get tree for target: $target\"\n+\n+    test \"$src_tree\" = \"$tgt_tree\" ||\n+        die \"source and target should point to the same tree\"\n+\n+    # Tag the source commit\n+    src_tag=\"bisect-replace-with-$tgt_commit\"\n+    git tag \"$src_tag\" \"$src_commit\" || exit\n+\n+    # Create branch for the target commit\n+    tgt_branch=\"bisect-replace-$src_commit\"\n+    git branch \"$tgt_branch\" \"$tgt_commit\" || exit\n+}\n+\n \n case \"$#\" in\n 0)\n@@ -645,6 +681,8 @@ case \"$#\" in\n \tcat \"$GIT_DIR/BISECT_LOG\" ;;\n     run)\n         bisect_run \"$@\" ;;\n+    replace)\n+        bisect_replace \"$@\" ;;\n     *)\n         usage ;;\n     esac\n-- \n1.6.0.3.531.gd12eb.dirty\n"},{"id":"94622","messageId":"alpine.DEB.1.00.0811020515370.22125@pacific.mpi-cbg.de.mpi-cbg.de","threadId":"16126","inReplyTo":"20081102021910.fef1532e.chriscool@tuxfamily.org","subject":"Re: [RFC/PATCH 1/2] bisect: add \"git bisect replace\" subcommand","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-11-02T04:16:30Z","receivedAt":"2008-11-02T04:16:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 2 Nov 2008, Christian Couder wrote:\n\n> This new subcommand should be used when you have a branch or a part of a \n> branch that isn't easily bisectable because at some point, say A, a bug \n> as been introduced. The bug has been fixed latter at another point, say \n> B, but between these points the code is not easily testable because of \n> the bug, so it's not easy to bisect between these points.\n\nWould it not be more intuitive to have support for\n\n\tgit bisect skip A..B\n\n?\n\nCiao,\nDscho\n"},{"id":"94655","messageId":"200811021220.09439.chriscool@tuxfamily.org","threadId":"16126","inReplyTo":"alpine.DEB.1.00.0811020515370.22125@pacific.mpi-cbg.de.mpi-cbg.de","subject":"Re: [RFC/PATCH 1/2] bisect: add \"git bisect replace\" subcommand","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-11-02T11:20:09Z","receivedAt":"2008-11-02T11:20:09Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Hi,\n\nLe dimanche 2 novembre 2008, Johannes Schindelin a écrit :\n> Hi,\n>\n> On Sun, 2 Nov 2008, Christian Couder wrote:\n> > This new subcommand should be used when you have a branch or a part of\n> > a branch that isn't easily bisectable because at some point, say A, a\n> > bug as been introduced. The bug has been fixed latter at another point,\n> > say B, but between these points the code is not easily testable because\n> > of the bug, so it's not easy to bisect between these points.\n>\n> Would it not be more intuitive to have support for\n>\n> \tgit bisect skip A..B\n>\n> ?\n\nWe can have both. \"bisect skip\" is about not being able or wanting to test \nsome commits and \"bisect replace\" is about testing using fixed up branches \n(that you can share with others) instead of branches that you can't test.\n\nWhen working on big projects where many people are often bisecting (like the \nLinux kernel), then having shared \"bisect-replace\" branches (and tags) \nmight save a lot of time to all people bisecting, as they will not have to \noften skip the same commits or maintain sets of patches to apply when \nbisecting.\n\nThanks,\nChristian.\n"}]}