Git阅读笔记(2021.3)

169 阅读11分钟

阅读自廖雪峰Git教程:www.liaoxuefeng.com/wiki/896043…

一、Git简介

part1:

  • Git是目前世界上最先进的分布式版本控制系统
  • “能自动记录每次文件的改动,还可以让同事协作编辑,不用自己管理一堆类似的文件,也不需要把文件传来传去。如果想查看某次改动,只需要瞄一眼就可以。”
  • “结束了手动管理多个‘版本’的史前时代,进入到版本控制的21世纪。”
  • “如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好用的Git了。”

part2: 集中式VS分布式

  • 集中式版本控制系统,版本库是集中存放在中央服务器的,干活时用的都是自己的电脑,所以要先从中央服务器取得最新的版本,开始干活,干完活了,再把自己的活推送给中央服务器。”
  • “集中式版本控制系统最大的毛病就是必须联网才能工作。遇到网速慢的话,可能提交一个10M的文件就需要5分钟。”
  • 分布式版本控制系统根本没有‘中央服务器’,每个人的电脑上都是一个完整的版本库。多人协作时,同事之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。”
  • “分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活。”
  • “分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。”
  • “后面我们还会看到Git极其强大的分支管理。”

二、安装Git & 创建版本库

  • 版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
  • 初始化一个Git仓库,使用git init命令。
//选择一个合适的地方,创建一个空目录
$ mkdir learngit
$ cd learngit
//pwd命令用于显示当前目录。在我的Mac上,这个仓库位于/Users/michael/learngit
$ pwd
/Users/michael/learngit
//通过git init命令把这个目录变成Git可以管理的仓库
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/
  • 添加文件到Git仓库,使用命令git add < file >,使用命令git commit -m < message >
//现在我们编写一个readme.txt文件,一定要放到learngit目录下(子目录也行)
//第一步,用命令git add告诉Git,把文件添加到仓库
$ git add readme.txt
//第二步,用命令git commit告诉Git,把文件提交到仓库
$ git commit -m "wrote a readme file"
[master (root-commit) eaadf4e] wrote a readme file
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt
 //git commit命令中-m后面输入的是本次提交的说明

三、时光机穿梭

  • 要随时掌握工作区的状态,使用git status命令。
  • 如果git status告诉你有文件被修改过,用git diff < file >可以查看修改内容

part1:版本回退

  • Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id。
  • 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本(看得眼花缭乱的,可以试试加上 --pretty=oneline参数)。
  • HEAD指向的版本就是当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,往上100个版本写100个^数不过来,写成HEAD~100。
  • 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。
  • 版本号没必要写全,前几位就可以,Git会自动去找。

part2:工作区和暂存区

  • 工作区(Working Directory)就是你在电脑里能看到的目录,比如learngit文件夹就是一个工作区。
  • 版本库(Repository):工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
  • 我们把文件往Git版本库里添加的时候,是分两步执行的:第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改

part3:管理修改

  • Git跟踪并管理的是修改,而非文件。
  • 当用git add命令后,在工作区的第一次修改被放入暂存区,准备提交,但是,在工作区的第二次修改并没有放入暂存区,所以,git commit只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。

part4:撤销修改

  • 场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。
  • 场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD < file >,就回到了场景1,第二步按场景1操作。
  • 场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。

part5:删除文件

  • 确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit。
$ git rm test.txt
rm 'test.txt'

$ git commit -m "remove test.txt"
[master d46f35e] remove test.txt
 1 file changed, 1 deletion(-)
 delete mode 100644 test.txt
  • 如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本你会丢失最近一次提交后你修改的内容。git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

四、远程仓库

  • GitHub网站,提供Git仓库托管服务。只要注册一个GitHub账号,就可以免费获得Git远程仓库。
  • 使用前,按步骤创建、添加SSH Key

part1:添加远程库

  • 关联一个远程库,在本地的repo-name仓库下运行命令:git remote add origin git@server-name:path/repo-name.git。
$ git remote add origin git@github.com:michaelliao/learngit.git
//把上面的michaelliao替换成自己的GitHub账户名,learngit替换成自己的文件夹名
  • 关联后,使用命令git push -u origin master第一次推送master分支的所有内容
  • 此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改

part2:删除远程库

  • 如果添加的时候地址写错了,或者就是想删除远程库,可以用git remote rm < name >命令。使用前,建议先用git remote -v查看远程库信息
$ git remote -v
origin  git@github.com:michaelliao/learn-git.git (fetch)
origin  git@github.com:michaelliao/learn-git.git (push)
  • 然后,根据名字删除,比如删除origin。此处的“删除”其实是解除了本地和远程的绑定关系,并不是物理上删除了远程库。远程库本身并没有任何改动。
$ git remote rm origin

part3:从远程库克隆

  • 克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆。
$ git clone git@github.com:michaelliao/gitskills.git
//Git库的地址换成你自己的
  • Git支持多种协议,包括https,但ssh协议速度最快。

五、分支管理

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

part1:创建与合并分支

Git鼓励大量使用分支

  • 查看分支:git branch
  • 创建分支:git branch
  • 切换分支:git checkout 或者git switch
  • 创建+切换分支:git checkout -b 或者git switch -c
  • 合并某分支到当前分支:git merge
  • 删除分支:git branch -d (有好多图!不记得了回去看:www.liaoxuefeng.com/wiki/896043…

part2:解决冲突

  • 当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
  • 解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
  • 用git log --graph命令可以看到分支合并图。

part3:分支管理策略

Git分支十分强大,在团队开发中应该充分应用

  • 进行分支管理的几个基本原则:首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
  • 合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
$ git merge --no-ff -m "merge with no-ff" dev
//合并dev分支,因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去

part4:Bug分支

  • 修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除。
$ git checkout -b issue-101

//修复Bug之后,然后提交
$ git add readme.txt 
$ git commit -m "fix bug 101"
[issue-101 4c805e2] fix bug 101
 1 file changed, 1 insertion(+), 1 deletion(-)
 
//修复完成后,切换到master分支,并完成合并,最后删除issue-101分支
$ git switch master

$ git merge --no-ff -m "merged bug fix 101" issue-101
 
  • 当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。
$ git stash

//用git stash list命令查看刚才存储的工作现场
$ git stash list

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

//也可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash
//用git stash apply恢复,但是恢复后需要用git stash drop来删除
$ git stash list
stash@{0}: WIP on dev: f52c633 add merge
$ git stash apply stash@{0}
$ git stash drop stash@{0}
  • 在master分支上修复的bug,想要合并到当前dev分支,可以用git cherry-pick < commit >命令,把bug提交的修改“复制”到当前分支,避免重复劳动。
$ git branch
* dev
  master

//把4c805e2 fix bug 101这个提交所做的修改“复制”到dev分支
$ git cherry-pick 4c805e2
[master 1d4b803] fix bug 101
 1 file changed, 1 insertion(+), 1 deletion(-)

part5:Feature分支

  • “软件开发中,总有无穷无尽的新的功能要不断添加进来。添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。”
//开发代号为Vulcan的新功能
$ git switch -c feature-vulcan
Switched to a new branch 'feature-vulcan'
  • 如果要丢弃一个没有被合并过的分支,可以通过git branch -D < name >强行删除
$ git branch -D feature-vulcan
Deleted branch feature-vulcan (was 287773e).

part6:多人协作

多人协作的工作模式通常是这样:

  1. 首先,可以试图用git push origin < branch-name >推送自己的修改;
  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
  3. 如果合并有冲突,则解决冲突,并在本地提交;
  4. 没有冲突或者解决掉冲突后,再用git push origin < branch-name >推送就能成功!
  • 查看远程库信息,使用git remote -v;本地新建的分支如果不推送到远程,对其他人就是不可见的。
  • 如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to < branch-name > origin/< branch-name >。
  • “总之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,视你的心情而定!”

part7:Rebase

  • rebase操作可以把本地未push的分叉提交历史整理成直线
  • rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。

六、标签管理

发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。

  • 命令git tag < tagname >用于新建一个标签,默认为HEAD,也可以指定一个commit id;
  • 命令git tag -a < tagname > -m "blablabla..."可以指定标签信息
  • 命令git tag可以查看所有标签
  • 命令git push origin 可以推送一个本地标签;
  • 命令git push origin --tags可以推送全部未推送过的本地标签;
  • 命令git tag -d 可以删除一个本地标签;
  • 命令git push origin :refs/tags/可以删除一个远程标签。