Git(二)分支管理与远程仓库操作

上一次写了Git的简介、安装、版本库创建,文件的创建,修改,删除等操作。这次写写别的

一、远程仓库

首先我们列出相关的代码,然后再详细解释背后的原理和操作步骤

  • git remote add origin <url of git>,关联目标远程库,而这个库的url,一般从你的github上可以看到。
  • git push -u origin master关联成功后,第一次第一次推送master分支的所有内容;
  • 此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;

如果只是在一个仓库管理文件历史,Git和其他版本控制系统有啥区别?这篇文章开始,就要深入学习Git了(深呼吸~),作为一个分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上,怎么分布呢?最早,肯定只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本库其实都是一样的,并没有主次之分。

也就是说,我们用一台电脑就可以play多个版本库,但是如果你在自己的电脑上维护了多个版本库,硬盘一挂全盘都挂,很难受。实际情况往往是这样,找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。玩过服务器的当然可以自己搭一个服务器,但是为了学Git先搭个服务器绝对是小题大作。好在这个世界上有个叫GitHub的神奇的网站,从名字就可以看出,**这个网站就是提供Git仓库托管服务的,**所以,只要注册一个GitHub账号,就可以免费获得Git远程仓库。注册账号ing。。。

然额本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要一点设置:

  • 创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Git Bash,创建SSH Key:$ ssh-keygen -t rsa -C "youremail@example.com"你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。
    如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsaid_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。
    在这里插入图片描述
  • 登陆GitHub,打开“Account settings”,“SSH Keys”页面:title名字任意取,在Key文本框里粘贴id_rsa.pub文件的内容:
    在这里插入图片描述
    然后点击 Add SSH Key就可以看到新添加得了。
    在这里插入图片描述

1、添加远程库

用了github的远程库和我们自己的本地库,我们如何让二者协同工作呢?

  • 首先,新建一个仓库。点击 new repository按钮,然后为库命名,不妨命名为learngit。然后就创建成功了,
    在这里插入图片描述
    目前,在GitHub上的这个learngit仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。
    在这里插入图片描述
    现在,我们根据GitHub的提示,在本地的learngit仓库下运行命令:
    在这里插入图片描述
    添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

下一步,就可以把本地库的所有内容推送到远程库上:

10690@DESKTOP-PO000PL MINGW64 /e/GitRepository/test (master)
$ git push -u origin master
Enumerating objects: 21, done.
Counting objects: 100% (21/21), done.
Delta compression using up to 8 threads
Compressing objects: 100% (9/9), done.
Writing objects: 100% (21/21), 1.49 KiB | 169.00 KiB/s, done.
Total 21 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), done.
To https://github.com/userYiFanZhang/learngit.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。

由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令

我们可以看一看成果
在这里插入图片描述
success!从现在起,只要本地作了提交,就可以通过命令:$ git push origin master把本地master分支的最新修改推送至GitHub,现在,你就拥有了真正的分布式版本库!

SSH警告
当你第一次使用Git的clone或者push命令连接GitHub时,会得到一个警告:

The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?

这是因为Git使用SSH连接,而SSH连接在第一次验证GitHub服务器的Key时,需要你确认GitHub的Key的指纹信息是否真的来自GitHub的服务器,输入yes回车即可。

Git会输出一个警告,告诉你已经把GitHub的Key添加到本机的一个信任列表里了:

Warning: Permanently added 'github.com' (RSA) to the list of known hosts.

这个警告只会出现一次,后面的操作就不会有任何警告了。

如果你实在担心有人冒充GitHub服务器,输入yes前可以对照GitHub的RSA Key的指纹信息是否与SSH连接给出的一致。

分布式版本系统的最大好处之一是在本地工作完全不需要考虑远程库的存在,也就是有没有联网都可以正常工作,而SVN在没有联网的时候是拒绝干活的!当有网络的时候,再把本地提交推送一下就完成了同步,真是太方便了!

2、从远程库克隆

上面说的是如何在拥有本地库的情况下关联远程库,而如果我们从零开始,那么就需要先在github上做好远程库,从远程库克隆过来。

我们创建一个learngit2,我们勾选Initialize this repository with a README,这样GitHub会自动为我们创建一个README.md文件。创建完毕后,可以看到README.md文件:
在这里插入图片描述
现在,远程库已经准备好了,下一步是用命令git clone克隆一个本地库:
在这里插入图片描述
该命令的用法是git clone <版本库的网址>,网址我是直接在我的库上取下来的
在这里插入图片描述

10690@DESKTOP-PO000PL MINGW64 /e/GitRepository/test (master)
$ git clone https://github.com/userYiFanZhang/learngit2.git
Cloning into 'learngit2'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 599 bytes | 5.00 KiB/s, done.

在这里插入图片描述
真的出现了这个文件夹,而且确实将README.md文件克隆下来了。

二、创建与合并分支

首先我们列出所有相关代码,然后再一一解释
最后,总结所有代码

  • 创建分支:git branch <name>
  • 进入分支git switch <name>
  • 创建加进入:git switch -c <name>
  • 查看当前分支信息 git branch
  • 合并某分支到当前分支:git merge <name>
  • 删除分支:git branch -d <name>

还记得git init的时候,我们自动将当前文件夹定义为master嘛?它被叫做主分支,在这里插入图片描述
再回忆一个定义HEAD,之前说过HEAD指向当前版本。如果我们只有主分支,那么你最新一次提交的内容就是matser的指向,然后HEAD指向master,如图 C 1 , C 2 , C 3 C1,C2,C3 C1,C2,C3历史版本, C 3 C3 C3是最新的commit
在这里插入图片描述
此时如果我们新添加一个分支,HEADmaster会同时移动到新的分支吗?答案是否定的,对Git而言,新添加一个分支相当于多了一个子指针(master是唯一的,不会指向子分支),那么我们如何在子分支进行工作呢?只能使用HEAD指针了。
在这里插入图片描述
我们创建了一个新的分支New branch,并用HEAD指向该分支,接下来他该如何工作呢?想必你已经猜到了,HEAD指向新分支的指针,每次commit,新分支的指针向后移动。
在这里插入图片描述
如果要合并呢(显然我们不可能把主分支合并到子分支,一定是将new branch的内容合并到master里),也就是说,master重新接管主动权(HEAD指向master),并且覆盖new branch的位置。
在这里插入图片描述
此时可以发现,我们再进行操作就是操作master了,如果你不想要New Branch也问题不大,可以看到把这个指针删除了其实也没啥影响。最后再讲代码

$ git switch -c newB
Switched to a new branch 'newB'

代码gir branch <name>用于创建一个叫做name的分支,git switch <name>用于进入name分支。你也可以使用git switch -c <name>相当于创建+进入二合一(-c:create)。
在这里插入图片描述
我们使用git branch命令列出所有的分支,当前分支(拥有HEAD指针的分支会有*作为标记),然后我们在newB分支上进行一次操作,加上一行

Add a new branch!
10690@DESKTOP-PO000PL MINGW64 /e/GitRepository/test (newB)
$ git add readme

10690@DESKTOP-PO000PL MINGW64 /e/GitRepository/test (newB)
$ git commit -m "test new branch"
[newB 7ac4d88] test new branch
 1 file changed, 2 insertions(+), 1 deletion(-)

然后我们切换回master

10690@DESKTOP-PO000PL MINGW64 /e/GitRepository/test (newB)
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
10690@DESKTOP-PO000PL MINGW64 /e/GitRepository/test (master)

此时我们查看一下刚才加了一句话的readme

$ cat readme
Hello boss! I am yfZhang!
boss: Your paper likes rubbish!
rewrite! rewrite! rewrite!

少了最后一行!为什么呢?因为我们在newB里的操作并不能直接修改主分支,那么合并之后会是怎样的呢?

$ git merge newB
Updating e734d03..7ac4d88
Fast-forward
 test/readme | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

git merge命令用于合并指定分支到当前分支。合并后,再查看readme的内容,就可以看到,和newB分支的最新提交是完全一样的。

注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向newB的当前提交,所以合并速度非常快。当然也有其他方式,这里就不细说了。然后我们可以删除子分支。然后查看当前的分支信息,确实只剩下了master

$ git branch -d newB
Deleted branch newB (was 7ac4d88).
$ git branch
 * master

那么为什么我们不在master上进行工作,而是要创建子分支修改,然后合并呢?其实利用子分支工作,即使出了大错主分支也不会受影响,我们只需要在工作的末尾把它们合并即可,安全性更高。

三、合并冲突Automatic merge failed; fix conflicts and then commit the result.

再来回顾一下我们刚才的合并过程,如左下图此时masterHEAD都会指向 C 4 C4 C4 C 3 C3 C3HEAD^,整条链很完整。但是你有没有考虑过右下方的场景,也就是说分支newB经过了一次commit,主分支master也经过了一次commit,此时 C 3 C3 C3HEAD^,如果我们强行将masterHEAD指向 C 5 C5 C5的位置,那么 C 4 C4 C4处将没有任何指针,也就是说,版本会丢失?那么我们来试验一下Git会不会允许我们这样做。
在这里插入图片描述

  • 新建并进入一个分支,修改readmeaddcommit
$ git switch -c newB
Switched to a new branch 'newB'

//给readme添加一句话 “Is there exists a conflict?”
$ git add readme
$ git commit -m "add new line-newB"
  • 换回master分支,他会友善的提醒我们当前分支比远程库超前一个提交,还会让我们push一下,当然现在我们不需要。我们将刚才添加的这句话改为“Is there exists some conflicts?”,addcommit
$ git switch master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)
$ git add readme
$ git commit -m "revise the new line"

现在我们的master达到了上图中的 C 4 C4 C4,而newB处于 C 5 C5 C5,来合并一下看看会怎样 输入$ git merge newB,被提示合并冲突,而且必须手动解决,不妨再输入git status看看冲突的详细信息

Auto-merging test/readme
CONFLICT (content): Merge conflict in test/readme
Automatic merge failed; fix conflicts and then commit the result.

在这里插入图片描述
这里我们需要注意的其实是这一句,提示我们出错的文件是readme,并且是因为两个分支下都修改了

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   readme

看看readme现在长啥样<<<<<<<,=======,>>>>>>>标记不同分支,当前HEAD指向的分支是some conflicts,newB分支则是a conflict

Hello boss! I am yfZhang!
boss: Your paper likes rubbish!
rewrite! rewrite! rewrite!
Add a new branch!
<<<<<<< HEAD
Is there exists some conflicts?
=======
Is there exists a conflict?
>>>>>>> newB

我们将它修改成这样

Hello boss! I am yfZhang!
boss: Your paper likes rubbish!
rewrite! rewrite! rewrite!
Add a new branch!
There exists conflicts.

然后重新提交

$ git add readme
$ git commit -m "merge"

他就变成了下图这样,理论上你最后一次修改的内容覆盖了 C 4 , C 5 C4,C5 C4,C5但是我们依然可以找到他们的记录号
在这里插入图片描述
输入$ git log即可

$ git log
commit f60e859dfe2546ba96348680c9f3294726abae5a (HEAD -> master)
Merge: cda14ab 0412e10
Author: yifanZhang <1069005360@qq.com>
Date:   Sun Mar 15 12:04:45 2020 +0800

    merge

commit cda14abcd54f76f5b0c43d9473bd29e90cc2c788
Author: yifanZhang <1069005360@qq.com>
Date:   Sun Mar 15 11:55:17 2020 +0800

    revise the new line

commit 0412e1070e99b2668917fa7412a3acc518b3095f (newB)
Author: yifanZhang <1069005360@qq.com>
Date:   Sun Mar 15 11:50:56 2020 +0800

    add new line-newB

commit 7ac4d88bad1dcc5261270d83551b55339b29a991
Author: yifanZhang <1069005360@qq.com>
Date:   Sun Mar 15 09:38:09 2020 +0800

这时再删除newB分支就没有错误了

$ git branch -d newB
Deleted branch newB (was 0412e10).

如果想可视化的观察一下你的分支过程,可以使用git log --graph,tips:退出按Q,一开始被逼的重启好几次 ̄□ ̄||难受。

$ git log --graph
*   commit f60e859dfe2546ba96348680c9f3294726abae5a (HEAD -> master)
|\  Merge: cda14ab 0412e10
| | Author: yifanZhang <1069005360@qq.com>
| | Date:   Sun Mar 15 12:04:45 2020 +0800
| |
| |     merge
| |
| * commit 0412e1070e99b2668917fa7412a3acc518b3095f
| | Author: yifanZhang <1069005360@qq.com>
| | Date:   Sun Mar 15 11:50:56 2020 +0800
| |
| |     add new line-newB
| |
* | commit cda14abcd54f76f5b0c43d9473bd29e90cc2c788
|/  Author: yifanZhang <1069005360@qq.com>
|   Date:   Sun Mar 15 11:55:17 2020 +0800
|
|       revise the new line

2、团队开发需知

我们再仔细看看,上述的这个git log --graph,整个历史记录里面是没有newB存在的,也就是说这个分支一旦删除就没有了,仿佛从未出现过,你可能觉得删除不就是为了清空吗,实际上我们有时候是需要分支信息的,比如在下图,每个分支对应着一个版本,我们需要记录什么时候对哪些版本进行了合并,我写版本一你写版本二,工作完成后合并到提交版本这样子。
在这里插入图片描述
此时我们不希望任何一个版本分支的信息丢失,而且要记录所有版本信息的合并历史,怎么做?很简单,合并分支时使用git merge --no-ff -m,加上--no-ff参数,我们就可以保留所有分支的合并历史,不加默认使用的是fast forward模式,一旦删除分支就丢弃分支信息。

依然使用上一节那样的操作,方便我们比对,

  • 创建并切换分支,修改文件,加入一句“merge with no ff.”,提交新的commit
git switch -c newB
(修改readme文件)
git add readme
git commit -m "add one line"
  • 返回master,合并分支,记得使用--no-ff参数
git switch master
git merge --no-ff -m "merge" newB

然后我们再来查看历史合并图,可以看到分支的信息已经标注在那里了。

$ git log --graph
*   commit ff8cb702222ea4f6ddfc7922b4bee1ca716d6d4c (HEAD -> master)
|\  Merge: 272258c 00b0217
| | Author: yifanZhang <1069005360@qq.com>
| | Date:   Sun Mar 15 12:43:29 2020 +0800
| |
| |     merge
| |
| * commit 00b021729220a439529cec372cbd8ae40fc7907e (newB)
|/  Author: yifanZhang <1069005360@qq.com>
|   Date:   Sun Mar 15 12:41:24 2020 +0800
|
|       add merge
|

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值