Git 笔记
1. 基础概念
- 工作区 Working Directory: 就是你在文件管理器中看到的目录,包含你的文件,
.git目录,里面包含所有内容,如修改但未跟踪(未添加到暂存区)的文件,git add 暂存的文件、git commit 提交后的版本库、当前所处分支等信息。 - 版本库 Repository: 工作区下有个
.git目录,里面存储了git运行所需的所有数据,包括暂存区 stage、分支信息、提交信息等。 - 暂存区 Stage:
2. 暂存区 stage
2.1. 添加到暂存区 stage
# 添加所有文件
git add .
# 添加指定文件
git add file.txt
# 添加指定目录
git add dir/
# 使用通配符
git add *.txt2.2. 从暂存区移除
# 移除所有文件, 其中 HEAD 表示最新的提交
git reset HEAD
# 移除指定文件
git reset HEAD file.txt
# 新语法
git restore --staged file.txt这样操作不会恢复你修改的内容,只是从暂存区移除而已。
3. 提交到本地仓库 commit
# 指定消息提交
git commit -m "message"
# 添加所有文件到暂存区并提交 (等于自动先执行了 git add .)
git commit -am "message"4. 查看提交记录 log
# 查看提交记录
git log
# 以每条记录一行的简洁方式查看
git log --pretty=oneline
# 包含分支的图表情况
git log --graph显示的结果是当前提交以及之前的提交,时间倒序排列。
5. 回退到上个版本 reset
# 恢复到上个版本
git reset --hard HEAD^
# 恢复到上上个版本
git reset --hard HEAD^^
# 恢复到上 n 个版本
git reset --hard HEAD~n
# 恢复到指定 commit_id 的版本, commit_id 可以通过 git log 查看
git reset --hard commit_id6. 查看操作记录 reflog
如你提交了 5 个版本,恢复到了第 2 次提交后,你想再恢复到第 5 次,但通过 git log 只能看到第 1-2 次提交的记录,第 3-5 次提交的记录看不到了,这时可以通过 git reflog 查看所有操作记录。
git reflog7. 撤销修改 checkout
# 撤销工作区的修改
git checkout -- file
# 新语法
git restore file.txt注意上面的命令是撤销工作区的修改,具体分为以下几种情况:
- 文件修改自修改后还未提交到暂存区:撤销后文件会和版本库的内容一致。
- 文件提交到过暂存区,但再次修改后未提交到暂存区:撤销后文件会和暂存区的内容一致。
如果已经提交到了暂存区,可以参考上面的 从暂存区移除.
其中
--是为了避免歧义,表示后面的是文件名,不是分支名。
8. 比较差异
# 工作区与暂存区比较
git diff file
# 暂存区与版本库比较, 也可以用 --staged, 效果是一样的
git diff --cached file
# 工作区与版本库比较
git diff HEAD file
# 工作区和某次提交比较
git diff commit_id file
# 比较两次提交
git diff commit_id1 commit_id29. 分支管理 branch
9.1. 创建, 查看, 切换, 合并, 删除分支
9.1.1. 添加分支
# 创建分支
git branch branch_name
# 创建并切换到该分支
git checkout -b branch_name
git switch -c branch_name9.1.2. 查看分支
# 查看所有分支
git branch9.1.3. 切换分支
git checkout branch_name
git switch branch_name9.1.4. 合并分支 merge
# 合并指定分支到当前分支
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_name9.1.5. 删除分支
git branch -d branch_name
# 如果分支未合并,则上面的命令会删除失败,需使用 -D 参数强制删除
git branch -D branch_name9.1.6. 重命名分支
# 修改当前所在分支名
git branch -m new_branch_name
# 修改指定分支名
git branch -m old_branch_name new_branch_name9.2. 冲突解决
当合并分支时,如果有冲突,会提示:
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the result.执行 git status 会显示冲突的文件:
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")提示我们有两个选择,手动解决冲突或放弃合并。
放弃冲突将会恢复合并前的状态:
git merge --abort手动合并的话,需要编辑冲突的文件,先来看看冲突文件的内容:
hello world java !
nihao
hello python;
add from main branch
<<<<<<< HEAD
2
=======
1
>>>>>>> dev上面的内容表示冲突的部分,<<<<<<< HEAD 到 ======= 之间是当前分支的内容,======= 到 >>>>>>> dev 之间是合并的分支的内容,我们需要手动解决冲突,编辑后再提交。
10. 高级技巧
10.1. stash 暂存区
如你正在开发一个功能,但突然有个 bug 需要修复,但是你本地还有开发一半的功能没法提交,这时可以使用 git stash 命令将当前工作区的内容暂存起来,等 bug 修复后再恢复。
# 暂存当前工作区
git stash修复 bug 后,回到开发分支后可以通过 git stash list 查看暂存的内容:
stash@{0}: WIP on main: 1389c31 merge bug branchstash@{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 分支。
如:
# 在 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 查看本地分支关联的远程分支。