{"id":3383,"date":"2024-01-15T02:15:00","date_gmt":"2024-01-15T07:15:00","guid":{"rendered":"https:\/\/www.both.org\/?p=3383"},"modified":"2024-01-09T15:39:17","modified_gmt":"2024-01-09T20:39:17","slug":"git-concepts-in-less-than-10-minutes","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=3383","title":{"rendered":"Git concepts in less than 10 minutes"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"3383\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">1    <\/span>\r\n<\/div><\/div>\n<p><a href=\"https:\/\/opensource.com\/resources\/what-is-git\" target=\"_blank\" rel=\"noreferrer noopener\">Git<\/a>\u00a0has become the default way to store and transport code in the DevOps generation. Over 93% of developers report that Git is their primary version control system. Almost anyone who has used version control is familiar with\u00a0<code>git add<\/code>,\u00a0<code>git commit<\/code>, and\u00a0<code>git push<\/code>. For most users, that\u2019s all they ever plan to do with Git, and they&#8217;re comfortable with that. It just works for their needs.  <\/p>\n\n\n\n<p>However, from time to time, almost everyone encounters the need to do something a little more advanced, like&nbsp;<code>git rebase<\/code>&nbsp;or&nbsp;<code>git cherry-pick<\/code>&nbsp;or work in a detached head state. This is where many devs start to get a bit nervous.<\/p>\n\n\n\n<p>I&#8217;m here to tell you it is ok! Everyone who has or will ever use Git will likely go through those same pangs of panic.<\/p>\n\n\n\n<p>Git is awesome, but it&#8217;s also intimidating to learn, and it can feel downright confusing sometimes. Git is unlike almost anything else in computer science. You typically learn it piecemeal, specifically in the context of other coding work. Most developers I have met have never formally studied Git beyond perhaps a&nbsp;<a href=\"https:\/\/opensource.com\/resources\/what-is-git\">quick tutorial<\/a>.<\/p>\n\n\n\n<p>Git is open source, meaning you have the freedom to examine the code and see how it works. It&#8217;s written mainly in C which, for many devs and people learning computer science, can make it hard to understand. At the same time, the documentation uses terms like&nbsp;<a href=\"https:\/\/git-scm.com\/docs\/git-rev-parse#_name\">massage parameters<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/git-scm.com\/docs\/gitglossary#Documentation\/gitglossary.txt-aiddefcommit-ishacommit-ishalsocommittish\">commit-ish<\/a>. It can feel a little baffling. You might feel like Git was written for an advanced Linux professional. That is because it originally was.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A brief Git history<\/h2>\n\n\n\n<p>Git started as a specific set of scripts for Linus Torvalds to use to manage patches.<\/p>\n\n\n\n<p>Here&#8217;s how he introduced what would become&nbsp;<a href=\"https:\/\/lore.kernel.org\/all\/Pine.LNX.4.58.0504070747580.28951@ppc970.osdl.org\/\">Git to the Linux kernel mailing list<\/a>:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>So I&#8217;m writing some scripts to try to track things a whole lot faster. Initial indications are that I should be able to do it almost as quickly as I can just apply the patch, but quite frankly, I&#8217;m at most half done, and if I hit a snag, maybe that&#8217;s not true at all. Anyway, the reason I can do it quickly is that my scripts will _not_ be an SCM, they&#8217;ll be a very specific &#8220;log Linus&#8217; state&#8221; kind of thing. That will make the linear patch merge a lot more time-efficient, and thus possible.<\/p>\n<\/blockquote>\n\n\n\n<p>One of the first things I do when I get confused about how Git works is to imagine why and how Linus would apply it to managing patches. It has grown to handle a lot more than that and is indeed a full source code management (SCM), but remembering the first use case is helpful in understanding the &#8220;why&#8221; sometimes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"git-commit\">Git commit<\/h2>\n\n\n\n<p>The core conceptual unit of work in Git is the commit. These are snapshots of the files being tracked within your project folder ( where the&nbsp;<code>.git<\/code>&nbsp;folder lives.)<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"305\" src=\"https:\/\/www.both.org\/wp-content\/uploads\/2024\/01\/gitbeyond.snapshots.png\" alt=\"\" class=\"wp-image-3546\"\/><\/figure>\n\n\n\n<p>It&#8217;s important to remember that Git stores compressed snapshots of the file system, not diffs. Any time you change a file, a whole new compressed version of that file is made and stored in that commit. It does this by creating a super compressed Binary Large Object (blob) out of the file, and then keeping track of it by generating a checksum made with the SHA hashing algorithm. The permanence of your Git history is one of the reasons it&#8217;s vital never to store or hardcode sensitive data in your Git projects. Anyone who can&nbsp;<a href=\"https:\/\/opensource.com\/article\/18\/2\/how-clone-modify-add-delete-git-files\" target=\"_blank\" rel=\"noreferrer noopener\">clone the repo<\/a>&nbsp;has full access to&nbsp;<strong>all<\/strong>&nbsp;the versions of the files.<\/p>\n\n\n\n<p>Git is really efficient. If a file does not change between commits, Git does not make a whole new compressed version for storage. Instead, it just refers back to the previous commit. All commits know what commit came directly before it, called its parents. You can easily see this chain of commits when you run&nbsp;<code>git log<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"265\" src=\"https:\/\/www.both.org\/wp-content\/uploads\/2024\/01\/gitbeyond.commitsandparents.png\" alt=\"Image of commits and their parents.\" class=\"wp-image-3549\"\/><\/figure>\n\n\n\n<p>You have full control over these chains of commits and can do some pretty cool things with them. You can create, delete, merge and reorder them as you see fit. You can even effectively travel through time, explore and even write your commit histories. But it all relies on understanding how Git sees chains of commits, which are generally referred to as branches.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"git-branches\">Git branches<\/h2>\n\n\n\n<p><a href=\"https:\/\/opensource.com\/article\/18\/5\/git-branching\" target=\"_blank\" rel=\"noreferrer noopener\">Branching<\/a>&nbsp;lets you work with multiple chains of commits inside a project. Working with multiple branches (especially when you work with&nbsp;<code>rebase<\/code>) is where many users start to sweat. A common mental model most people have about what branches even are adds to the confusion.<\/p>\n\n\n\n<p>When thinking about branching, most people conjure up images of swim lanes, diverging, and intersecting dots. While those models can be helpful when understanding specific branching strategies and workflows, thinking of Git as a series of numbered dots on a graph can muddy the waters when trying to think about how Git does what it does.<\/p>\n\n\n\n<p>An alternative mental model I find helpful is to think of branches existing in a big spreadsheet. The first column is the parent commit ID, the second is the new commit ID, and then there are columns for metadata, including all the pointers.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1184\" height=\"672\" src=\"https:\/\/www.both.org\/wp-content\/uploads\/2024\/01\/beyondgit.GiBrancheConceptuallytohowGitseesthem.png\" alt=\"Image of how Git organizes its branches.\" class=\"wp-image-3553\"\/><\/figure>\n\n\n\n<p>Pointers keep track of where you are, and which branch is which. Pointers are convenient human-readable references to specific commits. Any reference that leads back to a specific commit is referred to as commit-ish.<\/p>\n\n\n\n<p>The special pointer used to name a branch always points to the newest commit on the chain. You can arbitrarily assign a pointer to any commit with&nbsp;<code>git tag<\/code>, which doesn&#8217;t move. When you&nbsp;<code>git checkout<\/code>&nbsp;or&nbsp;<code>git switch<\/code>&nbsp;between branches, you&#8217;re really telling Git that you want to change the point of reference of Git and move a very special pointer called HEAD in every&nbsp;<code>.git<\/code>&nbsp;folder.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-.git-folder\">The .git folder<\/h2>\n\n\n\n<p>One of the best ways to understand what is going on with Git is to dig into the&nbsp;<code>.git<\/code>&nbsp;folder. If you&#8217;ve never opened this file before, I highly encourage you to open it up and see what&#8217;s there. If you&#8217;re very nervous you might break something, clone an arbitrary open source project to play around with until you feel confident to look into your own project repos.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2048\" height=\"947\" src=\"https:\/\/www.both.org\/wp-content\/uploads\/2024\/01\/gitbeyond.contentsofgitfolder.png\" alt=\"\" class=\"wp-image-3556\"\/><\/figure>\n\n\n\n<p>One of the first things you notice is how small the files are.<\/p>\n\n\n\n<p>Things are measured in terms of bytes or kilobytes, at the largest. Git is extremely efficient!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"head\">HEAD<\/h3>\n\n\n\n<p>Here in the&nbsp;<code>.git<\/code>&nbsp;folder, you find the special file HEAD. It&#8217;s a very small file, only a handful of bytes in size. If you open it up, you see it\u2019s only one line long.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git &gt; HEAD\n  ref:refs\/heads\/main<\/code><\/pre>\n\n\n\n<p>One of the phrases you will often encounter when reading about Git is &#8220;everything is local.&#8221; From Git&#8217;s perspective, wherever HEAD is pointing is &#8220;here.&#8221; HEAD is the point of reference for how Git interacts with other branches, other refs, and other copies of itself.<\/p>\n\n\n\n<p>In this example, the&nbsp;<code>ref:<\/code>&nbsp;is pointing at another pointer, a branch name pointer. Following that path, you can find a file that looks much like the spreadsheet from earlier. Git just takes the latest commit ID from the file and knows that is the commit HEAD is referring to.<\/p>\n\n\n\n<p>If HEAD refers to a specific commit with no other pointer attached, then HEAD is referred to as &#8220;detached.&#8221; Working in a detached HEAD state is completely safe, but limits what you can do, like make new commits from there. To get out of a detached HEAD state, just checkout another pointer, like the branch name, for example,&nbsp;<code>git checkout main<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"config\">Config<\/h3>\n\n\n\n<p>Another critical file for helping Git keep track of things is the&nbsp;<code>.git\/config<\/code>&nbsp;file. This is just one of the places Git leads and stores configuration. You&#8217;re likely already familiar with the&nbsp;<code>--global<\/code>&nbsp;level of Git config, stored in your home directory in your&nbsp;<code>.gitconfig<\/code>&nbsp;file. There are actually five places Git loads config, each overriding the previous configuration. The order Git loads config is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>--system<\/code>&nbsp;This loads config specific to your operating system<\/li>\n\n\n\n<li><code>--global<\/code>&nbsp;Affects you as a user,&nbsp;<code>user.name<\/code>&nbsp;and&nbsp;<code>user.email<\/code>&nbsp;stored here<\/li>\n\n\n\n<li><code>--local<\/code>&nbsp;This sets repo specific info, like remotes and hooksPath<\/li>\n\n\n\n<li><code>--worktree<\/code>&nbsp;The worktree is what is compressed into an individual commit<\/li>\n\n\n\n<li><code>--blob<\/code>&nbsp;individual compressed files can have their own settings<\/li>\n<\/ul>\n\n\n\n<p>You can see all config for a repo by running&nbsp;<code>git config --list --show-origin<\/code><\/p>\n\n\n\n<p>You can leverage your local config to use multiple Git personas. Override the&nbsp;<code>user.name<\/code>&nbsp;and&nbsp;<code>user.email<\/code>&nbsp;in&nbsp;<code>.gitconfig<\/code>. Leveraging the local config is particularly useful when dividing your time between work projects, personal repos, and any open source contributions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"git-hooks\">Git hooks<\/h3>\n\n\n\n<p>Git has a built-in powerful automation platform called&nbsp;<a href=\"https:\/\/www.redhat.com\/sysadmin\/git-hooks?intcmp=7013a000002qLH8AAM\" target=\"_blank\" rel=\"noreferrer noopener\">Git hooks<\/a>. Git hooks allows you to execute scripts that will run when certain events happen in Git. You can write scripts in any scripting language you prefer that is available to your environment. There are 17 hooks available.<\/p>\n\n\n\n<p>If you look in any repo&#8217;s&nbsp;<code>.git\/hooks<\/code>&nbsp;folder, you see a collection of&nbsp;<code>.sample<\/code>&nbsp;files. These are pre-written samples meant to get you started. Some of them contain some odd-looking code. Odd, perhaps, until you remember that these mainly were added to serve the original use case for Linux kernel work and were written by people living in a sea of Perl and Bash scripts. You can make the scripts do anything you want.<\/p>\n\n\n\n<p>Here&#8217;s an example of a hook I use for personal repos:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/sur\/bin\/env bash\ncurl https:\/\/icanhazdadjoke.com\necho \u201c\u201d<\/code><\/pre>\n\n\n\n<p>In this example, every time I run&nbsp;<code>git commit<\/code>&nbsp;but before the commit message is committed to my Git history, Git executes the script. (Thanks to Edward Thomson&#8217;s&nbsp;<a href=\"https:\/\/www.edwardthomson.com\/blog\/reintroducing_git_dad.html\">git-dad<\/a>&nbsp;for the inspiration.)<\/p>\n\n\n\n<p>Of course, you can do practical things, too, like checking for&nbsp;<a href=\"https:\/\/github.com\/GitGuardian\/ggshield#pre-commit\">hardcoded secrets before making a commit<\/a>. To read more about Git Hooks and to find many, many example scripts, check out Matthew Hudson&#8217;s fantastic&nbsp;<a href=\"https:\/\/githooks.com\/\">GitHooks.com<\/a>&nbsp;site.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"advanced-git\">Advanced Git<\/h2>\n\n\n\n<p>Now you have a better understanding of how Git sees the world and works behind the scenes, and you&#8217;ve seen how you can make it do your bidding with scripts. In my next article, I&#8217;ll address some advanced tools and commands in Git.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Understanding Git is essential to open source development, but it can be intimidating to learn. Let this tutorial be your first step to getting to know Git.<\/p>\n","protected":false},"author":36,"featured_media":3545,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[202],"tags":[206,205],"class_list":["post-3383","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-git","tag-concepts","tag-git"],"modified_by":"David Both","_links":{"self":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/3383","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/36"}],"replies":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3383"}],"version-history":[{"count":10,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/3383\/revisions"}],"predecessor-version":[{"id":3573,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/3383\/revisions\/3573"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/3545"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3383"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3383"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3383"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}