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 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 status命令可以让我们看到仓库当前的状态,这里显示readme. text已经被修改过了,但是这个修改还没有提交。
用命令git diff可以查看文件具体修改的内容:

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

  • 第一步git add
    用命令git status查看仓库当前状态:

    这里显示将要被提交的修改包括了readme. text
  • 第二步git commit
    提交后,再用命令git status查看仓库当前状态:

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

查看历史记录

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


这里可以看到最近的一次是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再次查看当前版本库的状态:

可以看到版本库中只剩下第一个版本了。
现在可以使用add distributed的版本号回到add distributed的版本:

这样版本又回到了add distributed
如果不记得版本号而且还把弹窗关了,可以使用命令git reflog来查找之前的命令:

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


工作区与暂存区

工作区(Working Directory)

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

版本库(Repository)

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

暂存区(Temporary Area)

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


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


管理修改

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


然后再修改一次readme.text的内容:
删除第一行的distributed


再提交:

查看状态:

可以看到第二次的修改并没有被提交。
提交后,用git diff HEAD -- readme.text命令可以查看工作区和版本库里面最新版本的区别:

如果想要第二次修改也被提交,则可以在第二次修改后git add,和第一次修改一起git commit;或者在第一次修改被提交之后,再将第二次修改git add,然后单独将第二次修改git commit:


撤销修改

我们可以使用git checkout -- <file>来撤销工作区(还没有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 add到暂存区了(但是还没有git commit):

可以使用命令git reset HEAD <file>把暂存区的修改重新放回工作区:

然后再用git checkout -- readme.text撤销工作区的修改;

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


删除文件

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


现在使用命令rm new text删除文件:

此时只是在工作区中执行了删除new.text文件的命令,但是文件依然存在于版本库中,如果想要在版本库中删除new.text文件,那就用命令git rm删掉,并且git commit

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


远程仓库

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

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

  • 第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开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是公钥,可以放心地告诉任何人。
  • 第2步:登陆GitHub,在主页点击右上角的个人头像,选择setting,然后在边的列表里点击SSH and GPG keys,再点击New SSH key。填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:

添加远程库

先在GitHub上新建一个仓库


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

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

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

从远程库克隆

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


勾选Initialize this repository with a README,这样GitHub会自动为我们创建一个README.md文件。创建完毕后,可以看到README.md文件:

现在可以用命令git clone来克隆仓库:
$ git clone git@github.com:dragon-mystic/copy.git

(这里克隆的是本地库,后面同样写的是自己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上进行了修改):

此时分支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 <name>

推送分支

当从远程仓库克隆时,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常用命令总结(方便快速查找):



未完待续······

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335