<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>weatherstar</title>
        <link>https://paragraph.com/@weatherstar</link>
        <description>undefined</description>
        <lastBuildDate>Thu, 27 Aug 2026 20:34:12 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>weatherstar</title>
            <url>https://storage.googleapis.com/papyrus_images/94a17698eff33383c0c00251f43fc4baaed757e9fb93ef5d580c899fa8cc1f03.jpg</url>
            <link>https://paragraph.com/@weatherstar</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Understanding the Nginx Configuration File Structure and Configuration Contexts]]></title>
            <link>https://paragraph.com/@weatherstar/understanding-the-nginx-configuration-file-structure-and-configuration-contexts</link>
            <guid>TxJzeQGK7G5uFaSN6b9V</guid>
            <pubDate>Mon, 11 Oct 2021 01:53:56 GMT</pubDate>
            <description><![CDATA[IntroductionNginx is a high performance web server that is responsible for handling the load of some of the largest sites on the internet. It is especially good at handling many concurrent connections and excels at serving static content. While many users are aware of Nginx’s capabilities, new users are often confused by some of the conventions they find in Nginx configuration files. In this guide, we will focus on discussing the basic structure of an Nginx configuration file along with some ...]]></description>
            <content:encoded><![CDATA[<h3 id="h-introduction" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Introduction</h3><p>Nginx is a high performance web server that is responsible for handling the load of some of the largest sites on the internet. It is especially good at handling many concurrent connections and excels at serving static content.</p><p>While many users are aware of Nginx’s capabilities, new users are often confused by some of the conventions they find in Nginx configuration files. In this guide, we will focus on discussing the basic structure of an Nginx configuration file along with some guidelines on how to design your files.</p><p>This guide will cover the basic structure found in the main Nginx configuration file. The location of this file will vary depending on how you installed the software on your machine. For many distributions, the file will be located at <code>/etc/nginx/nginx.conf</code>. If it does not exist there, it may also be at <code>/usr/local/nginx/conf/nginx.conf</code> or <code>/usr/local/etc/nginx/nginx.conf</code>.</p><p>One of the first things that you should notice when looking at the main configuration file is that it appears to be organized in a tree-like structure, defined by sets of brackets (that look like <code>{</code> and <code>}</code>). In Nginx parlance, the areas that these brackets define are called “contexts” because they contain configuration details that are separated according to their area of concern. Basically, these divisions provide an organizational structure along with some conditional logic to decide whether to apply the configurations within.</p><p>Because contexts can be layered within one another, Nginx provides a level of directive inheritance. As a general rule, if a directive is valid in multiple nested scopes, a declaration in a broader context will be passed on to any child contexts as default values. The children contexts can override these values at will. It is worth noting that an override to any array-type directives will <em>replace</em> the previous value, not append to it.</p><p>Directives can only be used in the contexts that they were designed for. Nginx will error out on reading a configuration file with directives that are declared in the wrong context. The <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://nginx.org/en/docs/dirindex.html">Nginx documentation</a> contains information about which contexts each directive is valid in, so it is a great reference if you are unsure.</p><p>Below, we’ll discuss the most common contexts that you’re likely to come across when working with Nginx.</p><h2 id="h-the-core-contexts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The Core Contexts</h2><p>The first group of contexts that we will discuss are the core contexts that Nginx utilizes in order to create a hierarchical tree and separate the concerns of discrete configuration blocks. These are the contexts that comprise the major structure of an Nginx configuration.</p><h3 id="h-the-main-context" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The Main Context</h3><p>The most general context is the “main” or “global” context. It is the only context that is not contained within the typical context blocks that look like this:</p><pre data-type="codeBlock" text="# The main context is here, outside any other contexts

. . .

context {

    . . .

}
"><code># The main context <span class="hljs-keyword">is</span> here, outside any other contexts

. . .

context {

    . . .

}
</code></pre><p>Any directive that exist entirely outside of these blocks is said to inhabit the “main” context. Keep in mind that if your Nginx configuration is set up in a modular fashion, some files will contain instructions that appear to exist outside of a bracketed context, but which will be included within such a context when the configuration is stitched together.</p><p>The main context represents the broadest environment for Nginx configuration. It is used to configure details that affect the entire application on a basic level. While the directives in this section affect the lower contexts, many of these aren’t <em>inherited</em> because they cannot be overridden in lower levels.</p><p>Some common details that are configured in the main context are the user and group to run the worker processes as, the number of workers, and the file to save the main process’s PID. You can even define things like worker CPU affinity and the “niceness” of worker processes. The default error file for the entire application can be set at this level (this can be overridden in more specific contexts).</p><h3 id="h-the-events-context" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The Events Context</h3><p>The “events” context is contained within the “main” context. It is used to set global options that affect how Nginx handles connections at a general level. There can only be a single events context defined within the Nginx configuration.</p><p>This context will look like this in the configuration file, outside of any other bracketed contexts:</p><pre data-type="codeBlock" text="# main context

events {

    # events context
    . . .

}
"><code># main context

events {

    # events context
    . . .

}
</code></pre><p>Nginx uses an event-based connection processing model, so the directives defined within this context determine how worker processes should handle connections. Mainly, directives found here are used to either select the connection processing technique to use, or to modify the way these methods are implemented.</p><p>Usually, the connection processing method is automatically selected based on the most efficient choice that the platform has available. For Linux systems, the <code>epoll</code> method is usually the best choice.</p><p>Other items that can be configured are the number of connections each worker can handle, whether a worker will only take a single connection at a time or take all pending connections after being notified about a pending connection, and whether workers will take turns responding to events.</p><h3 id="h-the-http-context" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The HTTP Context</h3><p>When configuring Nginx as a web server or reverse proxy, the “http” context will hold the majority of the configuration. This context will contain all of the directives and other contexts necessary to define how the program will handle HTTP or HTTPS connections.</p><p>The http context is a sibling of the events context, so they should be listed side-by-side, rather than nested. They both are children of the main context:</p><pre data-type="codeBlock" text="# main context

events {
    # events context

    . . .

}

http {
    # http context

    . . .

}
"><code># main context

events {
    # events context

    . . .

}

http {
    # http context

    . . .

}
</code></pre><p>While lower contexts get more specific about how to handle requests, directives at this level control the defaults for every virtual server defined within. A large number of directives are configurable at this context and below, depending on how you would like the inheritance to function.</p><p>Some of the directives that you are likely to encounter control the default locations for access and error logs (<code>access_log</code> and <code>error_log</code>), configure asynchronous I/O for file operations (<code>aio</code>, <code>sendfile</code>, and <code>directio</code>), and configure the server’s statuses when errors occur (<code>error_page</code>). Other directives configure compression (<code>gzip</code> and <code>gzip_disable</code>), fine-tune the TCP keep alive settings (<code>keepalive_disable</code>, <code>keepalive_requests</code>, and <code>keepalive_timeout</code>), and the rules that Nginx will follow to try to optimize packets and system calls (<code>sendfile</code>, <code>tcp_nodelay</code>, and <code>tcp_nopush</code>). Additional directives configure an application-level document root and index files (<code>root</code> and <code>index</code>) and set up the various hash tables that are used to store different types of data (<code>*_hash_bucket_size</code> and <code>*_hash_max_size</code> for <code>server_names</code>, <code>types</code>, and <code>variables</code>).</p><h3 id="h-the-server-context" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The Server Context</h3><p>The “server” context is declared <em>within</em> the “http” context. This is our first example of nested, bracketed contexts. It is also the first context that allows for multiple declarations.</p><p>The general format for server context may look something like this. Remember that these reside within the http context:</p><pre data-type="codeBlock" text="# main context

http {

    # http context

    server {

        # first server context

    }

    server {

        # second server context

    }

}
"><code><span class="hljs-section"># main context</span>

http {

<span class="hljs-code">    # http context
</span>
<span class="hljs-code">    server {
</span>
<span class="hljs-code">        # first server context
</span>
<span class="hljs-code">    }
</span>
<span class="hljs-code">    server {
</span>
<span class="hljs-code">        # second server context
</span>
<span class="hljs-code">    }
</span>
}
</code></pre><p>The reason for allowing multiple declarations of the server context is that each instance defines a specific virtual server to handle client requests. You can have as many server blocks as you need, each of which can handle a specific subset of connections.</p><p>Due to the possibility and likelihood of multiple server blocks, this context type is also the first that Nginx must use a selection algorithm to make decisions. Each client request will be handled according to the configuration defined in a single server context, so Nginx must decide which server context is most appropriate based on details of the request. The directives which decide if a server block will be used to answer a request are:</p><ul><li><p><strong>listen</strong>: The ip address / port combination that this server block is designed to respond to. If a request is made by a client that matches these values, this block will potentially be selected to handle the connection.</p></li><li><p><strong>server_name</strong>: This directive is the other component used to select a server block for processing. If there are multiple server blocks with listen directives of the same specificity that can handle the request, Nginx will parse the “Host” header of the request and match it against this directive.</p></li></ul><p>The directives in this context can override many of the directives that may be defined in the http context, including logging, the document root, compression, etc. In addition to the directives that are taken from the http context, we also can configure files to try to respond to requests (<code>try_files</code>), issue redirects and rewrites (<code>return</code> and <code>rewrite</code>), and set arbitrary variables (<code>set</code>).</p><h3 id="h-the-location-context" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The Location Context</h3><p>The next context that you will deal with regularly is the location context. Location contexts share many relational qualities with server contexts. For example, multiple location contexts can be defined, each location is used to handle a certain type of client request, and each location is selected by virtue of matching the location definition against the client request through a selection algorithm.</p><p>While the directives that determine whether to select a server block are defined within the server <em>context</em>, the component that decides on a location’s ability to handle a request is located in the location <em>definition</em> (the line that opens the location block).</p><p>The general syntax looks like this:</p><pre data-type="codeBlock" text="location match_modifier location_match {

    . . .

}
"><code>location match_modifier location_match {

    . . .

}
</code></pre><p>Location blocks live within server contexts and, unlike server blocks, can be nested inside one another. This can be useful for creating a more general location context to catch a certain subset of traffic, and then further processing it based on more specific criteria with additional contexts inside:</p><pre data-type="codeBlock" text="# main context

server {

    # server context

    location /match/criteria {

        # first location context

    }

    location /other/criteria {

        # second location context

        location nested_match {

            # first nested location

        }

        location other_nested {

            # second nested location

        }

    }

}
"><code><span class="hljs-section"># main context</span>

server {

<span class="hljs-code">    # server context
</span>
<span class="hljs-code">    location /match/criteria {
</span>
<span class="hljs-code">        # first location context
</span>
<span class="hljs-code">    }
</span>
<span class="hljs-code">    location /other/criteria {
</span>
<span class="hljs-code">        # second location context
</span>
<span class="hljs-code">        location nested_match {
</span>
<span class="hljs-code">            # first nested location
</span>
<span class="hljs-code">        }
</span>
<span class="hljs-code">        location other_nested {
</span>
<span class="hljs-code">            # second nested location
</span>
<span class="hljs-code">        }
</span>
<span class="hljs-code">    }
</span>
}
</code></pre><p>While server contexts are selected based on the requested IP address/port combination and the host name in the “Host” header, location blocks further divide up the request handling within a server block by looking at the request URI. The request URI is the portion of the request that comes after the domain name or IP address/port combination.</p><p>So, if a client requests <code>http://www.example.com/blog</code> on port 80, the <code>http</code>, <code>www.example.com</code>, and port 80 would all be used to determine which server block to select. After a server is selected, the <code>/blog</code> portion (the request URI), would be evaluated against the defined locations to determine which further context should be used to respond to the request.</p><p>Many of the directives you are likely to see in a location context are also available at the parent levels. New directives at this level allow you to reach locations outside of the document root (<code>alias</code>), mark the location as only internally accessible (<code>internal</code>), and proxy to other servers or locations (using http, fastcgi, scgi, and uwsgi proxying).</p><h2 id="h-other-contexts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Other Contexts</h2><p>While the above examples represent the essential contexts that you will encounter with Nginx, other contexts exist as well. The contexts below were separated out either because they depend on more optional modules, they are used only in certain circumstances, or they are used for functionality that most people will not be using.</p><p>We will <em>not</em> be discussing each of the available contexts though. The following contexts will not be discussed in any depth:</p><ul><li><p><code>split_clients</code>: This context is configured to split the clients that the server receives into categories by labeling them with variables based on a percentage. These can then be used to do A/B testing by providing different content to different hosts.</p></li><li><p><code>perl / perl_set</code>: These contexts configures Perl handlers for the location they appear in. This will only be used for processing with Perl.</p></li><li><p><code>map</code>: This context is used to set the value of a variable depending on the value of another variable. It provides a mapping of one variable’s values to determine what the second variable should be set to.</p></li><li><p><code>geo</code>: Like the above context, this context is used to specify a mapping. However, this mapping is specifically used to categorize client IP addresses. It sets the value of a variable depending on the connecting IP address.</p></li><li><p><code>types</code>: This context is again used for mapping. This context is used to map MIME types to the file extensions that should be associated with them. This is usually provided with Nginx through a file that is sourced into the main <code>nginx.conf</code> config file.</p></li><li><p><code>charset_map</code>: This is another example of a mapping context. This context is used to map a conversion table from one character set to another. In the context header, both sets are listed and in the body, the mapping takes place.</p></li></ul><p>The contexts below are not as common as the ones we have discussed so far, but are still very useful to know about.</p><h3 id="h-the-upstream-context" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The Upstream Context</h3><p>The upstream context is used to define and configure “upstream” servers. Basically, this context defines a named pool of servers that Nginx can then proxy requests to. This context will likely be used when you are configuring proxies of various types.</p><p>The upstream context should be placed within the http context, outside of any specific server contexts. The general form looks something like this:</p><pre data-type="codeBlock" text="# main context

http {

    # http context

    upstream upstream_name {

        # upstream context

        server proxy_server1;
        server proxy_server2;

        . . .

    }

    server {

        # server context

    }

}
"><code><span class="hljs-section"># main context</span>

http {

<span class="hljs-code">    # http context
</span>
<span class="hljs-code">    upstream upstream_name {
</span>
<span class="hljs-code">        # upstream context
</span>
<span class="hljs-code">        server proxy_server1;
        server proxy_server2;
</span>
<span class="hljs-code">        . . .
</span>
<span class="hljs-code">    }
</span>
<span class="hljs-code">    server {
</span>
<span class="hljs-code">        # server context
</span>
<span class="hljs-code">    }
</span>
}
</code></pre><p>The upstream context can then be referenced by name within server or location blocks to pass requests of a certain type to the pool of servers that have been defined. The upstream will then use an algorithm (round-robin by default) to determine which specific server to hand the request to. This context gives our Nginx the ability to do some load balancing when proxying requests.</p><h3 id="h-the-mail-context" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The Mail Context</h3><p>Although Nginx is most often used as a web or reverse proxy server, it can also function as a high performance mail proxy server. The context that is used for directives of this type is called, appropriately, “mail”. The mail context is defined within the “main” or “global” context (outside of the http context).</p><p>The main function of the mail context is to provide an area for configuring a mail proxying solution on the server. Nginx has the ability to redirect authentication requests to an external authentication server. It can then provide access to POP3 and IMAP mail servers for serving the actual mail data. The mail context can also be configured to connect to an SMTP Relayhost if desired.</p><p>In general, a mail context will look something like this:</p><pre data-type="codeBlock" text="# main context

events {

    # events context

}

mail {

    # mail context

}
"><code><span class="hljs-meta"># main context</span>

events {

    <span class="hljs-meta"># events context</span>

}

mail {

    <span class="hljs-meta"># mail context</span>

}
</code></pre><h3 id="h-the-if-context" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The If Context</h3><p>The “if” context can be established to provide conditional processing of directives defined within. Like an if statement in conventional programming, the if directive in Nginx will execute the instructions contained if a given test returns “true”.</p><p>The if context in Nginx is provided by the rewrite module and this is the primary intended use of this context. Since Nginx will test conditions of a request with many other purpose-made directives, if should <strong>not</strong> be used for most forms of conditional execution. This is such an important note that the Nginx community has created a page called <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/">if is evil</a>.</p><p>The problem is basically that the Nginx processing order can very often lead to unexpected results that seem to subvert the meaning of an if block. The only directives that are considered reliably safe to use inside of these contexts are the <code>return</code> and <code>rewrite</code> directives (the ones this context was created for). Another thing to keep in mind when using an if context is that it renders a <code>try_files</code> directive in the same context useless.</p><p>Most often, an if will be used to determine whether a rewrite or return is needed. These will most often exist in location blocks, so the common form will look something like this:</p><pre data-type="codeBlock" text="# main context

http {

    # http context

    server {

        # server context

        location location_match {

            # location context

            if (test_condition) {

                # if context

            }

        }

    }

}
"><code><span class="hljs-section"># main context</span>

http {

<span class="hljs-code">    # http context
</span>
<span class="hljs-code">    server {
</span>
<span class="hljs-code">        # server context
</span>
<span class="hljs-code">        location location_match {
</span>
<span class="hljs-code">            # location context
</span>
<span class="hljs-code">            if (test_condition) {
</span>
<span class="hljs-code">                # if context
</span>
<span class="hljs-code">            }
</span>
<span class="hljs-code">        }
</span>
<span class="hljs-code">    }
</span>
}
</code></pre><h3 id="h-the-limitexcept-context" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The Limit_except Context</h3><p>The <code>limit_except</code> context is used to restrict the use of certain HTTP methods within a location context. For example, if only certain clients should have access to POST content, but everyone should have the ability to read content, you can use a <code>limit_except</code> block to define this requirement.</p><p>The above example would look something like this:</p><pre data-type="codeBlock" text=". . .

# server or location context

location /restricted-write {

    # location context

    limit_except GET HEAD {

        # limit_except context

        allow 192.168.1.1/24;
        deny all;
    }
}
"><code>. . .

# server or location context

location <span class="hljs-operator">/</span>restricted<span class="hljs-operator">-</span>write {

    # location context

    limit_except GET HEAD {

        # limit_except context

        allow <span class="hljs-number">192.168</span><span class="hljs-number">.1</span><span class="hljs-number">.1</span><span class="hljs-operator">/</span><span class="hljs-number">24</span>;
        deny all;
    }
}
</code></pre><p>This will apply the directives inside the context (meant to restrict access) when encountering any HTTP methods <strong>except</strong> those listed in the context header. The result of the above example is that any client can use the GET and HEAD verbs, but only clients coming from the <code>192.168.1.1/24</code> subnet are allowed to use other methods.</p><h2 id="h-general-rules-to-follow-regarding-contexts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">General Rules to Follow Regarding Contexts</h2><p>Now that you have an idea of the common contexts that you are likely to encounter when exploring Nginx configurations, we can discuss some best practices to use when dealing with Nginx contexts.</p><h3 id="h-apply-directives-in-the-highest-context-available" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Apply Directives in the Highest Context Available</h3><p>Many directives are valid in more than one context. For instance, there are quite a few directives that can be placed in the http, server, or location context. This gives us flexibility in setting these directives.</p><p>However, as a general rule, it is usually best to declare directives in the highest context to which they are applicable, and overriding them in lower contexts as necessary. This is possible because of the inheritance model that Nginx implements. There are many reasons to use this strategy.</p><p>First of all, declaring at a high level allows you to avoid unnecessary repetition between sibling contexts. For instance, in the example below, each of the locations is declaring the same document root:</p><pre data-type="codeBlock" text="http {
    server {
        location / {
            root /var/www/html;

            . . .

        }

        location /another {
            root /var/www/html;

            . . .

        }

    }
}
"><code>http {
    server {
        location <span class="hljs-operator">/</span> {
            root <span class="hljs-operator">/</span><span class="hljs-keyword">var</span><span class="hljs-operator">/</span>www<span class="hljs-operator">/</span>html;

            . . .

        }

        location <span class="hljs-operator">/</span>another {
            root <span class="hljs-operator">/</span><span class="hljs-keyword">var</span><span class="hljs-operator">/</span>www<span class="hljs-operator">/</span>html;

            . . .

        }

    }
}
</code></pre><p>You could move the root out to the server block, or even to the http block, like this:</p><pre data-type="codeBlock" text="http {
    root /var/www/html;
    server {
        location / {

            . . .

        }

        location /another {

            . . .

        }
    }
}
"><code>http {
    root <span class="hljs-operator">/</span><span class="hljs-keyword">var</span><span class="hljs-operator">/</span>www<span class="hljs-operator">/</span>html;
    server {
        location <span class="hljs-operator">/</span> {

            . . .

        }

        location <span class="hljs-operator">/</span>another {

            . . .

        }
    }
}
</code></pre><p>Most of the time, the server level will be most appropriate, but declaring at the higher level has its advantages. This not only allows you to set the directive in fewer places, it also allows you to cascade the default value down to all of the child elements, preventing situations where you run into an error by forgetting a directive at a lower level. This can be a major issue with long configurations. Declaring at higher levels provides you with a sane default.</p><h3 id="h-use-multiple-sibling-contexts-instead-of-if-logic-for-processing" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Use Multiple Sibling Contexts Instead of If Logic for Processing</h3><p>When you want to handle requests differently depending on some information that can be found in the client’s request, often users jump to the “if” context to try to conditionalize processing. There are a few issues with this that we touched on briefly earlier.</p><p>The first is that the “if” directive often return results that do not align with the administrator’s expectations. Although the processing will always lead to the same result given the same input, the way that Nginx interprets the environment can be vastly different than can be assumed without heavy testing.</p><p>The second reason for this is that there are already optimized, purpose-made directives that are used for many of these purposes. Nginx already engages in a well-documented selection algorithm for things like selecting server blocks and location blocks. So if it is possible, it is best to try to move your different configurations into their own blocks so that this algorithm can handle the selection process logic.</p><p>For instance, instead of relying on rewrites to get a user supplied request into the format that you would like to work with, you should try to set up two blocks for the request, one of which represents the desired method, and the other that catches messy requests and redirects (and possibly rewrites) them to your correct block.</p><p>The result is usually easier to read and also has the added benefit of being more performant. Correct requests undergo no additional processing and, in many cases, incorrect requests can get by with a redirect rather than a rewrite, which should execute with lower overhead.</p><h2 id="h-conclusion" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Conclusion</h2><p>By this point, you should have a good grasp on Nginx’s most common contexts and the directive that create the blocks that define them.</p><p>Always check <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://nginx.org/en/docs/dirindex.html">Nginx’s documentation</a> for information about which contexts a directive can be placed in and to evaluate the most effective location. Taking care when creating your configurations will not only increase maintainability, but will also often increase performance.</p>]]></content:encoded>
            <author>weatherstar@newsletter.paragraph.com (weatherstar)</author>
        </item>
        <item>
            <title><![CDATA[🌳🚀 CS Visualized: Useful Git Commands]]></title>
            <link>https://paragraph.com/@weatherstar/cs-visualized-useful-git-commands</link>
            <guid>70EArXZm1cVNmy2g6rPP</guid>
            <pubDate>Sat, 09 Oct 2021 09:06:09 GMT</pubDate>
            <description><![CDATA[Although Git is a very powerful tool, I think most people would agree when I say it can also be... a total nightmare 😐 I&apos;ve always found it very useful to visualize in my head what&apos;s happening when working with Git: how are the branches interacting when I perform a certain command, and how will it affect the history? Why did my coworker cry when I did a hard reset on master, force pushed to origin and rimraf&apos;d the .git folder? I thought it would be the perfect use case to crea...]]></description>
            <content:encoded><![CDATA[<p>Although Git is a very powerful tool, I think most people would agree when I say it can also be... a total nightmare 😐 I&apos;ve always found it very useful to visualize in my head what&apos;s happening when working with Git: how are the branches interacting when I perform a certain command, and how will it affect the history? Why did my coworker cry when I did a hard reset on <code>master</code>, <code>force push</code>ed to origin and <code>rimraf</code>&apos;d the <code>.git</code> folder?</p><p>I thought it would be the perfect use case to create some visualized examples of the most common and useful commands! 🥳 Many of the commands I&apos;m covering have optional arguments that you can use in order to change their behavior. In my examples, I&apos;ll cover the default behavior of the commands without adding (too many) config options! 😄</p><hr><h2 id="h-unsupported-embedmerging" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedMerging</h2><p>Having multiple branches is extremely convenient to keep new changes separated from each other, and to make sure you don&apos;t accidentally push unapproved or broken changes to production. Once the changes have been approved, we want to get these changes in our production branch!</p><p>One way to get the changes from one branch to another is by performing a <code>git merge</code>! There are two types of merges Git can perform: a <strong>fast-forward</strong>, or a <strong>no-fast-forward</strong> 🐢</p><p>This may not make a lot of sense right now, so let&apos;s look at the differences!</p><h3 id="h-unsupported-embedfast-forward-ff" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedFast-forward (<code>--ff</code>)</h3><p>A <strong>fast-forward merge</strong> can happen when the current branch has no extra commits compared to the branch we’re merging. Git is... <em>lazy</em> and will first try to perform the easiest option: the fast-forward! This type of merge doesn’t create a new commit, but rather merges the commit(s) on the branch we’re merging right in the current branch 🥳</p><br><p>Perfect! We now have all the changes that were made on the <code>dev</code> branch available on the <code>master</code> branch. So, what&apos;s the <strong>no-fast-forward</strong> all about?</p><h3 id="h-unsupported-embedno-fast-foward-no-ff" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedNo-fast-foward (<code>--no-ff</code>)</h3><p>It&apos;s great if your current branch doesn&apos;t have any extra commits compared to the branch that you want to merge, but unfortunately that&apos;s rarely the case! If we committed changes on the current branch that the branch we want to merge doesn&apos;t have, git will perform a <em>no-fast-forward</em> merge.</p><p>With a no-fast-forward merge, Git creates a new <em>merging commit</em> on the active branch. The commit&apos;s parent commits point to both the active branch and the branch that we want to merge!</p><br><p>No big deal, a perfect merge! 🎉 The <code>master</code> branch now contains all the changes that we&apos;ve made on the <code>dev</code> branch.</p><h3 id="h-unsupported-embedmerge-conflicts" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedMerge Conflicts</h3><p>Although Git is good at deciding how to merge branches and add changes to files, it cannot always make this decision all by itself 🙂 This can happen when the two branches we&apos;re trying to merge have changes on the same line in the same file, or if one branch deleted a file that another branch modified, and so on.</p><p>In that case, Git will ask you to help decide which of the two options we want to keep! Let&apos;s say that on both branches, we edited the first line in the <code>README.md</code>.</p><br><p>If we want to merge <code>dev</code> into <code>master</code>, this will end up in a merge conflict: would you like the title to be <code>Hello!</code> or <code>Hey!</code>?</p><p>When trying to merge the branches, Git will show you where the conflict happens. We can manually remove the changes we don&apos;t want to keep, save the changes, add the changed file again, and commit the changes 🥳</p><br><p>Yay! Although merge conflicts are often quite annoying, it makes total sense: Git shouldn&apos;t just <em>assume</em> which change we want to keep.</p><hr><h2 id="h-unsupported-embedrebasing" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedRebasing</h2><p>We just saw how we could apply changes from one branch to another by performing a <code>git merge</code>. Another way of adding changes from one branch to another is by performing a <code>git rebase</code>.</p><p>A <code>git rebase</code> <em>copies</em> the commits from the current branch, and puts these copied commits on top of the specified branch.</p><br><p>Perfect, we now have all the changes that were made on the <code>master</code> branch available on the <code>dev</code> branch! 🎊</p><p>A big difference compared to merging, is that Git won&apos;t try to find out which files to keep and not keep. The branch that we&apos;re rebasing always has the latest changes that we want to keep! You won&apos;t run into any merging conflicts this way, and keeps a nice linear Git history.</p><p>This example shows rebasing on the <code>master</code> branch. In bigger projects, however, you usually don&apos;t want to do that. A <code>git rebase</code> <strong>changes the history of the project</strong> as new hashes are created for the copied commits!</p><p>Rebasing is great whenever you&apos;re working on a feature branch, and the master branch has been updated. You can get all the updates on your branch, which would prevent future merging conflicts! 😄</p><h3 id="h-unsupported-embedinteractive-rebase" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedInteractive Rebase</h3><p>Before rebasing the commits, we can modify them! 😃 We can do so with an <em>interactive rebase</em>. An interactive rebase can also be useful on the branch you&apos;re currently working on, and want to modify some commits.</p><p>There are 6 actions we can perform on the commits we&apos;re rebasing:</p><ul><li><p><code>reword</code>: Change the commit message</p></li><li><p><code>edit</code>: Amend this commit</p></li><li><p><code>squash</code>: Meld commit into the previous commit</p></li><li><p><code>fixup</code>: Meld commit into the previous commit, without keeping the commit&apos;s log message</p></li><li><p><code>exec</code>: Run a command on each commit we want to rebase</p></li><li><p><code>drop</code>: Remove the commit</p></li></ul><p>Awesome! This way, we can have full control over our commits. If we want to remove a commit, we can just <code>drop</code> it.</p><br><p>Or if we want to squash multiple commits together to get a cleaner history, no problem!</p><br><p>Interactive rebasing gives you a lot of control over the commits you&apos;re trying to rebase, even on the current active branch!</p><hr><h2 id="h-unsupported-embedresetting" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedResetting</h2><p>It can happen that we committed changes that we didn&apos;t want later on. Maybe it&apos;s a <code>WIP</code> commit, or maybe a commit that introduced bugs! 🐛 In that case, we can perform a <code>git reset</code>.</p><p>A <code>git reset</code> gets rid of all the current staged files and gives us control over where <code>HEAD</code> should point to.</p><h3 id="h-unsupported-embedsoft-reset" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedSoft reset</h3><p>A <em>soft reset</em> moves <code>HEAD</code> to the specified commit (or the index of the commit compared to <code>HEAD</code>), without getting rid of the changes that were introduced on the commits afterward!</p><p>Let&apos;s say that we don&apos;t want to keep the commit <code>9e78i</code> which added a <code>style.css</code> file, and we also don&apos;t want to keep the commit <code>035cc</code> which added an <code>index.js</code> file. However, we do want to keep the newly added <code>style.css</code> and <code>index.js</code> file! A perfect use case for a soft reset.</p><br><p>When typing <code>git status</code>, you&apos;ll see that we still have access to all the changes that were made on the previous commits. This is great, as this means that we can fix the contents of these files and commit them again later on!</p><h3 id="h-unsupported-embedhard-reset" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedHard reset</h3><p>Sometimes, we don&apos;t want to keep the changes that were introduced by certain commits. Unlike a soft reset, we shouldn&apos;t need to have access to them any more. Git should simply reset its state back to where it was on the specified commit: this even includes the changes in your working directory and staged files! 💣</p><br><p>Git has discarded the changes that were introduced on <code>9e78i</code> and <code>035cc</code>, and reset its state to where it was on commit <code>ec5be</code>.</p><hr><h3 id="h-unsupported-embedreverting" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedReverting</h3><p>Another way of undoing changes is by performing a <code>git revert</code>. By reverting a certain commit, we create a <em>new commit</em> that contains the reverted changes!</p><p>Let&apos;s say that <code>ec5be</code> added an <code>index.js</code> file. Later on, we actually realize we didn&apos;t want this change introduced by this commit anymore! Let&apos;s revert the <code>ec5be</code> commit.</p><br><p>Perfect! Commit <code>9e78i</code> reverted the changes that were introduced by the <code>ec5be</code> commit. Performing a <code>git revert</code> is very useful in order to undo a certain commit, without modifying the history of the branch.</p><hr><h2 id="h-unsupported-embedcherry-picking" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedCherry-picking</h2><p>When a certain branch contains a commit that introduced changes we need on our active branch, we can <code>cherry-pick</code> that command! By <code>cherry-pick</code>ing a commit, we create a new commit on our active branch that contains the changes that were introduced by the <code>cherry-pick</code>ed commit.</p><p>Say that commit <code>76d12</code> on the <code>dev</code> branch added a change to the <code>index.js</code> file that we want in our <code>master</code> branch. We don&apos;t want the <em>entire</em> we just care about this one single commit!</p><br><p>Cool, the master branch now contains the changes that <code>76d12</code> introduced!</p><hr><h2 id="h-unsupported-embedfetching" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedFetching</h2><p>If we have a remote Git branch, for example a branch on Github, it can happen that the remote branch has commits that the current branch doesn&apos;t have! Maybe another branch got merged, your colleague pushed a quick fix, and so on.</p><p>We can get these changes locally, by performing a <code>git fetch</code> on the remote branch! It doesn&apos;t affect your local branch in any way: a <code>fetch</code> simply downloads new data.</p><br><p>We can now see all the changes that have been made since we last pushed! We can decide what we want to do with the new data now that we have it locally.</p><hr><h2 id="h-unsupported-embedpulling" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedPulling</h2><p>Although a <code>git fetch</code> is very useful in order to get the remote information of a branch, we can also perform a <code>git pull</code>. A <code>git pull</code> is actually two commands in one: a <code>git fetch</code>, and a <code>git merge</code>. When we&apos;re pulling changes from the origin, we&apos;re first fetching all the data like we did with a <code>git fetch</code>, after which the latest changes are automatically merged into the local branch.</p><br><p>Awesome, we&apos;re now perfectly in sync with the remote branch and have all the latest changes! 🤩</p><hr><h2 id="h-unsupported-embedreflog" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Unsupported embedReflog</h2><p>Everyone makes mistakes, and that&apos;s totally okay! Sometimes it may feel like you&apos;ve screwed up your git repo so badly that you just want to delete it entirely.</p><p><code>git reflog</code> is a very useful command in order to show a log of all the actions that have been taken! This includes merges, resets, reverts: basically any alteration to your branch.</p><p>)</p><p>If you made a mistake, you can easily redo this by resetting <code>HEAD</code> based on the information that <code>reflog</code> gives us!</p><p>Say that we actually didn&apos;t want to merge the origin branch. When we execute the <code>git reflog</code> command, we see that the state of the repo before the merge is at <code>HEAD@{1}</code>. Let&apos;s perform a <code>git reset</code> to point HEAD back to where it was on <code>HEAD@{1}</code>!</p><br><p>We can see that the latest action has been pushed to the <code>reflog</code>!</p><hr><p>Git has so many useful porcelain and plumbing commands, I wish I could cover them all! 😄 I know there are many other commands or alterations that I didn&apos;t have time for to cover right now - let me know what your favorite/most useful commands are, and I may cover them in another post!</p><p>And as always, feel free to reach out to me! 😊</p>]]></content:encoded>
            <author>weatherstar@newsletter.paragraph.com (weatherstar)</author>
        </item>
    </channel>
</rss>