Loading... ## 1. 基础概念 - 工作区 Working Directory: 就是你在文件管理器中看到的目录,包含你的文件,`.git` 目录,里面包含所有内容,如修改但未跟踪(未添加到暂存区)的文件,git add 暂存的文件、git commit 提交后的版本库、当前所处分支等信息。 - 版本库 Repository: 工作区下有个 `.git` 目录,里面存储了 `git` 运行所需的所有数据,包括暂存区 stage、分支信息、提交信息等。 - 暂存区 Stage: ## 2. 暂存区 stage ### 2.1. 添加到暂存区 stage ```bash # 添加所有文件 git add . # 添加指定文件 git add file.txt # 添加指定目录 git add dir/ # 使用通配符 git add *.txt ``` ### 2.2. 从暂存区移除 ```bash # 移除所有文件, 其中 HEAD 表示最新的提交 git reset HEAD # 移除指定文件 git reset HEAD file.txt # 新语法 git restore --staged file.txt ``` > 这样操作不会恢复你修改的内容,只是从暂存区移除而已。 ## 3. 提交到本地仓库 commit ```bash # 指定消息提交 git commit -m "message" # 添加所有文件到暂存区并提交 (等于自动先执行了 git add .) git commit -am "message" ``` ## 4. 查看提交记录 log ```bash # 查看提交记录 git log # 以每条记录一行的简洁方式查看 git log --pretty=oneline # 包含分支的图表情况 git log --graph ``` > 显示的结果是当前提交以及之前的提交,时间倒序排列。 ## 5. 回退到上个版本 reset ```bash # 恢复到上个版本 git reset --hard HEAD^ # 恢复到上上个版本 git reset --hard HEAD^^ # 恢复到上 n 个版本 git reset --hard HEAD~n # 恢复到指定 commit_id 的版本, commit_id 可以通过 git log 查看 git reset --hard commit_id ``` ## 6. 查看操作记录 reflog 如你提交了 5 个版本,恢复到了第 2 次提交后,你想再恢复到第 5 次,但通过 `git log` 只能看到第 1-2 次提交的记录,第 3-5 次提交的记录看不到了,这时可以通过 `git reflog` 查看所有操作记录。 ```bash git reflog ``` ## 7. 撤销修改 checkout ```bash # 撤销工作区的修改 git checkout -- file # 新语法 git restore file.txt ``` 注意上面的命令是撤销**工作区**的修改,具体分为以下几种情况: - 文件修改自修改后还未提交到暂存区:撤销后文件会和版本库的内容一致。 - 文件提交到过暂存区,但再次修改后未提交到暂存区:撤销后文件会和暂存区的内容一致。 如果已经提交到了暂存区,可以参考上面的 [从暂存区移除](#从暂存区移除). > 其中 `--` 是为了避免歧义,表示后面的是文件名,不是分支名。 ## 8. 比较差异 ```bash # 工作区与暂存区比较 git diff file # 暂存区与版本库比较, 也可以用 --staged, 效果是一样的 git diff --cached file # 工作区与版本库比较 git diff HEAD file # 工作区和某次提交比较 git diff commit_id file # 比较两次提交 git diff commit_id1 commit_id2 ``` ## 9. 分支管理 branch ### 9.1. 创建, 查看, 切换, 合并, 删除分支 #### 9.1.1. 添加分支 ```bash # 创建分支 git branch branch_name # 创建并切换到该分支 git checkout -b branch_name git switch -c branch_name ``` #### 9.1.2. 查看分支 ```bash # 查看所有分支 git branch ``` #### 9.1.3. 切换分支 ```bash git checkout branch_name git switch branch_name ``` #### 9.1.4. 合并分支 merge ```bash # 合并指定分支到当前分支 git merge branch_name # 合并分支时,加上 --no-ff 参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而默认的 fast forward 合并就看不出来曾经做过合并。 # 如 master 合并 dev 分支的修改,从指针上说: # fast forward 模式: 直接将 master 指针指向 dev 指针指向的内容. # no fast forward 模式: master 新建了一个跟 dev 指针内容一样的空间,并将 master 指向这个新 new 的指针. git merge --no-ff -m "merge branch xxx" branch_name ``` #### 9.1.5. 删除分支 ```bash git branch -d branch_name # 如果分支未合并,则上面的命令会删除失败,需使用 -D 参数强制删除 git branch -D branch_name ``` #### 9.1.6. 重命名分支 ```bash # 修改当前所在分支名 git branch -m new_branch_name # 修改指定分支名 git branch -m old_branch_name new_branch_name ``` ### 9.2. 冲突解决 当合并分支时,如果有冲突,会提示: ```bash Auto-merging file.txt CONFLICT (content): Merge conflict in file.txt Automatic merge failed; fix conflicts and then commit the result. ``` 执行 `git status` 会显示冲突的文件: ```bash On branch main You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: file.txt no changes added to commit (use "git add" and/or "git commit -a") ``` 提示我们有两个选择,手动解决冲突或放弃合并。 放弃冲突将会恢复合并前的状态: ```bash git merge --abort ``` 手动合并的话,需要编辑冲突的文件,先来看看冲突文件的内容: ```bash hello world java ! nihao hello python; add from main branch <<<<<<< HEAD 2 ======= 1 >>>>>>> dev ``` 上面的内容表示冲突的部分,`<<<<<<< HEAD` 到 `=======` 之间是当前分支的内容,`=======` 到 `>>>>>>> dev` 之间是合并的分支的内容,我们需要手动解决冲突,编辑后再提交。 ## 10. 高级技巧 ### 10.1. stash 暂存区 如你正在开发一个功能,但突然有个 bug 需要修复,但是你本地还有开发一半的功能没法提交,这时可以使用 `git stash` 命令将当前工作区的内容暂存起来,等 bug 修复后再恢复。 ```bash # 暂存当前工作区 git stash ``` 修复 bug 后,回到开发分支后可以通过 `git stash list` 查看暂存的内容: ```bash stash@{0}: WIP on main: 1389c31 merge bug branch ``` `stash@{0}` 表示**最新一次暂存**的内容,如果多次暂存会以压栈的方式存储,后面的内容是**暂存时的**分支信息:`WIP` 表示工作区(Working Directory)的意思,`main` 表示当前分支,`1389c31` 表示提交的 commit_id,`merge bug branch` 表示提交的消息。 可以通过 `git stash apply` 恢复暂存的内容(恢复栈顶也就是最新一次暂存的内容),不过恢复完后没有从栈中移除,可以通过 `git stash drop` 删除栈顶的内容,或者恢复时使用 `git stash pop` 恢复并删除栈顶的内容。 如果你不是要恢复栈顶的内容,可以通过 `git stash list` 查看暂存列表信息,然后通过 `git stash apply stash@{n}` 恢复指定的内容。 命令参考: | 命令 | 说明 | |------------------------------------------|----------------| | `git stash list` | 查看暂存列表 | | `git stash apply stash@{n}` | 恢复暂存内容 | | `git stash drop stash@{n}` | 删除暂存内容 | | `git stash pop stash@{n}` | 恢复并删除暂存内容 | | `git stash show stash@{n}` | 查看暂存的内容(修改的文件) | | `git stash branch branch_name stash@{n}` | 从暂存创建新分支 | | `git stash save "message"` | 暂存并添加消息 | | `git stash create` | 创建一个暂存,但不应用 | | `git stash clear` | 清空暂存列表 | ### 10.2. cherry-pick 优选 如你有两个分支 `master`, `dev`, 你正在 `dev` 分支开发,按照上一节的 `stash` 功能你为了修复紧急问题创建了个 `bug` 分支,修复后合并到 `master` 分支。 但是你正在开发的 `dev` 分支也需要这个修复,这时可以使用 `cherry-pick` 命令将 `master` 分支的修复 **"复制"** 到 `dev` 分支。 如: ```bash # 在 dev 上执行, commit_id 是 master 分支的修复提交 git cherry-pick commit_id ``` 这样会自动将指定的 `commit` 复制到当前分支并提交(如果有冲突需要手动解决),提交的日期、提交人、提交消息也是和优选的提交一样。 ## 11. 多人协作 - 远程仓库 | 命令 | 说明 | |---------------------------------------------------------------|-------------------------------------| | `git remote` | 查看远程仓库名称 | | `git remote -v` | 查看远程仓库详细信息 | | `git remote add <fetch\|push> origin repo_url` | 添加远程仓库, fetch 是拉取, push 是推送 | | `git remote rm origin` | 删除远程仓库 | | `git remote show origin` | 查看远程仓库详细信息 | | `git clone repo_url` | 克隆远程仓库 | | `git push origin master` | 把当前所在本地分支推送到远程仓库 origin 的 master 分支 | | `git push -u origin branch_name` | 一次性推送并关联远程分支 | | `git pull origin master` | 拉取远程仓库 origin 的 master 分支 | | `git branch --set-upstream-to=origin/branch_name branch_name` | 关联远程分支 | | `git branch -vv` | 查看本地分支关联的远程分支 | ### 关联远程仓库分支 `git clone` 时默认只会克隆远程仓库的主分支,如果想克隆其他分支,可以通过 `git checkout -b branch_name origin/branch_name` 创建并切换到指定分支,后面的 `origin/branch_name` 是关联的远程分支,如果不指定就是基于当前本地的分支创建新分支,而不是关联获取远程分支了。 如果你在本地创建了一个新分支,想推送到远程仓库,可以通过 `git push origin branch_name` 推送到远程仓库,如果远程仓库没有这个分支,会自动创建。 不过这样你每次推送都需要指定 `origin branch_name`,可以通过 `git push -u origin branch_name` 一次性推送并关联远程分支,以后推送就可以直接 `git push` 了。 如果你忘记加 `-u` 参数,可以通过 `git branch --set-upstream-to=origin/branch_name branch_name` 关联远程分支。 你可以通过 `git branch -vv` 查看本地分支关联的远程分支。 最后修改:2024 年 05 月 10 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请我喝杯咖啡吧。