A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.html 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="fr">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>Git email flow vs Github flow (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f7f7f7">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
  26. <meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
  27. <!-- Documented, feel free to shoot an email. -->
  28. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  29. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  30. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  31. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  32. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  35. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  36. <script>
  37. function toggleTheme(themeName) {
  38. document.documentElement.classList.toggle(
  39. 'forced-dark',
  40. themeName === 'dark'
  41. )
  42. document.documentElement.classList.toggle(
  43. 'forced-light',
  44. themeName === 'light'
  45. )
  46. }
  47. const selectedTheme = localStorage.getItem('theme')
  48. if (selectedTheme !== 'undefined') {
  49. toggleTheme(selectedTheme)
  50. }
  51. </script>
  52. <meta name="robots" content="noindex, nofollow">
  53. <meta content="origin-when-cross-origin" name="referrer">
  54. <!-- Canonical URL for SEO purposes -->
  55. <link rel="canonical" href="https://blog.brixit.nl/git-email-flow-versus-github-flow/">
  56. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  57. <article>
  58. <header>
  59. <h1>Git email flow vs Github flow</h1>
  60. </header>
  61. <nav>
  62. <p class="center">
  63. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  64. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
  65. </svg> Accueil</a> •
  66. <a href="https://blog.brixit.nl/git-email-flow-versus-github-flow/" title="Lien vers le contenu original">Source originale</a>
  67. </p>
  68. </nav>
  69. <hr>
  70. <p>So I've been using the Github flow for some years now from both the maintainer side and contributor side to open source projects. I've also been using the email workflow for git from both sides for about a year now. Using email for git sounded quite horrible before I actually started using it. Now I prefer it so I thought I would document my experience here.</p>
  71. <h2>The Github flow</h2>
  72. <p>This isn't strictly for Github, it's the flow many developers are accustomed to:</p>
  73. <ol>
  74. <li>Fork the project repo</li>
  75. <li>Make a change on your fork</li>
  76. <li>Create a pull request from a branch on your fork to the main repository</li>
  77. <li>Get comments on the pull request</li>
  78. <li>Force-push to the same branch to update the state of the pull request</li>
  79. <li>Somebody clicks merge</li>
  80. </ol>
  81. <p>Basically the same flow is also used on Gitlab and the other smaller git hosting services. This flow works reasonably well. It gets slightly more annoying after the first pull request because you actually have to keep your own local branch up to date.</p>
  82. <p>In theory this also gives some nice discoverability of people working on the project by looking at the forks of the project. In practice this is a bunch of outdated copies of the project by people who have mistaken the fork button for a like button.</p>
  83. <p>From a maintainer point of view this flow also works alright, unless your project starts to grow. For example when postmarketOS was still on Github we ran into the issue that the merge button isn't really useful. Once you have a reasonable volume of pull requests the branches of those pull requests get outdated quickly meaning they have to be rebased before merging or every change will have an extra merge commit in the history.</p>
  84. <p>In the postmarketOS case it was decided that merge commits are extra noise in the git history we'd like to avoid so we'd need to rebase things, and to properly rebase we have to do it from the command line because Github can't deal at all with conflicts. Rebasing from the command line also gives a lot more flexibility with squashing and having a nice commit message.</p>
  85. <p>The only reason that merge button was used on Github was because Github can't seem to mark the pull request as merged if it isn't done by the button.
  86. The all-knowing button from Github</p>
  87. <p>The old workflow documentation postmarketOS had when Github was used can be read in the wiki history: <a href="https://wiki.postmarketos.org/index.php?title=Merge_Workflow&amp;oldid=3441">https://wiki.postmarketos.org/index.php?title=Merge_Workflow&amp;oldid=3441</a></p>
  88. <p>Now we've moved to Gitlab we're basically dealing with the same issue, we have to mess with the commits before merging so we're always force-pushing to the git fork of the author of the pull request (which they have to enable on the merge request, if they don't we first have to tell them to enable that checkbox) and then finally merge them with the button in the web UI so Gitlab doesn't lose track of what happened.</p>
  89. <h2>The git-send-email flow</h2>
  90. <p>The flow for pull requests in github isn't the original way to make pull requests. Since git was originally written for the development of the Linux kernel it has been designed with the workflow of the kernel in mind. The kernel uses mailing lists.</p>
  91. <p>[insert image of horrified developers here]</p>
  92. <p>The first patch I emailed was with the assistence of <a href="https://git-send-email.io/">https://git-send-email.io/</a>, I needed to learn how to use the email flow because at the time I was working on my very first kernel patch. This was quite a daunting task involing triple-checking everything against the <a href="https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html">patch submission documentation</a> for Linux which describes the easy 16 step process.</p>
  93. <p>Then after the final step the email gets sent out and you wait... for response emails.</p>
  94. <p>Since then I've made contributions to projects hosted on Sourcehut, which also uses the email workflow, and now I also maintain some projects on this platform. For example <a href="https://git.sr.ht/~martijnbraam/megapixels">Megapixels</a>.</p>
  95. <p>This is the workflow for submitting a patch to a project using the email flow:</p>
  96. <ol>
  97. <li>Clone the repository locally</li>
  98. <li>Make your changes on your local checkout</li>
  99. <li>Run git send-email with a ref pointing to one or a range of commits</li>
  100. <li>Get comments as response to the patch as emails, mirrored on the webpage of the mailing list</li>
  101. <li>Fix up your previous mistakes, run git send-email again with the -v2 argument to send an updated version</li>
  102. <li>The maintainer applies the patch from the email.</li>
  103. </ol>
  104. <p>As a maintainer getting the patches like this is quite nice since unless there's a conflict you don't have to merge branches or rebase things, the patches is just ... a patch, it only has the changes from the author, not the full git history.</p>
  105. <p>Also, one thing to note about the process above is that, except for receiving the feedback, it will never touch your mail client. Git does SMTP itself and make sure the emails you send out are up-to-spec so maintainers can apply the changes directly by feeding the email into git am</p>
  106. <p>If your main complaint is that email is horrible to work with, the issue is most likely not email, it's probably your mail client.</p>
  107. <p>One of the other main issues with the email workflow is that you can't just see the full state of the "pull request" because there's no nice pull request page to see what's happening. This is one of the main reasons I like the mailing lists on Sourcehut, the patch view fixes most of the visibility issues, for example this simple patch: <a href="https://lists.sr.ht/~martijnbraam/public-inbox/patches/14382">https://lists.sr.ht/~martijnbraam/public-inbox/patches/14382</a>
  108. The overview of a patch submitted to a Sourcehut mailing list</p>
  109. <p>There you see the patch description in the first block, which is in this case didn't have any extra text added in the git send-email stage, so it only shows a summary of the changes in this patch.</p>
  110. <p>Below that is the actual patch, with the subject of the patch as header and then showing the full commit message below that if there were more lines and then the full diff. This patch can also be exported directly as a .patch file using the link right of the subject.</p>
  111. <p>Finally, below the diff is a comment from Eyal who applied this patch to the development branch and thanked the author; the mailing list will generate a nice threaded view here if there's more discussion.</p>
  112. <p>The block on the right will show the status of the patch, APPLIED in this case and gives some extra tools to get a copy of the full patchset that can be applied using git am</p>
  113. <h2>Conclusion</h2>
  114. <p>I personally prefer the e-mail workflow now, it saves me from keeping branches/forks up to date as with this workflow only diffs are sent around. Also after working in Gitlab for most of the things I do on postmarketOS I really like how quickly sourcehut pages load and that I just can get all info from the patch without clicking on tabs to switch between comments, diffs and commit messages with loading times in between.</p>
  115. <p>Also one nice improvement is that instead of doing half the maintainer flow in the browser by clicking things and half by patching stuff up in my local git branch and force pushing that, it just lets me do everything in the shell and then just send an email back telling the author their patch got merged.</p>
  116. <p>All together people are most likely already used to having all the comments and info emailed to them as notifications, it's just that in the gitlab/hub case it will send you a link to continue on their website and in the sourcehut/email flow case the email is everything you need to continue without ever opening the browser.</p>
  117. </article>
  118. <hr>
  119. <footer>
  120. <p>
  121. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  122. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
  123. </svg> Accueil</a> •
  124. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  125. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-rss2"></use>
  126. </svg> Suivre</a> •
  127. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  128. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-user-tie"></use>
  129. </svg> Pro</a> •
  130. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  131. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-mail"></use>
  132. </svg> Email</a> •
  133. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  134. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-hammer2"></use>
  135. </svg> Légal</abbr>
  136. </p>
  137. <template id="theme-selector">
  138. <form>
  139. <fieldset>
  140. <legend><svg class="icon icon-brightness-contrast">
  141. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-brightness-contrast"></use>
  142. </svg> Thème</legend>
  143. <label>
  144. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  145. </label>
  146. <label>
  147. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  148. </label>
  149. <label>
  150. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  151. </label>
  152. </fieldset>
  153. </form>
  154. </template>
  155. </footer>
  156. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  157. <script>
  158. function loadThemeForm(templateName) {
  159. const themeSelectorTemplate = document.querySelector(templateName)
  160. const form = themeSelectorTemplate.content.firstElementChild
  161. themeSelectorTemplate.replaceWith(form)
  162. form.addEventListener('change', (e) => {
  163. const chosenColorScheme = e.target.value
  164. localStorage.setItem('theme', chosenColorScheme)
  165. toggleTheme(chosenColorScheme)
  166. })
  167. const selectedTheme = localStorage.getItem('theme')
  168. if (selectedTheme && selectedTheme !== 'undefined') {
  169. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  170. }
  171. }
  172. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  173. window.addEventListener('load', () => {
  174. let hasDarkRules = false
  175. for (const styleSheet of Array.from(document.styleSheets)) {
  176. let mediaRules = []
  177. for (const cssRule of styleSheet.cssRules) {
  178. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  179. continue
  180. }
  181. // WARNING: Safari does not have/supports `conditionText`.
  182. if (cssRule.conditionText) {
  183. if (cssRule.conditionText !== prefersColorSchemeDark) {
  184. continue
  185. }
  186. } else {
  187. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  188. continue
  189. }
  190. }
  191. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  192. }
  193. // WARNING: do not try to insert a Rule to a styleSheet you are
  194. // currently iterating on, otherwise the browser will be stuck
  195. // in a infinite loop…
  196. for (const mediaRule of mediaRules) {
  197. styleSheet.insertRule(mediaRule.cssText)
  198. hasDarkRules = true
  199. }
  200. }
  201. if (hasDarkRules) {
  202. loadThemeForm('#theme-selector')
  203. }
  204. })
  205. </script>
  206. </body>
  207. </html>