A place to cache linked articles (think custom and personal wayback machine)
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  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>
  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,minimum-scale=1,initial-scale=1,shrink-to-fit=no">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>Every line of code is always documented (archive) — David Larlet</title>
  13. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  14. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons/apple-touch-icon.png">
  15. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons/favicon-32x32.png">
  16. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons/favicon-16x16.png">
  17. <link rel="manifest" href="/manifest.json">
  18. <link rel="mask-icon" href="/static/david/icons/safari-pinned-tab.svg" color="#5bbad5">
  19. <link rel="shortcut icon" href="/static/david/icons/favicon.ico">
  20. <meta name="apple-mobile-web-app-title" content="David Larlet">
  21. <meta name="application-name" content="David Larlet">
  22. <meta name="msapplication-TileColor" content="#da532c">
  23. <meta name="msapplication-config" content="/static/david/icons/browserconfig.xml">
  24. <meta name="theme-color" content="#f0f0ea">
  25. <!-- That good ol' feed, subscribe :p. -->
  26. <link rel=alternate type="application/atom+xml" title=Feed href="/david/log/">
  27. <meta name="robots" content="noindex, nofollow">
  28. <meta content="origin-when-cross-origin" name="referrer">
  29. <!-- Canonical URL for SEO purposes -->
  30. <link rel="canonical" href="https://mislav.net/2014/02/hidden-documentation/">
  31. <style>
  32. /* http://meyerweb.com/eric/tools/css/reset/ */
  33. html, body, div, span,
  34. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  35. a, abbr, address, big, cite, code,
  36. del, dfn, em, img, ins,
  37. small, strike, strong, tt, var,
  38. dl, dt, dd, ol, ul, li,
  39. fieldset, form, label, legend,
  40. table, caption, tbody, tfoot, thead, tr, th, td,
  41. article, aside, canvas, details, embed,
  42. figure, figcaption, footer, header, hgroup,
  43. menu, nav, output, ruby, section, summary,
  44. time, mark, audio, video {
  45. margin: 0;
  46. padding: 0;
  47. border: 0;
  48. font-size: 100%;
  49. font: inherit;
  50. vertical-align: baseline;
  51. }
  52. /* HTML5 display-role reset for older browsers */
  53. article, aside, details, figcaption, figure,
  54. footer, header, hgroup, menu, nav, section { display: block; }
  55. body { line-height: 1; }
  56. blockquote, q { quotes: none; }
  57. blockquote:before, blockquote:after,
  58. q:before, q:after {
  59. content: '';
  60. content: none;
  61. }
  62. table {
  63. border-collapse: collapse;
  64. border-spacing: 0;
  65. }
  66. /* http://practicaltypography.com/equity.html */
  67. /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
  68. /* https://www.filamentgroup.com/lab/js-web-fonts.html */
  69. @font-face {
  70. font-family: 'EquityTextB';
  71. src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
  72. url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
  73. font-weight: 300;
  74. font-style: normal;
  75. font-display: swap;
  76. }
  77. @font-face {
  78. font-family: 'EquityTextB';
  79. src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
  80. url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
  81. font-weight: 300;
  82. font-style: italic;
  83. font-display: swap;
  84. }
  85. @font-face {
  86. font-family: 'EquityTextB';
  87. src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
  88. url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
  89. font-weight: 700;
  90. font-style: normal;
  91. font-display: swap;
  92. }
  93. @font-face {
  94. font-family: 'ConcourseT3';
  95. src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
  96. url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
  97. font-weight: 300;
  98. font-style: normal;
  99. font-display: swap;
  100. }
  101. /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
  102. body {
  103. /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
  104. font-family: "EquityTextB", Palatino, serif;
  105. background-color: #f0f0ea;
  106. color: #07486c;
  107. font-kerning: normal;
  108. -moz-osx-font-smoothing: grayscale;
  109. -webkit-font-smoothing: subpixel-antialiased;
  110. text-rendering: optimizeLegibility;
  111. font-variant-ligatures: common-ligatures contextual;
  112. font-feature-settings: "kern", "liga", "clig", "calt";
  113. }
  114. pre, code, kbd, samp, var, tt {
  115. font-family: 'TriplicateT4c', monospace;
  116. }
  117. em {
  118. font-style: italic;
  119. color: #323a45;
  120. }
  121. strong {
  122. font-weight: bold;
  123. color: black;
  124. }
  125. nav {
  126. background-color: #323a45;
  127. color: #f0f0ea;
  128. display: flex;
  129. justify-content: space-around;
  130. padding: 1rem .5rem;
  131. }
  132. nav:last-child {
  133. border-bottom: 1vh solid #2d7474;
  134. }
  135. nav a {
  136. color: #f0f0ea;
  137. }
  138. nav abbr {
  139. border-bottom: 1px dotted white;
  140. }
  141. h1 {
  142. border-top: 1vh solid #2d7474;
  143. border-bottom: .2vh dotted #2d7474;
  144. background-color: #e3e1e1;
  145. color: #323a45;
  146. text-align: center;
  147. padding: 5rem 0 4rem 0;
  148. width: 100%;
  149. font-family: 'ConcourseT3';
  150. display: flex;
  151. flex-direction: column;
  152. }
  153. h1.single {
  154. padding-bottom: 10rem;
  155. }
  156. h1 span {
  157. position: absolute;
  158. top: 1vh;
  159. left: 20%;
  160. line-height: 0;
  161. }
  162. h1 span a {
  163. line-height: 1.7;
  164. padding: 1rem 1.2rem .6rem 1.2rem;
  165. border-radius: 0 0 6% 6%;
  166. background: #2d7474;
  167. font-size: 1.3rem;
  168. color: white;
  169. text-decoration: none;
  170. }
  171. h2 {
  172. margin: 4rem 0 1rem;
  173. border-top: .2vh solid #2d7474;
  174. padding-top: 1vh;
  175. }
  176. h3 {
  177. text-align: center;
  178. margin: 3rem 0 .75em;
  179. }
  180. hr {
  181. height: .4rem;
  182. width: .4rem;
  183. border-radius: .4rem;
  184. background: #07486c;
  185. margin: 2.5rem auto;
  186. }
  187. time {
  188. display: bloc;
  189. margin-left: 0 !important;
  190. }
  191. ul, ol {
  192. margin: 2rem;
  193. }
  194. ul {
  195. list-style-type: square;
  196. }
  197. a {
  198. text-decoration-skip-ink: auto;
  199. text-decoration-thickness: 0.05em;
  200. text-underline-offset: 0.09em;
  201. }
  202. article {
  203. max-width: 50rem;
  204. display: flex;
  205. flex-direction: column;
  206. margin: 2rem auto;
  207. }
  208. article.single {
  209. border-top: .2vh dotted #2d7474;
  210. margin: -6rem auto 1rem auto;
  211. background: #f0f0ea;
  212. padding: 2rem;
  213. }
  214. article p:last-child {
  215. margin-bottom: 1rem;
  216. }
  217. p {
  218. padding: 0 .5rem;
  219. margin-left: 3rem;
  220. }
  221. p + p,
  222. figure + p {
  223. margin-top: 2rem;
  224. }
  225. blockquote {
  226. background-color: #e3e1e1;
  227. border-left: .5vw solid #2d7474;
  228. display: flex;
  229. flex-direction: column;
  230. align-items: center;
  231. padding: 1rem;
  232. margin: 1.5rem;
  233. }
  234. blockquote cite {
  235. font-style: italic;
  236. }
  237. blockquote p {
  238. margin-left: 0;
  239. }
  240. figure {
  241. border-top: .2vh solid #2d7474;
  242. background-color: #e3e1e1;
  243. text-align: center;
  244. padding: 1.5rem 0;
  245. margin: 1rem 0 0;
  246. font-size: 1.5rem;
  247. width: 100%;
  248. }
  249. figure img {
  250. max-width: 250px;
  251. max-height: 250px;
  252. border: .5vw solid #323a45;
  253. padding: 1px;
  254. }
  255. figcaption {
  256. padding: 1rem;
  257. line-height: 1.4;
  258. }
  259. aside {
  260. display: flex;
  261. flex-direction: column;
  262. background-color: #e3e1e1;
  263. padding: 1rem 0;
  264. border-bottom: .2vh solid #07486c;
  265. }
  266. aside p {
  267. max-width: 50rem;
  268. margin: 0 auto;
  269. }
  270. /* https://fvsch.com/code/css-locks/ */
  271. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  272. font-size: 1rem;
  273. line-height: calc( 1.5em + 0.2 * 1rem );
  274. }
  275. h1 {
  276. font-size: 1.9rem;
  277. line-height: calc( 1.2em + 0.2 * 1rem );
  278. }
  279. h2 {
  280. font-size: 1.6rem;
  281. line-height: calc( 1.3em + 0.2 * 1rem );
  282. }
  283. h3 {
  284. font-size: 1.35rem;
  285. line-height: calc( 1.4em + 0.2 * 1rem );
  286. }
  287. @media (min-width: 20em) {
  288. /* The (100vw - 20rem) / (50 - 20) part
  289. resolves to 0-1rem, depending on the
  290. viewport width (between 20em and 50em). */
  291. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  292. font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
  293. line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
  294. margin-left: 0;
  295. }
  296. h1 {
  297. font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  298. line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
  299. }
  300. h2 {
  301. font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  302. line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
  303. }
  304. h3 {
  305. font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  306. line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
  307. }
  308. }
  309. @media (min-width: 50em) {
  310. /* The right part of the addition *must* be a
  311. rem value. In this example we *could* change
  312. the whole declaration to font-size:2.5rem,
  313. but if our baseline value was not expressed
  314. in rem we would have to use calc. */
  315. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  316. font-size: calc( 1rem + .6 * 1rem );
  317. line-height: 1.5em;
  318. }
  319. p, li, pre, details {
  320. margin-left: 3rem;
  321. }
  322. h1 {
  323. font-size: calc( 1.9rem + 1.5 * 1rem );
  324. line-height: 1.2em;
  325. }
  326. h2 {
  327. font-size: calc( 1.5rem + 1.5 * 1rem );
  328. line-height: 1.3em;
  329. }
  330. h3 {
  331. font-size: calc( 1.35rem + 1.5 * 1rem );
  332. line-height: 1.4em;
  333. }
  334. figure img {
  335. max-width: 500px;
  336. max-height: 500px;
  337. }
  338. }
  339. figure.unsquared {
  340. margin-bottom: 1.5rem;
  341. }
  342. figure.unsquared img {
  343. height: inherit;
  344. }
  345. @media print {
  346. body { font-size: 100%; }
  347. a:after { content: " (" attr(href) ")"; }
  348. a, a:link, a:visited, a:after {
  349. text-decoration: underline;
  350. text-shadow: none !important;
  351. background-image: none !important;
  352. background: white;
  353. color: black;
  354. }
  355. abbr[title] { border-bottom: 0; }
  356. abbr[title]:after { content: " (" attr(title) ")"; }
  357. img { page-break-inside: avoid; }
  358. @page { margin: 2cm .5cm; }
  359. h1, h2, h3 { page-break-after: avoid; }
  360. p3 { orphans: 3; widows: 3; }
  361. img {
  362. max-width: 250px !important;
  363. max-height: 250px !important;
  364. }
  365. nav, aside { display: none; }
  366. }
  367. ul.with_columns {
  368. column-count: 1;
  369. }
  370. @media (min-width: 20em) {
  371. ul.with_columns {
  372. column-count: 2;
  373. }
  374. }
  375. @media (min-width: 50em) {
  376. ul.with_columns {
  377. column-count: 3;
  378. }
  379. }
  380. ul.with_two_columns {
  381. column-count: 1;
  382. }
  383. @media (min-width: 20em) {
  384. ul.with_two_columns {
  385. column-count: 1;
  386. }
  387. }
  388. @media (min-width: 50em) {
  389. ul.with_two_columns {
  390. column-count: 2;
  391. }
  392. }
  393. .gallery {
  394. display: flex;
  395. flex-wrap: wrap;
  396. justify-content: space-around;
  397. }
  398. .gallery figure img {
  399. margin-left: 1rem;
  400. margin-right: 1rem;
  401. }
  402. .gallery figure figcaption {
  403. font-family: 'ConcourseT3'
  404. }
  405. footer {
  406. font-family: 'ConcourseT3';
  407. display: flex;
  408. flex-direction: column;
  409. border-top: 3px solid white;
  410. padding: 4rem 0;
  411. background-color: #07486c;
  412. color: white;
  413. }
  414. footer > * {
  415. max-width: 50rem;
  416. margin: 0 auto;
  417. }
  418. footer a {
  419. color: #f1c40f;
  420. }
  421. footer .avatar {
  422. width: 200px;
  423. height: 200px;
  424. border-radius: 50%;
  425. float: left;
  426. -webkit-shape-outside: circle();
  427. shape-outside: circle();
  428. margin-right: 2rem;
  429. padding: 2px 5px 5px 2px;
  430. background: white;
  431. border-left: 1px solid #f1c40f;
  432. border-top: 1px solid #f1c40f;
  433. border-right: 5px solid #f1c40f;
  434. border-bottom: 5px solid #f1c40f;
  435. }
  436. </style>
  437. <h1>
  438. <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
  439. Every line of code is always documented (archive)
  440. <time>Pour la pérennité des contenus liés. Non-indexé, retrait sur simple email.</time>
  441. </h1>
  442. <section>
  443. <article>
  444. <h3><a href="https://mislav.net/2014/02/hidden-documentation/">Source originale du contenu</a></h3>
  445. <p>Every line of code comes with a hidden piece of documentation.</p>
  446. <p>Whoever wrote line 4 of the following code snippet decided to access the
  447. <code>clientLeft</code> property of a DOM node for some reason, but do nothing with the
  448. result. It&rsquo;s pretty mysterious. Can you tell why they did it, or is it safe to
  449. change or remove that call in the future?</p>
  450. <div class="highlight"><pre><code class="language-js" data-lang="js"><span class="lineno">1</span> <span class="c1">// ...</span>
  451. <span class="lineno">2</span> <span class="k">if</span> <span class="p">(</span><span class="nx">duration</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="nx">endEvent</span><span class="p">,</span> <span class="nx">wrappedCallback</span><span class="p">)</span>
  452. <span class="lineno">3</span>
  453. <span class="lineno">4</span> <span class="hll"><span class="k">this</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="mi">0</span><span class="p">).</span><span class="nx">clientLeft</span>
  454. </span><span class="lineno">5</span>
  455. <span class="lineno">6</span> <span class="k">this</span><span class="p">.</span><span class="nx">css</span><span class="p">(</span><span class="nx">cssValues</span><span class="p">)</span></code></pre></div>
  456. <p>If someone pasted you this code, like I did here, you probably won&rsquo;t be able to
  457. tell who wrote this line, what was their reasoning, and is it necessary to keep
  458. it. <em>However</em>, most of the time when working on a project you&rsquo;ll have access to
  459. its history via version control systems.</p>
  460. <p><strong>A project&rsquo;s history is its most valuable documentation.</strong></p>
  461. <p>The mystery ends when we view the commit message which introduced this line:</p>
  462. <div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>git show <span class="k">$(</span>git blame example.js -L 4,4 <span class="p">|</span> awk <span class="s1">&#39;{print $1}&#39;</span><span class="k">)</span></code></pre></div>
  463. <blockquote><p><strong>Fix animate() for elements just added to DOM</strong></p>
  464. <p>Activating CSS transitions for an element just added to the DOM won&rsquo;t work in
  465. either Webkit or Mozilla. To work around this, we used to defer setting CSS
  466. properties with setTimeout (see 272513b).</p>
  467. <p>This solved the problem for Webkit, but not for latest versions of Firefox.
  468. Mozilla seems to need at least 15ms timeout, and even this value varies.</p>
  469. <p>A better solution for both engines is to trigger &ldquo;layout&rdquo;. This is done here
  470. by reading <code>clientLeft</code> from an element. There are other properties and
  471. methods that trigger layout; see
  472. <a href="http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html">gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit</a></p></blockquote>
  473. <p>As it turns out, this line—more specifically, the <em>change</em> which introduced this
  474. line—is <strong>heavily documented</strong> with information about why it was necessary, why did
  475. the previous approach (referred to by a commit SHA) not work, which browsers are
  476. affected, and a link for further reading.</p>
  477. <p>As it also turns out, <a href="https://github.com/madrobby/zepto/pull/586">the author of that mysterious line was me</a>. There are
  478. ways I could have written that code itself better: by <strong>encapsulating the magic
  479. property access</strong> in a function with an <a href="http://signalvnoise.com/posts/3531-intention-revealing-methods">intention-revealing name</a> such as
  480. <code>triggerLayout()</code>, or at least by <strong>adding a code comment</strong> with a short
  481. explanation that this kicks off the animation. For whatever reason, I might have
  482. failed that day to make this particular code expressive. <strong>Code happens, and
  483. it&rsquo;s not always perfect</strong>.</p>
  484. <p>Even if this code <em>was</em> more expressive or if it <em>had</em> contained lines of code
  485. comments, a project&rsquo;s history will be able to provide even richer information:</p>
  486. <ol>
  487. <li><em>Who</em> added this code;</li>
  488. <li><em>When</em> did they add this code;</li>
  489. <li>Which was the <em>accompanying test</em> (if any);</li>
  490. <li>The full commit message can be a whole novel (while code comments should be
  491. kept succinct).</li>
  492. </ol>
  493. <p>Code quality still matters a lot. But when pondering how you could improve your
  494. coding even further, you should consider aiming for better commit messages. You
  495. should request this not just from yourself, but from your entire team and all
  496. the contributors. <strong>The story of a software matters as much as its latest
  497. checkout</strong>.</p>
  498. <h2>Effective spelunking of project&rsquo;s history</h2>
  499. <h3>git blame</h3>
  500. <p>I&rsquo;ve already demonstrated how to use <code>git blame</code> from the command line above.
  501. When you don&rsquo;t have access to the local git repository, you can also open the
  502. &ldquo;Blame&rdquo; view for <a href="https://github.com/madrobby/zepto/blame/2ed0123eaddc023a8579df0a3a084a70a392d792/src/fx.js#L90">any file on GitHub</a>.</p>
  503. <p>A very effective way of exploring a file&rsquo;s history is with Vim and <a href="https://github.com/tpope/vim-fugitive" title="fugitive.vim: a Git wrapper so awesome, it should be illegal">Fugitive</a>:</p>
  504. <ol>
  505. <li>Use <code>:Gblame</code> in a buffer to open the blame view;</li>
  506. <li>If you need to go deeper, press <kbd>Shift-P</kbd> on a line of blame pane to
  507. re-blame at the parent of that commit;</li>
  508. <li>Press <kbd>o</kbd> to open a split showing the commit currently selected in
  509. the blame pane.</li>
  510. <li>Use <code>:Gbrowse</code> in the commit split to open the commit in the GitHub web interface;</li>
  511. <li>Press <kbd>gq</kbd> to close the blame pane and return to the main buffer.</li>
  512. </ol>
  513. <p><img width=827 height=445 style="max-width:100%" alt="git blame view in vim Fugitive"
  514. src="https://mislav.net/images/Screen%20Shot%202014-02-07%20at%203.38.20%20PM.png"></p>
  515. <p>See <code>:help Gblame</code> for more information.</p>
  516. <h3>Find the pull request where a commit originated</h3>
  517. <p>With git blame you might have obtained a commit SHA that introduced a change,
  518. but commit messages don&rsquo;t always carry enough information or context to explain
  519. the rationale behind the change. However, if the team behind a project practices
  520. <a href="http://guides.github.com/overviews/flow/" title="Lightweight, branch-based workflow that supports teams and projects where deployments are made regularly">GitHub Flow</a>, the context might be found in the pull request discussion:</p>
  521. <div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>git log --merges --ancestry-path --oneline &lt;SHA&gt;..origin <span class="p">|</span> tail
  522. ...
  523. <span class="hll">bc4712d Merge pull request <span class="c">#42 from sticky-sidebar</span>
  524. </span>3f883f0 Merge branch <span class="s1">&#39;master&#39;</span> into sticky-sidebar</code></pre></div>
  525. <p>Here, a single commit SHA was enough to discover that it originated in pull
  526. request #42.</p>
  527. <h3>The git pickaxe</h3>
  528. <p>Sometimes you&rsquo;ll be trying to find something that is missing: for instance, a
  529. past call to a function that is no longer invoked from anywhere. The best way to
  530. find which commits have introduced or removed a certain keyword is with the
  531. &lsquo;pickaxe&rsquo; argument to <code>git log</code>:</p>
  532. <pre><code>$ git log -S&lt;string&gt;
  533. </code></pre>
  534. <p>This way you can dig up commits that have, for example, removed calls to a
  535. specific function, or added a certain CSS classname.</p>
  536. <h3>git churn</h3>
  537. <p>It&rsquo;s possible to get valuable insight from history of a project not only by
  538. viewing individual commits, but by <strong>analyzing sets of changes as a whole</strong>. For
  539. instance, <a href="https://github.com/garybernhardt/dotfiles/blob/f0c0ff92209e5aed4fa3ef6faf056eb9944a8f12/bin/git-churn">git-churn</a> is a simple but valuable script that wraps
  540. <code>git log</code> to compile stats about which files change the most. For example, to
  541. see where the development of an app was focused on in the past 6 months:</p>
  542. <pre><code>$ git churn --since='6 months ago' app/ | tail
  543. </code></pre>
  544. <p>Incidentally, such analysis also highlights potential problems with technical
  545. debt in a project. A specific file changing too often is generally a red flag,
  546. since it probably means that the code in that file either needed to be
  547. frequently fixed for bugs, or that the file holds too much responsibility in
  548. general and should be split into smaller units.</p>
  549. <p>Similar methods of history analysis can be employed to see which people were
  550. responsible recently for development of a certain part of the codebase. For
  551. instance, to see who contributed most often to the API part of an application:</p>
  552. <pre><code>$ git log --format='%an' --since='6 months ago' app/controllers/api/ | \
  553. sort | uniq -c | sort -rn | head
  554. 109 Edmond Dantès
  555. 13 Jonathan Livingston
  556. 7 Ebanezer Scrooge
  557. </code></pre>
  558. <h2>Being on the right side of history</h2>
  559. <p>Keep in mind that everything that you&rsquo;re making today is going to enter the
  560. project&rsquo;s history and stay there forever. To be nicer to other people who work
  561. with you (even if it&rsquo;s a solo project, that includes yourself in 3 months),
  562. follow these ground rules when making commits:</p>
  563. <ul>
  564. <li><p>Always write commit messages as if you are <strong>explaining the change</strong> to a
  565. colleague sitting next to you who has no idea of what&rsquo;s going on. Per
  566. <a href="http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message" title="5 Useful Tips For A Better Commit Message">Thoughtbot&rsquo;s tips for better commit messages</a>:</p>
  567. <blockquote><p>Answer the following questions:</p>
  568. <ul>
  569. <li>Why is this change necessary?</li>
  570. <li>How does it address the issue?</li>
  571. <li>What side effects does this change have?</li>
  572. <li>Consider including a link [to the discussion.]</li>
  573. </ul>
  574. </blockquote></li>
  575. <li><p><strong>Avoid unrelated changes in a single commit</strong>. You might have spotted a typo
  576. or did tiny code refactoring in the same file where you made some other changes,
  577. but resist the temptation to record them together with the main change unless
  578. they&rsquo;re directly related.</p></li>
  579. <li><p><strong>Always be cleaning up your history before pushing</strong>. If the commits haven&rsquo;t
  580. been shared yet, it&rsquo;s safe to <a href="/2013/02/merge-vs-rebase/" title="Git merge vs. rebase">rebase the heck out of them</a>. The
  581. following could have been permanent history of the Faraday project, but I
  582. squashed it down to only 2 commits and edited their messages to hide the fact
  583. I had troubles setting the script up in the first place:</p>
  584. <p><img width=470 style="max-width:100%" alt="messy git history before rebase"
  585. src="https://mislav.net/images/Image%202013-04-04%20at%201.38.33%20AM.png"></p></li>
  586. <li><p>Corollary of avoiding unrelated changes: <strong>stick to a line-based coding
  587. style</strong> that allows you to append, edit or remove values from lists without
  588. changing adjacent lines. Some examples:</p>
  589. <pre><code> var one = "foo"
  590. , two = "bar"
  591. , three = "baz" // Comma-first style allows us to add or remove a
  592. // new variable without touching other lines
  593. # Ruby:
  594. result = make_http_request(
  595. :method =&gt; 'POST',
  596. :url =&gt; api_url,
  597. :body =&gt; '...', // Ruby allows us to leave a trailing comma, making it
  598. ) // possible to add/remove params while not touching others
  599. </code></pre>
  600. <p>Why would you want to use such coding styles? Well, always think about the
  601. person who&rsquo;s going to <code>git blame</code> this. In the JavaScript example, if you were
  602. the one who added a committed the value <code>"baz"</code>, you don&rsquo;t want your name to
  603. show up when somebody blames the line that added <code>"bar"</code>, since the two
  604. variables might be unrelated.</p></li>
  605. </ul>
  606. <h2>Bonus script</h2>
  607. <p>Since you&rsquo;ve read this far, I&rsquo;ll reward you with an extra script. I call it
  608. <a href="https://github.com/mislav/dotfiles/blob/7ac8cbfcd56cfa6c39b5719ea183e87878ea6ed5/bin/git-overwritten">git-overwritten</a> and it shows blame information about original authors of
  609. lines changed or removed in a given branch:</p>
  610. <pre><code>$ git overwritten feature origin/master
  611. </code></pre>
  612. <pre class='ansi'> 28 2014-02-04 <span class='ansi-0 ansi-yellow'>1fb2633</span> <span class='ansi-0 ansi-green'>Mislav Marohnić</span>: Add Makefile for building and testing
  613. 1 2014-01-13 <span class='ansi-0 ansi-yellow'>b2d896a</span> <span class='ansi-0 ansi-green'>Jingwen Owen Ou</span>: Add -t to mktemp in script/make
  614. 17 2014-01-07 <span class='ansi-0 ansi-yellow'>385ccee</span> <span class='ansi-0 ansi-green'>Jingwen Owen Ou</span>: Add script/make for homebrew build
  615. </pre>
  616. <p>This is useful when opening pull requests per <a href="http://guides.github.com/overviews/flow/" title="Lightweight, branch-based workflow that supports teams and projects where deployments are made regularly">GitHub Flow</a>; you&rsquo;ll want your
  617. pull request reviewed by colleagues but you might not be sure who to ping. With
  618. <code>git-overwritten</code> you&rsquo;ll get the names of people who wrote the lines you just
  619. changed, so you&rsquo;ll know who to @-mention when opening a pull request.</p>
  620. </article>
  621. </section>
  622. <nav id="jumpto">
  623. <p>
  624. <a href="/david/blog/">Accueil du blog</a> |
  625. <a href="https://mislav.net/2014/02/hidden-documentation/">Source originale</a> |
  626. <a href="/david/stream/2019/">Accueil du flux</a>
  627. </p>
  628. </nav>
  629. <footer>
  630. <div>
  631. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  632. <p>
  633. Bonjour/Hi!
  634. Je suis <a href="/david/" title="Profil public">David&nbsp;Larlet</a>, je vis actuellement à Montréal et j’alimente cet espace depuis 15 ans. <br>
  635. Si tu as apprécié cette lecture, n’hésite pas à poursuivre ton exploration. Par exemple via les <a href="/david/blog/" title="Expériences bienveillantes">réflexions bimestrielles</a>, la <a href="/david/stream/2019/" title="Pensées (dés)articulées">veille hebdomadaire</a> ou en t’abonnant au <a href="/david/log/" title="S’abonner aux publications via RSS">flux RSS</a> (<a href="/david/blog/2019/flux-rss/" title="Tiens c’est quoi un flux RSS ?">so 2005</a>).
  636. </p>
  637. <p>
  638. Je m’intéresse à la place que je peux avoir dans ce monde. En tant qu’humain, en tant que membre d’une famille et en tant qu’associé d’une coopérative. De temps en temps, je fais aussi des <a href="https://github.com/davidbgk" title="Principalement sur Github mais aussi ailleurs">trucs techniques</a>. Et encore plus rarement, <a href="/david/talks/" title="En ce moment je laisse plutôt la place aux autres">j’en parle</a>.
  639. </p>
  640. <p>
  641. Voici quelques articles choisis :
  642. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  643. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  644. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  645. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  646. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  647. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  648. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  649. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  650. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  651. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  652. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  653. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  654. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  655. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  656. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  657. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  658. </p>
  659. <p>
  660. On peut <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">échanger par courriel</a>. Si éventuellement tu souhaites que l’on travaille ensemble, tu devrais commencer par consulter le <a href="http://larlet.com">profil dédié à mon activité professionnelle</a> et/ou contacter directement <a href="http://scopyleft.fr/">scopyleft</a>, la <abbr title="Société coopérative et participative">SCOP</abbr> dont je fais partie depuis six ans. Je recommande au préalable de lire <a href="/david/blog/2018/cout-site/" title="Attention ce qui va suivre peut vous choquer">combien coûte un site</a> et pourquoi je suis plutôt favorable à une <a href="/david/pro/devis/" title="Discutons-en !">non-demande de devis</a>.
  661. </p>
  662. <p>
  663. Je ne traque pas ta navigation mais mon
  664. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  665. conserve des logs d’accès.
  666. </p>
  667. </div>
  668. </footer>
  669. <script type="text/javascript">
  670. ;(_ => {
  671. const jumper = document.getElementById('jumper')
  672. jumper.addEventListener('click', e => {
  673. e.preventDefault()
  674. const anchor = e.target.getAttribute('href')
  675. const targetEl = document.getElementById(anchor.substring(1))
  676. targetEl.scrollIntoView({behavior: 'smooth'})
  677. })
  678. })()
  679. </script>