Git的学习(写给自己的教程)


Git(分布式版本控制系统)

Git

Git是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。


Git的特点

分布式相比于集中式的最大区别在于开发者可以提交到本地,每个开发者可以通过克隆(git clone)在本地机器上拷贝一个完整的Git仓库。


优点

1.适合分布式开发,强调个体。
2.公共服务器压力和数据量都不会太大。
3.速度快、灵活。
4.任意两个开发者之间可以很容易的解决冲突。
5.离线工作。


缺点

1.学习周期相对而言比较长。
2.代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。


Git的一些操作及相关概念

创建版本库:git init

版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

  • 首先,选择一个合适的地方,创建一个空目录(目录名不要包含中文):
    例如:

    然后在该文件夹里右键单击选择Git Bush Here,在弹窗中输入:
$ mkdir learngit
$ cd learngit
$ pwd

pwd命令用于显示当前目录。我的仓库位于/e/Git/the first repository/learngit

Git的学习(写给自己的教程)_第1张图片

  • 第二步,通过git init命令把这个目录变成Git可以管理的仓库:



    (这是一个空仓库,当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,不能乱动。如果没有看到.git目录,那是因为这个目录默认是隐藏的,用ls -ah命令就可以看见。)


把文件添加到版本库

所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片的占用内存大小变了,但到底改了啥,版本控制系统不知道,也没法知道。
(windows系统不要使用自带文本软件,可使用Notepad++代替)
先编写一个readme.text文件,内容如下:

Git is a version control system.
Git is a free software.

把这个文件放到learngit目录下(子目录也行),即一定要放到你的Git仓库里面。接下来添加命令使文件添加到仓库里面:

  • 第一步,用命令git add将文件添加到仓库(可以同时将多个文件添加进仓库):
    $ git add readme.text

    (没有显示其他东西就说明成功了)
  • 第二步,用命令git commit将文件提交到仓库:
    $ git commit -m"wrote a readme file"

    -m后面输入的是本次提交的说明,可以输入任意内容,方便自己能从历史记录里找到自己的改动记录。
    git commit命令执行成功后会有:1 file changed:1个文件被改动(新添加的readme. text文件);2 insertions:插入了两行内容(readme. text有两行内容)。

修改仓库里的文件

在前面已经添加了readme. text文件的基础上,我们可以对文件进行修改,改成如下内容:

Git is a distributed version control system.
Git is a free software. 

用命令git status查看结果:

Git的学习(写给自己的教程)_第2张图片

git status命令可以让我们看到仓库当前的状态,这里显示 readme. text已经被修改过了,但是这个修改还没有提交。
用命令 git diff可以查看文件具体修改的内容:
Git的学习(写给自己的教程)_第3张图片

这里显示我们在第一行添加了 distributed
接下来就是提交修改的文件,提交修改的文件和之前提交新文件的步骤是一样的:

  • 第一步git add
    用命令git status查看仓库当前状态:
    Git的学习(写给自己的教程)_第4张图片

    这里显示将要被提交的修改包括了readme. text
  • 第二步git commit
    提交后,再用命令git status查看仓库当前状态:
    Git的学习(写给自己的教程)_第5张图片

    这里显示没有需要提交的修改,工作目录是干净的。

查看历史记录

用命令git log可以查看提交日志:

Git的学习(写给自己的教程)_第6张图片

这里可以看到最近的一次是 add distributed,最早的一次是 wrote a readme file
可以试试加上 --pretty=oneline参数使显示的更简洁:

(这里的一串数字和字母的组合是 commit id即版本号,例如 33b2d9c···就是 wrote a readme file的版本号)
每提交一个新版本,Git就会把它们自动串成一条时间线。


版本回退

在Git中,用HEAD表示当前版本,上一个版本是HEAD^,上上个版本是HEAD^^。如果版本过多可以用HEAD~number,例如往上100个版本:HEAD~100
可以使用命令git reset使版本从add distributed回退到wrote a readme file


可以看到版本已经退回到了 wrote a readme file
使用命令 cat可以查看 readme.text是否真的退回到了上一个版本:

使用命令 git log再次查看当前版本库的状态:
Git的学习(写给自己的教程)_第7张图片

可以看到版本库中只剩下第一个版本了。
现在可以使用 add distributed的版本号回到 add distributed的版本:
Git的学习(写给自己的教程)_第8张图片

这样版本又回到了 add distributed
如果不记得版本号而且还把弹窗关了,可以使用命令 git reflog来查找之前的命令:
Git的学习(写给自己的教程)_第9张图片

这样就找到之前的版本号了。


工作区与暂存区

工作区(Working Directory)

就是能在电脑里面看到的目录,比如这里的learngit文件夹就是一个工作区

Git的学习(写给自己的教程)_第10张图片

版本库(Repository)

工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

暂存区(Temporary Area)

Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git自动创建的第一个分支master,而前面用到的HEAD命令就是指向master的指针。

Git的学习(写给自己的教程)_第11张图片

在之前的提交文件到仓库的过程中:用 git add把文件添加进去,实际上就是把文件修改添加到暂存区;用 git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。因为创建Git版本库时,Git自动创建了唯一一个 master分支,所以现在, git commit就是往 master分支上提交更改。可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。


管理修改

Git管理的是修改,而不是文件。
举个例子
readme.text中添加一行:
Git has a mutable index called stage.
然后添加并查看状态:

Git的学习(写给自己的教程)_第12张图片

然后再修改一次 readme.text的内容:
删除第一行的 distributed
Git的学习(写给自己的教程)_第13张图片


再提交:

查看状态:
Git的学习(写给自己的教程)_第14张图片

可以看到第二次的修改并没有被提交。
提交后,用 git diff HEAD -- readme.text命令可以查看工作区和版本库里面最新版本的区别:
Git的学习(写给自己的教程)_第15张图片

如果想要第二次修改也被提交,则可以在第二次修改后 git add,和第一次修改一起 git commit;或者在第一次修改被提交之后,再将第二次修改 git add,然后单独将第二次修改 git commit:
Git的学习(写给自己的教程)_第16张图片


撤销修改

我们可以使用git checkout -- 来撤销工作区(还没有git add)的修改。
命令git checkout -- readme.text意思就是,把readme.text文件在工作区的修改全部撤销,这里有两种情况:

  • 一种是readme.text自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
  • 一种是readme.text已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。

总之,就是让这个文件回到最近一次git commitgit add时的状态。
先在readme.text里面加一句话:
oh my god!


此时并没有 git add,我们可以使用命令 git checkout -- readme.text进行撤销:
Git的学习(写给自己的教程)_第17张图片

如果不小心把这句话已经 git add到暂存区了(但是还没有 git commit):
Git的学习(写给自己的教程)_第18张图片

可以使用命令 git reset HEAD 把暂存区的修改重新放回工作区:
Git的学习(写给自己的教程)_第19张图片

然后再用 git checkout -- readme.text撤销工作区的修改;
Git的学习(写给自己的教程)_第20张图片

如果已经将修改 git commit到版本库里了,就使用版本回退的方法。(前提是没有推送到远程仓库)


删除文件

我们可以使用命令rm来删除文件。
首先,先建立一个新的文件new.text并且提交:

Git的学习(写给自己的教程)_第21张图片

现在使用命令 rm new text删除文件:
Git的学习(写给自己的教程)_第22张图片

此时只是在工作区中执行了删除 new.text文件的命令,但是文件依然存在于版本库中,如果想要在版本库中删除 new.text文件,那就用命令 git rm删掉,并且 git commit
Git的学习(写给自己的教程)_第23张图片

假如是不小心误删了这个文件(还没有从版本库里删除),我们依然可以用命令 git checkout来还原(即撤销上一步操作)。(从来没有被添加到版本库就被删除的文件,是无法恢复的!)


远程仓库

远程仓库相当于是一个服务器,你可以推送自己的东西到这个服务器上,同时也能拉取别人的推送。

创建远程仓库(在GitHub上创建)

  • 第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key
    $ ssh-keygen -t rsa -C "[email protected]"
    把邮件地址换成自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsaid_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。
  • 第2步:登陆GitHub,在主页点击右上角的个人头像,选择setting,然后在边的列表里点击SSH and GPG keys,再点击New SSH key。填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:
    Git的学习(写给自己的教程)_第24张图片

    Git的学习(写给自己的教程)_第25张图片

添加远程库

先在GitHub上新建一个仓库

Git的学习(写给自己的教程)_第26张图片

GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。
现在,我们根据GitHub的提示,在本地的learngit仓库下运行命令:
$ git remote add origin [email protected]:dragon-mystic/binglan-week1.git
其中 orgin是远程库的意思, dragon-mystic是自己在GitHub上的账户名, binglan-week1是GitHub仓库名称。
下面就可以把把本地库的内容推送到远程,用 git push命令,实际上是把当前分支 master推送到远程。
由于远程库是空的,第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
Git的学习(写给自己的教程)_第27张图片

这里出现了一个 SSH警告,这是因为Git使用SSH连接,而SSH连接在第一次验证GitHub服务器的Key时,需要你确认GitHub的Key的指纹信息是否真的来自GitHub的服务器,输入yes回车即可。Git会输出一个警告,告诉你已经把GitHub的Key添加到本机的一个信任列表里了。这个警告只会出现一次,后面的操作就不会有任何警告了。
此时刷新网页可以看到GitHub的仓库内容和本地的一样了:
Git的学习(写给自己的教程)_第28张图片

从现在起,只要本地作了提交,就可以通过命令:
$ git push origin master
把本地master分支的最新修改推送至GitHub。

从远程库克隆

首先先建立一个新的仓库copy

Git的学习(写给自己的教程)_第29张图片

勾选 Initialize this repository with a README,这样GitHub会自动为我们创建一个 README.md文件。创建完毕后,可以看到 README.md文件:
Git的学习(写给自己的教程)_第30张图片

现在可以用命令 git clone来克隆仓库:
$ git clone [email protected]:dragon-mystic/copy.git
Git的学习(写给自己的教程)_第31张图片

(这里克隆的是本地库,后面同样写的是自己GitHub的仓库地址)
copy会存在于本地库的 learngit目录下,而且可以看到 copy目录下有 README.md文件;


分支管理

一开始Git会自动创建一个分支master,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点。每次提交master会跟着提交不断延长,指向最新的提交。

创建与合并分支

创建新的分支之后,把HEAD的指向改变到新的分支上,继续提交,新的分支就会根据后来的提交而移动,而原来的master就会停止在HEAD指向改变之前的最后一次的提交。
使用命令git checkout创建新的分支binglan


git checkout命令加上 -b参数表示创建并切换,相当于以下两条命令:

$ git branch binglan
$ git checkout binglan
Switched to branch 'binglan'

git branch命令查看当前分支:


*后面就是当前分支。然后就可以在分支 binglan上提交工作了。如果再想回到分支 master上就使用命令 git checkout就行了:

如果之前在分支上 binglan上做了任何的操作,在回到分支 master之后是看不到的。
使用命令 git merge可以合并分支(前提是你在分支 binglan上进行了修改):
Git的学习(写给自己的教程)_第32张图片

此时分支 master上的内容就会和分支 binglan上的一样。上面显示的 Fast-foward是快进的意思,由于这次的修改你较小,所以合并速度很快。
合并完成后可以使用命令 git branch -d删除分支:

就只剩下 master分支了:

switch

这是一个更科学的命令,同样可以用来创建合并分支:
创建并切换到新的binglan分支,可以使用:
$ git switch -c dev
直接切换到已有的master分支,可以使用:
$ git switch master


解决冲突

在两个分支上分别做一个修改时(master分支和新分支各自都分别有新的提交),Git无法执行“快速合并”,只能试图把各自的修改合并,此时很有可能会发生冲突,此时Git会提示冲突,使用命令git status同样可以查看这个冲突。此时需要手动去更改,使用命令git log --graph --pretty=oneline --abbrev-commit可以查看合并情况,最后再删去新分支。

分支管理策略

在合并时,Git一般会使用Fast-forward的模式,但是在删除分支之后会丢失这条分支的信息。使用命令git merge --no-ff -m "merge with no-ff" binglan可以强制禁用Fast-forward模式,Git会在merge时产生一个新的commit,这样就可以在分支历史上查看分支信息(git log)。
Git创建的master分支是很稳定的,而自己创建的新分支是不稳定的。所以一般都在自己创建的新分支上进行工作,最后再合并到master上。(在团队合作的情况下非常实用,一人一条分支,最终合并到一起)

Bug分支

用于临时修复Bug创建的一个临时分支。当在用自己创建的分支工作时突然要修复一个Bug,此时使用命令git stash可以隐藏当前工作的分支并保存工作进度,再创建一个临时分支去修复Bug。可以使用命令git stash list查看隐藏的分支,在Bug修复之后,删去临时分支,使用命令git stash apply恢复隐藏的分支,再使用命令git stash drop删除隐藏分支时stash内容(也可以使用命令git stash pop恢复并删除)。stash可以重复使用多次,要恢复指定的stash,用命令$ git stash apply stash@{0}{}里面就是恢复的第几次的stash)。
使用命令cherry-pick ···能复制一个特定的提交到当前分支,···即你想要的`commit·的版本号。

Feature分支

用于开发新的东西,防止一些实验性质的代码把主分支搞乱,Feature分支在合并时和Bug分支是一样的,如果要强行删除这个Feature分支,则要使用命令git branch -D

推送分支

当从远程仓库克隆时,Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。可以使用命令git remote查看远程库的信息,或者,用git remote -v显示更详细的信息:


上面显示了可以抓取和推送的origin的地址。
推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,例如: $ git push origin master

  • master分支是主分支,因此要时刻与远程同步;
  • 自己创建的主分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
  • bug分支只用于在本地修复bug,就没必要推到远程了。
  • feature分支是否推到远程,取决于是否和其他人合作在上面开发。

抓取分支

一般情况下,别人从你的远程库clone只能看到你的master分支,但是如果别人想在你自己创建的分支binglan上开发,就必须使用命令$ git checkout -b binglan origin/binglan创建远程origin的binglan分支到本地。然后他就可以在binglan这个分支上进行修改并push。如果别人和你在这个分支上对相同的文件进行了修改,并且试图推送,会发生冲突,此时需要用命令git pull把最新的提交从origin/binglan上抓取下来,然后在本地合并,解决冲突,再推送(在git pull时一定要先设置binglan和origin/binglan的链接: $ git branch --set-upstream-to=origin/binglan binglanpull)。再将合并的冲突进行手动解决,就和分支管理的一样。解决后再push


结语

Git的功能真的很强大,可以实现多人协作开发,能与别人分享自己的经验和作品,有关Git还要学的东西还很多。
插上一个Git常用命令总结(方便快速查找):


Git的学习(写给自己的教程)_第33张图片

未完待续······

你可能感兴趣的:(Git的学习(写给自己的教程))