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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  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>Telling stories with your Git history (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://about.futurelearn.com/blog/telling-stories-with-your-git-history">
  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. Telling stories with your Git history (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://about.futurelearn.com/blog/telling-stories-with-your-git-history">Source originale du contenu</a></h3>
  445. <p><b>Seb Jacobs, a Developer at FutureLearn, discusses how we maintain a </b><b>useful Git history and outlines five principles we live by when making code commits.</b></p>
  446. <p>Development started on the FutureLearn platform on 2 April 2013 and since that time, our codebase has gone through rapid changes, covering over 10,000 commits.</p>
  447. <p>With a rapidly changing codebase and a growing development team, being able to communicate how and why your code evolves over time is crucial.</p>
  448. <p>In order to manage the complex process of changing coding, we not only believe in having well factored code and tests, but also a simple Git history, which allows us to make informed decisions about future code changes.</p>
  449. <h2>Telling stories with your Git history</h2>
  450. <p><a href="https://github.com/Futurelearn">Our Git history</a> is a living, ever-changing, searchable record that tells the story of how and why our code is the way it is. The ability to document code effectively using Git (or another version control system) is just as important as being able to ship a feature, write clean code or readable tests.</p>
  451. <p>Although your code should be self-documenting, it doesn&#8217;t tell the story of why the code is the way it is or how it came to be.</p>
  452. <p>You may be used to more conventional methods of code documentation such as a Readme or a Wiki, however these forms of documentation can often become out of date.</p>
  453. <p>The other method of code documentation that comes to mind is code comments. These can be noisy and are not always relevant. I believe you should apply the same rules you apply to code design, in terms of separating your concerns, using Git for the documentation and the code for the code. These comments also have a tendency of becoming out of date.</p>
  454. <p>Here are five principles we live by at FutureLearn when it comes to Git:</p>
  455. <h2><b>1. Atomic commits</b></h2>
  456. <p>Large commits can be difficult to read, especially when they contain changes which are unrelated. I&#8217;ll admit that it is often difficult to think about how you might split up a large commit, but I find it helps to think about the purpose of each commit.</p>
  457. <p>Think of atomic commits as the smallest amount of code changed which delivers value &#8211; whether it’s tidying up existing code or introducing a new (small) feature.</p>
  458. <pre>commit: [REDACTED]
  459. Date: [REDACTED]
  460. Allow educators to invite users onto courses.
  461. 61 files changed, 937 insertions(+), 81 deletions(-)</pre>
  462. <p>With this example there are a lot of changes in this one commit. On the surface it might look like all these changes are related. However, if you were to break down the changes, you would have a better sense of what&#8217;s going on, for example:</p>
  463. <pre>a6455f8 Record when enrolment is created via an invitation.
  464. b529f6d Allow invited users to enrol on courses.
  465. b5bb6e4 Allow invited users to see the course description page.
  466. c829cbc Send enrolment invitation emails in batches of 1000.
  467. 5feaccf Allow educators to invite users onto courses.</pre>
  468. <p>Now that this example has been split up, it starts to become more useful; not only is each commit smaller, it also gives you a better story of what has happened.</p>
  469. <h2><b>2. Useful commit messages</b></h2>
  470. <p>Writing commit messages can be difficult, but it helps to have a purpose in mind. We’re already breaking the changes down into atomic commits, meaning we should have a good idea of the value of each commit.</p>
  471. <p>If there&#8217;s one thing to remember, it is to explain why you&#8217;ve made the change in the first place. This is the perfect opportunity to reflect on what you&#8217;re doing and to provide context &#8211; whether it&#8217;s to satisfy a user requirement, to fix a bug or to make another change easier to make in the future.</p>
  472. <p>I find it helps to look at the commit from the perspective of another developer. What questions might they be asking when looking at your code changes? What might not be immediately obvious?</p>
  473. <p>In terms of good practice, the following template is a good start. However, bear in mind that every commit is different.</p>
  474. <pre>Short one line title.
  475. An explanation of the problem, providing context (this may be as simple
  476. as a reference to the user story).
  477. Longer description of what the change does.
  478. An explanation of why the change is being made.
  479. Perhaps a discussion of alternatives that were considered.</pre>
  480. <p>The first line should be used to explain the value of the changes, rather than focussing on the implementation details. By keeping this concise, we allow the reader to easily scan over the commit and find the code changes they are interested in.</p>
  481. <p>The rest of the Git commit message depends on the change, but it’s always useful to explain what you’ve changed and why you’ve changed it.</p>
  482. <p>I find it also helps in some cases, to provide further context such as explaining alternative solutions you&#8217;ve ruled out or providing external references.</p>
  483. <pre>Correct the colour of FAQ link in course notice footer
  484. PT: https://www.pivotaltracker.com/story/show/84753832
  485. In some email clients the colour of the FAQ link in the course notice
  486. footer was being displayed as blue instead of white. The examples given
  487. in PT are all different versions of Outlook. Outlook won't implement
  488. CSS changes that include `!important` inline [1].
  489. Therefore, since we were using it to define the colour of that link,
  490. Outlook wasn't applying that style and thus simply set its default
  491. style(blue, like in most browsers).
  492. Removing that `!important` should fix the problem.
  493. [1] https://www.campaignmonitor.com/blog/post/3143/outlook-2007-and-
  494. the-inline-important-declaration/</pre>
  495. <p>This example has a clear headline, it outlines the problem, the developer’s intent and also provides context around the change.</p>
  496. <h2><b>3. Revise history before sharing</b></h2>
  497. <p>When developing your code, you are bound to change direction or even make mistakes (most commonly introducing typos or bugs).</p>
  498. <pre>324d079 Fix typo in enrolment flash message
  499. 3a85f77 Only display enrol button for users who can enrol
  500. 4cc4778 Allow users to enrol on courses</pre>
  501. <p>In this example, the developer has introduced a typo in their first commit, which they have fixed in a later commit.</p>
  502. <p>Before you share your commit history, it&#8217;s important to think about what is useful information for someone else to read. You shouldn’t think of your Git history as a &#8220;truthful&#8221; log of what you worked on step-by-step. Just as we refactor code, we should refactor our commits before sharing them with others.</p>
  503. <p>The power of Git makes it simple to re-order, reword and refactor your commits until they tell the clearest story possible.</p>
  504. <p>Git’s interactive rebasing functionality allows us to tell a clearer story:</p>
  505. <pre>$ git rebase --interactive
  506. 3a85f77 Only display enrol button for users who can enrol
  507. 773e345 Allow users to enrol on courses</pre>
  508. <p>By reducing the amount of noise in your commit history, you can save you and your team time.</p>
  509. <p>If you&#8217;re struggling with this process, I find that using Pull Requests is a great way to collaborate on shaping the commit history of your feature branch.</p>
  510. <h2><b>4. Single purpose branches</b></h2>
  511. <p>Long-living feature branches can often be difficult to keep up to date with master. I find that it is important to think about the purpose and scope of your feature branch.</p>
  512. <p>Although you might be working on a single feature (user story), this doesn&#8217;t necessarily mean that you can&#8217;t deliver value in stages.</p>
  513. <pre>5ce95fb Notify educators when an invitation has been accepted.
  514. 5ce95fb Refactor specs around enrolment invitations.
  515. ee95245 Extend enrolment invitation to educators.
  516. cfb2fb4 Tidy up whitespace in enrolment invitations spec.</pre>
  517. <p>Like with this example, you may find that you are having to change/refactor key areas of the codebase in order to implement the feature you are developing. These changes can often provide a clear benefit that isn’t directly related to the feature branch, and can be landed on master separately (and earlier).</p>
  518. <pre>$ git cherry-pick cfb2fb4 5ce95fb
  519. * 0564508 Merge branch 'educator-enrolment-invitations'
  520. |\
  521. | _ 5ce95fb Notify educators when an invitation has been accepted.
  522. | _ ee95245 Extend enrolment invitation to educators.
  523. | |
  524. |/
  525. * 5ce95fb Refactor specs around enrolment invitations.
  526. * cfb2fb4 Tidy up whitespace in enrolment invitations spec.</pre>
  527. <p><p>By splitting up your feature branches, you not only reduce the pain of merging each branch, you also deliver value sooner and make your Git history more readable.</p>
  528. <h2><b>5. Keep your history linear</b></h2>
  529. <p>Often, merging changes into master can result in your history becoming tangled and difficult to read.</p>
  530. <pre><em> ce91a05 Merge branch 'reprint-statements'
  531. |\
  532. | * ae43ad0 Disable reprint link for refunded purchases.
  533. | * 0b1abb0 Allow admins to flag purchases for re-printing.
  534. * | 35d0357 Put dates formats in the pattern library
  535. * | 275206c Merge branch 'fulfilment-attempt'
  536. |\ \
  537. | _ | 7aae45b Populate <code>fulfilled?</code> for existing purchases.
  538. | _ | 8e461b1 Display purchase fulfilment attempts to admins.
  539. * | | 1adc0a9 Reduce padding around the course run date
  540. | |/
  541. |/|</pre>
  542. <p>This becomes even more of an issue when you have several feature branches being developed in parallel.</p>
  543. <pre></em> ce91a05 Merge branch 'reprint-statements'
  544. |\
  545. | * ae43ad0 Disable reprint link for refunded purchases.
  546. | * 0b1abb0 Allow admins to flag purchases for re-printing.
  547. |/
  548. * 35d0357 Put dates formats in the pattern library
  549. * 275206c Merge branch 'fulfilment-attempt'
  550. |\
  551. | _ 7aae45b Populate <code>fulfilled?</code> for existing purchases.
  552. | _ 8e461b1 Display purchase fulfilment attempts to admins.
  553. | * 44cbfd0 Introduce Fulfilment attempts
  554. |/
  555. * 1adc0a9 Reduce padding around the course run date</pre>
  556. <p>When it comes to merging, we try to preserve our merges commits and to rebase our feature branches before merging.</p>
  557. <pre>$ git checkout reprint-statements
  558. $ git rebase master
  559. $ git checkout master
  560. $ git merge --no-ff reprint-statements</pre>
  561. <p>This allows us to group related commits together while keeping our merges clean, making it a lot easier to identify when a particular change was introduced.</p>
  562. <p>We also find it often helps to commit smaller changes directly onto master.</p>
  563. <h2><b>Summary</b></h2>
  564. <p>If you spend as much time ensuring your commits are well factored as you do refactoring your code and tests, it will save you and your team time and pain in the future.</p>
  565. <p><strong>How do you use Git? What sort of problems do you think it solves? Let us know in the comments below.</strong></p>
  566. <p><strong>Want to know more about how we use Git? <a href="https://skillsmatter.com/skillscasts/6128-telling-stories-through-your-commits">Watch a talk from our CTO</a>, Joel Chippindale.</strong></p>
  567. <p><strong>You might also find the following links useful: <a href="http://pcottle.github.io/learnGitBranching">LearnGitBranching</a>; <a href="http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html">A Note About Git Commit Messages</a>; <a href="http://think-like-a-git.net/">Think Like a Git</a>; and <a href="https://github.com/gazler/githug">GitHug</a>.</strong></p></p>
  568. </article>
  569. </section>
  570. <nav id="jumpto">
  571. <p>
  572. <a href="/david/blog/">Accueil du blog</a> |
  573. <a href="https://about.futurelearn.com/blog/telling-stories-with-your-git-history">Source originale</a> |
  574. <a href="/david/stream/2019/">Accueil du flux</a>
  575. </p>
  576. </nav>
  577. <footer>
  578. <div>
  579. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  580. <p>
  581. Bonjour/Hi!
  582. 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>
  583. 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>).
  584. </p>
  585. <p>
  586. 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>.
  587. </p>
  588. <p>
  589. Voici quelques articles choisis :
  590. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  591. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  592. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  593. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  594. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  595. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  596. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  597. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  598. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  599. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  600. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  601. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  602. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  603. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  604. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  605. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  606. </p>
  607. <p>
  608. 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>.
  609. </p>
  610. <p>
  611. Je ne traque pas ta navigation mais mon
  612. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  613. conserve des logs d’accès.
  614. </p>
  615. </div>
  616. </footer>
  617. <script type="text/javascript">
  618. ;(_ => {
  619. const jumper = document.getElementById('jumper')
  620. jumper.addEventListener('click', e => {
  621. e.preventDefault()
  622. const anchor = e.target.getAttribute('href')
  623. const targetEl = document.getElementById(anchor.substring(1))
  624. targetEl.scrollIntoView({behavior: 'smooth'})
  625. })
  626. })()
  627. </script>