赞
踩
2005的时候,linus使用2周时间用C语言写出来了一个Git,供全世界Linux开发者使用
集中式版本控制:版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
分布式版本控制:是Git使用的版本管理方式;每个人都各自管理版本库,当双方都有修改的时候,就会将自己的修改推送给对方就行了
Git官网:https://git-scm.com/downloads
按照对应方式下载就行:Git下载
这里有一个特别注意:
使用Windows的童鞋要特别注意:
千万不要使用Windows自带的记事本编辑任何文本文件。原因是Microsoft开发记事本的团队使用了一个非常弱智的行为来保存UTF-8编码的文件,他们自作聪明地在每个文件开头添加了0xefbbbf(十六进制)的字符,你会遇到很多不可思议的问题,比如,网页第一行可能会显示一个“?”,明明正确的程序一编译就报语法错误,等等,都是由记事本的弱智行为带来的。建议你下载Notepad++代替记事本,不但功能强大,而且免费!记得把Notepad++的默认编码设置为UTF-8 without BOM即可:
Q:输入git add readme.txt,得到错误:fatal: not a git repository (or any of the parent directories)。
A:Git命令必须在Git仓库目录内执行(git init除外),在仓库目录外执行是没有意义的。
Q:输入git add readme.txt,得到错误fatal: pathspec ‘readme.txt’ did not match any files。
A:添加某个文件时,该文件必须在当前目录下存在,用ls或者dir命令查看当前目录的文件,看看文件是否存在,或者是否写错了文件名。
这里廖老师举了个例子,关于打游戏的:我拿精灵宝可梦红宝石(就是我们看得:宠物小精灵)来举例吧,当你想获得想要的道具,或者想抓捕你想要的小精灵的时候,我们就会不停的存档,读档,一直到获得自己想要的才停止;git也有相对应的方式保存你每一次提交到仓库的状态,git将你每一次commit都保存一个状态,你可以恢复到任意一个commit节点;
游戏中你不需要自己记下来上一次保存的时间,而是直接去存档列表中挑选你回到的位置;
git中也有这么个存档列表
这里进一步解释一下,git生成的版本号(commit id)
需要友情提示的是,你看到的一大串类似1094adb…的是commit id(版本号),和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示,而且你看到的commit id和我的肯定不一样,以你自己的为准。为什么commit id需要用这么一大串数字表示呢?因为Git是分布式的版本控制系统,后面我们还要研究多人在同一个版本库里工作,如果大家都用1,2,3……作为版本号,那肯定就冲突了。
在git中,使用HEAD来表示当前版本,也就是最新提交的版本,那么上一个版本就是HEAD^ ,上上个版本是HEAD^ ^ ,那么一百个版本以前是什么 ,肯定不 是HEAD ^ 后面跟100^,而是使用HEAD~100的方式退回到100个版本以前
git reset --hard HEAD^
将版本库返回上一个版本,这时候,我们使用git log来查看版本库的状态;
你会发现,回退的版本不见了,你的存档删除了,当然你现在还没有关掉你的窗口,你还可以用使用
git reset --hard 版本号(commit id 进行回退)
注意这里commit id 可以不用写全 git会自动去寻找
其实你可以把HEAD想象成一个指针:
┌────┐
│HEAD│
└────┘
│
└──> ○ append GPL
│
○ add distributed
│
○ wrote a readme file
他仅仅是从上一个位置,移动到你指定的位置
┌────┐
│HEAD│
└────┘
│
│ ○ append GPL
│ │
└──> ○ add distributed
│
○ wrote a readme file
然后顺便将你的文件更新了~
那么当你后悔了,但是你已经将窗口关闭了,这时候你已经找不到前面的commit id了你该怎么办:
也是有办法的;可以使用git reflog命令,这个命令记录了你所有的命令,这样你就可以找到对应的commit id了
也就是你的使用 git init 的文件夹
你使用git init 后会在文件夹中产生一个.git的文件夹,这个就是版本库,其中最为重要的就是称之为“stage”的暂存区;git创建版本库后,会自动创建master分支,以及指向master的指针HEAD
其实是版本库中的一个重要区域,如上图所示,文件会先git add到暂存区
前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:
我们可以使用git status 来查看当前工作区中文件的状态
当我们将暂存区的文件进行commit 提交到分支上的时候,再使用git status 的时候 就会是空的;你会看到:
On branch master
nothing to commit, working tree clean
这里就是一个需要理解的小概念:git管理的是修改,而非文件
当你这样执行修改一个文件后:第一次修改 -> git add -> 第二次修改 -> git commit
git只会将第一次修改去进行提交到版本库,git只会去跟踪你的修改,文件变化是没有监视的,也就是说没有提交到暂存区的文件,可能会与真实文件不一致,这大大提升了协同工作;
这里就是针对你犯错误的时候,请认真观看
我这边分为以下几种情况:
那么恭喜你了!你发现的很早,你现在只需要把错误修改了,神不知鬼不觉的提交就好了,
或者使用git checkout – 文件名 就可以回到和版本库中一样的文件了(这个文件,全部会覆盖嗷)
git reset HEAD 以把暂存区的修改撤销掉(unstage),重新放回工作区:
使用git checkout – 文件名 就可以回到和暂存库中一样的文件了(这个文件,全部会覆盖嗷)
那么直接使用 git reset --hard HEAD^撤回到上一个commit就行了(这个文件,全部会覆盖嗷)
你就真的惨了……
特别注意
git checkout – file命令中的–很重要,没有–,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到git checkout命令。
使用git rm 删除暂存区的文件
创建远程仓库:不管你是什么平台(GitHub,GitLab,Gitee)
创建完成后你会获得一个连接:git@*******/.git**
这时候,你在你的版本库中执行
git remote add origin git@*******/**.git
这时候相当于连接上了远程仓库:这时候你的远程仓库的名字就是origin,这是git默认对于远程版本库的叫法
下一步就是将你的本地库推送到远程库上:
git push -u origin master
由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
这里贴上一个小问题;以便大家以后遇到排查
我也遇到了fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.的问题
廖老师是通过 git@github.com:michaelliao/learngit.git 关联的,我在win7和win10上测试推送时都不能成功,https的才可以。如果已经用git@关联,则可以在.git目录下的config文件中,把 url = 后面的内容改为https类型的即可。 https类型的格式为: $ git remote add origin https://github.com/daoke0818/testGit2.git
另外我发现:
如果在第一步中创建时已经初始化过项目,则这时会提醒 error: failed to push some refs to ‘https://github.com/daoke0818/testGit2.git’ hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., ‘git pull …’) before pushing again. hint: See the ‘Note about fast-forwards’ in ‘git push --help’ for details.
因为远程库中已经存在readme文件了,所以需要先pull下来。命令如下: $ git pull origin master
这时又会报错: From https://github.com/daoke0818/testGit
branch master -> FETCH_HEAD fatal: refusing to merge unrelated histories 说这两个库有不相干的历史记录而无法合并,这时我们可以加上一个参数 --allow-unrelated-histories 即可成功pull: $ git pull origin master --allow-unrelated-histories
但是这时会可能会提示必须输入提交的信息,默认会打开vim编辑器,先按 i 切换到插入模式,写完后 Esc→:→wq 即可保存退出编辑器。如果不进入vim编辑器,则会自动生成一个合并代码的commit。然后再使用前面的命令push将本地提交推送到远程仓库。后面如果本地还有commit,就可以直接用 git push origin master 推送。
使用git clone git@*******/**.git 可以直接从远程仓库克隆一个本地库
如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。
你也许还注意到,GitHub给出的地址不止一个,还可以用https://github.com/michaelliao/gitskills.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。
使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。
先解释一下分支的概念
在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:
每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
你看,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!
不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
所以Git合并分支也很快!就改改指针,工作区内容也不变!
合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:
注意这些点
对于所有分支而言, 工作区和暂存区是公共的。
分支修改后没有提交是无法切换到另一分支的
$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
README.md
Please commit your changes or stash them before you switch branches.
但是我看到有些人是可以违规切换到其他分支的,不太清楚这是怎么操作的
当你处理分支冲突的时候,合并后使用git会告诉你哪些文件冲突了,你可以打开这些冲突文件,你会看到git已经帮你预处理了一下
比如:
Git tracks changes of files.
<<<<<<<HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>>dev
这时候你就明白上面的是现在指向的分支内容,下面是你提交的分支内容
你只需要将这个文件处理一下
比如你想保留你在dev分支的内容:
Git tracks changes of files.
Creating a new branch is quick AND simple.
这时候你再提交,冲突已经被你解决了
以下为流程图:
如上图,你解决后的文件被提交到下一个commit节点上去了
这里提到一个概念:
git会默认使用Fast forward模式,这种模式会丢掉分支信息
我的理解:在你合并后,查看分支历史git log,你只会看到你当前分支的信息
但是当你merge的时候添加–no-ff参数,就会保留你分支的信息
比如:git merge --no-ff -m “merge with no-ff” dev
这时候git log;你还可以在这个分支上,看到dev的分支历史
在实际开发中,我们应该按照几个基本原则进行分支管理:
这一节点主要讲述的内容是,当你正在开发dev分支,但是突然需要你修改一个bug,但是你目前的改动还不能提交(commit),怎么办?
可以使用git stash将现在工作区的操作全部保存下来
这时候你修改完成bug后:回到dev分支,可以使用git stash list查看你的保存的状态
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
当你多次使用git stash想要恢复到指定的状态时
可以使用git stash apply {{stash id}}
也可以回到你开发时的状态
注意,当你在其他分支进行提交,但你又不想将整个分支都合并到你现在发分支:可以使用git cherry-pick 命令
真实场景:在主分支上修改bug,提交后,你的dev上分支肯定没有修改好这个bug,但你又不想将主分支上的代码全部都移交过来,这时候你就可以使用git cherry-pick 只将主分支的这次提交合并过来;注意,这里的commit id指的是你想要合并过来的操作的commit id
这一节点主要讲:如果要丢弃一个没有被合并过的分支,可以通过git branch -D 强行删除。
这里,本人使用idea系列产品和vscode并没有遇到特别多的困难
我阐述一下多人协作的模式:
因此,多人协作的工作模式通常是这样:
首先,可以试图用git push origin 推送自己的修改;
如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用git push origin 推送就能成功!
如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to origin/。
这就是多人协作的工作模式,一旦熟悉了,就非常简单。
使用git tag 就可以打一个新标签:
可以用命令git tag查看所有标签:
用命令git show 可以看到说明文字:
命令git push origin 可以推送一个本地标签;
命令git push origin --tags可以推送全部未推送过的本地标签;
命令git tag -d 可以删除一个本地标签;
命令git push origin :refs/tags/可以删除一个远程标签。
命令git push origin --delete 也可以删除一个远程标签。
我对于标签的理解:其实就是针对特定节点的一个记录,类似于app的版本号,标签创建完成后,使用git show tagname就可以看到对应的commit id还有相关提交人信息,其实可以理解成时标签绑定到一个commit id之上
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。