<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>repository on Digi Hunch</title><link>https://static.digihunch.com/tag/repository/</link><description>Recent content in repository on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Tue, 01 Apr 2025 23:34:34 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/repository/index.xml" rel="self" type="application/rss+xml"/><item><title>GitHub Action Gotchas</title><link>https://static.digihunch.com/2023/01/github-action-gotchas/</link><pubDate>Fri, 27 Jan 2023 01:15:02 -0400</pubDate><guid>https://static.digihunch.com/2023/01/github-action-gotchas/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/gh-action-feature.webp" alt="Featured image of post GitHub Action Gotchas" /&gt;&lt;p class="wp-block-paragraph"&gt;I &lt;a href="https://static.digihunch.com/2021/05/getting-started-with-github-actions/"&gt;started with GitHub Actions&lt;/a&gt; a couple years ago. Recently I came across a few interesting use cases while I was trying to setup Terraform workflow with GitHub actions. These use cases prompted me to make use some new features in GitHub Action. So I put them in a post here.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-runners-can-assume-iam-role-in-aws"&gt;Runners can assume IAM Role in AWS&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In many scenarios we want to execute AWS CLI command from GitHub action. Also, executables such as terraform inherits credential from AWS CLI. The credential should be a temporary role-based credential instead of an IAM user based on access keys. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There is a GitHub Action called &lt;a href="https://github.com/marketplace/actions/configure-aws-credentials-for-github-actions"&gt;configure-aws-credentials-for-github-actions&lt;/a&gt; that can help configure GitHub runner using OIDC identity provider (since Nov 2021 v1.6.0). With the action, the GitHub runner can assume an IAM role as an IAM user (with access key), or using a web identity.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For a GitHub runner to have a web identity thereby assume an IAM role, we should &lt;a href="https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#adding-the-identity-provider-to-aws"&gt;configure OIDC provider&lt;/a&gt; in AWS. We can do that from AWS console (i.e. under IAM), or using CloudFormation code. Below is a snippet as an example:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Resources&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;GitHubOIDC&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Type&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AWS&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;IAM&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;OIDCProvider&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Properties&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Url&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;https&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#75715e"&gt;//token.actions.githubusercontent.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ClientIdList&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sts&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;amazonaws&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ThumbprintList&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6938&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fd4d98bab03faadb97b34396831e3780aea1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then from the configured OIDC provider, we can &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html"&gt;obtain a thumbprint&lt;/a&gt;. GitHub action gives the thumbprint &lt;a href="https://github.blog/changelog/2022-01-13-github-actions-update-on-oidc-based-deployments-to-aws/"&gt;here&lt;/a&gt;. In AWS, we configure an IAM role whose AssumeRolePolicyDocument will reference the thumbprint. &lt;a href="https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#adding-the-identity-provider-to-aws"&gt;Here&lt;/a&gt; is an example. In the condition section of AssumeRolePolicyDocument, we can also specify a specific GitHub repository so that only Actions from that repository can assume the IAM role with their web identities.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Configure&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AWS&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Credentials&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;uses&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aws&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;actions&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;configure&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;aws&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;credentials&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;node16&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;role&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;to&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;assume&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;{{ &lt;span style="color:#a6e22e"&gt;vars&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;IAM_ROLE_ARN&lt;/span&gt; }}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;aws&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;region&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;{{ &lt;span style="color:#a6e22e"&gt;vars&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;AWS_REGION&lt;/span&gt; }}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This way, we map a GitHub runner&amp;#8217;s web identity to an IAM role with a &lt;a href="https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#updating-your-github-actions-workflow"&gt;step&lt;/a&gt; using the Action above. We also filter what GitHub org and what repo can trigger actions that assumes the role, by the condition clause in the role statement. If the step fails, we can look at CloudTrail on the AWS side for causes. Look for entries with &lt;em&gt;AssumeRoleWithWebIdentity&lt;/em&gt; as Event Name.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-reusable-workflows"&gt;Reusable workflows &lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For better reusability of Action steps, GitHub introduced reusable workflows (&lt;a href="https://github.blog/2021-11-29-github-actions-reusable-workflows-is-generally-available/"&gt;generally available&lt;/a&gt; since Nov 2021). It is particularly helpful when we need to run a workflow for different environments. The reusable workflows files (YML) can be placed in separate repositories, and be reference as such. This allows enterprises to centralize the management of reusable workflows.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I have been using the &lt;a href="https://github.com/nektos/act"&gt;act&lt;/a&gt; project to emulate GitHub action locally on MacBook. As of Jan 2023, act does &lt;a href="https://github.com/nektos/act/issues/826"&gt;not support&lt;/a&gt; reusable workflow. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With the split between caller and reusable workflows, we have a new challenge of passing secrets and variables between them. It is not straightforward and GitHub documentation needs improvement to get the documentation clear. Also because the word &amp;#8220;environment&amp;#8221; is used in different contexts, it is ambiguous and therefore difficult to Google relevant information.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-passing-variables"&gt;Passing variables&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;First, there are several types of &lt;a href="https://docs.github.com/en/actions/learn-github-actions/variables#defining-environment-variables-for-a-single-workflow"&gt;variables&lt;/a&gt; in GitHub action:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;Environment variable&lt;/strong&gt;: declared under &lt;em&gt;env&lt;/em&gt; keyword in a workflow. To use environment variable, use the &lt;em&gt;env&lt;/em&gt; context. For example: ${{ env.MY_VARIABLE }}&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Configuration variable&lt;/strong&gt;: &lt;a href="https://github.blog/changelog/2023-01-10-github-actions-support-for-configuration-variables-in-workflows/"&gt;introduced&lt;/a&gt; in Jan 2023, &lt;a href="https://docs.github.com/en/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows"&gt;configuration variables&lt;/a&gt; are defined at repository, environment and organization levels. To use configuration variable, use &lt;em&gt;vars&lt;/em&gt; context, and ensure the workflow job specifies a value for environment attribute. &lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Secrets&lt;/strong&gt;: GitHub also calls it &lt;a href="https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-secrets"&gt;Environment secret&lt;/a&gt; when defined at environment level. It works the same way as a configuration variable because it is also specific to an environment. The content is not viewable once set. &lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The reason GitHub action makes this so confusing, is that on &lt;a href="https://docs.github.com/en/actions/learn-github-actions/variables#about-variables"&gt;one&lt;/a&gt; page, its documentation distinguishes between environment variable and configuration variable:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="240" src="https://static.digihunch.com/wp-content/uploads/2023/01/gh1.webp" alt="" class="wp-image-12891" srcset="https://static.digihunch.com/wp-content/uploads/2023/01/gh1.webp 1024w, https://static.digihunch.com/wp-content/uploads/2023/01/gh1-300x70.webp 300w, https://static.digihunch.com/wp-content/uploads/2023/01/gh1-768x180.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On &lt;a href="https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-variables"&gt;another page,&lt;/a&gt; the document refers to configuration variables at environment level as environment variable:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="185" src="https://static.digihunch.com/wp-content/uploads/2023/01/gh2.png" alt="" class="wp-image-12892" srcset="https://static.digihunch.com/wp-content/uploads/2023/01/gh2.png 1024w, https://static.digihunch.com/wp-content/uploads/2023/01/gh2-300x54.png 300w, https://static.digihunch.com/wp-content/uploads/2023/01/gh2-768x139.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It seems that &amp;#8220;configuration variable&amp;#8221; is too new for GitHub to refine its documentation as of January. This semantical confusion gave me a hard time investigating how to pass &amp;#8220;Environment variable&amp;#8221; to reusable workflows. I will stick to the meaning on the first page to distinguish environment variable and configuration variable at environment level. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Passing environment variable isn&amp;#8217;t straightforward. In &lt;a href="https://github.com/orgs/community/discussions/26671"&gt;this&lt;/a&gt; discussion thread, people discussed how inconvenient it is. I used the workaround in &lt;a href="https://github.com/orgs/community/discussions/26671#discussioncomment-4295807"&gt;this&lt;/a&gt; comment, where I had to create a job for the sake of storing variable values to output. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Pass secret is easier. &lt;a href="https://colinsalmcorner.com/consuming-environment-secrets-in-reusable-workflows/"&gt;This&lt;/a&gt; is an insightful blog post (Dec 2021) about passing secret to reusable workflow. The attempt 3 in the post works for me. First, we pass the value of environment to the reusable workflow as an input, then at job level specify the environment with the value. Then in the jobs we can reference secrets as ${{ secrets.NAME }}. The job will pick up the secret based on the correct environment. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It appears that since May 2022, GitHub &lt;a href="https://github.blog/changelog/2022-05-03-github-actions-simplify-using-secrets-with-reusable-workflows/"&gt;introduced&lt;/a&gt; &lt;em&gt;&lt;code&gt;secrets: inherit&lt;/code&gt;&lt;/em&gt; keyword to address this. However, the method above still works for configuration variable.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-authentication-of-github-actions"&gt;Authentication of GitHub Actions &lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;By default, a GitHub action can access the code repository that triggers the action and no other repositories (with &lt;a href="https://docs.github.com/en/actions/security-guides/automatic-token-authentication#about-the-github_token-secret"&gt;GITHUB_TOKEN&lt;/a&gt;). However, in many cases we need to access external repositories. For example, &lt;code&gt;terraform init&lt;/code&gt; command from a GitHub action implicitly calls &lt;code&gt;git clone&lt;/code&gt; to pull module code from external repositories. A GitHub workflow may also reference a workflow file from external repositories.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The question is how to authenticate GitHub workflow to access external repo. This &lt;a href="https://michaelheap.com/ultimate-guide-github-actions-authentication/"&gt;post&lt;/a&gt; has a thorough discussion. We may create a &lt;a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token"&gt;Personal Access Token&lt;/a&gt; and pass it to &lt;a href="https://github.com/marketplace/actions/setup-git-credentials"&gt;set-git-credentials&lt;/a&gt; action. We are essentially sharing a personal credential (and repo access) with a GitHub action, which is not a good practice. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The proper way to solve this problem, is to create a separate GitHub App and grant the access only the repo that the workflow needs to access. The GitHub App will generate a private key. Then we supply the private key to &lt;a href="https://github.com/marketplace/actions/workflow-application-token-action"&gt;workflow-application-token-action&lt;/a&gt; so the workflow can act as the GitHub App, thereby access the external repos. The post has more &lt;a href="https://michaelheap.com/ultimate-guide-github-actions-authentication/#github-apps"&gt;details&lt;/a&gt; in the GitHub App section. Suppose we have &lt;code&gt;terraform get&lt;/code&gt; command to clone external repo, the actions may look like this:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HashiCorp&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Setup&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Terraform&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;uses&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hashicorp&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setup&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;terraform&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Get&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RepoReader&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Token&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_repo_reader_token&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;uses&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;peter&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;murray&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workflow&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;application&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;token&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;action&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;application_id&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;{{ &lt;span style="color:#a6e22e"&gt;vars&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;REPO_READER_APPLICATION_ID&lt;/span&gt; }}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;application_private_key&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;{{ &lt;span style="color:#a6e22e"&gt;secrets&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;REPO_READER_PRIVATE_KEY&lt;/span&gt; }}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Cache&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Git&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Creds&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;uses&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;de&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;vri&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;es&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setup&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;git&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;credentials&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;credentials&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;https&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#75715e"&gt;//x-access-token:${{ steps.get_repo_reader_token.outputs.token }}@github.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Terraform&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Get&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;implicitly&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calls&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;git&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;clone&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;which&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;uses&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;the&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;credential&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cached&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;above&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Terraform&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Get&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;terraform&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Another benefit of using GitHub App is that the token is a short-lived credential that expires as the job is finished, whereas a PAT will expire on a preset date. In this use case we can think of GitHub App as a service account with minimized privilege to read a short list of repos.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-final-words"&gt;Final words&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I came across &lt;a href="https://www.reddit.com/r/devops/comments/10t0xqj/unpopular_opinion_cicd_engines_are_an_awful_idea/"&gt;this&lt;/a&gt; reddit post against pipeline use and there are some legit points. For example, the user is frustrated with the limitation with variable passing and unclear documentation. The post wasn&amp;#8217;t specific to GitHub action but I do share some frustration while working with GitHub Actions.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On a positive note, since I first used GitHub actions, it has evolved quite a bit with new features, although the documentation is somewhat lagging. It is still very helpful as all of these are free to personal use. I look forward to more interesting features. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2023/01/optimize-cpu-and-memory-for-kubernetes-pods/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Optimize CPU and Memory for Kubernetes Pod&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2023/02/dicom-testing-with-tls/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;DICOM testing over TLS&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Getting started with GitHub Actions</title><link>https://static.digihunch.com/2021/05/getting-started-with-github-actions/</link><pubDate>Thu, 27 May 2021 13:52:31 -0400</pubDate><guid>https://static.digihunch.com/2021/05/getting-started-with-github-actions/</guid><description>&lt;p class="wp-block-paragraph"&gt;In my &lt;a class="rank-math-link" href="https://github.com/digihunch/orthweb"&gt;orthweb&lt;/a&gt; &lt;a href="https://static.digihunch.com/projects/"&gt;project&lt;/a&gt;, I had to compile a library on my own. In search for free computing resources I realized that GitHub action can meet all my needs.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-ci-cd-pipeline"&gt;CI/CD pipeline&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As a development project grows, there are many operational tasks demanding automation. Prior to pipeline technology, developers used to use &lt;a href="https://en.wikipedia.org/wiki/Make_(software)"&gt;Makefile&lt;/a&gt; to organize command execution locally. Today, its role has declined, but &lt;a href="https://tech.trivago.com/post/2019-12-20-makefiles-in-2019/"&gt;Makefile&lt;/a&gt; is a good choice in certain situations. In most cases though, to offload the build command execution to a shared system, automation engines like Jenkins came around. Then Jenkins evolved into pipelines.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In strict terms, CI pipeline is the build pipeline; and CD pipeline is release pipeline. The two types of pipelines use pretty much the same pool of building blocks, with different purposes. The build pipeline focuses on producing quality artifact in a consistent manner. The release pipelines focus on system stability while deploying an artifact across different environments. Because release pipelines may connect to different environment, it has to deal with various situations. It is very common to have multiple stages in release pipeline, each stage pointing to a different environment (e.g. DEV, TEST and PROD). At workplace both could be loosely referred to as CI/CD pipeline, or even simply pipeline.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A lot of projects provide pipeline capability: BitBucket, Bamboo, TeamCity, Jenkins, Azure DevOps, AWS CodePipeline, TravisCI etc. Since late 2018, GitHub also joined the game with GitHub actions. It is openly &lt;a class="rank-math-link" href="https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#:~:text=GitHub%20Actions%20usage%20is%20free,is%20controlled%20by%20spending%20limits."&gt;free&lt;/a&gt; for public repositories, and has a free tier for private repositories. It executes task as defined in .github/workflow/action.yaml in the code project. I will take my own project as an example.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-runners"&gt;Runners&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can run jobs in self-hosted runners or GitHub managed runners, similar to other pipeline solutions (e.g. self-hosted agent vs managed agent from Azure DevOps). The &lt;a href="https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#github-hosted-runners" class="rank-math-link"&gt;GitHub hosted runners&lt;/a&gt; only have three operating systems to support: Windows, Ubuntu and MacOS. The Ubuntu and Windows runners are built from Standard_DS2_v2 VMs in Microsoft Azure. They are pre-installed with a &lt;a href="https://github.com/actions/virtual-environments" class="rank-math-link"&gt;virtual environment &lt;/a&gt;with packages required for common build tasks. The same virtual environment is also used in hosted agents by Azure DevOps. While they are free and you can elevate privilege on the runner, you cannot SSH or RDP to it for further troubleshooting. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The &lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners" class="rank-math-link"&gt;self-hosted runners&lt;/a&gt; require users to manage the instance on their own, including configuring virtual environment, installing &lt;a href="https://github.com/actions/runner" class="rank-math-link"&gt;GitHub Action Runner&lt;/a&gt;, etc.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-workflow-file"&gt;Workflow file&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Most pipeline declaration uses YAML or JSON, such as &lt;a href="https://www.jenkins.io/doc/book/pipeline/jenkinsfile/" class="rank-math-link"&gt;Jenkinsfile&lt;/a&gt;, AWS &lt;a href="https://docs.aws.amazon.com/code-samples/latest/catalog/code-catalog-cloudformation-codepipeline.html" class="rank-math-link"&gt;CodePipeline&lt;/a&gt;. GitHub refers to an automation process as a &amp;#8220;workflow&amp;#8221; and you can program the workflow in YAML (.github/workflow/action.yaml). Here is the &lt;a href="https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions" class="rank-math-link"&gt;reference&lt;/a&gt; and an example with environmental variable and versioning: &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;script src="https://gist.github.com/digihunch/e6ed668872c5b0506d25f638ff70727e.js"&gt;&lt;/script&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The handling of environment is documented &lt;a href="https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable" class="rank-math-link"&gt;here&lt;/a&gt;. There are a lot of custom actions available in GitHub &lt;a href="https://github.com/marketplace" class="rank-math-link"&gt;Marketplace&lt;/a&gt;. For example, the versioning in the above example, uses an &lt;a href="https://github.com/marketplace/actions/nuget-build-number-generator" class="rank-math-link"&gt;action&lt;/a&gt; by &lt;a href="https://einaregilsson.com/a-github-action-for-generating-sequential-build-numbers/" class="rank-math-link"&gt;Einar Egilsson&lt;/a&gt;, which is open source itself.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-example-pipeline"&gt;Example pipeline&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;My example &lt;a href="https://github.com/digihunch/orthweb/blob/67542d9329be36e3b8ca895c8b71805c9711aaa3/.github/workflows/action.yml" class="rank-math-link"&gt;pipeline&lt;/a&gt; consists of two phases: &lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Build Library: spin up a docker container to build source code, and publish the artifact&lt;/li&gt;&#10;&lt;li&gt;Publish Image: add the artifact to an existing Docker image, and publish the result as my own image.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The status of the pipeline is also open, and can be found &lt;a href="https://github.com/digihunch/orthweb/actions" class="rank-math-link"&gt;here&lt;/a&gt;. The retention period of artifact is 90 days by default but can be &lt;a href="https://docs.github.com/en/actions/reference/usage-limits-billing-and-administration#artifact-and-log-retention-policy" class="rank-math-link"&gt;customized&lt;/a&gt;. To persist the artifact, I add it to my own Docker image and publish it to &lt;a href="https://hub.docker.com/r/digihunch/orthanc-plugin" class="rank-math-link"&gt;DockerHub&lt;/a&gt;, hence the second phase.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1152" height="724" src="https://static.digihunch.com/wp-content/uploads/2021/05/image-1.png" alt="" class="wp-image-2299"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt; When building the second phase, I need to generate secret from my DockerHub account and store that &lt;a href="https://docs.github.com/en/actions/reference/encrypted-secrets" class="rank-math-link"&gt;encrypted secrets&lt;/a&gt; in GitHub settings, so that the secret value can be referenced in workflow file.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Failures in Actions are displayed in error steps and by default the rest of the steps are skipped. &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="968" height="624" src="https://static.digihunch.com/wp-content/uploads/2021/05/image-2.png" alt="" class="wp-image-2301"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I use the &lt;strong&gt;&lt;a class="rank-math-link" href="https://github.com/marketplace/actions/docker-build-push-action"&gt;Docker build &amp;amp; push plugin&lt;/a&gt;&lt;/strong&gt; to build and push my own docker image to DockerHub. Apart from DockerHub as my choice, GitHub also has its own artifactory GitHub &lt;a class="rank-math-link" href="https://github.com/features/packages"&gt;Packages&lt;/a&gt; with a small free tier. It supports NPM, Docker, Maven, Gradle, etc. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Triggers of Action&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Most of the times, GitHub action are triggered upon commit to main branch of the repo. In GitHub, this is known as a &lt;a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch"&gt;workflow_dispatch&lt;/a&gt; event. This is not the only event that can trigger GitHub action. All the available events are listed &lt;a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#available-events"&gt;here&lt;/a&gt; on its documentation. This makes it very flexible to trigger action at many points in the workflow. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;One example is to trigger GitHub action during PR review. When a developer opens a PR with a few commits in the proposed branch, the PR can preemptively check linting, style, etc and even build the application. These activities can also be defined in a GitHub action manifest with &lt;strong&gt;pull_request&lt;/strong&gt; as triggering event.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Troubleshooting&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In general, it is painful to troubleshoot activities happening inside of runners. I often had to write a few steps for the sake of printing variables, and trigger a run to see what their value is. This requires a lot of time especially when I have to wait for available runners. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To help troubleshooting pipeline runs there is an open-source utility called &lt;a href="https://github.com/nektos/act"&gt;act&lt;/a&gt;. You can run GitHub actions locally from a Docker container on your MacBook. You can deliver environment variables and secrets via files. If you ever need to troubleshoot the runner environment, you have the option to connect to the Shell environment inside of the runner container. This tool is extremely helpful.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-closing-remarks"&gt;Closing remarks&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;GitHub action really makes the CI/CD pipeline capability available to any developers who stores their code on GitHub. GitHub expands from a code repository solution to a full CI/CD solution with a free tier sufficient for personal projects.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/05/secure-web-application-deployment/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Secure web application deployment&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/06/kubernetes-storage-explained/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes Storage Explained – from in-tree plugin to CSI&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Git Branching Strategy</title><link>https://static.digihunch.com/2021/03/git-branching-strategy/</link><pubDate>Sun, 07 Mar 2021 19:20:42 -0400</pubDate><guid>https://static.digihunch.com/2021/03/git-branching-strategy/</guid><description>&lt;p class="wp-block-paragraph"&gt;I have been in two discussions about &lt;a href="https://static.digihunch.com/2019/06/git-explained-1-of-2/"&gt;Git&lt;/a&gt; branching strategy in different organizations. Too many concepts! So I open this post to jot down the lineage of common branching strategies to help organizations develop their branching policies. In terms of reference, there is a lot from Atlassian documentation. In addition, I also find this one &lt;a class="rank-math-link" href="https://medium.com/factualopinions/branching-models-in-a-nutshell-bf24ea1d888a"&gt;article &lt;/a&gt;a good resource.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-centralized-workflow-no-branching"&gt;Centralized workflow (no branching)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In &lt;a href="https://www.atlassian.com/git/tutorials/comparing-workflows#centralized-workflow" class="rank-math-link"&gt;Centralized Workflow&lt;/a&gt;, the team uses a central repository to serve as the single-point-of-entry for all changes to the project. The default branch is master, and all changes are committed to this branch. This workflow does not require any other branches beside master. Local changes may conflict with upstream commits, and conflict needs to be resolved.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This workflow is usually seen in teams transitioning from SVN, with very basic skill level. This workflow may also be adopted in teams working on configuration management instead of source code. Centralized workflow is great for small teams. The conflict resolution process can form a bottleneck as the team scales in size.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-feature-branch-workflow"&gt;Feature Branch Workflow &lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Instead of directly committing on their local master branch, developers create a new branch every time they start work on a new feature. Feature branches should have descriptive names (e.g. issue#112). Feature branches are pushed to the central repository so that they can be shared to other developers without touching any official (master) code. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To get feedback on the new feature branch, create a pull request in a repository management solution (e.g. Bitbucket Cloud, Bitbucket Server). Before merge, you may have to resolve merge conflicts if others have made changes to the master branch of repo. This is to make sure your local master is synchronized with the upstream master. When your pull request is approved and conflict free, you can merge your branch to master branch.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter is-resized"&gt;&lt;img decoding="async" src="https://wac-cdn.atlassian.com/dam/jcr:09308632-38a3-4637-bba2-af2110629d56/07.svg?cdnVersion=1491" alt="Feature Branch Workflow: Merging a feature branch" style="width:549px;height:97px"/&gt;&lt;figcaption class="wp-element-caption"&gt;feature branch workflow&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Git Feature Branch Workflow is a composable workflow that can be leveraged by other high-level Git workflows. Git Feature Branch Workflow is branching model focused, instead of release focused. The Git Feature Branch Workflow can be incorporated into other workflows. The Gitflow, and Git Forking Workflows traditionally use a Git Feature Branch Workflow in regards to their branching models.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-gitflow-workflow"&gt;Gitflow Workflow&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;First &lt;a href="https://nvie.com/posts/a-successful-git-branching-model/"&gt;published&lt;/a&gt; in 2010 by Vincent Driessen. Gitflow defines a strict branching model designed around the project release. This provides a robust framework for managing larger projects. In addition to Feature Branch Workflow, Gitflow workflow assigns very specific roles to different branches and defines how and when they should interact.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Instead of a single master branch, this workflow uses two branches to record the history of the project. The master branch stores the official release history, and the develop branch serves as an integration branch for features. It is also convenient to tag all commits in the master branch with a version number.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This workflow is operated in the following ways:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;A develop branch is created from master&lt;/li&gt;&#10;&lt;li&gt;Feature branches are created from develop. When a feature is complete, with PR reviewed, it is merged into the develop branch. Features branches&lt;/li&gt;&#10;&lt;li&gt;Once develop has acquired enough features for a release (or a predetermined release date is approaching), we fork a release branch off of develop. Creating this branch starts the next release cycle, so new features can be added to develop after this point. On the release branch itself, only bug fixes, documentation generation, and other release-oriented tasks should go in this branch. Once ready to ship, the release branch gets merged into master and tagged with a version number. In addition, it should also be merged back into develop, which may have progressed since the release was initiated.&lt;/li&gt;&#10;&lt;li&gt;Maintenance or hotfix branches are used to quicly patch production releases. Hotfix branches are a lot like release branchs and feature branches except they&amp;#8217;re based on master instead of develop. As soon as the fix is complete, it should be merged into both master and develop (or the current release branch), and master should be tagged with an updated version number. &lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter is-resized"&gt;&lt;img decoding="async" src="https://wac-cdn.atlassian.com/dam/jcr:61ccc620-5249-4338-be66-94d563f2843c/05%20(2).svg?cdnVersion=1491" alt="Git flow workflow - Hotfix Branches" style="width:572px;height:409px"/&gt;&lt;figcaption class="wp-element-caption"&gt;Gitflow workflow&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There is a Git extension named git-flow to provide high-level repository operations for this Workflow, such as start a release, finish a release, start a hotfix, finish a hotfix.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Gitflow is ideally suited for projects that have a scheduled release cycle and for the DevOps best practice of continuous delivery. It ensures that the master branch reflects what is deployed (e.g. in production). However, it is quite &lt;strong&gt;complex&lt;/strong&gt; and have a &lt;strong&gt;steep learning curve&lt;/strong&gt; for organizations. It also runs &lt;strong&gt;long-lived branches&lt;/strong&gt;, which is considered bad from CI/CD perspective. Branches are by definition to isolate and hide changes, whereas &lt;strong&gt;continuous integration &lt;/strong&gt;is about exposing changes early on and frequently. In that sense, the Gitflow branching model and CI/CD are &lt;strong&gt;mutually exclusive&lt;/strong&gt; ideas. &lt;/p&gt;&#10;&lt;blockquote class="wp-block-quote is-style-plain is-layout-flow wp-block-quote-is-layout-flow"&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In 2020, Vincent Driessen added a note at the beginning of his &lt;a href="https://nvie.com/posts/a-successful-git-branching-model/"&gt;article&lt;/a&gt; on Gitflow:&lt;/p&gt;&#10;&lt;cite&gt;If your team is doing continuous delivery of software, I would suggest to adopt a much simpler workflow (like GitHub flow) instead of trying to shoehorn git-flow into your team.&lt;br&gt;If, however, you are building software that is explicitly versioned, or if you need to support multiple versions of your software in the wild, then git-flow may still be as good of a fit to your team as it has been to people in the last 10 years.&lt;/cite&gt;&lt;/blockquote&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Driessen&amp;#8217;s notes also points to some simple alternatives. On the other hand, the &lt;a href="https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow"&gt;Atlassian tutorial&lt;/a&gt; on Gitflow has described Gitflow workflow as a legacy (since Aug 2021 based on web &lt;a href="https://web.archive.org/web/20210802194504/https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow"&gt;archive&lt;/a&gt;). It points out at the beginning that Gitflow has fallen in popularity in favor of&amp;nbsp;&lt;a href="https://www.atlassian.com/continuous-delivery/continuous-integration/trunk-based-development"&gt;trunk-based workflows&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-github-flow-trunk-based-development-tbd-and-gitlab-flow"&gt;GitHub flow, Trunk-based development (TBD) and GitLab flow&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It is operationally expensive to manage multiple mainlines in Git flow workflow, with both source control and release in the picture. Some simple alternatives have been evolved, with single mainline, for example, &lt;strong&gt;GitHub flow&lt;/strong&gt; and &lt;strong&gt;trunk-based development&lt;/strong&gt;. They differ in where the release is performed from. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the &lt;a href="https://guides.github.com/introduction/flow/" class="rank-math-link"&gt;GitHub flow&lt;/a&gt;, release is performed from branch before being merged back to master (trunk).&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter"&gt;&lt;img decoding="async" src="https://trunkbaseddevelopment.com/alternative-branching-models/githubflow1.png" alt=""/&gt;&lt;figcaption class="wp-element-caption"&gt;GitHub flow&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In &lt;a href="https://www.atlassian.com/continuous-delivery/continuous-integration/trunk-based-development" class="rank-math-link"&gt;trunk-based development&lt;/a&gt;, release is not performed until the feature branch has been merged to the trunk (master). In trunk-based development, feature branches are supposed to be short-lived. It is a common practice among DevOps teams, since it streamlines merging and integration phases.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter"&gt;&lt;img decoding="async" src="https://trunkbaseddevelopment.com/5-min-overview/trunk_pr.png" alt=""/&gt;&lt;figcaption class="wp-element-caption"&gt;Trunk-based development&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Trunk-based development has gained some momentum in recent years, due to its DevOps friendliness. &lt;a href="https://trunkbaseddevelopment.com/" class="rank-math-link"&gt;This &lt;/a&gt;is a website that advocates it and here&amp;#8217;s a DZone &lt;a href="https://dzone.com/articles/why-i-prefer-trunk-based-development-over-feature" class="rank-math-link"&gt;article &lt;/a&gt;about it.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-gitlab-flow"&gt;Gitlab Flow&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In response to the shortcomings of GitHub flow and Gitflow, Gitlab introduced its own proposal of branching strategy, known as &lt;a href="https://docs.gitlab.com/ee/topics/gitlab_flow.html" class="rank-math-link"&gt;Gitlab flow&lt;/a&gt;. The most distinctive aspect is the environment branches. In Gitlab flow, you run multiple long-lived branches, each of them representing an environment. The typical steps are as follows:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;You create short-lived feature branches, and merge them often to the master.&lt;/li&gt;&#10;&lt;li&gt;Every developer starts from master and targets master. Other branches are merged from previous lower environment branches.&lt;/li&gt;&#10;&lt;li&gt;You can deploy a new version to production, by merging master into the production branch.&lt;/li&gt;&#10;&lt;li&gt;If you need to know what code is in production, you can check out the production branch to see.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="528" height="700" src="https://static.digihunch.com/wp-content/uploads/2023/01/gitlab_flow.png" alt="" class="wp-image-7742" srcset="https://static.digihunch.com/wp-content/uploads/2023/01/gitlab_flow.png 528w, https://static.digihunch.com/wp-content/uploads/2023/01/gitlab_flow-226x300.png 226w" sizes="auto, (max-width: 528px) 100vw, 528px" /&gt;&lt;figcaption class="wp-element-caption"&gt;&lt;strong&gt;Gitlab flow&lt;/strong&gt;&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You only need to work with release branches, if you need to release software code to the outside world. Here are some &lt;a class="rank-math-link" href="https://about.gitlab.com/topics/version-control/what-are-gitlab-flow-best-practices/"&gt;best practices&lt;/a&gt; in GitLab flow.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-forking-workflow"&gt;Forking Workflow&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Forking workflow is fundamentally different. The key steps are as follows:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;A developer &amp;#8216;forks&amp;#8217; an &amp;#8216;official&amp;#8217; server-side repository. This creates their own server-side copy. This is their personal public repository, and no other developer are allowed to push to it.&lt;/li&gt;&#10;&lt;li&gt;The new server-side copy is cloned to their local system. This forms an environment dedicated to this developer.&lt;/li&gt;&#10;&lt;li&gt;With the local clone, developer needs to create the upstream remote manually using &amp;#8220;git remote add upstream&amp;#8221; command. This allows the developer keep the local repository up-to-date as the official project progresses. &lt;/li&gt;&#10;&lt;li&gt;A new local feature branch is created. Developer commits to the new local branch, and pushes to their own copy of repository on server.&lt;/li&gt;&#10;&lt;li&gt;Developer files a pull request from the new branch (in own copy of repository) to the &amp;#8216;official&amp;#8217; repository. The project maintainer knows that an update is ready to be integrated. The PR also serves as a discussion thread.&lt;/li&gt;&#10;&lt;li&gt;The PR gets approved for merge and is merged into the original server-side repository.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This workflow has other names, such as &lt;a href="https://blog.scottlowe.org/2015/01/27/using-fork-branch-git-workflow/" class="rank-math-link"&gt;fork-and-branch workflow&lt;/a&gt;, and is commonly used in GitHub for managing open-source projects. However, this should not be confused with the aforementioned GitHub flow.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-conclusion"&gt;Conclusion&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In order to fully support distributed source control, Git abstract version control problems into concepts such as commit, branch, etc. This makes discussion about Git workflow and branching strategy difficult due to the conceptual hurdles and organization differences. We covered choices of Git branching strategy in this post. As Vincent Driessen commented in his &lt;a class="rank-math-link" href="https://nvie.com/posts/a-successful-git-branching-model/"&gt;original Gitflow posting&lt;/a&gt;, panaceas don&amp;#8217;t exist. We should consider the context (e.g. team size, Git skill level, etc) to determine the best Git branching strategy.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/02/interpret-census-data-from-statistics-canada/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Census Data from Statistics Canada&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/03/intro-to-data-analytics-platform/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Intro to Data Analytics Platform on Azure&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Git Explained 2 of 2</title><link>https://static.digihunch.com/2019/06/git-explained-2-of-2/</link><pubDate>Tue, 18 Jun 2019 17:06:00 -0400</pubDate><guid>https://static.digihunch.com/2019/06/git-explained-2-of-2/</guid><description>&lt;p class="wp-block-paragraph"&gt;This is a continuation from &lt;a href="https://static.digihunch.com/2019/06/git-explained-1-of-2/"&gt;Git Explained 1 of 2 &lt;/a&gt;where the fundamental concepts are covered. In this article we introduce some tools for customization and maintenance.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As for Git configuration, there are two files to dictate your Git configuration. ~/.gitconfig and .git/config in project directory. Running `git config &amp;#8211;list &amp;#8211;show-origin` shows all config entries and where they are from. For example you can custom your Git hooks location. Neither of the two files are being version controlled, so the configuration is only effective in the client environment,&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;&lt;strong&gt;Server side Git hooks&lt;/strong&gt;&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Git implementation supports server side hooks (pre-receive, update, post-receive). They are bash scripts placed in .git/hooks with specific names, fired upon event occurrence. Exit code of 1 from the scripts fails the event. Since server side Git hook consumes server resources, many repository hosting vendors (e.g. &lt;a href="https://community.atlassian.com/t5/Bitbucket-questions/Does-Bitbucket-Cloud-support-git-pre-receive-hooks/qaq-p/950235"&gt;BitBucket Cloud&lt;/a&gt;) do not support it. You will need to enable it in self-hosted servers (e.g. BitBucketServer).&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;&lt;strong&gt;Client side Git hooks&lt;/strong&gt;&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Since server side hooks are not widely supported in every vendor, client-side Git hooks is good alternative places to implement functions such as code style check, commit size check, etc&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The default directory for hooks is .git/hooks/ under the project directory is not version controlled and not easy to share with the team. If the hook needs to be shared among project contributors, we can place hooks files in .githooks/ under project directory. This will make the hook files version controlled. In addition, we need to point the hooks to this directory in configuration, by running `git config core.hooksPath .githooks` from project directory.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img loading="lazy" decoding="async" width="1020" height="767" src="https://static.digihunch.com/wp-content/uploads/2019/10/git-hooks.png" alt="" class="wp-image-211"/&gt;&lt;/figure&gt;&#10;&lt;h3 class="wp-block-heading"&gt;&lt;strong&gt;Web hooks &lt;/strong&gt;&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Web hooks can be thought of as an event notification mechanism. It is a common feature provided by VCS repository hosting providers. If a certain type of event occurs to the repo, web hook will fire an RESTful API call. The HTTP Endpoint, authentication secret and event payload are pre-configured in the repo settings. Web hooks are commonly supported by Git-based repo implementation, such as &lt;a href="https://confluence.atlassian.com/bitbucket/manage-webhooks-735643732.html"&gt;BitBucket cloud&lt;/a&gt;, &lt;a href="https://developer.github.com/webhooks/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://docs.gitlab.com/ee/user/project/integrations/webhooks.html"&gt;GitLab&lt;/a&gt; or &lt;a href="https://docs.aws.amazon.com/codecommit/latest/userguide/how-to-notify.html"&gt;AWS CodeCommit&lt;/a&gt;. It can also be enabled in self hosted Git repo. Web hook is a powerful tool to drive downstream event, such as Jenkins to start building the code. The major difference between server side hook and web hook is web hook is RESTful API driven, whereas server side hook is executing a script.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-pipelines"&gt;&lt;strong&gt;Pipelines&lt;/strong&gt;&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Some repo hosting vendor also provide a feature named pipeline. BitBucket has &lt;a href="https://confluence.atlassian.com/bitbucket/get-started-with-bitbucket-pipelines-792298921.html"&gt;Pipeline&lt;/a&gt; as a CI/CD tool, AWS has &lt;a href="https://aws.amazon.com/codepipeline/"&gt;AWS Code Pipeline&lt;/a&gt;, and GitLab offers &lt;a href="https://docs.gitlab.com/ee/ci/pipelines/"&gt;CI/CD pipeline&lt;/a&gt; as well. These pipelines are usually in the form of a YAML file in the repo with a special name. The YAML spell out the steps to perform along the pipeline.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;&lt;strong&gt;Squash&lt;/strong&gt; Commits&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For small projects I was in the habit of committing to main branch. I often need to squash a number of commits into one to &amp;#8220;clean up&amp;#8221;. Usually a Pull Request (e.g. in GitHub) or Merge Request (e.g. in GitLab) have such option during approval. We can squash a few commits with git command as well (suppose we want to squash the most recent 16 commits):&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git rebase -i HEAD~16&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git push origin +main&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The command will open text editor to allow you to mark what to do with each commit. You can mark all except one commit as squash. For the commit to keep, mark it as pick. Then save the text editor. Git rebase will perform the squash for you. However, since this is a rebase, do not do this if there are other collaborators working on the same branch.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;&lt;strong&gt;Cleanse a repository&lt;/strong&gt;&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Take BitBucket cloud for example, the size of a remote repo has a &lt;a href="https://confluence.atlassian.com/bitbucket/what-kind-of-limits-do-you-have-on-repository-file-size-273877699.html"&gt;non-expandable hard limit&lt;/a&gt; of 2GB, and a soft limit of 1GB. Once the soft limit is reached, a warning will be displayed on Bitbucket&amp;#8217;s landing page as well as when contributors pushes changes. Once the hard limit is reached, the entire repo will turn read-only mode.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Space consumption can be caused by accidental committing of large file. As covered in the &lt;a href="https://static.digihunch.com/2019/06/git-explained-1-of-2/"&gt;previous post&lt;/a&gt;, files are stored as blob objects in .git directory. If a file was deleted by `git rm` command, it simply means it is de-referenced from the next commit and on. After all, Git as a distributed version control system, has the ability to magically restore the deleted file when we want. The cost of that magic, is that deleted file is permanently stored in the repo, in the form of blob object, although not present in the working directory. It consumes space not only in remote repo, but also in the local repo of each contributor.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The purpose of Git repository is to store source code which are fairly small texts. However if a contributor pushed in large files, it can be tricky to cleanse a Git repo on the remote side. Here is some guidelines:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt; Before cleansing, identify large unwanted files in current working directory, delete them with `git rm` and then commit this change in master branch. &lt;/li&gt;&#10;&lt;li&gt;Consolidate branches (e.g. delete useless remote branches with `git push origin &amp;#8211;delete branch_name`). This step itself does not free up space in remote repo but it simplifies the branches;&lt;/li&gt;&#10;&lt;li&gt;Remove large blob objects and commit objects that reference them. This step essentially is re-writing the commit history of repo. Given the risk, it is recommended to perform this step from a separate local project directory with bare repo only without working directory. &lt;a href="https://www.nicoespeon.com/en/2014/04/clean-git-repo-like-a-boss/"&gt;This article&lt;/a&gt; presents some good advices and illustrations. The command recommended is `git filter-branch -f &amp;#8211;tree-filter &amp;#8220;rm -rf \large_file.zip&amp;#8221; &amp;#8211;prune-empty &amp;#8212; &amp;#8211;all` ; and if that is too slow &lt;a href="https://rtyley.github.io/bfg-repo-cleaner/"&gt;here&lt;/a&gt; is an alternative named BFG Repo-Cleaner.&lt;/li&gt;&#10;&lt;li&gt;After this step, each commit will have a new hash id. For the repo size to reduce, either wait until the next garbage collection on the server side, or request cloud vendor to run a manual garbage collection.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2019/06/git-explained-1-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Git Explained 1 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2019/07/practical-cryptography-for-it-professional/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Cryptography Basics 1 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Git Explained 1 of 2</title><link>https://static.digihunch.com/2019/06/git-explained-1-of-2/</link><pubDate>Sat, 08 Jun 2019 22:39:00 -0400</pubDate><guid>https://static.digihunch.com/2019/06/git-explained-1-of-2/</guid><description>&lt;p class="wp-block-paragraph"&gt;In a nutshell, Git is a distributed version control system, commonly used as source control management. It places files in one of three logical areas (working dir, staging, repo) below depending where it is in its lifecycle. &lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img loading="lazy" decoding="async" width="1618" height="992" src="https://static.digihunch.com/wp-content/uploads/2019/10/image.png" alt="" class="wp-image-178"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are many cheetsheets out there but this article will just sort through some concepts unique to Git. To understand how Git works it is crucial to think in terms of Git data model.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Working directory&lt;/strong&gt; a single checkout of one version of the project. These files are pulled out of the object database in the Git directory (upon checkout) and placed in the project directory on disk, for you to use or modify;&amp;nbsp;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Index&lt;/strong&gt; a file contained in your Git directory (stored as binary data in file .git/index) that keeps information about what will go into your next commit.&amp;nbsp;To display what&amp;#8217;s in the index, run `git ls-files &amp;#8211;stage`. Read &lt;a href="https://hackernoon.com/https-medium-com-zspajich-understanding-git-data-model-95eb16cc99f5"&gt;this post&lt;/a&gt; for further details&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Repository&lt;/strong&gt;: where Git stores the metadata and &lt;code&gt;&lt;span style="text-decoration: underline;"&gt;object database&lt;/span&gt;&lt;/code&gt; for your project.&amp;nbsp;The local repository is in .git/ under the project directory.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Add&lt;/strong&gt; &amp;#8211; register one or more modified files to staging area. You may edit several files with only a few needed registered for future commit. Add activity ensures the file edited are recorded in the index (as a preview of next commit). You technically need to run add against each file. But the command syntax with * or . allows you to capture all edits in the same directory or under.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Commit&lt;/strong&gt; &amp;#8211; persist the staged file edits to the repository (so they are stored in Git object database). A commit represents all the file edits that were staged by add command in previous steps.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Branch&lt;/strong&gt; &amp;#8211; a branch is simply a movable pointer to a commit. Default branch name created by git init is called &amp;#8220;master&amp;#8221;. Other than the name, there is nothing special about master branch. Everytime you commit, the master branch pointer moves forward automatically. Branch pointers are kept in .git/refs directory. Read &lt;a href="https://hackernoon.com/understanding-git-branching-2662f5882f9"&gt;this post&lt;/a&gt; for further details.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;HEAD&lt;/strong&gt; &amp;#8211; the pointer to the current branch reference, which is in turn a pointer to the last commit made on that branch. Git use HEAD pointer to know what branch you&amp;#8217;re currently on. HEAD will be the parent of the upcoming commit.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Tag&lt;/strong&gt; &amp;#8211; an annotated tag contains the SHA of the commit being tagged. Alias of a commit.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Merge&lt;/strong&gt; &amp;#8211; choose current commit of other branch and apply it onto your branch.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Rebase&lt;/strong&gt; &amp;#8211; copy all commits from other branch to your branch. Compared to merge, rebasing forms a cleaner commit history.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Cherrypick&lt;/strong&gt; &amp;#8211; choose a previous commit from other branch and apply it onto your branch.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Stash&lt;/strong&gt; &amp;#8211; &amp;nbsp;temporarily stashes changes you&amp;#8217;ve made to working tree so you can work on something else, and then come back and re-apply them later on.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Reset&lt;/strong&gt; &amp;#8211; at a high level, reset is to revert some operations. After pulling code, developer usually follow three steps: editing-&amp;gt;add-&amp;gt;commit. reset is to reverse these steps, based on different modes. The Pro Git reference has further details on the &lt;a href="https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified"&gt;three different modes&lt;/a&gt;:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;soft mode&lt;/strong&gt; (reverse operation of commit): based on what branch HEAD points to, move where that branch points to (e.g. from latest commit, to a different commit several steps up the link);&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;mixed mode&lt;/strong&gt; (default; reverse operation of commit and add) &amp;#8211; in addition to soft mode, also update index;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;hard mode&lt;/strong&gt; (reverse operation of commit, add and file editing)- in addition to mixed mode, also update working directory. Edit on files are discarded.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Git object model&lt;/strong&gt; &amp;#8211; In Git database, files, commits and directories are stored as objects, In Git &lt;a href="https://shafiul.github.io/gitbook/1_the_git_object_model.html"&gt;object model&lt;/a&gt;, there are three types (to tell object type, run `git cat-file -t`). Read &lt;a href="https://hackernoon.com/https-medium-com-zspajich-understanding-git-data-model-95eb16cc99f5"&gt;this post&lt;/a&gt; for further details:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;blob object&lt;/strong&gt; &amp;#8211; stores file data with metadata; use `git show` to examine blob object;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;tree object&lt;/strong&gt; &amp;#8211; represents a directory. It references other tree objects (sub-directories) or blob objects (files under the directory, of a certain version); use `git ls-tree` to examine tree object;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;commit object&lt;/strong&gt; &amp;#8211; represents a commit. It references its parent commit, as well as a tree object that represents the entire project directory. use `git cat-file -p` to inspect commit object;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This &lt;a href="https://git-scm.com/book/en/v2/Git-Internals-Git-Objects"&gt;diagram&lt;/a&gt; from from Git Pro outlines the interactions amongst these types of objects.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://git-scm.com/book/en/v2/images/data-model-3.png" alt="All the reachable objects in your Git directory."/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;For more details&lt;/strong&gt;, the&amp;nbsp;&lt;a href="https://git-scm.com/book/en/v2"&gt;official documentation&lt;/a&gt;&amp;nbsp;is actually the most helpful reference with illustrations. In addition, I find on Hakcermoon three excellent articles with thorough explanation on&amp;nbsp;&lt;a href="https://hackernoon.com/https-medium-com-zspajich-understanding-git-data-model-95eb16cc99f5"&gt;data model&lt;/a&gt;,&amp;nbsp;&lt;a href="https://hackernoon.com/understanding-git-branching-2662f5882f9"&gt;branching&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="https://hackernoon.com/understanding-git-index-4821a0765cf"&gt;index&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2019/05/automation-with-ansible-a-primer/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Set up automation with Ansible&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2019/06/git-explained-2-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Git Explained 2 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>