{"id":20207075,"url":"https://github.com/chiclaim/gittutorials","last_synced_at":"2026-03-15T23:11:37.941Z","repository":{"id":117753901,"uuid":"225570114","full_name":"chiclaim/GitTutorials","owner":"chiclaim","description":"Git In Action，超级实用的 Git 实战教程","archived":false,"fork":false,"pushed_at":"2024-07-10T03:16:45.000Z","size":48,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-19T00:26:15.529Z","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/chiclaim.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-12-03T08:37:42.000Z","updated_at":"2024-07-10T03:16:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"2e6b38f9-5922-4185-8d9f-bef171ae1ded","html_url":"https://github.com/chiclaim/GitTutorials","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chiclaim%2FGitTutorials","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chiclaim%2FGitTutorials/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chiclaim%2FGitTutorials/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chiclaim%2FGitTutorials/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chiclaim","download_url":"https://codeload.github.com/chiclaim/GitTutorials/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243196657,"owners_count":20251861,"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":"2024-11-14T05:27:22.559Z","updated_at":"2025-12-27T00:43:42.365Z","avatar_url":"https://github.com/chiclaim.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# GitTutorials\n\n\n## git area（重要）\n\ngit area 主要由以下几个：\n- workspace area 也称之为 working tree\n- index area 也称之为 staging area\n- repository area 也称之为 local repository \n\n如下图所示：\n\n![git areas](images/git-areas.png)\n\n\n\n- `git add` 用于将文件内容添加到 `index`\n- `git commit` 将修改记录到 `repository`\n\n---\n\n- `git ls-files` 显示 index area 或 working tree 的文件信息\n- `git status` 显示 working tree 的状态\n\n## git 撤销操作\n\n\n### 使用场景 1\n\n当你在工作区，写了若干代码，但是你发现，这些代码没用，需要将这些修改撤销，但是修改的文件较多不可能一个一个文件手动撤销，这时你可以使用如下命令：\n\n```\n// 如果文件是新增的，处于 untracked（撤销所有）\ngit clean -f   // 如果有目录可以加上 -d\n\n// 如果文件是新增的（撤销指定）\ngit clean -f filenames\n\n// 如果是在已经存在文件基础上修改（撤销所有）\ngit checkout .\n\n// 如果是在已经存在文件基础上修改（撤销指定文件）\ngit checkout filenames // 撤销指定文件\ngit restore filenames // git 2.23.0 新增命令\n```\n\n上面的命令只会撤销 `workspace area` 的修改。\n\n### 使用场景 2\n\n当你写了若干代码后，执行了 git add（或 IDE 设置了自动 git add），那么文件的处于 tracked 状态，修改内容在 stage area(index area) 区域中\n\n此时你想撤销修改，但是修改的内容还想保留到工作区（仅仅从 stage area 撤销，即变成 untracked 状态），可以使用如下命令：\n\n```\ngit reset  // 针对所有修改\ngit reset filenames  // 指定具体文件\ngit restore --staged filenames  // 指定具体文件\n```\n\n如果撤销时不想保留工作区，可以使用：\n\n```\n// 不管是否是新建的文件、文件夹会一并被撤销\ngit checkout -f // 无法指定文件名\n```\n\n### 使用场景3\n\n当你的修改已经 commit（local repository），此时想要撤销怎么办？可以使用如下命令：\n\n```\n// 撤销后，修改会保留在 staging area 和 workspace area\ngit reset --soft HEAD~1\n\n// 撤销后，修改会保留在 workspace area\ngit reset --mixed HEAD~1   // 等同 git reset HEAD~1\n\n// 同时撤销在 `local repository` 和 `staging area`、`workspace area` 的修改：\ngit reset --hard HEAD~1  // 使用的时候需要注意\n```\n\n\u003e HEAD~1 表示回到当前(HEAD) commit 记录的上 1 个 commit.\n\n### git reset VS git revert\n\n`git revert`，它不会撤销原来的 commit 记录，而是新增一条 commit 记录。\n\n`git revert commit_id`，会在该 commit_id 的基础上做反操作，例如，添加一行，他就会删除该行。\n\n使用时也可以使用 `HEAD~`，如：\n```\ngit revert HEAD~1\n```\n\ngit revert 还可以撤销中间的某个 commit，其他的 commit 保持不变（git reset 则做不到这一点），如：\n\n```\n// 例如 commit 4 次，每次新增了一个文件，log 日志如下所示：\n~$ git reflog\n11584b6 (HEAD -\u003e master) HEAD@{0}: commit: t4\n947f0cc HEAD@{1}: commit: t3\n8f3f8ee HEAD@{2}: commit: t2\n8bc1c0b HEAD@{3}: commit (initial): t1\n// revert 第三次 commit\n~$ git revert 947f0cc\n~$ git reflog\n64eea6b (HEAD -\u003e master) HEAD@{0}: revert: Revert \"t3\"\n11584b6 HEAD@{1}: commit: t4\n947f0cc HEAD@{2}: commit: t3\n8f3f8ee HEAD@{3}: commit: t2\n8bc1c0b HEAD@{4}: commit (initial): t1\n~$ ls -l\ntotal 0\n-rw-r--r--  1 yuzhiqiang  staff  0 10 23 19:06 t1.txt\n-rw-r--r--  1 yuzhiqiang  staff  0 10 23 19:06 t2.txt\n-rw-r--r--  1 yuzhiqiang  staff  0 10 23 19:06 t4.txt\n// 可以看到第三次提交的文件不见了\n```\n\nreset 和 revert 使用场景的异同：\n\n1. 如果撤销的是你个人的分支（分支只有你一个人修改），可以使用 git reset，这样 git 记录也比较简洁\n2. 如果你需要撤销 git 记录中间的某条 commit，可以使用 git revert\n3. 如果撤销的是公共分支 （其他正在使用），则建议使用 git revert。如果使用 git reset 的话，当你 push 的时候后，其他人 pull，其本地记录可能会乱。\n\n\n\n## 删除操作汇总\n\n- **git clean 删除 working tree 中的 untracked file**\n\n  `git clean -f -d` 其中 -f(force)，-d(directory)    \n   需要注意的是，该命令不能删除 tracked file，如果需要将丢弃所有最近未 commit 的内容\n   可以先执行 `git checkout .` 然后执行 `git clean -f -d`\n\n\n- **git rm 从 working tree 和 index 中移除文件**\n\n    `git rm file` 文件会从 working tree 和 index 中移除\n    如果仅仅从 index 中移除，但保留在 working tree，可以使用 `git rm --cache`，那么文件会保留(cache)在 working tree 中\n    如果文件不在 index 中，即 untracked，那么 git rm 无法删除该文件\n    例如：你想将某个已提交的目录(.idea)，加入到 ignore 中，那么你可以：`git rm --cached -r .idea`, 然后修改 .gitignore 文件，最后，commit, push\n- **删除已经push的大文件**\n  \n  `python3 -m pip install git-filter-repo` （git 官方推荐）\n   按照文件大小升序排列并取最后40个文件:\n  ```\n  git rev-list --objects --all | grep \"$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -40 | awk '{print$1}')\"\n  ```\n  打印文件大小(brew install coreutils)：\n  ```\n\tgit rev-list --objects --all \\\n\t| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \\\n\t| sed -n 's/^blob //p' \\\n\t| sort --numeric-sort --key=2 \\\n\t| tail -n 20 \\\n\t| cut -c 1-12,41- \\\n\t| $(command -v gnumfmt || echo numfmt) --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest\n  ```\n  \n  例如删除，已经 push 的 apk 文件\n  ```\n  git filter-repo --force --invert-paths --path-regex .+\\.apk\n  ```\n  最后 push\n  ```\n  git push -f origin master\n  ```\n  \u003e https://stackoverflow.com/questions/37937984/git-refusing-to-merge-unrelated-histories-on-rebase\n    \n## 代码合并\n\n```\ngit merge master\n```\n\n也可以：\n```\ngit pull origin master\n```\n如果提示如下错误：\n```\nhint: Diverging branches can't be fast-forwarded, you need to either:\nhint:\nhint: \tgit merge --no-ff\nhint:\nhint: or:\nhint:\nhint: \tgit rebase\nhint:\nhint: Disable this message with \"git config advice.diverging false\"\n```\n\n```\n# you can use disable pull rebase by:\ngit config pull.rebase false\n\n# and change ff only to true\ngit config pull.ff true\n```\n\n\n\n\n\n## git 多用户\n\n描述：在同一台机器上，我们可能需要配置多个用户，例如公司的项目，需要使用公司的 git 账户，但是有的时候需要维护 github 上开源的项目。提交代码的时候需要区分用户。\n\n我们可以在不同的 repo 仓库使用 git config 来配置，如：\n\n```\ngit config user.name \"xxx\"\ngit config user.email \"xxx@xxx\"\n```\n\n但是项目多了，就比较麻烦，而且容易忘记。可以使用 `includeIf` 来设置，步骤如下：\n\n创建两个 `git-config` 文件，一个用于公司项目 一个用于个人项目：\n\n**.gitconfig-personal** \n\n```\n[user]\n\tname = your_name\n\temail = your_email\n```\n\n\n\n**.gitconfig-work**\n```\n[user]\n\tname = work_nick_name\n\temail = your_work_email\n```\n\n然后在 `.gitconfig` 中指定某个文件夹（如 CompanyProjects）使用 `.gitconfig-work` 的配置，其他文件夹均使用 .gitconfig-personal 的配置：\n\n```\n[include]\n    path = ~/.gitconfig-personal\n[includeIf \"gitdir:~/CompanyProjects/\"]\n    path = ~/.gitconfig-work\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchiclaim%2Fgittutorials","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchiclaim%2Fgittutorials","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchiclaim%2Fgittutorials/lists"}