<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ version control - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ version control - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 22 May 2026 17:39:45 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/version-control/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Save Multiple Drafts in Git: A Guide to Using Stash ]]>
                </title>
                <description>
                    <![CDATA[ Writing code can be similar to writing tutorials. In both cases, you’ll typically need to create and work on multiple drafts before reaching the final version. In an ideal setting, you would write cod ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-save-multiple-drafts-in-git-a-guide-to-using-stash/</link>
                <guid isPermaLink="false">6989f72cfec80c4e91c007a4</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chidiadi Anyanwu ]]>
                </dc:creator>
                <pubDate>Mon, 09 Feb 2026 15:03:08 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770649372924/7c949e9d-627a-4b06-99fe-40ce0e7c8507.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Writing code can be similar to writing tutorials. In both cases, you’ll typically need to create and work on multiple drafts before reaching the final version.</p>
<p>In an ideal setting, you would write code for a feature, add that code to the staging area, and then commit it before going to the next part. This helps keep your commit history clean. (Don't worry if you don't have a clean history. Many of us don’t.)</p>
<p>But now, imagine a scenario where you have multiple features to build. You've committed the first. You've started the third, but then you found out you needed to build the second one first, because the third depends on it. It might seem like you have to go back in time and build out that second feature without mixing in the code changes for the third, and without deleting the code changes for the third.</p>
<p>So how do you do that?</p>
<p>In this article, you’re going to learn about Git stash, what it is, and the basic commands you need to be able to use it.</p>
<h2 id="heading-what-well-cover">What We’ll Cover:</h2>
<ul>
<li><p><a href="#heading-what-is-git-stash">What is Git Stash?</a></p>
</li>
<li><p><a href="#heading-how-to-use-git-stash">How to Use Git Stash</a></p>
<ul>
<li><p><a href="#heading-pushing-commands-to-the-stash">Pushing Commands To The Stash</a></p>
</li>
<li><p><a href="#heading-applying-changes-from-the-stash-to-the-working-directory">Applying Changes From The Stash To The Working Directory</a></p>
</li>
<li><p><a href="#heading-listing-the-items-in-the-stash-list">Listing The Items In The Stash List</a></p>
</li>
<li><p><a href="#heading-removing-items-from-the-stash">Removing Items From The Stash</a></p>
</li>
<li><p><a href="#heading-creating-a-new-branch-from-stash">Creating A New Branch From Stash</a></p>
</li>
<li><p><a href="#heading-showing-the-changes-in-the-stash">Showing The Changes In The Stash</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<p>To understand and get the most out of this tutorial, you’ll need to have a basic understanding of Git.</p>
<h2 id="heading-what-is-git-stash">What is Git Stash?</h2>
<p>Git stash provides storage (in the form of a stack) where you can store changes to your code. It lets you keep these changes separate from the current working directory until you're ready to apply them.</p>
<p><code>git stash</code> is a relatively simple command, and has a few variations like:</p>
<ul>
<li><p><code>git stash push</code></p>
</li>
<li><p><code>git stash pop</code></p>
</li>
<li><p><code>git stash apply</code></p>
</li>
<li><p><code>git stash drop</code></p>
</li>
<li><p><code>git stash clear</code></p>
</li>
<li><p><code>git stash show</code></p>
</li>
<li><p><code>git stash list</code></p>
</li>
</ul>
<h2 id="heading-how-to-use-git-stash">How to Use Git Stash</h2>
<h3 id="heading-pushing-code-changes-to-the-stash">Pushing Code Changes to the Stash</h3>
<p>To push uncommitted changes from the working directory to the stash, you can use <code>git stash push.</code> When you do that, the changes disappear from the working directory and are saved in the stash. The working directory is then set back to the last commit (which, in the example below, is the Feature one).</p>
<pre><code class="language-bash">git stash push
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/7652801b-cb1e-45cc-ac94-281512252f37.png" alt="7652801b-cb1e-45cc-ac94-281512252f37" style="display:block;margin:0 auto" width="1019" height="382" loading="lazy">

<p>You can also write the <code>git stash push</code> command as just <code>git stash</code> – it means the same thing and performs the same way. You can also add a message to it with the <code>-m</code> or <code>--message</code> flag:</p>
<pre><code class="language-bash">git stash push -m "Feature two I was working on"
</code></pre>
<p>You can use the <code>-u</code> flag or <code>--include-untracked</code> to include untracked changes in the stash. This way, the changes not yet tracked by Git can be included in the stash.</p>
<pre><code class="language-bash">git stash push -u
git stash push --include-untracked
</code></pre>
<p>On the other hand, you can decide to push only staged changes to the stash with the <code>-s</code> or <code>--staged</code> flag:</p>
<pre><code class="language-bash">git stash push -s
</code></pre>
<p>You can also suppress feedback messages with the <code>-q</code> or <code>--quiet</code> flag:</p>
<pre><code class="language-bash">git stash push -q
</code></pre>
<p>When you're done with your edits on the current working directory, you can commit and push without the older changes bleeding into it. They're safely stowed away in the stash.</p>
<p>Anytime you use the git stash command, you add a stash to the stash list. The stashes are identified by their index numbers.</p>
<h3 id="heading-applying-changes-from-the-stash-to-the-working-directory">Applying Changes from the Stash to the Working Directory</h3>
<p>Let’s say you had a quick fix to do. You’re done committing that, and you want to continue with what you were working on. You can restore the changes from the stash to continue working on them.</p>
<p>You can do this by using the <code>git stash apply</code> command or the <code>git stash pop</code> command:</p>
<pre><code class="language-bash">git stash apply
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/89d30b86-ba75-412f-8aba-b8bf1ac32933.png" alt="89d30b86-ba75-412f-8aba-b8bf1ac32933" style="display:block;margin:0 auto" width="1005" height="475" loading="lazy">

<p><code>git stash apply</code> applies the latest changes from the stash to the working directory, but doesn’t delete the code from the stash. You can select a particular entry to apply by index number:</p>
<pre><code class="language-bash">git stash apply --index stash@{1}
# You'd need to use quotes "stash@{1}" if you're writing this in PowerShell
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/4a26b84c-9bf0-4bd2-9687-7ebb94046f5d.png" alt="4a26b84c-9bf0-4bd2-9687-7ebb94046f5d" style="display:block;margin:0 auto" width="1001" height="212" loading="lazy">

<p><code>git stash pop</code>, on the other hand, applies the latest changes from the stash, then deletes them from the stash. Basically, popping from a stack. You can select a particular stash entry to pop by index number.</p>
<pre><code class="language-bash">git stash pop
</code></pre>
<pre><code class="language-bash">git stash pop --index stash@{1}
# You'd need to use quotes "stash@{1}" if you're writing this in PowerShell
</code></pre>
<h3 id="heading-listing-the-items-in-the-stash-list">Listing the Items in the Stash List</h3>
<p>You can use <code>git stash list</code> to list out the stashes in the stash list. It’s arranged by index number (like {0}, {1}, and so on). Any time you do a git stash push, it adds a stash to the stash list.</p>
<pre><code class="language-bash">git stash list
stash@{0}: WIP on master: b2a2709 Feature one
stash@{1}: WIP on master: b2a2709 Feature one
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/46c7b4a8-6701-4227-8d48-9da354c9d1b7.png" alt="46c7b4a8-6701-4227-8d48-9da354c9d1b7" style="display:block;margin:0 auto" width="1014" height="156" loading="lazy">

<h3 id="heading-removing-items-from-the-stash">Removing Items from the Stash</h3>
<p>You can use <code>git stash clear</code> to clear the stash list. But if you just want to drop a particular entry from the stash list, you can use <code>git stash drop</code> and specify the entry you want to drop by the index number. This doesn’t apply its changes to the working directory.</p>
<pre><code class="language-bash">git stash clear
</code></pre>
<pre><code class="language-bash">git stash drop stash@{0}
# You'd need to use quotes "stash@{0}" if you're writing this in PowerShell
</code></pre>
<h3 id="heading-creating-a-new-branch-from-stash">Creating a New Branch from Stash</h3>
<p>You can also create a new branch from a stash using <code>git stash branch</code>. The syntax is <code>git stash branch &lt;branchname&gt; [&lt;stash&gt;].</code></p>
<pre><code class="language-bash">git stash branch premium-branch stash@{0}
# You'd need to use quotes "stash@{0}" if you're writing this in PowerShell
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/a14db1c1-b0ac-4a81-ae4d-4b4859989489.png" alt="a14db1c1-b0ac-4a81-ae4d-4b4859989489" style="display:block;margin:0 auto" width="1018" height="232" loading="lazy">

<p>If you don’t add the stash index, it will just use the last stash.</p>
<pre><code class="language-bash">git stash branch premium-branch
</code></pre>
<h3 id="heading-showing-the-changes-in-the-stash">Showing the Changes in the Stash</h3>
<p>You can use <code>git stash show</code> to show the changes you’ve made in your stashed changes.</p>
<pre><code class="language-bash">C:\file-path\git_stash_example&gt; git stash show
 text.md | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/9d5a5e83-7c2f-4a2d-a004-f406b5ed1af7.png" alt="9d5a5e83-7c2f-4a2d-a004-f406b5ed1af7" style="display:block;margin:0 auto" width="1008" height="196" loading="lazy">

<h2 id="heading-conclusion">Conclusion</h2>
<p>Git stash is one of those quiet tools that becomes indispensable once your workflow starts to get messy. It allows you to shelve unfinished ideas, switch context without panic, and keep your commits clean. With it, you can safely carry out urgent fixes, and juggle dependent features without muddling up your commit history.</p>
<p>If you enjoyed this article, share it with others. You can also reach me on <a href="https://linkedin.com/in/chidiadi-anyanwu">LinkedIn</a> or <a href="https://linkedin.com/in/chidiadi-anyanwu">X.</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Lazygit to Improve Your Git Workflow ]]>
                </title>
                <description>
                    <![CDATA[ Lazygit is an open-source command line terminal UI for Git commands that I’ve used for the last couple of years, and it’s become my new best friend. Basically, the Lazygit tool is a wrapper for the Git command line that replaces it with a UI. Instead... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-lazygit-to-improve-your-git-workflow/</link>
                <guid isPermaLink="false">67f7cc7aaf72aa46d378eaa0</guid>
                
                    <category>
                        <![CDATA[ Lazygit-tutorial ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Lazygit ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rajdeep Singh ]]>
                </dc:creator>
                <pubDate>Thu, 10 Apr 2025 13:49:46 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744293114488/5332db88-bff6-4aef-91eb-3423f3b95e1a.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><a target="_blank" href="https://github.com/jesseduffield/lazygit">Lazygit</a> is an open-source command line terminal UI for Git commands that I’ve used for the last couple of years, and it’s become my new best friend.</p>
<p>Basically, the Lazygit tool is a wrapper for the Git command line that replaces it with a UI. Instead of typing out Git commands again and again in your terminal, you can use keyboard shortcuts to commit, push, pull, create, edit, and delete branches in your project.</p>
<p>In simple terms, Lazygit helps you increase your productivity while working with Git.</p>
<p>In this article, we'll walk through the essential features of Lazygit, and I’ll show you how it works.</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-how-to-install-lazygit">How to Install Lazygit</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-use-lazygit">How to Use Lazygit</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-shortcuts-and-key-mappings-in-lazygit">Shortcuts and Key Mappings in Lazygit</a></p>
</li>
<li><p><a class="post-section-overview" href="#other-keybindings-in-lazygit">Other Keybindings in Lazygit</a></p>
</li>
<li><p><a class="post-section-overview" href="#conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-how-to-install-lazygit">How to Install Lazygit</h2>
<p>Before we start, you’ll need to make sure it’s installed on your machine. You can install the tool in your system using the following methods (depending on your system):</p>
<h3 id="heading-homebrew">Homebrew</h3>
<p>You can <a target="_blank" href="https://formulae.brew.sh/formula/lazygit#default">install lazygit</a> in macOS using Homebrew like this:</p>
<pre><code class="lang-bash">brew install lazygit
</code></pre>
<h3 id="heading-scoop-windows">Scoop (Windows)</h3>
<p>You can <a target="_blank" href="https://scoop.sh/#/apps?q=lazygit">install lazygit</a> in Windows using Scoop like this:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Add the extras bucket</span>
scoop bucket add extras

<span class="hljs-comment"># Install lazygit</span>
scoop install lazygit
</code></pre>
<h3 id="heading-arch-linux">Arch Linux</h3>
<p>You can <a target="_blank" href="https://aur.archlinux.org/packages/lazygit-git">install lazygit</a> in Arch using Pacman like this:</p>
<pre><code class="lang-bash">sudo pacman -S lazygit
</code></pre>
<h3 id="heading-ubuntu-and-debian">Ubuntu and Debian</h3>
<p>You can install lazygit in Ubuntu and Debian using the following command:</p>
<pre><code class="lang-bash">LAZYGIT_VERSION=$(curl -s <span class="hljs-string">"https://api.github.com/repos/jesseduffield/lazygit/releases/latest"</span> | \grep -Po <span class="hljs-string">'"tag_name": *"v\K[^"]*'</span>)
curl -Lo lazygit.tar.gz <span class="hljs-string">"https://github.com/jesseduffield/lazygit/releases/download/v<span class="hljs-variable">${LAZYGIT_VERSION}</span>/lazygit_<span class="hljs-variable">${LAZYGIT_VERSION}</span>_Linux_x86_64.tar.gz"</span>
tar xf lazygit.tar.gz lazygit
sudo install lazygit -D -t /usr/<span class="hljs-built_in">local</span>/bin/
</code></pre>
<p>Verify the correct installation of lazygit:</p>
<pre><code class="lang-bash">lazygit --version
</code></pre>
<p>The command output looks like this:</p>
<pre><code class="lang-bash">➜  lazygit --version
commit=, build date=, build <span class="hljs-built_in">source</span>=nix, version=0.44.1, os=linux, arch=amd64, git version=2.47.0
</code></pre>
<h3 id="heading-fedora-and-rhel">Fedora and RHEL</h3>
<p>You can install lazygit in Fedora and RHEL using DNF like this:</p>
<pre><code class="lang-bash">sudo dnf copr <span class="hljs-built_in">enable</span> atim/lazygit -y
sudo dnf install lazygit
</code></pre>
<h3 id="heading-nixos">NixOS</h3>
<p>You can <a target="_blank" href="https://search.nixos.org/packages?channel=24.11&amp;from=0&amp;size=50&amp;sort=relevance&amp;type=packages&amp;query=lazygit">install lazygit</a> in NixOS using the following method:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># with nix-shell</span>
nix-shell -p lazygit

<span class="hljs-comment"># with nix-env</span>
nix-env -iA lazygit

<span class="hljs-comment"># with /etc/nixos/configuration.nix</span>
environment.systemPackages = [
  pkgs.lazygit
];
<span class="hljs-comment"># or with enable lazygit flakes</span>
nix run nixpkgs<span class="hljs-comment">#lazygit</span>
</code></pre>
<h2 id="heading-how-to-use-lazygit">How to Use Lazygit</h2>
<p>To use Lazygit, you don’t need any advanced knowledge about Lazygit or the Git CLI. If you are a beginner, that’s okay – I’ll walk you through the process and the basics here.</p>
<p>The main thing to understand is how the key mappings (shortcut keys) work. In this tutorial, I won’t discuss every key mapping, but I’ll teach you about some of the most common Lazygit key mappings which you’ll use on a daily basis. They’ll help you build a solid base for using the tool effectively.</p>
<p>To use Lazygit, first open the terminal you use. For example, I’m using the GNOME distro, so I’ll use the <a target="_blank" href="https://gitlab.gnome.org/chergert/ptyxis">Ptyxis terminal</a>.</p>
<p>Type the <code>lazygit</code> command in your terminal:</p>
<pre><code class="lang-bash">lazygit
</code></pre>
<p>The command output should look like this in your terminal:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743685042853/ab3f10f0-0d13-44d3-a86a-a58676cf30a5.gif" alt="Lazygit cli demo" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<p>The Lazygit UI is divided into six panels, or sections. Each panel serves a specific use case. Let’s explore these panels in more detail. You can see them highlighted in the image below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743687006438/5ca2451e-d4a0-42a7-89b2-0b94fd4ca162.png" alt="Explore the Lazygit panels" class="image--center mx-auto" width="1920" height="1048" loading="lazy"></p>
<h3 id="heading-panels-or-sections-in-lazygit">Panels or Sections in Lazygit</h3>
<p>As I mentioned above, there are six main panels in Lazygit. They are:</p>
<ol>
<li><p>Status</p>
</li>
<li><p>Files</p>
</li>
<li><p>Branches</p>
</li>
<li><p>Commits</p>
</li>
<li><p>Stash</p>
</li>
<li><p>Previews</p>
</li>
</ol>
<p>The most important panels in Lazygit are files, branches, and commits, but we’ll examine each of the six now.</p>
<h4 id="heading-status-panel">Status panel</h4>
<p>The status panel provides an overview of your current repository and the current checked-out branch, including local and remote changes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743759630157/a7ef738b-5353-4941-9eb5-073d3235aaba.png" alt="Status panel in Lazygit" class="image--center mx-auto" width="648" height="98" loading="lazy"></p>
<p>Also, when you click on the status panel text, it opens a new tab or panel where it shows the recently opened repository list.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743760171736/8edb2f41-86ad-4e64-95f2-b1310d8c6f57.png" alt="Recently opened repos" class="image--center mx-auto" width="1920" height="1048" loading="lazy"></p>
<h4 id="heading-files-panel">Files panel</h4>
<p>The Files panel shows lists of the files in your repository that have been modified or changed. You can see files that you’ve deleted or discarded and unstaged.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743760570130/c891940b-4ba2-4fcb-a867-817b74e53618.png" alt="Files panel in Lazygit" class="image--center mx-auto" width="652" height="305" loading="lazy"></p>
<h4 id="heading-branches-panel">Branches panel</h4>
<p>The Branches panel shows lists of local and remote branches which are available in this repository.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743761276628/b34dc945-11c8-482d-8c4d-51783c68bf55.png" alt="Branches panel in lazygit" class="image--center mx-auto" width="649" height="256" loading="lazy"></p>
<h4 id="heading-commits-panel">Commits panel</h4>
<p>The Commits panel shows a list of commits in the current branch, which allows you to view, checkout, or interact with (view/undo/and so on) specific commits.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743761671236/80a7321a-8d16-4add-bc4a-db52d2987836.png" alt="commits panel in lazygit" class="image--center mx-auto" width="649" height="300" loading="lazy"></p>
<h4 id="heading-stashes-panel">Stashes panel</h4>
<p>The Stashes panel helps you manage your stashed changes, allowing you to apply, drop, or view them. Git stash is a location for storing uncommitted changes (modified, staged, or untracked files) in a hidden place, letting you switch branches without committing or discarding them.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743764679570/d7233d92-cfb0-4757-a338-bcc3d9fec2b8.png" alt="Stashes panel in laygit" class="image--center mx-auto" width="650" height="220" loading="lazy"></p>
<h4 id="heading-preview-panel">Preview panel</h4>
<p>The preview panel lets you preview unstaged changes, commits, logs, file content, and so on in Lazygit.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743765844602/7c492361-bbcf-4d2c-8588-b0c3e8704132.png" alt="Preview panel in lazygit" class="image--center mx-auto" width="1920" height="1048" loading="lazy"></p>
<p>To switch between panels, use the left and right arrow keys or the specific keybindings displayed at the top of each panel.</p>
<p>Press <code>1</code> to open the Status panel, <code>2</code> for Files, <code>3</code> for Branches, <code>4</code> for Commits, and <code>5</code> for the Stash panel.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743766590099/91689f4d-eba3-47cf-80a6-e18307c326cd.gif" alt="Navigation between panels in lazygit" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<h2 id="heading-shortcuts-and-key-mappings-in-lazygit"><strong>Shortcuts and Key Mappings in Lazygit</strong></h2>
<p>Lazygit is especially popular because of its shortcuts. You don’t need to write the same Git commands in the terminal over and over. Rather, you just need to use a shortcut.</p>
<p>For example, usually when you commit a file, you’ll first add the file using <code>git add</code> and then commit the file using <code>git commit</code>.</p>
<p>But in Lazygit, you just have to select the file using your mouse or the up and down keys and press space to commit the file.</p>
<p>In Lazygit, everything works around the shortcut commands, and you use shortcuts to perform common Git operations. Here are a few essential commands we’ll go over in this tutorial:</p>
<ul>
<li><p><code>a</code> – Stage or unstage all the files available in the Files panel.</p>
</li>
<li><p><code>space</code> (file panel) – Stage or unstage a single file in the Files panel.</p>
</li>
<li><p><code>c</code> – Commit staged changes by opening a commit message editor.</p>
</li>
<li><p><code>p</code> – Push commits to the remote repository.</p>
</li>
<li><p><code>P</code> – Pull changes from the remote repository.</p>
</li>
<li><p><code>z</code> – Undo the commit.</p>
</li>
<li><p><code>s</code> – Stash changes, allowing you to switch branches or perform other operations.</p>
</li>
<li><p><code>S</code> – View and apply stashed changes.</p>
</li>
<li><p><code>n</code> – Create a new branch.</p>
</li>
<li><p><code>d</code> – Delete your branch.</p>
</li>
<li><p><code>y</code> – Copy to clipboard.</p>
</li>
<li><p><code>M</code> – Merge branch.</p>
</li>
<li><p><code>space</code> (branches panel) – Check out the selected target branch.</p>
</li>
<li><p><code>e</code> – Edit or open the file in an external editor.</p>
</li>
<li><p><code>q</code> – Quit Lazygit and return to the terminal.</p>
</li>
<li><p><code>d</code> – Discard any changes in the file.</p>
</li>
<li><p><code>?</code> – Open the keybinding menu.</p>
</li>
</ul>
<p>Now let’s go over these shortcuts so you can understand how they work and see them in action.</p>
<h3 id="heading-how-to-commit-a-file">How to Commit a File</h3>
<p>To commit a file in Lazygit, first select the file you need by pressing the <code>space</code> key or the <code>a</code> key or double-clicking on the file. Then press <code>c</code>, and a new panel should open. There, you can add a message and hit enter to commit the file.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743770682782/cbd83578-a286-482f-aeaa-31a9715a5483.gif" alt="cbd83578-a286-482f-aeaa-31a9715a5483" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<h3 id="heading-how-to-pull-and-push-code">How to Pull and Push Code</h3>
<p>To pull remote code from the Git server (Github, GitLab, Gitea, and so on), you can press <code>p</code> (lower case p):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743774642242/decec44c-7622-432a-9da5-81b14b60ef8a.gif" alt="decec44c-7622-432a-9da5-81b14b60ef8a" class="image--center mx-auto" width="680" height="371" loading="lazy"></p>
<p>To push local code into a Git server, you can press <code>P</code> (upper case P):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743842516002/37647a76-afe5-4d4b-acfc-fc85f1010749.gif" alt="37647a76-afe5-4d4b-acfc-fc85f1010749" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<h3 id="heading-how-to-create-and-delete-a-branch">How to Create and Delete a Branch</h3>
<p>To create a new branch in Lazygit, press <code>n</code>. A new panel will open where you’ll add the name of the branch and hit Enter.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743843881624/6c4db14e-0102-4333-be56-5d3796ab1c50.gif" alt="Create a new branch in lazygit" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<p>To delete a branch, press <code>d</code> and then specify whether you want to delete the branch in a local or remote repository. In the following example, I’m deleting a local branch.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743847541934/34e378b6-03ac-4e6d-93d0-35aaeda39e57.gif" alt="34e378b6-03ac-4e6d-93d0-35aaeda39e57" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<blockquote>
<p>Note: To delete and create a new branch in Lazygit, first select the branch panel and then press the corresponding shortcut key for deleting a branch. Press the d key to delete, and then to create a branch press the n key. Otherwise, it won’t work.</p>
</blockquote>
<h3 id="heading-how-to-undo-a-commit">How to Undo a Commit</h3>
<p>To undo the last commit in Lazygit, just press <code>z</code>. A new panel will open, showing the details of the commit you are undoing. Then, hit Enter.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743852917448/a3f2cab7-2806-48e4-a749-90f821b537dc.gif" alt="Undo commit in lazygit" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<h3 id="heading-how-to-merge-a-branch">How to Merge a Branch</h3>
<p>To merge a branch, press <code>M</code> (capital M). To open the merge options, choose the merge type, then hit Enter.</p>
<h4 id="heading-merge-type">Merge type:</h4>
<ul>
<li><p><strong>Merge:</strong> A standard merge, preserving the branch history.</p>
</li>
<li><p><strong>Squash merge:</strong> Combines all commits from the branch into a single commit on the target branch.</p>
</li>
<li><p><strong>Squash merge and leave uncommitted</strong>: Same as squash merge, but leaves the changes uncommitted.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743921595283/e46e0c89-b69a-4462-acd3-295045c99dfd.gif" alt="Merge branch in lazygit" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<h3 id="heading-how-to-resolve-merge-conflicts">How to Resolve Merge Conflicts</h3>
<p>To resolve merge conflicts in Lazygit, first merge a branch by pressing <code>M</code>, then choose the merge type (which I describe in the subsection on how to merge a branch) and hit Enter.</p>
<p>If any merge conflicts occur, the conflicting file(s) appear in the files panel. Press Enter to view the merge conflicts in the preview panel and navigate between conflicts using the up and down keys. Select the correct merge conflicts, press the space key, and your merge issue will be resolved.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743921640247/e5b7f971-f027-47df-be4c-a90b356e24f8.gif" alt="resolve merge conflicts in lazygit" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<h3 id="heading-how-to-discard-changes">How to Discard Changes</h3>
<p>To discard or drop any changes in a file or commit, press <code>d</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743774406564/bc5b91fb-2d33-41d0-95b9-667478c4c8db.gif" alt="bc5b91fb-2d33-41d0-95b9-667478c4c8db" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<h3 id="heading-how-to-copy">How to Copy</h3>
<p>To copy a file name, path, commit hash, message, URL, author, or any other details, first select the commit or file, then press <code>y</code> to copy the information.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743856793802/e23d9e5c-b0b4-40a0-8124-f94669b377c0.gif" alt="e23d9e5c-b0b4-40a0-8124-f94669b377c0" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<h2 id="heading-other-keybindings-in-lazygit">Other Keybindings in Lazygit</h2>
<p>There are other keybindings in Lazygit which I did not discuss in this article. To learn about every keybinding, you can check out the keybindings menu. Open the keybindings menu and press the <code>?</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743843262905/a4aba097-999b-4ff8-bd00-661181d96aad.gif" alt="a4aba097-999b-4ff8-bd00-661181d96aad" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<p>When you open the keybindings help menu, it changes according to the panel you’re in.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743915037200/9339b7b1-b2a4-45e5-8a51-5be0a9f2a319.gif" alt="9339b7b1-b2a4-45e5-8a51-5be0a9f2a319" class="image--center mx-auto" width="1000" height="545" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Lazygit helps you become more productive when working with Git or Git commands. As a beginner, starting with Lazygit can be somewhat challenging because of its key mappings, but once you get the hang of them, they’re pretty easy to remember and use.</p>
<p>If you are a first-time Lazygit user, my suggestion is to avoid using Lazygit on a working repository. Instead, create a demo repository and try it out/practice.</p>
<p>To learn more about <a target="_blank" href="https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Keybindings_en.md">LazyGit keybindings or shortcuts</a>, you can refer to the Lazygit documentation. You can also check out the following YouTube tutorials for beginners:</p>
<ul>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=A6F_8ajlrYQ">LazyGIt - A Faster, Easier Way to Use Git on Terminal &amp; NeoVim</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=Ihg37znaiBo">Lazygit - The Best Way To Use Git On The Terminal &amp; Neovim</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=06lEP59XAgM">My new favorite way to use Git</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=dSWJKcEiAaM">LazyGit: Effortless Git in Your Terminal!</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Git through Gamification – A Visual Guide to Key Version Control Concepts ]]>
                </title>
                <description>
                    <![CDATA[ Git has many concepts and commands that you’ll need to understand before you feel confident using it. Some of these concepts may sound trivial, especially to someone who has worked with Git before. But like most Git and coding concepts, even the “sim... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-git-through-gamification/</link>
                <guid isPermaLink="false">67c1cfa78df3594301bc3fef</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ gamification  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ coding ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learn coding ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ visualization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jacob Stopak ]]>
                </dc:creator>
                <pubDate>Sun, 02 Mar 2025 06:00:00 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740686401633/ffd9ac3c-668a-47bf-b2ba-f7cee14e74a8.webp" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Git has many concepts and commands that you’ll need to understand before you feel confident using it. Some of these concepts may sound trivial, especially to someone who has worked with Git before. But like most Git and coding concepts, even the “simple” ones tend to be abstract.</p>
<p>The three concepts that stand out to me as the most fundamental for being able to effectively work with Git at a basic level are:</p>
<ol>
<li><p>The <strong>working directory</strong></p>
</li>
<li><p>The <strong>staging area</strong></p>
</li>
<li><p>The <strong>commit history</strong></p>
</li>
</ol>
<p>In this article, we’ll take a new approach to representing these three concepts: by <em>visualizing them in an immersive, 3D game world!</em></p>
<p>I’ll provide a tangible, visual representation of these key Git concepts which are almost always described in an abstract and confusing way. I hope that this will make them much more intuitive for you to grasp.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-visualize-your-working-directory">Visualize your Working Directory</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-demystify-your-staging-area">Demystify your Staging Area</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-literally-walk-through-your-commit-history">Literally Walk through your Commit History</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-try-it-yourself">Try it Yourself</a></p>
</li>
</ol>
<h2 id="heading-visualize-your-working-directory">Visualize your Working Directory</h2>
<p>What does your brain picture when you think of the “working directory”? I assume it’s something like a folder structure starting at the project root, containing the code files and subfolders that make up the project.</p>
<p>While that is a fair description of the working directory, it is a bit hard to imagine and misses the segmentation that Git applies to your project. Although the current state of your entire project, folder structure, and code files do reside in the working directory, Git doesn’t really need to do much about that unless certain <em>changes</em> are detected in those files.</p>
<p>Git detects and reports changes to the working directory with the <a target="_blank" href="https://initialcommit.com/blog/git-status">Git status command</a>, which shows output like this:</p>
<pre><code class="lang-bash">Jack@RAPTOR ~/my-project (main)&gt; git status
On branch main
Your branch is up to date with <span class="hljs-string">'origin/main'</span>.

Changes not staged <span class="hljs-keyword">for</span> commit:
  (use <span class="hljs-string">"git add &lt;file&gt;..."</span> to update what will be committed)
  (use <span class="hljs-string">"git restore &lt;file&gt;..."</span> to discard changes <span class="hljs-keyword">in</span> working directory)
        modified:   main.py
        modified:   settings.py

Untracked files:
  (use <span class="hljs-string">"git add &lt;file&gt;..."</span> to include <span class="hljs-keyword">in</span> what will be committed)
        one.py
        three.py
        two.py

no changes added to commit (use <span class="hljs-string">"git add"</span> and/or <span class="hljs-string">"git commit -a"</span>)
</code></pre>
<p>The two relevant sections here are:</p>
<ol>
<li><p><strong>Changes not staged for commit:</strong> Lists existing files tracked by Git which currently contain code changes. In the example above, we see two “modified files”: <code>main.py</code> and <code>settings.py</code>.</p>
</li>
<li><p><strong>Untracked files:</strong> Lists new files in your project that Git doesn’t know about yet. In the example above, we see three new, untracked files: <code>one.py</code>, <code>two.py</code>, and <code>three.py</code>.</p>
</li>
</ol>
<p>When it comes to understanding Git, thinking of the working directory as the changes Git sees in these two sections – <strong>Untracked files</strong> and <strong>Modified files</strong> – is quite helpful.</p>
<p>But the <code>git status</code> command reports these details in the terminal in a purely text-based way, which doesn’t do newer Git users any favors when it comes to wrapping their heads around Git.</p>
<p>Some Git GUI’s do a better job with this (they do provide a safer point-and-click interface, after all), but in my experience, none of them make things <em>obvious at a glance</em>.</p>
<p>Instead, imagine that as a new Git user, you saw this:</p>
<p><a target="_blank" href="https://devlands.com"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740587730262/375bef09-b8b8-43e3-a18c-5b1e589b6097.png" alt="Image captured from Devlands, the gamified Git interface and tutorial, showing the untracked files and modified files sections of the working directory wall" class="image--center mx-auto" width="600" height="400" loading="lazy"></a></p>
<p>A nice big wall with clearly delineated sections for <strong>Untracked files</strong> and <strong>Modified files</strong>. Files corresponding to each section are represented as blocks on the wall within that section, clearly labelled with their filename.</p>
<p>More specifically, the blocks representing files <code>one.py</code>, <code>two.py</code>, and <code>three.py</code> are all sitting neatly in the <strong>Untracked files</strong> section, and the blocks representing the files <code>main.py</code> and <code>settings.py</code> are in the <strong>Modified files</strong> section.</p>
<p>This makes it abundantly clear to even a total novice that Git is interpreting these files differently and categorizing them in a logical way. It takes the abstract Git concept of the “working directory” and transforms it into a form that almost anyone can wrap their heads around at a glance.</p>
<p>But something is missing here. Let’s say you run the command <code>git add one.py</code>. This stages the untracked file <code>one.py</code> to be included in the next commit. What happens to the block labelled <code>one.py</code> on the wall?</p>
<h2 id="heading-demystify-your-staging-area">Demystify your Staging Area</h2>
<p>To answer that, let’s move on to the mysterious <a target="_blank" href="https://initialcommit.com/blog/git-add">Git “staging area”</a>. But first, where exactly IS the staging area?</p>
<p>Well, technically any staged file changes are still just sitting in the working directory, which makes things a bit confusing.</p>
<p>Here is how Git reports this in the terminal:</p>
<pre><code class="lang-bash">Jack@RAPTOR ~/D/git-worlds (main)&gt; git status
On branch main
Your branch is up to date with <span class="hljs-string">'origin/main'</span>.

Changes to be committed:
  (use <span class="hljs-string">"git restore --staged &lt;file&gt;..."</span> to unstage)
        new file:   one.py
</code></pre>
<p>As you can see from Git’s output, it now includes the section <strong>Changes to be committed</strong>, which includes the file <code>one.py</code> that was staged with the <code>git add</code> command.</p>
<p>But this is still a bit unclear. Are the staged file changes in <code>one.py</code> still a part of the working directory? Or does Git store them elsewhere?</p>
<p>Well, the answer is… BOTH:</p>
<p><a target="_blank" href="https://devlands.com"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740592262850/dc65c06d-0ec6-4de6-bbe9-53307d523e68.png" alt="Image captured from Devlands, the gamified Git interface and tutorial, adding the staged files section onto the working directory wall" class="image--center mx-auto" width="600" height="400" loading="lazy"></a></p>
<p>Here you can see that we zoomed out a bit from the previous image, to reveal a third section of the wall labeled <strong>Staged files</strong>.</p>
<p>Since we ran the command <code>git add one.py</code>, you can see that the corresponding block representing the <code>one.py</code> file moved from the Untracked files column to the Staged files column.</p>
<p>This conveys quite clearly that a file sitting in the staging area is still a part of the working directory (because it is a part of the overall wall), while also being segmented into its own designated space.</p>
<p>From a technical perspective, Git’s staging area is just a file named <strong>index</strong> which lives in the <code>.git/</code> folder. Git builds up the code changes specified by the <code>git add</code> command in this file, which is used as the source for those changes the next time the <code>git commit</code> command is run.</p>
<p>But from a workflow perspective, representing the staging area as a section on the “working directory wall” as in the image above makes things more intuitive to understand.</p>
<p>Next, let’s explore how we might visualize things once the staged changes are turned into a new Git commit and become a part of the active branch.</p>
<h2 id="heading-literally-walk-through-your-commit-history">Literally Walk through your Commit History</h2>
<p>What does your mind’s eye see when you think of Git’s “commit history”?</p>
<p>Well, the prettiest way Git does it in the terminal is by using the <a target="_blank" href="https://initialcommit.com/blog/git-log">Git log command</a>, such as <code>git log --graph --all</code>, which provides output like:</p>
<pre><code class="lang-bash">* commit 88085cff3e2d7657f26eb6479b308526df7d2bba (HEAD -&gt; dev, origin/dev)
| Author: Jacob Stopak &lt;jacob@initialcommit.io&gt;
| Date:   Tue Apr 23 20:31:24 2024 -0700
|
|     Fix <span class="hljs-built_in">command</span> as title clip, ellipses and arrow length <span class="hljs-keyword">in</span> rebase subcommand
|
|     Signed-off-by: Jacob Stopak &lt;jacob@initialcommit.io&gt;
|
*   commit e264605ea26a808c34d4dc2fbc6dad65a8e28c5f
|\  Merge: cb3fa5f b8c071c
| | Author: Jacob Stopak &lt;jacob@initialcommit.io&gt;
| | Date:   Wed Mar 20 19:51:06 2024 -0700
| |
| |     Merge branch <span class="hljs-string">'main'</span> into dev
| |
* | commit cb3fa5f3bdbdcff3d9a8c844cda99d46bf64e337
| | Author: Jacob Stopak &lt;jacob@initialcommit.io&gt;
| | Date:   Sat Mar 9 22:00:49 2024 -0800
| |
| |     Add --staged flag to git restore subcommand
| |
| |     Signed-off-by: Jacob Stopak &lt;jacob@initialcommit.io&gt;
| |
| * commit b8c071cb9a1653748525aa01c2b6bafe06ed9100
|/  Author: Jacob Stopak &lt;jacob@initialcommit.io&gt;
|   Date:   Wed Mar 20 19:50:53 2024 -0700
|
|       Correct license specified <span class="hljs-keyword">in</span> pyproject.toml from MIT to GNU GPLv2
|
|       Signed-off-by: Jacob Stopak &lt;jacob@initialcommit.io&gt;
|
* commit 32a3a3fca583f6c68225b974716e74b557a1a094
| Author: Jacob Stopak &lt;49353917+initialcommit-io@users.noreply.github.com&gt;
| Date:   Tue Aug 22 11:31:38 2023 -0700
|
|     Update README.md
</code></pre>
<p>Unfortunately, this is not so pretty at all. This long, garbled list of commit IDs, names, dates, and commit messages is definitely not something most folks would consider user-friendly.</p>
<p>The <code>--graph</code> option supplied above does show the commit relationships by drawing little lines connecting each commit in the terminal, but the purely text-based nature of this is just not intuitive to most people at a glance.</p>
<p>Now consider the following gamified representation of Git’s commit history:</p>
<p><a target="_blank" href="https://devlands.com"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740594184258/8d5a33c8-ad60-4496-a50d-a27fc6b8e752.png" alt="Image captured from Devlands, the gamified Git interface and tutorial, showing the project's commit history and branches" class="image--center mx-auto" width="600" height="400" loading="lazy"></a></p>
<p>Now we’re talkin’! In this image, each Git commit is represented by a white block with a shortened 6-character commit ID.</p>
<p>Each white commit block points back to its parent commit with an arrow, forming very clear chains of commits that make up Git branches.</p>
<p>You might have noticed that some of the white commit blocks have colored blocks sitting on top of them. The green blocks are <a target="_blank" href="https://initialcommit.com/blog/git-branches">branch names</a>, the yellow blocks are <a target="_blank" href="https://initialcommit.com/blog/git-tag">Git tags</a>, the blue block is <a target="_blank" href="https://initialcommit.com/blog/what-is-git-head">Git’s HEAD pointer</a>, and the red blocks are remote-tracking branches. These are collectively referred to as <a target="_blank" href="https://initialcommit.com/blog/what-is-git-head#git-refs-and-heads">Git refs</a>.</p>
<p>Besides being able to easily distinguish between them, representing ref types as different colored blocks clarifies another often-confusing Git concept. In Git, branches (along with other refs types) are just “pointers” to a specific commit. It is tempting to think of a branch as a series of connected commits that share a history – and conceptually this is correct – but in Git, a branch is really just a glorified label pointing to a specific commit.</p>
<p>In this gamified world, you can <em>literally walk through your commit history</em> to see, interact with, and examine the code changes in any commit.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this article, we explored how Git’s fundamental concepts - the working directory, staging area, and commit history - can be difficult to grasp due to their abstract nature.</p>
<p>To make these concepts more accessible, we introduced a gamified, visual approach that transforms them into something tangible: an immersive game world where files and commits are represented as interactive blocks.</p>
<p>By presenting Git this way, beginner coders, students, and developers of all experience levels can intuitively learn Git concepts and commands, and confidently apply them in professional projects.</p>
<h2 id="heading-try-it-yourself">Try it Yourself</h2>
<p>The images in this post were captured in <a target="_blank" href="https://devlands.com">Devlands</a>, the first and only <em>gamified Git interface and tutorial</em>, which I’m building in Python.</p>
<p>In Devlands, not only can you walk through your codebase… You can also learn Git concepts and commands with a character-guided tutorial, simulate and run Git commands directly in the game, see their results applied in the game world in real time, and use AI to explain code you don’t understand.</p>
<p>If you or someone you know is a visual learner, beginner coder, or newer Git user, <a target="_blank" href="https://devlands.com">consider checking it out!</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Improve and Restructure Your Codebase with AI Tools & Version Control ]]>
                </title>
                <description>
                    <![CDATA[ A codebase can become messy and hard to manage over time. This happens because of quick fixes, outdated features, or just not enough time to clean things up. When code becomes difficult to read or change, it slows down progress and can even cause bug... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/improve-and-restructure-codebase-with-ai-tools/</link>
                <guid isPermaLink="false">6720f7fb2e452955f9433899</guid>
                
                    <category>
                        <![CDATA[ best practices ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Tips ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ optimization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ improve performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Pull Requests ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwadamisi Samuel ]]>
                </dc:creator>
                <pubDate>Tue, 29 Oct 2024 14:58:03 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730194934749/feb606d0-bbbd-43ae-a58c-5932d8c2d76c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A codebase can become messy and hard to manage over time. This happens because of quick fixes, outdated features, or just not enough time to clean things up.</p>
<p>When code becomes difficult to read or change, it slows down progress and can even cause bugs. To keep a codebase healthy and easy to work with, you’ll need to take care of it.</p>
<p>Improving and organizing old code can feel like a big task, but there are tools and methods that can make it easier. This guide will show how to refresh your codebase step by step which will make it simpler to work with and less likely to cause issues.</p>
<h3 id="heading-table-of-contents">Table of Contents</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-how-to-review-your-code-effectively">How to Review Your Code Effectively</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-identify-technical-debt-and-problem-areas-in-code">How to Identify Technical Debt and Problem Areas in Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-measure-code-quality-with-code-analysis-tools">How to Measure Code Quality with Code Analysis Tools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-ai-tools-to-help-you-improve-your-code">AI Tools to Help You Improve Your Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-version-control-best-practices-for-code-changes">Version Control Best Practices for Code Changes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-how-to-review-your-code-effectively">How to Review Your Code Effectively</h2>
<p>Code reviews are essential for catching issues early, improving readability, and ensuring long-term maintainability. Reviewing your own code or someone else’s involves more than just scanning for errors – you’ll also want to make sure each part is clear, efficient, and follows good practices.</p>
<p>Here’s a step-by-step approach to help you review code effectively, with practical strategies, tools, and what to look for during the process.</p>
<h3 id="heading-strategies-for-effective-code-review">Strategies for Effective Code Review</h3>
<ol>
<li><p><strong>Break Down the Review Process:</strong> Reviewing code all at once can be overwhelming, especially in large projects. Focus on small sections of the codebase at a time, such as individual functions or modules. This approach helps you examine each part closely and avoids missing issues that could be overlooked in a quick scan.</p>
</li>
<li><p><strong>Review for Clarity and Simplicity:</strong> Good code should be easy to read and understand. When reading through the code:</p>
<ul>
<li><p><strong>Variable and Function Names:</strong> Are variable names descriptive enough to convey their purpose? Long, unclear names make code harder to follow.</p>
</li>
<li><p><strong>Function Length:</strong> Keep functions short and focused on one task. Long functions are harder to debug and maintain.</p>
</li>
<li><p><strong>Comments and Documentation:</strong> Comments should explain <em>why</em> something is done rather than <em>what</em> is happening, which should be clear from the code itself. For instance, avoid excessive commenting on trivial lines and focus on complex logic or business rules.</p>
</li>
</ul>
</li>
<li><p><strong>Check for Code Reusability and Modularity:</strong> Look for repeated code or functions performing multiple tasks. By modularizing code, you make it easier to test, update, and reuse. In a review, look for:</p>
<ul>
<li><p><strong>Duplicate Code:</strong> Repeated code can often be refactored into a function.</p>
</li>
<li><p><strong>Single Responsibility:</strong> Each function should handle one task, making it easier to maintain and update.</p>
</li>
</ul>
</li>
<li><p><strong>Examine Error Handling and Edge Cases:</strong> Robust code should handle unexpected inputs or errors gracefully. During a review, think about potential edge cases that could break the code:</p>
<ul>
<li><p><strong>Null or Undefined Values:</strong> Does the code check for undefined values where needed?</p>
</li>
<li><p><strong>Out-of-Range Errors:</strong> Ensure array indexes and calculations won’t produce errors with edge cases.</p>
</li>
<li><p><strong>Error Messages:</strong> Make sure error handling is meaningful, with clear error messages where applicable.</p>
</li>
</ul>
</li>
<li><p><strong>Look for Performance Issues:</strong> Performance may not always be critical, but it’s good to check for potential bottlenecks. Look for:</p>
<ul>
<li><p><strong>Loop Optimization:</strong> Avoid deeply nested loops or repeated work inside loops.</p>
</li>
<li><p><strong>Database Queries:</strong> Minimize unnecessary database calls.</p>
</li>
<li><p><strong>Heavy Computation in the Main Thread:</strong> Move any heavy processing outside the main application thread if possible.</p>
</li>
</ul>
</li>
<li><p><strong>Ensure Consistency with Coding Standards:</strong> Following a consistent coding style improves readability across the team. Many teams use linters or style guides to enforce these standards. Look for:</p>
<ul>
<li><p><strong>Code Format:</strong> Consistent indentation, spacing, and use of braces.</p>
</li>
<li><p><strong>Naming Conventions:</strong> Follow agreed naming conventions (camelCase, snake_case, and so on) consistently.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-tools-to-assist-with-code-reviews">Tools to Assist with Code Reviews</h3>
<p>There are a number of tools out there that can help streamline your code reviews, whether you’re checking your own code or collaborating with others:</p>
<h4 id="heading-1-linters-like-eslint-and-pylint"><strong>1. Linters (like ESLint and Pylint)</strong></h4>
<p>Linters check for syntax errors, code smells, and style guide violations. They are especially useful for catching minor issues, like inconsistent formatting or unused variables. We will discuss ESLint more in an upcoming section.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Example: Run ESLint on a JavaScript project</span>
npx eslint src/
</code></pre>
<h4 id="heading-2-static-analysis-tools-like-sonarqube"><strong>2. Static Analysis Tools (like SonarQube)</strong></h4>
<p>These tools analyze code for deeper issues like security vulnerabilities, code duplication, and complex functions that might need refactoring.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Configuring SonarQube to scan a project</span>
sonar.projectKey=my_project
sonar.sources=src
sonar.host.url=http://localhost:9000
sonar.login=my_token
</code></pre>
<h4 id="heading-3-automated-testing-tools"><strong>3. Automated Testing Tools</strong></h4>
<p>Running tests can verify that code changes don’t introduce new bugs. Use testing frameworks like Jest for JavaScript, PyTest for Python, or JUnit for Java to confirm your code behaves as expected.</p>
<h3 id="heading-example-of-refactoring-during-code-review">Example of Refactoring During Code Review</h3>
<p>Let’s say you encounter a long function with multiple responsibilities. The goal is to split it into smaller, focused functions. Here’s how you can do that:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Original: A single function that handles everything</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processOrder</span>(<span class="hljs-params">order</span>) </span>{
    <span class="hljs-comment">// Calculate total price</span>
    <span class="hljs-keyword">let</span> total = <span class="hljs-number">0</span>;
    order.items.forEach(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> {
        total += item.price * item.quantity;
    });

    <span class="hljs-comment">// Apply discount</span>
    <span class="hljs-keyword">if</span> (order.discountCode) {
        total = total * <span class="hljs-number">0.9</span>; <span class="hljs-comment">// 10% discount</span>
    }

    <span class="hljs-comment">// Send order confirmation email</span>
    sendEmail(order.customerEmail, <span class="hljs-string">'Order Confirmation'</span>, <span class="hljs-string">'Your order total is '</span> + total);
}

<span class="hljs-comment">// Improved: Break into smaller functions for readability and reusability</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateTotal</span>(<span class="hljs-params">order</span>) </span>{
    <span class="hljs-keyword">return</span> order.items.reduce(<span class="hljs-function">(<span class="hljs-params">sum, item</span>) =&gt;</span> sum + item.price * item.quantity, <span class="hljs-number">0</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">applyDiscount</span>(<span class="hljs-params">total, discountCode</span>) </span>{
    <span class="hljs-keyword">return</span> discountCode ? total * <span class="hljs-number">0.9</span> : total;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendConfirmationEmail</span>(<span class="hljs-params">email, total</span>) </span>{
    sendEmail(email, <span class="hljs-string">'Order Confirmation'</span>, <span class="hljs-string">'Your order total is '</span> + total);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processOrder</span>(<span class="hljs-params">order</span>) </span>{
    <span class="hljs-keyword">let</span> total = calculateTotal(order);
    total = applyDiscount(total, order.discountCode);
    sendConfirmationEmail(order.customerEmail, total);
}
</code></pre>
<p>Breaking down the process into smaller functions makes the code cleaner, more readable, and easier to test. Each function now has a single responsibility, which helps reduce bugs and makes future updates simpler.</p>
<h2 id="heading-how-to-identify-technical-debt-and-problem-areas-in-code">How to Identify Technical Debt and Problem Areas in Code</h2>
<p>Technical debt refers to the accumulation of issues within a codebase that arise when development shortcuts are taken, often to meet tight deadlines or speed up releases. While these shortcuts may enable quicker progress initially, they lead to complications down the line.</p>
<p>Technical debt requires proactive management. If you leave it unchecked, it can reduce productivity, create bugs, and slow down development.</p>
<p>Think of technical debt like financial debt: taking on debt can be helpful in the short term, but failing to address it or pay it down will lead to greater challenges.</p>
<p>Common causes of technical debt include:</p>
<ul>
<li><p><strong>Rushed development cycles:</strong> When teams prioritize quick delivery over thorough design and testing, they may produce incomplete or hastily written code.</p>
</li>
<li><p><strong>Lack of planning for future changes:</strong> Sometimes, code is written without accounting for scalability, leading to issues as the project grows.</p>
</li>
<li><p><strong>Insufficient documentation or testing:</strong> Without proper documentation and test coverage, codebases become difficult to understand and validate over time.</p>
</li>
<li><p><strong>Outdated frameworks and dependencies:</strong> When frameworks or libraries aren’t updated, they can become incompatible with newer components or security standards, introducing risk and hindering future updates.</p>
</li>
</ul>
<h3 id="heading-types-of-technical-debt">Types of Technical Debt</h3>
<p>Technical debt manifests in different ways. Here are some common examples:</p>
<p><strong>1. Code Duplication:</strong></p>
<p>Repeated code across multiple places within a project can lead to inconsistencies, as fixing an issue or updating a feature in one area may not carry over to others. Refactoring duplicate code into reusable functions or components is an effective way to reduce this debt.</p>
<p><strong>Example:</strong> In a web application, you might find similar code for user authentication scattered across different modules. Instead, centralizing this logic into a single authentication module ensures consistent updates.</p>
<p><strong>2. Outdated Dependencies and Frameworks:</strong></p>
<p>Using old libraries or frameworks can slow down development and introduce security vulnerabilities. Over time, dependencies may lose support or become incompatible with new features, making them costly to maintain.</p>
<p><strong>Solution:</strong> Regularly update libraries and frameworks, and monitor for deprecations or vulnerabilities. This can be streamlined by using dependency managers, which help check for updates and security patches.</p>
<p><strong>3. Complex, Long Functions with Multiple Responsibilities:</strong></p>
<p>Large, complex functions that handle multiple tasks are difficult to understand, test, and modify. Known as “God functions,” these make debugging cumbersome and increase the risk of introducing new bugs.</p>
<p><strong>Solution:</strong> Follow the <strong>Single Responsibility Principle (SRP)</strong>. This means that each function or method should accomplish one task. Breaking down large functions into smaller, focused units makes the code easier to read and test.</p>
<p><strong>Example:</strong> Instead of having a single <code>processUserRequest</code> function that handles authentication, logging, and database queries, split it into three functions: <code>authenticateUser</code>, <code>logRequest</code>, and <code>queryDatabase</code>.</p>
<p><strong>4. Insufficient Error Handling:</strong></p>
<p>Code that lacks proper error handling can lead to bugs and unexpected behavior, especially in larger systems. Without clear error messages, diagnosing and fixing issues can be challenging.</p>
<p><strong>Solution:</strong> Include comprehensive error handling and ensure that meaningful error messages are displayed. Log errors in a way that helps developers track and diagnose issues.</p>
<p><strong>5. Hardcoded Values:</strong></p>
<p>Hardcoding values directly into code makes it difficult to adjust settings without modifying the source code. For example, using fixed URLs or credentials directly in the codebase can create security risks and maintenance headaches.</p>
<p><strong>Solution:</strong> Use configuration files or environment variables to store values that might change. This improves security and allows for easy updates.</p>
<p><strong>6. Lack of Documentation and Testing:</strong></p>
<p>Documentation and testing are often neglected when time is short. But without proper documentation and test coverage, the code becomes challenging to understand and validate, slowing down development and increasing the risk of bugs.</p>
<p><strong>Solution:</strong> Implement test-driven development (TDD) or include time in the development cycle for creating documentation and writing tests. Aim for at least basic test coverage for critical paths and functions.</p>
<h3 id="heading-how-to-identify-and-manage-technical-debt">How to Identify and Manage Technical Debt</h3>
<p>Identifying technical debt is crucial if you want to address and improve it. Here are some strategies you can follow:</p>
<ol>
<li><p><strong>Code Reviews:</strong> Regular peer reviews help uncover areas of potential debt. In reviews, team members can flag complex code, lack of tests, or unclear logic, helping address these issues early.</p>
</li>
<li><p><strong>Automated Static Code Analysis:</strong> Tools like SonarQube, Code Climate, and ESLint (for JavaScript) analyze codebases for code smells, vulnerabilities, and complexity. They’re effective for spotting issues like duplicate code, long functions, and outdated dependencies.</p>
</li>
<li><p><strong>Regular Refactoring Sessions:</strong> Scheduling dedicated time for refactoring allows the team to improve existing code quality. During these sessions, focus on simplifying code, breaking down large functions, and removing duplicates.</p>
</li>
<li><p><strong>Technical Debt Backlog:</strong> Track technical debt items in a backlog, prioritizing them alongside feature development. This backlog helps balance feature work with debt reduction and keeps everyone aware of existing debt.</p>
</li>
</ol>
<h3 id="heading-how-to-deal-with-technical-debt-in-code">How to Deal with Technical Debt in Code</h3>
<p>Here’s a practical example to demonstrate how refactoring can help address technical debt, specifically by removing code duplication.</p>
<h4 id="heading-example-removing-duplicate-code">Example: Removing Duplicate Code</h4>
<p>Let’s say we have two functions that send different types of emails but use repeated code:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Duplicate code example</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_welcome_email</span>(<span class="hljs-params">user</span>):</span>
    send_email(user.email, <span class="hljs-string">"Welcome!"</span>, <span class="hljs-string">"Thanks for joining!"</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_password_reset_email</span>(<span class="hljs-params">user</span>):</span>
    send_email(user.email, <span class="hljs-string">"Password Reset"</span>, <span class="hljs-string">"Click here to reset your password."</span>)
</code></pre>
<p>Each function has a similar structure, so refactoring can make the code cleaner and reduce duplication.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Refactored code</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_email_to_user</span>(<span class="hljs-params">user, subject, message</span>):</span>
    send_email(user.email, subject, message)

<span class="hljs-comment"># Use the refactored function</span>
send_email_to_user(new_user, <span class="hljs-string">"Welcome!"</span>, <span class="hljs-string">"Thanks for joining!"</span>)
send_email_to_user(existing_user, <span class="hljs-string">"Password Reset"</span>, <span class="hljs-string">"Click here to reset your password."</span>)
</code></pre>
<p>This example demonstrates how consolidation can reduce repetition and make the code more flexible.</p>
<h3 id="heading-how-to-avoid-technical-debt">How to Avoid Technical Debt</h3>
<p>Proactively managing technical debt helps reduce it over time. Here are ways to avoid accumulating more debt:</p>
<ul>
<li><p><strong>Establish Code Standards:</strong> Create and enforce coding standards within the team. Consistent practices reduce complexity, improve readability, and make it easier to identify issues early.</p>
</li>
<li><p><strong>Refactor Regularly:</strong> Rather than waiting for debt to accumulate, make minor improvements during routine work. A “leave it better than you found it” approach ensures code quality remains high over time.</p>
</li>
<li><p><strong>Encourage Thorough Testing:</strong> Strong test coverage identifies potential problems early, reducing the likelihood of code with hidden issues. Testing tools like Jest for JavaScript or PyTest for Python make it easy to add tests to each function and module.</p>
</li>
<li><p><strong>Plan for Scalability:</strong> Think about future needs when designing code. Avoid shortcuts that might restrict scalability and performance as the application grows.</p>
</li>
<li><p><strong>Limit Workarounds and Temporary Fixes:</strong> If temporary fixes are necessary, document them and prioritize removing them as soon as possible. Keeping track of these “quick fixes” ensures they don’t become long-term issues.</p>
</li>
</ul>
<h2 id="heading-how-to-measure-code-quality-with-code-analysis-tools">How to Measure Code Quality with Code Analysis Tools</h2>
<p>Code quality tools can help you find issues that might not be obvious. They can point out things like unused variables, code that’s hard to read, or security problems. Popular tools include <code>ESLint</code> for <code>JavaScript</code>, <code>Pylint</code> for <code>Python</code>, and <code>SonarQube</code> for different programming languages.</p>
<p>Here’s how to set up a simple code check with ESLint:</p>
<ol>
<li><p><strong>Install ESLint</strong>:</p>
<pre><code class="lang-bash"> npm install eslint --save-dev
</code></pre>
</li>
<li><p><strong>Initialize ESLint</strong>:</p>
<pre><code class="lang-bash"> npx eslint --init
</code></pre>
<p> This command will prompt you to answer a few configuration questions. You can choose your preferred style guide and select a few options about your environment and file format.</p>
</li>
<li><p><strong>Example Code with Issues</strong></p>
<p> Here’s a sample JavaScript file (<code>example.js</code>) with a few common issues:</p>
<pre><code class="lang-javascript"> <span class="hljs-comment">// example.js</span>

 <span class="hljs-keyword">var</span> x = <span class="hljs-number">10</span>;   <span class="hljs-comment">// Unused variable</span>
 <span class="hljs-keyword">let</span> y = <span class="hljs-number">5</span>;
 <span class="hljs-keyword">const</span> z = <span class="hljs-string">'Hello World'</span>

 <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateSum</span>(<span class="hljs-params">a, b</span>) </span>{
     <span class="hljs-keyword">return</span> a + b
 }

 calculateSum(<span class="hljs-number">3</span>, <span class="hljs-number">4</span>);

 <span class="hljs-comment">// Missing semicolon and inconsistent indentation</span>
 <span class="hljs-keyword">if</span>(y &gt; <span class="hljs-number">3</span>){
     <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Y is greater than 3"</span>)
 }
</code></pre>
</li>
<li><p><strong>Run ESLint</strong>:</p>
<pre><code class="lang-bash"> npx eslint example.js
</code></pre>
<p> After running this command, ESLint will analyze <code>example.js</code> and report any issues based on the configured rules.</p>
</li>
<li><p><strong>ESLint Output</strong></p>
<p> ESLint provides detailed feedback about the issues it detects:</p>
<pre><code class="lang-plaintext"> /path/to/example.js
   1:5  warning  'x' is assigned a value but never used          no-unused-vars
   3:12  error    Missing semicolon                               semi
   6:25  error    Missing semicolon                               semi
   10:1  error    Expected indentation of 4 spaces but found 3    indent
   11:26 error    Missing semicolon                               semi

 ✖ 5 problems (4 errors, 1 warning)
</code></pre>
<p> Here’s a breakdown of each issue detected by ESLint:</p>
<ul>
<li><p><strong>Unused Variable</strong>: ESLint identifies that <code>x</code> is declared but never used (<code>no-unused-vars</code> rule).</p>
</li>
<li><p><strong>Missing Semicolons</strong>: ESLint flags lines where semicolons are missing at the end of statements (<code>semi</code> rule).</p>
</li>
<li><p><strong>Inconsistent Indentation</strong>: ESLint notices that line 10 doesn’t follow consistent indentation (<code>indent</code> rule).</p>
</li>
</ul>
</li>
<li><p><strong>Fixing the Code</strong></p>
<p> Based on ESLint’s feedback, here’s the corrected code:</p>
<pre><code class="lang-javascript"> <span class="hljs-comment">// example.js</span>

 <span class="hljs-keyword">let</span> y = <span class="hljs-number">5</span>;
 <span class="hljs-keyword">const</span> z = <span class="hljs-string">'Hello World'</span>;

 <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateSum</span>(<span class="hljs-params">a, b</span>) </span>{
     <span class="hljs-keyword">return</span> a + b;
 }

 calculateSum(<span class="hljs-number">3</span>, <span class="hljs-number">4</span>);

 <span class="hljs-keyword">if</span> (y &gt; <span class="hljs-number">3</span>) {
     <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Y is greater than 3"</span>);
 }
</code></pre>
<ul>
<li><p>We removed the unused variable <code>x</code>.</p>
</li>
<li><p>We added missing semicolons.</p>
</li>
<li><p>And we adjusted indentation for consistent spacing.</p>
</li>
</ul>
</li>
<li><p><strong>Re-run ESLint to Verify Fixes</strong></p>
<p> After making these changes, you can run <code>npx eslint example.js</code> again to confirm that there are no remaining issues. ESLint will return no output if everything is now clean, confirming that the code adheres to the configured standards.</p>
</li>
</ol>
<h3 id="heading-additional-tip-auto-fixing-with-eslint">Additional Tip: Auto-Fixing with ESLint</h3>
<p>ESLint can automatically fix some issues for you. To do this, use the <code>--fix</code> flag:</p>
<pre><code class="lang-bash">npx eslint example.js --fix
</code></pre>
<p>This command will automatically correct issues like indentation, unused variables, and missing semicolons where possible. But it’s important to review the changes to ensure they align with your intended functionality.</p>
<p>Reviewing code, spotting technical debt, and using quality tools help keep the codebase healthy. If you follow these steps, your project will be easier to manage and less likely to break.</p>
<h2 id="heading-ai-tools-to-help-you-improve-your-code">AI Tools to Help You Improve Your Code</h2>
<p>Using AI tools to restructure code makes improving code quality much faster and easier. These tools help find issues, suggest changes, and can even automate some parts of the refactoring process.</p>
<p>I'll share some AI tools that can help you with code analysis, refactoring, and dependency management, based on my own experience and what I've found useful.</p>
<h3 id="heading-best-ai-tools-for-code-restructuring">Best AI Tools for Code Restructuring</h3>
<p>AI-powered tools are becoming more common, and they offer different ways to boost code quality and simplify refactoring. Here are some I've found helpful:</p>
<h4 id="heading-1-github-copilot"><strong>1. GitHub Copilot</strong></h4>
<p>GitHub Copilot is like a coding assistant that provides smart suggestions as you write code. It can complete code snippets, suggest new functions, and help rework existing code to make it more efficient. I’ve found it useful for writing repetitive code blocks or coming up with quick refactorings.</p>
<p>For example, let’s say you need to rewrite a function to be more efficient:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Original function that checks if a number is prime</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">is_prime</span>(<span class="hljs-params">n</span>):</span>
    <span class="hljs-keyword">if</span> n &lt; <span class="hljs-number">2</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>, n):
        <span class="hljs-keyword">if</span> n % i == <span class="hljs-number">0</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
    <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
</code></pre>
<p>GitHub Copilot might suggest optimizing the function like this:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Optimized version suggested by Copilot</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">is_prime</span>(<span class="hljs-params">n</span>):</span>
    <span class="hljs-keyword">if</span> n &lt; <span class="hljs-number">2</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>, int(n**<span class="hljs-number">0.5</span>) + <span class="hljs-number">1</span>):
        <span class="hljs-keyword">if</span> n % i == <span class="hljs-number">0</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
    <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
</code></pre>
<p>The updated version checks factors only up to the square root of <code>n</code>, making it faster for large numbers.</p>
<h4 id="heading-2-qodogen"><strong>2. QodoGen</strong></h4>
<p>QodoGen provides automated suggestions for refactoring and can detect common code issues, like unused variables or large functions doing too many tasks. It also helps split complex code into smaller, more manageable pieces and can explain sections of the code base or the entire codebase which will facilitate the restructuring process.</p>
<p>This tool is capable of doing this because, unlike other AI assistants and general purpose code generation tools, Qodo focuses on code integrity, while generating tests that help you understand how your code behaves. This can help you discover edge cases and suspicious behaviors, and make your code more robust.</p>
<p>For example, if you have a function handling multiple tasks, QodoGen might suggest breaking it down:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Before refactoring</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_user_data</span>(<span class="hljs-params">user_data</span>):</span>
    validate_data(user_data)
    save_to_database(user_data)
    send_welcome_email(user_data)

<span class="hljs-comment"># After refactoring</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_user_data</span>(<span class="hljs-params">user_data</span>):</span>
    validated_data = validate_data(user_data)
    save_data(validated_data)
    notify_user(validated_data)
</code></pre>
<p>Separating the steps makes the code easier to maintain and test.</p>
<h4 id="heading-3-chatgpt-for-code-assistance"><strong>3. ChatGPT for Code Assistance</strong></h4>
<p>ChatGPT can act as a helpful companion when working on code restructuring tasks. Arguably the most used coding assistant, it provides advice on refactoring strategies, explains how to implement changes, or offers example snippets. It’s like having an expert to consult whenever you need guidance or ideas.</p>
<p>For instance, if you’re unsure how to optimize a function or restructure a class, ChatGPT can provide sample code or describe best practices. You can also ask it for help with understanding errors or fixing specific problems in your code.</p>
<p>Just make sure you double-check the code it provides (same goes for all these AI assistants) as it can hallucinate and make mistakes.</p>
<h3 id="heading-automated-tools-for-refactoring-and-analysis">Automated Tools for Refactoring and Analysis</h3>
<p>AI tools not only assist with writing code but also with analyzing it for quality improvements:</p>
<h4 id="heading-1-sonarqube"><strong>1. SonarQube</strong></h4>
<p>SonarQube scans the code to detect bugs, vulnerabilities, and code smells. It generates reports with suggestions on what to fix, helping maintain a healthy codebase.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Sample SonarQube configuration</span>
sonar.projectKey=my_project
sonar.sources=src
sonar.host.url=http://localhost:9000
sonar.login=my_token
</code></pre>
<h4 id="heading-2-resharper"><strong>2. ReSharper</strong></h4>
<p>This tool integrates with Visual Studio and offers automatic refactoring options. It highlights code that can be simplified or cleaned up and suggests ways to optimize the codebase.</p>
<h4 id="heading-3-depcheck-for-dependency-management"><strong>3. DepCheck for Dependency Management</strong></h4>
<p>AI tools like DepCheck help find unused dependencies in JavaScript projects, keeping package files clean.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Running DepCheck to find unused dependencies</span>
npx depcheck
</code></pre>
<h3 id="heading-how-these-tools-help-with-code-restructuring">How These Tools Help with Code Restructuring</h3>
<p>Using AI tools like GitHub Copilot, QodoGen, and ChatGPT speeds up the process of code restructuring. They provide suggestions that save time and catch issues early, making the code easier to maintain.</p>
<p>Combining these tools with automated analysis tools like SonarQube and ReSharper ensures all aspects of the codebase are covered, from quality checks to refactoring.</p>
<p>These AI tools have other features that facilitate this process: for example, they all have a chat feature that lets you ask questions and get replies about your code and any best practices you should be following. Also, QodoGen allows you to add parts of or the whole codebase for context with the click of a button, along with other features for test generation and pull request reviews.</p>
<p>When restructuring your codebase, having a variety of AI tools can make the process smoother and more efficient. This is AI usage at its best.</p>
<h2 id="heading-version-control-best-practices-for-code-changes">Version Control Best Practices for Code Changes</h2>
<p>Version control keeps track of code changes, making it easier to manage updates, collaborate with others, and fix issues. Following some best practices can help maintain a clean and organized codebase.</p>
<p>Let’s look at how to manage code changes, track updates, and ensure quality through code reviews.</p>
<h3 id="heading-using-git-branching-strategies-to-manage-code-changes">Using Git Branching Strategies to Manage Code Changes</h3>
<p>Git branching helps keep different versions of the code separate, allowing multiple developers to work without affecting the main codebase. Here are some common strategies:</p>
<h4 id="heading-1-feature-branching"><strong>1. Feature Branching</strong></h4>
<p>Feature branches allow developers to work on a new feature without changing the main codebase. Each feature gets its own branch, and once complete, it can be merged into the main branch.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Creating a new feature branch</span>
git checkout -b feature/new-login-page

<span class="hljs-comment"># Working on the new feature and then committing changes</span>
git add .
git commit -m <span class="hljs-string">"Added login page UI"</span>

<span class="hljs-comment"># Merging the feature branch into the main branch</span>
git checkout main
git merge feature/new-login-page
</code></pre>
<h4 id="heading-2-gitflow-strategy"><strong>2. GitFlow Strategy</strong></h4>
<p>This strategy involves using multiple branches for different stages of development, such as feature, develop, and release. It separates development work and allows smoother integration and deployment.</p>
<ul>
<li><p><strong>Main Branch</strong>: Contains production-ready code.</p>
</li>
<li><p><strong>Develop Branch</strong>: Holds the latest completed work, ready for the next release.</p>
</li>
<li><p><strong>Feature Branches</strong>: Created from the develop branch for new features.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Switch to the develop branch</span>
git checkout develop

<span class="hljs-comment"># Create a new branch for a feature</span>
git checkout -b feature/upgrade-search

<span class="hljs-comment"># Commit changes and push the feature branch</span>
git add .
git commit -m <span class="hljs-string">"Improved search feature"</span>
git push origin feature/upgrade-search
</code></pre>
<h3 id="heading-how-to-track-and-document-code-updates">How to Track and Document Code Updates</h3>
<p>Documenting code changes helps keep the team informed and makes it easier to understand what was done later. Here are some tips for tracking updates:</p>
<h4 id="heading-1-writing-clear-commit-messages"><strong>1. Writing Clear Commit Messages</strong></h4>
<p>Commit messages should explain what was changed and why. A clear message helps others know the purpose of each update.</p>
<p>Example:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Good commit message</span>
git commit -m <span class="hljs-string">"Fixed bug that caused login failure on mobile devices"</span>

<span class="hljs-comment"># Bad commit message</span>
git commit -m <span class="hljs-string">"Fixed bug"</span>
</code></pre>
<h4 id="heading-2-using-tags-to-mark-releases"><strong>2. Using Tags to Mark Releases</strong></h4>
<p>Tags can be used to label important points in the project’s history, such as release versions. This makes it easier to find stable versions of the code.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create a tag for version 1.0</span>
git tag v1.0

<span class="hljs-comment"># Push the tag to the remote repository</span>
git push origin v1.0
</code></pre>
<h4 id="heading-3-creating-and-using-changelogs"><strong>3. Creating and Using Changelogs</strong></h4>
<p>A changelog lists the changes made in each version, helping developers and users see what was updated or fixed.</p>
<p>Example format for a changelog:</p>
<pre><code class="lang-plaintext">## [1.0.1] - 2024-10-01
### Added
- New login feature

### Fixed
- Resolved search issue on homepage

### Changed
- Updated user dashboard layout
</code></pre>
<h3 id="heading-importance-of-code-reviews-in-maintaining-code-quality">Importance of Code Reviews in Maintaining Code Quality</h3>
<p>Code reviews help catch errors, share knowledge, and ensure code stays clean and maintainable. Here are some practices to follow for effective code reviews:</p>
<h4 id="heading-1-keep-code-changes-small"><strong>1. Keep Code Changes Small</strong></h4>
<p>Smaller changes are easier to review, making it more likely to spot mistakes. Large changes can be broken down into smaller parts.</p>
<h4 id="heading-2-use-pull-requests-for-reviews"><strong>2. Use Pull Requests for Reviews</strong></h4>
<p>Pull requests create a space for discussion around changes. Team members can review the changes, suggest improvements, and approve the updates.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Push the feature branch to the remote repository</span>
git push origin feature/new-feature

<span class="hljs-comment"># Create a pull request on GitHub, GitLab, or Bitbucket</span>
</code></pre>
<h4 id="heading-3-provide-constructive-feedback"><strong>3. Provide Constructive Feedback</strong></h4>
<p>Code reviews should aim to improve the code without discouraging the developer. Suggest better ways to solve problems and explain the reasoning.</p>
<p>Example comments during a code review:</p>
<ul>
<li><p>"Consider using a list instead of a dictionary for this data structure, as it simplifies the code."</p>
</li>
<li><p>"This function is doing multiple tasks. It might be clearer if we split it into two separate functions."</p>
</li>
</ul>
<p>Using these practices helps ensure code changes are managed effectively, updates are well-documented, and the quality of the codebase remains high. Regular code reviews and proper branching strategies make it easier for teams to collaborate and keep the project on track.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Reviving and restructuring a codebase can seem like a big task, but taking small, planned steps makes it manageable. Start by checking the current state of the code and making a list of areas that need work. Set clear goals and create a plan to improve the code, step by step.</p>
<p>Using the tools we discussed here can help find issues, suggest changes, and even automate some tasks. Version control practices, such as branching strategies and code reviews, keep changes organized and ensure the quality stays high.</p>
<p>With a solid approach, even the messiest codebase can become clean, efficient, and easier to work with.</p>
<h3 id="heading-resources">Resources</h3>
<ul>
<li><p>AI tools have been developed to assist with the Git branching, Pull Request reviews and approval. Check out <a target="_blank" href="https://dev.to/oluwadamisisamuel1/merge-mastery-elevating-your-pull-request-game-in-open-source-projects-25fo">this article</a> to read more on one of my favorites.</p>
</li>
<li><p>If you want a step by step tutorial on how to revive and refactor your code, check out <a target="_blank" href="https://youtu.be/yMQJUaUtiJo?si=CGd2WBcD117p7lrS">this youtube video</a>.</p>
</li>
<li><p>Check out <a target="_blank" href="https://www.freecodecamp.org/news/best-practices-for-refactoring-code/">this freecodecamp article</a> on code restructuring to dive deeper.</p>
</li>
</ul>
<p>Connect with me on <a target="_blank" href="https://www.linkedin.com/in/samuel-oluwadamisi-01b3a4236/?lipi=urn%3Ali%3Apage%3Ad_flagship3_feed%3BxAUJMbSgQTeDtb7n2d0mQQ%3D%3D">LinkedIn</a>, <a target="_blank" href="https://twitter.com/Data_Steve_">Twitter</a>, and <a target="_blank" href="https://dev.to/dashboard">my peronal blog</a> if you found this helpful.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Git Checkout Remote Branch – How to Fetch and List Remote Branches ]]>
                </title>
                <description>
                    <![CDATA[ You can use branches in Git to work on different features without affecting your main codebase. For example, you can experiment with a new layout for your webpage on a different branch without affecting the main branch where your website is being dep... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/git-checkout-remote-branch-how-to-fetch-and-list-remote-branches/</link>
                <guid isPermaLink="false">66312218ca07c0eea04f8067</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ihechikara Abba ]]>
                </dc:creator>
                <pubDate>Tue, 30 Apr 2024 16:53:44 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/UT8LMo-wlyk/upload/c907bdb799b1331e27dd68f35a2b2e25.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>You can use branches in Git to work on different features without affecting your main codebase. For example, you can experiment with a new layout for your webpage on a different branch without affecting the main branch where your website is being deployed from.</p>
<p>Branches are used for different purposes like feature development, bug fixes, versioning, experimentation, <a target="_blank" href="https://contribute.freecodecamp.org/#/">contributing to open source projects</a>, and so on.</p>
<p>In this article, you'll learn how to use different Git commands to interact with remote branches.</p>
<h1 id="heading-how-to-fetch-and-list-remote-branches">How to Fetch and List Remote Branches</h1>
<p>I've created a repository (repo) for this article with three different branches: main, feat/create-hobbies-list, and feat/create-language-list. You can download the repo <a target="_blank" href="https://github.com/ihechikara/git-branches-article">here</a>, or clone it to your computer using this command:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/ihechikara/git-branches-article.git
</code></pre>
<p>The command above downloads the main branch of the repository to your computer.</p>
<p>Feel free to follow along with your own codebase/Git repo.</p>
<h2 id="heading-how-to-list-remote-branches">How to List Remote Branches</h2>
<p>When you look at the repo you just cloned on GitHub, you'll notice that there are three branches.</p>
<p>But when you run the <code>git branch</code> command, you'll only get a list of branches in the local repo. In our case, that is the main branch. This happens for a couple of reasons:</p>
<ul>
<li><p>The <code>git branch</code> command only shows local branches.</p>
</li>
<li><p>Cloning a branch doesn't automatically download all other branches in the remote repo.</p>
</li>
</ul>
<p>So how do you list the remote branches? You can do that using the <code>git branch -r</code> command:</p>
<pre><code class="lang-bash">git branch -r

origin/HEAD -&gt; origin/main
origin/feat/create-hobbies-list
origin/feat/create-language-list
origin/main
</code></pre>
<p>From the command output above, you can see all the branches in the remote repo. The main branch which also acts as the default branch (origin/HEAD), and two other branches: feat/create-hobbies-list and feat/create-language-list.</p>
<p>Now that you know how to list remote branches, let's see how to fetch and work on them locally.</p>
<h2 id="heading-how-to-fetch-remote-branches">How to Fetch Remote Branches</h2>
<p>You can fetch remote branches for different reasons like code review, updating your local repo with changes made to the remote repo, experimentation, and so on.</p>
<h3 id="heading-how-to-fetch-remote-branches-using-git-fetch">How to Fetch Remote Branches Using <code>git fetch</code></h3>
<p>You can use the <code>git fetch</code> command to "fetch" recent changes made to the remote repo without merging them into your local repo.</p>
<p>For example, let's assume that new changes were pushed to the feat/create-language-list branch. When you run the <code>git fetch</code> command, Git retrieves the new changes in the remote repo but you won't see them in my local branch/repo.</p>
<p>You can then use commands like <code>git diff</code> and <code>git log</code> to compare the changes.</p>
<p>In a case where you're satisfied with the changes, you can use the <code>git merge</code> command to merge those changes into your local branch. At this point, the changes from the remote branch will be visible/seen locally.</p>
<p>That is:</p>
<pre><code class="lang-bash">git checkout feat/create-language-list
</code></pre>
<p>The command above switches to the feat/create-language-list branch.</p>
<pre><code class="lang-bash">git fetch
</code></pre>
<p>The command above retrieves current changes made to the remote branch that aren't in your local branch.</p>
<pre><code class="lang-bash">git diff feat/create-language-list origin/feat/create-language-list
</code></pre>
<p>The command above compares the changes you just fetched with your local branch. In the terminal, the red characters denote the state of your local branch while the green characters denote new changes from the remote branch. That is:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714451407216/fd2ec3a7-a20f-4c1f-94a1-d7e916f183d4.png" alt="git diff command showing changes retrieved from remote branch" class="image--center mx-auto" width="502" height="466" loading="lazy"></p>
<pre><code class="lang-bash">git merge
</code></pre>
<p>The command above merges the changes into your local branch. In this case, the <strong>languages.txt</strong> file will be updated with the new changes.</p>
<p>In summary, <code>git fetch</code> retrieves the changes while <code>git merge</code> merges the changes to your local branch.</p>
<h3 id="heading-how-to-fetch-remote-branches-using-git-pull">How to Fetch Remote Branches Using <code>git pull</code></h3>
<p>The <code>git pull</code> command is similar to <code>git fetch</code> and <code>git merge</code>.</p>
<p>The difference is that <code>git pull</code> automatically merges new changes into your local branch. That is, you don't get to compare changes before merging (you won't get the chance to run <code>git diff</code>).</p>
<p><code>git pull</code> executes both <code>git fetch</code> and <code>git merge</code> at the same time.</p>
<p>So once you run the <code>git pull</code> command, the remote changes will appear locally if there are no merge conflicts.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this article, you learned how to list remote branches using the <code>git branch -r</code> command.</p>
<p>You also learned how to fetch remote branches. The <code>git fetch</code> command fetches changes from the remote branch while the <code>git merge</code> command merges the remote changes to your local branch. This process give you the opportunity to compare changes before merging them.</p>
<p>On the other hand, the <code>git pull</code> command automatically fetches and merges changes from a remote branch as long as there are no merge conflicts.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is a GitHub Wiki and How Do You Use it? ]]>
                </title>
                <description>
                    <![CDATA[ A GitHub wiki is a great place for your project's documentation. You can use the wiki to create, manage, and host documentation for your repository so others can use and contribute to your project. GitHub wikis are easy to start using without install... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-github-wiki-and-how-do-you-use-it/</link>
                <guid isPermaLink="false">66d038c3ccf811d3117aef0c</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rajdeep Singh ]]>
                </dc:creator>
                <pubDate>Mon, 15 Apr 2024 20:46:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/What-is-GitHub-Wiki-and-How-Do-You-Use-it.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A GitHub wiki is a great place for your project's documentation. You can use the wiki to create, manage, and host documentation for your repository so others can use and contribute to your project.</p>
<p>GitHub wikis are easy to start using without installing any other software. The best part is that the wiki is integrated with your GitHub repository. </p>
<p>You do not need any other tool – you just need to know how to use markdown, as you'll use it to write your wiki. (You can <a target="_blank" href="https://www.freecodecamp.org/news/github-flavored-markdown-syntax-examples/">read all about that in my other article here</a>.)</p>
<h2 id="heading-how-to-start-using-github-wiki">How to Start Using GitHub Wiki</h2>
<p>You can start your GitHub wiki with just one click. Every GitHub repository has a Wiki tab in the menu at the top of the page. To start, click on it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/github-wiki.png" alt="GitHub repository Page" width="600" height="400" loading="lazy">
<em>GitHub repository Page</em></p>
<p>The wiki tab is sometimes not shown by default in the GitHub repository nav bar. First, you'll need to enable wikis in your repository settings.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/no-wiki.png" alt="No wiki tab is show." width="600" height="400" loading="lazy">
<em>No wiki tab is shown.</em></p>
<p>To do that, go to your repository settings page, scroll down, and find the features section. Then enable wikis by checking the "Wikis" box.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Wiki-enable.png" alt="Enable wiki.in GitHub" width="600" height="400" loading="lazy">
<em>Enable wiki</em></p>
<p>To initialize the wiki in your GitHub repository, create the home page in your wiki.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/first-page.png" alt="Initialize the wiki in GitHub." width="600" height="400" loading="lazy">
<em>Initialize the wiki in GitHub.</em></p>
<p>When you click the "<strong>Create the first page</strong>" button, you'll be redirected to the editor page where you can create a home page in the wiki.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Home-wiki-Page.png" alt="Create a home page and initialize the wiki." width="600" height="400" loading="lazy">
<em>Create a home page and initialize the wiki.</em></p>
<p>Your wiki home page should now look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Your-wiki-is-look-like-this.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wiki home page</em></p>
<h2 id="heading-how-to-clone-a-github-wiki-locally">How to Clone a GitHub Wiki Locally</h2>
<p>Sometimes, new developers are confused about how to clone the wiki locally. To do this, just copy the link where it says “Clone this wiki locally”, as you can see in the image below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/clone.png" alt="Copy the link to clone the GitHub wiki." width="600" height="400" loading="lazy">
<em>Copy the link to clone the GitHub wiki.</em></p>
<p>Copy that link and clone the GitHub wiki repository locally on your laptop or machine.</p>
<p>Now, you can make changes in the wiki, such as editing, updating, or changing documentation locally. After you finish any documentation changes, you can push your local wiki documentation to the GitHub wiki repository.</p>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">clone</span> https://github.com/officialrajdeepsingh/github-wiki-tutorial.wiki.git
Cloning into <span class="hljs-string">'github-wiki-tutorial.wiki'</span>...
remote: Enumerating objects: 6, <span class="hljs-keyword">done</span>.
remote: Counting objects: 100% (6/6), <span class="hljs-keyword">done</span>.
remote: Compressing objects: 100% (2/2), <span class="hljs-keyword">done</span>.
remote: Total 6 (delta 1), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), <span class="hljs-keyword">done</span>.
Resolving deltas: 100% (1/1), <span class="hljs-keyword">done</span>.
</code></pre>
<h2 id="heading-how-to-customize-your-wiki">How to Customize Your Wiki</h2>
<p>Wikis have limited customization options for the sidebar, home page, and footer. But you can extend these options using HTML, CSS, and Markdown.</p>
<p>We have already discussed the home page, and now we'll discuss the footer and sidebar.</p>
<p>The footer and sidebar show or contain helpful links such as contact information, navigation links, social media links, and so on.</p>
<p>The footer is shown at the bottom of every page on your site, and the sidebar is typically a vertical column on the left or right side of a web page. Both are visible on all pages of the wiki.</p>
<h3 id="heading-how-to-create-a-custom-sidebar">How to create a custom sidebar</h3>
<p>There are two ways to create a sidebar in the GitHub wiki.</p>
<ol>
<li>With the GitHub UI</li>
<li>Locally in your IDE</li>
</ol>
<p>We'll look at each method here so you can choose the one that works best for you.</p>
<h4 id="heading-with-the-github-ui">With the GitHub UI</h4>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/sidebar-1.png" alt="Create a sidebar" width="600" height="400" loading="lazy">
<em>Create a sidebar</em></p>
<p>Go to the wiki home page and click on the “Add a custom sidebar” button to create a sidebar in your wiki.</p>
<p>Next, it will redirect you to the editor page to create a sidebar page. In the sidebar file, you can write markdown content such as navigation links, and so on. After that, click the <strong>save button</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/create-sidebar-page.png" alt="Create _Sidebar.md file in github wiki." width="600" height="400" loading="lazy">
_Create <code>_Sidebar.md</code> file._</p>
<h4 id="heading-locally-in-your-ide">Locally in your IDE</h4>
<p>The second way is to clone your wiki locally and then create a <code>_Sidebar.md</code><br>file in your wiki at the root level using VS Code or any other IDE which you like. </p>
<h3 id="heading-how-to-create-a-custom-footer">How to create a custom footer</h3>
<p>You'll follow basically the same steps as in the sidebar section to create your custom wiki footer.</p>
<h4 id="heading-with-the-github-ui-1">With the GitHub UI</h4>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/footer.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Go to your wiki page and click on the “Add a custom footer” button to create a footer in your wiki.</p>
<p>Next, it will redirect you to the editor page to create a footer. In the footer file, you can write markdown content such as navigation links, and so on. After that, click the <strong>save button</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/footer-editor.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create a footer</em></p>
<h4 id="heading-locally-in-your-ide-1">Locally in your IDE</h4>
<p>The second way is to clone your wiki locally and then create a <code>_Footer.md</code><br>file in your wiki at the root level using VS Code or any other IDE which you like. </p>
<h2 id="heading-what-is-a-page-how-do-you-create-a-new-page-in-the-wiki">What is a Page? How Do You Create a New Page in the Wiki?</h2>
<p>In a wiki, a page has functionality similar to other CMSs, giving you the power to manage your content and documentation.</p>
<p>With the wiki page, you can divide your content or docs into different sections such as installation, configuration, and so on.</p>
<p>To create a new page, click on the new page button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/create-a-page.png" alt="Create a new wiki page" width="600" height="400" loading="lazy">
<em>Create a new wiki page</em></p>
<p>It redirects you to the editor page, where you can add a title and content. After your writing is finished, click on the save button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/create-a-new-page-with-wiki.png" alt="Create a wiki page" width="600" height="400" loading="lazy">
<em>Create a wiki page</em></p>
<p>Your page looks like this in the wiki after it is published:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/your-installation-page.png" alt="The Wiki page looks like this in the browser after publishing." width="600" height="400" loading="lazy">
<em>The Wiki page looks like this in the browser after publishing.</em></p>
<p>Everybody can access your pages section. Every page you publish is shown in the pages section on your wiki.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/access-the-page.png" alt="The page section shows the published page list." width="600" height="400" loading="lazy">
<em>The page section shows the published page list.</em></p>
<h2 id="heading-how-to-enable-and-disable-collaboration-in-the-wiki">How to Enable and Disable Collaboration in the Wiki</h2>
<p>To enable collaboration for everyone in the wiki, go to your GitHub repository settings page, scroll down, find the features, and unselect the "Restrict editing to collaborators only" checkbox.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/access-to-eveyone-in-wiki.png" alt="Enable Collaboration in the GitHub Wiki." width="600" height="400" loading="lazy">
<em>Enable Collaboration in the GitHub Wiki.</em></p>
<p>You can turn off collaboration for everyone, so that you and your team are the only ones responsible for updating, deleting, and editing the wiki.</p>
<p>To do this, you need to restrict editing for other users. Enabling the <strong>Restrict editing to collaborators only</strong> option quickly accomplishes this.</p>
<p>After there haven't been any edits, invite your team and give them access to it. Then just click the "Restrict editing to collaborators only" checkbox.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/enable-it.png" alt="Disable Collaboration in the GitHub Wiki." width="600" height="400" loading="lazy">
<em>Disable Collaboration in the GitHub Wiki.</em></p>
<h2 id="heading-why-is-github-wiki-so-useful">Why is GitHub Wiki So Useful?</h2>
<p>GitHub wikis can be useful for everyone. You can start your documentation with a wiki in less than one minute. You do not need anything to start writing your documentation except basic knowledge of Markdown syntax. </p>
<p>Using GitHub wikis, you can just focus on writing basic documentation and on the project itself. GitHub wiki handles the rest of your documentation such as hosting concerns, search, and so on. Most importantly, for public repository wikis, it's <a target="_blank" href="https://docs.github.com/en/communities/documenting-your-project-with-wikis/adding-or-editing-wiki-pages">totally free</a>. </p>
<p>Many famous open-source projects use Wiki nowadays, such as <a target="_blank" href="https://github.com/facebook/hhvm/wiki">hhvm</a>, <a target="_blank" href="https://github.com/neovim/neovim/wiki">neovim</a>, <a target="_blank" href="https://github.com/guard/guard/wiki">guard</a>, <a target="_blank" href="https://github.com/apple/foundationdb/wiki">foundation db</a>, and others.</p>
<p>Check out the <a target="_blank" href="https://github.com/MyHoneyBadger/awesome-github-wiki">list of projects used in Wiki</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>There are many documentation frameworks on the market, such as Nextra, Lume, Starlight, and Docusaurus. But they take some time to learn, configure, and set up. </p>
<p>Also, if you're still working on your coding skills and you aren't comfortable with tools like React, MDX, and so on, you'll need to take some time to learn them before using these more advanced documentation frameworks.</p>
<p>With GitHub Wiki, you can start creating your documentation right away, and you do not need to worry about deploying and hosting anything managed by GitHub.</p>
<p>GitHub Wiki is a great choice for small and early-stage projects. You and your team can focus on the project while composing straightforward documentation.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Git and GitHub – a Guide for Beginners and Experienced Developers ]]>
                </title>
                <description>
                    <![CDATA[ Welcome to Git and GitHub for Beginners! This comprehensive guide is tailored to help you navigate the world of version control and collaboration.  Whether you're a newbie just starting out or an experienced developer looking to brush up on your skil... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/guide-to-git-github-for-beginners-and-experienced-devs/</link>
                <guid isPermaLink="false">66bb56fe0da5b03e481107c4</guid>
                
                    <category>
                        <![CDATA[ beginner ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Isaiah Clifford Opoku ]]>
                </dc:creator>
                <pubDate>Sat, 06 Apr 2024 01:38:29 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/Attractive.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Welcome to Git and GitHub for Beginners! This comprehensive guide is tailored to help you navigate the world of version control and collaboration. </p>
<p>Whether you're a newbie just starting out or an experienced developer looking to brush up on your skills, this guide offers a step-by-step approach to understanding and effectively using Git and GitHub.</p>
<p>By the end of this journey, you'll have a solid foundation in Git and GitHub. You'll be equipped with practical knowledge to streamline your coding workflow, collaborate seamlessly with teams, and contribute to open-source projects. </p>
<p>So, let's dive in and get started on your Git and GitHub adventure!</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-who-is-this-guide-for">Who is this guide for?</a></li>
<li><a class="post-section-overview" href="#heading-technologies">Technologies</a></li>
<li><a class="post-section-overview" href="#heading-terms">Terms</a></li>
<li><a class="post-section-overview" href="#heading-what-is-github">What is GitHub?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-github-used-for">What is GitHub used for?</a></li>
<li><a class="post-section-overview" href="#heading-common-tasks-youll-perform-with-git">Common tasks you'll perform with Git</a></li>
<li><a class="post-section-overview" href="#heading-how-to-install-git">How to install Git</a></li>
<li><a class="post-section-overview" href="#heading-how-to-configure-git">How to configure Git</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-the-default-editor">How to set the default editor</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-repository-using-the-github-website">How to create a repository using the Github website</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-repository-using-the-git-command-line">How to create a repository using the Git command line</a></li>
<li><a class="post-section-overview" href="#heading-how-to-connect-a-local-repository-to-a-remote-repository-on-github">How to connect a local repository to a remote repository on GitHub</a></li>
<li><a class="post-section-overview" href="#heading-how-to-pull-changes-from-a-remote-repository-to-a-local-repository">How to pull changes from a remote repository to a local repository</a></li>
<li><a class="post-section-overview" href="#heading-how-to-work-with-git-commands">How to work with Git commands</a></li>
<li><a class="post-section-overview" href="#heading-how-to-make-changes-to-a-file">How to make changes to a file</a></li>
<li><a class="post-section-overview" href="#heading-how-to-check-the-status-of-the-current-branch">How to check the status of the current branch</a></li>
<li><a class="post-section-overview" href="#heading-how-to-stage-changes">How to stage changes</a></li>
<li><a class="post-section-overview" href="#heading-how-to-commit-changes">How to commit changes</a></li>
<li><a class="post-section-overview" href="#heading-how-to-push-changes-to-a-remote-repository">How to push changes to a remote repository</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-branch">How to create a branch</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-pull-request">How to create a pull request</a></li>
<li><a class="post-section-overview" href="#heading-how-to-merge-a-pull-requset">How to merge a pull request</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ul>
<h2 id="who-is-this-guide-for">Who is This Guide For?</h2>

<p>This guide is for everyone who wants to level up their coding skills and become proficient in using Git and GitHub. </p>
<p>Whether you're:</p>
<ul>
<li>just starting your tech career and need to learn the basics of version control.</li>
<li>an aspiring developer eager to integrate <code>Git</code> into your workflow.</li>
<li>an experienced programmer looking to refresh your knowledge or discover new features.</li>
<li>a team lead or manager interested in fostering a culture of collaboration and efficient code management.</li>
</ul>
<p>Regardless of your background or experience, this guide is designed to empower you with the tools and knowledge you need to excel in your coding endeavors.</p>
<h2 id="technologies">Technologies</h2>

<p>Before you start, make sure:</p>
<ul>
<li>You have a <a target="_blank" href="https://github.com/">GitHub account</a></li>
<li><a target="_blank" href="https://git-scm.com/">Git</a> is installed on your machine</li>
<li>You have a text editor, such as <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code</a> installed</li>
<li><a target="_blank" href="https://nodejs.org/en/">Node.js</a> is installed on your machine</li>
</ul>
<h2 id="terms">Terms</h2>

<p>They are a lot of terms around Git and Github that you may meet when you're working with version control. Let me break it down for you before we start:</p>
<ul>
<li><strong>Branch</strong>: A version of the codebase that diverges from the main branch to isolate changes for specific features, fixes, or experiments.</li>
<li><strong>Commit</strong>: A snapshot of your changes, saved to your local repository. Each commit is uniquely identified by a checksum.</li>
<li><strong>Stage</strong>: The area where Git tracks changes that are ready to be included in the next commit. Files in the staging area are prepared (staged) for the next commit.</li>
<li><strong>Merge</strong>: The process of integrating changes from one branch into another, typically the main branch.</li>
<li><strong>Pull Request</strong>: A proposal to merge changes from one branch into another, often used in collaborative environments to review and discuss changes before they are merged.</li>
<li><strong>Fork</strong>: A personal copy of someone else's project that lives on your GitHub account.</li>
<li><strong>Clone</strong>: The act of downloading a repository from a remote source to your local machine.</li>
<li><strong>Remote</strong>: A common repository that all team members use to exchange their changes.</li>
<li><strong>Origin</strong>: The default name Git gives to the server from which you cloned.</li>
<li><strong>Upstream</strong>: The original repository that was cloned.</li>
<li><strong>Master</strong>: The default branch name given to a repository when it is created. In modern practice, it is often replaced with <code>main</code>.</li>
<li><strong>Repository</strong>: A storage location where your project lives, containing all the files and revision history.</li>
<li><strong>Working Directory</strong>: The directory on your computer where you are making changes to your project.</li>
<li><strong>Staging Area</strong>: Also known as the "Index," it's an area where Git tracks changes that are ready to be committed.</li>
<li><strong>Index</strong>: Another name for the staging area, where Git tracks changes that are ready to be committed.</li>
<li><strong>HEAD</strong>: A reference to the last commit in the currently checked-out branch.</li>
<li><strong>Checkout</strong>: The action of switching from one branch to another or to a specific commit.</li>
<li><strong>Push</strong>: The action of sending your commits to a remote repository.</li>
<li><strong>Pull</strong>: The action of fetching changes from a remote repository and merging them into your current branch.</li>
<li><strong>Fetch</strong>: The action of retrieving updates from a remote repository without merging them into your current branch.</li>
</ul>
<h2 id="what-is-github">What is GitHub?</h2>

<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/GitHub-1.png" alt="GitHub-1" width="600" height="400" loading="lazy"></p>
<p>GitHub is a platform that hosts code, providing version control and collaboration features. It enables you and others to work together on projects from anywhere in the world. </p>
<p>This guide will introduce you to essential GitHub concepts such as <code>repositories</code>, <code>branches</code>, <code>commits</code>, and <code>Pull Requests</code>. You will learn how to create your own 'Hello World' repository and understand GitHub's Pull Request workflow, a widely-used method for creating and reviewing code. </p>
<p>By the end of this guide, you'll be equipped with the knowledge and skills to collaborate effectively on GitHub.</p>
<h2 id="what-is-github-used-for">What is GitHub Used For?</h2>

<p>GitHub is more than just a code hosting platform. It's a tool that allows for seamless collaboration and version control. Here are some of its uses:</p>
<ul>
<li>Hosting and sharing your code with others.</li>
<li>Tracking and assigning issues to maintain an organized workflow.</li>
<li>Managing pull requests to review and incorporate changes into your project.</li>
<li>Creating your own website using GitHub Pages, a static site hosting service.</li>
<li>Collaborating with others on projects, making it an excellent tool for open-source contributions.</li>
</ul>
<h2 id="what-is-git">What is Git?</h2>

<p>Git is a free and open-source distributed version control system. It's designed to handle everything from small to very large projects with speed and efficiency</p>
<p>Git is easy to learn and has a tiny footprint with lightning-fast performance. It outclasses SCM tools like Subversion, CVS, Perforce, and ClearCase with features like cheap local branching, convenient staging areas, and multiple workflows</p>
<p>Git was initially designed and developed by Linus Torvalds for Linux kernel development.</p>
<p>Some features/benefits of Git:</p>
<ul>
<li>Allows you to track changes to your code over time.</li>
<li>Enables you to collaborate with others on the same codebase.</li>
<li>You can easily revert to a previous version of your code or experiment with new features without affecting the main codebase.</li>
<li>Provides a record of all changes made to your code, including who made them and when which can be useful for auditing and debugging.</li>
</ul>
<h2 id="common-tasks-youll-perform-with-git"> Common Tasks You'll Perform with Git </h2>

<ul>
<li>Create a repository</li>
<li>Create a branch</li>
<li>Make changes to a file</li>
<li>Stage changes</li>
<li>Commit changes</li>
<li>Push changes to a remote repository</li>
<li>Merge changes</li>
<li>Revert changes</li>
<li>Delete a branch</li>
</ul>
<h2 id="how-to-install-git">  How to Install Git </h2>

<p>To install Git on your local machine, you need to follow these steps:</p>
<ol>
<li><p>Download Git from the official website: <a target="_blank" href="https://git-scm.com/downloads">Git Downloads</a></p>
</li>
<li><p>Install Git on your local machine by following the instructions provided on the official website: <a target="_blank" href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git">Installing Git</a></p>
</li>
</ol>
<p><em>Congratulations!</em> You have successfully installed Git on your local machine. You are now ready to start using Git for your projects.</p>
<h2 id="how-to-configure-git">  How to Configure Git </h2>

<p>Git offers a variety of configurations that can streamline your workflow. In this section, I will guide you through the process of setting up Git on your local machine. Let's get started.</p>
<p>Configuring your <code>name</code> and <code>email</code> address on your local machine is an essential step in setting up Git. These details are attached to each commit you make, providing context and ownership. Let's learn how to use the <code>git config --global</code> command to set your name and email globally on your local machine.</p>
<p>To set up your name, you need to type the following command in your terminal:</p>
<pre><code class="lang-bash">
<span class="hljs-comment"># Set a name that is identifiable for credit when reviewing version history</span>

$ git config --global user.name <span class="hljs-string">"Your Name"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/userNameEmail.png" alt="userNameEmail" width="600" height="400" loading="lazy"></p>
<p>As you can see in the image above, I have entered my name.</p>
<p>After entering your name, press <code>Enter</code> to save it. You won't receive any response, but rest assured, your name has been stored successfully.</p>
<p>Just like we set up the user name, we also need to set up the user email. This email will be associated with each commit you make. Let's learn how to use the <code>git config --global</code> command to set your email globally on your local machine.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Set an email address that will be associated with each history marker</span>
$ git config --global user.email <span class="hljs-string">"your-email@example.com"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Email.png" alt="Email" width="600" height="400" loading="lazy"></p>
<p>Make sure to replace this with your actual email used in your GitHub account.</p>
<p>Now that we have finished setting up your username and email for Git and GitHub, let's verify that everything is configured correctly.</p>
<p>To do this, use the following command:</p>
<pre><code class="lang-bash">git config --global --list
</code></pre>
<p>This command will list the username and email being used in the console for you to see.</p>
<p>You should see some information displayed in your terminal.</p>
<h2 id="how-to-set-the-default-editor"> How to Set the Default Editor</h2>

<p>In modern development, having a code editor can significantly simplify your workflow, especially when you're focused on coding.</p>
<p>Now, let's see how to configure Git to use a default editor by using this command:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Set the default editor for Git</span>
$ git config --global core.editor <span class="hljs-string">"code --wait"</span>
</code></pre>
<p><em>Congratulations!</em> You have successfully configured Git on your local machine. You are now ready to start using Git for your projects.</p>
<h2 id="how-to-create-a-repository-using-the-github-website">  How to Create a Repository Using the Github Website </h2>

<p>Creating a repository is the first step in using Git. A repository is a storage location where your projects live, containing all the files and revision history. </p>
<p>In this section, I will guide you through the process of creating a repository on GitHub. </p>
<p>There are two ways to create a repository: using the <code>GitHub website</code> or the command line. Let's get started. In this section, we'll focus on creating a repository using the GitHub website and the command line.</p>
<p>After logging into your GitHub account, you can create a new repository by following these steps:</p>
<ol>
<li>Click on the <code>+</code> sign in the top right corner of the page and select <code>New Repository</code> from the dropdown menu.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Github-create-repo.png" alt="Github-create-repo" width="600" height="400" loading="lazy"></p>
<p>Above is an image of the new repository button on GitHub.</p>
<ol start="2">
<li><p>You will be directed to a new page where you can fill in the details of your new repository. You will need to enter the following information:</p>
</li>
<li><p><code>Repository name</code>: This is the name of your repository. It should be unique and descriptive.</p>
</li>
<li><code>Description</code>: A brief description of your repository.</li>
<li><code>Public or Private</code>: You can choose to make your repository public or private. Public repositories are visible to everyone, while private repositories are only visible to you and the people you share them with.</li>
<li><code>Initialize</code> this repository with a README: You can choose to initialize your repository with a README file. This is useful if you want to provide information about your project or instructions on how to use it.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/github-repo-infor.png" alt="github-repo-infor" width="600" height="400" loading="lazy"></p>
<p>The image above shows the form where you'll fill in the details of your new repository.</p>
<ol start="3">
<li>Once you have filled in the details, click on the <code>Create Repository</code> button to create your new repository.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/github-create-repo-button.png" alt="github-create-repo-button" width="600" height="400" loading="lazy"></p>
<p>The image above shows the <code>Create Repository</code> button_.</p>
<p><em>Congratulations!</em> You have successfully created a new repository on GitHub. You can now start adding files and making changes to your repository.</p>
<p>You should see a page like the one below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/github-new-repo.png" alt="github-new-repo" width="600" height="400" loading="lazy"></p>
<p>Now let's create a repository using the command line.</p>
<h2 id="how-to-create-a-repository-using-the-git-command-line">  How to Create a Repository Using the Git Command Line </h2>


<p>To create a new <code>repository</code> using the command line, you need to follow these steps:</p>
<ol>
<li><p>Open your terminal and navigate to the directory where you want to create your new repository.</p>
</li>
<li><p>Use the <code>git init</code> command to create a new repository. This command will create a new directory called <code>.git</code> in your current directory, which will contain all the necessary files for your repository.</p>
</li>
</ol>
<pre><code class="lang-bash">
<span class="hljs-comment"># initialize a new repository called my-project</span>

$ git init my-project
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/terminal-init.png" alt="terminal-init" width="600" height="400" loading="lazy"></p>
<p>The image above shows the command to initialize a new repository called <code>my-project</code>.</p>
<ol start="3">
<li>Once you have created your new repository, you can start adding files and making changes to it. You can also connect your local repository to a remote repository on GitHub by following the instructions provided on the GitHub website.</li>
</ol>
<p><em>Congratulations!</em> You have successfully created a new repository using the command line. </p>
<p>Now we have successfully created a repository using the GitHub website and the command line – but how do we connect them? Now let's learn how to connect a local repository to a remote repository on GitHub.</p>
<h2 id="how-to-connect-a-local-repository-to-a-remote-repository-on-github">  How to Connect a Local Repository to a Remote Repository on GitHub </h2>

<p>To connect your local repository to a remote repository on GitHub, you need to follow these steps:</p>
<ol>
<li><p>On GitHub, navigate to the main page of the repository you created earlier.</p>
</li>
<li><p>Click on the <code>Code</code> button to copy the URL of your repository.</p>
</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Github-code-url-cope.png" alt="Github-code-url-cope" width="600" height="400" loading="lazy"></p>
<p>The image above shows the code button to copy the URL of your repository.</p>
<ol start="3">
<li><p>In your terminal, navigate to the directory of your local repository.</p>
</li>
<li><p>Use the <code>git remote add origin</code> command to connect your local repository to the remote repository on GitHub. Replace repository-URL with the URL of your repository.</p>
</li>
</ol>
<pre><code class="lang-bash">$ git remote add origin repository-url
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/terminal-remote-add-origin.png" alt="terminal-remote-add-origin" width="600" height="400" loading="lazy"></p>
<p>The image above shows the command to connect your local repository to the remote repository on GitHub.</p>
<ol start="5">
<li>Once you have connected your local repository to the remote repository on GitHub, you can start pushing your changes to the remote repository using the <code>git push</code> command.</li>
</ol>
<p><em>Congratulations!</em> You have successfully connected your local repository to the remote repository on GitHub.</p>
<h2 id="how-to-pull-changes-from-a-remote-repository-to-a-local-repository">   How to Pull Changes from a Remote Repository to a Local Repository </h2>

<p>To pull changes from the remote repository to the local repository, you need to follow these steps:</p>
<ol>
<li><p>In your terminal, navigate to the directory of your local repository.</p>
</li>
<li><p>Use the <code>git pull</code> command to pull changes from the remote repository to the local repository.</p>
</li>
</ol>
<pre><code class="lang-bash">
$ git pull origin main
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/terminal-git-pull.png" alt="terminal-git-pull" width="600" height="400" loading="lazy"></p>
<p>The image above shows the command to pull changes from the remote repository to the local repository.</p>
<p>After that, navigate the main branch by using the following command:</p>
<pre><code class="lang-bash">
$ git checkout main
</code></pre>
<p><em>Congratulations!</em> You have successfully pulled changes from a remote repository to a local repository. Your local repository is now up-to-date with the remote repository on GitHub*.</p>
<h2 id="how-to-work-with-git-commands"> How to Work with Git Commands </h2>

<p>In this section, we will cover some of the most commonly used Git commands and their functions. These commands will help you navigate your way through the Git workflow in your GitHub repository. Let's get started. </p>
<p>First, I will add some files so that we can start using the Git commands.</p>
<h2 id="how-to-make-changes-to-a-file"> How to Make Changes to a File </h2>

<p>To make changes to a file in Git, you need to follow these steps:</p>
<ol>
<li><p>Open your terminal and navigate to the directory of your local repository.</p>
</li>
<li><p>Use a text editor to make changes to the file. For example, you can use the <code>code</code> command to open the file in Visual Studio Code.</p>
</li>
</ol>
<pre><code class="lang-bash">
$ code file-name  <span class="hljs-comment"># For example, code index.html</span>
</code></pre>
<ol start="3">
<li>Once you have made your changes, save the file and close the text editor.</li>
</ol>
<p><em>Congratulations!</em> You have successfully made changes to a file in your local repository. Next, let's proceed to the next step: staging changes.</p>

<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/file-cahnge-added.png" alt="file-cahnge-added" width="600" height="400" loading="lazy"></p>
<p>The image above shows the new file I added which is a React and TypeScript app.</p>
<p>Visual Studio Code (VS Code) includes a source control feature that allows you to interact directly with your GitHub repository. This feature supports a variety of operations, including staging, committing, pushing, and pulling changes. </p>
<p>In addition to the source control feature, you can also use the integrated terminal in VS Code to interact with your GitHub repository. </p>
<p>Currently, if you look at the source control section in VS Code, you'll see the file we added listed under changes. </p>
<p>Next, let's explore how to use the terminal to interact with our GitHub repository.</p>
<p>Open your terminal and navigate to the directory of your local repository.</p>
<p>Now, let's use the <code>git status</code> command to check the status of the current branch.</p>
<h2 id="how-to-check-the-status-of-the-current-branch">  How to Check the Status of the Current Branch </h2>

<p>The <code>git status</code> command shows the status of the current branch, including any changes that have been made to the files in the repository. It provides information about which files have been modified, which files have been staged, and which files are untracked. </p>
<p>This command is useful for understanding the current state of your repository and determining which files need to be staged and committed.</p>
<pre><code class="lang-bash"><span class="hljs-comment">#  Check the status of the current branch</span>

$ git status  <span class="hljs-comment"># On branch master</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/terminal-git-status.png" alt="terminal-git-status" width="600" height="400" loading="lazy"></p>
<p>The image above shows the command to check the status of the current branch.</p>
<p>You may notice that parts of the file are highlighted in different colors. The <code>red</code> color indicates that the file has been modified, while the <code>green</code> color signifies that the file has been added to the staging area. </p>
<p>Currently, all files should be highlighted in <code>red</code> because we have not yet added any files to the staging area.</p>
<p>Let's add the file to the staging area using the <code>git add</code> command.</p>
<h2 id="how-to-stage-changes">  How to Stage Changes </h2>

<p>The <code>git add</code> command adds files to the staging area, preparing them for the next commit. You can add all the files in the current directory to the staging area using the <code>git add .</code> command. </p>
<p>If you want to add a specific file, use the <code>git add &lt;file-name&gt;</code> command, replacing <code>&lt;file-name&gt;</code> with the name of your file. This process is known as staging, which prepares files for the next commit.</p>
<pre><code class="lang-bash">
<span class="hljs-comment"># Add files to the staging area</span>

$ git add .  <span class="hljs-comment"># Changes to be committed:</span>

or 

$ git add file-name  <span class="hljs-comment"># Changes to be committed:</span>
</code></pre>
<p>Think of it like this: getting into the car is like adding files to the staging area, and driving the car is like making a commit. </p>
<p>Now, let's use the <code>git commit</code> command to commit the changes to the current branch.</p>
<h2 id="how-to-commit-changes">  How to Commit Changes </h2>

<p>The <code>git commit</code> command commits the changes to the current branch. You can use the <code>-m</code> flag to add a message to your commit. This message should provide a brief summary of the changes you've made.</p>
<p>For instance, "Initial commit" could be your commit message. This command is used to save the changes to the local repository.</p>
<pre><code class="lang-bash">

<span class="hljs-comment"># Commit changes to the current branch</span>

$ git commit -m <span class="hljs-string">"Commit message"</span>   <span class="hljs-comment"># For example, git commit -m "Initial commit"</span>
</code></pre>
<p>We've successfully committed the changes to the current branch. Next, we'll push these changes to the remote repository on GitHub using the <code>git push</code> command.</p>
<h2 id="how-to-push-changes-to-a-remote-repository">  How to Push Changes to a Remote Repository </h2>

<p>The <code>git push</code> command pushes changes from your local repository to a remote repository on GitHub. You can use the <code>git push</code> command to push changes from your local repository to the remote repository on GitHub. This process is essential for updating the remote repository with the changes you've made locally.</p>
<pre><code class="lang-bash">
<span class="hljs-comment"># Push changes to a remote repository</span>

$ git push origin main  <span class="hljs-comment"># For example, git push origin master</span>
</code></pre>
<p><em>Congratulations!</em> You have successfully pushed your changes to the remote repository on GitHub. You can now view your changes on the GitHub website.  </p>
<p>Now that we've successfully pushed our changes to the remote repository on GitHub, let's proceed to the next step: creating a branch. </p>
<p>Depending on your PC environment, your local repository may have a default branch named either <code>main</code> or <code>master</code>. In this guide, we'll use <code>main</code> as the default branch name, aligning with GitHub's recent change from <code>master</code> to <code>main</code>.</p>
<p>Before we start adding files, let's ensure our local repository is up-to-date with the remote repository by pulling any changes. </p>
<p>If the term <code>branch</code> seems unfamiliar, don't worry. In the next section, we'll cover how to create a branch and how to pull changes from the remote repository to the local repository.</p>
<h2 id="how-to-create-a-branch">  How to Create a Branch </h2>

<p>Branching is a fundamental concept in Git. It allows you to diverge from the main line of development and continue working without impacting the main codebase. </p>
<p>In this section, I'll guide you through the process of creating a new branch using the <code>git branch</code> command. This command creates a new branch but does not switch to it. In the following steps, we'll also cover how to switch to your newly created branch using the <code>git checkout</code> command. Let's dive in.</p>
<p>To create a new branch, you need to follow these steps:</p>
<ol>
<li><p>Open your terminal and navigate to the directory of your local repository.</p>
</li>
<li><p>Use the <code>git branch</code> command to create a new branch. Replace <code>&lt;branch-name&gt;</code> with the name of your new branch.</p>
</li>
</ol>
<pre><code class="lang-bash">
<span class="hljs-comment"># Create a new branch</span>

$ git branch &lt;branch-name&gt;  <span class="hljs-comment"># For example, git branch feature-branch</span>
</code></pre>
<p>The <code>git branch</code> command creates a new branch but does not switch to it. To switch to your newly created branch, use the <code>git checkout</code> command.</p>
<pre><code class="lang-bash">
<span class="hljs-comment"># Switch to the newly created branch</span>

$ git checkout &lt;branch-name&gt;  <span class="hljs-comment"># For example, git checkout feature-branch</span>
</code></pre>
<p>The <code>git checkout</code> command is used to switch from one branch to another. Replace <code>&lt;branch-name&gt;</code> with the name of your new branch. In this case, we're switching to the <code>feature-branch</code> branch. But we if want to delete the branch, we can use the following command:</p>
<pre><code class="lang-bash">

<span class="hljs-comment"># Delete a branch</span>

$ git branch -d &lt;branch-name&gt;  <span class="hljs-comment"># For example, git branch -d feature-branch</span>
</code></pre>
<p>The <code>git branch -d</code> command is used to delete a branch. Replace <code>&lt;branch-name&gt;</code> with the name of the branch you want to delete. In this case, we're deleting the <code>feature-branch</code> branch.</p>
<p><em>Congratulations!</em> You have successfully created a new branch and switched to it. You can now start adding files and making changes to your new branch.</p>
<p>Now you know how to create GitHub repository, connect a local repository to a remote repository on GitHub, pull changes from a remote repository to a local repository, work with Git commands, and create a branch. </p>
<p>Let's proceed to the next section, where we'll cover how to create a pull request. This is a crucial step in the collaborative workflow, as it allows you to propose changes and request a review from other collaborators.</p>
 <h2 id="how-to-create-a-pull-request"> How to Create a Pull Request  </h2>

<p>A pull request is a proposal to merge changes from one branch into another. It's a widely-used method for creating and reviewing code. In this section, I'll guide you through the process of creating a pull request using the GitHub website. </p>
<p>For instance, let's say you have a branch named <code>feature-branch</code> and you want to merge it into the <code>main</code> branch. We'll walk you through how to create a pull request for this scenario. Let's get started.</p>
<p>First, let's make a change to our feature branch by adding a file to it:</p>
<pre><code class="lang-bash">
$ git checkout feature-branch
</code></pre>
<p>You should see something like this in your terminal:</p>
<pre><code class="lang-bash">
git checkout feature-branch
Switched to a new branch <span class="hljs-string">'feature-branch'</span>
branch <span class="hljs-string">'feature-branch'</span> <span class="hljs-built_in">set</span> up to track <span class="hljs-string">'origin/feature-branch'</span>.
</code></pre>
<p>Now, let's add a file to the feature branch. </p>
<pre><code class="lang-bash">
$ touch feature-branch-file.txt
</code></pre>
<p>After running the command, you should see a new file called <code>feature-branch-file.txt</code> in your directory.</p>
<p>The <code>touch</code> command is used to create a new file. Replace <code>feature-branch-file.txt</code> with the name of your file. In this case, we're creating a new file called <code>feature-branch-file.txt</code>.</p>
<p>Now, let's add some content to the file.</p>
<pre><code class="lang-bash">
$ <span class="hljs-built_in">echo</span> <span class="hljs-string">"This is a file in the feature branch"</span> &gt;&gt; feature-branch-file.txt
</code></pre>
<p>This command adds the text "This is a file in the feature branch" to the <code>feature-branch-file.txt</code> file.</p>
<p>The <code>echo</code> command is used to add content to a file. In this case, we're adding the text "This is a file in the feature branch" to the <code>feature-branch-file.txt</code> file.</p>
<p>Now that we have some text in the file, let's stage and commit the changes to the feature branch.</p>
<pre><code class="lang-bash">
$ git add .
</code></pre>
<p>The <code>git add .</code> command stages all the changes in the current directory.</p>
<pre><code class="lang-bash">

$ git commit -m <span class="hljs-string">"Add file to feature branch"</span>
</code></pre>
<p>The <code>git commit -m</code> command commits the changes to the current branch. Replace <code>Add file to feature branch</code> with your own descriptive message. This message should provide a brief summary of the changes you've made. In this case, we're committing the changes to the feature branch.</p>
<p>Now, let's push the changes to the remote repository on GitHub.</p>
<pre><code class="lang-bash">
$ git push origin feature-branch
</code></pre>
<p>The <code>git push</code> command is used to push changes from your local repository to the remote repository on GitHub. Replace <code>feature-branch</code> with the name of your branch. In this case, we're pushing the changes to the <code>feature-branch</code> branch.</p>
<p><em>Congratulations!</em> You have successfully pushed your changes to the remote repository on GitHub. You can now view your changes on the GitHub website.</p>
<p>Now when you open your GitHub repository, you should see a message indicating that you recently pushed a new branch. You can click on the <code>Compare &amp; pull request</code> button to create a pull request for the <code>feature-branch</code> branch. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/github-compare-pull-request.png" alt="github-compare-pull-request" width="600" height="400" loading="lazy"></p>
<p>The image above shows the <code>Compare &amp; pull request</code> button on GitHub.</p>
<p>After clicking on the <code>Compare &amp; pull request</code> button, you will be directed to a new page where you can fill in the details of your pull request. </p>
<p>You will need to enter the following information:</p>
<ul>
<li>Title: a brief summary of your pull request.</li>
<li>Description: a detailed description of your pull request, including information about the changes you've made and why you've made them.</li>
<li>Reviewers: you can choose to request a review from specific collaborators.</li>
<li>Assignees: you can choose to assign your pull request to specific collaborators.</li>
<li>Labels: you can choose to add labels to your pull request to categorize it.</li>
<li>Projects: you can choose to add your pull request to a project board.</li>
<li>Milestone: you can choose to add your pull request to a milestone.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/github-pull-request-form.png" alt="github-pull-request-form" width="600" height="400" loading="lazy"></p>
<p>The image above shows the form to fill in the details of your pull request.</p>
<p>You can decide to file the details of your pull request or create the pull request. After creating the pull request, you can view it on the GitHub website. You can also request a review from specific collaborators and make changes to your pull request if necessary. </p>
<p>Once your pull request has been reviewed and approved, you can merge it into the <code>main</code> branch. In our case we not going to file the form but we are going to create the pull request.</p>

<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/github-pull-request-created.png" alt="github-pull-request-created" width="600" height="400" loading="lazy"></p>
<p>The image above shows the pull request created on GitHub.</p>
<p>Now that we have created a pull request, let's proceed to the next section, where we'll cover how to merge a pull request. This is the final step in the collaborative workflow, as it allows you to incorporate changes into the main codebase.</p>
<h2 id="how-to-merge-a-pull-request">How to Merge a Pull Requset  </h2>

<p>Merging a pull request signifies the integration of changes from one branch into another, often the main branch. This step is pivotal in collaborative workflows, enabling the assimilation of modifications into the primary codebase. </p>
<p>In this section, we'll navigate the process of merging a pull request via the GitHub website. </p>
<p>After creating a pull request, you can merge it into the <code>main</code> branch by following these steps:</p>
<ol>
<li><p>On GitHub, navigate to the main page of the repository where you created the pull request.</p>
</li>
<li><p>Click on the <code>Pull requests</code> tab to view the list of pull requests.</p>
</li>
</ol>

<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/github-pull-request-tab.png" alt="github-pull-request-tab" width="600" height="400" loading="lazy"></p>
<p>The image above shows the <code>Pull requests</code> tab on GitHub.</p>
<ol start="3">
<li><p>Click on the pull request you want to merge.</p>
</li>
<li><p>Click on the <code>Merge pull request</code> button to merge the pull request into the <code>main</code> branch.</p>
</li>
<li><p>Click on the <code>Confirm merge</code> button to confirm the merge.</p>
</li>
</ol>
<p>After that you should see a message indicating that the pull request has been successfully merged. You can also delete the branch after merging the pull request.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/github-pull-request-merged.png" alt="github-pull-request-merged" width="600" height="400" loading="lazy"></p>
<p>Now you have successfully merged the pull request into the <code>main</code> branch. You can now delete the <code>feature-branch</code> branch, as it is no longer needed.  </p>
 <h2 id="wrapping-up"> Wrapping Up </h2>

<p>Throughout this guide, we've delved into the core concepts of Git and GitHub, equipping you with a robust understanding of version control and collaborative practices. </p>
<p>We've navigated the essential Git operations, including setting up a repository, linking the local repository to its remote counterpart on GitHub, synchronizing changes between the local and remote repositories, executing Git commands, branching, initiating pull requests, and merging those requests. </p>
<p>Mastering these principles will significantly enhance your coding workflow, facilitate seamless team collaboration, and enable meaningful contributions to open-source projects. </p>
<p>I trust that this guide has instilled in you the knowledge and confidence to excel in your programming journey and start contributing to open source projects. Here's to your success in coding!</p>
<p>You can contact me on <a target="_blank" href="https://twitter.com/Clifftech_Dev">Twitter</a> or <a target="_blank" href="https://www.linkedin.com/in/isaiah-clifford-opoku/">LinkedIn</a> for any questions or feedback. I'd love to hear from you!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Git Fundamentals – A Handbook on Day-to-Day Development Tasks ]]>
                </title>
                <description>
                    <![CDATA[ Welcome to my comprehensive guide on Git, the distributed version control system that has revolutionized collaboration and code management in software development.  Whether you're a seasoned developer or just starting your journey in programming, und... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-git-basics/</link>
                <guid isPermaLink="false">66c7218e55df43f1418b5b2c</guid>
                
                    <category>
                        <![CDATA[ beginner ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Samyak Jain ]]>
                </dc:creator>
                <pubDate>Wed, 03 Apr 2024 03:57:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/Learn-Git-Basics-Cover-3--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Welcome to my comprehensive guide on Git, the distributed version control system that has revolutionized collaboration and code management in software development. </p>
<p>Whether you're a seasoned developer or just starting your journey in programming, understanding Git is essential to gain proper control over your code, efficiently managing your projects and collaborating with others. </p>
<p>In this tutorial, I'll take you through the fundamentals of Git, covering everything from its basic workflow to advanced branching strategies and rebasing techniques. </p>
<p>By the end of this guide, you'll have a solid understanding of Git's core concepts and be confident and well equipped with the skills to effectively use it in your development workflow.</p>
<h2 id="heading-prerequisites">Prerequisites:</h2>
<p>All you need to bring to the table is a curious and eager-to-learn mindset. This guide is crafted with beginners in mind, so no prior knowledge of version control systems or programming is required. Whether you're a complete novice or have some experience with coding, you'll find this tutorial accessible and easy to follow.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents:</strong></h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-git">What is Git?</a><br>– <a class="post-section-overview" href="#heading-what-makes-git-different-from-other-version-control-systems">Difference from other version control systems</a><br>– <a class="post-section-overview" href="#heading-the-three-states-and-basic-git-workflow">The Three States and Basic Git Workflow</a></li>
<li><a class="post-section-overview" href="#heading-first-time-git-setup">First-Time Git Setup</a></li>
<li><a class="post-section-overview" href="#heading-how-to-get-help-in-git">Get Help in Git</a></li>
<li><a class="post-section-overview" href="#heading-how-to-get-a-git-repository">How to Get a Git Repository</a><br>– <a class="post-section-overview" href="#heading-1-how-to-initialize-a-repository-in-an-existing-directory-in-git">Initialize a Repository in an Existing Directory</a><br>– <a class="post-section-overview" href="#heading-2-how-to-clone-an-existing-repository-in-git">Clone an Existing Repository in Git</a></li>
<li><a class="post-section-overview" href="#heading-how-to-record-changes-to-the-repository">How to Record Changes to the Repository</a></li>
<li><a class="post-section-overview" href="#heading-how-to-view-commit-history-in-git">View Commit History in Git</a></li>
<li><a class="post-section-overview" href="#heading-how-to-undo-things-in-git">Undo Things in Git</a></li>
<li><a class="post-section-overview" href="#how-to-work-with-remote-repositories-in-git">Remote Repositories in Git</a></li>
<li><a class="post-section-overview" href="#heading-tagging-in-git">Tagging in Git</a></li>
<li><a class="post-section-overview" href="#heading-git-aliases">Git Aliases</a></li>
<li><a class="post-section-overview" href="#heading-git-branching">Git Branching</a><br>– <a class="post-section-overview" href="#heading-how-to-create-a-new-branch-in-git">Create a New Branch in Git</a><br>– <a class="post-section-overview" href="#heading-understanding-branches">Understanding Branches</a><br>– <a class="post-section-overview" href="#heading-how-to-switch-to-another-branch-in-git">Switch to Another Branch in Git</a><br>– <a class="post-section-overview" href="#how-to-visualise-branches-in-git-">Visualise Branches in Git</a></li>
<li><a class="post-section-overview" href="#heading-how-to-manage-branches-in-git">How to Manage Branches in Git</a><br>– <a class="post-section-overview" href="#heading-how-to-manage-merged-branches">Managing Merged Branches</a><br>– <a class="post-section-overview" href="#heading-how-to-rename-branches">Renaming Branches</a><br>– <a class="post-section-overview" href="#heading-how-to-change-the-default-branch-name">Changing the Default Branch Name</a></li>
<li><a class="post-section-overview" href="#heading-branching-workflow">Branching Workflow</a></li>
<li><a class="post-section-overview" href="#heading-rebasing-in-git">Rebasing in Git</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-what-is-git">What is Git?</h2>
<p>Git is a distributed version control system that helps you and your team collaborate effectively while keeping your project's history safe. It's like having a time machine for your code!</p>
<h3 id="heading-what-makes-git-different-from-other-version-control-systems">What makes Git different from other Version Control Systems?</h3>
<h4 id="heading-conceptual-difference">Conceptual Difference:</h4>
<p>The big thing that sets Git apart from other tools is how it thinks about data. Instead of storing changes to files, Git thinks of its data as a series of snapshots of your project, means, every time you make a change and save it (commit), Git takes a snapshot of all your files at that moment. If a file hasn't changed, Git just keeps a link to the previous identical file.</p>
<h4 id="heading-local-operations">Local Operations:</h4>
<p>With Git, most things you do don't need a connection to a server. Because you have the entire project history on your computer, operations are super fast. You can browse project history or see changes between versions without waiting for a server.</p>
<h4 id="heading-data-integrity">Data Integrity:</h4>
<p>Git makes sure nothing gets lost or corrupted. Every file and directory is checksummed, and Git knows if anything changes. </p>
<p>Git uses a SHA-1 hash, a unique code for each version of a file. If any changes are made to the content, even a single character, it will result in a different SHA-1 hash.</p>
<h4 id="heading-append-only-model">Append-Only Model:</h4>
<p>In Git, almost everything adds data to the project, making it hard to accidentally lose information. Once you commit changes, they are safely stored. Experimenting is less risky with Git.</p>
<h3 id="heading-the-three-states-and-basic-git-workflow">The Three States and Basic Git Workflow</h3>
<p>Understanding Git's three states—modified, staged, and committed—is essential for effective version control:</p>
<ul>
<li><strong>Modified</strong>: Changes made to files in your <strong>Working tree</strong> that are not yet committed.</li>
<li><strong>Staged</strong>: Modifications marked for the next commit in the <strong>Staging area</strong> to be included in next commit.</li>
<li><strong>Committed</strong>: Changes permanently stored in the local <strong>Git directory</strong>.</li>
</ul>
<p><strong>Basic Git Workflow</strong>:</p>
<ol>
<li><strong>Modify files</strong> in your working tree.</li>
<li><strong>Stage changes</strong> you want to include in the next commit.</li>
<li><strong>Commit changes</strong>, which permanently saves snapshots to the Git directory.</li>
</ol>
<h2 id="heading-first-time-git-setup">First-Time Git Setup</h2>
<p>Setting up Git for the first time involves customizing your Git environment to suit your preferences. But first, you'll need to download Git from <a target="_blank" href="https://git-scm.com/download/win">Git - Downloads</a> or use the Chocolatey package. Then just follow the installation instructions and you should be good to go.</p>
<h3 id="heading-git-configuration">Git Configuration</h3>
<p>We use the <code>git config</code> tool to customize our Git environment. This tool allows us to both retrieve and set configuration variables that dictate how Git operates. These variables can be stored in three different locations:</p>
<ol>
<li><strong>System-wide Configuration:</strong><br>Stored in the <code>/etc/gitconfig</code> file, these settings apply to all users on the system and all repositories. We can interact with this file using the <code>--system</code> option with <code>git config</code>.</li>
<li><strong>User-specific Configuration:</strong><br>Stored in <code>~/.gitconfig</code> or <code>~/.config/git/config</code>, these values are specific to you as a user. We can interact with this file using the <code>--global</code> option with <code>git config</code>, affecting all repositories you work with on your system.</li>
<li><strong>Repository-specific Configuration:</strong><br>Stored in the <code>.git/config</code> file within a specific repository, these settings override global configurations and apply only to that repository.</li>
</ol>
<p>Each level of configuration overrides values from the previous level. For instance, values in <code>.git/config</code> will override those in <code>~/.gitconfig</code>.</p>
<p>To view all configuration settings and their sources/origins:</p>
<pre><code class="lang-bash">$ git config --list --show-origin
</code></pre>
<h4 id="heading-how-to-configure-your-identity-in-git">How to Configure your identity in Git:</h4>
<p>Identity in Git is used for attributing commits properly. Let's set up your user name and email address.</p>
<pre><code class="lang-bash">$ git config --global user.name <span class="hljs-string">"Your Name"</span>
$ git config --global user.email <span class="hljs-string">"your.email@example.com"</span>
</code></pre>
<p>If you need to override this for specific projects, you can omit the <code>--global</code> option when setting the values, and they'll only apply to that particular repository.</p>
<h4 id="heading-how-to-configure-your-default-text-editor">How to Configure Your Default Text Editor</h4>
<p>After configuring your identity, it's important to set up your default text editor in Git. This text editor will be used when Git needs you to input messages, such as when writing commit messages or resolving merge conflicts.</p>
<p>By default, Git uses your system's default text editor. However, if you prefer to use a different text editor, such as Emacs, you can set it up like this:</p>
<pre><code class="lang-bash">$ git config --global core.editor <span class="hljs-string">"emacs"</span>
</code></pre>
<p>On Windows systems, setting up a different text editor requires specifying the full path to its executable file. For example, if you want to use Notepad++, you might use a command like this:</p>
<pre><code class="lang-bash">$ git config --global core.editor <span class="hljs-string">"'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"</span>
</code></pre>
<p>Make sure you provide the correct path to the executable file of your text editor.</p>
<p>By the way, these – <code>"-multiInst -notabbar -nosession -noPlugin"</code> – are options used to customize the behavior of Notepad++ when it is launched by Git.</p>
<h4 id="heading-how-to-change-default-branch-name-in-git-optional">How to Change default branch name in Git (optional):</h4>
<p>By default, when you initialize a new repository with <code>git init</code>, Git creates a branch named <code>master</code>. But from Git version 2.28 onwards, you have the option to set a different name for the initial branch.</p>
<pre><code class="lang-bash">$ git config --global init.defaultBranch main
</code></pre>
<h4 id="heading-how-to-check-configurationsettings-in-git">How to Check Configuration/settings in Git:</h4>
<p>You can view your Git configuration using:</p>
<pre><code class="lang-bash">$ git config --list
$ git config user.name  <span class="hljs-comment"># To check a specific setting (e.g., user name):</span>
</code></pre>
<p>The <code>git config --list</code> command lists all the configuration settings Git can find at that moment.</p>
<h2 id="heading-how-to-get-help-in-git">How to Get Help in Git</h2>
<p>There are three equivalent ways to get detailed help for any Git command:</p>
<ol>
<li>Git Help Command: <code>$ git help &lt;verb&gt;</code></li>
<li>Using the <code>--help</code> Option: <code>$ git &lt;verb&gt; --help</code></li>
<li>Manual pages (manpages): <code>$ man git-&lt;verb&gt;</code></li>
</ol>
<p>Replace the <code>&lt;verb&gt;</code> with whatever command you need help with. For example, to get help for the <code>config</code> command, you can type:</p>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">help</span> config
or
$ man git-config
</code></pre>
<p>These commands work offline as well, which is handy.</p>
<p>If you need quick, concise information about the available options for a Git command, you can use the <code>-h</code> option:</p>
<pre><code class="lang-bash">$ git add -h    <span class="hljs-comment"># This will display options available for the add command</span>
</code></pre>
<h2 id="heading-how-to-get-a-git-repository">How to Get a Git Repository</h2>
<p>To start using Git, you typically obtain a Git repository. There are essentially two main ways to get started:</p>
<h3 id="heading-1-how-to-initialize-a-repository-in-an-existing-directory-in-git">1. How to Initialize a Repository in an Existing Directory in Git</h3>
<p>Open a terminal or command prompt. Use the <code>cd</code> command to change the directory to your project's location: <code>cd /path/to/your/project</code>.</p>
<p>Once you're in your project directory, initialize a Git repository by running:</p>
<pre><code class="lang-bash">$ git init
</code></pre>
<p>This command creates a new subdirectory named <code>.git</code> where Git stores all the necessary files for your Git repository. At this point, none of your project files are being tracked yet.</p>
<p>Now, Suppose you have certain files that you want Git to start tracking:</p>
<pre><code class="lang-bash">$ git add *.py        <span class="hljs-comment"># Add all Python files</span>
$ git add README.md   <span class="hljs-comment"># Add README file</span>
$ git commit -m <span class="hljs-string">'Initial commit'</span>
</code></pre>
<p><code>git add</code> adds files to the staging area indicating that you want to include them in the next commit, and then commit the changes. The <code>-m</code> flag allows you to add a descriptive message to the commit.</p>
<h3 id="heading-2-how-to-clone-an-existing-repository-in-git">2. How to Clone an Existing Repository in Git:</h3>
<p>The second way to obtain a Git repository is by cloning an existing one. This is useful when you want to work on a project that already exists elsewhere (for example, a project you'd like to contribute to).</p>
<p><strong>Note:</strong> When you clone a repository, Git retrieves a full copy of nearly all data that the server has. This includes every version of every file for the history of the project. This means you'll have a complete copy of the repository's history on your local machine.</p>
<p>To clone a repo, Use the <code>git clone</code> command followed by the URL of the repo you want to clone. For example, to clone the grok-1 repository, you can use:</p>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">clone</span> https://github.com/xai-org/grok-1.git
</code></pre>
<p>This creates a directory named grok-1, initializes a <code>.git</code> directory inside it, and pulls down all the data for that repository.</p>
<p>BTW, <code>.git</code> is just a convention to signify that the URL points to a Git repository. You can use it or not, it doesn't matter.</p>
<p>If you want to clone into a directory with a different name, you can specify it. To clone the grok-1 repo into a directory named "chatgpt" instead of "grok-1", do this:</p>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">clone</span> https://github.com/xai-org/grok-1.git chatgpt
</code></pre>
<p>Git provides various transfer protocols you can use for cloning repos. The example above uses the <code>https://</code> protocol, but you may also see <code>git://</code> or <code>user@server:path/to/repo.git</code>, which uses the SSH transfer protocol.</p>
<h2 id="heading-how-to-record-changes-to-the-repository">How to Record Changes to the Repository</h2>
<p>Now that you have a Git repository set up, you'll often need to make changes and record those changes in your repository. The process involves tracking files, staging changes, and committing snapshots. Let's explore the steps involved:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/lifecycle.png" alt="Image" width="600" height="400" loading="lazy">
<em>pic credit - https://git-scm.com/</em></p>
<h3 id="heading-1-how-to-check-the-status-of-your-files-in-git">1. How to Check the Status of Your Files in Git:</h3>
<p>When working with a Git repository, it's crucial to understand the status of your files. </p>
<p>Git categorizes files into two types: tracked and untracked. Tracked files are those that Git recognizes, either because they were part of the last snapshot (commit) or have been staged. Untracked files are everything else—files that Git is not currently monitoring. To check the status of your repository:</p>
<pre><code class="lang-bash">$ git status
</code></pre>
<p>This command provides comprehensive information about the current branch, its synchronization status, and the status of your files. </p>
<p><code>git status</code> also suggests actions you can take. For instance, when files are modified but not staged for commit, <code>git status</code> suggests using <code>git add &lt;file&gt;</code> to stage them. It also suggests using <code>git checkout -- &lt;file&gt;</code> to discard changes in the working directory. These suggestions streamline your workflow by providing quick access to relevant Git commands.</p>
<p>Also, <code>git status</code> offers a Short Status mode (<code>git status -s</code>), which presents a more concise view of your changes using symbols like M (modified), A (added), and ?? (untracked) to represent file statuses.</p>
<h3 id="heading-2-how-to-track-new-files-in-git">2. How to Track New Files in Git</h3>
<p>When you create a new file in your project, Git initially considers it untracked. To start tracking a new file, you need to add it to the staging area using the <code>git add</code> command.</p>
<p>For instance, let's create a new file called <code>index.html</code> for our project and add it to the staging area:</p>
<pre><code class="lang-bash">$ touch index.html
$ git add index.html
</code></pre>
<p>After adding, running <code>git status</code> again will show that the <code>index.html</code> file is now tracked and staged for commit.</p>
<h3 id="heading-3-how-to-stage-modified-files-in-git">3. How to Stage Modified Files in Git</h3>
<p>If you modify an existing tracked file, you need to stage the changes using <code>git add</code>. Let's say we modify an existing file called <code>styles.css</code></p>
<pre><code class="lang-bash">$ vim styles.css
</code></pre>
<p>After making changes, stage the file:</p>
<pre><code class="lang-bash">$ git add styles.css
</code></pre>
<p>Now, when you check the status, you'll see both the modified file and the new file staged for commit.</p>
<h3 id="heading-4-how-to-ignore-files-in-git">4. How to Ignore Files in Git</h3>
<p>Often, there are files or directories within a project that aren't intended for Git tracking. These might include log files, build artifacts, or sensitive information like local environment settings (such as *.env or config.json). You can specify these files to be ignored using a <code>.gitignore</code> file.</p>
<p>Create a <code>.gitignore</code> file :</p>
<pre><code class="lang-bash">$ nano .gitignore
</code></pre>
<p>List the patterns of files or directories you want to ignore.:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">echo</span> <span class="hljs-string">'*.log'</span> &gt;&gt; .gitignore
$ <span class="hljs-built_in">echo</span> <span class="hljs-string">'build/'</span> &gt;&gt; .gitignore
</code></pre>
<p>Here, we're telling Git to ignore all files with a <code>.log</code> extension and the <code>build/</code> directory.</p>
<p><strong>Note:</strong> Files already tracked by Git before being added to the <code>.gitignore</code> file will remain tracked. To remove them, you'll need to manually untrack them using Git commands. </p>
<p>Here are some patterns you can use to work more effectively in Git.</p>
<ul>
<li><strong>Target individual files or file extensions precisely:</strong> For example, <code>test.txt</code> ignores only that specific file, while <code>*.log</code> ignores all files ending with <code>.log</code>.</li>
<li><strong>Wildcards for broader matches:</strong> The asterisk (<code>*</code>) wildcard matches any number of characters. For example, <code>*.doc</code> ignores all files with the <code>.doc</code> extension, regardless of their name.</li>
</ul>
<h3 id="heading-5-how-to-view-changes-in-git">5. How to View Changes in Git:</h3>
<p>If you want to see the exact changes you've made to your files before committing, you can use the <code>git diff</code> command.</p>
<p>To see unstaged changes:</p>
<pre><code class="lang-bash">$ git diff
</code></pre>
<p>And to see staged changes:</p>
<pre><code class="lang-bash">$ git diff --cached README.md
</code></pre>
<p><code>git diff</code> provides a detailed view of the actual modifications. Use <code>git diff &lt;filename&gt;</code> to focus on changes within a particular file.</p>
<h3 id="heading-6-how-to-commit-changes">6. How to Commit Changes:</h3>
<p>When you are ready to commit your changes, use the <code>git commit</code> command. This opens your text editor for you to provide a commit message. Alternatively, you can use the <code>-m</code> flag to add a commit message directly:</p>
<p>Once you have staged the changes you want to include in the commit, you can commit them using <code>git commit</code></p>
<pre><code class="lang-bash">$ git commit -m <span class="hljs-string">"Your commit message here"</span>
</code></pre>
<h3 id="heading-7-how-to-remove-files-in-git">7. How to Remove Files in Git:</h3>
<p>If you need to remove a file from Git's tracking, you can use <code>git rm</code>. It remove the file from both the repository and working directory. Suppose you want to remove a file named <code>temp.txt</code>:</p>
<pre><code class="lang-bash">$ git rm temp.txt
</code></pre>
<p>If you only want to remove it from the repository but keep it in the working directory, use the <code>--cached</code> option:</p>
<pre><code class="lang-bash">$ git rm --cached temp.txt
</code></pre>
<h3 id="heading-8-how-to-move-or-rename-files-in-git">8. How to Move (or Rename) Files in Git:</h3>
<p>Git doesn't explicitly track file movements. But you can use <code>git mv</code> to rename or move files within your repository. For example, to rename <code>old_file.txt</code> to <code>new_file.txt</code>:</p>
<pre><code class="lang-bash">$ git mv old_file.txt new_file.txt
</code></pre>
<p>It is equivalent to manually moving the file, followed by using <code>git rm</code> to remove the old file, and then <code>git add</code> to add the new file. <code>git mv</code> basically consolidates these steps into a single command.</p>
<p>These commands form the basic workflow for making changes, staging them, and committing them to your Git repository.</p>
<h2 id="heading-how-to-view-commit-history-in-git">How to View Commit History in Git</h2>
<p>After creating multiple commits or cloning a repository, the <code>git log</code> command allows you to examine the commit history. </p>
<p>By default, it lists commits in reverse chronological order, displaying each commit with its SHA-1 checksum, author's name and email, date, and commit message.<br>Now let's see how can we enhance this output:</p>
<h3 id="heading-how-to-view-commit-differences-in-git">How to View Commit Differences in Git:</h3>
<p>To view the difference introduced in each commit, you can use the <code>-p</code> or <code>--patch</code> option:</p>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">log</span> -p -2    <span class="hljs-comment"># -2 is used to view the differences introduced in each of the last two commits</span>
</code></pre>
<h3 id="heading-how-to-display-statistics-in-git">How to Display Statistics in Git:</h3>
<p>The <code>--stat</code> option provides summarized statistics for each commit, including the modified files, lines added/deleted, and a summary.</p>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">log</span> --<span class="hljs-built_in">stat</span>
</code></pre>
<h3 id="heading-how-to-customize-git-log-output-format">How to Customize Git Log Output Format:</h3>
<p>The <code>--pretty</code> option allows you to alter the log output format. Various options are available for different formats:</p>
<ul>
<li><code>oneline</code>: Concise, single-line summary of each commit. </li>
<li><code>short</code>: Default format with author, date, and message. </li>
<li><code>full</code>: Detailed format with commit hash, author, date, message, and diff.</li>
<li><code>fuller</code>: More detailed format, including full file paths. </li>
<li><code>format</code>: Customize the output using format specifiers.</li>
</ul>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">log</span> --pretty=oneline
</code></pre>
<p><strong>Useful format specifiers for</strong> <code>--pretty=format</code>:</p>
<ul>
<li><code>%h:</code> Abbreviated commit hash</li>
<li><code>%an:</code> Author name</li>
<li><code>%ae:</code> Author email</li>
<li><code>%ad:</code> Author date</li>
<li><code>%s:</code> Subject (commit message)</li>
</ul>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">log</span> --pretty=format:<span class="hljs-string">"%h %an %ad %s"</span>
</code></pre>
<p><strong>ASCII Graph</strong>:</p>
<p>Using <code>--graph</code>, you can also visualize branch and merge history.</p>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">log</span> --pretty=format:<span class="hljs-string">"%h %s"</span> --graph
</code></pre>
<h3 id="heading-how-to-limit-git-log-output">How to Limit Git Log Output:</h3>
<p>In addition to formatting options, <code>git log</code> offers various limiting options to refine the displayed commit history.</p>
<ul>
<li><code>-&lt;n&gt;:</code> Shows only the last n commits.</li>
<li><code>--since, --until:</code> Limits commits to those made after/before the specified date.</li>
<li><code>--author:</code> Shows commits only by a specific author.</li>
<li><code>--grep:</code> Filters commits by a keyword in the commit messages.</li>
<li><code>-S:</code> Shows commits changing</li>
</ul>
<p><strong>Example Usage:</strong> View the last 3 commits by author Abbey since a certain date, with patch details:</p>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">log</span> --author=<span class="hljs-string">"Abbey"</span> --since=<span class="hljs-string">"2024-01-01"</span> -p -3
</code></pre>
<h2 id="heading-how-to-undo-things-in-git">How to Undo Things in Git</h2>
<p>Undoing changes is a common need in Git, and several options are available for this purpose.</p>
<h3 id="heading-how-to-undo-a-commit-in-git">How to Undo a Commit in Git</h3>
<p>If you've committed too early or need to make additional changes to the last commit, use this command:</p>
<pre><code class="lang-bash">$ git commit --amend
</code></pre>
<p>This opens the commit message editor allowing you to modify the message. If no changes were made since the last commit, it simply allows you to edit the commit message.</p>
<p><strong>Note</strong>: Only amend commits that are still local and haven't been pushed yet to avoid issues for collaborators.</p>
<h3 id="heading-how-to-unstage-a-staged-file-with-git-reset">How to Unstage a Staged File with <code>git reset</code></h3>
<p>To unstage a file that was accidentally included, you can use the <code>git reset HEAD &lt;file&gt;</code> command. For example:</p>
<pre><code class="lang-bash">$ git reset HEAD CONTRIBUTING.md
</code></pre>
<p>The file is unstaged, allowing you to make further changes without committing the unintended ones.</p>
<h3 id="heading-how-to-unmodify-a-modified-file-with-git-checkout">How to Unmodify a Modified File with <code>git checkout</code></h3>
<p>Suppose you made some modifications to files that you later realize you don't want to keep. Use <code>git checkout -- &lt;file&gt;</code> to discard the changes made to a file and revert it back to its previous state.</p>
<pre><code class="lang-bash">$ git checkout -- CONTRIBUTING.md
</code></pre>
<p>This will replace the modified file with the last staged or committed version. </p>
<h3 id="heading-undoing-things-with-git-restore">Undoing Things with <code>git restore</code></h3>
<p>Let's explore the alternatives introduced by Git version 2.23.0, <code>git restore</code>, which serves as an alternative to <code>git reset</code> for many undo operations.</p>
<h4 id="heading-how-to-unstage-a-staged-file-with-git-restore">How to unstage a staged file with <code>git restore</code></h4>
<p>If you accidentally stage a file that you didn't intend to commit, you can use <code>git restore --staged &lt;file&gt;</code> to unstage it.</p>
<pre><code class="lang-bash">$ git restore --staged CONTRIBUTING.md
</code></pre>
<p>The file is unstaged, similar to <code>git reset HEAD &lt;file&gt;</code>, allowing you to make further changes without committing the unintended ones.</p>
<h4 id="heading-how-to-unmodify-a-modified-file-with-git-restore">How to unmodify a modified file with <code>git restore</code></h4>
<p>To discard changes made to a file in the working directory, use <code>git restore &lt;file&gt;</code>:</p>
<pre><code class="lang-bash">$ git restore CONTRIBUTING.md
</code></pre>
<p>Similar to <code>git checkout -- &lt;file&gt;</code>, this command discard the changes made to the specified file, reverting it back to the state it was in at the last commit.</p>
<p><strong>Important Note:</strong> Use commands like <code>git reset</code>, <code>git checkout --</code>,<code>git restore</code> cautiously as they can discard local changes permanently. Use these commands when you're certain that the changes are not needed and you don't have any unsaved local changes. </p>
<p><strong>Alternatives:</strong> Stashing and branching are alternative methods to temporarily set aside changes without discarding them entirely. These methods are safer if you're unsure about discarding changes.</p>
<h2 id="heading-how-to-work-with-remotes-in-git">How to Work with Remotes in Git</h2>
<p>Remote repositories are versions of your project hosted on the internet or a network. Collaborating with others involves managing these remote repositories, including adding, removing, and inspecting them. Let's learn how to manage them effectively.</p>
<h3 id="heading-how-to-show-your-remotes-in-git">How to Show Your Remotes in Git</h3>
<p>To start, let's see which remote servers are configured for our project using:</p>
<pre><code class="lang-bash">$ git remote
</code></pre>
<p>This command lists the shortnames of all remote handles we've specified. For instance, if we've cloned a repository, we'll typically see <code>origin</code>, the default name Git assigns to the server we cloned from.</p>
<p>Adding the <code>-v</code> option provides additional details, such as the URLs associated with each remote.</p>
<pre><code class="lang-bash">$ git remote -v
</code></pre>
<p>This displays both the fetch and push URLs for each remote, allowing us to understand where our project is hosted and how we interact with it.</p>
<h3 id="heading-how-to-add-remote-repositories-in-git">How to Add Remote Repositories in Git</h3>
<p>To explicitly add a new remote repository, use <code>git remote add &lt;shortname&gt; &lt;url&gt;</code>:</p>
<pre><code class="lang-bash">$ git remote add example https://github.com/example/example.git
</code></pre>
<p>Here, we've added a remote named <code>example</code> with the specified URL. This allows us to reference this remote repository using the shortname <code>example</code> in our commands.</p>
<h3 id="heading-how-to-fetch-and-pull-from-remotes-in-git">How to Fetch and Pull from Remotes in Git</h3>
<p>To fetch data from a remote repository, we use the <code>git fetch</code> command followed by the remote name:</p>
<pre><code class="lang-bash">$ git fetch origin // Here we are not specifying any particular branch.
</code></pre>
<p>It downloads any new changes from the <code>origin</code> remote repository to our local repository, allowing us to stay up-to-date with the latest developments. </p>
<p>Alternatively, if we want to fetch and merge changes from a remote branch into our current branch in a single step, we use the <code>git pull</code> command:</p>
<pre><code class="lang-bash">$ git pull origin master
</code></pre>
<p>Here, we're specifically pulling changes from the <code>master</code> branch of the <code>origin</code> remote repository into our current branch.</p>
<h3 id="heading-how-to-push-changes-to-remotes-in-git">How to Push Changes to Remotes in Git</h3>
<p>To share our work with others, we push our changes to a remote repository using:</p>
<pre><code class="lang-bash">$ git push origin main
</code></pre>
<p>In this example, we're pushing our local changes to the <code>main</code> branch of the <code>origin</code> remote repository.</p>
<h3 id="heading-how-to-inspect-a-remote-in-git">How to Inspect a Remote in Git</h3>
<p>Lastly, we can inspect a remote repository to gather more information about it using:</p>
<pre><code class="lang-bash">$ git remote show origin
</code></pre>
<p>This command displays details such as the fetch and push URLs, the tracked branches, and local branch configurations associated with the <code>origin</code> remote repository.</p>
<h3 id="heading-how-to-rename-remotes-in-git">How to Rename Remotes in Git</h3>
<p>Now Suppose we want to rename a remote's shortname from <code>example</code> to <code>new-example</code>:</p>
<pre><code class="lang-bash">$ git remote rename example new-example
</code></pre>
<h3 id="heading-how-to-remove-remotes-in-git">How to Remove Remotes in Git</h3>
<p>If, for some reason, we no longer need a remote repository and want to remove it from our project:</p>
<pre><code class="lang-bash">$ git remote remove new-example
or
$ git remote rm new-example
</code></pre>
<p>After removal, the remote-tracking branches and associated configuration settings are also deleted.</p>
<h2 id="heading-tagging-in-git">Tagging in Git</h2>
<p>Tagging in Git is a fundamental feature allowing developers to mark specific points in a repository's history as significant. Typically, tags are used to denote release points, such as v1.0, v2.0, and so forth.</p>
<h3 id="heading-how-to-list-existing-tags-in-git">How to List Existing Tags in Git</h3>
<p>Imagine you're working on a project with multiple release versions. To list existing tags:</p>
<pre><code class="lang-bash">$ git tag
</code></pre>
<p>Also, you can search for tags matching a specific pattern using the <code>-l</code> or <code>--list</code> option. For Example:</p>
<pre><code class="lang-bash">$ git tag -l <span class="hljs-string">"v2.0*"</span>
</code></pre>
<p>This command will list tags like <code>v2.0</code>, <code>v2.0-beta</code>, and so on, matching the specified pattern.</p>
<h3 id="heading-how-to-create-tags-in-git">How to Create Tags in Git</h3>
<p>Git supports two types of tags: lightweight and annotated.</p>
<h4 id="heading-lightweight-tags">Lightweight Tags</h4>
<p>Use lightweight tags when you want to mark a specific commit without adding any additional information. Example:</p>
<pre><code class="lang-bash">$ git tag v1.1-lw
</code></pre>
<p>To view commit information associated with this tag, use:</p>
<pre><code class="lang-bash">$ git show v1.1-lw
</code></pre>
<h4 id="heading-annotated-tags">Annotated Tags</h4>
<p>Annotated tags, on the other hand, contain additional info such as tagger information, date, and a tagging message.</p>
<p>Creating an annotated tag involves using the <code>-a</code> option with the <code>git tag</code> command, along with a tagging message. e.g:</p>
<pre><code class="lang-bash">$ git tag -a v2.0 -m <span class="hljs-string">"Release version 2.0"</span>
</code></pre>
<p>To view detailed information about this tag, including the commit it points to and the tagging message, use:</p>
<pre><code class="lang-bash">$ git show v2.0
</code></pre>
<h3 id="heading-how-to-tag-an-older-commit-in-git">How to tag an older commit in Git</h3>
<p>Sometimes, you might forget to tag a specific commit. Not to worry, you can tag it later by specifying the commit checksum</p>
<p>Example: suppose you forgot to tag a commit with ID <code>abcdefg</code>. You can tag it as follows:</p>
<pre><code class="lang-bash">$ git tag -a v1.2 abcdefg
</code></pre>
<h4 id="heading-how-to-push-tag-to-a-remote-repo-in-git">How to Push Tag to a Remote repo in Git</h4>
<p>To push a specific tag to a remote server, you can use:</p>
<pre><code class="lang-bash">$ git push origin &lt;tagname&gt;
</code></pre>
<p>If you have multiple tags and want to push them all at once, you can use the <code>--tags</code> option:</p>
<pre><code class="lang-bash">$ git push origin --tags
</code></pre>
<h4 id="heading-how-to-delete-tags-in-git">How to Delete Tags in Git</h4>
<p>To delete a tag locally (removing from local repo):</p>
<pre><code class="lang-bash">$ git tag -d &lt;tagname&gt;
</code></pre>
<p>For Example, to delete a lightweight tag named <code>v1.4-lw</code>:</p>
<pre><code class="lang-bash">$ git tag -d v1.4-lw
</code></pre>
<p>On the other hand, you can delete a tag from a remote server in two ways:</p>
<ol>
<li>Using the <code>git push</code> command with a refspec:</li>
</ol>
<pre><code class="lang-bash">$ git push origin :refs/tags/v1.1-lw
</code></pre>
<ol start="2">
<li>Using the <code>--delete</code> option with <code>git push</code>:</li>
</ol>
<pre><code class="lang-bash">$ git push origin --delete v1.1-lw
</code></pre>
<h4 id="heading-how-to-check-out-tags-in-git">How to Check Out Tags in Git</h4>
<p>To view the state of files at a specific tag, you can check out that tag:</p>
<pre><code class="lang-bash">$ git checkout v2.0
</code></pre>
<p>This command puts your repository in a "detached HEAD" state, where you can view files but cannot make changes directly.</p>
<p>If you need to work on files at that tag, it's better to create a new branch:</p>
<pre><code class="lang-bash">$ git checkout -b v2.0-branch v2.0
</code></pre>
<p>Now you can make changes and commits without altering the original tag.</p>
<h2 id="heading-git-aliases">Git Aliases</h2>
<p>Git aliases are shortcuts or custom commands that you can create to simplify and streamline your Git workflow.  </p>
<p>To create a Git alias, you use the <code>git config</code> command with the <code>--global</code> flag to make the alias available across all your Git repositories. </p>
<h3 id="heading-basic-aliases-for-common-commands">Basic Aliases for Common Commands</h3>
<p>You can create aliases for frequently used Git commands to make them easier to remember and type. For example:</p>
<pre><code class="lang-bash">$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
</code></pre>
<p>Now, instead of typing out the full commands, you can use shorter aliases like <code>git co</code>, <code>git br</code>, and <code>git ci</code> respectively.</p>
<p>You can also <strong>create custom aliases for actions you frequently perform</strong> or for improving command readability. Example:</p>
<pre><code class="lang-bash">$ git config --global alias.unstage <span class="hljs-string">'reset HEAD --'</span>
</code></pre>
<p>Now, you can use <code>git unstage &lt;file&gt;</code> instead of <code>git reset HEAD -- &lt;file&gt;</code> to unstage a file.</p>
<h4 id="heading-how-to-combine-multiple-commands-in-git">How to Combine Multiple Commands in Git</h4>
<p>Aliases can also be used to combine multiple Git commands into a single alias. For example, let's create an alias to stage all changes and then commit them with a single command:</p>
<pre><code class="lang-bash">$ git config --global alias.commitall <span class="hljs-string">'!git add -A &amp;&amp; git commit'</span>
</code></pre>
<p>Now, running <code>git commitall</code> will stage all changes (<code>git add -A</code>) and then commit them, saving you time and keystrokes.</p>
<h2 id="heading-git-branching">Git Branching</h2>
<p>Branches in Git provide a powerful way to manage your project's codebase, allowing for parallel development and experimentation without affecting the main codebase.</p>
<p>Git branching allows you to diverge from the main line of development, work on features or fixes, and then merge your changes back. Unlike many other version control systems, Git's branching model is lightweight and efficient, making branching operations nearly instantaneous.</p>
<h3 id="heading-what-are-branches-in-git">What are Branches in Git?</h3>
<p>A branch is a lightweight, movable pointer to a commit. The default branch name is often "master," but it's not special – it's like any other branch.</p>
<p>Creating and switching between branches allows you to work on different features simultaneously.</p>
<h3 id="heading-how-to-create-a-new-branch-in-git">How to Create a New Branch in Git:</h3>
<p>When you want to start working on a new feature or experiment with an idea, you can create a new branch in Git. This new branch serves as a separate line of development, allowing you to make changes without affecting the main branch.</p>
<pre><code class="lang-bash">$ git branch new_feature
</code></pre>
<p>This command creates a new branch named 'new-feature' pointing to the same commit as the current branch. Branches can coexist, and Git keeps a special pointer called <code>HEAD</code> to indicate the current branch.</p>
<h3 id="heading-understanding-branches">Understanding Branches</h3>
<p>Firstly, let's grasp the basics of branches in Git. When you initialize a Git repository, you start with a default branch, usually named 'master' or 'main'. Branches are essentially pointers to commits, enabling you to work on different features or fixes independently. </p>
<p>To view all branches in your repository, use the command:</p>
<pre><code class="lang-bash">$ git branch
</code></pre>
<p>This will display a list of branches with an asterisk (*) indicating the currently checked out branch. For additional information like the last commit on each branch, utilize:</p>
<pre><code class="lang-bash">$ git branch -v
</code></pre>
<h3 id="heading-how-to-switch-to-another-branch-in-git">How to Switch to Another Branch in Git:</h3>
<p>To switch to an existing different branch, use <code>git checkout</code>. </p>
<pre><code class="lang-bash">$ git checkout new_feature
</code></pre>
<p>This command switches the 'HEAD' pointer to the 'new-feature' branch, making it the currently active branch.</p>
<p>To create and switch to a new branch in one operation:</p>
<pre><code class="lang-bash">$ git checkout -b &lt;newbranchname&gt;
</code></pre>
<p>In Git version 2.23 onwards, you can use <code>git switch</code> instead of <code>git checkout</code>.</p>
<ul>
<li>Switch to an existing branch: <code>git switch existing-branch</code>.</li>
<li>Create and switch to new branch: <code>git switch -c new-branch</code>.</li>
</ul>
<h3 id="heading-how-to-visualize-branches-in-git">How to Visualize Branches in Git:</h3>
<p>After creating and switching branches, you can visualize the branch structure using:</p>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">log</span> --oneline --decorate --graph --all
</code></pre>
<p>This command displays a concise and graphical representation of the commit history and branch pointers, allowing you to see how branches diverge and merge over time.</p>
<h2 id="heading-how-to-manage-branches-in-git">How to Manage Branches in Git</h2>
<h3 id="heading-how-to-manage-merged-branches">How to Manage Merged Branches</h3>
<p>As your project evolves, you'll merge branches back into the main branch once their changes are finalized. To identify merged branches, execute:</p>
<pre><code class="lang-bash">$ git branch --merged
</code></pre>
<p>This command lists branches that have been successfully merged into the current branch. These branches are generally safe to delete using:</p>
<pre><code class="lang-bash">$ git branch -d branch_name
</code></pre>
<p>However, for branches containing unmerged work, use:</p>
<pre><code class="lang-bash">$ git branch --no-merged
</code></pre>
<p>Deleting such branches requires the '-D' flag:</p>
<pre><code class="lang-bash">$ git branch -D branch_name
</code></pre>
<p>This ensures that you don't inadvertently lose any unmerged changes.</p>
<h3 id="heading-how-to-rename-branches">How to Rename Branches</h3>
<p>To rename a local branch:</p>
<pre><code class="lang-bash">$ git branch --move old_branch_name new_branch_name
</code></pre>
<p>This command updates the branch name locally. To reflect the change on the remote repository, push the renamed branch:</p>
<pre><code class="lang-bash">$ git push --set-upstream origin new_branch_name
</code></pre>
<p>Verify the changes using: </p>
<pre><code class="lang-bash">$ git branch --all
</code></pre>
<p>Ensure to delete the old branch on the remote:</p>
<pre><code class="lang-bash">$ git push origin --delete old_branch_name
</code></pre>
<p>This ensures uniformity across local and remote repositories.</p>
<h3 id="heading-how-to-change-the-default-branch-name">How to Change the Default Branch Name</h3>
<p>Renaming the default branch, often 'master', requires caution and coordination, as it impacts project integrations and collaborators.</p>
<pre><code class="lang-bash">$ git branch --move master main
</code></pre>
<p>Once renamed, push the updated branch to the remote repo:</p>
<pre><code class="lang-bash">$ git push --set-upstream origin main
</code></pre>
<p>Make sure you remember to update references and configurations across dependencies, tests, scripts, and repository hosts. Once done, delete the old master branch on the remote:</p>
<pre><code class="lang-bash">$ git push origin --delete master
</code></pre>
<p>This is <strong>different from <code>$ git config --global init.defaultBranch main</code></strong> that we discussed in the configuration part in the following ways:</p>
<ul>
<li><code>$ git branch --move master main</code>: This command renames the existing branch named "master" to "main" within the current repository. It is a sort of local operation that affects only the repository.</li>
<li><code>$ git config --global init.defaultBranch main</code>: This command sets the default branch name for new repositories globally. It does not rename existing branches but ensures that any new repositories created thereafter will use "main" as the default branch name instead of "master".</li>
</ul>
<p><strong>Additional Resource</strong>: Consider checking out this official Git <a target="_blank" href="https://git-scm.com/book/en/v2/Git-Branching-Remote-Branches">resource</a> for its informative visuals and diagrams which can provide you more clarity on remote branches and branch management concepts.</p>
<h2 id="heading-branching-workflow">Branching Workflow</h2>
<p>Let's understand branches in more detail and look at a common branching workflow that is used in large projects.</p>
<h3 id="heading-long-running-branches">Long-Running Branches:</h3>
<p>In Git, long-running branches are branches that remain open over an extended period. </p>
<h3 id="heading-topic-branches">Topic Branches:</h3>
<p><code>Topic</code>/<code>Feature</code> branches are short-lived branches created for specific features or pieces of work. Unlike long-running branches, which persist over time, topic branches are created, used, and often deleted once the work is complete. </p>
<p><strong>Example:</strong> Let's consider a scenario where a team maintains two long-running branches: <code>master</code> and <code>develop</code>.</p>
<ul>
<li>The <code>master</code> branch contains only stable code, possibly what has been released or will be released.</li>
<li>The <code>develop</code> branch acts as a staging area for ongoing development. While it might not always be stable, it serves as a testing ground for new features.</li>
</ul>
<p>Developers merge changes from feature branches into the <code>develop</code> branch for testing. Once features are thoroughly tested and stable, they are merged into <code>master</code>.</p>
<p>Note how changes progress through different levels of stability, moving from the least stable (feature branches) to more stable ones (such as the develop branch), as they undergo testing and refinement, and are finally merged into the most stable main/master branch. </p>
<p>This maintains a clear separation between stable and development code, ensuring that only thoroughly tested features make their way into the stable release.</p>
<h3 id="heading-branching-best-practices">Branching Best Practices</h3>
<ol>
<li><strong>Create Descriptive Branch Names</strong>: Use meaningful branch names that reflect the purpose or feature being developed.</li>
<li><strong>Delete Unused Branches</strong>: Once a branch has served its purpose and its changes have been merged into the main branch, consider deleting it to keep the repository clean and manageable.</li>
</ol>
<h2 id="heading-rebasing-in-git">Rebasing in Git</h2>
<p>In Git, when you're working with branches, there are two primary ways to integrate changes from one branch into another: merging and rebasing. </p>
<p>Unlike merging, which can create a cluttered history with multiple merge commits, rebasing produces a linear history, making it easier to understand the sequence of changes made over time. </p>
<h3 id="heading-basic-rebase-example">Basic Rebase Example:</h3>
<p>Imagine you're working on a project with two branches: "feature" and "master". You've made some commits on the "feature" branch and now want to integrate these changes into the "master" branch using rebasing.</p>
<p>First, you switch to your "feature" branch:</p>
<pre><code class="lang-bash">$ git checkout feature
</code></pre>
<p>Then, you rebase your feature branch onto the master branch: </p>
<pre><code class="lang-bash">$ git rebase master
</code></pre>
<p>This command takes all the commits/changes you made on your "feature" branch and applies them on top of the latest commits in the "master" branch, and replays the commits one by one.</p>
<p>Not only master branch, you can also rebase a topic branch onto another topic branch. Example:</p>
<p>Suppose you're working on a project with two feature branches: "frontend" and "backend". You made some commits on the "frontend" branch and now want to integrate these changes into the "backend" branch.</p>
<p>Let's use a different approach this time -<br>use <code>--onto</code> option of <code>git rebase</code> to rebase the "frontend" branch onto the "backend" branch:</p>
<pre><code class="lang-bash">$ git rebase --onto backend frontend
</code></pre>
<p>After rebasing, switch back to the "backend" branch and perform a fast-forward merge:</p>
<pre><code class="lang-bash">$ git checkout backend
$ git merge frontend
</code></pre>
<p>Now, your project history appears linear, reflecting the sequential integration of changes from the "frontend" branch into the "backend" branch.</p>
<h3 id="heading-rebasing-vs-merging-which-is-better">Rebasing vs Merging: Which is Better?</h3>
<h4 id="heading-rebasing-use-cases">Rebasing Use Cases:</h4>
<ul>
<li>Suitable for feature branches that need a clean integration into the mainline branch.</li>
<li>Preferred for open-source contributions where a clean commit history is valued.</li>
</ul>
<h4 id="heading-merging-use-cases">Merging Use Cases:</h4>
<ul>
<li>Appropriate for collaborative environments where transparency in the project's development process is crucial.</li>
<li>Useful for projects where maintaining an accurate historical record is a priority.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This handbook serves as a comprehensive guide to understanding and utilizing Git, a powerful version control system widely used in software development. </p>
<p>From basic workflows to setting up a repository, tagging, and branching remote repositories, we have learnt a comprehensive suite of features that will help streamlining the development process.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Gitting Things Done – A Visual and Practical Guide to Git [Full Book] ]]>
                </title>
                <description>
                    <![CDATA[ Introduction Git is awesome. Most software developers use Git on a daily basis. But how many truly understand Git? Do you feel like you know what's going on under the hood as you use Git to perform various tasks? For example, what happens when you us... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/gitting-things-done-book/</link>
                <guid isPermaLink="false">66c17c2bea5637f064224a06</guid>
                
                    <category>
                        <![CDATA[ book ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Omer Rosenbaum ]]>
                </dc:creator>
                <pubDate>Mon, 08 Jan 2024 17:12:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/12/Gitting-Things-Done-Cover-with-Photo.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="heading-introduction">Introduction</h2>
<p>Git is awesome.</p>
<p>Most software developers use Git on a daily basis. But how many truly understand Git? Do <em>you</em> feel like you know what's going on under the hood as you use Git to perform various tasks?</p>
<p>For example, what happens when you use <code>git commit</code>? What is stored between commits? Is it just a diff between the current and previous commit? If so, how is the diff encoded? Or is an entire snapshot of the repository stored each time?</p>
<p>Most people who use Git don't know the answers to the questions posed above. But does it really matter? Do you really have to know all of those things?</p>
<p>I'd argue that it does matter. As professionals, we should strive to understand the tools we use, especially if we use them all the time, like Git.</p>
<p>Even more acutely, I've found that understanding how Git actually works is <strong>useful</strong> in many scenarios — whether resolving merge conflicts, looking to conduct an interesting rebase, or even just when something goes slightly wrong. </p>
<p>So many times have I received questions about Git from experienced, highly skilled software engineers. I have seen wonderful developers react in fear when something happened in their commit history, and they just didn't know what to do. It doesn't have to be this way.</p>
<p>By reading this book, you will gain a new perspective of Git. You will feel <strong>confident</strong> when working with Git, and you will <strong>understand</strong> Git's underlying mechanisms, at least those that are useful to understand. You will <em>Git</em> it. You will be <em>Gitting things done</em>.</p>
<h1 id="heading-table-of-contents">Table of Contents</h1>
<ul>
<li><a class="post-section-overview" href="#heading-introduction">Introduction</a></li>
<li><a class="post-section-overview" href="#heading-part-1-main-objects-and-introducing-changes">Part 1 - Main Objects and Introducing Changes</a><ul>
<li><a class="post-section-overview" href="#heading-chapter-1-git-objects">Chapter 1 - Git Objects</a></li>
<li><a class="post-section-overview" href="#heading-chapter-2-branches-in-git">Chapter 2 - Branches in Git</a></li>
<li><a class="post-section-overview" href="#heading-chapter-3-how-to-record-changes-in-git">Chapter 3 - How to Record Changes in Git</a></li>
<li><a class="post-section-overview" href="#heading-chapter-4-how-to-create-a-repo-from-scratch">Chapter 4 - How to Create a Repo From Scratch</a></li>
<li><a class="post-section-overview" href="#heading-chapter-5-how-to-work-with-branches-in-git-under-the-hood">Chapter 5 - How to Work with Branches in Git — Under the Hood</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-part-2-branching-and-integrating-changes">Part 2 - Branching and Integrating Changes</a><ul>
<li><a class="post-section-overview" href="#heading-chapter-6-diffs-and-patches">Chapter 6 - Diffs and Patches</a></li>
<li><a class="post-section-overview" href="#heading-chapter-7-understanding-git-merge">Chapter 7 - Understanding Git Merge</a></li>
<li><a class="post-section-overview" href="#heading-chapter-8-understanding-git-rebase">Chapter 8 - Understanding Git Rebase</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-part-3-undoing-changes">Part 3 - Undoing Changes</a><ul>
<li><a class="post-section-overview" href="#heading-chapter-9-git-reset">Chapter 9 - Git Reset</a></li>
<li><a class="post-section-overview" href="#heading-chapter-10-additional-tools-for-undoing-changes">Chapter 10 - Additional Tools for Undoing Changes</a></li>
<li><a class="post-section-overview" href="#heading-chapter-11-exercises">Chapter 11 - Exercises</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-part-4-amazing-and-useful-git-tools">Part 4 - Amazing and Useful Git Tools</a><ul>
<li><a class="post-section-overview" href="#heading-chapter-12-git-log">Chapter 12 - Git Log</a></li>
<li><a class="post-section-overview" href="#heading-chapter-13-git-bisect">Chapter 13 - Git Bisect</a></li>
<li><a class="post-section-overview" href="#heading-chapter-14-other-useful-commands">Chapter 14 - Other Useful Commands</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-summary">Summary</a></li>
<li><a class="post-section-overview" href="#heading-appendixes">Appendixes</a></li>
</ul>
<h2 id="heading-who-is-this-book-for">Who Is This Book For?</h2>
<p>Any software developer who wants to deepen their knowledge about Git.</p>
<p>If you are experienced with Git - I am sure you will be able to deepen your knowledge. Even if you are new to Git - I will start with an overview of the mechanisms of Git, and the terms used throughout this book.</p>
<p>This book is for you. I wrote it so you can learn more about Git, and also come to appreciate, or even love Git.</p>
<p>You will also notice that I use a casual style throughout the book. I believe that learning Git should be insightful and fun. Learning new things is always hard, and I felt like writing in a less casual style wouldn't really make a good service. And as I already mentioned - this book is for you.</p>
<h2 id="heading-who-am-i">Who Am I?</h2>
<p>This book is about you, and your journey with Git. But I would like to tell you a bit about why I think I can contribute to your journey.</p>
<p>I am the CTO and one of the co-founders of <a target="_blank" href="https://swimm.io">Swimm.io</a>, a knowledge management tool for code. Part of what we do is linking parts from code in Git repositories to parts of the documentation, and then tracking changes in the repository to update the documentation if needed. </p>
<p>At Swimm, I got to dissect parts of Git, understand its underlying mechanisms and also gain intuition about why Git is implemented the way it is.</p>
<p>Before founding Swimm I practiced teaching in many different environments - among them, managing the Cyber track of Israel Tech Challenge, founding Check Point Security Academy, and writing a full text book.</p>
<p>This book is my attempt to make the most of both worlds - my teaching experience as well as my in-depth hands-on experience with Git, and give you the best learning experience I can.</p>
<h2 id="heading-the-approach-of-this-book">The Approach of This Book</h2>
<p>This is definitely not the first book about Git. When sitting down to write it, I had three principles in mind.</p>
<ol>
<li><strong>Practical</strong> - in this book, you will learn how to accomplish things in Git. How to introduce changes, how to undo them, and how to fix things when they go wrong. You will understand how Git works not just for the sake of understanding, but with a practical mindset. I sometimes refer to this as the "practicality principle" - which guides me in deciding whether to include certain topics, and to what extent.</li>
<li><strong>In depth</strong> - you will dive deep into Git's way of operating, to understand its mechanisms. You will build your understanding gradually, and always link your knowledge to real scenarios you might face in your work. In order to achieve an in-depth understanding, I almost always prefer the command line over graphical interfaces, so you can really see what commands are running.</li>
<li><strong>Visual</strong> - as I strive to provide you with intuition, the chapters will be accompanied by visual aids.</li>
</ol>
<h2 id="heading-why-is-this-book-publicly-available">Why Is This Book Publicly Available?</h2>
<p>I think everyone should have access to high quality content about Git, and I'd like this book to get to as many people as possible.</p>
<p>If you would like to support this book, you are welcome to buy the <a target="_blank" href="https://www.amazon.com/dp/B0CQXTJ5V5">Paperback version</a>, an <a target="_blank" href="https://www.buymeacoffee.com/omerr/e/197232">E-Book version</a>, or <a target="_blank" href="https://www.buymeacoffee.com/omerr">buy me a coffee</a>. Thank you!</p>
<h2 id="heading-accompanying-videos">Accompanying Videos</h2>
<p>I have covered many topics from this book on my YouTube channel - Brief (<a target="_blank" href="https://www.youtube.com/@BriefVid">https://www.youtube.com/@BriefVid</a>). You are welcome to check them out as well.</p>
<h2 id="heading-get-your-hands-dirty">Get Your Hands Dirty</h2>
<p>Throughout this book, I will mostly use the second person singular - and directly write to <em>you</em>. I will ask <em>you</em> to get your hands dirty, run the commands yourself, so you actually get to <em>feel</em> what it's like to use do things with Git, not just read about it.</p>
<h2 id="heading-gits-feelings">Git's Feelings</h2>
<p>Throughout the book, I sometimes refer to Git with words such as "believes", "thinks", or "wants". As you may argue, Git is not a human, and it doesn't have feelings or beliefs. Well, that's true, but in order for us to enjoy playing around with Git, and to help you enjoy reading (and me writing) this book, I feel like referring to Git as more than just code makes it all so much more enjoyable.</p>
<h2 id="heading-my-setup">My Setup</h2>
<p>I will include screenshots. There's no need for your setup to match mine, but if you're curious about my setup, then:</p>
<ul>
<li>I am using Ubuntu 20.04 (WSL).</li>
<li>For my terminal, I use <a target="_blank" href="https://ohmyz.sh/">Oh My Zsh</a></li>
<li>I also use plugins for Oh My Zsh, you can <a target="_blank" href="https://www.freecodecamp.org/news/jazz-up-your-zsh-terminal-in-seven-steps-a-visual-guide-e81a8fd59a38/">follow this tutorial on freeCodeCamp</a>.</li>
<li><a target="_blank" href="https://github.com/mlange-42/git-graph">git-graph (my alias is <code>gg</code>)</a></li>
</ul>
<h2 id="heading-feedback-is-welcome">Feedback Is Welcome</h2>
<p>This book has been created to help you and people like you learn, understand Git, and apply that knowledge in real life. </p>
<p>Right from the beginning, I asked for feedback and was lucky to receive it from great people (see <a class="post-section-overview" href="#heading-acknowledgements">Acknowledgments</a>) to make sure the book achieves these goals. If you liked something about this book, felt that something was missing, or that something needed improvement - I would love to hear from you. Please reach out at <a target="_blank" href="mailto:gitting.things@gmail.com">gitting.things@gmail.com</a>.</p>
<h2 id="heading-note">Note</h2>
<p>This book is provided for free on freeCodeCamp as described above and according to <a target="_blank" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International</a>.</p>
<p>If you would like to support this book, you are welcome to buy the <a target="_blank" href="https://www.amazon.com/dp/B0CQXTJ5V5">Paperback version</a>, an <a target="_blank" href="https://www.buymeacoffee.com/omerr/e/197232">E-Book version</a>, or <a target="_blank" href="https://www.buymeacoffee.com/omerr">buy me a coffee</a>. Thank you!</p>
<h1 id="heading-part-1-main-objects-and-introducing-changes">Part 1 - Main Objects and Introducing Changes</h1>
<h2 id="heading-chapter-1-git-objects">Chapter 1 - Git Objects</h2>
<p>It's time to start your journey into the depths of Git. In this chapter - starting with the basics - you will learn about the most important Git objects, and adopt a way of thinking about Git. Let's get to it!</p>
<h3 id="heading-git-as-a-system-for-maintaining-a-file-system">Git as a System for Maintaining a File System</h3>
<p>While there are different ways to use Git, I'll adopt here the way I've found to be the most clear and useful: Viewing Git as a system maintaining a file system, and specifically  -  snapshots of that file system over time.</p>
<p>A file system begins with a root directory (in UNIX-based systems, <code>/</code>), which usually contains other directories (for example, <code>/usr</code> or <code>/bin</code>). These directories contain other directories, and/or files (for example, <code>/usr/1.txt</code>). On a Windows machine, a root directory of a drive would be <code>C:\</code>, and a subdirectory could be <code>C:\users</code>. I will adopt the convention of UNIX-based systems throughout this book.</p>
<h3 id="heading-blobs">Blobs</h3>
<p>In Git, the contents of files are stored in objects called <strong>blob</strong>s, short for binary large objects.</p>
<p>The difference between blobs and files is that files also contain meta-data. For example, a file "remembers" when it was created, so if you move that file from one directory into another directory, its creation time remains the same.</p>
<p>Blobs, in contrast, are just binary streams of data, like a file's contents. A blob does not register its creation date, its name, or anything other than its contents.</p>
<p>Every blob in Git is identified by its <a target="_blank" href="https://en.wikipedia.org/wiki/SHA-1">SHA-1 hash</a>. SHA-1 hashes consist of 20 bytes, usually represented by 40 characters in hexadecimal form. Throughout this book I will sometimes show just the first characters of that hash. As hashes, and specifically SHA-1 hashes are so ubiquitous within Git, it is important you understand the basic characteristics of hashes.</p>
<h3 id="heading-hashes">Hashes</h3>
<p>A hash is a deterministic, one-way mathematical function.</p>
<p><em>Deterministic</em> means that the same input will provide the same output. That is - you take a stream of data, run a hash function on that stream, and you get a result. </p>
<p>For example, if you provide the SHA-1 hash function with the stream <code>hello</code>, you will get <code>0xaaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d</code>. If you run the SHA-1 hash function again, from a different machine, and provide it the same data (<code>hello</code>), you will get the same value.</p>
<p>Git uses SHA-1 as its hash function in order to identify objects. It relies on it being deterministic, such that an object will always have the same identifier.</p>
<p>A <em>one-way</em> function is a function that is hard to invert given an output. That is,  it is impossible (or at least, very hard) to tell, given the result of the hash function (for example <code>0xaaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d</code>), what input yielded that result (in this example, <code>hello</code>).</p>
<h3 id="heading-back-to-git">Back to Git</h3>
<p>Back to Git - Blobs, just like other Git objects, have SHA-1 hashes associated with them.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/blob_sha.png" alt="Blobs have corresponding SHA-1 values" width="600" height="400" loading="lazy">
<em>Blobs have corresponding SHA-1 values</em></p>
<p>As I said in the beginning, Git can be viewed as a system to maintain a file system. File systems consist of files and directories. A blob is the Git object representing the contents of a file.</p>
<h3 id="heading-trees">Trees</h3>
<p>In Git, the equivalent of a directory is a <strong>tree</strong>. A tree is basically a directory listing, referring to blobs, as well as other trees.</p>
<p>Trees are identified by their SHA-1 hashes as well. Referring to these objects, either blobs or other trees, happens via the SHA-1 hash of the objects.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/tree_objs.png" alt="A tree is a directory listing" width="600" height="400" loading="lazy">
<em>A tree is a directory listing</em></p>
<p>Consider the drawing above. Note that the tree <code>CAFE7</code> refers to the blob <code>F92A0</code> as the file <code>pic.png</code>. In another tree, that same blob may have another name - but as long as the contents are the same, it will still be the same blob object, and still have the same SHA-1 value.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/tree_sub_trees.png" alt="A tree may contain sub-trees, as well as blobs" width="600" height="400" loading="lazy">
<em>A tree may contain sub-trees, as well as blobs</em></p>
<p>The diagram above is equivalent to a file system with a root directory that has one file at <code>/test.js</code>, and a directory named <code>/docs</code> consisting of two files: <code>/docs/pic.png</code>, and <code>/docs/1.txt</code>.</p>
<h3 id="heading-commits">Commits</h3>
<p>Now it's time to take a snapshot of that file system — and store all the files that existed at that time, along with their contents.</p>
<p>In Git, a snapshot is a <strong>commit</strong>. A commit object includes a pointer to the main tree (the root directory of the file system), as well as other meta-data such as the committer (the user who authored the commit), a commit message, and the commit time.</p>
<p>In most cases, a commit also has one or more parent commits — the previous snapshot (or snapshots). Of course, commit objects are also identified by their SHA-1 hashes. These are the hashes you are probably used to seeing when you use commands such as <code>git log</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit.png" alt="A commit is a snapshot in time. It refers to the root tree. As this is the first commit, it has no parents" width="600" height="400" loading="lazy">
<em>A commit is a snapshot in time. It refers to the root tree. As this is the first commit, it has no parents</em></p>
<p>Every commit holds the entire snapshot, not just differences between itself and its parent commit or commits.</p>
<p>How can that work? Doesn't that mean that Git has to store a lot of data for every commit?</p>
<p>Examine what happens if you change the contents of a file. Say that you edit the file <code>1.txt</code>, and add an exclamation mark — that is, you changed the content from <code>HELLO WORLD</code>, to <code>HELLO WORLD!</code>.</p>
<p>Well, this change means that Git creates a new blob object, with a new SHA-1 hash. This makes sense, as <code>sha1("HELLO WORLD")</code> is different from <code>sha1("HELLO WORLD!")</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_blob_new_sha.png" alt="Changing the blob results in a new SHA-1" width="600" height="400" loading="lazy">
<em>Changing the blob results in a new SHA-1</em></p>
<p>Since you have a new hash, then the tree's listing should also change. After all, your tree no longer points to blob <code>73D8A</code>, but rather blob <code>62E7A</code> instead. Since you change the tree's contents, you also change its hash.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_tree_new_hash.png" alt="The tree that points to the changed blob needs to change as well" width="600" height="400" loading="lazy">
<em>The tree that points to the changed blob needs to change as well</em></p>
<p>And now, since the hash of that tree is different, you also need to change the parent tree — as the latter no longer points to tree <code>CAFE7</code>, but rather to tree <code>24601</code>. Consequently, the parent tree will also have a new hash.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_root_tree.png" alt="The root tree also changes, and so does its hash" width="600" height="400" loading="lazy">
<em>The root tree also changes, and so does its hash</em></p>
<p>Almost ready to create a new commit object, and it seems like you are going to store a lot of data — the entire file system, once more! But is that really necessary?</p>
<p>Actually, some objects, specifically blob objects, haven't changed since the previous commit — the blob <code>F92A0</code> remained intact, and so did the blob <code>F00D1</code>.</p>
<p>So this is the trick — as long as an object doesn't change, Git doesn't store it again. In this case, Git doesn't need to store blob <code>F92A0</code> or blob <code>F00D1</code> once more. Git can refer to them using only their hash values. You can then create your commit object.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_commit.png" alt="Blobs that remained intact are referenced by their hash values" width="600" height="400" loading="lazy">
<em>Blobs that remained intact are referenced by their hash values</em></p>
<p>Since this commit is not the first commit, it also has a parent commit — commit <code>A1337</code>.</p>
<h3 id="heading-considering-hashes">Considering Hashes</h3>
<p>After introducing blobs, trees, and commits - consider the hashes of these objects. Assume I wrote the string <code>Git is awesome!</code>, and created a blob object from it. You did the same on your system. Would we have the same hash?</p>
<p>The answer is — Yes. Since the blobs consist of the same data, they'll have the same SHA-1 values.</p>
<p>What if I made a tree that references the blob of <code>Git is awesome!</code>, and gave it a specific name and metadata, and you did exactly the same on your system. Would we have the same hash?</p>
<p>Again, yes. Since the tree objects are the same, they would have the same hash.</p>
<p>What if I created a commit pointing to that tree with the commit message <code>Hello</code>, and you did the same on your system? Would we have the same hash?</p>
<p>In this case, the answer is — No. Even though our commit objects refer to the same tree, they have different commit details — time, committer, and so on.</p>
<h3 id="heading-how-are-objects-stored">How Are Objects Stored?</h3>
<p>You now understand the purpose of blobs, trees, and commits. In the next chapters, you will also create these objects yourself. Despite being interesting, understanding how these objects are actually encoded and stored is not vital to your understanding, and for gitting things done.</p>
<h4 id="heading-short-recap-git-objects">Short Recap - Git Objects</h4>
<p>To recap, in this section we introduced three Git objects:</p>
<ul>
<li><strong>Blob</strong> — contents of a file.</li>
<li><strong>Tree</strong> — a directory listing (of blobs and trees).</li>
<li><strong>Commit</strong> — a snapshot of the working tree.</li>
</ul>
<p>In the next chapter, we will understand branches in Git.</p>
<h2 id="heading-chapter-2-branches-in-git">Chapter 2 - Branches in Git</h2>
<p>In the previous chapter, I suggested that we should view Git as a system for maintaining a file system.</p>
<p>One of the wonders of Git is that it enables multiple people to work on that file system, in parallel, (mostly) without interfering with each other's work. Most people would say that they are "working on branch <code>X</code>." But what does that <em>actually</em> mean?</p>
<p><strong>A branch is just a named reference to a commit.</strong></p>
<p>You can always reference a commit by its SHA-1 hash, but humans usually prefer other ways to name objects. A branch is one way to reference a commit, but it's really just that.</p>
<p>In most repositories, the main line of development is done in a branch called <code>main</code>. This is just a name, and it's created when you use <code>git init</code>, making it widely used. However, you could use any other name you'd like.</p>
<p>Typically, the branch points to the latest commit in the line of development you are currently working on.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/branch_01.png" alt="A branch is just a named reference to a commit" width="600" height="400" loading="lazy">
<em>A branch is just a named reference to a commit</em></p>
<p>To create another branch, you can use the <code>git branch</code> command. When you do that, Git creates another pointer. If you created a branch called <code>test</code>, by using <code>git branch test</code>, you would be creating another pointer that points to the same commit as the branch you are on:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_branch.png" alt="Using  creates another pointer" width="600" height="400" loading="lazy">
<em>Using <code>git branch</code> creates another pointer</em></p>
<p>How does Git know which branch you're currently on? It keeps another designated pointer, called <code>HEAD</code>. Usually, <code>HEAD</code> points to a branch, which in turns points to a commit. In the case described, <code>HEAD</code> might point to <code>main</code>, which in turn points to commit <code>B2424</code>. In some cases, <code>HEAD</code> can also point to a commit directly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/head_main.png" alt=" points to the branch you are currently on" width="600" height="400" loading="lazy">
<em><code>HEAD</code> points to the branch you are currently on</em></p>
<p>To switch the active branch to be <code>test</code>, you can use the command <code>git checkout test</code>, or <code>git switch test</code>. Now you can already guess what this command actually does — it just changes <code>HEAD</code> to point to <code>test</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/head_test.png" alt=" changes where  points" width="600" height="400" loading="lazy">
<em><code>git checkout test</code> changes where <code>HEAD</code> points</em></p>
<p>You could also use <code>git checkout -b test</code> before creating the <code>test</code> branch, which is the equivalent of running <code>git branch test</code> to create the branch, and then <code>git checkout test</code> to move <code>HEAD</code> to point to the new branch.</p>
<p>At the point represented in the drawing above, what would happen if you made some changes and created a new commit using <code>git commit</code>? Which branch will the new commit be added to?</p>
<p>The answer is the <code>test</code> branch, as this is the active branch (since <code>HEAD</code> points to it). Afterwards, the <code>test</code> pointer will move to the newly added commit. Note that <code>HEAD</code> still points to <code>test</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/test_commit-1.png" alt="Every time we use , the branch pointer moves to the newly created commit" width="600" height="400" loading="lazy">
<em>Every time we use <code>git commit</code>, the branch pointer moves to the newly created commit</em></p>
<p>If you go back to <code>main</code> by using <code>git checkout main</code>, Git will move <code>HEAD</code> to point to <code>main</code> again.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/back_to_main-1.png" alt="The resulting state after using " width="600" height="400" loading="lazy">
<em>The resulting state after using <code>git checkout main</code></em></p>
<p>Now, if you create another commit, which branch will it be added to?</p>
<p>That's right, it will be added to the <code>main</code> branch (and its parent would be commit <code>B2424</code>).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_to_main-1.png" alt="The resulting state after creating another commit on the  branch" width="600" height="400" loading="lazy">
<em>The resulting state after creating another commit on the <code>main</code> branch</em></p>
<h3 id="heading-short-recap-branches">Short Recap - Branches</h3>
<ul>
<li>A branch is a named reference to a commit.</li>
<li>When you use <code>git commit</code>, Git creates a commit object, and moves the branch to point to the newly created commit.</li>
<li><code>HEAD</code> is a special pointer telling Git which branch is the active branch (in rare cases, it can point directly to a commit).</li>
</ul>
<p>In the next chapters, you will learn how to introduce changes to Git. You will create a repository from scratch — without using <code>git init</code>, <code>git add</code>, or <code>git commit</code>. This will allow you to deepen your understanding of what is happening under the hood when you work with Git. You will also create new branches, switch branches, and create additional commits — all without using <code>git branch</code> or <code>git checkout</code>. I don't know about you, but I am excited already!</p>
<h2 id="heading-chapter-3-how-to-record-changes-in-git">Chapter 3 - How to Record Changes in Git</h2>
<p>So far, we've learned about four different entities in Git:</p>
<ol>
<li><strong>Blob</strong> — contents of a file.</li>
<li><strong>Tree</strong> — a directory listing (of blobs and trees).</li>
<li><strong>Commit</strong> — a snapshot of the working tree, with some meta-data such as the time or the commit message.</li>
<li><strong>Branch</strong> — a named reference to a commit.</li>
</ol>
<p>The first three are <em>objects</em>, whereas the fourth is one way to refer to objects (specifically, commits).</p>
<p>Now, it's time to understand how to introduce changes in Git.</p>
<p>When you work on your source code, you work from a <strong>working dir</strong>. A working dir(ectory) (also called "working tree") is any directory on your file system which has a repository associated with it. It contains the folders and files of your project, and also a directory called <code>.git</code> that we will talk more about later. Remember that we said that Git is a system to maintain a file system. The working directory is the root of the file system for Git.</p>
<p>After you make some changes, you might want to record them in your repository. A <strong>repository</strong> (in short: "repo") is a collection of commits, each of which is an archive of what the project's working tree looked like at a past date, whether on your machine or someone else's. That is, as I said before, a commit is a snapshot of the working tree.</p>
<p>A repository also includes things other than your code files, such as <code>HEAD</code> and <code>branches</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/working_dir_repo.png" alt="A working dir alongside the repository" width="600" height="400" loading="lazy">
<em>A working dir alongside the repository</em></p>
<p>Note regarding the drawing conventions I use: I include <code>.git</code> within the working directory, to remind you that it is a folder within the project's folder on the filesystem. The <code>.git</code> folder actually contains the objects of the repository, as we will see in <a class="post-section-overview" href="#heading-chapter-4-how-to-create-a-repo-from-scratch">chapter 4</a>.</p>
<p>There are other version control systems where changes are committed directly from the working dir to the repository. In Git, this is not the case. Instead, changes are first registered in something called the <strong>index</strong>, or the <strong>staging area</strong>.</p>
<p>Both of these terms refer to the same thing, and they are used often in Git's documentation. I will use these terms interchangeably throughout this book, as you should feel comfortable with both of them.</p>
<p>You can think of adding changes to the index as a way of "confirming" your changes, one by one, before creating a commit (which records all your approved changes at once).</p>
<p>When you <code>checkout</code> a branch, Git populates the index and the working dir with the contents of the files as they exist in the commit that branch is pointing to. When you use <code>git commit</code>, Git creates a new commit object based on the state of the index.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/working_dir_index_repo.png" alt="The three &quot;states&quot; - working dir, index, and repository" width="600" height="400" loading="lazy">
<em>The three "states" - working dir, index, and repository</em></p>
<p>Using the index allows you to carefully prepare each commit. For example, you may have two files with changes in your working dir:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/working_dir_index_repo_02.png" alt="Working dir includes two files with changes" width="600" height="400" loading="lazy">
<em>Working dir includes two files with changes</em></p>
<p>For example, assume these two files are <code>1.txt</code> and <code>2.txt</code>. It is possible to only add one of them (for instance, <code>1.txt</code>) to the index, by using <code>git add 1.txt</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/working_dir_index_repo_03.png" alt="The state after staging " width="600" height="400" loading="lazy">
<em>The state after staging <code>1.txt</code></em></p>
<p>As a result, the state of the index matches the state of <code>HEAD</code> (in this case, "Commit 2"), with the exception of the file <code>1.txt</code>, which matches the state of <code>1.txt</code> in the working directory. Since you did not stage <code>2.txt</code>, the index does not include the updated version of <code>2.txt</code>. So the state of <code>2.txt</code> in the index matches the state of <code>2.txt</code> in "Commit 2".</p>
<p>Behind the scenes - once you stage a version of a file, Git creates a blob object with the file's contents. This blob object is then added to the index. As long as you only modify the file on the working directory, without staging it, the changes you make are not recorded in blob objects. </p>
<p>When considering the previous figure, note that I do not draw the staged version of the file as part of the "repository", as in this representation, the "repository" refers to a tree of commits and their references, and this blob has not been a part of any commit.</p>
<p>Now, you can use <code>git commit</code> to record the change to <code>1.txt</code> <em>only</em>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/working_dir_index_repo_04.png" alt="The state after using " width="600" height="400" loading="lazy">
<em>The state after using <code>git commit</code></em></p>
<p>Using <code>git commit</code> performs two main operations:</p>
<ol>
<li>It creates a new commit object. This commit object reflects the state of the index when you ran the <code>git commit</code> command.</li>
<li>Updates the active branch to point to the newly created commit. In this example, <code>main</code> now points to "Commit 3", the new commit object.</li>
</ol>
<h3 id="heading-how-to-create-a-repo-the-conventional-way">How to Create a Repo — The Conventional Way</h3>
<p>Let's make sure that you understand how the terms we've introduced relate to the process of creating a new repository. This is a quick high-level view, before diving much deeper into this process.</p>
<p>Initialize a new repository using <code>git init my_repo</code>, and then change your directory to that of the repository using <code>cd my_repo</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_init.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git init</code></em></p>
<p>By using <code>tree -f .git</code> you can see that running <code>git init my_repo</code> resulted in quite a few sub-directories inside <code>.git</code>. (The flag <code>-f</code> includes files in tree's output).</p>
<p>Note: if you're using Windows, run <code>tree /f .git</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_init_tree_f.png" alt="The output of  after using " width="600" height="400" loading="lazy">
<em>The output of <code>tree -f .git</code> after using <code>git init</code></em></p>
<p>Create a file inside the <code>my_repo</code> directory:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_f_txt.png" alt="Creating " width="600" height="400" loading="lazy">
<em>Creating <code>f.txt</code></em></p>
<p>This file is within your working directory. If you run <code>git status</code>, you'll see this file is untracked:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_f_txt_git_status.png" alt="The result of " width="600" height="400" loading="lazy">
<em>The result of <code>git status</code></em></p>
<p>Files in your working directory can be in one of two states: <strong>tracked</strong> or <strong>untracked</strong>.</p>
<p><strong>Tracked</strong> files are files that Git "knows" about. They either were in the last commit, or they are staged now (that is, they are in the staging area).</p>
<p><strong>Untracked</strong> files are everything else — any files in your working directory that were not in your last commit, and are not in your staging area.</p>
<p>The new file (<code>f.txt</code>) is currently untracked, as you haven't added it to the staging area, and it hasn't been included in a previous commit.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/drawing_new_untracked_file.png" alt=" is in the working directory (and untracked)" width="600" height="400" loading="lazy">
<em><code>f.txt</code> is in the working directory (and untracked)</em></p>
<p>You can now add this file to the staging area (also referred to as staging this file) by using <code>git add f.txt</code>. You can verify that it has been staged by running <code>git status</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_add_status.png" alt="Adding the new file to the staging area" width="600" height="400" loading="lazy">
<em>Adding the new file to the staging area</em></p>
<p>So now the state of the index matches that of the working dir:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/drawing_new_staged_file.png" alt="The state after adding the new file" width="600" height="400" loading="lazy">
<em>The state after adding the new file</em></p>
<p>You can now create a commit using <code>git commit</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/initial_commit.png" alt="Committing an initial commit" width="600" height="400" loading="lazy">
<em>Committing an initial commit</em></p>
<p>If you run <code>git status</code> again, you'll see that the status is clean - that is, the state of <code>HEAD</code> (which points to your initial commit) equals the state of the index, and also the state of the working dir. By using <code>git log</code> you will see indeed that <code>HEAD</code> points to <code>main</code> which in turn points to your new commit:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/initial_commit_git_log.png" alt="The output of  after introducing the first commit" width="600" height="400" loading="lazy">
<em>The output of <code>git log</code> after introducing the first commit</em></p>
<p>Has something changed within the <code>.git</code> directory? Run <code>tree -f .git</code> to check:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/tree_f_after_initial_commit.png" alt="A lot of things have changed within " width="600" height="400" loading="lazy">
<em>A lot of things have changed within <code>.git</code></em></p>
<p>Apparently, quite a lot has changed. It's time to dive deeper into the structure of <code>.git</code> and understand what is going on under the hood when you run <code>git init</code>, <code>git add</code> or <code>git commit</code>. That's exactly what the next chapter will cover.</p>
<h3 id="heading-recap-how-to-record-changes-in-git">Recap - How to Record Changes in Git</h3>
<p>You learned about the three different "states" of the file system that Git maintains:</p>
<ul>
<li><strong>Working dir(ectory)</strong> (also called "working tree") - any directory on your file system which has a repository associated with it.</li>
<li><strong>Index</strong>, or the <strong>Staging Area</strong> - a playground for the next commit.</li>
<li><strong>Repository</strong> (in short: "repo") - a collection of commits, each of which is a snapshot of the working tree.</li>
</ul>
<p>When you introduce changes in Git, you almost always follow this order:</p>
<ol>
<li>You change the working directory first</li>
<li>Then you stage these changes (or some of them) to the index</li>
<li>And finally, you commit these changes - thereby updating the repository with a new commit. The state of this new commit matches the state of the index.</li>
</ol>
<p>Ready to dive deeper?</p>
<h2 id="heading-chapter-4-how-to-create-a-repo-from-scratch">Chapter 4 - How to Create a Repo From Scratch</h2>
<p>So far we've covered some Git fundamentals, and now you should be ready to really <em>Git</em> going (I can't seem to get enough of that pun).</p>
<p>In order to deeply understand how Git works, you will create a repository, but this time — you will build it from scratch. As in other chapters, I encourage you to try out the commands alongside this chapter.</p>
<h3 id="heading-how-to-set-up-git">How to Set Up <code>.git</code></h3>
<p>Create a new directory, and run <code>git status</code> within it:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_dir_git_status.png" alt=" in a new directory" width="600" height="400" loading="lazy">
<em><code>git status</code> in a new directory</em></p>
<p>Alright, so Git seems unhappy as you don't yet have a <code>.git</code> folder. The natural thing to do would be to create that directory and try again:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/mkdir_git_git_status.png" alt=" after creating " width="600" height="400" loading="lazy">
<em><code>git status</code> after creating <code>.git</code></em></p>
<p>Apparently, creating a <code>.git</code> directory is just not enough. You need to add some content to that directory.</p>
<p>A Git repository has two main components:</p>
<ul>
<li>A collection of <strong>objects</strong> — blobs, trees, and commits.</li>
<li>A system of <strong>naming</strong> those objects — called references.</li>
</ul>
<p>A repository may also contain other things, such as hooks, but at the very least — it must include objects and references.</p>
<p>Create a directory for the objects at <code>.git/objects</code>, and a directory for the references (in short: "refs") at <code>.git/refs</code> (on Windows systems — <code>.git\   objects</code> and <code>.git\refs</code>, respectively).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_folders_git_tree.png" alt="Considering the directory tree" width="600" height="400" loading="lazy">
<em>Considering the directory tree</em></p>
<p>One type of reference is branches. Internally, Git calls branches by the name <code>heads</code>. Create a directory for branches — <code>.git/refs/heads</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_heads_folder_git_tree.png" alt="The directory tree" width="600" height="400" loading="lazy">
<em>The directory tree</em></p>
<p>This still doesn't change the result of <code>git status</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_heads_folder_git_status.png" alt=" after creating " width="600" height="400" loading="lazy">
<em><code>git status</code> after creating <code>.git/refs/heads</code></em></p>
<p>How does Git know where to start when looking for a commit in the repository? As I explained earlier, it looks for <code>HEAD</code>, which points to the current active branch (or commit, in some cases).</p>
<p>So, you need to create <code>HEAD</code>, which is just a file residing at <code>.git/HEAD</code>. You can apply the following:</p>
<p>On UNIX:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"ref: refs/heads/main"</span> &gt; .git/HEAD
</code></pre>
<p>On Windows:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> ref: refs/heads/main &gt; .git\HEAD
</code></pre>
<p>So you now know how <code>HEAD</code> is implemented — it is simply a file, and its contents describe what it points to.</p>
<p>Following the command above, <code>git status</code> seems to change its mind:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_head_git_status.png" alt=" is just a file" width="600" height="400" loading="lazy">
<em><code>HEAD</code> is just a file</em></p>
<p>Notice that Git "believes" you are on a branch called <code>main</code>, even though you haven't created this branch. <code>main</code> is just a name. You can also make Git believe you are on a branch called <code>banana</code> if you wish:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/banana.png" alt="Creating a branch named " width="600" height="400" loading="lazy">
<em>Creating a branch named <code>banana</code></em></p>
<p>Switch back to <code>main</code>, as you will keep working from (mostly) there throughout this chapter, just to adhere to the regular convention:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"ref: refs/heads/main"</span> &gt; .git/HEAD
</code></pre>
<p>Now that you have your <code>.git</code> directory ready, you can work your way to make a commit (again, without using <code>git add</code> or <code>git commit</code>).</p>
<h3 id="heading-plumbing-vs-porcelain-commands-in-git">Plumbing vs Porcelain Commands in Git</h3>
<p>At this point, it would be helpful to make a distinction between two types of Git commands: plumbing and porcelain. The application of the terms oddly comes from toilets, traditionally made of porcelain, and the infrastructure of plumbing (pipes and drains).</p>
<p>The porcelain layer provides a user-friendly interface to the plumbing. Most people only deal with the porcelain. Yet, when things go (terribly) wrong, and someone wants to understand why, they would have to roll up their sleeves and deal with the plumbing.</p>
<p>Git uses this terminology as an analogy to separate the low-level commands that users don't usually need to use directly ("plumbing" commands) from the more user-friendly high level commands ("porcelain" commands).</p>
<p>So far, you have dealt with porcelain commands — <code>git init</code>, <code>git add</code> or <code>git commit</code>. It's time to go deeper, and get yourself acquainted with some plumbing commands.</p>
<h3 id="heading-how-to-create-objects-in-git">How to Create Objects in Git</h3>
<p>Start by creating an object and writing it into the objects database of Git, residing within <code>.git/objects</code>. To know the SHA-1 hash value of a blob, you can <code>git hash-object</code> (yes, a plumbing command), in the following way:</p>
<p>On UNIX:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"Git is awesome"</span> | git hash-object --stdin
</code></pre>
<p>On Windows:</p>
<pre><code class="lang-bash">&gt; <span class="hljs-built_in">echo</span> Git is awesome | git hash-object --stdin
</code></pre>
<p>By using <code>--stdin</code> you are instructing <code>git hash-object</code> to take its input from the standard input. This will provide you with the relevant hash value:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/hash_object.png" alt="Getting a blob's SHA-1" width="600" height="400" loading="lazy">
<em>Getting a blob's SHA-1</em></p>
<p>In order to actually write that blob into Git's object database, you can add the <code>-w</code> switch for <code>git hash-object</code>. Then, you check the contents of the <code>.git</code> folder, and see that they have changed:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/write_blob.png" alt="Writing a blob to the objects' database" width="600" height="400" loading="lazy">
<em>Writing a blob to the objects' database</em></p>
<p>You can see that the hash of your blob is <code>7a9bd34a0244eaf2e0dda907a521f43d417d94f6</code>. You can also see that a directory has been created under <code>.git/objects</code>, a directory named <code>7a</code>, and within it, a file by the name of <code>9bd34a0244eaf2e0dda907a521f43d417d94f6</code>.</p>
<p>What Git did here is take the <em>first two characters</em> of the SHA-1 hash, and use them as the name of a directory. The remaining characters are used as the filename for the file that actually contains the blob.</p>
<p>Why is that so? Consider a fairly big repository, one that has 400,000 objects (blobs, trees, and commits) in its database. Looking up a hash inside that list of 400,000 hashes might take a while. Thus, Git simply divides that problem by <code>256</code>. </p>
<p>To look up the hash above, Git would first look for the directory named <code>7a</code> inside the directory <code>.git/objects</code>, which may have up to 256 directories (<code>00</code> through <code>FF</code>). Then, it will search within that directory, narrowing down the search as it goes.</p>
<p>Back to the process of generating a commit. You have just created an object. What is the type of that object? You can use another plumbing command, <code>git cat-file -t</code> (<code>-t</code> stands for "type"), to check that out:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/cat_file_t_blob.png" alt="Using  reveals the type of the Git object" width="600" height="400" loading="lazy">
_Using <code>git cat-file -t &amp;lt;object_sha&amp;gt;</code> reveals the type of the Git object_</p>
<p>Not surprisingly, this object is a blob. You can also use <code>git cat-file -p</code> (<code>-p</code> stands for "pretty-print") to see its contents:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/cat_file_p_blob.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git cat-file -p</code></em></p>
<p>This process of creating a blob object under <code>.git/objects</code> usually happens when you add something to the staging area — that is, when you use <code>git add</code>. So blobs are not created every time you save a file to the file system (the working dir), but only when you stage it.</p>
<p>Remember that Git creates a blob of the <em>entire</em> file that is staged. Even if a single character is modified or added, the file has a new blob with a new hash (as in the example in <a class="post-section-overview" href="#heading-chapter-1-git-objects">chapter 1</a> where you added <code>!</code> at the end of a line).</p>
<p>Will there be any change to <code>git status</code>?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_blob.png" alt=" after creating a blob object" width="600" height="400" loading="lazy">
<em><code>git status</code> after creating a blob object</em></p>
<p>Apparently, no. Adding a blob object to Git's internal database does not change the status, as Git does not know of any tracked (or untracked) files at this stage.</p>
<p>You need to track this file — add it to the staging area. To do that, you can use another plumbing command, <code>git update-index</code>, like so:</p>
<pre><code class="lang-bash">git update-index --add --cacheinfo 100644 &lt;blob-hash&gt; &lt;filename&gt;
</code></pre>
<p>Note: The <code>cacheinfo</code> is a 16-bit file mode as stored by Git, following the layout of POSIX types and modes. This is not within the scope of this book, as it is really not important for you to Git things done.</p>
<p>Running the command above will result in a change to <code>.git</code>'s contents:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/update_index.png" alt="The state of  after updating the index" width="600" height="400" loading="lazy">
<em>The state of <code>.git</code> after updating the index</em></p>
<p>Can you spot the change? A new file by the name of <code>index</code> has been created. This is it — the famous index (or staging area), is basically a file that resides within <code>.git/index</code>.</p>
<p>So now that your blob has been added to the index, do you expect <code>git status</code> to look different?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_update_index.png" alt=" after using " width="600" height="400" loading="lazy">
<em><code>git status</code> after using <code>git update-index</code></em></p>
<p>That's interesting! Two things happened here.</p>
<p>First, you can see that <code>awesome.txt</code> appears in <em>green</em>, in the "Changes to be committed" area. That is so because the index now includes <code>awesome.txt</code>, waiting to be committed.</p>
<p>Second, we can see that <code>awesome.txt</code> appears in <em>red</em> — because Git believes the file <code>awesome.txt</code> has been deleted, and the fact that the file has been deleted is not staged.</p>
<p>(Note: You may have noticed that I sometimes refer to Git with words such as "believes", "thinks", or "wants". As I explained in the <a class="post-section-overview" href="#heading-introduction">introduction of this book</a> - in order for us to enjoy playing around with Git, and reading (and writing) this book, I feel like referring to Git as more than just code makes it all so much more enjoyable.)</p>
<p>This happens as you added the blob with the contents <code>Git is awesome</code> to the objects' database, and updated the index that the file <code>awesome.txt</code> holds the contents of that blob, but you never actually created that file on disk.</p>
<p>You can easily solve this by taking the contents of the blob and writing them to our file system, to a file called <code>awesome.txt</code>:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"Git is awesome"</span> &gt; awesome.txt
</code></pre>
<p>As a result, it will no longer appear in red by <code>git status</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_creating_file_on_disk.png" alt=" after creating  on disk" width="600" height="400" loading="lazy">
<em><code>git status</code> after creating <code>awesome.txt</code> on disk</em></p>
<p>So now it's time to create a commit object from your staging area. As explained in <a class="post-section-overview" href="#heading-chapter-1-git-objects">chapter 1</a>, a commit object has a reference to a tree, so you need to create a tree.</p>
<p>You can achieve this using the command <code>git write-tree</code>, which records the contents of the index in a tree object. Of course, you can use git <code>cat-file -t</code> to see that it's indeed a tree:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/write_tree.png" alt="Creating a tree object with the contents of the index" width="600" height="400" loading="lazy">
<em>Creating a tree object with the contents of the index</em></p>
<p>And you can use <code>git cat-file -p</code> to see its contents:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/cat_file_p_tree.png" alt=" to see the tree's contents" width="600" height="400" loading="lazy">
<em><code>git cat-file -p</code> to see the tree's contents</em></p>
<p>Great, so you created a tree, and now you need to create a commit object that references this tree. To do that, you can use the command:</p>
<pre><code class="lang-bash">git commit-tree &lt;tree-hash&gt; -m &lt;commit message&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit-tree.png" alt="Committing using the tree object" width="600" height="400" loading="lazy">
<em>Committing using the tree object</em></p>
<p>You should now feel comfortable with the commands used to check the created object's type, and print its contents:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_object_cat_file.png" alt="Creating a commit object" width="600" height="400" loading="lazy">
<em>Creating a commit object</em></p>
<p>Note that this commit object doesn't have a parent, because it is the first commit. When you add another commit you will probably want to declare its parent — don't worry, you will do so later.</p>
<p>The last hash that we got — <code>b6d05ee40344ef5d53502539772086da14ad2b07</code> – is a commit's hash. You should actually be used to using these hashes — you probably look at them all the time (when using <code>git log</code>, for instance). Note that this commit object points to a tree object, with its own hash, which you rarely specify explicitly.</p>
<p>Will something change in <code>git status</code>?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_creating_commit_object.png" alt=" after creating a commit object" width="600" height="400" loading="lazy">
<em><code>git status</code> after creating a commit object</em></p>
<p>No, nothing has changed. Why is that?</p>
<p>Well, to know that your file has been committed, Git needs to know about the latest commit. How does Git do that? It goes to the <code>HEAD</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/looking_at_head_1.png" alt="Looking at the contents of " width="600" height="400" loading="lazy">
<em>Looking at the contents of <code>HEAD</code></em></p>
<p><code>HEAD</code> points to <code>main</code>, but what is <code>main</code>? You haven't really created it yet.</p>
<p>As we explained earlier in <a class="post-section-overview" href="#heading-chapter-2-branches-in-git">chapter 2</a>, a branch is simply a named reference to a commit. And in this case, we would like <code>main</code> to refer to the commit object with the hash <code>b6d05ee40344ef5d53502539772086da14ad2b07</code>.</p>
<p>You can achieve this by creating a file at <code>.git/refs/heads/main</code>, with the contents of this hash, like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/creating_main.png" alt="Creating " width="600" height="400" loading="lazy">
<em>Creating <code>main</code></em></p>
<p>In sum, a branch is just a file inside <code>.git/refs/heads</code>, containing a hash of the commit it refers to.</p>
<p>Now, finally, <code>git status</code> and <code>git log</code> seem to appreciate our efforts:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_commit_1.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git status</code></em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_commit_1.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git log</code></em></p>
<p>You have successfully created a commit without using porcelain commands! How cool is that?</p>
<h3 id="heading-recap-how-to-create-a-repo-from-scratch">Recap - How to Create a Repo From Scratch</h3>
<p>In this chapter, you fearlessly deep-dived into Git. You stopped using porcelain commands and switched to plumbing commands.</p>
<p>By using echo and low-level commands such as <code>git hash-object</code>, you were able to create a blob, add it to the index, create a tree of the index, and create a commit object pointing to that tree.</p>
<p>You also learned that <code>HEAD</code> is a file, located in <code>.git/HEAD</code>. Branches are also files, located under <code>.git/refs/heads</code>. When you understand how Git operates, those abstract notions of <code>HEAD</code> or "branches" become very tangible.</p>
<p>The next chapter will deepen your understanding of how branches work under the hood.</p>
<h2 id="heading-chapter-5-how-to-work-with-branches-in-git-under-the-hood">Chapter 5 - How to Work with Branches in Git — Under the Hood</h2>
<p>In the previous chapter you created a repository and a commit without using <code>git init</code>, <code>git add</code> or <code>git commit</code>. In this chapter, you we will create and switch between branches without using porcelain commands (<code>git branch</code>, <code>git switch</code>, or <code>git checkout</code>).</p>
<p>It's perfectly understandable if you are excited, I am too!</p>
<p>Continuing from the previous chapter - you only have one branch, named <code>main</code>. To create another one with the name <code>test</code> (as the equivalent of <code>git branch test</code>), you would need to create a file named <code>test</code> within <code>.git/refs/heads</code>, and the contents of that file would be the same commit's hash as the <code>main</code> branch points to.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_test_branch.png" alt="Creating  branch" width="600" height="400" loading="lazy">
<em>Creating <code>test</code> branch</em></p>
<p>If you use <code>git log</code>, you can see that this is indeed the case — both <code>main</code> and <code>test</code> point to this commit:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_after_creating_test_branch.png" alt=" after creating  branch" width="600" height="400" loading="lazy">
<em><code>git log</code> after creating <code>test</code> branch</em></p>
<p>(Note: if you run this command and don't see a valid output, you may have written something other than the commit's hash into <code>.git/refs/heads/test</code>.)</p>
<p>Next, switch to our newly created branch (the equivalent of <code>git checkout test</code>). How would you do that? Try to answer for yourself before moving on to the next paragraph.</p>
<p>To change the active branch, you should change <code>HEAD</code> to point to your new branch:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/change_head_to_test.png" alt="Switching to branch  by changing " width="600" height="400" loading="lazy">
<em>Switching to branch <code>test</code> by changing <code>HEAD</code></em></p>
<p>As you can see, <code>git status</code> confirms that <code>HEAD</code> now points to <code>test</code>, which is, therefore, the active branch.</p>
<p>You can now use the commands you have already used in the previous chapter to create another file and add it to the index:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/writing_another_file.png" alt="Writing and staging another file" width="600" height="400" loading="lazy">
<em>Writing and staging another file</em></p>
<p>Following the commands above, you:</p>
<ul>
<li>Create a blob with the content of <code>Another File</code> (using <code>git hash-object</code>).</li>
<li>Add it to the index by the name <code>another_file.txt</code> (using <code>git update-index</code>).</li>
<li>Create a corresponding file on disk with the contents of the blob (using <code>git cat-file -p</code>).</li>
<li>Create a tree object representing the index (using <code>git write-tree</code>).</li>
</ul>
<p>It's now time to create a commit referencing this tree. This time, you should also specify the parent of this commit — which would be the previous commit. You specify the parent using the <code>-p</code> switch of <code>git commit-tree</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_2.png" alt="Creating another commit object" width="600" height="400" loading="lazy">
<em>Creating another commit object</em></p>
<p>We have just created a commit, with a tree as well as a parent, as you can see:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/cat_file_commit_2.png" alt="Observing the new commit object" width="600" height="400" loading="lazy">
<em>Observing the new commit object</em></p>
<p>(Note: the SHA-1 value of your commit object will be different than the one shown in the screenshot above, as it includes the timestamp of the commit, and also author's details - which would be different on your machine.)</p>
<p>Will <code>git log</code> show us the new commit?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_after_creating_commit_2.png" alt=" after creating &quot;Commit 2&quot;" width="600" height="400" loading="lazy">
<em><code>git log</code> after creating "Commit 2"</em></p>
<p>As you can see, <code>git log</code> doesn't show anything new. Why is that?</p>
<p>Remember that <code>git log</code> traces the branches to find relevant commits to show. It shows us now <code>test</code> and the commit it points to, and it also shows <code>main</code> which points to the same commit.</p>
<p>That's right — you need to change <code>test</code> to point to the new commit object. You can do that by changing the contents of <code>.git/refs/heads/test</code>:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> 22267a945af8fde78b62ee7f705bbecfdd276b3d &gt; .git/refs/heads/<span class="hljs-built_in">test</span>
</code></pre>
<p>And now if you run <code>git log</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_after_updating_test_branch.png" alt=" after updating  branch" width="600" height="400" loading="lazy">
<em><code>git log</code> after updating <code>test</code> branch</em></p>
<p>It worked!</p>
<p><code>git log</code> goes to <code>HEAD</code>, which tells Git to go to the branch <code>test</code>, which points to commit <code>222..3d</code>, which links back to its parent commit <code>b6d..07</code>.</p>
<p>Feel free to admire the beauty, I Git you. 😊</p>
<p>By inspecting your repository's folder, you can see that you have six different objects under the folder <code>.git/objects</code> - these are the two blobs you created (one for <code>awesome.txt</code> and one for <code>file.txt</code>), two commit objects ("Commit 1" and "Commit 2"), and the tree objects - each pointed to by one of the commit objects.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/tree_after_commit_2.png" alt="The tree listing after creating &quot;Commit 2&quot;" width="600" height="400" loading="lazy">
<em>The tree listing after creating "Commit 2"</em></p>
<p>You also have <code>.git/HEAD</code> that points to the active branch or commit, and two branches - within <code>.git/refs/heads</code>.</p>
<h3 id="heading-recap-how-to-work-with-branches-in-git-under-the-hood">Recap - How to Work with Branches in Git — Under the Hood</h3>
<p>In this chapter you understood how branches actually work in Git.</p>
<p>The main things we covered:</p>
<ul>
<li>A branch is a file under <code>.git/refs/heads</code>, where the content of the file is a SHA-1 value of a commit.</li>
<li>To create a new branch, Git simply creates a new file under <code>.git/refs/heads</code> with the name of the branch - for example, <code>.git/refs/heads/my_branch</code> for the branch <code>my_branch</code>.</li>
<li>To switch the active branch, Git modifies the contents of <code>.git/HEAD</code> to refer to the new active branch. <code>.git/HEAD</code> may also point to a commit object directly.</li>
<li>When committing using <code>git commit</code>, Git creates a commit object, and also moves the current branch (that is, the contents of the file under <code>.git/refs/heads</code>) to point to the newly created commit object.</li>
</ul>
<h2 id="heading-part-1-summary">Part 1 - Summary</h2>
<p>This part introduced you to the internals of Git. We started by covering <a class="post-section-overview" href="#heading-chapter-1-git-objects">the basic objects</a> — blobs, trees, and commits.</p>
<p>You learned that a <strong>blob</strong> holds the contents of a file. A <strong>tree</strong> is a directory-listing, containing blobs and/or sub-trees. A <strong>commit</strong> is a snapshot of our working directory, with some meta-data such as the time or the commit message.</p>
<p>You learned about <strong><a class="post-section-overview" href="#heading-chapter-2-branches-in-git">branches</a></strong>, seeing that they are nothing but a named reference to a commit.</p>
<p>You learned the process of <a class="post-section-overview" href="#heading-chapter-3-how-to-record-changes-in-git">recording changes in Git</a>, and that it involves the <strong>working directory</strong>, a directory that has a repository associated with it, the <strong>staging area (index)</strong> which holds the tree for the next commit, and the <strong>repository</strong>, which is a collection of commits and references.</p>
<p>We clarified how these terms relate to Git commands we know by creating a new repository and committing a file using the well-known <code>git init</code>, <code>git add</code>, and <code>git commit</code>.</p>
<p>Then you <a class="post-section-overview" href="#heading-chapter-4-how-to-create-a-repo-from-scratch">created a new repository from scratch</a>, by using <code>echo</code> and low-level commands such as <code>git hash-object</code>. You created a blob, added it to the index, created a tree object representing the index, and even created a commit object pointing to that tree.</p>
<p>You were also able to create and <a class="post-section-overview" href="#heading-chapter-5-how-to-work-with-branches-in-git-under-the-hood">switch between branches by modifying files directly</a>. Kudos to those of you who tried this on your own!</p>
<p>All together, after following along through this part, you should feel that you've deepened your understanding of what is happening under the hood when working with Git.</p>
<p>The next part will explore different strategies for integrating changes when working in different branches in Git - specifically, merge and rebase.</p>
<h1 id="heading-part-2-branching-and-integrating-changes">Part 2 - Branching and Integrating Changes</h1>
<h2 id="heading-chapter-6-diffs-and-patches">Chapter 6 - Diffs and Patches</h2>
<p>In Part 1 you learned how Git works under the hood, the different Git objects, and how to create a repo from scratch.</p>
<p>When teams work with Git, they introduce sequences of changes, usually in branches, and then they need to combine different change histories together. To really understand how this is achieved, you should learn how Git treats diffs and patches. You will then apply your knowledge to understand the process of merge and rebase.</p>
<p>Many of the interesting processes in Git like merging, rebasing, or even committing are based on diffs and patches. Developers work with diffs all the time, whether using Git directly or relying on the IDE's diff view. In this chapter, you will learn what Git diffs and patches are, their structure, and how to apply patches.</p>
<p>As a reminder from the <a class="post-section-overview" href="#heading-chapter-1-git-objects">chapter on Git Objects</a>, a commit is a snapshot of the working tree at a certain point in time, in addition to some meta-data.</p>
<p>Yet, it is really hard to make sense of individual commits by looking at the entire working tree. Rather, it is more helpful to look at how different a commit is from its parent commit, that is, the diff between these commits.</p>
<p>So, what do I mean when I say "diff"? Let's start with some history.</p>
<h3 id="heading-git-diffs-history">Git Diff's History</h3>
<p>Git's <code>diff</code> is based on the diff utility on UNIX systems. <code>diff</code> was developed in the early 1970's on the Unix operating system. The first released version shipped with the Fifth Edition of Unix in 1974.</p>
<p><code>git diff</code> is a command that takes two inputs, and computes the difference between them. Inputs can be commits, but also files, and even files that have never been introduced to the repository.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_definition.png" alt="Git diff takes two inputs, which can be commits or files" width="600" height="400" loading="lazy">
<em>Git diff takes two inputs, which can be commits or files</em></p>
<p>This is important - <code>git diff</code> computes the <em>difference</em> between two strings, which most of the time happen to consist of code, but not necessarily.</p>
<h3 id="heading-time-to-get-hands-on">Time to Get Hands-On</h3>
<p>As always, you are encouraged to run the commands yourself while reading this chapter. Unless noted otherwise, I will use the following repository:</p>
<p><a target="_blank" href="https://github.com/Omerr/gitting_things_repo.git">https://github.com/Omerr/gitting_things_repo.git</a></p>
<p>You can clone it locally and have the same starting point I am using for this chapter.</p>
<p>Consider this short text file on my machine, called <code>file.txt</code>, which consists of 6 lines:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/file_txt_1.png" alt=" consists of six lines" width="600" height="400" loading="lazy">
<em><code>file.txt</code> consists of six lines</em></p>
<p>Now, modify this file a bit. Remove the second line, and insert a new line as the fourth line. Add an exclamation mark (<code>!</code>) to the end of the last line, so you get this result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_file_txt_1.png" alt="After modifying , we get different six lines" width="600" height="400" loading="lazy">
<em>After modifying <code>file.txt</code>, we get different six lines</em></p>
<p>Save this file with a new name, <code>new_file.txt</code>.</p>
<p>Now you can run <code>git diff</code> to compute the difference between the files like so:</p>
<pre><code class="lang-bash">git diff --no-index file.txt new_file.txt
</code></pre>
<p>(I will explain the <code>--no-index</code> switch of this command later. For now it's enough to understand it allows us to compare between two files that are not part of a Git repository.)</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_1.png" alt="The output of " width="600" height="400" loading="lazy">
_The output of <code>git diff --no-index file.txt new_file.txt</code>_</p>
<p>The output of <code>git diff</code> shows quite a lot of things.</p>
<p>Focus on the part starting with <code>This is a file</code>. You can see that the added line (<code>// new test</code>) is preceded by a <code>+</code> sign. The deleted line is preceded by a <code>-</code> sign.</p>
<p>Interestingly, notice that Git views a modified line as a sequence of two changes - erasing a line and adding a new line instead. So the patch includes deleting the last line, and adding a new line that's equal to that line, with the addition of a <code>!</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_format_lines.png" alt="Addition lines are preceded by , deletion lines by , and modification lines are sequences of deletions and additions" width="600" height="400" loading="lazy">
<em>Addition lines are preceded by <code>+</code>, deletion lines by <code>-</code>, and modification lines are sequences of deletions and additions</em></p>
<p>Now would be a good time to discuss the terms "patch" and "diff". These two are often used interchangeably, although there is a distinction, at least historically. </p>
<p>A <strong>diff</strong> shows the differences between two files, or snapshots, and can be quite minimal in doing so. A <strong>patch</strong> is an extension of a diff, augmented with further information such as context lines and filenames, which allow it to be <em>applied</em> more widely. It is a text document that describes how to alter an existing file or codebase.</p>
<p>These days, the Unix <code>diff</code> program, and <code>git diff</code>, can produce patches of various kinds.</p>
<p>A patch is a compact representation of the differences between two files. It describes how to turn one file into another.</p>
<p>In other words, if you apply the "instructions" produced by <code>git diff</code> on <code>file.txt</code> - that is, remove the second line, insert <code>// new test</code> as the fourth line, remove the last line, and add instead a line with the same content and <code>!</code> - you will get the content of <code>new_file.txt</code>.</p>
<p>Another important thing to note is that a patch is <strong>asymmetric</strong>: the patch from <code>file.txt</code> to <code>new_file.txt</code> is not the same as the patch for the other direction. Generating a patch between <code>new_file.txt</code> and <code>file.txt</code>, in this order, would mean exactly the opposite instructions than before - add the second line instead of removing it, and so on.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/patch_asymmetric.png" alt="A patch consists of asymmetric instructions to get from one file to another" width="600" height="400" loading="lazy">
<em>A patch consists of asymmetric instructions to get from one file to another</em></p>
<p>Try it out:</p>
<pre><code class="lang-bash">git diff --no-index new_file.txt file.txt
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_2.png" alt="Running git diff in the reverse direction yields the reverse instructions - add a line instead of removing it, and so on" width="600" height="400" loading="lazy">
<em>Running git diff in the reverse direction yields the reverse instructions - add a line instead of removing it, and so on</em></p>
<p>The patch format uses context, as well as line numbers, to locate differing file regions. This allows a patch to be applied to a somewhat earlier or later version of the first file than the one from which it was derived, as long as the applying program can still locate the context of the change. We will see exactly how these are used.</p>
<h3 id="heading-the-structure-of-a-diff">The Structure of a Diff</h3>
<p>It's time to dive deeper.</p>
<p>Generate a diff from <code>file.txt</code> to <code>new_file.txt</code> again, and consider the output more carefully:</p>
<pre><code class="lang-bash">git diff --no-index file.txt new_file.txt
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_1-1.png" alt="The output of " width="600" height="400" loading="lazy">
_The output of <code>git diff --no-index file.txt new_file.txt</code>_</p>
<p>The first line introduces the compared files. Git always gives one file the name <code>a</code>, and the other the name <code>b</code>. So in this case <code>file.txt</code> is called <code>a</code>, whereas <code>new_file.txt</code> is called <code>b</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_structure_1.png" alt="The first line in 's output introduces the files being compared" width="600" height="400" loading="lazy">
<em>The first line in <code>diff</code>'s output introduces the files being compared</em></p>
<p>Then the second line, starting with <code>index</code>, includes the blob SHAs of these files. So even though in our case they are not even stored within a Git repo, Git shows their corresponding SHA-1 values.</p>
<p>The third value in this line, <code>100644</code>, is the "mode bits", indicating that this is a "regular" file: not executable and not a symbolic link.</p>
<p>The use of two dots (<code>..</code>) here between the blob SHAs is just as a separator (unlike other cases where it's used within Git).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_structure_2.png" alt="The second line in 's output includes the blob SHAs of the compared files, as well as the mode bits" width="600" height="400" loading="lazy">
<em>The second line in <code>diff</code>'s output includes the blob SHAs of the compared files, as well as the mode bits</em></p>
<p>Other header lines might indicate the old and new mode bits if they've changed, old and new filenames if the files were being renamed, and so on.</p>
<p>The blob SHAs (also called "blob IDs") are helpful if this patch is later applied by Git to the same project and there are conflicts while applying it. You will better understand what this means when you learn about the merges in <a class="post-section-overview" href="#heading-chapter-7-understanding-git-merge">the next chapter</a>.</p>
<p>After the blob IDs, we have two lines: one starting with <code>-</code> signs, and the other starting with <code>+</code> signs. This is the traditional "unified diff" header, again showing the files being compared and the direction of the changes: <code>-</code> signs show lines in the A version that are missing from the B version, and <code>+</code> signs show lines missing in the A version but present in B.</p>
<p>If the patch were of this file being added or deleted in its entirety, then one of these would be <code>/dev/null</code> to signal that.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_structure_3.png" alt=" signs show lines in the A version but missing from the B version; and  signs, lines missing in A version but present in B" width="600" height="400" loading="lazy">
<em><code>-</code> signs show lines in the A version but missing from the B version, and <code>+</code> signs, lines missing in A version but present in B</em></p>
<p>Consider the case where you delete a file:</p>
<pre><code class="lang-bash">rm awesome.txt
</code></pre>
<p>And then use <code>git diff</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/rm_diff.png" alt="'s output for a deleted file" width="600" height="400" loading="lazy">
<em><code>git diff</code>'s output for a deleted file</em></p>
<p>The <code>A</code> version, representing the state of the index, is currently <code>awesome.txt</code>, compared to the working dir where this file does not exist, so it is <code>/dev/null</code>. All lines are preceded by <code>-</code> signs as they exist only in the <code>A</code> version.</p>
<p>For now, undo the deleting (more on undoing changes in Part 3):</p>
<pre><code class="lang-bash">git restore awesome.txt
</code></pre>
<p>Going back to the diff we started with:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_1-2.png" alt="The output of " width="600" height="400" loading="lazy">
_The output of <code>git diff --no-index file.txt new_file.txt</code>_</p>
<p>After this unified diff header, we get to the main part of the diff, consisting of "difference sections", also called "hunks" or "chunks" in Git. Note that these terms are used interchangeably, and you may stumble upon either of them in Git's documentation and tutorials, as well as Git's source code.</p>
<p>Every hunk begins with a single line, starting with two <code>@</code> signs. These signs are followed by at most four numbers, and then a header for the chunk - which is an educated guess by Git. Usually, it will include the beginning of a function or a class, when possible.</p>
<p>In this example it doesn't include anything as this is a text file, so consider another example for a moment:</p>
<pre><code class="lang-bash">git diff --no-index example.py example_changed.py
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_example_changed.png" alt="When possible, Git includes a header for each hunk, for example a function or class definition" width="600" height="400" loading="lazy">
<em>When possible, Git includes a header for each hunk, for example a function or class definition</em></p>
<p>In the image above, the hunk's header includes the beginning of the function that includes the changed lines - <code>def example_function(x)</code>.</p>
<p>Back to our previous example then:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_1-3.png" alt="Back to the previous diff" width="600" height="400" loading="lazy">
<em>Back to the previous diff</em></p>
<p>After the two <code>@</code> signs, you'll find four numbers:</p>
<p>The first numbers are preceded by a <code>-</code> sign as they refer to <code>file A</code>. The first number represents the line number corresponding to the first line in <code>file A</code> that this hunk refers to. In the example above, it is <code>1</code>, meaning that the line <code>This is a file</code> corresponds to line number <code>1</code> in version <code>file A</code>.</p>
<p>This number is followed by a comma (<code>,</code>), and then the number of lines this chunk consists of in <code>file A</code>. This number includes all context lines (the lines preceded with a space in the <code>diff</code>), or lines marked with a <code>-</code> sign, as they are part of <code>file A</code>, but not lines marked with a <code>+</code> sign, as they do not exist in <code>file A</code>.</p>
<p>In our example, this number is <code>6</code>, counting the context line <code>This is a file</code>, the <code>-</code> line <code>It has a nice poem:</code>, then the three context lines, and lastly <code>Are belong to you</code>.</p>
<p>As you can see, the lines beginning with a space character are context lines, which means they appear as shown in both <code>file A</code> and <code>file B</code>.</p>
<p>Then, we have a <code>+</code> sign to mark the two numbers that refer to <code>file B</code>. First, there's the line number corresponding to the first line in <code>file B</code>, followed by the number of lines this chunk consists of in <code>file B</code>.</p>
<p>This number includes all context lines, as well as lines marked with the <code>+</code> sign, as they are part of <code>file B</code>, but not lines marked with a <code>-</code> sign.</p>
<p>These four numbers are followed by two additional <code>@</code> signs.</p>
<p>After the header of the chunk, we get the actual lines - either context, <code>-</code>, or <code>+</code> lines.</p>
<p>Typically and by default, a hunk starts and ends with three context lines. For example, if you modify lines 4-5 in a file with ten lines:</p>
<ul>
<li>Line 1 - context line (before the changed lines)</li>
<li>Line 2 - context line (before the changed lines)</li>
<li>Line 3 - context line (before the changed lines)</li>
<li>Line 4 - changed line</li>
<li>Line 5 - another changed line</li>
<li>Line 6 - context line (after the changed lines)</li>
<li>Line 7 - context line (after the changed lines)</li>
<li>Line 8 - context line (after the changed lines)</li>
<li>Line 9 - this line will not be part of the hunk</li>
</ul>
<p>So by default, changing lines 4-5 results in a hunk consisting of lines 1-8, that is, three lines before and three lines after the modified lines.</p>
<p>If that file doesn't have nine lines, but rather six lines - then the hunk will contain only one context line after the changed lines, and not three. Similarly, if you change the second line of a file, then there would be only one line of context before the changed lines.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_structure_4.png" alt="The patch format by " width="600" height="400" loading="lazy">
<em>The patch format by <code>git diff</code></em></p>
<h3 id="heading-how-to-produce-diffs">How to Produce Diffs</h3>
<p>The last example we considered shows a diff between two files. A single patch file can contain the differences for <em>any</em> number of files, and <code>git diff</code> produces diffs for all altered files in the repository in a single patch.</p>
<p>Often, you will see the output of <code>git diff</code> showing two versions of the same file and the difference between them.</p>
<p>To demonstrate, consider the state in another branch called <code>diffs</code>:</p>
<pre><code class="lang-bash">git checkout diffs
</code></pre>
<p>Again, I encourage you to run the commands with me - make sure you clone the repository from:</p>
<p><a target="_blank" href="https://github.com/Omerr/gitting_things_repo.git">https://github.com/Omerr/gitting_things_repo.git</a></p>
<p>At the current state, the active directory is a Git repository, with a clean status:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_branch_diffs.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git status</code></em></p>
<p>Take an existing file, <code>my_file.py</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/nano_my_file.png" alt="An example file - " width="600" height="400" loading="lazy">
_An example file - <code>my_file.py</code>_</p>
<p>And change the second line from <code>print('An example function!')</code> to <code>print('An example function! And it has been changed!')</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/nano_my_file_after_change.png" alt="The contents of  after modifying the second line" width="600" height="400" loading="lazy">
_The contents of <code>my_file.py</code> after modifying the second line_</p>
<p>Save your changes, but don't stage or commit them. Next, run <code>git diff</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_my_file.png" alt="The output of  for  after changing it" width="600" height="400" loading="lazy">
_The output of <code>git diff</code> for <code>my_file.py</code> after changing it_</p>
<p>The output of <code>git diff</code> shows the difference between <code>my_file.py</code>'s version in the staging area, which in this case is the same as the last commit (<code>HEAD</code>), and the version in the working directory.</p>
<p>I covered the terms "working directory", "staging area", and "commit" in the <a class="post-section-overview" href="#heading-chapter-1-git-objects">Git objects chapter</a>, so check it out in ccase you would like to refresh your memory. As a reminder, the terms "staging area" and "index" are interchangeable, and both are widely used.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/repo_state_commit_2_staging_area.png" alt="At this state, the status of the working dir is different from the status of the index. The status of the index is the same as that of " width="600" height="400" loading="lazy">
<em>At this state, the status of the working dir is different from the status of the index. The status of the index is the same as that of <code>HEAD</code></em></p>
<p>To see the difference between the <strong>working dir</strong> and the <strong>staging area</strong>, use <code>git diff</code>, without any additional flags.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/repo_state_commit_2_git_diff-1.png" alt="Without switches,  shows the difference between the staging area and the working directory" width="600" height="400" loading="lazy">
<em>Without switches, <code>git diff</code> shows the difference between the staging area and the working directory</em></p>
<p>As you can see, <code>git diff</code> lists here both <code>file A</code> and <code>file B</code> pointing to <code>my_file.py</code>. <code>file A</code> here refers to the version of <code>my_file.py</code> in the staging area, whereas <code>file B</code> refers to its version in the working dir.</p>
<p>Note that if you modify <code>my_file.py</code> in a text editor, and don't save the file, then <code>git diff</code> will not be aware of the changes you've made. This is because they haven't been saved to the working dir.</p>
<p>We can provide a few switches to <code>git diff</code> to get the diff between the working dir and a specific commit, or between the staging area and the latest commit, or between two commits, and so on.</p>
<p>First create a new file, <code>new_file.txt</code>, and save it:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/nano_new_file.png" alt="A simple new file saved as new_file.txt" width="600" height="400" loading="lazy">
_A simple new file saved as <code>new_file.txt</code>_</p>
<p>Currently the file is in the working dir, and it is actually untracked in Git.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_file_working_dir.png" alt="A new, untracked file" width="600" height="400" loading="lazy">
<em>A new, untracked file</em></p>
<p>Now stage and commit this file:</p>
<pre><code class="lang-bash">git add new_file.txt
git commit -m <span class="hljs-string">"Commit 3"</span>
</code></pre>
<p>Now, the state of <code>HEAD</code> is the same as the state of the staging area, as well as the working tree:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/repo_state_commit_3.png" alt="The state of HEAD is the same as the index and the working dir" width="600" height="400" loading="lazy">
<em>The state of <code>HEAD</code> is the same as the index and the working dir</em></p>
<p>Next, edit <code>new_file.txt</code> by adding a new line at the beginning and another new line at the end:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_file_edited.png" alt="Modifying  by adding a line in the beginning and another in the end" width="600" height="400" loading="lazy">
_Modifying <code>new_file.txt</code> by adding a line in the beginning and another in the end_</p>
<p>As a result, the state is as follows:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/repo_state_start_end.png" alt="After saving, the state in the working dir is different than that of the index or " width="600" height="400" loading="lazy">
<em>After saving, the state in the working dir is different than that of the index or <code>HEAD</code></em></p>
<p>A nice trick would be to use <code>git add -p</code>, which allows you to split the changes even within a file, and consider which ones you'd like to stage.</p>
<p>In this case, add the first line to the index, but not the last line. To do that, you can split the hunk using <code>s</code>, then accept to stage the first hunk (using <code>y</code>), and not the second part (using <code>n</code>).</p>
<p>If you are not sure what each letter stands for, you can always use a <code>?</code> and Git will tell you.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/add_p.png" alt="Using , you can stage only the first change" width="600" height="400" loading="lazy">
<em>Using <code>git add -p</code>, you can stage only the first change</em></p>
<p>So now the state in <code>HEAD</code> is without either of those new lines. In the staging area you have the first line but not the last line, and in the working dir you have both new lines.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/repo_state_after_add_p.png" alt="The state after staging only the first line" width="600" height="400" loading="lazy">
<em>The state after staging only the first line</em></p>
<p>If you use <code>git diff</code>, what will happen?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_3.png" alt=" shows the difference between the index and the working dir" width="600" height="400" loading="lazy">
<em><code>git diff</code> shows the difference between the index and the working dir</em></p>
<p>Well, as stated before, you get the diff between the staging area and the working tree.</p>
<p>What happens if you want to get the diff between <code>HEAD</code> and the staging area? For that, you can use <code>git diff --cached</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_cached.png" alt=" shows the difference between  and the index" width="600" height="400" loading="lazy">
<em><code>git diff --cached</code> shows the difference between <code>HEAD</code> and the index</em></p>
<p>And what if you want the difference between <code>HEAD</code> and the working tree? For that you can run <code>git diff HEAD</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_HEAD.png" alt=" shows the difference between  and the working dir" width="600" height="400" loading="lazy">
<em><code>git diff HEAD</code> shows the difference between <code>HEAD</code> and the working dir</em></p>
<p>To summarize the different switches for git diff we have seen so far, here's a diagram:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_diagram_1.png" alt="Different switches for " width="600" height="400" loading="lazy">
<em>Different switches for <code>git diff</code></em></p>
<p>As a reminder, at the beginning of this chapter you used <code>git diff --no-index</code>. With the <code>--no-index</code> switch, you can compare two files that are not part of the repository - or of any staging area.</p>
<p>Now, commit the changes you have in the staging area:</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"Commit 4"</span>
</code></pre>
<p>To observe the diff between this commit and its parent commit, you can run the following command:</p>
<pre><code class="lang-bash">git diff HEAD~1 HEAD
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_HEAD_1_HEAD.png" alt="The output of " width="600" height="400" loading="lazy">
<em>The output of <code>git diff HEAD~1 HEAD</code></em></p>
<p>By the way, you can omit the <code>1</code> above and write <code>HEAD~</code>, and get the same result. Using <code>1</code> is the explicit way to state you are referring to the first parent of the commit.</p>
<p>Note that writing the parent commit here, <code>HEAD~1</code>, first results in a diff showing how to get <em>from</em> the parent commit <em>to</em> the current commit. Of course, I could also generate the reverse diff by writing:</p>
<pre><code class="lang-bash">git diff HEAD HEAD~1
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_HEAD_HEAD_1.png" alt="The output of  generates the reverse patch" width="600" height="400" loading="lazy">
<em>The output of <code>git diff HEAD HEAD~1</code> generates the reverse patch</em></p>
<p>To summarize all the different switches for git diff we covered in this section, see this diagram:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_diagram_2.png" alt="The different switches for " width="600" height="400" loading="lazy">
<em>The different switches for <code>git diff</code></em></p>
<p>A short way to view the diff between a commit and its parent is by using <code>git show</code>, for example:</p>
<pre><code class="lang-bash">git show HEAD
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git show HEAD</code></em></p>
<p>This is the same as writing:</p>
<pre><code class="lang-bash">git diff HEAD~ HEAD
</code></pre>
<p>We can now update our diagram:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_diagram_3.png" alt=" is used to show the difference between commits" width="600" height="400" loading="lazy">
<em><code>git diff HEAD~ HEAD</code> is used to show the difference between commits</em></p>
<p>You can go back to this diagram as a reference when needed.</p>
<p>As a reminder, Git commits are snapshots - of the entire working directory of the repository, at a certain point in time. Yet, it's sometimes not useful to regard a commit as a whole snapshot, but rather by the <strong>changes</strong> this specific commit introduced. In other words, by the diff between a parent commit to the next commit.</p>
<p>As you learned in the <a class="post-section-overview" href="#heading-chapter-1-git-objects">Git Objects chapter</a>, Git stores the <strong>entire</strong> snapshots. The diff is dynamically generated from the snapshot data - by comparing the root trees of the commit and its parent.</p>
<p>Of course, Git can compare any two snapshots in time, not just adjacent commits, and also generate a diff of files not included in a repository.</p>
<h3 id="heading-how-to-apply-patches">How to Apply Patches</h3>
<p>By using <code>git diff</code> you can see a patch Git generates, and you can then apply this patch using <code>git apply</code>.</p>
<h4 id="heading-historical-note">Historical Note</h4>
<p>Actually, sharing patches used to be the main way to share code in the early days of open source. But now - virtually all projects have moved to sharing Git commits directly through pull requests (called "merge requests" on some platforms).</p>
<p>The biggest problem with using patches is that it is hard to apply a patch when your working directory does not match the sender's previous commit. Losing the commit history makes it difficult to resolve conflicts. You will better understand this as you dive deeper into the process of <code>git apply</code>, especially in the next chapter where we cover merges.</p>
<h4 id="heading-a-simple-patch">A Simple Patch</h4>
<p>What does it mean to apply a patch? It's time to try it out!</p>
<p>Take the output of <code>git diff</code>:</p>
<pre><code class="lang-bash">git diff HEAD~1 HEAD
</code></pre>
<p>And store it in a file:</p>
<pre><code class="lang-bash">git diff HEAD~1 HEAD &gt; my_patch.patch
</code></pre>
<p>Use <code>reset</code> to undo the last commit:</p>
<pre><code class="lang-bash">git reset --hard HEAD~1
</code></pre>
<p>Don't worry about the last command - I'll explain it in detail in Part 3, where we discuss undoing changes. In short, it allows us to "reset" the state of where <code>HEAD</code> is pointing to, as well as the state of the index and of the working dir. In the example above, they are all set to the state of <code>HEAD~1</code>, or "Commit 3" in the diagram.</p>
<p>So after running the reset command, the contents of the file are as follows (the state from "Commit 3"):</p>
<pre><code class="lang-bash">nano new_file.txt
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/nano_new_file-1.png" alt="Image" width="600" height="400" loading="lazy">
_<code>new_file.txt</code>_</p>
<p>And you will apply this patch that you've just saved:</p>
<pre><code class="lang-bash">nano my_patch.patch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/my_patch.png" alt="The patch you are about to apply, as generated by git diff" width="600" height="400" loading="lazy">
<em>The patch you are about to apply, as generated by git diff</em></p>
<p>This patch tells Git to find the lines:</p>
<pre><code class="lang-txt">This is a new file
With new content!
</code></pre>
<p>Those lines used to be line number 1 and line number 2 in <code>new_file.txt</code>, and add a line with the content <code>START!</code> right above them.</p>
<p>Run this command to apply the patch:</p>
<pre><code class="lang-bash">git apply my_patch.patch
</code></pre>
<p>And as a result, you get this version of your file, just like the commit you have created before:</p>
<pre><code class="lang-bash">nano new_file.txt
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_file_after_applying.png" alt="The contents of  after applying the patch" width="600" height="400" loading="lazy">
_The contents of <code>new_file.txt</code> after applying the patch_</p>
<h4 id="heading-understanding-the-context-lines">Understanding the Context Lines</h4>
<p>To understand the importance of context lines, consider a more advanced scenario. What happens if line numbers have changed since you created the patch file?</p>
<p>To test, start by creating another file:</p>
<pre><code class="lang-bash">nano test.text
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/testing_file.png" alt="Creating another file - " width="600" height="400" loading="lazy">
<em>Creating another file - <code>test.txt</code></em></p>
<p>Stage and commit this file:</p>
<pre><code class="lang-bash">git add test.txt

git commit -m <span class="hljs-string">"Test file"</span>
</code></pre>
<p>Now, change this file by adding a new line, and also erasing the line before the last one:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/testing_file_modified.png" alt="Changes to " width="600" height="400" loading="lazy">
<em>Changes to <code>test.txt</code></em></p>
<p>Observe the difference between the original version of the file and the version including your changes:</p>
<pre><code class="lang-bash">git diff -- test.txt
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/testing_file_diff.png" alt="The output for git diff -- " width="600" height="400" loading="lazy">
<em>The output for <code>git diff -- test.txt</code></em></p>
<p>(Using <code>-- test.txt</code> tells Git to run the command <code>diff</code>, taking into consideration only <code>test.txt</code>, so you don't get the diff for other files.)</p>
<p>Store this diff into a patch file:</p>
<pre><code class="lang-bash">git diff -- test.txt &gt; new_patch.patch
</code></pre>
<p>Now, reset your state to that before introducing the changes:</p>
<pre><code class="lang-bash">git reset --hard
</code></pre>
<p>If you were to apply new_patch.patch now, it would simply work.</p>
<p>Let's now consider a more interesting case. Modify <code>test.txt</code> again by adding a new line at the beginning:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/testing_file_added_first_line.png" alt="Adding a new line at the beginning of " width="600" height="400" loading="lazy">
<em>Adding a new line at the beginning of <code>test.txt</code></em></p>
<p>As a result, the line numbers are different from the original version where the patch has been created. Consider the patch you created before:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_patch.png" alt="Image" width="600" height="400" loading="lazy">
_<code>new_patch.patch</code>_</p>
<p>It assumes that the line <code>With more text</code> is the second line in <code>test.txt</code>, which is no longer the case. So...will <code>git apply</code> work?</p>
<pre><code class="lang-bash">git apply new_patch.patch
</code></pre>
<p>It worked!</p>
<p>By default, Git looks for 3 lines of context before and after each change introduced in the patch - as you can see, they are included in the patch file. If you take three lines before and after the added line, and three lines before and after the deleted line (actually only one line after, as no other lines exist) - you get to the patch file. If these lines all exist - then applying the patch works, even if the line numbers changed.</p>
<p>Reset the state again:</p>
<pre><code class="lang-bash">git reset --hard
</code></pre>
<p>What happens if you change one of the context lines? Try it out by changing the line <code>With more text</code> to <code>With more text!</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/testing_file_modifying_second_line.png" alt="Changing the line  to " width="600" height="400" loading="lazy">
<em>Changing the line <code>With more text</code> to <code>With more text!</code></em></p>
<p>And now:</p>
<pre><code class="lang-bash">git apply new_patch.patch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_new_patch.png" alt=" doesn't apply the patch" width="600" height="400" loading="lazy">
<em><code>git apply</code> doesn't apply the patch</em></p>
<p>Well, no. The patch does not apply. If you are not sure why, or just want to better understand the process Git is performing, you can add the <code>--verbose</code> flag to <code>git apply</code>, like so:</p>
<pre><code class="lang-bash">git apply --verbose new_patch.patch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_new_patch_verbose.png" alt=" shows the process Git is taking to apply the patch" width="600" height="400" loading="lazy">
<em><code>git apply --verbose</code> shows the process Git is taking to apply the patch</em></p>
<p>It seems that Git searched lines from the file, including the line "With more text", right before the line "It has some really nice lines". This sequence of lines no longer exists in the file. As Git cannot find this sequence, it cannot apply the patch.</p>
<p>As mentioned earlier, by default, Git looks for 3 lines of context before and after each change introduced in the patch. If the surrounding three lines do not exist, Git cannot apply the patch.</p>
<p>You can ask Git to rely on fewer lines of context, using the <code>-C</code> argument. For example, to ask Git to look for 1 line of the surrounding context, run the following command:</p>
<pre><code class="lang-bash">git apply -C1 new_patch.patch
</code></pre>
<p>The patch applies!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_c1.png" alt="Image" width="600" height="400" loading="lazy">
_<code>git apply -C1 new_patch.patch</code>_</p>
<p>Why is that? Consider the patch again:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_patch-1.png" alt="Image" width="600" height="400" loading="lazy">
_<code>new_patch.patch</code>_</p>
<p>When applying the patch with the <code>-C1</code> option, Git is looking for the lines:</p>
<pre><code class="lang-txt">Like this one
And that one
</code></pre>
<p>in order to add the line <code>!!!This is the new line!!!</code> between these two lines. These lines exist (and, importantly, they appear one right after the other). As a result, Git can successfully add the line between them, even though the line numbers changed.</p>
<p>Similarly, Git would look for the lines:</p>
<pre><code class="lang-txt">How wonderful
So we are writing an example
Git is awesoome!
</code></pre>
<p>As Git can find these lines, Git can erase the middle one.</p>
<p>If we changed one of these lines, say, changed "How wonderful" to "How very wondeful", then Git would not be able to find the string above, and thus the patch would not apply.</p>
<h3 id="heading-recap-git-diff-and-patch">Recap - Git Diff and Patch</h3>
<p>In this chapter, you learned what a diff is, and the difference between a diff and a patch. You learned how to generate various patches using different switches for <code>git diff</code>. You also learned what the output of git diff looks like, and how it is constructed. Ultimately, you learned how patches are applied, and specifically the importance of context.</p>
<p>Understanding diffs is a major milestone for understanding many other processes within Git - for example, merging or rebasing, that we will explore in the next chapters.</p>
<h2 id="heading-chapter-7-understanding-git-merge">Chapter 7 - Understanding Git Merge</h2>
<p>By reading this chapter, you are going to really understand <code>git merge</code>, one of the most common operations you'll perform in your Git repositories.</p>
<h3 id="heading-what-is-a-merge-in-git">What is a Merge in Git?</h3>
<p>Merging is the process of combining the recent changes from several branches into a single new commit. This commit points back to these branches.</p>
<p>In a way, merging is the complement of branching in version control: a branch allows you to work simultaneously with others on a particular set of files, whereas a merge allows you to later combine separate work on branches that diverged from a common ancestor commit.</p>
<p>OK, let's take this bit by bit.</p>
<p>Remember that in Git, a branch is just a name pointing to a single commit. When we think about commits as being "on" a specific branch, they are actually reachable through the parent chain from the commit that the branch is pointing to.</p>
<p>That is, if you consider this commit graph:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_graph_1.png" alt="Commit graph with " width="600" height="400" loading="lazy">
_Commit graph with <code>feature_1</code>_</p>
<p>You see the branch <code>feature_1</code>, which points to a commit with the SHA-1 value of <code>ba0d2</code>. As in previous chapters, I only write the first 5 digits of the SHA-1 value for brevity.</p>
<p>Notice that commit <code>54a9d</code> is also "on" this branch, as it is the parent commit of <code>ba0d2</code>. So if you start from the pointer of <code>feature_1</code>, you get to <code>ba0d2</code>, which then points to <code>54a9d</code>. You can go on the chain of parents, and all these reachable commits are considered to be "on" <code>feature_1</code>.</p>
<p>When you merge with Git, you merge commits. Almost always, we merge two commits by referring to them with the branch names that point to them. Thus we say we "merge branches" - though under the hood, we actually merge commits.</p>
<h3 id="heading-time-to-get-hands-on-1">Time to Get Hands-on</h3>
<p>For this chapter, I will use the following repository:</p>
<p><a target="_blank" href="https://github.com/Omerr/gitting_things_merge.git">https://github.com/Omerr/gitting_things_merge.git</a></p>
<p>As in previous chapters, I encourage you to clone it locally and have the same starting point I am using for this chapter.</p>
<p>OK, so let's say I have this simple repository here, with a branch called <code>main</code>, and a few commits with the commit messages of "Commit 1", "Commit 2", and "Commit 3":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commits_1_3.png" alt="A simple repository with three commits" width="600" height="400" loading="lazy">
<em>A simple repository with three commits</em></p>
<p>Next, create a feature branch by typing <code>git branch new_feature</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_branch_new_feature.png" alt="Creating a new branch with " width="600" height="400" loading="lazy">
<em>Creating a new branch with <code>git branch</code></em></p>
<p>And switch <code>HEAD</code> to point to this new branch, by using <code>git checkout new_feature</code> (or <code>git switch new_feature</code>). You can look at the outcome by using git log:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_checkout_new_feature.png" alt="The output of  after using " width="600" height="400" loading="lazy">
_The output of <code>git log</code> after using <code>git checkout new_feature</code>_</p>
<p>As a reminder, you could also write <code>git checkout -b new_feature</code>, which would both create a new branch and change <code>HEAD</code> to point to this new branch.</p>
<p>If you need a reminder about branches and how they're implemented under the hood, please check out <a class="post-section-overview" href="#heading-chapter-2-branches-in-git">chapter 2</a>. Yes, check out. Pun intended 😇</p>
<p>Now, on the <code>new_feature</code> branch, implement a new feature. In this example, I will edit an existing file that looks like this before the edit:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_before_changes.png" alt=" before editing it" width="600" height="400" loading="lazy">
<em><code>code.py</code> before editing it</em></p>
<p>And I will now edit it to include a new function:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_new_feature.png" alt="Implementing " width="600" height="400" loading="lazy">
_Implementing <code>new_feature</code>_</p>
<p>And luckily, this is not a programming book, so this function is legit 😇</p>
<p>Next, stage and commit this change:</p>
<pre><code class="lang-bash">git add code.py

git commit -m <span class="hljs-string">"Commit 4"</span>
</code></pre>
<p>Looking at the history, you have the <code>branch new_feature</code>, now pointing to "Commit 4", which points to its parent, "Commit 3". The branch main is also pointing to "Commit 3".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commits_1_4.png" alt="The history after committing &quot;Commit 4&quot;" width="600" height="400" loading="lazy">
<em>The history after committing "Commit 4"</em></p>
<p>Time to merge the new feature! That is, merge these two branches, <code>main</code> and <code>new_feature</code>. Or, in Git's lingo, merge <code>new_feature</code> <em>into</em> <code>main</code>. This means merging "Commit 4" and "Commit 3". This is pretty trivial, as after all, "Commit 3" is an ancestor of "Commit 4".</p>
<p>Check out the main branch (with <code>git checkout main</code>), and perform the merge by using <code>git merge new_feature</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_merge_new_feature.png" alt="Merging  into " width="600" height="400" loading="lazy">
_Merging <code>new_feature</code> into <code>main</code>_</p>
<p>Since <code>new_feature</code> never really diverged from main, Git could just perform a fast-forward merge. So what happened here? Consider the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_ff_merge.png" alt="The result of a fast-forward merge" width="600" height="400" loading="lazy">
<em>The result of a fast-forward merge</em></p>
<p>Even though you used <code>git merge</code>, there was no actual merging here. Actually, Git did something very simple - it <code>reset</code> the main branch to point to the same commit as the branch <code>new_feature</code>.</p>
<p>In case you don't want that to happen, but rather you want Git to really perform a merge, you could either change Git's configuration, or run the merge command with the <code>--no-ff</code> flag.</p>
<p>First, undo the last commit:</p>
<pre><code class="lang-bash">git reset --hard HEAD~1
</code></pre>
<p>Reminder: if this way of using reset is not clear to you, don't worry - we will cover it in detail in Part 3. It is not crucial for this introduction of merge, though. For now, it's important to understand that it basically undoes the merge operation.</p>
<p>Just to clarify, now if you checked out <code>new_feature</code> again:</p>
<pre><code class="lang-bash">git checkout new_feature
</code></pre>
<p>The history would look just like before the merge:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_reset_after_merge.png" alt="The history after using " width="600" height="400" loading="lazy">
<em>The history after using <code>git reset --hard HEAD~1</code></em></p>
<p>Next, perform the merge with the <code>--no-fast-forward</code> flag (<code>--no-ff</code> for short):</p>
<pre><code class="lang-bash">git checkout main
git merge new_feature --no-ff
</code></pre>
<p>Now, if we look at the history using <code>git lol</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_lol_1.png" alt="History after merging with the  flag" width="600" height="400" loading="lazy">
<em>History after merging with the <code>--no-ff</code> flag</em></p>
<p>(Reminder: <code>git lol</code> is an alias I added to Git to visibly see the history in a graphical manner. You can find it, along with the other components of my setup, at the <a class="post-section-overview" href="#heading-my-setup">My Setup</a> part of the <a class="post-section-overview" href="#heading-introduction">Introduction</a> chapter.)</p>
<p>Considering this history, you can see Git created a new commit, a merge commit.</p>
<p>If you consider this commit a bit closer:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> -n1
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_after_lol_1.png" alt="The merge commit has two parents" width="600" height="400" loading="lazy">
<em>The merge commit has two parents</em></p>
<p>You will see that this commit actually has two parents - "Commit 4", which was the commit that <code>new_feature</code> pointed to when you ran <code>git merge</code>, and "Commit 3", which was the commit that <code>main</code> pointed to.</p>
<p><strong>A merge commit has two parents: the two commits it merged.</strong></p>
<p>The merge commit shows us the concept of merge quite well. Git takes two commits, usually referenced by two different branches, and merges them together.</p>
<p>After the merge, as you started the process from <code>main</code>, you are still on <code>main</code>, and the history from <code>new_feature</code> has been <em>merged</em> into this branch. Since you started with <code>main</code>, then "Commit 3", which <code>main</code> pointed to, is the first parent of the merge commit, whereas "Commit 4", which you merged into <code>main</code>, is the second parent of the merge commit.</p>
<p>Notice that you started on <code>main</code> when it pointed to "Commit 3", and Git went quite a long way for you. It changed the working tree, the index, and also <code>HEAD</code> and created a new commit object. At least when you use <code>git merge</code> without the <code>--no-commit</code> flag and when it's not a fast-forward merge, Git does all of that.</p>
<p>This was a super simple case, where the branches you merged didn't diverge at all. We will soon consider more interesting cases.</p>
<p>By the way, you can use <code>git merge</code> to merge more than two commits - actually, any number of commits. This is rarely done, and to adhere to the practicality principle of this book, I won't delve into it.</p>
<p>Another way to think of <code>git merge</code> is by joining two or more development histories together. That is, when you merge, you incorporate changes from the named commits, since the time their histories diverged <em>from</em> the current branch, <em>into</em> the current branch. I used the term "branch" here, but I am stressing this again - <strong>we are actually merging commits</strong>.</p>
<h3 id="heading-time-for-a-more-advanced-case">Time For a More Advanced Case</h3>
<p>Time to consider a more advanced case, which is probably the most common case where we use <code>git merge</code> explicitly - where you need to merge branches that did diverge from one another.</p>
<p>Assume we have two people working on this repo now, John and Paul.</p>
<p>John created a branch:</p>
<pre><code class="lang-bash">git checkout -b john_branch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_john_branch.png" alt="A new branch, " width="600" height="400" loading="lazy">
_A new branch, <code>john_branch</code>_</p>
<p>And John has written a new song in a new file, <code>lucy_in_the_sky_with_diamonds.md</code>. Well, I believe John Lennon didn't really write in Markdown format, or use Git for that matter, but let's pretend he did for this explanation.</p>
<pre><code class="lang-bash">git add lucy_in_the_sky_with_diamonds.md
git commit -m <span class="hljs-string">"Commit 5"</span>
</code></pre>
<p>While John was working on this song, Paul was also writing, on another branch. Paul had started from main:</p>
<pre><code class="lang-bash">git checkout main
</code></pre>
<p>And created his own branch:</p>
<pre><code class="lang-bash">git checkout -b paul_branch
</code></pre>
<p>And Paul wrote his song into a file called <code>penny_lane.md</code>. Paul staged and committed this file:</p>
<pre><code class="lang-bash">git add penny_lane.md
git commit -m <span class="hljs-string">"Commit 6"</span>
</code></pre>
<p>So now our history looks like this - where we have two different branches, branching out from <code>main</code>, with different histories:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_6.png" alt="The history after John and Paul committed" width="600" height="400" loading="lazy">
<em>The history after John and Paul committed</em></p>
<p>John is happy with his branch (that is, his song), so he decides to merge it into the <code>main</code> branch:</p>
<pre><code class="lang-bash">git checkout main
git merge john_branch
</code></pre>
<p>Actually, this is a fast-forward merge, as we have learned before. You can validate that by looking at the history (using <code>git lol</code>, for example):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/merge_after_commit_6.png" alt="Merging  into  results in a fast-forward merge" width="600" height="400" loading="lazy">
_Merging <code>john_branch</code> into <code>main</code> results in a fast-forward merge_</p>
<p>At this point, Paul also wants to merge his branch into <code>main</code>, but now a fast-forward merge is no longer relevant - there are two different histories here: the history of <code>main</code>'s and that of <code>paul_branch</code>'s. It's not that <code>paul_branch</code> only adds commits on top of main branch or vice versa.</p>
<p>Now things get interesting. 😎😎</p>
<p>First, let Git do the hard work for you. After that, we will understand what's actually happening under the hood.</p>
<pre><code class="lang-bash">git merge paul_branch
</code></pre>
<p>Consider the history now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/merge_after_commit_6_paul_branch.png" alt="When you merge , you get a new merge commit\label{fig-history-after-git-merge}" width="600" height="400" loading="lazy">
_When you merge <code>paul_branch</code>, you get a new merge commit_</p>
<p>What you have is a new commit, with two parents - "Commit 5" and "Commit 6".</p>
<p>In the working dir, you can see that both John's song as well as Paul's song are there (if you use <code>ls</code>, you will see both files in the working dir).</p>
<p>Nice, Git really did merge the changes for you. But how does that happen?</p>
<p>Undo this last commit:</p>
<pre><code class="lang-bash">git reset --hard HEAD~
</code></pre>
<h3 id="heading-how-to-perform-a-three-way-merge-in-git">How to Perform a Three-way Merge in Git</h3>
<p>It's time to understand what's really happening under the hood. 😎</p>
<p>What Git has done here is it called a <strong>3-way merge</strong>. In outlining the process of a 3-way merge, I will use the term "branch" for simplicity, but you should remember you could also merge two (or more) commits that are not referenced by a branch.</p>
<p>The 3-way merge process includes these stages:</p>
<p>First, Git locates the common ancestor of the two branches. That is, the common commit from which the merging branches most recently diverged. Technically, this is actually the first commit that is reachable from both branches. This commit is then called the merge base.</p>
<p>Second, Git calculates two diffs - one diff from the merge base to the first branch, and another diff from the merge base to the second branch. Git generates patches based on those diffs.</p>
<p>Third, Git applies both patches to the merge base using a 3-way merge algorithm. The result is the state of the new merge commit.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge.png" alt="The three steps of the 3-way merge algorithm: (1) locate the common ancestor; (2) calculate diffs from the merge base to the first branch, and from the merge base to the second branch; (3) apply both patches together" width="600" height="400" loading="lazy">
<em>The three steps of the 3-way merge algorithm: (1) locate the common ancestor (2) calculate diffs from the merge base to the first branch, and from the merge base to the second branch (3) apply both patches together</em></p>
<p>So, back to our example.</p>
<p>In the first step, Git looks from both branches - <code>main</code> and <code>paul_branch</code> - and traverses the history to find the first commit that is reachable from both. In this case, this would be… which commit?</p>
<p>Correct, the merge commit (the one with "Commit 3" and "Commit 4" as its parents).</p>
<p>If you are not sure, you can always ask Git directly:</p>
<pre><code class="lang-bash">git merge-base main paul_branch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_base.png" alt="The merge base is the merge commit with &quot;Commit 3&quot; and &quot;Commit 4&quot; as its parents. Note: the previous commit merge is blurred as it is not reachable via the current history following the  command" width="600" height="400" loading="lazy">
<em>The merge base is the merge commit with "Commit 3" and "Commit 4" as its parents. Note: the previous commit merge is blurred as it is not reachable via the current history following the <code>reset</code> command</em></p>
<p>By the way, this is the most common and simple case, where we have a single obvious choice for the merge base. In more complicated cases, there may be multiple possibilities for a merge base, but this is not within our focus.</p>
<p>In the second step, Git calculates the diffs. So it first calculates the diff between the merge commit and "Commit 5":</p>
<pre><code class="lang-bash">git diff 4f90a62 4683aef
</code></pre>
<p>(The SHA-1 values will be different on your machine.)</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_4_5.png" alt="The diff between the merge commit and &quot;Commit 5&quot;\label{fig-john-patch}" width="600" height="400" loading="lazy">
<em>The diff between the merge commit and "Commit 5"</em></p>
<p>If you don't feel comfortable with the output of <code>git diff</code>, you can read the previous chapter where I described it in detail.</p>
<p>You can store that diff to a file:</p>
<pre><code class="lang-bash">git diff 4f90a62 4683aef &gt; john_branch_diff.patch
</code></pre>
<p>Next, Git calculates the diff between the merge commit and "Commit 6":</p>
<pre><code class="lang-bash">git diff 4f90a62 c5e4951
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_4_6.png" alt="The diff between the merge commit and &quot;Commit 6&quot;" width="600" height="400" loading="lazy">
<em>The diff between the merge commit and "Commit 6"</em></p>
<p>Write this one to a file as well:</p>
<pre><code class="lang-bash">git diff 4f90a62 c5e4951 &gt; paul_branch_diff.patch
</code></pre>
<p>Now Git applies those patches on the merge base.</p>
<p>First, try that out directly - just apply the patches (I will walk you through it in a moment). This is not what Git really does under the hood, but it will help you gain a better understanding of why Git needs to do something different.</p>
<p>Checkout the merge base first, that is, the merge commit:</p>
<pre><code class="lang-bash">git checkout 4f90a62
</code></pre>
<p>And apply John's patch first (as a reminder, this is the patch shown in the image with the caption "The diff between the merge commit and "Commit 5""):</p>
<pre><code class="lang-bash">git apply --index john_branch_diff.patch
</code></pre>
<p>Notice that for now there is no merge commit. <code>git apply</code> updates the working dir as well as the index, as we used the <code>--index</code> switch.</p>
<p>You can observe the status using <code>git status</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_apply_john.png" alt="Applying John's patch on the merge commit" width="600" height="400" loading="lazy">
<em>Applying John's patch on the merge commit</em></p>
<p>So now John's new song is incorporated into the index. Apply the other patch:</p>
<pre><code class="lang-bash">git apply --index paul_branch_diff.patch
</code></pre>
<p>As a result, the index contains changes from both branches.</p>
<p>Now it's time to commit your merge. Since the porcelain command <code>git commit</code> always generates a commit with a single parent, you would need the underlying plumbing command - <code>git commit-tree</code>.</p>
<p>If you need a reminder about porcelain vs plumbing commands, check out <a class="post-section-overview" href="#heading-chapter-4-how-to-create-a-repo-from-scratch">chapter 4</a> where I explained these terms, and created an entire repo from scratch.</p>
<p>Remember that every Git commit object points to a single tree. So you need to record the contents of the index in a tree:</p>
<pre><code class="lang-bash">git write-tree
</code></pre>
<p>Now you get the SHA-1 value of the created tree, and you can create a commit object using <code>git commit-tree</code>:</p>
<pre><code class="lang-bash">git commit-tree &lt;TREE_SHA&gt; -p &lt;COMMIT_5&gt; -p &lt;COMMIT_6&gt; -m <span class="hljs-string">"Merge commit!"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_merge_commit.png" alt="Creating a merge commit" width="600" height="400" loading="lazy">
<em>Creating a merge commit</em></p>
<p>Great, so you have created a commit object!</p>
<p>Recall that <code>git merge</code> also changes <code>HEAD</code> to point to the new merge commit object. So you can simply do the same:</p>
<pre><code class="lang-bash">git reset --hard db315a
</code></pre>
<p>If you look at the history now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_reset_to_merge_commit_git_lol.png" alt="The history after creating a merge commit and resetting " width="600" height="400" loading="lazy">
<em>The history after creating a merge commit and resetting <code>HEAD</code></em></p>
<p>(Note: in this state, <code>HEAD</code> is "detached" - that is, it directly points to a commit object rather than a named reference. <code>gg</code> does not show <code>HEAD</code> when it is "detached", so don't be confused if you can't see <code>HEAD</code> in the output of <code>gg</code>.)</p>
<p>This is almost what we wanted. Remember that when you ran <code>git merge</code>, the result was <code>HEAD</code> pointing to <code>main</code> which pointed to the newly created commit (as shown in the image with the caption "When you merge <code>paul_branch</code>, you get a new merge commit". What should you do then?</p>
<p>Well, what you want is to modify <code>main</code>, so you can just point it to the new commit:</p>
<pre><code class="lang-bash">git checkout main
git reset --hard db315a
</code></pre>
<p>And now you have the same result as when you ran <code>git merge</code>: <code>main</code> points to the new commit, which has "Commit 5" and "Commit 6" as its parents. You can use <code>git lol</code> to verify that.</p>
<p>So this is exactly the same result as the merge done by Git, with the exception of the timestamp and thus the SHA-1 value, of course.</p>
<p>Overall, you got to merge both the contents of the two commits - that is, the state of the files, and also the history of those commits - by creating a merge commit that points to both histories.</p>
<p>In this simple case, you could actually just apply the patches using <code>git apply</code>, and everything works quite well.</p>
<h3 id="heading-quick-recap-of-a-three-way-merge">Quick Recap of a Three-way Merge</h3>
<p>So to quickly recap, on a three-way merge, Git:</p>
<ul>
<li>First, locates the merge base - the common ancestor of the two branches. That is, the first commit that is reachable from both branches.</li>
<li>Second, Git calculates two diffs - one diff from the merge base to the first branch, and another diff from the merge base to the second branch.</li>
<li>Third, Git applies both patches to the merge base, using a 3-way merge algorithm. I haven't explained the 3-way merge yet, but I will elaborate on that later. The result is the state of the new merge commit.</li>
</ul>
<p>You can also understand why it's called a "3-way merge": Git merges three different states - that of the first branch, that of the second branch, and their common ancestor. In our previous example, <code>main</code>, <code>paul_branch</code>, and the merge commit (with "Commit 3" and "Commit 4" as parents), respectively.</p>
<p>This is unlike, say, the fast-forward examples we saw before. The fast-forward examples are actually a case of a two-way merge, as Git only compares two states - for example, where <code>main</code> pointed to, and where <code>john_branch</code> pointed to.</p>
<h3 id="heading-moving-on">Moving on</h3>
<p>Still, this was a simple case of a 3-way merge. John and Paul created different songs, so each of them touched a different file. It was pretty straightforward to execute the merge.</p>
<p>What about more interesting cases?</p>
<p>Let's assume that now John and Paul are co-authoring a new song.</p>
<p>So, John checked out <code>main</code> branch and started writing the song:</p>
<pre><code class="lang-bash">git checkout main
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/a_day_in_the_life_md.png" alt="John's new song" width="600" height="400" loading="lazy">
<em>John's new song</em></p>
<p>He staged and committed it ("Commit 7"):</p>
<pre><code class="lang-bash">git add a_day_in_the_life.md
git commit -m <span class="hljs-string">"Commit 7"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_7.png" alt="John's new song is committed" width="600" height="400" loading="lazy">
<em>John's new song is committed</em></p>
<p>Now, Paul branches:</p>
<pre><code class="lang-bash">git checkout -b paul_branch_2
</code></pre>
<p>And edits the song, adding another verse:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/a_day_in_the_life_paul_verse.png" alt="Paul added a new verse" width="600" height="400" loading="lazy">
<em>Paul added a new verse</em></p>
<p>Of course, the original song does not include the title "Paul's Verse", but I added it here for clarity.</p>
<p>Paul stages and commits the changes:</p>
<pre><code class="lang-bash">git add a_day_in_the_life.md
git commit -m <span class="hljs-string">"Commit 8"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_8.png" alt="The history after introducing &quot;Commit 8&quot;" width="600" height="400" loading="lazy">
<em>The history after introducing "Commit 8"</em></p>
<p>John also branches out from main and adds an additional two lines at the end:</p>
<pre><code class="lang-bash">git checkout main
git checkout -b john_branch_2
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/a_day_in_the_life_john_addition.png" alt="John added the two last lines" width="600" height="400" loading="lazy">
<em>John added the two last lines</em></p>
<p>John stages and commits his changes too ("Commit 9"):</p>
<pre><code class="lang-bash">git add a_day_in_the_life.md
git commit -m <span class="hljs-string">"Commit 9"</span>
</code></pre>
<p>This is the resulting history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_9.png" alt="The history after John's last commit" width="600" height="400" loading="lazy">
<em>The history after John's last commit</em></p>
<p>So, both Paul and John modified the same file on different branches. Will Git be successful in merging them?</p>
<p>Say now we don't go through <code>main</code>, but John will try to merge Paul's new branch into his branch:</p>
<pre><code class="lang-bash">git merge paul_branch_2
</code></pre>
<p>Wait! Don't run this command! Why would you let Git do all the hard work? You are trying to understand the process here.</p>
<p>So, first, Git needs to find the merge base. Can you see which commit that would be?</p>
<p>Correct, it would be the last commit on the <code>main</code> branch, where the two diverged - that is, "Commit 7".</p>
<p>You can verify that by using:</p>
<pre><code class="lang-bash">git merge-base john_branch_2 paul_branch_2
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/merge_base_2.png" alt="&quot;Commit 7&quot; is the merge base" width="600" height="400" loading="lazy">
<em>"Commit 7" is the merge base</em></p>
<p>Checkout the merge base so you can later apply the patches you will create:</p>
<pre><code class="lang-bash">git checkout main
</code></pre>
<p>Great, now Git should compute the diffs and generate the patches. You can observe the diffs directly:</p>
<pre><code class="lang-bash">git diff main paul_branch_2
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_main_paul_branch_2.png" alt="The output of " width="600" height="400" loading="lazy">
_The output of <code>git diff main paul_branch_2</code>_</p>
<p>Will applying this patch succeed? Well, no problem, Git has all the context lines in place.</p>
<p>Switch to the merge-base (which is "Commit 7", also referenced by <code>main</code>), and ask Git to apply this patch:</p>
<pre><code class="lang-bash">git checkout main
git diff main paul_branch_2 &gt; paul_branch_2.patch
git apply --index paul_branch_2.patch
</code></pre>
<p>And this worked, no problem at all.</p>
<p>Now, compute the diff between John's new branch and the merge base. Notice that you haven't committed the applied changes, so <code>john_branch_2</code> still points at the same commit as before, "Commit 9":</p>
<pre><code class="lang-bash">git diff main john_branch_2
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_main_john_branch_2.png" alt="The output of " width="600" height="400" loading="lazy">
_The output of <code>git diff main john_branch_2</code>_</p>
<p>Will applying this diff work?</p>
<p>Well, indeed, yes. Notice that even though the line numbers have changed on the current version of the file, thanks to the context lines Git is able to locate where it needs to add these lines…</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_main_john_branch_2_context.png" alt="Git can rely on the context lines" width="600" height="400" loading="lazy">
<em>Git can rely on the context lines</em></p>
<p>Save this patch and apply it then:</p>
<pre><code class="lang-bash">git diff main john_branch_2 &gt; john_branch_2.patch
git apply --index john_branch_2.patch
</code></pre>
<p>Observe the result file:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/a_day_in_the_life_after_merge.png" alt="The result after applying Paul's patch" width="600" height="400" loading="lazy">
<em>The result after applying Paul's patch</em></p>
<p>Cool, exactly what we wanted.</p>
<p>You can now create the tree and relevant commit:</p>
<pre><code class="lang-bash">git write-tree
</code></pre>
<p>Don't forget to specify both parents:</p>
<pre><code class="lang-bash">git commit-tree &lt;TREE-ID&gt; -p paul_branch_2 -p john_branch_2 -m <span class="hljs-string">"Merging new changes"</span>
</code></pre>
<p>See how I used the branch names here? After all, they are just pointers to the commits we want.</p>
<p>Cool, look at the log from the new commit:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_lol_merging_new_changes.png" alt=" after creating the merge commit" width="600" height="400" loading="lazy">
_<code>git lol &amp;lt;SHA_OF_THE_MERGE_COMMIT&amp;gt;</code> after creating the merge commit_</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_merging_new_changes_commit.png" alt="The history after creating the merge commit" width="600" height="400" loading="lazy">
<em>The history after creating the merge commit</em></p>
<p>Exactly what we wanted.</p>
<p>You can also let Git perform the job for you. You can checkout <code>john_branch_2</code>, which you haven't moved - so it still points to the same commit as it did before the merge. So all you need to do is run:</p>
<pre><code class="lang-bash">git checkout john_branch_2
git merge paul_branch_2
</code></pre>
<p>Observe the resulting history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/merge_branches_2.png" alt=" after letting Git perform the merge" width="600" height="400" loading="lazy">
<em><code>git lol</code> after letting Git perform the merge</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_merging_with_git.png" alt="A visualization of the history after letting Git perform the merge" width="600" height="400" loading="lazy">
<em>A visualization of the history after letting Git perform the merge</em></p>
<p>Just as before, you have a merge commit pointing to "Commit 8" and "Commit 9" as its parents. "Commit 9" is the first parent since you merged into it.</p>
<p>But this was still quite simple… John and Paul worked on the same file, but on very different parts. You could also directly apply Paul's changes to John's branch. If you go back to John's branch before the merge:</p>
<pre><code class="lang-bash">git reset --hard HEAD~
</code></pre>
<p>And now apply Paul's changes:</p>
<pre><code class="lang-bash">git apply --index paul_branch_2.patch
</code></pre>
<p>You will get the same result.</p>
<p>But what happens when the two branches include changes on the same files, in the same locations?</p>
<h3 id="heading-more-advanced-git-merge-cases">More Advanced Git Merge Cases</h3>
<p>What would happen if John and Paul were to coordinate a new song, and work on it together?</p>
<p>In this case, John creates the first version of this song in the main branch:</p>
<pre><code class="lang-bash">git checkout main
nano everyone.md
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_1.png" alt="The contents of  prior to the first commit" width="600" height="400" loading="lazy">
<em>The contents of <code>everyone.md</code> prior to the first commit</em></p>
<p>By the way, this text is indeed taken from the version that John Lennon recorded for a demo in 1968. But this isn't a book about the Beatles. If you're curious about the process the Beatles underwent while writing this song, you can follow the links in the end of this chapter.</p>
<pre><code class="lang-bash">git add everyone.md
git commit -m <span class="hljs-string">"Commit 10"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_commit_10.png" alt="Introducing &quot;Commit 10&quot;" width="600" height="400" loading="lazy">
<em>Introducing "Commit 10"</em></p>
<p>Now John and Paul split. Paul creates a new verse in the beginning:</p>
<pre><code class="lang-bash">git checkout -b paul_branch_3
nano everyone.md
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_2.png" alt="Paul added a new verse in the beginning" width="600" height="400" loading="lazy">
<em>Paul added a new verse in the beginning</em></p>
<p>Also, while talking to John, they decided to change the word "feet" to "foot", so Paul adds this change as well.</p>
<p>And Paul adds and commits his changes to the repo:</p>
<pre><code class="lang-bash">git add everyone.md
git commit -m <span class="hljs-string">"Commit 11"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_11.png" alt="The history after introducing &quot;Commit 11&quot;" width="600" height="400" loading="lazy">
<em>The history after introducing "Commit 11"</em></p>
<p>You can observe Paul's changes, by comparing this branch's state to the state of branch <code>main</code>:</p>
<pre><code class="lang-bash">git diff main
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main.png" alt="The output of  from Paul's branch" width="600" height="400" loading="lazy">
<em>The output of <code>git diff main</code> from Paul's branch</em></p>
<p>Store this diff in a patch file:</p>
<pre><code class="lang-bash">git diff main &gt; paul_3.patch
</code></pre>
<p>Now back to <code>main</code>…</p>
<pre><code class="lang-bash">git checkout main
</code></pre>
<p>John decides to make another change, in his own new branch:</p>
<pre><code class="lang-bash">git checkout -b john_branch_3
</code></pre>
<p>And he replaces the line "Everyone had the boot in" with the line "Everyone had a wet dream". In addition, John changed the word "feet" to "foot", following his talk with Paul.</p>
<p>Observe the diff:</p>
<pre><code class="lang-bash">git diff main
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_2.png" alt="The output of  from John's branch" width="600" height="400" loading="lazy">
<em>The output of <code>git diff main</code> from John's branch</em></p>
<p>Store this output as well:</p>
<pre><code class="lang-bash">git diff main &gt; john_3.patch
</code></pre>
<p>Now, stage and commit:</p>
<pre><code class="lang-bash">git add everyone.md
git commit -m <span class="hljs-string">"Commit 12"</span>
</code></pre>
<p>This should be your current history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_12.png" alt="The history after introducing &quot;Commit 12&quot;" width="600" height="400" loading="lazy">
<em>The history after introducing "Commit 12"</em></p>
<p>Note that I deleted <code>john_branch_2</code> and <code>paul_branch_2</code> for simplicity. Of course, you can erase them from Git by using <code>git branch -D &lt;branch_name&gt;</code>. As a result, these branch names will not appear in the output of <code>git log</code> or other similar commands.</p>
<p>This also applies to commits that are no longer reachable from any named reference, such as "Commit 8" or "Commit 9". Since they are not reachable from any named reference via the parents' chain, they will not be included in the output of commands such as <code>git log</code>.</p>
<p>Back to our story - Paul told John he had added a new verse, so John would like to merge Paul's changes.</p>
<p>Can John simply apply Paul's patch?</p>
<p>Consider the patch again:</p>
<pre><code class="lang-bash">git diff main paul_branch_3
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main-1.png" alt="The output of " width="600" height="400" loading="lazy">
_The output of <code>git diff main paul_branch_3</code>_</p>
<p>As you can see, this diff relies on the line "Everyone had the boot in", but this line no longer exists on John's branch. As a result, you could expect applying the patch to fail. Go on, give it a try:</p>
<pre><code class="lang-bash">git apply paul_3.patch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_paul_3.png" alt="Applying the patch failed" width="600" height="400" loading="lazy">
<em>Applying the patch failed</em></p>
<p>Indeed, you can see that it failed.</p>
<p>But should it really fail?</p>
<p>As explained earlier, <code>git merge</code> uses a 3-way merge algorithm, and this can come in handy here. What would be the first step of this algorithm?</p>
<p>Well, first, Git would find the merge base - that is, the common ancestor of Paul's branch and John's branch. Consider the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_12-1.png" alt="The history after introducing &quot;Commit 12&quot;" width="600" height="400" loading="lazy">
<em>The history after introducing "Commit 12"</em></p>
<p>So the common ancestor of "Commit 11" and "Commit 12" is "Commit 10". You can verify this by running the command:</p>
<pre><code class="lang-bash">git merge-base john_branch_3 paul_branch_3
</code></pre>
<p>Now we can take the patches we generated from the diffs on both branches, and apply them to <code>main</code>. Would that work?</p>
<p>First, try to apply John's patch, and then Paul's patch.</p>
<p>Consider the diff:</p>
<pre><code class="lang-bash">git diff main john_branch_3
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_2-1.png" alt="The output of " width="600" height="400" loading="lazy">
_The output of <code>git diff main john_branch_3</code>_</p>
<p>We can store it in a file:</p>
<pre><code class="lang-bash">git diff main john_branch_3 &gt; john_3.patch
</code></pre>
<p>And apply this patch on main:</p>
<pre><code class="lang-bash">git checkout main
git apply john_3.patch
</code></pre>
<p>Let's consider the result:</p>
<pre><code class="lang-bash">nano everyone.md
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_3.png" alt="The contents of  after applying John's patch" width="600" height="400" loading="lazy">
<em>The contents of <code>everyone.md</code> after applying John's patch</em></p>
<p>The line changed as expected. Nice 😎</p>
<p>Now, can Git apply Paul's patch? To remind you, this is the patch:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main-2.png" alt="The contents of Paul's patch" width="600" height="400" loading="lazy">
<em>The contents of Paul's patch</em></p>
<p>Well, Git cannot apply this patch, because this patch assumes that the line "Everyone had the boot in" exists. Trying to apply it is liable to fail:</p>
<pre><code class="lang-bash">git apply -v paul_3.branch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_v_paul_3.png" alt="Applying Paul's patch failed" width="600" height="400" loading="lazy">
<em>Applying Paul's patch failed</em></p>
<p>What you tried to do now, applying Paul's patch on the <code>main</code> branch after applying John's patch, is the same as being on <code>john_branch_3</code>, and attempting to apply the patch. That is, running:</p>
<pre><code class="lang-bash">git apply paul_3.patch
</code></pre>
<p>What would happen if we tried the other way around?</p>
<p>First, clean up the state:</p>
<pre><code class="lang-bash">git reset --hard
</code></pre>
<p>And start from Paul's branch:</p>
<pre><code class="lang-bash">git checkout paul_branch_3
</code></pre>
<p>Can we apply John's patch? As a reminder, this is the status of <code>everyone.md</code> on this branch:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_2-1.png" alt="The contents of  on " width="600" height="400" loading="lazy">
_The contents of <code>everyone.md</code> on <code>paul_branch_3</code>_</p>
<p>And this is John's patch:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_2-2.png" alt="The contents of John's patch" width="600" height="400" loading="lazy">
<em>The contents of John's patch</em></p>
<p>Would applying John's patch work?</p>
<p>Try to answer yourself before reading on.</p>
<p>You can try:</p>
<pre><code class="lang-bash">git apply john_3.patch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_3_john_3.png" alt="Git fails to apply John's patch" width="600" height="400" loading="lazy">
<em>Git fails to apply John's patch</em></p>
<p>Well, no! Again, if you are not sure what happened, you can always ask <code>git apply</code> to be a bit more verbose:</p>
<pre><code class="lang-bash">git apply -v john_3.patch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_v_john_3.png" alt="You can get more information by using the  flag" width="600" height="400" loading="lazy">
<em>You can get more information by using the <code>-v</code> flag</em></p>
<p>Git is looking for "Everyone put the feet down", but Paul has already changed this line so it now consists of the word "foot" instead of "feet". As a result, applying this patch fails.</p>
<p>Notice that changing the number of context lines here (that is, using <code>git apply</code> with the <code>-C</code> flag, as discussed in the <a class="post-section-overview" href="#heading-chapter-6-diffs-and-patches">previous chapter</a>) is irrelevant - Git is unable to locate the actual line that the patch is trying to erase.</p>
<p>But actually, Git can make this work, if you just add a flag to apply, telling it to perform a 3-way merge under the hood:</p>
<pre><code class="lang-bash">git apply -3 john_3.patch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_3_john_3-1.png" alt="Applying with  flag succeeds" width="600" height="400" loading="lazy">
<em>Applying with <code>-3</code> flag succeeds</em></p>
<p>And consider the result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_4.png" alt="The contents of  after the merge" width="600" height="400" loading="lazy">
<em>The contents of <code>everyone.md</code> after the merge</em></p>
<p>Exactly what we wanted! You have Paul's verse, and both of John's changes!</p>
<p>So, how was Git able to accomplish that?</p>
<p>Well, as I mentioned, Git really did a <strong>3-way merge</strong>, and with this example, it will be a good time to dive into what this actually means.</p>
<h3 id="heading-how-gits-3-way-merge-algorithm-works">How Git's 3-way Merge Algorithm Works</h3>
<p>Get back to the state before applying this patch:</p>
<pre><code class="lang-bash">git reset --hard
</code></pre>
<p>You have now three versions: the merge base, which is "Commit 10", Paul's branch, and John's branch. In general terms, we can say these are the <code>merge base</code>, <code>commit A</code> and <code>commit B</code>. Notice that the <code>merge base</code> is by definition an ancestor of both <code>commit A</code> and <code>commit B</code>.</p>
<p>To perform the merge, Git looks at the diff between the three different versions of the file in question on these three revisions. In your case, it's the file everyone.md, and the revisions are "Commit 10", Paul's branch - that is, "Commit 11", and John's branch, that is, "Commit 12".</p>
<p>Git makes the merging decision based on the status of each line in each of these versions.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_versions.png" alt="The three versions considered for the 3-way merge" width="600" height="400" loading="lazy">
<em>The three versions considered for the 3-way merge</em></p>
<p>In case not all three versions match, that is a conflict. Git can resolve many of these conflicts automatically, as we will now see.</p>
<p>Let's consider specific lines.</p>
<p>The first lines here exist only on Paul's branch:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_versions_1.png" alt="Lines that appear on Paul's branch only" width="600" height="400" loading="lazy">
<em>Lines that appear on Paul's branch only</em></p>
<p>This means that the state of John's branch is equal to the state of the merge base. So the 3-way merge goes with Paul's version.</p>
<p>In general, if the state of the merge base is the same as <code>A</code>, the algorithm goes with <code>B</code>. The reason is that since the merge base is the ancestor of both <code>A</code> and <code>B</code>, Git assumes that this line hasn't changed in <code>A</code>, and it <em>has</em> changed in <code>B</code>, which is the most recent version for that line, and should thus be taken into account.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_1.png" alt="If the state of the merge base is the same as , and this state is different from , the algorithm goes with " width="600" height="400" loading="lazy">
<em>If the state of the merge base is the same as <code>A</code>, and this state is different from <code>B</code>, the algorithm goes with <code>B</code></em></p>
<p>Next, you can see lines where all three versions agree - they exist on the merge base, <code>A</code> and <code>B</code>, with equal data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_versions_2.png" alt="Lines where all three versions agree" width="600" height="400" loading="lazy">
<em>Lines where all three versions agree</em></p>
<p>In this case the algorithm has a trivial choice - just take that version.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_2.png" alt="In case all three versions agree, the algorithm goes with that single version" width="600" height="400" loading="lazy">
<em>In case all three versions agree, the algorithm goes with that single version</em></p>
<p>In a previous example, we saw that if the merge base and <code>A</code> agree, and <code>B</code>'s version is different, the algorithm picks <code>B</code>. This works in the other direction too - for example, here you have a line that exists on John's branch, different than that on the merge base and Paul's branch.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_versions_3.png" alt="A line where Paul's version matches the merge base's version, and John has a different version" width="600" height="400" loading="lazy">
<em>A line where Paul's version matches the merge base's version, and John has a different version</em></p>
<p>Hence, John's version is chosen.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_3.png" alt="If the state of the merge base is the same as , and this state is different from , the algorithm goes with " width="600" height="400" loading="lazy">
<em>If the state of the merge base is the same as <code>B</code>, and this state is different from <code>A</code>, the algorithm goes with <code>A</code></em></p>
<p>Now consider another case, where both <code>A</code> and <code>B</code> agree on a line, but the value they agree upon is different from the merge base: both John and Paul agreed to change the line "Everyone put their feet down" to "Everyone put their foot down":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_versions_4.png" alt="A line where Paul's version matches John's version; yet the merge base has a different version" width="600" height="400" loading="lazy">
<em>A line where Paul's version matches John's version, yet the merge base has a different version</em></p>
<p>In this case, the algorithm picks the version on both <code>A</code> and <code>B</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_4.png" alt="In case A and B agree on a version which is different from the merge base's version, the algorithm picks the version on both A and B" width="600" height="400" loading="lazy">
<em>In case <code>A</code> and <code>B</code> agree on a version which is different from the merge base's version, the algorithm picks the version on both <code>A</code> and <code>B</code></em></p>
<p>Notice this is not a democratic vote. In the previous case, the algorithm picked the minority version, as it resembled the newest version of this line. In this case, it happens to pick the majority - but only because <code>A</code> and <code>B</code> are the revisions that agree on the new version.</p>
<p>The same would happen if we used <code>git merge</code>:</p>
<pre><code class="lang-bash">git merge john_branch_3
</code></pre>
<p>Without specifying any flags, <code>git merge</code> will default to using a <code>3-way merge</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_merge_default.png" alt="By default,  uses a 3-way merge algorithm" width="600" height="400" loading="lazy">
<em>By default, <code>git merge</code> uses a 3-way merge algorithm</em></p>
<p>The status of <code>everyone.md</code> after running <code>git merge john_branch</code> would be the same as the result you achieved by applying the patches with <code>git apply -3</code>.</p>
<p>If you consider the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_merge.png" alt="Git's history after performing the merge" width="600" height="400" loading="lazy">
<em>Git's history after performing the merge</em></p>
<p>You will see that the merge commit indeed has two parents: the first is "Commit 11", that is, where <code>paul_branch_3</code> pointed to before the merge. The second is "Commit 12", where <code>john_branch_3</code> pointed to, and still points to now.</p>
<p>What will happen if you now merge from <code>main</code>? That is, switch to the <code>main</code> branch, which is pointing to "Commit 10":</p>
<pre><code class="lang-bash">git checkout main
</code></pre>
<p>And then merge Paul's branch?</p>
<pre><code class="lang-bash">git merge paul_branch_3
</code></pre>
<p>Indeed, we get a fast-forward merge - as before running this command, <code>main</code> was an ancestor of <code>paul_branch_3</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/fast_forward_merge.png" alt="A fast-forward merge" width="600" height="400" loading="lazy">
<em>A fast-forward merge</em></p>
<p>So, this is a 3-way merge. In general, if all versions agree on a line, then this line is used. If <code>A</code> and the merge base match, and <code>B</code> has another version, <code>B</code> is taken. In the opposite case, where the merge base and <code>B</code> match, the <code>A</code> version is selected. If <code>A</code> and <code>B</code> match, this version is taken, whether the merge base agrees or not.</p>
<p>This description leaves one open question though: What happens in cases where all three versions disagree?</p>
<p>Well, that's a conflict that Git does not resolve automatically. In these cases, Git calls for a human's help.</p>
<h3 id="heading-how-to-resolve-merge-conflicts">How to Resolve Merge Conflicts</h3>
<p>By following so far, you should understand the basics of the command <code>git merge</code>, and how Git can automatically resolve some conflicts. You also understand what cases are automatically resolved.</p>
<p>Next, let's consider a more advanced case.</p>
<p>Say Paul and John keep working on this song.</p>
<p>Paul creates a new branch:</p>
<pre><code class="lang-bash">git checkout -b paul_branch_4
</code></pre>
<p>And he decides to add some "Yeah"s to the song, so he changes this verse as follows:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/paul_branch_4_additions.png" alt="Paul's additions" width="600" height="400" loading="lazy">
<em>Paul's additions</em></p>
<p>So Paul stages and commits these changes:</p>
<pre><code class="lang-bash">git add everyone.md
git commit -m <span class="hljs-string">"Commit 13"</span>
</code></pre>
<p>Paul also creates another song, <code>let_it_be.md</code> and adds it to the repo:</p>
<pre><code class="lang-bash">git add let_it_be.md
git commit -m <span class="hljs-string">"Commit 14"</span>
</code></pre>
<p>This is the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_14.png" alt="The history after Paul introduced &quot;Commit 14&quot;" width="600" height="400" loading="lazy">
<em>The history after Paul introduced "Commit 14"</em></p>
<p>Going back to <code>main</code>:</p>
<pre><code class="lang-bash">git checkout main
</code></pre>
<p>John also branches out:</p>
<pre><code class="lang-bash">git checkout -b john_branch_4
</code></pre>
<p>And John also works on the song "Everyone had a hard year", later to be called "I've got a feeling" (again, this is not a book about the Beatles, so I won't elaborate on it here. See the additional links if you are curious).</p>
<p>John decides to change all occurrences of "Everyone" to "Everybody":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_5.png" alt="John changes all occurrences of &quot;Everyone&quot; to &quot;Everybody&quot;" width="600" height="400" loading="lazy">
<em>John changes all occurrences of "Everyone" to "Everybody"</em></p>
<p>He stages and commits this song to the repo:</p>
<pre><code class="lang-bash">git add everyone.md
git commit -m <span class="hljs-string">"Commit 15"</span>
</code></pre>
<p>Nice. Now John also creates another song, <code>across_the_universe.md</code>. He adds it to the repo as well:</p>
<pre><code class="lang-bash">git add across_the_universe.md
git commit -m <span class="hljs-string">"Commit 16"</span>
</code></pre>
<p>Observe the history again:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_16.png" alt="The history after John introduced &quot;Commit 16&quot;" width="600" height="400" loading="lazy">
<em>The history after John introduced "Commit 16"</em></p>
<p>You can see that the history diverges from <code>main</code>, to two different branches - <code>paul_branch_4</code>, and <code>john_branch_4</code>.</p>
<p>At this point, John would like to merge the changes introduced by Paul.</p>
<p>What is going to happen here?</p>
<p>Remember the changes introduced by Paul:</p>
<pre><code class="lang-bash">git diff main paul_branch_4
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_paul_branch_4.png" alt="The output of " width="600" height="400" loading="lazy">
_The output of <code>git diff main paul_branch_4</code>_</p>
<p>What do you think? Will merge work?</p>
<p>Try it out:</p>
<pre><code class="lang-bash">git merge paul_branch_4
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/merge_conflict.png" alt="A merge conflict" width="600" height="400" loading="lazy">
<em>A merge conflict</em></p>
<p>We have a conflict!</p>
<p>Git cannot merge these branches on its own. You can get an overview of the merge state, using <code>git status</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_merge_failed.png" alt="The output of  right after the merge operation" width="600" height="400" loading="lazy">
<em>The output of <code>git status</code> right after the merge operation</em></p>
<p>The changes that Git had no problem resolving are staged for commit. And there is a separate section for "unmerged paths" - these are files with conflicts that Git could not resolve on its own.</p>
<p>It's time to understand why and when these conflicts happen, how to resolve them, and also how Git handles them under the hood.</p>
<p>Alright then! I hope you are at least as excited as I am. 😇</p>
<p>Let's recall what we know about 3-way merges:</p>
<p>First, Git will look for the merge base - the common ancestor of <code>john_branch_4</code> and <code>paul_branch_4</code>. Which commit would that be?</p>
<p>It would be the tip of the <code>main</code> branch, the commit in which we merged <code>john_branch_3</code> into <code>paul_branch_3</code>.</p>
<p>Again, if you are not sure, you can verify that by running:</p>
<pre><code class="lang-bash">git merge-base john_branch_4 paul_branch_4
</code></pre>
<p>And at the current state, <code>git status</code> knows which files are staged and which aren't.</p>
<p>Consider the process for each <em>file</em>, which is the same as the 3-way merge algorithm we considered per line, but on a file's level:</p>
<p><code>across_the_universe.md</code> exists on John's branch, but doesn't exist on the merge base or on Paul's branch. So Git chooses to include this file. Since you are already on John's branch and this file is included in the tip of this branch, it is not mentioned by <code>git status</code>.</p>
<p><code>let_it_be.md</code> exists on Paul's branch, but doesn't exist on the merge base or John's branch. So <code>git merge</code> "chooses" to include it.</p>
<p>What about <code>everyone.md</code>? Well, here we have three different states of this file: its state on the merge base, its state on John's branch, and its state on Paul's branch. While performing a merge, Git stores all of these versions on the index.</p>
<p>Let's observe that by looking directly at the index with the command <code>git ls-files</code>:</p>
<pre><code class="lang-bash">git ls-files -s --abbrev
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/ls_files_abbrev.png" alt="The output of  after the merge operation" width="600" height="400" loading="lazy">
<em>The output of <code>git ls-files -s --abbrev</code> after the merge operation</em></p>
<p>You can see that <code>everyone.md</code> has three different entries. Git assigns each version a number that represents the "stage" of the file, and this is a distinct property of an index entry, alongside the file's name and the mode bits.</p>
<p>When there is no merge conflict regarding a file, its "stage" is <code>0</code>. This is indeed the state for <code>across_the_universe.md</code>, and for <code>let_it_be.md</code>.</p>
<p>On a conflict's state, we have:</p>
<ul>
<li>Stage <code>1</code> - which is the merge base.</li>
<li>Stage <code>2</code> - which is "your" version. That is, the version of the file on the branch you are merging <em>into</em>. In our example, this would be <code>john_branch_4</code>.</li>
<li>Stage <code>3</code> - which is "their" version, also called the <code>MERGE_HEAD</code>. That is, the version on the branch you are merging (into the current branch). In our example, that is <code>paul_branch_4</code>.</li>
</ul>
<p>To observe the file's contents in a specific stage, you can use a command I introduced in a previous post, git cat-file, and provide the blob's SHA:</p>
<pre><code class="lang-bash">git cat-file -p &lt;BLOB_SHA_FOR_STAGE_2&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/cat_file.png" alt="Using -file to present the content of the file on John's branch, right from its state in the index" width="600" height="400" loading="lazy">
<em>Using <code>git cat-file</code> to present the content of the file on John's branch, right from its state in the index</em></p>
<p>And indeed, this is the content we expected - from John's branch, where the lines start with "Everybody" rather than "Everyone".</p>
<p>A nice trick that allows you to see the content quickly without providing the blob's SHA-1 value, is by using <code>git show</code>, like so:</p>
<pre><code class="lang-bash">git show :&lt;STAGE&gt;:everyone.md
</code></pre>
<p>For example, to get the content of the same version as with git cat-file -p , you can write <code>git show :2:everyone.md</code>.</p>
<p>Git records the three states of the three commits into the index in this way at the start of the merge. It then follows the three-way merge algorithm to quickly resolve the simple cases:</p>
<p>In case all three stages match, then the selection is trivial.</p>
<p>If one side made a change while the other did nothing - that is, stage <code>1</code> matches stage <code>2</code>- then we choose stage <code>3</code>, or vice versa. That's exactly what happened with <code>let_it_be.md</code> and <code>across_the_universe.md</code>.</p>
<p>In case of a deletion on the incoming branch, for example, and given there were no changes on the current branch, then we would see that stage <code>1</code> matches stage <code>2</code>, but there is no stage <code>3</code>. In this case, <code>git merge</code> removes the file for the merged version.</p>
<p>What's really cool here is that for matching, Git doesn't need the actual files. Rather, it can rely on the SHA-1 values of the corresponding blobs. This way, Git can easily detect the state a file is in.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_4-1.png" alt="Git performs the same 3-way merge algorithm on a files level" width="600" height="400" loading="lazy">
<em>Git performs the same 3-way merge algorithm on a files level</em></p>
<p>For <code>everyone.md</code> you have this special case - where stage <code>1</code>, stage <code>2</code> and stage <code>3</code> are all different from one another. That is, they have different blob SHAs. It's time to go deeper and understand the merge conflict. 😊</p>
<p>One way to do that would be to simply use <code>git diff</code>. In a <a class="post-section-overview" href="#heading-chapter-6-diffs-and-patches">previous chapter</a>, we examined git diff in detail, and saw that it shows the differences between various combinations of the working tree, index or commits.</p>
<p>But <code>git diff</code> also has a special mode for helping with merge conflicts:</p>
<pre><code class="lang-bash">git diff
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_conflict.png" alt="The output of  during a merge conflict" width="600" height="400" loading="lazy">
<em>The output of <code>git diff</code> during a merge conflict</em></p>
<p>This output may be confusing at first, but once you get used to it, it's pretty clear. Let's start by understanding it, and then see how you can resolve conflicts with other, more visual tools.</p>
<p>The conflicted section is separated by the "equal" marks (<code>====</code>), and marked with the corresponding branches. In this context, "ours" is the current branch. In this example, that would be <code>john_branch_4</code>, the branch that <code>HEAD</code> was pointing to when we initiated the <code>git merge</code> command. "Theirs" is the <code>MERGE_HEAD</code>, the branch that we are merging in - in this case, <code>paul_branch_4</code>.</p>
<p>So <code>git diff</code> without any special flags shows changes between the working tree and the index - which in this case are the conflicts yet to be resolved. The output doesn't include staged changes, which is very convenient for resolving the conflict.</p>
<p>Time to resolve this manually. Fun!</p>
<p>So, why is this a conflict?</p>
<p>For Git, Paul and John made different changes to the same line, for a few lines. John changed it to one thing, and Paul changed it to another thing. Git cannot decide which one is correct.</p>
<p>This is not the case for the last lines, like the line that used to be "Everyone had a hard year" on the merge base. Paul hasn't changed this line, or the lines surrounding it, so its version on paul_branch_4, or "theirs" in our case, agrees with the <code>merge_base</code>. Yet John's version, "ours", is different. Thus <code>git merge</code> can easily decide to take this version.</p>
<p>But what about the conflicted lines?</p>
<p>In this case, I know what I want, and that is actually a combination of these lines. I want the lines to start with "Everybody", following John's change, but also to include Paul's "yeah"s. So go ahead and create the desired version by editing everyone.md:</p>
<pre><code class="lang-bash">nano everyone.md
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_6.png" alt="Editing the file manually to achieve the desired state" width="600" height="400" loading="lazy">
<em>Editing the file manually to achieve the desired state</em></p>
<p>To compare the result file to what you had in the branch prior to the merge, you can run:</p>
<pre><code class="lang-bash">git diff --ours
</code></pre>
<p>Similarly, if you wish to see how the result of the merge differs from the branch you merged into our branch, you can run:</p>
<pre><code class="lang-bash">git diff --theirs
</code></pre>
<p>You can even see how the result is different from both sides using:</p>
<pre><code class="lang-bash">git diff --base
</code></pre>
<p>Now you can stage the fixed version:</p>
<pre><code class="lang-bash">git add everyone.md
</code></pre>
<p>After staging, if you look at <code>git status</code>, you will see no conflicts:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_manual_fix.png" alt="After staging the fixed version , there are no conflicts" width="600" height="400" loading="lazy">
<em>After staging the fixed version <code>everyone.md</code>, there are no conflicts</em></p>
<p>You can now simply use <code>git commit</code>, and Git will present you with a commit message containing details about the merge. You can modify it if you like, or leave it as is. Regardless of the commit message, Git will create a "merge commit" - that is, a commit with more than one parent.</p>
<p>To validate that, consider the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_merge_2.png" alt="The history after completing the merge operation" width="600" height="400" loading="lazy">
<em>The history after completing the merge operation</em></p>
<p><code>john_branch_4</code> now points to the new merge commit. The incoming branch, "theirs", in this case, <code>paul_branch_4</code>, stays where it was.</p>
<h3 id="heading-how-to-use-vs-code-to-resolve-conflicts">How to Use VS Code to Resolve Conflicts</h3>
<p>You will now see how to resolve the same conflict using a graphical tool. For this example, I use VS Code, which is a free and popular code editor. There are many other tools, but the process is similar, so I will just show VS Code as an example.</p>
<p>First, get back to the state before the merge:</p>
<pre><code class="lang-bash">git reset --hard HEAD~
</code></pre>
<p>And try to merge again:</p>
<pre><code class="lang-bash">git merge paul_branch_4
</code></pre>
<p>You should be back at the same status:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_merge_failed-1.png" alt="Back at the conflicting status" width="600" height="400" loading="lazy">
<em>Back at the conflicting status</em></p>
<p>Let's see how this appears on VS Code:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/vs_code_1.png" alt="Conflict resolution with VS Code" width="600" height="400" loading="lazy">
<em>Conflict resolution with VS Code</em></p>
<p>VS Code marks the different versions with "Current Change" - which is the "ours" version, the current <code>HEAD</code>, and "Incoming Change" for the branch we are merging into the active branch. You can accept one of the changes (or both) by clicking on one of the options.</p>
<p>If you clicked on <code>Resolve in Merge editor</code>, you'll get a more visual view of the state. VS Code shows the status of each line:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/vs_code_2-1.png" alt="VS Code's Merge Editor" width="600" height="400" loading="lazy">
<em>VS Code's Merge Editor</em></p>
<p>If you look closely, you will see that VS Code shows changes within words - for example, showing that "Every<strong>one</strong>" was changed to "Every<strong>body</strong>", marking the changed parts.</p>
<p>You can accept either version, or you can accept a combination. In this case, if you click on "Accept Combination", you get this result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/vs_code_3.png" alt="VS Code's Merge Editor after clicking on &quot;Accept Combination&quot;" width="600" height="400" loading="lazy">
<em>VS Code's Merge Editor after clicking on "Accept Combination"</em></p>
<p>VS Code did a really good job! The same three way merge algorithm was implemented here and used on the <em>word</em> level rather than the <em>line</em> level. So VS Code was able to actually resolve this conflict in a rather impressive way. Of course, you can modify VS Code's suggestion, but it provided a <em>very</em> good start.</p>
<h3 id="heading-one-more-powerful-tool">One More Powerful Tool</h3>
<p>Well, this was the first time in this book that I've used a tool with a graphical user interface. Indeed, graphical interfaces can be convenient to understand what's going on when you are resolving merge conflicts.</p>
<p>However, like in many other cases, when we need to really understand what's going on, the command line becomes handy. So, let's get back to the command line and learn a tool that can come in handy in more complicated cases.</p>
<p>Again, go back to the state before the merge:</p>
<pre><code class="lang-bash">git reset --hard HEAD~
</code></pre>
<p>And merge:</p>
<pre><code class="lang-bash">git merge paul_branch_4
</code></pre>
<p>And say, you are not exactly sure what happened. Why is there a conflict? One very useful command would be:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> -p --merge
</code></pre>
<p>As a reminder, <code>git log</code> shows the history of commits that are reachable from <code>HEAD</code>. Adding <code>-p</code> tells <code>git log</code> to show the commits along with the diffs they introduced. The <code>--merge</code> switch makes the command show all commits containing changes relevant to any unmerged files, on either branch, together with their diffs.</p>
<p>This can help you identify the changes in history that led to the conflicts. So in this example, you'd see:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_p_merge.png" alt="The output of " width="600" height="400" loading="lazy">
<em>The output of <code>git log -p --merge</code></em></p>
<p>The first commit we see is "Commit 15", as in this commit John modified everyone.md, a file that still has conflicts. Next, Git shows "Commit 13", where Paul changed <code>everyone.md</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_p_merge_2.png" alt="The output of  - continued" width="600" height="400" loading="lazy">
<em>The output of <code>git log -p --merge</code> - continued</em></p>
<p>Notice that <code>git log --merge</code> did not mention previous commits that changed <code>everyone.md</code> before "Commit 13", as they didn't affect the current conflict.</p>
<p>This way, <code>git log</code> tells you all you need to know to understand the process that got you into the current conflicting state. Cool! 😎</p>
<p>Using the command line, you can also ask Git to take only one side of the changes - either "ours" or "theirs", even for a specific file.</p>
<p>You can also instruct Git to take some parts of the diffs of one file and another from another file. I will provide links that describe how to do that in <a class="post-section-overview" href="#heading-diffs-and-patches">the additional resources of this chapter in the appendix</a>.</p>
<p>For the most part, you can accomplish that pretty easily, either manually or from the UI of your favorite IDE.</p>
<p>For now, it's time for a recap.</p>
<h3 id="heading-recap-understanding-git-merge">Recap - Understanding Git Merge</h3>
<p>In this chapter, you got an extensive overview of merging with Git. You learned that merging is the process of combining the recent changes from several branches into a single new commit. The new commit has two parents - those commits which had been the tips of the branches that were merged.</p>
<p>We considered a simple, fast-forward merge, which is possible when one branch diverged from the base branch, and then just added commits on top of the base branch.</p>
<p>We then considered three-way merges, and explained the three-stage process:</p>
<ul>
<li>First, Git locates the merge base. As a reminder, this is the first commit that is reachable from both branches.</li>
<li>Second, Git calculates two diffs - one diff from the merge base to the <em>first</em> branch, and another diff from the merge base to the <em>second</em> branch. Git generates patches based on those diffs.</li>
<li>Third and last, Git applies both patches to the merge base using a 3-way merge algorithm. The result is the state of the new merge commit.</li>
</ul>
<p>We dove deeper into the process of a 3-way merge, whether at a file level or a hunk level. We considered when Git is able to rely on a 3-way merge to automatically resolve conflicts, and when it just can't.</p>
<p>You saw the output of <code>git diff</code> when we are in a conflicting state, and how to resolve conflicts either manually or with VS Code.</p>
<p>There is much more to be said about merges - different merge strategies, recursive merges, and so on. Yet, I believe this chapter covered everything needed so you have a robust understanding of what merge is, and what happens under the hood in the vast majority of cases.</p>
<h3 id="heading-beatles-related-resources">Beatles-Related Resources</h3>
<ul>
<li><a target="_blank" href="https://www.the-paulmccartney-project.com/song/ive-got-a-feeling/">https://www.the-paulmccartney-project.com/song/ive-got-a-feeling/</a></li>
<li><a target="_blank" href="https://www.cheatsheet.com/entertainment/did-john-lennon-or-paul-mccartney-write-the-classic-a-day-in-the-life.html/">https://www.cheatsheet.com/entertainment/did-john-lennon-or-paul-mccartney-write-the-classic-a-day-in-the-life.html/</a></li>
<li><a target="_blank" href="http://lifeofthebeatles.blogspot.com/2009/06/ive-got-feeling-lyrics.html">http://lifeofthebeatles.blogspot.com/2009/06/ive-got-feeling-lyrics.html</a></li>
</ul>
<h2 id="heading-chapter-8-understanding-git-rebase">Chapter 8 - Understanding Git Rebase</h2>
<p>One of the most powerful tools a developer can have in their toolbox is <code>git rebase</code>. Yet it is notorious for being complex and misunderstood.</p>
<p>The truth is, if you understand what it actually does, <code>git rebase</code> is a very elegant, and straightforward tool to achieve so many different things in Git.</p>
<p>In the previous chapters in this part, you learned what Git diffs are, what a merge is, and how Git resolves merge conflicts. In this chapter, you will understand what Git rebase is, why it's different from merge, and how to rebase with confidence.</p>
<h3 id="heading-short-recap-what-is-git-merge">Short Recap - What is Git Merge?</h3>
<p>Under the hood, <code>git rebase</code> and <code>git merge</code> are very, very different things. Then why do people compare them all the time?</p>
<p>The reason is their usage. When working with Git, we usually work in different branches and introduce changes to those branches.</p>
<p>In the previous chapter, we considered the example where John and Paul (of the Beatles) were co-authoring a new song. They started from the <code>main</code> branch, and then each diverged, modified the lyrics, and committed their changes.</p>
<p>Then, the two wanted to <em>integrate</em> their changes, which is something that happens very frequently when working with Git.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diverging_history_commit_9.png" alt="A diverging history -  and  diverged from " width="600" height="400" loading="lazy">
_A diverging history - <code>paul_branch</code> and <code>john_branch</code> diverged from <code>main</code>_</p>
<p>There are two main ways to integrate changes introduced in different branches in Git, or in other words, different commits and commit histories. These are merge and rebase.</p>
<p>In the previous chapter, we got to know <code>git merge</code> pretty well. We saw that when performing a merge, we create a <strong>merge commit</strong> - where the contents of this commit are a combination of the two branches, and it also has two parents, one in each branch.</p>
<p>So, say you are on the branch <code>john_branch</code> (assuming the history depicted in the drawing above), and you run <code>git merge paul_branch</code>. You will get to this state - where on <code>john_branch</code>, there is a new commit with two parents. The first one will be the commit on the <code>john_branch</code> branch where <code>HEAD</code> was pointing to a state before performing the merge - in this case, "Commit 6". The second will be the commit pointed to by <code>paul_branch</code>, "Commit 9".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_merge_paul_branch.png" alt="The result of running : a new Merge Commit with two parents" width="600" height="400" loading="lazy">
_The result of running <code>git merge paul_branch</code>: a new Merge Commit with two parents_</p>
<p>Look again at the history graph: you created a <strong>diverged</strong> history. You can actually see where it branched and where it merged again.</p>
<p>So when using <code>git merge</code>, you do not rewrite history - but rather, you add a commit to the existing history. And specifically, a commit that creates a diverged history.</p>
<h3 id="heading-how-is-git-rebase-different-than-git-merge">How is <code>git rebase</code> Different than <code>git merge</code>?</h3>
<p>When using <code>git rebase</code>, something different happens.</p>
<p>Let's start with the big picture: if you are on <code>paul_branch</code>, and use <code>git rebase john_branch</code>, Git goes to the common ancestor of John's branch and Paul's branch. Then it takes the patches introduced in the commits on Paul's branch, and applies those changes to John's branch.</p>
<p>So here, you use <code>rebase</code> to take the changes that were committed on one branch - Paul's branch - and replay them on a different branch, <code>john_branch</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_rebase_john_branch.png" alt="The result of running : the commits on  were &quot;replayed&quot; on top of " width="600" height="400" loading="lazy">
_The result of running <code>git rebase john_branch</code>: the commits on <code>paul_branch</code> were "replayed" on top of <code>john_branch</code>_</p>
<p>Wait, what does that mean?</p>
<p>We will now take this bit by bit to make sure you fully understand what's happening under the hood 😎</p>
<h3 id="heading-cherry-pick-as-a-basis-for-rebase"><code>cherry-pick</code> as a Basis for Rebase</h3>
<p>It is useful to think of rebase as performing <code>git cherry-pick</code> - a command that takes a commit, computes the patch this commit introduces by computing the difference between the parent's commit and the commit itself, and then cherry-pick "replays" this difference.</p>
<p>Let's do this manually.</p>
<p>If we look at the difference introduced by "Commit 5" by performing <code>git diff main &lt;SHA_OF_COMMIT_5&gt;</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_commit_5.png" alt="Running  to observe the patch introduced by &quot;Commit 5&quot;" width="600" height="400" loading="lazy">
<em>Running <code>git diff</code> to observe the patch introduced by "Commit 5"</em></p>
<p>As always, you are encouraged to run the commands yourself while reading this chapter. Unless noted otherwise, I will use the following repository:</p>
<p><a target="_blank" href="https://github.com/Omerr/rebase_playground.git">https://github.com/Omerr/rebase_playground.git</a></p>
<p>I recommend you clone it locally and have the same starting point I am using for this chapter.</p>
<p>You can see that in this commit, John started working on a song called "Lucy in the Sky with Diamonds":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_commit_5_output.png" alt="The output of  - the patch introduced by &quot;Commit 5&quot;" width="600" height="400" loading="lazy">
<em>The output of <code>git diff</code> - the patch introduced by "Commit 5"</em></p>
<p>As a reminder, you can also use the command <code>git show</code> to get the same output:</p>
<pre><code class="lang-bash">git show &lt;SHA_OF_COMMIT_5&gt;
</code></pre>
<p>Now, if you <code>cherry-pick</code> this commit, you will introduce <em>this change</em> specifically, on the active branch. Switch to <code>main</code> first:</p>
<pre><code class="lang-bash">git checkout main (or git switch main)
</code></pre>
<p>And create another branch:</p>
<pre><code class="lang-bash">git checkout -b my_branch (or git switch -c my_branch)
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_my_branch.png" alt="Creating  that branches from " width="600" height="400" loading="lazy">
_Creating <code>my_branch</code> that branches from <code>main</code>_</p>
<p>Next, <code>cherry-pick</code> "Commit 5":</p>
<pre><code class="lang-bash">git cherry-pick &lt;SHA_OF_COMMIT_5&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/cherry_pick_commit_5.png" alt="Using  to apply the changes introduced in &quot;Commit 5&quot; onto " width="600" height="400" loading="lazy">
<em>Using <code>cherry-pick</code> to apply the changes introduced in "Commit 5" onto <code>main</code></em></p>
<p>Consider the log (output of <code>git lol</code>):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_lol_commit_5.png" alt="The output of " width="600" height="400" loading="lazy">
<em>The output of <code>git lol</code></em></p>
<p>It seems like you <em>copy-pasted</em> "Commit 5". Remember that even though it has the same commit message, and introduces the same changes, and even points to the same tree object as the original "Commit 5" in this case - it is still a different commit object, as it was created with a different timestamp.</p>
<p>Looking at the changes, using <code>git show HEAD</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD-1.png" alt="The output of " width="600" height="400" loading="lazy">
<em>The output of <code>git show HEAD</code></em></p>
<p>They are the same as "Commit 5"'s.</p>
<p>And of course, if you look at the file (say, by using <code>nano lucy_in_the_sky_with_diamonds.md</code>), it will be in the same state as it has been after the original "Commit 5".</p>
<p>Cool! 😎</p>
<p>You can now remove the new branch so it doesn't appear on your history every time:</p>
<pre><code class="lang-bash">git checkout main
git branch -D my_branch
</code></pre>
<h3 id="heading-beyond-cherry-pick-how-to-use-git-rebase">Beyond <code>cherry-pick</code> - How to Use <code>git rebase</code></h3>
<p>You can view <code>git rebase</code> as a way to perform multiple <code>cherry-pick</code>s one after the other - that is, to "replay" multiple commits. This is not the only thing you can do with rebase, but it's a good starting point for our explanation.</p>
<p>It's time to play with <code>git rebase</code>!</p>
<p>Before, you merged <code>paul_branch</code> into <code>john_branch</code>. What would happen if you <em>rebased</em> <code>paul_branch</code> on top of <code>john_branch</code>? You would get a very different history.</p>
<p>In essence, it would seem as if we took the changes introduced in the commits on <code>paul_branch</code>, and replayed them on <code>john_branch</code>. The result would be a linear history.</p>
<p>To understand the process, I will provide the high level view, and then dive deeper into each step. The process of rebasing one branch on top of another branch is as follows:</p>
<ol>
<li>Find the common ancestor.</li>
<li>Identify the commits to be "replayed".</li>
<li>For every commit <code>X</code>, compute <code>diff(parent(X), X)</code>, and store it as a <code>patch(X)</code>.</li>
<li>Move <code>HEAD</code> to the new base.</li>
<li>Apply the generated patches in order on the target branch. Each time, create a new commit object with the new state.</li>
</ol>
<p>The process of making new commits with the same change sets as existing ones is also called "<strong>replaying</strong>" those commits, a term we have already used.</p>
<h3 id="heading-time-to-get-hands-on-with-rebase">Time to Get Hands-On with Rebase</h3>
<p>Before running the following command command, make sure you have <code>john_branch</code> locally, so run:</p>
<pre><code class="lang-bash">git checkout john_branch
</code></pre>
<p>Start from Paul's branch:</p>
<pre><code class="lang-bash">git checkout paul_branch
</code></pre>
<p>This is the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/diverging_history_commit_9-1.png" alt="Commit history before performing " width="600" height="400" loading="lazy">
<em>Commit history before performing <code>git rebase</code></em></p>
<p>And now, to the exciting part:</p>
<pre><code class="lang-bash">git rebase john_branch
</code></pre>
<p>And observe the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_rebase.png" alt="The history after rebasing" width="600" height="400" loading="lazy">
<em>The history after rebasing</em></p>
<p>With <code>git merge</code> you added to the history, while with <code>git rebase</code> you <strong>rewrite history</strong>. You create <strong>new</strong> commit objects. In addition, the result is a linear history graph - rather than a diverging graph.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_rebase_2.png" alt="The history after rebasing" width="600" height="400" loading="lazy">
<em>The history after rebasing</em></p>
<p>In essence, you "copied" the commits that were on <code>paul_branch</code> and that were introduced after "Commit 4", and "pasted" them on top of <code>john_branch</code>.</p>
<p>The command is called "rebase", because it changes the base commit of the branch it's run from. That is, in your case, before running <code>git rebase</code>, the base of <code>paul_branch</code> was "Commit 4" - as this is where the branch was "born" (from <code>main</code>). With <code>rebase</code>, you asked Git to give it another base - that is, pretend as if it had been born from "Commit 6".</p>
<p>To do that, Git took what used to be "Commit 7", and "replayed" the changes introduced in this commit onto "Commit 6". Then it created a new commit object. This object differs from the original "Commit 7" in three aspects:</p>
<ol>
<li>It has a different timestamp.</li>
<li>It has a different parent commit - "Commit 6", rather than "Commit 4".</li>
<li>The tree object it is pointing to is different - as the changes were introduced to the tree pointed to by "Commit 6", and not the tree pointed to by "Commit 4".</li>
</ol>
<p>Notice the last commit here, "Commit 9'". The snapshot it represents (that is, the tree that it points to) is exactly the same tree you would get by merging the two branches. The state of the files in your Git repository would be <strong>the same</strong> as if you used <code>git merge</code>. It's only the <em>history</em> that is different, and the commit objects of course.</p>
<p>Now, you can simply use:</p>
<pre><code class="lang-bash">git checkout main
git merge paul_branch
</code></pre>
<p>Hm.... What would happen if you ran this last command? Consider the commit history again, after checking out <code>main</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_checkout_main.png" alt="The history after rebasing and checking out " width="600" height="400" loading="lazy">
<em>The history after rebasing and checking out <code>main</code></em></p>
<p>What would it mean to merge <code>main</code> and <code>paul_branch</code>?</p>
<p>Indeed, Git can simply perform a fast-forward merge, as the history is completely linear (if you need a reminder about fast-forward merges, check out the previous chapter). As a result, <code>main</code> and <code>paul_branch</code> now point to the same commit:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/fast_forward_merge_result.png" alt="The result of a fast-forward merge" width="600" height="400" loading="lazy">
<em>The result of a fast-forward merge</em></p>
<h3 id="heading-advanced-rebasing-in-git">Advanced Rebasing in Git</h3>
<p>Now that you understand the basics of rebase, it is time to consider more advanced cases, where additional switches and arguments to the rebase command will come in handy.</p>
<p>In the previous example, when you only used <code>rebase</code> (without additional switches), Git replayed all the commits from the common ancestor to the tip of the current branch.</p>
<p>But rebase is a super-power. It's an almighty command capable of…well, rewriting history. And it can come in handy if you want to modify history to make it your own.</p>
<p>Undo the last merge by making <code>main</code> point to "Commit 4" again:</p>
<pre><code class="lang-bash">git reset --hard &lt;ORIGINAL_COMMIT 4&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_hard_1.png" alt="&quot;Undoing&quot; the last merge operation" width="600" height="400" loading="lazy">
<em>"Undoing" the last merge operation</em></p>
<p>And undo the rebasing by using:</p>
<pre><code class="lang-bash">git checkout paul_branch
git reset --hard &lt;ORIGINAL_COMMIT 9&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_hard_2.png" alt="&quot;Undoing&quot; the rebase operation" width="600" height="400" loading="lazy">
<em>"Undoing" the rebase operation</em></p>
<p>Notice that you got to exactly the same history you used to have:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_undoing_rebase.png" alt="Visualizing the history after &quot;undoing&quot; the rebase operation" width="600" height="400" loading="lazy">
<em>Visualizing the history after "undoing" the rebase operation</em></p>
<p>To be clear, "Commit 9" doesn't just disappear when it's not reachable from the current <code>HEAD</code>. Rather, it's still stored in the object database. And as you used <code>git reset</code> now to change <code>HEAD</code> to point to this commit, you were able to retrieve it, and also its parent commits since they are also stored in the database. Pretty cool, huh? 😎 </p>
<p>You will learn more about <code>git reset</code> in the next part, where we discuss undoing changes in Git.</p>
<p>View the changes that Paul introduced:</p>
<pre><code class="lang-bash">git show HEAD
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD_2.png" alt=" shows the patch introduced by &quot;Commit 9&quot;" width="600" height="400" loading="lazy">
<em><code>git show HEAD</code> shows the patch introduced by "Commit 9"</em></p>
<p>Keep going backwards in the commit graph:</p>
<pre><code class="lang-bash">git show HEAD~
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD-.png" alt=" (same as ) shows the patch introduced by &quot;Commit 8&quot;" width="600" height="400" loading="lazy">
<em><code>git show HEAD~</code> (same as <code>git show HEAD~1</code>) shows the patch introduced by "Commit 8"</em></p>
<p>And one commit further:</p>
<pre><code class="lang-bash">git show HEAD~2
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD-2.png" alt=" shows the patch introduced by &quot;Commit 7&quot;" width="600" height="400" loading="lazy">
<em><code>git show HEAD~2</code> shows the patch introduced by "Commit 7"</em></p>
<p>Perhaps Paul doesn't want this kind of history. Rather, he wants it to seem as if he introduced the changes in "Commit 7" and "Commit 8" as a single commit.</p>
<p>For that, you can use an <strong>interactive rebase</strong>. To do that, we add the <code>-i</code> (or <code>--interactive</code>) switch to the rebase command:</p>
<pre><code class="lang-bash">git rebase -i &lt;SHA_OF_COMMIT_4&gt;
</code></pre>
<p>Or, since main is pointing to "Commit 4", we can run:</p>
<pre><code class="lang-bash">git rebase -i main
</code></pre>
<p>By running this command, you tell Git to use a new base, "Commit 4". So you are asking Git to go back to all commits that were introduced after "Commit 4" and that are reachable from the current <code>HEAD</code>, and replay those commits.</p>
<p>For every commit that is replayed, Git asks us what we'd like to do with it:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_1.png" alt=" prompts you to select what to do with each commit" width="600" height="400" loading="lazy">
<em><code>git rebase -i main</code> prompts you to select what to do with each commit</em></p>
<p>In this context it's useful to think of a commit as a patch. That is, "Commit 7", as in "the patch that "Commit 7" introduced on top of its parent".</p>
<p>One option is to use <code>pick</code>. This is the default behavior, which tells Git to replay the changes introduced in this commit. In this case, if you just leave it as is - and <code>pick</code> all commits - you will get the same history, and Git won't even create new commit objects.</p>
<p>Another option is <code>squash</code>. A <em>squashed</em> commit will have its contents "folded" into the contents of the commit preceding it. So in our case, Paul would like to squash "Commit 8" into "Commit 7":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_2.png" alt="Squashing &quot;Commit 8&quot; into &quot;Commit 7&quot;" width="600" height="400" loading="lazy">
<em>Squashing "Commit 8" into "Commit 7"</em></p>
<p>As you can see, <code>git rebase -i</code> provides additional options, but we won't go into all of them in this chapter. If you allow the rebase to run, you will get prompted to select a commit message for the newly created commit (that is, the one that introduced the changes of both "Commit 7" and "Commit 8"):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_3.png" alt="Providing the commit message: Commits 7+8" width="600" height="400" loading="lazy">
<em>Providing the commit message: Commits 7+8</em></p>
<p>And look at the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_interactive_rebase.png" alt="The history after the interactive rebase" width="600" height="400" loading="lazy">
<em>The history after the interactive rebase</em></p>
<p>Exactly as we wanted! On <code>paul_branch</code>, we have "Commit 9" (of course, it's a different object than the original "Commit 9"). This object points to "Commits 7+8", which is a single commit introducing the changes of both the original "Commit 7" and the original "Commit 8". This commit's parent is "Commit 4", where <code>main</code> is pointing to.</p>
<p>Oh wow, isn't that cool? 😎</p>
<p><code>git rebase</code> grants you unlimited control over the shape of any branch. You can use it to reorder commits, or to remove incorrect changes, or modify a change in retrospect. Alternatively, you could perhaps move the base of your branch onto another commit, any commit that you wish.</p>
<h3 id="heading-how-to-use-the-onto-switch-of-git-rebase">How to Use the <code>--onto</code> Switch of <code>git rebase</code></h3>
<p>Let's consider one more example. Get to <code>main</code> again:</p>
<pre><code class="lang-bash">git checkout main
</code></pre>
<p>And delete the pointers to paul_branch and john_branch so you don't see them in the commit graph anymore:</p>
<pre><code class="lang-bash">git branch -D paul_branch
git branch -D john_branch
</code></pre>
<p>Next, branch from <code>main</code> to a new branch:</p>
<pre><code class="lang-bash">git checkout -b new_branch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_new_branch.png" alt="Creating  that diverges from " width="600" height="400" loading="lazy">
_Creating <code>new_branch</code> that diverges from <code>main</code>_</p>
<p>This is the clean history you should have:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_new_branch.png" alt="A clean history with  that diverges from " width="600" height="400" loading="lazy">
_A clean history with <code>new_branch</code> that diverges from <code>main</code>_</p>
<p>Now, change the file <code>code.py</code> (for example, add a new function) and commit your changes:</p>
<pre><code class="lang-bash">nano code.py
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_1.png" alt="Adding the function  to " width="600" height="400" loading="lazy">
_Adding the function <code>new_branch</code> to <code>code.py</code>_</p>
<pre><code class="lang-bash">git add code.py
git commit -m <span class="hljs-string">"Commit 10"</span>
</code></pre>
<p>Get back to <code>main</code>:</p>
<pre><code class="lang-bash">git checkout main
</code></pre>
<p>And introduce another change - adding a docstring at the beginning of the file:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_2.png" alt="Added a docstring at the beginning of the file" width="600" height="400" loading="lazy">
<em>Added a docstring at the beginning of the file</em></p>
<p>Time to stage and commit these changes:</p>
<pre><code class="lang-bash">git add code.py
git commit -m <span class="hljs-string">"Commit 11"</span>
</code></pre>
<p>And yet another change, perhaps add <code>@Author</code> to the docstring:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_3.png" alt="Added  to the docstring" width="600" height="400" loading="lazy">
<em>Added <code>@Author</code> to the docstring</em></p>
<p>Commit this change as well:</p>
<pre><code class="lang-bash">git add code.py
git commit -m <span class="hljs-string">"Commit 12"</span>
</code></pre>
<p>Oh wait, now I realize that I wanted you to make the changes introduced in "Commit 11" as a part of the <code>new_branch</code>. Ugh. What can you do?</p>
<p>Consider the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_12-2.png" alt="The history after introducing &quot;Commit 12&quot;" width="600" height="400" loading="lazy">
<em>The history after introducing "Commit 12"</em></p>
<p>Instead of having "Commit 11" reside only on the <code>main</code> branch, I want it to be on <em>both</em> the <code>main</code> branch as well as <code>new_branch</code>. Visually, I would want to <em>move</em> it down the graph here:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/push_commit_10_down.png" alt="Visually, I want you to &quot;push down&quot; &quot;Commit 10&quot;" width="600" height="400" loading="lazy">
<em>Visually, I want you to "push down" "Commit 10"</em></p>
<p>Can you see where I am going? 😇</p>
<p>Well, <code>rebase</code> allows you to basically replay the changes introduced in <code>new_branch</code>, those introduced in "Commit 10", as if they had been originally conducted on "Commit 11", rather than "Commit 4".</p>
<p>To do that, you can use other arguments of <code>git rebase</code>. Specifically, you can use <code>git rebase --onto</code>, which optionally takes three parameters:</p>
<pre><code class="lang-bash">git rebase --onto &lt;new_parent&gt; &lt;old_parent&gt; &lt;until&gt;
</code></pre>
<p>That is, you take all commits between <code>old_parent</code> and <code>until</code>, and you "cut" and "paste" them <em>onto</em> <code>new_parent</code>.</p>
<p>In this case, you'd tell Git that you want to take all the history introduced between the common ancestor of <code>main</code> and <code>new_branch</code>, which is "Commit 4", and have the new base for that history be "Commit 11". To do that, use:</p>
<pre><code class="lang-bash">git rebase --onto &lt;SHA_OF_COMMIT_11&gt; main new_branch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_1.png" alt="The history before and after the rebase, &quot;Commit 10&quot; has been &quot;pushed&quot;" width="600" height="400" loading="lazy">
<em>The history before and after the rebase, "Commit 10" has been "pushed"</em></p>
<p>And look at our beautiful history! 😍</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_2.png" alt="The history before and after the rebase, &quot;Commit 10&quot; has been &quot;pushed&quot;" width="600" height="400" loading="lazy">
<em>The history before and after the rebase, "Commit 10" has been "pushed"</em></p>
<p>Let's consider another case.</p>
<p>Say I started working on a new feature, and by mistake I started working from <code>feature_branch_1</code>, rather than from <code>main</code>.</p>
<p>So to emulate this, create <code>feature_branch_1</code>:</p>
<pre><code class="lang-bash">git checkout main
git checkout -b feature_branch_1
</code></pre>
<p>And erase <code>new_branch</code> so you don't see it in the graph anymore:</p>
<pre><code class="lang-bash">git branch -D new_branch
</code></pre>
<p>Create a simple Python file called <code>1.py</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/1_py_1.png" alt="A new file, , with " width="600" height="400" loading="lazy">
<em>A new file, <code>1.py</code>, with <code>print('Hello world!')</code></em></p>
<p>Stage and commit this file:</p>
<pre><code class="lang-bash">git add 1.py
git commit -m  <span class="hljs-string">"Commit 13"</span>
</code></pre>
<p>Now branch out from <code>feature_branch_1</code> (this is the mistake you will later fix):</p>
<pre><code class="lang-bash">git checkout -b feature_branch_2
</code></pre>
<p>And create another file, <code>2.py</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/2_py_1.png" alt="Creating " width="600" height="400" loading="lazy">
<em>Creating <code>2.py</code></em></p>
<p>Stage and commit this file as well:</p>
<pre><code class="lang-bash">git add 2.py
git commit -m  <span class="hljs-string">"Commit 14"</span>
</code></pre>
<p>And introduce some more code to <code>2.py</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/2_py_2.png" alt="Modifying " width="600" height="400" loading="lazy">
<em>Modifying <code>2.py</code></em></p>
<p>Stage and commit these changes too:</p>
<pre><code class="lang-bash">git add 2.py
git commit -m  <span class="hljs-string">"Commit 15"</span>
</code></pre>
<p>So far you should have this history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_15.png" alt="The history after introducing &quot;Commit 15&quot;" width="600" height="400" loading="lazy">
<em>The history after introducing "Commit 15"</em></p>
<p>Get back to <code>feature_branch_1</code> and edit <code>1.py</code>:</p>
<pre><code class="lang-bash">git checkout feature_branch_1
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/1_py_2.png" alt="Modifying " width="600" height="400" loading="lazy">
<em>Modifying <code>1.py</code></em></p>
<p>Now stage and commit:</p>
<pre><code class="lang-bash">git add 1.py
git commit -m  <span class="hljs-string">"Commit 16"</span>
</code></pre>
<p>Your history should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_16-1.png" alt="The history after introducing &quot;Commit 16&quot;" width="600" height="400" loading="lazy">
<em>The history after introducing "Commit 16"</em></p>
<p>Say now you realize that you've made a mistake. You actually wanted <code>feature_branch_2</code> to be born from the <code>main</code> branch, rather than from <code>feature_branch_1</code>.</p>
<p>How can you achieve that?</p>
<p>Try to think about it given the history graph and what you've learned about the <code>--onto</code> flag for the <code>rebase</code> command.</p>
<p>Well, you want to "replace" the parent of your first commit on <code>feature_branch_2</code>, which is "Commit 14", so that it's on top of <code>main</code> branch - in this case, "Commit 12" - rather than the beginning of <code>feature_branch_1</code> - in this case, "Commit 13". So again, you will be creating a <em>new base</em>, this time for the first commit on <code>feature_branch_2</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/plan_commit14_15.png" alt="You want to move around &quot;Commit 14&quot; and &quot;Commit 15&quot;" width="600" height="400" loading="lazy">
<em>You want to move around "Commit 14" and "Commit 15"</em></p>
<p>How would you do that?</p>
<p>First, switch to <code>feature_branch_2</code>:</p>
<pre><code class="lang-bash">git checkout feature_branch_2
</code></pre>
<p>And now you can use:</p>
<pre><code class="lang-bash">git rebase --onto main &lt;SHA_OF_COMMIT_13&gt;
</code></pre>
<p>This tells Git to take the history with "Commit 13" as a base, and change that base to be "Commit 12" (pointed to by <code>main</code>) instead.</p>
<p>As a result, you have <code>feature_branch_2</code> based on <code>main</code> rather than <code>feature_branch_1</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_3.png" alt="The commit history after performing rebase" width="600" height="400" loading="lazy">
<em>The commit history after performing rebase</em></p>
<p>The syntax of the command is:</p>
<pre><code class="lang-bash">git rebase --onto &lt;new_parent&gt; &lt;old_parent&gt;
</code></pre>
<h3 id="heading-how-to-rebase-on-a-single-branch">How to Rebase on a Single Branch</h3>
<p>You can also use <code>git rebase</code> while looking at the history of a single branch.</p>
<p>Let's see if you can help me here.</p>
<p>Say I worked from <code>feature_branch_2</code>, and specifically edited the file <code>code.py</code>. I started by changing all strings to be wrapped by double quotes rather than single quotes:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_4.png" alt="Changing  into  in " width="600" height="400" loading="lazy">
<em>Changing <code>'</code> into <code>"</code> in <code>code.py</code></em></p>
<p>Then, I staged and committed:</p>
<pre><code class="lang-bash">git add code.py
git commit -m <span class="hljs-string">"Commit 17"</span>
</code></pre>
<p>I then decided to add a new function at the beginning of the file:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_5.png" alt="Adding the function " width="600" height="400" loading="lazy">
_Adding the function <code>another_feature</code>_</p>
<p>Again, I staged and committed:</p>
<pre><code class="lang-bash">git add code.py
git commit -m <span class="hljs-string">"Commit 18"</span>
</code></pre>
<p>And now I realized that I actually forgot to change the single quotes to double quotes wrapping <code>__main__</code> (as you might have noticed), so I did that too:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_6.png" alt="Changing  into " width="600" height="400" loading="lazy">
<em>Changing <code>'__main__'</code> into <code>"__main__"</code></em></p>
<p>Of course, I staged and committed this change:</p>
<pre><code class="lang-bash">git add code.py
git commit -m <span class="hljs-string">"Commit 19"</span>
</code></pre>
<p>Now, consider the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_19.png" alt="The commit history after introducing &quot;Commit 19&quot;" width="600" height="400" loading="lazy">
<em>The commit history after introducing "Commit 19"</em></p>
<p>It isn't really nice, is it? I mean, I have two commits that are related to one another, "Commit 17" and "Commit 19" (turning <code>'</code>s into <code>"</code>s), but they are split by the unrelated "Commit 18" (where I added a new function). What can we do? Can you help me?</p>
<p>Intuitively, I want to edit the history here:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/plan_edit_commits_17_18.png" alt="These are the commits I want to edit" width="600" height="400" loading="lazy">
<em>These are the commits I want to edit</em></p>
<p>So, what would you do?</p>
<p>You are right!</p>
<p>I can <code>rebase</code> the history from "Commit 17" to "Commit 19", on top of "Commit 15". To do that:</p>
<pre><code class="lang-bash">git rebase --interactive --onto &lt;SHA_OF_COMMIT_15&gt; &lt;SHA_OF_COMMIT_15&gt;
</code></pre>
<p>Notice I specified "Commit 15" as the beginning of the range of commits, excluding this commit. And I didn't need to explicitly specify <code>HEAD</code> as the last parameter.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_4.png" alt="Using  on a single branch" width="600" height="400" loading="lazy">
<em>Using <code>rebase --onto</code> on a single branch</em></p>
<p>(Note: If you follow the steps above with my repository and get a merge conflict, you may have a different configuration than on my machine with regards to whitespace characters at line endings. In that case, you can add the <code>--ignore-whitespace</code> switch to the <code>rebase</code> command, resulting in the following command: <code>git rebase --ignore-whitespace --interactive --onto &lt;SHA_OF_COMMIT_15&gt; &lt;SHA_OF_COMMIT_15&gt;</code>. If you are curious to find out more about this issue, search for <code>autocrlf</code>.)</p>
<p>After following your advice and running the <code>rebase</code> command (thanks! 😇) I get the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_4.png" alt="Interactive rebase" width="600" height="400" loading="lazy">
<em>Interactive rebase</em></p>
<p>So what would I do? I want to put "Commit 19" before "Commit 18", so it comes right after "Commit 17". I can go further and <code>squash</code> them together, like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_5.png" alt="Interactive rebase - changing the order of commit and squashing" width="600" height="400" loading="lazy">
<em>Interactive rebase - changing the order of commit and squashing</em></p>
<p>Now when I get prompted for a commit message, I can provide the message "Commit 17+19":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_6.png" alt="Providing a commit message" width="600" height="400" loading="lazy">
<em>Providing a commit message</em></p>
<p>And now, see our beautiful history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_5.png" alt="The resulting history" width="600" height="400" loading="lazy">
<em>The resulting history</em></p>
<p>Thanks again!</p>
<h3 id="heading-more-rebase-use-cases-more-practice">More Rebase Use Cases + More Practice</h3>
<p>By now I hope you feel comfortable with the syntax of rebase. The best way to actually understand it is to consider various cases and figure out how to solve them yourself.</p>
<p>With the upcoming use cases, I strongly suggest you stop reading after I've introduced each use case, and then try to solve it on your own.</p>
<h4 id="heading-how-to-exclude-commits">How to Exclude Commits</h4>
<p>Say you have this history on another repo:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/another_history_1.png" alt="Another commit history" width="600" height="400" loading="lazy">
<em>Another commit history</em></p>
<p>Before playing around with it, store a tag to "Commit F" so you can get back to it later:</p>
<pre><code class="lang-bash">git tag original_commit_f
</code></pre>
<p>(A tag is a named reference to a commit, just like a branch - but it doesn't change when you add additional commits. It is like a constant named reference.)</p>
<p>Now, you actually don't want the changes in "Commit C" and "Commit D" to be included. You could use an interactive rebase like before and remove their changes. Or, you could use <code>git rebase --onto</code> again. How would you use <code>--onto</code> in order to "remove" these two commits?</p>
<p>You can rebase <code>HEAD</code> on top of "Commit B", where the old parent was actually "Commit D", and now it should be "Commit B". Consider the history again:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/another_history_1-1.png" alt="The history again" width="600" height="400" loading="lazy">
<em>The history again</em></p>
<p>Rebasing so that "Commit B" is the base of "Commit E" means "moving" both "Commit E" and "Commit F", and giving them another base - "Commit B". Can you come up with the command yourself?</p>
<pre><code class="lang-bash">git rebase --onto &lt;SHA_OF_COMMIT_B&gt; &lt;SHA_OF_COMMIT_D&gt; HEAD
</code></pre>
<p>Notice that using the syntax above (exactly as provided) would <em>not</em> move <em>main</em> to point to the new commit, so the result is a "detached" <code>HEAD</code>. If you use <code>gg</code> or another tool that displays the history reachable from branches, it might confuse you:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_6.png" alt="Rebasing with  results in a detached " width="600" height="400" loading="lazy">
<em>Rebasing with <code>--onto</code> results in a detached <code>HEAD</code></em></p>
<p>But if you simply use <code>git log</code> (or my alias <code>git lol</code>), you will see the desired history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_lol.png" alt="The resulting history" width="600" height="400" loading="lazy">
<em>The resulting history</em></p>
<p>I don't know about you, but these kinds of things make me really happy. 😊😇</p>
<p>By the way, you could omit <code>HEAD</code> from the previous command as this is the default value for the third parameter. So just using:</p>
<pre><code class="lang-bash">git rebase --onto &lt;SHA_OF_COMMIT_B&gt; &lt;SHA_OF_COMMIT_D&gt;
</code></pre>
<p>Would have the same effect. The last parameter actually tells Git where the end of the current sequence of commits to rebase is. So the syntax of <code>git rebase --onto</code> with three arguments is:</p>
<pre><code class="lang-bash">git rebase --onto &lt;new_parent&gt; &lt;old_parent&gt; &lt;until&gt;
</code></pre>
<h4 id="heading-how-to-move-commits-across-branches">How to Move Commits Across Branches</h4>
<p>So let's say we get to the same history as before:</p>
<pre><code class="lang-bash">git checkout original_commit_f
</code></pre>
<p>And now I want only "Commit E" to be on a branch based on "Commit B". That is, I want to have a new branch, branching from "Commit B", with only "Commit E".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/another_history_2.png" alt="The current history, considering &quot;Commit E&quot;" width="600" height="400" loading="lazy">
<em>The current history, considering "Commit E"</em></p>
<p>So, what does this mean in terms of <code>rebase</code>? Consider the image above. What commit (or commits) should I rebase, and which commit would be the new base?</p>
<p>I know I can count on you here 😉</p>
<p>What I want is to take "Commit E", and this commit only, and change its base to be "Commit B". In other words, to replay the changes introduced in "Commit E" onto "Commit B".</p>
<p>Can you apply that logic to the syntax of git rebase?</p>
<p>Here it is (this time I'm writing <code>&lt;COMMIT_X&gt;</code> instead of <code>&lt;SHA_OF_COMMIT_X&gt;</code>, for brevity):</p>
<pre><code class="lang-bash">git rebase --onto &lt;COMMIT_B&gt; &lt;COMMIT_D&gt; &lt;COMMIT_E&gt;
</code></pre>
<p>Now the history looks like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_rebase_3.png" alt="The history after rebase" width="600" height="400" loading="lazy">
<em>The history after rebase</em></p>
<p>Notice that <code>rebase</code> moved <code>HEAD</code>, but not any other reference named (such as a branch or a tag). In other words, you are in a detached <code>HEAD</code> state. So here too, using <code>gg</code> or another tool that displays the history reachable from branches and tags might confuse you. You can use <code>git log</code> (or my alias <code>git lol</code>) to display the reachable history from <code>HEAD</code>.</p>
<p>Awesome!</p>
<h3 id="heading-a-note-about-conflicts">A Note About Conflicts</h3>
<p>Note that when performing a rebase, you may run into conflicts just as when merging. You may have conflicts because, when rebasing, you are trying to apply patches on a different base, perhaps where the patches do not apply.</p>
<p>For example, consider the previous repository again, and specifically, consider the change introduced in "Commit 12", pointed to by <code>main</code>:</p>
<pre><code class="lang-bash">git show main
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/patch_commit_12.png" alt="The patch introduced in &quot;Commit 12&quot;" width="600" height="400" loading="lazy">
<em>The patch introduced in "Commit 12"</em></p>
<p>I already covered the format of <code>git diff</code> in detail in <a class="post-section-overview" href="#heading-chapter-6-diffs-and-patches">chapter 6</a>, but as a quick reminder, this commit instructs Git to add a line after the two lines of context:</p>
<pre><code class="lang-patch">
</code></pre>
<p>This is a sample file</p>
<pre><code>
And before these three lines <span class="hljs-keyword">of</span> context:

<span class="hljs-string">``</span><span class="hljs-string">`patch</span>
</code></pre><p>def new_feature():
  print('new feature')</p>
<pre><code>
Say you are trying to rebase <span class="hljs-string">"Commit 12"</span> onto another commit. If, <span class="hljs-keyword">for</span> some reason, these context lines don<span class="hljs-string">'t exist as they do in the patch on the commit you are rebasing onto, then you will have a conflict.

### Zooming Out for the Big Picture

![Comparing rebase and merge](https://www.freecodecamp.org/news/content/images/2023/12/compare_rebase_merge.png)
_Comparing rebase and merge_

In the beginning of this chapter, I started by mentioning the similarity between `git merge` and `git rebase`: both are used to integrate changes introduced in different histories.

But, as you now know, they are very different in how they operate. While merging results in a _diverged_ history, rebasing results in a _linear_ history. Conflicts are possible in both cases. And there is one more column described in the table above that requires some close attention.

Now that you know what "Git rebase" is, and how to use interactive rebase or rebase `--onto`, as I hope you agree, `git rebase` is a super powerful tool. Yet, it has one huge drawback when compared with merging.

**Git rebase changes the history.**

This means that you should **not** rebase commits that exist outside your local copy of the repository, and that other people may have based their commits on.

In other words, if the only commits in question are those you created locally - go ahead, use rebase, go wild.

But if the commits have been pushed, this can lead to a huge problem - as someone else may rely on these commits that you later overwrite, and then you and they will have different versions of the repository.

This is unlike `merge` which, as we have seen, does not modify history.

For example, consider the last case where we rebased and resulted in this history:

![The history after rebase](https://www.freecodecamp.org/news/content/images/2023/12/history_after_rebase_3-1.png)
_The history after rebase_

Now, assume that I have already pushed this branch to the remote. And after I had pushed the branch, another developer pulled it and branched out from "Commit C". The other developer didn'</span>t know that meanwhile, I was locally rebasing my branch, and would later push it again.

This results <span class="hljs-keyword">in</span> an inconsistency: the other developer works <span class="hljs-keyword">from</span> a commit that is no longer available on my copy <span class="hljs-keyword">of</span> the repository.

I will not elaborate on what exactly <span class="hljs-built_in">this</span> causes <span class="hljs-keyword">in</span> <span class="hljs-built_in">this</span> book, <span class="hljs-keyword">as</span> my main message is that you should definitely avoid such cases. If you<span class="hljs-string">'re interested in what would actually happen, I'</span>ll leave a link to a useful resource <span class="hljs-keyword">in</span> the [additional references](#heading-additional-references-by-part). For now, <span class="hljs-keyword">let</span><span class="hljs-string">'s summarize what we have covered.

### Recap - Understanding Git Rebase

In this chapter, you learned about `git rebase`, a super-powerful tool to rewrite history in Git. You considered a few use cases where git rebase can be helpful, and how to use it with one, two, or three parameters, with and without the `--onto` switch.

I hope I was able to convince you that `git rebase` is powerful - but also that it is quite simple once you get the gist. It is a tool you can use to "copy-paste" commits (or, more accurately, patches). And it'</span>s a useful tool to have under your belt. In essence, <span class="hljs-string">`git rebase`</span> takes the patches introduced by commits, and replays them on another commit. As described <span class="hljs-keyword">in</span> <span class="hljs-built_in">this</span> chapter, <span class="hljs-built_in">this</span> is useful <span class="hljs-keyword">in</span> many different scenarios.

## Part <span class="hljs-number">2</span> - Summary

In <span class="hljs-built_in">this</span> part you learned about branching and integrating changes <span class="hljs-keyword">in</span> Git.

You learned what a **diff** is, and the difference between a diff and a **patch**. You also learned how the output <span class="hljs-keyword">of</span> <span class="hljs-string">`git diff`</span> is constructed.

Understanding diffs is a major milestone <span class="hljs-keyword">for</span> understanding many other processes within Git such <span class="hljs-keyword">as</span> merging or rebasing.

Then, you got an extensive overview <span class="hljs-keyword">of</span> merging <span class="hljs-keyword">with</span> Git. You learned that **merging** is the process <span class="hljs-keyword">of</span> **combining the recent changes <span class="hljs-keyword">from</span> several branches into a single <span class="hljs-keyword">new</span> commit**. The <span class="hljs-keyword">new</span> commit has multiple parents - those commits which had been the tips <span class="hljs-keyword">of</span> the branches that were merged. In most cases, merging combines the changes <span class="hljs-keyword">from</span> two branches, and the resulting merge commit then has two parents - one <span class="hljs-keyword">from</span> each branch.

We considered a simple, fast-forward merge, which is possible when one branch diverged <span class="hljs-keyword">from</span> the base branch, and then just added commits on top <span class="hljs-keyword">of</span> the base branch.

We then considered three-way merges, and explained the three-stage process:

* First, Git locates the merge base. As a reminder, <span class="hljs-built_in">this</span> is the first commit that is reachable <span class="hljs-keyword">from</span> both branches.
* Second, Git calculates two diffs - one diff <span class="hljs-keyword">from</span> the merge base to the _first_ branch, and another diff <span class="hljs-keyword">from</span> the merge base to the _second_ branch. Git generates patches based on those diffs.
* Third and last, Git applies both patches to the merge base using a <span class="hljs-number">3</span>-way merge algorithm. The result is the state <span class="hljs-keyword">of</span> the <span class="hljs-keyword">new</span> merge commit.

You saw the output <span class="hljs-keyword">of</span> <span class="hljs-string">`git diff`</span> when we are <span class="hljs-keyword">in</span> a conflicting state, and how to resolve conflicts either manually or <span class="hljs-keyword">with</span> VS Code.

Ultimately, you got to know Git rebase. You saw that <span class="hljs-string">`git rebase`</span> is powerful - but also that it is quite simple once you understand what it does. It is a tool to <span class="hljs-string">"copy-paste"</span> commits (or, more accurately, patches).

![Comparing rebase and merge](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/12/compare_rebase_merge-1.png)</span>
_Comparing rebase and merge_

Both <span class="hljs-string">`git merge`</span> and <span class="hljs-string">`git rebase`</span> are used to integrate changes introduced <span class="hljs-keyword">in</span> different histories.

Yet, they differ <span class="hljs-keyword">in</span> how they operate. While merging results <span class="hljs-keyword">in</span> a _diverged_ history, rebasing results <span class="hljs-keyword">in</span> a _linear_ history. <span class="hljs-string">`git rebase`</span> _changes_ the history, whereas <span class="hljs-string">`git merge`</span> adds to the existing history.

With <span class="hljs-built_in">this</span> deep understanding <span class="hljs-keyword">of</span> diffs, patches, merge and rebase, you should feel confident introducing changes to a git repository.

The next part will focus on what happens when things go wrong - how you can change history (<span class="hljs-keyword">with</span> or without <span class="hljs-string">`git rebase`</span>), or find <span class="hljs-string">"lost"</span> commits.

# Part <span class="hljs-number">3</span> - Undoing Changes

Did you ever get to a point where you said: <span class="hljs-string">"Uh-oh, what did I just do?"</span> I guess you have, just like about anyone who uses Git.

Perhaps you committed to the wrong branch. Perhaps you lost some code that you had written. Perhaps you committed something that you didn<span class="hljs-string">'t mean to.

This part will give you the tools to rewrite history with confidence, thereby "undoing" all kinds of changes in Git. 

Just like the other parts of the book, this part will be practical yet in-depth - so instead of providing you with a list of things to do when things go wrong, we will understand the underlying mechanisms, so that you will feel confident whenever you get to the "uh-oh" moment. Actually, you will find these moments as opportunities for an interesting challenge, rather than a dreadful scenario.

## Chapter 9 - Git Reset

Our journey starts with a powerful command that can be used to undo many different actions with Git - `git reset`.

### A Short Reminder - Recording Changes

In [chapter 3](#heading-chapter-3-how-to-record-changes-in-git), you learned how to record changes in Git. If you remember everything from this part, feel free to jump to the next section.

It is very useful to think about Git as a system for recording snapshots of a filesystem in time. Considering a Git repository, it has three "states" or "trees":

1. The **working directory**, a directory that has a repository associated with it.
2. The **staging area (index)** which holds the tree for the next commit.
3. The **repository**, which is a collection of commits and references.

![The three "trees" of a Git repo](https://www.freecodecamp.org/news/content/images/2023/12/3_trees.png)
_The three "trees" of a Git repo_

Note regarding the drawing conventions I use: I include `.git` within the working directory, to remind you that it is a folder within the project'</span>s folder on the filesystem. The <span class="hljs-string">`.git`</span> folder actually contains the objects and references <span class="hljs-keyword">of</span> the repository, <span class="hljs-keyword">as</span> explained <span class="hljs-keyword">in</span> [chapter <span class="hljs-number">4</span>](#heading-chapter<span class="hljs-number">-4</span>-how-to-create-a-repo-<span class="hljs-keyword">from</span>-scratch).

#### Hands-on Demonstration

Use <span class="hljs-string">`git init`</span> to initialize a <span class="hljs-keyword">new</span> repository. Write some text into a file called <span class="hljs-string">`1.txt`</span>:

<span class="hljs-string">``</span><span class="hljs-string">`bash
mkdir my_repo
cd my_repo
git init
echo Hello world &gt; 1.txt</span>
</code></pre><p>Out of the three tree states described above, where is <code>1.txt</code> now?</p>
<p>In the working tree, as it hasn't yet been introduced to the index.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/1_txt_working_dir.png" alt="The file  is now a part of the working dir only" width="600" height="400" loading="lazy">
<em>The file <code>1.txt</code> is now a part of the working dir only</em></p>
<p>In order to <em>stage</em> it, to <em>add</em> it to the index, use:</p>
<pre><code class="lang-bash">git add 1.txt
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/1_txt_index.png" alt="Using  stages the file so it is now in the index as well" width="600" height="400" loading="lazy">
<em>Using <code>git add</code> stages the file so it is now in the index as well</em></p>
<p>Notice that once you stage <code>1.txt</code>, Git creates a blob object with the content of this file, and adds it to the internal object database (within <code>.git</code> folder), as covered in <a class="post-section-overview" href="#heading-chapter-3-how-to-record-changes-in-git">chapter 3</a> and <a class="post-section-overview" href="#heading-chapter-4-how-to-create-a-repo-from-scratch">chapter 4</a>. I do not draw it as part of the "repository" as in this representation, the "repository" refers to a tree of commits and their references, and this blob has not been a part of any commit.</p>
<p>Now, use <code>git commit</code> to commit your changes to the repository:</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"Commit 1"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_1.png" alt="Using  creates a commit object in the repository" width="600" height="400" loading="lazy">
<em>Using <code>git commit</code> creates a commit object in the repository</em></p>
<p>You created a new <strong>commit</strong> object, which includes a pointer to a <strong>tree</strong> describing the entire <strong>working tree</strong>. In this case, this tree consists only of <code>1.txt</code> within the root folder. In addition to a pointer to the tree, the commit object includes metadata, such as timestamps and author information.</p>
<p>When considering the diagrams, notice that we only have a single copy of the file <code>1.txt</code> on disk, and a corresponding blob object in Git's object database. The "repository" tree now shows this file as it is part of the active commit - that is, the commit object "Commit 1" points to a tree that points to the blob with the contents of <code>1.txt</code>, the same blob that the index is pointing to.</p>
<p>For more information about the objects in Git (such as commits and trees), refer to <a class="post-section-overview" href="#heading-chapter-1-git-objects">chapter 1</a>.</p>
<p>Next, create a new file, and add it to the index, as before:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> second file &gt; 2.txt
git add 2.txt
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/2_txt_index.png" alt="The file  is in the working dir and the index after staging it with " width="600" height="400" loading="lazy">
<em>The file <code>2.txt</code> is in the working dir and the index after staging it with <code>git add</code></em></p>
<p>Next, commit:</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"Commit 2"</span>
</code></pre>
<p>Importantly, <code>git commit</code> does two things:</p>
<p>First, it creates a <strong>commit object</strong>, so there is an object within Git's internal object database with a corresponding SHA-1 value. This new commit object also points to the parent commit. That is the commit that <code>HEAD</code> was pointing to when you wrote the <code>git commit</code> command.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_commit_object.png" alt="A new commit object has been created, at first —  still points to the previous commit" width="600" height="400" loading="lazy">
<em>A new commit object has been created, at first - <code>main</code> still points to the previous commit</em></p>
<p>Second, <code>git commit</code> <strong>moves the pointer of the active branch</strong> — in our case, that would be <code>main</code>, to point to the newly created commit object.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_updates_active_branch.png" alt=" also updates the active branch to point to the newly created commit object" width="600" height="400" loading="lazy">
<em><code>git commit</code> also updates the active branch to point to the newly created commit object</em></p>
<h3 id="heading-introducing-git-reset">Introducing <code>git reset</code></h3>
<p>You will now learn how to reverse the process of introducing a commit. For that, you will get to know the command <code>git reset</code>.</p>
<h4 id="heading-git-reset-soft"><code>git reset --soft</code></h4>
<p>The very last step you did before was to <code>git commit</code>, which actually means two things — Git created a commit object and moved <code>main</code>, the active branch. To undo this step, use the following command:</p>
<pre><code class="lang-bash">git reset --soft HEAD~1
</code></pre>
<p>The syntax <code>HEAD~1</code> refers to the first parent of <code>HEAD</code>. Consider a case where I had more than one commit in the commit-graph, say "Commit 3" pointing to "Commit 2", which is, in turn, pointing to "Commit 1. And consider <code>HEAD</code> was pointing to "Commit 3". You could use <code>HEAD~1</code> to refer to "Commit 2", and <code>HEAD~2</code> would refer to "Commit 1".</p>
<p>So, back to the command: <code>git reset --soft HEAD~1</code></p>
<p>This command asks Git to change whatever <code>HEAD</code> is pointing to. (Note: In the diagrams below, I use <code>*HEAD</code> for "whatever <code>HEAD</code> is pointing to".) In our example, <code>HEAD</code> is pointing to <code>main</code>. So Git will only change the pointer of <code>main</code> to point to <code>HEAD~1</code>. That is, <code>main</code> will point to "Commit 1".</p>
<p>However, this command did <strong>not</strong> affect the state of the index or the working tree. So if you use <code>git status</code> you will see that <code>2.txt</code> is staged, just like before you ran <code>git commit</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_reset_soft.png" alt=" shows that  is in the index, but not in the active commit" width="600" height="400" loading="lazy">
<em><code>git status</code> shows that <code>2.txt</code> is in the index, but not in the active commit</em></p>
<p>The state is now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/reset_soft_1.png" alt="Resetting  to &quot;Commit 1&quot;" width="600" height="400" loading="lazy">
<em>Resetting <code>main</code> to "Commit 1"</em></p>
<p>(Note: I removed <code>2.txt</code> from the "repository" in the diagram as it is not part of the active commit - that is, the tree pointed to by "Commit 1" does not reference this file. However, it has not been removed from the file system - as it still exists in the working tree and the index.)</p>
<p>What about <code>git log</code>? It will start from <code>HEAD</code> , go to <code>main</code>, and then to "Commit 1":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_after_reset_soft.png" alt="The output of " width="600" height="400" loading="lazy">
<em>The output of <code>git log</code></em></p>
<p>Notice that this means that "Commit 2" is no longer reachable from our history.</p>
<p>Does that mean the commit object of "Commit 2" is deleted?</p>
<p>No, it's not deleted. It still resides within Git's internal object database of objects.</p>
<p>If you push the current history now, by using <code>git push</code>, Git will not push "Commit 2" to the remote server (as it is not reachable from the current <code>HEAD</code>), but the commit object <em>still exists</em> on your local copy of the repository.</p>
<p>Now, commit again - and use the commit message of "Commit 2.1" to differentiate this new object from the original "Commit 2":</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"Commit 2.1"</span>
</code></pre>
<p>This is the resulting state:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_2_1.png" alt="Creating a new commit" width="600" height="400" loading="lazy">
<em>Creating a new commit</em></p>
<p>I omitted "Commit 2" as it is not reachable from <code>HEAD</code>, even though its object exists in Git's internal object database.</p>
<p>Why are "Commit 2" and "Commit 2.1" different? Even if we used the same commit message, and even though they point to the same tree object (of the root folder consisting of <code>1.txt</code> and <code>2.txt</code>), they still have different timestamps, as they were created at different times. Both "Commit 2" and "Commit 2.1" now point to "Commit 1", but only "Commit 2.1" is reachable from <code>HEAD</code>.</p>
<h4 id="heading-git-reset-mixed"><code>git reset --mixed</code></h4>
<p>It's time to undo even further. This time, use:</p>
<pre><code class="lang-bash">git reset --mixed HEAD~1
</code></pre>
<p>(Note: <code>--mixed</code> is the default switch for <code>git reset</code>.)</p>
<p>This command starts the same as <code>git reset --soft HEAD~1</code>. That is, the command takes the pointer of whatever <code>HEAD</code> is pointing to now, which is the <code>main</code> branch, and sets it to <code>HEAD~1</code>, in our example - "Commit 1".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_mixed_1.png" alt="The first step of  is the same as " width="600" height="400" loading="lazy">
<em>The first step of <code>git reset --mixed</code> is the same as <code>git reset --soft</code></em></p>
<p>Next, Git goes further, effectively undoing the changes we made to the index. That is, changing the index so that it matches with the current <code>HEAD</code>, the new <code>HEAD</code> after setting it in the first step.</p>
<p>If we ran <code>git reset --mixed HEAD~1</code>, then <code>HEAD</code> (<code>main</code>) would be set to <code>HEAD~1</code> ("Commit 1"), and then Git would match the index to the state of "Commit 1" - in this case, it means that <code>2.txt</code> would no longer be part of the index.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_mixed_2.png" alt="The second step of  is to match the index with the new " width="600" height="400" loading="lazy">
<em>The second step of <code>git reset --mixed</code> is to match the index with the new <code>HEAD</code></em></p>
<p>It's time to create a new commit with the state of the original "Commit 2". This time you need to stage <code>2.txt</code> again before creating it:</p>
<pre><code class="lang-bash">git add 2.txt
git commit -m <span class="hljs-string">"Commit 2.2"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_2_2.png" alt="Creating &quot;Commit 2.2&quot;" width="600" height="400" loading="lazy">
<em>Creating "Commit 2.2"</em></p>
<p>Similarly to "Commit 2.1", I "name" this commit "Commit 2.2" to differentiate it from the original "Commit 2" or "Commit 2.1" - these commits result in the same state as the original "Commit 2", but they are different commit objects.</p>
<h4 id="heading-git-reset-hard"><code>git reset --hard</code></h4>
<p>Go on, undo even more!</p>
<p>This time, use the <code>--hard</code> switch, and run:</p>
<pre><code class="lang-bash">git reset --hard HEAD~1
</code></pre>
<p>Again, Git starts with the <code>--soft</code> stage, setting whatever <code>HEAD</code> is pointing to (<code>main</code>), to <code>HEAD~1</code> ("Commit 1").</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_hard_1-1.png" alt="The first step of  is the same as " width="600" height="400" loading="lazy">
<em>The first step of <code>git reset --hard</code> is the same as <code>git reset --soft</code></em></p>
<p>Next, moving on to the <code>--mixed</code> stage, matching the index with <code>HEAD</code>. That is, Git undoes the staging of <code>2.txt</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_hard_2-1.png" alt="The second step of  is the same as " width="600" height="400" loading="lazy">
<em>The second step of <code>git reset --hard</code> is the same as <code>git reset --mixed</code></em></p>
<p>Next comes the <code>--hard</code> step, where Git goes even further and matches the working dir with the stage of the index. In this case, it means removing <code>2.txt</code> also from the working dir.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_hard_3.png" alt="The third step of  matches the state of the working dir with that of the index" width="600" height="400" loading="lazy">
<em>The third step of <code>git reset --hard</code> matches the state of the working dir with that of the index</em></p>
<p>So to introduce a change to Git, you have three steps: you change the working dir, the index, or the staging area, and then you commit a new snapshot with those changes. To undo these changes:</p>
<ul>
<li>If we use <code>git reset --soft</code>, we undo the commit step.</li>
<li>If we use <code>git reset --mixed</code>, we also undo the staging step.</li>
<li>If we use <code>git reset --hard</code>, we undo the changes to the working dir.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_switches.png" alt="The three main switches of " width="600" height="400" loading="lazy">
<em>The three main switches of <code>git reset</code></em></p>
<h3 id="heading-real-life-scenarios">Real-Life Scenarios</h3>
<h4 id="heading-scenario-1">Scenario #1</h4>
<p>So in a real-life scenario, write "I love Git" into a file (<code>love.txt</code>), as we all love Git 😍. Go ahead, stage and commit this as well:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> I love Git &gt; love.txt
git add love.txt
git commit -m <span class="hljs-string">"Commit 2.3"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_2_3.png" alt="Creating &quot;Commit 2.3&quot;" width="600" height="400" loading="lazy">
<em>Creating "Commit 2.3"</em></p>
<p>Also, save a tag so that you can get back to this commit later if needed:</p>
<pre><code class="lang-bash">git tag scenario-1
</code></pre>
<p>Oh, oops!</p>
<p>Actually, I didn't want you to commit it.</p>
<p>What I actually wanted you to do is write some more love words in this file before committing it.</p>
<p>What can you do?</p>
<p>Well, one way to overcome this would be to use <code>git reset --mixed HEAD~1</code>, effectively undoing both the committing and the staging actions you took:</p>
<pre><code class="lang-bash">git reset --mixed HEAD~1
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/reset_commit_2_3.png" alt="Undoing the staging and committing steps" width="600" height="400" loading="lazy">
<em>Undoing the staging and committing steps</em></p>
<p>So <code>main</code> points to "Commit 1" again, and <code>love.txt</code> is no longer a part of the index. However, the file remains in the working dir. You can now add more content to it:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> and Gitting Things Done &gt;&gt; love.txt
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/adding_love_lyrics.png" alt="Adding more love lyrics" width="600" height="400" loading="lazy">
<em>Adding more love lyrics</em></p>
<p>Stage and commit your file:</p>
<pre><code class="lang-bash">git add love.txt
git commit -m <span class="hljs-string">"Commit 2.4"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_2_4.png" alt="Introducing &quot;Commit 2.4&quot;" width="600" height="400" loading="lazy">
<em>Introducing "Commit 2.4"</em></p>
<p>Well done!</p>
<p>You got this clear, nice history of "Commit 2.4" pointing to "Commit 1".</p>
<p>You now have a new tool in your toolbox, <code>git reset</code>.</p>
<p>This tool is super, super useful, and you can accomplish almost anything with it. It's not always the most convenient tool to use, but it's capable of solving almost any rewriting-history scenario if you use it carefully.</p>
<p>For beginners, I recommend using only <code>git reset</code> for almost any time you want to undo in Git. Once you feel comfortable with it, move on to other tools.</p>
<h4 id="heading-scenario-2">Scenario #2</h4>
<p>Let us consider another case.</p>
<p>Create a new file called <code>new.txt</code>; stage and commit:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> this is a new file &gt; new.txt
git add new.txt
git commit -m <span class="hljs-string">"Commit 3"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_3.png" alt="Creating  and &quot;Commit 3&quot;" width="600" height="400" loading="lazy">
<em>Creating <code>new.txt</code> and "Commit 3"</em></p>
<p>(Note: In the drawing I omitted the files from the repository to avoid clutter. Commit 3 includes <code>1.txt</code>, <code>love.txt</code> and <code>new.txt</code> at this stage).</p>
<p>Oops. Actually, that's a mistake. You were on <code>main</code>, and I wanted you to create this commit on a feature branch. My bad 😇</p>
<p>There are two most important tools I want you to take from this chapter. The <em>second</em> is <code>git reset</code>. The first and by far more important one is to whiteboard the current state versus the state you want to be in.</p>
<p>For this scenario, the current state and the desired state look like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/scenario_2.png" alt="Scenario #2: current-vs-desired states" width="600" height="400" loading="lazy">
<em>Scenario #2: current-vs-desired states</em></p>
<p>(Note: In following diagrams, I will refer to the current state as the "original" state - before starting the process of rewriting history.)</p>
<p>You will notice three changes:</p>
<ol>
<li><code>main</code> points to "Commit 3" (the blue one) in the current state, but to "Commit 2.4" in the desired state.</li>
<li><code>feature_branch</code> doesn't exist in the current state, yet it exists and points to "Commit 3" in the desired state.</li>
<li><code>HEAD</code> points to <code>main</code> in the current state, and to <code>feature_branch</code> in the desired state.</li>
</ol>
<p>If you can draw this and you know how to use <code>git reset</code>, you can definitely get yourself out of this situation.</p>
<p>So again, the most important thing is to take a breath and draw this out.</p>
<p>Observing the drawing above, how do you get from the current state to the desired one?</p>
<p>There are a few different ways of course, but I will present one option only for each scenario. Feel free to play around with other options as well.</p>
<p>You can start by using <code>git reset --soft HEAD~1</code>. This would set <code>main</code> to point to the previous commit, "Commit 2.4":</p>
<pre><code class="lang-bash">git reset --soft HEAD~1
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/scenario_2_1.png" alt="Changing ; &quot;Commit 3 is still there, just not reachable from " width="600" height="400" loading="lazy">
<em>Changing <code>main</code>: "Commit 3" is still there, just not reachable from <code>HEAD</code></em></p>
<p>Peeking at the current-vs-desired diagram again, you can see that you need a new branch, right? You can use <code>git switch -c feature_branch</code> for it, or <code>git checkout -b feature_branch</code> (which does the same thing):</p>
<pre><code class="lang-bash">git switch -c feature_branch
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/scenario_2_2.png" alt="Creating  branch" width="600" height="400" loading="lazy">
_Creating <code>feature_branch</code> branch_</p>
<p>This command also updates <code>HEAD</code> to point to the new branch.</p>
<p>Since you used <code>git reset --soft</code>, you didn't change the index, so it currently has exactly the state you want to commit - how convenient! You can simply commit to <code>feature_branch</code>:</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"Commit 3.1"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_3_1.png" alt="Committing to  branch" width="600" height="400" loading="lazy">
_Committing to <code>feature_branch</code> branch_</p>
<p>And you got to the desired state.</p>
<h4 id="heading-scenario-3">Scenario #3</h4>
<p>Ready to apply your knowledge to additional cases?</p>
<p>Still on <code>feature_branch</code>, add some changes to <code>love.txt</code>, and create a new file called <code>cool.txt</code>. Stage them and commit:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> Some changes &gt;&gt; love.txt
<span class="hljs-built_in">echo</span> Git is cool &gt; cool.txt
git add love.txt
git add cool.txt
git commit -m <span class="hljs-string">"Commit 4"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_4.png" alt="The history, as well as the state of the index and the working dir after creating &quot;Commit 4&quot;" width="600" height="400" loading="lazy">
<em>The history, as well as the state of the index and the working dir after creating "Commit 4"</em></p>
<p>Oh, oops, actually I wanted you to create two <em>separate</em> commits, one with each change...</p>
<p>Want to try this one yourself (before reading on)?</p>
<p>You can undo the committing and staging steps:</p>
<pre><code class="lang-bash">git reset --mixed HEAD~1
</code></pre>
<p>Following this command, the index no longer includes those two changes, but they're both still in your file system:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/reset_commit_4.png" alt="Resulting state after using " width="600" height="400" loading="lazy">
<em>Resulting state after using <code>git reset --mixed HEAD~1</code></em></p>
<p>So now, if you only stage <code>love.txt</code>, you can commit it separately:</p>
<pre><code class="lang-bash">git add love.txt
git commit -m <span class="hljs-string">"Love"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_love.png" alt="Resulting state after committing the changes to " width="600" height="400" loading="lazy">
<em>Resulting state after committing the changes to <code>love.txt</code></em></p>
<p>Then, do the same for <code>cool.txt</code>:</p>
<pre><code class="lang-bash">git add cool.txt
git commit -m <span class="hljs-string">"Cool"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_separately.png" alt="Committing separately" width="600" height="400" loading="lazy">
<em>Committing separately</em></p>
<p>Nice!</p>
<h4 id="heading-scenario-4">Scenario #4</h4>
<p>To clear up the state, switch to <code>main</code> and use <code>reset --hard</code> to make it point to "Commit 3.1", while setting the index and the working dir to the state of "Commit 3.1":</p>
<pre><code class="lang-bash">git checkout main
git reset --hard &lt;SHA_OF_COMMIT_3_1&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/reset_main_commit_3_1.png" alt="Resetting  to &quot;Commit 3.1&quot;" width="600" height="400" loading="lazy">
<em>Resetting <code>main</code> to "Commit 3.1"</em></p>
<p>Create another file (<code>another.txt</code>) with some text, and add some text to <code>love.txt</code>. Stage both changes, and commit them:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> Another file &gt; another.txt
<span class="hljs-built_in">echo</span> More love &gt;&gt; love.txt
git add another.txt
git add love.txt
git commit -m <span class="hljs-string">"Commit 4.1"</span>
</code></pre>
<p>This should be the result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_more_changes.png" alt="A new commit" width="600" height="400" loading="lazy">
<em>A new commit</em></p>
<p>Oops...</p>
<p>So this time, I wanted it to be on another branch, but not a new branch, rather - an already-existing branch.</p>
<p>So what can you do?</p>
<p>I'll give you a hint. The answer is really short and really easy. What do we do first?</p>
<p>No, not <code>reset</code>. We <em>draw</em>. That's the first thing to do, as it would make everything else so much easier. So this is the current state:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/scenario_4.png" alt="The new commit on  appears blue" width="600" height="400" loading="lazy">
<em>The new commit on <code>main</code> appears blue</em></p>
<p>And the desired state?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/scenario_4_1-1.png" alt="We want the &quot;blue&quot; commit to be on another, , branch\label{fig-scenario-4-1}" width="600" height="400" loading="lazy">
<em>We want the "blue" commit to be on another, <code>existing</code>, branch</em></p>
<p>How do you get from the current state to the desired state, what would be easiest?</p>
<p>One way would be to use <code>git reset</code> as you did before, but there is another way that I would like you to try.</p>
<p>Note that the following commands indeed assume the branch <code>existing</code> exists on your repository, yet you haven't created it earlier. To match a state where this branch actually exists, you can use the following commands:</p>
<pre><code class="lang-bash">git checkout &lt;SHA_OF_COMMIT_1&gt;
git checkout -b existing
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Hello"</span> &gt; x.txt
git add x.txt
git commit -m <span class="hljs-string">"Commit X"</span>
git checkout &lt;SHA_OF_COMMIT_3_1&gt; -- love.txt
git commit -m <span class="hljs-string">"Commit Y"</span>
git checkout main
</code></pre>
<p>(The command <code>git checkout &lt;SHA_OF_COMMIT_3_1&gt; -- love.txt</code> copies the contents of <code>love.txt</code> from "Commit 3.1" to the index and the working dir, so that you can commit it on the <code>existing</code> branch. We need the state of <code>love.txt</code> on "Commit Y" to be the same as of "Commit 3.1" to avoid conflicts.)</p>
<p>Now your history should match the one shown in the picture with the caption "We want the "blue" commit to be on another, <code>existing</code>, branch".</p>
<p>First, move <code>HEAD</code> to point to existing branch:</p>
<pre><code class="lang-bash">git switch existing
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/switch_existing.png" alt="Switch to the  branch" width="600" height="400" loading="lazy">
<em>Switch to the <code>existing</code> branch</em></p>
<p>Intuitively, what you want to do is take the changes introduced in "Commit 4.1", and apply these changes ("copy-paste") on top of <code>existing</code> branch. And Git has a tool just for that.</p>
<p>To ask Git to take the changes introduced between a commit and its parent commit and just apply these changes on the active branch, you can use <code>git cherry-pick</code>, a command we introduced in <a class="post-section-overview" href="#heading-chapter-8-understanding-git-rebase">chapter 8</a>. This command takes the changes introduced in the specified revision and applies them to the state of the active commit. Run:</p>
<pre><code class="lang-bash">git cherry-pick &lt;SHA_OF_COMMIT_4_1&gt;
</code></pre>
<p>You can specify the SHA-1 identifier of the desired commit, but you can also use <code>git cherry-pick main</code>, as the commit whose changes you are applying is the one <code>main</code> is pointing to.</p>
<p><code>git cherry-pick</code> also creates a new commit object, and updates the active branch to point to this new object, so the resulting state would be:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/cherry_pick.png" alt="The result after using " width="600" height="400" loading="lazy">
<em>The result after using <code>git cherry-pick</code></em></p>
<p>I mark the commit as "Commit 4.2" since it has a different timestamp, parent and SHA-1 value than "Commit 4.1", though the changes it introduces are the same.</p>
<p>You made good progress - the desired commit is now on the <code>existing</code> branch! But we don't want these changes to exist on <code>main</code> branch. <code>git cherry-pick</code> only applied the changes to the existing branch. How can you remove them from <code>main</code>?</p>
<p>One way would be to switch back to <code>main</code>, and then <code>reset</code> it:</p>
<pre><code class="lang-bash">git switch main
git reset --hard HEAD~1
</code></pre>
<p>And the result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/reset_cherry_pick.png" alt="The resulting state after resetting " width="600" height="400" loading="lazy">
<em>The resulting state after resetting <code>main</code></em></p>
<p>You did it!</p>
<p>Note that <code>git cherry-pick</code> actually computes the difference between the specified commit and its parent, and then applies the difference to the active commit. This means that sometimes, Git won't be able to apply those changes due to a conflict.</p>
<p>Also, note that you can ask Git to <code>cherry-pick</code> the changes introduced in any commit, not only commits referenced by a branch.</p>
<h3 id="heading-recap-git-reset">Recap - Git Reset</h3>
<p>In this chapter, we learned how <code>git reset</code> operates, and clarified its three main modes of operation:</p>
<ul>
<li><code>git reset --soft &lt;commit&gt;</code>, which changes whatever <code>HEAD</code> is pointing to - to <code>&lt;commit&gt;</code>.</li>
<li><code>git reset --mixed &lt;commit&gt;</code>, which goes through the <code>--soft</code> stage, and also sets the state of the index to match that of <code>HEAD</code>.</li>
<li><code>git reset --hard &lt;commit&gt;</code>, which goes through the <code>--soft</code> and <code>--mixed</code> stages, and then sets the state of the working dir to match that of the index.</li>
</ul>
<p>You then applied your knowledge about <code>git reset</code> to solve some real-life issues that arise when using Git.</p>
<p>By understanding the way Git operates, and by whiteboarding the current state versus the desired state, you can confidently tackle all kinds of scenarios.</p>
<p>In the future chapters, we will cover additional Git commands and how they can help us solve all kinds of undesired situations.</p>
<h2 id="heading-chapter-10-additional-tools-for-undoing-changes">Chapter 10 - Additional Tools for Undoing Changes</h2>
<p>In the previous chapter, you met <code>git reset</code>. Indeed, <code>git reset</code> is a super powerful tool, and I highly recommend to use it until you feel completely comfortable with it.</p>
<p>Yet, <code>git reset</code> is not the only tool at our disposal. Some of the times, it is not the most convenient tool to use. In others, it's just not enough. This short chapter touches a few tools that are helpful for undoing changes in Git.</p>
<h3 id="heading-git-commit-amend"><code>git commit --amend</code></h3>
<p>Consider <a target="_blank" href="https://www.freecodecamp.org/news/p/f7b355ea-3f22-4613-8218-e95c67779d9f/scenario-1">Scenario #1</a> from the previous chapter again. As a reminder, you wrote "I love Git" into a file (<code>love.txt</code>), staged and committed this file:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/image-52.png" alt="Image" width="600" height="400" loading="lazy">
<em>The state after creating "Commit 2.3"</em></p>
<p>And then I realized I didn't want you to commit it at that state, but rather - write some more love words in this file before committing it.</p>
<p>To match this state, simply checkout the tag you created, which points to "Commit 2.3":</p>
<pre><code class="lang-bash">git checkout scenario-1
</code></pre>
<p>In the previous chapter, when we introduced <code>git reset</code>, you solved this issue by using <code>git reset --mixed HEAD~1</code>, effectively undoing both the committing and the staging actions you took.</p>
<p>Now I would like you to consider another approach. Keep working at the state of the last introduced commit ("Commit 2.3", referenced by the tag "scenario-1"), and make the changes you want:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> And I love this book &gt;&gt; love.txt
</code></pre>
<p>Add this change to the index:</p>
<pre><code class="lang-bash">git add love.txt
</code></pre>
<p>Now, you can use <code>git commit</code> with the <code>--amend</code> switch, which tells it to override the commit <code>HEAD</code> is pointing to. Actually, it will create another, new commit, pointing to <code>HEAD~1</code> ("Commit 1" in our example), and make <code>HEAD</code> point to this newly created commit. By providing the <code>-m</code> argument you can specify a new commit message as well:</p>
<pre><code class="lang-bash">git commit --amend -m <span class="hljs-string">"Commit 2.4"</span>
</code></pre>
<p>After running this command, <code>HEAD</code> points to <code>main</code>, which points to "Commit 2.4", which in turn points to "Commit 1". The previous "Commit 2.3" is no longer reachable from the history.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_amend-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>The state after using <code>git commit --amend</code> (Commit "2.3" is unreachable and thus not included in the drawing)</em></p>
<p>This tool is useful when you want to quickly override the last commit you created. Indeed, you could use <code>git reset</code> to accomplish the same thing, but you can view <code>git commit --amend</code> as a more convenient shortcut.</p>
<h3 id="heading-git-revert"><code>git revert</code></h3>
<p>Okay, so another day, another problem.</p>
<p>Add the following text to <code>love.txt</code>, stage and commit as follows:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> This is more tezt &gt;&gt; love.txt
git add love.txt
git commit -m <span class="hljs-string">"Commit 3"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_revert_1-1.png" alt="Committing &quot;More changes&quot;" width="600" height="400" loading="lazy">
<em>The state after committing "Commit 3"</em></p>
<p>And push it to the remote server:</p>
<pre><code class="lang-bash">git push origin HEAD
</code></pre>
<p>Um, oops 😓…</p>
<p>I just noticed something. I had a typo there. I wrote "This is more tezt" instead of "This is more text". Whoops. So what's the big problem now? I <code>push</code>ed, which means that someone else might have already <code>pull</code>ed those changes.</p>
<p>If I override those changes by using <code>git reset</code>, we will have different histories, and all hell might break loose. You can rewrite your own copy of the repo as much as you like until you <code>push</code> it.</p>
<p>Once you <code>push</code> the change, you need to be certain no one else has fetched those changes if you are going to rewrite history.</p>
<p>Alternatively, you can use another tool called <code>git revert</code>. This command takes the commit you're providing it with and computes the diff from its parent commit, just like <code>git cherry-pick</code>, but this time, it computes the <em>reverse</em> changes. That is, if in the specified commit you added a line, the reverse would delete the line, and vice versa. </p>
<p>In our case we are reverting "Commit 3", so the reverse would be to delete the line "This is more tezt" from <code>love.txt</code>. Since "Commit 3" is referenced by <code>main</code> and <code>HEAD</code>, we can use any of these named references in this command:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_revert_2.png" alt="Using  to undo the changes" width="600" height="400" loading="lazy">
<em>Using <code>git revert</code> to undo the changes</em></p>
<p><code>git revert</code> created a new commit object, which means it's an addition to the history. By using <code>git revert</code>, you didn't rewrite history. You admitted your past mistake, and this commit is an acknowledgment that you made a mistake and now you fixed it.</p>
<p>Some would say it's the more mature way. Some would say it's not as clean a history as you would get if you used <code>git reset</code> to rewrite the previous commit. But this is a way to avoid rewriting history.</p>
<p>You can now fix the typo and commit again:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> This is more text &gt;&gt; love.txt
git add love.txt
git commit -m <span class="hljs-string">"Commit 3.1"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_revert_3.png" alt="Redoing the changes" width="600" height="400" loading="lazy">
<em>The resulting state after redoing the changes</em></p>
<p>You can use <code>git revert</code> to revert a commit other than <code>HEAD</code>. Say that you want to reverse the parent of <code>HEAD</code>, you can use:</p>
<pre><code class="lang-bash">git revert HEAD~1
</code></pre>
<p>Or you could provide the SHA-1 of the commit to revert.</p>
<p>Notice that since Git will apply the reverse patch of the previous patch - this operation might fail, as the patch may no longer apply and you might get a conflict.</p>
<h3 id="heading-git-rebase-as-a-tool-for-undoing-things">Git Rebase as a Tool for Undoing Things</h3>
<p>In <a class="post-section-overview" href="#heading-chapter-8-understanding-git-rebase">chapter 8</a>, you learned about Git rebase. We then considered it mainly as a tool to combine changes introduced in different branches. Yet, as long as you haven't <code>push</code>ed your changes, using <code>rebase</code> on your own branch can be a very convenient way to rearrange your commit history.</p>
<p>For that, you would usually <a class="post-section-overview" href="#heading-how-to-rebase-on-a-single-branch">rebase on a single branch</a>, and use interactive rebase. Consider again this example covered in <a class="post-section-overview" href="#heading-chapter-8-understanding-git-rebase">chapter 8</a>, where I worked from <code>feature_branch_2</code>, and specifically edited the file <code>code.py</code>. I started by changing all strings to be wrapped by double quotes rather than single quotes:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_4-1.png" alt="Changing  into  in " width="600" height="400" loading="lazy">
<em>Changing <code>'</code> into <code>"</code> in <code>code.py</code></em></p>
<p>Then, I staged and committed:</p>
<pre><code class="lang-bash">git add code.py
git commit -m <span class="hljs-string">"Commit 17"</span>
</code></pre>
<p>I then decided to add a new function at the beginning of the file:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_5-1.png" alt="Adding the function " width="600" height="400" loading="lazy">
_Adding the function <code>another_feature</code>_</p>
<p>Again, I staged and committed:</p>
<pre><code class="lang-bash">git add code.py
git commit -m <span class="hljs-string">"Commit 18"</span>
</code></pre>
<p>And now I realized I actually forgot to change the single quotes to double quotes wrapping the <code>__main__</code> (as you might have noticed), so I did that too:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_6-1.png" alt="Changing  into " width="600" height="400" loading="lazy">
<em>Changing <code>'__main__'</code> into <code>"__main__"</code></em></p>
<p>Of course, I staged and committed this change:</p>
<pre><code class="lang-bash">git add code.py
git commit -m <span class="hljs-string">"Commit 19"</span>
</code></pre>
<p>Now, consider the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_19-1.png" alt="The commit history after introducing &quot;Commit 19&quot;" width="600" height="400" loading="lazy">
<em>The commit history after introducing "Commit 19"</em></p>
<p>As explained in <a class="post-section-overview" href="#heading-chapter-8-understanding-git-rebase">chapter 8</a>, I got to a state with two commits that are related to one another, "Commit 17" and "Commit 19" (turning <code>'</code>s into <code>"</code>s), but they are split by the unrelated "Commit 18" (where I added a new function).</p>
<p>This is a classic case where <code>git rebase</code> would come in handy, to undo the local changes before <code>push</code>ing a clean history.</p>
<p>Intuitively, I want to edit the history here:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/plan_edit_commits_17_18-1.png" alt="These are the commits I want to edit" width="600" height="400" loading="lazy">
<em>These are the commits I want to edit</em></p>
<p>I can <code>rebase</code> the history from "Commit 17" to "Commit 19", on top of "Commit 15". To do that:</p>
<pre><code class="lang-bash">git rebase --interactive --onto &lt;SHA_OF_COMMIT_15&gt; &lt;SHA_OF_COMMIT_15&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_4-1.png" alt="Using  on a single branch" width="600" height="400" loading="lazy">
<em>Using <code>rebase --onto</code> on a single branch</em></p>
<p>This results in the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_4-1.png" alt="Interactive rebase" width="600" height="400" loading="lazy">
<em>Interactive rebase</em></p>
<p>So what would I do? I want to put "Commit 19" before "Commit 18", so it comes right after "Commit 17". I can go further and <code>squash</code> them together, like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_5-1.png" alt="Interactive rebase - changing the order of commit and squashing" width="600" height="400" loading="lazy">
<em>Interactive rebase - changing the order of commit and squashing</em></p>
<p>Now when I get prompted for a commit message, I can provide the message "Commit 17+19":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_6-1.png" alt="Providing a commit message" width="600" height="400" loading="lazy">
<em>Providing a commit message</em></p>
<p>And now, see our beautiful history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_5-1.png" alt="The resulting history" width="600" height="400" loading="lazy">
<em>The resulting history</em></p>
<p>The syntax used above, <code>git rebase --interactive --onto &lt;COMMIT X&gt; &lt;COMMIT X&gt;</code> would be the most commonly used syntax by those who use <code>rebase</code> regularly. The state of mind these developers usually have is to create atomic commits while working, all the time, without being scared to change them later. Then, before <code>push</code>ing their changes, they would <code>rebase</code> the entire set of changes since the last <code>push</code>, and rearrange it so the history becomes coherent.</p>
<h3 id="heading-git-reflog"><code>git reflog</code></h3>
<p>Time to consider a more startling case.</p>
<p>Go back to "Commit 2.4":</p>
<pre><code class="lang-bash">git reset --hard &lt;SHA_OF_COMMIT_2_4&gt;
</code></pre>
<p>Get some work done, write some code, and add it to <code>love.txt</code>. Stage this change, and commit it:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> lots of work &gt;&gt; love.txt
git add love.txt
git commit -m <span class="hljs-string">"Commit 3.2"</span>
</code></pre>
<p>(I'm using "Commit 3.2" to indicate that this is not the same commit as "Commit 3" we used when explaining <code>git revert</code>.)</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/reflog_commit_3-1.png" alt="Another commit" width="600" height="400" loading="lazy">
<em>Another commit - "Commit 3.2"</em></p>
<p>I did the same on my machine, and I used the <code>Up</code> arrow key on my keyboard to scroll back to previous commands, and then I hit <code>Enter</code>, and… Wow.</p>
<p>Whoops.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/reflog_commit_3_reset.png" alt="Did I just ?" width="600" height="400" loading="lazy">
<em>Did I just <code>git reset -- hard</code>?</em></p>
<p>Did I just use <code>git reset --hard</code>? 😨</p>
<p>What actually happened? As you learned in the <a class="post-section-overview" href="#heading-chapter-9-git-reset">previous chapter</a>, Git moved the pointer to <code>HEAD~1</code>, so the last commit, with all of my precious work, is not reachable from the current history. Git also removed all the changes from the staging area, and then matched the working dir to the state of the staging area.</p>
<p>That is, everything matches this state where my work is… gone.</p>
<p>Freak out time. Freaking out.</p>
<p>But, really, is there a reason to freak out? Not really… We're relaxed people. What do we do? Well, intuitively, is the commit really, really gone?</p>
<p>No. Why not? It still exists inside the internal database of Git.</p>
<p>If I only knew where that is, I would know the <code>SHA-1</code> value that identifies this commit, and we could restore it. I could even undo the undoing, and <code>reset</code> back to this commit.</p>
<p>Actually, the only thing I really need here is the <code>SHA-1</code> of the "deleted" commit.</p>
<p>Now the question is, how do I find it? Would <code>git log</code> be useful?</p>
<p>Well, not really. <code>git log</code> would go to <code>HEAD</code>, which points to <code>main</code>, which points to the parent commit of the commit we are looking for. Then, <code>git log</code> would trace back through the parent chain, which does not include the commit with my precious work.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/reflog_git_log.png" alt=" doesn't help in this case" width="600" height="400" loading="lazy">
<em><code>git log</code> doesn't help in this case</em></p>
<p>Thankfully, the very smart people who created Git also created a backup plan for us, and that is called the <code>reflog</code>.</p>
<p>While you work with Git, whenever you change <code>HEAD</code>, which you can do by using <code>git reset</code>, but also other commands like <code>git switch</code> or <code>git checkout</code>, Git adds an entry to the <code>reflog</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reflog.png" alt=" shows us where  was" width="600" height="400" loading="lazy">
<em><code>git reflog</code> shows us where <code>HEAD</code> was</em></p>
<p>We found our commit! It's the one starting with <code>0fb929e</code>.</p>
<p>We can also relate to it by its "nickname" - <code>HEAD@{1}</code>. Similar to the way Git uses <code>HEAD~1</code> to get to the first parent of <code>HEAD</code>, and <code>HEAD~2</code> to refer to the second parent of <code>HEAD</code> and so on, Git uses <code>HEAD@{1}</code> to refer to the first <em>reflog</em> parent of <code>HEAD</code>, that is, where <code>HEAD</code> pointed to in the previous step.</p>
<p>We can also ask <code>git rev-parse</code> to show us its value:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/reflog_revparse.png" alt="Using " width="600" height="400" loading="lazy">
<em>Using <code>git rev-parse HEAD@{1}</code></em></p>
<p>Note: In case you are using Windows, you may need to wrap it with quotation marks - like so:</p>
<pre><code class="lang-bash">git rev-parse <span class="hljs-string">"HEAD@{1}"</span>
</code></pre>
<p>Another way to view the <code>reflog</code> is by using <code>git log -g</code>, which asks <code>git log</code> to actually consider the <code>reflog</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_g.png" alt="The output of " width="600" height="400" loading="lazy">
<em>The output of <code>git log -g</code></em></p>
<p>You can see in the output of <code>git log -g</code> that the <code>reflog</code>'s entry <code>HEAD@{0}</code>, just like <code>HEAD</code>, points to <code>main</code>, which points to "Commit 2". But the parent of that entry in the <code>reflog</code> points to "Commit 3".</p>
<p>So to get back to "Commit 3", you can just use <code>git reset --hard HEAD@{1}</code> (or the <code>SHA-1</code> value of "Commit 3"):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reflog_reset.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git reset --hard HEAD@{1}</code></em></p>
<p>And now, if you <code>git log</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_2.png" alt="Our history is back!!!" width="600" height="400" loading="lazy">
<em>Our history is back!!!</em></p>
<p>We saved the day!</p>
<p>What would happen if I used this command again? And ran <code>git reset --hard HEAD@{1}</code>?</p>
<p>Git would set <code>HEAD</code> to where <code>HEAD</code> was pointing before the last <code>reset</code>, meaning to "Commit 2". We can keep going all day:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_again.png" alt=" again" width="600" height="400" loading="lazy">
<em><code>git reset --hard</code> again</em></p>
<h3 id="heading-recap-additional-tools-for-undoing-changes">Recap - Additional Tools for Undoing Changes</h3>
<p>In the previous chapter, you learned how to use <code>git reset</code> to undo changes.</p>
<p>In this chapter, you extended your toolbox for undoing changes in Git with a few new commands:</p>
<ul>
<li><code>git commit --amend</code> - which "overrides" the last commit with the stage of the index. Mostly useful when you just committed something and want to modify that last commit.</li>
<li><code>git revert</code> - which creates a new commit, that reverts a past commit by adding a new commit to the history with the reversed changes. Useful especially when the "faulty" commit has already been pushed to the remote.</li>
<li><code>git rebase</code> - which you already know from <a class="post-section-overview" href="#heading-chapter-8-understanding-git-rebase">chapter 8</a>, and is useful for rewriting the history of multiple commits, especially before pushing them.</li>
<li><code>git reflog</code> (and <code>git log -g</code>) - which tracks all changes to <code>HEAD</code>, so you might find the SHA-1 value of a commit you need to get back to.</li>
</ul>
<p>The most important tool, even more important than the tools I just listed, is to whiteboard the current situation vs the desired one. Trust me on this, it will make every situation seem less daunting and the solution more clear.</p>
<p>There are additional tools that allow you to reverse changes in Git (I will provide links in the <a class="post-section-overview" href="#heading-additional-references-by-part">appendix</a>), but the collection of tools covered here should prepare you to tackle any challenge with confidence.</p>
<h2 id="heading-chapter-11-exercises">Chapter 11 - Exercises</h2>
<p>This chapter includes a few exercises to deepen your understanding of the tools you learned in Part 3. The full version of this book also includes detailed solutions for each.</p>
<p>The exercises are found on this repository:</p>
<p><a target="_blank" href="https://github.com/Omerr/undo-exercises.git">https://github.com/Omerr/undo-exercises.git</a></p>
<p>Each exercise exists on a branch with the name <code>exercise_XX</code>, so Exercise 1 is found on branch <code>exercise_01</code>, Exercise 2 is found on branch <code>exercise_02</code> and so on.</p>
<p>Note: As explained in previous chapters, if you work with commits that can be found on a remote server (which you are in this case, as you are using my repository "undo-exercises"), you should probably use <code>git revert</code> instead of <code>git reset</code>. Similar to <code>git rebase</code>, the command <code>git reset</code> also rewrites history - and thus you should refrain from using it on commits that others may have relied on. </p>
<p>For the purposes of these exercises, you can assume no one else has cloned or pulled code from the remote repository. Just remember - in real life, you should probably use <code>git revert</code> instead of commands that rewrite history in such cases.</p>
<h3 id="heading-exercise-1">Exercise 1</h3>
<p>On branch <code>exercise_01</code>, consider the file <code>hello.txt</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_01_1.png" alt="The file " width="600" height="400" loading="lazy">
<em>The file <code>hello.txt</code></em></p>
<p>This file includes a typo (in the last character). Find the commit that introduced this typo.</p>
<h4 id="heading-exercise-1a">Exercise (1a)</h4>
<p>Remove this commit from the reachable history using <code>git reset</code> (with the right arguments), fix the typo, and commit again. Consider your history.</p>
<p>Revert to the previous state.</p>
<h4 id="heading-exercise-1b">Exercise (1b)</h4>
<p>Remove the faulty commit using <code>git commit --amend</code>, and get to the same state of the history as in the end of exercise (1a).</p>
<p>Revert to the previous state.</p>
<h4 id="heading-exercise-1c">Exercise (1c)</h4>
<p><code>revert</code> the faulty commit using <code>git revert</code> and fix the typo. Consider your history.</p>
<p>Revert to the previous state.</p>
<h4 id="heading-exercise-1d">Exercise (1d)</h4>
<p>Using <code>git rebase</code>, get to the same state as in the end of exercise (1a).</p>
<h3 id="heading-exercise-2">Exercise 2</h3>
<p>Switch to <code>exercise_02</code>, and consider the contents of <code>exercise_02.txt</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_02_1.png" alt="The contents of " width="600" height="400" loading="lazy">
_The contents of <code>exercise_02.txt</code>_</p>
<p>A simple file, with one character at each line.</p>
<p>Consider the history (using <code>git lol</code>):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_02_2.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git lol</code></em></p>
<p>Oh my. Each character was introduced in a separate commit. That doesn't make any sense!</p>
<p>Use the tools you've acquired to create a history where the creation of <code>exercise_02.txt</code> is all done in a single commit.</p>
<h3 id="heading-exercise-3">Exercise 3</h3>
<p>Consider the history on branch <code>exercise_03</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_03_1.png" alt="The history on " width="600" height="400" loading="lazy">
_The history on <code>exercise_03</code>_</p>
<p>This seems like a mess. You will notice that:</p>
<ul>
<li>The order is skewed. We need "Commit 1" to be the earliest commit on this branch, and have "Initial Commit" as its parent, followed by "Commit 2" and so on.</li>
<li>We shouldn't have "Commit 2a" and "Commit 2b", or "Commit 4a" and "Commit 4b" - these two pairs need to be combined into a single commit each - "Commit 2" and "Commit 4".</li>
<li>There is a typo on the commit message of "Commit 1", it should not have 3 <code>m</code>s.</li>
</ul>
<p>Fix these issues, but rely on the changes of each original commit. The resulting history should look like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_03_2.png" alt="The desired history" width="600" height="400" loading="lazy">
<em>The desired history</em></p>
<h3 id="heading-exercise-4">Exercise 4</h3>
<p>This exercise actually consists of three branches: <code>exercise_04</code>, <code>exercise_04_a</code>, and <code>exercise_04_b</code>.</p>
<p>To see the history of these branches without others, use the following syntax:</p>
<pre><code class="lang-bash">git lol --branches=<span class="hljs-string">"exercise_04*"</span>
</code></pre>
<p>The result is:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_04_1.png" alt="The output of " width="600" height="400" loading="lazy">
_The output of <code>git lol --branches="exercise_04*"</code>_</p>
<p>Your goal is to make <code>exercise_04_b</code> independent of <code>exercise_04_a</code>. That is, get to this history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_04_2.png" alt="The desired history" width="600" height="400" loading="lazy">
<em>The desired history</em></p>
<p><strong>Good luck!</strong></p>
<h1 id="heading-part-4-amazing-and-useful-git-tools">Part 4 - Amazing and Useful Git Tools</h1>
<p>Git has lots of commands, and these commands have so many options and arguments. I could try to cover them all (though they do change over time), but I don't see a point in that. You should probably know a subset of these commands really well, those that you use regularly. Then, you can always search for a specific command to perform a task at hand.</p>
<p>This part relies on the basics you acquired in the previous parts, and covers specific commands and options that you may find useful. Given your understanding of how Git works, having these small tools can make you a real pro in Gitting things done.</p>
<h2 id="heading-chapter-12-git-log">Chapter 12 - Git Log</h2>
<p>You used <code>git log</code> many times across different chapters, and you had probably used it many times before reading this book.</p>
<p>Most developers use <code>git log</code>, few use it effectively. In this chapter you will learn useful tweaks for making the most of <code>git log</code>. Once you feel comfortable with the different switches of this command, it will be a game changer in your day to day work with Git.</p>
<p>Thinking about it, <code>git log</code> encompasses the essence of every version control system - that is, to record changes in versions. You record versions so that you can consider the history of your project - perhaps revert or apply specific changes, prefer to switch to a different point in time and test things there. Perhaps you would like to know who contributed a certain piece of code or when they did that.</p>
<p>While <code>git</code> does preserve this information by using commit objects, that also point to their parent commits, and references to commit objects (such as branches or <code>HEAD</code>), this storing of versions is not enough. Without being able to find the relevant commit you would like to consider, or gather the relevant information about it, having this data stored is pretty useless.</p>
<p>You can think of your commit objects as different books that pile up in a huge stack, or in a library, filling long shelves. The information you might need is in these books, but if you don't have an index - a way to know in which book the information you seek lies, or where this book is located within the library - you wouldn't be able to make much use of it. <code>git log</code> is this indexing of your library - it's a way to find the relevant commits and the information about them.</p>
<p>The useful arguments for <code>git log</code> that you will learn in this chapter either format how commits are displayed in the log, or filter specific commits.</p>
<p><code>git lol</code>, an alias which I have used throughout the book, uses some of these switches, as I will demonstrate. Feel free to tweak this alias (or create another from scratch) after reading this chapter.</p>
<p>As in other chapters, the goal is not to provide a complete reference, therefore I will not provide <em>all</em> different switches of <code>git log</code>. I will focus on the switches I believe you will find useful.</p>
<h3 id="heading-filtering-commits">Filtering Commits</h3>
<p>Consider the default output of <code>git log</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_1.png" alt="The output of  without additional switches" width="600" height="400" loading="lazy">
<em>The output of <code>git log</code> without additional switches</em></p>
<p>The log starts from <code>HEAD</code>, and follows the parent chain.</p>
<h4 id="heading-commits-not-reachable-from">Commits (Not) Reachable From...</h4>
<p>When you write <code>git log &lt;revision&gt;</code>, <code>git log</code> will include all entries reachable from <code>&lt;revision&gt;</code>. By "reachable", I refer to reachable by following the parent chain. So running <code>git log</code> without any arguments is equivalent to running <code>git log HEAD</code>.</p>
<p>You can specify multiple revisions for <code>git log</code> - if you write <code>git log branch_1 branch_2</code>, you ask <code>git log</code> to include every commit that is reachable from <code>branch_1</code> or <code>branch_2</code> (or both).</p>
<p><code>git log</code> will <strong>exclude</strong> any commits that are reachable from revisions preceded by a <code>^</code>.</p>
<p>For example, the following command:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> branch_1 ^branch_2
</code></pre>
<p>asks <code>git log</code> to include every commit that is reachable from <code>branch_1</code>, but not those reachable from <code>branch_2</code>.</p>
<p>Consider the history when I use <code>git log feature_branch_1</code> on this repo:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_2-1.png" alt="Image" width="600" height="400" loading="lazy">
_<code>git log feature_branch_1</code>_</p>
<p>The history includes all commits reachable by <code>feature_branch_1</code>. Since this branch "branched off" <code>main</code> (that is, "Commit 12", which <code>main</code> points to, is reachable from the parent chain) - the log also includes the commits reachable from <code>main</code>.</p>
<p>What would happen if I ran this command?</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> feature_branch_1 ^main
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_3.png" alt="Image" width="600" height="400" loading="lazy">
_<code>git log feature_branch_1 ^main</code>_</p>
<p>Indeed, <code>git log</code> outputs only "Commit 13" and "Commit 16", which are reachable from <code>feature_branch_1</code> but not from <code>main</code>.</p>
<h4 id="heading-git-log-all"><code>git log --all</code></h4>
<p>To follow commits that are reachable from any named reference or (any refs in <code>refs/</code>) or <code>HEAD</code>.</p>
<h4 id="heading-by-author">By Author</h4>
<p>If you know you are looking for a commit that a specific person has authored, you can filter these commits by using that user's name or email, like so:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --author=<span class="hljs-string">"Name"</span>
</code></pre>
<p>You can use regular expressions to look for author names that match a specific pattern, for example:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --author=<span class="hljs-string">"John\|Jane"</span>
</code></pre>
<p>will filter commits authored by either John or Jane.</p>
<h4 id="heading-by-date">By Date</h4>
<p>When you know that the change you are looking for has been committed within a specific timeframe, you can use <code>--before</code> or <code>--after</code> to filter commits from that timeframe.</p>
<p>For example, to get all commits introduced after April 12th, 2023 (inclusive), use:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --after=<span class="hljs-string">"2023-04-12"</span>
</code></pre>
<h4 id="heading-by-paths">By Paths</h4>
<p>You can ask <code>git log</code> to only show commits where <em>changes</em> to files in specific paths have been introduced. Notice that this does not mean any commit that points to a tree that includes the files in question, but rather that if we compute the difference between the commit in question and its parent, we would see that at least one of the paths has been modified.</p>
<p>For example, you can use:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --all -- 1.py
</code></pre>
<p>to find all commits that are reachable from any named pointer, or <code>HEAD</code>, and introduce a change to <code>1.py</code>. You can specify multiple paths:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --all -- 1.py 2.py
</code></pre>
<p>The previous command will make <code>git log</code> include reachable commits that introduced a change to <code>1.py</code> or <code>2.py</code> (or both).</p>
<p>You can also use a glob pattern, for example:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> -- *.py
</code></pre>
<p>will include commits reachable from <code>HEAD</code> that include a change to any file in the root directory whose name ends with a <code>.py</code>. To look for any file whose name ends with <code>.py</code>, you can use:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> -- **/*.py
</code></pre>
<h4 id="heading-by-commit-message">By Commit Message</h4>
<p>If you know the commit message (or parts of it) of the commit you are searching, you can use the <code>--grep</code> switch for "git log", for example:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --grep=<span class="hljs-string">"Commit 12"</span>
</code></pre>
<p>yields back the commit with the message "Commit 12".</p>
<h4 id="heading-by-diff-content">By Diff Content</h4>
<p>This one is super useful, and it saved me countless times. By using <code>git log -S</code>, you can search for commits that introduce or remove a particular line of source code. </p>
<p>This comes in handy, for example, when you know you have created something in the repo, but you don't know where it is now. You can't find it anywhere on your filesystem (it's not in <code>HEAD</code>), and you know it must be there - lurking somewhere in this library (bunch of commits) that you have.</p>
<p>Say I remember I wrote a line with the text <code>Git is awesome</code>, but I can't find it now. I could run:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --all -S<span class="hljs-string">"Git is awesome"</span>
</code></pre>
<p>Notice I used <code>--all</code> to avoid restraining myself to commits reachable from <code>HEAD</code>.</p>
<p>You can also search for a regular expression, using <code>-G</code>:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --all -G<span class="hljs-string">"Git .* awesome"</span>
</code></pre>
<h3 id="heading-formatting-log">Formatting Log</h3>
<p>Consider the default output of <code>git log</code> again:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_1-1.png" alt="The output of  without additional switches" width="600" height="400" loading="lazy">
<em>The output of <code>git log</code> without additional switches</em></p>
<p>The log starts from <code>HEAD</code>, and follows the parent chain.</p>
<p>Each log entry begins with a line starting with <code>commit</code> and then the SHA-1 of the commit, perhaps followed by additional pointers that point to this commit.<br>It is then followed by the author, date, and commit message.</p>
<h4 id="heading-oneline"><code>--oneline</code></h4>
<p>The main difficulty with the default output of <code>git log</code> is that it is hard to understand a history with more than a few commits, as you simply don't see them all. </p>
<p>In the output of <code>git log</code> shown before, only four commit objects appeared on my screen. Using <code>git log --oneline</code> provides a more concise view, showing the SHA-1 of the commit, next to its message, and named references if relevant:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_5.png" alt="The output of " width="600" height="400" loading="lazy">
<em>The output of <code>git log --oneline</code></em></p>
<p>If you wish to omit the named references, you can add the <code>--no-decorate</code> switch:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_6.png" alt="The output of " width="600" height="400" loading="lazy">
<em>The output of <code>git log --oneline --no-decorate</code></em></p>
<p>To explicitly ask for <code>git log</code> to show decorations, you can use <code>git log --decorate</code>.</p>
<h4 id="heading-graph"><code>--graph</code></h4>
<p><code>git log --oneline</code> shows a compact representation. That is great when we have a linear history, perhaps on a single branch. But what happens when we have multiple branches, that may diverge from one another?</p>
<p>Consider the output of the following command on my repository:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --oneline feature_branch_1 feature_branch_2
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_7.png" alt="The output of " width="600" height="400" loading="lazy">
_The output of <code>git log --oneline feature_branch_1 feature_branch_2</code>_</p>
<p><code>git log</code> outputs any commit reachable by <code>feature_branch_1</code>, <code>feature_branch_2</code>, or both. But what does the history look like? Did <code>feature_branch_2</code> diverge from <code>feature_branch_1</code>? Or did it diverge from <code>main</code>? It is impossible to tell from this view. </p>
<p>This is where <code>--graph</code> comes in handy, drawing an ASCII graph representing the branch structure of the commit history. If we add this option to the previous command:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_8.png" alt="The output of " width="600" height="400" loading="lazy">
_The output of <code>git log --oneline --graph feature_branch_1 feature_branch_2</code>_</p>
<p>You can actually <em>see</em> that <code>feature_branch_1</code> branched from <code>main</code> (as "Commit 12", <code>main</code>, is the parent of "Commit 13"), and also that <code>feature_branch_2</code> branched from <code>main</code> (as the parent of "Commit 14" is also "Commit 12").</p>
<p>The <code>*</code> symbol tells us which branch a certain commit is "on", so you can know for sure that "Commit 13" is on <code>feature_branch_1</code>, and not <code>feature_branch_2</code>.</p>
<h4 id="heading-prettyformat"><code>--pretty=format</code></h4>
<p>The above result is already very useful! Yet, it lacks a few things. We don't know the author or the time of the commit. These two information details were included in the default output of <code>git log</code> which was very long. Perhaps we can add them in a more compact way?</p>
<p>By using <code>--pretty=format:</code>, you can display the information of each commit in various ways using <code>printf</code>-style placeholders.</p>
<p>In the following command, the <code>%s</code>, <code>%an</code> and <code>%cd</code> placeholders are replaced by the commit's subject (message), author name, and the commit's date, respectively.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --oneline --graph feature_branch_1 feature_branch_2 --pretty=format:<span class="hljs-string">"%s (%an) [%cd]"</span>
</code></pre>
<p>The output looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_9.png" alt="Image" width="600" height="400" loading="lazy">
_<code>git log --oneline --graph feature_branch_1 feature_branch_2 --pretty=format:"%s (%an) [%cd]</code>_</p>
<p>That's useful, but not really great to look at. We can then use other formatting tricks, specifically <code>%C(color)</code> that will switch the color to <code>color</code>, until reaching a <code>%Creset</code> that resets the color. To make the author name's yellow, you can use:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --oneline --graph feature_branch_1 feature_branch_2 --pretty=format:<span class="hljs-string">"%s %C(yellow)(%an)%Creset [%cd]"</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_10.png" alt="Image" width="600" height="400" loading="lazy">
_<code>git log --oneline --graph feature_branch_1 feature_branch_2 --pretty=format:"%s %C(yellow)(%an)%Creset [%cd]"</code>_</p>
<p>For some colors, like <code>red</code> or <code>green</code>, it is unnecessary to include the parenthesis, so <code>Cred</code> is enough.</p>
<h4 id="heading-how-is-git-lol-structured">How is <code>git lol</code> Structured?</h4>
<p>When I run <code>git lol</code>, it actually executes the following:</p>
<p><code>git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&lt;%an&gt;%Creset' --abbrev-commit</code></p>
<p>Can you take this bit by bit?</p>
<p>You already know <code>--graph</code>, which makes the output include an ASCII graph.</p>
<p><code>--abbrev-commit</code> uses a short prefix from the full SHA-1 of the commit (in my configuration, the first seven characters).</p>
<p>The rest is just coloring of various details about the commit:</p>
<pre><code class="lang-bash">git lol --all
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_11.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git lol --all</code></em></p>
<p>I like this output because I find it clear. It gives me the information I need, with enough coloring so that every detail stands out without hurting my eyes. But if you prefer other information, other colors, a different order, or anything else - go ahead and tweak it to your liking.</p>
<h3 id="heading-setting-an-alias">Setting an alias</h3>
<p>As you know, I set <code>git lol</code> as an alias - that is, when I run <code>git lol</code>, it executes the long command I provided previously.</p>
<p>How can you create an alias in Git?</p>
<p>The easiest way is to use <code>git alias</code>, like so:</p>
<pre><code class="lang-bash">git config --global alias.co checkout
</code></pre>
<p>This command sets <code>co</code> to be an alias for the command <code>checkout</code>, so you can use <code>git co main</code> instead of <code>git checkout main</code>.</p>
<p>To define <code>git lol</code> as an alias, you can use:</p>
<pre><code class="lang-bash">git config --global alias.lol <span class="hljs-string">'log --graph --pretty=format:'</span>%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&lt;%an&gt;%Creset<span class="hljs-string">' --abbrev-commit'</span>
</code></pre>
<h2 id="heading-chapter-13-git-bisect">Chapter 13 - Git Bisect</h2>
<p>Oops.</p>
<p>I have a bug.</p>
<p>Yes, that happens some times, to all of us. Something in my system is broken, and I can't tell why. I have been debugging for a while, but the solution is not clear.</p>
<p>I can tell that two weeks ago, this didn't happen. Luckily for me, I have been using Git (obviously, I know...), so I can go back in time and test a past version of my code. Indeed, in this version - everything worked fine.</p>
<p>But... I have made many changes in these two weeks. Alas, not just me - my entire team has contributed commits that add, delete, or modify parts of the code base. Where do I begin? Should I go over every change introduced in those two weeks?</p>
<p>Enter - <code>git bisect</code>.</p>
<p>The goal of <code>git bisect</code> is help you find the commit where a bug was introduced, in an effective manner.</p>
<h3 id="heading-how-does-git-bisect-work">How Does <code>git bisect</code> Work?</h3>
<p><code>git bisect</code> first asks you to mark one commit as "bad" (where the bug occurs), and another commit as "good" (one without the bug). Then, it checks out a commit halfway between these two commits, and then asks you to identify the commit as either "good" or "bad". This process is repeated until you find the first "bad" commit.</p>
<p>The key here is using binary search - by looking at the halfway point and deciding if it is the new top or bottom of the list of commits, you can find the right commit efficiently. Even if you have 10,000 commits to hunt through, it only takes a maximum of 13 steps to find the first commit that introduced the bug.</p>
<h3 id="heading-git-bisect-example"><code>git bisect</code> Example</h3>
<p>For this example, I will use the repository on <a target="_blank" href="https://github.com/Omerr/bisect-exercise.git">https://github.com/Omerr/bisect-exercise.git</a>. To create it, I adapted the open source repository <a target="_blank" href="https://github.com/bast/git-bisect-exercise">https://github.com/bast/git-bisect-exercise</a> (according to its license).</p>
<p>In this repository, we have a single python file that is used to compute the value of pi (which is approximately <code>3.14</code>). If you run <code>python3 get_pi.py</code> on <code>main</code>, however, you will get a wrong result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_1.png" alt="A wrong result, we have a bug" width="600" height="400" loading="lazy">
<em>A wrong result, we have a bug</em></p>
<p>This branch consists of more than 500 commits.</p>
<p>Find the first commit on this branch by using:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --oneline | tail -n 1
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_2.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git log --oneline | tail -n 1</code></em></p>
<p>If you <code>checkout</code> to this commit and run <code>python3 get_pi.py</code> again, the result is correct:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_1_pi.png" alt="From the first commit, the result is valid" width="600" height="400" loading="lazy">
<em>From the first commit, the result is valid</em></p>
<p>So somewhere between <code>HEAD</code> and commit <code>f0ea950</code>, a change was introduced that resulted in this wrong output.</p>
<p>To find it using <code>git bisect</code>, <code>start</code> the bisect process, and mark this commit as "good":</p>
<pre><code class="lang-bash">git bisect start
git bisect good
</code></pre>
<p>By default, <code>git bisect good</code> would take <code>HEAD</code> as the "good" commit. To mark <code>main</code> as "bad", you can use <code>git bisect bad main</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_3.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git bisect bad main</code></em></p>
<p><code>git bisect</code> checked out commit number <code>251</code>, the "middle point" of <code>main</code> branch. Does the state in this commit produce the right or wrong output?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_4.png" alt="Trying again..." width="600" height="400" loading="lazy">
<em>Trying again...</em></p>
<p>We still get the wrong output, which means we can discard commits <code>252</code> through <code>500</code> (and additional commits after that), and narrow our search to commits <code>2</code> through <code>251</code>. Mark this as <code>bad</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_5.png" alt="Mark as " width="600" height="400" loading="lazy">
<em>Mark as <code>bad</code></em></p>
<p><code>git bisect</code> checked out the "middle" commit (number <code>126</code>), and running the code again results in the right answer! This means that this commit is "good", and that the first "bad" commit is somewhere between <code>127</code> and <code>251</code>. Mark it as "good":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_6.png" alt="Mark as " width="600" height="400" loading="lazy">
<em>Mark as <code>good</code></em></p>
<p>Nice, <code>git bisect</code> takes us to commit <code>188</code>, as this is the "middle" commit between <code>127</code> and <code>251</code>. By running the code again, you can see that the result is wrong, so this is actually a "bad" commit, which means the first faulty commit is somewhere between <code>127</code> and <code>188</code>. As you can see, <code>git bisect</code> narrows down the search space by half on each iteration.</p>
<p>Come on, now it's your turn - keep going from here! Test the result of <code>python3 get_pi.py</code> and use <code>git bisect good</code> or <code>git bisect bad</code> to mark the commit accordingly. What is the faulty commit?</p>
<p>When you are done, use <code>git bisect reset</code> to stop the bisect process.</p>
<h3 id="heading-automatic-git-bisect">Automatic <code>git bisect</code></h3>
<p>In the previous example, you could simply run <code>python3 get_pi.py</code> and check the result. Other times, the process of validating whether a certain commit is "good" or "bad" can be tricky, error prone, or just time consuming. </p>
<p>It is possible to automate the process of <code>git bisect</code> by creating code that would be executed on each iteration, returning <code>0</code> when the current commit is "good", and a value between <code>1-127</code> (inclusive), except <code>125</code>, if it should be considered "bad".</p>
<p>The syntax is:</p>
<pre><code class="lang-bash">git bisect run my_script arguments
</code></pre>
<p>As this book is not about programming and doesn't assume you know a specific programming language, I will not show an example of implementing <code>my_script</code>. The <code>README.md</code> file in the repository used in this chapter (<a target="_blank" href="https://github.com/Omerr/bisect-exercise.git">https://github.com/Omerr/bisect-exercise.git</a>) includes an example for a script that you can run with <code>git bisect run</code> to automatically find the faulty commit for the previous example.</p>
<h2 id="heading-chapter-14-other-useful-commands">Chapter 14 - Other Useful Commands</h2>
<p>This chapter highlights a few commands that had have already been mentioned in previous chapters. I am putting them here together so that you can come back to them as a reference when needed.</p>
<h3 id="heading-git-cherry-pick"><code>git cherry-pick</code></h3>
<p>Introduced in <a class="post-section-overview" href="#heading-chapter-8-understanding-git-rebase">chapter 8</a>, this command takes a given commit, computes the <strong>patch</strong> this commit introduces by computing the difference between the parent's commit and the commit itself, and then <code>cherry-pick</code> "replays" this difference. It is like "copy-pasting" a commit, that is, the diff this commit introduced.</p>
<p>In <a class="post-section-overview" href="#heading-chapter-8-understanding-git-rebase">chapter 8</a> we considered the difference introduced by "Commit 5" (using <code>git diff main &lt;SHA_OF_COMMIT_5&gt;</code>):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_commit_5-1.png" alt="Running  to observe the patch introduced by &quot;Commit 5&quot;" width="600" height="400" loading="lazy">
<em>Running <code>git diff</code> to observe the patch introduced by "Commit 5"</em></p>
<p>You can see that in this commit, John started working on a song called "Lucy in the Sky with Diamonds":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_commit_5_output-1.png" alt="The output of  - the patch introduced by &quot;Commit 5&quot;" width="600" height="400" loading="lazy">
<em>The output of <code>git diff</code> - the patch introduced by "Commit 5"</em></p>
<p>As a reminder, you can also use the command <code>git show</code> to get the same output:</p>
<pre><code class="lang-bash">git show &lt;SHA_OF_COMMIT_5&gt;
</code></pre>
<p>Now, if you <code>cherry-pick</code> this commit, you will introduce <em>this change</em> specifically, on the active branch. You can switch to <code>main</code> branch:</p>
<pre><code class="lang-bash">git checkout main (or git switch main)
</code></pre>
<p>And create another branch:</p>
<pre><code class="lang-bash">git checkout -b my_branch (or git switch -c my_branch)
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_my_branch-1.png" alt="Creating  that branches from " width="600" height="400" loading="lazy">
_Creating <code>my_branch</code> that branches from <code>main</code>_</p>
<p>Next, <code>cherry-pick</code> "Commit 5":</p>
<pre><code class="lang-bash">git cherry-pick &lt;SHA_OF_COMMIT_5&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/cherry_pick_commit_5-1.png" alt="Using  to apply the changes introduced in &quot;Commit 5&quot; onto " width="600" height="400" loading="lazy">
<em>Using <code>cherry-pick</code> to apply the changes introduced in "Commit 5" onto <code>main</code></em></p>
<p>Consider the log (output of <code>git lol</code>):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_lol_commit_5-1.png" alt="The output of " width="600" height="400" loading="lazy">
<em>The output of <code>git lol</code></em></p>
<p>It seems like you <em>copy-pasted</em> "Commit 5". Remember that even though it has the same commit message, and introduces the same changes, and even points to the same tree object as the original "Commit 5" in this case - it is still a different commit object, as it was created with a different timestamp.</p>
<p>Looking at the changes, using <code>git show HEAD</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD-3.png" alt="The output of " width="600" height="400" loading="lazy">
<em>The output of <code>git show HEAD</code></em></p>
<p>They are the same as "Commit 5"'s.</p>
<h3 id="heading-git-revert-1"><code>git revert</code></h3>
<p><code>git revert</code> is essentially the reverse of <code>git cherry-pick</code>, introduced in <a class="post-section-overview" href="#heading-chapter-10-additional-tools-for-undoing-changes">chapter 10</a>. This command takes the commit you're providing it with and computes the diff from its parent commit, just like <code>git cherry-pick</code>, but this time, it computes the <em>reverse</em> changes. That is, if in the specified commit you added a line, the reverse would delete the line, and vice versa.</p>
<h3 id="heading-git-add-p"><code>git add -p</code></h3>
<p>Staging changes is an integral part of introducing changes to Git. Sometimes, you wish to stage all changes together (with <code>git add .</code>), or perhaps stage all changes of a specific file (using <code>git add &lt;file_path&gt;</code>). Yet there are times where it would be convenient to stage only certain parts of modified files.</p>
<p>In <a target="_blank" href="https://www.freecodecamp.org/news/p/f7b355ea-3f22-4613-8218-e95c67779d9f/chapter-6-diffs-and-patches">chapter 6</a>, we introduced <code>git add -p</code>. This command allows you to stage certain parts of files, by splitting them into hunks (<code>p</code> stands for <code>patch</code>). For example, say you have this file, <code>my_file.py</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/my_file_py_1.png" alt="Image" width="600" height="400" loading="lazy">
_<code>my_file.py</code>_</p>
<p>You then modify this file - by changing text within <code>function_1</code>, and also adding a new function, <code>function_5</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/my_file_py_2.png" alt=" after the changes" width="600" height="400" loading="lazy">
_<code>my_file.py</code> after the changes_</p>
<p>If you used <code>git add my_file.py</code> at this point, you would stage both of these changes together. In case you want to separate them into different commits, you could use <code>git add -p</code>, which splits these two changes and asks you about each one as a standalone hunk:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/add_p_1.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git add -p</code></em></p>
<p>By typing <code>?</code>, you can see what the different options stand for:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/add_p_2.png" alt="Using a  to get a description of the different options" width="600" height="400" loading="lazy">
<em>Using a <code>?</code> to get a description of the different options</em></p>
<p>In this case, say we only want to stage the change introducing <code>function_5</code>. We do not want to stage the change of <code>function_1</code>, so we select <code>n</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/add_p_3.png" alt="Not staging the change to " width="600" height="400" loading="lazy">
_Not staging the change to <code>function_1</code>_</p>
<p>Next, we are prompted for the second change - the one introducing <code>function_5</code>. We want to stage this hunk indeed, to can do so we can type <code>y</code>.</p>
<h1 id="heading-summary">Summary</h1>
<p>Well, this was FUN!</p>
<p>Can you believe how much you have learned?</p>
<p>In <strong>Part 1</strong> you learned about - blobs, trees, and commits.</p>
<p>You then learned about <strong>branches</strong>, seeing that they are nothing but a named reference to a commit.</p>
<p>You learned the process of recording changes in Git, and that it involves the <strong>working directory</strong>, the <strong>staging area (index)</strong>, and the <strong>repository</strong>.</p>
<p>Then - you created a new repository from scratch, by using <code>echo</code> and low-level commands such as <code>git hash-object</code>. You created a blob, a tree, and a commit object pointing to that tree.</p>
<p>In <strong>Part 2</strong> you learned about branching and integrating changes in Git.</p>
<p>You learned what a <strong>diff</strong> is, and the difference between a diff and a <strong>patch</strong>. You also learned how the output of <code>git diff</code> is constructed.</p>
<p>Then, you got an extensive overview of merging with Git, specifically understanding the three-way merge algorithm. You understood when <strong>merging conflicts</strong> occur, when Git can resolve them automatically, and how to resolve them manually when needed.</p>
<p>You saw that <code>git rebase</code> is powerful - but also that it is quite simple once you understand what it does. You understood the differences between merging and rebasing, and when you should use each.</p>
<p>In <strong>Part 3</strong> you learned how to <strong>undo changes</strong> in Git - especially when things go wrong. You learned how to use a bunch of tools, like <code>git reset</code>, <code>git commit --amend</code>, <code>git revert</code>, <code>git reflog</code> (and <code>git log -g</code>).</p>
<p>The most important tool, even more important than the tools I just listed, is to whiteboard the current situation vs the desired one. Trust me on this, it will make every situation seem less daunting and the solution more clear.</p>
<p>In <strong>Part 4</strong> you acquired additional powerful tools, like different switches of <code>git log</code>, <code>git bisect</code>, <code>git cherry-pick</code>, <code>git revert</code> and <code>git add -p</code>.</p>
<p>Wow, you should be proud of yourself!</p>
<h3 id="heading-a-message-from-me-to-you">A Message From Me to You</h3>
<p>Indeed, this was fun, but all things must pass. You finished reading this book, but this doesn't mean your learning journey ends here.</p>
<p>What you have acquired, more than any specific tool, is intuition and understanding of how Git operates, and how to think about various operations in Git. Keep researching, reading, and using Git. I am sure you will be able to teach me something new, and by all means - please do.</p>
<p>If you liked this book, please share it with more people.</p>
<p>If you want to read more of my Git articles and handbooks, here they are:</p>
<ol>
<li><a target="_blank" href="https://www.freecodecamp.org/news/git-rebase-handbook/">The Git Rebase Handbook</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/">The Git Merge Handbook</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/git-diff-and-patch/">The Git Diff and Patch Handbook</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">Git Internals - Objects, Branches, and How to Create a Repo</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/save-the-day-with-git-reset/">Git Reset Command Explained</a></li>
</ol>
<h3 id="heading-acknowledgements">Acknowledgements</h3>
<p>Many people helped make this book the best it can be. Among them, I was lucky to have many beta readers that provided me with feedback so that I can improve the book. Specifically, I would like to thank Jason S. Shapiro, Anna Łapińska, C. Bruce Hilbert, and Jonathon McKitrick for their thorough reviews.</p>
<p>Abbey Rennemeyer has been a wonderful editor. After she has reviewed my posts for freeCodeCamp for over three years, it was clear that I would like to ask her to be the editor of this book as well. She helped me improve the book in many ways, and I am grateful for her help.</p>
<p>Quincy Larson founded the amazing community at freeCodeCamp, motivated me throughout emails and face to face discussions. I thank him for starting this incredible community, and for his friendship.</p>
<p>Estefania Cassingena Navone designed the cover of this book. I am grateful for her professional work and her patience with my perfectionism and requests.</p>
<p>Daphne Gray-Grant's website, <a target="_blank" href="https://www.publicationcoach.com/">"Publication Coach"</a>, has provided me with inspiring as well as technical advice that has greatly helped me with my writing process.</p>
<h3 id="heading-if-you-wish-to-support-this-book">If You Wish to Support This Book</h3>
<p>If you would like to support this book, you are welcome to buy the <a target="_blank" href="https://www.amazon.com/dp/B0CQXTJ5V5">Paperback version</a>, an <a target="_blank" href="https://www.buymeacoffee.com/omerr/e/197232">E-Book version</a>, or <a target="_blank" href="https://www.buymeacoffee.com/omerr">buy me a coffee</a>. Thank you!</p>
<h3 id="heading-contact-me">Contact Me</h3>
<p>This book has been created to help you and people like you learn, understand Git, and apply their knowledge in real life. </p>
<p>Right from the beginning, I asked for feedback and was lucky to receive it from great people (mentioned in the <a class="post-section-overview" href="#heading-acknowledgements">Acknowledgements</a>) to make sure the book achieves these goals. If you liked something about this book, felt that something was missing or needed improvement - I would love to hear from you. Please reach out at <a target="_blank" href="mailto:gitting.things@gmail.com">gitting.things@gmail.com</a>.</p>
<p>Thank you for learning and allowing me to be a part of your journey.</p>
<ul>
<li>Omer Rosenbaum</li>
</ul>
<h1 id="heading-appendixes">Appendixes</h1>
<h2 id="heading-additional-references-by-part">Additional References - By Part</h2>
<p>(Note - this is a short list. You can find a longer list of references on the <a target="_blank" href="https://www.buymeacoffee.com/omerr/e/197232">E-Book</a> or <a target="_blank" href="https://www.amazon.com/dp/B0CQXTJ5V5">printed</a> version.)</p>
<h3 id="heading-part-1">Part 1</h3>
<ul>
<li>Git Internals YouTube playlist - by Brief:<br><a target="_blank" href="https://www.youtube.com/playlist?list=PL9lx0DXCC4BNUby5H58y6s2TQVLadV8v7">https://www.youtube.com/playlist?list=PL9lx0DXCC4BNUby5H58y6s2TQVLadV8v7</a></li>
<li>Tim Berglund's lecture  - "Git From the Bits Up":<br><a target="_blank" href="https://www.youtube.com/watch?v=MYP56QJpDr4">https://www.youtube.com/watch?v=MYP56QJpDr4</a></li>
<li>as promised, docs: Git for the confused:<br><a target="_blank" href="https://www.gelato.unsw.edu.au/archives/git/0512/13748.html">https://www.gelato.unsw.edu.au/archives/git/0512/13748.html</a></li>
</ul>
<h3 id="heading-part-2">Part 2</h3>
<h4 id="heading-diffs-and-patches">Diffs and Patches</h4>
<p>Git Diffs algorithms:</p>
<ul>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Diff">https://en.wikipedia.org/wiki/Diff</a></li>
</ul>
<p>The most default diff algorithm in Git is Myers:</p>
<ul>
<li><a target="_blank" href="https://www.nathaniel.ai/myers-diff/">https://www.nathaniel.ai/myers-diff/</a></li>
<li><a target="_blank" href="https://blog.jcoglan.com/2017/02/12/the-myers-diff-algorithm-part-1/">https://blog.jcoglan.com/2017/02/12/the-myers-diff-algorithm-part-1/</a></li>
<li><a target="_blank" href="https://blog.robertelder.org/diff-algorithm/">https://blog.robertelder.org/diff-algorithm/</a></li>
</ul>
<h4 id="heading-git-merge">Git Merge</h4>
<ul>
<li><a target="_blank" href="https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging">https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging</a></li>
<li><a target="_blank" href="https://blog.plasticscm.com/2010/11/live-to-merge-merge-to-live.html">https://blog.plasticscm.com/2010/11/live-to-merge-merge-to-live.html</a></li>
</ul>
<h4 id="heading-git-rebase">Git Rebase</h4>
<ul>
<li><a target="_blank" href="https://jwiegley.github.io/git-from-the-bottom-up/1-Repository/7-branching-and-the-power-of-rebase.html">https://jwiegley.github.io/git-from-the-bottom-up/1-Repository/7-branching-and-the-power-of-rebase.html</a></li>
<li><a target="_blank" href="https://git-scm.com/book/en/v2/Git-Branching-Rebasing">https://git-scm.com/book/en/v2/Git-Branching-Rebasing</a></li>
</ul>
<h4 id="heading-beatles-related-resources-1">Beatles-Related Resources</h4>
<ul>
<li><a target="_blank" href="https://www.the-paulmccartney-project.com/song/ive-got-a-feeling/">https://www.the-paulmccartney-project.com/song/ive-got-a-feeling/</a></li>
<li><a target="_blank" href="https://www.cheatsheet.com/entertainment/did-john-lennon-or-paul-mccartney-write-the-classic-a-day-in-the-life.html/">https://www.cheatsheet.com/entertainment/did-john-lennon-or-paul-mccartney-write-the-classic-a-day-in-the-life.html/</a></li>
<li><a target="_blank" href="http://lifeofthebeatles.blogspot.com/2009/06/ive-got-feeling-lyrics.html">http://lifeofthebeatles.blogspot.com/2009/06/ive-got-feeling-lyrics.html</a></li>
</ul>
<h3 id="heading-part-3">Part 3</h3>
<ul>
<li><a target="_blank" href="https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified">https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified</a></li>
<li><a target="_blank" href="https://www.edureka.co/blog/common-git-mistakes/">https://www.edureka.co/blog/common-git-mistakes/</a></li>
</ul>
<h1 id="heading-about-the-author">About the Author</h1>
<p><a target="_blank" href="https://www.linkedin.com/in/omer-rosenbaum-034a08b9/">Omer Rosenbaum</a> is <a target="_blank" href="https://swimm.io/">Swimm</a>’s Chief Technology Officer. He's the author of the <a target="_blank" href="https://youtube.com/@BriefVid">Brief YouTube Channel</a>. He's also a cyber training expert and founder of Checkpoint Security Academy. He's the author of <a target="_blank" href="https://data.cyber.org.il/networks/networks.pdf">Computer Networks (in Hebrew)</a>. You can find him on <a target="_blank" href="https://twitter.com/Omer_Ros">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The Git Rebase Handbook – A Definitive Guide to Rebasing ]]>
                </title>
                <description>
                    <![CDATA[ One of the most powerful tools a developer can have in their toolbox is git rebase. Yet it is notorious for being complex and misunderstood.  The truth is, if you understand what it actually does, git rebase is a very elegant, and straightforward too... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/git-rebase-handbook/</link>
                <guid isPermaLink="false">66c17c2632867815f7100b62</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Omer Rosenbaum ]]>
                </dc:creator>
                <pubDate>Mon, 03 Jul 2023 13:56:34 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/07/The-Git-Rebase-Handbook-Book-Cover--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>One of the most powerful tools a developer can have in their toolbox is <code>git rebase</code>. Yet it is notorious for being complex and misunderstood. </p>
<p>The truth is, if you understand what it <em>actually</em> does, <code>git rebase</code> is a very elegant, and straightforward tool to achieve so many different things in Git.</p>
<p>In previous posts, you understood <a target="_blank" href="https://www.freecodecamp.org/news/git-diff-and-patch/">what Git diffs are</a>, <a target="_blank" href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/">what a merge is</a>, and <a target="_blank" href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/">how Git resolves merge conflicts</a>. In this post, you will understand what Git rebase is, why it's different from merge, and how to rebase with confidence 💪🏻</p>
<h2 id="heading-notes-before-we-start">Notes before we start</h2>
<ol>
<li>I also created a video covering the contents of this post. If you wish to watch alongside reading, you can find it <a target="_blank" href="https://youtu.be/3VFsitGUB3s">here</a>.</li>
<li>If you want to play around with the repository I used and try out the commands for yourself, you can get the repo <a target="_blank" href="https://github.com/Omerr/rebase_playground">here</a>.</li>
<li>I am working on a book about Git! Are you interested in reading the initial versions and providing feedback? Send me an email: <a target="_blank" href="https://www.freecodecamp.org/news/p/2e1fc200-f447-4f55-b0a3-73ef790a2190/gitting.things@gmail.com">gitting.things@gmail.com</a></li>
</ol>
<p>OK, are you ready?</p>
<h1 id="heading-short-recap-what-is-git-merge">Short Recap - What is Git Merge? 🤔</h1>
<p>Under the hood, <code>git rebase</code> and <code>git merge</code> are very, very different things. Then why do people compare them all the time?</p>
<p>The reason is their usage. When working with Git, we usually work in different branches and introduce changes to those branches. </p>
<p>In <a target="_blank" href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/#howgits3waymergealgorithmworks">a previous tutorial</a>, I gave an example where John and Paul (of the Beatles) were co-authoring a new song. They started from the <code>main</code> branch, and then each diverged, modified the lyrics and committed their changes. </p>
<p>Then, the two wanted to integrate their changes, which is something that happens very frequently when working with Git.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-197.png" alt="Image" width="600" height="400" loading="lazy">
_A diverging history - <code>paul_branch</code> and <code>john_branch</code> diverged from <code>main</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)_</p>
<p>There are two main ways to integrate changes introduced in different branches in Git, or in other words, different commits and commit histories. These are merge and rebase.</p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/">In a previous tutorial</a>, we got to know <code>git merge</code> pretty well. We saw that when performing a merge, we create a <strong>merge commit</strong> – where the contents of this commit are a combination of the two branches, and it also has two parents, one in each branch.</p>
<p>So, say you are on the branch <code>john_branch</code> (assuming the history depicted in the drawing above), and you run <code>git merge paul_branch</code>. You will get to this state – where on <code>john_branch</code>, there is a new commit with two parents. The first one will be the commit on <code>john_branch</code> branch where <code>HEAD</code> was pointing to before performing the merge, in this case - "Commit 6". The second will be the commit pointed to by <code>paul_branch</code>, "Commit 9".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-196.png" alt="Image" width="600" height="400" loading="lazy">
_The result of running <code>git merge paul_branch</code>: a new Merge Commit with two parents (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)_</p>
<p>Look again at the history graph: you created a <strong>diverged</strong> history. You can actually see where it branched and where it merged again.</p>
<p>So when using <code>git merge</code>, you do not rewrite history – but rather, you add a commit to the existing history. And specifically, a commit that creates a diverged history.</p>
<h1 id="heading-how-is-git-rebase-different-than-git-merge">How is <code>git rebase</code> Different than <code>git merge</code>? 🤔</h1>
<p>When using <code>git rebase</code>, something different happens. 🥁</p>
<p>Let's start with the big picture: if you are on <code>paul_branch</code>, and use <code>git rebase john_branch</code>, Git goes to the common ancestor of John's branch and Paul's branch. Then it takes the patches introduced in the commits on Paul's branch, and applies those changes to John's branch. </p>
<p>So here, you use <code>rebase</code> to take the changes that were committed on one branch – Paul's branch – and replay them on a different branch, <code>john_branch</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-198.png" alt="Image" width="600" height="400" loading="lazy">
_The result of running <code>git rebase john_branch</code>: the commits on <code>paul_branch</code> were "replayed" on top of <code>john_branch</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)_</p>
<p>Wait, what does that mean? 🤔</p>
<p>We will now take this bit by bit to make sure you fully understand what's happening under the hood 😎</p>
<h1 id="heading-cherry-pick-as-a-basis-for-rebase"><code>cherry-pick</code> as a Basis for Rebase</h1>
<p>It is useful to think of rebase as performing <code>git cherry-pick</code> – a command takes a commit, computes the <em>patch</em> this commit introduces by computing the difference between the parent's commit and the commit itself, and then <code>cherry-pick</code> "replays" this difference.</p>
<p>Let's do this manually.</p>
<p>If we look at the difference introduced by "Commit 5" by performing <code>git diff main &lt;SHA_OF_COMMIT_5&gt;</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-199.png" alt="Image" width="600" height="400" loading="lazy">
<em>Running <code>git diff</code> to observe the patch introduced by "Commit 5" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>(If you want to play around with the repository I used and try out the commands for yourself, you can get the repo <a target="_blank" href="https://github.com/Omerr/rebase_playground">here</a>).</p>
<p>You can see that in this commit, John started working on a song called "Lucy in the Sky with Diamonds":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-200.png" alt="Image" width="600" height="400" loading="lazy">
<em>The output of <code>git diff</code> - the patch introduced by "Commit 5" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>As a reminder, you can also use the command <code>git show</code> to get the same output:</p>
<pre><code>git show &lt;SHA_OF_COMMIT_5&gt;
</code></pre><p>Now, if you <code>cherry-pick</code> this commit, you will introduce this change specifically, on the active branch. Switch to <code>main</code> first:</p>
<p><code>git checkout main</code> (or <code>git switch main</code>)</p>
<p>And create another branch, just to be clear:</p>
<p><code>git checkout -b my_branch</code> (or <code>git switch -c my_branch</code>)</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-201.png" alt="Image" width="600" height="400" loading="lazy">
_Creating <code>my_branch</code> that branches from <code>main</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)_</p>
<p>And <code>cherry-pick</code> this commit:</p>
<pre><code>git cherry-pick &lt;SHA_OF_COMMIT_5&gt;
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-202.png" alt="Image" width="600" height="400" loading="lazy">
<em>Using <code>cherry-pick</code> to apply the changes introduced in "Commit 5" onto <code>main</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Consider the log (output of <code>git lol</code>):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-205.png" alt="Image" width="600" height="400" loading="lazy">
<em>The output of <code>git lol</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>(<code>git lol</code> is an alias I added to Git to visibly see the history in a graphical manner. You can find it <a target="_blank" href="https://gist.github.com/Omerr/8134a61b56ca82dd90e546e7ef04eb77">here</a>).</p>
<p>It seems like you <em>copy-pasted</em> "Commit 5". Remember that even though it has the same commit message, and introduces the same changes, and even points to the same tree object as the original "Commit 5" in this case – it is still a different commit object, as it was created with a different timestamp.</p>
<p>Looking at the changes, using <code>git show HEAD</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-204.png" alt="Image" width="600" height="400" loading="lazy">
<em>The output of <code>git show HEAD</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>They are the same as "Commit 5"'s.</p>
<p>And of course, if you look at the file (say, by using <code>nano lucy_in_the_sky_with_diamonds.md</code>), it will be in the same state as it has been after the original "Commit 5".</p>
<p>Cool! 😎</p>
<p>OK, you can now remove the new branch so it doesn't appear on your history every time:</p>
<pre><code>git checkout main
git branch -D my_branch
</code></pre><h2 id="heading-beyond-cherry-pick-how-to-use-git-rebase">Beyond <code>cherry-pick</code> – How to Use <code>git rebase</code></h2>
<p>You can look at <code>git rebase</code> as a way to perform multiple <code>cherry-pick</code>s one after the other – that is, to "replay" multiple commits. This is not the only thing you can do with <code>rebase</code>, but it's a good starting point for our explanation.</p>
<p>It's time to play with <code>git rebase</code>! 👏🏻👏🏻</p>
<p>Before, you merged <code>paul_branch</code> into <code>john_branch</code>. What would happen if you <em>rebased</em> <code>paul_branch</code> on top of  <code>john_branch</code>? You would get a very different history.</p>
<p>In essence, it would seem as if we took the changes introduced in the commits on <code>paul_branch</code>, and replayed them on <code>john_branch</code>. The result would be a <strong>linear</strong> history.</p>
<p>To understand the process, I will provide the high level view, and then dive deeper into each step. The process of rebasing one branch on top of another branch is as follows:</p>
<ol>
<li>Find the common ancestor.</li>
<li>Identify the commits to be "replayed".</li>
<li>For every commit <code>X</code>, compute <code>diff(parent(X), X)</code>, and store it as a <code>patch(X)</code>.</li>
<li>Move <code>HEAD</code> to the new base.</li>
<li>Apply the generated patches in order on the target branch. Each time, create a new commit object with the new state.</li>
</ol>
<p>The process of making new commits with the same changesets as existing ones is also called <strong>"replaying"</strong> those commits, a term we have already used.</p>
<h1 id="heading-time-to-get-hands-on-with-rebase"><strong>Time to Get Hands-On with Rebase🙌🏻</strong></h1>
<p>Start from Paul's branch:</p>
<pre><code>git checkout paul_branch
</code></pre><p>This is the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-206.png" alt="Image" width="600" height="400" loading="lazy">
<em>Commit history before performing <code>git rebase</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>And now, to the exciting part:</p>
<pre><code>git rebase john_branch
</code></pre><p>And observe the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-207.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history after rebasing (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>( <code>gg</code> is an alias for an external tool I introduced <a target="_blank" href="https://youtu.be/3VFsitGUB3s">in the video</a>).</p>
<p>So whereas with <code>git merge</code> you added to the history, with <code>git rebase</code> you <strong>rewrite history</strong>. You create <strong>new</strong> commit objects. In addition, the result is a linear history graph – rather than a diverging graph.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-209.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history after rebasing (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>In essence, we "copied" the commits that were on <code>paul_branch</code> and introduced after "Commit 4", and "pasted" them on top of <code>john_branch</code>.</p>
<p>The command is called "rebase", because it changes the base commit of the branch it's run from. That is, in your case, before running <code>git rebase</code>, the base of <code>paul_branch</code> was "Commit 4" – as this is where the branch was "born" (from <code>main</code>). With <code>rebase</code>, you asked Git to give it another base – that is, pretend as if it had been born from "Commit 6".</p>
<p>To do that, Git took what used to be "Commit 7", and "replayed" the changes introduced in this commit onto "Commit 6", and then created a new commit object. This object differs from the original "Commit 7" in three aspects:</p>
<ol>
<li>It has a different timestamp.</li>
<li>It has a different parent commit – "Commit 6" rather than "Commit 4".</li>
<li>The <a target="_blank" href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">tree object</a> it is pointing to is different - as the changes were introduced to the tree pointed to by "Commit 6", and not the tree pointed to by "Commit 4".</li>
</ol>
<p>Notice the last commit here, "Commit 9'". The snapshot it represents (that is, the <a target="_blank" href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">tree</a> that it points to) is exactly the same tree you would get by merging the two branches. The state of the files in your Git repository would be <strong>the same</strong> as if you used <code>git merge</code>. It's only the history that is different, and the commit objects of course.</p>
<p>Now, you can simply use:</p>
<pre><code>git checkout main
git merge paul_branch
</code></pre><p>Hm.... What would happen if you ran this last command? 🤔 Consider the commit history again, after checking out <code>main</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-210.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history after rebasing and checking out <code>main</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>What would it mean to merge <code>main</code> and <code>paul_branch</code>?</p>
<p>Indeed, Git can simply perform a fast-forward merge, as the history is completely linear (if you need a reminder about fast forward merges, check out <a target="_blank" href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/#timetogethandson">this post</a>). As a result, <code>main</code> and <code>paul_branch</code> now point to the same commit:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-211.png" alt="Image" width="600" height="400" loading="lazy">
<em>The result of a fast-forward merge (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<h1 id="heading-advanced-rebasing-in-git">Advanced Rebasing in Git💪🏻</h1>
<p>Now that you understand the basics of rebase, it is time to consider more advanced cases, where additional switches and arguments to the <code>rebase</code> command will come in handy.</p>
<p>In the previous example, when you only said <code>rebase</code> (without additional switches), Git replayed all the commits from the common ancestor to the tip of the current branch.</p>
<p>But rebase is a super-power, it's an almighty command capable of…well, rewriting history. And it can come in handy if you want to modify history to make it your own.</p>
<p>Undo the last merge by making <code>main</code> point to "Commit 4" again:</p>
<pre><code>git reset -–hard &lt;ORIGINAL_COMMIT <span class="hljs-number">4</span>&gt;
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-238.png" alt="Image" width="600" height="400" loading="lazy">
<em>"Undoing" the last merge operation (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>And undo the rebasing by using:</p>
<pre><code>git checkout paul_branch
git reset -–hard &lt;ORIGINAL_COMMIT <span class="hljs-number">9</span>&gt;
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-239.png" alt="Image" width="600" height="400" loading="lazy">
<em>"Undoing" the rebase operation (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Notice that you got to exactly the same history you used to have:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-240.png" alt="Image" width="600" height="400" loading="lazy">
<em>Visualizing the history after "undoing" the rebase operation (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Again, to be clear, "Commit 9" doesn't just disappear when it's not reachable from the current <code>HEAD</code>. Rather, it's still stored in the object database. And as you used <code>git reset</code> now to change <code>HEAD</code> to point to this commit, you were able to retrieve it, and also its parent commits since they are also stored in the database. Pretty cool, huh? 😎</p>
<p>OK, quickly view the changes that Paul introduced:</p>
<pre><code>git show HEAD
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-241.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git show HEAD</code> shows the patch introduced by "Commit 9" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Keep going backwards in the commit graph:</p>
<pre><code>git show HEAD~
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-242.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git show HEAD~</code> (same as <code>git show HEAD~1</code>) shows the patch introduced by "Commit 8" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>And one commit further:</p>
<pre><code>git show HEAD~<span class="hljs-number">2</span>
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-243.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git show HEAD~2</code> shows the patch introduced by "Commit 7" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>So, these changes are nice, but perhaps Paul doesn't want this kind of history. Rather, he wants it to seem as if he introduced the changes in "Commit 7" and "Commit 8" as a single commit.</p>
<p>For that, you can use an <strong>interactive</strong> rebase. To do that, we add the <code>-i</code> (or <code>--interactive</code>) switch to the <code>rebase</code> command:</p>
<pre><code>git rebase -i &lt;SHA_OF_COMMIT_4&gt;
</code></pre><p>Or, since <code>main</code> is pointing to "Commit 4", we can simply run:</p>
<pre><code>git rebase -i main
</code></pre><p>By running this command, you tell Git to use a new base, "Commit 4". So you are asking Git to go back to all commits that were introduced after "Commit 4" and that are reachable from the current <code>HEAD</code>, and replay those commits.</p>
<p>For every commit that is replayed, Git asks us what we'd like to do with it:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-250.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>git rebase -i main</code> prompts you to select what to do with each commit (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>In this context it's useful to think of a commit as a patch. That is, "Commit 7" as in "the patch that "Commit 7" introduced on top of its parent".</p>
<p>One option is to use <code>pick</code>. This is the default behavior, which tells Git to replay the changes introduced in this commit. In this case, if you just leave it as is – and <code>pick</code> all commits – you will get the same history, and Git won't even create new commit objects.</p>
<p>Another option is <code>squash</code>. A <em>squashed</em> commit will have its contents "folded" into the contents of the commit preceding it. So in our case, Paul would like to squash "Commit 8" into "Commit 7":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-251.png" alt="Image" width="600" height="400" loading="lazy">
<em>Squashing "Commit 8" into "Commit 7" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>As you can see, <code>git rebase -i</code> provides additional options, but we won't go into all of them in this post. If you allow the rebase to run, you will get prompted to select a commit message for the newly created commit (that is, the one that introduced the changes of both "Commit 7" and "Commit 8"):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-252.png" alt="Image" width="600" height="400" loading="lazy">
<em>Providing the commit message: <code>Commits 7+8</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>And look at the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-253.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history after the interactive rebase (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Exactly as we wanted! We have on <code>paul_branch</code> "Commit 9" (of course, it's a different object than the original "Commit 9"). This points to "Commits 7+8", which is a single commit introducing the changes of both the original "Commit 7" and the original "Commit 8". This commit's parent is "Commit 4", where <code>main</code> is pointing to. You have <code>john_branch</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-254.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history after the interactive rebase - visualized (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Oh wow, isn't that cool? 😎</p>
<p><code>git rebase</code> grants you unlimited control over the shape of any branch. You can use it to reorder commits, or to remove incorrect changes, or modify a change in retrospect. Alternatively, you could perhaps move the base of your branch onto another commit, any commit that you wish.</p>
<h2 id="heading-how-to-use-the-onto-switch-of-git-rebase">How to Use the <code>--onto</code> Switch of <code>git rebase</code></h2>
<p>Let's consider one more example. Get to <code>main</code> again:</p>
<pre><code>git checkout main
</code></pre><p>And delete the pointers to <code>paul_branch</code> and <code>john_branch</code> so you don't see them in the commit graph anymore:</p>
<pre><code>git branch -D paul_branch
git branch -D john_branch
</code></pre><p>And now branch from <code>main</code> to a new branch:</p>
<pre><code>git checkout -b new_branch
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-255.png" alt="Image" width="600" height="400" loading="lazy">
_Creating <code>new_branch</code> that diverges from <code>main</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)_</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-256.png" alt="Image" width="600" height="400" loading="lazy">
_A clean history with <code>new_branch</code> that diverges from <code>main</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)_</p>
<p>Now, add a few changes here and commit them:</p>
<pre><code>nano code.py
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-257.png" alt="Image" width="600" height="400" loading="lazy">
_Adding the function <code>new_branch</code> to <code>code.py</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)_</p>
<pre><code>git add code.py
git commit -m <span class="hljs-string">"Commit 10"</span>
</code></pre><p>Get back to <code>main</code>:</p>
<pre><code>git checkout main
</code></pre><p>And introduce another change:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-258.png" alt="Image" width="600" height="400" loading="lazy">
<em>Added a docstring at the beginning of the file (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Time to stage and commit these changes:</p>
<pre><code>git add code.py
git commit -m <span class="hljs-string">"Commit 11"</span>
</code></pre><p>And yet another change:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-259.png" alt="Image" width="600" height="400" loading="lazy">
<em>Added <code>@Author</code> to the docstring (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Commit this change as well:</p>
<pre><code>git add code.py
git commit -m <span class="hljs-string">"Commit 12"</span>
</code></pre><p>Oh wait, now I realize that I wanted you to make the changes introduced in "Commit 11" as a part of the <code>new_branch</code>. Ugh. What can you do? 🤔</p>
<p>Consider the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-260.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history after introducing "Commit 12" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>What I want is, instead of having "Commit 10" reside only on the <code>main</code> branch, I want it to be on both the <code>main</code> branch as well as the <code>new_branch</code>. Visually, I would want to move it down the graph here:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-261.png" alt="Image" width="600" height="400" loading="lazy">
<em>Visually, I want you to "push" "Commit 10" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Can you see where I am going? 😇</p>
<p>Well, as we understand, rebase allows us to basically <em>replay</em> the changes introduced in <code>new_branch</code>, those introduced in "Commit 10", as if they had been originally conducted on "Commit 11", rather than "Commit 4".</p>
<p>To do that, you can use other arguments of <code>git rebase</code>. You'd tell Git that you want to take all the history introduced between the common ancestor of <code>main</code> and <code>new_branch</code>, which is "Commit 4", and have the new base for that history be "Commit 11". To do that, use:</p>
<pre><code>git rebase -–onto &lt;SHA_OF_COMMIT_11&gt; main new_branch
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-262.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history before and after the rebase, "Commit 10" has been "pushed" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>And look at our beautiful history! 😍</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-263.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history before and after the rebase, "Commit 10" has been "pushed" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Let's consider another case.</p>
<p>Say I started working on a branch, and by mistake I started working from <code>feature_branch_1</code>, rather than from <code>main</code>.</p>
<p>So to emulate this, create <code>feature_branch_1</code>:</p>
<pre><code>git checkout main
git checkout -b feature_branch_1
</code></pre><p>And erase <code>new_branch</code> so you don't see it in the graph anymore:</p>
<pre><code>git branch -D new_branch
</code></pre><p>Create a simple Python file called <code>1.py</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-264.png" alt="Image" width="600" height="400" loading="lazy">
<em>A new file, <code>1.py</code>, with <code>print('Hello world!')</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Stage and commit this file:</p>
<pre><code>git add <span class="hljs-number">1.</span>py
git commit -m  <span class="hljs-string">"Commit 13"</span>
</code></pre><p>Now branched out (by mistake) from <code>feature_branch_1</code>:</p>
<pre><code>git checkout -b feature_branch_2
</code></pre><p>And create another file, <code>2.py</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-265.png" alt="Image" width="600" height="400" loading="lazy">
<em>Creating <code>2.py</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Stage and commit this file as well:</p>
<pre><code>git add <span class="hljs-number">2.</span>py
git commit -m  <span class="hljs-string">"Commit 14"</span>
</code></pre><p>And introduce some more code to <code>2.py</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-266.png" alt="Image" width="600" height="400" loading="lazy">
<em>Modifying <code>2.py</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Stage and commit these changes too:</p>
<pre><code>git add <span class="hljs-number">2.</span>py
git commit -m  <span class="hljs-string">"Commit 15"</span>
</code></pre><p>So far you should have this history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-267.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history after introducing "Commit 15" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Get back to <code>feature_branch_1</code> and edit <code>1.py</code>:</p>
<pre><code>git checkout feature_branch_1
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-268.png" alt="Image" width="600" height="400" loading="lazy">
<em>Modifying <code>1.py</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Now stage and commit:</p>
<pre><code>git add <span class="hljs-number">1.</span>py
git commit -m  <span class="hljs-string">"Commit 16"</span>
</code></pre><p>Your history should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-270.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history after introducing "Commit 16" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Say now you realize, you've made a mistake. You actually wanted <code>feature_branch_2</code> to be born from the <code>main</code> branch, rather than from <code>feature_branch_1</code>.</p>
<p>How can you achieve that? 🤔</p>
<p>Try to think about it given the history graph and what you've learned about the <code>--onto</code> flag for the <code>rebase</code> command.</p>
<p>Well, you want to "replace" the parent of your first commit on <code>feature_branch_2</code>, which is "Commit 14", to be on top of <code>main</code> branch, in this case, "Commit 12", rather than the beginning of <code>feature_branch_1</code>, in this case, "Commit 13". So again, you will be creating a <em>new base,</em> this time for the first commit on <code>feature_branch_2</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-271.png" alt="Image" width="600" height="400" loading="lazy">
<em>You want to move around "Commit 14" and "Commit 15" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>How would you do that?</p>
<p>First, switch to <code>feature_branch_2</code>:</p>
<pre><code>git checkout feature_branch_2
</code></pre><p>And now you can use:</p>
<pre><code>git rebase -–onto main &lt;SHA_OF_COMMIT_13&gt;
</code></pre><p>As a result, you have <code>feature_branch_2</code> based on <code>main</code> rather than <code>feature_branch_1</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-272.png" alt="Image" width="600" height="400" loading="lazy">
<em>The commit history after performing rebase (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>The syntax is of the command is:</p>
<pre><code>git rebase --onto &lt;new_parent&gt; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">old_parent</span>&gt;</span></span>
</code></pre><h2 id="heading-how-to-rebase-on-a-single-branch">How to rebase on a single branch</h2>
<p>You can also use <code>git rebase</code> while looking at a history of a single branch.</p>
<p>Let's see if you can help me here.</p>
<p>Say I worked from <code>feature_branch_2</code>, and specifically edited the file <code>code.py</code>. I started by changing all strings to be wrapped by double quotes rather than single quotes:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-273.png" alt="Image" width="600" height="400" loading="lazy">
<em>Changing <code>'</code> into <code>"</code> in <code>code.py</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Then, I staged and committed:</p>
<pre><code>git add code.py
git commit -m <span class="hljs-string">"Commit 17"</span>
</code></pre><p>I then decided to add a new function at the beginning of the file:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-274.png" alt="Image" width="600" height="400" loading="lazy">
_Adding the function <code>another_feature</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)_</p>
<p>Again, I staged and committed:</p>
<pre><code>git add code.py
git commit -m <span class="hljs-string">"Commit 18"</span>
</code></pre><p>And now I realized I actually forgot to change the single quotes to double quotes wrapping the <code>__main__</code> (as you might have noticed), so I did that too:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-275.png" alt="Image" width="600" height="400" loading="lazy">
<em>Changing <code>'__main__'</code> into <code>"__main__"</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Of course, I staged and committed this change:</p>
<pre><code>git add code.py
git commit -m <span class="hljs-string">"Commit 19"</span>
</code></pre><p>Now, consider the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-276.png" alt="Image" width="600" height="400" loading="lazy">
<em>The commit history after introducing "Commit 19" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>It isn't really nice, is it? I mean, I have two commits that are related to one another, "Commit 17" and "Commit 19" (turning <code>'</code>s into <code>"</code>s), but they are split by the unrelated "Commit 18" (where I added a new function). What can we do? 🤔 Can you help me?</p>
<p>Intuitively, I want to edit the history here:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-277.png" alt="Image" width="600" height="400" loading="lazy">
<em>These are the commits I want to edit (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p> So, what would you do?</p>
<p>You are right! 👏🏻</p>
<p>I can rebase the history from "Commit 17" to "Commit 19", on top of "Commit 15". To do that:</p>
<pre><code>git rebase --interactive --onto &lt;SHA_OF_COMMIT_15&gt; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SHA_OF_COMMIT_15</span>&gt;</span></span>
</code></pre><p>Notice I specified "Commit 15" as the beginning of the range of commits, excluding this commit. And I didn't need to explicitly specify <code>HEAD</code> as the last parameter.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-279.png" alt="Image" width="600" height="400" loading="lazy">
<em>Using <code>rebase --onto</code> on a single branch (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>After following your advice and running the <code>rebase</code> command (thanks! 😇) I get the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-280.png" alt="Image" width="600" height="400" loading="lazy">
<em>Interactive rebase (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>So what would I do? I want to put "Commit 19" <em>before</em> "Commit 18", so it comes right after "Commit 17". I can go further and squash them together, like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-281.png" alt="Image" width="600" height="400" loading="lazy">
<em>Interactive rebase - changing the order of commit and squashing (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Now when I get prompted for a commit message, I can provide the message "Commit 17+19":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-282.png" alt="Image" width="600" height="400" loading="lazy">
<em>Providing a commit message (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>And now, see our beautiful history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-283.png" alt="Image" width="600" height="400" loading="lazy">
<em>The resulting history (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Thanks again! 🙌🏻</p>
<h1 id="heading-more-rebase-use-cases-more-practice">More Rebase Use Cases + More Practice</h1>
<p>By now I hope you feel comfortable with the syntax of rebase. The best way to actually understand it is to consider various cases and figure out how to solve them yourself. </p>
<p>With the upcoming use cases, I strongly suggest you stop reading after I've introduced each use case, and then try to solve it on your own.</p>
<h2 id="heading-how-to-exclude-commits">How to Exclude Commits</h2>
<p>Say you have this history on another repo:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-284.png" alt="Image" width="600" height="400" loading="lazy">
<em>Another commit history (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Before playing around with it, store a tag to "Commit F" so you can get back to it later:</p>
<pre><code>git tag original_commit_f
</code></pre><p>Now, you actually don't want the changes in "Commit C" and "Commit D" to be included. You could use an interactive rebase like before and remove their changes. Or, could can use again <code>git rebase -–onto</code>. How would you use <code>--onto</code> in order to "remove" these two commits?</p>
<p>You can rebase <code>HEAD</code> on top of "Commit B", where the old parent was actually "Commit D", and now it should be "Commit B". Consider the history again:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-284.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history again (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Rebasing so that "Commit B" is the base of "Commit E", means "moving" both "Commit E" and "Commit F", and giving them another <em>base</em> – "Commit B". Can you come up with the command yourself?</p>
<pre><code>git rebase --onto &lt;SHA_OF_COMMIT_B&gt; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SHA_OF_COMMIT_D</span>&gt;</span> HEAD</span>
</code></pre><p>Notice that using the syntax above would not move <code>main</code> to point to the new commit, so the result is a "detached" <code>HEAD</code>. If you use <code>gg</code> or another tool that displays the history reachable from branches it might confuse you:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-285.png" alt="Image" width="600" height="400" loading="lazy">
<em>Rebasing with <code>--onto</code> results in a detached <code>HEAD</code> (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>But if you simply use <code>git log</code> (or my alias <code>git lol</code>), you will see the desired history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-286.png" alt="Image" width="600" height="400" loading="lazy">
<em>The resulting history (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>I don't know about you, but these kinds of things make me really happy. 😊😇</p>
<p>By the way, you could omit <code>HEAD</code> from the previous command as this is the default value for the third parameter. So just using:</p>
<pre><code>git rebase --onto &lt;SHA_OF_COMMIT_B&gt; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SHA_OF_COMMIT_D</span>&gt;</span></span>
</code></pre><p>Would have the same effect. The last parameter actually tells Git where the end of the current sequence of commits to rebase is. So the syntax of <code>git rebase --onto</code> with three arguments is:</p>
<pre><code>git rebase --onto &lt;new_parent&gt; &lt;old_parent&gt; &lt;until&gt;
</code></pre><h2 id="heading-how-to-move-commits-across-branches">How to move commits across branches</h2>
<p>So let's say we get to the same history as before:</p>
<pre><code>git checkout original_commit_f
</code></pre><p>And now I want only "Commit E", to be on a branch based on "Commit B". That is, I want to have a new branch, branching from "Commit B", with only "Commit E".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-287.png" alt="Image" width="600" height="400" loading="lazy">
<em>The current history, considering "Commit E" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>So, what does this mean in terms of rebase? Consider the image above. What commit (or commits) should I rebase, and which commit would be the new base?</p>
<p>I know I can count on you here 😉</p>
<p>What I want is to take "Commit E", and this commit only, and change its base to be "Commit B". In other words, to <em>replay</em> the changes introduced in "Commit E" onto "Commit B".</p>
<p>Can you apply that logic to the syntax of <code>git rebase</code>?</p>
<p>Here it is (this time I'm writing <code>&lt;COMMIT_B&gt;</code> instead of <code>&lt;SHA_OF_COMMIT_B&gt;</code>, for brevity):</p>
<pre><code>git rebase –-onto &lt;COMMIT_B&gt; &lt;COMMIT_D&gt; &lt;COMMIT_E&gt;
</code></pre><p>Now the history looks like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-288.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history after rebase (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Awesome!</p>
<h1 id="heading-a-note-about-conflicts">A Note About Conflicts</h1>
<p>Note that when performing a rebase, you may run into conflicts just as when merging. You may have conflicts because when rebasing, you are trying to apply patches on a different base, perhaps where the patches do not apply.</p>
<p>For example, consider the previous repository again, and specifically, consider the change introduced in "Commit 12", pointed to by <code>main</code>:</p>
<pre><code>git show main
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-289.png" alt="Image" width="600" height="400" loading="lazy">
<em>The patch introduced in "Commit 12" (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>I already covered the format of <code>git diff</code> in detail in <a target="_blank" href="https://www.freecodecamp.org/news/git-diff-and-patch/">a previous post</a>, but as a quick reminder, this commit instructs Git to add a line after the two lines of context:</p>
<pre><code>
</code></pre><p>This is a sample file</p>
<pre><code>
And before these three lines <span class="hljs-keyword">of</span> context:
</code></pre><pre><code>def new_feature():
  print(<span class="hljs-string">'new feature'</span>)
</code></pre><p>Say you are trying to rebase "Commit 12" onto another commit. If, for some reason, these context lines don't exist as they do in the patch on the commit you are rebasing <em>onto</em>, then you will have a conflict. To learn more about conflicts and how to resolve them, see <a target="_blank" href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/">this guide</a>.</p>
<h1 id="heading-zooming-out-for-the-big-picture">Zooming Out for the Big Picture</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-290.png" alt="Image" width="600" height="400" loading="lazy">
<em>Comparing rebase and merge (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>In the beginning of this guide, I started by mentioning the similarity between <code>git merge</code> and <code>git rebase</code>: both are used to integrate changes introduced in different histories. </p>
<p>But, as you now know, they are very different in how they operate. While merging results in a diverged history, rebasing results in a linear history. Conflicts are possible in both cases. And there is one more column described in the table above that requires some close attention.</p>
<p>Now that you know what "Git rebase" is, and how to use interactive rebase or <code>rebase --onto</code>, as I hope you agree, <code>git rebase</code> is a super powerful tool. Yet, it has one huge drawback when compared with merging.</p>
<p>Git rebase changes the history.</p>
<p>This means that you should <strong>not</strong> rebase commits that exist outside your local copy of the repository, and that other people may have based their commits on.</p>
<p>In other words, if the only commits in question are those you created locally – go ahead, use rebase, go wild.</p>
<p>But if the commits have been pushed, this can lead to a huge problem – as someone else may rely on these commits, that you later overwrite, and then you and they will have different versions of the repository. </p>
<p>This is unlike <code>merge</code> which, as we have seen, does not modify history.</p>
<p>For example, consider the last case where we rebased and resulted in this history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-288.png" alt="Image" width="600" height="400" loading="lazy">
<em>The history after rebase (Source: <a target="_blank" href="https://youtu.be/3VFsitGUB3s">Brief</a>)</em></p>
<p>Now, assume that I have already pushed this branch to the remote. And after I had pushed the branch, another developer pulled it and branched out from "Commit C". The other developer didn't know that meanwhile, I was locally rebasing my branch, and would later push it again.</p>
<p>This results in an inconsistency: the other developer works from a commit that is no longer available on my copy of the repository.</p>
<p>I will not elaborate on what exactly this causes in this guide, as my main message is that you should definitely avoid such cases. If you're interested in what would actually happen, I'll leave a link to a useful resource below. For now, let's summarize what we have covered.</p>
<h1 id="heading-recap">Recap</h1>
<p>In this tutorial, you learned about <code>git rebase</code>, a super-powerful tool to rewrite history in Git. You considered a few use cases where <code>git rebase</code> can be helpful, and how to use it with one, two, or three parameters, with and without the <code>--onto</code> switch.</p>
<p>I hope I was able to convince you that <code>git rebase</code> is powerful – but also that it is quite simple once you get the gist. It is a tool to "copy-paste" commits (or, more accurately, patches). And it's a useful tool to have under your belt.</p>
<h1 id="heading-additional-references">Additional References</h1>
<ul>
<li><a target="_blank" href="https://www.youtube.com/playlist?list=PL9lx0DXCC4BNUby5H58y6s2TQVLadV8v7">Git Internals YouTube playlist — by Brief</a> (my YouTube channel).</li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">Omer's previous post about Git internals.</a></li>
<li><a target="_blank" href="https://medium.com/@Omer_Rosenbaum/git-undo-how-to-rewrite-git-history-with-confidence-d4452e2969c2">Omer's tutorial about Git UNDO - rewriting history with Git</a>.</li>
<li><a target="_blank" href="https://git-scm.com/book/en/v2/Git-Branching-Rebasing">Git docs on rebasing</a></li>
<li><a target="_blank" href="https://jwiegley.github.io/git-from-the-bottom-up/1-Repository/7-branching-and-the-power-of-rebase.html">Branching and the power of rebase</a></li>
<li><a target="_blank" href="https://jwiegley.github.io/git-from-the-bottom-up/1-Repository/8-interactive-rebasing.html">Interactive rebasing</a></li>
<li><a target="_blank" href="https://womanonrails.com/git-rebase-onto">Git rebase --onto</a></li>
</ul>
<h1 id="heading-about-the-author"><strong>About the Author</strong></h1>
<p><a target="_blank" href="https://www.linkedin.com/in/omer-rosenbaum-034a08b9/">Omer Rosenbaum</a> is <a target="_blank" href="https://swimm.io/">Swimm</a>’s Chief Technology Officer. He's the author of the <a target="_blank" href="https://youtube.com/@BriefVid">Brief YouTube Channel</a>. He's also a cyber training expert and founder of Checkpoint Security Academy. He's the author of <a target="_blank" href="https://data.cyber.org.il/networks/networks.pdf">Computer Networks (in Hebrew)</a>. You can find him on <a target="_blank" href="https://twitter.com/Omer_Ros">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Git Change Commit Message – How to Edit Commit Messages with Git Amend ]]>
                </title>
                <description>
                    <![CDATA[ By Shittu Olumide Commit messages play a crucial role in Git version control. They provide a historical record of changes made to a repository.  Clear and descriptive commit messages help you collaborate better with team members, more easily maintain... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-edit-git-commit-messages-with-git-amend/</link>
                <guid isPermaLink="false">66d46103230dff016690586d</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 09 Jun 2023 17:58:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/06/Shittu-Olumide-Git-Change-Commit-Message---How-to-Edit-Commit-Messages-with-Git-Amend.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Shittu Olumide</p>
<p>Commit messages play a crucial role in Git version control. They provide a historical record of changes made to a repository. </p>
<p>Clear and descriptive commit messages help you collaborate better with team members, more easily maintain your code, and understand how the project works. </p>
<p>But there are times when you may need to edit a commit message due to typos, inaccuracies, or insufficient information. This is where Git <strong>amend</strong> comes into play.</p>
<p>In this article, we will explore the power of Git amend and its ability to modify commit messages. We will cover everything from identifying the commit to be amended to saving and pushing the changes. I'll, also share best practices, tips, and guidelines to help you make informed decisions about when and how to edit commit messages.</p>
<p>By understanding and utilizing Git amend effectively, you can maintain a clean and accurate commit history.</p>
<h2 id="heading-what-is-git-amend">What is Git amend?</h2>
<p>Git amend is a command in Git that allows you to make changes to the most recent commit in your repository without creating additional commits. It is particularly useful for editing commit messages, although you can also use it to add or remove files from the previous commit.</p>
<p>When you use Git amend, it modifies the most recent commit and replaces it with a new commit that includes the changes you made. This allows you to make corrections or improvements to the commit message or the content of the commit itself.</p>
<p>Git amend provides a convenient way to fix small mistakes or omissions in your commits without having to create a new commit altogether. It helps maintain a clean commit history by allowing you to make adjustments without cluttering the repository with unnecessary commits.</p>
<h2 id="heading-how-to-edit-git-commit-messages">How to Edit Git Commit Messages</h2>
<h3 id="heading-step-1-identify-the-commit-to-be-amended">Step 1: Identify the commit to be amended.</h3>
<p>Use the following command to view the commit history and identify the commit message you want to edit:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span>
</code></pre>
<p>Look for the specific commit hash or commit message that you want to amend.</p>
<h3 id="heading-step-2-edit-the-commit-message">Step 2: Edit the commit message.</h3>
<p>Once you've identified the commit, use the following command to amend the commit message without changing any other details:</p>
<pre><code class="lang-bash">git commit --amend --no-edit
</code></pre>
<p>This command will open the default text editor (usually Vim or nano) with the existing commit message. Make the necessary changes to the message.</p>
<p>Then save and exit the text editor.</p>
<h3 id="heading-step-3-save-the-changes">Step 3: Save the changes.</h3>
<p>After editing the commit message, Git will update the commit with the amended message. But it's crucial to review the changes before saving.</p>
<p>You can use the following command to review the changes made to the commit message:</p>
<pre><code class="lang-bash">git show HEAD
</code></pre>
<p>This will display the changes you made to the commit message. Make sure that the changes are correct and reflect the desired message.</p>
<h3 id="heading-step-4-push-the-amended-commit">Step 4: Push the amended commit.</h3>
<p>Pushing amended commits can be problematic if you have already pushed the original commit to a shared repository. It's generally advised not to amend commits that have been pushed and shared with others, as it can lead to conflicts.</p>
<p>If the commit has not been pushed yet or if you're working in a local repository, you can push the amended commit using the following command:</p>
<pre><code class="lang-bash">git push --force origin &lt;branch-name&gt;
</code></pre>
<p>Be cautious when using the <code>--force</code> option, as it overwrites the remote branch with your local changes. Make sure to communicate with team members before using this option.</p>
<p>That's it! You have successfully learned how to use Git amend to edit a commit message.</p>
<h2 id="heading-why-clear-and-descriptive-commit-messages-are-important">Why Clear and Descriptive Commit Messages Are Important</h2>
<p>Clear and descriptive commit messages are essential in version control systems like Git for several reasons:</p>
<ol>
<li><strong>Communication</strong>: Commit messages serve as a form of communication between developers. When collaborating on a project, clear and descriptive commit messages help team members understand the purpose and intent behind changes made to the codebase. </li>
<li><strong>Understanding Changes</strong>: Commit messages provide context and clarity about the changes made in a particular commit. They help answer questions such as why a change was made, what problem it addresses, and how it affects the codebase. </li>
<li><strong>Debugging and Issue Tracking</strong>: When encountering a bug or an issue, commit messages can provide crucial information for debugging and tracking down the source of the problem. By examining commit messages, developers can identify the specific changes that may have introduced the bug or caused the issue, making it easier to pinpoint and fix the problem.</li>
<li><strong>Documentation and Historical Reference</strong>: Commit messages serve as a form of documentation for the project's history. They provide a chronological record of changes made to the codebase, documenting the evolution of the project over time.</li>
<li><strong>Code Maintenance and Maintenance Handover</strong>: Well-crafted commit messages make code maintenance more manageable. When maintaining a project, developers can refer to commit messages to understand the rationale behind previous changes and make informed decisions about further modifications. </li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Git amend is a powerful tool that allows developers to edit commit messages and improve the clarity and accuracy of their version control history. By following the step-by-step guide outlined in this article, you can easily modify commit messages in your Git repository.</p>
<p>However, it's important to use Git amend judiciously. While it can be beneficial to correct minor typos or add missing details, excessive use of Git amend can lead to confusion and disrupt the integrity of the commit history. </p>
<p>It's important to strike a balance between maintaining accurate information and preserving the chronological order and context of commits.</p>
<p>For further learning on Git commit messages and version control best practices, you can explore additional resources such as Git documentation, tutorials, and online communities.</p>
<p>Let's connect on <a target="_blank" href="https://www.twitter.com/Shittu_Olumide_">Twitter</a> and on <a target="_blank" href="https://www.linkedin.com/in/olumide-shittu">LinkedIn</a>. You can also subscribe to my <a target="_blank" href="https://www.youtube.com/channel/UCNhFxpk6hGt5uMCKXq0Jl8A">YouTube</a> channel.</p>
<p>Happy Coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Git Abort Merge – How to Cancel a Merge in Git ]]>
                </title>
                <description>
                    <![CDATA[ By Shittu Olumide Version control is a system that helps manage changes to files and directories over time. It allows multiple people to collaborate on a project, keep track of modifications, and revert to previous versions if needed.  One of the mos... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/git-abort-merge-how-to-cancel-a-merge-in-git/</link>
                <guid isPermaLink="false">66d460f838f2dc3808b790e5</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 30 May 2023 14:18:30 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/Shittu-Olumide-Git-Abort-Merge---How-to-Cancel-a-Merge-in-Git.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Shittu Olumide</p>
<p>Version control is a system that helps manage changes to files and directories over time. It allows multiple people to collaborate on a project, keep track of modifications, and revert to previous versions if needed. </p>
<p>One of the most popular version control systems is Git. <a target="_blank" href="https://git-scm.com/">Git</a> is a distributed version control system (DVCS) that was created by Linus Torvalds in 2005. It was designed to handle the complexities of managing the Linux kernel's source code, but it has since become widely adopted and used for various software development projects. </p>
<p>Git is known for its speed, flexibility, and ability to handle both small and large-scale projects efficiently.</p>
<p>The core concept of Git revolves around the repository, which is a collection of files and directories that make up a project. Each user has a complete local copy of the repository, including its full history. This distributed nature allows for offline work and provides redundancy in case of server failures.</p>
<h2 id="heading-what-is-git-merge">What is Git Merge?</h2>
<p>Git merge is a fundamental operation in Git that combines changes from different branches into a single branch. It allows developers to integrate new features, bug fixes, or updates made in one branch with the changes in another branch. This process is crucial for collaboration and maintaining a coherent codebase.</p>
<p>In Git, a branch is a lightweight, movable pointer to a specific commit within a repository's commit history. It represents an independent line of development and developers typically create branches for various purposes, such as: feature development, bug fixes, experimental work, release management simultaneously without interfering with each other's changes.</p>
<p>There are different types of merges in Git:</p>
<ol>
<li><strong>Fast-forward merge</strong>: This type of merge occurs when the branch being merged is ahead of the branch being merged into. In this case, Git simply moves the branch pointer forward to incorporate the new commits. It's a straightforward and automatic process that doesn't create a new commit.</li>
<li><strong>Recursive merge</strong>: A recursive merge is the most common type of merge in Git. It combines the changes from two branches with divergent histories. Git analyzes the commit history and identifies a common ancestor, then applies the changes from both branches to create a new merge commit. If there are conflicts, manual resolution may be required.</li>
<li><strong>Octopus merge</strong>: An octopus merge occurs when merging more than two branches simultaneously. It allows combining multiple branches into a single branch in one operation. This type of merge is useful for consolidating changes from different feature branches into a release branch.</li>
</ol>
<p>While merging is typically a straightforward process, there are scenarios where cancelling a merge becomes necessary:</p>
<ol>
<li><strong>Conflict resolution issues</strong>: When merging branches with conflicting changes, Git may prompt for manual conflict resolution. If the conflicts are difficult to resolve or lead to unexpected issues, cancelling the merge allows developers to reevaluate the changes and find alternative solutions.</li>
<li><strong>Incorrect merge selection</strong>: In complex development workflows with multiple branches, it's possible to accidentally initiate a merge with the wrong branch. Cancelling the merge helps avoid merging unintended changes and allows developers to correct the mistake.</li>
<li><strong>Unexpected changes or regressions</strong>: Sometimes, during the merge process, unexpected changes or regressions may occur in the merged branch. If these changes are significant or break the functionality of the codebase, cancelling the merge allows developers to investigate and address the issues before proceeding with the merge.</li>
<li><strong>Abandoned or incomplete changes</strong>: If a merge involves changes that are abandoned or incomplete, cancelling the merge can prevent unfinished or unnecessary changes from being incorporated into the codebase. It ensures that only fully tested and complete changes are merged.</li>
<li><strong>Rollback to a previous state</strong>: In some cases, a merge may introduce undesirable changes or regressions that cannot be easily resolved. Cancelling the merge allows developers to roll back to the state before the merge and maintain a stable codebase until the issues can be resolved properly.</li>
</ol>
<h2 id="heading-step-by-step-guide-to-abort-a-merge">Step-by-Step Guide to Abort a Merge</h2>
<h3 id="heading-check-the-merge-status-before-aborting">Check the merge status before aborting:</h3>
<ol>
<li>Open your Git command-line interface or terminal.</li>
<li>Navigate to the repository where the merge operation is in progress.</li>
<li>Use the command <code>git status</code> to check the current status of the repository.</li>
<li>Look for any messages or indications of an ongoing merge process.</li>
</ol>
<h3 id="heading-execute-the-git-merge-abort-command">Execute the <code>git merge --abort</code> command:</h3>
<ol>
<li>If you have confirmed that a merge operation is indeed in progress and needs to be cancelled, execute the following command:</li>
</ol>
<pre><code class="lang-git">git merge --abort
</code></pre>
<ol start="2">
<li>Press Enter to execute the command.</li>
</ol>
<h3 id="heading-verify-the-successful-cancellation-of-the-merge">Verify the successful cancellation of the merge</h3>
<ol>
<li>After executing the command, Git will attempt to abort the merge process.</li>
<li>Git will display a message indicating whether the merge was successfully cancelled.</li>
<li>Use the command <code>git status</code> again to check the repository's status.</li>
<li>Ensure that the status reflects the cancellation of the merge and that there are no remaining indications of an ongoing merge.</li>
</ol>
<h3 id="heading-handle-conflicts-or-inconsistencies-after-the-merge-cancellation">Handle conflicts or inconsistencies after the merge cancellation</h3>
<ol>
<li>In some cases, cancelling a merge can leave the repository in a conflicted state.</li>
<li>Use the command <code>git status</code> to identify any remaining conflicts or inconsistencies.</li>
<li>If conflicts exist, resolve them manually by editing the conflicting files.</li>
<li>After resolving conflicts, use the command <code>git add &lt;file&gt;</code> to stage the changes.</li>
<li>Finally, use the command <code>git commit</code> to complete the process and create a new commit.</li>
</ol>
<p>Note: It's important to remember that aborting a merge may result in lost changes, so it should be done with caution. Always ensure you have a backup or another copy of your work before proceeding with the merge cancellation.</p>
<h2 id="heading-git-abort-merge-best-practices">Git Abort Merge Best Practices</h2>
<p>When it comes to aborting a Git merge, there are several best practices and tips that can help ensure a smooth process. Here are some recommendations:</p>
<ol>
<li><strong>Create a backup</strong>: If possible, create a backup or a branch snapshot before aborting the merge. This ensures that you have a point of reference in case you need to recover any lost work or investigate the merge later.</li>
<li><strong>Review the merge process</strong>: Take the opportunity to review the merge process that led to the need for an abort. Identify any patterns, pitfalls, or areas for improvement to prevent similar issues in future merges.</li>
<li><strong>Resolve conflicts if necessary</strong>: Before aborting the merge, make sure to resolve any conflicts that have arisen. Use Git's merge conflict resolution tools to address conflicts manually or consider using a merge tool for assistance.</li>
<li><strong>Communicate with collaborators</strong>: If you're working on a shared repository or collaborating with others, it's crucial to communicate your intention to abort the merge. Discuss the reasons behind the decision and coordinate with your team to avoid any conflicts or confusion.</li>
<li><strong>Clean up the working directory</strong>: After aborting the merge, ensure that your working directory is clean. Remove any residual files or artifacts from the aborted merge to avoid potential conflicts or confusion in future operations.</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, the <code>git merge --abort</code> command provides a simple and effective way to cancel or abort a merge operation, allowing you to revert back to the previous state of your repository. </p>
<p>By understanding and utilizing this command, you can avoid potential issues and conflicts that may arise during the merging process.</p>
<p>Let's connect on <a target="_blank" href="https://www.twitter.com/Shittu_Olumide_">Twitter</a> and on <a target="_blank" href="https://www.linkedin.com/in/olumide-shittu">LinkedIn</a>. You can also subscribe to my <a target="_blank" href="https://www.youtube.com/channel/UCNhFxpk6hGt5uMCKXq0Jl8A">YouTube</a> channel.</p>
<p>Happy Coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Git Best Practices – A Guide to Version Control for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ If you're a software developer, you may be familiar with the concept of version control. Version control is the practice of managing changes to your codebase over time. It's an essential tool for any development project. One of the most popular versi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-git-best-practices-for-beginners/</link>
                <guid isPermaLink="false">66d45d5ec17d4b8ace5b9eae</guid>
                
                    <category>
                        <![CDATA[ beginner ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Adekola Olawale ]]>
                </dc:creator>
                <pubDate>Tue, 16 May 2023 16:33:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/header-min-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're a software developer, you may be familiar with the concept of version control. Version control is the practice of managing changes to your codebase over time. It's an essential tool for any development project.</p>
<p>One of the most popular version control systems is Git, which is widely used by developers around the world. Git is a powerful and flexible tool that can help you manage your codebase, collaborate with other developers, and keep track of changes over time.</p>
<p>But Git can also be complex and intimidating, especially if you're new to version control. In this tutorial, we'll cover some of the best practices for using Git, including basic commands, remote repositories, and collaboration tools.</p>
<p>Whether you're a beginner or an experienced developer, this guide will help you get the most out of Git and improve your workflow.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-version-control">What is Version Control?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-git">What is Git?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-get-started-with-git">How to Get Started with Git</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-a-new-git-repository">How to Set Up a New Git Repository</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-basic-commands-to-create-and-commit-changes">Basic Commands to Create and Commit Changes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-collaborate-with-git">How to Collaborate with Git</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-for-using-git">Best Practices for Using Git</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-version-control">What is Version Control?</h2>
<p>Version control is the management of changes to documents, files, or any other type of data. In software development, it is essential for managing and tracking changes to the codebase, ensuring code quality, reducing errors, and improving collaboration among team members.</p>
<p>Without version control, managing and tracking code changes would be a difficult and error-prone task. Version control tools like Git provide a way to manage code changes, keep track of versions, and collaborate with team members. This makes it a critical component of modern software development, used by virtually all software development teams.</p>
<h2 id="heading-what-is-git">What is Git?</h2>
<p>Git is a popular version control system used by developers to manage changes to code. It allows developers to track changes made to their codebase, collaborate with team members, and revert to previous versions if needed.</p>
<p>Git is widely used in software development due to its flexibility, speed, and ability to handle large codebases with ease. It also offers a range of features and tools for managing and organizing code, such as branching and merging. And it has a large and active community of users who contribute to its development and provide support.</p>
<h2 id="heading-how-to-get-started-with-git">How to Get Started with Git</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/FireShot-Capture-140---Git---Downloads---git-scm.com.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Download Page</em></p>
<h3 id="heading-how-to-install-git">How to Install Git</h3>
<p>Git is a popular version control system used by software developers to manage and track changes to code. Here are the steps to install Git:</p>
<h4 id="heading-step-1-download-git">Step 1: Download Git</h4>
<p>To get started, go to the official Git website (<a target="_blank" href="https://git-scm.com/downloads">https://git-scm.com/downloads</a>) and download the appropriate installer for your operating system.</p>
<p>As you can see on the download page in the graphic, the Git download page is smart enough to pick the OS (operating system) you are using – it is based on this that the desktop graphic will show the download button inside it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-installer-ui-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Installer UI</em></p>
<h4 id="heading-step-2-run-the-installer">Step 2: Run the Installer</h4>
<p>Once the download is complete, run the installer and follow the prompts. The installation process will vary depending on your operating system, but the installer should guide you through the process.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-installer-ui-step2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Installation Options</em></p>
<h4 id="heading-step-3-select-installation-options">Step 3: Select Installation Options</h4>
<p>During the installation process, you'll be prompted to select various options. For most users, the default options will be sufficient, but you can choose to customize your installation if desired.</p>
<p>On Windows and macOS, you can accept the default installation options, but on Linux, you may need to customize the installation process depending on your distribution.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-installation-done-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Installation Done</em></p>
<h4 id="heading-step-4-complete-the-installation">Step 4: Complete the Installation</h4>
<p>Once you've selected your installation options, the installer will install Git on your computer. This may take a few minutes depending on your system.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-bash-snippet.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Verify Git Installation</em></p>
<h4 id="heading-step-5-verify-the-installation">Step 5: Verify the Installation</h4>
<p>After the installation is complete, you can verify that Git has been installed correctly by opening a command prompt or terminal window and running the command <code>git --version</code>. This should display the current version of Git that is installed on your system, something like <code>git version 2.40.1.windows.1</code>.</p>
<h3 id="heading-how-to-set-up-a-new-git-repository">How to Set Up a New Git Repository</h3>
<p>Git repositories are used to manage and track changes to code. Setting up a new Git repository is a simple process that just takes a few steps.</p>
<h4 id="heading-step-1-create-a-new-directory">Step 1: Create a New Directory</h4>
<p>The first step in setting up a new Git repository is to create a new directory on your computer. This directory will serve as the root directory of your new repository.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-bash-init-snippet.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><code>git init</code></p>
<h4 id="heading-step-2-initialize-git">Step 2: Initialize Git</h4>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-file.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>.git file</em></p>
<p>Once you have Git installed, the next step is to initialize a new repository. To do this, navigate to the root directory of your project in the command line or terminal and run the command <code>git init</code>. This will create a new <strong>.git</strong> directory in your project's root directory, which is where Git stores all of its metadata and version control information.</p>
<p>Once you’ve initialized the repository, you can start tracking changes to your project and making commits. It’s important to note that you only need to initialize a repository once for each project, so you won’t need to repeat this step for subsequent commits or changes.</p>
<h4 id="heading-step-3-add-files">Step 3: Add Files</h4>
<p>After initializing your Git repository, the next step is to start tracking changes to your project by adding files to the staging area.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-stage.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Staging files</em></p>
<p>To do this, use the command <code>git add &lt;filename&gt;</code> to add each file to the staging area. You can also use the command <code>git add .</code> to add all of the files in the current directory and its subdirectories to the staging area at once.</p>
<p>Also, as you see in the graphic above, there's a label of <strong>(master)</strong> after the <strong>~/Desktop/Projects/GIT for Beginners</strong>. The <strong>(master)</strong> signifies the current branch for the project. This is the default branch for all projects that initialize Git.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-staging.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Staging Snippet</em></p>
<p>Once a file is added to the staging area, it's ready to be committed to the repository. It's important to note that adding files to the staging area doesn't actually commit them – it just prepares them for the commit. You can continue to add and modify files as needed before making a commit.</p>
<h4 id="heading-step-4-commit-changes">Step 4: Commit Changes</h4>
<p>After adding files to the staging area, the next step is to commit the changes to your repository using the <code>git commit</code> command.</p>
<p>When committing changes, it's important to provide a clear and descriptive message that explains what changes you made in the commit. This message will be used to track the changes in the repository's history and will help other contributors understand the changes you made.</p>
<p>To commit changes, use the command <code>git commit -m 'commit message'</code> , replacing '<code>commit message</code>' with a clear and descriptive message that explains the changes made in the commit. Once committed, the changes will be saved to the repository's history and can be tracked, reverted, or merged with other branches as needed.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-commit.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git commit</em></p>
<h4 id="heading-step-5-connect-to-a-remote-repository">Step 5: Connect to a Remote Repository</h4>
<p>To share your changes with other developers or collaborate on a project, you can connect your local repository to a remote repository using Git.</p>
<p>A remote repository is a copy of your repository that is hosted on a server, such as GitHub, GitLab, or BitBucket, and allows multiple contributors to work on the same codebase.</p>
<p>To connect to a remote repository, use the <code>git remote add</code> command followed by the URL of the remote repository.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-add.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Connect to Remote Repository</em></p>
<p>For example, to connect to a GitHub repository, you would use the command <code>git remote add origin &lt;repository URL&gt;</code>. Before you can even connect to the remote repository, you need to create it.</p>
<p>Navigate to <a target="_blank" href="https://scribehow.com/shared/How_to_Create_a_New_Repository_on_GitHub__OGEKiV2UT42dB8Kre8KfCg">S</a>cribe and follow the steps to create a repository on GitHub. But before doing this, you need to create a GitHub account if you don’t have one already.</p>
<p>Once connected, you can push your changes to the remote repository using this <code>git push -u &lt;default branch&gt;</code> command. This command is often used when pushing changes for the first time to establish the relationship between the local branch and the remote branch.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-push.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git First Remote Push</em></p>
<p>However, for subsequent push changes, use the command <code>git push</code> without specifying any additional arguments. Git will attempt to push changes from the current local branch on your local machine (computer) to the corresponding branch on the remote repository. It assumes that the local branch and the remote branch have the same name.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-push2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Subsequent Remote Push</em></p>
<p>The <code>git pull</code> command fetches the latest changes made by other contributors from a remote repository and automatically merges them into the current branch. By connecting to a remote repository, you can collaborate with other developers and contribute to open-source projects.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-pull.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Pull</em></p>
<p>By following these simple steps, you can set up a new Git repository and start managing changes to your codebase.</p>
<h3 id="heading-basic-commands-to-create-and-commit-changes">Basic Commands to Create and Commit Changes</h3>
<p>Once you've set up a new Git repository and added some files to it, you'll need to commit changes to your repository. Here are the basic commands to create and commit changes in Git.</p>
<h4 id="heading-step-1-check-the-status">Step 1: Check the Status</h4>
<p>Before committing changes, you should check the status of your repository to see what changes have been made. To do this, run the command <code>git status</code> in a terminal or command prompt window.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-status.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Status</em></p>
<h4 id="heading-step-2-stage-changes">Step 2: Stage Changes</h4>
<p>To commit changes, you'll need to stage them first using the <code>git add</code> command. This tells Git which files to include in the next commit. You can stage all changes by running the command <code>git add .</code> or stage specific changes by running the command <code>git add &lt;filename&gt;</code> .</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-stage-css.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Staging</em></p>
<p>When you stage changes, Git takes a snapshot of the files at that moment in time. This snapshot includes all of the changes you've made since the last commit.</p>
<p>Staging changes allows you to carefully review your changes before committing them. You can stage changes in small chunks and commit them separately, or stage all changes and commit them together. This gives you more control over the changes you make to your codebase and helps you keep track of what changes have been made over time.</p>
<p>By staging changes in Git, you can ensure that your commits accurately reflect the changes you've made to your codebase.</p>
<h4 id="heading-step-3-commit-changes">Step 3: Commit Changes</h4>
<p>Once you’ve staged your changes, you can commit them to your repository using the <code>git commit</code> command. This creates a new snapshot of your repository with the changes you made.</p>
<p>The commit is a snapshot of the changes made then, and it includes a reference to the previous commit in the branch’s history. This allows developers to track the changes made to the code over time, collaborate with other developers, and roll back to previous versions of the code if necessary.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-commit2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Commit</em></p>
<p>You’ll need to include a commit message to describe the changes you made using the <code>-m</code> flag. For example, <code>git commit -m Added new feature</code>the "<code>Added new feature</code>“ part is what the commit is called.</p>
<p>By including a clear and concise commit message like "<code>Added new feature</code>," other developers can quickly understand the purpose of the commit and what changes were made. This makes collaboration and code maintenance easier.</p>
<h4 id="heading-step-4-push-changes">Step 4: Push Changes</h4>
<p>If you’re working on a team or want to share your changes with others, you can push your changes to a remote repository using this <code>git push</code> command. This uploads your changes to a shared repository that others can access.</p>
<p>To push changes to a remote repository, you’ll first need to add a remote URL using the <code>git remote add</code> command. This tells Git where to push your changes.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-add-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git</em></p>
<p>For example, <code>git remote add origin[https://github.com/username/repository.git](https://github.com/username/repository.git)</code>. Before you get a remote URL to push, you need to create a repository on your GitHub account. To do this, navigate to <a target="_blank" href="https://bit.ly/417ULB7">https://bit.ly/417ULB7</a> .</p>
<p>By adding a remote repository, you establish a connection between your local repository and the remote repository, allowing you to push and pull changes between them.</p>
<p>Here's what <code>git remote add &lt;repository URL&gt;</code> does:</p>
<ol>
<li><p><code>git remote</code>: It is a Git command that manages the remote repositories associated with your local repository.</p>
</li>
<li><p><code>add</code>: It is an option used with the <code>git remote</code> command to add a new remote repository.</p>
</li>
<li><p><code>&lt;repository URL&gt;</code>: This is the URL of the remote repository you want to add. It typically points to the Git repository hosting service where your remote repository resides.</p>
</li>
</ol>
<p>Once you've added a remote URL, you can push your changes to the remote repository using the <code>git push</code> command. For example, <code>git push origin master</code> pushes changes to the "<code>master</code>" branch of the remote repository.</p>
<p>It's important to note that you'll need the appropriate permissions to push changes to a remote repository. If you're working on a team, you may need to coordinate with others to ensure you have the necessary permissions.</p>
<p>Pushing changes to a remote repository makes it easier for you to collaborate with others on software development projects and ensure that your team members are working with the latest version of the codebase.</p>
<p>By following these basic commands, you can create and commit changes to your Git repository. With Git, you can easily track changes to your codebase and collaborate with others on software development projects.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/collaboration-vector-min.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-collaborate-with-git">How to Collaborate with Git</h2>
<p>A key benefit of using Git is its ability to facilitate collaboration between developers. Git allows you to work on the same codebase with others simultaneously, without overwriting other developers’ changes.</p>
<p>To collaborate on a Git project, you typically use a central repository that serves as the source of truth for the project. Each developer has a local copy of the repository on their machine, and they make changes and commit them to their local repository.</p>
<p>When you’re ready to share your changes with the rest of the team, you push your changes to the central repository. Other team members can then pull those changes down to their local repositories.</p>
<h3 id="heading-what-are-remote-repositories">What are Remote Repositories?</h3>
<p>Remote repositories are an essential component of Git workflows. A <em>remote repository</em> is a version-controlled repository that is hosted on a remote server. It can be accessed and modified by multiple developers from different locations.</p>
<p>Using remote repositories lets you efficiently collaborate with other developers on the same codebase, share your work with others, and track changes made to the codebase over time.</p>
<p>In Git, remote repositories are typically hosted on platforms such as GitHub, GitLab, or Bitbucket, and you can access them using the Git command line or a graphical user interface.</p>
<p>When working with remote repositories, you can push your local changes to the remote repository or pull changes from the remote repository to your local copy to keep your codebase up-to-date.</p>
<p>Git provides powerful tools for managing remote repositories, such as creating branches, managing pull requests, and resolving merge conflicts. This makes it a popular choice for distributed software development teams.</p>
<p>By using remote repositories in Git, you can collaborate with others on software development projects and share your codebase with them.</p>
<h3 id="heading-how-to-clone-a-repository">How to Clone a Repository</h3>
<p>Cloning a repository is a common task when working with Git. Cloning creates a local copy of a remote repository, including all the files and history of the project.</p>
<p>Cloning a repository is straightforward in Git, and you can do it in several ways, such as using the command line or a graphical user interface. It’s a simple process that enables you to access the repository’s code, commit history, and branches. Let’s walk through the steps involved in cloning a repository:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-clone.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Copy Repository URL</em></p>
<ol>
<li><p><strong>Copy the repository URL</strong>: Start by obtaining the URL of the remote repository you want to clone. You can find this URL on the repository’s hosting platform, such as GitHub or GitLab.</p>
</li>
<li><p><strong>Open a terminal or command prompt.</strong> Open your preferred command-line interface. This could be the Terminal on macOS and Linux or the Command Prompt on Windows.</p>
</li>
<li><p><strong>Navigate to the Desired Location</strong>: Use the<code>cd</code> command to navigate to the directory where you want to clone the repository. For example, if you want to clone it into the "Projects" directory on your desktop, you would run <code>cd ~/Desktop/Projects</code>.</p>
</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/terminal-cd.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Changing directory</em></p>
<ol start="4">
<li><strong>Clone the repository</strong>: Execute the<code>git clone</code> command followed by the repository URL. This command initiates the cloning process and creates a local copy of the repository. For instance, to clone a repository with the URL, you would run <code>git clone [https://github.com/username/repository.git](https://github.com/username/repository.git.)</code><a target="_blank" href="https://github.com/username/repository.git.">.</a></li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-cloning.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Cloning</em></p>
<ol start="5">
<li><strong>Verify the Cloning Process</strong>: Once the cloning process completes, you will see the repository’s files and commit history in the specified directory. You can now navigate into the cloned repository using<code>cd repository</code> (where the name of the directory is the same as the cloned repository).</li>
</ol>
<p>If you observe the graphic below, the<code>cd better-commits</code> command changes the directory to the better-commits directory, which has the same name as the cloned repository, as explained earlier. To further verify if there are any cloned files in the directory, the<code>ls</code> command is used to list all the files in the directory.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/verify-clone.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Verify</em> <code>git clone</code></p>
<p>That’s it! You have successfully cloned a Git repository to your local machine. You can now start working with the code, make changes, and utilize Git’s version control features to manage your project effectively.</p>
<p>The<code>git clone &lt;repository URL&gt;</code> command is used to create a copy of a remote Git repository on your local machine. It allows you to retrieve the entire history, branches, and files from the remote repository and sets up a local copy that you can work with.</p>
<p>Here’s what <code>git clone &lt;repository URL&gt;</code> does:</p>
<ol>
<li><p><code>git clone</code>It is a Git command that creates a clone or copy of a remote Git repository.</p>
</li>
<li><p><code>&lt;repository URL&gt;</code>This is the URL of the remote repository you want to clone. It typically points to the Git repository hosting service where the remote repository is located.</p>
</li>
</ol>
<p>When you run the <code>git clone &lt;repository URL&gt;</code> command, it creates a new directory on your local machine with the same name as the remote repository. It initializes a new Git repository within that directory and copies all the files and commits history from the remote repository into the local repository.</p>
<p>Additionally, the <code>git clone</code> command automatically sets up a connection between your local repository and the remote repository. It configures the remote repository as the default upstream source and assigns a name <code>origin</code> to it.</p>
<p>Cloning repositories is a key part of Git workflows and an essential tool for distributed software development teams, whether you are collaborating with others, contributing to open-source projects, or simply working on your projects. It enables you to have a local copy of the codebase and keeps you in sync with the latest changes from the remote repository.</p>
<h3 id="heading-how-to-push-and-pull-changes-in-git">How to Push and Pull Changes in Git</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-push-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Push setting upstream branch</em></p>
<p>The upstream branch refers to the branch on a remote repository that your local branch is associated with. It represents the remote branch that your local branch will be synchronized with when using commands like <code>git pull</code> or <code>git push</code>.</p>
<p>When you set up an upstream branch, it establishes a connection between your local branch and the corresponding branch in the remote repository. This connection allows you to easily push and pull changes between the local and remote branches.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-push2-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Push without setting an upstream branch</em></p>
<p>Conversely, when you want to update your local copy of the repository with changes made by others, you can pull the changes from the remote repository using the <code>git pull</code> command. Pulling updates to your local repository with the latest changes made to the remote repository.</p>
<p>These operations are essential for collaborating on a Git project and keeping everyone's local copy of the repository up to date with the latest changes.</p>
<p>Git provides tools for resolving conflicts that may arise when pushing or pulling changes, such as merging changes or choosing which changes to keep. By using pushing and pulling in Git workflows, you can work more efficiently and effectively on software development projects.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/best-practices-vector-min.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-best-practices-for-using-git">Best Practices for Using Git</h2>
<p>To get the most out of Git, it's important to follow best practices when working with the tool.</p>
<p>Some best practices include keeping commits small and focused, using clear and concise commit messages, branching frequently to isolate changes and reduce the risk of conflicts, and using pull requests for code reviews.</p>
<p>It's also important to regularly push changes to the remote repository, pull changes from the remote repository, and keep the local copy of the repository up to date.</p>
<p>Let's look at each of these a bit more in-depth now.</p>
<h3 id="heading-keep-commits-small-and-focused">Keep Commits Small and Focused</h3>
<p>When working with Git, it's important to keep commits small and focused on specific changes or features. This makes it easier to understand what was changed in each commit and helps reduce the risk of conflicts.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/short-focused-commit.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Short Commit Message</em></p>
<p>If a commit includes multiple changes, it can be difficult to understand the purpose of each change and how they relate to each other.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/long-commit.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Long Commit Message</em></p>
<p>On the other hand, if a commit is focused on a single change, it’s much easier to understand the purpose of that change and to revert it if necessary. Keeping commits small and focused also makes it easier to review changes and track the progress of a project over time.</p>
<p>In the <em>Long Commit Message</em> image graphic above, you can see that there are up to three changes that were implemented based on the commit message: The <code>-m</code> flag means message, and with this kind of message, it would be hard for developers reviewing your code changes to focus on because a couple of changes were implemented in just one commit.</p>
<p>To make the code changes easier to review, stick to one change, probably the <em>Fix broken link in the footer</em> change. Then commit the change accordingly, like in the <em>Short Commit Message</em> image graphic above.</p>
<p>Doing this will ease the workflow process for your team members, and they will enjoy working with you.</p>
<h3 id="heading-use-clear-and-concise-commit-messages">Use Clear and Concise Commit Messages</h3>
<p>When making changes to a codebase, it’s important to use clear and concise commit messages that describe what changes you made and why.</p>
<p>A good commit message should provide enough information to understand the context of the change without being too long or verbose. Clear and concise commit messages make it easier for other developers to understand what you changed and why, which is particularly important when reviewing changes or investigating issues.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-commit3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Concise Commit Message</em></p>
<p>As we discussed in the previous sections, each commit should be limited to just one change in the code. Keeping commit messages plain and succinct further builds on this by aiding your team members in understanding what each of your commits is all about.</p>
<p>A great commit message should be less than 10 words. When your commit message gets longer, it is beginning to become really wordy, and the main message of the commit may be lost.</p>
<p>These are examples of clear and effective commit messages:</p>
<ul>
<li><p>Update dependencies to latest versions</p>
</li>
<li><p>Add error handling for database connection</p>
</li>
<li><p>Remove debug console.log statements</p>
</li>
<li><p>Update styling for mobile responsiveness</p>
</li>
<li><p>Refactor variable names for clarity</p>
</li>
</ul>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">'Update dependencies to latest versions'</span>
git commit -m <span class="hljs-string">'Add error handling for database connection'</span>
git commit -m <span class="hljs-string">'Remove debug console.log statements'</span>
git commit -m <span class="hljs-string">'Update styling for mobile responsiveness'</span>
git commit -m <span class="hljs-string">'Refactor variable names for clarity'</span>
</code></pre>
<p>Using good commit messages also makes it easier to track changes over time and understand the history of a project.</p>
<p>By following this best practice, you can improve the quality and maintainability of your codebase and make it easier for yourself and others to work with the code in the future.</p>
<h3 id="heading-branch-frequently-to-isolate-changes">Branch Frequently to Isolate Changes</h3>
<p>Branching is a powerful feature of Git that allows you to work on different changes or features in isolation from the main codebase. By creating a branch for each change or feature, you can make and test changes without affecting the main codebase, and merge your changes back into the main codebase once the changes are complete.</p>
<p>Branching frequently also makes it easier to manage changes and collaborate with other developers. For example, if multiple developers are working on different changes, they can each create their own branches and merge them back into the main codebase once their changes are complete.</p>
<p>Branching frequently in CI/CD (Continuous Integration/Continuous Deployment) is a best practice that involves creating separate branches to isolate changes. It enables parallel development, allowing teams to work independently on different features or bug fixes without conflict. By working on isolated branches, developers can focus on their specific changes, run tests, and ensure stability.</p>
<p>This approach facilitates risk-free integration, as changes are thoroughly tested within the branches before merging them back into the main codebase. Branching frequently promotes efficient collaboration, accelerates development cycles, and enhances the overall quality of the software by providing a controlled environment for individual changes.</p>
<p>To create a branch, use <code>git branch &lt;branch-name&gt;</code> command in your terminal. To switch to the new branch, use <code>git checkout &lt;branch-name&gt;</code>. Also, you can combine these two steps into just one command: <code>git checkout -b &lt;branch-name&gt;</code>. This command will create the branch and simultaneously switch to the newly created branch.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-branch.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Branching</em></p>
<p>Observe in the <em>Git Branching</em> graphic image above that the <code>git checkout -b stellar-feature</code> command created and switched to the <code>stellar-feature</code> branch simultaneously. This is different from having to create the moonshot-experiment branch with the command <code>git branch moonshot-experiment</code> and then branching to it with the command, <code>git checkout moonshot-experiment</code>.</p>
<p>By following this best practice, you can reduce the risk of conflicts and errors in your codebase.</p>
<h3 id="heading-use-pull-requests-for-code-reviews">Use Pull Requests for Code Reviews</h3>
<p>Code reviews are an essential part of the software development process. They help ensure that code changes are of high quality, follow best practices, and meet the requirements of the project.</p>
<p>One way to facilitate code reviews is to use pull requests. Pull requests allow you to share your changes with others and request feedback before merging them into the main codebase.</p>
<p>By using pull requests, other developers can review your changes, provide feedback, and suggest improvements. Pull requests also make it easier to track changes and ensure that code changes are properly tested and documented before they are merged.</p>
<p>Using pull requests (PRs) for code reviews in open-source projects enables collaboration and quality control. Developers create a branch, make changes, push it to a forked repository, and submit a PR. Reviewers provide feedback, suggest changes, and discuss improvements. Once approved, changes are merged into the main project, ensuring a robust and well-reviewed codebase.</p>
<p>PRs foster community involvement and allow project maintainers to ensure code quality and maintain coding standards.</p>
<p>PRs for code reviews are mostly applied in two situations:</p>
<ul>
<li><p>Working on a project with team members in your company</p>
</li>
<li><p>Helping to improve open-source projects through bug fixes and adding new features.</p>
</li>
</ul>
<p>And these open-source projects can even be libraries or frameworks (for example, React, Vue, and others) you work with to build applications.</p>
<h4 id="heading-working-on-projects-with-team-members">Working on Projects with Team Members</h4>
<p>Building upon the previous best practices we discussed earlier, create a new branch and switch to it with the command <code>git checkout -b blackhole-security</code>. At this point, you can start working on the project and make sure you stick with working on the feature you created the branch for.</p>
<p>This means that you should only work on the <em>blackhole-security</em> feature in the project; do not start building a feature like <em>supernova-optimization</em>. This will make it easier for your code reviewer to review it down the road.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/git-pr.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Git Pull Request</em></p>
<p>Once you are done working on the <em>blackhole-security</em> feature, stage and commit the changes with just a <code>git commit -am 'Blackhole security fully implemented'</code> command. At this point, you can now go ahead and push your change to the remote repository for your project manager to review. You can do this with the command <code>git push origin blackhole-security</code>. Or if you were working on a branch named <em>planet-discovery</em>, you would go ahead with the command, <code>git push origin planet-discovery</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/annotely_image-pr.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Compare &amp; Pull Request</em></p>
<p>The <strong>Compare &amp; Pull Request</strong> graphic image above as you can see in the red rectangle has a button there to click to create a pull request.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/FireShot-Capture-143---Comparing-master...blackhole-security---Kola92_git-for-beginners---github.com.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Open Pull Request</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/FireShot-Capture-144---Blackhole-security-by-Kola92---Pull-Request--1---Kola92_git-for-begin_---github.com.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Merge Pull Request</em></p>
<p>The <strong>Open Pull Request</strong> graphic image above has the <strong>Create Pull Request</strong> button to open the pull request for code review. With the <strong>Merge Pull Request</strong> graphic image, this is the screen where your code reviewer provides feedback if any is needed before merging your PR into the <em>master</em> branch.</p>
<h4 id="heading-working-on-open-source-projects">Working on Open-Source Projects</h4>
<p>Before beginning collaboration on any open-source project, you will need to fork the open-source repository (a fork is a personal copy of a repository that allows independent development and contribution without altering the source code).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/FireShot-Capture-145---Fork-imartinez_privateGPT---github.com.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Create New Fork</em></p>
<p>When the repository is done forking, you can go ahead and clone the forked repository <code>git clone [https://github.com/Kola92/privateGPT.git](https://github.com/Kola92/privateGPT.git.)</code><a target="_blank" href="https://github.com/Kola92/privateGPT.git.">.</a></p>
<p>Once the forked repository has been cloned to your local machine, you can create a branch and switch to it. Then you can go ahead and start working on the project by committing, pushing to the remote repository, and creating a PR for code review.</p>
<p>Good PRs help improve the quality and maintainability of your codebase and ensure that changes are properly reviewed and approved before they are merged.</p>
<h3 id="heading-keep-the-repository-clean-and-up-to-date">Keep the Repository Clean and Up to Date</h3>
<p>A clean and up-to-date repository is crucial for maintaining the health and usability of your codebase.</p>
<p>One way to keep the repository clean is by avoiding committing unnecessary files, such as temporary files or build artifacts. This keeps the repository small and makes it easier to navigate. The following files are considered unnecessary:</p>
<ul>
<li><p>IDE-specific files or directories (for example, .idea, .vscode) that are used for local development environment configurations.</p>
</li>
<li><p>Temporary files or backup files created by text editors or other tools (for example, .bak, .tmp).</p>
</li>
<li><p>Dependencies or package directories (for example, node_modules, vendor) that can be regenerated using package managers.</p>
</li>
<li><p>Configuration files containing sensitive information (for example, API keys, and passwords). Use environment variables or configuration files outside the repository for such sensitive data.</p>
</li>
<li><p>Build artifacts or output directories (for example, dist, build) that can be regenerated during the build process.</p>
</li>
</ul>
<p>To avoid committing unnecessary files in a repository, follow these steps:</p>
<ol>
<li><p>Create a <code>.gitignore</code> file in the root directory of your repository.</p>
</li>
<li><p>Open the <code>.gitignore</code> file in a text editor.</p>
</li>
<li><p>List the filenames, directories, or file patterns that you want to exclude from version control, each on a new line.</p>
</li>
<li><p>Save the <code>.gitignore</code> file.</p>
</li>
</ol>
<p>Common patterns to include in <code>.gitignore</code> are:</p>
<ul>
<li><p>Directory names (for example, <code>node_modules/</code>, <code>dist/</code>, <code>build/</code>)</p>
</li>
<li><p>File extensions (for example, <code>*.log</code>, <code>*.tmp</code>, <code>.env</code>)</p>
</li>
<li><p>Specific files (for example, <code>secrets.txt</code>, <code>config.ini</code>)</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/gitignore.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating</em> <code>.gitignore</code> file</p>
<p>Ensure that the <code>.gitignore</code> file is committed and pushed to the repository. Git will then automatically exclude the listed files and directories from being staged or committed.</p>
<p>Regularly review and update the <code>.gitignore</code> file as new files or directories become unnecessary to include in the repository. This practice helps maintain a clean and focused version control history.</p>
<h4 id="heading-reasons-to-avoid-committing-unnecessary-files">Reasons to Avoid Committing Unnecessary Files</h4>
<p>As mentioned before, avoiding unnecessary files in a repository is crucial for maintaining efficiency, security, and collaboration. Here are a few reasons why it's important:</p>
<ol>
<li><p><strong>Reduced repository size:</strong> Unnecessary files can bloat the repository size, making cloning and fetching slower for collaborators.</p>
</li>
<li><p><strong>Improved performance:</strong> Large repositories with unnecessary files can impact the performance of various Git operations, such as branching, merging, and history traversal.</p>
</li>
<li><p><strong>Enhanced collaboration:</strong> Excluding unnecessary files ensures that only relevant code and assets are shared among team members, improving collaboration and reducing confusion.</p>
</li>
<li><p><strong>Version control clarity:</strong> By omitting unnecessary files, the version control history remains focused on meaningful changes, making it easier to understand and review the development timeline.</p>
</li>
<li><p><strong>Security and confidentiality:</strong> Avoiding the inclusion of sensitive information, such as API keys or passwords, in the repository helps maintain security and confidentiality.</p>
</li>
<li><p><strong>Easier maintenance and deployment:</strong> When unnecessary files are excluded, maintenance tasks, such as cloning or deploying the repository, become faster and more streamlined.</p>
</li>
</ol>
<p>Plus, it's important to keep the repository up to date by regularly pulling changes from the main branch and resolving any conflicts. This prevents merge conflicts and ensures that everyone is working with the most current version of the code.</p>
<p>By following these best practices, you can work more efficiently and collaboratively on Git projects, reduce the risk of errors and conflicts, and keep your codebase clean and maintainable.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, we've covered some of the best practices for using Git to manage your software development projects.</p>
<p>We discussed the importance of version control and how Git can help you keep track of changes to your codebase. We also covered the basic commands for creating and committing changes, and how to work with remote repositories. Finally, we discussed some of the best practices for using Git, including keeping commits small and focused, using clear and concise commit messages, branching frequently to isolate changes, and using pull requests for code reviews.</p>
<p>While we've covered some of the basics of Git, there's much more to learn and explore. Git is a powerful tool that can help you manage complex software development projects, collaborate with other developers, and streamline your workflow.</p>
<p>I encourage you to continue learning about Git and exploring its capabilities. By doing so, you can become a more effective and efficient developer, and improve the quality and maintainability of your codebase.</p>
<p>Whether you're a beginner or an experienced developer, there's always something new to learn about Git. So keep exploring, keep experimenting, and keep pushing the boundaries of what you can do with Git.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Git Pull Remote Branch – How To Fetch Remote Branches in Git ]]>
                </title>
                <description>
                    <![CDATA[ Git is a popular version control system that's used by millions of developers to manage their codebases. One of the most powerful features of Git is its ability to work with remote repositories. When working on a project with multiple collaborators, ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/git-pull-remote-branch-how-to-fetch-remote-branches-in-git/</link>
                <guid isPermaLink="false">66d45f8038f2dc3808b790d3</guid>
                
                    <category>
                        <![CDATA[ Collaboration ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joel Olawanle ]]>
                </dc:creator>
                <pubDate>Thu, 04 May 2023 14:27:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/cover-template--12-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Git is a popular version control system that's used by millions of developers to manage their codebases. One of the most powerful features of <a target="_blank" href="https://kinsta.com/knowledgebase/install-git/">Git</a> is its ability to work with remote repositories.</p>
<p>When working on a project with multiple collaborators, you must be able to fetch changes from the remote repository and merge them with your local repository. This article will teach you how to fetch remote branches in Git.</p>
<h2 id="heading-what-is-a-remote-branch">What is a Remote Branch?</h2>
<p>Before diving into how to fetch remote branches, let's define a remote branch.</p>
<p>A remote branch is a branch that exists on a remote repository, such as <a target="_blank" href="https://kinsta.com/knowledgebase/git-vs-github/">GitHub</a>, GitLab, or Bitbucket.</p>
<p>When you clone a repository, Git automatically creates a "<strong>remote</strong>" that points to the original repository. You can then use this remote to fetch changes made by other collaborators on the project.</p>
<h2 id="heading-how-to-fetch-remote-branches-in-git">How to Fetch Remote Branches in Git</h2>
<p>When you clone a repository, you can access all its remote branches. You can verify this using the <code>git branch</code> command alongside the <code>-r</code> option:</p>
<pre><code class="lang-bash">git branch -r
</code></pre>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_4A23CAD3B56D51AD7DA85730E428F7A2E6F6289B6BB197975176BE233B3F0EA9_1682869187912_image.png" alt="s_4A23CAD3B56D51AD7DA85730E428F7A2E6F6289B6BB197975176BE233B3F0EA9_1682869187912_image" width="2074" height="188" loading="lazy"></p>
<p>You can checkout to any of these branches using the <code>git checkout</code> command.</p>
<p>When you are working with a group of people, one contributor creates a new branch remotely. You may need to fetch this remote branch into your project. You can do this with the <code>git fetch</code> command.</p>
<p>The <code>git fetch</code> command goes out to your remote project and pulls down all the data from that remote project that you don’t have yet. After you do this, you should have references to all the branches from that remote, which you can merge in or inspect at any time.</p>
<pre><code class="lang-bash">git fetch
</code></pre>
<p>You can attach the remote repository name, which by default is <code>origin</code>:</p>
<pre><code class="lang-bash">git fetch origin
</code></pre>
<p>It is important to understand that when you use the <code>git fetch</code> command, it only downloads the changes made in the remote repository to your local repository without automatically merging them with your work or modifying what you are currently working on. You will need to merge the changes manually when you are ready.</p>
<p>To access the fetched content, you need to use the <code>git checkout</code> command. This ensures that fetching is a safe way to review commits before integrating them into your local repository.</p>
<p>If you want to fetch remote branches and merge them with your work or modify your current work, you can use the <code>git pull</code> command. To achieve this, use the following command:</p>
<pre><code class="lang-bash">git pull --all
</code></pre>
<p>You can then run the <code>git branch -r</code> to verify if the remote repository has been added.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Fetching remote branches in Git is a crucial aspect of collaboration in a development environment.</p>
<p>By following the steps outlined in this article, you can fetch changes made by other collaborators on remote branches and merge them with your local repository. This enables you to work on different branches of a Git repository and collaborate effectively with other developers.</p>
<p>Embark on a journey of learning! <a target="_blank" href="https://joelolawanle.com/contents">Browse 200+ expert articles on web development</a>. Check out <a target="_blank" href="https://joelolawanle.com/posts">my blog</a> for more captivating content from me.</p>
<p>Have fun coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The Git Merge Handbook – Definitive Guide to Merging in Git ]]>
                </title>
                <description>
                    <![CDATA[ By reading this post, you are going to really understand git merge, one of the most common operations you'll perform in your Git repositories. Notes before we start I also created two videos covering the contents of this post. If you wish to watch a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/</link>
                <guid isPermaLink="false">66c17c4958ee0865d2671b62</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Omer Rosenbaum ]]>
                </dc:creator>
                <pubDate>Thu, 27 Apr 2023 17:07:19 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/07/The-Git-Merge-Handbook-Book-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By reading this post, you are going to <em>really</em> understand <code>git merge</code>, one of the most common operations you'll perform in your Git repositories.</p>
<h2 id="heading-notes-before-we-start">Notes before we start</h2>
<ol>
<li>I also created two videos covering the contents of this post. If you wish to watch alongside reading, you can find them here (<a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Part 1</a>, <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Part 2</a>).</li>
<li>I am working on a book about Git! Are you interested in reading the initial versions and providing feedback? Send me an email: gitting.things@gmail.com</li>
</ol>
<p>OK, are you ready?</p>
<h1 id="heading-table-of-contents">Table of Contents</h1>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-a-merge-in-git">What is a Merge in Git?</a></li>
<li><a class="post-section-overview" href="#heading-time-to-get-hands-on">Time to Get Hands-on 🙌🏻</a></li>
<li><a class="post-section-overview" href="#heading-time-for-a-more-advanced-case">Time For a More Advanced Case</a></li>
<li><a class="post-section-overview" href="#heading-quick-recap-on-a-three-way-merge">Quick recap on a three-way merge</a></li>
<li><a class="post-section-overview" href="#heading-moving-on">Moving on 👣</a></li>
<li><a class="post-section-overview" href="#heading-more-advanced-git-merge-cases">More Advanced Git Merge Cases</a></li>
<li><a class="post-section-overview" href="#heading-how-gits-3-way-merge-algorithm-works">How Git's 3-way Merge Algorithm Works</a></li>
<li><a class="post-section-overview" href="#heading-how-to-resolve-merge-conflicts">How to Resolve Merge Conflicts</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-vs-code-to-resolve-conflicts">How to Use VS Code to Resolve Conflicts</a></li>
<li><a class="post-section-overview" href="#heading-one-more-powerful-tool">One More Powerful Tool 🪛</a></li>
<li><a class="post-section-overview" href="#heading-recap">Recap</a></li>
</ul>
<h1 id="heading-what-is-a-merge-in-git">What is a Merge in Git?</h1>
<p>Merging is the process of combining the recent changes from several branches into a single new commit that will be on all those branches.</p>
<p>In a way, merging is the complement of branching in version control: a branch allows you to work simultaneously with others on a particular set of files, whereas a merge allows you to later combine separate work on branches that diverged from a common ancestor commit.</p>
<p>OK, let's take this bit by bit.</p>
<p>Remember that in Git, <a target="_blank" href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">a branch is just a name pointing to a single commit</a>. When we think about commits as being "on" a specific branch, they are actually reachable through the parent chain from the commit that the branch is pointing to. </p>
<p>That is, if you consider this commit graph:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-140.png" alt="Image" width="600" height="400" loading="lazy">
_Commit graph with two pointers (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>You see the branch <code>feature_1</code>, which points to a commit with the SHA-1 value of <code>ba0d2</code>. Of course, as in other posts, I only write the first 5 digits of the SHA-1 value. </p>
<p>Notice that commit <code>54a9d</code> is also on this branch, as it is the parent commit of <code>ba0d2</code>. So if you start from the pointer of <code>feature_1</code>, you get to <code>ba0d2</code>, which then points to <code>54a9d</code>.</p>
<p>When you merge with Git, you merge <strong>commits</strong>. Almost always, we merge two commits by referring to them with the branch names that point to them. Thus we say we "merge branches" – though under the hood, we actually merge commits.</p>
<h1 id="heading-time-to-get-hands-on">Time to Get Hands-on 🙌🏻</h1>
<p>OK, so let's say I have this simple repository here, with a branch called <code>main</code>, and a few commits with the commit messages of "Commit 1", "Commit 2" and "Commit 3":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-141.png" alt="Image" width="600" height="400" loading="lazy">
_A simple repository with three commits (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Next, create a feature branch by typing <code>git branch new_feature</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-142.png" alt="Image" width="600" height="400" loading="lazy">
_Creating a new branch with <code>git branch</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>And switch <code>HEAD</code> to point to this new branch, by using <code>git checkout new_feature</code>. You can look at the outcome by using <code>git log</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-143.png" alt="Image" width="600" height="400" loading="lazy">
_The output of <code>git log</code> after using <code>git checkout new_feature</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>As a reminder, you could also write <code>git checkout -b new_feature</code>, which would both create a new branch and change <code>HEAD</code> to point to this new branch. </p>
<p>If you need a reminder about branches and how they're implemented under the hood, please check out <a target="_blank" href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">a previous post on the subject</a>. Yes, check out. Pun intended 😇</p>
<p>Now, on the <code>new_feature</code> branch, implement a new feature. In this example I will edit an existing file that looks like this before the edit:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-144.png" alt="Image" width="600" height="400" loading="lazy">
_<code>code.py</code> before editing it (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>And I will now edit it to include a new function:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-145.png" alt="Image" width="600" height="400" loading="lazy">
_Implementing <code>new_feature</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>And thankfully, this is not a programming tutorial, so this function is legit 😇<br>Next, stage and commit this change:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-146.png" alt="Image" width="600" height="400" loading="lazy">
_Committing the changes to "Commit 4" (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Looking at the history, you have the branch <code>new_feature</code>, now pointing to "Commit 4", which points to its parent, "Commit 3". The branch <code>main</code> is also pointing to "Commit 3".</p>
<p>Time to merge the new feature! That is, merge these two branches, <code>main</code> and <code>new_feature</code>. Or, in Git's lingo, merge <code>new_feature</code> <em>into</em> <code>main</code>. This means merging "Commit 4" and "Commit 3". This is pretty trivial, as after all, "Commit 3" is an ancestor of "Commit 4".</p>
<p>Check out the main branch (with <code>git checkout main</code>), and perform the merge by using <code>git merge new_feature</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-197.png" alt="Image" width="600" height="400" loading="lazy">
_Merging <code>new_feature</code> into <code>main</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Since <code>new_feature</code> never really <em>diverged</em> from <code>main</code>, Git could just perform a fast-forward merge. So what happened here? Consider the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image--7-.png" alt="Image" width="600" height="400" loading="lazy">
_The result of a fast-forward merge (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Even though you used <code>git merge</code>, there was no actual merging here. Actually, Git did something very simple – it reset the <code>main</code> branch to point to the same commit as the branch <code>new_feature</code>.</p>
<p>In case you don't want that to happen, but rather you want Git to really perform a merge, you could either change Git's configuration, or run the <code>merge</code> command with the <code>--no-ff</code> flag.</p>
<p>First, undo the last commit:</p>
<pre><code class="lang-git">git reset --hard HEAD~1
</code></pre>
<p>If this way of using reset is not clear to you, feel free to check out <a target="_blank" href="https://medium.com/@Omer_Rosenbaum/git-undo-how-to-rewrite-git-history-with-confidence-d4452e2969c2">a post where I covered <code>git reset</code> in depth</a>. It is not crucial for this introduction of <code>merge</code>, though. For now, it's important to understand that it basically undoes the merge operation.</p>
<p>Just to clarify, now if you checked out <code>new_feature</code> again:</p>
<pre><code class="lang-git">git checkout new_feature
</code></pre>
<p>The history would look just like before the merge:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image--8-.png" alt="Image" width="600" height="400" loading="lazy">
_The history after using <code>git reset --hard HEAD~1</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Next, perform the merge with the <code>--no-fast-forward</code> flag (<code>--no-ff for short</code>):</p>
<pre><code class="lang-git">git checkout main
git merge new_feature --no-ff
</code></pre>
<p>Now, if we look at the history using <code>git lol</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-200.png" alt="Image" width="600" height="400" loading="lazy">
_History after merging with the <code>--no-ff</code> flag (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>(<code>git lol</code> is an alias I added to Git to visibly see the history in a graphical manner. You can find it <a target="_blank" href="https://gist.github.com/Omerr/8134a61b56ca82dd90e546e7ef04eb77">here</a>).</p>
<p>Considering this history, you can see Git created a new commit, a merge commit.</p>
<p>If you consider this commit a bit closer:</p>
<pre><code>git log -n1
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-201.png" alt="Image" width="600" height="400" loading="lazy">
_The merge commit has two parents (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>You will see that this commit actually has two parents – "Commit 4", which was the commit that <code>new_feature</code> pointed to when you ran <code>git merge</code>, and "Commit 3", which was the commit that <code>main</code> pointed to. So a merge commit has two parents: the two commits it merged.</p>
<p>The merge commit shows us the concept of merge quite well. Git takes two commits, usually referenced by two different branches, and merges them together. </p>
<p>After the merge, as you started the process from <code>main</code>, you are still on <code>main</code>, and the history from <code>new_feature</code> has been merged into this branch. Since you started with <code>main</code>, then "Commit 3", which <code>main</code> pointed to, is the first parent of the merge commit, whereas "Commit 4", which you merged <em>into</em> <code>main</code>, is the second parent of the merge commit.</p>
<p>Notice that you started on <code>main</code> when it pointed to "Commit 3", and Git went quite a long way for you. It changed the working tree, the index, and also <code>HEAD</code> and created a new commit object. At least when you use <code>git merge</code> without the <code>--no-commit</code> flag and when it's not a fast-forward merge, Git does all of that.</p>
<p>This was a super simple case, where the branches you merged didn't diverge at all.</p>
<p>By the way, you can use <code>git merge</code> to merge more than two commits – actually, any number of commits. This is rarely done and I don't see a good reason to elaborate on it here.</p>
<p>Another way to think of <code>git merge</code> is by joining two or more <em>development histories</em> together. That is, when you merge, you incorporate changes from the named commits, since the time their histories diverged <em>from</em> the current branch, <em>into</em> the current branch. I used the term <code>branch</code> here, but I am stressing this again – we are actually merging commits.</p>
<h1 id="heading-time-for-a-more-advanced-case">Time For a More Advanced Case 💪🏻</h1>
<p>Time to consider a more advanced case, which is probably the most common case where we use <code>git merge</code> explicitly – where you need to merge branches that <em>did</em> diverge from one another.</p>
<p>Assume we have two people working on this repo now, John and Paul.</p>
<p>John created a branch:</p>
<pre><code>git checkout -b john_branch
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-348.png" alt="Image" width="600" height="400" loading="lazy">
_A new branch, <code>john_branch</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>And John has written a new song in a new file, <code>lucy_in_the_sky_with_diamonds.md</code>. Well, I believe John Lennon didn't really write in Markdown format, or use Git for that matter, but let's pretend he did for this explanation.</p>
<pre><code>git add lucy_in_the_sky_with_diamonds.md
git commit -m <span class="hljs-string">"Commit 5"</span>
</code></pre><p>While John was working on this song, Paul was also writing, on another branch. Paul had started from <code>main</code>:</p>
<pre><code>git checkout main
</code></pre><p>And created his own branch:</p>
<pre><code>git checkout -b paul_branch
</code></pre><p>And Paul wrote his song into a file:</p>
<pre><code>nano penny_lane.md
</code></pre><p>And committed it:</p>
<pre><code>git add penny_lane.md
git commit -m <span class="hljs-string">"Commit 6"</span>
</code></pre><p>So now our history looks like this – where we have two different branches, branching out from <code>main</code>, with different histories.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-203.png" alt="Image" width="600" height="400" loading="lazy">
_The output of <code>git lol</code> shows the history after John and Paul committed (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>John is happy with his branch (that is, his song), so he decides to merge it into the <code>main</code> branch:</p>
<pre><code>git checkout main
git merge john_branch
</code></pre><p>Actually, this is a fast-forward merge, as we have learned before. You can validate that by looking at the history (using <code>git lol</code>, for example):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-349.png" alt="Image" width="600" height="400" loading="lazy">
_Merging <code>john_branch</code> into <code>main</code> results in a fast-forwrad merge (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>At this point, Paul also wants to merge his branch into <code>main</code>, but now a fast-forward merge is no longer relevant – there are two <em>different</em> histories here: the history of <code>main</code>'s and that of <code>paul_branch</code>'s. It's not that <code>paul_branch</code> only adds commits on top of <code>main</code> branch or vice versa.</p>
<p>Now things get interesting. 😎😎</p>
<p>First, let Git do the hard work for you. After that, we will understand what's actually happening under the hood.</p>
<pre><code>git merge paul_branch
</code></pre><p>Consider the history now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-206.png" alt="Image" width="600" height="400" loading="lazy">
_When you merge <code>paul_branch</code>, you get a new merge commit (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>What you have is a new commit, with two parents – "Commit 5" and "Commit 6".
In the working dir, you can see that both John's song as well as Paul's song are there:
<code>ls</code></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-242.png" alt="Image" width="600" height="400" loading="lazy">
_The working dir after the merge (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Nice, Git really did merge the changes for us. But how does that happen?</p>
<p>Undo this last commit:</p>
<pre><code>git reset --hard HEAD~
</code></pre><h2 id="heading-how-to-perform-a-three-way-merge-in-git">How to perform a three-way merge in Git</h2>
<p>It's time to understand what's really happening under the hood. 😎</p>
<p>What Git has done here is it called a <code>3-way merge</code>. In outlining the process of a 3-way merge, I will use the term "branch" for simplicity, but you should remember you could also merge two (or more) commits that are not referenced by a branch.</p>
<p>The 3-way merge process includes these stages:</p>
<p>First, Git locates the common ancestor of the two branches. That is, the common commit from which the merging branches most recently diverged. Technically, this is actually the first commit that is reachable from both branches. This commit is then called the <strong>merge base</strong>.</p>
<p>Second, Git calculates two diffs – one diff from the merge base to the first branch, and another diff from the merge base to the second branch. Git generates patches based on those diffs.</p>
<p>Third, Git applies both patches to the merge base using a 3-way merge algorithm. The result is the state of the new, merge commit.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-357.png" alt="Image" width="600" height="400" loading="lazy">
_The three steps of the 3-way merge algorithm: (1) locate the common ancestor; (2) calculate diffs from the merge base to the first branch, and from the merge base to the second branch; (3) apply both patches together (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>So, back to our example.</p>
<p>In the first step, Git looks from both branches – <code>main</code> and <code>paul_branch</code> – and traverses the history to find the first commit that is reachable from both. In this case, this would be...which commit?</p>
<p>Correct, "Commit 4".</p>
<p>If you are not sure, you can always ask Git directly:</p>
<pre><code>git merge-base main paul_branch
</code></pre><p>By the way, this is the most common and simple case, where we have a single obvious choice for the merge base. In more complicated cases, there may be multiple possibilities for a merge base, but this is a topic for another post.</p>
<p>In the second step, Git calculates the diffs. So it first calculates the diff between "Commit 4" and "Commit 5":</p>
<pre><code>git diff <span class="hljs-number">4</span>f90a62 <span class="hljs-number">4683</span>aef
</code></pre><p>(The SHA-1 values will be different on your machine)</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-247.png" alt="Image" width="600" height="400" loading="lazy">
_The diff between "Commit 4" and "Commit 5" (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>If you don't feel comfortable with the output of <code>git diff</code>, please read <a target="_blank" href="https://www.freecodecamp.org/news/git-diff-and-patch/">the previous post</a> where I described it in detail.</p>
<p>You can store that diff to a file:</p>
<pre><code>git diff <span class="hljs-number">4</span>f90a62 <span class="hljs-number">4683</span>aef &gt; john_branch_diff.patch
</code></pre><p>Next, Git calculates the diff between "Commit 4" and "Commit 6":</p>
<pre><code>git diff <span class="hljs-number">4</span>f90a62 c5e4951
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-249.png" alt="Image" width="600" height="400" loading="lazy">
_The diff between "Commit 4" and "Commit 6" (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Write this one to a file as well:</p>
<pre><code>git diff <span class="hljs-number">4</span>f90a62 c5e4951 &gt; paul_branch_diff.patch
</code></pre><p>Now Git applies those patches on the merge base. </p>
<p>First, try that out directly – just apply the patches (I will walk you through it in a moment). This is <em>not</em> what Git really does under the hood, but it will help you gain a better understanding of why Git needs to do something different.</p>
<p>Checkout the merge base first, that is, "Commit 4":</p>
<pre><code>git checkout <span class="hljs-number">4</span>f90a62
</code></pre><p>And apply John's patch first:</p>
<pre><code>git apply -–index john_branch_diff.patch
</code></pre><p>Notice that for now there is no merge commit. <code>git apply</code> updates the working dir as well as the index, as we used the <code>--index</code> switch.</p>
<p>You can observe the status using <code>git status</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-250.png" alt="Image" width="600" height="400" loading="lazy">
_Applying John's patch on "Commit 4" (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>So now John's new song is incorporated into the index. Apply the other patch:</p>
<p><code>git apply -–index paul_branch_diff.patch</code></p>
<p>As a result, the index contains changes from both branches.</p>
<p>Now it's time to commit your merge. Since the porcelain command <code>git commit</code> always generates a commit with a <em>single</em> parent, you would need the underlying plumbing command – <code>git commit-tree</code>. </p>
<p>If you need a reminder about porcelain vs plumbing commands, check out <a target="_blank" href="https://medium.com/swimm/getting-hardcore-creating-a-repo-from-scratch-cc747edbb11c">the post where I explained these terms, and created an entire repo from scratch</a>.</p>
<p>Remember that <a target="_blank" href="https://medium.com/swimm/a-visualized-intro-to-git-internals-objects-and-branches-68df85864037">every Git commit object points to a single tree</a>. So you need to record the contents of the index in a tree:</p>
<pre><code>git write-tree
</code></pre><p>Now you get the SHA-1 value of the created tree, and you can create a commit object using <code>git commit-tree</code>:</p>
<pre><code>git commit-tree &lt;TREE_SHA&gt; -p &lt;COMMIT_4&gt; -p &lt;COMMIT_5&gt; -m <span class="hljs-string">"Merge commit!"</span>
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-251.png" alt="Image" width="600" height="400" loading="lazy">
_Creating a merge commit (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Great, so you have created a commit object 💪🏻</p>
<p>Recall that <code>git merge</code> also changes <code>HEAD</code> to point to the new merge commit object. So you can simply do the same:
<code>git reset –-hard db315a</code></p>
<p>If you look at the history now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-252.png" alt="Image" width="600" height="400" loading="lazy">
_The history after creating a merge commit and resetting <code>HEAD</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>You can see that you've reached the same result as the merge done by Git, with the exception of the timestamp and thus the SHA-1 value, of course.</p>
<p>So you got to merge both the <strong>contents</strong> of the two commits – that is, the state of the files, and also the <strong>history</strong> of those commits – by creating a merge commit that points to both histories.</p>
<p>In this simple case, you could actually just apply the patches using <code>git apply</code>, and everything worked quite well.</p>
<h2 id="heading-quick-recap-on-a-three-way-merge">Quick recap on a three-way merge</h2>
<p>So to quickly recap, on a three-way merge, Git:</p>
<ul>
<li>First, locates the merge base – the common ancestor of the two branches. That is, the first commit that is reachable from both branches. </li>
<li>Second, Git calculates two diffs – one diff from the merge base to the first branch, and another diff from the merge base to the second branch. </li>
<li>Third, Git applies both patches to the merge base, using a 3-way merge algorithm. I haven't explained the 3-way merge yet, but I will elaborate on that later. The result is the state of the new, merge commit.</li>
</ul>
<p>You can also understand why it's called a "3-way merge": Git merges three different states – that of the first branch, that of the second branch, and their common ancestor. In our previous example, <code>main</code>, <code>paul_branch</code>, and <code>Commit 4</code>.</p>
<p>This is unlike, say, the fast-forward examples we saw before. The fast-forward examples are actually a case of a <strong>two</strong>-way merge, as Git only compares two states – for example, where <code>main</code> pointed to, and where <code>john_branch</code> pointed to.</p>
<h1 id="heading-moving-on">Moving on 👣</h1>
<p>Still, this was a simple case of a 3-way merge. John and Paul created different songs, so each of them touched a different file. It was pretty straightforward to execute the merge.</p>
<p>What about more interesting cases?</p>
<p>Let's assume that now John and Paul are co-authoring a new song.</p>
<p>So, John checkedout <code>main</code> branch and started writing the song:</p>
<pre><code>git checkout main
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-253.png" alt="Image" width="600" height="400" loading="lazy">
_John's new song (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>He staged and committed it ("Commit 7"):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-254.png" alt="Image" width="600" height="400" loading="lazy">
_John's new song is committed (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Now, Paul branches:</p>
<pre><code>git checkout -b paul_branch_2
</code></pre><p>And edits the song, adding another verse:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-255.png" alt="Image" width="600" height="400" loading="lazy">
_Paul added a new verse (Source: <a target="_blank" href="https://www.youtube.com/watch?v=ZS4stBVdDII&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Of course, in the original song, we don't have the title "Paul's Verse", but I'll add it here for simplicity.</p>
<p>Paul stages and commits the changes:</p>
<pre><code>git add a_day_in_the_life.md
git commit -m <span class="hljs-string">"Commit 8"</span>
</code></pre><p>John also branches out from <code>main</code> and adds a few last lines:
```git checkout main
git checkout -b john_branch_2</p>
<pre><code>

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-256.png)</span>
_Paul committed, and now it<span class="hljs-string">'s John'</span>s turn again (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_</span>

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-257.png)</span>
_John added a few lines (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_</span>

And he stages and commits his changes too (<span class="hljs-string">"Commit 9"</span>):

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-258.png)</span>
_John committed his changes (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_</span>

This is the resulting history:

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-350.png)</span>
_The history after John<span class="hljs-string">'s last commit (Source: [Brief](https://www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_

So, both Paul and John modified the same file on different branches. Will Git be successful in merging them? 🤔

Say now we don'</span>t go through <span class="hljs-string">`main,`</span> but John will <span class="hljs-keyword">try</span> to merge Paul<span class="hljs-string">'s new branch into his branch:</span>
</code></pre><p>git merge paul_branch_2</p>
<pre><code>
Wait!! 🤚🏻 Don<span class="hljs-string">'t run this command! Why would you let Git do all the hard work? You are trying to understand the process here.

So, first, Git needs to find the merge base. Can you see which commit that would be?

Correct, it would be the last commit on `main` branch, where the two diverged.

You can verify that by using:</span>
</code></pre><p>git merge-base john_branch_2 paul_branch_2</p>
<pre><code>

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-260.png)</span>
_Finding the merge base (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_</span>

Great, now Git should compute the diffs and generate the patches. You can observe the diffs directly:
</code></pre><p>git diff main paul_branch_2</p>
<pre><code>

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-261.png)</span>
_The output <span class="hljs-keyword">of</span> <span class="hljs-string">`git diff main paul_branch_2`</span> (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_</span>

Will applying <span class="hljs-built_in">this</span> patch succeed? Well, no problem, Git has all the context lines <span class="hljs-keyword">in</span> place.

Ask Git to apply <span class="hljs-built_in">this</span> patch:
</code></pre><p>git diff main paul_branch_2 &gt; paul_branch_2.patch
git apply -–index paul_branch_2.patch</p>
<pre><code>
And <span class="hljs-built_in">this</span> worked, no problem at all.

Now, compute the diff between John<span class="hljs-string">'s new branch and the merge base. Notice that you haven'</span>t committed the applied changes, so <span class="hljs-string">`john_branch_2`</span> still points at the same commit <span class="hljs-keyword">as</span> before, <span class="hljs-string">"Commit 9"</span>:
</code></pre><p>git diff main john_branch_2</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-262.png)</span>
_The output <span class="hljs-keyword">of</span> <span class="hljs-string">`git diff main john_branch_2`</span> (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_</span>

Will applying <span class="hljs-built_in">this</span> diff work?

Well, indeed, yes. Notice that even though the line numbers have changed on the current version <span class="hljs-keyword">of</span> the file, thanks to the context lines Git is able to locate where it needs to add these lines…

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-263.png)</span>
_Git can rely on the context lines (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_</span>

Save <span class="hljs-built_in">this</span> patch and apply it then:
</code></pre><p>git diff main john_branch_2 &gt; john_branch_2.patch
git apply –-index john_branch_2.patch</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-264.png)</span>
_Apply Paul<span class="hljs-string">'s patch (Source: [Brief](https://www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_

Observe the result file:

![Image](https://www.freecodecamp.org/news/content/images/2023/04/image-265.png)
_The result after applying Paul'</span>s patch (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_</span>

Cool, exactly what we wanted 👏🏻
You can now create the tree and relevant commit:
</code></pre><p>git write-tree</p>
<pre><code>
Don<span class="hljs-string">'t forget to specify both parents:</span>
</code></pre><p>git commit-tree  -p paul_branch_2 -p john_branch_2 -m "Merging new changes"</p>
<pre><code>

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-266.png)</span>
_Creating a merge commit (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_</span>

See how I used the branches names here? After all, they are just pointers to the commits we want.

Cool, look at the log <span class="hljs-keyword">from</span> the <span class="hljs-keyword">new</span> commit:

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-270.png)</span>
_The history after creating the merge commit (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=ZS4stBVdDII&amp;amp;ab_channel=Brief))_</span>

Exactly what we wanted.

You can also <span class="hljs-keyword">let</span> Git perform the job <span class="hljs-keyword">for</span> you. You can simply checkout <span class="hljs-string">`john_branch_2`</span>, which you haven<span class="hljs-string">'t moved – so it still points to the same commit as it did before the merge. So all you need to do is run:</span>
</code></pre><p>git merge paul_branch_2</p>
<pre><code>
Observe the resulting history:

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-271.png)</span>
_The history after letting Git perform the merge (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

Just <span class="hljs-keyword">as</span> before, you have a merge commit pointing to <span class="hljs-string">"Commit 8"</span> and <span class="hljs-string">"Commit 9"</span> <span class="hljs-keyword">as</span> its parents. <span class="hljs-string">"Commit 9"</span> is the first parent since you merged into it.

But <span class="hljs-built_in">this</span> was still quite simple… John and Paul worked on the same file, but on very different parts. You could also directly apply Paul<span class="hljs-string">'s changes to John'</span>s branch. If you go back to John<span class="hljs-string">'s branch before the merge:</span>
</code></pre><p>git reset --hard HEAD~</p>
<pre><code>
And now apply Paul<span class="hljs-string">'s changes:</span>
</code></pre><p>git apply -–index paul_branch_2.patch</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-272.png)</span>
_Applying Paul<span class="hljs-string">'s changes directly to John'</span>s branch (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

You will get the same result.

But what happens when the two branches include changes on the same files, <span class="hljs-keyword">in</span> the same locations? 🤔

# More Advanced Git Merge Cases

What would happen <span class="hljs-keyword">if</span> John and Paul were to coordinate a <span class="hljs-keyword">new</span> song, and work on it together?

In <span class="hljs-built_in">this</span> <span class="hljs-keyword">case</span>, John creates the first version <span class="hljs-keyword">of</span> <span class="hljs-built_in">this</span> song <span class="hljs-keyword">in</span> the <span class="hljs-string">`main`</span> branch:
</code></pre><p>git checkout main
nano everyone.md</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-273.png)</span>
_The contents <span class="hljs-keyword">of</span> <span class="hljs-string">`everyone.md`</span> prior to the first commit (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

By the way, <span class="hljs-built_in">this</span> text is indeed taken <span class="hljs-keyword">from</span> the version that John Lennon recorded <span class="hljs-keyword">for</span> a demo <span class="hljs-keyword">in</span> <span class="hljs-number">1968.</span> But <span class="hljs-built_in">this</span> isn<span class="hljs-string">'t an article about the Beatles, so if you'</span>re curious about the process the Beatles underwent <span class="hljs-keyword">while</span> writing <span class="hljs-built_in">this</span> song, you can follow the links <span class="hljs-keyword">in</span> the appendix below.
</code></pre><p>git add everyone.md
git commit -m "Commit 10"</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-275.png)</span>
_Introducing <span class="hljs-string">"Commit 10"</span> (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

Now John and Paul split. Paul creates a <span class="hljs-keyword">new</span> verse <span class="hljs-keyword">in</span> the beginning:
</code></pre><p>git checkout -b paul_branch_3
nano everyone.md</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-276.png)</span>
_Paul added a <span class="hljs-keyword">new</span> verse <span class="hljs-keyword">in</span> the beginning (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

Also, <span class="hljs-keyword">while</span> talking to John, they decided to change the word <span class="hljs-string">"feet"</span> to <span class="hljs-string">"foot"</span>, so Paul adds <span class="hljs-built_in">this</span> change <span class="hljs-keyword">as</span> well.

And Paul adds and commits his changes to the repo:
</code></pre><p>git add everyone.md
git commit -m "Commit 11"</p>
<pre><code>
You can observe Paul<span class="hljs-string">'s changes, by comparing this branch'</span>s state to the state <span class="hljs-keyword">of</span> branch <span class="hljs-string">`main`</span>:
</code></pre><p>git diff main</p>
<pre><code>

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-277.png)</span>
_The output <span class="hljs-keyword">of</span> <span class="hljs-string">`git diff main`</span> <span class="hljs-keyword">from</span> Paul<span class="hljs-string">'s branch (Source: [Brief](https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_

Store this diff in a patch file:</span>
</code></pre><p>git diff main &gt; paul_3.patch</p>
<pre><code>
Now back to <span class="hljs-string">`main`</span>...
</code></pre><p>git checkout main</p>
<pre><code>
John decides to make another change, <span class="hljs-keyword">in</span> his own <span class="hljs-keyword">new</span> branch:
</code></pre><p>git checkout -b john_branch_3</p>
<pre><code>
And he replaces the line <span class="hljs-string">"Everyone had the boot in"</span> <span class="hljs-keyword">with</span> the line <span class="hljs-string">"Everyone had a wet dream"</span>. In addition, John changed the word <span class="hljs-string">"feet"</span> to <span class="hljs-string">"foot"</span>, following his talk <span class="hljs-keyword">with</span> Paul.

Observe the diff:
</code></pre><p>git diff main</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-278.png)</span>
_The output <span class="hljs-keyword">of</span> <span class="hljs-string">`git diff main`</span> <span class="hljs-keyword">from</span> John<span class="hljs-string">'s branch (Source: [Brief](https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_

Store this output as well:</span>
</code></pre><p>git diff main &gt; john_3.patch</p>
<pre><code>
Now, stage and commit:
</code></pre><p>git add everyone.md
git commit -m "Commit 12"</p>
<pre><code>
This is our current history:

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-351.png)</span>
_The history after introducing <span class="hljs-string">"Commit 12"</span> (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

Paul told John he added a <span class="hljs-keyword">new</span> verse, so John would like to merge Paul<span class="hljs-string">'s changes.

Can John simply apply Paul'</span>s patch?

Consider the patch again:
</code></pre><p>git diff main paul_branch_3</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-277.png)</span>
_The output <span class="hljs-keyword">of</span> <span class="hljs-string">`git diff main paul_branch_3`</span> (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

As you can see, <span class="hljs-built_in">this</span> diff relies on the line <span class="hljs-string">"Everyone had the boot in"</span>, but <span class="hljs-built_in">this</span> line no longer exists on John<span class="hljs-string">'s branch. As a result, you could expect applying the patch to fail. Go on, give it a try:</span>
</code></pre><p>git apply paul_3.patch</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-280.png)</span>
_Applying the patch failed (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

Indeed, you can see that it failed.

But should it really fail? 🤔

As explained earlier, <span class="hljs-string">`git merge`</span> uses a <span class="hljs-number">3</span>-way merge algorithm, and <span class="hljs-built_in">this</span> can come <span class="hljs-keyword">in</span> handy here. What would be the first step <span class="hljs-keyword">of</span> <span class="hljs-built_in">this</span> algorithm?

Well, first, Git would find the merge base – that is, the common ancestor <span class="hljs-keyword">of</span> Paul<span class="hljs-string">'s branch and John'</span>s branch. Consider the history:

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-351.png)</span>
_The history after introducing <span class="hljs-string">"Commit 12"</span> (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

So the common ancestor <span class="hljs-keyword">of</span> <span class="hljs-string">"Commit 11"</span> and <span class="hljs-string">"Commit 12"</span> is <span class="hljs-string">"Commit 10"</span>. We can verify <span class="hljs-built_in">this</span> by running the command:
</code></pre><p>git merge-base john_branch_3 paul_branch_3</p>
<pre><code>
Now we can take the patches we generated <span class="hljs-keyword">from</span> the diffs on both branches, and apply them to <span class="hljs-string">`main`</span>. Would that work?

First, <span class="hljs-keyword">try</span> to apply John<span class="hljs-string">'s patch, and then Paul'</span>s patch.

Consider the diff:
</code></pre><p>git diff main john_branch_3</p>
<pre><code>

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-278.png)</span>
_The output <span class="hljs-keyword">of</span> <span class="hljs-string">`git diff main john_branch_3`</span> (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

We can store it <span class="hljs-keyword">in</span> a file:
</code></pre><p>git diff main john_branch_3 &gt; john_3.patch</p>
<pre><code>
And I want to apply <span class="hljs-built_in">this</span> patch on <span class="hljs-string">`main`</span>, <span class="hljs-attr">so</span>:
</code></pre><p>git checkout main
git apply john_3.patch</p>
<pre><code>
Let<span class="hljs-string">'s consider the result:</span>
</code></pre><p>nano everyone.md</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-282.png)</span>
_The contents <span class="hljs-keyword">of</span> <span class="hljs-string">`everyone.md`</span> after applying John<span class="hljs-string">'s patch (Source: [Brief](https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_

The line changed as expected. Nice 😎

Now, can Git apply Paul'</span>s patch? To remind you, <span class="hljs-built_in">this</span> is the patch:

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-283.png)</span>
_The contents <span class="hljs-keyword">of</span> Paul<span class="hljs-string">'s patch (Source: [Brief](https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_

Well, Git **cannot** apply this patch, because this patch assumes that the line  "Everyone had the boot in" exists. Trying to apply is liable to fail:</span>
</code></pre><p>git apply -v paul_3.branch</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-284.png)</span>
_Applying Paul<span class="hljs-string">'s patch failed._

What you tried to do now, applying Paul'</span>s patch on <span class="hljs-string">`main`</span> branch after applying John<span class="hljs-string">'s patch, is the same as being on `john_branch_3`, and attempting to apply the patch, that is:

```git checkout john_branch_3
git apply paul_3.patch</span>
</code></pre><p>What would happen if we tried the other way around?</p>
<p>First, clean up the state:</p>
<pre><code>git reset --hard
</code></pre><p>And start from Paul's branch:</p>
<pre><code>git checkout paul_branch_3
</code></pre><p>Can we apply John's patch? As a reminder, this is the status of <code>everyone.md</code> on this branch:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-285.png" alt="Image" width="600" height="400" loading="lazy">
_The contents of <code>everyone.md</code> on <code>paul_branch_3</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>And this is John's patch:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-286.png" alt="Image" width="600" height="400" loading="lazy">
_The contents of John's patch (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Would applying John's patch work? 🤔
Try to answer yourself before reading on.</p>
<p>You can try:</p>
<pre><code>git apply john_3.patch
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-287.png" alt="Image" width="600" height="400" loading="lazy">
_Git fails to apply John's patch (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Well, no! Again, if you are not sure what happened, you can always ask <code>git apply</code> to be a bit more verbose:</p>
<pre><code>git apply john_3.patch -v
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-288.png" alt="Image" width="600" height="400" loading="lazy">
_You can get more information by using the <code>-v</code> flag (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Git is looking for "Everyone put the feet down", but Paul has already changed this line so it now consists of the word "foot" instead of "feet". As a result, applying this patch fails.</p>
<p>Notice that changing the number of context lines here (that is, using <code>git apply</code> with the <code>-C</code> flag, as discussed in <a target="_blank" href="https://www.freecodecamp.org/news/git-diff-and-patch/">a previous post</a>) is irrelevant – Git is unable to locate the actual line that the patch is trying to erase.</p>
<p>But actually, Git <em>can</em> make this work, if you just add a flag to <code>apply</code>, telling it to perform a 3-way merge under the hood:</p>
<pre><code>git apply <span class="hljs-number">-3</span> john_3.patch
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-289.png" alt="Image" width="600" height="400" loading="lazy">
_Applying with <code>-3</code> flag succeeds (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>And let's consider the result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-290.png" alt="Image" width="600" height="400" loading="lazy">
_The contents of <code>everyone.md</code> after ther merge (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Exactly what we wanted! You have Paul's verse (marked in the image above), and both of John's changes!</p>
<p>So, how was Git able to accomplish that?</p>
<p>Well, as I mentioned, Git really did <strong>a 3-way merge</strong>, and with this example, it will be a good time to dive into what this actually means.</p>
<h1 id="heading-how-gits-3-way-merge-algorithm-works">How Git's 3-way Merge Algorithm Works</h1>
<p>Get back to the state before applying this patch:</p>
<pre><code>git reset --hard
</code></pre><p>You have now three versions: the merge base, which is "Commit 10", Paul's branch, and John's branch. In general terms, we can say these are the <code>merge base</code>, <code>commit A</code> and <code>commit B</code>. Notice that the <code>merge base</code> is by definition an ancestor of both <code>commit A</code> and <code>commit B</code>.</p>
<p>To perform the merge, Git looks at the diff between the three different versions of the file in question on these three revisions. In your case, it's the file <code>everyone.md</code>, and the revisions are "Commit 10", Paul's branch – that is, "Commit 11", and John's branch, that is, "Commit 12".</p>
<p>Git makes the merging decision based on the status of each line in each of these versions.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-291.png" alt="Image" width="600" height="400" loading="lazy">
_The three versions considered for the 3-way merge (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>In case <em>not</em> all three versions match, that is a conflict. Git can resolve many of these conflicts automatically, as we will now see.</p>
<p>Let's consider specific lines.</p>
<p>The first lines here exist only on Paul's branch:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-292.png" alt="Image" width="600" height="400" loading="lazy">
_Lines that appear on Paul's branch only (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>This means that the state of John's branch is equal to the state of the merge base. So the 3-way merge goes with Paul's version.</p>
<p>In general, if the state of the merge base is the same as <code>A</code>, the algorithm goes with <code>B</code>. The reason is that since the merge base is the ancestor of both <code>A</code> and <code>B</code>, Git assumes that this line hasn't changed in <code>A</code>, and it <em>has</em> changed in <code>B</code>, which is the most recent version for that line, and should thus be taken into account.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-353.png" alt="Image" width="600" height="400" loading="lazy">
_If the state of the merge base is the same as <code>A</code>, and this state is different from <code>B</code>, the algorithm goes with <code>B</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Next, you can see lines where all three versions agree – they exist on the merge base, <code>A</code> and <code>B</code>, with equal data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-294.png" alt="Image" width="600" height="400" loading="lazy">
_Lines where all three versions agree (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>So the algorithm has a trivial choice – just take that version.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-355.png" alt="Image" width="600" height="400" loading="lazy">
_In case all three versions agree, the algorithm goes with that single version (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>In a previous example, we saw that if the merge base and <code>A</code> agree, and <code>B</code>'s version is different, the algorithm picks <code>B</code>. This works in the other direction too – for example, here you have a line that exists on John's branch, different than that on the merge base and Paul's branch.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-296.png" alt="Image" width="600" height="400" loading="lazy">
_A line where Paul's version matches the merge base's version, and John has a different version (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p> Hence, John's version is chosen.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-354.png" alt="Image" width="600" height="400" loading="lazy">
_If the state of the merge base is the same as <code>B</code>, and this state is different from <code>A</code>, the algorithm goes with <code>A</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Now consider another case, where both <code>A</code> and <code>B</code> agree on a line, but the value they agree upon is different from the <code>merge base</code> – both John and Paul agreed to change the line "Everyone put their feet down" to "Everyone put their foot down":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-297.png" alt="Image" width="600" height="400" loading="lazy">
_A line where Paul's version matches the John's version; yet the merge base has a different version (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>In this case, the algorithm picks the version on both <code>A</code> and <code>B</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-352.png" alt="Image" width="600" height="400" loading="lazy">
_In case <code>A</code> and <code>B</code> agree on a version which is different from the merge base's version, the algorithm picks the version on both <code>A</code> and <code>B</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Notice this is not a democratic vote. In the previous case, the algorithm picked the minority version, as it resembled the newest version of this line. In this case, it <em>happens to</em> pick the majority – but only because <code>A</code> and <code>B</code> are the revisions that agree on the new version.</p>
<p>The same would happen if we used <code>git merge</code>:</p>
<pre><code>git merge john_branch_3
</code></pre><p>Without specifying any flags, <code>git merge</code> will default to using a 3-way merge.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-302.png" alt="Image" width="600" height="400" loading="lazy">
_By default, <code>git merge</code> uses a 3-way merge algorithm (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>The status of <code>everyone.md</code> after running the command above would be the same as the result you achieved by applying the patches with <code>git apply -3</code>.</p>
<p>If you consider the history:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-303.png" alt="Image" width="600" height="400" loading="lazy">
_Git's history after performing the merge (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>You will see that the merge commit indeed has two parents: the first is "Commit 11", that is, where <code>paul_branch_3</code> pointed to before the merge. The second is "Commit 12", where <code>john_branch_3</code> pointed to, and still points to now.</p>
<p>What will happen if you now merge from <code>main</code>? That is, switch to the main branch, which is pointing to "Commit 10":</p>
<pre><code>git checkout main
</code></pre><p>And then merge Paul's branch?</p>
<pre><code>git merge paul_branch_3
</code></pre><p>Indeed, a fast forward, as before running this command, <code>main</code> was an ancestor of <code>paul_branch_3</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-304.png" alt="Image" width="600" height="400" loading="lazy">
_A fast-forward merge (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>So, this is a 3-way merge. In general, if all versions agree on a line, then this line is used. If <code>A</code> and the <code>merge base</code> match, and <code>B</code> has another version, <code>B</code> is taken. In the opposite case, where the <code>merge base</code> and <code>B</code> match, the <code>A</code> version is selected. If <code>A</code> and <code>B</code> match, this version is taken, whether the merge base agrees or not.</p>
<p>This description leaves one open question though: What happens in cases where all three versions disagree?</p>
<p>Well, that's a conflict that Git does not resolve automatically. In these cases, Git calls for a human's help.</p>
<h2 id="heading-how-to-resolve-merge-conflicts">How to Resolve Merge Conflicts</h2>
<p>By following so far, you should understand the basics of <code>git merge</code>, and how Git can automatically resolve some conflicts. You also understand what cases are automatically resolved.</p>
<p>Next, let's consider a more advanced case.</p>
<p>Say Paul and John keep working on this song.</p>
<p>Paul creates a new branch:</p>
<pre><code>git checkout -b paul_branch_4
</code></pre><p>And he decides to add some "Yeah"s to the song, so he changes this verse as follows:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-305.png" alt="Image" width="600" height="400" loading="lazy">
_Paul's additions (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>So Paul stages and commits these changes:</p>
<p>```git add everyone.md
git commit -m "Commit 13"</p>
<pre><code>
Paul also creates another song, <span class="hljs-string">`let_it_be.md`</span> and adds it to the repo:
</code></pre><p>git add let_it_be.md
git commit -m "Commit 14"</p>
<pre><code>
This is the history:


![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-356.png)</span>
_The history after Paul introduced <span class="hljs-string">"Commit 14"</span> (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

Back to <span class="hljs-string">`main`</span>:
</code></pre><p>git checkout main</p>
<pre><code>
John also branches out:
</code></pre><p>git checkout -b john_branch_4</p>
<pre><code>
And John also works on the song <span class="hljs-string">"Everyone had a hard year"</span>, later to be called <span class="hljs-string">"I've got a feeling"</span> (again, <span class="hljs-built_in">this</span> is not an article about the Beatles, so I won<span class="hljs-string">'t elaborate on it here. See the appendix if you are curious).

John decides to change all occurrences of "Everyone" to "Everybody":


![Image](https://www.freecodecamp.org/news/content/images/2023/04/image-307.png)
_John changes al occurrences of "Everyone" to "Everybody" (Source: [Brief](https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_

He stages and commits this song to the repo:</span>
</code></pre><p>git add everyone.md
git commit -m "Commit 15"</p>
<pre><code>
Nice. Now John also creates another song, <span class="hljs-string">`across_the_universe.md`</span>. He adds it to the repo <span class="hljs-keyword">as</span> well:
</code></pre><p>git add across_the_universe.md
git commit -m "Commit 16"</p>
<pre><code>
Observe the history again:


![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-308.png)</span>
_The history after John introduced <span class="hljs-string">"Commit 16"</span> (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

You can see that the history diverges <span class="hljs-keyword">from</span> <span class="hljs-string">`main`</span>, to two different branches – <span class="hljs-string">`paul_branch_4`</span>, and <span class="hljs-string">`john_branch_4`</span>.

At <span class="hljs-built_in">this</span> point, John would like to merge the changes introduced by Paul.

What is going to happen here?

Remember the changes introduced by Paul:
</code></pre><p>git diff main paul_branch_4</p>
<pre><code>
![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-309.png)</span>
_The output <span class="hljs-keyword">of</span> <span class="hljs-string">`git diff main paul_branch_4`</span> (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

What <span class="hljs-keyword">do</span> you think? Will merge work? 🤔

Try it out:
</code></pre><p>git merge paul_branch_4</p>
<pre><code>

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-311.png)</span>
_A merge conflict (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

We have a conflict! 🥁

It seems that Git cannot merge these branches on its own. You can get an overview <span class="hljs-keyword">of</span> the merge state, using <span class="hljs-string">`git status`</span>:


![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-310.png)</span>
_The output <span class="hljs-keyword">of</span> <span class="hljs-string">`git status`</span> right after the <span class="hljs-string">`merge`</span> operation (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

The changes that Git had no problem resolving are staged <span class="hljs-keyword">for</span> commit. And there is a separate section <span class="hljs-keyword">for</span> <span class="hljs-string">"unmerged paths"</span> – these are files <span class="hljs-keyword">with</span> conflicts that Git could not resolve on its own.

It<span class="hljs-string">'s time to understand why and when these conflicts happen, how to resolve them, and also how Git handles them under the hood.
Alright then! I hope you are at least as excited as I am. 😇

Let'</span>s recall what we know about <span class="hljs-number">3</span>-way merges:

First, Git will look <span class="hljs-keyword">for</span> the merge base – the common ancestor <span class="hljs-keyword">of</span> <span class="hljs-string">`john_branch_4`</span> and <span class="hljs-string">`paul_branch_4`</span>. Which commit would that be?

Correct, it would be the tip <span class="hljs-keyword">of</span> <span class="hljs-string">`main`</span> branch, the commit <span class="hljs-keyword">in</span> which we merged <span class="hljs-string">`john_branch_3`</span> into <span class="hljs-string">`paul_branch_3`</span>.

Again, <span class="hljs-keyword">if</span> you are not sure, you can verify that by running:
</code></pre><p>git merge-base john_branch_4 paul_branch_4</p>
<pre><code>
And at the current state, <span class="hljs-string">`git status`</span> knows which files are staged and which aren<span class="hljs-string">'t.

Consider the process for each file, which is the same as the 3-way merge algorithm we considered per line, but on a file'</span>s level:

<span class="hljs-string">`across_the_universe.md`</span> exists on John<span class="hljs-string">'s branch, but doesn'</span>t exist on the merge base or on Paul<span class="hljs-string">'s branch. So Git chooses to include this file. Since you are already on John'</span>s branch and <span class="hljs-built_in">this</span> file is included <span class="hljs-keyword">in</span> the tip <span class="hljs-keyword">of</span> <span class="hljs-built_in">this</span> branch, it is not mentioned by <span class="hljs-string">`git status`</span>.

<span class="hljs-string">`let_it_be.md`</span> exists on Paul<span class="hljs-string">'s branch, but doesn'</span>t exist on the merge-base or John<span class="hljs-string">'s branch. So `git merge` "chooses" to include it.

What about `everyone.md`? Well, here we have three different states of this file: its state on the merge base, its state on John'</span>s branch, and its state on Paul<span class="hljs-string">'s branch. While performing a `merge`, Git stores all of these versions on the **index**. 

Let'</span>s observe that by looking directly at the index <span class="hljs-keyword">with</span> the command <span class="hljs-string">`git ls-files`</span>:
</code></pre><p>git ls-files -s –-abbrev</p>
<pre><code>

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-312.png)</span>
_The output <span class="hljs-keyword">of</span> <span class="hljs-string">`git ls-files -s –-abbrev`</span> after the merge operation (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

You can see that <span class="hljs-string">`everyone.md`</span> has three different entries. Git assigns each version a number that represents the <span class="hljs-string">"stage"</span> <span class="hljs-keyword">of</span> the file, and <span class="hljs-built_in">this</span> is a distinct property <span class="hljs-keyword">of</span> an index entry, alongside the file<span class="hljs-string">'s name and the mode bits (I covered the index in [a previous post](https://medium.com/swimm/a-visualized-intro-to-git-internals-objects-and-branches-68df85864037)).

When there is no merge conflict regarding a file, its "stage" is `0`. This is indeed the state for `across_the_universe.md`, and for `let_it_be.md`.

On a conflict'</span>s state, we have:

* Stage <span class="hljs-string">`1`</span> – which is the merge base.
* Stage <span class="hljs-string">`2`</span> – which is <span class="hljs-string">"your"</span> version. That is, the version <span class="hljs-keyword">of</span> the file on the branch you are merging *into*. In our example, <span class="hljs-built_in">this</span> would be <span class="hljs-string">`john_branch_4`</span>.
* Stage <span class="hljs-string">`3`</span> – which is <span class="hljs-string">"their"</span> version, also called the <span class="hljs-string">`MERGE_HEAD`</span>. That is, the version on the branch you are merging (into the current branch). In our example, that is <span class="hljs-string">`paul_branch_4`</span>.

To observe the file<span class="hljs-string">'s contents in a specific stage, you can use a command I introduced in [a previous post](https://medium.com/swimm/getting-hardcore-creating-a-repo-from-scratch-cc747edbb11c), `git cat-file`, and provide the blob'</span>s SHA:
</code></pre><p>git cat-file -p </p>
<pre><code>

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-313.png)</span>
_Using <span class="hljs-string">`git cat-file`</span> to present the content <span class="hljs-keyword">of</span> the file on John<span class="hljs-string">'s branch, right from its state in the index (Source: [Brief](https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_

And indeed, this is the content we expected – from John'</span>s branch, where the lines start <span class="hljs-keyword">with</span> <span class="hljs-string">"Everybody"</span> rather than <span class="hljs-string">"Everyone"</span>.

A nice trick that allows you to see the content quickly without providing the blob<span class="hljs-string">'s SHA-1 value, is by using `git show`, like so:</span>
</code></pre><p>git show ::everyone.md</p>
<pre><code>
For example, to get the content <span class="hljs-keyword">of</span> the same version <span class="hljs-keyword">as</span> <span class="hljs-keyword">with</span> <span class="hljs-string">`git cat-file -p &lt;BLOB_SHA_FOR_STAGE_2&gt;`</span>, you can write <span class="hljs-string">`git show :2:everyone.md`</span>.

Git records the three states <span class="hljs-keyword">of</span> the three commits into the index <span class="hljs-keyword">in</span> <span class="hljs-built_in">this</span> way at the start <span class="hljs-keyword">of</span> the merge. It then follows the three-way merge algorithm to quickly resolve the simple cases:

In <span class="hljs-keyword">case</span> all three stages match, then the selection is trivial.

If one side made a change <span class="hljs-keyword">while</span> the other did nothing – that is, stage <span class="hljs-number">1</span> matches stage <span class="hljs-number">2</span>, then we choose stage <span class="hljs-number">3</span> – or vice versa. That<span class="hljs-string">'s exactly what happened with `let_it_be.md` and `across_the_universe.md`.

In case of a deletion on the incoming branch, for example, and given there were no changes on the current branch, then we would see that stage 1 matches stage 2, but there is no stage 3. In this case, `git merge` removes the file for the merged version.

What'</span>s really cool here is that <span class="hljs-keyword">for</span> matching, Git doesn<span class="hljs-string">'t need the actual files. Rather, it can rely on the SHA-1 values of the corresponding blobs. This way, Git can easily detect the state a file is in.

![Image](https://www.freecodecamp.org/news/content/images/2023/04/image-352.png)
_Git performs the same 3-way merge algorithm on a files level (Source: [Brief](https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_

Cool, so for `everyone.md` you have this special case – where stage 1, stage 2 and stage 3 are all different from one another. That is, they have different blob SHAs. It'</span>s time to go deeper and understand the merge conflict. 😊

One way to <span class="hljs-keyword">do</span> that would be to simply use <span class="hljs-string">`git diff`</span>. In [a previous post](https:<span class="hljs-comment">//www.freecodecamp.org/news/git-diff-and-patch/), we examined `git diff` in detail, and saw that it shows the differences between various combinations of the working tree, index or commits. </span>

But <span class="hljs-string">`git diff`</span> also has a special mode <span class="hljs-keyword">for</span> helping <span class="hljs-keyword">with</span> merge conflicts:

<span class="hljs-string">`git diff`</span>

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-314.png)</span>
_The output <span class="hljs-keyword">of</span> <span class="hljs-string">`git diff`</span> during a conflict (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

This output may be confusing at first, but once you get used to it, it<span class="hljs-string">'s pretty clear. Let'</span>s start by understanding it, and then see how you can resolve conflicts <span class="hljs-keyword">with</span> other, more visual tools.

The conflicted section is separated by the <span class="hljs-string">"equal"</span> marks (====), and marked <span class="hljs-keyword">with</span> the corresponding branches. In <span class="hljs-built_in">this</span> context, <span class="hljs-string">"ours"</span> is the current branch. In <span class="hljs-built_in">this</span> example, that would be <span class="hljs-string">`john_branch_4`</span>, the branch that <span class="hljs-string">`HEAD`</span> was pointing to when we initiated the <span class="hljs-string">`git merge`</span> command. <span class="hljs-string">"Theirs"</span> is the <span class="hljs-string">`MERGE_HEAD`</span>, the branch that we are merging <span class="hljs-keyword">in</span> – <span class="hljs-keyword">in</span> <span class="hljs-built_in">this</span> <span class="hljs-keyword">case</span>, <span class="hljs-string">`paul_branch_4`</span>.

So <span class="hljs-string">`git diff`</span> without any special flags shows changes between the working tree and the index, which <span class="hljs-keyword">in</span> <span class="hljs-built_in">this</span> <span class="hljs-keyword">case</span> are the conflicts yet to be resolved. The output doesn<span class="hljs-string">'t include staged changes, which is very convenient for resolving the conflict.

Time to resolve this manually. Fun!

So, why is this a conflict?

For Git, Paul and John made different changes to the same line, for a few lines. John changed it to one thing, and Paul changed it to another thing. Git cannot decide which one is correct.

This is not the case for the last lines, like the line that used to be "Everyone had a hard year" on the merge base. Paul hasn'</span>t changed <span class="hljs-built_in">this</span> line, or the lines surrounding it, so its version on <span class="hljs-string">`paul_branch_4`</span>, or <span class="hljs-string">"theirs"</span> <span class="hljs-keyword">in</span> our <span class="hljs-keyword">case</span>, agrees <span class="hljs-keyword">with</span> the merge_base. Yet John<span class="hljs-string">'s version, "ours", is different. Thus `git merge` can easily decide to take this version.

But what about the conflicted lines?

In this case, I know what I want, and that is actually a combination of these lines. I want the lines to start with `Everybody`, following John'</span>s change, but also to include Paul<span class="hljs-string">'s "yeah"s. So go ahead and create the desired version by editing `everyone.md`:
`nano everyone.md`

![Image](https://www.freecodecamp.org/news/content/images/2023/04/image-315.png)
_Editing the file manually to achieve the desired state (Source: [Brief](https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_

To compare the result file to what you had in the branch prior to the merge, you can run:</span>
</code></pre><p>git diff --ours</p>
<pre><code>
Similarly, <span class="hljs-keyword">if</span> you wish to see how the result <span class="hljs-keyword">of</span> the merge differs <span class="hljs-keyword">from</span> the branch you merged into our branch, you can run:
</code></pre><p>git diff -–theirs</p>
<pre><code>
You can even see how the result is different <span class="hljs-keyword">from</span> both sides using:
</code></pre><p>git diff -–base</p>
<pre><code>
Now you can stage the fixed version:
</code></pre><p>git add everyone.md</p>
<pre><code>
After staging, <span class="hljs-keyword">if</span> you look at <span class="hljs-string">`git status`</span>, you will see no conflicts:

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-316.png)</span>
_After staging the fixed version <span class="hljs-string">`everyone.md`</span>, there are no conflicts (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

You can now simply use <span class="hljs-string">`git commit`</span>, and Git will present you <span class="hljs-keyword">with</span> a commit message containing details about the merge. You can modify it <span class="hljs-keyword">if</span> you like, or leave it <span class="hljs-keyword">as</span> is. Regardless <span class="hljs-keyword">of</span> the commit message, Git will create a <span class="hljs-string">"merge commit"</span> – that is, a commit <span class="hljs-keyword">with</span> more than one parent. 

To validate that, consider the history:

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-317.png)</span>
_The history after completing the merge operation (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

<span class="hljs-string">`john_branch_4`</span> now points to the <span class="hljs-keyword">new</span> merge commit. The incoming branch, <span class="hljs-string">"theirs"</span>, <span class="hljs-keyword">in</span> <span class="hljs-built_in">this</span> <span class="hljs-keyword">case</span>, <span class="hljs-string">`paul_branch_4`</span>, stays where it was.

# How to Use VS Code to Resolve Conflicts

I will show you now how to resolve the same conflict using a graphical tool. For <span class="hljs-built_in">this</span> example, I will use VS Code, which is free and very common. There are many other tools, yet the process is similar, so I will just show VS Code <span class="hljs-keyword">as</span> an example. 

First, get back to the state before the merge:
</code></pre><p>git reset --hard HEAD~</p>
<pre><code>
And <span class="hljs-keyword">try</span> to merge again:
</code></pre><p>git merge paul_branch_4</p>
<pre><code>
You should be back at the same status:

![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-318.png)</span>
_Back at the conflicting status (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

Let<span class="hljs-string">'s see how this appears on VS Code:

![Image](https://www.freecodecamp.org/news/content/images/2023/04/image-320.png)
_Conflict resolution with VS Code (Source: [Brief](https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_

VS Code marks the different versions with "Current Change" – which is the "ours" version, the current `HEAD`, and "Incoming Change" for the branch we are merging into the active branch. You can accept one of the changes (or both) by clicking on one of the options.

If you clicked on `Resolve in Merge editor`, you would get a more visual view of the state. VS Code shows the status of each line:


![Image](https://www.freecodecamp.org/news/content/images/2023/04/image-321.png)
_VS Code'</span>s Merge Editor (Source: [Brief](https:<span class="hljs-comment">//www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_</span>

If you look closely, you will see that VS Code shows changes within words – <span class="hljs-keyword">for</span> example, showing that <span class="hljs-string">"Every**one**"</span> was changed to <span class="hljs-string">"Every**body**"</span>, marking the changed parts. 

You can accept either version, or you can accept a combination. In <span class="hljs-built_in">this</span> <span class="hljs-keyword">case</span>, <span class="hljs-keyword">if</span> you click on <span class="hljs-string">"Accept Combination"</span>, you get <span class="hljs-built_in">this</span> result:


![Image](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2023/04/image-322.png)</span>
_VS Code<span class="hljs-string">'s Merge Editor after clicking on "Accept Combination" (Source: [Brief](https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;amp;t=561s&amp;amp;ab_channel=Brief))_

VS Code did a really good job! The same three way merge algorithm was implemented here and used on the *word* level rather than the *line* level. So VS Code was able to actually resolve this conflict in a rather impressive way. Of course, you can modify VS Code'</span>s suggestion, but it provided a very good start.


# One More Powerful Tool 🪛
Well, <span class="hljs-built_in">this</span> was the first time <span class="hljs-keyword">in</span> <span class="hljs-built_in">this</span> entire series <span class="hljs-keyword">of</span> Git articles that I use a tool <span class="hljs-keyword">with</span> a graphical user interface. Indeed, graphical interfaces can be very convenient to understand what<span class="hljs-string">'s going on when you are resolving merge conflicts.

However, like in many other cases, when we need the big guns or *really* understand what'</span>s going on, the command line becomes handy. So <span class="hljs-keyword">let</span><span class="hljs-string">'s get back to the command line and learn a tool that can come in handy in more complicated cases.

Again, go back to the state before the merge:</span>
</code></pre><p>git reset --hard HEAD~</p>
<pre><code>
And merge:
</code></pre><p>git merge paul_branch_4</p>
<pre><code>
And say, you are not exactly sure what happened. Why is there a conflict? One very useful command would be:
</code></pre><p>git log -p -–merge
```</p>
<p>As a reminder, <code>git log</code> shows the history of commits that are reachable from <code>HEAD</code>. Adding <code>-p</code> tells <code>git log</code> to show the commits along the diffs they introduced. The <code>--merge</code> switch makes the command show all commits containing changes relevant to any <em>unmerged files</em>, on either branch, together with their diffs.</p>
<p>This can help you identify the changes in history that led to the conflicts. So in this example, you'd see:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-323.png" alt="Image" width="600" height="400" loading="lazy">
_The output of <code>git log -p -–merge</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>The first commit we see is "Commit 15", as in this commit John modified <code>everyone.md</code>, a file that still has conflicts. Next, Git shows "Commit 13", where Paul changed <code>everyone.md</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-324.png" alt="Image" width="600" height="400" loading="lazy">
_The output of <code>git log -p -–merge</code> - continued (Source: <a target="_blank" href="https://www.youtube.com/watch?v=BCNZ5Uxctuk&amp;t=561s&amp;ab_channel=Brief">Brief</a>)_</p>
<p>Notice that <code>git log --merge</code> did not mention previous commits that had changed <code>everyone.md</code> before "Commit 13", as they had not affected the current conflict.</p>
<p>This way, <code>git log</code> tells you all you need to know to understand the process that got you into the current conflicting state. Cool! 😎</p>
<p>Using the command line, you can also ask Git to take only one side of the changes – either "ours" or "theirs", even for a specific file. </p>
<p>You can also instruct Git to take some parts of the diffs of one file and another from another file. I will provide links that describe how to do that in the additional resources section below. </p>
<p>For the most part, you can accomplish that pretty easily either manually or from the UI of your favorite IDE.</p>
<p>For now, it's time for a recap.</p>
<h1 id="heading-recap">Recap</h1>
<p>In this guide, you got an extensive overview of merging with Git. You learned that merging is the process of combining the recent changes from several branches into a single new commit. The new commit has two parents – those commits which had been the tips of the branches that were merged.</p>
<p>We considered a simple, fast-forward merge, which is possible when one branch diverged from the base branch, and then just added commits on top of the base branch. </p>
<p>We then considered three-way merges, and explained the three-stage process:</p>
<ul>
<li>First, Git locates the merge base. As a reminder, this is the first commit that is reachable from both branches.</li>
<li>Second, Git calculates two diffs – one diff from the merge base to the <em>first</em> branch, and another diff from the merge base to the <em>second</em> branch. Git generates patches based on those diffs.</li>
<li>Third and last, Git applies both patches to the merge base using a 3-way merge algorithm. The result is the state of the new, merge commit.</li>
</ul>
<p>We dove deeper into the process of a 3-way merge, whether at a file level or a hunk level. We considered when Git is able to rely on a 3-way merge to automatically resolve conflicts, and when it just can't. </p>
<p>You saw the output of <code>git diff</code> when we are in a conflicting state, and how to resolve conflicts either manually or with VS Code.</p>
<p>There is much more to be said about merges – different merge strategies, recursive merges, and so on. Yet, after this guide, you should have a robust understanding of what merge is, and what happens under the hood in the vast majority of cases.</p>
<h1 id="heading-about-the-author"><strong>About the Author</strong></h1>
<p><a target="_blank" href="https://www.linkedin.com/in/omer-rosenbaum-034a08b9/">Omer Rosenbaum</a> is <a target="_blank" href="https://swimm.io/">Swimm</a>’s Chief Technology Officer. He's the author of the Brief <a target="_blank" href="https://youtube.com/@BriefVid">YouTube Channel</a>. He's also a cyber training expert and founder of Checkpoint Security Academy. He's the author of <a target="_blank" href="https://data.cyber.org.il/networks/networks.pdf">Computer Networks (in Hebrew)</a>. You can find him on <a target="_blank" href="https://twitter.com/Omer_Ros">Twitter</a>.</p>
<h1 id="heading-additional-references"><strong>Additional References</strong></h1>
<ul>
<li><a target="_blank" href="https://www.youtube.com/playlist?list=PL9lx0DXCC4BNUby5H58y6s2TQVLadV8v7">Git Internals YouTube playlist — by Brief</a>.</li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">Omer's previous post about Git internals.</a></li>
<li><a target="_blank" href="https://medium.com/@Omer_Rosenbaum/git-undo-how-to-rewrite-git-history-with-confidence-d4452e2969c2">Omer's piece about Git UNDO - rewriting history with Git</a>.</li>
<li><a target="_blank" href="https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging">https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging</a>.</li>
<li><a target="_blank" href="https://blog.plasticscm.com/2010/11/live-to-merge-merge-to-live.html">https://blog.plasticscm.com/2010/11/live-to-merge-merge-to-live.html</a>.</li>
<li><a target="_blank" href="https://www.oreilly.com/library/view/git-pocket-guide/9781449327507/ch07.html">https://www.oreilly.com/library/view/git-pocket-guide/9781449327507/ch07.html</a>.</li>
<li><a target="_blank" href="https://jwiegley.github.io/git-from-the-bottom-up/1-Repository/4-how-trees-are-made.html">https://jwiegley.github.io/git-from-the-bottom-up/1-Repository/4-how-trees-are-made.html</a>.</li>
</ul>
<h1 id="heading-appendix-beatles-related-resources">Appendix – Beatles-related resources</h1>
<ul>
<li><a target="_blank" href="https://www.the-paulmccartney-project.com/song/ive-got-a-feeling/">https://www.the-paulmccartney-project.com/song/ive-got-a-feeling/</a></li>
<li><a target="_blank" href="https://www.cheatsheet.com/entertainment/did-john-lennon-or-paul-mccartney-write-the-classic-a-day-in-the-life.html/">https://www.cheatsheet.com/entertainment/did-john-lennon-or-paul-mccartney-write-the-classic-a-day-in-the-life.html/</a></li>
<li><a target="_blank" href="http://lifeofthebeatles.blogspot.com/2009/06/ive-got-feeling-lyrics.html">http://lifeofthebeatles.blogspot.com/2009/06/ive-got-feeling-lyrics.html</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
