{"id":1049,"date":"2023-02-10T11:16:17","date_gmt":"2023-02-10T11:16:17","guid":{"rendered":"https:\/\/www.aviator.co\/blog\/?p=1049"},"modified":"2025-09-25T14:00:13","modified_gmt":"2025-09-25T14:00:13","slug":"how-do-git-commits-actually-work","status":"publish","type":"post","link":"https:\/\/www.aviator.co\/blog\/how-do-git-commits-actually-work\/","title":{"rendered":"How do git commits actually work?"},"content":{"rendered":"\n<figure class=\"wp-block-image aligncenter size-large is-resized\"><img decoding=\"async\" src=\"https:\/\/github.githubassets.com\/images\/modules\/site\/social-cards\/git-guides\/git-commit.png\" alt=\"\" style=\"width:600px;height:314px\"\/><\/figure>\n\n\n\n<p><span style=\"font-weight: 400;\">Git is often one of the first tools developers learn to use, but it also is a black box of ~magic~ to many for that same reason. However, by learning about how Git operates at a lower level, you\u2019ll more intuitively understand what is happening when you run commands like and <code>git cherry pick<\/code>.<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">Whether you&#8217;re a Git novice or an experienced developer, this post will provide valuable insights into the inner workings of the world\u2019s most popular and powerful version control system.<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/docs.aviator.co\/mergequeue\" target=\"_blank\" rel=\" noreferrer noopener\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"264\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1-1024x264.png\" alt=\"MergeQueue CTA\" class=\"wp-image-4921\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1-1024x264.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1-300x77.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1-768x198.png 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1-1536x396.png 1536w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1.png 1940w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><b><a href=\"https:\/\/git-scm.com\/book\/en\/v2\/Git-Internals-Git-Objects\">Git is a content-addressable filesystem<\/a><\/b><\/h2>\n\n\n\n<p><span style=\"font-weight: 400;\">In other words, at the heart of Git lies a straightforward key-value data store. And, as its name suggests, it stores and accesses values (the data\/ content) with keys (the content address). <br><br>So what exactly do those keys and values look like? Hashes of the values, mostly.<br><br>More specifically, the keys are just SHA-1 hashes of the values. So then what are the values \/ the content of which we are taking the hash? To understand that, we have to learn more about Git objects <\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><b>Objects<\/b><\/h2>\n\n\n\n<p><span style=\"font-weight: 400;\">Git objects are the fundamental building blocks of a Git repository, used to store data such as commits, files, and directories.&nbsp;<\/span><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><b>Blob objects<\/b><\/h4>\n\n\n\n<p><span style=\"font-weight: 400;\">A blob, short for &#8220;binary large object,&#8221; is a type of Git object that stores the contents of a file as a snapshot in the Git object database.<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">To generate the hash for a blob object, Git calculates the SHA-1 hash of the file contents. This hash is later used to locate the blob object in the Git object database (.git\/objects). When you make changes to a file and commit the changes, Git stores the new contents of the file (<\/span><b><i>in its entirety, not just the diff<\/i><\/b><span style=\"font-weight: 400;\">) as a new blob object with a new SHA-1 hash. This allows Git to track the changes to the file over time and manage the file&#8217;s history.<br><br>If there existed a JSON representation of a blob object, it could look something like this: <br><\/span><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img decoding=\"async\" width=\"520\" height=\"265\" class=\"wp-image-1942\" style=\"width: 520px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-blob.png\" alt=\"git commit blob example\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-blob.png 1180w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-blob-300x153.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-blob-1024x522.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-blob-768x392.png 768w\" sizes=\"(max-width: 520px) 100vw, 520px\" \/><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">A couple things to note here First, git objects are not stored as JSON in Git. Second blob objects do not store the name of the file in it and only stores the contents of a file.<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">So then, how do we match a file with its respective contents?&nbsp;<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">With tree objects!&nbsp;<\/span><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><b>Tree objects<\/b><\/h4>\n\n\n\n<p><span style=\"font-weight: 400;\">A tree object is a type of Git object that represents the contents of a directory in a Git repository. It\u2019s an abstraction that enables Git to store a collection of files and directories together in a single object.&nbsp;<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">It does this by including a list of the files and directories contained in the directory, along with the SHA-1 object name (a unique identifier) of each file or directory. This creates a mapping between the names of the files and directories to their corresponding hashes.&nbsp;<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">To calculate the SHA-1 hash of a tree object, Git follows these steps:<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">Git creates a list of all the files and directories contained in the tree, along with their mode, type, and SHA-1 object name.<\/span><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img decoding=\"async\" width=\"529\" height=\"204\" class=\"wp-image-1943\" style=\"width: 529px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-files.png\" alt=\"git commit files\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-files.png 1180w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-files-300x115.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-files-1024x394.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-files-768x295.png 768w\" sizes=\"(max-width: 529px) 100vw, 529px\" \/><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">Git then sorts the list of files and directories alphabetically by name and creates a tree object that looks something like this:&nbsp;<\/span><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"529\" height=\"186\" class=\"wp-image-1945\" style=\"width: 529px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-tree.png\" alt=\"git tree object\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-tree.png 1180w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-tree-300x106.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-tree-1024x361.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-tree-768x271.png 768w\" sizes=\"(max-width: 529px) 100vw, 529px\" \/><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">In Git, the file mode specifies the type and permissions of a file. The number 100644 indicates that the file is a normal, non-executable file. The blob keyword indicates that the following hash refers to a blob object. The hash abcdef01 is the SHA-1 object name of the blob object for the file file1.txt.<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">For each file or directory in the list, it retrieves the SHA-1 object name of the file or directory. Then, it concatenates the object names and file or directory names into a single string. For example: <\/span><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"529\" height=\"237\" class=\"wp-image-1944\" style=\"width: 529px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-object.png\" alt=\"git commit tree hash\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-object.png 1180w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-object-300x134.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-object-1024x458.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commit-object-768x344.png 768w\" sizes=\"(max-width: 529px) 100vw, 529px\" \/><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">This hash, <\/span><b>9a42e3cecbace1112a02720e43451f89266a261b<\/b><span style=\"font-weight: 400;\">, would be the hash of the tree object.<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">This is just a general high-level overview of how Git creates an SHA-1 hash of a tree object.<br><br>A visual representation of a JSON tree object might look something like this: <\/span><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"532\" height=\"540\" class=\"wp-image-1947\" style=\"width: 532px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-json-tree.png\" alt=\"git json tree object\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-json-tree.png 1180w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-json-tree-295x300.png 295w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-json-tree-1009x1024.png 1009w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-json-tree-768x780.png 768w\" sizes=\"(max-width: 532px) 100vw, 532px\" \/><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><b>Commit objects<\/b><\/h4>\n\n\n\n<p><span style=\"font-weight: 400;\">A commit object is a type of Git object that represents a snapshot of the repository at a particular point in time. It stores a reference to a tree object, which represents the state of the repository&#8217;s directories and their respective files at the time of the commit, as well as a reference to one or more parent commit objects. Commit objects also include metadata such as the commit message, author, and timestamp.<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">Commit objects are created when you run the git commit command, and they form a linear chain of commits in the repository&#8217;s history. Each commit object is linked to its parent(s) through a reference, creating a linked list of commits. <\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">If there existed a JSON representation of a commit object, it would look something like the following:&nbsp;<br><\/span><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"530\" height=\"421\" class=\"wp-image-1946\" style=\"width: 530px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-json-commit.png\" alt=\"git json commit object\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-json-commit.png 1180w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-json-commit-300x238.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-json-commit-1024x814.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-json-commit-768x610.png 768w\" sizes=\"(max-width: 530px) 100vw, 530px\" \/><\/p>\n\n\n\n<p><b><strong>Example <\/strong><\/b><span style=\"font-weight: 400;\"><br>Now that we\u2019ve learned about Git objects, let\u2019s take a look at an example to actually see the inner workings of git using some plumbing commands!&nbsp;<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">To follow along, set up a demo-repo and a file called test.txt with \u201ctest content\u201d inside. Let\u2019s also go ahead and add that to our staging area, which will generate a blob object for the file,<\/span><b> test.txt. <\/b><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"530\" height=\"319\" class=\"wp-image-1948\" style=\"width: 530px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commands.png\" alt=\"git commands\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commands.png 928w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commands-300x180.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-commands-768x462.png 768w\" sizes=\"(max-width: 530px) 100vw, 530px\" \/><\/p>\n\n\n\n<p class=\"has-text-align-left\"><span style=\"font-weight: 400;\">When we added the file to our staging area, we essentially took a snapshot of the contents of test.txt. To take this snapshot, we create a blob object and generate a SHA-1 hash of the contents of the file, test.txt, for the key. <br><br>Now, if you run \u201cfind .git\/objects -type f\u201d in the command line, it\u2019ll come up with a file path that resembles a SHA-1 Hash \u2014 because that\u2019s exactly what it is! <\/span><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"296\" class=\"wp-image-1949\" style=\"width: 700px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/find-git-objects.png\" alt=\"find git objects\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/find-git-objects.png 1320w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/find-git-objects-300x127.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/find-git-objects-1024x433.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/find-git-objects-768x325.png 768w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\"><br>Note: Notice that Git split the hash into d6 &amp; 70460\u2026 \u2014 Git names the subdirectory with the first 2 characters of the SHA-1, and the filename is the remaining 38 characters.<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">To check the value (or the content of the .git\/object that we just found), we can use \u201cgit cat-file -p &lt;HASH&gt;\u201d. The git cat-file command will display the contents of a git object, such as a blob in this example.<\/span><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"296\" class=\"wp-image-1951\" style=\"width: 700px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-file.png\" alt=\"git cat file\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-file.png 1320w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-file-300x127.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-file-1024x433.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-file-768x325.png 768w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\"><br>In this example, we are operating at the lowest level of abstraction (tracking only files, not directories etc), so we are just taking the SHA-1 of files and creating blob objects. Can we now create a tree object? <br><br>Of course! Recall that a commit object is merely a reference to a tree object. So, if we go ahead and \u201cgit commit\u201d our staged changes, we\u2019ll effectively not only create a tree object, but also a commit object! <br><\/span><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"253\" class=\"wp-image-1950\" style=\"width: 700px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-commit-object.png\" alt=\"git cat commit object\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-commit-object.png 1476w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-commit-object-300x109.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-commit-object-1024x370.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-commit-object-768x278.png 768w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\"><br>Here, we re-use the <code>git cat-file<\/code> command to explore the tree object that\u2019s pointed to by the latest commit object on the main branch currently. Then, to explore the commit object that is pointing to the tree object, we can use <code>git rev-parse<\/code> to first find the hash of the latest commit on the main branch: <br><\/span><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"227\" class=\"wp-image-1953\" style=\"width: 600px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-rev-parse.png\" alt=\"git rev parse\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-rev-parse.png 1476w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-rev-parse-300x113.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-rev-parse-1024x387.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-rev-parse-768x290.png 768w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">Then we can use the <code>git cat-file<\/code> command again to display the contents of the commit object, using the SHA-1 object name obtained in the previous step:<br><\/span><\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"254\" class=\"wp-image-1952\" style=\"width: 600px;\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-sha-1.png\" alt=\"git cat sha1\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-sha-1.png 1600w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-sha-1-300x127.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-sha-1-1024x434.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-sha-1-768x325.png 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/git-cat-sha-1-1536x651.png 1536w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">Finally, let\u2019s list all of the git objects in our .git\/objects folder by:&nbsp;<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">As<\/span> we expected, we see the 3 git objects we\u2019ve explored using git plumbing commands: d6\/704.. (blob), 80\/865\u2026(tree), 28\/000&#8230; (commit). We can double-check<span style=\"font-weight: 400;\"> these via the hashes we found in the previous steps.&nbsp;<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><b><a href=\"https:\/\/github.blog\/2020-12-17-commits-are-snapshots-not-diffs\/\" target=\"_blank\" rel=\"noreferrer noopener\">Commits are snapshots, not diffs<\/a><\/b><\/h2>\n\n\n\n<p><span style=\"font-weight: 400;\">In conclusion, rather than a series of changes or diffs, commits in Git are snapshots of the repository at specific points in time as seen in the \u201csnapshot\u201d design of blob objects &amp; its key-value store design.&nbsp;<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">As we saw, this design choice allows Git to store the entire history of a repository efficiently, without having to track the changes (or diffs) made to each file individually.&nbsp;<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">Having rebuilt (or built for the first time) our mental models of how git commits <\/span><i><span style=\"font-weight: 400;\">actually<\/span><\/i><span style=\"font-weight: 400;\"> work, we\u2019ll be able to more effectively use this powerful tool in our daily work to supercharge development and make better decisions while building workflows for our teams!<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/www.aviator.co\/\" target=\"_blank\" rel=\"noreferrer noopener\">Aviator<\/a>: Automate your cumbersome merge processes<\/h2>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/www.aviator.co\/\" target=\"_blank\" rel=\"noreferrer noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"727\" src=\"https:\/\/blog.aviator.co\/wp-content\/uploads\/2022\/08\/blog-cta-1024x727.png\" alt=\"\" class=\"wp-image-57\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2022\/08\/blog-cta-1024x727.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2022\/08\/blog-cta-300x213.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2022\/08\/blog-cta-768x545.png 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2022\/08\/blog-cta-1536x1090.png 1536w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2022\/08\/blog-cta-2048x1454.png 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Aviator automates tedious developer workflows by managing git Pull Requests (PRs) and continuous integration test (CI) runs to help your team avoid broken builds, streamline cumbersome merge processes, manage cross-PR dependencies, and handle flaky tests while maintaining their security compliance.<\/p>\n\n\n\n<p>There are 4 key components to Aviator:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>MergeQueue<\/strong>&nbsp;\u2013 an automated queue that manages the merging workflow for your GitHub repository to help protect important branches from broken builds. The Aviator bot uses GitHub Labels to identify Pull Requests (PRs) that are ready to be merged, validates CI checks, processes semantic conflicts, and merges the PRs automatically.<\/li>\n\n\n\n<li><strong>ChangeSets<\/strong>&nbsp;\u2013 workflows to synchronize validating and merging multiple PRs within the same repository or multiple repositories. Useful when your team often sees groups of related PRs that need to be merged together, or otherwise treated as a single broader unit of change.<\/li>\n\n\n\n<li><strong>FlakyBot<\/strong>&nbsp;\u2013 a tool to automatically detect, take action on, and process results from flaky tests in your CI infrastructure.<\/li>\n\n\n\n<li><strong>Stacked PRs CLI<\/strong>&nbsp;\u2013 a command line tool that helps developers manage cross-PR dependencies. This tool also automates syncing and merging of stacked PRs. Useful when your team wants to promote a culture of smaller, incremental PRs instead of large changes, or when your workflows involve keeping multiple, dependent PRs in sync.<\/li>\n<\/ol>\n\n\n\n<p><a href=\"https:\/\/www.aviator.co\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Try it for free.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A simple post that helps to build (or rebuild) your mental models for how Git commits work.<\/p>\n","protected":false},"author":16,"featured_media":1108,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[301],"tags":[29],"class_list":["post-1049","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials-guides"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":6}},"acf":[],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/01\/git-commit.png","post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/1049","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/comments?post=1049"}],"version-history":[{"count":14,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/1049\/revisions"}],"predecessor-version":[{"id":4968,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/1049\/revisions\/4968"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/media\/1108"}],"wp:attachment":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/media?parent=1049"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/categories?post=1049"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/tags?post=1049"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}