A place to cache linked articles (think custom and personal wayback machine)
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

pirms 5 gadiem
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  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>How to Write a Git Commit Message (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://chris.beams.io/posts/git-commit/">
  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. How to Write a Git Commit Message (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://chris.beams.io/posts/git-commit/">Source originale du contenu</a></h3>
  445. <p><a href="#intro">Introduction</a>
  446. | <a href="#seven-rules">The Seven Rules</a> | <a href="#tips">Tips</a></p>
  447. <hr/>
  448. <h2 id="intro">Introduction: Why good commit messages matter</h2>
  449. <p>If you browse the log of any random Git repository, you will probably find its commit messages are more or less a mess. For example, take a look at <a href="https://github.com/spring-projects/spring-framework/commits/e5f4b49?author=cbeams">these gems</a> from my early days committing to Spring:</p>
  450. <div class="highlighter-rouge"><pre class="highlight"><code>$ git log --oneline -5 --author cbeams --before "Fri Mar 26 2009"
  451. e5f4b49 Re-adding ConfigurationPostProcessorTests after its brief removal in r814. @Ignore-ing the testCglibClassesAreLoadedJustInTimeForEnhancement() method as it turns out this was one of the culprits in the recent build breakage. The classloader hacking causes subtle downstream effects, breaking unrelated tests. The test method is still useful, but should only be run on a manual basis to ensure CGLIB is not prematurely classloaded, and should not be run as part of the automated build.
  452. 2db0f12 fixed two build-breaking issues: + reverted ClassMetadataReadingVisitor to revision 794 + eliminated ConfigurationPostProcessorTests until further investigation determines why it causes downstream tests to fail (such as the seemingly unrelated ClassPathXmlApplicationContextTests)
  453. 147709f Tweaks to package-info.java files
  454. 22b25e0 Consolidated Util and MutableAnnotationUtils classes into existing AsmUtils
  455. 7f96f57 polishing
  456. </code></pre>
  457. </div>
  458. <p>Yikes. Compare that with these <a href="https://github.com/spring-projects/spring-framework/commits/5ba3db?author=philwebb">more recent</a> commits from the same repository:</p>
  459. <div class="highlighter-rouge"><pre class="highlight"><code>$ git log --oneline -5 --author pwebb --before "Sat Aug 30 2014"
  460. 5ba3db6 Fix failing CompositePropertySourceTests
  461. 84564a0 Rework @PropertySource early parsing logic
  462. e142fd1 Add tests for ImportSelector meta-data
  463. 887815f Update docbook dependency and generate epub
  464. ac8326d Polish mockito usage
  465. </code></pre>
  466. </div>
  467. <p>Which would you rather read?</p>
  468. <p>The former varies in length and form; the latter is concise and consistent.<br/>
  469. The former is what happens by default; the latter never happens by accident.</p>
  470. <p>While many repositories’ logs look like the former, there are exceptions. The <a href="https://github.com/torvalds/linux/commits/master">Linux kernel</a> and <a href="https://github.com/git/git/commits/master">Git itself</a> are great examples. Look at <a href="https://github.com/spring-projects/spring-boot/commits/master">Spring Boot</a>, or any repository managed by <a href="https://github.com/tpope/vim-pathogen/commits/master">Tim Pope</a>.</p>
  471. <p>The contributors to these repositories know that a well-crafted Git commit message is the best way to communicate <em>context</em> about a change to fellow developers (and indeed to their future selves). A diff will tell you <em>what</em> changed, but only the commit message can properly tell you <em>why</em>. Peter Hutterer <a href="http://who-t.blogspot.co.at/2009/12/on-commit-messages.html">makes this point</a> well:</p>
  472. <blockquote>
  473. <p>Re-establishing the context of a piece of code is wasteful. We can’t avoid it completely, so our efforts should go to <a href="http://www.osnews.com/story/19266/WTFs_m">reducing it</a> [as much] as possible. Commit messages can do exactly that and as a result, <em>a commit message shows whether a developer is a good collaborator</em>.</p>
  474. </blockquote>
  475. <p>If you haven’t given much thought to what makes a great Git commit message, it may be the case that you haven’t spent much time using <code class="highlighter-rouge">git log</code> and related tools. There is a vicious cycle here: because the commit history is unstructured and inconsistent, one doesn’t spend much time using or taking care of it. And because it doesn’t get used or taken care of, it remains unstructured and inconsistent.</p>
  476. <p>But a well-cared for log is a beautiful and useful thing. <code class="highlighter-rouge">git blame</code>, <code class="highlighter-rouge">revert</code>, <code class="highlighter-rouge">rebase</code>, <code class="highlighter-rouge">log</code>, <code class="highlighter-rouge">shortlog</code> and other subcommands come to life. Reviewing others’ commits and pull requests becomes something worth doing, and suddenly can be done independently. Understanding why something happened months or years ago becomes not only possible but efficient.</p>
  477. <p>A project’s long-term success rests (among other things) on its maintainability, and a maintainer has few tools more powerful than his project’s log. It’s worth taking the time to learn how to care for one properly. What may be a hassle at first soon becomes habit, and eventually a source of pride and productivity for all involved.</p>
  478. <p>In this post, I am addressing just the most basic element of keeping a healthy commit history: how to write an individual commit message. There are other important practices like commit squashing that I am not addressing here. Perhaps I’ll do that in a subsequent post.</p>
  479. <p>Most programming languages have well-established conventions as to what constitutes idiomatic style, i.e. naming, formatting and so on. There are variations on these conventions, of course, but most developers agree that picking one and sticking to it is far better than the chaos that ensues when everybody does their own thing.</p>
  480. <p>A team’s approach to its commit log should be no different. In order to create a useful revision history, teams should first agree on a commit message convention that defines at least the following three things:</p>
  481. <p><strong>Style.</strong> Markup syntax, wrap margins, grammar, capitalization, punctuation. Spell these things out, remove the guesswork, and make it all as simple as possible. The end result will be a remarkably consistent log that’s not only a pleasure to read but that actually <em>does get read</em> on a regular basis.</p>
  482. <p><strong>Content.</strong> What kind of information should the body of the commit message (if any) contain? What should it <em>not</em> contain?</p>
  483. <p><strong>Metadata.</strong> How should issue tracking IDs, pull request numbers, etc. be referenced?</p>
  484. <p>Fortunately, there are well-established conventions as to what makes an idiomatic Git commit message. Indeed, many of them are assumed in the way certain Git commands function. There’s nothing you need to re-invent. Just follow the <a href="#seven-rules">seven rules</a> below and you’re on your way to committing like a pro.</p>
  485. <h2 id="seven-rules">The seven rules of a great Git commit message</h2>
  486. <blockquote>
  487. <p><em>Keep in mind: <a href="http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html">This</a> <a href="https://www.git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines">has</a> <a href="https://github.com/torvalds/subsurface-for-dirk/blob/master/README#L92-L120">all</a> <a href="http://who-t.blogspot.co.at/2009/12/on-commit-messages.html">been</a> <a href="https://github.com/erlang/otp/wiki/writing-good-commit-messages">said</a> <a href="https://github.com/spring-projects/spring-framework/blob/30bce7/CONTRIBUTING.md#format-commit-messages">before</a>.</em></p>
  488. </blockquote>
  489. <ol>
  490. <li><a href="#separate">Separate subject from body with a blank line</a></li>
  491. <li><a href="#limit-50">Limit the subject line to 50 characters</a></li>
  492. <li><a href="#capitalize">Capitalize the subject line</a></li>
  493. <li><a href="#end">Do not end the subject line with a period</a></li>
  494. <li><a href="#imperative">Use the imperative mood in the subject line</a></li>
  495. <li><a href="#wrap-72">Wrap the body at 72 characters</a></li>
  496. <li><a href="#why-not-how">Use the body to explain <em>what</em> and <em>why</em> vs. <em>how</em></a></li>
  497. </ol>
  498. <p>For example:</p>
  499. <div class="highlighter-rouge"><pre class="highlight"><code>Summarize changes in around 50 characters or less
  500. More detailed explanatory text, if necessary. Wrap it to about 72
  501. characters or so. In some contexts, the first line is treated as the
  502. subject of the commit and the rest of the text as the body. The
  503. blank line separating the summary from the body is critical (unless
  504. you omit the body entirely); various tools like `log`, `shortlog`
  505. and `rebase` can get confused if you run the two together.
  506. Explain the problem that this commit is solving. Focus on why you
  507. are making this change as opposed to how (the code explains that).
  508. Are there side effects or other unintuitive consequences of this
  509. change? Here's the place to explain them.
  510. Further paragraphs come after blank lines.
  511. * Bullet points are okay, too
  512. * Typically a hyphen or asterisk is used for the bullet, preceded
  513. by a single space, with blank lines in between, but conventions
  514. vary here
  515. If you use an issue tracker, put references to them at the bottom,
  516. like this:
  517. Resolves: #123
  518. See also: #456, #789
  519. </code></pre>
  520. </div>
  521. <h3 id="separate">1. Separate subject from body with a blank line</h3>
  522. <p>From the <code class="highlighter-rouge">git commit</code> <a href="https://www.kernel.org/pub/software/scm/git/docs/git-commit.html#_discussion">manpage</a>:</p>
  523. <blockquote>
  524. <p>Though not required, it’s a good idea to begin the commit message with a single short (less than 50 character) line summarizing the change, followed by a blank line and then a more thorough description. The text up to the first blank line in a commit message is treated as the commit title, and that title is used throughout Git. For example, Git-format-patch(1) turns a commit into email, and it uses the title on the Subject line and the rest of the commit in the body.</p>
  525. </blockquote>
  526. <p>Firstly, not every commit requires both a subject and a body. Sometimes a single line is fine, especially when the change is so simple that no further context is necessary. For example:</p>
  527. <div class="highlighter-rouge"><pre class="highlight"><code>Fix typo in introduction to user guide
  528. </code></pre>
  529. </div>
  530. <p>Nothing more need be said; if the reader wonders what the typo was, she can simply take a look at the change itself, i.e. use <code class="highlighter-rouge">git show</code> or <code class="highlighter-rouge">git diff</code> or <code class="highlighter-rouge">git log -p</code>.</p>
  531. <p>If you’re committing something like this at the command line, it’s easy to use the <code class="highlighter-rouge">-m</code> option to <code class="highlighter-rouge">git commit</code>:</p>
  532. <div class="highlighter-rouge"><pre class="highlight"><code>$ git commit -m"Fix typo in introduction to user guide"
  533. </code></pre>
  534. </div>
  535. <p>However, when a commit merits a bit of explanation and context, you need to write a body. For example:</p>
  536. <div class="highlighter-rouge"><pre class="highlight"><code>Derezz the master control program
  537. MCP turned out to be evil and had become intent on world domination.
  538. This commit throws Tron's disc into MCP (causing its deresolution)
  539. and turns it back into a chess game.
  540. </code></pre>
  541. </div>
  542. <p>Commit messages with bodies are not so easy to write with the <code class="highlighter-rouge">-m</code> option. You’re better off writing the message in a proper text editor. If you do not already have an editor set up for use with Git at the command line, read <a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration">this section of Pro Git</a>.</p>
  543. <p>In any case, the separation of subject from body pays off when browsing the log. Here’s the full log entry:</p>
  544. <div class="highlighter-rouge"><pre class="highlight"><code>$ git log
  545. commit 42e769bdf4894310333942ffc5a15151222a87be
  546. Author: Kevin Flynn &lt;kevin@flynnsarcade.com&gt;
  547. Date: Fri Jan 01 00:00:00 1982 -0200
  548. Derezz the master control program
  549. MCP turned out to be evil and had become intent on world domination.
  550. This commit throws Tron's disc into MCP (causing its deresolution)
  551. and turns it back into a chess game.
  552. </code></pre>
  553. </div>
  554. <p>And now <code class="highlighter-rouge">git log --oneline</code>, which prints out just the subject line:</p>
  555. <div class="highlighter-rouge"><pre class="highlight"><code>$ git log --oneline
  556. 42e769 Derezz the master control program
  557. </code></pre>
  558. </div>
  559. <p>Or, <code class="highlighter-rouge">git shortlog</code>, which groups commits by user, again showing just the subject line for concision:</p>
  560. <div class="highlighter-rouge"><pre class="highlight"><code>$ git shortlog
  561. Kevin Flynn (1):
  562. Derezz the master control program
  563. Alan Bradley (1):
  564. Introduce security program "Tron"
  565. Ed Dillinger (3):
  566. Rename chess program to "MCP"
  567. Modify chess program
  568. Upgrade chess program
  569. Walter Gibbs (1):
  570. Introduce protoype chess program
  571. </code></pre>
  572. </div>
  573. <p>There are a number of other contexts in Git where the distinction between subject line and body kicks in—but none of them work properly without the blank line in between.</p>
  574. <h3 id="limit-50">2. Limit the subject line to 50 characters</h3>
  575. <p>50 characters is not a hard limit, just a rule of thumb. Keeping subject lines at this length ensures that they are readable, and forces the author to think for a moment about the most concise way to explain what’s going on.</p>
  576. <blockquote>
  577. <p><em>Tip: If you’re having a hard time summarizing, you might be committing too many changes at once. Strive for <a href="https://www.freshconsulting.com/atomic-commits/">atomic commits</a> (a topic for a separate post).</em></p>
  578. </blockquote>
  579. <p>GitHub’s UI is fully aware of these conventions. It will warn you if you go past the 50 character limit:</p>
  580. <p><img src="https://i.imgur.com/zyBU2l6.png" alt="gh1"/></p>
  581. <p>And will truncate any subject line longer than 72 characters with an ellipsis:</p>
  582. <p><img src="https://i.imgur.com/27n9O8y.png" alt="gh2"/></p>
  583. <p>So shoot for 50 characters, but consider 72 the hard limit.</p>
  584. <h3 id="capitalize">3. Capitalize the subject line</h3>
  585. <p>This is as simple as it sounds. Begin all subject lines with a capital letter.</p>
  586. <p>For example:</p>
  587. <ul>
  588. <li>Accelerate to 88 miles per hour</li>
  589. </ul>
  590. <p>Instead of:</p>
  591. <ul>
  592. <li>accelerate to 88 miles per hour</li>
  593. </ul>
  594. <h3 id="end">4. Do not end the subject line with a period</h3>
  595. <p>Trailing punctuation is unnecessary in subject lines. Besides, space is precious when you’re trying to keep them to <a href="#limit-50">50 chars or less</a>.</p>
  596. <p>Example:</p>
  597. <p>Instead of:</p>
  598. <h3 id="imperative">5. Use the imperative mood in the subject line</h3>
  599. <p><em>Imperative mood</em> just means “spoken or written as if giving a command or instruction”. A few examples:</p>
  600. <ul>
  601. <li>Clean your room</li>
  602. <li>Close the door</li>
  603. <li>Take out the trash</li>
  604. </ul>
  605. <p>Each of the seven rules you’re reading about right now are written in the imperative (“Wrap the body at 72 characters”, etc.).</p>
  606. <p>The imperative can sound a little rude; that’s why we don’t often use it. But it’s perfect for Git commit subject lines. One reason for this is that <strong>Git itself uses the imperative whenever it creates a commit on your behalf</strong>.</p>
  607. <p>For example, the default message created when using <code class="highlighter-rouge">git merge</code> reads:</p>
  608. <p>And when using <code class="highlighter-rouge">git revert</code>:</p>
  609. <div class="highlighter-rouge"><pre class="highlight"><code>Revert "Add the thing with the stuff"
  610. This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.
  611. </code></pre>
  612. </div>
  613. <p>Or when clicking the “Merge” button on a GitHub pull request:</p>
  614. <div class="highlighter-rouge"><pre class="highlight"><code>Merge pull request #123 from someuser/somebranch
  615. </code></pre>
  616. </div>
  617. <p>So when you write your commit messages in the imperative, you’re following Git’s own built-in conventions. For example:</p>
  618. <ul>
  619. <li>Refactor subsystem X for readability</li>
  620. <li>Update getting started documentation</li>
  621. <li>Remove deprecated methods</li>
  622. <li>Release version 1.0.0</li>
  623. </ul>
  624. <p>Writing this way can be a little awkward at first. We’re more used to speaking in the <em>indicative mood</em>, which is all about reporting facts. That’s why commit messages often end up reading like this:</p>
  625. <ul>
  626. <li>Fixed bug with Y</li>
  627. <li>Changing behavior of X</li>
  628. </ul>
  629. <p>And sometimes commit messages get written as a description of their contents:</p>
  630. <ul>
  631. <li>More fixes for broken stuff</li>
  632. <li>Sweet new API methods</li>
  633. </ul>
  634. <p>To remove any confusion, here’s a simple rule to get it right every time.</p>
  635. <p><strong>A properly formed Git commit subject line should always be able to complete the following sentence</strong>:</p>
  636. <ul>
  637. <li>If applied, this commit will <em><u>your subject line here</u></em></li>
  638. </ul>
  639. <p>For example:</p>
  640. <ul>
  641. <li>If applied, this commit will <em>refactor subsystem X for readability</em></li>
  642. <li>If applied, this commit will <em>update getting started documentation</em></li>
  643. <li>If applied, this commit will <em>remove deprecated methods</em></li>
  644. <li>If applied, this commit will <em>release version 1.0.0</em></li>
  645. <li>If applied, this commit will <em>merge pull request #123 from user/branch</em></li>
  646. </ul>
  647. <p>Notice how this doesn’t work for the other non-imperative forms:</p>
  648. <ul>
  649. <li>If applied, this commit will <em>fixed bug with Y</em></li>
  650. <li>If applied, this commit will <em>changing behavior of X</em></li>
  651. <li>If applied, this commit will <em>more fixes for broken stuff</em></li>
  652. <li>If applied, this commit will <em>sweet new API methods</em></li>
  653. </ul>
  654. <blockquote>
  655. <p><em>Remember: Use of the imperative is important only in the subject line. You can relax this restriction when you’re writing the body.</em></p>
  656. </blockquote>
  657. <h3 id="wrap-72">6. Wrap the body at 72 characters</h3>
  658. <p>Git never wraps text automatically. When you write the body of a commit message, you must mind its right margin, and wrap text manually.</p>
  659. <p>The recommendation is to do this at 72 characters, so that Git has plenty of room to indent text while still keeping everything under 80 characters overall.</p>
  660. <p>A good text editor can help here. It’s easy to configure Vim, for example, to wrap text at 72 characters when you’re writing a Git commit. Traditionally, however, IDEs have been terrible at providing smart support for text wrapping in commit messages (although in recent versions, IntelliJ IDEA has <a href="https://youtrack.jetbrains.com/issue/IDEA-53615">finally</a> <a href="https://youtrack.jetbrains.com/issue/IDEA-53615#comment=27-448299">gotten</a> <a href="https://youtrack.jetbrains.com/issue/IDEA-53615#comment=27-446912">better</a> about this).</p>
  661. <h3 id="why-not-how">7. Use the body to explain what and why vs. how</h3>
  662. <p>This <a href="https://github.com/bitcoin/bitcoin/commit/eb0b56b19017ab5c16c745e6da39c53126924ed6">commit from Bitcoin Core</a> is a great example of explaining what changed and why:</p>
  663. <div class="highlighter-rouge"><pre class="highlight"><code>commit eb0b56b19017ab5c16c745e6da39c53126924ed6
  664. Author: Pieter Wuille &lt;pieter.wuille@gmail.com&gt;
  665. Date: Fri Aug 1 22:57:55 2014 +0200
  666. Simplify serialize.h's exception handling
  667. Remove the 'state' and 'exceptmask' from serialize.h's stream
  668. implementations, as well as related methods.
  669. As exceptmask always included 'failbit', and setstate was always
  670. called with bits = failbit, all it did was immediately raise an
  671. exception. Get rid of those variables, and replace the setstate
  672. with direct exception throwing (which also removes some dead
  673. code).
  674. As a result, good() is never reached after a failure (there are
  675. only 2 calls, one of which is in tests), and can just be replaced
  676. by !eof().
  677. fail(), clear(n) and exceptions() are just never called. Delete
  678. them.
  679. </code></pre>
  680. </div>
  681. <p>Take a look at the <a href="https://github.com/bitcoin/bitcoin/commit/eb0b56b19017ab5c16c745e6da39c53126924ed6">full diff</a> and just think how much time the author is saving fellow and future committers by taking the time to provide this context here and now. If he didn’t, it would probably be lost forever.</p>
  682. <p>In most cases, you can leave out details about how a change has been made. Code is generally self-explanatory in this regard (and if the code is so complex that it needs to be explained in prose, that’s what source comments are for). Just focus on making clear the reasons why you made the change in the first place—the way things worked before the change (and what was wrong with that), the way they work now, and why you decided to solve it the way you did.</p>
  683. <p>The future maintainer that thanks you may be yourself!</p>
  684. <h2 id="tips">Tips</h2>
  685. <h3 id="learn-to-love-the-command-line-leave-the-ide-behind">Learn to love the command line. Leave the IDE behind.</h3>
  686. <p>For as many reasons as there are Git subcommands, it’s wise to embrace the command line. Git is insanely powerful; IDEs are too, but each in different ways. I use an IDE every day (IntelliJ IDEA) and have used others extensively (Eclipse), but I have never seen IDE integration for Git that could begin to match the ease and power of the command line (once you know it).</p>
  687. <p>Certain Git-related IDE functions are invaluable, like calling <code class="highlighter-rouge">git rm</code> when you delete a file, and doing the right stuff with <code class="highlighter-rouge">git</code> when you rename one. Where everything falls apart is when you start trying to commit, merge, rebase, or do sophisticated history analysis through the IDE.</p>
  688. <p>When it comes to wielding the full power of Git, it’s command-line all the way.</p>
  689. <p>Remember that whether you use Bash or Zsh or Powershell, there are <a href="https://git-scm.com/book/en/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Bash">tab</a> <a href="https://git-scm.com/book/en/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Zsh">completion</a> <a href="https://git-scm.com/book/en/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Powershell">scripts</a> that take much of the pain out of remembering the subcommands and switches.</p>
  690. <h3 id="read-pro-git">Read Pro Git</h3>
  691. <p>The <a href="https://git-scm.com/book/en/v2">Pro Git</a> book is available online for free, and it’s fantastic. Take advantage!</p>
  692. </article>
  693. </section>
  694. <nav id="jumpto">
  695. <p>
  696. <a href="/david/blog/">Accueil du blog</a> |
  697. <a href="https://chris.beams.io/posts/git-commit/">Source originale</a> |
  698. <a href="/david/stream/2019/">Accueil du flux</a>
  699. </p>
  700. </nav>
  701. <footer>
  702. <div>
  703. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  704. <p>
  705. Bonjour/Hi!
  706. 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>
  707. 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>).
  708. </p>
  709. <p>
  710. 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>.
  711. </p>
  712. <p>
  713. Voici quelques articles choisis :
  714. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  715. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  716. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  717. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  718. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  719. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  720. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  721. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  722. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  723. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  724. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  725. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  726. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  727. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  728. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  729. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  730. </p>
  731. <p>
  732. 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>.
  733. </p>
  734. <p>
  735. Je ne traque pas ta navigation mais mon
  736. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  737. conserve des logs d’accès.
  738. </p>
  739. </div>
  740. </footer>
  741. <script type="text/javascript">
  742. ;(_ => {
  743. const jumper = document.getElementById('jumper')
  744. jumper.addEventListener('click', e => {
  745. e.preventDefault()
  746. const anchor = e.target.getAttribute('href')
  747. const targetEl = document.getElementById(anchor.substring(1))
  748. targetEl.scrollIntoView({behavior: 'smooth'})
  749. })
  750. })()
  751. </script>