{"thread":{"id":"16259","subject":"[PATCH 1/9 v4] bisect: add \"git bisect replace\" subcommand","startedAt":"2008-11-11T05:39:04Z","lastAt":"2008-11-15T14:19:27Z","messageCount":9,"participants":["Christian Couder","Junio C Hamano","Paolo Bonzini"],"isPatch":true,"patchVersion":4,"patchTotal":9},"messages":[{"id":"95429","messageId":"20081111063904.7da4df94.chriscool@tuxfamily.org","threadId":"16259","inReplyTo":null,"subject":"[PATCH 1/9 v4] bisect: add \"git bisect replace\" subcommand","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-11-11T05:39:04Z","receivedAt":"2008-11-11T05:39:04Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This subcommand should be used when you have a branch or a part of a\nbranch that isn't easily bisectable because of a bug that has been\nfixed latter.\n\nWe suppose that a bug as been introduced at some point, say A, and\nthat it has been fixed latter at another point, say B, but that\nbetween these points the code is not easily testable because of the\nbug, 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 commits 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 a branch will be created that points to commit Yn and that has a\nspecial name like: \"bisect-replace-B\"\n\nWhen bisecting, the branch names will be scanned and each branch named\n\"bisect-replace-X\" and pointing to commit Y will be grafted so that\nX will only have Y as parent.\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\nAs the branches created by \"git bisect replace\" can be shared between\ndevelopers, this feature might be especially usefull on big projects\nwhere many people often bisect the same code base.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin-rev-list.c |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++-\n git-bisect.sh      |   37 +++++++++++++++++++++++++-\n 2 files changed, 105 insertions(+), 3 deletions(-)\n\n\tChanges since the previous series (v3) are the following:\n\n\t- move 2 lines of code in patch 1, \n\t- added tests in patch 7,\n\t- added --no-replace option (patches 8 and 9) \n\n\tI still wonder about the following:\n\n\t- perhaps \"git bisect replace\" should have a \"NAME\" argument\n\tso that the branch names could be like \"bisect-replace-X-NAME\"\n\twhich could be more descriptive,\n\t- maybe a way to check that the replace branches all point to\n\texisting commits would be useful,\n\t- perhaps bisect log/replay could be improved to handle\n\treplace branches\n\n\tBut I think it's already possible to do many things in the\n\tcurrent state, especially by using \"git branch -m\" (to rename\n\tbranches). For example to give a more explicit name:\n\n\t$ git branch -m bisect-replace-X bisect-replace-X-explicit-name\n\n\tand to not replace a branch any more (but keep it in case you may\n\tuse it again latter):\n\n\t$ git branch -m bisect-replace-Y bisect-do-not-replace-Y\n\n\t...\n\n\tSo as I don't want to over-engineer this and I am a bit lazy too,\n\tI will wait for some comments. Thanks in advance for them!\n\ndiff --git a/builtin-rev-list.c b/builtin-rev-list.c\nindex 06cdeb7..c0717f6 100644\n--- a/builtin-rev-list.c\n+++ b/builtin-rev-list.c\n@@ -574,6 +574,72 @@ static struct commit_list *find_bisection(struct commit_list *list,\n \treturn best;\n }\n \n+static void replace_parents(struct commit *commit,\n+\t\t\t    const char *refname,\n+\t\t\t    const unsigned char *sha1)\n+{\n+\tstruct commit *new_parent = lookup_commit(sha1);\n+\tif (!new_parent) {\n+\t\twarning(\"branch '%s' points to unknown commit '%s'\",\n+\t\t\trefname, sha1_to_hex(sha1));\n+\t\treturn;\n+\t}\n+\n+\tfree_commit_list(commit->parents);\n+\tcommit->parents = NULL;\n+\tcommit_list_insert(new_parent, &commit->parents);\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+\tunsigned char child[20];\n+\tstruct object *obj;\n+\tstruct commit_graft *graft;\n+\n+\tif (prefixcmp(refname, \"bisect-replace-\"))\n+\t\treturn 0;\n+\n+\tif (get_sha1_hex(refname + 15, child)) {\n+\t\twarning(\"bad sha1 in branch name '%s'\", refname);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Check if child commit exist and is already parsed */\n+\n+\tobj = lookup_object(child);\n+\tif (obj) {\n+\t\tstruct commit *commit;\n+\t\tif (obj->type != OBJ_COMMIT) {\n+\t\t\twarning(\"branch name '%s' refers to non commit '%s'\",\n+\t\t\t\trefname, refname + 15);\n+\t\t\treturn 0;\n+\t\t}\n+\t\tcommit = (struct commit *) obj;\n+\t\tif (commit->object.parsed) {\n+\t\t\treplace_parents(commit, refname, sha1);\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\t/* Create a graft to replace child commit parents */\n+\n+\tgraft = xmalloc(sizeof(*graft) + 20);\n+\n+\thashcpy(graft->sha1, child);\n+\tgraft->nr_parent = 1;\n+\thashcpy(graft->parent[0], sha1);\n+\n+\tregister_commit_graft(graft, 1);\n+\n+\treturn 0;\n+}\n+\n+static void bisect_replace_all(void)\n+{\n+\tfor_each_branch_ref(bisect_replace, NULL);\n+}\n+\n int cmd_rev_list(int argc, const char **argv, const char *prefix)\n {\n \tstruct commit_list *list;\n@@ -646,8 +712,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\tbisect_replace_all();\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..b0139d5 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|replace|run]'\n LONG_USAGE='git bisect help\n         print this long help message.\n git bisect start [<bad> [<good>...]] [--] [<pathspec>...]\n@@ -21,6 +21,8 @@ git bisect replay <logfile>\n         replay bisection log.\n git bisect log\n         show bisect log.\n+git bisect replace <rev> [<rev>]\n+        use another branch for bisection.\n git bisect run <cmd>...\n         use <cmd>... to automatically bisect.\n \n@@ -566,6 +568,36 @@ bisect_replay () {\n \tbisect_auto_next\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+    # Create branch for the target commit\n+    tgt_branch=\"bisect-replace-$src_commit\"\n+    git branch \"$tgt_branch\" \"$tgt_commit\"\n+}\n+\n bisect_run () {\n     bisect_next_check fail\n \n@@ -618,7 +650,6 @@ bisect_run () {\n     done\n }\n \n-\n case \"$#\" in\n 0)\n     usage ;;\n@@ -643,6 +674,8 @@ case \"$#\" in\n \tbisect_replay \"$@\" ;;\n     log)\n \tcat \"$GIT_DIR/BISECT_LOG\" ;;\n+    replace)\n+        bisect_replace \"$@\" ;;\n     run)\n         bisect_run \"$@\" ;;\n     *)\n-- \n1.6.0.3.614.g0f3b9\n"},{"id":"95504","messageId":"7v8wrpyhhs.fsf@gitster.siamese.dyndns.org","threadId":"16259","inReplyTo":"20081111063904.7da4df94.chriscool@tuxfamily.org","subject":"Re: [PATCH 1/9 v4] bisect: add \"git bisect replace\" subcommand","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-11-11T23:23:27Z","receivedAt":"2008-11-11T23:23:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <chriscool@tuxfamily.org> writes:\n\n> This subcommand should be used when you have a branch or a part of a\n> branch that isn't easily bisectable because of a bug that has been\n> fixed latter.\n\nWhile I acknowledge your effort to make bisect easier to use, I do\nnot think this is going in the right direction, from the point of view of\nthe workflow.\n\nI do agree that the issue it tries to solve is a problem in real life.\nWhen you want to hunt for a bug, it is certainly possible that your tests\nfail for a bug that is unrelated to what you are hunting for for a range\nof commits.  Borrowing from your picture:\n\n    ...--O--A--X1--X2--...--Xn--B--...\n\nnon of the commit marked as Xi may not be testable.\n\nBut at that point, will you really spend time to rebuild history between A\nand B by fixing an unrelated bug that hinders your bisect, so that you can\nhave a parallel history that is bisectable?  I doubt anybody would.\n\nEven if we assume that somebody wants to adopt the workflow to first fix\nan unrelated bug (that may be totally uninteresting for the purpose of\nsolving the original issue he set out to figure out) to rewrite the\nhistory, what he first needs to do is to find out what part of the history\nto rewrite.  IOW, he needs to know A and B (and in general, the history is\nnot even linear).  Maybe he guesses what A and B is.  But for one thing,\nafter making the guess, he would certainly test A and B to see if the\noriginal issue exists at these commits.  The sequence of commits Xi become\nirrelevant if A turns out to be bad or B turns out to be good.\n\nAnd if A is good and B is bad, then the _original bug_ is in the very\nsequence of Xi you are going to rewrite.  By the time you made a rewritten\nhistory with sequence of commits Yi to be grafted like this:\n\n\n         C--Y1--Y2--...--Yn\n       /\n ...--O--A--X1--X2--...--Xn--B--...\n\nto make it bisectable, it is very likely that you would have already seen\nthe original bug.\n\nIn such a case where you need to figure out what an unrelated bug is, and\nwhich commit A and B are involved while bisecting, I think you are much\nbetter off using bisect skip, as Johannes mentioned earlier.\n\nOn the other hand, if you already have a well-known bug that was\nintroduced at A whose fix at B is also very well-known, you would not even\nneed a separate \"bisect replace\" command nor replace_parents() machinery\nonly for the purpose of bisection, would you?  In such a case I think you\ncan just use a usual graft.\n\n\nI have a separate idea make 'grafts' easier on object transfer, that is\nsomewhat related to this one, by the way.  Instead of making the grafts\ncompletely a local matter as we do now, we can reserve refs/replace/\nnamespace, and record a new commit object to replace an existing commit\nwhose object name is $sha1 as refs/replace/$sha1.  We make almost all the\ncommands except object enumeration (fsck, receive-pack, send-pack, prune,\netc.  Roughly speaking, anything that involves \"rev-list --objects\") honor\nthis commit replacement, so that any time you ask for commit $sha1, the\nobject layer gives you the replacement commit object back.  In this way,\nyou can clone or fetch from such a repository (along with refs in\nrefs/replace/ hierarchy) and fsck/prune won't lose the original parents\n(because it does not see replacements).  Things like paranoid update hook\nneeds to become very careful about refs/replace/ for security reasons, but\nI think this would make the grafts much easier to use.\n"},{"id":"95562","messageId":"200811121515.48277.chriscool@tuxfamily.org","threadId":"16259","inReplyTo":"7v8wrpyhhs.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 1/9 v4] bisect: add \"git bisect replace\" subcommand","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-11-12T14:15:47Z","receivedAt":"2008-11-12T14:15:47Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Le mercredi 12 novembre 2008, Junio C Hamano a écrit :\n> Christian Couder <chriscool@tuxfamily.org> writes:\n> > This subcommand should be used when you have a branch or a part of a\n> > branch that isn't easily bisectable because of a bug that has been\n> > fixed latter.\n>\n> While I acknowledge your effort to make bisect easier to use, I do\n> not think this is going in the right direction, from the point of view of\n> the workflow.\n>\n> I do agree that the issue it tries to solve is a problem in real life.\n> When you want to hunt for a bug, it is certainly possible that your tests\n> fail for a bug that is unrelated to what you are hunting for for a range\n> of commits.  Borrowing from your picture:\n>\n>     ...--O--A--X1--X2--...--Xn--B--...\n>\n> non of the commit marked as Xi may not be testable.\n>\n> But at that point, will you really spend time to rebuild history between\n> A and B by fixing an unrelated bug that hinders your bisect, so that you\n> can have a parallel history that is bisectable?  I doubt anybody would.\n\nI think kernel developers and perhaps others do that somehow. I mean, there \nis the following text in the git-bisect(1) documentation:\n\n\"\nYou may often find that during bisect you want to have near-constant tweaks \n(e.g., s/#define DEBUG 0/#define DEBUG 1/ in a header file, or \"revision \nthat does not have this commit needs this patch applied to work around \nother problem this bisection is not interested in\") applied to the revision \nbeing tested.\n\nTo cope with such a situation, after the inner git-bisect finds the next \nrevision to test, with the \"run\" script, you can apply that tweak before \ncompiling, run the real test, and after the test decides if the revision \n(possibly with the needed tweaks) passed the test, rewind the tree to the \npristine state. Finally the \"run\" script can exit with the status of the \nreal test to let the \"git bisect run\" command loop to determine the \noutcome.\n\"\n\nSo we suggest that people patch at bisect time in case of problems. But I \nthink creating a parallel branch should be better in the long run, because \nyou can easily keep the work you did to make things easier to bisect and \nyou can easily share it with other people working with you. Also using \"git \nrebase -i\" to create the fixed branch might be easier and more reliable \nthan trying to patch at each step.\n\nOf course it also depends on how often people use \"git bisect\", but it seems \nthat there are people out there bisecting very frequently and that these \npeople care very much about bisectability of the tree.\n\n> Even if we assume that somebody wants to adopt the workflow to first fix\n> an unrelated bug (that may be totally uninteresting for the purpose of\n> solving the original issue he set out to figure out) to rewrite the\n> history, what he first needs to do is to find out what part of the\n> history to rewrite.\n\nNot necessarily. People may decide to adopt a workflow that consists in \ncreating a fixed branch as soon as they know about a fix that may prevent \ntheir code from being tested. This way they know that they will be able to \nbisect at each commit of their full history.\n\n> IOW, he needs to know A and B (and in general, the \n> history is not even linear).  Maybe he guesses what A and B is.  But for\n> one thing, after making the guess, he would certainly test A and B to see\n> if the original issue exists at these commits.  The sequence of commits\n> Xi become irrelevant if A turns out to be bad or B turns out to be good.\n\nYes that's possible. But in some cases people might find it simpler (for \nexample because it might take a long time or a lot of manpower to fully \ntest one commit) to just create a fixed branch as soon as they find \nsomething that prevents testing which might happen during a bisection or \nnot.\n\n> And if A is good and B is bad, then the _original bug_ is in the very\n> sequence of Xi you are going to rewrite.  By the time you made a\n> rewritten history with sequence of commits Yi to be grafted like this:\n>\n>\n>          C--Y1--Y2--...--Yn\n>        /\n>  ...--O--A--X1--X2--...--Xn--B--...\n>\n> to make it bisectable, it is very likely that you would have already seen\n> the original bug.\n\nI am not sure I understand/agree with that, because I think it may be quite \neasy to make such a fixed branch, especially if the commit message of B is \na good one like \"fix build problem on platform 'foo' introduced by A\".\n\n> In such a case where you need to figure out what an unrelated bug is, and\n> which commit A and B are involved while bisecting, I think you are much\n> better off using bisect skip, as Johannes mentioned earlier.\n\nEven if there was a bisect skip command that could skip a range of commit, \nyou might find in the end that the original bug you are looking for was \nintroduced in a range you skipped.\n\n> On the other hand, if you already have a well-known bug that was\n> introduced at A whose fix at B is also very well-known, you would not\n> even need a separate \"bisect replace\" command nor replace_parents()\n> machinery only for the purpose of bisection, would you?  In such a case I\n> think you can just use a usual graft.\n\nI don't know very much usual grafts but I think that the problem is that \nusual grafts rewrite history for (nearly) all the commands.\n\nIt seems to me that with usual grafts for this purpose, people may for \nexample have problems refering to some commits, because it might happen \nthat the sha1 of a commit might be in a branch that has been grafted out \nthe current branch for easier bisecting.\n\nFor example in my patch series, the 2 last patches add a --no-replace option \nto \"git bisect\", so that it's easy not to use \"bisect-replace\" branches if \none does not want too. And I fear that if graft use is generalized, it may \nbe necessary to add such options to many other commands (instead of just \none). And even then, people may want to use some of the grafts but not \nothers (for example grafts to see some very old commits imported after the \ninitial repo was created but not grafts to fix history) for some purposes \nand a different set (for example all the grafts) for other purposes (like \nbisecting).\n\n> I have a separate idea make 'grafts' easier on object transfer, that is\n> somewhat related to this one, by the way.  Instead of making the grafts\n> completely a local matter as we do now, we can reserve refs/replace/\n> namespace, and record a new commit object to replace an existing commit\n> whose object name is $sha1 as refs/replace/$sha1.  We make almost all the\n> commands except object enumeration (fsck, receive-pack, send-pack, prune,\n> etc.  Roughly speaking, anything that involves \"rev-list --objects\")\n> honor this commit replacement, so that any time you ask for commit $sha1,\n> the object layer gives you the replacement commit object back.  In this\n> way, you can clone or fetch from such a repository (along with refs in\n> refs/replace/ hierarchy) and fsck/prune won't lose the original parents\n> (because it does not see replacements).  Things like paranoid update hook\n> needs to become very careful about refs/replace/ for security reasons,\n> but I think this would make the grafts much easier to use.\n\nI agree that it would make grafts much easier to use (and would be very \nsecurity sensitive).\n\nBut except for grafts used to connect to old histories, do you know many \nspecial commands other than \"git bisect\" that may use the refs/replace/ \nnamespace?\n\nI mean, it may be a good idea to use a special namespace with sha1 named \nrefs like \"refs/xxx/$sha1\" instead of branches named \nlike \"bisect-replace-SHA1\", but I think that it would be better if grafts \nused to fix history for bisecting purpose would be separated from other \nkind of grafts, for example perhaps in \"refs/replace/bisect/$sha1\".\n\nRegards,\nChristian.\n"},{"id":"95674","messageId":"7v63mshsb7.fsf@gitster.siamese.dyndns.org","threadId":"16259","inReplyTo":"200811121515.48277.chriscool@tuxfamily.org","subject":"Re: [PATCH 1/9 v4] bisect: add \"git bisect replace\" subcommand","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-11-13T09:46:20Z","receivedAt":"2008-11-13T09:46:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <chriscool@tuxfamily.org> writes:\n\n> Le mercredi 12 novembre 2008, Junio C Hamano a écrit :\n> ...\n>> When you want to hunt for a bug, it is certainly possible that your tests\n>> fail for a bug that is unrelated to what you are hunting for for a range\n>> of commits.  Borrowing from your picture:\n>>\n>>     ...--O--A--X1--X2--...--Xn--B--...\n>>\n>> non of the commit marked as Xi may not be testable.\n>>\n>> But at that point, will you really spend time to rebuild history between\n>> A and B by fixing an unrelated bug that hinders your bisect, so that you\n>> can have a parallel history that is bisectable?  I doubt anybody would.\n>\n> I think kernel developers and perhaps others do that somehow. I mean, there \n> is the following text in the git-bisect(1) documentation:\n>\n> \"\n> You may often find that during bisect you want to have near-constant tweaks \n> (e.g., s/#define DEBUG 0/#define DEBUG 1/ in a header file, or \"revision \n> that does not have this commit needs this patch applied to work around \n> other problem this bisection is not interested in\") applied to the revision \n> being tested.\n>\n> To cope with such a situation, after the inner git-bisect finds the next \n> revision to test, with the \"run\" script, you can apply that tweak before \n> compiling,...\n> \"\n>\n> So we suggest that people patch at bisect time in case of problems. But I \n> think creating a parallel branch should be better in the long run, because \n> you can easily keep the work you did to make things easier to bisect and \n> you can easily share it with other people working with you.\n\nI strongly disagree.\n\nMaybe you hit X2 which does have a breakage, and you would need to patch\nup that one before being able to test for your bug, but after you say good\nor bad on that one, the next pick will be far away from that Xi segment.\nYou will test many more revisions before you come back to X3 or X5.  Why\nshould we force the users to fix all the commits in the segment \"just in\ncase\" somebody's bisect falls into the range before that actually happens?\n\nIn other words, unless the breakage you are hunting for exists between\npoint A and B that you cannot bisect for that other breakage, you won't\nneed to patch-up _every single revision_ in the range for the breakage.\nDoing so beforehand is wasteful.\n\nAnd if you know the range of A..B and the fix, the procedure to follow the\nsuggestion you quoted above from the doc can even be automated relatively\neasily.  Your \"run\" script would need to do two merge-base to see if the\nversion to be tested falls inside the range, and if so apply the known fix\nbefore testing (and clean it up afterwards).\n\nCome to think of it, you do not even need to have a custom run script.\nHow about an approach illustrated by this patch?\n\nI think it also needs to call unapply_fixup when \"bisect reset\" is given\nto clean up, but this is more about a possible approach and not about a\nadding a polished and finished shiny new toy, so...\n\n-- >8 --\nbisect: use canned \"fixup patch\"\n\nThis allows you to have $GIT_DIR/bisect-fixup directory, populated with\n\"fixup\" patch files.  When revisions between A and B (inclusive) cannot be\ntested for your bisection purpose because they have other unrelated\nbreakage whose fix is already known, you can store a fix-up patch in the\nfile whose name is A-B (the commit object name of A, a dash, then the\ncommit object name of B).  When \"git bisect\" suggests you to test a\nrevision that falls in that range, the patch will automatically be\napplied to the working tree, so that you can test with the known fix\nalready in place.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n git-bisect.sh           |   36 ++++++++++++++++++++++++++\n t/t6035-bisect-fixup.sh |   64 +++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 100 insertions(+), 0 deletions(-)\n\ndiff --git c/git-bisect.sh w/git-bisect.sh\nindex 0d0e278..600d9aa 100755\n--- c/git-bisect.sh\n+++ w/git-bisect.sh\n@@ -338,13 +338,48 @@ exit_if_skipped_commits () {\n \tfi\n }\n \n+apply_fixup() {\n+\t>\"$GIT_DIR/BISECT_FIXUP\"\n+\t(\n+\t\tcd \"$GIT_DIR\" 2>/dev/null &&\n+\t\tfind bisect-fixup -type f -print\n+\t) |\n+\twhile read _fixup\n+\tdo\n+\t\t_btm=$(expr \"$_fixup\" : 'bisect-fixup/\\([0-9a-f]*\\)-[0-9a-f]*$') &&\n+\t\t_btm=$(git rev-parse --quiet --verify \"$_btm\" 2>/dev/null) &&\n+\t\t_top=$(expr \"$_fixup\" : 'bisect-fixup/[0-9a-f]*-\\([0-9a-f]*\\)$') &&\n+\t\t_top=$(git rev-parse --quiet --verify \"$_top\" 2>/dev/null) ||\n+\t\tcontinue\n+\t\tif\ttest \"z$(git merge-base $_btm \"$1\")\" = z$_btm &&\n+\t\t\ttest \"z$(git merge-base \"$1\" $_top)\" = \"z$1\"\n+\t\tthen\n+\t\t\techo \"Applying $_fixup...\"\n+\t\t\tgit apply \"$GIT_DIR/$_fixup\" || exit 1\n+\t\t\techo >>\"$GIT_DIR/BISECT_FIXUP\" \"$_fixup\"\n+\t\tfi\n+\tdone\n+}\n+\n+unapply_fixup() {\n+\ttest -r \"$GIT_DIR/BISECT_FIXUP\" || return 0\n+\t@@PERL@@ -e \"print reverse <>\" \"$GIT_DIR/BISECT_FIXUP\" |\n+\twhile read _fixup\n+\tdo\n+\t\techo \"Unapplying $_fixup...\"\n+\t\tgit apply -R \"$GIT_DIR/$_fixup\" || exit\n+\tdone\n+}\n+\n bisect_checkout() {\n+\tunapply_fixup || exit ;# should not happen but try to be careful\n \t_rev=\"$1\"\n \t_msg=\"$2\"\n \techo \"Bisecting: $_msg\"\n \tmark_expected_rev \"$_rev\"\n \tgit checkout -q \"$_rev\" || exit\n \tgit show-branch \"$_rev\"\n+\tapply_fixup \"$_rev\" || exit\n }\n \n is_among() {\n@@ -532,6 +567,7 @@ bisect_clean_state() {\n \tdo\n \t\tgit update-ref -d $ref $hash || exit\n \tdone\n+\trm -f \"$GIT_DIR/BISECT_FIXUP\" &&\n \trm -f \"$GIT_DIR/BISECT_EXPECTED_REV\" &&\n \trm -f \"$GIT_DIR/BISECT_ANCESTORS_OK\" &&\n \trm -f \"$GIT_DIR/BISECT_LOG\" &&\ndiff --git c/t/t6035-bisect-fixup.sh w/t/t6035-bisect-fixup.sh\nnew file mode 100755\nindex 0000000..4745b73\n--- /dev/null\n+++ w/t/t6035-bisect-fixup.sh\n@@ -0,0 +1,64 @@\n+#!/bin/sh\n+# Copyright (c) 2008, Junio C Hamano\n+\n+test_description='bisect fixup'\n+\n+. ./test-lib.sh\n+\n+cat >test-fixup <<\\EOF\n+diff a/elif b/elif\n+--- a/elif\n++++ b/elif\n+@@ -1 +1 @@\n+-0\n++Z\n+EOF\n+\n+test_expect_success setup '\n+\techo 0 >elif\n+\tgit add elif\n+\tfor i in 1 2 3 4 5 6 7 8 9\n+\tdo\n+\t\ttest_tick &&\n+\t\techo $i >file &&\n+\t\tgit add file &&\n+\t\tgit commit -m $i &&\n+\t\tgit tag t$i\n+\tdone &&\n+\n+\tmkdir \".git/bisect-fixup\" &&\n+\n+\tbtm=$(git rev-parse --short t3) &&\n+\ttop=$(git rev-parse --short t5) &&\n+\tcat test-fixup >\".git/bisect-fixup/$btm-$top\" &&\n+\n+\tbtm=$(git rev-parse --short t7) &&\n+\ttop=$(git rev-parse --short t8) &&\n+\tsed -e \"s|Z|A|\" test-fixup >\".git/bisect-fixup/$btm-$top\"\n+'\n+\n+test_expect_success 'bisect fixup' '\n+\tt1=$(git rev-parse t1) &&\n+\tt5=$(git rev-parse t5) &&\n+\tt6=$(git rev-parse t6) &&\n+\tt7=$(git rev-parse t7) &&\n+\tt9=$(git rev-parse t9) &&\n+\n+\tgit bisect start &&\n+\ttest $(git rev-parse HEAD) = $t9 &&\n+\tgit bisect bad t9 &&\n+\ttest $(git rev-parse HEAD) = $t9 &&\n+\tgit bisect good t1 &&\n+\ttest $(git rev-parse HEAD) = $t5 &&\n+\tgrep Z elif &&\n+\n+\tgit bisect good &&\n+\ttest $(git rev-parse HEAD) = $t7 &&\n+\tgrep A elif &&\n+\n+\tgit bisect bad &&\n+\ttest $(git rev-parse HEAD) = $t6 &&\n+\tgrep 0 elif\n+'\n+\n+test_done\n"},{"id":"95695","messageId":"491C58A3.2000609@gnu.org","threadId":"16259","inReplyTo":"200811121515.48277.chriscool@tuxfamily.org","subject":"Re: [PATCH 1/9 v4] bisect: add \"git bisect replace\" subcommand","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2008-11-13T16:41:07Z","receivedAt":"2008-11-13T16:41:07Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"\n> Of course it also depends on how often people use \"git bisect\", but it seems \n> that there are people out there bisecting very frequently and that these \n> people care very much about bisectability of the tree.\n\nWhat about \"git bisect cherry-pick COMMIT\" which would do a \"cherry-pick\n-n\" of COMMIT after every bisection unless COMMIT is in the ancestry of\nthe current revision?  So if you have to bisect between A and B, and you\nknow that a bug present between A and B was fixed by C, you could do\n\n  git bisect good A\n  git bisect bad B\n  git bisect cherry-pick C\n\nThis would subsume Junio's proposal: users could also set up a few\nspecial bisect/set-debug-to-1, bisect/remove-cflags-o2 and so on patches\nthat you could use for purposes other than ensuring known bugs are fixed.\n\nFinally, you could have a [bisect] configuration section with entries\nlike \"cherry-pick = BROKEN-SHA1 FIX-SHA1\" and \"git bisect\" would apply\nFIX-SHA1 automatically if the bisect tip were in BROKEN-SHA1..FIX-SHA1.\n\n>> Things like paranoid update hook\n>> needs to become very careful about refs/replace/ for security reasons,\n>> but I think this would make the grafts much easier to use.\n> \n> I agree that it would make grafts much easier to use (and would be very \n> security sensitive).\n\nNot so much.  People with public servers could create refs/replace in\nthe server and give it 400 permissions, and/or git would refuse to\ncreate the refs/replace directory, forcing users to create it manually\nunless it is already in the server.\n\nPaolo\n"},{"id":"95704","messageId":"200811131850.40951.chriscool@tuxfamily.org","threadId":"16259","inReplyTo":"7v63mshsb7.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 1/9 v4] bisect: add \"git bisect replace\" subcommand","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-11-13T17:50:40Z","receivedAt":"2008-11-13T17:50:40Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Le jeudi 13 novembre 2008, Junio C Hamano a écrit :\n> Christian Couder <chriscool@tuxfamily.org> writes:\n> > Le mercredi 12 novembre 2008, Junio C Hamano a écrit :\n> > ...\n> >\n> >> When you want to hunt for a bug, it is certainly possible that your\n> >> tests fail for a bug that is unrelated to what you are hunting for for\n> >> a range of commits.  Borrowing from your picture:\n> >>\n> >>     ...--O--A--X1--X2--...--Xn--B--...\n> >>\n> >> non of the commit marked as Xi may not be testable.\n> >>\n> >> But at that point, will you really spend time to rebuild history\n> >> between A and B by fixing an unrelated bug that hinders your bisect,\n> >> so that you can have a parallel history that is bisectable?  I doubt\n> >> anybody would.\n> >\n> > I think kernel developers and perhaps others do that somehow. I mean,\n> > there is the following text in the git-bisect(1) documentation:\n> >\n> > \"\n> > You may often find that during bisect you want to have near-constant\n> > tweaks (e.g., s/#define DEBUG 0/#define DEBUG 1/ in a header file, or\n> > \"revision that does not have this commit needs this patch applied to\n> > work around other problem this bisection is not interested in\") applied\n> > to the revision being tested.\n> >\n> > To cope with such a situation, after the inner git-bisect finds the\n> > next revision to test, with the \"run\" script, you can apply that tweak\n> > before compiling,...\n> > \"\n> >\n> > So we suggest that people patch at bisect time in case of problems. But\n> > I think creating a parallel branch should be better in the long run,\n> > because you can easily keep the work you did to make things easier to\n> > bisect and you can easily share it with other people working with you.\n>\n> I strongly disagree.\n>\n> Maybe you hit X2 which does have a breakage, and you would need to patch\n> up that one before being able to test for your bug, but after you say\n> good or bad on that one, the next pick will be far away from that Xi\n> segment. You will test many more revisions before you come back to X3 or\n> X5.  Why should we force the users to fix all the commits in the segment\n> \"just in case\" somebody's bisect falls into the range before that\n> actually happens?\n\nThe users would not be _forced_ at all to use \"git bisect replace\", they can \nignore it if they want. And even if other coworkers use it, they are not \nforced at all to use it themself. If they get none of \nthe \"bisect-replace-*\" branches, the behavior of git bisect will not change \nat all.\n\n> In other words, unless the breakage you are hunting for exists between\n> point A and B that you cannot bisect for that other breakage, you won't\n> need to patch-up _every single revision_ in the range for the breakage.\n> Doing so beforehand is wasteful.\n\nI think that it depends on many factors. More precisely, it depends on how \neasy it is to fully test (because to make sure that the bug your are \nbisecting is between A and B you need to test A and B, so you waste some \ntesting) vs how easy it is to patch up every single revision between A and \nB.\n\nAnd I think it can be really easy to patch up every revision between A and \nB, you might need only something like:\n\n$ git checkout -b patch-up B\n$ git rebase -i A^\n\nand then squash the last commit into the first one, in the list \"git \nrebase -i\" gives you. It may even be easy to automate this with code like \nthis (completely untested, and it assumes git rebase -i accept a script \nfrom stdin which may not work right now):\n\ncreate_replace_branch() {\n\t_a=\"$1\"\n\t_b=\"$2\"\n\tgit checkout -b bisect-replace-$_b \"$_b\" || exit\n\tgit rev-list ^\"$_a\"^ \"$_b\" | {\n\t\twhile read sha1\n\t\tdo\n\t\t\tcase $sha1 in\n\t\t\t\t$_a) echo \"pick $_a\"; echo \"squash $_b\" ;;\n\t\t\t\t$_b) ;;\n\t\t\t\t*) echo \"pick $sha1 ;;\n\t\t\tesac\n\t\tdone\n\t} | git rebase -i \"$_a\"^\n}\n\n> And if you know the range of A..B and the fix, the procedure to follow\n> the suggestion you quoted above from the doc can even be automated\n> relatively easily.  Your \"run\" script would need to do two merge-base to\n> see if the version to be tested falls inside the range, and if so apply\n> the known fix before testing (and clean it up afterwards).\n>\n> Come to think of it, you do not even need to have a custom run script.\n> How about an approach illustrated by this patch?\n\nThis is interesting, but the fix up patch might not apply cleanly on all the \ncommits in the range, and there is no simple way to share these patches \n(and changes to them) in a team. Perhaps more importantly, there is also no \nsimple way to look at the result from applying the patch or to manipulate \nit with other git commands.\n\nI mean it was decided to store changes in Git as blob, trees and commits, \nnot patches, so why would we store these changes as patches?\n\nRegards,\nChristian.\n"},{"id":"95773","messageId":"200811141034.06282.chriscool@tuxfamily.org","threadId":"16259","inReplyTo":"491C58A3.2000609@gnu.org","subject":"Re: [PATCH 1/9 v4] bisect: add \"git bisect replace\" subcommand","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-11-14T09:34:05Z","receivedAt":"2008-11-14T09:34:05Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Le jeudi 13 novembre 2008, Paolo Bonzini a écrit :\n> > Of course it also depends on how often people use \"git bisect\", but it\n> > seems that there are people out there bisecting very frequently and\n> > that these people care very much about bisectability of the tree.\n>\n> What about \"git bisect cherry-pick COMMIT\" which would do a \"cherry-pick\n> -n\" of COMMIT after every bisection unless COMMIT is in the ancestry of\n> the current revision?  So if you have to bisect between A and B, and you\n> know that a bug present between A and B was fixed by C, you could do\n>\n>   git bisect good A\n>   git bisect bad B\n>   git bisect cherry-pick C\n>\n> This would subsume Junio's proposal:\n\nYes, it looks better than Junio's, except when there is no existing commit \nthat perfectly works.\n\n> users could also set up a few \n> special bisect/set-debug-to-1, bisect/remove-cflags-o2 and so on patches\n> that you could use for purposes other than ensuring known bugs are fixed.\n\nIn this case it is similar to Junio's proposal. But I think that for changes \nlike set-debug-to-1 and remove-cflags-o2, using the right make command \nshould be enough.\n\n> Finally, you could have a [bisect] configuration section with entries\n> like \"cherry-pick = BROKEN-SHA1 FIX-SHA1\" and \"git bisect\" would apply\n> FIX-SHA1 automatically if the bisect tip were in BROKEN-SHA1..FIX-SHA1.\n\nYes, but how do you share this between members of a team?\n\nYour proposal and Junio's proposal also don't use real sha1 names for \ncommits that are tested, so it's more difficult to talk about them, share \nthem, use them, ...\n\nRegards,\nChristian.\n"},{"id":"95775","messageId":"491D4D02.6080004@gnu.org","threadId":"16259","inReplyTo":"200811141034.06282.chriscool@tuxfamily.org","subject":"Re: [PATCH 1/9 v4] bisect: add \"git bisect replace\" subcommand","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2008-11-14T10:03:46Z","receivedAt":"2008-11-14T10:03:46Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"\n>> users could also set up a few \n>> special bisect/set-debug-to-1, bisect/remove-cflags-o2 and so on patches\n>> that you could use for purposes other than ensuring known bugs are fixed.\n> \n> In this case it is similar to Junio's proposal. But I think that for changes \n> like set-debug-to-1 and remove-cflags-o2, using the right make command \n> should be enough.\n\nYeah, I couldn't think of a better usecase, but you got the idea.\n\n>> Finally, you could have a [bisect] configuration section with entries\n>> like \"cherry-pick = BROKEN-SHA1 FIX-SHA1\" and \"git bisect\" would apply\n>> FIX-SHA1 automatically if the bisect tip were in BROKEN-SHA1..FIX-SHA1.\n> \n> Yes, but how do you share this between members of a team?\n\nThat's a common problem with stuff that goes in .gitconfig.  It does not\nbelong in the repository, though...\n\nPaolo\n"},{"id":"95881","messageId":"200811151519.27426.chriscool@tuxfamily.org","threadId":"16259","inReplyTo":"491D4D02.6080004@gnu.org","subject":"Re: [PATCH 1/9 v4] bisect: add \"git bisect replace\" subcommand","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-11-15T14:19:27Z","receivedAt":"2008-11-15T14:19:27Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Le vendredi 14 novembre 2008, Paolo Bonzini a écrit :\n> >> users could also set up a few\n> >> special bisect/set-debug-to-1, bisect/remove-cflags-o2 and so on\n> >> patches that you could use for purposes other than ensuring known bugs\n> >> are fixed.\n> >\n> > In this case it is similar to Junio's proposal. But I think that for\n> > changes like set-debug-to-1 and remove-cflags-o2, using the right make\n> > command should be enough.\n>\n> Yeah, I couldn't think of a better usecase, but you got the idea.\n>\n> >> Finally, you could have a [bisect] configuration section with entries\n> >> like \"cherry-pick = BROKEN-SHA1 FIX-SHA1\" and \"git bisect\" would apply\n> >> FIX-SHA1 automatically if the bisect tip were in\n> >> BROKEN-SHA1..FIX-SHA1.\n> >\n> > Yes, but how do you share this between members of a team?\n>\n> That's a common problem with stuff that goes in .gitconfig.  It does not\n> belong in the repository, though...\n\nWhy?\n\nGit encourages people to develop by creating many branches of commits, \nworking on them and sharing them, and that seems to work very well. So I \nreally don't understand why _the hell_ people using bisect could not also \nbenefit of from creating patched up branches, sharing them, bisecting on \nthem.\n\nEspecially as, in my patch series, it does not in _any way_ change anything \nfor people who just don't want to use patched up branches. They just need \nto not download any \"bisect-replace-*\" branch, or we can even implement a \nconfig option \"bisect.useReplaceBranches\" that default to \"no\" if that is \nsuch a big threat to them.\n\nI agree that the name of the branches \"bisect-replace-*\" may not be the best \nor that using special refs in \"refs/replace/\" might be better (except that \nthese refs should have in my opinion a special namespace to be easily \ndistinguished from others), but I don't think _at all_ that this should be \nenough to discard the whole idea (and implementation but that's another \nstory).\n\nOr is there a god command I don't know about that says:\n\nThou shall not use patched up branches to bisect!\nThou shall bisect painfully!\n\nRegards,\nChristian.\n"}]}