{"id":24319930,"url":"https://github.com/gerardbosch/git-cheatsheet","last_synced_at":"2025-07-04T09:04:42.851Z","repository":{"id":103396981,"uuid":"199702979","full_name":"gerardbosch/git-cheatsheet","owner":"gerardbosch","description":"A compilation of advanced git tricks and hacks","archived":false,"fork":false,"pushed_at":"2021-11-15T17:07:35.000Z","size":7,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-27T09:50:48.092Z","etag":null,"topics":["git"],"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/gerardbosch.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,"publiccode":null,"codemeta":null}},"created_at":"2019-07-30T18:04:50.000Z","updated_at":"2021-11-15T17:07:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"d571ded0-2097-4e62-b59e-1ea4b1a687db","html_url":"https://github.com/gerardbosch/git-cheatsheet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gerardbosch/git-cheatsheet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerardbosch%2Fgit-cheatsheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerardbosch%2Fgit-cheatsheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerardbosch%2Fgit-cheatsheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerardbosch%2Fgit-cheatsheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gerardbosch","download_url":"https://codeload.github.com/gerardbosch/git-cheatsheet/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerardbosch%2Fgit-cheatsheet/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263480867,"owners_count":23473164,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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"],"created_at":"2025-01-17T15:47:00.533Z","updated_at":"2025-07-04T09:04:42.813Z","avatar_url":"https://github.com/gerardbosch.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"A compilation of not trivial Git tricks and hacks\n\n# Git advanced cheatsheet\n\n## Add submodule, but specific paths only (sparse-checkout)\n\nThis should do the trick and only add the specified subset of submodule files (just tweak `.git/modules/\u003csub\u003e/info/sparse-checkout` accordingly):\n\nhttps://stackoverflow.com/questions/45688121/how-to-do-submodule-sparse-checkout-with-git\n\n```console\ngit clone --no-checkout path/to/sub sub  # optional: --depth=1\ngit submodule add ./sub\ngit submodule absorbgitdirs\ngit -C sub config core.sparseCheckout true\necho 'foo/*' \u003e\u003e .git/modules/sub/info/sparse-checkout\ngit submodule update --force --checkout sub\n```\n*N.B. Maybe newer versions of Git can achieve the above in a more simple way.*\n\n## Squash all commits in a branch (disregarding it has merge-commits in between)\n\nTo rebase a branch upon the point it was born, e.g. `develop` and squash all commits in that branch\n(typical use case can be a shared branch with frequent _pulls_ from develop), do the following:\n\n```shell\ngit reset $(git merge-base origin/develop YOUR_BRANCH)   # or just `develop` if updated with origin\ngit add -A\ngit commit\n```\n\nAll the commits in `YOUR_BRANCH` will be gone, leading to a single final commit on top of `develop`.\n\n**N.B.** Rebasing rewrites the history, so be sure the branch is no longer shared when you squash\nit. Finally do a `push --force` if the branch was already pushed.\n\n## Misc\n\nUnset remote tracking branch: `git branch --unset-upstream`\n\n#### Remove tag (local and remote)\n```shell script\ngit push --delete origin TAG\ngit tag -d TAG\n```\n\n#### Stop tracking a commited file (prevent future updates)\n\n**Temporarily** ignore changes:\n\nDuring development it's convenient to stop tracking file changes to a file committed into your git repo. This is very\nconvenient when customizing settings or configuration files that are part of your project source for your own work\nenvironment.\n\n\u003e git update-index --assume-unchanged \u003cfile\u003e\n\nResume tracking files with:\n\n\u003e git update-index --no-assume-unchanged \u003cfile\u003e\n\n**Permanently** ignore changes to a file:\n\nIf a file is already tracked by Git, adding that file to `.gitignore` is not enough to ignore changes to the file.\nYou also need to remove the information about the file from Git's index:\n\n_These steps will not delete the file from your system._ They just tell Git to ignore future updates to the file.\n\n1. Add the file in your .gitignore.\n1. \u003e git rm --cached FILE\n1. Commit\n\n\n#### Cherry-pick from another repo (using patch)\n\n```shell script\ncd taret-repo\ngit --git-dir=../\u003csome_other_repo\u003e/.git \\\nformat-patch -k -1 --stdout \u003ccommit SHA\u003e | \\\ngit am -3 -k\n```\n\n(`-1` = single commit; `-3` = 3-way merge)\n\n#### Move a file between repos preserving history\n\n(Option A) Using patch (if history is sane):\n```shell script\ngit log --pretty=email --patch-with-stat --reverse -- path/to/file_or_folder | (cd /path/to/new_repository \u0026\u0026 git am)\n```\n\n(Option B) Adding the source repo as temporary remote:\n```shell script\ngit remote add srcrepo https://example.link/source-repository.git\ngit fetch srcrepo\ngit merge srcrepo/srcbranch --allow-unrelated-histories\ngit remote rm srcrepo\n```\nAnd resolve potential conflicts.\n\n(Option C) Fetching a repository branch:\n\n```\ngit fetch https://example.link/source-repository.git master\ngIt checkout master\ngit merge FETCH_HEAD\n```\nAnd resolve potential conflicts.\n\n**N.B.** `fetch` and `merge` can be replaced by `pull srcrepo srcbranch`\n\n#### Merge a whole remote repository into the current one (subtree merge)\n\nThis will allow you to migrate code from repository `srcrepo` to repository `dstrepo` while\npreserving `srcrepo`'s history and authorship of files. This can be done into a specific prefix path\nof destination repository instead of merging into the root, effectively allowing the merge of two\ndifferent projects together.\n\n```shell script\ngit remote add -f srcrepo https://example.link/source-repository.git\ngit merge -s ours --no-commit --allow-unrelated-histories srcrepo/master\ngit read-tree --prefix=path/to/destination -u srcrepo/master\ngit commit -m \"Srcrepo merged into dstrepo\"\ngit remote rm srcrepo\n```\n\nNotes (in command order):\n  * `-f` stands for `fetch`, so add remote and fetch it.\n  * `-s` ours makes it not apply the changes, as that would apply them to the root of the repository\n    (not to a subdirectory).\n  * `-u` makes it apply them not only to index, but also to the working directory.\n\nMore about it:\n  * https://gist.github.com/x-yuri/8ad01701db51ec2891ca431b78c58c72\n  * https://stackoverflow.com/a/32684526/6108874\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgerardbosch%2Fgit-cheatsheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgerardbosch%2Fgit-cheatsheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgerardbosch%2Fgit-cheatsheet/lists"}