github实战

github实战链接:https://learngitbranching.js.org/

主要

git commit
这里写图片描述

git commit
git commit

git branch
创建一个名为 bugFix 的新分支,然后切换过去。
对了,有个更简洁的方式:如果你想创建一个新的分支同时切换到新创建的分支的话,可以通过 git checkout -b 来实现。
这里写图片描述

git checkout -b bugFix

git merge
如何将两个分支合并到一起。就是说我们新建一个分支,在其上开发某个新功能,开发完成后再合并回主线。
咱们先来看一下第一种方法 —— git merge。在 Git 中合并两个分支时会产生一个特殊的提交记录,它有两个父节点。翻译成自然语言相当于:“我要把这两个父节点本身及它们所有的祖先都包含进来。”
这里写图片描述

git checkout -b bugFix
git commit
git checkout master
git commit
git merge bugFix

git rebase
第二种合并分支的方法是 git rebase。Rebase 实际上就是取出一系列的提交记录,“复制”它们,然后在另外一个地方逐个的放下去。
这里写图片描述

git checkout -b bugFix
git commit
git checkout master
git commit
git rebase master bugFix

分离HEAD
HEAD 是一个对当前检出记录的符号引用 —— 也就是指向你正在其基础上进行工作的提交记录。
HEAD 总是指向当前分支上最近一次提交记录。大多数修改提交树的 Git 命令都是从改变 HEAD 的指向开始的。
想完成此关,从 bugFix 分支中分离出 HEAD 并让其指向一个提交记录。
通过哈希值指定提交记录。每个提交记录的哈希值显示在代表提交记录的圆圈中。
这里写图片描述

git checkout C4

相对引用^
相对引用非常给力,这里我介绍两个简单的用法:
使用 ^ 向上移动 1 个提交记录
使用 ~ 向上移动多个提交记录,如 ~3
这里写图片描述

git checkout bugFix^

相对引用~
我使用相对引用最多的就是移动分支。可以直接使用 -f 选项让分支指向另一个提交。例如:
git branch -f master HEAD~3
要完成此关,移动 HEAD,master 和 bugFix 到目标所示的位置。
这里写图片描述

git branch -f master C6
git checkout HEAD~1
git branch -f bugFix HEAD~1

撤销变更
git reset 通过把分支记录回退几个提交记录来实现撤销改动。你可以将这想象成“改写历史”。git reset 向上移动分支,原来指向的提交记录就跟从来没有提交过一样。
虽然在你的本地分支中使用 git reset 很方便,但是这种“改写历史”的方法对大家一起使用的远程分支是无效的哦!
为了撤销更改并分享给别人,我们需要使用 git revert。
要完成此关,分别撤销 local 分支和 pushed 分支上的最近一次提交。共需要撤销两个提交(每个分支一个)。
记住 pushed 是远程分支,local 是本地分支。
这里写图片描述

git reset C1
git checkout pushed
git revert C2

git cherry-pick
git cherry-pick, 命令形式为:
git cherry-pick <提交号>…
如果你想将一些提交复制到当前所在的位置(HEAD)下面的话, Cherry-pick 是最直接的方式了。
这里写图片描述

git cherry-pick C3 C4 C7

交互式rebase
当你你知道你所需要的提交记录(并且还知道这些提交记录的哈希值)时, 用 cherry-pick 再好不过了 —— 没有比这更简单的方式了。
但是如果你不清楚你想要的提交记录的哈希值呢? 幸好 Git 帮你想到了这一点, 我们可以利用交互式的 rebase —— 如果你想从一系列的提交记录中找到想要的记录, 这就是最好的方法了。
交互式 rebase 指的是使用带参数 –interactive 的 rebase 命令, 简写为 -i
如果你在命令后增加了这个选项, Git 会打开一个 UI 界面并列出将要被复制到目标分支的备选提交记录,它还会显示每个提交记录的哈希值和提交说明,提交说明有助于你理解这个提交进行了哪些更改。
这里写图片描述

扫描二维码关注公众号,回复: 2412336 查看本文章
git rebase -i master~4

只取一个提交记录
确保 master 分支能得到 bugFix 分支上的相关提交。
这里写图片描述

git checkout master
git cherry-pick bugFix

提交的技巧
接下来这种情况也是很常见的:你之前在 newImage 分支上进行了一次提交,然后又基于它创建了 caption 分支,然后又提交了一次。
此时你想对的某个以前的提交记录进行一些小小的调整。比如设计师想修改一下 newImage 中图片的分辨率,尽管那个提交记录并不是最新的了。
我们可以使用 rebase -i 对提交记录进行重新排序。只要把我们想要的提交记录挪到最前端,我们就可以很轻松的用 –amend 修改它,然后把它们重新排成我们想要的顺序。
这里写图片描述

git rebase -i HEAD~2 --solution-ordering C3,C2
git commit --amend
git rebase -i HEAD~2 --solution-ordering C2'',C3'
git rebase caption master

提交的技巧
正如你在上一关所见到的,我们可以使用 rebase -i 对提交记录进行重新排序。只要把我们想要的提交记录挪到最前端,我们就可以很轻松的用 –amend 修改它,然后把它们重新排成我们想要的顺序。
但这样做就唯一的问题就是要进行两次排序,而这有可能造成由 rebase 而导致的冲突。下面还是看看 git cherry-pick 是怎么做的吧。
要在心里牢记 cherry-pick 可以将提交树上任何地方的提交记录取过来追加到 HEAD 上(只要不是 HEAD 上游的提交就没问题)。
这一关的目标和上一关一样,通过 –amend 改变提交记录 C2,但你不能用 rebase -i。
这里写图片描述

git checkout master
git cherry-pick C2
git commit --amend
git cherry-pick C3

git tag
分支很容易被人为移动,并且当有新的提交时,它也会移动。分支很容易被改变,大部分分支还只是临时的,并且还一直在变。
有没有什么可以永远指向某个提交记录的标识呢,比如软件发布新的大版本,或者是修正一些重要的 Bug 或是增加了某些新特性,有没有比分支更好的可以永远指向这些提交的方法呢?
当然有了!Git 的 tag 就是干这个用的啊,它们可以(在某种程度上 —— 因为标签可以被删除后重新在另外一个位置创建同名的标签)永久地将某个特定的提交命名为里程碑,然后就可以像分支一样引用了。
更难得的是,它们并不会随着新的提交而移动。你也不能检出到某个标签上面进行修改提交,它就像是提交树上的一个锚点,标识了某个特定的位置。
在这个关卡中,按照目标建立两个标签,然后检出到 v1 上面,要注意你会进到分离 HEAD 的状态 —— 这是因为不能直接在v1 上面做 commit
这里写图片描述

git tag v0 C1
git tag v1 C2
git checkout v1

git describe
由于标签在代码库中起着“锚点”的作用,Git 还为此专门设计了一个命令用来描述离你最近的锚点(也就是标签),它就是 git describe!
Git Describe 能帮你在提交历史中移动了多次以后找到方向;当你用 git bisect(一个查找产生 Bug 的提交记录的指令)找到某个提交记录时,或者是当你坐在你那刚刚度假回来的同事的电脑前时, 可能会用到这个命令。
git describe 的​​语法是:
git describe {ref}
{ref} 可以是任何能被 Git 识别成提交记录的引用,如果你没有指定的话,Git 会以你目前所检出的位置(HEAD)。
它输出的结果是这样的:
{tag}_{numCommits}_g{hash}
tag 表示的是离 ref 最近的标签,numCommits 是表示这个 ref 与 tag 相差有多少个提交记录, hash 表示的是你所给定的 ref 所表示的提交记录哈希值的前几位。
当 ref 提交记录上有某个标签时,则只输出标签名称
这里写图片描述

git describe master 会输出:
v1_2_gC2

git describe side 会输出:
v2_1_gC4

多次rebase
我们准备了很多分支!咱们把这些分支 rebase 到 master 上吧。
但是你的领导给你提了点要求 —— 他们希望得到有序的提交历史,也就是我们最终的结果应该是 C6’ 在 C7’ 上面, C5’ 在 C6’ 上面,依此类推。
这里写图片描述

git rebase master bugFix
git rebase bugFix side
git rebase side another
git rebase another master

两个父节点

操作符 ^ 与 ~ 符一样,后面也可以跟一个数字。
但是该操作符后面的数字与 ~ 后面的不同,并不是用来指定向上返回几代,而是指定合并提交记录的某个父提交。还记得前面提到过的一个合并提交有两个父提交吧,所以遇到这样的节点时该选择哪条路径就不是很清晰了。
Git 默认选择合并提交的“第一个”父提交,在操作符 ^ 后跟一个数字可以改变这一默认行为。
要完成此关,在指定的目标位置创建一个新的分支。
很明显可以简单地直接使用提交记录的哈希值(比如 C6),但我要求你使用刚刚讲到的相对引用修饰符!
这里写图片描述

git branch bugWork master^^2^

纠缠不清的分支
现在我们的 master 分支是比 one、two 和 three 要多几个提交。出于某种原因,我们需要把 master 分支上最近的几次提交做不同的调整后,分别添加到各个的分支上。
one 需要重新排序并删除 C5,two 仅需要重排排序,而 three 只需要提交一次。
这里写图片描述

git checkout one
git cherry-pick C4 C3 C2
git checkout two
git cherry-pick C5 C4 C3 C2
git branch -f three C2

远程

git clone
git clone 命令在真实的环境下的作用是在本地创建一个远程仓库的拷贝(比如从 github.com)。
这里写图片描述

git clone

远程分支
既然你已经看过 git clone 命令了,咱们深入地看一下发生了什么。
你可能注意到的第一个事就是在我们的本地仓库多了一个名为 o/master 的分支, 这种类型的分支就叫远程分支。由于远程分支的特性导致其拥有一些特殊属性。
远程分支反映了远程仓库(在你上次和它通信时)的状态。这会有助于你理解本地的工作与公共工作的差别 —— 这是你与别人分享工作成果前至关重要的一步。
远程分得有一个特别的属性,在你检出时自动进入分离 HEAD 状态。Git 这么做是出于不能直接在这些分支上进行操作的原因, 你必须在别的地方完成你的工作, (更新了远程分支之后)再用远程分享你的工作成果。
为什么有 o/?
你可能想问这些远程分支的前面的 o/ 是什么意思呢?好吧, 远程分支有一个命名规范 —— 它们的格式是:
{remote name}/{branch name}
因此,如果你看到一个名为 o/master 的分支,那么这个分支就叫 master,远程仓库的名称就是 o。
大多数的开发人员会将它们主要的远程仓库命名为 origin,并不是 o。这是因为当你用 git clone 某个仓库时,Git 已经帮你把远程仓库的名称设置为 origin 了
不过 origin 对于我们的 UI 来说太长了,因此不得不使用简写 o
这里写图片描述

git commit
git checkout o/master
git commit

get fetch
git fetch 完成了仅有的但是很重要的两步:
从远程仓库下载本地仓库中缺失的提交记录
更新远程分支指针(如 o/master)
git fetch 实际上将本地仓库中的远程分支更新成了远程仓库相应分支最新的状态。
git fetch 并不会改变你本地仓库的状态。它不会更新你的 master 分支,也不会修改你磁盘上的文件。
理解这一点很重要,因为许多开发人员误以为执行了 git fetch 以后,他们本地仓库就与远程仓库同步了。它可能已经将进行这一操作所需的所有数据都下载了下来,但是并没有修改你本地的文件。
这里写图片描述

get fetch

git pull
git pull 就是 git fetch 和 git merge {just-fetched-branch} 的缩写!
这里写图片描述

git pull

模拟团队合作
自己制作的命令–fakeTeamwork 默认操作就是在远程仓库的 master 分支上做一次提交。
这里写图片描述

git clone
git fakeTeamwork 2
git commit
git pull

git push
git push 负责将你的变更上传到指定的远程仓库,并在远程仓库上合并你的新提交记录。一旦 git push 完成, 你的朋友们就可以从这个远程仓库下载你分享的成果了!
这里写图片描述

git commit
git commit
git push

偏离的提交历史
假设你周一克隆了一个仓库,然后开始研发某个新功能。到周五时,你新功能开发测试完毕,可以发布了。但是 —— 天啊!你的同事这周写了一堆代码,还改了许多你的功能中使用的 API,这些变动会导致你新开发的功能变得不可用。但是他们已经将那些提交推送到远程仓库了,因此你的工作就变成了基于项目旧版的代码,与远程仓库最新的代码不匹配了。
这种情况下, git push 就不知道该如何操作了。如果你执行 git push,Git 应该让远程仓库回到星期一那天的状态吗?还是直接在新代码的基础上添加你的代码,异或由于你的提交已经过时而直接忽略你的提交?
因为这情况(历史偏离)有许多的不确定性,Git 是不会允许你 push 变更的。实际上它会强制你先合并远程最新的代码,然后才能分享你的工作。
那该如何解决这个问题呢?很简单,你需要做的就是使你的工作基于最新的远程分支。
有许多方法做到这一点呢,不过最直接的方法就是通过 rebase 调整你的工作。咱们继续,看看怎么 rebase!
git pull 就是 fetch 和 merge 的简写,类似的 git pull –rebase 就是 fetch 和 rebase 的简写!
这里写图片描述
要完成本关,你需要完成以下几步:
克隆你的仓库
模拟一次远程提交(fakeTeamwork)
完成一次本地提交
用 rebase 发布你的工作

git clone
git fakeTeamwork
git commit
git pull --rebase
git push

推送主分支
这里写图片描述
这个关卡的 Boss 很厉害 —— 以下是通关提示:
这里共有三个特性分支 —— side1 side2 和 side3
我需要将这三分支按顺序推送到远程仓库
因为远程仓库已经被更新过了,所以我们还要把那些工作合并过来
方式1:

git checkout master
git pull --rebase
git cherry-pick C2 C3 C4 C5 C6 C7
git push

方式2:

git fetch
git rebase o/master side1
git rebase side1 side2
git rebase side2 side3
git rebase side3 master
git push

合并远程仓库
在开发社区里,有许多关于 merge 与 rebase 的讨论。以下是关于 rebase 的优缺点:
优点:
Rebase 使你的提交树变得很干净, 所有的提交都在一条线上
缺点:
Rebase 修改了提交树的历史
这里写图片描述
本关,我们还是解决上一关卡中的问题,但是要用 merge 替换 rebase。这显然有点画蛇添足,但这只是为了更好的说明上面的观点。

git checkout master
git pull
git merge side1
git merge side2
git merge side3
git push

远程追踪
pull 操作时, 提交记录会被先下载到 o/master 上,之后再合并到本地的 master 分支。隐含的合并目标由这个关联确定的。
push 操作时, 我们把工作从 master 推到远程仓库中的 master 分支(同时会更新远程分支 o/master) 。这个推送的目的地也是由这种关联确定的!
直接了当地讲,master 和 o/master 的关联关系就是由分支的“remote tracking”属性决定的。master 被设定为跟踪 o/master —— 这意味着为 master 分支指定了推送的目的地以及拉取后合并的目标。
你可能想知道 master 分支上这个属性是怎么被设定的,你并没有用任何命令指定过这个属性呀!好吧, 当你克隆仓库的时候, Git 就自动帮你把这个属性设置好了。
当你克隆时, Git 会为远程仓库中的每个分支在本地仓库中创建一个远程分支(比如 o/master)。然后再创建一个跟踪远程仓库中活动分支的本地分支,默认情况下这个本地分支会被命名为 master。
克隆完成后,你会得到一个本地分支(如果没有这个本地分支的话,你的目录就是“空白”的),但是可以查看远程仓库中所有的分支(如果你好奇心很强的话)。这样做对于本地仓库和远程仓库来说,都是最佳选择。

我能自己指定这个属性吗?
当然可以啦!你可以让任意分支跟踪 o/master, 然后该分支会像 master 分支一样得到隐含的 push 目的地以及 merge 的目标。 这意味着你可以在分支 totallyNotMaster 上执行 git push,将工作推送到远程仓库的 master 分支上。
有两种方法设置这个属性,第一种就是通过远程分支检出一个新的分支,执行:
git checkout -b totallyNotMaster o/master
就可以创建一个名为 totallyNotMaster 的分支,它跟踪远程分支 o/master。

第二种方法
另一种设置远程追踪分支的方法就是使用:git branch -u 命令,执行:
git branch -u o/master foo
这样 foo 就会跟踪 o/master 了。如果当前就在 foo 分支上, 还可以省略 foo:
git branch -u o/master
这里写图片描述

git checkout -b side o/master
git commit
git pull --rebase
git push

git push 参数
我们可以为 push 指定参数,语法是:
git push {remote} {place}
{place}参数是什么意思呢?我们稍后会深入其中的细节, 先看看例子, 这个命令是:
git push origin master
把这个命令翻译过来就是:
切到本地仓库中的“master”分支,获取所有的提交,再到远程仓库“origin”中找到“master”分支,将远程仓库中没有的提交记录都添加上去,搞定之后告诉我。
我们通过“place”参数来告诉 Git 提交记录来自于 master, 要推送到远程仓库中的 master。它实际就是要同步的两个仓库的位置。
需要注意的是,因为我们通过指定参数告诉了 Git 所有它需要的信息, 所以它就忽略了我们所检出的分支的属性!
这里写图片描述
本关我们要更新远程仓库中的 foo 和 master, 但是 git checkout 被禁用了!
注意:远程分支使用 o/ 开头是因为 origin/ 对于 UI 来说太长了。不用太在意这个,直接用 origin 作为远程仓库的名称就可以了。

git push origin master
git push origin foo

git push 参数2
要同时为源和目的地指定 {place} 的话,只需要用冒号 : 将二者连起来就可以了:
git push origin {source}:{destination}
这个参数实际的值是个 refspec,“refspec” 是一个自造的词,意思是 Git 能识别的位置(比如分支 foo 或者 HEAD~1)
这里写图片描述

git push origin master^:foo
git push origin 

git fetch参数
如果你像如下命令这样为 git fetch 设置 {place} 的话:
git fetch origin foo
Git 会到远程仓库的 foo 分支上,然后获取所有本地不存在的提交,放到本地的 o/foo 上。
这里写图片描述

git fetch origin foo:master
git fetch origin master^:foo
git checkout foo
git merge master

没有source的source
古怪的 {source}
Git 有两种关于 {source} 的用法是比较诡异的,即你可以在 git push 或 git fetch 时不指定任何 source,方法就是仅保留冒号和 destination 部分,source 部分留空。
git push origin :side
git fetch origin :bugFix
如果 push 空 {source>}到远程仓库会如何呢?它会删除远程仓库中的分支!
如果 fetch 空 {source} 到本地,会在本地创建一个新分支。
这里写图片描述

git push origin :foo
git fetch origin :bar

git pull的参数
git pull 到头来就是 fetch 后跟 merge 的缩写。你可以理解为用同样的参数执行 git fetch,然后再 merge 你所抓取到的提交记录。
以下命令在 Git 中是等效的:
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 origin bar:foo
 git pull origin 

猜你喜欢

转载自blog.csdn.net/u012319493/article/details/81037302