<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cerise Norling</title><link>https://norling.io/</link><description>Recent content on Cerise Norling</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 27 Mar 2023 10:00:00 -0600</lastBuildDate><atom:link href="https://norling.io/index.xml" rel="self" type="application/rss+xml"/><item><title>Recovering From a Botched Git Rebase</title><link>https://norling.io/rebase-recovery/</link><pubDate>Mon, 27 Mar 2023 10:00:00 -0600</pubDate><guid>https://norling.io/rebase-recovery/</guid><description>&lt;img src="https://norling.io/rebase-recovery/pexels-delcho-dichev-517884.jpg" alt="Featured image of post Recovering From a Botched Git Rebase" />&lt;p>&lt;img src="https://norling.io/rebase-recovery/rebase-messup.jpg"
width="672"
height="429"
srcset="https://norling.io/rebase-recovery/rebase-messup_hu506c34896c96864deb1e6640acb7fb2b_69275_480x0_resize_q75_box.jpg 480w, https://norling.io/rebase-recovery/rebase-messup_hu506c34896c96864deb1e6640acb7fb2b_69275_1024x0_resize_q75_box.jpg 1024w"
loading="lazy"
alt="we&amp;rsquo;ve all been there"
class="gallery-image"
data-flex-grow="156"
data-flex-basis="375px"
>&lt;/p>
&lt;p>When rebasing, it&amp;rsquo;s inevitable that you will delete something you didn&amp;rsquo;t intend to, or finish a rebase before you&amp;rsquo;re actually done. When this happens, the best thing you can do is take a step back and truly evaluate the current state of the remote repository and your local repository.&lt;/p>
&lt;ul>
&lt;li>Is the content actually deleted?&lt;/li>
&lt;li>Have I pushed my changes out yet?&lt;/li>
&lt;li>Could someone else have a copy of the content I deleted?&lt;/li>
&lt;/ul>
&lt;p>Even if you&amp;rsquo;ve already force pushed out your changes, there are ways to recover deleted content.&lt;/p>
&lt;h2 id="check-if-theres-anything-in-git-reflog">Check if there&amp;rsquo;s anything in git reflog&lt;/h2>
&lt;p>Git Reflog is a &lt;em>referential log&lt;/em> of all the states your local git repository has been in. Every removed branch, deleted commit, unsigned commit, previously squashed commits, even viewing a specific commit SHA is logged and recorded. Reflog is a local only thing, so if you delete a local git repository and clone it down again you&amp;rsquo;ll lose all your reflogs.&lt;/p>
&lt;p>You can access your referential logs by running &lt;code>git reflog&lt;/code>. By default, it retains the last 90 days of git activity. Every time you run a git specific action, git runs a garbage collector that discards anything outside the defined retention period. If you wanted to, you could increase this threshold by running &lt;code>git config gc.reflogExpire 120&lt;/code>. Don&amp;rsquo;t forget to pass &lt;code>--global&lt;/code> if you want it to apply to all repositories.&lt;/p>
&lt;h3 id="accessing-reflogs">Accessing reflogs&lt;/h3>
&lt;p>All reflogs are dynamic and measured according to an offset from your latest action. To access reflogs, first you need to identify which reflog to examine. Run &lt;code>git reflog&lt;/code> to identify the state you want to examine. Then run &lt;code>git checkout HEAD{23}&lt;/code> where 23 is the number offset from &lt;code>git reflog&lt;/code>.&lt;/p>
&lt;p>In this state, you can poke around and look at the file content to confirm that it is what it should be.&lt;/p>
&lt;h3 id="accessing-git-logs-within-reflogs">Accessing git logs within reflogs&lt;/h3>
&lt;p>Reflogs are really just a reference to a specific commit SHA. The content of that SHA also happens to include the historical revisions at that point in time. That includes the historical output from &lt;code>git log&lt;/code>. If you need to identify a commit SHA that&amp;rsquo;s no longer in &lt;code>git log&lt;/code>, you can checkout an earlier reflog and run &lt;code>git log&lt;/code> to browse commits that were associated with your branch at that point in time. It&amp;rsquo;s very useful for identifying deleted content.&lt;/p>
&lt;p>&lt;img src="https://norling.io/rebase-recovery/reflog-log.png"
width="1024"
height="688"
srcset="https://norling.io/rebase-recovery/reflog-log_hu1e48aad445ea6c2e917bf218a25b915d_82055_480x0_resize_box_3.png 480w, https://norling.io/rebase-recovery/reflog-log_hu1e48aad445ea6c2e917bf218a25b915d_82055_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="Even &amp;ldquo;reflogs&amp;rdquo; have logs"
class="gallery-image"
data-flex-grow="148"
data-flex-basis="357px"
>&lt;/p>
&lt;h3 id="what-if-i-dont-have-reflogs">What if I don&amp;rsquo;t have reflogs?&lt;/h3>
&lt;p>Even if your reflogs are empty, if you know the commit SHA or have tagged a specific commit you can perform a &lt;code>git reset --hard $SHA&lt;/code> to reset to that point in time. The trick there is to know the SHA since if there&amp;rsquo;s no reflog, you&amp;rsquo;re going to have a hard time finding the SHA if it&amp;rsquo;s just local.&lt;/p>
&lt;h2 id="examples">Examples&lt;/h2>
&lt;h3 id="completely-undoing-a-git-rebase">Completely undoing a git rebase&lt;/h3>
&lt;p>Undoing a rebase completely actually isn&amp;rsquo;t that bad. The process is simply to identify the commit SHA or reflog before the rebase started, then perform a &lt;code>git reset --hard $REF&lt;/code> like so&lt;/p>
&lt;p>&lt;img src="https://norling.io/rebase-recovery/rebase-undo.png"
width="1024"
height="711"
srcset="https://norling.io/rebase-recovery/rebase-undo_hu159e2797ef8bebcd1b1a3b2c94cf796d_91982_480x0_resize_box_3.png 480w, https://norling.io/rebase-recovery/rebase-undo_hu159e2797ef8bebcd1b1a3b2c94cf796d_91982_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="Undoing a git rebase"
class="gallery-image"
data-flex-grow="144"
data-flex-basis="345px"
>&lt;/p>
&lt;h3 id="cherrypicking-deleted-commits">Cherrypicking deleted commits&lt;/h3>
&lt;p>If you need to be more selective about what you do and don&amp;rsquo;t recover, cherrypicking commit SHAs might be a good option for you.&lt;/p>
&lt;p>The hard part is knowing and discovering the commit SHA you intend to recover. Even after you delete commits, they still exist both locally and (maybe) remotely. If you&amp;rsquo;re trying to recover a deleted commit and you know the commit SHA, you can run &lt;code>git cherry-pick $SHA&lt;/code> to get that commit back. After the cherrypick, the commit SHA might change since it&amp;rsquo;s now incorporating the changes between how far back from head it was and where it is now.&lt;/p>
&lt;p>&lt;em>(unless the deleted commit was the latest one, then it will be the same)&lt;/em>&lt;/p>
&lt;p>&lt;img src="https://norling.io/rebase-recovery/soft-delete.png"
width="1024"
height="462"
srcset="https://norling.io/rebase-recovery/soft-delete_hu38138fff9dcaf0ccf220c430f328fa9a_53049_480x0_resize_box_3.png 480w, https://norling.io/rebase-recovery/soft-delete_hu38138fff9dcaf0ccf220c430f328fa9a_53049_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="Commits never die, they just fade away"
class="gallery-image"
data-flex-grow="221"
data-flex-basis="531px"
>&lt;/p>
&lt;h2 id="summary">Summary&lt;/h2>
&lt;p>Unless you&amp;rsquo;ve configured your git garbage collector to discard reflogs, you definitely have everything you need to fix a messed up git rebase. I hope you learned something from this article!&lt;/p>
&lt;p>If you enjoyed this article, have any questions, noticed something inaccurate, or you just want to say hi feel free to drop a comment below or send an email to &lt;a class="link" href="mailto:me@norling.io" >me@norling.io&lt;/a>&lt;/p></description></item><item><title>Writing my Resume in LaTeX</title><link>https://norling.io/latex-resume/</link><pubDate>Sat, 18 Mar 2023 10:00:00 -0600</pubDate><guid>https://norling.io/latex-resume/</guid><description>&lt;img src="https://norling.io/latex-resume/orion-nebula-gb8faf4a6f_1920.jpg" alt="Featured image of post Writing my Resume in LaTeX" />&lt;p>Writing LaTeX sucks, but the results are undeniably better than anything else. This article is a brief introduction into LaTeX, the basic prerequisites to writing documents, what the ecosystem is like, and what it was like writing my resume in LaTeX.&lt;/p>
&lt;h2 id="dark-times-before-latex">Dark Times Before LaTeX&lt;/h2>
&lt;p>I am very picky about resume formatting. If things aren&amp;rsquo;t perfectly aligned, it bothers me on a spiritual level. Before LaTeX, my solution for writing my resume was to make a table in Google Docs, organize the content into columns, and set the table line width to 0 so it would be transparent. This setup worked for quite some time, but it had drawbacks.&lt;/p>
&lt;ul>
&lt;li>Changing the column width for one cell had implications for other cells&lt;/li>
&lt;li>The witdth of each cell was independent from other similar cells. This led to inconsistent spacing on the headers and sections&lt;/li>
&lt;li>Content would shift between when the table was set to 1 or 0 line width&lt;/li>
&lt;li>A lot of cells had to be merged together&lt;/li>
&lt;li>Content had to be manually shuffled around for appropriate page balancing&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://norling.io/latex-resume/old-resume.png"
width="1225"
height="888"
srcset="https://norling.io/latex-resume/old-resume_hub344f9099b17fb396f2101a0f7a55a88_184676_480x0_resize_box_3.png 480w, https://norling.io/latex-resume/old-resume_hub344f9099b17fb396f2101a0f7a55a88_184676_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="My old resume with the table cell outline set to 1pt and 0pt width"
class="gallery-image"
data-flex-grow="137"
data-flex-basis="331px"
>&lt;/p>
&lt;p>I felt really good about the results, but over time as I would make modifications the pain points started to wear on me. I asked my friend &lt;a class="link" href="https://github.com/Persistent13" target="_blank" rel="noopener"
>Dakota Clark&lt;/a> about his resume, and he said he wrote his in LaTeX. I didn&amp;rsquo;t know much about LaTeX at the time. I knew it was frequently used for academic papers and was developed as an easier way to express mathematical equations.&lt;/p>
&lt;p>My interest was piqued, and I decided to give it a shot. He gave me a copy of his resume, and I scanned over it to try and learn LaTeX. I also looked on Overleaf for public LaTeX resumes, but I didn&amp;rsquo;t see anything that really looked like what I wanted. I ended up writing my own from scratch!&lt;/p>
&lt;h2 id="latex-concepts">LaTeX Concepts&lt;/h2>
&lt;h3 id="environments">Environments&lt;/h3>
&lt;p>When you declare things like font, size, color, and other text modifiers, you&amp;rsquo;re applying it to an environment. Think of an environment as something like a title, paragraph, footer, or table; A subsection of things that needs to be handled in a certain way. You can create your own environments, or you can use pre-made ones included in libraries. You can use a pre-made an environment like so&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>environmentName&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> I&amp;#39;m in the environment!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>environmentName&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Any text alterations you make inside that codeblock will only apply to that subset of text. You can declare your own custom environment like so&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newenvironment&lt;/span>&lt;span class="nb">{&lt;/span>foo&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">% executes as the top portion of the environment
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span> &lt;span class="k">\color&lt;/span>&lt;span class="nb">{&lt;/span>Green&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>list&lt;span class="nb">}{&lt;/span>x&lt;span class="nb">}{&lt;/span>&lt;span class="k">\raggedright&lt;/span>&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">% executes as the bottom portion of the environment
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>list&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>You can also have environments within environments&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>environmentName&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> I&amp;#39;m in the environment!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>foo&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> I&amp;#39;m in the custom environment!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>foo&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>environmentName&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="packages">Packages&lt;/h3>
&lt;p>TeXLive has a large number of default document classes and packages that are immediately available at your disposal, and you&amp;rsquo;ll have to use a lot of them. Set a page&amp;rsquo;s margins? Use &lt;code>geometry&lt;/code>. Merge cells in a table? Use &lt;code>multirow&lt;/code> or &lt;code>multicol&lt;/code>. Color something? Use &lt;code>xcolor&lt;/code>. Want to add a hyperlink? Use &lt;code>hyperref&lt;/code>.&lt;/p>
&lt;p>Package discovery largely entails scrawling through StackOverflow or Overleaf for threads where people talk about how to do things. Overall, the ecosystem is well documented with most LaTeX libraries choosing to document their programs in PDFs on CTAN. You can find an example of the geometry package &lt;a class="link" href="https://ctan.org/pkg/geometry" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>You can import a package like so&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\usepackage&lt;/span>&lt;span class="nb">{&lt;/span>fontawesome&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="text-sizing">Text Sizing&lt;/h3>
&lt;p>Because of how LaTeX handles text, you are limited to a small range of predetermined sizes that should meet most people&amp;rsquo;s needs. If you want to go larger or smaller, you&amp;rsquo;ll need to find a package with different supported sizes. Overleaf has some excellent docuemntation on font sizing you can read &lt;a class="link" href="https://www.overleaf.com/learn/latex/Font_sizes%2C_families%2C_and_styles" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;h3 id="fonts">Fonts&lt;/h3>
&lt;p>Using a specific font isn&amp;rsquo;t as easy as you might think it would be. To use a font, you first have to identify what the font&amp;rsquo;s name as it&amp;rsquo;s defined in LaTeX. Once you have that name, you can apply it to an environment like so&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>foo&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\fontfamily&lt;/span>&lt;span class="nb">{&lt;/span>&amp;lt;familyname&amp;gt;&lt;span class="nb">}&lt;/span>&lt;span class="k">\selectfont&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>foo&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Packages like fontenc make using fonts much easier. To look at fonts online, I&amp;rsquo;d recommend reading over the tug.org font catalogue &lt;a class="link" href="https://tug.org/FontCatalogue" target="_blank" rel="noopener"
>https://tug.org/FontCatalogue&lt;/a>&lt;/p>
&lt;h3 id="tolerance">Tolerance&lt;/h3>
&lt;p>Whenever a line of text is justified, LaTeX must make a determination on how much whitespace spread between words can be tolerated without looking weird. It also decides just how much you can go past a margin before it puts the next word on a newline. Tolerance is an integer set between 0 and 10000. It&amp;rsquo;s easiest to understand in a picture&lt;/p>
&lt;p>&lt;img src="https://norling.io/latex-resume/tolerance.png"
width="1101"
height="549"
srcset="https://norling.io/latex-resume/tolerance_hud584df6b618d60d99949f82aea12c5fd_122223_480x0_resize_box_3.png 480w, https://norling.io/latex-resume/tolerance_hud584df6b618d60d99949f82aea12c5fd_122223_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="An image showcasing tolerance in LaTex"
class="gallery-image"
data-flex-grow="200"
data-flex-basis="481px"
>&lt;/p>
&lt;h3 id="document-classes">Document Classes&lt;/h3>
&lt;p>There are many different types of documents, and all those documents have things in common regardless of who wrote the document. Classes are a collection of common parameters and characteristics in a document that should apply to all documents of that type. TeXLive includes a few document classes that you can use like report, book, article, or letter. Article is a good class to use if you want a blank template to work with.&lt;/p>
&lt;h3 id="functions-and-variables">Functions and Variables&lt;/h3>
&lt;p>You declare a variable the same way you declare a function; Just create a function that returns the value you want assigned to the variable. You can then use that function wherever you want to.&lt;/p>
&lt;h3 id="drawing-things">Drawing Things&lt;/h3>
&lt;p>There are a million ways to do what you probably want, and 50% of those ways will probably involve using TikZ. TikZ allows you to draw pictures in LaTeX. The way you draw pictures might be appealing to mathemeticians, but it&amp;rsquo;s not a very enjoyable experience otherwise. There are a lot of packages that utilize TikZ to draw things for you in a more easy to write format.&lt;/p>
&lt;p>I use a package called &lt;code>mdframed&lt;/code> that uses TikZ to outline text boxes around words and color them.&lt;/p>
&lt;h2 id="writing-the-resume">Writing the Resume&lt;/h2>
&lt;p>It can be very helpful to observe a project from creation to completion, so I&amp;rsquo;ve added a step by step example on github you can inspect to compare. A picture of the PDF output is included in the &lt;code>README.md&lt;/code> of the repository so this blogpost doesn&amp;rsquo;t get too long. You can find it &lt;a class="link" href="https://github.com/cnorling/resume-public/tree/main/example" target="_blank" rel="noopener"
>here&lt;/a>&lt;/p>
&lt;h3 id="file-setup">File Setup&lt;/h3>
&lt;p>I start by defining a document and a document class. &lt;code>resume.cls&lt;/code> is the class and &lt;code>resume.tex&lt;/code> is the document. I put shared functions and formatting related things in &lt;code>resume.cls&lt;/code>. The content of the resume itself goes in &lt;code>resume.tex&lt;/code>. I add some content to &lt;code>resume.cls&lt;/code> to declare its parent document class, and link &lt;code>resume.tex&lt;/code> to that class. I also add a special environment named document to &lt;code>resume.tex&lt;/code> and put my name in it.&lt;/p>
&lt;p>&lt;img src="https://norling.io/latex-resume/01_file-setup.png"
width="645"
height="912"
srcset="https://norling.io/latex-resume/01_file-setup_hua8b2ff1cea4f7b648e6f0d9d68c039b4_5150_480x0_resize_box_3.png 480w, https://norling.io/latex-resume/01_file-setup_hua8b2ff1cea4f7b648e6f0d9d68c039b4_5150_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="general file setup"
class="gallery-image"
data-flex-grow="70"
data-flex-basis="169px"
>&lt;/p>
&lt;h3 id="content">Content&lt;/h3>
&lt;p>When working with a document that requires a lot of formatting, it can be helpful to have all your content already on the page so you can observe how the text will behave as you make changes. For this example, there&amp;rsquo;s a mix of real text and fake text. I&amp;rsquo;ll use the lipsum package and add it to &lt;code>resume.cls&lt;/code>. After it&amp;rsquo;s imported, I can use the &lt;code>\lipsum&lt;/code> function to get some example content.&lt;/p>
&lt;p>Some of the content needs to be handled differently from the others though. I&amp;rsquo;ll declare a list environment for the qualifications and skills, then add some placeholder items to it.&lt;/p>
&lt;p>&lt;img src="https://norling.io/latex-resume/02_content.png"
width="642"
height="908"
srcset="https://norling.io/latex-resume/02_content_hu706936aa629809b124f64a43cd5f123f_83903_480x0_resize_box_3.png 480w, https://norling.io/latex-resume/02_content_hu706936aa629809b124f64a43cd5f123f_83903_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="adding some content"
class="gallery-image"
data-flex-grow="70"
data-flex-basis="169px"
>&lt;/p>
&lt;h3 id="heading">Heading&lt;/h3>
&lt;p>The first formatting thing I want to tackle is the page margins. I like my resume to have short vertical margins and wider horizontal margins. I can use the geometry package to setup page margins like so&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\usepackage&lt;/span>&lt;span class="nb">{&lt;/span>geometry&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\geometry&lt;/span>&lt;span class="nb">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> a4paper,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> left=20mm,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> right=20mm,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> top=8mm,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> bottom=8mm,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The second formatting thing I want to tackle is the heading. Before I can do that, I need to add some variables so that I can use their content in &lt;code>resume.cls&lt;/code>. After adding them with &lt;code>\newcommand{\functionName}{string}&lt;/code> I can then call &lt;code>\functionName&lt;/code> to access their output.&lt;/p>
&lt;p>My heading isn&amp;rsquo;t something that&amp;rsquo;s really going to change, so the strategy I use for my heading is a function that takes no parameters that pulls from the variables we just declared. I define a heading command and add the content we have in our header like so&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\heading&lt;/span>&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\name&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\github&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\website&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\email&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\phone&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\address&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>I want things roughly aligned with where they need to go, and I can do that with an environment called a tabular. Table declarations in LaTeX are very finnicky. They look best as code when their content is kept simple and straightforward. We pass a few parameters to indicate how many cells we want, how wide those cells should be, and how they should align. We&amp;rsquo;ll also want to use the package &lt;code>tabularx&lt;/code> since it fixes some issues that native LaTeX tabulars have. Here&amp;rsquo;s an example&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}{&lt;/span>p&lt;span class="nb">{&lt;/span>200pt&lt;span class="nb">}&lt;/span> p&lt;span class="nb">{&lt;/span>120pt&lt;span class="nb">}&lt;/span> p&lt;span class="nb">{&lt;/span>120pt&lt;span class="nb">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">% define the table content and separate cells with &amp;amp;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span> &lt;span class="c">% newlines in tables are declared with \\ at the end
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span> &lt;span class="k">\name&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\github&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\website&lt;/span> &lt;span class="k">\\&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\email&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\phone&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The document is already looking much better! The next thing I want to do is increase the size of my name and capitalize it as well as the sections. For that, we can use &lt;code>\MakeUppercase{}&lt;/code> and &lt;code>\huge&lt;/code>. I also want the things on the right side of the heading to align to the right side of the page; We can do that by applying the &lt;code>&amp;gt;{\raggedright\arraybackslash}&lt;/code> directive to the column in question.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\heading&lt;/span>&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}{&lt;/span>p&lt;span class="nb">{&lt;/span>200pt&lt;span class="nb">}&lt;/span> p&lt;span class="nb">{&lt;/span>120pt&lt;span class="nb">}&lt;/span> &amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\RaggedLeft&lt;/span>&lt;span class="nb">}&lt;/span>p&lt;span class="nb">{&lt;/span>120pt&lt;span class="nb">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\MakeUppercase&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\huge\name&lt;/span>&lt;span class="nb">}&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\github&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\website&lt;/span> &lt;span class="k">\\&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\email&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\phone&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;img src="https://norling.io/latex-resume/03_weird-spacing.png"
width="624"
height="58"
srcset="https://norling.io/latex-resume/03_weird-spacing_hub312725c3a2f848c5bccfe4c94ee9a65_7061_480x0_resize_box_3.png 480w, https://norling.io/latex-resume/03_weird-spacing_hub312725c3a2f848c5bccfe4c94ee9a65_7061_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="Heading without any cells merged"
class="gallery-image"
data-flex-grow="1075"
data-flex-basis="2582px"
>&lt;/p>
&lt;p>My name looks bigger, but now the table&amp;rsquo;s content isn&amp;rsquo;t aligned. To fix this, I merge the empty cell below my name with the &lt;code>multirow&lt;/code> package. It&amp;rsquo;s at this point that I give up keeping rough cell alignment since the cast name is so long.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\heading&lt;/span>&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}{&lt;/span>p&lt;span class="nb">{&lt;/span>200pt&lt;span class="nb">}&lt;/span> p&lt;span class="nb">{&lt;/span>120pt&lt;span class="nb">}&lt;/span> &amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\RaggedLeft&lt;/span>&lt;span class="nb">}&lt;/span>p&lt;span class="nb">{&lt;/span>120pt&lt;span class="nb">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\multirow&lt;/span>&lt;span class="nb">{&lt;/span>2&lt;span class="nb">}{&lt;/span>200pt&lt;span class="nb">}{&lt;/span>&lt;span class="k">\MakeUppercase&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\huge\name&lt;/span>&lt;span class="nb">}}&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\github&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\website&lt;/span> &lt;span class="k">\\&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\email&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\phone&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;img src="https://norling.io/latex-resume/03_better-spacing.png"
width="623"
height="43"
srcset="https://norling.io/latex-resume/03_better-spacing_hu042a27ee156c7244a7a19e8fde3e74b7_6910_480x0_resize_box_3.png 480w, https://norling.io/latex-resume/03_better-spacing_hu042a27ee156c7244a7a19e8fde3e74b7_6910_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="Heading with the two cells merged"
class="gallery-image"
data-flex-grow="1448"
data-flex-basis="3477px"
>&lt;/p>
&lt;p>Okay my name is vertically aligned now, but that line to print my name is absurdly long and makes the table illegible from a code standpoint. I&amp;rsquo;m going to obfuscate how my name&amp;rsquo;s casted with another command.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\heading&lt;/span>&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}{&lt;/span>p&lt;span class="nb">{&lt;/span>200pt&lt;span class="nb">}&lt;/span> p&lt;span class="nb">{&lt;/span>120pt&lt;span class="nb">}&lt;/span> &amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\RaggedLeft&lt;/span>&lt;span class="nb">}&lt;/span>p&lt;span class="nb">{&lt;/span>120pt&lt;span class="nb">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\multirow&lt;/span>&lt;span class="nb">{&lt;/span>2&lt;span class="nb">}{&lt;/span>200pt&lt;span class="nb">}{&lt;/span>&lt;span class="k">\printName&lt;/span>&lt;span class="nb">}&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\github&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\website&lt;/span> &lt;span class="k">\\&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\email&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\phone&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\printName&lt;/span>&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\MakeUppercase&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\huge\name&lt;/span>&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Definitely better than before, but there&amp;rsquo;s room for improvement.&lt;/p>
&lt;p>&lt;img src="https://norling.io/latex-resume/03_heading.png"
width="591"
height="840"
srcset="https://norling.io/latex-resume/03_heading_huf3ab08dec794e66a46c4bad27211cd64_71346_480x0_resize_box_3.png 480w, https://norling.io/latex-resume/03_heading_huf3ab08dec794e66a46c4bad27211cd64_71346_1024x0_resize_box_3.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="70"
data-flex-basis="168px"
>&lt;/p>
&lt;h3 id="formatting">Formatting&lt;/h3>
&lt;h4 id="paragraph-indentation">Paragraph Indentation&lt;/h4>
&lt;p>To fix the paragraph indentation on this resume, I use the &lt;code>parskip&lt;/code> package. I don&amp;rsquo;t have the capability to fix the heading indentation at this time, but it won&amp;rsquo;t be a problem with the styling we&amp;rsquo;ll do later.&lt;/p>
&lt;h4 id="hyphenated-linebreaks">Hyphenated Linebreaks&lt;/h4>
&lt;p>Some of the words are spread across multiple lines, so I&amp;rsquo;ll want to configure the page&amp;rsquo;s tolerance and disable hyphenation with the &lt;code>hyphenat&lt;/code> package.&lt;/p>
&lt;h4 id="bullet-points">Bullet Points&lt;/h4>
&lt;p>I&amp;rsquo;d prefer to use a nicer icon than just an asterisk. The &lt;code>favicon&lt;/code> LaTeX library has a lot of good icons to use. I like &lt;code>\faCheckSquare&lt;/code>. I want the bullet points to be in-line with the left side of the page, so I&amp;rsquo;ll have to edit the list&amp;rsquo;s parameters. I also want to change the separation between items to be tighter like so&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>list&lt;span class="nb">}{&lt;/span>&lt;span class="k">\faCheckSquare&lt;/span>&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\setlength&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\leftmargin&lt;/span>&lt;span class="nb">}{&lt;/span>15pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\setlength&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\itemsep&lt;/span>&lt;span class="nb">}{&lt;/span>0pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\itemsep&lt;/span> -0.5em &lt;span class="k">\vspace&lt;/span>&lt;span class="nb">{&lt;/span>-0.5em&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\raggedright&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> foo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> bar
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> baz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> biz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> boz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> buz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> bez
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>list&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h4 id="multiple-column-list">Multiple Column List&lt;/h4>
&lt;p>I&amp;rsquo;d like the skills and tools to be spread out across the page. A package called &lt;code>multicol&lt;/code> lets me spread a single list across multiple columns like so&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>multicols&lt;span class="nb">}{&lt;/span>4&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>list&lt;span class="nb">}{&lt;/span>&lt;span class="k">\faCheckSquare&lt;/span>&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\setlength&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\leftmargin&lt;/span>&lt;span class="nb">}{&lt;/span>15pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\setlength&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\itemsep&lt;/span>&lt;span class="nb">}{&lt;/span>0pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\itemsep&lt;/span> -0.5em &lt;span class="k">\vspace&lt;/span>&lt;span class="nb">{&lt;/span>-0.5em&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\raggedright&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> foo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> bar
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> baz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> biz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> boz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> buz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> bez
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> fiz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> faz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> fox
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> foz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> fyz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>list&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>multicols&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Some of the formatting has leaked into the &lt;code>resume.tex&lt;/code> file with how things are setup now. To fix this, I&amp;rsquo;ll create a custom environment that declares the list as well as a few other options. The skills environment will have one parameter that we declare with &lt;code>\newenvironment{envname}[3]{}{}&lt;/code> where the integer is how many arguments we want the function to have. Values from those parameters are used by referencing their integer in the position prefixed by a pound like this: &lt;code>#1&lt;/code>&lt;/p>
&lt;p>When you use the environment, you add a set of curly brackets after the environment&amp;rsquo;s name with your input like this: &lt;code>\begin{envname}{foo}{bar}{baz}&lt;/code>. Our use-case is much simpler though since we only have one parameter.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="c">% resume.cls
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="k">\newenvironment&lt;/span>&lt;span class="nb">{&lt;/span>skills&lt;span class="nb">}&lt;/span>[1]&lt;span class="nb">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>multicols&lt;span class="nb">}{&lt;/span>#1&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>list&lt;span class="nb">}{&lt;/span>*&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\setlength&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\leftmargin&lt;/span>&lt;span class="nb">}{&lt;/span>15pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\setlength&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\itemsep&lt;/span>&lt;span class="nb">}{&lt;/span>0pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\itemsep&lt;/span> -0.5em &lt;span class="k">\vspace&lt;/span>&lt;span class="nb">{&lt;/span>-0.5em&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\raggedright&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>list&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>multicols&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">% resume.tex
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>skills&lt;span class="nb">}{&lt;/span>4&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> foo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> bar
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> baz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> biz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> boz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> buz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> bez
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> fiz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> faz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> fox
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> foz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\item&lt;/span> fyz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>skills&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h4 id="vertical-padding">Vertical Padding&lt;/h4>
&lt;p>At this point, the spacing between the list we have for qualifications vs skills and tools is different, so I&amp;rsquo;ll have to tweak the qualifications environment a bit with some padding to even things out. I can do this with the &lt;code>\vspace*{8pt}&lt;/code> command.&lt;/p>
&lt;p>What&amp;rsquo;s that asterisk mean? Well, to be honest a lot of the default behaviors of LaTeX are inconsistent and sometimes undesirable. Rather than update the package, newer packages by maintainers are added to TeXlive to fix these issues. But now there are package naming conflicts. The solution is to change the case sensitivity of the package or suffix an asterisk at the end. &lt;code>\vspace&lt;/code> and &lt;code>\vspace*&lt;/code> are both different packages with different behaviors. If you see a package with an asterisk, you should use that over the default package because it&amp;rsquo;s more likely up-to-date.&lt;/p>
&lt;h4 id="font">Font&lt;/h4>
&lt;p>We&amp;rsquo;ll want to set the font too. I like &lt;code>comfortaa&lt;/code>, so I&amp;rsquo;ll set it globally with the &lt;code>comfortaa&lt;/code> package.&lt;/p>
&lt;h4 id="text-color">Text Color&lt;/h4>
&lt;p>Black on white is very harsh on the eyes, so changing the text color will help. I can do that by configuring a default color in the class like this &lt;code>\color{darkgray}&lt;/code>.&lt;/p>
&lt;p>I&amp;rsquo;d like to also organize the job content similar to how the header is handled. I&amp;rsquo;ll create a new environment that takes 3 parameters with a 2x2 table. To format the text, I&amp;rsquo;ll bold the job and date, italicize the title, and capitalize the date. With this table, I&amp;rsquo;ll need some more advanced formatting utilities so I&amp;rsquo;ll use a &lt;code>tabularx&lt;/code> instead.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="c">% resume.cls
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="k">\newenvironment&lt;/span>&lt;span class="nb">{&lt;/span>job&lt;span class="nb">}&lt;/span>[3]&lt;span class="nb">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\vspace&lt;/span>&lt;span class="nb">{&lt;/span>5pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>tabularx&lt;span class="nb">}{&lt;/span>1&lt;span class="k">\textwidth&lt;/span>&lt;span class="nb">}&lt;/span> &lt;span class="nb">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> @&lt;span class="nb">{}&lt;/span>&amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\hsize&lt;/span>=1&lt;span class="k">\hsize\linewidth&lt;/span>=&lt;span class="k">\hsize\raggedright\arraybackslash&lt;/span>&lt;span class="nb">}&lt;/span>X@&lt;span class="nb">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> @&lt;span class="nb">{}&lt;/span>&amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\hsize&lt;/span>=1&lt;span class="k">\hsize\linewidth&lt;/span>=&lt;span class="k">\hsize\raggedleft\arraybackslash&lt;/span>&lt;span class="nb">}&lt;/span>X@&lt;span class="nb">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\textbf&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\large&lt;/span> #1&lt;span class="nb">}&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\MakeUppercase&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\textbf&lt;/span>&lt;span class="nb">{&lt;/span>#3&lt;span class="nb">}}&lt;/span> &lt;span class="k">\\&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\textit&lt;/span>&lt;span class="nb">{&lt;/span>#2&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>tabularx&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">% resume.tex
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>job&lt;span class="nb">}{&lt;/span>job name&lt;span class="nb">}{&lt;/span>job title&lt;span class="nb">}{&lt;/span>12-2021 - present&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>job&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;img src="https://norling.io/latex-resume/04_formatting.png"
width="643"
height="913"
srcset="https://norling.io/latex-resume/04_formatting_hu5a6dbd0cb12451978251e8aadeeed6d9_98753_480x0_resize_box_3.png 480w, https://norling.io/latex-resume/04_formatting_hu5a6dbd0cb12451978251e8aadeeed6d9_98753_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="Now we&amp;rsquo;re cooking"
class="gallery-image"
data-flex-grow="70"
data-flex-basis="169px"
>&lt;/p>
&lt;h3 id="styling">Styling&lt;/h3>
&lt;p>Now I want to add some style to the page to make it less plain.&lt;/p>
&lt;h4 id="favicons-and-hyperlinks">Favicons and Hyperlinks&lt;/h4>
&lt;p>With the favicon package I imported earlier, I can add some cool icons to the header. I&amp;rsquo;ll need to expand the table width and add a few more helper functions and packages to setup hyperlinks and size the icons; The &lt;code>hyperref&lt;/code> package lets me setup hyperlinks. I&amp;rsquo;ll also configure a color variable globally and use that later on.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\heading&lt;/span>&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}{&lt;/span> p&lt;span class="nb">{&lt;/span>200pt&lt;span class="nb">}&lt;/span> &amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\raggedleft\arraybackslash&lt;/span>&lt;span class="nb">}&lt;/span>p&lt;span class="nb">{&lt;/span>30pt&lt;span class="nb">}&lt;/span> p&lt;span class="nb">{&lt;/span>90pt&lt;span class="nb">}&lt;/span>&amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\raggedleft\arraybackslash&lt;/span>&lt;span class="nb">}&lt;/span> p&lt;span class="nb">{&lt;/span>90pt&lt;span class="nb">}&lt;/span> &amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\raggedright\arraybackslash&lt;/span>&lt;span class="nb">}&lt;/span> p&lt;span class="nb">{&lt;/span>30pt&lt;span class="nb">}&lt;/span> &lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\multirow&lt;/span>&lt;span class="nb">{&lt;/span>2&lt;span class="nb">}{&lt;/span>200pt&lt;span class="nb">}{&lt;/span>&lt;span class="k">\printName&lt;/span>&lt;span class="nb">}&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\icogithub&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\github&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\website&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\icowebsite&lt;/span> &lt;span class="k">\\&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\icophone&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\phone&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\email&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\icomail&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\printName&lt;/span>&lt;span class="nb">}{&lt;/span>&lt;span class="k">\MakeUppercase&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\huge&lt;/span> &lt;span class="k">\name&lt;/span>&lt;span class="nb">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\ico&lt;/span>&lt;span class="nb">}&lt;/span>[2]&lt;span class="nb">{{&lt;/span>&lt;span class="k">\large\href&lt;/span>&lt;span class="nb">{&lt;/span>#1&lt;span class="nb">}{&lt;/span>#2&lt;span class="nb">}}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\icogithub&lt;/span>&lt;span class="nb">}{&lt;/span>&lt;span class="k">\ico&lt;/span>&lt;span class="nb">{&lt;/span>https://github.com/&lt;span class="k">\github&lt;/span>&lt;span class="nb">}{&lt;/span>&lt;span class="k">\faGithub&lt;/span>&lt;span class="nb">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\icomail&lt;/span>&lt;span class="nb">}{&lt;/span>&lt;span class="k">\ico&lt;/span>&lt;span class="nb">{&lt;/span>mailto:&lt;span class="k">\email&lt;/span>&lt;span class="nb">}{&lt;/span>&lt;span class="k">\faEnvelope&lt;/span>&lt;span class="nb">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\icophone&lt;/span>&lt;span class="nb">}{&lt;/span>&lt;span class="k">\ico&lt;/span>&lt;span class="nb">{&lt;/span>tel:&lt;span class="k">\phone&lt;/span>&lt;span class="nb">}{&lt;/span>&lt;span class="k">\faPhone&lt;/span>&lt;span class="nb">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\icowebsite&lt;/span>&lt;span class="nb">}{&lt;/span>&lt;span class="k">\ico&lt;/span>&lt;span class="nb">{&lt;/span>https://&lt;span class="k">\website&lt;/span>&lt;span class="nb">}{&lt;/span>&lt;span class="k">\faGlobe&lt;/span>&lt;span class="nb">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\setcolor&lt;/span>&lt;span class="nb">}{&lt;/span>&lt;span class="k">\color&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\colour&lt;/span>&lt;span class="nb">}}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h4 id="text-boxes">Text Boxes&lt;/h4>
&lt;p>I found a package called &lt;code>mdframed&lt;/code> that lets me draw boxes around text. It works by allowing you to declare a type of environment that&amp;rsquo;s specific to the &lt;code>mdframed&lt;/code> package. I declare a positive and negative variant for some variety on the page like so&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newmdenv&lt;/span>[
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> middlelinewidth=0pt,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> backgroundcolor=&lt;span class="k">\colour&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> roundcorner=2pt,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> fontcolor=White,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> innerleftmargin=5pt,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> innertopmargin=-8pt,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> userdefinedwidth=150pt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">]&lt;span class="nb">{&lt;/span>infobox&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newmdenv&lt;/span>[
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> userdefinedwidth=&lt;span class="k">\textwidth&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> linecolor=&lt;span class="k">\colour&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> linewidth=1pt,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> backgroundcolor=White,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> roundcorner=2pt,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> fontcolor=&lt;span class="k">\colour&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> innerleftmargin=5pt,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> innerbottommargin=2pt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">]&lt;span class="nb">{&lt;/span>infoboxinvert&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>I use the infobox like I would any ordinary environment. For the header, I&amp;rsquo;m going to override a few settings on the infobox. I&amp;rsquo;ll also tweak the name to be splayed across two lines by adjusting the multirow cell width like so&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\heading&lt;/span>&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>infobox&lt;span class="nb">}&lt;/span>[
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> innertopmargin=4pt,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> innerbottommargin=25pt,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> innerleftmargin=0pt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}{&lt;/span> p&lt;span class="nb">{&lt;/span>200pt&lt;span class="nb">}&lt;/span> &amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\raggedleft&lt;/span>&lt;span class="nb">}&lt;/span>p&lt;span class="nb">{&lt;/span>30pt&lt;span class="nb">}&lt;/span> p&lt;span class="nb">{&lt;/span>90pt&lt;span class="nb">}&lt;/span>&amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\raggedleft&lt;/span>&lt;span class="nb">}&lt;/span> p&lt;span class="nb">{&lt;/span>90pt&lt;span class="nb">}&lt;/span> &amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\raggedright\arraybackslash&lt;/span>&lt;span class="nb">}&lt;/span> p&lt;span class="nb">{&lt;/span>30pt&lt;span class="nb">}&lt;/span> &lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\multirow&lt;/span>&lt;span class="nb">{&lt;/span>2&lt;span class="nb">}{&lt;/span>150pt&lt;span class="nb">}{&lt;/span>&lt;span class="k">\printName&lt;/span>&lt;span class="nb">}&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\icogithub&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\github&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\website&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\icowebsite&lt;/span> &lt;span class="k">\\&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\icophone&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\phone&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\email&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\icomail&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>tabular&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>infobox&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Now I&amp;rsquo;ll wrap the job environment in the inverted infobox.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newenvironment&lt;/span>&lt;span class="nb">{&lt;/span>job&lt;span class="nb">}&lt;/span>[3]&lt;span class="nb">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\vspace&lt;/span>&lt;span class="nb">{&lt;/span>5pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>infoboxinvert&lt;span class="nb">}&lt;/span>[]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>tabularx&lt;span class="nb">}{&lt;/span>1&lt;span class="k">\textwidth&lt;/span>&lt;span class="nb">}&lt;/span> &lt;span class="nb">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> @&lt;span class="nb">{}&lt;/span>&amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\hsize&lt;/span>=1&lt;span class="k">\hsize\linewidth&lt;/span>=&lt;span class="k">\hsize\raggedright\arraybackslash&lt;/span>&lt;span class="nb">}&lt;/span>X@&lt;span class="nb">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> @&lt;span class="nb">{}&lt;/span>&amp;gt;&lt;span class="nb">{&lt;/span>&lt;span class="k">\hsize&lt;/span>=1&lt;span class="k">\hsize\linewidth&lt;/span>=&lt;span class="k">\hsize\raggedleft\arraybackslash&lt;/span>&lt;span class="nb">}&lt;/span>X@&lt;span class="nb">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\textbf&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\large&lt;/span> #1&lt;span class="nb">}&lt;/span> &lt;span class="nb">&amp;amp;&lt;/span> &lt;span class="k">\MakeUppercase&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\textbf&lt;/span>&lt;span class="nb">{&lt;/span>#3&lt;span class="nb">}}&lt;/span> &lt;span class="k">\\&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\textit&lt;/span>&lt;span class="nb">{&lt;/span>#2&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>tabularx&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>infoboxinvert&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}{}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>For the sections, I&amp;rsquo;ll declare a function that uses the infobox environment and accepts a parameter for the section name. I&amp;rsquo;ll configure the width of the boxes to be static so they all align down the page.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newcommand&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\sector&lt;/span>&lt;span class="nb">}&lt;/span>[1]&lt;span class="nb">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>infobox&lt;span class="nb">}&lt;/span>[userdefinedwidth=143pt]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\section*&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\MakeUppercase&lt;/span>&lt;span class="nb">{&lt;/span>#1&lt;span class="nb">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>infobox&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>I&amp;rsquo;ll set the color of the checkboxes as well with the &lt;code>\setcolor&lt;/code> command I defined earlier.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-latex" data-lang="latex">&lt;span class="line">&lt;span class="cl">&lt;span class="k">\newenvironment&lt;/span>&lt;span class="nb">{&lt;/span>skills&lt;span class="nb">}&lt;/span>[1]&lt;span class="nb">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\vspace*&lt;/span>&lt;span class="nb">{&lt;/span>-5pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>multicols&lt;span class="nb">}{&lt;/span>#1&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\begin&lt;/span>&lt;span class="nb">{&lt;/span>list&lt;span class="nb">}{&lt;/span>&lt;span class="k">\setcolor\faCheckSquare&lt;/span>&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\setlength&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\leftmargin&lt;/span>&lt;span class="nb">}{&lt;/span>15pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\setlength&lt;/span>&lt;span class="nb">{&lt;/span>&lt;span class="k">\itemsep&lt;/span>&lt;span class="nb">}{&lt;/span>0pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\itemsep&lt;/span> -0.5em &lt;span class="k">\vspace&lt;/span>&lt;span class="nb">{&lt;/span>-0.5em&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\raggedright&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>list&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\end&lt;/span>&lt;span class="nb">{&lt;/span>multicols&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">\vspace*&lt;/span>&lt;span class="nb">{&lt;/span>-5pt&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>I&amp;rsquo;ll also update some of the placeholder content to be more like an actual resume.&lt;/p>
&lt;p>&lt;img src="https://norling.io/latex-resume/05_styling.png"
width="641"
height="911"
srcset="https://norling.io/latex-resume/05_styling_hue9752f2687018aeb8fbea1ba464c4fa3_166641_480x0_resize_box_3.png 480w, https://norling.io/latex-resume/05_styling_hue9752f2687018aeb8fbea1ba464c4fa3_166641_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="The final resume"
class="gallery-image"
data-flex-grow="70"
data-flex-basis="168px"
>&lt;/p>
&lt;h2 id="ending-notes">Ending Notes&lt;/h2>
&lt;p>LaTeX is a very old language with a lot of inconsistencies, weird syntax, and small issues that can make it a frustrating language to work with. That being said, I love the results and will definitely use it going forward. If you&amp;rsquo;d like to see this resume on github, check it out &lt;a class="link" href="https://github.com/cnorling/resume-public" target="_blank" rel="noopener"
>here&lt;/a>! You&amp;rsquo;re more than welcome to fork it for personal use and tweak it however you like =]&lt;/p>
&lt;p>If you enjoyed this article, have any questions, noticed something inaccurate, or you just want to say hi feel free to drop a comment below or send an email to &lt;a class="link" href="mailto:me@norling.io" >me@norling.io&lt;/a>&lt;/p></description></item><item><title>Easily Resolving Git Merge Conflicts</title><link>https://norling.io/merge-conflicts/</link><pubDate>Mon, 13 Mar 2023 10:00:00 -0600</pubDate><guid>https://norling.io/merge-conflicts/</guid><description>&lt;img src="https://norling.io/merge-conflicts/pexels-pixabay-41951.jpg" alt="Featured image of post Easily Resolving Git Merge Conflicts" />&lt;h2 id="when-it-rains-it-pours">When it rains it pours&lt;/h2>
&lt;p>It seems like whenever there&amp;rsquo;s a merge conflict, it&amp;rsquo;s rarely just one file in a single commit. It&amp;rsquo;s always multiple files in multiple commits, and that&amp;rsquo;s where the endless stream of pain comes when you do things like cherry pick multiple commits or run &lt;code>git pull origin main&lt;/code>.&lt;/p>
&lt;p>Merge conflicts in git are a necessary evil &lt;em>because&lt;/em> of the nature of git. Git has zero insight into which changes precede over eachother, and it relies on the user to make those informed decisions.&lt;/p>
&lt;h2 id="making-things-easier-with-merge-strategy-options">Making things easier with merge strategy options&lt;/h2>
&lt;p>Any command that involves a merge conflict is also going to include the optional parameter for specifying a merge strategy. &lt;code>-X ours&lt;/code> and &lt;code>-X theirs&lt;/code> are two neat ways to say&lt;/p>
&lt;blockquote>
&lt;p>If there are conflicts, prefer these changes over those&lt;/p>
&lt;/blockquote>
&lt;h2 id="in-practice">In Practice&lt;/h2>
&lt;p>If you want to try it for yourself, run this shell script!&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">git&lt;/span> branch a
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">git&lt;/span> branch b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">git&lt;/span> checkout a
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">echo&lt;/span> &lt;span class="s2">&amp;#34;a&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> foo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">git&lt;/span> add foo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">git&lt;/span> commit &lt;span class="na">-m&lt;/span> &lt;span class="s2">&amp;#34;added a to foo&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">git&lt;/span> checkout b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">echo&lt;/span> &lt;span class="s2">&amp;#34;b&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> foo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">git&lt;/span> add foo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">git&lt;/span> commit &lt;span class="na">-m&lt;/span> &lt;span class="s2">&amp;#34;added b to foo&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">git&lt;/span> merge a &lt;span class="na">-X&lt;/span> theirs
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>After running this script, &lt;code>foo&lt;/code> in branch &lt;code>b&lt;/code> will be overwritten with the changes from branch &lt;code>a&lt;/code>. You can safely delete both branches &lt;code>a&lt;/code> and &lt;code>b&lt;/code> without reprecussions (unless for some reason you have a branch that already exists named a or b).&lt;/p>
&lt;p>If you enjoyed this article, have any questions, noticed something inaccurate, or you just want to say hi feel free to drop a comment below or send an email to &lt;a class="link" href="mailto:me@norling.io" >me@norling.io&lt;/a>&lt;/p></description></item><item><title>Rewriting History With Git Rebases</title><link>https://norling.io/git-rebase/</link><pubDate>Mon, 06 Mar 2023 10:00:00 -0600</pubDate><guid>https://norling.io/git-rebase/</guid><description>&lt;img src="https://norling.io/git-rebase/stars-ijf3k5368.jpg" alt="Featured image of post Rewriting History With Git Rebases" />&lt;p>Have you or a loved one ever wanted to:&lt;/p>
&lt;ul>
&lt;li>delete a commit&lt;/li>
&lt;li>edit the content of a commit&lt;/li>
&lt;li>remove a specific file that was accidentally added to a commit&lt;/li>
&lt;li>include missed files in a commit&lt;/li>
&lt;li>fix a typo in an old commit message&lt;/li>
&lt;li>combine a bunch of commits together&lt;/li>
&lt;/ul>
&lt;p>If you&amp;rsquo;ve worked with git, you&amp;rsquo;ve likely needed to do at least one of these at some point. And if you&amp;rsquo;re like me, you&amp;rsquo;ve probably read over the &lt;code>--help&lt;/code> documentation of git to figure out how to do some of these things, and oh boy the docs can be cagey about telling you what exactly to do. This article is a reference on just a few things you can do with git rebases, and how to do it. &lt;a class="link" href="https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History" target="_blank" rel="noopener"
>Here&amp;rsquo;s the equivalent article&lt;/a> directly from the git documentation if you&amp;rsquo;re interested in further reading.&lt;/p>
&lt;h2 id="rewriting-history-is-controversial">Rewriting history is controversial&lt;/h2>
&lt;p>&lt;em>Rebasing involves rewriting history.&lt;/em> &lt;br>
&lt;em>Rewriting history involves force pushing to overwrite the remote state of a repository.&lt;/em> &lt;br>
&lt;em>Force pushing has the potential to delete others work (if you rebase recklessly).&lt;/em>&lt;/p>
&lt;p>Rewriting history is controversial. Some say it&amp;rsquo;s okay to modify history because it&amp;rsquo;s sometimes necessary and can enhance git history. Others say it&amp;rsquo;s not okay because git is supposed to be a historical representation of all changes, and you should prefer to roll your fixes forward. In my opinion if your historical modifications don&amp;rsquo;t impact others, it should be acceptable to rewrite history. It&amp;rsquo;s important when managing git history to ensure that you aren&amp;rsquo;t impacting other people&amp;rsquo;s work. You should follow these general practices:&lt;/p>
&lt;ul>
&lt;li>Always use &lt;code>--force-with-lease&lt;/code> when pushing out rebases.&lt;/li>
&lt;li>Avoid rewriting history if you&amp;rsquo;re collaborating with others on the same branch.&lt;/li>
&lt;li>If you have to rebase changes while working with others, &lt;code>git pull&lt;/code> often to always make sure you&amp;rsquo;re working with the latest content.&lt;/li>
&lt;li>Don&amp;rsquo;t edit other people&amp;rsquo;s commits unless they know about and consent to the edits.&lt;/li>
&lt;/ul>
&lt;h2 id="so-what-is-a-git-rebase">So what is a git rebase?&lt;/h2>
&lt;p>A git rebase is the act of disassembling and reassembling a range of commits. The function&amp;rsquo;s name comes from its original purpose of changing the forked location of your branch to a different commit or branch. There are two general types of rebases. Ones that require human interaction to complete, and ones that do not. A human interactive rebase would involve doing things like adding, editing, deleting, combining, and splitting commits. A noninteractive rebase would be attaching your base to a different branch.&lt;/p>
&lt;p>Interactive rebases are executed by running &lt;code>git rebase --interactive $GITREVISION&lt;/code>
Non-interactive rebases are executed by running &lt;code>git rebase $GITREVISION&lt;/code>&lt;/p>
&lt;h2 id="how-do-i-git-rebase">How do I git rebase?&lt;/h2>
&lt;h3 id="determine-what-commits-to-rebase">Determine what commits to rebase&lt;/h3>
&lt;p>You can use most valid forms of &lt;a class="link" href="https://git-scm.com/docs/gitrevisions" target="_blank" rel="noopener"
>gitrevision syntax&lt;/a>, but &lt;code>git log --oneline&lt;/code> and &lt;code>git reflog&lt;/code> are the most common options for discovering historical edits. &lt;code>git log --oneline&lt;/code> will only show you commits. &lt;code>git reflog&lt;/code> will show you commits in addition to actions you take like checking out branches, other rebases you&amp;rsquo;ve done, git resets, commit amends, and other historical modifications made to git. The only time I use referential syntax is if I&amp;rsquo;m recovering a previously deleted commit since git will locally log the commit even after deleting it.&lt;/p>
&lt;p>&lt;img src="https://norling.io/git-rebase/reflog-vs-log.png"
width="1479"
height="557"
srcset="https://norling.io/git-rebase/reflog-vs-log_hu8e79abb3556b9acee6e463bc311d5ade_90512_480x0_resize_box_3.png 480w, https://norling.io/git-rebase/reflog-vs-log_hu8e79abb3556b9acee6e463bc311d5ade_90512_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="an example showcasing the differences between a git log and git reflog with git commits in their relative positions"
class="gallery-image"
data-flex-grow="265"
data-flex-basis="637px"
>&lt;/p>
&lt;p>Here&amp;rsquo;s a table of some gitrevision syntaxes you can use in a rebase, and what they roughly translate to.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>syntax&lt;/th>
&lt;th>meaning&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>016a428&lt;/code>&lt;/td>
&lt;td>rebase all commits between HEAD and &lt;code>016a428&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>HEAD@{5}&lt;/code>&lt;/td>
&lt;td>rebase all commits contained in my last 5 git actions&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>HEAD~5&lt;/code>&lt;/td>
&lt;td>rebase the last 5 commits&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>HEAD@{5hr}&lt;/code>&lt;/td>
&lt;td>rebase all commits made in the last 5 hours&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>':/^Foo'&lt;/code>&lt;/td>
&lt;td>rebase all commits made between HEAD and the first commit found with a commit message that matches the regular expression &lt;code>^Foo&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;img src="https://norling.io/git-rebase/git-log-output.png"
width="1024"
height="300"
srcset="https://norling.io/git-rebase/git-log-output_huca4dee658d4610e5872360461a217451_14147_480x0_resize_box_3.png 480w, https://norling.io/git-rebase/git-log-output_huca4dee658d4610e5872360461a217451_14147_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="an example of the output from git log &amp;ndash;oneline"
class="gallery-image"
data-flex-grow="341"
data-flex-basis="819px"
>&lt;/p>
&lt;h3 id="edit-your-git-rebase-todo">Edit your git-rebase-todo&lt;/h3>
&lt;p>A &lt;code>git-rebase-todo&lt;/code> file is a manifest containing all the commits in your rebase that you can edit to instruct git on what changes you want to make. It includes the action you want to do, the commit hash, and the commit message for easy identification. An example looks like this:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">pick&lt;/span> e9f16f3 baz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">pick&lt;/span> ff783de buz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Rebase aa7b423..ff783de onto aa7b423 (2 commands)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Commands:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># p, pick &amp;lt;commit&amp;gt; = use commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># r, reword &amp;lt;commit&amp;gt; = use commit, but edit the commit message
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># e, edit &amp;lt;commit&amp;gt; = use commit, but stop for amending
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># s, squash &amp;lt;commit&amp;gt; = use commit, but meld into previous commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># f, fixup [-C | -c] &amp;lt;commit&amp;gt; = like &amp;#34;squash&amp;#34; but keep only the previous
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># commit&amp;#39;s log message, unless -C is used, in which case
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># keep only this commit&amp;#39;s message; -c is same as -C but
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># opens the editor
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># x, exec &amp;lt;command&amp;gt; = run command (the rest of the line) using shell
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># b, break = stop here (continue rebase later with &amp;#39;git rebase --continue&amp;#39;)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># d, drop &amp;lt;commit&amp;gt; = remove commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># l, label &amp;lt;label&amp;gt; = label current HEAD with a name
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># t, reset &amp;lt;label&amp;gt; = reset HEAD to a label
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># m, merge [-C &amp;lt;commit&amp;gt; | -c &amp;lt;commit&amp;gt;] &amp;lt;label&amp;gt; [# &amp;lt;oneline&amp;gt;]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># . create a merge commit using the original merge commit&amp;#39;s
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># . message (or the oneline, if no original merge commit was
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># . specified); use -c &amp;lt;commit&amp;gt; to reword the commit message
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># These lines can be re-ordered; they are executed from top to bottom.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># If you remove a line here THAT COMMIT WILL BE LOST.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># However, if you remove everything, the rebase will be aborted.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The only commands in that list I haven&amp;rsquo;t used are exec, break, label, reset, and merge.&lt;/p>
&lt;h3 id="start-the-rebase">Start the rebase&lt;/h3>
&lt;p>As soon as you save the &lt;code>git-rebase-todo&lt;/code> file and close it, the rebase will start. The first step git does is it saves all your commits into a staging area for safekeeping if you need to perform any reversions. Then it goes through each commit oldest to newest. Actions like pick, squash, fixup, and drop will be executed automatically. Actions like reword and edit will pause for you to make your requested changes. If it&amp;rsquo;s a git message change, it will open the commit message file and allow you to make your changes.&lt;/p>
&lt;p>Edit steps are a bit more complex. Git has no idea what modifications you intend to make on the edit step, so you need to tell it when you&amp;rsquo;re finished. You can make any changes you need to the commit, and once you&amp;rsquo;re finished you run &lt;code>git commit --amend&lt;/code> to add your content to the commit. Then run &lt;code>git rebase --continue&lt;/code> to tell git you&amp;rsquo;re done with the current commit.&lt;/p>
&lt;h3 id="push-up-your-rebase">Push up your rebase&lt;/h3>
&lt;p>If you&amp;rsquo;re editing any commits that aren&amp;rsquo;t strictly local to your machine, you&amp;rsquo;ll have to instruct your remote git website that yes, you did mean to delete that commit. To do this, run &lt;code>git push --force-with-lease&lt;/code>. If you don&amp;rsquo;t, git will reject your changes when you try and push because it thinks it has content you&amp;rsquo;re missing that you need to pull down.&lt;/p>
&lt;p>&lt;code>--force-with-lease&lt;/code> is the same as &lt;code>--force&lt;/code> except it has a failsafe to abort if there are remote changes your local git client doesn&amp;rsquo;t know about. Always use it when force pushing changes.&lt;/p>
&lt;h2 id="deleting-commits">Deleting commits&lt;/h2>
&lt;ol>
&lt;li>Determine what commits you want to delete by running &lt;code>git log --oneline&lt;/code> and find the hash of the commit you intend to delete&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">486f3bf&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="nf">HEAD&lt;/span> &lt;span class="na">-&amp;gt;&lt;/span> main&lt;span class="o">)&lt;/span> e18155c658
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">28cabde&lt;/span> 0523d2af6c
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">58098cf&lt;/span> 5a0be3f060
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">add66be&lt;/span> &lt;span class="m">8759405589&lt;/span> &lt;span class="c"># let&amp;#39;s delete this commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">76d462d&lt;/span> f6ecfd8500
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">beeef8f&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="nf">origin&lt;/span>/main, origin/HEAD&lt;span class="o">)&lt;/span> Initial commit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ol start="2">
&lt;li>Go one past that commit and copy its hash&lt;/li>
&lt;li>Run &lt;code>git rebase --interactive 76d462d&lt;/code>&lt;/li>
&lt;li>Modify the &lt;code>git-rebase-todo&lt;/code> to delete the commit&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">drop&lt;/span> add66be &lt;span class="m">8759405589&lt;/span> &lt;span class="c"># I&amp;#39;ve change the action on this commit to drop
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">pick&lt;/span> 58098cf 5a0be3f060
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">pick&lt;/span> 28cabde 0523d2af6c
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">pick&lt;/span> 486f3bf e18155c658
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ol start="5">
&lt;li>Save and close the &lt;code>git-rebase-todo&lt;/code>&lt;/li>
&lt;li>Run &lt;code>git push --force-with-lease&lt;/code> if working with remote changes to overwrite history&lt;/li>
&lt;/ol>
&lt;p>If everything worked, the commit should be gone. You can run &lt;code>git log --oneline&lt;/code> to validate its deletion.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">6144ecd&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="nf">HEAD&lt;/span> &lt;span class="na">-&amp;gt;&lt;/span> main&lt;span class="o">)&lt;/span> e18155c658
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">28971d0&lt;/span> 0523d2af6c
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">ee09104&lt;/span> 5a0be3f060
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># yay the commit is gone!
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">76d462d&lt;/span> f6ecfd8500
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">beeef8f&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="nf">origin&lt;/span>/main, origin/HEAD&lt;span class="o">)&lt;/span> Initial commit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="editing-commit-content">Editing commit content&lt;/h2>
&lt;ol>
&lt;li>Determine what commit you want to edit by running &lt;code>git log --oneline&lt;/code> and find the SHA of the commit you intend to modify&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">2f512ca&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="nf">HEAD&lt;/span> &lt;span class="na">-&amp;gt;&lt;/span> main&lt;span class="o">)&lt;/span> b8e34da2fb
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">1daec94&lt;/span> 53a8322ae0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">49338d3&lt;/span> &lt;span class="m">1890202347&lt;/span> &lt;span class="c"># let&amp;#39;s edit this commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">6dd4f4e&lt;/span> 3fc41f2708
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">10b8051&lt;/span> 79d8d9fc4b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">beeef8f&lt;/span> Initial commit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ol start="2">
&lt;li>Go one past that commit and copy its commit SHA&lt;/li>
&lt;li>Run &lt;code>git rebase --interactive 6dd4f4e&lt;/code>&lt;/li>
&lt;li>Modify the &lt;code>git-rebase-todo&lt;/code> to include your request to edit the commit&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">edit&lt;/span> 49338d3 &lt;span class="m">1890202347&lt;/span> &lt;span class="c"># I&amp;#39;ve changed the action on this commit to edit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">pick&lt;/span> 1daec94 53a8322ae0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">pick&lt;/span> 2f512ca b8e34da2fb
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ol start="5">
&lt;li>Save and close the &lt;code>git-rebase-todo&lt;/code>&lt;/li>
&lt;li>Git will pause on the commit you want to edit&lt;/li>
&lt;li>Make your changes and run &lt;code>git commit --amend&lt;/code> to include the edits&lt;/li>
&lt;li>Run &lt;code>git rebase --continue&lt;/code> to tell git you&amp;rsquo;re done making your changes&lt;/li>
&lt;li>Run &lt;code>git push --force-with-lease&lt;/code> if working with remote changes to overwrite history&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">2093981&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="nf">HEAD&lt;/span> &lt;span class="na">-&amp;gt;&lt;/span> main&lt;span class="o">)&lt;/span> b8e34da2fb
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">d3ecdd3&lt;/span> 53a8322ae0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">12d9704&lt;/span> &lt;span class="m">1890202347&lt;/span> &lt;span class="c"># this commit has a new SHA meaning the changes went through!
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">6dd4f4e&lt;/span> 3fc41f2708
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">10b8051&lt;/span> 79d8d9fc4b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">beeef8f&lt;/span> Initial commit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>If everything worked, the commit should be edited with a new SHA. You can run &lt;code>git log --oneline&lt;/code> to validate its modification.&lt;/p>
&lt;h2 id="combining-commits-by-squashing">Combining commits by squashing&lt;/h2>
&lt;ol>
&lt;li>Determine what commits you want to squash by running &lt;code>git log --oneline&lt;/code> and find the hash of the oldest commit you want to squash&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">c3640e6&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="nf">HEAD&lt;/span> &lt;span class="na">-&amp;gt;&lt;/span> main&lt;span class="o">)&lt;/span> 7ce9769337
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">9f2e595&lt;/span> 3c8c13dfff &lt;span class="c"># let&amp;#39;s squash these two commits
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">e1fce22&lt;/span> 600affbb4a &lt;span class="c"># let&amp;#39;s squash these two commits
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">ed85848&lt;/span> &lt;span class="m">1186105185&lt;/span> &lt;span class="c"># into this commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">64378f8&lt;/span> c8f8d0faf9
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">beeef8f&lt;/span> Initial commit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ol start="2">
&lt;li>go one past that commit and copy its hash&lt;/li>
&lt;li>run &lt;code>git rebase --interactive 64378f8&lt;/code>&lt;/li>
&lt;li>modify the &lt;code>git-rebase-todo&lt;/code> to include your squashes&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">pick&lt;/span> ed85848 &lt;span class="m">1186105185&lt;/span> &lt;span class="c"># this is the commit we&amp;#39;re squashing into
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">squash&lt;/span> e1fce22 600affbb4a &lt;span class="c"># these are the commits we&amp;#39;re squashing
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">squash&lt;/span> 9f2e595 3c8c13dfff &lt;span class="c"># these are the commits we&amp;#39;re squashing
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">pick&lt;/span> c3640e6 7ce9769337
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ol start="5">
&lt;li>save and close the &lt;code>git-rebase-todo&lt;/code>&lt;/li>
&lt;li>git will pause on the newly squashed commit and give you an opportunity to modify the commit message if desired&lt;/li>
&lt;li>save and close the &lt;code>COMMIT_EDITMSG&lt;/code> file to finish the rebase&lt;/li>
&lt;li>run &lt;code>git push --force-with-lease&lt;/code> if working with remote changes to overwrite history&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">8188e83&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="nf">HEAD&lt;/span> &lt;span class="na">-&amp;gt;&lt;/span> main&lt;span class="o">)&lt;/span> 7ce9769337
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">1b4f942&lt;/span> &lt;span class="m">1186105185&lt;/span> &lt;span class="c"># the commit has a new SHA meaning the commits were squashed in!
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">64378f8&lt;/span> c8f8d0faf9
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">beeef8f&lt;/span> Initial commit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>If everything worked, the commit should be edited with a new SHA. You can run &lt;code>git log --oneline&lt;/code> to validate its modification.&lt;/p>
&lt;p>If you enjoyed this article, have any questions, noticed something inaccurate, or you just want to say hi feel free to drop a comment below or send an email to &lt;a class="link" href="mailto:me@norling.io" >me@norling.io&lt;/a>&lt;/p></description></item><item><title>Editing Git Commit Messages</title><link>https://norling.io/edit-commit-messages/</link><pubDate>Sun, 26 Feb 2023 10:00:00 -0600</pubDate><guid>https://norling.io/edit-commit-messages/</guid><description>&lt;img src="https://norling.io/edit-commit-messages/stars-gdb805d2e7_1920.jpg" alt="Featured image of post Editing Git Commit Messages" />&lt;h2 id="summary">Summary&lt;/h2>
&lt;p>You can edit your most recent commit message by running &lt;code>git commit --amend&lt;/code>.&lt;/p>
&lt;p>If you&amp;rsquo;ve already pushed out your commit, you&amp;rsquo;ll have to tell the remote git repository that you intend to rewrite history. You can do this by running &lt;code>git push --force-with-lease&lt;/code> after amending your commit.&lt;/p>
&lt;h2 id="editing-older-commit-messages">Editing older commit messages&lt;/h2>
&lt;p>You can edit older commits with an interactive rebase. A rebase is a way to deconstruct and reconstruct older commits. You can modify things like the files changed in a commit, if the commit was signed, when the commit was created, who it was created by, and in our case you can edit commit messages.&lt;/p>
&lt;p>The first step of a rebase is identifying the rebase&amp;rsquo;s span. Run &lt;code>git log --oneline&lt;/code> to get a top-down list of your latest commits. Find the commit you want to edit, then select the commit hash after it and run &lt;code>git rebase --interactive $HASH&lt;/code>&lt;/p>
&lt;p>In the below example, If we want to edit the commit message &lt;code>baz [e9f16f3]&lt;/code>, we will want to run an interactive rebase on &lt;code>bar [aa7b423]&lt;/code>&lt;/p>
&lt;p>&lt;img src="https://norling.io/edit-commit-messages/rebase.png"
width="373"
height="158"
srcset="https://norling.io/edit-commit-messages/rebase_hu1f4f45ca0aea6edf864db14061657cc4_7006_480x0_resize_box_3.png 480w, https://norling.io/edit-commit-messages/rebase_hu1f4f45ca0aea6edf864db14061657cc4_7006_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="an example of how to select commits for an interactive rebase"
class="gallery-image"
data-flex-grow="236"
data-flex-basis="566px"
>&lt;/p>
&lt;p>After you run this command, git will start a rebase and your configured git editor will give you a prompt asking how you want to proceed with the rebase. It&amp;rsquo;s worth reading this prompt entirely if you&amp;rsquo;ve never seen it before. I&amp;rsquo;ll summarize what&amp;rsquo;s needed for changing the commit message below this codeblock.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">pick&lt;/span> e9f16f3 baz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">pick&lt;/span> ff783de buz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Rebase aa7b423..ff783de onto aa7b423 (2 commands)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Commands:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># p, pick &amp;lt;commit&amp;gt; = use commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># r, reword &amp;lt;commit&amp;gt; = use commit, but edit the commit message
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># e, edit &amp;lt;commit&amp;gt; = use commit, but stop for amending
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># s, squash &amp;lt;commit&amp;gt; = use commit, but meld into previous commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># f, fixup [-C | -c] &amp;lt;commit&amp;gt; = like &amp;#34;squash&amp;#34; but keep only the previous
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># commit&amp;#39;s log message, unless -C is used, in which case
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># keep only this commit&amp;#39;s message; -c is same as -C but
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># opens the editor
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># x, exec &amp;lt;command&amp;gt; = run command (the rest of the line) using shell
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># b, break = stop here (continue rebase later with &amp;#39;git rebase --continue&amp;#39;)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># d, drop &amp;lt;commit&amp;gt; = remove commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># l, label &amp;lt;label&amp;gt; = label current HEAD with a name
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># t, reset &amp;lt;label&amp;gt; = reset HEAD to a label
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># m, merge [-C &amp;lt;commit&amp;gt; | -c &amp;lt;commit&amp;gt;] &amp;lt;label&amp;gt; [# &amp;lt;oneline&amp;gt;]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># . create a merge commit using the original merge commit&amp;#39;s
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># . message (or the oneline, if no original merge commit was
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># . specified); use -c &amp;lt;commit&amp;gt; to reword the commit message
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># These lines can be re-ordered; they are executed from top to bottom.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># If you remove a line here THAT COMMIT WILL BE LOST.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># However, if you remove everything, the rebase will be aborted.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The file you&amp;rsquo;re editing is a &lt;code>git-rebase-todo&lt;/code> file. It&amp;rsquo;s used as a catalog of actions you intend to perform with each commit. It includes the action you want to do, the commit hash, and the commit message for easy identification. It&amp;rsquo;s also bottom-up instead of top-down (your newest commits are at the bottom).&lt;/p>
&lt;p>&lt;code>pick&lt;/code> is the default action. Commits prefixed with &lt;code>pick&lt;/code> are left intact as they were before the rebase began. Since we want to edit the commit message &amp;ldquo;baz&amp;rdquo; The action we want to use is &lt;code>reword&lt;/code>. Edit your git-rebase-todo file and change the word &lt;code>pick&lt;/code> to &lt;code>reword&lt;/code> like so&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">reword&lt;/span> e9f16f3 baz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">pick&lt;/span> ff783de buz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Rebase aa7b423..ff783de onto aa7b423 (2 commands)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Commands:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># p, pick &amp;lt;commit&amp;gt; = use commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># r, reword &amp;lt;commit&amp;gt; = use commit, but edit the commit message
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># e, edit &amp;lt;commit&amp;gt; = use commit, but stop for amending
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># s, squash &amp;lt;commit&amp;gt; = use commit, but meld into previous commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># f, fixup [-C | -c] &amp;lt;commit&amp;gt; = like &amp;#34;squash&amp;#34; but keep only the previous
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># commit&amp;#39;s log message, unless -C is used, in which case
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># keep only this commit&amp;#39;s message; -c is same as -C but
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># opens the editor
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># x, exec &amp;lt;command&amp;gt; = run command (the rest of the line) using shell
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># b, break = stop here (continue rebase later with &amp;#39;git rebase --continue&amp;#39;)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># d, drop &amp;lt;commit&amp;gt; = remove commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># l, label &amp;lt;label&amp;gt; = label current HEAD with a name
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># t, reset &amp;lt;label&amp;gt; = reset HEAD to a label
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># m, merge [-C &amp;lt;commit&amp;gt; | -c &amp;lt;commit&amp;gt;] &amp;lt;label&amp;gt; [# &amp;lt;oneline&amp;gt;]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># . create a merge commit using the original merge commit&amp;#39;s
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># . message (or the oneline, if no original merge commit was
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># . specified); use -c &amp;lt;commit&amp;gt; to reword the commit message
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># These lines can be re-ordered; they are executed from top to bottom.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># If you remove a line here THAT COMMIT WILL BE LOST.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># However, if you remove everything, the rebase will be aborted.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>After you&amp;rsquo;ve made your changes, save the file and close it. Git will then prompt you to edit the commit message.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fish" data-lang="fish">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">baz&lt;/span> &lt;span class="c"># change this line to anything but baz
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Please enter the commit message for your changes. Lines starting
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># with &amp;#39;#&amp;#39; will be ignored, and an empty message aborts the commit.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Date: Sun Feb 26 00:19:24 2023 -0700
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># interactive rebase in progress; onto aa7b423
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Last command done (1 command done):
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># reword e9f16f3 baz
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Next command to do (1 remaining command):
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># pick ff783de buz
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># You are currently editing a commit while rebasing branch &amp;#39;git&amp;#39; on &amp;#39;aa7b423&amp;#39;.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Changes to be committed:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># new file: baz
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">#
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Once you&amp;rsquo;ve made your commit message changes, save the file and close it. Git will finalize the rebase, and you can run &lt;code>git log --oneline&lt;/code> to inspect the changes. To push your changes to the remote git repository, you&amp;rsquo;ll have to run &lt;code>git push --force-with-lease&lt;/code> here as well&lt;/p>
&lt;p>&lt;img src="https://norling.io/edit-commit-messages/edited.png"
width="373"
height="158"
srcset="https://norling.io/edit-commit-messages/edited_huf6671da211fd6c4fd902d6bcb5e8f2a8_4299_480x0_resize_box_3.png 480w, https://norling.io/edit-commit-messages/edited_huf6671da211fd6c4fd902d6bcb5e8f2a8_4299_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="the final message edited"
class="gallery-image"
data-flex-grow="236"
data-flex-basis="566px"
>&lt;/p>
&lt;p>If you enjoyed this article, have any questions, noticed something inaccurate, or you just want to say hi feel free to drop a comment below or send an email to &lt;a class="link" href="mailto:me@norling.io" >me@norling.io&lt;/a>&lt;/p></description></item><item><title>Good Kyverno Admission Control Patterns</title><link>https://norling.io/kyverno-patterns/</link><pubDate>Tue, 12 Jul 2022 16:12:18 -0600</pubDate><guid>https://norling.io/kyverno-patterns/</guid><description>&lt;img src="https://norling.io/kyverno-patterns/pexels-photo-1169754.jpeg" alt="Featured image of post Good Kyverno Admission Control Patterns" />&lt;p>Kyverno is a Kubernetes admission controller used to add policies to your cluster. Admission controllers intercept incoming requests to the Kubernetes api server and check if a field matches a regular expression, then approve or deny the request based on that determination. If you&amp;rsquo;re not familiar with admission controllers already, I&amp;rsquo;d recommend reading &lt;a class="link" href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#what-are-they" target="_blank" rel="noopener"
>the official documentation&lt;/a>.&lt;/p>
&lt;p>If you&amp;rsquo;re in the process of deciding which admisson controller to use in your environment, consider the background of the team that will be maintaining the policies. Do they all know how to program in Golang? If so, &lt;a class="link" href="https://github.com/open-policy-agent/gatekeeper" target="_blank" rel="noopener"
>OPA Gatekeeper&lt;/a> may be a better choice for you. I personally believe that Kyverno is a better admission controller because the barrier for reading and writing policies is significantly lower than OPA. I haven&amp;rsquo;t run into a scenario where I need more verbose or complex syntax beyond what ships in Kyverno by default.&lt;/p>
&lt;h2 id="summary">Summary&lt;/h2>
&lt;ul>
&lt;li>Have some way to whitelist resources&lt;/li>
&lt;li>Make all your transformations with JSON patches&lt;/li>
&lt;li>Narrow down the scope of your whitelists as much as possible&lt;/li>
&lt;li>Configure all policies to accept an array of rules rather than a single ruleset&lt;/li>
&lt;li>Have some way to unit test against admission controller policies when working with k8s manifests in a github repository&lt;/li>
&lt;li>Separate your Kyverno installation from the underlying policies&lt;/li>
&lt;li>Have some way to toggle rule actions between audit and enforcement&lt;/li>
&lt;li>Add remote policies using raw.githubusercontent.com rather than copying them locally&lt;/li>
&lt;li>When referencing remote policies, target a commit hash or branch version rather than the main branch&amp;rsquo;s head&lt;/li>
&lt;li>Avoid mutating resources with policies when possible&lt;/li>
&lt;/ul>
&lt;h2 id="example-boilerplate">Example Boilerplate&lt;/h2>
&lt;p>I created this example github repository that illustrates all of the principles in this article
&lt;a class="link" href="https://github.com/salineselin/kyverno-example" target="_blank" rel="noopener"
>https://github.com/salineselin/kyverno-example&lt;/a>&lt;/p>
&lt;h2 id="recommendations">Recommendations&lt;/h2>
&lt;p>The following sections expand on the gists described earlier&lt;/p>
&lt;h3 id="have-some-way-to-whitelist-resources">Have some way to whitelist resources&lt;/h3>
&lt;p>It is inevitable that you will have resources in your kubernetes clusters that violate policies. Defining some generic templatized process around how you add exceptions to a whitelist is crucial. You can whitelist resources by using the &lt;code>exclude&lt;/code> key like so:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kyverno.io/v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ClusterPolicy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">disallow-capabilities&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">validationFailureAction&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">audit&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">background&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">rules&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">adding-capabilities&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">exclude&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">any&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kinds&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">Pod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">selector&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matchLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">app&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">managed-prometheus-collector&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">match&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">any&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kinds&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">Pod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">validate&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">message&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">&amp;gt;-&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> Any capabilities added beyond the allowed list (AUDIT_WRITE, CHOWN, DAC_OVERRIDE, FOWNER,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> FSETID, KILL, MKNOD, NET_BIND_SERVICE, SETFCAP, SETGID, SETPCAP, SETUID, SYS_CHROOT)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> are disallowed.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">deny&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">conditions&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">all&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{ request.object.spec.[ephemeralContainers, initContainers, containers][].securityContext.capabilities.add[] }}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">operator&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">AnyNotIn&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">value&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">SYS_CHROOT&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="make-all-your-changes-with-json-patches">Make all your changes with JSON patches&lt;/h3>
&lt;p>This applies if you&amp;rsquo;re using Kustomize to manage your Kyverno transformations. Kustomize overlays are excellent at implicitly overlaying all the necessary parameters, but when you start working with array indexes more, you start wiping data that you don&amp;rsquo;t intend to and you usually end up repeating yourself a lot. If you make all your transformations with JSON patches rather than overlays, you have a complete list of all your transformations, and debugging those transformations becomes a lot easier when kustomize executes and can explicitly point out a faulty JSON patch.&lt;/p>
&lt;h3 id="narrow-down-the-scope-of-your-whitelists-as-much-as-possible">Narrow down the scope of your whitelists as much as possible&lt;/h3>
&lt;p>Whitelisting a namespace is a very primitive control for adding exceptions for entities. It&amp;rsquo;s fast and easy to understand, but is grossly overpermissive. Unless you have your RBAC hardened to a point where clusters users don&amp;rsquo;t have visibility into what the policy exceptions are, its trivial for an attacker to just use a different namespace that&amp;rsquo;s been whitelisted.&lt;/p>
&lt;h3 id="configure-all-policies-to-accept-an-array-of-rules-rather-than-a-single-ruleset">Configure all policies to accept an array of rules rather than a single ruleset&lt;/h3>
&lt;p>There are multiple valid syntaxes when defining a policy. You can match according to one object or an array of objects. The preferred method is an array of objects. It&amp;rsquo;s not mentioned in Kyverno&amp;rsquo;s documentation, but if you use an &lt;code>any&lt;/code> match selector, you also have to use the &lt;code>any&lt;/code> selector when creating exclusions. To demonstrate why you want to only work with an array of matches rather than a single defined match, let&amp;rsquo;s work with the following policy:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kyverno.io/v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ClusterPolicy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">disallow-capabilities&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">validationFailureAction&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">audit&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">background&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">rules&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">adding-capabilities&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">match&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kinds&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">Pod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">validate&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">message&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">&amp;gt;-&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> Any capabilities added beyond the allowed list (AUDIT_WRITE, CHOWN, DAC_OVERRIDE, FOWNER,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> FSETID, KILL, MKNOD, NET_BIND_SERVICE, SETFCAP, SETGID, SETPCAP, SETUID, SYS_CHROOT)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> are disallowed.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">deny&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">conditions&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">all&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{ request.object.spec.[ephemeralContainers, initContainers, containers][].securityContext.capabilities.add[] }}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">operator&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">AnyNotIn&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">value&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">SYS_CHROOT&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This policy which you can find in source &lt;a class="link" href="https://github.com/kyverno/policies/blob/main/pod-security/baseline/disallow-capabilities/disallow-capabilities.yaml" target="_blank" rel="noopener"
>here&lt;/a> is perfectly valid. The problem is when you want to whitelist a particular namespace or add another ruleset with more advanced targeting, you have to heavily modify the underlying ruleset with JSON patches.&lt;/p>
&lt;p>Let&amp;rsquo;s say I wanted to add two exceptions according to a label selector. Instead of a single JSON patch that looks something like the following, you would have to add multiple patches to get your policy into your defined state. Transformations are necessary, but excessive transformations mean you have more code to maintain, and legibility is decreased.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">op&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">add&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">/spec/rules/0/exclude&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">value&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">any&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kinds&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">Pod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">selector&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matchLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># gke&amp;#39;s managed prometheus uses the host ports&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">app&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">managed-prometheus-collector&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kinds&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">Pod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">selector&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matchLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># gke&amp;#39;s managed prometheus rule evaluator needs them as well&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">app&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">rule-evaluator&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This is the desirable syntax&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">match&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">any&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kinds&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">Pod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>And this is the less-than-desirable syntax&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">match&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kinds&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">Pod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Almost all of the policies you find today in the &lt;a class="link" href="https://github.com/kyverno/policies" target="_blank" rel="noopener"
>public Kyverno policies repository&lt;/a> now use the array syntax by default, but it wasn&amp;rsquo;t always that way. In &lt;a class="link" href="https://github.com/kyverno/policies/commit/944498575e423eb98d4b31f6ae69e1e8161004c6#diff-77b3af0188557903b284d66fac9ef6be3532b5474ec9382c28f1ec8388f832d1" target="_blank" rel="noopener"
>this earlier commit&lt;/a> you can find remnants of when the configured rules did not use the array syntax.&lt;/p>
&lt;h3 id="have-some-way-to-unit-test-against-admission-controller-policies-when-working-with-k8s-manifests-in-a-github-repository">Have some way to unit test against admission controller policies when working with k8s manifests in a github repository&lt;/h3>
&lt;p>Debugging CI sucks. If your CI|CD pipeline is verbose and takes five minutes to deploy something to a cluster, but it fails due to a failed policy check, it chisels at your soul. Feedback loops become repetitive, slow, and unfruitful. If you&amp;rsquo;re using a CI provider like Github Actions, make a pipeline that runs a unit test using &lt;code>kubectl apply -f /path/to/yaml --dry-run=server&lt;/code>. If this method is unpalatable for your use-case, it&amp;rsquo;s worth looking into tools like &lt;a class="link" href="https://datree.io/" target="_blank" rel="noopener"
>Datree&lt;/a> that offer admission controller unit testing. I personally don&amp;rsquo;t use Datree because until they ship their own admission controller, there will always be a lack of parity between the policies Datree provides and the policies you provide in Kyverno.&lt;/p>
&lt;p>If that isn&amp;rsquo;t soon enough and you&amp;rsquo;re still experiencing pain with iteration, you could potentially use a git hook when you push source control changes to remote (similar to how &lt;a class="link" href="https://www.npmjs.com/package/husky" target="_blank" rel="noopener"
>husky&lt;/a> does it) to get that feedback even sooner. I&amp;rsquo;d recommend only implementing a hook like this if the developers working on kubernetes manifests are acclimated to kubernetes and have their policies pulled down into their local dev cluster, or they&amp;rsquo;re authenticated into a remote cluster with a context they can use to &lt;code>--dry-run=server&lt;/code> against.&lt;/p>
&lt;p>Most of the manifests you write are likely written and then rarely touched, so iteration slow and frequent enough to cause admission controller heartache is likely seldom.&lt;/p>
&lt;h3 id="separate-your-kyverno-installation-from-the-underlying-policies">Separate your Kyverno installation from the underlying policies&lt;/h3>
&lt;p>Respect that the policies you install are separate from the application that enforces the policies. They have divergent lifecycles, but should be respected as harmonious companions&lt;/p>
&lt;h3 id="have-some-way-to-toggle-rule-actions-between-audit-and-enforcement">Have some way to toggle rule actions between audit and enforcement&lt;/h3>
&lt;p>If you&amp;rsquo;re working with remote policies a lot, most of them are usually set to &lt;code>audit&lt;/code> rather than &lt;code>enforce&lt;/code>, so you&amp;rsquo;ll need to make a transformation that changes the &lt;code>validationFailureAction&lt;/code> value. I use this JSON patch:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">op&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">replace&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">/spec/validationFailureAction&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">value&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">enforce&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="add-remote-policies-using-rawgithubusercontentcom-rather-than-copying-them-locally">Add remote policies using raw.githubusercontent.com rather than copying them locally&lt;/h3>
&lt;p>Kustomize allows you to target local as well as remote resources too! Make use of the &lt;a class="link" href="https://github.com/kyverno/policies" target="_blank" rel="noopener"
>Kyverno/policies&lt;/a> repository and use those instead of rewriting what&amp;rsquo;s likely already been written. An example kustomize manifest that uses remote resources looks like this:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kustomize.config.k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Kustomization&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">commonLabels&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">app&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kyverno&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># remote policies&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">https://raw.githubusercontent.com/kyverno/policies/release-1.7/pod-security/baseline/disallow-capabilities/disallow-capabilities.yaml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">https://raw.githubusercontent.com/kyverno/policies/release-1.7/pod-security/baseline/disallow-host-namespaces/disallow-host-namespaces.yaml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">https://raw.githubusercontent.com/kyverno/policies/release-1.7/pod-security/baseline/disallow-host-ports/disallow-host-ports.yaml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">https://raw.githubusercontent.com/kyverno/policies/097ca254c5d52d05bf1aa385d140e8743b9f21ba/best-practices/disallow_default_namespace/disallow_default_namespace.yaml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="when-referencing-remote-policies-target-a-commit-hash-or-branch-version-rather-than-the-main-branchs-head">When referencing remote policies, target a commit hash or branch version rather than the main branch&amp;rsquo;s head&lt;/h3>
&lt;p>In the previous example, you can see that explicit commit hashes are targeted rather than the latest and greatest. If you&amp;rsquo;re using transformations, you&amp;rsquo;ll likely have to stage the changes and update your patches on major updates.&lt;/p>
&lt;h3 id="avoid-mutating-resources-with-policies-when-possible">Avoid mutating resources with policies when possible&lt;/h3>
&lt;p>You can use an admission controller to &lt;a class="link" href="https://kyverno.io/docs/writing-policies/mutate/" target="_blank" rel="noopener"
>mutate offending resources&lt;/a> rather than failing them outright. In my opinion this is something you should not do if you can avoid it. It is generally better to correct the resource manifest at its source rather than mutating it. Mutations are excellent for objects like logging sidecars and other container adjacent services.&lt;/p>
&lt;p>If you enjoyed this article, have any questions, noticed something inaccurate, or you just want to say hi feel free to drop a comment below or send an email to &lt;a class="link" href="mailto:me@norling.io" >me@norling.io&lt;/a>&lt;/p></description></item></channel></rss>