推荐网站
师傅推荐的 一个很好的学习 Git 的网站
主要内容
基础篇
git commit
提交操作
git checkout <分支名>
用 git checkout <分支名> 来切换当前分支。
git branch <分支名>
用 git branch <分支名> 来创建分支
注意:git checkout -b <分支名> 一次性实现创建分支并切换到该分支。
git merge <分支名>
将<分支名>合并到当前分支
注:合并后要记得修改<分支名>,使得每一个分支都包含了代码库的所有修改。
git rebase <分支名>
rebase 的优势就是可以创造更线性的提交历史,这听上去有些难以理解。如果只允许使用 rebase 的话,代码库的提交历史将会变得异常清晰。
下图为 bugFix rebase 到 main 分支示例
高级篇
head
head 是一个对当前检出记录的符号引用 —— 也就是指向你正在其基础上进行工作的提交记录。
git checkout <提交记录上的标签(哈希值)>
由于不一定有可视化界面,所以我们可以用 git log 来查查看提交记录的哈希值。
相对引用 ^ ~
格式:git checkout <提交记录标签>^/~x
两个简单的用法:
使用 ^ 向上移动 1 个提交记录。
使用 ~ 向上移动多个提交记录,如 ~3。
例如:
main^ 相当于“main 的父节点”。
main^^ 是 main 的第二个父节点。
例子:
git checkout main^ 或者 git checkout check^ 指向父节点
git checkout main~4
强制相对引用 -f
格式:git branch -f <分支名> ^/~x
-f 是 force,强制。
撤销变更 git reset、git revert
git reset、git revert
本地分支中使用 git reset 很方便,但是这种“改写历史”的方法对大家一起使用的远程分支是无效的。
为了撤销更改并分享给别人,我们需要使用 git revert。
到现在我们已经学习了 Git 的基础知识 —— 提交、分支以及在提交树上移动。 这些概念涵盖了 Git 90% 的功能,同样也足够满足开发者的日常需求
移动提交记录
git cherry-pick
格式:git cherry-pick <提交号>...
更改顺序,按照提交号的顺序。
交互式的 rebase
格式:git rebase <分支名> -i
交互式 rebase 指的是使用带参数 --interactive 的 rebase 命令, 简写为 -i
杂项
只提交一个记录
如图所示,不想将 printf 的调试信息提交,只提交一个bugFix。
可以用 git cherry_pick 和 git rebase 结合解决。
提交的技巧#1
两次提交,想改 newImage 的,采用重新排序,修改,再重新排序的方式。
用到 rebase -i 和 commit -amend ,然后再次 rebase -i。
最后 merge 一下 main 和 caption 即可
提交的技巧#2
还是前面的问题,用 git cherry-pick 解决
git checkout main
git cherry-pick c2
git commit --amend
git cherry-pick c3
Git Tags
格式:git tag <标签名> <提交记录名>
标签在代码库中起着“锚点”的作用,可以标记大的版本更新,不会变换位置。
如果不指定提交记录,Git 会用 HEAD 所指向的位置。
Git Describe
格式:git describe <ref>
<ref> 可以是任何能被 Git 识别成提交记录的引用,如果你没有指定的话,Git 会以你目前所检出的位置(HEAD)。
输出的结果是这样的:
<tag>_<numCommits>_g<hash>
tag 表示的是离 ref 最近的标签, numCommits 是表示这个 ref 与 tag 相差有多少个提交记录, hash 表示的是你所给定的 ref 所表示的提交记录哈希值的前几位。
当 ref 提交记录上有某个标签时,则只输出标签名称
高级话题
多次 rebase
很多分支,要把这些分支 rebase 到 main 上。
两个父节点
操作符 ^ 与 ~ 符一样,后面也可以跟一个数字。
但是该操作符后面的数字与 ~ 后面的不同,并不是用来指定向上返回几代,而是指定合并提交记录的某个父提交。
Git 默认选择合并提交的“第一个”父提交,在操作符 ^ 后跟一个数字可以改变这一默认行为。
注:支持链式操作
这样就可以通过快速移动,到目标位置增加分支。
纠缠不清的分支
一道练习题
远程内容
Push & Pull —— Git 远程仓库
git clone
克隆
远程分支
clone 后,会发现本地仓库多了一个名为 o/main 的分支,这种类型的分支就叫远程分支。由于远程分支的特性导致其拥有一些特殊属性。
远程分支有一个特别的属性,在你检出时自动进入分离 HEAD 状态。
远程分支有一个命名规范 —— 它们的格式是:
<remote name>/<branch name>
远程仓库默认为 origin,o/main 的 o 是 origin 的缩写
git fetch
git fetch 完成了仅有的但是很重要的两步:
- 从远程仓库下载本地仓库中缺失的提交记录
- 更新远程分支指针(如 o/main)
git fetch 通常通过互联网(使用 http:// 或 git:// 协议) 与远程仓库通信。
git fetch 并不会改变你本地仓库的状态。它不会更新你的 main 分支,也不会修改你磁盘上的文件。
git pull
git pull 就是 git fetch 和 git merge 的合并。
然后是一个模拟训练。
git push
git push 负责将你的变更上传到指定的远程仓库,并在远程仓库上合并你的新提交记录。一旦 git push 完成,你的朋友们就可以从这个远程仓库下载你分享的成果。
注意 :git push 不带任何参数时的行为与 Git 的一个名为 push.default 的配置有关。它的默认值取决于你正使用的 Git 的版本,但是在教程中我们使用的是 upstream。 这没什么太大的影响,但是在你的项目中进行推送之前,最好检查一下这个配置。
偏离的工作
pull 下来进行开发,到提交的时候,这段时间别人有提交,与别人提交的有冲突。
可以用 fetch,rebase,再 push
也可以用 fetch,merge,再 push
可以用 git pull --rebase 再 git push
远程服务器拒绝(Remote Rejected)
pull requests
就是请求别人 pull 你的修改,一般别人不会让你直接在原仓库捣鼓的,你需要建个分支,改了之后,pull requests 给对方,对方觉得你的修改合理,才合并到 main 分支里。
关于 origin 和它的周边 —— Git 远程仓库高级操作
合并特性分支
更简洁的做法
合并远程仓库
经常用 rebase 而不用 merge
优点:Rebase 使你的提交树变得很干净, 所有的提交都在一条线上。
缺点:Rebase 修改了提交树的历史。
一些开发人员喜欢保留提交历史,因此更偏爱 merge。而其他人可能更喜欢干净的提交树,于是偏爱 rebase。这个仁者见仁,智者见智。
远程追踪
有两种方法设置这个属性,第一种就是通过远程分支检出一个新的分支
格式:git checkout -b totallyNotMain o/main
就可以创建一个名为 totallyNotMain 的分支,它跟踪远程分支 o/main
另一种设置远程追踪分支的方法就是使用:git branch -u 命令
格式:git branch -u o/main foo
这样 foo 就会跟踪 o/main 了。如果当前就在 foo 分支上, 还可以省略 foo:
git branch -u o/main
git push 的参数
我们可以为 push 指定参数,格式:git push <remote> <place>
git push origin main
把这个命令翻译过来就是:
切到本地仓库中的“main”分支,获取所有的提交,再到远程仓库“origin”中找到“main”分支,将远程仓库中没有的提交记录都添加上去,搞定之后告诉我。
我们通过“place”参数来告诉 Git 提交记录来自于 main, 要推送到远程仓库中的 main。它实际就是要同步的两个仓库的位置。
git push 的参数2
当为 git push 指定 place 参数为 main 时,我们同时指定了提交记录的来源和去向。
你可能想问 —— 如果来源和去向分支的名称不同呢?比如你想把本地的 foo 分支推送到远程仓库中的 bar 分支。
要同时为源和目的地指定 <place> 的话,只需要用冒号 : 将二者连起来就可以了:
格式:git push origin <source>:<destination>
git fetch 的参数
git fetch 的参数和 git push 极其相似。他们的概念是相同的,只是方向相反罢了。
没有 source 的 source