<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Eyar Zilberman</title>
    <description>The latest articles on Forem by Eyar Zilberman (@eyarz).</description>
    <link>https://forem.com/eyarz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F147438%2Ff63e194c-eb25-4c0f-b421-53888b3697f8.png</url>
      <title>Forem: Eyar Zilberman</title>
      <link>https://forem.com/eyarz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/eyarz"/>
    <language>en</language>
    <item>
      <title>A Deep Dive Into Kubernetes Schema Validation</title>
      <dc:creator>Eyar Zilberman</dc:creator>
      <pubDate>Tue, 01 Jun 2021 10:24:16 +0000</pubDate>
      <link>https://forem.com/datreeio/a-deep-dive-into-kubernetes-schema-validation-39ll</link>
      <guid>https://forem.com/datreeio/a-deep-dive-into-kubernetes-schema-validation-39ll</guid>
      <description>&lt;h2&gt;
  
  
  Why run schema validation?
&lt;/h2&gt;

&lt;p&gt;How do you ensure the stability of your Kubernetes clusters? How do you know that your manifests are syntactically valid? Are you sure you don’t have any invalid data types? Are any mandatory fields missing? &lt;/p&gt;

&lt;p&gt;Most often, we only become aware of these misconfigurations at the worst time - when trying to deploy the new manifests. &lt;/p&gt;

&lt;p&gt;Specialized tools and a “shift-left” approach make it possible to verify a Kubernetes schema before they’re applied to a cluster. In this article, I'll address how you can avoid misconfigurations and which tools are best to use.&lt;/p&gt;

&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;p&gt;Running schema validation tests is important, and the sooner the better.&lt;/p&gt;

&lt;p&gt;If all machines (local developers environment, CI, etc.) have access to your Kubernetes cluster, run &lt;code&gt;kubectl --dry-run&lt;/code&gt; in server mode on every code change. If this isn’t possible, and you want to perform schema validation tests offline, use kubeconform together with a policy enforcement tool to have optimal validation coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Available tools
&lt;/h2&gt;

&lt;p&gt;Verifying the state of Kubernetes manifests may seem like a trivial task, because the Kubernetes CLI (kubectl) has the ability to verify resources before they’re applied to a cluster.  You can verify the schema by using the &lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/576-dry-run/README.md" rel="noopener noreferrer"&gt;dry-run&lt;/a&gt; flag (&lt;code&gt;--dry-run=client/server&lt;/code&gt;) when specifying the &lt;code&gt;kubectl create&lt;/code&gt; or &lt;code&gt;kubectl apply&lt;/code&gt; commands, which will perform the validation without applying Kubernetes resources to the cluster.&lt;/p&gt;

&lt;p&gt;But I can assure you that it’s actually more complex. A running Kubernetes cluster is required to obtain the schema for the set of resources being validated. So, when incorporating manifest verification into a CI process, you must also manage connectivity and credentials to perform the validation. This becomes even more challenging when dealing with multiple microservices in several environments (prod, dev, etc.).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/instrumenta/kubeval/tree/master/kubeval" rel="noopener noreferrer"&gt;Kubeval&lt;/a&gt; and &lt;a href="https://github.com/yannh/kubeconform" rel="noopener noreferrer"&gt;kubeconform&lt;/a&gt; are command-line tools that were developed with the intent to validate Kubernetes manifests without the requirement of having a running Kubernetes environment. Because kubeconform was inspired by kubeval, they operate similarly — verification is performed against pre-generated JSON schemas that are created from the OpenAPI specifications (&lt;a href="https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/swagger.json" rel="noopener noreferrer"&gt;swagger.json&lt;/a&gt;) for each particular Kubernetes version. All that remains &lt;a href="https://github.com/datreeio/kubernetes-schema-validation#running-schema-validation-tests" rel="noopener noreferrer"&gt;to run&lt;/a&gt; the schema validation tests is to point the tool executable to a single manifest, directory or pattern.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn6dd2b38kr7o57z9fxv9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn6dd2b38kr7o57z9fxv9.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;kubeval&lt;/li&gt;
&lt;li&gt;kubeconform&lt;/li&gt;
&lt;li&gt;kubectl dry-run in ‘client’ mode&lt;/li&gt;
&lt;li&gt;kubectl dry-run in ‘server’ mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we covered the tools that are available for Kubernetes schema validation, let’s compare some core abilities (misconfigurations coverage, speed test, different versions support, CRD support and docs).&lt;/p&gt;

&lt;h3&gt;
  
  
  Misconfigurations coverage&lt;sup id="fnref1"&gt;1&lt;/sup&gt;
&lt;/h3&gt;

&lt;p&gt;I donned my QA hat and generated some (basic) Kubernetes manifest files with some &lt;a href="https://github.com/datreeio/kubernetes-schema-validation/tree/main/misconfigs" rel="noopener noreferrer"&gt;intended misconfigurations&lt;/a&gt;, and then ran it against all four tools&lt;sup id="fnref2"&gt;2&lt;/sup&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Misconfig/Tool&lt;/th&gt;
&lt;th&gt;kubeval / kubeconform&lt;/th&gt;
&lt;th&gt;kubectl dry-run in ‘client’ mode&lt;/th&gt;
&lt;th&gt;kubectl dry-run in ‘server’ mode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/datreeio/kubernetes-schema-validation#api-deprecationyaml" rel="noopener noreferrer"&gt;API deprecation&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/datreeio/kubernetes-schema-validation#invalid-kind-valueyaml" rel="noopener noreferrer"&gt;Invalid kind value&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;td&gt;❌ Didn't catch&lt;/td&gt;
&lt;td&gt;🚧 Caught&lt;sup id="fnref3"&gt;3&lt;/sup&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/datreeio/kubernetes-schema-validation#invalid-label-valueyaml" rel="noopener noreferrer"&gt;Invalid label value&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;❌ Didn't catch&lt;/td&gt;
&lt;td&gt;❌ Didn't catch&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/datreeio/kubernetes-schema-validation#invalid-protocol-typeyaml" rel="noopener noreferrer"&gt;Invalid protocol type&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;td&gt;❌ Didn't catch&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/datreeio/kubernetes-schema-validation#invalid-spec-keyyaml" rel="noopener noreferrer"&gt;Invalid spec key&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/datreeio/kubernetes-schema-validation#missing-imageyaml" rel="noopener noreferrer"&gt;Missing image&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;❌ Didn't catch&lt;/td&gt;
&lt;td&gt;❌ Didn't catch&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/datreeio/kubernetes-schema-validation#wrong-k8s-indentationyaml" rel="noopener noreferrer"&gt;Wrong K8s indentation&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;td&gt;✅ Caught&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Conclusion: Running kubectl dry-run in ‘server’ mode caught all misconfigurations, while kubeval/kubeconform missed two of them. It’s also interesting to see that running kubectl dry-run in ‘client’ mode is almost useless because it’s missing some obvious misconfigurations, and also requires a connection to a running Kubernetes environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benchmark speed test
&lt;/h3&gt;

&lt;p&gt;I used &lt;a href="https://github.com/sharkdp/hyperfine" rel="noopener noreferrer"&gt;hyperfine&lt;/a&gt; to benchmark the execution time of each tool&lt;sup id="fnref4"&gt;4&lt;/sup&gt;. First I ran it against &lt;a href="https://github.com/datreeio/kubernetes-schema-validation/tree/main/misconfigs" rel="noopener noreferrer"&gt;(1)&lt;/a&gt; all the files with misconfigurations (seven files in total), and then I ran it against &lt;a href="https://github.com/datreeio/kubernetes-schema-validation/tree/main/benchmark" rel="noopener noreferrer"&gt;(2)&lt;/a&gt; 100 Kubernetes files (all the files contain the same config).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(1)&lt;/strong&gt; Results for running the tools against seven files with different Kubernetes schema misconfigurations:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazbwpj5ppcf92pku1qiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazbwpj5ppcf92pku1qiw.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(2)&lt;/strong&gt; Results for running the tools against 100 files with valid Kubernetes schemas:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid0o1tf7t5ytg6vyqwdc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid0o1tf7t5ytg6vyqwdc.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Conclusion: We can see that while &lt;code&gt;kubeconform&lt;/code&gt; (#1), &lt;code&gt;kubeval&lt;/code&gt; (#2) and &lt;code&gt;kubectl --dry-run=client&lt;/code&gt; (#3) are providing fast results on both tests, while &lt;code&gt;kubectl --dry-run=server&lt;/code&gt; (#4) is working slower, especially when it needs to evaluate 100 files — 60 seconds for generating a result is still a good outcome in my opinion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kubernetes versions support
&lt;/h3&gt;

&lt;p&gt;Both kubeval and kubeconform accept the Kubernetes schema version as a flag. Although both tools are similar (as mentioned, kubeconfrom is based on kubeval), one of the key differences between them is that each tool relies on its own set of pre-generated JSON schemas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kubeval&lt;/strong&gt; - &lt;a href="https://github.com/instrumenta/kubernetes-json-schema" rel="noopener noreferrer"&gt;instrumenta/kubernetes-json-schema&lt;/a&gt; &lt;em&gt;(last commit: 133f848 on April 29, 2020)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubeconform&lt;/strong&gt; - &lt;a href="https://github.com/yannh/kubernetes-json-schema" rel="noopener noreferrer"&gt;yannh/kubernetes-json-schema&lt;/a&gt; &lt;em&gt;(last commit: a660f03 on May 15, 2021)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As of today (May 2021), kubeval only supports Kubernetes schema versions up to 1.18.1, while kubeconform supports the latest Kubernetes schema available today — 1.21.0. With kubectl, it’s a little bit trickier. I don’t know which version of kubectl introduced the dry-run, but I tried it with Kubernetes version 1.16.0 and it still worked, so I know it’s available in Kubernetes versions 1.16.0-1.18.0.&lt;/p&gt;

&lt;p&gt;The variety of Kubernetes schemas support is especially important if you want to migrate to a new Kubernetes version. With kubeval and kubeconform you can set the version and start the process of evaluating which configurations must be changed to support the cluster upgrade.&lt;/p&gt;

&lt;p&gt;Conclusion: The fact that kubeconform has all the schemas for all the different Kubernetes versions available — and also doesn’t require minikube setup (as kubectl does) — makes it a superior tool when comparing these capabilities to its alternatives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other things to consider
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Custom Resource Definition (CRD) support&lt;/strong&gt;&lt;br&gt;
Both kubectl dry-run and kubeconform support resource type &lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/" rel="noopener noreferrer"&gt;CRD&lt;/a&gt;, while kubeval does not. According to kubeval docs, you can pass a flag to kubeval to ignore missing schemas, so it will not fail when testing a bunch of manifests for which only some are resource type CRD.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt; &lt;br&gt;
Kubeval is a more popular project than kubeconform, and therefore, its community and &lt;a href="https://kubeval.instrumenta.dev/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; are more extensive. Kubeconform doesn't have official docs but it does have a well-written &lt;a href="https://github.com/yannh/kubeconform/blob/master/Readme.md" rel="noopener noreferrer"&gt;README&lt;/a&gt; file that explains pretty well its capabilities. The interesting part is that although Kubernetes native tools, like kubectl, are usually well-documented, it was really hard to find the necessary information needed to understand how the &lt;code&gt;dry-run&lt;/code&gt; flag actually works and its limitations.&lt;/p&gt;

&lt;p&gt;Conclusion: Although it’s not as famous as kubeval, the CRD support and good-enough documentation make kubeconform the winner in my opinion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item/Tool&lt;/th&gt;
&lt;th&gt;kubeval&lt;/th&gt;
&lt;th&gt;kubeconform&lt;/th&gt;
&lt;th&gt;dry-run client&lt;/th&gt;
&lt;th&gt;dry-run server&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Misconfigurations coverage&lt;/td&gt;
&lt;td&gt;+/-&lt;/td&gt;
&lt;td&gt;+/-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Benchmark speed test&lt;/td&gt;
&lt;td&gt;+/-&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;+/-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kubernetes versions support&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;+/-&lt;/td&gt;
&lt;td&gt;+/-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CRD support&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documentation&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;+/-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now that you know the pros and cons associated with each tool, here are some best practices for how to best leverage them within your Kubernetes production-scale development flow. &lt;/p&gt;

&lt;h2&gt;
  
  
  Strategies for validating Kubernetes schema using these tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;⬅️ Shift-left: When possible, the best setup is if you can run &lt;code&gt;kubectl --dry-run=server&lt;/code&gt; on every code change, but you probably can’t do it because you can’t allow every developer or CI machine in your organization to have a connection to your cluster. So, the second-best effort is to run kubeconform. &lt;/li&gt;
&lt;li&gt;🚔 Because kubeconform doesn’t cover all common misconfigurations, it’s recommended to run it with a policy enforcement tool on every code change to fill the coverage gap.&lt;/li&gt;
&lt;li&gt;💸 Buy vs. build: If you enjoy the &lt;a href="https://jrott.com/posts/why-buy/" rel="noopener noreferrer"&gt;engineering overhead&lt;/a&gt;, then kubeconform + &lt;a href="https://www.conftest.dev/" rel="noopener noreferrer"&gt;conftest&lt;/a&gt; is a great combination of tools to get good coverage. Alternatively, there are tools that can provide you with an out-of-the-box experience to help you save time and resources, such as &lt;a href="https://hub.datree.io/schema-validation/?utm_source=dev.to&amp;amp;utm_medium=schema-validation"&gt;Datree&lt;/a&gt;&lt;sup id="fnref5"&gt;5&lt;/sup&gt; (whose schema validation is powered by kubeconform).&lt;/li&gt;
&lt;li&gt;🚀 During the CD step, it shouldn’t be a problem to have a connection with your cluster, so you should always run &lt;code&gt;kubectl --dry-run=server&lt;/code&gt; before deploying your new code changes. &lt;/li&gt;
&lt;li&gt;👯 Another option for using kubectl dry-run in server mode, without having a connection to your Kubernetes environment, is to run minikube + &lt;code&gt;kubectl --dry-run=server&lt;/code&gt;. The downside of this hack is that it’s also required to set up the minikube cluster like prod (same volumes, namespace, etc.) or you’ll encounter errors when trying to validate your Kubernetes manifests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  GRATITUDE
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Thank you to &lt;a href="https://github.com/yannh" rel="noopener noreferrer"&gt;Yann Hamon&lt;/a&gt; for creating kubeconform - it’s awesome!&lt;/em&gt;&lt;br&gt;
&lt;em&gt;This article wouldn’t be possible without you. Thank you for all of your guidance.&lt;/em&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;All the schemas validation tests performed against Kubernetes version 1.18.0 ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Because kubeconform is based on kubeval, they provide the same result and run them against the files with the misconfigurations. kubectl is one tool but each mode (client or server) produces a different result as you can see from the table ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Server mode didn’t mark the file as valid (exit code 1) but the error message is wrong: &lt;code&gt;Kind=pod doesn't support dry-run&lt;/code&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;All benchmark test performed on my MacBook Pro with a 2.3 GHz Quad-Core Intel Core i7 processor ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;Disclaimer - self-promotion here :) ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>gitops</category>
    </item>
    <item>
      <title>💻 Coding your way out of the Coronavirus 🚑</title>
      <dc:creator>Eyar Zilberman</dc:creator>
      <pubDate>Tue, 17 Mar 2020 00:38:04 +0000</pubDate>
      <link>https://forem.com/eyarz/coding-your-way-out-of-the-coronavirus-5f7</link>
      <guid>https://forem.com/eyarz/coding-your-way-out-of-the-coronavirus-5f7</guid>
      <description>&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; The following post includes unfunny jokes about the Coronavirus (COVID-19) and the Corona crisis. Some people may find this content offensive, so continue reading at your own risk. This blog should not be taken seriously under any circumstances.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0qt3wzmp19tpzw38f5no.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0qt3wzmp19tpzw38f5no.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Coronavirus is creating shock waves around the world, forcing more developers to work from home. While the practices to avoid the Coronavirus spread among humans is pretty clear for most of us, this blog will cover the best practices to avoid your code from being infected (prevention), checking to see if your code is infected (detection) and what to do in the case of contamination (post-infection). It is also important to remember that the statistics show us that new (freshly developed) code has a higher chance of recovery after infection. Legacy code (any code that was created &lt;a href="https://github.com/dspinellis/unix-history-repo/commit/430b982fd0979c7b04c454dbdee5592bb2a7cba0" rel="noopener noreferrer"&gt;before the year 2010&lt;/a&gt;) is at the high-risk group.&lt;/p&gt;

&lt;h1&gt;
  
  
  ✋ Prevention
&lt;/h1&gt;

&lt;p&gt;Due to the high infection rate and the fact that &lt;a href="https://thenextweb.com/neural/2020/03/02/alibabas-new-ai-system-can-detect-coronavirus-in-seconds-with-96-accuracy/" rel="noopener noreferrer"&gt;Alibaba AI&lt;/a&gt; didn’t create the anti-coronavirus, all experts agree that the best cure, for now, is prevention.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid using protocols that require handshaking
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Handshaking" rel="noopener noreferrer"&gt;Handshaking&lt;/a&gt; is the most common way to establish an exchange of information between two machines. Unfortunately, this is also the most common way to get infected and to spread the Coronavirus. Therefore, try to avoid using protocols that require handshaking to start communication (e.g. TCP, TLC, etc.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjdnrp8za7kfcrd5jcm7g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjdnrp8za7kfcrd5jcm7g.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Be careful when copying code from crowded places
&lt;/h3&gt;

&lt;p&gt;Crowded places like stack overflow and open source projects, especially the ones with plenty of contributors, have more chances to contain code that is infected by the Coronavirus. Instead, try to copy code from your teammates, unpopular open-source projects, and bad stack overflow answers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiu4odfttc0kczreq71gn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiu4odfttc0kczreq71gn.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Achieve (and maintain) code hygiene
&lt;/h3&gt;

&lt;p&gt;Now it is the best time to stop writing “quick-and-dirty” and to start refactoring, so you will have &lt;a href="https://medium.com/mindorks/how-to-write-clean-code-lessons-learnt-from-the-clean-code-robert-c-martin-9ffc7aef870c" rel="noopener noreferrer"&gt;clean code&lt;/a&gt; because keeping high code hygiene standards will help to avoid infection. Also, be sure to verify you’re &lt;a href="https://www.smashingmagazine.com/2011/01/keeping-web-users-safe-by-sanitizing-input-data/" rel="noopener noreferrer"&gt;sanitizing (any) input data&lt;/a&gt; received, especially if it received from external services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fenxhsa35gpl51sii3d05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fenxhsa35gpl51sii3d05.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  🔎 Detection
&lt;/h1&gt;

&lt;p&gt;If your code is acting funky, maybe it is not because you’re a sh*ty developer, but because you got infected. It is crucial to constantly debug, monitor and scan your code with different anti-viruses solutions (like &lt;a href="https://www.virustotal.com/gui/home/upload" rel="noopener noreferrer"&gt;VirusTotal&lt;/a&gt;) to check your code health.&lt;/p&gt;

&lt;h1&gt;
  
  
  😱 Post-infection
&lt;/h1&gt;

&lt;p&gt;If you find that your &lt;a href="https://usa.kaspersky.com/blog/coronavirus-used-to-spread-malware-online/20213/" rel="noopener noreferrer"&gt;code got contaminated&lt;/a&gt;, you should follow the guides under this section &lt;strong&gt;ASAP&lt;/strong&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  Git blame to see how you got infected
&lt;/h3&gt;

&lt;p&gt;Thanks to the ability to use &lt;a href="https://git-scm.com/docs/git-blame" rel="noopener noreferrer"&gt;&lt;code&gt;git blame&lt;/code&gt;&lt;/a&gt; it is possible to detect how your code got infected so the relevant safety measurements can be taken to prevent the spread of the Coronavirus.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fic771g0pbbt0netf4p1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fic771g0pbbt0netf4p1p.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Use only localhost to serve your app
&lt;/h3&gt;

&lt;p&gt;Infected code should stay in quarantine until fully recovered. Therefore, if your app contains code with Coronavirus, for public safety, it should be accessible only on the &lt;a href="https://en.wikipedia.org/wiki/Localhost" rel="noopener noreferrer"&gt;localhost&lt;/a&gt; and not exposed to the world.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv8hyqpjgqhk1ohqduytw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv8hyqpjgqhk1ohqduytw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Mask your IP in public places
&lt;/h3&gt;

&lt;p&gt;Contrary to the myth that masks should protect you from getting infected, they are actually supposed to &lt;a href="https://www.cbsnews.com/news/coronavirus-prevention-face-mask-not-helpful-wash-hands/" rel="noopener noreferrer"&gt;help infected code&lt;/a&gt; not to infect other code snippets out there. So if you MUST deploy your code on the WWW, at least mask your server IP to minimize the exposure to others.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh5pd9ri0rzsmijf0s2c5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh5pd9ri0rzsmijf0s2c5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  FYI, I followed all those practices and my code is Corona free since 93'.
&lt;/h4&gt;

</description>
      <category>covid19</category>
      <category>coronavirus</category>
      <category>gag</category>
    </item>
    <item>
      <title>10 insanely useful Git commands you wish existed – and their alternatives</title>
      <dc:creator>Eyar Zilberman</dc:creator>
      <pubDate>Tue, 23 Apr 2019 13:43:50 +0000</pubDate>
      <link>https://forem.com/datreeio/10-insanely-useful-git-commands-you-wish-existed-and-their-alternatives-8e6</link>
      <guid>https://forem.com/datreeio/10-insanely-useful-git-commands-you-wish-existed-and-their-alternatives-8e6</guid>
      <description>&lt;h2&gt;
  
  
  There’s a git command for that
&lt;/h2&gt;

&lt;p&gt;Git commands aren’t always intuitive. If they were, we would have these 10 commands at our disposal. They would be super useful for accomplishing common tasks like creating or renaming a git branch, removing files, and undoing changes.&lt;/p&gt;

&lt;p&gt;For each git command in our wishlist, we’ll show you the commands that actually exist and you can use to accomplish the same tasks. If you’re still learning Git, this list reads like a tutorial and is worth keeping as a cheatsheet.&lt;/p&gt;




&lt;h2&gt;
  
  
  # 9 – git create branch: create a new branch with git checkout
&lt;/h2&gt;

&lt;p&gt;The fastest way to create a new branch is to actually do it from the git terminal. This way you don’t have to use GitHub UI, for example, if you use GitHub for version control.&lt;/p&gt;

&lt;p&gt;This command actually exists in git, only in a different name – &lt;code&gt;$ git checkout&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to create a branch with git checkout:
&lt;/h3&gt;

&lt;p&gt;One-line command: &lt;code&gt;$ git checkout -b &amp;lt;branch-name&amp;gt; master&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(master) $ git checkout -b feature-branch master
-&amp;gt; commit-test git:(feature-branch) $
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git tip&lt;/strong&gt;: Just like with &lt;a href="https://datree.io/blog/git-commit-message-conventions-for-readable-git-log/"&gt;commit messages&lt;/a&gt;, having a naming convention for git &lt;a href="https://stackoverflow.com/questions/273695/what-are-some-examples-of-commonly-used-practices-for-naming-git-branches"&gt;branches&lt;/a&gt; is a good best practice to adopt.&lt;/p&gt;




&lt;h2&gt;
  
  
  # 8 – git force pull: overwrite local with git pull
&lt;/h2&gt;

&lt;p&gt;You find out you’ve made changes that seemingly conflict with the upstream changes. At this point, you decide to overwrite your changes instead of keeping them, so you do a &lt;code&gt;$ git pull&lt;/code&gt; and you get this error message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(master) $ git pull
Updating db40e41..2958dc6
error: Your local changes to the following files would be overwritten by merge:
README.md
hint: Please, commit your changes before merging.
fatal: Exiting because of unfinished merge.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How to overwrite local changes with git pull:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Stash local changes: &lt;code&gt;$ git stash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Pull changes from remote: &lt;code&gt;$ git pull&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(master) $ git stash
Updating db40e41..2958dc6
Saved working directory and index state WIP on master: d8fde76 fix(API): remove ‘test’ end-point
-&amp;gt; commit-test git:(master) $ git pull
Auto-merging README.md
Merge made by the ‘recurive’ strategy.
README.md     | 1 +
ENDPOINT.js    | 3 ++–
2 files changes, 3 insertions(+), 1 deletions(-)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git tip&lt;/strong&gt;: If you want to retrieve your changes just do: &lt;code&gt;$ git stash apply&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  # 7 – git remove untracked files: delete untracked files from working tree
&lt;/h2&gt;

&lt;p&gt;When having unnecessary files and dirs in your own local copy of a repository, and you want to delete those files, in opposed to just ignore them (with .gitignore), you can use git clean to remove all files which are not tracked by git.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to remove untracked files and dirs:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Start with a dry-run to see what will be deleted: &lt;code&gt;$ git clean -n -d&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;After you are sure, run the git clean command with “-f” flag: &lt;code&gt;$ git clean -f -d&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(master) $ git clean -n -d
Would remove dontTrackDir/untracked_file1.py
Would remove untracked_file2.py
-&amp;gt; commit-test git:(master) $ git clean -f -d
Removing dontTrackDir/untracked_file1.py
Removing untracked_file2.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git tip&lt;/strong&gt;: Instead of untracking files, a good practice is to prevent those files from being tracked in the first place by &lt;a href="https://docs.datree.io/docs/include-mandatory-files-gitignore"&gt;using .gitignore&lt;/a&gt; file.&lt;/p&gt;




&lt;h2&gt;
  
  
  # 6 – git unstage: unstage file(s) from index
&lt;/h2&gt;

&lt;p&gt;When you’re adding files (&lt;code&gt;$ git add&lt;/code&gt;) to the working tree, you are adding them to the staging area, meaning you are staging them. If you want Git to stop tracking specific files on the working tree, you need to remove them from your stage files (.git/index).&lt;/p&gt;

&lt;h3&gt;
  
  
  How to unstage file(s) from index:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Keep the file but remove it from the index: &lt;code&gt;$ git rm --cached &amp;lt;file-name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(master) $ git rm –cached unstageMe.js
rm unstageMe.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;To leave the entire working tree untouched, unstage all files (clear your index): &lt;code&gt;$ git reset&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(master) $ git reset
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git tip&lt;/strong&gt;: you can also untrack files which already added to git repository &lt;a href="http://www.codeblocq.com/2016/01/Untrack-files-already-added-to-git-repository-based-on-gitignore/"&gt;based on .gitignore&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  # 5 – git undo merge: abort (cancel) a merge after it happened
&lt;/h2&gt;

&lt;p&gt;Sometimes you get in a situation (we’ve all been there) where you merged branches and realize you need to undo the merge because you don’t want to release the code you just merged.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to abort (cancel) a merge and maintain all committed history:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Checkout to the master branch: &lt;code&gt;$ git checkout master&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run git log and get the id of the merge commit: &lt;code&gt;$ git log --oneline&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Revert merge by commit id: &lt;code&gt;$ git revert -m 1 &amp;lt;merge-commit-id&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Commit the revert and push changes to the remote repo. You can start putting on your poker face and pretend “nothing’s happened”.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(master) $ git log –oneline
812d761 Merge pull request #524 from datreeio/DAT-1332-resolve-installation-id
b06dee0 feat: added installation event support
8471b2b fix: get organization details from repository object

-&amp;gt; commit-test git:(master) $ git revert -m 1 812d761
Revert “Merge pull request #524 from datreeio/DAT-1332-resolve-installation-id”
[master 75b85db] Revert “Merge pull request #524 from datreeio/DAT-1332-resolve-installation-id”
1 file changed, 1 deletion(-)
-&amp;gt; commit-test git:(master) $ git commit -m “revert merge #524”
-&amp;gt; commit-test git:(master) $ git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git tip&lt;/strong&gt;: Instead of reverting merge, working with pull requests and setting up or improving your &lt;a href="https://phauer.com/2018/code-review-guidelines/"&gt;code review&lt;/a&gt; process can lower the possibility of a faulty merge.&lt;/p&gt;




&lt;h2&gt;
  
  
  # 4 – git remove file: remove file(s) from a commit on remote
&lt;/h2&gt;

&lt;p&gt;You wish to delete a file (or files) on remote, maybe because it is deprecated or because this file not supposed to be there in the first place. So, you wonder, what is the protocol to delete files from a remote git repository?&lt;/p&gt;

&lt;h3&gt;
  
  
  How to remove file(s) from commit:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Remove your file(s): &lt;code&gt;$ git rm &amp;lt;file-A&amp;gt; &amp;lt;file-B&amp;gt; &amp;lt;file-C&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Commit your changes: &lt;code&gt;$ git commit -m "removing files"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Push your changes to git: &lt;code&gt;$ git push&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(delete-files) $ git rm deleteMe.js
rm ‘deleteMe.js’
-&amp;gt; commit-test git:(delete-files) $ git commit -m “removing files”
[delete-files 75e998e] removing files
1 file changed, 2 deletions(-)
delete mode 100644 deleteMe.js
-&amp;gt; commit-test git:(delete-files) $ git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git tip&lt;/strong&gt;: When a file is removed from Git, it doesn’t mean it is removed from history. The file will keep “living” in the repository history until the file will be &lt;a href="https://help.github.com/en/articles/removing-sensitive-data-from-a-repository"&gt;completely deleted&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  # 3 – git uncommit: undo the last commit
&lt;/h2&gt;

&lt;p&gt;You made a commit but now you regret it. Maybe you &lt;a href="https://datree.io/blog/secrets-management-git-version-control/"&gt;committed secrets&lt;/a&gt; by accident – not a good idea – or maybe you want to add more tests to your code changes. These are all legit reasons to undo your last commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to uncommit (undo) the last commit:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;To keep the changes from the commit you want to undo: &lt;code&gt;$ git reset --soft HEAD^&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;To destroy the changes from the commit you want to undo: &lt;code&gt;$ git reset --hard HEAD^&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(undo-commit) $ git commit -m “I will regret this commit”
[undo-commit a7d8ed4] I will regret this commit
1 file changed, 1 insertion(+)
-&amp;gt; commit-test git:(undo-commit) $ git reset –soft HEAD^
-&amp;gt; commit-test git:(undo-commit) $ git status
On branch undo-commit
Changes to be committed:
(use “git reset HEAD &amp;lt;file&amp;gt;…” to unstage)

    modified: README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git tip&lt;/strong&gt;: Git &lt;a href="https://gist.github.com/eyarz/64770d343b9cab442b257869f497af9e"&gt;pre-commit hook&lt;/a&gt; is a built-in feature that lets you define scripts that will run automatically before each commit. Use it to reduce the need to cancel commits.&lt;/p&gt;




&lt;h2&gt;
  
  
  # 2 – git diff between branches
&lt;/h2&gt;

&lt;p&gt;When you are working with multiple git branches, it’s important to be able to compare and contrast the differences between two different branches on the same repository. You can do this using the &lt;code&gt;$ git diff&lt;/code&gt; command.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to get the diff between two branches:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Find the diff between the tips of the two branches: &lt;code&gt;$ git diff branch_1..branch_2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Produce the diff between two branches from common ancestor commit: &lt;code&gt;$ git diff branch_1...branch_2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Comparing files between branches: &lt;code&gt;$ git diff branch1:file branch2:file&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(diff-me) $ git diff master..diff-me
diff –git a/README.md b/README.md
index b74512d..da1e423 100644
— a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
# commit-test
-Text on “master” branch
+Text on “diff-me” branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git tip&lt;/strong&gt;: &lt;a href="https://github.com/so-fancy/diff-so-fancy"&gt;diff-so-fancy&lt;/a&gt; is a great open source solution to make your diffs human readable.&lt;/p&gt;




&lt;h2&gt;
  
  
  # 1 – git delete tag: remove a tag from branch
&lt;/h2&gt;

&lt;p&gt;In the case of a “buggy” release, you probably don’t want someone to accidentally use the release linked to this tag. The best solution is to delete the tag and remove the connection between a release and its co-related tag.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to delete tag by removing it from branch:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;If you have a remote tag  to delete, and your remote is origin, then simply: &lt;code&gt;$ git push origin :refs/tags/&amp;lt;tag-name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you also need to delete the tag locally: &lt;code&gt;$ git tag -d &amp;lt;tag-name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(delete-tag) $ git push origin :refs/tags/v1.0.0
To github.com:datreeio/commit-test.git
– [deleted]         v1.0.0
-&amp;gt; commit-test git:(delete-tag) $ git tag -d v1.0.0
Deleted tag ‘v1.0.0’ (was af4d0ea)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git tip&lt;/strong&gt;: Not sure when or why to use tags? &lt;a href="https://medium.com/@kevinkreuzer/the-way-to-fully-automated-releases-in-open-source-projects-44c015f38fd6"&gt;Read here&lt;/a&gt; to learn more (TL;DR: automatic releasing)&lt;/p&gt;




&lt;h2&gt;
  
  
  # 0 – git rename branch: change branch name
&lt;/h2&gt;

&lt;p&gt;As I mentioned, having a branch naming convention a good practice and should be adopted as part of your coding standards, and it is especially useful in supporting automation of git workflows. But what to do when you find out your branch name is not aligned with the convention, after already pushing code to the branch? Don’t worry, you can still rename your branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to rename branch name after it was created:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Checkout to the branch you need to rename: &lt;code&gt;$ git checkout &amp;lt;old-name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Rename branch name locally: &lt;code&gt;$ git branch -m &amp;lt;new-name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Delete old branch from remote: &lt;code&gt;$ git push origin :&amp;lt;old-name&amp;gt; &amp;lt;new-name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reset the upstream branch for the new branch name: &lt;code&gt;$ git push origin -u &amp;lt;new-name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-&amp;gt; commit-test git:(old-name) $ git branch -m new-name
-&amp;gt; commit-test git:(new-name) $ git push origin :old-name new-name
Total 0 (delta 0), reused 0 (delta 0)
To github.com:datreeio/commit-test.git
–  [deleted]             old-name
* [new branch]      new-name -&amp;gt; new-name
-&amp;gt; commit-test git:(new-name) $ git push origin -u new-name
Branch new-name set up to track remote branch new-name from origin.
Everything up-to-date
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git tip&lt;/strong&gt;: Want to make sure all branch names will always follow your convention? Set a Git-enforced &lt;a href="https://docs.datree.io/docs/branch-name"&gt;branch naming policy&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Found some useful commands? you can also set &lt;a href="https://github.com/GitAlias/gitalias"&gt;alias commands&lt;/a&gt; for them! &lt;br&gt;
Relevant alias to this blog post are provided by &lt;a class="comment-mentioned-user" href="https://dev.to/mfrata"&gt;@mfrata&lt;/a&gt;
 in &lt;a href="https://dev.to/mfrata/comment/aab8"&gt;his comment&lt;/a&gt; - you can thank him :)&lt;/p&gt;




&lt;p&gt;Originally posted on &lt;a href="https://datree.io/resources/git-commands"&gt;https://datree.io/resources/git-commands&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>top10</category>
    </item>
    <item>
      <title>Top 10 GitHub Best Practices</title>
      <dc:creator>Eyar Zilberman</dc:creator>
      <pubDate>Mon, 15 Apr 2019 13:28:03 +0000</pubDate>
      <link>https://forem.com/datreeio/top-10-github-best-practices-3kl2</link>
      <guid>https://forem.com/datreeio/top-10-github-best-practices-3kl2</guid>
      <description>&lt;p&gt;After scanning thousands of repositories and interviewing hundreds of GitHub, I created a list of common best practices which are strongly recommended to be adopted in every modern software development organization which is using GitHub to store their code:&lt;/p&gt;

&lt;h2&gt;
  
  
  9. 🚧 Protect the main branches from direct commits
&lt;/h2&gt;

&lt;p&gt;Anything in the master branch should always be deployable, that’s why you should never commit to the default branches directly and why &lt;a href="https://nvie.com/posts/a-successful-git-branching-model/" rel="noopener noreferrer"&gt;Gitflow workflow&lt;/a&gt; has become the standard. Using &lt;a href="https://help.github.com/articles/configuring-protected-branches/" rel="noopener noreferrer"&gt;branch protection&lt;/a&gt; can help you prevent direct commits and of course, everything should be managed via pull requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgithub-branch-protection.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgithub-branch-protection.gif" alt="branch protection"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. 👻 Avoid unrecognized committers
&lt;/h2&gt;

&lt;p&gt;Maybe you are working on a new environment, or you didn’t notice that your &lt;a href="https://help.github.com/articles/why-are-my-commits-linked-to-the-wrong-user/" rel="noopener noreferrer"&gt;Git configuration is incorrect&lt;/a&gt; which causes the user to commit code with the wrong email address. Now, their commit is not associated with the right user and makes it nearly impossible to trace back who wrote what.&lt;/p&gt;

&lt;p&gt;Make sure that your &lt;a href="https://help.github.com/articles/setting-your-commit-email-address-in-git/" rel="noopener noreferrer"&gt;Git client is configured&lt;/a&gt; with the correct email address and linked to your GitHub user. Check your pull requests during code review for unrecognized commits.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Funrecognized-commits.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Funrecognized-commits.jpg" alt="unrecognized committer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  7. 🎩 Define CODEOWNERS for each repository
&lt;/h2&gt;

&lt;p&gt;Using the &lt;a href="https://help.github.com/articles/about-codeowners/" rel="noopener noreferrer"&gt;CODEOWNERS&lt;/a&gt; feature allows you to define which teams and people are automatically selected as reviewers for the repository. This ability automatically requests a review from the repository owners. Nowadays organizations have dozens if not hundreds of repositories and CODEOWNERS gives the option to define who the repo maintainers are across your organization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgithub-code-owners-datree.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgithub-code-owners-datree.png" alt="codeowners"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. 🙊 Separate secret credentials from source code
&lt;/h2&gt;

&lt;p&gt;When building a Cloud Native app, there are many secrets — account passwords, API keys, private tokens, and SSH keys — that we safeguard. NEVER! commit any secrets into your code. Instead, use environment variables that are injected externally from a secure store.&lt;/p&gt;

&lt;p&gt;You can use tools like &lt;a href="https://www.vaultproject.io/" rel="noopener noreferrer"&gt;Vault&lt;/a&gt; and &lt;a href="https://aws.amazon.com/secrets-manager/" rel="noopener noreferrer"&gt;AWS Secrets Manager&lt;/a&gt; to help with your secret management in production.&lt;/p&gt;

&lt;p&gt;There are lots of great tools to identify existing secrets in your code and prevent new ones. For example, &lt;a href="https://dev.toGit-secrets"&gt;Git-secrets&lt;/a&gt; can help you to identify passwords in your code. With &lt;a href="https://githooks.com/" rel="noopener noreferrer"&gt;Git Hooks&lt;/a&gt; you can build a &lt;a href="https://github.com/git/git/blob/master/templates/hooks--pre-commit.sample" rel="noopener noreferrer"&gt;pre-commit hook&lt;/a&gt; and check every pull request for secrets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgithub-secrets-in-code-datree.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgithub-secrets-in-code-datree.png" alt="secrets in code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. ⛔ Avoid committing dependencies into your project
&lt;/h2&gt;

&lt;p&gt;Pushing dependencies into your remote origin will increase repository size. Remove any projects dependencies included in your repositories and let your package manager download them in each build. if you are afraid of “dependencies availability” you should consider using a binary repository manager solution like &lt;a href="https://jfrog.com/" rel="noopener noreferrer"&gt;Jfrog&lt;/a&gt; or &lt;a href="https://www.sonatype.com/nexus-repository-sonatype" rel="noopener noreferrer"&gt;Nexus Repository&lt;/a&gt;. Also, check out &lt;a href="https://github.com/github/git-sizer" rel="noopener noreferrer"&gt;Git-Sizer&lt;/a&gt; by GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. 🔧 Separate configuration files from source code
&lt;/h2&gt;

&lt;p&gt;We strongly recommend against committing your local config files to version control. Usually, those are private configuration files which you don’t want to push to remote because they are holding secrets, personal preferences, history or general information which should stay only in your local environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  📤 3. Create a meaningful .gitignore file for your projects
&lt;/h2&gt;

&lt;p&gt;A .gitignore file is a must in each repository to ignore predefined files and directories. It will help you to prevent secret keys, dependencies and many other possible discrepancies in your code. You can choose a relevant template from &lt;a href="https://www.gitignore.io/" rel="noopener noreferrer"&gt;Gitignore.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgitignore.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgitignore.gif" alt="gitignore"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. 💀 Archive dead repositories
&lt;/h2&gt;

&lt;p&gt;Over time, for various reasons, we find ourself with unmaintained repositories. Maybe you opened a new repository for an ad hoc use case (or you wanted to POC a new tech) or you have some repositories with old and irrelevant code. The problem is the same – those repositories are not actively developed anymore after they served their purpose, so you don’t want to maintain them or other people will rely on/use them. The best practice will always be to archive those repositories which will make them “read-only” to everyone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgithub-archive-repo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgithub-archive-repo.gif" alt="archive repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. 🔒 Lock package version
&lt;/h2&gt;

&lt;p&gt;Your manifest file holds the information about all of your packages versions to maintain consistent results without breaking your code every time you install your app dependencies. The best practice is to use a manifest lock file to avoid any discrepancies and confirm that you are getting the same packages version each time. The opposite being that you leave your code component version imprecise, are uncertain which version will be installed on the next build and your code may break.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fkoa-latest-version.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fkoa-latest-version.gif" alt="lock version"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  0. ♻️ Align packages versioning
&lt;/h2&gt;

&lt;p&gt;Although you are using the same package, a different version distribution will make it harder to reuse code and tests in various projects.&lt;/p&gt;

&lt;p&gt;If you have a package which is used in multiple projects, try at a minimum to use the same major version across the different repositories.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgithub-version-distribution-datree-catalog.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatree.io%2Fwp-content%2Fuploads%2F2018%2F10%2Fgithub-version-distribution-datree-catalog.jpg" alt="align version"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 What’s next?
&lt;/h2&gt;

&lt;p&gt;All that’s left for you to do is check off each of the aforementioned best practices, on each of your repositories, one by one.&lt;/p&gt;

&lt;p&gt;Or, save your sanity and connect with &lt;a href="https://github.com/marketplace/datree/?source=dev.to"&gt;Datree’s GitHub app&lt;/a&gt; (it's even free!) to scan your repositories and generate your free status report to assess if your repositories align with the listed best practices.&lt;/p&gt;

</description>
      <category>github</category>
      <category>bestpractices</category>
      <category>top10</category>
    </item>
    <item>
      <title>How to Get More Out of Your Git Commit Message</title>
      <dc:creator>Eyar Zilberman</dc:creator>
      <pubDate>Thu, 28 Mar 2019 12:06:00 +0000</pubDate>
      <link>https://forem.com/datreeio/how-to-get-more-out-of-your-git-commit-message-59bj</link>
      <guid>https://forem.com/datreeio/how-to-get-more-out-of-your-git-commit-message-59bj</guid>
      <description>&lt;h1&gt;
  
  
  Git commit message
&lt;/h1&gt;

&lt;p&gt;If you aren’t already, &lt;a href="http://www.commitlogsfromlastnight.com/"&gt;defining your project Git commit message&lt;/a&gt; convention is always on every developer’s “To-Do” list. Like flossing your teeth – everyone knows it’s necessary best practice for healthy gums and avoiding the dentist, but it ends up on the ‘I’ll move it to tomorrow’s to-do list’ aka, procrastination galore.&lt;/p&gt;

&lt;p&gt;I’m going to break down the reasons why you really have NO excuse not to set a Git commit message convention (or floss), and the required steps in order to move this task from your “To-Do” list to “DONE” in a few simple steps!&lt;/p&gt;

&lt;p&gt;I’ll leave your dentist to yell at you about not flossing 😁&lt;/p&gt;

&lt;h1&gt;
  
  
  Why use a commit message convention?
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Better collaboration between potential and existing committers
&lt;/h3&gt;

&lt;p&gt;It is important to communicate the nature of changes in projects in order to foster transparency to a slew of people: existing teammates, future contributors, and sometimes to the public and other stakeholders. It’s obvious why a well-formatted Git commit message convention is the best way to communicate context about a change to fellow developers (and their future selves) when requesting a peer code review. A commit message convention also makes it easier to explore a more structured commit history and to understand which notable changes have been made between each release (or version) of the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Squeeze the most out of git utilities
&lt;/h3&gt;

&lt;p&gt;“$ &lt;a href="https://git-scm.com/docs/git-log"&gt;git log&lt;/a&gt;” is a beautiful and useful snippet. A well-organized commit message history leads to more readable messages that are easy to follow when looking through the project history. Suddenly, navigating through the log output become a possible mission! Embracing a commit message convention will also help you properly use other git commands like git blame, git revert, git rebase, git shortlog and other git subcommands.&lt;/p&gt;

&lt;h3&gt;
  
  
  Support different automation tools
&lt;/h3&gt;

&lt;p&gt;Automation, automation, automation. Once you know you can rely on a standardized Git commit message, you can start building a flow around it and leverage the power of automation to level-up your project development flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic generation of CHANGELOG – keeps everyone up to date on &lt;a href="https://github.com/lob/generate-changelog"&gt;what happened between releases&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Automatic bump ups to the correct version – determine a &lt;a href="https://github.com/semantic-release/semantic-release"&gt;release semantic version&lt;/a&gt; based on the types of commits made per release.&lt;/li&gt;
&lt;li&gt;Automatic triggers to other processes – you are only limited by your own imagination on this one. For example, you can decide that a predefined string in the commit message &lt;a href="https://github.com/jenkinsci/commit-message-trigger-plugin"&gt;will trigger your CI&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Choosing the right commit message convention
&lt;/h1&gt;

&lt;p&gt;Now that we know that having a commit message convention is useful whether you’re working on an open source project, working on your own, or working with your team on a single project, standardizing the Git commit message is the only right way to commit!&lt;/p&gt;

&lt;p&gt;We covered the “why” part and now we will move to the “how” part – in my opinion, there are pretty much only two ways to go:&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Adopt defacto best practices
&lt;/h3&gt;

&lt;p&gt;This approach is a simple and easy guideline, good for getting used to the idea of having a convention/have a majority of coders or junior developers on the team. It’s the top 5 best practices to implement TODAY:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Have a commit message – white space or no characters at all can’t be a good description for any code change.&lt;/li&gt;
&lt;li&gt;Keep a short subject line – long subjects won’t look good when executing some git commands. Limit the subject line to 50 characters.&lt;/li&gt;
&lt;li&gt;Don’t end the subject line with a period – it’s unnecessary. Especially when you are trying to keep the commit title to under 50 characters.&lt;/li&gt;
&lt;li&gt;Start with a capital letter – straight from the source: “this is as simple as it sounds. Begin all subject lines with a capital letter”.&lt;/li&gt;
&lt;li&gt;Link to a planning system – if you are working with a planning system (like Jira), it is important to create a logical link between the planning ticket number and the subsequent code change.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  B. Adopt an existing conventions framework
&lt;/h3&gt;

&lt;p&gt;This approach is relevant for advanced/engaged teams, the key benefit of this approach is that you can also use the supporting tools in the ecosystem of the chosen conventions. There are plenty of different conventions so I will focus on the top two:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit"&gt;Angular Git commit message guidelines&lt;/a&gt; – well known and proven Git commit message convention which was introduced by the Angular project (A.K.A. Google).&lt;/li&gt;
&lt;li&gt;Emoji Git commit message convention – I’m not kidding, &lt;a href="https://github.com/carloscuesta/gitmoji"&gt;it’s a thing&lt;/a&gt;. Incorporating emoji in the commit message is an easy way of identifying the purpose or intention of a commit at a glance, and of course, emoji are fun 😜. Because this convention is a philosophy and not a method, if chosen, I would recommend &lt;a href="https://opensource.com/article/19/2/emoji-log-git-commit-messages"&gt;“Emoji-Log” commit message convention (by Ahmad Awais)&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  How to enforce Git commit message?
&lt;/h1&gt;

&lt;p&gt;If you got this far, you probably agree with my opinion that every project should have a defined commit message convention. Now, the question is how can I make sure all the project committers (me, outside contributors and teammates) are aligned about the chosen convention and apply to it? My top two solutions for that are:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔧 1. Git hooks
&lt;/h3&gt;

&lt;h3&gt;
  
  
  🚔 2. Server-side policy enforcement
&lt;/h3&gt;

&lt;p&gt;Both options explained with a guide on my &lt;a href="https://datree.io/blog/git-commit-message-conventions-for-readable-git-log/?source=dev.to"&gt;original blog post&lt;/a&gt; (I didn't add it here to keep this post short).&lt;/p&gt;

</description>
      <category>git</category>
      <category>commitmessage</category>
    </item>
  </channel>
</rss>
