Git&GitHub-进阶教程

目录

1. 远程仓库-GitHub

Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。怎么分布呢?最早,肯定只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本库其实都是一样的,并没有主次之分。

实际情况往往是这样,找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。

1.1 本地电脑如何关联GitHub?

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

  • 创建SSH Key
$ ssh-keygen -t rsa -C "haochen273@gmail.com"

一路回车就可以了

如果一切顺利的话,可以在用户主目录(C:\Users\haoch.ssh)里找到.ssh目录,里面有id_rsaid_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。

  • 设置GitHub的SSH Key

在GitHub主页找到Account Seetings, SSH Key页面:将id_rsa.pub的内容粘贴到里面即可Add

《Git&GitHub-进阶教程》

GitHub为什么要用SSH Key呢?

因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。

当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。

1.2. 创建并操控远程库GitHub

在GitHub中创建一个远程库名为learngit:
《Git&GitHub-进阶教程》

(1) 把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。:本地->远程

  • 关联
    在本地库运行命令:
$ git remote add origin git@github.com:haochen95/learngit.git

添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

  • 推送
    使用命令git push -u origin master -f
$ git push -u origin master -f
Enumerating objects: 23, done.
Counting objects: 100% (23/23), done.
Delta compression using up to 8 threads
Compressing objects: 100% (17/17), done.
Writing objects: 100% (23/23), 1.82 KiB | 465.00 KiB/s, done.
Total 23 (delta 5), reused 0 (delta 0)
remote: Resolving deltas: 100% (5/5), done.
To github.com:haochen95/learngit.git
 + cc71eae...1f108b4 master -> master (forced update)
Branch 'master' set up to track remote branch 'master' from 'origin'.

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

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

成功后的页面

《Git&GitHub-进阶教程》

  • 以后的每次提交只写一个命令
    $ git push origin master

把本地master分支的最新修改推送至GitHub,现在,你就拥有了真正的分布式版本库!

(2) 从GitHub克隆库到本地: 远程->本地

现在我们另外创建一个空文件夹: D:\git_clone
克隆的代码是: $ git clone git@github.com:haochen/learngit.git

$ git clone git@github.com:haochen95/learngit.git
Cloning into 'learngit'...
remote: Enumerating objects: 23, done.
remote: Counting objects: 100% (23/23), done.
remote: Compressing objects: 100% (12/12), done.
Receiving objects: 100% (23/23), done.
Resolving deltas: 100% (5/5), done.
remote: Total 23 (delta 5), reused 23 (delta 5), pack-reused 0

你看,本地的库里面就有了跟GitHub一样的内容
《Git&GitHub-进阶教程》

2. Git分支管理(重要)

创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

2.1. 创建和合并分支

版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向mastermaster才是指向提交的,所以,HEAD指向的就是当前分支

一开始的时候,master分支是一条线,Gitmaster指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:

《Git&GitHub-进阶教程》

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长:
《Git&GitHub-进阶教程》

1)增加分支的原理

我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev`上

《Git&GitHub-进阶教程》

增加分支的原理: 增加一个指针,更改HEAD的指向

2)增加分支后的提交变化

现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
《Git&GitHub-进阶教程》

3) 分支合并

就是直接把master指向dev的当前提交,就完成了合并
《Git&GitHub-进阶教程》

合并分支的原理: 改改指针(dev->master)

4)分支删除

删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支
《Git&GitHub-进阶教程》

代码测试

1. 创建分支

$ git checkout -b dev
Switched to a new branch 'dev'

git checkout命令加上-b参数表示创建并切换

2. 查看分支

$ git branch
* dev
  master

3. 在分支上提交
增加一个文件命名为love.txt并且提交

$ git add love.txt

$ git commit -m "love"
[dev b3045f0] love
 1 file changed, 1 insertion(+)
 create mode 100644 love.txt

4. 从dev分支切换回master分支

$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

再次查看文件夹发现没有love.txt文件,因为那个提交是在dev分支上,而master分支此刻的提交点并没有变
《Git&GitHub-进阶教程》

5. master和dev分支合并

$ git merge dev
Updating 1f108b4..b3045f0
Fast-forward
 love.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 love.txt

6. 删除dev分支
$ git branch -d dev Deleted branch dev (was b3045f0).
7. 再次查看branch信息
$ git branch * master

2.2. 解决合并冲突

问题: 在分支上提交一个修改,转到master后又提交一个修改,两个修改都在同一个位置,请问如何合并?
《Git&GitHub-进阶教程》

现在,master分支和feature1分支各自都分别有新的提交,变成了这样:

《Git&GitHub-进阶教程》

这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看

$ git merge feature1
Auto-merging love.txt
CONFLICT (content): Merge conflict in love.txt
Automatic merge failed; fix conflicts and then commit the result.

需要手动解决冲突

通过git status查看状态

$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)

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:   love.txt

no changes added to commit (use "git add" and/or "git commit -a")

我们可以直接查看love.txt的内容:

<<<<<<< HEAD
I love you
=======
I come from china
>>>>>>> feature1

我们重新修改为

I come from china

然后再提交

$ git commit -m "loving"
[master e6c7c5f] loving

现在,master分支和feature1分支变成了下图所示:

《Git&GitHub-进阶教程》

我们可以通过命令$ git log --graph --pretty=oneline --abbrev-commit查看分支情况

$ git log --graph --pretty=oneline --abbrev-commit
*   e6c7c5f (HEAD -> master) loving
|\
| * 445380a (feature1) from china
* | 62b6881 love you
|/
* b3045f0 love
* 1f108b4 (origin/master) remove text.txt
* f2863ca new text
* aa4f64e git tracks
* 45700b2 how it works
* 5103166 delete software
* 9fbb435 github infor
* 4fb84da add new line
* f7f8050 write to readme

2.3. 分支管理策略

  1. master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
  2. 干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本
  3. 你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
  4. 使用git merge --no-ff -m "merge with no-ff" dev合并会留下历史信息,建议这样用
    《Git&GitHub-进阶教程》

2.4. Bug分支

假设,你正正在完成love.txt的编辑工作,但是这个文件需要2天才能完成,但是现在老板给你说readme.txt有一个错误(I love USA)你需要更改这个bug, 那怎么办? 你想创建一个分支issue-101来修复它,但是,等等,当前正在feature1上进行的工作还没有提交:

$ git status
On branch feature1
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   love.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   readme.txt

1) git stash

这个功能是把当前工作现场“储藏”起来,等以后恢复现场后继续工作:

$ git stash
Saved working directory and index state WIP on feature1: f1f394f modifyed

现在,用git status查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。

2) 创建issue分支解决bug

在master上创建分支

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 4 commits.
  (use "git push" to publish your local commits)  

$ git checkout -b issue
Switched to a new branch 'issue'  

然后修改readme.txt的删除I love China,在提交

$ git commit -m "fix issue101"
[issue bdc0b2e] fix issue101
 1 file changed, 1 deletion(-)

然后转到master合并分支

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 4 commits.
  (use "git push" to publish your local commits)


$ git merge --no-ff -m "merged bug fix 101" issue
Merge made by the 'recursive' strategy.
 readme.txt | 1 -
 1 file changed, 1 deletion(-)

哈哈,Bug解决啦,是时候回到feature1分支继续工作啦

$ git checkout feature1
Switched to branch 'feature1'

$ git status
On branch feature1
nothing to commit, working tree clean

工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看

$ git stash list
stash@{0}: WIP on feature1: f1f394f modifyed

工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法

1)恢复办法1:git stash apply

git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;

2)恢复方法2: git stash pop

git stash pop,恢复的同时把stash内容也删了

2.5. Feature分支

添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。

    原文作者:Bricker666
    原文地址: https://www.cnblogs.com/haochen273/p/10214293.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞