<?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>DEV Community: José David Ureña Torres</title>
    <description>The latest articles on DEV Community by José David Ureña Torres (@jodaut).</description>
    <link>https://dev.to/jodaut</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%2F804927%2F1b5ce23a-c0dd-4b39-9c4e-1a1c229e13f2.jpeg</url>
      <title>DEV Community: José David Ureña Torres</title>
      <link>https://dev.to/jodaut</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jodaut"/>
    <language>en</language>
    <item>
      <title>How SSH Works—and How It Breaks: A Practical Guide to Secure Remote Access</title>
      <dc:creator>José David Ureña Torres</dc:creator>
      <pubDate>Sun, 29 Mar 2026 01:04:45 +0000</pubDate>
      <link>https://dev.to/jodaut/how-ssh-works-and-how-it-breaks-a-practical-guide-to-secure-remote-access-4m09</link>
      <guid>https://dev.to/jodaut/how-ssh-works-and-how-it-breaks-a-practical-guide-to-secure-remote-access-4m09</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;SSH (Secure Shell) is a cornerstone of modern computing. It’s no exaggeration to say that almost every software engineer and IT administrator has used an SSH client to manage a remote machine at some point of their careers. This protocol has been around since 1995 and it remains the gold standard of secure shell access.&lt;/p&gt;

&lt;p&gt;SSH provides encrypted tunnels over insecure networks, allowing secure access to remote machines. While the protocol itself is very robust and mature, its security ultimately depends on how it is used. Misconfigurations, inexperience and lack of knowledge can be an open door for attackers.&lt;/p&gt;

&lt;p&gt;And I’m speaking from experience. I've used SSH in insecure ways in the past, mainly because I didn’t fully understand how to protect my systems and applications correctly.&lt;/p&gt;

&lt;p&gt;In this series of three parts, we will explore how SSH can be misused, how attackers exploit common pitfalls, and how to avoid them.&lt;/p&gt;

&lt;p&gt;In the first part, we’ll discuss why you shouldn’t blindly trust the server you’re connecting to, and provide a high-level overview of how host key verification works.&lt;/p&gt;

&lt;p&gt;In the second part, we'll go through a small lab exercise to demonstrate a Man-in-the-Middle (MITM) attack, showing how an attacker can capture credentials and monitor live user activity.&lt;/p&gt;

&lt;p&gt;The last part focuses on hardening and best practices. We’ll cover practical, actionable security measures to protect your infrastructure and applications.&lt;/p&gt;

&lt;p&gt;Let’s get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why hostnames and IP addresses cannot be trusted for SSH authentication
&lt;/h2&gt;

&lt;p&gt;When you SSH to a remote machine, are you sure you are connecting to the right server? You might think that double-checking the hostname or IP address eliminates the risk, but that's not true. Verifying a destination address is not enough to guarantee a server's identity.&lt;/p&gt;

&lt;p&gt;At first glance, trusting an SSH connection based on a hostname seems secure. If you point your client toward &lt;code&gt;server.example.com&lt;/code&gt;, it feels like you must be connecting to the right place, right? However, hostnames and IP addresses are not inherently trustworthy, especially outside private networks; they depend on multiple layers of infrastructure that can be manipulated.&lt;/p&gt;

&lt;p&gt;For this reason, SSH security relies on cryptographic host key verification rather than simply trusting where the network appears to be routing your traffic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Attack Vectors
&lt;/h3&gt;

&lt;p&gt;There are different methods that can be used to redirect a connection to a malicious server without you even noticing, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS poisoning&lt;/li&gt;
&lt;li&gt;Host file poisoning&lt;/li&gt;
&lt;li&gt;Network-level and routing attacks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will cover these attacks in the following sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  DNS poisoning
&lt;/h3&gt;

&lt;p&gt;When you connect using a hostname (e.g., &lt;code&gt;ssh server.example.com&lt;/code&gt;), your system relies on DNS to resolve it to an IP address. Because low-level network communication requires IP addresses rather than human-readable names, this resolution step is a critical point of failure.&lt;/p&gt;

&lt;p&gt;In a DNS poisoning attack, an actor corrupts this resolution process so that a legitimate hostname resolves to a malicious IP address. This silently redirects your SSH connection, making the redirection nearly impossible to detect if you rely solely on the hostname for trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hosts file poisoning
&lt;/h3&gt;

&lt;p&gt;Operating systems can override external DNS resolution using a local hosts file (e.g., &lt;code&gt;/etc/hosts&lt;/code&gt; on Linux). If an attacker gains sufficient access to your machine, they can modify this file to force trusted hostnames to point to malicious IP addresses.&lt;/p&gt;

&lt;p&gt;While an attacker with this level of access could likely cause even more damage to your machine, this technique remains effective because it is simple and redirects traffic without raising immediate suspicion. It is important to note that hosts file poisoning is not a network attack, but rather a post-compromise persistence or redirection technique that bypasses DNS entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network-level and routing attacks
&lt;/h3&gt;

&lt;p&gt;Even if your DNS and local configurations are secure, the network path itself may be compromised. Attackers who control or compromise routers and switches can intercept or alter traffic in transit. This enables man-in-the-middle attacks, particularly on untrusted networks like public Wi-Fi or poorly secured internal LANs.&lt;/p&gt;

&lt;p&gt;At a larger scale, global internet routing can be manipulated as well. Attacks such as Border Gateway Protocol (BGP) hijacking allow malicious actors to redirect traffic through attacker-controlled networks, even when the destination IP address seems correct. Furthermore, IP addresses themselves are not permanent guarantors of a server's identity.&lt;/p&gt;

&lt;p&gt;In cloud environments, for example, IPs are frequently reassigned, meaning an address you trusted yesterday may belong to a completely different system today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Host Key Verification: How SSH Verifies the Server's Identity
&lt;/h2&gt;

&lt;p&gt;When you connect to a remote machine for the first time using SSH, your client likely does not know the server's public key yet. That is because the client has no record of this server, it will present a cryptographic fingerprint and ask if you want to proceed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;The authenticity of host &lt;span class="s1"&gt;'ssh-lab-server (172.18.3.102)'&lt;/span&gt; can&lt;span class="s1"&gt;'t be established.
ED25519 key fingerprint is SHA256:lgJpFZwUmV3iwY7kp9+gsiFrczV2/o3dIzP9kBq5czE.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you type yes, the server's public key is saved to the &lt;code&gt;~/.ssh/known_hosts&lt;/code&gt; file in your home directory. You can inspect this file to see the stored key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/known_hosts
ssh-lab-server ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEOQy4+6J3BirR3SuwLPRweCiTvkC/oVSdw/4XPBvm4t
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  When the Fingerprints Don't Match
&lt;/h3&gt;

&lt;p&gt;The next time you connect, the SSH client will compare the key provided by the server against the one stored in your known_hosts file. If they match, the connection proceeds.&lt;/p&gt;

&lt;p&gt;However, if the host key does not match, the OpenSSH client blocks the connection and displays an alarming warning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now &lt;span class="o"&gt;(&lt;/span&gt;man-in-the-middle attack&lt;span class="o"&gt;)!&lt;/span&gt;
It is also possible that a host key has just been changed.
The fingerprint &lt;span class="k"&gt;for &lt;/span&gt;the RSA key sent by the remote host is
SHA256:8o/qY3/YXiEUh5yHMH5Xe6Zpekiroj5QTVSBt7cF03o.
Please contact your system administrator.
Add correct host key &lt;span class="k"&gt;in&lt;/span&gt; /home/myclient/.ssh/known_hosts to get rid of this message.
Offending ED25519 key &lt;span class="k"&gt;in&lt;/span&gt; /home/myclient/.ssh/known_hosts:1
Host key &lt;span class="k"&gt;for &lt;/span&gt;ssh-lab-server has changed and you have requested strict checking.
Host key verification failed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the default behavior of the OpenSSH client, and it is your primary line of defense. It forces you to stop and investigate what happened, before continue and potentially send data or credentials to a malicious server.&lt;/p&gt;

&lt;h3&gt;
  
  
  But What Is a Fingerprint in the First Place?
&lt;/h3&gt;

&lt;p&gt;An SSH key fingerprint is a condensed, hash-based and fixed-length representation of a much larger public key.&lt;/p&gt;

&lt;p&gt;You might wonder: Why do we need a fingerprint if we can just check the public key directly? Essentially, for human readability and consistency. Public keys can be incredibly long and vary in size depending on the algorithm used (RSA vs ED25519). Displaying a short, fixed-length fingerprint is much more convenient for manual verification, logging, and monitoring.&lt;/p&gt;

&lt;p&gt;For example, consider this known_hosts file generated by pulling the public keys for GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-keyscan github.com &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.ssh/known_hosts
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/known_hosts
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk&lt;span class="o"&gt;=&lt;/span&gt;
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg&lt;span class="o"&gt;=&lt;/span&gt;
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the keys have different lengths, especially the RSA key, which is quite huge. Trying to visually compare those strings would be a nightmare. However, if we compute the fingerprints using ssh-keygen, the data becomes much more manageable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-keygen &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ~/.ssh/known_hosts
3072 SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s www.github.com &lt;span class="o"&gt;(&lt;/span&gt;RSA&lt;span class="o"&gt;)&lt;/span&gt;
256 SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM www.github.com &lt;span class="o"&gt;(&lt;/span&gt;ECDSA&lt;span class="o"&gt;)&lt;/span&gt;
256 SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU www.github.com &lt;span class="o"&gt;(&lt;/span&gt;ED25519&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much easier to read, isn't it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Questions and Misconceptions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  If I see a host key verification error, am I under a man-in-the-middle attack?
&lt;/h3&gt;

&lt;p&gt;Not necessarily, but you should never ignore the error. A server's public key can change for legitimate reasons, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server was rebuilt or reinstalled, generating new keys.&lt;/li&gt;
&lt;li&gt;The OS was upgraded or reconfigured.&lt;/li&gt;
&lt;li&gt;You are connecting to a new instance behind a load balancer or an autoscaling group.&lt;/li&gt;
&lt;li&gt;The infrastructure is ephemeral (e.g., cloud instances frequently destroyed and recreated).&lt;/li&gt;
&lt;li&gt;The administrator intentionally rotated the keys for security.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You must verify that this change is valid before proceeding.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why would anyone intentionally disable host key verification?
&lt;/h3&gt;

&lt;p&gt;It often happens because skipping the check feels "simpler" during development, especially when learning to use SSH libraries. These libraries often include warning logs specifically to alert developers who forget to implement verification. While disabling it might save time during a "Hello World" project, it creates a massive security hole if that code ever reaches production.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if I’m connecting via VPN or a private network?
&lt;/h3&gt;

&lt;p&gt;You might argue that internal infrastructure is "safe," but that is exactly the assumption attackers rely on. However, once an attacker is inside your VPN, they can compromise one or more machines. The risk is lower than the open internet, but it is never zero.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about automation tools like Ansible?
&lt;/h3&gt;

&lt;p&gt;This is one of the most common places where verification is disabled. Developers are often tempted to bypass host key verification to avoid friction when configuring and managing environments.&lt;/p&gt;

&lt;p&gt;This is typically done in one of three ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the configuration file: By setting &lt;code&gt;host_key_checking = False&lt;/code&gt; inside the [defaults] section of the ansible.cfg file.&lt;/li&gt;
&lt;li&gt;As an environment variable: By exporting &lt;code&gt;ANSIBLE_HOST_KEY_CHECKING=False&lt;/code&gt; in the terminal session before running a playbook.&lt;/li&gt;
&lt;li&gt;Directly at SSH level: By specifying &lt;code&gt;StrictHostKeyChecking=no&lt;/code&gt; as a connection argument, via &lt;code&gt;ansible_ssh_common_args&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this simplifies the first stages of a project, it is a habit that must be broken. Eventually, you should implement a proper verification strategy (like using a Certificate Authority or pre-populating known_hosts), especially when connecting to machines outside your immediate control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do testing environments really need this level of caution?
&lt;/h3&gt;

&lt;p&gt;You might think a test server has no useful data, but that depends on your configuration. Attackers often use "low-value" environments as a stepping stone. If your test environment uses the same credentials or has network access to your production database, a stolen SSH session on a testing machine could potentially compromise the rest of the company's infrastructure.&lt;/p&gt;

&lt;p&gt;The risk is naturally lower when working with ephemeral and immutable infrastructure, where machines are frequently destroyed and recreated. In contrast, environments with long-lived infrastructure should always apply strict SSH host key verification practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this first part, we discussed how SSH verifies a server's identity and why hostnames and IP addresses are not reliable guarantors of that identity. We explored how attackers can manipulate network infrastructure via DNS poisoning, host file modification, or routing attacks to take advantage of poor SSH configurations. Knowing the risks of improper SSH configurations is the first step toward hardening applications and infrastructure that rely on SSH.&lt;/p&gt;

&lt;p&gt;In the next article, we will move from theory to practice. We’ll walk through a lab exercise to demonstrate exactly how an attacker can steal credentials and monitor live user activity using a man-in-the-middle attack.&lt;/p&gt;

&lt;p&gt;Stay tuned for Part 2!&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliography
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Clouflare | 2026 | &lt;a href="https://www.cloudflare.com/learning/dns/dns-cache-poisoning/" rel="noopener noreferrer"&gt;What is DNS cache poisoning?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;eG Innovations | 2026 | &lt;a href="https://www.eginnovations.com/glossary/ansible" rel="noopener noreferrer"&gt;What is Ansible?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ergaster | 2023 | &lt;a href="https://ergaster.org/posts/2023/10/18-checking-ssh-fingerprints/" rel="noopener noreferrer"&gt;Should you check SSH fingerprints?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Mercans | 2026 | &lt;a href="https://mercans.com/client-resource-center/why-ssh-fingerprint-verification-is-essential-for-secure-sftp-access-meeting-industry-standards/" rel="noopener noreferrer"&gt;Why SSH Fingerprint Verification Is Essential for Secure SFTP Access: Meeting Industry Standards&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>networking</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Linux Without Fanboyism: An Honest Developer’s Perspective</title>
      <dc:creator>José David Ureña Torres</dc:creator>
      <pubDate>Sun, 14 Dec 2025 00:02:44 +0000</pubDate>
      <link>https://dev.to/jodaut/linux-without-fanboyism-an-honest-developers-perspective-3mhf</link>
      <guid>https://dev.to/jodaut/linux-without-fanboyism-an-honest-developers-perspective-3mhf</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a software engineer, I try not to get too attached to a single operating system. Computers are just tools we use to get the job done, and unless your work depends on platform-specific software, most modern operating systems will serve you well.&lt;/p&gt;

&lt;p&gt;Whenever possible, I like to use more than one operating system to avoid being biased by personal preferences. In this article, I’ll share my personal experience using Linux as a daily desktop operating system, highlighting both the good and the bad.&lt;/p&gt;

&lt;p&gt;Everything here reflects my own opinions and experiences, so keep in mind that they may be subjective.&lt;/p&gt;

&lt;p&gt;This article is aimed at developers and technical users who are curious about Linux as a desktop operating system, especially those coming from Windows or macOS. If you’re looking for an honest, experience-based perspective rather than a sales pitch, this is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Linux Journey
&lt;/h2&gt;

&lt;p&gt;If you thought I was going to talk about how Linux is the best operating system and why all the others are garbage, you’re wrong. And this is probably not the article for you. I’ve used Windows, Linux, and macOS, and I like them all. Each one shines in different situations.&lt;/p&gt;

&lt;p&gt;I’m not the person who will tell you that Windows is evil or that you’re a superior human being if you compile the Linux kernel yourself. Windows is great, and if you don’t have a good reason to try Linux, that’s totally fine.&lt;/p&gt;

&lt;p&gt;That said, I do have a nostalgic relationship with Linux.&lt;/p&gt;

&lt;p&gt;When I started college, I couldn’t afford a new computer. I was using an old laptop that struggled with basic tasks like web browsing, office work, and coding. I planned to replace it by the end of the year, but in the meantime I needed a way to make it usable. I didn’t want to go into debt just to buy a computer.&lt;/p&gt;

&lt;p&gt;While researching ways to reduce resource usage, I discovered Linux. What caught my attention were stories about how it could give old computers a second life.&lt;/p&gt;

&lt;p&gt;As a beginner, I ran into many problems installing and configuring it, mostly because I wasn’t familiar with the terminal. After a few days of trial and error, I managed to install everything I needed for college, and the machine became usable again, at least long enough for me to save up for a new one.&lt;/p&gt;

&lt;p&gt;Of course, I broke my system a few times along the way and dealt with the usual beginner issues: Wi-Fi problems, hardware compatibility quirks, laggy video playback, and poor battery life. I eventually fixed most of them, except for battery life, which is still a common challenge on some laptops today.&lt;/p&gt;

&lt;p&gt;Despite the frustration, that period taught me a lot about how computers and operating systems actually work. I spent hours reading documentation and forum posts to solve these problems.&lt;/p&gt;

&lt;p&gt;Today, I use a MacBook Air for portability, but I also have a desktop PC that I built specifically to run Linux. I don’t have enough time to experiment with new distributions as much as I used to, but I still enjoy using Linux regularly and staying connected to the ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The good parts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The appeal of Linux
&lt;/h3&gt;

&lt;p&gt;Once you’re comfortable with Linux, you start missing some features when using other operating systems. Personally, I love how easy it is to install and uninstall software using a package manager like &lt;code&gt;apt&lt;/code&gt; or &lt;code&gt;dnf&lt;/code&gt;. Windows has Chocolatey and macOS has Homebrew, but Linux package managers generally feel more integrated and robust.&lt;/p&gt;

&lt;h3&gt;
  
  
  Highly customizable
&lt;/h3&gt;

&lt;p&gt;Linux gives you a high level of control over your computer. You can customize the operating system to fit your needs. Of course, this varies depending on the distribution and the desktop environment you’re using, but most distros offer extensive customization options.&lt;/p&gt;

&lt;p&gt;You can install several desktop environments at once: GNOME, KDE, XFCE, i3, dwm, etc. Linux’s modular nature makes it easy for them to coexist.&lt;/p&gt;

&lt;h3&gt;
  
  
  Familiar if you use Linux at work
&lt;/h3&gt;

&lt;p&gt;If you already use Linux at work, such as when connecting to remote machines or managing a VPS on a cloud provider, using Linux on your personal machine feels natural. It’s also a great way to practice and improve your skills.&lt;/p&gt;

&lt;p&gt;The knowledge you gain often becomes useful later when dealing with servers, Docker containers, or production environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker containers run natively on Linux
&lt;/h3&gt;

&lt;p&gt;Containers are a lightweight form of operating-system-level virtualization. They package applications and all their dependencies into an isolated, portable, and consistent environment.&lt;/p&gt;

&lt;p&gt;This technology is fundamentally a Linux feature. Docker is mostly an orchestrator and convenience layer; the actual containerization is handled by the Linux kernel itself. To simplify a bit, containers are regular Linux processes that run directly on the host kernel, but inside restricted environments created using namespaces (to isolate things like filesystems, networking, and PIDs) and cgroups (to limit CPU, memory, and other resources).&lt;/p&gt;

&lt;p&gt;Because this relies on Linux kernel features, Docker Desktop on Windows and macOS uses an additional virtualization layer to provide a Linux environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scripting and automation
&lt;/h3&gt;

&lt;p&gt;Linux is also great for writing scripts or automate repetitive tasks. You can write Bash, Python, or Go scripts and run them as systemd services, or add them to your &lt;code&gt;PATH&lt;/code&gt; so they behave like regular commands.&lt;/p&gt;

&lt;p&gt;Of course, most of this is possible on other operating systems, but I personally find it easier and more natural to do on Linux.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trade-offs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Things can break
&lt;/h3&gt;

&lt;p&gt;Especially if you’re new and don’t fully know what you’re doing, things are more likely to break or not work as expected. On Windows, things usually “just work”, and that’s probably what I like the most about it: you plug something in, and it magically works. At least that has been my experience with Windows. On Linux, be prepared to spend time reading documentation and troubleshooting issues.&lt;/p&gt;

&lt;p&gt;And sometimes it’s not even your fault. Even though Linux itself is generally rock-solid, that doesn’t mean all software running on Linux is bug-free. In many cases, companies don’t invest much effort into fixing Linux-specific issues because their main target audience uses Windows or macOS. It is what it is. You learn to deal with it and move on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning curve
&lt;/h3&gt;

&lt;p&gt;Linux can be intimidating at first. You need to learn new ways of doing things that you were already comfortable with on Windows or macOS. In many cases, you’ll have to learn the “Linux way”.&lt;/p&gt;

&lt;p&gt;New users also have to decide which Linux distribution they want to install, and the differences between them are not always clear. And Linux has many different distributions. Also, depending on the distro, you also need to choose a desktop environment from several options. All of this can be confusing at the beginning.&lt;/p&gt;

&lt;p&gt;You’ll also find yourself using the terminal more often. On Linux, typing a command sometimes feels faster and easier than clicking through a graphical interface. I know, it sounds contradictory. Why would typing commands be faster than clicking icons and menus? But trust me, most Linux users would probably agree: typing commands somehow just feels faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hardware support
&lt;/h3&gt;

&lt;p&gt;This is another point in favor of Windows. On Linux, some hardware may need extra configuration or may not work perfectly. I’ve experienced issues with multi-monitor setups, headphones, and HDMI connections, not necessarily due to faulty hardware, but because of drivers, firmware, or display-server quirks. Multi-monitor setups often depend on graphics drivers and desktop environment settings, while headphones and HDMI sometimes require minor tweaks. Tasks like these can occasionally be tricky, though support has improved significantly in recent years.&lt;/p&gt;

&lt;p&gt;If you’re building a new PC specifically to run Linux, my recommendation is to first verify that your hardware is well supported. Some components can still be problematic depending on the setup. For example, NVIDIA GPUs may require extra configuration or proprietary drivers, which can occasionally lead to issues.&lt;/p&gt;

&lt;p&gt;Despite careful hardware selection, some minor problems can still occur.&lt;/p&gt;

&lt;h3&gt;
  
  
  Software compatibility
&lt;/h3&gt;

&lt;p&gt;Not all software is available on Linux. Microsoft Office and Adobe applications are two common examples. While open-source alternatives exist, you may feel that they don’t fully match their proprietary counterparts.&lt;/p&gt;

&lt;p&gt;For document and spreadsheet editing, for example, I usually rely on the web version of Office 365, which is more than enough for my needs. I also keep LibreOffice installed, just in case.&lt;/p&gt;

&lt;p&gt;Open-source software is created and maintained by communities and companies, but these projects aren’t always driven by profit. In many cases, contributors and maintainers aren’t making any money from it, so don't blame them. I say “in many cases” because there are open-source projects that do have a business model behind, such as VS Code or Next.js.&lt;/p&gt;

&lt;p&gt;Most contributors work on these projects simply because they want to. Remember, they also have personal lives and often full-time jobs. Depending on the project, you can contribute as well. So if you’re a developer and have some free time when you encounter a bug, consider investigating it, you might find a fix and submit a Pull Request. Even small contributions like this help improve open-source software for everyone.&lt;/p&gt;

&lt;p&gt;That way, we can all contribute to open-source software, even in small ways. But I know, that’s much easier said than done.&lt;/p&gt;

&lt;p&gt;Despite these downsides, most of the problems I’ve mentioned can be avoided or mitigated with some guidance. Hardware compatibility, as well as choosing a distribution and desktop environment that suit your needs, play a major role in how smooth or frustrating your Linux experience will be. The next sections focus on practical tips to help you get started on the right foot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the right hardware for you
&lt;/h2&gt;

&lt;p&gt;There’s no magic advice here; do your homework. First, determine your hardware needs and research components based on that. You can use websites like &lt;a href="https://linux-hardware.org/" rel="noopener noreferrer"&gt;Linux Hardware&lt;/a&gt; to look up specific components; it was very helpful for me.&lt;/p&gt;

&lt;p&gt;If you’re buying a PC piece by piece, try to avoid hardware that is known to be problematic on Linux, such as certain NVIDIA GPUs or very recent components that haven’t been properly tested yet.&lt;/p&gt;

&lt;p&gt;Reddit forums are also a great resource for researching hardware compatibility issues on Linux.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the right Linux distribution for you
&lt;/h2&gt;

&lt;p&gt;A Linux distribution is a complete operating system that includes the Linux kernel, usually the GNU user-space tools and libraries, a package manager, some preinstalled applications, and default configurations. A desktop environment may also be included, depending on the distribution.&lt;/p&gt;

&lt;p&gt;There are many articles and videos about Linux distributions. Others may disagree, but if you’re just starting out, I think there are only three you need to consider: Ubuntu, Linux Mint, and Fedora.&lt;/p&gt;

&lt;p&gt;For your first Linux distribution, I’d recommend choosing either Mint or Ubuntu. You can’t really go wrong with either. I prefer Linux Mint because it feels more familiar if you’re coming from Windows, but both are excellent choices. Linux Mint is based on Ubuntu.&lt;/p&gt;

&lt;p&gt;For developers, Fedora can also be a solid option. It’s a more bleeding-edge distribution, which means it includes newer packages compared to Ubuntu and Mint. It also tends to ship new features earlier, which may take some time to appear in other distributions. However, this also means you might encounter occasional errors or compatibility issues that are less common in more stable distributions.&lt;/p&gt;

&lt;p&gt;There are other distributions that I think are better suited for more advanced users, or at least users who already have strong preferences. Debian and Arch Linux fall into this category. They are great distributions, but probably not ideal as a first distro.&lt;/p&gt;

&lt;p&gt;Personally, I use Fedora on my desktop PC today, but years ago I used Linux Mint as my main system. Both have been very good experiences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the right desktop environment for you
&lt;/h2&gt;

&lt;p&gt;This largely depends on the distribution you choose. For example, Ubuntu comes with a customized version of GNOME. Linux Mint offers three editions: Cinnamon (the default), MATE, and XFCE.&lt;/p&gt;

&lt;p&gt;Fedora provides even more options on its website, including GNOME (default), KDE Plasma, XFCE, LXQt, and Cinnamon.&lt;/p&gt;

&lt;p&gt;If you’re not sure which desktop environment to choose, install a few of them and try them out. On Linux, you can have multiple desktop environments installed at the same time. &lt;/p&gt;

&lt;p&gt;If you don’t want to experiment too much, you can safely choose between GNOME or KDE. KDE is usually a solid choice if you’re coming from Windows.&lt;/p&gt;

&lt;p&gt;Nowadays, the desktop environment I use is XFCE because it’s very lightweight and works well out of the box. There’s no particular reason beyond that. I installed it, it worked well, and I stuck with it. No reason to change.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few common questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is Linux for everyone?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. If your work depends heavily on proprietary software or specific hardware that doesn’t work well on Linux, it may not be the right choice; and that’s okay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should you switch to Linux full-time?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Not necessarily. Many people, including me, benefit from using Linux alongside Windows or macOS, either on a separate machine, a dual-boot setup, or a virtual machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it worth trying Linux at least once?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Definitely. Even if you don’t stick with it, the experience can teach you a lot about operating systems, tools, and how computers work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are already using Linux, should you switch to another distribution?&lt;/strong&gt;&lt;br&gt;
It depends, but usually no. If you’re switching just because of FOMO, it’s probably not worth it. If you’re facing a specific issue and you’ve confirmed that it’s handled better on another distribution, then switching can make sense. That said, hardware issues are rarely fixed simply by changing distros.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article reflects my personal experience with Linux, and yours may be very different. My main recommendation is to try a few distributions using VirtualBox or similar virtualization tools and see what works best for you. Once you choose one, try to stick with it for a while instead of constantly distro-hopping. If I had to recommend a single distribution to start with, I can confidently suggest Linux Mint.&lt;/p&gt;

&lt;p&gt;Once you step into the Linux world, try not to become overly “religious” about it. Avoid distro wars and pointless debates, especially on forums and social media. Just relax, learn, explore, and enjoy the experience.&lt;/p&gt;

&lt;p&gt;For me, learning Linux has been a very positive experience. Early in my career as a software engineer, even a basic understanding of Linux helped me work more efficiently and understand systems at a deeper level. Even if Linux never becomes your main operating system, the knowledge you gain from using it will almost certainly pay off.&lt;/p&gt;

&lt;p&gt;I can’t promise you’ll love Linux, but you might. Either way, it’s worth trying at least once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliography
&lt;/h2&gt;

&lt;p&gt;Arch Linux Wiki | 2025 | &lt;a href="https://wiki.archlinux.org/title/Arch_compared_to_other_distributions" rel="noopener noreferrer"&gt;Arch compared to other distributions&lt;/a&gt;&lt;br&gt;
Arch Linux Wiki | 2025 | &lt;a href="https://wiki.archlinux.org/title/Desktop_environment" rel="noopener noreferrer"&gt;Desktop environment&lt;/a&gt;&lt;br&gt;
Hardware for Linux | 2025 | &lt;a href="https://linux-hardware.org/" rel="noopener noreferrer"&gt;Hardware for Linux&lt;/a&gt;&lt;br&gt;
Red Hat | 2017 | &lt;a href="https://www.redhat.com/en/blog/containers-are-linux" rel="noopener noreferrer"&gt;Containers are Linux&lt;/a&gt;&lt;br&gt;
Red Hat | 2025 | &lt;a href="https://www.redhat.com/en/topics/containers/whats-a-linux-container" rel="noopener noreferrer"&gt;What is a Linux container&lt;/a&gt;&lt;br&gt;
Wikipedia | 2018 | &lt;a href="https://en.wikipedia.org/wiki/List_of_Linux_distributions" rel="noopener noreferrer"&gt;List of Linux Distributions&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>programming</category>
      <category>software</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Building A Minimal SSH Server in Go</title>
      <dc:creator>José David Ureña Torres</dc:creator>
      <pubDate>Tue, 02 Sep 2025 05:21:57 +0000</pubDate>
      <link>https://dev.to/jodaut/implementing-a-minimal-ssh-server-in-go-3b2k</link>
      <guid>https://dev.to/jodaut/implementing-a-minimal-ssh-server-in-go-3b2k</guid>
      <description>&lt;p&gt;SSH is one of those technologies we often take for granted. Most engineers use it daily to connect to and manage remote machines. It’s a foundational part of internet infrastructure, and the modern digital world would look very different without it.&lt;/p&gt;

&lt;p&gt;It enables secure remote access over unsecured networks, relying on cryptography to authenticate and encrypt connections between devices.&lt;br&gt;
As a weekend project, I’ve been building a minimal SSH server in Go. My goal wasn’t to reinvent the wheel, but to gain a deeper understanding of the protocol’s inner workings.&lt;/p&gt;

&lt;p&gt;My experience with SSH was primarily as a user: opening terminals, setting up port forwarding, and occasionally tweaking the &lt;code&gt;sshd_config&lt;/code&gt; file to suit specific needs. Like many engineers, I've always found it a bit magical. You type a command, and boom: you are connected to a remote machine. I wanted to understand what happen behind the scenes.&lt;/p&gt;

&lt;p&gt;When I want to learn something new, my usual approach is to study the theory first, reading articles and documentation or doing an online course depending on the case, and then try to wrap up that knowledge by building a small project. Getting your hands dirty is, in my opinion, one of the best ways to truly internalize a concept.&lt;/p&gt;

&lt;p&gt;In this reading, I'll walk you through how I built a minimal SSH server as a weekend project. If you're just here for the code, feel free to jump to the GitHub link at the end. The README file has all the information you need of how to compile and use the application.&lt;/p&gt;

&lt;p&gt;I'll also share my thought process as a software engineer when tackling a new project. Keep in mind this was a time-boxed experiment, so I made a few trade-offs to keep things simple and focused. Still, if you're a college student or someone learning to code, I hope this gives you some insight into how small projects can complement your learning journey.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why An SSH Server?
&lt;/h2&gt;

&lt;p&gt;One option was to build an SSH client instead, which would've been an interesting choice too. But creating something that could run as a service, managed by tools like &lt;code&gt;systemd&lt;/code&gt; on Linux, sounded more appealing.&lt;/p&gt;

&lt;p&gt;After thinking about it, I decided to explore the server side of the SSH protocol and write a small SSH server. I wanted to go deep enough to understand the core message flow that makes SSH connections work. &lt;/p&gt;

&lt;p&gt;So I spent a few days reading about the SSH protocol in my free time. After that, I scoped out the requirements for my weekend project.&lt;/p&gt;
&lt;h2&gt;
  
  
  Overview of SSH Channel Types and Requests
&lt;/h2&gt;

&lt;p&gt;This section provides a high-level overview of key aspects of the SSH protocol, focusing on the events and messages I needed for this project. &lt;/p&gt;

&lt;p&gt;The SSH protocol runs over TCP and supports multiple channel types, each serving different purposes. Some channels handle data streams, while others are designed to process request messages.&lt;/p&gt;
&lt;h3&gt;
  
  
  SSH Channel Types
&lt;/h3&gt;

&lt;p&gt;Each channel type defines what the channel is used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;session: The most common channel type. Used for remote shells, and command execution and subsystems.&lt;/li&gt;
&lt;li&gt;x11: Used for X11 forwarding. Allows remote GUI apps to display locally via the X Window System.&lt;/li&gt;
&lt;li&gt;forwarded-tcpip: Used for local port forwarding. Data sent to a local port is forwarded through the SSH tunnel to a destination host/port.&lt;/li&gt;
&lt;li&gt;direct-tcpip: Used for remote port forwarding. The remote SSH server connects to a specified address/port and sends data through the tunnel back to the client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to these, OpenSSH defines some extended channel types that are not part of the official SSH protocol:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;direct-streamlocal@openssh.com&lt;/code&gt;: Used for forwarding Unix domain sockets. It's similar to direct-tcpip, but forwards socket paths instead of TCP ports.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;forwarded-streamlocal@openssh.com&lt;/code&gt;: Used for forwarding Unix domain sockets in the opposite direction.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Channel Requests
&lt;/h3&gt;

&lt;p&gt;The session channel is the main channel type that receives channel requests. Other channels, such as x11, direct-tcpip, and forwarded-tcpip, do not receive channel requests. Those are primarily used for raw data forwarding.&lt;/p&gt;

&lt;p&gt;Here is a list of the most common requests types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pty-req: Requests a pseudo-terminal for interactive shell.&lt;/li&gt;
&lt;li&gt;shell: Starts an interactive shell session.&lt;/li&gt;
&lt;li&gt;exec: Executes a single command.&lt;/li&gt;
&lt;li&gt;subsystem: Requests a subsystem (e.g., sftp).&lt;/li&gt;
&lt;li&gt;x11-req: Requests X11 forwarding for the session.&lt;/li&gt;
&lt;li&gt;env: Sets environment variables.&lt;/li&gt;
&lt;li&gt;window-change: Notifies of window size changes.&lt;/li&gt;
&lt;li&gt;signal: Sends POSIX signals (e.g., SIGINT) to the remote process.&lt;/li&gt;
&lt;li&gt;exit-status: Sent by server to indicate process exit code.&lt;/li&gt;
&lt;li&gt;exit-signal: Sent by server to indicate process was terminated by signal.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Project Scope and Technical Approach
&lt;/h2&gt;

&lt;p&gt;This section describes the project scope and the requirements I chose to include. In real-world projects, features typically go through several rounds of refinement before development begins. The final output often consists of a set of well-defined tickets, each with specific tasks and clear acceptance criteria.&lt;/p&gt;
&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;The goal was to build a very minimal SSH server with support for two use cases: executing a single remote command and starting an interactive shell session. &lt;/p&gt;

&lt;p&gt;If you are not familiarized with this terms, when using the OpenSSH client, you can run a remote command like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh &amp;lt;user&amp;gt;@&amp;lt;address&amp;gt; &amp;lt;command&amp;gt;
ssh myuser@x.x.x.x echo hello world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or for starting an interactive shell you can omit the command as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh &amp;lt;user&amp;gt;@&amp;lt;address&amp;gt;
ssh myuser@x.x.x.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I decided to add support for only these two use cases. While adding features like port forwarding might be fun in the future, for this initial version I wanted to focus on the most basic functionality. &lt;/p&gt;

&lt;p&gt;The server must close the sessions properly once the remote command finishes, or when the user exits the shell or terminates the process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;p&gt;SSH typically supports two main authentication methods: password authentication and public key authentication.&lt;/p&gt;

&lt;p&gt;At first glance, password authentication might seem easier to implement. However, it actually requires handling interactive password prompts, which adds complexity. To keep things simple, I decided to go with public key authentication for this initial version.&lt;/p&gt;

&lt;p&gt;With this approach, I just need to generate an SSH key pair and provide an &lt;code&gt;authorized_keys&lt;/code&gt; file. This file tells the server which public keys are allowed to authenticate.&lt;/p&gt;

&lt;p&gt;To connect, the user must specify their private key explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -i &amp;lt;path-to-private-key&amp;gt; &amp;lt;user&amp;gt;@&amp;lt;address&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It might seem that we are sending the private key to the server, but actually not. The SSH client derives the public key from the private key, which is what actually gets sent to the server for authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSH server configuration
&lt;/h3&gt;

&lt;p&gt;I initially considered creating a simplified version of &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;, the configuration file used by the OpenSSH server. But for this minimal project, I only needed a few basic settings to customize the application.&lt;/p&gt;

&lt;p&gt;So, I went with a simple YAML file that gets read at startup. This allows the application to specify things like the network interface and port to listen on, or which users are allowed to connect, and that is more than enough for the scope of this project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Access control
&lt;/h3&gt;

&lt;p&gt;I decided to implement an allowlist-based access control model using an &lt;code&gt;authorized_users&lt;/code&gt; setting in the config file. With this approach, only the users listed there are allowed to connect.&lt;/p&gt;

&lt;p&gt;In a typical SSH setup, the server reads each user's ~/.ssh/authorized_keys file, and you can add a public key for a particular user with the &lt;code&gt;ssh-copy-id&lt;/code&gt; command. But for simplicity, this implementation reads a single &lt;code&gt;authorized_keys&lt;/code&gt; file specified in the config. That also means multiple users can authenticate using the same key, as long as they possess it.&lt;/p&gt;

&lt;p&gt;Additionally, the application should read the &lt;code&gt;/etc/passwd&lt;/code&gt; file to ensure that the user exists, have a home directory and a default login shell.&lt;/p&gt;

&lt;h3&gt;
  
  
  Concurrency
&lt;/h3&gt;

&lt;p&gt;The application needs to allow multiple clients connected at the same time. For this minimal version, we can skip using a thread pool or any advanced scheduling, but the design must still support concurrent usage from the beginning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;At a minimum, there should be tests covering the most essential scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can a user connect with a valid key?&lt;/li&gt;
&lt;li&gt;Does the server reject unknown users or invalid keys?&lt;/li&gt;
&lt;li&gt;Can the server execute a single command correctly?&lt;/li&gt;
&lt;li&gt;Can the server start an interactive shell session?&lt;/li&gt;
&lt;li&gt;Can the server handle multiple simultaneous user connections?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Language
&lt;/h3&gt;

&lt;p&gt;As the title already suggests, this project was written in Go. It's a solid choice for scripting, command-line tools, small APIs, socket programming, and services that run as background processes on the Operating System.&lt;/p&gt;

&lt;p&gt;It offers excellent built-in support for networking and concurrency, making it a natural fit for implementing an SSH server. And since it’s a compiled language, packaging and running the final application is simple and efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coding phase
&lt;/h2&gt;

&lt;p&gt;Since this project focuses only on executing single commands and starting interactive shells, the only channel type I needed to implement was the session one. I didn't have to support every possible request type, but at least the essentials: exec, shell, and pty-req.&lt;/p&gt;

&lt;h3&gt;
  
  
  High-Level Steps
&lt;/h3&gt;

&lt;p&gt;Here is what the application needs to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the configuration file, which defines allowed users, the listening address, and the port.&lt;/li&gt;
&lt;li&gt;Read information about the authorized users, like uid, gid, home directory and default login shell.&lt;/li&gt;
&lt;li&gt;Initialize the SSH server using these settings.&lt;/li&gt;
&lt;li&gt;Load the server’s private key, which acts as the host key. (In OpenSSH, these are typically located in &lt;code&gt;/etc/ssh/&lt;/code&gt;.)&lt;/li&gt;
&lt;li&gt;Start a TCP listener on the configured interface and port.&lt;/li&gt;
&lt;li&gt;Ignore non-session channels, since only session is supported in this version.&lt;/li&gt;
&lt;li&gt;Handle exec, shell, and pty-req requests on session channels.&lt;/li&gt;
&lt;li&gt;For exec requests, run the provided command and return the output.&lt;/li&gt;
&lt;li&gt;For interactive sessions, pty-req usually arrives before the shell request, so save the terminal info to be used when launching the shell.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Challenges
&lt;/h3&gt;

&lt;p&gt;Most of the implementation went smoothly, but there were a few tricky areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managing &lt;code&gt;stdout&lt;/code&gt; and &lt;code&gt;stderr&lt;/code&gt; from the command or shell process correctly without blocking the stream of data. I ended up using separate Go routines to stream output back to the client.&lt;/li&gt;
&lt;li&gt;Minor issues parsing SSH keys due to a mistake in the &lt;code&gt;authorized_keys&lt;/code&gt; file. I used a wrong format for the public keys.&lt;/li&gt;
&lt;li&gt;Implementing PTY handling, especially attaching the shell to a pseudo-terminal to support features like prompts and signal handling. This feature was not implemented completely, proper signal handling and terminal modes is pending.&lt;/li&gt;
&lt;li&gt;Had some issues closing the session correctly. It was not working correctly at first, causing the connection to freeze on the client side. It was being caused by a channel not being closed properly.&lt;/li&gt;
&lt;li&gt;Commands must be executed as the connecting user. To achieve this I required to add &lt;code&gt;cap_setuid&lt;/code&gt; and &lt;code&gt;cap_setgid&lt;/code&gt; capabilities to the binary, which was not part of my plan. Without those capabilities the application does not have enough permissions to run commands as other users.&lt;/li&gt;
&lt;li&gt;While writing integration tests, I found that OpenSSH is slightly more permissive than the Go SSH library when handling certain protocol errors from the server. In some cases, the code worked with the OpenSSH client but failed with the Go SSH library. But this was actually good, as it helped me to improve the implementation to better align with the SSH standard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eventually, I got everything working. I took inspiration from a couple of excellent resources to solve some of the harder parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gopher Academy (2015)&lt;/strong&gt; - &lt;a href="https://blog.gopheracademy.com/advent-2015/ssh-server-in-go/" rel="noopener noreferrer"&gt;Building an SSH Server in Go&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gliderlabs (2025)&lt;/strong&gt; - &lt;a href="https://github.com/gliderlabs/ssh" rel="noopener noreferrer"&gt;Gliderlabs SSH Package&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Source code
&lt;/h2&gt;

&lt;p&gt;If you want dive into the code it's available on my &lt;a href="https://github.com/JoDaUT/go-ssh-server" rel="noopener noreferrer"&gt;Github&lt;/a&gt;. Feel free to explore, clone it, or use it as a reference for your own experiments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliography
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cloudfare - 2025 - &lt;a href="https://www.cloudflare.com/learning/access-management/what-is-ssh/" rel="noopener noreferrer"&gt;What is SSH&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Digital Ocean - 2025 - &lt;a href="https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys" rel="noopener noreferrer"&gt;SSH essentials: Working with ssh servers clients and keys&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The Internet Society - 2006 - &lt;a href="https://www.rfc-editor.org/rfc/rfc4250" rel="noopener noreferrer"&gt;RFC 4250&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The Internet Society - 2006 - &lt;a href="https://www.rfc-editor.org/rfc/rfc4251" rel="noopener noreferrer"&gt;RFC 4251&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The Internet Society - 2006 - &lt;a href="https://www.rfc-editor.org/rfc/rfc4252" rel="noopener noreferrer"&gt;RFC 4252&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The Internet Society - 2006 - &lt;a href="https://www.rfc-editor.org/rfc/rfc4253" rel="noopener noreferrer"&gt;RFC 4253&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The Internet Society - 2006 - &lt;a href="https://www.rfc-editor.org/rfc/rfc4254" rel="noopener noreferrer"&gt;RFC 4254&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Understanding ICMP: How to Send and Receive ICMP Messages in Go</title>
      <dc:creator>José David Ureña Torres</dc:creator>
      <pubDate>Mon, 24 Feb 2025 04:28:03 +0000</pubDate>
      <link>https://dev.to/jodaut/understanding-icmp-how-to-send-and-receive-icmp-messages-in-go-3o17</link>
      <guid>https://dev.to/jodaut/understanding-icmp-how-to-send-and-receive-icmp-messages-in-go-3o17</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you like video games you have probably heard the term ping. In gaming, ping measures the round-trip time (RTT) it takes for a packet to travel from your device to the game server and back. This is a key component of network latency. When playing an online game, higher latency means that it takes longer for messages between your computer and and the other players' computers, resulting in bad gameplay performance &lt;a href="https://www.reddit.com/r/explainlikeimfive/comments/zcbs65/comment/iyvntq5/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button" rel="noopener noreferrer"&gt;Schnutzel, 2021&lt;/a&gt;. Additionally, we can use ping to check whether we can reach a machine or if it is accessible from our own computer.&lt;/p&gt;

&lt;p&gt;Have you wondered how it works? Ping relies on ICMP, a protocol used for network diagnostics and error reporting. Actually, you can try it out by opening a terminal and typing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bash-3.2$ ping www.google.com

PING www.google.com (142.250.64.132): 56 data bytes
64 bytes from 142.250.64.132: icmp_seq=0 ttl=114 time=54.802 ms
64 bytes from 142.250.64.132: icmp_seq=1 ttl=114 time=51.040 ms
64 bytes from 142.250.64.132: icmp_seq=2 ttl=114 time=48.910 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the time value in each message, indicating the latency between my computer and the destination machine. The output also includes useful information like the number of bytes sent and how many hops the packet can take before being discarded (TTL).&lt;/p&gt;

&lt;p&gt;However, if we try to reach a host that does not exist or it is not available we get the following response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ping 127.0.0.2                                                                                                        2 х │ 10:01:29 PM
PING 127.0.0.2 (127.0.0.2): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This article demonstrates how to send and receive ICMP messages using Go. For simplicity, I decided to cover only &lt;code&gt;Echo&lt;/code&gt; and &lt;code&gt;Echo Reply&lt;/code&gt;. If you want to learn more about other ICMP types and codes I encourage you to read the &lt;a href="https://datatracker.ietf.org/doc/html/rfc792" rel="noopener noreferrer"&gt;RFC 792 standard&lt;/a&gt;, the official specification for ICMP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Go?
&lt;/h3&gt;

&lt;p&gt;Other languages like C, C++ or even Rust might be preferred under certain circumstances. However, Go is still a solid choice for this type of applications. It offers an easy-to-read syntax, with the advantages of statically typed languages. Moreover, Go is efficient in terms of speed and executable size because it is a compiled language.&lt;/p&gt;

&lt;p&gt;The Go &lt;a href="//golang.org/x/net/icmp"&gt;icmp&lt;/a&gt; package provides structs for ICMP messages, allowing us to avoid crafting the packets manually. We will be using that package through this guide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding ICMP
&lt;/h3&gt;

&lt;p&gt;The Internet Control Message Protocol (ICMP) is a fundamental component of the Internet Protocol Suite, primarily used for diagnostic and error-reporting purposes. Unlike TCP or UDP, ICMP is not used for transmitting application data but rather for sending control messages that help manage network behavior.&lt;/p&gt;

&lt;p&gt;ICMP messages are commonly associated with network utilities like ping and traceroute, which rely on it to test connectivity and trace the route of packets across a network. These messages can indicate unreachable destinations, packet loss, or excessive delays, making ICMP essential for network troubleshooting and performance monitoring.&lt;/p&gt;

&lt;p&gt;Despite its usefulness, ICMP can also be exploited for network attacks, such as ICMP flood (ping flood) or smurf attacks, leading to its restriction or filtering in certain environments. However, when used correctly, ICMP remains a vital tool for understanding and maintaining network health.&lt;/p&gt;

&lt;h3&gt;
  
  
  ICMP packet structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
   0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Type      |     Code      |          Checksum             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Identifier          |        Sequence Number        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Data ...
   +-+-+-+-+-
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the structure of an ICMP Echo packet, commonly used for ping requests and replies. Here's a breakdown of each field:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type (8 bits): Specifies the message type. Echo Request = 8, Echo Reply = 0.&lt;/li&gt;
&lt;li&gt;Code (8 bits): Provides additional information. For Echo messages, this is always 0.&lt;/li&gt;
&lt;li&gt;Checksum (16 bits): Used for error-checking the packet.&lt;/li&gt;
&lt;li&gt;Identifier (16 bits): Helps match requests with replies.&lt;/li&gt;
&lt;li&gt;Sequence Number (16 bits): Tracks the order of packets.&lt;/li&gt;
&lt;li&gt;Data (Variable length): Contains the payload, e.g: timestamps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  List of ICMP Messages
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Message Name&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Code&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Echo Reply&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Response to an ICMP Echo Request (ping response).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Destination Unreachable&lt;/td&gt;
&lt;td&gt;0-15&lt;/td&gt;
&lt;td&gt;Indicates that a packet could not reach its destination. Different codes specify the reason.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Source Quench&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Deprecated. Previously used to indicate network congestion.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Redirect&lt;/td&gt;
&lt;td&gt;0-3&lt;/td&gt;
&lt;td&gt;Suggests a better route for the packet.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Echo Request&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Used for ping tests to check connectivity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Router Advertisement&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Sent by routers to advertise their presence.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Router Solicitation&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Sent by hosts to request router advertisements.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;11&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Time Exceeded&lt;/td&gt;
&lt;td&gt;0-1&lt;/td&gt;
&lt;td&gt;Packet exceeded its lifetime (TTL expired or reassembly timeout).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;12&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Parameter Problem&lt;/td&gt;
&lt;td&gt;0-2&lt;/td&gt;
&lt;td&gt;Packet contains an invalid header field.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;13&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Timestamp Request&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Requests a timestamp from the destination.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;14&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Timestamp Reply&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Response to a Timestamp Request.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Information Request&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Deprecated. Previously used for address assignments.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;16&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Information Reply&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Response to an Information Request.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;17&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Address Mask Request&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Used to request the subnet mask of a network.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;18&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Address Mask Reply&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Response to an Address Mask Request.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For the purpose of this reading pay attention to the &lt;code&gt;Echo&lt;/code&gt; and &lt;code&gt;Echo Reply&lt;/code&gt; messages, which have types 8 and 0 respectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use
&lt;/h2&gt;

&lt;p&gt;First, you must start the docker containers. The repo includes two containers &lt;code&gt;icmp-client&lt;/code&gt; and &lt;code&gt;icmp-server&lt;/code&gt;, with a client and server application respectively. Docker will take care of installing the necessary tools and compiling both applications. See the &lt;a href="https://github.com/JoDaUT/icmp-go/blob/main/docker-compose.yml" rel="noopener noreferrer"&gt;docker-compose.yml&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up --build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can run them separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose run icmp-client
docker compose run icmp-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run client
&lt;/h3&gt;

&lt;p&gt;We need to connect to the client container and start the client application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it icmp-client /bin/sh
bin/client icmp-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program will print a output similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/code # bin/client icmp-server
21 bytes from 172.22.0.3: pid=921, icmp_type=echo reply, icmp_seq=0, data=hello from client, time:590μs
21 bytes from 172.22.0.3: pid=921, icmp_type=echo reply, icmp_seq=1, data=hello from client, time:506μs
21 bytes from 172.22.0.3: pid=921, icmp_type=echo reply, icmp_seq=2, data=hello from client, time:505μs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, who is responding to the message if we have not started the server yet?&lt;/p&gt;

&lt;p&gt;An ICMP request does not require any specialized server software to handle it, because the operating system running on the machine has built-in functionality for handling ICMP messages. Specifically, the OS is set up to recognize and respond to ICMP Echo Requests by automatically sending back an ICMP Echo Reply. This built-in mechanism is part of the network stack in the operating system, which manages network communication. The client determines the latency by calculating the elapsed time between the echo and the echo reply.&lt;/p&gt;

&lt;p&gt;However, it does not mean that we can send ICMP requests to any server. Routers and firewalls could prevent or filter those messages. Others will limit the rate to prevent flooding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I used microseconds instead of milliseconds just for convenience. The elapsed time is very short in this case to use milliseconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run server
&lt;/h3&gt;

&lt;p&gt;We can run our own ICMP handler if we want. Our handler will process the packet and send it back to the sender, but changing the type to &lt;code&gt;echo reply&lt;/code&gt;. We are not covering other special cases in this article.&lt;/p&gt;

&lt;p&gt;Now that the machines are running, connect to the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it icmp-server /bin/sh
bin/server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you start the client you will see a similar output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/code # bin/server
21 bytes from 172.22.0.2: pid=927, icmp_type=echo, icmp_seq=0, data=hello from client
21 bytes from 172.22.0.2: pid=927, icmp_type=echo, icmp_seq=1, data=hello from client
21 bytes from 172.22.0.2: pid=927, icmp_type=echo, icmp_seq=2, data=hello from client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/code # bin/client icmp-server
21 bytes from 172.22.0.3: pid=927, icmp_type=echo reply, icmp_seq=0, data=hello from client, time:1017μs
21 bytes from 172.22.0.3: pid=927, icmp_type=echo reply, icmp_seq=0, data=hello from client, time:660μs
21 bytes from 172.22.0.3: pid=927, icmp_type=echo reply, icmp_seq=1, data=hello from client, time:525μs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the server is receiving the packets and echoing the message back to the sender. The same way as before the client can determine the latency by calculating the elapsed time between the echo and the echo reply. Also note that send request is of type &lt;code&gt;echo&lt;/code&gt; and the answer from the server is of type &lt;code&gt;echo reply&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation details
&lt;/h2&gt;

&lt;p&gt;If you want to see the full code, navigate to the &lt;a href="https://github.com/JoDaUT/icmp-go" rel="noopener noreferrer"&gt;Github repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is the code to send Echo requests to a server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Ping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;raddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResolveIPAddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ip4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to resolve target address: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DialIP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ip4:icmp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raddr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to create ICMP connection: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello from client"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;attempts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;echoReq&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;icmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ipv4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ICMPTypeEcho&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;icmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Echo&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getpid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="m"&gt;0xffff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Seq&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;msgBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echoReq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to marshal ICMP message: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetReadDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set read deadline: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;timeStart&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msgBytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to send ICMP message: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;512&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;peer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;timeEnd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to read ICMP response: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;parsedMsg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;icmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to parse ICMP message: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;echoType&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;parsedMsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;parsedMsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;icmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Echo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;parsedMsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;parsedMsg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;ipv4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ICMPTypeEchoReply&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;timeEnd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeStart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%d bytes from %s: pid=%d, icmp_type=%v, icmp_seq=%d, data=%s, time:%dμs&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proto&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;peer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;echoType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;elapsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Microseconds&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"received unexpected message from %s: pid=%d, icmp_type=%v, icmp_seq=%d, data=%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;peer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;echoType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, this is the code for receiving those ICMP requests and sending them back to the sender:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Pong&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"0.0.0.0"&lt;/span&gt;
    &lt;span class="n"&gt;raddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResolveIPAddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ip4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error resolving ip: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenIP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ip4:icmp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raddr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error listening package: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;512&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;numRead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;echoReq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;icmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;numRead&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error parsing message: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echoReq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;icmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Echo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;echoType&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echoReq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;
        &lt;span class="n"&gt;proto&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echoReq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;echoType&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;ipv4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ICMPTypeEcho&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"received unexpected message from %s: pid=%d, icmp_type=%v, icmp_seq=%d, data=%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;echoType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%d bytes from %s: pid=%d, icmp_type=%v, icmp_seq=%d, data=%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proto&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;echoType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;icmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ipv4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ICMPTypeEchoReply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;icmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Echo&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Seq&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;replyBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error serializing reply: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;replyBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error sending reply: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;The Internet Control Message Protocol (ICMP) is a fundamental part of networking, providing useful information regarding the communication between devices. The concept of "ping," often associated with online gaming and other real-time applications, relies heavily on ICMP Echo requests and replies to determine network latency. Understanding and using ICMP correctly can help diagnose network issues, measure latency, and optimize connectivity in both personal and professional environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliography
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GeeksForGeeks - 2024 - &lt;a href="https://www.geeksforgeeks.org/internet-control-message-protocol-icmp/" rel="noopener noreferrer"&gt;Internet Control Message Protocol (ICMP)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;golang.org - 2024 - &lt;a href="https://pkg.go.dev/golang.org/x/net/icmp#example-PacketConn-NonPrivilegedPing" rel="noopener noreferrer"&gt;icmp-example&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;RFC-792 - 2024 - &lt;a href="https://www.rfc-editor.org/rfc/rfc792.html" rel="noopener noreferrer"&gt;ICMP&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;stackoverflow - 2024 - &lt;a href="https://stackoverflow.com/questions/2937123/implementing-icmp-ping-in-go" rel="noopener noreferrer"&gt;Implementing ICMP ping in Go&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>softwareengineering</category>
      <category>network</category>
    </item>
    <item>
      <title>Messed up a git rebase? Now What?</title>
      <dc:creator>José David Ureña Torres</dc:creator>
      <pubDate>Sun, 08 Sep 2024 15:14:34 +0000</pubDate>
      <link>https://dev.to/jodaut/messed-up-a-git-rebase-now-what-m06</link>
      <guid>https://dev.to/jodaut/messed-up-a-git-rebase-now-what-m06</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Git rebase is a powerful tool that can help you to move or combine one or more commits onto a new base commit, rewriting the project history to make your branch appear as it was created from another commit. This helps maintain a cleaner and more linear history. In this article, we will cover the fundamentals of rebasing branches, explore some common pitfalls, provide real life examples, and suggestions of how to deal with them. &lt;/p&gt;

&lt;p&gt;Keep in mind that this article focuses on Git, not on collaborative tools for Git repositories like Github or Gitlab, except for common concepts such as code approvals, pull requests, remote repository, that we will mention as they come up.&lt;/p&gt;

&lt;p&gt;That said, let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Rebase: The basics
&lt;/h2&gt;

&lt;p&gt;Why would someone do a rebase if there is a &lt;code&gt;git merge&lt;/code&gt; command? There are scenarios when rebasing is more useful than merging. For instance, let's say you have been working on a new feature on a separate branch for some time. During that time, the master branch has progressed with new commits that your working branch does not have, because it was created before those new commits were added. &lt;br&gt;
This situation is very common when you work with other people. Also, rebasing helps to maintain a cleaner history of the project and facilitates troubleshooting when a bug appears in a feature that was previously working fine.&lt;/p&gt;

&lt;p&gt;I personally prefer the interactive tool for doing a rebase. If you are not familiarized with it, you can use it by adding the &lt;code&gt;-i&lt;/code&gt; or &lt;code&gt;--interactive&lt;/code&gt; flag, e.g. &lt;code&gt;git rebase -i master&lt;/code&gt; to rebase your working branch with master. &lt;/p&gt;

&lt;p&gt;With the interactive mode, I take the opportunity to squash my commits into the few as possible. What do I mean by that? If you are working on a small or medium-sized ticket, it is often unnecessary to keep all the commits you made. Instead you can combine them into a single commit and give it a descriptive name. &lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Prefer a single commit on the master branch
e184504 (HEAD -&amp;gt; master) feature A

// instead of separate commits that belong to the same feature
e754500 (HEAD -&amp;gt; master) add Z
714fb43 add Y
8147fb0 add X
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interactive tool allows to perform different operations during the rebase like pick, drop, reword or squash. If you want to learn more about this interactive mode, check this resource: &lt;a href="https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History" rel="noopener noreferrer"&gt;rewriting history&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Imagine that you are working on a project where the master branch has two commits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;e754500 (HEAD -&amp;gt; master) add About page
714fb43 add Login page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you created a &lt;code&gt;feature-1&lt;/code&gt; branch from master branch and worked on it. Here is the history for the new branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3ac2d3d (HEAD -&amp;gt; feature-1) fix bug with contact service
0a298d8 add fix bug in contact form
f91cc77 add Contact page
e754500 add About page
714fb43 add Login page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you got the necessary approvals on Github, the branch is ready to be merged. However, you found that other team members are being merging changes into the master branch while you were working on feature-1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdf9f3f (HEAD -&amp;gt; master) add Home page // feature-1 does not have this commit
902add0 add Blog page // feature-1 does not have this commit
e754500 add About page
714fb43 add Login page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where git rebase comes into play. First you need to pull the latest changes from master, by checking out master and executing &lt;code&gt;git pull origin master&lt;/code&gt;. Then, if you type &lt;code&gt;git rebase master&lt;/code&gt; a normal rebase you can make your working branch to look similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;c1fbb22 (HEAD -&amp;gt; feature-1) fix bug with contact service
85d4677 add fix bug in contact form
701da95 add Contact page
cdf9f3f (master) add Home page
902add0 add Blog page
e754500 add About page
714fb43 add Login page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Github and Gitlab have options for doing this in the same website.&lt;/p&gt;

&lt;p&gt;With the interactive mode you can use the squash option to combine your commits into a single commit. You can achieve it by changing the word pick for squash or the letter &lt;code&gt;s&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;pick c1fbb22 fix bug with contact service
squash 85d4677 add fix bug in contact form
squash 701da95 add Contact page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will combine three commits from your working branch into a single commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fb8036f (HEAD -&amp;gt; feature-1) add Contact page
cdf9f3f (master) add Home page
902add0 add Blog page
e754500 add About page
714fb43 add Login page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can merge your branch without any issues. &lt;/p&gt;

&lt;p&gt;If you want to learn more about rebasing, I wrote other article some time ago: &lt;a href="https://dev.to/jodaut/beyond-the-basics-guide-to-deeply-understand-merge-rebase-squash-and-cherry-pick-when-to-use-them-with-real-world-examples-3f2m"&gt;Guide to deeply understand merge rebase squash and cherry-pick&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Sometimes there will be conflicts during the rebase. When that happens, Git will ask you to resolve them first. If things go wrong during the rebase, you can always execute &lt;code&gt;git rebase --abort&lt;/code&gt; to cancel the operation and start over. After you resolved all the conflicts, you can continue the process by typing &lt;code&gt;git rebase --continue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let's dive into a more complex situation when things have gone really wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Undoing a Committed Rebase
&lt;/h3&gt;

&lt;p&gt;What happens if, for some reason, you dropped a commit that should have not been deleted, or squashed a commit that you did not wanted to squash. One situation where this might happen is when you need to refactor a service or a class to prepare it for your new feature, and you were not expecting it. &lt;/p&gt;

&lt;p&gt;Ideally, you should create a separate branch for this refactor and open a Pull Request, so that your co-workers or team lead can review the refactor first, avoiding unnecessary noise to the feature. I encourage you to do that whenever possible.&lt;/p&gt;

&lt;p&gt;However, let's say that you decided to keep the refactor in the same branch. If you make a mistake like dropping or squashing the wrong commits, a git revert will not help you, because they will not appear in the history anymore.&lt;/p&gt;

&lt;p&gt;Let's break this down with an example:&lt;/p&gt;

&lt;p&gt;You have been working on a new feature for a project. During the development, you encountered a blocker, some legacy code that needs to be refactored to support your feature. Let's say that you kept it in the same branch, with the plan to create a separate branch for it later, once your feature is finished. &lt;/p&gt;

&lt;p&gt;Your history looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;d600d8a (HEAD -&amp;gt; feature-1) fix bugs related to feature 1
37356d2 initial implementation of feature 1
92829c9 (refactor) prepare codebase for feature 1
fb8036f other commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are ready to push your changes to the remote repository. But first, you need to squash your commits, to maintain your history clean. I know that it does not make much sense if the branch has just two commits. But in a real scenario there could be a lot of commits in your working branch.&lt;/p&gt;

&lt;p&gt;Thus, you decided to rebase your branch to fetch the latest changes from master and take the opportunity to squash your commits during the process, giving them a descriptive name. You did this by typing &lt;code&gt;git rebase -i master&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is the output of that command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick 92829c9 (refactor) prepare codebase for feature 1
pick 37356d2 initial implementation for feature 1
pick d600d8a fix bugs related to feature 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, by accident you told Git to combine your feature with the refactor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick 92829c9 (refactor) prepare codebase for feature 1
squash 37356d2 initial implementation for feature 1 # this one should have remained as "pick"
squash d600d8a fix bugs related to feature 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After saving your changes with &lt;code&gt;:wq&lt;/code&gt;, git allows you to change the commit name if you want. Now the history looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;404824f (HEAD -&amp;gt; feature-1) add feature 1
fb8036f other commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, you noticed your mistake. The refactor commit is gone. The three commits were combined, and you only intended to combine the last two. You can always pull your changes from the remote repository and restore your branch, &lt;strong&gt;if and only if&lt;/strong&gt; you pushed your changes previous to rebase your branch. To make it worse, let's say you pushed your changes with &lt;code&gt;git push -f&lt;/code&gt;. Now we are in trouble. &lt;/p&gt;

&lt;p&gt;However, we can still try one more thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Be careful. If you pull the remote branch after a rebase you can loose your progress on the local branch, specially if you did not pushed your changes previous to the rebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Reflog
&lt;/h2&gt;

&lt;p&gt;Something interesting about Git is that it is difficult to really delete things. Even if the deleted commits are no longer visible in the history, there is a change that we can still access them by checking the reference logs, also known as reflog. &lt;/p&gt;

&lt;p&gt;The reflog records almost everything that you do in the local repository, and provides more information than commands like &lt;code&gt;git log&lt;/code&gt;. We can access the reflog by typing &lt;code&gt;git reflog show&lt;/code&gt;. Here are part of my reflogs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;404824f (HEAD -&amp;gt; feature-1) HEAD@{0}: rebase (finish): returning to refs/heads/feature-1
404824f (HEAD -&amp;gt; feature-1) HEAD@{1}: rebase (squash): add feature 1
df8d688 HEAD@{2}: rebase (squash): # This is a combination of 2 commits
92829c9 HEAD@{3}: rebase (start): checkout master
d600d8a HEAD@{4}: commit: fix bugs related to feature 1
37356d2 HEAD@{5}: commit: initial implementation for feature 1
92829c9 HEAD@{6}: commit: (refactor) prepare codebase for feature 1
fb8036f HEAD@{7}: checkout: moving from master to feature-1
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Based on that, we can infer that the rebase occurred between &lt;code&gt;HEAD&lt;/code&gt; and &lt;code&gt;HEAD@{2}&lt;/code&gt;. Additionally, &lt;code&gt;HEAD@{3}&lt;/code&gt;, &lt;code&gt;HEAD@{4}&lt;/code&gt;, &lt;code&gt;HEAD@{5}&lt;/code&gt; and &lt;code&gt;HEAD@{6}&lt;/code&gt; points to the changes before the rebase. You can safely check out any of those commits. Just keep in mind that any checkout operation also generates entries in the reflog, which means the &lt;code&gt;HEAD@{n}&lt;/code&gt; reference will change for a particular commit. You can checkout the commit by its hash as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; According to the official documentation, the reflog has a default expiration of 90 days.&lt;/p&gt;

&lt;p&gt;After inspected those commits with &lt;code&gt;git checkout&lt;/code&gt;, it seems that the best candidate is &lt;code&gt;HEAD@{4} (d600d8a)&lt;/code&gt;. Let's restore our branch.&lt;/p&gt;

&lt;p&gt;There are multiple ways to do it. One approach would be to delete the  working branch and recreate it from &lt;code&gt;d600d8a&lt;/code&gt; by typing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout d600d8a
git branch -D feature-1
git checkout -b feature-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can reset your working branch with &lt;code&gt;git reset --soft d600d8a&lt;/code&gt;. I personally prefer this approach, but use whatever works better for your specific case. &lt;/p&gt;

&lt;p&gt;After the git reset, here are the history logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;d600d8a (HEAD -&amp;gt; feature-1) fix bugs related to feature 1
37356d2 initial implementation for feature 1
92829c9 (refactor) prepare codebase for feature 1
fb8036f other commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. Now we have the commits previous to the rebase, and since we learned from our mistakes, we proceed to push our changes to the remote repository before even start the rebase. After that, we can safely rebase the working branch and do what we need to do. In this case, we wanted to squash the last two commits and keep the refactor as a separate commit. Now the history looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;d600d8a (HEAD -&amp;gt; feature-1) add feature 1
92829c9 (refactor) prepare codebase for feature 1
fb8036f other commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, once we are 100% sure that the rebase was successful we can push the changes to the remote repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Git is a powerful and versatile tool, but its flexibility can lead to human errors. It is important to know those common errors, how to prevent them and deal with them if necessary. &lt;/p&gt;

&lt;p&gt;In this article we learned how to combine commits and rewrite the log history using git rebase. We also explored some examples where things can go wrong and introduced git reflog as an method to restore deleted commits in our working branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliography
&lt;/h2&gt;

&lt;p&gt;Atlassian | 2024 | &lt;a href="https://www.atlassian.com/git/tutorials/refs-and-the-reflog" rel="noopener noreferrer"&gt;Ref And The Reflog&lt;/a&gt;&lt;br&gt;
Atlassian | 2024 | &lt;a href="https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase" rel="noopener noreferrer"&gt;Rewriting History&lt;/a&gt;&lt;br&gt;
Git Reference | 2024 | &lt;a href="https://git-scm.com/docs/git-reflog" rel="noopener noreferrer"&gt;Git Reflog&lt;/a&gt;&lt;br&gt;
Git Reference | 2024 | &lt;a href="https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History" rel="noopener noreferrer"&gt;Git Tools Rewriting History&lt;/a&gt;&lt;br&gt;
Jodaut | 2023 | &lt;a href="https://dev.to/jodaut/beyond-the-basics-guide-to-deeply-understand-merge-rebase-squash-and-cherry-pick-when-to-use-them-with-real-world-examples-3f2m"&gt;Beyong-the-basics-guide-to-deeply-understand-merge-rebase-squash-and-cherry-pick&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>softwareengineering</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Beyond the Basics. Guide to Deeply Understand Merge, Rebase, Squash, and Cherry Pick - When to Use Them With Real-World Examples</title>
      <dc:creator>José David Ureña Torres</dc:creator>
      <pubDate>Fri, 28 Jul 2023 15:00:04 +0000</pubDate>
      <link>https://dev.to/jodaut/beyond-the-basics-guide-to-deeply-understand-merge-rebase-squash-and-cherry-pick-when-to-use-them-with-real-world-examples-3f2m</link>
      <guid>https://dev.to/jodaut/beyond-the-basics-guide-to-deeply-understand-merge-rebase-squash-and-cherry-pick-when-to-use-them-with-real-world-examples-3f2m</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;
Merge or rebase, which should you use?

&lt;ul&gt;
&lt;li&gt;Merge approach&lt;/li&gt;
&lt;li&gt;
Rebase approach

&lt;ul&gt;
&lt;li&gt;Cannot push my changes after a rebase&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

Cherry pick

&lt;ul&gt;
&lt;li&gt;Is Cherry Pick a bad practice?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Git squash

&lt;ul&gt;
&lt;li&gt;Squash with merge&lt;/li&gt;
&lt;li&gt;Squash with rebase&lt;/li&gt;
&lt;li&gt;What happens if I messed up a branch when rebasing or merging?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Conclusions&lt;/li&gt;

&lt;li&gt;Bibliography&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Git is a powerful tool that helps developers work together on software projects. Created by Linus Torvalds in 2005, it has become one of the most widely used version control systems in the software development industry. &lt;/p&gt;

&lt;p&gt;If you're new to Git, you might find it challenging to find information about when and how to use certain commands with real-world examples. Many tutorials only give you the commands, which might be enough for experienced developers but not for beginners.&lt;/p&gt;

&lt;p&gt;Imagine you work in a small company with a few developers and no established version control practices. It's up to you to improve the development process, but there are no senior developers to guide you. Knowing Git deeply can make a big difference for you and your colleagues.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore fundamental Git commands to combine branches effectively and how to respond to different situations. We will cover the main differences between merging and rebasing, and when should you use each of them. Also, how to use cherry pick to add specific commits into one or more branches, and why you should combine related commits into a single one to keep your branch clean. Finally, we'll discuss how to prevent some common issues when working with branches.&lt;/p&gt;

&lt;p&gt;If you're completely new to Git, you can still read this article, but some concepts might be unclear. Feel free to come back later once you have the basics down. That being said, let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Merge or rebase, which should you use?
&lt;/h2&gt;

&lt;p&gt;Choosing between merge and rebase can be tough and usually depends on your company's practices. If you have the choice, knowing the pros and cons of each method is vital for making the right decision based on your company's needs.&lt;/p&gt;

&lt;p&gt;Git merge combines changes from one branch into another, creating a new commit with the merged changes. On the other hand, Git rebase rewrites the history of one branch onto another, adding your commits on top of the updated branch. To put it simply, it temporarily removes your commits, updates the branch from the specified one, and then adds your commits at the top of the history.&lt;/p&gt;

&lt;p&gt;Now, let's explore each method in more detail.&lt;/p&gt;

&lt;p&gt;Consider a &lt;code&gt;main&lt;/code&gt; branch with the commit history below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
0a9c4e8 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class="o"&gt;)&lt;/span&gt; feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These codes at the beginning of every line are called commit hashes or commit IDs, and they serve as unique identifiers associated to every commit created. A commit ID consists of a 40-digit long SHA-hash (a hash algorithm), which can be abbreviated to a shorter 7-digit version.&lt;/p&gt;

&lt;p&gt;Continuing with the example, you have a ticket assigned and need to create a &lt;code&gt;feature4&lt;/code&gt; branch with &lt;code&gt;git branch feature4&lt;/code&gt; and &lt;code&gt;git checkout feature4&lt;/code&gt;. You develop your feature, add tests, and now it’s ready to be merged to &lt;code&gt;main&lt;/code&gt;. It has the following commit history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout feature4
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
dd01e58 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; feature4&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature4
55b4a8b feature4
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, you go to Github and create a new Pull Request, but you find that &lt;code&gt;main&lt;/code&gt; was updated while you where working on your branch. In other words, the &lt;code&gt;main&lt;/code&gt; branch now is different from the one you created your branch. It has a new commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git pull origin main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
cf0e10a &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class="o"&gt;)&lt;/span&gt; feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, conflicts can arise when the destination branch has new commits that modify the same sections you were working on your branch. In such cases, you have an alternative: instead of merging &lt;code&gt;feature4&lt;/code&gt; into &lt;code&gt;main&lt;/code&gt; (&lt;code&gt;main&lt;/code&gt; ← &lt;code&gt;feature4&lt;/code&gt;), you can update feature4 with the changes from main (&lt;code&gt;main&lt;/code&gt; → &lt;code&gt;feature4&lt;/code&gt;). To achieve this, you have two options: merge or rebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Merge approach
&lt;/h3&gt;

&lt;p&gt;If you merge &lt;code&gt;main&lt;/code&gt; into &lt;code&gt;feature4&lt;/code&gt;, then Git will create a new commit containing the changes from &lt;code&gt;main&lt;/code&gt; and will add them at the top of the working tree. Let’s see it in action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout feature4
git merge main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git will open the editor you set up, which is typically Vim by default. You will see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Merge branch &lt;span class="s1"&gt;'main'&lt;/span&gt; into feature4
&lt;span class="c"&gt;# Please enter a commit message to explain why this merge is necessary,&lt;/span&gt;
&lt;span class="c"&gt;# especially if it merges an updated upstream into a topic branch.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Lines starting with '#' will be ignored, and an empty message aborts&lt;/span&gt;
&lt;span class="c"&gt;# the commit.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For simplicity, I'll keep this default commit message. To save it, press &lt;code&gt;ESC+:wq&lt;/code&gt;. If you're unfamiliar with Vim commands, consider taking a brief tutorial on YouTube or your preferred platform.&lt;/p&gt;

&lt;p&gt;Now check the commit history again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
96f49c0 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; feature4&lt;span class="o"&gt;)&lt;/span&gt; Merge branch &lt;span class="s1"&gt;'main'&lt;/span&gt; into feature4
cf0e10a &lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; feature5
dd01e58 &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature4
55b4a8b feature4
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that there are two new commits, but &lt;code&gt;cf0e10a&lt;/code&gt; is the only one that was on &lt;code&gt;main&lt;/code&gt; . Where did this other commit come from? &lt;/p&gt;

&lt;p&gt;When you merge a branch, Git adds the commits from the source branch and creates a new commit that combines the changes from both branches. If there are no conflicts, this commit will be automatically created. However, if conflicts occur, you must resolve them and then create the commit manually.&lt;/p&gt;

&lt;p&gt;Remember to update your local &lt;code&gt;main&lt;/code&gt; branch before the merge. If you don’t do it, there will be nothing to merge into &lt;code&gt;feature4&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;Now you can push your changes with &lt;code&gt;git push origin feature4&lt;/code&gt; and then merge it into &lt;code&gt;main&lt;/code&gt;. For simplicity let’s do a local git merge to &lt;code&gt;main&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git merge feature4
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
96f49c0 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main, feature4&lt;span class="o"&gt;)&lt;/span&gt; Merge branch &lt;span class="s1"&gt;'main'&lt;/span&gt; into feature4
cf0e10a feature5
dd01e58 &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature4
55b4a8b feature4
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice this (&lt;code&gt;HEAD&lt;/code&gt; -&amp;gt; &lt;code&gt;main&lt;/code&gt;, &lt;code&gt;feature4&lt;/code&gt;). It means that &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;feature4&lt;/code&gt; now have the same commit at the HEAD. In other words, both branches point to the same commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rebase approach
&lt;/h3&gt;

&lt;p&gt;As mentioned before, a rebase is slightly different. It basically rewrites the history of a branch, adding your commits on top of the updated branch. But, what does “rewrite” mean in this context? It means to modify the original commit history by creating new commits with different hashes and add them to the commit history, but not necessarily at the top. After that, the old commit history is replaced by the new one. Let’s see an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git pull origin main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout feature4
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git rebase main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
0c847bd &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; feature4&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature4
b86b56d feature4
cf0e10a &lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see &lt;code&gt;cf0e10a&lt;/code&gt; was added before you commits, and that commit was created after the ones from &lt;code&gt;feature4&lt;/code&gt;. With Git rebase, your changes are added to the top of the history without extra commits like a merge. However, you may notice that the hashes of your two commits from &lt;code&gt;feature4&lt;/code&gt; are not the same as before, while the commits from &lt;code&gt;main&lt;/code&gt; remain unchanged. Weird, right?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dd01e58&lt;/code&gt; changed to &lt;code&gt;0c847bd&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;55b4a8b&lt;/code&gt; changed to &lt;code&gt;b86b56d&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is a particularity of git rebase, as it rewrites the git history, creating new commits with your changes and discarding the originals. As a result, the new commits are not the same as the original ones. The good news is that the original dates and author information remain unchanged. This is the reason why some companies prefer not to rebase branches and instead opt for using merge, as rebasing alters the past commits.&lt;/p&gt;

&lt;p&gt;Now that &lt;code&gt;feature4&lt;/code&gt; is updated, you can perform a normal merge into &lt;code&gt;main&lt;/code&gt;. Remember, that in the real life, you would need to push your changes and create a Pull Request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git merge feature4
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
0c847bd &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main, feature4&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature4
b86b56d feature4
cf0e10a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time, the commit hashes between both branches are identical, and there is no extra commit. However, it's worth noting that Git may behave differently on platforms like GitLab and GitHub, where additional commits might be added.&lt;/p&gt;

&lt;p&gt;My personal recommendation is to avoid using rebase on &lt;code&gt;main&lt;/code&gt; or other critical branches to preserve the original hashes for better traceability. Instead, use it for temporary branches derived from another branch, like feature branches. If your branch is going to be deleted after a merge, then you can rebase it. For &lt;code&gt;main&lt;/code&gt; is not the case. Once your commits were added to &lt;code&gt;main&lt;/code&gt; you should not override them. &lt;/p&gt;

&lt;p&gt;Also, rebase will prevent a long series of commits from being scattered in the commit history and cause a lot of noise in your branch.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cannot push my changes after a rebase
&lt;/h4&gt;

&lt;p&gt;In real environments, you don't merge into main directly. In fact, you probably won't be able to merge to the &lt;code&gt;main&lt;/code&gt; branch on GitHub either. Instead, you'll need to create a Pull Request (or Merge Request if you are using GitLab) to be able to merge your changes. Assuming you've already created your branch and pushed it to the remote repository, when you proceed to push your changes with &lt;code&gt;git push origin &amp;lt;branch&amp;gt;&lt;/code&gt; you could get an error similar to this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Your branch and &lt;span class="s1"&gt;'origin/&amp;lt;branch&amp;gt;'&lt;/span&gt; have diverged,
    ...
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git pull"&lt;/span&gt; to merge the remote branch into yours&lt;span class="o"&gt;)&lt;/span&gt;
nothing to commit, working tree clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you force a git pull, you could lose your changes. You can solve it by executing this command: &lt;code&gt;git push -f origin &amp;lt;branch&amp;gt;&lt;/code&gt;. Keep in mind that &lt;code&gt;git push -f&lt;/code&gt; will override the upstream branch, so be careful with this. Later in this reading, we will explore ways to prevent lost of information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cherry pick
&lt;/h2&gt;

&lt;p&gt;Imagine that you work for a company with three different branches under development: main, legacy-v1, and legacy-v2. The naming convention for branches is just for educational purposes.&lt;/p&gt;

&lt;p&gt;The QA team has discovered an issue with an old feature present in all three branches under development. After fixing the issue, you need to bring the changes into all three branches. But how should you do it? Copy the code to all the other branches? That's probably not a good idea.&lt;/p&gt;

&lt;p&gt;The next logical solution that comes to mind is to create a new Pull Request to merge these changes into the other branches. However, there is a problem: the other two branches might differ significantly from the main branch, resulting in numerous conflicts. In such cases, it could be impossible to merge them cleanly. This is where cherry-pick comes in.&lt;/p&gt;

&lt;p&gt;This command allows you to append arbitrary commits from a branch to the HEAD of another branch, without the need for a full merge.&lt;/p&gt;

&lt;p&gt;The syntax is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cherry-pick &amp;lt;commit-sha&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, you need to find the commit that you want to backport to the other branches. You can use &lt;code&gt;git log&lt;/code&gt; for that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;                 
8d84e7b &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature 1
222159b feature 4
32d540d feature 3
718f740 feature 2
78662d0 feature 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ℹ️ The &lt;code&gt;--oneline&lt;/code&gt; flag is just minimal information. I usually recommend to use &lt;code&gt;git log --stat&lt;/code&gt; to get full information of your commits.&lt;/p&gt;

&lt;p&gt;Suppose that &lt;code&gt;8d84e7b&lt;/code&gt; (short version) or &lt;code&gt;8d84e7b6bf5ed8a4fee96dfa820e544567542785&lt;/code&gt;  is the commit hash that you want to backport to the other two branches.&lt;/p&gt;

&lt;p&gt;You only have to switch to the other branch an execute the command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout legacy-v1
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git cherry-pick 8d84e7b6bf5ed8a4fee96dfa820e544567542785
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the commit has been appended successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
0c41007 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; legacy-v1&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature 1
9689a1c feature 5
222159b feature 4
32d540d feature 3
718f740 feature 2
78662d0 feature 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repeat the process for &lt;code&gt;legacy-v2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout legacy-v2
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git cherry-pick 8d84e7b6bf5ed8a4fee96dfa820e544567542785
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
73deb0b &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; legacy-v2&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature 1
0b67041 feature 6
222159b feature 4
32d540d feature 3
718f740 feature 2
78662d0 feature 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the commit hashes of &lt;code&gt;legacy-v1&lt;/code&gt; and &lt;code&gt;legacy-v2&lt;/code&gt; are different from main. This is because during the cherry-pick, Git created a new commit from &lt;code&gt;8d84e7b&lt;/code&gt; and appended it to the destination branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Cherry Pick a bad practice?
&lt;/h3&gt;

&lt;p&gt;Some developers, especially the most purist Git users, will not recommend using this command. They will prefer a merge over a cherry-pick. But probably, they do not believe the cherry-pick command to be bad per se, but how you use it can be bad for your repository.&lt;/p&gt;

&lt;p&gt;I like this comment that was posted on a StackOverflow question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The SHA1 identifier of a commit identifies it not just in and of itself but also &lt;em&gt;in relation to&lt;/em&gt; all other commits that precede it. This offers you a guarantee that the state of the repository at a given SHA1 is identical across all clones. There is (in theory) no chance that someone has done what looks like the same change but is actually corrupting or hijacking your repository. You can cherry-pick in individual changes and they are likely the same, but you have no guarantee. (As a minor secondary issue the new cherry-picked commits will take up extra space if someone else cherry-picks in the same commit again, as they will both be present in the history even if your working copies end up being identical.) &lt;a href="https://stackoverflow.com/questions/1241720/git-cherry-pick-vs-merge-workflow/47786628#47786628" rel="noopener noreferrer"&gt;(Git Cherry-pick vs Merge Workflow, 2017)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my opinion, this command is very useful when you have to maintain different branches under development that differ a lot between them, and merging is not an option anymore. If you can merge without problems, then do it, but if not, don't worry and just use cherry pick.&lt;/p&gt;

&lt;p&gt;However, you have to be very careful if your commit is complex, modifies different files, and causes merge conflicts. It's recommended to have good testing coverage that helps you detect quickly if something breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git squash
&lt;/h2&gt;

&lt;p&gt;The last command that we are going to cover in this article is git squash. This command can help you maintain your &lt;code&gt;main&lt;/code&gt; branch clean if you created a lot of small commits. &lt;/p&gt;

&lt;p&gt;Imagine that your just finished to work in a feature in notice that your branch has a lot of commits with smalls changes made during the days you worked on that feature.  For you they make sense, but for your colleagues, they are just random commits. Let’s see and example of a group of commits created during the development of payment feature.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;b86b56d Add initial HTML structure &lt;span class="k"&gt;for &lt;/span&gt;payment checkout page.
a5e392f Implement basic CSS styles &lt;span class="k"&gt;for &lt;/span&gt;payment form.
cf872e2 Fix alignment issues &lt;span class="k"&gt;in &lt;/span&gt;the payment summary section.
0c31e2d Add credit card input validation &lt;span class="k"&gt;for &lt;/span&gt;card number and expiration date.
d6c59a7 Implement UI &lt;span class="k"&gt;for &lt;/span&gt;selecting payment method &lt;span class="o"&gt;(&lt;/span&gt;credit card, PayPal, etc.&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
e8af221 Add CSS transitions &lt;span class="k"&gt;for &lt;/span&gt;a smoother payment form experience.
3e987b8 Fix bug with PayPal payment option not showing up &lt;span class="k"&gt;in &lt;/span&gt;the UI.
95c67f2 Update button styles &lt;span class="k"&gt;for &lt;/span&gt;the payment confirmation step.
713bd64 Integrate backend API &lt;span class="k"&gt;for &lt;/span&gt;processing payment requests.
2d344ef Update success message &lt;span class="k"&gt;for &lt;/span&gt;completed payments.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You probably will be agree with me that, in the long run, those small related commits are not important seen them individually. In this case you should use a git squash. This command allows to combine a group of commits in a single commit with a more meaningful name your your team. Those commits can be summarize into a single descriptive commit as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;b86b56d Implement new payment checkout UI with improved user experience, payment method selection, validation, and backend integration.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It sounds better, right? It’s very common that companies try to have a single commit per feature in their main branch, because it’s easier to rollback if something goes wrong, or add tags to their new releases.&lt;/p&gt;

&lt;p&gt;Let’s see another example.&lt;/p&gt;

&lt;p&gt;You have two branches: &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;feature4&lt;/code&gt;. The following is the log history of both branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
d303a7a &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class="o"&gt;)&lt;/span&gt; feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout feature4
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
0c847bd &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; feature4&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature4
b86b56d feature4
d303a7a &lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example the &lt;code&gt;feature4&lt;/code&gt; branch only have two commits, but they could be a lot. Also, note that the last commit seems to refer to some kind of fix or improvement made to the code or suggestion you received from another coworker. &lt;/p&gt;

&lt;p&gt;Maybe these commits messages may not be relevant in the big picture of the product. The only thing that matters is that the &lt;code&gt;feature4&lt;/code&gt; is ready to be merged into &lt;code&gt;main&lt;/code&gt;.  To squash these commits you can use rebase or merge.&lt;/p&gt;

&lt;p&gt;The two branches have the following commit history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
159678e &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class="o"&gt;)&lt;/span&gt; feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout feature4
0c847bd &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; feature4&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature4
b86b56d feature4
d303a7a &lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Squash with merge
&lt;/h3&gt;

&lt;p&gt;This command is quite similar to the traditional merge process. The only difference is that you may add the &lt;code&gt;—squash&lt;/code&gt; flag. This will add the changes from &lt;code&gt;feature4&lt;/code&gt; to the index (equivalent to if you just have written all the changes and executed &lt;code&gt;git add&lt;/code&gt; ). Then, you have to commit the changes with a meaningful name to finalize the merge process.  See the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git merge &lt;span class="nt"&gt;--squash&lt;/span&gt; feature4
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feature4"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have merge conflicts you have to solve them before committing.&lt;/p&gt;

&lt;p&gt;After the merge, a new commit containing the other two commits will have been created as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
cda90a7 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class="o"&gt;)&lt;/span&gt; feature4
159678e feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that the commit was added after &lt;code&gt;feature6&lt;/code&gt; , although it was added after the &lt;code&gt;feature4&lt;/code&gt; last commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Squash with rebase
&lt;/h3&gt;

&lt;p&gt;To do this you need to add a &lt;code&gt;-i&lt;/code&gt; flag in your rebase as follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout feature4
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git will open Vim. You should see something similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pick b86b56d feature4
pick 0c847bd &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature4

&lt;span class="c"&gt;# Rebase 159678e..0c847bd onto 159678e (2 commands)&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Commands:&lt;/span&gt;
&lt;span class="c"&gt;# p, pick &amp;lt;commit&amp;gt; = use commit&lt;/span&gt;
&lt;span class="c"&gt;# r, reword &amp;lt;commit&amp;gt; = use commit, but edit the commit message&lt;/span&gt;
&lt;span class="c"&gt;# e, edit &amp;lt;commit&amp;gt; = use commit, but stop for amending&lt;/span&gt;
&lt;span class="c"&gt;# s, squash &amp;lt;commit&amp;gt; = use commit, but meld into previous commit&lt;/span&gt;
&lt;span class="c"&gt;# f, fixup [-C | -c] &amp;lt;commit&amp;gt; = like "squash" but keep only the previous&lt;/span&gt;
&lt;span class="c"&gt;#                    commit's log message, unless -C is used, in which case&lt;/span&gt;
&lt;span class="c"&gt;#                    keep only this commit's message; -c is same as -C but&lt;/span&gt;
&lt;span class="c"&gt;#                    opens the editor&lt;/span&gt;
&lt;span class="c"&gt;# x, exec &amp;lt;command&amp;gt; = run command (the rest of the line) using shell&lt;/span&gt;
&lt;span class="c"&gt;# b, break = stop here (continue rebase later with 'git rebase --continue')&lt;/span&gt;
&lt;span class="c"&gt;# d, drop &amp;lt;commit&amp;gt; = remove commit&lt;/span&gt;
&lt;span class="c"&gt;# l, label &amp;lt;label&amp;gt; = label current HEAD with a name&lt;/span&gt;
&lt;span class="c"&gt;# t, reset &amp;lt;label&amp;gt; = reset HEAD to a label&lt;/span&gt;
&lt;span class="c"&gt;# m, merge [-C &amp;lt;commit&amp;gt; | -c &amp;lt;commit&amp;gt;] &amp;lt;label&amp;gt; [# &amp;lt;oneline&amp;gt;]&lt;/span&gt;
&lt;span class="c"&gt;#         create a merge commit using the original merge commit's&lt;/span&gt;
&lt;span class="c"&gt;#         message (or the oneline, if no original merge commit was&lt;/span&gt;
&lt;span class="c"&gt;#         specified); use -c &amp;lt;commit&amp;gt; to reword the commit message&lt;/span&gt;
&lt;span class="c"&gt;# u, update-ref &amp;lt;ref&amp;gt; = track a placeholder for the &amp;lt;ref&amp;gt; to be updated&lt;/span&gt;
&lt;span class="c"&gt;#                       to this position in the new commits. The &amp;lt;ref&amp;gt; is&lt;/span&gt;
&lt;span class="c"&gt;#                       updated at the end of the rebase&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# These lines can be re-ordered; they are executed from top to bottom.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# If you remove a line here THAT COMMIT WILL BE LOST.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# However, if you remove everything, the rebase will be aborted.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don’t panic. All these lines starting with # are just instructions of what can you do with this utility. The only one that matter for us right now  is the &lt;code&gt;squash&lt;/code&gt; option, or its abbreviation &lt;code&gt;s&lt;/code&gt;. You have to replace the word “pick” starting with the second one from the top as follows::&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pick b86b56d feature4
squash 0c847bd &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the lines with &lt;code&gt;squash&lt;/code&gt; will be combine into the previous one that has the &lt;code&gt;pick&lt;/code&gt; word. &lt;/p&gt;

&lt;p&gt;To save this changes press &lt;code&gt;ESC + :wq&lt;/code&gt; .  Git will open Vim again, but this name asking you for a commit message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# This is a combination of 2 commits.&lt;/span&gt;
&lt;span class="c"&gt;# This is the 1st commit message:&lt;/span&gt;

feature4

&lt;span class="c"&gt;# This is the commit message #2:&lt;/span&gt;

&lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature4

&lt;span class="c"&gt;# Please enter the commit message for your changes. Lines starting&lt;/span&gt;
&lt;span class="c"&gt;# with '#' will be ignored, and an empty message aborts the commit.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Date:      Sat Jul 15 09:11:55 2023 -0600&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# interactive rebase in progress; onto 159678e&lt;/span&gt;
&lt;span class="c"&gt;# Last commands done (2 commands done):&lt;/span&gt;
&lt;span class="c"&gt;#    pick b86b56d feature4&lt;/span&gt;
&lt;span class="c"&gt;#    squash 0c847bd (fix) feature4&lt;/span&gt;
&lt;span class="c"&gt;# No commands remaining.&lt;/span&gt;
&lt;span class="c"&gt;# You are currently rebasing branch 'feature4' on '159678e'.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Changes to be committed:&lt;/span&gt;
&lt;span class="c"&gt;#       new file:   file2.txt&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a meaningful name. In this case, for the purpose of this tutorial, &lt;code&gt;feature4&lt;/code&gt; is enough.  You can delete all the lines by pressing &lt;code&gt;DD&lt;/code&gt; or &lt;code&gt;D&amp;lt;number-of-lines-to-delete&amp;gt;D&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;After that, press &lt;code&gt;ESC+:wq&lt;/code&gt; again to save the changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
62b8724 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; feature4&lt;span class="o"&gt;)&lt;/span&gt; feature4
159678e &lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, Git created a new commit and added it at the top of the log history. Notice that the commit hash is not the same as the one with you specified the &lt;code&gt;pick&lt;/code&gt; option that would contain all the commits with the &lt;code&gt;squash&lt;/code&gt; option:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b86b56d&lt;/code&gt; (before the rebase)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;62b8724&lt;/code&gt; (after the rebase)&lt;/p&gt;

&lt;p&gt;That is because Git cannot reuse a hash code containing different changes. In this case, Git is forced to use a different hash and save all the changes as a new commit. By requiring an initial "pick" commit, Git establishes a clear reference point for the rebase operation. This ensures that the rebase proceeds in an organized and predictable manner, without any ambiguity about the order of commits.&lt;/p&gt;

&lt;p&gt;Now you can switch to &lt;code&gt;main&lt;/code&gt; and perform a regular merge as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git merge feature4
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
62b8724 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main, feature4&lt;span class="o"&gt;)&lt;/span&gt; feature4
159678e feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As it is a regular merge, the &lt;code&gt;62b8724&lt;/code&gt; commit was kept. This also means that &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;feature4&lt;/code&gt; now point to the same commit.&lt;/p&gt;

&lt;h1&gt;
  
  
  What happens if I messed up a branch when rebasing or merging?
&lt;/h1&gt;

&lt;p&gt;The best way handle these situations is with prevention. If you are going to make important changes in your code base, it is recommended to do it in your local computer if possible. In that case, if you damage your branch, you can always download it again from the remote repository as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout main
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git branch &lt;span class="nt"&gt;-D&lt;/span&gt; feature4 &lt;span class="c"&gt;# delete the feature4 branch&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout origin feature4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another alternative that you have is to backup the branches that will be affected before executing risky commands. Continuing with the previous example, you can backup your &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;feature4&lt;/code&gt; branches before any operation that can affect them irreversibly. &lt;/p&gt;

&lt;p&gt;This option is preferred if you are planning to push your changes to your remote repository, because if you execute a &lt;code&gt;git push -f origin &amp;lt;branch&amp;gt;&lt;/code&gt; you will override the remote branches and could lose information if you don’t know what you are doing. Backup your branches is as simple as follows and can save you a lot of headaches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git branch feature4-backup feature4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By doing that, if you delete or damage accidentally your local and remote branches, you can execute this commands to restore the branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git branch feature4 feature4-backup
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git push &lt;span class="nt"&gt;--set-upstream&lt;/span&gt; origin feature4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A third alternative is to save the commit hash instead of backup the entire branch. Since the nature of Git, you can still access commits by hash even if you deleted the branch which they belonged. Consider a branch called &lt;code&gt;feature8&lt;/code&gt; with the following commits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git checkout feature8
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
407f3e2 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; feature8&lt;span class="o"&gt;)&lt;/span&gt; feature8
309129e &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature7
9ec402e feature7
62b8724 feature4
159678e feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can save these commits in a file you can access later. In this way, if you delete your branch you can restore from the commit. Imagine that you delete some commits by accident using this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; HEAD~3
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git push &lt;span class="nt"&gt;-f&lt;/span&gt; origin feature8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the log history looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;62b8724 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; feature8&lt;span class="o"&gt;)&lt;/span&gt; feature4
159678e feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although, it seems that you lost all your work you still have a chance to restore it with the commit hash that you previously saved. Try with these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout feature8
git merge 407f3e2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you commit history is restored.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
407f3e2 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class="o"&gt;)&lt;/span&gt; feature8
309129e &lt;span class="o"&gt;(&lt;/span&gt;fix&lt;span class="o"&gt;)&lt;/span&gt; feature7
9ec402e feature7
62b8724 feature4
159678e feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don’t forger to push your changes to the remote repository to repair your remote branch as well.&lt;/p&gt;

&lt;p&gt;ℹ️ There are more techniques like &lt;code&gt;git reflog&lt;/code&gt;. However, they are not covered in this tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Throughout this article, we have explored essential Git commands and their practical applications. We covered the fundamental differences between merging, rebasing, cherry-picking and squashing. &lt;/p&gt;

&lt;p&gt;It's important to choose the right approach depending on your team's practices and the specific project needs. By combining deep knowledge of Git with careful consideration of the project's requirements, you can improve significantly the quality of the development workflow. Each approach has its use cases, and knowing when to use them can save you from future problems.&lt;/p&gt;

&lt;p&gt;This tutorial was just a collection of lessons and real-world examples that I would have love to read when I was learning about Git. Having readings like this one would have made my learning process more robust, providing more context not only on how but also when should I use all these commands that I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliography
&lt;/h2&gt;

&lt;p&gt;Git - Book | 2023 | &lt;a href="https://git-scm.com/book/en/v2" rel="noopener noreferrer"&gt;Git Docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stack Overflow | 2013 | &lt;a href="https://stackoverflow.com/questions/11835948/git-cherry-pick-vs-rebase#:~:text=They%20are%20very%20different%3A,grained%20operation%20which%20copies%20commits" rel="noopener noreferrer"&gt;Git cherry pick vs rebase&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stack Overflow | 2017 | &lt;a href="https://stackoverflow.com/questions/1241720/git-cherry-pick-vs-merge-workflow" rel="noopener noreferrer"&gt;Git Cherry-pick vs Merge Workflow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Atlassian Bitbucket | 2023 | &lt;a href="https://www.atlassian.com/git/tutorials/merging-vs-rebasing" rel="noopener noreferrer"&gt;Merging vs. Rebasing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Atlassian Bitbucket | 2023 | &lt;a href="https://www.atlassian.com/git/tutorials/cherry-pick" rel="noopener noreferrer"&gt;Git Cherry Pick&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>softwaredevelopment</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Firebase Learning: Key Considerations to Keep in Mind</title>
      <dc:creator>José David Ureña Torres</dc:creator>
      <pubDate>Wed, 08 Feb 2023 06:48:09 +0000</pubDate>
      <link>https://dev.to/jodaut/firebase-learning-key-considerations-to-keep-in-mind-3910</link>
      <guid>https://dev.to/jodaut/firebase-learning-key-considerations-to-keep-in-mind-3910</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Firebase is a suite of cloud-based tools and services on Google Cloud Platform for application development. It offers hosting, authentication, storage, and databases that can be easily integrated into your app. One of its most popular tools is called Firestore, a key-value non-relational database. That means that uses structures similar to JSON to store information.&lt;/p&gt;

&lt;p&gt;During my professional experience with Firebase and Google Cloud, I encountered challenges with optimizing and securing applications. To help others overcome these difficulties, I have compiled some key insights that I wish I had known from the start. Whether you're a beginner or an experienced developer, the concepts outlined in this article are essential for a successful learning journey with these technologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Rules
&lt;/h2&gt;

&lt;p&gt;Firebase documentation does not emphasize enough the importance of Security Rules, especially for those just starting to integrate Firebase into their projects. If you do not properly implement security rules in your production application it can have severe consequences. Without proper security, anyone can potentially modify your database through API access, such as through Bash or Powershell.&lt;/p&gt;

&lt;p&gt;It is crucial to design your Firebase Security Rules before writing any code. If Security Rules are added at the end of the development process, you may be faced with the issue of accumulated technical debt and security vulnerabilities, which can be both time-consuming and costly to resolve.&lt;/p&gt;

&lt;p&gt;Security Rules should be considered a critical component of database design and should be discussed throughout the entire project, especially in the early stages. It's more efficient to revise and make changes to a draft on paper or a Jamboard than to retroactively fix a production implementation affecting numerous users.&lt;/p&gt;

&lt;p&gt;There are several patterns for controlling access to your application, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authenticated-only access&lt;/li&gt;
&lt;li&gt;Content-owner-only access&lt;/li&gt;
&lt;li&gt;Granular access control&lt;/li&gt;
&lt;li&gt;Functional access control&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Authenticated-only access
&lt;/h3&gt;

&lt;p&gt;You can restrict reading access to a collection of only signed-in users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match posts/{document=**} {
      allow read: if request.auth != null
            allow write: if false
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Content-owner-only access
&lt;/h3&gt;

&lt;p&gt;Also, you can implement a content-owner-only access pattern. In this way, users can access only their own documents, that is, the documents that have the same uid as the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /user/{userId}/{documents=**} {
      allow read, write: if request.auth != null &amp;amp;&amp;amp; request.auth.uid == userId
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Granular control access
&lt;/h3&gt;

&lt;p&gt;Another option is to add more granular rules to restrict access depending on the specific operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /posts/{documents=**} {
      allow read: if request.auth != null &amp;amp;&amp;amp; request.auth.uid &amp;amp;&amp;amp; get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Reader"
            allow create, update: if request.auth != null if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Writer"
            allow delete: if request.auth != null if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Admin"
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the user only can read a post if he has reading access, and only can create and update a post if he is a writer. Also, only an Admin can delete content inside the &lt;code&gt;posts&lt;/code&gt; collection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Functional control access
&lt;/h3&gt;

&lt;p&gt;If your project has a lot of duplicated code in your security rules, you can refactor it into functions and call those functions instead of copy and paste your rules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
        function isAuthenticated(){
            return request.auth != null
        }
        function isAdmin(){
            return isAuthenticated() &amp;amp;&amp;amp; get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Admin"
        }

    match /products/{documents=**} {
            allow read, write: if isAdmin()
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: You have to keep in mind that &lt;code&gt;{documents=**}&lt;/code&gt; means that it includes all the subcollections inside the &lt;code&gt;products&lt;/code&gt; collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Local Emulator Suite
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F0tpj4cwx1r26bgcn7d5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F0tpj4cwx1r26bgcn7d5k.png" alt="Local Emulator Suite" width="800" height="669"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It would be helpful if Firebase's documentation emphasized how important it is to use this tool, especially for those who use Firebase Functions. However, it doesn't seem like the documentation talks about it very much. There are entries on their website related to the Emulator Suite, but it feels a little messy sometimes. It took me months to understand that I could take advantage of that Emulator Suite and how to use it properly.&lt;/p&gt;

&lt;p&gt;This tool lets you test your projects on your own computer without affecting the real services. The local emulators support Firestore, Realtime Database, Functions, Storage, Authentication, and PubSubs.&lt;/p&gt;

&lt;p&gt;Testing your security rules and storage rules with the local emulators before you publish them to Google Cloud can help you find problems early. Plus, it can help you save money because fewer deploys mean fewer charges. Keeping all your rules in one place also makes it easier to keep track of them.&lt;/p&gt;

&lt;p&gt;You can see the &lt;a href="https://firebase.google.com/docs/emulator-suite" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; to learn more about the Local Emulator Suite&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizations for performance and scalability
&lt;/h2&gt;

&lt;p&gt;It might seem like a waste of time to focus on scalability and performance at the start of a small project. This is correct, in a way. Engineers have to avoid over-engineering. However, it is important to have a solid understanding of algorithms and logic so you are prepared when the project grows and performance becomes an issue. Otherwise, you may end up having to spend a lot of time and money fixing slow execution time or high memory consumption. To be efficient, you should learn techniques for writing more efficient Firebase Functions, like how to delete big collections or update many documents with complicated conditions.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to delete large collections
&lt;/h3&gt;

&lt;p&gt;Some collections can grow to millions of documents, and deleting documents inside of them can be a computation-intensive task. The examples below come from the official Firebase documentation. These show the recommended way of handling this type of task.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deleteCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;collectionPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;batchSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;collectionRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collectionPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;collectionRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;__name__&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;batchSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nf"&gt;deleteQueryBatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deleteQueryBatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;batchSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;batchSize&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// When there are no documents left, we are done&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// Delete documents in a batch&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// Recurse on the next process tick, to avoid&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// exploding the stack.&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextTick&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nf"&gt;deleteQueryBatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're working with big files and running into processing issues, one solution could be to give your function more resources, like extra RAM or a longer timeout.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;convertLargeFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runWith&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// Ensure the function has enough memory and time&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// to process large files&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;timeoutSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1GB&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onFinalize&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// Do some complicated things that take a lot of memory and time&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enqueued Cloud Tasks
&lt;/h3&gt;

&lt;p&gt;For time-consuming, resource-intensive, or bandwidth-limited tasks that need to run asynchronously, Google Cloud offers the possibility to enqueue functions with Cloud Tasks. You can control the number of attempts, backoff second, and the max of concurrent dispatches. The example below comes from the &lt;a href="https://firebase.google.com/docs/functions/task-functions" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backupApod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SOME_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;taskQueue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;retryConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;maxAttempts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;minBackoffSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;rateLimits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;maxConcurrentDispatches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;onDispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//your complex task&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enqueueBackupTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFunctions&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;taskQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;backupApod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enqueues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// Enqueue each task with i*60 seconds day. Our task queue function&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// should process ~1 task/min.&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scheduleDelaySeconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;enqueues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`task-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;scheduleDelaySeconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;dispatchDeadlineSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="c1"&gt;// 5 minutes&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enqueues&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Backups in Firebase
&lt;/h2&gt;

&lt;p&gt;As far as I know, right now Google Cloud doesn't have a way to automatically backup Firestore. I use &lt;a href="https://backupfire.dev/" rel="noopener noreferrer"&gt;BackupFire&lt;/a&gt; to do it for me, but you can also write a solution using Firebase Functions. Just keep in mind that when you restore a backup, &lt;strong&gt;Firebase tries to merge it with the original database, not overwrite it&lt;/strong&gt;. This can have important consequences. Consider this example:&lt;/p&gt;

&lt;p&gt;There are two customers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User A, uid: &lt;code&gt;z1V5scLfVPX7YD8fRCFRhhRAwVN2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;User B, uid: &lt;code&gt;Zk5olEuvZ1WokRrCqIN5gGaIu353&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;User A gained a gift card or discount code and it was saved in a subcollection inside the user document.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;users/z1V5scLfVPX7YD8fRCFRhhRAwVN2/discountCodes/dGn5OxSEPohqpZbIyLmCjqVEiwz2&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dGn5OxSEPohqpZbIyLmCjqVEiwz2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;expirationDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2023-01-18T18:34:33.565Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;isAGift&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app allows users to transfer codes to others. User A transferred the code to User B&lt;/p&gt;

&lt;p&gt;&lt;code&gt;users/z1V5scLfVPX7YD8fRCFRhhRAwVN2/discountCodes/dGn5OxSEPohqpZbIyLmCjqVEiwz2&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dGn5OxSEPohqpZbIyLmCjqVEiwz2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;expirationDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2023-01-18T18:34:33.565Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;isAGift&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, a backup from the previous day had to be restored due to an emergency. Upon checking, there were inconsistencies in the database. Both User A and User B now have the same discount code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;users/z1V5scLfVPX7YD8fRCFRhhRAwVN2/discoutCodes/dGn5OxSEPohqpZbIyLmCjqVEiwz2&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dGn5OxSEPohqpZbIyLmCjqVEiwz2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;expirationDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2023-01-18T18:34:33.565Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;isAGift&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;users/z1V5scLfVPX7YD8fRCFRhhRAwVN2/discoutCodes/dGn5OxSEPohqpZbIyLmCjqVEiwz2&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dGn5OxSEPohqpZbIyLmCjqVEiwz2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;expirationDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2023-01-18T18:34:33.565Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;isAGift&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To avoid these issues in Firestore, you can create a script that verifies the correct documents and removes the duplicates. Another solution is to design your database in a way that avoids documents that can be transferred, for example, with a collection in the root path of your database. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;discoutCodes/dGn5OxSEPohqpZbIyLmCjqVEiwz2&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dGn5OxSEPohqpZbIyLmCjqVEiwz2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;expirationDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2023-01-18T18:34:33.565Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;isAGift&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;createdBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z1V5scLfVPX7YD8fRCFRhhRAwVN2&lt;/span&gt;
    &lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Zk5olEuvZ1WokRrCqIN5gGaIu353&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this way, there is only one code available and transfer it to another user means just editing the owner field inside this document. Keep in mind that this is a specific problem related to the key-value internal structure of Firestore and may not occur in other databases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;In conclusion, it is important to consider scalability and performance efficiency in the early stages when designing a project, especially with Firebase; but without over-engineering. This can save time and resources in the long run. Additionally, it is essential to have a backup plan for Firestore, as restoring a backup can sometimes result in inconsistencies. To mitigate these issues, one can either use a third-party service or create their own solution based on Firebase Functions. It is also crucial to design the database in such a way as to avoid transferable subcollections that could lead to document duplications.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Bibliography&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Backup Fire | 2022 | &lt;a href="https://backupfire.dev/" rel="noopener noreferrer"&gt;BackupFire Official Site&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Firebase Documentation | 2022 | &lt;a href="https://firebase.google.com/docs/emulator-suite" rel="noopener noreferrer"&gt;Emulator Suite&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Firebase Documentation | 2022 | &lt;a href="https://firebase.google.com/docs/rules/basics" rel="noopener noreferrer"&gt;Security Rules Basics&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Firebase Documentation | 2022 | &lt;a href="https://cloud.google.com/firestore/docs/security/get-started" rel="noopener noreferrer"&gt;Security Rules Getting Started&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Developers | 2022 | &lt;a href="https://firebase.google.com/docs/functions/task-functions" rel="noopener noreferrer"&gt;Task Functions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Developers | 2022 | &lt;a href="https://firebase.google.com/docs/functions/manage-functions" rel="noopener noreferrer"&gt;Manage Functions&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Google Cloud | 2002 | &lt;a href="https://cloud.google.com/firestore/docs/samples/firestore-data-delete-collection#firestore_data_delete_collection-nodejs" rel="noopener noreferrer"&gt;Delete a Firestore collection&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>crypto</category>
      <category>security</category>
    </item>
    <item>
      <title>Python type checking with Visual Studio Code</title>
      <dc:creator>José David Ureña Torres</dc:creator>
      <pubDate>Mon, 18 Apr 2022 14:46:17 +0000</pubDate>
      <link>https://dev.to/jodaut/python-type-checking-with-visual-studio-code-46a7</link>
      <guid>https://dev.to/jodaut/python-type-checking-with-visual-studio-code-46a7</guid>
      <description>&lt;p&gt;When working in a team, it's important to establish a set of best practices that allows all the developers, old and new, to be productive while reducing the number of bugs and time required to understand a block of code.&lt;/p&gt;

&lt;p&gt;If you are working with other developers and need to be explicit with function signatures and variables, using static typed languages can be a good choice for your project. Since Python 3, you can add static types, but the IDE or code editor does not display any errors if you assign the incorrect value to a variable.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will set up Python to behave like a static typed languages. We will configure real-time static types checking in VS Code for Python projects. I prefer that the setup only show errors when you explicitly add the type of variable or function parameter in your code, while still allowing for normal variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Venv
&lt;/h2&gt;

&lt;p&gt;Venv is a Python built-in tool for creating a virtual environment that isolates the project dependencies, so you can install dependencies only for that specific project without affecting other projects in your computer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows setup
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;py -m venv venv

.\venv\Scripts\activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Linux or MacOS setup
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -m venv venv

venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Install Mypy
&lt;/h2&gt;

&lt;p&gt;Next, install &lt;a href="https://mypy.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;Mypy&lt;/a&gt;. This package checks types in your Python code and define a set of rules according to your needs.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install mypy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Add Gitlens extension
&lt;/h2&gt;

&lt;p&gt;Install &lt;a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens" rel="noopener noreferrer"&gt;GitLens&lt;/a&gt; extension for VS Code.&lt;/p&gt;

&lt;p&gt;Next, add these settings in your local &lt;code&gt;settings.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"python.linting.mypyEnabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"python.linting.mypyArgs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"--ignore-missing-imports"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"--follow-imports=silent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"--show-column-numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"--allow-untyped-defs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"--allow-subclassing-any"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"--allow-untyped-calls"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"--strict"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--strict&lt;/code&gt;: This option enables strict type checking. Although, it can be over strict in some cases. When you have existing code, and you don't want to change it because you know it works. Furthermore, so many errors can be distracting for developers. The flags below customize this strict mode to make it less strict.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--ignore-missing-imports&lt;/code&gt;: Suppresses error messages about unresolved imports. In Django, some imports can raise a warning without this flag. Only use it if your project contains warnings that you know aren't a real problem.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--follow-imports=silent&lt;/code&gt;: Turn off type checking in imported modules. Many libraries were not developed with static type checking in mind, so it's better to suppress type checking in imported modules.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--show-column-numbers&lt;/code&gt;: Shows column numbers in error messages.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--allow-untyped-defs&lt;/code&gt;: Suppress errors if you have non-typed functions in Python.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--allow-subclassing-any&lt;/code&gt;: Permits subclassing a value of type Any. Some frameworks can throw these errors with Mypy, therefore if you have them, add this line.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--allow-untyped-calls&lt;/code&gt;: Allows you to invoke non-typed functions in your code.&lt;/p&gt;

&lt;p&gt;You should not have any issues by adding it gradually to your project with this setup. Mypy has a lot of options, feel free to try other configurations for your specific case.&lt;/p&gt;

&lt;h2&gt;
  
  
  First simple example
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;example.py&lt;/code&gt; in the root of your project.&lt;br&gt;
Add this code (yo lo dejaria hasta aqui) into that file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n2&lt;/span&gt;


&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see in the image below, a lot of errors are displayed because &lt;code&gt;sum&lt;/code&gt; expect two int parameters, but is given a float value. However, &lt;code&gt;sub&lt;/code&gt; lacks a type definition, no errors are displayed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ff1h1r1rbdchu4n7ftola.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ff1h1r1rbdchu4n7ftola.png" alt="Simple Example" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is really powerful. Errors are displayed only in functions and variables that are required, and it will not interfere with your existing codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Django example
&lt;/h3&gt;

&lt;p&gt;Let's try in a more complex scenario using a Django project. Django is a framework to build web applications. See the docs &lt;a href="https://docs.djangoproject.com/en/4.0/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. But don't worry, there is no need to know it to follow this section.&lt;/p&gt;

&lt;p&gt;Keep in mind that Django is not a static typed Framework. Using only the &lt;code&gt;--strict&lt;/code&gt; mode in &lt;code&gt;settings.json&lt;/code&gt; will result in a lot of errors. If you configured the &lt;code&gt;settings.json&lt;/code&gt; file as previously described, you shouldn't have any issues.&lt;/p&gt;

&lt;p&gt;To create a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    pip &lt;span class="nb"&gt;install &lt;/span&gt;django
    django-admin startproject myapp
    &lt;span class="nb"&gt;cd &lt;/span&gt;myapp
    py manage.py startapp clients
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's add some code that generates errors in your &lt;code&gt;client.views.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;JsonResponse&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.shortcuts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.request&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;venv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;createGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!!!!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getPower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;asdf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;asdf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1234&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getPower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;asdf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;JsonResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Despite many errors appeared in &lt;code&gt;clients.urls.py&lt;/code&gt;, the project is still running. Django imports and default code are fine because it will only check variables and functions that you manually type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fvjmaw9dwk7sigy9ssr7j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fvjmaw9dwk7sigy9ssr7j.png" alt="Django Example" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;During this tutorial, we learned how to configure Visual Studio Code to check static types in Python projects and display errors in development.&lt;/p&gt;

&lt;p&gt;Remember that you can be strict as needed, but be careful. Here is a list of considerations to keep in mind:&lt;/p&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If working in a team it reduces cognitive effort to understand how to use a piece of code.&lt;/li&gt;
&lt;li&gt;Increases productivity because the code documents itself.&lt;/li&gt;
&lt;li&gt;Improves code documentation and readability.&lt;/li&gt;
&lt;li&gt;Reduce redundant tests&lt;/li&gt;
&lt;li&gt;Constant real-time feedback.&lt;/li&gt;
&lt;li&gt;Reduces development errors&lt;/li&gt;
&lt;li&gt;It is customizable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increases the complexity of your project.&lt;/li&gt;
&lt;li&gt;Many Python developers don't like typing code.&lt;/li&gt;
&lt;li&gt;It is impossible to be certain that a function will return what it says.&lt;/li&gt;
&lt;li&gt;The less restrictive your configuration is, the fewer errors are displayed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use it to develop new libraries and complex modules that must be thoroughly tested. It's not recommended for trying to add static typed to third-party libraries or legacy codebases (unless strictly necessary), because it could cause a lot of problems and time spent. Focus on the new code to write. Feel free to try with different configurations. In the long run, you and your team will be grateful for incorporating this tool into the workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliography
&lt;/h2&gt;

&lt;p&gt;Tushar Sadhwani - 2021 - &lt;a href="https://dev.to/tusharsadhwani/the-comprehensive-guide-to-mypy-561m#using-mypy-in-vscode"&gt;The Comprehensive Guide to mypy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kracekumar - 2021 - &lt;a href="https://dev.to/kracekumar/type-check-your-django-application-1gba"&gt;Type Check Your Django Application&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>webdev</category>
      <category>vscode</category>
    </item>
  </channel>
</rss>
