{"id":23902688,"url":"https://github.com/mtumilowicz/git-notes","last_synced_at":"2026-06-22T07:31:48.568Z","repository":{"id":110875722,"uuid":"437656832","full_name":"mtumilowicz/git-notes","owner":"mtumilowicz","description":"Notes about git and its internals.","archived":false,"fork":false,"pushed_at":"2024-03-05T18:07:53.000Z","size":884,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-23T10:44:20.846Z","etag":null,"topics":["git","git-internals"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mtumilowicz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2021-12-12T21:08:54.000Z","updated_at":"2022-01-04T21:56:28.000Z","dependencies_parsed_at":"2024-03-05T19:27:09.602Z","dependency_job_id":"d0584f91-450c-45d3-a6b8-d695e5c3d3ec","html_url":"https://github.com/mtumilowicz/git-notes","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mtumilowicz/git-notes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fgit-notes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fgit-notes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fgit-notes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fgit-notes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mtumilowicz","download_url":"https://codeload.github.com/mtumilowicz/git-notes/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fgit-notes/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34639704,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["git","git-internals"],"created_at":"2025-01-04T22:49:53.481Z","updated_at":"2026-06-22T07:31:48.548Z","avatar_url":"https://github.com/mtumilowicz.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# git-notes\n\n* references\n    * https://www.manning.com/books/git-in-practice\n    * https://www.manning.com/books/learn-git-in-a-month-of-lunches\n    * https://git-scm.com/book/en/v2\n    * https://www.biteinteractive.com/understanding-git-merge/\n    * https://stackoverflow.com/questions/2304087/what-is-head-in-git\n    * https://www.atlassian.com/git/tutorials/git-submodule\n    * https://gist.github.com/gitaarik/8735255\n    * https://longair.net/blog/2010/06/02/git-submodules-explained/\n    * https://www.vogella.com/tutorials/GitSubmodules/article.html\n    * https://matthew-brett.github.io/curious-git/git_object_types.html\n    * https://stackoverflow.com/questions/61379397/how-is-git-using-git-objects-to-store-the-file-format\n    * [Git Internals - How Git Works - Fear Not The SHA!](https://www.youtube.com/watch?v=P6jD966jzlk)\n    * [Git Hidden Gems - Enrico Campidoglio - NDC Oslo 2023](https://www.youtube.com/watch?v=WtUCZYyv-_w)\n    * https://github.com/pluralsight/git-internals-pdf\n\n## basics\n* repository\n    * is the local collection of the files and contains a `.git` subdirectory in its root\n    * Git keeps track of the state of the files in the repository’s directory on disk\n    * remote repository = bare repository (Git repository that has no working directory)\n        * is only used as a collaboration point\n        * just the Git data (`.git` directory and nothing else)\n        * git remote --verbose\n            ```\n            origin  https://github.com/mtumilowicz/book-reports.wiki.git (fetch)\n            origin  https://github.com/mtumilowicz/book-reports.wiki.git (push)\n            ```\n            * what happens when the fetch and push urls differ?\n                * same repository accessed via different transports, not two separate repositories\n                    * example: ssh, https\n    * git stores all the history, branches, and commits locally\n        * example: querying history doesn’t require a network connection\n* git objects\n    * commits, blobs, tags, and trees\n    * overview\n    ![alt text](img/data_model2.png)\n* commit\n    * contains\n        * message entered by the author\n        * details of the commit author\n        * unique commit reference\n            * SHA-1 hashes such as `86bb0d659a39c98808439fadb8dbd594bec0004d`\n            * everything in Git is checksummed before it is stored and is then referred to by that checksum\n                * all commits effectively provide a checksum of the entire branch up until this point\n            * it’s impossible to change the contents of any file or directory without Git knowing about it\n            * Git stores everything in its database not by file name but by the hash value of its contents\n        * pointer to the preceding commit (parent commit)\n            * except for the first commit\n        * date the commit was created\n        * each commit object points to a tree object which represents the state of your source code at that commit\n* index\n    * Git doesn’t add anything to the index without your instruction\n    * the first thing you have to do with a file you want to include in a Git repository\n    is request that Git add it to the index\n    * stores information about what will go into your next commit\n    * workflow\n        ![alt text](img/workflow.png)\n* ref\n    * are the possible ways of addressing individual commits\n        * branch\n            * are pointers to specific commits\n            * referencing the branch master is the same as referencing the SHA-1 of the commit at the top of the master branch\n            * quicker and easier to remember for referencing commits than SHA-1\n            * how does Git know what branch you’re currently on\n                * special pointer: HEAD\n            * tracking branch\n                * local branches that have a direct relationship to a remote branch\n        * HEAD\n            * is you - points to whatever you checked out, wherever you are\n                * if you make a commit, HEAD will move, if you checkout something, HEAD will move\n            * example: if you checkout master, then master and HEAD are equivalent\n            * vs branch\n                * typically HEAD does not point to a commit - it points to a branch reference\n                * it is attached to that branch, and when you do certain things (e.g., commit or reset), the\n                attached branch will move along with HEAD\n            * detached HEAD state\n                * it means that HEAD points directly to a commit\n                * it is called a detached HEAD, because HEAD is pointing to something other than a branch reference\n                    * since you don't have a branch attached to you, the branch won't follow along with you as you\n                    make new commits\n                * you could be on the same commit as your master branch, but if HEAD is pointing to the commit\n                rather than the branch, it is detached and a new commit will not be associated with a branch reference\n                * representation of (HEAD -\u003e branch) vs. (HEAD, branch) with git log -1\n            * example\n                ```\n                cat .git/HEAD // ref: refs/heads/master\n                If you run git checkout test\n                cat .git/HEAD // ref: refs/heads/test\n                ```\n        * tag\n            * contains a tagger, a date, a message, and a pointer\n            * points to a commit rather than a tree\n            * like a branch reference, but it never moves\n                * always points to the same commit but gives it a friendlier name\n            * doesn’t need to point to a commit; you can tag any Git object\n    * `ref~1` or `ref^^` = one commit before that ref\n    * git rev-parse\n        * see what SHA-1 a given ref expands to\n\n## commands\n* git status\n    * tell you the state of your working directory\n* git history\n    * complete list of all commits made since the repository was created\n    * contains references to any branches, merges, and tags made within the repository\n* git add\n    * Git stages a file exactly as it is when you run the git add command\n    * if you `git commit`, the last `git add` version of the file will go into the commit\n        * not the version from your working directory\n        * if you modify a file after you run git add, you have to run git add again to\n        stage the latest version of the file\n    * Git can only keep track of files that it has been told about\n        * to introduce a new file you must use `git add` on that file first\n* git commit\n    * option: `-a`\n        * automatically stage every file that is already tracked before doing the commit\n        * performing the git add at the same time as git commit is a common shortcut\n        * you have to add the file first (with an initial `git add` ) before this shortcut can work\n* git amend\n    * when you’re amending your last commit, you’re replacing it with a new commit\n* git fetch\n    * fetches all the changes on the server that you don’t have\n    * not modify your working directory\n* git pull\n    * two phases\n        1. fetching the changes from a remote repository\n        1. merging them into the current branch\n    * option: `rebase`\n* git push\n* git merge\n    * result: a commit that has two (or even more) parent commits\n        * the latest commit from the master branch and the latest commit from the feature branch\n    * example\n        ```\n                          otherbranch\n                              |\n                    X \u003c- Y \u003c- Z\n                   /\n        A \u003c- B \u003c- C \u003c- D \u003c- E \u003c- F \u003c- G\n                                      |\n                                    master\n                                      |\n                                    HEAD\n        ```\n        * you are on `master` and you said `git merge otherbranch`\n            1. Git first figures out that the merge base is commit C\n            1. Git then calculates the diff from C to G (because G is master)\n            1. and the diff from C to Z (because Z is otherbranch)\n            1. Git then applies both of those diffs to C simultaneously — and commits the result on master\n                * That is the merge commit\n        ```\n                          otherbranch\n                              |\n                    X \u003c- Y \u003c- Z \u003c--------\\\n                   /                      \\\n        A \u003c- B \u003c- C \u003c- D \u003c- E \u003c- F \u003c- G \u003c- M\n                                           |\n                                         master\n                                           |\n                                         HEAD\n        ```\n    * conflicts\n        * one of the two diffs from the merge base shows that a certain line or clump of lines\n        was edited one way, and the other diff shows that the same clump of lines was edited a different way\n    * merge strategy\n        * is an algorithm that Git uses to decide how to perform a merge\n        * `--strategy=recursive`\n    * special case: fast-forward merge\n        * if incoming branch has the current branch as an ancestor, Git simplifies things\n        by moving the pointer forward\n            * there is no divergent work to merge\n* git rebase\n    * creates new, reparented commits on top of the existing commits\n    * all the changes that were committed on one branch and replay them on a different branch\n    * after rebasing you can fast-forward master branch\n* git stash\n    * you may find yourself working on a new commit and want to temporarily undo your current changes but\n    redo them at a later point\n    * live in their own namespace refs/stash\n    * stashes are stored on a stack structure\n        * when running git stash pop, the top stash on the stack ( stash@{0} ) is applied to the working\n        directory and removed from the stack\n* git tag\n    * usually used to mark release points (v1.0, v2.0 and so on)\n    * two types\n        * lightweight\n            * is like a branch that doesn’t change\n            * just a pointer to a specific commit\n        * annotated\n            * are stored as full objects in the Git database\n            * are checksummed\n                * contain the tagger name, email, date, and a tagging message\n    * by default, the git push command doesn’t transfer tags to remote servers\n        * use `git push origin --tags`\n    * `git checkout \u003ctagname\u003e`\n    * `git describe --tags` - list all tags\n* git cherry-pick\n    * used to include only a single commit from a branch onto the current branch rather than merging\n    * remark: sha-1 change on a cherry-pick\n* git diff\n* git revert\n* git config\n* git checkout\n* git reset\n    * modifies the current branch pointer so it points to another commit\n    * phases\n        1. Move the branch HEAD points to (stop here if --soft)\n        2. Make the index look like HEAD (stop here unless --hard)\n        3. Make the working directory look like the index.\n    * vs checkout\n        * checkout modifies the HEAD pointer so it points to another branch (or, rarely, commit)\n    * example\n        * `git commit --amend` resets to the previous commit and then creates a new commit with the same commit\n        message as the commit that was just reset\n* git reflog\n    * anything that is committed in Git can almost always be recovered\n        * even commits that were on branches that were deleted\n        * or commits that were overwritten with an --amend commit\n    * is updated whenever a commit pointer is updated (like a HEAD pointer or branch pointer)\n    * if everything is broken, you can use git reflog\n        * copy the hash of the event before your mistake, and then run\n    * is not shared with other repositories when you git push and aren’t fetched when you git fetch\n    * is an ordered list of the commits that HEAD has pointed to\n    * git reflog branch-name returns pointer history for specific branch\n    * suppose that we want to go back to things before rebase\n       * git reset --hard branch-name@{1} \n* git checkout\n    * will move HEAD itself to point to another branch (or commit)\n    * new command to separate the use cases of git checkout (does too many things)\n        * git switch - used to switch branches\n        * git restore - restore files to the state they were on a specified commit\n* git filter-branch\n    * rewriting the entire history of a branch\n    * iterates through the entire history of a branch and lets you rewrite every commit\n    * motivation\n        * accidentally committed confidential files\n        * committed a single huge file, every clone for all time will be forced to download that\n        large file, even if it was removed from the project\n            * it’s reachable from the history, it will always be there\n\n## submodules\n* motivation: while working on one project, you need to use another project from within it\n    * external code can be incorporated in a few different ways\n        1. external code can be directly copied and pasted into the main repository\n        1. incorporating external code is through the use of a language's package management system\n        1. git submodules\n* allow you to keep a Git repository as a subdirectory of another Git repository\n    * is a record that points to a specific commit in another external repository\n    * won't automatically be updated if the submodule's repository is updated\n    * they can be utilized exactly like stand-alone repositories\n* .gitmodules file\n    * contains meta data about the mapping between the submodule project's URL and local directory\n    * example\n        ```\n        [submodule \"awesomelibrary\"]\n         path = awesomelibrary\n         url = https://bitbucket.org/jaredw/awesomelibrary\n        ```\n* if you pull in new changes into the submodules, you need to create a new commit in your main\nrepository in order to track the updates of the nested submodules\n    * example\n        * one developer updates submodule to the latest commit\n            ```\n            # have the master branch checked out\n            cd [submodule directory]\n            git checkout master\n            git pull\n\n            # to use the latest commit in master of the submodule\n            cd ..\n            git commit -m \"move submodule to latest commit in master\"\n\n            git push\n            ```\n        * another developer can get the update\n            ```\n            git pull\n\n            git submodule update\n            ```\n* commands\n    * git submodule update\n        * moves into its subdirectory, run git fetch then git checkout the correct version\n        * used after pulling a change in the parent repository that updates the revision checked out in the submodule\n    * git submodule init\n        * if you freshly cloned the repo, you have to initiate submodules\n        * pull all the code from the submodule and place it in the directory that it's configured to\n    * git submodule status - show the current states of all submodules of a repository\n\n## internals\n* `.git` directory\n    * /.git/config // contains the configuration of the local repository\n    * /.git/description // is a file that describes the repository\n    * /.git/HEAD // HEAD pointer, respectively, that point to commits\n    * /.git/hooks/applypatch-msg.sample // event hooks: client- or server-side hook scripts\n    * /.git/info/exclude //  contains files that should be excluded from the repository\n    * /.git/objects/info // object information, used for object storage\n    * /.git/objects/pack // pack files, used for reference\n    * /.git/refs/heads // branch pointers, respectively, that point to commits\n    * /.git/refs/tags // tag pointers, respectively, that point to commits\n    * /.git/refs/remotes // stores the value you last pushed to that remote for each branch\n    * /.git/index // git’s index is a staging area used to build up new commits\n* Git doesn’t store data as a series of changesets or differences but as a series of snapshots\n* at the core of Git is a simple key-value data store\n    * you can insert any kind of content into a Git repository, for which Git will hand you\n    back a unique key you can use later to retrieve that content\n        * example\n            1. echo 'test content' | git hash-object -w --stdin\n                * option: -w\n                    * not simply return the key, but to write that object to the database\n                * option: --stdin\n                    * tells git hash-object to get the content to be processed from stdin\n            1. find .git/objects -type f\n* Git stores content in a manner similar to a UNIX filesystem, but a bit simplified\n    * all the content is stored as tree and blob objects\n        * trees ~ UNIX directory entries\n        * blobs ~ inodes or file contents\n    * each commit hash points to the tree object which in turn points to hash of blobs(files) and other tree's(folders)\n* example\n    ![alt text](img/data_model.png)\n* commands\n    * git cat-file -t \u003chash\u003e\n        * shows us the type of the object represented by a particular hash\n    * git cat-file -p \u003chash\u003e\n        * shows the contents of the file associated with this hash\n    * hash could be obtained from `git log`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fgit-notes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmtumilowicz%2Fgit-notes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fgit-notes/lists"}