Git学习笔记
参考练习通关:Learn Git Branchinghttps://learngitbranching.js.org/?locale=zh_CN
- 创建提交新的记录
git commit
- 创建分支与分支切换
git branch new_branch_name //创建新分支
git checkout (或switch) new_branch_name //切换到新分支
有个更简洁的方式:
如果你想创建一个新的分支同时切换到新创建的分支的话,可以通过 git checkout -b <new_branch_name> 来实现。
- 分支合并
两个分支,每个分支上各有一个独有的提交。这意味着没有一个分支包含了我们修改的所有内容。咱们通过合并这两个分支来解决这个问题。
方法一:git merge new_branch_name
git merge branch_main //合并两个分支
会产生一个特殊的提交记录,把这两个父节点本身及它们所有的祖先都包含进来
方法二:git rebase branch_main //在分支上执行,合并到branch_main线上
git rebase new_branch_name //将branch_main的引用向前移动
Rebase 实际上就是取出一系列的提交记录,“复制”它们,然后在另外一个地方逐个的放下去。
- 在提交树上移动
HEAD 总是指向当前分支上最近一次提交记录。HEAD 通常情况下是指向分支名。
如果想看 HEAD 指向,可以通过 cat .git/HEAD 查看, 如果 HEAD 指向的是一个引用,还可以用 git symbolic-ref HEAD 查看它的指向。
分离的HEAD:
分离的 HEAD 就是让其指向了某个具体的提交记录而不是分支名。
原始:HEAD->main->c1(提交记录hash值)
执行:git checkout c1
之后:HEAD ->c1,main->c1
在实际应用时, 不得不用 git log 来查查看提交记录的哈希值(40位)。Git 对哈希的处理只需要提供能够唯一标识提交记录的前几个字符。
使用相对引用的话,你就可以从一个易于记忆的地方(比如 branch_name 分支或 HEAD)开始计算
相对引用:
” ^ ” // 向上移动1步,可以一次几个实现移动多步
git checkout HEAD^ // ^相当于查找父节点
git checkout branch_name ^ //到分支的上一个提交记录
“~<num>” //移动多步
git checkout HEAD~4 //一次向后退4步
git branch -f main head~3 //将 main 分支强制指向 HEAD 的第 3 级父提交。
- 撤销变更
撤销变更由底层部分(暂存区的独立文件或者片段)和上层部分(变更到底是通过哪种方式被撤销的)组成。我们这个应用主要关注的是后者。
方法一:git reset HEAD~1
//分支记录回退几个提交记录来实现撤销改动
//本地分支中使用 git reset 很方便, 对大家一起使用的远程分支
方法二: git revert HEAD
//远程分支撤销变更
- 整理提交记录
git cherry-pick c2 c4 //知道提交记录的哈希值
//将C2和c4提交复制到当前所在的位置(HEAD)下面
不清楚你想要的提交记录的哈希值时,可以利用交互式的 rebase
交互式 rebase 指的是使用带参数 --interactive 的 rebase 命令, 简写为 -I
在实际使用时,所谓的 UI 窗口一般会在文本编辑器 —— 如 Vim —— 中打开一个文件。
git rebase -i HEAD~4 //不知道提交记录的哈希值
当 rebase UI界面打开时, 你能做3件事:
调整提交记录的顺序(通过鼠标拖放来完成)
删除你不想要的提交(通过切换 pick 的状态来完成,关闭就意味着你不想要这个提交记录)
合并提交。简而言之,它允许你把多个提交记录合并成一个。
- 本地栈式提交
把 bugFix 分支里的工作合并回 main 分支。
你可以选择通过 fast-forward 快速合并到 main 分支上,但这样的话 main 分支就会包含这些调试语句了。你肯定不想这样,应该还有更好的方式……
方法一:git rebase –i //
方法二:git cherry-pick //
- 提交的技巧1
接下来这种情况也是很常见的:你之前在 newImage 分支上进行了一次提交,然后又基于它创建了 caption 分支,然后又提交了一次。
此时你想对某个以前的提交记录进行一些小小的调整。比如设计师想修改一下 newImage 中图片的分辨率,尽管那个提交记录并不是最新的了。
方法步骤:
先用 git rebase -i 将提交重新排序,然后把我们想要修改的提交记录挪到最前
然后用 git commit --amend 来进行一些小修改
接着再用 git rebase -i 来将他们调回原来的顺序
最后我们把 main 移到修改的最前端(用你自己喜欢的方法),就大功告成啦!
- 提交的技巧2
上面我们使用 rebase -i 对提交记录进行重新排序。只要把我们想要的提交记录挪到最前端,我们就可以很轻松的用 --amend 修改它,然后把它们重新排成我们想要的顺序。
但这样做就唯一的问题就是要进行两次排序,而这有可能造成由 rebase 而导致的冲突。下面还是看看 git cherry-pick 是怎么做的吧。
cherry-pick 可以将提交树上任何地方的提交记录取过来追加到 HEAD 上(只要不是 HEAD 上游的提交就没问题)。
- 重要提交记录标签
git tag v1 c1 / /为重要提交记录c1创建标签v1
//不指定c1时默认指向HEAD位置
- 描述最近锚点
git 还为此专门设计了一个命令用来描述离你最近的锚点(也就是标签)
git describle <ref> // <ref> 可以是任何能被 Git 识别成提交记录的引用,如果你没有指定的话,Git 会以你目前所检出的位置(HEAD)
输出的结果是这样的:
<tag>_<numCommits>_g<hash>
tag 表示的是离 ref 最近的标签, numCommits 是表示这个 ref 与 tag 相差有多少个提交记录, hash 表示的是你所给定的 ref 所表示的提交记录哈希值的前几位。
- 选择父提交记录
这里有一个合并提交记录。如果不加数字修改符直接检出 main^,会回到第一个父提交记录。
git checkout main //回到第一个父提交
git checkout main^2 //回到第二个父提交
git checkout HEAD~;git check HEAD^2; git checkout HEAD~2;
<==> git checkout HEAD~^2~2
- 纠缠不清的分支
现在我们的 main 分支是比 one、two 和 three 要多几个提交。出于某种原因,我们需要把 main 分支上最近的几次提交做不同的调整后,分别添加到各个的分支上。
one 需要重新排序并删除 C5,two 仅需要重排排序,而 three 只需要提交一次。
- 远程仓库
git clone 命令在真实的环境下的作用是在本地创建一个远程仓库的拷贝(比如从 github.com)
- 远程分支
名为 o/main 的分支, 这种类型的分支就叫远程分支.
远程分支反映了远程仓库(在你上次和它通信时)的状态
<remote name>/<branch name> // o/main分支就叫 main,远程仓库的名称就是 o
大多数的开发人员会将它们主要的远程仓库命名为 origin; git clone 某个仓库, 仓库默认为 origin.
git checkout o/main //HEAD分离状态
- 远程仓库获取数据
git fetch 指令完成:
从远程仓库下载本地仓库中缺失的提交记录
更新远程分支指针(如 o/main)
git fetch 通常通过互联网(使用 http:// 或 git:// 协议) 与远程仓库通信。
可以将 git fetch 的理解为单纯的下载操作。
- 将变换更新
当远程分支中有新的提交时(以用指令git fetch ),你可以像合并本地分支那样来合并远程分支。也就是说就是你可以执行以下命令:
git cherry-pick o/main
git rebase o/main
git merge o/main
git pull //先抓取更新再合并到本地分支
git push //将自己的变更内容分享
- 提交历史的偏离
——同事的推送提交导致你的工作就变成了基于项目旧版的代码,与远程仓库最新的代码不匹配了,这时就不允许你推送了。
解决方法:
方法一:git fetch; git rebase o/main ; git push
方法二:git fetch; git merge o/main ; git push
方法三: git pull --rebase ; git push //就是 fetch 和 rebase 的简写!
方法四:git pull; git push
- 远程服务器拒绝
main被锁定,试图推送(push)修改, 你将会收到这样类似的信息:
! [远程服务器拒绝] main -> main (TF402455: 不允许推送(push)这个分支; 你必须使用pull request来更新这个分支. )
解决方法:
git reset –hard o/main //--hard 硬重置,git默认位mixed
git checkout -b new_branch_name c2
git push origin new_branch_name
- 特性分支集成到main并推送到远程
git fetch ; //获取远程更新
git rebase side1 side2; //分支2接在分支1后面
git rebase side2 side3;
git rebase o/main; //融合分支side1 接在o/main分支后
git rebase side3 main
git push //推送我的更新
- merge与rebase的讨论
优点:
Rebase 使你的提交树变得很干净, 所有的提交都在一条线上
缺点:
Rebase 修改了提交树的历史
merge——保留提交历史:rebase——形成干净的提交树。
git checkout main; //切的main分支
git pull //拉取——本地创建远程更新分支
git merge side1 //在side1分支生成一个提交节点,同时指向main 分支
git merge side2;
git merge side3
git push
- 远程跟踪分支
pull 操作时, 提交记录会被先下载到 o/main 上,之后再合并到本地的 main 分支。隐含的合并目标由这个关联确定的。
push 操作时, 我们把工作从 main 推到远程仓库中的 main 分支(同时会更新远程分支 o/main) 。这个推送的目的地也是由这种关联确定的。
main 和 o/main 的关联关系就是由分支的“remote tracking”属性决定的。
可以让任意分支跟踪 o/main,有两种方法设置这个属性,
第一种就是通过远程分支检出一个新的分支,执行:
git checkout -b totallyNotMain o/main
例如:git checkout -b foo o/main ; git pull;
git checkout -b foo o/main ; git commit; git push;
另一种设置远程追踪分支的方法就是使用:
git branch -u 命令,执行:git branch -u o/main foo
例如:git branch -u o/main foo ; git pull;
git branch -u o/main foo ; git commit; git push;
- git push 的参数
可以为 push 指定参数,语法是:git push <remote> <place>
例:git push origin main
意思是:切到本地仓库中的“main”分支,获取所有的提交,再到远程仓库“origin”中 找到“main”分支,将远程仓库中没有的提交记录都添加上去,搞定之后告诉我。(HEAD指向分支头)
- <place>参数详解
要同时为源和目的地指定 <place> 的话,只需要用冒号 : 将二者连起来就可以了:git push origin <source>:<destination>
例如:git push origin foo^ :main //foo上一次更新push到main分支
git push origin main:newBranch //目的分支不存在会自动创建
- git fetch 的参数
git fetch 的参数和 git push 极其相似。他们的概念是相同的,只是方向相反罢了。
例:git fetch origin foo
参数 <source>:<destination> source 现在指的是远程仓库中的位置,而 <destination> 才是要放置提交的本地仓库的位置。
例如:git fetch origin foo~1 :bar //将远程foo~1的提叫记录下载到bar分支
如果 git fetch 没有参数,它会下载所有的提交记录到各个远程分支……
- 古怪的< source >
在 git push 或 git fetch 时不指定任何 source,方法就是仅保留冒号和 destination 部分,source 部分留空。
git push origin :side //destination与source 为空的分支被删除
git fetch origin :bugFix //远程仓库没有,会在本地创建新分支
- git pull 参数
git pull 到头来就是 fetch 后跟 merge 的缩写
git pull origin foo 相当于:
git fetch origin foo; git merge o/foo
git pull origin bar~1:bugFix 相当于:
git fetch origin bar~1:bugFix; git merge bugFix
git pull 唯一关注的是提交最终合并到哪里(也就是为 git fetch 所提供的 destination 参数)
git pull origin main // merge 到我们的检出位置(*所在分支)
git pull origin main :foo //它先在本地创建了一个叫 foo 的分支,从远程仓库中的 main 分支中下载提交记录,并合并到 foo,然后再 merge 到我们的当前检出的分支 bar 上。