Compare commits

...

No commits in common. 'master' and 'gh-pages' have entirely different histories.

  1. 2
      .gitignore
  2. 3
      .gitmodules
  3. 29
      LICENSE
  4. 63
      README.md
  5. 4
      assets/fonts/font-awesome.css
  6. 13
      assets/fonts/material-icons.css
  7. BIN
      assets/fonts/specimen/FontAwesome.ttf
  8. BIN
      assets/fonts/specimen/FontAwesome.woff
  9. BIN
      assets/fonts/specimen/FontAwesome.woff2
  10. BIN
      assets/fonts/specimen/MaterialIcons-Regular.ttf
  11. BIN
      assets/fonts/specimen/MaterialIcons-Regular.woff
  12. BIN
      assets/fonts/specimen/MaterialIcons-Regular.woff2
  13. BIN
      assets/images/favicon.png
  14. 20
      assets/images/icons/bitbucket.1b09e088.svg
  15. 18
      assets/images/icons/github.f0b8504a.svg
  16. 38
      assets/images/icons/gitlab.6dd19c00.svg
  17. 1
      assets/javascripts/application.e72fd936.js
  18. 1
      assets/javascripts/lunr/lunr.da.js
  19. 1
      assets/javascripts/lunr/lunr.de.js
  20. 1
      assets/javascripts/lunr/lunr.du.js
  21. 1
      assets/javascripts/lunr/lunr.es.js
  22. 1
      assets/javascripts/lunr/lunr.fi.js
  23. 1
      assets/javascripts/lunr/lunr.fr.js
  24. 1
      assets/javascripts/lunr/lunr.hu.js
  25. 1
      assets/javascripts/lunr/lunr.it.js
  26. 1
      assets/javascripts/lunr/lunr.jp.js
  27. 1
      assets/javascripts/lunr/lunr.multi.js
  28. 1
      assets/javascripts/lunr/lunr.no.js
  29. 1
      assets/javascripts/lunr/lunr.pt.js
  30. 1
      assets/javascripts/lunr/lunr.ro.js
  31. 1
      assets/javascripts/lunr/lunr.ru.js
  32. 1
      assets/javascripts/lunr/lunr.stemmer.support.js
  33. 1
      assets/javascripts/lunr/lunr.sv.js
  34. 1
      assets/javascripts/lunr/lunr.tr.js
  35. 1
      assets/javascripts/lunr/tinyseg.js
  36. 1
      assets/javascripts/modernizr.1aa3b519.js
  37. 1176
      assets/stylesheets/application-palette.22915126.css
  38. 2552
      assets/stylesheets/application.451f80e5.css
  39. 1099
      branches/index.html
  40. 0
      css/custom.css
  41. 852
      docs/branches.md
  42. 548
      docs/easy.md
  43. 63
      docs/index.md
  44. 287
      docs/ohfk.md
  45. 71
      docs/transplant.md
  46. 827
      easy/index.html
  47. 0
      img/after.png
  48. 0
      img/before.png
  49. 0
      img/eakins-the-agnew-clinic-1889.jpg
  50. 0
      img/eakins-the-gross-clinic-1875.jpg
  51. 0
      img/first-successful-kidney-transplantation-brigham-1954-babb-1996.jpg
  52. 0
      img/git-commit-ectomy.jpg
  53. 0
      img/history.png
  54. 0
      img/william-morton-first-use-ether.jpg
  55. 490
      index.html
  56. 25
      memo
  57. 1
      mkdocs-material
  58. 32
      mkdocs.yml
  59. 683
      ohfk/index.html
  60. 2986
      search/lunr.js
  61. 96
      search/main.js
  62. 1
      search/search_index.json
  63. 128
      search/worker.js
  64. 28
      sitemap.xml
  65. BIN
      sitemap.xml.gz
  66. 515
      transplant/index.html

2
.gitignore

@ -1,2 +0,0 @@
site/

3
.gitmodules

@ -1,3 +0,0 @@
[submodule "mkdocs-material"]
path = mkdocs-material
url = https://git.charlesreid1.com/charlesreid1/mkdocs-material

29
LICENSE

@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2018, Chaz Reid
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

63
README.md

@ -1,63 +0,0 @@
# git-commit-ectomy
Perform a git-commit-ectomy to forever remove problematic commits from your repo history.
This uses the [git-forget-blob.sh](https://tinyurl.com/git-commit-ectomy) script from [@nachoparker](https://github.com/nachoparker).
![git-commit-ectomy main banner image](docs/img/git-commit-ectomy.jpg)
## what is this
This page covers how to perform a git-commit-ectomy.
This is a procedure that removes problematic files or
commits from your repository history.
For example, suppose the intern adds and commits a 1 GB
CSV file to your repository. After profusely apologizing,
the intern removes the 1 GB file, but the damage is done,
and the 1 GB file will forever bloat `.git`.
Enter the git surgeon. A git surgeon can remove such
problematic commits and get the commit history back in
shape.
[Git College of Surgery on Github](https://github.com/git-college-of-surgery)
## the procedure
This surgical procedure can happen one of four ways:
* Git-Commit-Ectomy the Easy Way: [Single Branch](docs/easy.md)
* Complications: [Dealing with Branches](docs/branches.md)
* Transplants: [Performing a Transplant with Patch](transplant.md)
* Oh F&!k: [Please Send Backup](docs/ohfk.md)
# consult with your doctor
You should consult with your doctor to determine if a
git-commit-ectomy is right for your repository.
This one-liner lists the 40 largest files in the repo
(modify the `tail` line to change the number of items
returned):
```
$ git rev-list --all --objects | \
sed -n $(git rev-list --objects --all | \
cut -f1 -d' ' | \
git cat-file --batch-check | \
grep blob | \
sort -n -k 3 | \
\
tail -n40 | \
\
while read hash type size; do
echo -n "-e s/$hash/$size/p ";
done) | \
sort -n -r -k1
```

4
assets/fonts/font-awesome.css

File diff suppressed because one or more lines are too long

13
assets/fonts/material-icons.css

@ -0,0 +1,13 @@
/*!
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE
* DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
* SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND
* LIMITATIONS UNDER THE LICENSE.
*/@font-face{font-family:"Material Icons";font-style:normal;font-weight:400;src:local("Material Icons"),local("MaterialIcons-Regular"),url("specimen/MaterialIcons-Regular.woff2") format("woff2"),url("specimen/MaterialIcons-Regular.woff") format("woff"),url("specimen/MaterialIcons-Regular.ttf") format("truetype")}

BIN
assets/fonts/specimen/FontAwesome.ttf

Binary file not shown.

BIN
assets/fonts/specimen/FontAwesome.woff

Binary file not shown.

BIN
assets/fonts/specimen/FontAwesome.woff2

Binary file not shown.

BIN
assets/fonts/specimen/MaterialIcons-Regular.ttf

Binary file not shown.

BIN
assets/fonts/specimen/MaterialIcons-Regular.woff

Binary file not shown.

BIN
assets/fonts/specimen/MaterialIcons-Regular.woff2

Binary file not shown.

BIN
assets/images/favicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

20
assets/images/icons/bitbucket.1b09e088.svg

@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" width="352" height="448"
viewBox="0 0 352 448" id="__bitbucket">
<path fill="currentColor" d="M203.75 214.75q2 15.75-12.625 25.25t-27.875
1.5q-9.75-4.25-13.375-14.5t-0.125-20.5 13-14.5q9-4.5 18.125-3t16 8.875
6.875 16.875zM231.5 209.5q-3.5-26.75-28.25-41t-49.25-3.25q-15.75
7-25.125 22.125t-8.625 32.375q1 22.75 19.375 38.75t41.375 14q22.75-2
38-21t12.5-42zM291.25
74q-5-6.75-14-11.125t-14.5-5.5-17.75-3.125q-72.75-11.75-141.5 0.5-10.75
1.75-16.5 3t-13.75 5.5-12.5 10.75q7.5 7 19 11.375t18.375 5.5 21.875
2.875q57 7.25 112 0.25 15.75-2 22.375-3t18.125-5.375 18.75-11.625zM305.5
332.75q-2 6.5-3.875 19.125t-3.5 21-7.125 17.5-14.5 14.125q-21.5
12-47.375 17.875t-50.5 5.5-50.375-4.625q-11.5-2-20.375-4.5t-19.125-6.75-18.25-10.875-13-15.375q-6.25-24-14.25-73l1.5-4
4.5-2.25q55.75 37 126.625 37t126.875-37q5.25 1.5 6 5.75t-1.25 11.25-2
9.25zM350.75 92.5q-6.5 41.75-27.75 163.75-1.25 7.5-6.75 14t-10.875
10-13.625 7.75q-63 31.5-152.5
22-62-6.75-98.5-34.75-3.75-3-6.375-6.625t-4.25-8.75-2.25-8.5-1.5-9.875-1.375-8.75q-2.25-12.5-6.625-37.5t-7-40.375-5.875-36.875-5.5-39.5q0.75-6.5
4.375-12.125t7.875-9.375 11.25-7.5 11.5-5.625 12-4.625q31.25-11.5
78.25-16 94.75-9.25 169 12.5 38.75 11.5 53.75 30.5 4 5 4.125
12.75t-1.375 13.5z" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

18
assets/images/icons/github.f0b8504a.svg

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="__github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

38
assets/images/icons/gitlab.6dd19c00.svg

@ -0,0 +1,38 @@
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500"
viewBox="0 0 500 500" id="__gitlab">
<g transform="translate(156.197863, 1.160267)">
<path fill="currentColor"
d="M93.667,473.347L93.667,473.347l90.684-279.097H2.983L93.667,
473.347L93.667,473.347z" />
</g>
<g transform="translate(28.531199, 1.160800)" opacity="0.7">
<path fill="currentColor"
d="M221.333,473.345L130.649,194.25H3.557L221.333,473.345L221.333,
473.345z" />
</g>
<g transform="translate(0.088533, 0.255867)" opacity="0.5">
<path fill="currentColor"
d="M32,195.155L32,195.155L4.441,279.97c-2.513,7.735,0.24,16.21,6.821,
20.99l238.514,173.29 L32,195.155L32,195.155z" />
</g>
<g transform="translate(29.421866, 280.255593)">
<path fill="currentColor"
d="M2.667-84.844h127.092L75.14-252.942c-2.811-8.649-15.047-8.649-17.856,
0L2.667-84.844 L2.667-84.844z" />
</g>
<g transform="translate(247.197860, 1.160800)" opacity="0.7">
<path fill="currentColor"
d="M2.667,473.345L93.351,194.25h127.092L2.667,473.345L2.667,
473.345z" />
</g>
<g transform="translate(246.307061, 0.255867)" opacity="0.5">
<path fill="currentColor"
d="M221.334,195.155L221.334,195.155l27.559,84.815c2.514,7.735-0.24,
16.21-6.821,20.99 L3.557,474.25L221.334,195.155L221.334,195.155z" />
</g>
<g transform="translate(336.973725, 280.255593)">
<path fill="currentColor"
d="M130.667-84.844H3.575l54.618-168.098c2.811-8.649,15.047-8.649,
17.856,0L130.667-84.844 L130.667-84.844z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

1
assets/javascripts/application.e72fd936.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.da.js

@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,i,n;e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=(r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){var e,n,t,s=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],o=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],u=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],c=new i;function l(){var e,r=c.limit-c.cursor;c.cursor>=n&&(e=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,c.find_among_b(o,4)?(c.bra=c.cursor,c.limit_backward=e,c.cursor=c.limit-r,c.cursor>c.limit_backward&&(c.cursor--,c.bra=c.cursor,c.slice_del())):c.limit_backward=e)}this.setCurrent=function(e){c.setCurrent(e)},this.getCurrent=function(){return c.getCurrent()},this.stem=function(){var r,i=c.cursor;return function(){var r,i=c.cursor+3;if(n=c.limit,0<=i&&i<=c.limit){for(e=i;;){if(r=c.cursor,c.in_grouping(d,97,248)){c.cursor=r;break}if(c.cursor=r,r>=c.limit)return;c.cursor++}for(;!c.out_grouping(d,97,248);){if(c.cursor>=c.limit)return;c.cursor++}(n=c.cursor)<e&&(n=e)}}(),c.limit_backward=i,c.cursor=c.limit,function(){var e,r;if(c.cursor>=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,e=c.find_among_b(s,32),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del();break;case 2:c.in_grouping_b(u,97,229)&&c.slice_del()}}(),c.cursor=c.limit,l(),c.cursor=c.limit,function(){var e,r,i,t=c.limit-c.cursor;if(c.ket=c.cursor,c.eq_s_b(2,"st")&&(c.bra=c.cursor,c.eq_s_b(2,"ig")&&c.slice_del()),c.cursor=c.limit-t,c.cursor>=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,e=c.find_among_b(a,5),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del(),i=c.limit-c.cursor,l(),c.cursor=c.limit-i;break;case 2:c.slice_from("løs")}}(),c.cursor=c.limit,c.cursor>=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,c.out_grouping_b(d,97,248)?(c.bra=c.cursor,t=c.slice_to(t),c.limit_backward=r,c.eq_v_b(t)&&c.slice_del()):c.limit_backward=r),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}});

1
assets/javascripts/lunr/lunr.de.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.du.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.es.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.fi.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.fr.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.hu.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.it.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.jp.js

@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.jp=function(){this.pipeline.reset(),this.pipeline.add(e.jp.stopWordFilter,e.jp.stemmer),r?this.tokenizer=e.jp.tokenizer:(e.tokenizer&&(e.tokenizer=e.jp.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.jp.tokenizer))};var t=new e.TinySegmenter;e.jp.tokenizer=function(n){if(!arguments.length||null==n||null==n)return[];if(Array.isArray(n))return n.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(var i=n.toString().toLowerCase().replace(/^\s+/,""),o=i.length-1;o>=0;o--)if(/\S/.test(i.charAt(o))){i=i.substring(0,o+1);break}return t.segment(i).filter(function(e){return!!e}).map(function(t){return r?new e.Token(t):t})},e.jp.stemmer=function(e){return e},e.Pipeline.registerFunction(e.jp.stemmer,"stemmer-jp"),e.jp.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",e.jp.stopWordFilter=function(t){if(-1===e.jp.stopWordFilter.stopWords.indexOf(r?t.toString():t))return t},e.jp.stopWordFilter=e.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),e.Pipeline.registerFunction(e.jp.stopWordFilter,"stopWordFilter-jp")}});

1
assets/javascripts/lunr/lunr.multi.js

@ -0,0 +1 @@
!function(e,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(e.lunr)}(this,function(){return function(e){e.multiLanguage=function(){for(var i=Array.prototype.slice.call(arguments),t=i.join("-"),r="",n=[],s=[],p=0;p<i.length;++p)"en"==i[p]?(r+="\\w",n.unshift(e.stopWordFilter),n.push(e.stemmer),s.push(e.stemmer)):(r+=e[i[p]].wordCharacters,n.unshift(e[i[p]].stopWordFilter),n.push(e[i[p]].stemmer),s.push(e[i[p]].stemmer));var o=e.trimmerSupport.generateTrimmer(r);return e.Pipeline.registerFunction(o,"lunr-multi-trimmer-"+t),n.unshift(o),function(){this.pipeline.reset(),this.pipeline.add.apply(this.pipeline,n),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add.apply(this.searchPipeline,s))}}}});

1
assets/javascripts/lunr/lunr.no.js

@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,n,i;e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=(r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){var e,i,t=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],o=[new r("dt",-1,-1),new r("vt",-1,-1)],s=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],a=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],m=[119,125,149,1],l=new n;this.setCurrent=function(e){l.setCurrent(e)},this.getCurrent=function(){return l.getCurrent()},this.stem=function(){var r,n,u,d,c=l.cursor;return function(){var r,n=l.cursor+3;if(i=l.limit,0<=n||n<=l.limit){for(e=n;;){if(r=l.cursor,l.in_grouping(a,97,248)){l.cursor=r;break}if(r>=l.limit)return;l.cursor=r+1}for(;!l.out_grouping(a,97,248);){if(l.cursor>=l.limit)return;l.cursor++}(i=l.cursor)<e&&(i=e)}}(),l.limit_backward=c,l.cursor=l.limit,function(){var e,r,n;if(l.cursor>=i&&(r=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,e=l.find_among_b(t,29),l.limit_backward=r,e))switch(l.bra=l.cursor,e){case 1:l.slice_del();break;case 2:n=l.limit-l.cursor,l.in_grouping_b(m,98,122)?l.slice_del():(l.cursor=l.limit-n,l.eq_s_b(1,"k")&&l.out_grouping_b(a,97,248)&&l.slice_del());break;case 3:l.slice_from("er")}}(),l.cursor=l.limit,n=l.limit-l.cursor,l.cursor>=i&&(r=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,l.find_among_b(o,2)?(l.bra=l.cursor,l.limit_backward=r,l.cursor=l.limit-n,l.cursor>l.limit_backward&&(l.cursor--,l.bra=l.cursor,l.slice_del())):l.limit_backward=r),l.cursor=l.limit,l.cursor>=i&&(d=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,(u=l.find_among_b(s,11))?(l.bra=l.cursor,l.limit_backward=d,1==u&&l.slice_del()):l.limit_backward=d),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}});

1
assets/javascripts/lunr/lunr.pt.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.ro.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.ru.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.stemmer.support.js

@ -0,0 +1 @@
!function(r,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(r.lunr)}(this,function(){return function(r){r.stemmerSupport={Among:function(r,t,i,s){if(this.toCharArray=function(r){for(var t=r.length,i=new Array(t),s=0;s<t;s++)i[s]=r.charCodeAt(s);return i},!r&&""!=r||!t&&0!=t||!i)throw"Bad Among initialisation: s:"+r+", substring_i: "+t+", result: "+i;this.s_size=r.length,this.s=this.toCharArray(r),this.substring_i=t,this.result=i,this.method=s},SnowballProgram:function(){var r;return{bra:0,ket:0,limit:0,cursor:0,limit_backward:0,setCurrent:function(t){r=t,this.cursor=0,this.limit=t.length,this.limit_backward=0,this.bra=this.cursor,this.ket=this.limit},getCurrent:function(){var t=r;return r=null,t},in_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e<=s&&e>=i&&t[(e-=i)>>3]&1<<(7&e))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&t[(e-=i)>>3]&1<<(7&e))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e>s||e<i)return this.cursor++,!0;if(!(t[(e-=i)>>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e<i)return this.cursor--,!0;if(!(t[(e-=i)>>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor+s)!=i.charCodeAt(s))return!1;return this.cursor+=t,!0},eq_s_b:function(t,i){if(this.cursor-this.limit_backward<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor-t+s)!=i.charCodeAt(s))return!1;return this.cursor-=t,!0},find_among:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=t[a],m=l;m<_.s_size;m++){if(n+l==u){f=-1;break}if(f=r.charCodeAt(n+l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){if(o>=(_=t[s]).s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=(m=t[a]).s_size-1-l;_>=0;_--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-m.s[_])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var m;if(o>=(m=t[s]).s_size){if(this.cursor=n-m.s_size,!m.method)return m.result;var b=m.method();if(this.cursor=n-m.s_size,b)return m.result}if((s=m.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}});

1
assets/javascripts/lunr/lunr.sv.js

@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,n,t;e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=(r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){var e,t,i=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],s=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],o=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],u=[119,127,149],m=new n;this.setCurrent=function(e){m.setCurrent(e)},this.getCurrent=function(){return m.getCurrent()},this.stem=function(){var r,n=m.cursor;return function(){var r,n=m.cursor+3;if(t=m.limit,0<=n||n<=m.limit){for(e=n;;){if(r=m.cursor,m.in_grouping(o,97,246)){m.cursor=r;break}if(m.cursor=r,m.cursor>=m.limit)return;m.cursor++}for(;!m.out_grouping(o,97,246);){if(m.cursor>=m.limit)return;m.cursor++}(t=m.cursor)<e&&(t=e)}}(),m.limit_backward=n,m.cursor=m.limit,function(){var e,r=m.limit_backward;if(m.cursor>=t&&(m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(i,37),m.limit_backward=r,e))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.in_grouping_b(u,98,121)&&m.slice_del()}}(),m.cursor=m.limit,r=m.limit_backward,m.cursor>=t&&(m.limit_backward=t,m.cursor=m.limit,m.find_among_b(s,7)&&(m.cursor=m.limit,m.ket=m.cursor,m.cursor>m.limit_backward&&(m.bra=--m.cursor,m.slice_del())),m.limit_backward=r),m.cursor=m.limit,function(){var e,r;if(m.cursor>=t){if(r=m.limit_backward,m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(a,5))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.slice_from("lös");break;case 3:m.slice_from("full")}m.limit_backward=r}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}});

1
assets/javascripts/lunr/lunr.tr.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/tinyseg.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/modernizr.1aa3b519.js

File diff suppressed because one or more lines are too long

1176
assets/stylesheets/application-palette.22915126.css

File diff suppressed because it is too large

2552
assets/stylesheets/application.451f80e5.css

File diff suppressed because it is too large

1099
branches/index.html

File diff suppressed because it is too large

0
docs/css/custom.css → css/custom.css

852
docs/branches.md

@ -1,852 +0,0 @@
This page walks through a demonstration
git-commit-ectomy that you can perform
starting with an empty git repository.
It addresses the **multi-branch case**.
![Painting: Morton and the First Use of Ether (Hinkley 1893).](img/william-morton-first-use-ether.jpg)
<br />
<br />
# table of contents
* [requirements](#requirements)
* [consult with your doctor](#consult-with-your-doctor)
* [an ascii art crash course in surgery](#an-ascii-art-crash-course-in-surgery)
* [demo surgery: setup](#demo-surgery-setup)
* [create initial shared commit history](#create-initial-shared-commit-history)
* [create multiple branches](#create-multiple-branches)
* [demo surgery: procedure](#demo-surgery-procedure)
* [git forget blob: cat\_branch1 (branch specific history)](#git-forget-blob-cat_branch1-branch-specific-history)
* [git forget blob: cat (shared history)](#git-forget-blob-cat-shared-history)
* [forget blob in one branch](#forget-blob-in-one-branch)
* [prepare for rebase by tagging commits](#prepare-for-rebase-by-tagging-commits)
* [perform rebase operation](#perform-rebase-operation)
* [stitch the patient back up](#stitch-the-patient-back-up)
* [tips for surgery](#tips-for-surgery)
<br />
<br />
# requirements
Before you begin, read through the [Easy Way](easy.md)
(even if it does not apply to your case) so that you
are familiar with how the process works. This page
will cover a slightly more complicated git-commit-ectomy.
# consult with your doctor
You should consult with your doctor to determine if a
git-commit-ectomy is right for you.
This one-liner lists the 40 largest files in the repo:
```
git rev-list --all --objects | \
sed -n $(git rev-list --objects --all | \
cut -f1 -d' ' | \
git cat-file --batch-check | \
grep blob | \
sort -n -k 3 | \
\
tail -n40 | \
\
while read hash type size; do
echo -n "-e s/$hash/$size/p ";
done) | \
sort -n -r -k1
```
# an ascii art crash course in surgery
Suppose our patient has a particularly painful
and unnaturally large commit located in their
multi-branch commit history:
```
This is the commit
to be "ectomied"
\/
__
o---o---(__)---o---o--------o---o---o branch A
\
\---o---o---o branch B
\
o---o---o branch C
```
The commit is first fixed on one of the branches,
creating a new history. However, the other branches
still require the old history to be retained:
```
This commit is the last
commit shared by the history
of each of the branches
\/
----o----o---o new (shared) history
/ \
| -------o---o---o branch A
| __
o---o----(__)----o---o old (shared) history
\
\---o---o---o branch B
\
o---o---o branch C
```
The second step of the procedure is to rebase
branch B and branch C onto the new history.
The rebase command requires three pieces of
information:
* The source commit (where to cut)
* The destination commit (where to graft)
* The branch name (how much to cut and graft)
Let us label the diagram above with the rebase
source and destination commits, and use valid
git branch names:
```
----o----o---o rebase_dest
/ \
| -------o---o---o branchA
|
| __
o---o----(__)----o---o rebase_src
\
\---o---o---o branchB
\
o---o---o branchC
```
Now the commands to rebase branch B and branch C are:
```
git rebase --onto rebase_dest rebase_src branchB
git rebase --onto rebase_dest rebase_src branchC
```
The commit history that results will look like the following:
```
----o----o---o
/ \
| \-----o---o---o branchA
| \
o---- \--o---o---o branchB
\
o---o---o branchC
```
# demo surgery: setup
To set up the demo surgery, we will start by
creating a single branch with commits that
are shared history between multiple branches.
Next, we create several branches with their
own commits not shared with other branches.
We want to show how to remove large files from
both the shared history of multiple branches,
and from a single branch's history.
## create initial shared commit history
Clone an example repo for performing surgery. You don't _need_
a remote repository to do the demo surgery, but we will use one
in our walkthrough.
```
git clone https://github.com/charlesreid1/git-commit-ectomy-example
cd git-commit-ectomy-example
```
In this example we will create a branch called `branch1` instead of
using the default `master` branch. Start by renaming the `master` branch
to `branch1`:
```
git branch branch1
git checkout branch1
```
Start with several text files, and add them to the repo history:
```
echo "hello foo" > foo.txt
echo "hello bar" > bar.txt
for item in `/bin/ls -1 *.txt`; do
git add ${item} && git commit ${item} -m "adding ${item}"
done
```
Now add several large files to the repo history:
```
mkdir data1; mkdir data2
```
Now create some files in each of the two directories:
```
cd data1/
dd if=/dev/urandom of=bat bs=1048576 count=10
dd if=/dev/urandom of=cat bs=1048576 count=10
dd if=/dev/urandom of=dat bs=1048576 count=10
cd ../
cd data2/
dd if=/dev/urandom of=fat bs=1048576 count=10
dd if=/dev/urandom of=rat bs=1048576 count=10
cd ../
```
This gives the following directory structure:
```
$ tree .
.
├── bar.txt
├── data1
│   ├── bat
│   ├── cat
│   └── dat
├── data2
│   ├── fat
│   └── rat
└── foo.txt
```
Add the files to the repo in _separate commits_:
```
for item in data1/bat data1/cat data1/dat data2/fat data2/rat; do
git add ${item} && git commit ${item} -m "adding ${item}"
done
```
At this point the git log should look like this:
```
$ git log --oneline
859fb5d (branch1) adding rat
7d104ee adding fat
ddf2903 adding dat
765708d adding cat
4c9f26f adding bat
3b92007 adding bar.txt
c2daf61 adding foo.txt
```
(So far, this is identical to the single-branch setup.)
## create multiple branches
Commit `859fb5d` (where we added the file `rat`) is the
last commit that is shared among the history of the three
branches we will create.
We start by checking out a particular commit and
creating each branch; this is equivalent to tagging
the commit `859fb5d` with three labels, `branch1`,
`branch2`, and `branch3`.
Next we add different files to the different branches.
Here is the directory structure we will create:
```
Branch 1 Branch 2 Branch 3
------------------- -------------------- ----------------------
. . .
├── bar.txt ├── bar.txt ├── bar.txt
├── foo.txt ├── foo.txt ├── foo.txt
├── data1 ├── data1 ├── data1
│   ├── bat │   ├── bat │   ├── bat
│   ├── cat │   ├── cat │   ├── cat
│   └── dat │   └── dat │   └── dat
├── data2 ├── data2 ├── data2
│   ├── fat │   ├── fat │   ├── fat
│   └── rat │   └── rat │   └── rat
│ │ │
└── branch1_data └── branch2_data └── branch3_data
   ├── branch1.txt    ├── branch2.txt    ├── branch3.txt
   ├── bat_branch1    ├── bat_branch2    ├── bat_branch3
   └── cat_branch1    └── cat_branch2    └── cat_branch3
```
Here are the commands to create the branch-specific
files and directories:
```
git branch branch1; git branch branch2; git branch branch3
for BRANCH in branch1 branch2 branch3; do
git checkout ${BRANCH}
mkdir ${BRANCH}_data
cd ${BRANCH}_data
echo "hello ${BRANCH}" > ${BRANCH}.txt
dd if=/dev/urandom of=bat_${BRANCH} bs=1048576 count=10
dd if=/dev/urandom of=cat_${BRANCH} bs=1048576 count=10
cd ../
git add ${BRANCH}_data
git commit ${BRANCH}_data -m "adding ${BRANCH}_data"
done
```
The log should now look like the following:
```
$ git log --oneline
2acb13d (branch3) adding branch3_data
a9473c6 (branch2) adding branch2_data
bfc1937 (branch1) adding branch1_data
859fb5d adding rat
7d104ee adding fat
ddf2903 adding dat
765708d adding cat
4c9f26f adding bat
3b92007 adding bar.txt
c2daf61 adding foo.txt
```
Visually, the commit history looks like this:
```
$ git lg2
* 4221760 - 2019-04-09 10:45:30 (branch3)
| adding branch3_data - C Reid
| * b83c9aa - 2019-04-09 10:45:28 (branch2)
|/ adding branch2_data - C Reid
| * f30c355 - 2019-04-09 10:45:26 (branch1)
|/ adding branch1_data - C Reid
* 859fb5d - 2019-04-09 10:34:19
| adding rat - C Reid
* 7d104ee - 2019-04-09 10:34:19
| adding fat - C Reid
* ddf2903 - 2019-04-09 10:34:18
| adding dat - C Reid
* 765708d - 2019-04-09 10:34:18
| adding cat - C Reid
* 4c9f26f - 2019-04-09 10:34:18
| adding bat - C Reid
* 3b92007 - 2019-04-09 10:33:21
| adding bar.txt - C Reid
* c2daf61 - 2019-04-09 10:33:14
adding foo.txt - C Reid
```
Or, drawing it with an ascii art tree:
```
o adding branch3_data
|
| o adding branch2_data
| |
| | o adding branch1_data
\ | /
\ | /
\ | /
\|/
o adding rat
|
o adding fat
|
o adding dat
|
o adding cat
|
o adding bat
|
o adding bar.txt
|
o adding foo.tx
|
|
[ ]
```
# demo surgery: procedure
In this demo surgery, we will show how to remove two files:
* The `cat_branch1` file, which was only added to branch 1
(this is essentially the equivalent procedure to the
single-branch [Easy Method](easy.md).)
* The `cat` file, which was added in a commit that is common to
multiple branches' commit histories (this is the more complicated case).
## git forget blob: `cat_branch1` (branch specific history)
We walk through how to remove a file that was only added
to one branch.
This procedure is basically equivalent to the
[Easy Method](easy.md), which deals with a single
branch. You are rewriting the last bit of the history
of that one branch. When the old commits are changed
to new commits, there will not be any other branches
pointing to the old history, so things are not complicated.
Start by checking out the branch:
```
git checkout branch1
```
Download the git forget blob script:
```
wget https://tinyurl.com/git-forget-blob-mac-sh -O git-forget-blob.sh
chmod +x git-forget-blob.sh
```
Check the size of the `.git` directory (before):
```
$ du -hs .git
290M .git
```
Now run the git forget blob script and pass the
relative path to `cat_branch1` in the repository:
```
$ ./git-forget-blob.sh branch1_data/cat_branch1
Enumerating objects: 89, done.
Counting objects: 100% (89/89), done.
Delta compression using up to 4 threads.
Compressing objects: 100% (81/81), done.
Writing objects: 100% (89/89), done.
Total 89 (delta 18), reused 0 (delta 0)
Rewrite f30c3554eb89d764adb91244197dd62b58f10de2 (7/8) (1 seconds passed, remaining 0 predicted) rm 'branch1_data/cat_branch1'
Ref 'refs/heads/branch1' was rewritten
Enumerating objects: 43, done.
Counting objects: 100% (43/43), done.
Delta compression using up to 4 threads.
Compressing objects: 100% (33/33), done.
Writing objects: 100% (43/43), done.
Total 43 (delta 7), reused 36 (delta 2)
```
Verify that the file was removed by checking the
size of the `.git` directory (after):
```
$ du -hs .git
100M .git
```
Also check the log to ensure that branch 1 has a new commit
history, and that no other branches had their histories
affected:
```
$ git lg2
* 4221760 - 2019-04-09 13:45:30 -0700 (4 hours ago) (branch3)
| adding branch3_data - C Reid
| * b83c9aa - 2019-04-09 13:45:28 -0700 (4 hours ago) (branch2)
|/ adding branch2_data - C Reid
| * 70b607b - 2019-04-09 13:45:26 -0700 (4 hours ago) (HEAD -> branch1)
|/ adding branch1_data - C Reid
* 859fb5d - 2019-04-09 10:34:19 -0700 (7 hours ago)
| adding data2/rat - C Reid
* 7d104ee - 2019-04-09 10:34:19 -0700 (7 hours ago)
| adding data2/fat - C Reid
* ddf2903 - 2019-04-09 10:34:18 -0700 (7 hours ago)
| adding data1/dat - C Reid
* 765708d - 2019-04-09 10:34:18 -0700 (7 hours ago)
| adding data1/cat - C Reid
* 4c9f26f - 2019-04-09 10:34:18 -0700 (7 hours ago)
| adding data1/bat - C Reid
* 3b92007 - 2019-04-09 10:33:21 -0700 (7 hours ago)
| adding bar.txt - C Reid
* c2daf61 - 2019-04-09 10:33:14 -0700 (7 hours ago)
adding foo.txt - C Reid
```
Now that you have rewritten the history of `branch1`
and replaced each commit with a new one, you can replace
the history of the branch on the remote by doing a
force-push:
```
git push origin master --force
```
## git forget blob: `cat` (shared history)
Now we walk through how to forget `cat`, a file
that was added in a commit that is shared between
two or more branches.
This case is more complicated, because once we
rewrite the commit history of branch 1 to forget
the commit where `cat` was added, branch 2 and
branch 3 still point to the old commit history.
To fix this, we graft branch 2 and branch 3 from
the old commit history onto the new commit history,
by picking two commits that are identical (but that
have different hashes) and using those as the
source and destination of our rebase operation.
### forget blob in one branch
We start by checking on the log (this uses the same
repo as resulted from rewriting branch 1 only):
```
$ git lg2
* 4221760 - 2019-04-09 13:45:30 -0700 (4 hours ago) (branch3)
| adding branch3_data - C Reid
| * b83c9aa - 2019-04-09 13:45:28 -0700 (4 hours ago) (branch2)
|/ adding branch2_data - C Reid
| * 70b607b - 2019-04-09 13:45:26 -0700 (4 hours ago) (HEAD -> branch1)
|/ adding branch1_data - C Reid
* 859fb5d - 2019-04-09 10:34:19 -0700 (7 hours ago)
| adding data2/rat - C Reid
* 7d104ee - 2019-04-09 10:34:19 -0700 (7 hours ago)
| adding data2/fat - C Reid
* ddf2903 - 2019-04-09 10:34:18 -0700 (7 hours ago)
| adding data1/dat - C Reid
* 765708d - 2019-04-09 10:34:18 -0700 (7 hours ago)
| adding data1/cat - C Reid
* 4c9f26f - 2019-04-09 10:34:18 -0700 (7 hours ago)
| adding data1/bat - C Reid
* 3b92007 - 2019-04-09 10:33:21 -0700 (7 hours ago)
| adding bar.txt - C Reid
* c2daf61 - 2019-04-09 10:33:14 -0700 (7 hours ago)
adding foo.txt - C Reid
```
We start by removing the large file `cat` from one
of the branches, then rebase the other branches onto
the new history that is created.
Here, we remove the file `cat` from branch 2, and rebase
branches 1 and 3 onto it.
Start by checking out the branch, and checking on the
size of the .git folder:
```
git checkout branch2
```
```
$ du -hs .git
100M .git
```
Now we run the forget blob script:
```
$ ./git-forget-blob.sh data1/cat
Enumerating objects: 43, done.
Counting objects: 100% (43/43), done.
Delta compression using up to 4 threads.
Compressing objects: 100% (28/28), done.
Writing objects: 100% (43/43), done.
Total 43 (delta 7), reused 43 (delta 7)
Rewrite 765708d262678c2bbc15dd5b999863ad5a4dab01 (4/8) (0 seconds passed, remaining 0 predicted) rm 'data1/cat'
Rewrite ddf2903c6d1fe41b171af7764579bc4d6a63e70f (5/8) (0 seconds passed, remaining 0 predicted) rm 'data1/cat'
Rewrite 7d104ee90da6b3adf08f9a86d2342e3c8690dc64 (6/8) (0 seconds passed, remaining 0 predicted) rm 'data1/cat'
Rewrite 859fb5d7db420b8aa745c50162b71c20331e90a9 (7/8) (0 seconds passed, remaining 0 predicted) rm 'data1/cat'
Rewrite b83c9aaecf238324aa2b8a51da1ac7f69015d4d4 (8/8) (0 seconds passed, remaining 0 predicted) rm 'data1/cat'
Ref 'refs/heads/branch2' was rewritten
Enumerating objects: 51, done.
Counting objects: 100% (51/51), done.
Delta compression using up to 4 threads.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (51/51), done.
Total 51 (delta 9), reused 40 (delta 5)
```
Check the size of the `.git` directory:
```
$ du -hs .git
100M .git
```
It did not change! We can see why when we check the log:
```
$ git lg1
* 4221760 - (4 hours ago) adding branch3_data - C Reid (branch3)
| * 5e2b657 - (4 hours ago) adding branch2_data - C Reid (HEAD -> branch2)
| * 6ec8be5 - (7 hours ago) adding data2/rat - C Reid
| * 15ec3be - (7 hours ago) adding data2/fat - C Reid
| * 03a671e - (7 hours ago) adding data1/dat - C Reid
| * 3cda75c - (7 hours ago) adding data1/cat - C Reid
| | * 70b607b - (4 hours ago) adding branch1_data - C Reid (branch1)
| |/
|/|
* | 859fb5d - (7 hours ago) adding data2/rat - C Reid
* | 7d104ee - (7 hours ago) adding data2/fat - C Reid
* | ddf2903 - (7 hours ago) adding data1/dat - C Reid
* | 765708d - (7 hours ago) adding data1/cat - C Reid
|/
* 4c9f26f - (7 hours ago) adding data1/bat - C Reid
* 3b92007 - (7 hours ago) adding bar.txt - C Reid
* c2daf61 - (7 hours ago) adding foo.txt - C Reid
```
branch 1 and branch 3 still refer to the old commit that added `cat`,
so the full contents of the `cat` file are still in the `.git` directory's
blobs.
Now that branch 2 has a new version of the shared history,
we want to rebase branch 1 and branch 3.
### prepare for rebase by tagging commits
Start the rebase operation for the remaining branches by
labeling our rebase source and destination commits. As
shown in the ascii art diagrams at the top of the page,
we want to find the last commit that our branches shared
in common in their commit history, and mark that commit
in the old history as the "rebase source" and mark that
commit in the new history as the "rebase destination".
In the case of our example, the commit that adds the file
`rat` is the last commit all our branches have in common.
This means that the rebase source will be the version of
the "adding rat" commit that is in the old history (the
history of branch 1 and branch 3) - commit `859fb5d`.
The rebase destination will be the version of the "adding
rat" commit that is in the new history of branch 2,
which corresponds to commit `6ec8be5`.
Mark these two commits as the `rebase_src` and `rebase_dest`
branches:
```
git checkout 859fb5d
git checkout -b rebase_src
git checkout 6ec8be5
git checkout -b rebase_dest
```
Now here is the state of the repo:
```
$ git lg1
* 4221760 - (5 hours ago) adding branch3_data - C Reid (branch3)
| * 5e2b657 - (5 hours ago) adding branch2_data - C Reid (branch2)
| * 6ec8be5 - (8 hours ago) adding data2/rat - C Reid (HEAD -> rebase_dest)
| * 15ec3be - (8 hours ago) adding data2/fat - C Reid
| * 03a671e - (8 hours ago) adding data1/dat - C Reid
| * 3cda75c - (8 hours ago) adding data1/cat - C Reid
| | * 70b607b - (5 hours ago) adding branch1_data - C Reid (branch1)
| |/
|/|
* | 859fb5d - (8 hours ago) adding data2/rat - C Reid (rebase_src)
* | 7d104ee - (8 hours ago) adding data2/fat - C Reid
* | ddf2903 - (8 hours ago) adding data1/dat - C Reid
* | 765708d - (8 hours ago) adding data1/cat - C Reid
|/
* 4c9f26f - (8 hours ago) adding data1/bat - C Reid
* 3b92007 - (8 hours ago) adding bar.txt - C Reid
* c2daf61 - (8 hours ago) adding foo.txt - C Reid
```
### perform rebase operation
Start the rebase operation by checking out branch 2:
```
git checkout branch2
```
Now rebase branch 1 from the old history onto the new history:
```
git rebase --onto rebase_dest rebase_src branch1
```
You should see output like this:
```
First, rewinding head to replay your work on top of it...
Applying: adding branch1_data
```
Verify that branch 1 and branch 2 now share a commit history:
```
$ git lg1
* 2af1225 - (5 hours ago) adding branch1_data - C Reid (HEAD -> branch1)
| * 4221760 - (5 hours ago) adding branch3_data - C Reid (branch3)
| * 859fb5d - (8 hours ago) adding data2/rat - C Reid (rebase_src)
| * 7d104ee - (8 hours ago) adding data2/fat - C Reid
| * ddf2903 - (8 hours ago) adding data1/dat - C Reid
| * 765708d - (8 hours ago) adding data1/cat - C Reid
| | * 5e2b657 - (5 hours ago) adding branch2_data - C Reid (branch2)
| |/
|/|
* | 6ec8be5 - (8 hours ago) adding data2/rat - C Reid (rebase_dest)
* | 15ec3be - (8 hours ago) adding data2/fat - C Reid
* | 03a671e - (8 hours ago) adding data1/dat - C Reid
* | 3cda75c - (8 hours ago) adding data1/cat - C Reid
|/
* 4c9f26f - (8 hours ago) adding data1/bat - C Reid
* 3b92007 - (8 hours ago) adding bar.txt - C Reid
* c2daf61 - (8 hours ago) adding foo.txt - C Reid
```
Repeat the process with branch 3:
```
git rebase --onto rebase_dest rebase_src branch3
```
You will see output like this:
```
First, rewinding head to replay your work on top of it...
Applying: adding branch3_data
```
Verify that all three branches now share a commit history:
```
$ git lg1
* b5642eb - (5 hours ago) adding branch3_data - C Reid (HEAD -> branch3)
| * 2af1225 - (5 hours ago) adding branch1_data - C Reid (branch1)
|/
| * 5e2b657 - (5 hours ago) adding branch2_data - C Reid (branch2)
|/
* 6ec8be5 - (8 hours ago) adding data2/rat - C Reid (rebase_dest)
* 15ec3be - (8 hours ago) adding data2/fat - C Reid
* 03a671e - (8 hours ago) adding data1/dat - C Reid
* 3cda75c - (8 hours ago) adding data1/cat - C Reid
| * 859fb5d - (8 hours ago) adding data2/rat - C Reid (rebase_src)
| * 7d104ee - (8 hours ago) adding data2/fat - C Reid
| * ddf2903 - (8 hours ago) adding data1/dat - C Reid
| * 765708d - (8 hours ago) adding data1/cat - C Reid
|/
* 4c9f26f - (8 hours ago) adding data1/bat - C Reid
* 3b92007 - (8 hours ago) adding bar.txt - C Reid
* c2daf61 - (8 hours ago) adding foo.txt - C Reid
```
Last, delete the rebase source and destination branches, so nothing points
at the problematic commits or the old history:
```
git branch -D rebase_src rebase_dest
```
Check the log to make sure we only see the new history:
```
$ git lg1
* b5642eb - (5 hours ago) adding branch3_data - C Reid (HEAD -> branch3)
| * 2af1225 - (5 hours ago) adding branch1_data - C Reid (branch1)
|/
| * 5e2b657 - (5 hours ago) adding branch2_data - C Reid (branch2)
|/
* 6ec8be5 - (8 hours ago) adding data2/rat - C Reid (rebase_dest)
* 15ec3be - (8 hours ago) adding data2/fat - C Reid
* 03a671e - (8 hours ago) adding data1/dat - C Reid
* 3cda75c - (8 hours ago) adding data1/cat - C Reid
* 4c9f26f - (8 hours ago) adding data1/bat - C Reid
* 3b92007 - (8 hours ago) adding bar.txt - C Reid
* c2daf61 - (8 hours ago) adding foo.txt - C Reid
```
Congratulations, you've completed a multi-branch git-commit-ectomy!
## stitch the patient back up
As with all surgeries, the last step is just as
important as the first.
All of the blobs for the old commits have been erased
from the `.git` directory and we're ready to push
the new, slimmer, rewritten history to the remote.
But as before, we _must_ do a force push, otherwise
both histories will be kept. To force push:
```
git push origin master --force
```
# tips for surgery
**Size up your patient before you start.**
Use the one-liner in the ["Consult with your Doctor"
section](#consult-with-your-doctor)
to size up your patient before you start.
**Get your patient some insurance.**
Back up any files you want to remove but still want to keep.
**Make sure you specify relative paths to file names.**
The `git-forget-blob.sh` script requires you to specify the
path to the file you want to remove, _relative to the top
level directory of the repository_.
Like this:
```
# CORRECT
./git-forget-blob.sh data/my_project/phase-1/proprietary/super_huge.file
```
Not like this:
```
# INCORRECT
./git-forget-blob.sh super_huge.file
```
The long one-liner in the ["Consult with your Doctor"
section](#consult-with-your-doctor)
will list the largest files in the repository, with the relative
path to that file (relative to the root of the repository).
If you pass it a filename without a path to the file,
the script will most likely complain that the file could
not be found. But it may attempt to remove the file and
rewrite history _anyway_ without removing any files.
If you are running `git-forget-blob.sh` and the size of the
`.git` folder is not going down, it may be because you are
specifying an incorrect path to the files you are trying to
remove.

548
docs/easy.md

@ -1,548 +0,0 @@
This page walks through a demonstration
git-commit-ectomy that you can perform
starting with an empty git repository.
It addresses the **single-branch case**.
![Painting: The Agnew Clinic (Eakins 1889).](img/eakins-the-agnew-clinic-1889.jpg)
<br />
<br />
# table of contents
* [requirements](#requirements)
* [consult with your doctor](#consult-with-your-doctor)
* [an ascii art crash course in surgery](#an-ascii-art-crash-course-in-surgery)
* [demo surgery: setup](#demo-surgery-setup)
* [side note: how to make a fat file](#side-note-how-to-make-a-fat-file)
* [make some text files](#make-some-text-files)
* [make some fat files](#make-some-fat-files)
* [commit files](#commit-files)
* [demo surgery: procedure](#demo-surgery-procedure)
* [prepare tools](#prepare-tools)
* [the command that doesn't work: git rm](#the-command-that-doesnt-work-git-rm)
* [the command that does work: git forget blob](#the-command-that-does-work-git-forget-blob)
* [how it worked](#how-it-worked)
* [stitch the patient back up](#stitch-the-patient-back-up)
* [tips for surgery](#tips-for-surgery)
<br />
<br />
# requirements
This guide utilizes GNU xargs.
You should run it on Linux,
or use Homebrew's gxargs if
on a Mac.
# consult with your doctor
You should consult with your doctor to determine if a
git-commit-ectomy is right for you.
This one-liner lists the 40 largest files in the repo
(modify the `tail` line to change the number):
```
$
git rev-list --all --objects | \
sed -n $(git rev-list --objects --all | \
cut -f1 -d' ' | \
git cat-file --batch-check | \
grep blob | \
sort -n -k 3 | \
\
tail -n40 | \
\
while read hash type size; do
echo -n "-e s/$hash/$size/p ";
done) | \
sort -n -r -k1
```
When you're ready to perform the surgery, append a `cut` command to get the
relative path to the file _only_, without listing the size of the file, which
is what we will need when we carry out the git-commit-ectomy:
```
$
git rev-list --all --objects | \
sed -n $(git rev-list --objects --all | \
cut -f1 -d' ' | \
git cat-file --batch-check | \
grep blob | \
sort -n -k 3 | \
\
tail -n40 | \
\
while read hash type size; do
echo -n "-e s/$hash/$size/p ";
done) | \
sort -n -r -k1 | \
cut -f 2 -d' '
```
# an ascii art crash course in surgery
Suppose our patient has a particularly painful
and unnaturally large commit located in their
commit history:
```
This is the commit
to be "ectomied"
\/
__
o---o---(__)---o---o--o
```
The git commit ectomy will rewrite the history
without the problematic commit:
```
__
o---o---(__)---o---o---o old history
\
\---o----o---o---o new history
/\
The problematic commit
is modified to be smaller
in the new history
```
If there is only one branch, no branches or tags
or labels will refer to the old history, so the
commits are not kept in the .git directory.
Finally, running a `git push <remote-name> <branch-name> --force`
will force the old history to be replaced with
the new history on the remote. Here is the final
commit history:
```
o---o
\
\---o----o---o---o new history
```
# demo surgery: setup
Clone an example repo for performing surgery. You don't _need_
a remote repository to do the demo surgery, but we will use one
in our walkthrough.
```
$
git clone https://github.com/charlesreid1/git-commit-ectomy-example
```
## side note: how to make a fat file
We will use the `dd` command to create files with a specified number
of bits. For example, to create a 10 MB file, we can issue the command:
```text
$
dd if=/dev/urandom of=my_big_fat_file bs=1048576 count=10
```
**Important:** You must use `/dev/urandom` with a non-zero block size.
If you use `/dev/zeros` then each file will be identical and git
will not store them separately. Then your surgery will go very badly.
**Note:** `1048576 = 2^20` bytes comes from
the fact that 1 KB = `2^10` bytes, and 1 MB = `2^10` KB,
for a total of `2^20` bytes per megabyte.
`count=10` means we make 10 blocks, each of size 1 MB (1048576 bytes).
## make some text files
We start by adding some small boring text files to the repository:
```
$
echo "hello foo" > foo.txt; echo "hello bar" > bar.txt
```
Now add them to the repo history:
```
$
for item in `/bin/ls -1 *.txt`; do
git add ${item} && git commit ${item} -m "adding ${item}"
done
```
## make some fat files
To demonstrate the importance of specifying the path to the
large files being removed from the repository, we add several
10 MB files inside of a subdirectory. Start with the directory
structure:
```
$
mkdir data1; mkdir data2
```
Now create some files in each of the two directories:
```
$
cd data1/
dd if=/dev/urandom of=bat bs=1048576 count=10
dd if=/dev/urandom of=cat bs=1048576 count=10
dd if=/dev/urandom of=dat bs=1048576 count=10
cd ../
cd data2/
dd if=/dev/urandom of=fat bs=1048576 count=10
dd if=/dev/urandom of=rat bs=1048576 count=10
cd ../
```
Now we have the following directory structure:
```
$
tree .
.
├── bar.txt
├── data1
│   ├── bat
│   ├── cat
│   └── dat
├── data2
│   ├── fat
│   └── rat
└── foo.txt
```
```
$
ls -lhg data1
-rw-r--r-- 1 staff 10M Apr 10 18:30 bat
-rw-r--r-- 1 staff 10M Apr 10 18:30 cat
-rw-r--r-- 1 staff 10M Apr 10 18:30 dat
$
ls -lhg data2
-rw-r--r-- 1 staff 10M Apr 10 18:30 fat
-rw-r--r-- 1 staff 10M Apr 10 18:30 rat
```
Also make sure they are unique (hence `/dev/random` and not `/dev/zero`):
```
$
for i in `/bin/ls -1 data1/*at data2/*at`; do
md5 ${i}
done
MD5 (bat) = 140c7d1e5a12c0eb2fefd5529250a280
MD5 (cat) = 9345ca4033c7e42fb009e3b8014570dc
MD5 (dat) = fadc3114fe9a70f688eba0db4e0dc7a9
MD5 (fat) = 39e98200043e438f9070369989b2d964
MD5 (rat) = 77b1c3077041078fd1f371b1bb7dd6e4
```
## commit files
Add the files to the repo in _separate commits_:
```
$
for item in data1/bat data1/cat data1/dat data2/fat data2/rat; do
git add ${item} && git commit ${item} -m "adding ${item}"
done
```
Now push all the commits to the remote (this will take a while):
```
$
git push origin master
```
Now you should see everything in the commit history on Github:
![Repo commit history](/img/history.png)
You should also see it locally in the git log:
```
$
git log --oneline
902b0d8 adding rat
b3376bd adding fat
e2427de adding dat
25682b5 addding cat
495235a addding bat
2506d38 adding bar.txt
2eb8d13 adding foo.txt
```
# demo surgery: procedure
## prepare tools
Use [git-forget-blob.sh](https://tinyurl.com/git-commit-ectomy)
to forget the blob. Start by downloading it:
```
$
wget https://tinyurl.com/git-forget-blob-mac-sh -O git-forget-blob.sh
chmod +x git-forget-blob.sh
```
This script will detect if you are on a Mac,
and if so, will use the GNU `gxargs` instead of
the BSD `xargs`. This requires GNU tools to be
installed via Homebrew:
```
$
brew install gnu-xargs