{"thread":{"id":"58301","subject":"\"bubbling up\" patches in a commit sequence.","startedAt":"2022-08-13T08:46:09Z","lastAt":"2022-08-15T12:25:57Z","messageCount":3,"participants":["demerphq","Jeff King","Johannes Schindelin"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"461165","messageId":"CANgJU+VYSuEkU+V0WRpsTPv9iPYeDo52MeMHuD7-Yp4JnA60NA@mail.gmail.com","threadId":"58301","inReplyTo":null,"subject":"\"bubbling up\" patches in a commit sequence.","fromName":"demerphq","fromEmail":"demerphq@gmail.com","sentAt":"2022-08-13T08:45:53Z","receivedAt":"2022-08-13T08:46:09Z","isPatch":false,"sender":{"key":"demerphq@gmail.com","avatar":null},"body":"Hi all,\n\nI keep finding myself using interactive rebase to try to find the\nearliest place in a change sequence that a given commit can be placed\nwithout conflicting with any other patch. When I am tired I do this by\nrepeatedly moving the given commit up by one or two lines manually and\nthen letting rebase interactive apply the new ordering, when it\nconflicts I abort and stop and either leave the patch in its new\nposition or more likely use the \"fixup\" option to merge it with the\npatch it conflicts with. Sometimes when I am more awake I try to do a\nbinary search pattern :-), but regardless the process is tedius. I\ncall this \"bubbling up a patch\".\n\nIn general I do this when I want to find a \"fixup\" pair that should be\nmerged together before the PR is pushed, but there are other reasons,\nsometimes a PR contains a number of sub topics which are evolving and\nusing this technique  can help the patches related to different sub\ntopics be grouped together for easier review.\n\nAnybody created tooling to do something like this? Or suggestions on\nhow to approach it efficiently?\n\nFor instance i would love to have tool that could give me a list of\nthe patches in my topic branch with information about which commits\nthey have to be after to not conflict (or some other way to understand\nthe \"conflict properties\" of the commit graph), and a way to move a\ncommit to the earliest position in the patch sequence where it would\nnot commit.\n\nPlease forgive me for not using the correct specialist git jargon for\nthese concepts, if there is any.\n\ncheers,\nYves\n-- \nperl -Mre=debug -e \"/just|another|perl|hacker/\"\n"},{"id":"461183","messageId":"YviZho4/BlRRNWEn@coredump.intra.peff.net","threadId":"58301","inReplyTo":"CANgJU+VYSuEkU+V0WRpsTPv9iPYeDo52MeMHuD7-Yp4JnA60NA@mail.gmail.com","subject":"Re: \"bubbling up\" patches in a commit sequence.","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2022-08-14T06:43:18Z","receivedAt":"2022-08-14T06:43:25Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Aug 13, 2022 at 10:45:53AM +0200, demerphq wrote:\n\n> In general I do this when I want to find a \"fixup\" pair that should be\n> merged together before the PR is pushed, but there are other reasons,\n> sometimes a PR contains a number of sub topics which are evolving and\n> using this technique  can help the patches related to different sub\n> topics be grouped together for easier review.\n> \n> Anybody created tooling to do something like this? Or suggestions on\n> how to approach it efficiently?\n\nI haven't used these myself, but there are some projects that might do\nwhat you want:\n\n   - https://github.com/tummychow/git-absorb\n\n   - https://github.com/torbiak/git-autofixup\n\n> Please forgive me for not using the correct specialist git jargon for\n> these concepts, if there is any.\n\nI think the key term is \"absorb\", but don't feel bad. I didn't remember\nthat either, but only had a vague feeling I had seen something recently.\nI skimmed the \"tools\" section of the last couple issues of Git Rev News\n(thanks, Rev News editors!) which led me to autofixup, which mentioned\n\"absorb\". :)\n\n-Peff\n"},{"id":"461220","messageId":"7o9n6751-2083-155s-02op-o5635o4qr278@tzk.qr","threadId":"58301","inReplyTo":"CANgJU+VYSuEkU+V0WRpsTPv9iPYeDo52MeMHuD7-Yp4JnA60NA@mail.gmail.com","subject":"Re: \"bubbling up\" patches in a commit sequence.","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-08-15T12:25:49Z","receivedAt":"2022-08-15T12:25:57Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Yves,\n\nOn Sat, 13 Aug 2022, demerphq wrote:\n\n> I keep finding myself using interactive rebase to try to find the\n> earliest place in a change sequence that a given commit can be placed\n> without conflicting with any other patch.\n\nI find myself doing that a lot, too. So much so that I wrote shell code to\ndo that for me. The essential idea is to use the diff hunk header of the\nhunk that I want to stage and transmogrify it into the `-L\n<start>,<end>:<path>` parameter of `git log` (and yes, the `sed` call to\ntransmogrify that is a bit hard to read).\n\nThe relevant part of the code looks like this:\n\n-- snip --\nsh_quote () {\n\tfor arg\n\tdo\n\t\techo \"'$(echo \"$arg\" | sed \"s/'/'\\\\''/g\")'\"\n\tdone\n}\n\nstaged_log () { # [--upstream=<ref> | -u <ref>]\n\tupstream=not\\ set\n\twhile case \"$1\" in\n\t--upstream) shift; upstream=\"$1\";;\n\t--upstream=*) upstream=\"${1#*=}\";;\n\t-u) shift; upstream=\"$1\";;\n\t-*) die \"Unknown option: $1\";;\n\t*) break;;\n\tesac; do shift; done\n\n\ttest not\\ set != \"$upstream\" ||\n\tupstream=\"$(git rev-parse @{upstream} 2>/dev/null)\"\n\n\t# look beyond upstream if identical to HEAD\n\ttest -z \"$upstream\" || test 0 != $(git rev-list --count $upstream..) || upstream=\n\tdiff=\"$(git diff --cached -U1)\"\n\tcached_diff=\"$diff\"\n\ttest -n \"$diff\" ||\n\tdiff=\"$(git diff -U1)\"\n\ttest -n \"$diff\" ||\n\tdie \"No changes\"\n\n\targs=\"$(echo \"$diff\" |\n\t\tsed -ne '/^--- a\\//{s/^-* a\\/\\(.*\\)/'\\''\\1'\\''/;x}' -e \\\n\t\t\t'/^@@ -/{s/^@@ -\\([^, ]*\\),\\([^ ]*\\).*/-L \\1,+\\2/;s/^@@ -\\([^,]*\\) .*/-L \\1,+1/;G;s/\\n/:/g;p}' |\n\t\t\ttr '\\n' ' ') ${upstream:+$upstream..} $(sh_quote \"$@\")\"\n\n\teval \"git log $args\"\n\n\trevs=\"$(eval \"git log --pretty=%H --no-patch $args\")\"\n\tcase \"$revs\" in\n\t*[!0-9a-z]*) ;; # multiple revs\n\t'')\n\t\t# not a single rev\n\t\ttest -z \"$upstream\" ||\n\t\tstaged_log -u ''\n\t\t;;\n\t?*)\n\t\tprintf \"Commit (yes/no/edit)? \"\n\t\tread line\n\t\tcase \"$line\" in\n\t\t[Yy]*) git commit --fixup \"$revs\" $(test -n \"$cached_diff\" || echo \"-a\");;\n\t\t[Ee]*) git commit --fixup \"$revs\" $(test -n \"$cached_diff\" || echo \"-a\") -se;;\n\t\tesac\n\t\t;;\n\tesac\n}\n-- snap --\n\nUnfortunately, the `-L <...>` code currently works reliably only for a\nsingle hunk, if I use multiple hunks, I sometimes run into assertions.\n\nTo help with that, the shell code looks at the staged hunk(s), if any.\nOnly if no changes are staged, it falls back to the unstaged diff.\n\nCiao,\nDscho\n"}]}