Git从入门到精通,Git命令大全
原文:Git从入门到精通,Git命令大全友人a的笔记丶Git入门
资料来源:https:www。runoob。comgitgittutorial。html、http:gitscm。comdocs
查看Git命令的帮助信息,githelp1。Git工作区、暂存区和版本库(以本地举例)、远程仓库工作区:就是你在电脑里能看到的目录。暂存区:英文叫stage或index。一般存放在。git目录下的index文件(。gitindex)中,所以我们把暂存区有时也叫作索引(index)。版本库:工作区有一个隐藏目录。git,这个不算工作区,而是Git的版本库。
Git工作区、暂存区和版本库图中左侧为工作区,右侧为版本库。在版本库中标记为index的区域是暂存区(stageindex),标记为master的是master分支所代表的目录树。图中我们可以看出此时HEAD实际是指向master分支的一个游标。所以图示的命令中出现HEAD的地方可以用master来替换。图中的objects标识的区域为Git的对象库,实际位于。gitobjects目录下,里面包含了创建的各种对象及内容。当对工作区修改(或新增)的文件执行gitadd命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。当执行提交操作(gitcommit)时,暂存区的目录树写到版本库(对象库)中,master分支会做相应的更新。即master指向的目录树就是提交时暂存区的目录树。当执行gitresetHEAD命令时,暂存区的目录树会被重写,被master分支指向的目录树所替换,但是工作区不受影响。当执行gitrmcached命令时,会直接从暂存区删除文件,工作区则不做出改变。当执行gitcheckout。或者gitcheckout命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区中的改动。当执行gitcheckoutHEAD。或者gitcheckoutHEAD命令时,会用HEAD指向的master分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。2。Git文件状态
在Git中文件大概分为四种状态:已修改(modified)、已暂存(staged)、已提交(committed)、未追踪(Untrack)。gitignore内的文件,不会拥有任何一种状态,被git彻底无视。处于ignore列表的文件,无法被add添加;但是可以强制添加空目录、以及子目录全部是空目录的目录不会有Untrack状态,也无法通过add改变状态(无效)工作目录新增文件时,只要不处于ignore目录,都会变成Untrack状态;没有add过的文件或者被restore(不带staged)的文件,处于Untrack状态;初次add和被add后产生修改的文件,会处于modifed状态。处于modified状态的文件,最开始可以进行add和restore两种操作,此时的add操作叫做更新要提交的内容,add后变为staged状态,restore(不加staged标记)后变为Untrack;add后变为staged状态的文件,可用restorestaged变回modified状态;这个staged状态的内容可以用来恢复内容。没有被add的modified状态文件内容没有被记录(虽然有撤回,但是本质不一样);处于staged状态的文件,在没有commit之前再次产生修改时,会同时具有staged和modified两个状态(可以把statged状态的内容拉回来,覆盖。);但是commit时会使用内容最新的那个状态;commit会提交所有staged状态的文件,所以commit可以理解有一个modified到staged状态的过程(实际可能不存在,因为暂存区本来就有变动的记录);所以暂存状态不能理解为处于暂存区,应当指的是被纳入下一次提交的文件;任何被追踪的产生修改的文件都会在暂存区被记录;成为下一次提交的一部分;未被追踪的文件被删除时,不会产生git状态。处于modofy未add时,会变成deleted状态;处于staged状态会保持暂存状态;已经被删除的(deleted状态)被追踪的文件,恢复后会变成modified状态;
提示:add的作用是将文件添加到暂存区,只有被add的文件才会被追踪
暂存区
(1)所谓的暂存区只是一个简单的索引文件而已。
(2)暂存区这个索引文件里面包含的是文件的目录树,像一个虚拟的工作区,在这个虚拟工作区的目录树中,记录了文件名、文件的时间戳、文件长度、文件类型以及最重要的SHA1值,文件的内容并没有存储在其中,所以说它像一个虚拟的工作区。
(3)索引指向的是。Gitobjects下的文件。
(4)暂存区的作用:除非是绕过暂存区直接提交,否则Git想把修改提交上去,就必须将修改存入暂存区最后才能commit。每次提交的是暂存区所对应的文件快照。拓展:status提示信息Changesnotstagedforcommit:(usegitaddfile。。。toupdatewhatwillbecommitted)(usegitcheckoutfile。。。todiscardchangesinworkingdirectory)既然是Changesnotstagedforcommit,就说明出现这个提示下的所有文件改动,都是存在于工作区的。stage是暂存区的意思,notstage说明都不在暂存区,那么说明在工作区。(usegitaddtoupdatewhatwillbecommitted)。执行这条命令就可以工作区里面的改变加入到暂存区。可以执行gitadd。把当前目录下所有改动加入暂存区。(usegitcheckouttodiscardchangesinworkingdirectory)。执行这条命令将丢弃在工作区的改动。可以执行gitcheckout把当前目录下所有工作区的改动丢弃掉Untrackedfiles:(usegitaddfile。。。toincludeinwhatwillbecommitted)Untrackedfiles,就说明出现这个提示下的所有文件都是当前HEAD没有被加入过的文件。这种改动也属于工作区。(usegitaddtoincludeinwhatwillbecommitted)。把Untrackedfiles加入暂存区。OnbranchmasterYourbranchisaheadoforiginmasterby1commit。(usegitpushtopublishyourlocalcommits)当前分支比远程分支多了一次commitYourbranchandoriginmasterhaveperged,andhave1and1differentcommitseach,respectively
pull报错了,查看状态显示这个,先留着待解决吧3。HEAD是什么
HEAD是Git中非常重要的一个概念,你可以称它为指针或者引用,它可以指向任意一个节点,并且指向的节点始终为当前工作目录,换句话说就是当前工作目录(也就是你所看到的代码)就是HEAD指向的节点。4。git重命名检测
Git采用了不同的方法:它没有选择去存储与文件移动操作相关的信息,而是采用了重命名检测算法。在该算法中,如果一个文件在某一次提交中消失了,它依然会存在于其前次提交,而如果某个拥有相同名字或相似内容的文件出现在了另一个位置,Git就会自动检测到。如果是这种情况,Git就会假定该文件被移动过了。Git项目文件说明
Gitinit后主要有两个重要的文件和目录:。git目录和。gitignore1。。gitignore
。gitignore文件存在于根目录(与。git同级的目录)用于在将文件提交到git暂存区时,指定将哪些文件排除;
有时候你想添加(gitadd)一个文件到Git,但发现添加不了,多半原因是这个文件被。gitignore忽略了
gitadd。不会添加被。gitignore忽视的文件,而gitaddf。强制添加所有文件,即使是。gitignore忽视的文件也添加。
当。gitignore文件不是你编写的,但是它编写的不符合实际需求,你可以使用gitcheckignore命令进行检查,看是哪一个规则有问题了检测gitcheckignorevApp。class结果。gitignore:3:。classApp。class
。gitignore只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改。gitignore是无效的。解决方法就是先把本地缓存删除(改变成未track状态),然后再提交。gitrmrcached。gitadd。gitcommitm‘update。gitignore’
也可以手动指定一个文件作为git忽略文件gitconfigcore。excludesfile
对于全局Git配置,可以使用如下命令对全部仓库进行配置。gitconfigglobalcore。excludesfile。gitignore(文件相对或绝对位置)
忽略规则如下:空格不匹配任意文件,可作为分隔符,可用反斜杠转义开头的文件标识注释,可以使用反斜杠进行转义!开头的模式标识否定,该文件将会再次被包含,如果排除了该文件的父级目录,则使用!也不会再次被包含。可以使用反斜杠进行转义结束的模式只匹配文件夹以及在该文件夹路径下的内容,但是不匹配该文件开始的模式匹配项目跟目录如果一个模式不包含斜杠,则它匹配相对于当前。gitignore文件路径的内容,如果该模式不在。gitignore文件中,则相对于项目根目录匹配多级目录,可在开始,中间,结束?通用匹配单个字符〔〕通用匹配单个字符列表
各种项目的gitignore
参考地址:https:github。comgithubgitignore2。。git目录
任意文件夹中,用gitinit命令初始化仓库,即可在此文件夹下创建。git文件夹(。打头为隐藏文件夹,所以平时可能看不到)。这个文件夹之外的部分叫做工作区(WorkingDirectory),。git文件夹我们称做Git仓库(GitRepository)。通常会有7个文件5个目录,常见目录如下:COMMITEDITMSGHEADORIGHEADFETCHHEADconfigdescriptionindexhooksinfologsobjectsrefs1。文件COMMITEDITMSG
此文件是一个临时文件,存储最后一次提交的信息内容,gitcommit命令之后打开的编辑器就是在编辑此文件,而你退出编辑器后,git会把此文件内容写入commit记录。
实际应用:gitpull远程仓库后,新增了很多提交,淹没了本地提交记录,直接cat。gitCOMMITEDITMSG就可以弄清楚最后工作的位置了。2。HEAD
此文件永远存储当前位置指针,就像linux中的PWD变量和命令提示符的箭头一样,永远指向当前位置,表明当前的工作位置。在git中HEAD永远指向当前正在工作的那个commit。(孤立HEAD?????)
HEAD存储一个分支的ref,Linux中运行:cat。gitHEAD通常会显示:ref:refsheadsmaster
这说明你目前正在master分支工作。此时你的任何commit,默认自动附加到master分支之上
gitcatfilepHEAD,显示详细的提交信息:tree4cbb261560348e1727b5137f3ab6eceae8e1f34dparent22c457fe24f737505356edfb8696c7e50fd9d971authorEvanYouyyx990803gmail。com16548576130800committerEvanYouyyx990803gmail。com16548576130800chore:testpass
孤立head,不指向任何commit3。ORIGHEAD
正因为HEAD比较重要,此文件会在你进行危险操作时备份HEAD,如以下操作时会触发备份gitresetgitmergegitrebasegitpull
此文件应用示例回滚到上一次的状态(慎用!!!)gitresethardORIGHEAD4。FETCHHEAD
这个文件作用在于追踪远程分支的拉取与合并,与其相关的命令有gitpullfetchmerge,而gitpull命令相当于执行以下两条命令:gitfetchgitmergeFETCHHEAD显示如下Fromhttps:github。comxxxxxxxbranchmasterFETCHHEADUpdatingf785638。。59db1b2
此时会默默备份HEAD到ORIGHEAD5。config
此文件存储项目本地的git设置,典型内容如下:〔core〕repositoryformatversion0filemodetruebarefalselogallrefupdatestrueignorecasetrue〔remoteorigin〕urlgitgitlab。xxxx。comxxx。gitfetchrefsheads:refsremotesorigin〔branchmaster〕remoteoriginmergerefsheadsmaster〔branchv2。6。0〕remoteoriginmergerefsheadsv2。6。0〔branchv2。8。0〕remoteoriginmergerefsheadsv2。8。0
〔core〕段的内容跟gitconfig命令对应
执行以下命令:gitconfiguser。nameabcgitconfiguser。emailabcabc。com
会在config文件中追加以下内容:。。。。。。〔user〕nameabcemailabcabc。com
gitconfigglobal影响的则是全局配置文件。gitconfig。
〔remote〕段表示远程仓库配置
〔branch〕段表示分支同步设置
假设当前在master分支,执行gitpull若出现以下提示:Thereisnotrackinginformationforthecurrentbranch。Pleasespecifywhichbranchyouwanttomergewith。Seegitpull(1)fordetails。
gitpull就说明。gitconfig文件缺少对应的〔branchmaster〕字段。
解决方案为:gitbranchuoriginmastermaster或者执行一次pushgitpushuoriginmaster
会出现提示:Branchmastersetuptotrackremotebranchmasterfromorigin。
其实就是生成以下内容在。gitconfig中:〔branchmaster〕remoteoriginmergerefsheadsmaster
手动编辑。gitconfig,效果一样。这就是upstream的真正含义,即生成config中的这段配置。6。description
说明这个文件主要用于GitWeb的描述,如果要启动GitWeb可用如下命令:确保lighttpd已安装:brewinstalllighttpdgitinstawebstart
默认会启动lighttpd服务并打开浏览器http:127。0。0。1:1234(试着改成对外IP并分享给别人?)
以下显示当前的git仓库名称以及描述,默认的描述如下:
默认描述
上面这段话就是默认的description文件的内容,编辑这个文件来让你GitWeb描述更友好。7。hooks目录
存放githooks,用于在git命令前后做检查或做些自定义动作。运行lsF1。githookspreparecommitmsg。samplegitcommit之前,编辑器启动之前触发,传入COMMITFILE,COMMITSOURCE,SHA1commitmsg。samplegitcommit之前,编辑器退出后触发,传入COMMITEDITMSG文件名precommit。samplegitcommit之前,commitmsg通过后触发,譬如校验文件名是否含中文prepush。samplegitpush之前触发prereceive。samplegitpush之后,服务端更新ref前触发update。samplegitpush之后,服务端更新每一个ref时触发,用于针对每个ref作校验等postupdate。samplegitpush之后,服务端更新ref后触发prerebase。samplegitrebase之前触发,传入rebase分支作参数applypatchmsg。sample用于gitam命令提交信息校验preapplypatch。sample用于gitam命令执行前动作fsmonitorwatchman。sample配合core。fsmonitor设置来更好监测文件变化
参考
https:gitscm。comdocsgithooks
如果要启用某个hook,只需把。sample删除即可,然后编辑其内容来实现相应的逻辑。
比如要校验每个commitmessage至少要包含两个单词,否则就提示并拒绝提交,将commitmsg。sample改为commitmsg后,编辑如下:!binshgrepqSsS1{echo提交信息至少为两个单词exit1;}
这样当提交一个commit时,会执行bash命令:。githookscommitmsg。gitCOMMITEDITMSG,退出值不为0,就拒绝提交。8。info目录
此文件夹基本就有两个文件:文件infoexclude用于排除规则,与。gitignore功能类似。可能会包含文件inforefs,用于跟踪各分支的信息。此文件一般通过命令gitupdateserverinfo生成,内容通常如下:94e1a0d952f577fe1348d828d145507d3709e11erefsheadsmasterobjecthashbranchreference这表示master分支所指向的文件对象hash值为:94e1a0d952f577fe1348d828d145507d3709e11e,运行gitcatfilep94e1a0d952f577fe1348d828d145507d3709e11e,可以看到master分支最后提交的记录信息。同时:cat。gitobjects94e1a0d952f577fe1348d828d145507d3709e11e可以看到最后提交文件的二进制内容表示。文件inforefs对于搭建git服务器来说至关重要。9。logs目录
记录了操作信息,gitreflog命令以及像HEAD{1}形式的路径会用到。如果删除此文件夹(危险!),那么依赖于reflog的命令就会报错。文件夹objects
此文件夹简单说,就是git的数据库,运行tree。gitobjects,可以看到目录结构:。gitobjects0cd370696b581c38ee01e62b148a759f80facc2d593d5b490556791212acd5a516a37bbfa05d44dd61be44eedde61d723e5761577a2b420ba0fc279464c0aed8ddcbb546bdcec2848938fc82348db227d49904676ce8ddde276bdbfa9bbec313e90e0f50infopackpack75e3f2aa378752ec93a8e9f375f01204d498605b。idxpack75e3f2aa378752ec93a8e9f375f01204d498605b。pack
这些文件分两种形式:pack压缩包形式放在pack目录下,除此之外都是hash文件形式,被叫做loostobjects。
这个文件夹以及相应的算法,我没找到独立的名称,就叫它hashobject体系吧。因为确实有个githashobject命令存在,是一个底层的负责生成这些loostobjects文件,如果要看到这些文件各自的含义,执行以下命令:gitcatfilebatchcheckbatchallobjects
可以看到04c87c65f142f33945f2f5951cf7801a32dfa240commit194098217953a6ca169bed33d2be8a07d584fcdaf30tree310cd370696b581c38ee01e62b148a759f80facc2dcommit2452a810017bfc85d7db2627f4aabdaa1583212bda3blob193920a07c1d5694df6b8658592b0939241d70e9e5tree93593d5b490556791212acd5a516a37bbfa05d44ddtag14861be44eedde61d723e5761577a2b420ba0fc2794tree154。。。。。。
但你会发现这个列表里有些值在文件夹中并不存在,因为除了loostobjects它还汇总了pack文件中的内容。
hash文件
又称为looseobject,文件名称共由40字符的SHA1hash值组成,其中前两个字符为文件夹分桶,后38个字符为文件名称。
按文件内容可分为四种类型:commit,tree,blob,tag,若执行以下命令会生成所有四种类型:echoenxxxx共3个字符gitadd。gitcommitmupdatexxgittagav1。0mrelease:1。0。0
经过以上操作后,对比一下文件树,发现多了四个hash文件:0cd370696b581c38ee01e62b148a759f80facc2d18143661f96845f11e0b4ab7312bdc0f356834ce3020feea86d222d83218eb3eb5aa9f58f73df04d593d5b490556791212acd5a516a37bbfa05d44dd61be44eedde61d723e5761577a2b420ba0fc279464c0aed8ddcbb546bdcec2848938fc82348db227adf4c9afac7afae3ff3e95e6c4eefe009d547f00ccc9bd67dc5c467859102d53d54c5ce851273bddd49904676ce8ddde276bdbfa9bbec313e90e0f50infopackpack75e3f2aa378752ec93a8e9f375f01204d498605b。idxpack75e3f2aa378752ec93a8e9f375f01204d498605b。pack
这四个hash文件分别是:ccc9bd67dc5c467859102d53d54c5ce851273bddblob3020feea86d222d83218eb3eb5aa9f58f73df04dcommitadf4c9afac7afae3ff3e95e6c4eefe009d547f00tree18143661f96845f11e0b4ab7312bdc0f356834cetag
其实这些文件都经过了压缩,压缩形式为zlib。先安装一下解压工具macOS版brewinstallpigz或windows版pigz,后执行:pigzd。gitobjectsccc9bd67dc5c467859102d53d54c5ce851273bddBLOB类型,显示结果为(注意xx后有个)blob3xxpigzd。gitobjects3020feea86d222d83218eb3eb5aa9f58f73df04dCOMMIT类型,显示结果为commit248treeadf4c9afac7afae3ff3e95e6c4eefe009d547f00parent0cd370696b581c38ee01e62b148a759f80facc2dauthorjamesyang。yjmjamesyang。yjmalibabainc。com15620448800800committerjamesyang。yjmjamesyang。yjmalibabainc。com15620448800800updatexxpigzd。gitobjectsadf4c9afac7afae3ff3e95e6c4eefe009d547f00TREE类型,显示结果为tree154100644abc???〕}?bJ?X2??100644asdf???CK?)?wZ???S?100644iou???CK?)?wZ???S?100644xx?g?FxYS?L?Q;?100644yy???CK?)?wZ???S?pigzd。gitobjects18143661f96845f11e0b4ab7312bdc0f356834ceTAG类型,显示结果为tag155object3020feea86d222d83218eb3eb5aa9f58f73df04dtypecommittagv1。0taggerjamesyang。yjmjamesyang。yjmalibabainc。com15620459420800release:1。0。0
会发现,显示结果都是typesize内容形式,这就是object文件的存储格式:〔type〕〔size〕〔NULL〕〔content〕
type可选值:commit,tree,blob,tag,NULL就是C语言里的字符结束符:,size就是NULL后内容的字节长度。
type的几种类型可以使用gitcatfilethash看到,内容可以用gitcatfilephash看到。gitcatfiletccc9bd67dc5c467859102d53d54c5ce851273bdd显示结果为blobgitcatfilepccc9bd67dc5c467859102d53d54c5ce851273bdd显示结果为xx
所以blob文件就是对原文件内容的全量拷贝,同时前面加了blobsize,而文件名称的hash值计算是计算整体字符的SHA1值:echoenblob3xxshasum显示结果为ccc9bd67dc5c467859102d53d54c5ce851273bdd
知道原理后,其它类型格式请自行参考斯坦福BenLynn所著的GitMagic。
所以,当我们gitshow3020feea86d222d83218eb3eb5aa9f58f73df04d时,会发生些什么?
找到3020feea86d222d83218eb3eb5aa9f58f73df04d这个commit,显示出来
找到此commit关联的treeobject:adf4c9afac7afae3ff3e95e6c4eefe009d547f00,拉取相应的blob文件,并与当前工作区内的文件做diff,然后显示出来
这就是objects文件夹作为git数据库被使用的真实例子。
pack文件
为什么会有。pack文件?
由于每次commit都会生成许多hash文件,并且由于blob文件都是全量存储的,导致git效率下降,于是有了packformat,优势:
对于大仓库存储效率高
利于网络传输,便于备份
增量存储,优化磁盘空间
将。gitobjects下的部分文件打包成pack格式tree。gitobjectswcl311gitgcEnumeratingobjects:288,done。Countingobjects:100(288288),done。Deltacompressionusingupto4threadsCompressingobjects:100(287287),done。Writingobjects:100(288288),done。Total288(delta131),reused90(delta0)tree。gitobjectswcl12
可以看到文件数量减小了不少,其中大部分文件被打到一个。pack包中,并且是增量存储,有部分变更的文件只存储基础hash变更内容,磁盘空间优化很明显。
gitgc其实运行了两条命令:gitrepack用来打包和gitprunepacked用来移除已打包的hash文件;11。文件夹refs
refs可以理解成文件系统中的symbollink,看下结构:tree。gitrefs。gitrefsheadsmastertagsv1。0cat。gitrefsheadsmaster5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5cat。gitrefstagsv1。05978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5gitcatfilet5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5commit
可以看到master和v1。0都指向5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5这个commit。
refsheads文件夹内的ref一般通过gitbranch生成。gitshowrefheads可以查看。
refstags文件夹内的ref一般通过gittag生成。gitshowreftags可以查看。
如下:gitbranchabctree。gitrefs。gitrefsheadsabcmastertagsv1。0cat。gitrefsheadsabc5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5
说明新建分支其实就是生成了一个指向某个commit的symbollink,当然在这里叫做ref。
而gittag命令本质与gitbranch相同,只生成一个ref放在tags目录下,所以被称为lightweighttag。
而gittagaxx命令会首先生成一个类型为tag的hash文件放到objects目录,然后生成ref放到tags目录下指向那个文件。这就叫做annotatedtag,好处是可包含一些元信息如tagger和message,被git的hashobject算法管理,可被GPG签名等,所以更稳定,更安全。
使用以下命令来拿到refs文件夹存储的信息:gitshowrefheaddereference5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5HEAD5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5refsheadsabc5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5refsheadsmaster5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5refstagsv1。05e84371048faa20412f5492e6af264a7e1edfec1refstagsxx5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5refstagsxx{}
我们来看这些信息如何变化的:touchnewfilegitadd。gitcommitmaddnewfile〔master44b0d05〕addnewfile1filechanged,0insertions(),0deletions()createmode100644newfilegitshowrefheaddereference44b0d05ddadaaa8d2cc40d6647cc474b26f5d8d3HEAD5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5refsheadsabc44b0d05ddadaaa8d2cc40d6647cc474b26f5d8d3refsheadsmaster5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5refstagsv1。05e84371048faa20412f5492e6af264a7e1edfec1refstagsxx5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5refstagsxx{}
diff一下可以看到:5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5HEAD5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5refsheadsmaster
这两行发生了变化。也就是每次commit时,HEAD与heads都会自动更新。12。index文件
文件保存成二进制对象以后,还需要通知Git哪些文件发生了变动。所有变动的文件,Git都记录在一个区域,叫做暂存区(英文叫做index或者stage)。等到变动告一段落,再统一把暂存区里面的文件写入正式的版本历史。
gitupdateindex命令用于在暂存区记录一个发生变动的文件。gitupdateindexaddcacheinfo1006443b18e512dba79e4c8300dd08aeb37f8e728b8dadtest。txt
上面命令向暂存区写入文件名test。txt、二进制对象名(哈希值)和文件权限。
gitlsfiles命令可以显示暂存区当前的内容。gitlsfilesstage1006443b18e512dba79e4c8300dd08aeb37f8e728b8dad0test。txt
上面代码表示,暂存区现在只有一个文件test。txt,以及它的二进制对象名和权限。知道了二进制对象名,就可以在。gitobjects子目录里面读出这个文件的内容。
gitstatus命令会产生更可读的结果。gitstatus要提交的变更:新文件:test。txt
上面代码表示,暂存区里面只有一个新文件test。txt,等待写入历史。
资料来源
参考:https:developer。aliyun。comarticle716483Git远程仓库
Git并不像SVN那样有个中心服务器。目前我们使用到的Git命令都是在本地执行,如果你想通过Git分享你的代码或者与其他开发人员合作。你就需要将数据放到一台其他开发人员能够连接的服务器上。1。添加远程仓库gitremoteadd〔shortname〕〔url〕添加远程仓库gitremotermname删除远程仓库gitremoterenameoldnamenewname修改仓库名2。查看远端仓库gitremoteorigingitremotevorigingitgithub。com:tianqixinrunoobgittest。git(fetch)origingitgithub。com:tianqixinrunoobgittest。git(push)3。获取远端仓库代码gitfetch只能fetch到一个空白的分支,然后可以手动mergegitfetch远程主机名远程分支名:本地分支名
不填的话都是默认4。拉取gitpullgitpull远程主机名远程分支名:本地分支名允许合并不相关的分支gitpullallowunrelatedhistories
gitpull操作其实是gitfetch与gitmerge两个命令的集合。gitfetch和gitmergeFETCHHEAD的简写。
相关文档:https:www。runoob。comgitgitremoterepo。html5。推送gitpush基本gitpush远程主机名本地分支名:远程分支名强制推送gitpushforceoriginmaster删除远程分支gitpushorigindeletemaster允许合并不相关的分支gitpushallowunrelatedhistories
提示
如果另一个开发者在我们之前已经做过一次push操作,此次push命令就会被拒绝传送提交。这时候,我们必须要先做一次pull操作,将其他人新上载的更新取回,并本地合并。
如果本地分支名与远程分支名相同,则可以省略冒号,带上u参数相当于记录了push到远端分支的默认值,这样当下次我们还想要继续push的这个远端分支的时候推送命令就可以简写成gitpush即可。Git分支1。创建分支命令gitbranch创建分支gitbranchbranch创建分支并跟踪远程分支gitbranchuomasterfoo2。切换分支命令gitcheckout
第一作用是切换分支,第二个是撤销修改。切换指定分支gitcheckoutbranchhashtag创建一个的分支,它跟踪远程分支gitcheckoutb本地分支名xorigin远程分支名x从暂存区恢复到工作区gitcheckout。
提示
当你切换分支的时候,Git会用该分支的最后提交的快照替换你的工作目录的内容,所以多个分支不需要多个目录。
实际测试:
假设分支1a文件未提交,分支2a文件已提交。切换到到分支2时会替换分支1的a文件。1切换到2时也会替换a文件;
两个分支都已经提交的切换时会互相替换。一个提交一个没提交时,从a到b,b会保持a的暂存区和工作区3。合并分支命令gitmerge合并指定分支到当前分支gitmergebranch4。删除分支gitbranchd删除指定分支gitbranchdbranch5。分支列表gitbranch列出所有分支gitbranch查看远程所有分支gitbranchr查看本地和远程所有分支gitbrancha
列出分支时,带号的分支为当前活动分支5。重命名分支gitbranchM重命名指定分支不填old默认重命名当前分支gitbranchmoldnew强制重命名指定分支gitbranchMoldnewgitrebase变基1。介绍
Gitrebase,通常被称作变基或衍合,可以理解为另外一种合并的方式,与merge会保留分支结构和原始提交记录不同,rebase是在公共祖先的基础上,把新的提交链截取下来,在目标分支上进行重放,逐个应用选中的提交来完成合并。
不同公司,不同情况有不同使用场景,不过大部分情况推荐如下:
自己单机的时候,拉公共分支最新代码的时候使用rebase,也就是gitpullr或gitpullrebase。这样的好处很明显,提交记录会比较简洁。但有个缺点就是rebase以后我就不知道我的当前分支最早是从哪个分支拉出来的了,因为基底变了嘛,所以看个人需求了。
往公共分支上合代码的时候,使用merge。如果使用rebase,那么其他开发人员想看主分支的历史,就不是原来的历史了,历史已经被你篡改了。举个例子解释下,比如张三和李四从共同的节点拉出来开发,张三先开发完提交了两次然后merge上去了,李四后来开发完如果rebase上去(注意李四需要切换到自己本地的主分支,假设先pull了张三的最新改动下来,然后执行,然后再gitpush到远端),则李四的新提交变成了张三的新提交的新基底,本来李四的提交是最新的,结果最新的提交显示反而是张三的,就乱套了。
正因如此,大部分公司其实会禁用rebase,不管是拉代码还是push代码统一都使用merge,虽然会多出无意义的一条提交记录Mergeto,但至少能清楚地知道主线上谁合了的代码以及他们合代码的时间先后顺序2。原理
变基操作的工作原理很简单:Git会让我们想要移动的提交序列在目标分支上按照相同的顺序重新再现一遍。这就相当于我们为各个原提交做了个副本,它们拥有相同的修改集、同一作者、日期以及注释信息。3。命令可以是commit版本号、分支名称,合并多个提交到一个版本gitrebasei〔startpoint〕〔endpoint〕变基发生冲突时,解决后继续变基gitrebasecontinue无视冲突,继续变基操作gitrebaseskip发生冲突时中断变基gitrebaseabort
i的意思是interactive,即弹出交互式的界面让用户编辑完成合并操作,〔startpoint〕〔endpoint〕则指定了一个编辑区间,如果不指定〔endpoint〕,则该区间的终点默认是当前分支HEAD所指向的commit(注:该区间指定的是一个前开后闭的区间)。Git标签
Git中的tag指向一次commit的id,通常用来给开发分支做一个标记,如标记一个版本号。1。添加标签gittagaversionmnote
注解:gittag是打标签的命令,a是添加标签,其后要跟新标签号,m及后面的字符串是对该标签的注释。2。提交标签到远程仓库gitpushorigintags
注解:就像gitpushoriginmaster把本地修改提交到远程仓库一样,tags可以把本地的打的标签全部提交到远程仓库。3。删除标签gittagdversion
注解:d表示删除,后面跟要删除的tag名字4。删除远程标签gitpushorigin:refstagsversion
注解:就像gitpushorigin:branch1可以删除远程仓库的分支branch1一样,冒号前为空表示删除远程仓库的tag。5。查看标签gittag或者gittaglGit存储
gitstash将本地未提交代码作为一个本地缓存。作用范围为本地工作区以及本地暂存区。1。使用场景当正在dev分支上开发某个项目,这时项目中出现一个bug,需要紧急修复,但是正在开发的内容只是完成一半,还不想提交,这时可以用gitstash命令将修改的内容保存至堆栈区,然后顺利切换到hotfix分支进行bug修复,修复完成后,再次切回到dev分支,从堆栈中恢复刚刚保存的内容。由于疏忽,本应该在dev分支开发的内容,却在master上进行了开发,需要重新切回到dev分支上进行开发,可以用gitstash将内容保存至堆栈中,切回到dev分支后,再次恢复内容即可。2。gitstash保存当前工作区、暂存区的所有未提交代码执行存储时,添加备注,方便查找gitstashsavesavemessage
只有gitstash也是可以的,但查找时不方便识别。3。查看stash列表查看stash了哪些存储gitstashlist4。恢复缓存gitstashpop
命令恢复之前缓存的工作目录,将缓存堆栈中的对应stash删除,并将对应修改应用到当前的工作目录下,默认为第一个stash,即stash{0},如果要应用并删除其他stash,命令:gitstashpopstash{num}
比如应用并删除第二个:gitstashpopstash{1}5。gitapply
使用apply命令恢复,stash列表中的信息是会继续保留的,而使用pop命令进行恢复,会将stash列表中的信息进行删除。参数同pop6。删除缓存gitstashdropstash{num}
删除某个保存,num是可选项,通过gitstashlist可查看具体值7。删除所有缓存删除所有缓存的stashgitstashclearGit常用命令,基于使用步骤
使用步骤
提示:正常步骤应该是:先commit然后pull再push;1。gitconfig,配置Git
用于查看和修改Git配置信息,当安装Git后首先要做的事情是设置用户名称和email地址。这是非常重要的,因为每次Git提交都会使用该用户信息设置用户信息gitconfigglobaluser。name未进化的程序猿gitconfigglobaluser。email486566947qq。com读取配置信息gitconfiglistgitconfiguser。nameetcgitconfig文件:系统中对所有用户都普遍适用的配置。若使用gitconfig时用system选项,读写的就是这个文件。。gitconfig文件:用户目录下的配置文件只适用于该用户。若使用gitconfig时用global选项,读写的就是这个文件。当前项目的Git目录中的配置文件(也就是工作目录中的。gitconfig文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以。gitconfig里的配置会覆盖etcgitconfig中的同名变量。
提示
PHPstorm中使用Git时的账号密码同样是Git配置中使用的账号密码2。初始化仓库,gitinit
Git使用gitinit命令来初始化一个Git仓库,Git的很多命令都需要在Git的仓库中运行,所以gitinit是使用Git的第一个命令。
在执行完成gitinit命令后,Git仓库会生成一个。git目录,该目录包含了资源的所有元数据,其他的项目目录保持不变。
使用当前目录作为Git仓库,我们只需使它初始化。gitinit
该命令执行完后会在当前目录生成一个。git目录。
使用我们指定目录作为Git仓库。gitinitnewrepo
初始化后,会在newrepo目录下会出现一个名为。git的目录,所有Git需要的数据和资源都存放在这个目录中。3。将文件纳入版本控制,gitadd
如果当前目录下有几个文件想要纳入版本控制,需要先用gitadd命令告诉Git开始对这些文件进行跟踪,然后提交:当前目录下。c结尾的所有文件(通配符)gitadd。c指定README等多个文件文件gitaddREADMEREADME。md。gitaddall无论在哪个目录执行都会提交相应文件。gitaddall。gitadd。只能够提交当前目录或者它后代目录下相应文件。gitadd。4。提交文件,gitcommit
注意
注:在Linux系统中,commit信息使用单引号,Windows系统,commit信息使用双引号。
所以在gitbash中gitcommitm提交说明这样是可以的,在Windows命令行中就要使用双引号gitcommitm提交说明。
暂存区保留本次变动的文件信息,等到修改了差不多了,就要把这些信息写入历史,这就相当于生成了当前项目的一个快照(snapshot)。
项目的历史就是由不同时点的快照构成。Git可以将项目恢复到任意一个快照。快照在Git里面有一个专门名词,叫做commit,生成快照又称为完成一次提交。
提示
每一次commit都会产生一个新的版本。产生一个代表版本号的散列值gitcommitm初始化项目版本,记录提交信息gitcommitam新增提交说明
设置了用户名和Email,保存快照的时候,会记录是谁提交的。
Git文件生命周期5。克隆仓库,gitclone
我们使用gitclone从现有Git仓库中拷贝项目,Git仓库一般是一个远程连接gitclonerepodirectoryrepo:Git仓库。directory:本地目录。6。当前提交状态,gitstatus
gitstatus命令用于查看在你上次提交之后是否有对文件进行再次修改。gitstatusOnbranchmasterInitialcommitChangestobecommitted:(usegitrmcachedfile。。。tounstage)newfile:READMEnewfile:hello。php
通常我们使用s参数来获得简短的输出结果:gitstatussAMREADMEAhello。php
AM状态的意思是这个文件在我们将它添加到缓存之后又有改动。7。gitdiff,比较差异
gitdiff命令比较文件的不同,即比较文件在暂存区和工作区的差异。(c上下文格式的diff、u合并格式diff)
gitdiff命令显示已写入暂存区和已经被修改但尚未写入暂存区文件的区别。
gitdiff有两个主要的应用场景。尚未缓存的改动:gitdiff查看已缓存的改动:gitdiffcached查看已缓存的与未缓存的所有改动:gitdiffHEAD显示摘要而非整个diff:gitdiffstat
显示暂存区和工作区的差异:gitdiff〔file〕
显示两次提交之间的差异:gitdiffcached〔file〕或gitdiffstaged〔file〕
显示暂存区和上一次提交(commit)的差异:gitdiff〔firstbranch〕。。。〔secondbranch〕
分支比较直接将两个分支上最新的提交做diffgitdifftopicmaster或gitdifftopic。。master输出自topic和master分别开发以来,master分支上的变更。gitdifftopic。。。master查看简单的diff结果,可以加上stat参数nameonly输出时只显示文件名8。回退版本,gitreset
gitreset命令用于回退版本,可以指定退回某一次提交的版本。只对本地分支有效,对远程分支无效gitreset〔softmixedhard〕〔HEAD〕
mixed为默认,可以不用带该参数,用于重置暂存区的文件与上一次的提交(commit)保持一致,工作区文件内容保持不变。gitreset〔HEAD〕
gitresetHEAD
执行gitresetHEAD以取消之前gitadd添加,但不希望包含在下一提交快照中的缓存。
实例:gitresetHEAD回退所有内容到上一个版本gitresetHEADhello。php回退hello。php文件的版本到上一个版本gitreset052e回退到指定版本
soft参数用于回退到某个版本:gitresetsoftHEAD3回退上上上一个版本
hard参数撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交:gitresethardHEAD3回退上上上一个版本gitresethardbae128回退到某个版本回退点之前的所有信息。gitresethardoriginmaster将本地的状态回退到和远程的一样HEAD表示当前版本HEAD上一个版本HEAD上上一个版本HEAD上上上一个版本
HEAD0表示当前版本HEAD1上一个版本HEAD2上上一个版本HEAD3上上上一个版本9。删除文件,gitrm
将文件从暂存区和工作区中删除:gitrmfile
如果想把文件从暂存区域移除,但仍然希望保留在当前工作目录中,换句话说,仅是从跟踪清单中删除,使用cached选项即可:gitrmcachedfile
可以递归删除,即如果后面跟的是一个目录做为参数,则会递归删除整个目录中的所有子目录和文件:gitrmr10。移动目录、文件,gitmv
gitmv命令用于移动或重命名一个文件、目录或软连接。gitmv〔file〕〔newfile〕
如果新文件名已经存在,但还是要重命名它,可以使用f参数:gitmvf〔file〕〔newfile〕11。查看提交历史gitlog、gitblame所有历史记录gitlog简洁版gitlogoneline拓扑图版gitloggraph反向显示gitlogreverse指定提交者gitlogauthorlius时间范围gitlogbefore{3。weeks。ago}after{20100418}反向显示gitlogreverse指定文件gitblamefile
以上多种参数可以组合使用12。gitshow查看分支最后一次提交或版本在代码层面的改动gitshowbracnchcommit13。gitreflog
reflog是referencelog的缩写,含义是引用日志,它会记录下HEAD节点和分支引用所指向的历史。可以使用gitreflog命令来查看引用日志14。gitgc
gc命令(gc指的是垃圾回收)可用于清理版本库,移除所有不属于当前分支的提交对象。15。gitlsfiles
查看一下git跟踪了哪些文件,此命令就可以列出所有git正在跟踪的文件12。撤销文件gitrestore将在工作区但是不在暂存区的文件撤销更改gitrestorefile作用是将暂存区的文件从暂存区撤出,但不会更改文件gitrestorestaged问题记录1。push和commit的区别
gitcommit操作的是本地库,gitpush操作的是远程库。
gitcommit是将本地修改过的文件提交到本地库中。
gitpush是将本地库中的最新信息发送给远程库。
如果本地不commit的话,修改的纪录可能会丢失,而有些修改当前是不需要同步至服务器的,所以什么时候同步过去由用户自己选择。什么时候需要同步再push到服务器2。pullrequests和mergerequests
github可以对不同的用户赋予不同的分支权限,例如Gitlab中的:Guest:可以创建issue、发表评论,不能读写版本库Reporter:可以克隆代码,不能提交,QA、PM可以赋予这个权限Developer:可以克隆代码、开发、提交、push,RD可以赋予这个权限Master:可以创建项目、添加tag、保护分支、添加项目成员、编辑项目,核心RD负责人可以赋予这个权限Owner:可以设置项目访问权限VisibilityLevel、删除项目、迁移项目、管理组成员,开发组leader可以赋予这个权限
github基于fork的模式下,PR用于请求分支管理员合并自己提交的代码(理解为请求拉取自己的代码),mergerequests同理;3。fetch和pull的区别
git在本地会保存两个版本的仓库,分为本地仓库和远程仓库。
fetch只能更新远程仓库的代码为最新的,本地仓库的代码还未被更新,我们需要通过gitmergeoriginmaster来合并这两个版本,你可以把它理解为合并分支一样的。
pull操作是将本地仓库和远程仓库(本地的)更新到远程的最新版本。fetchmerge,自动进行合并4。checkout和reset时的变化
签出切换分支、版本、标签时文件的变化当执行gitresetHEAD命令时,暂存区的目录树会被重写,被master分支指向的目录树所替换,但是工作区不受影响。加上hard时会强制替换工作区、暂存区的内容;gitrestore会清除暂存区的修改内容,例如修改了test。vue,会变为未修改时的内容;当执行gitrmcached命令时,会直接从暂存区删除文件,工作区则不做出改变。5。保存远程时输入的账号密码
在gitbash里输入命令:gitconfigglobalcredential。helperstore
然后执行git操作,输入一遍密码后就会记录密码,以后就不用输入了。
要更改记录的用户名和密码,只需要更改用户目录下的。gitcredentials文件即可。6。移除文件的版本控制还没有gitadd,在。gitignore中添加已经gitadd,先gitrmrcached文件,然后在。gitignore中添加已经加到版本控制中,先gitrmrcached文件,然后在。gitignore中添加,最后gticommitm提交。gitignore7。Git问题解决记录gitconfigglobalcredential。helperstore,解决SSl连接错误克隆一个指定目录:https:blog。csdn。netconstantrainarticledetails1249134078。Github常规目录说明:dist是指编译后的文件,可以理解为压缩发布版src源码文件,适合动手能力强的童鞋docs文档examples示例文件test测试脚本。gitignore告诉git哪些文件不要上传到GitHub,比如数据库配置文件等LICENSE。txt授权协议README。md自述文件,整个项目的简介、使用方法等bower。jsonBower包管理器配置文件package。jsonnpm包管理器配置文件
设置某个分支的权限(保护分支)
1。管理员身份登录GitHub,找到项目
2。SettingsBranchesProtectedbranchesChooseabranch。。。,选择需要保护的分支,然后点击edit按钮,
3。Branchprotectionfor所选的分支名勾选RestrictwhocanpushtothisbranchPeopleandteamswithpushaccess
若不选择任何人,则任何人都没有push代码到该分支的权限。9。git做不到一个文件一个分支有一个分支没有
例如一个数据库配置文件,本地和线索不一样,把它从暂存区拉出来,取消追踪变成deleted状态,本地文件实际还存在,同步到分支,远程分支当前版本已经没有这个文件了。10。Git拉取指定分支gitclone仓库地址默认master分支gitcloneb分支名仓库地址指定分支11。git常见的输出内容已经提交的改变Changestobecommitted:暂未提交的改变Changesnotstagedforcommit:常见状态deleted、modified12。报错nonfastforwardnonfastforward
Dealingwithnonfastforwarderrors:(Fromtimetotimeyoumayencounterthiserrorwhilepushing)
Topreventyoufromlosinghistory,nonfastforwardupdateswererejected。Mergetheremotechangesbeforepushingagain。Seethenonfastforwardsectionofgitpushhelpfordetails。
Thiserrorcanbeabitoverwhelmingatfirst,donotfear。Simplyput,gitcannotmakethechangeontheremotewithoutlosingcommits,soitrefusesthepush。Usuallythisiscausedbyanotheruserpushingtothesamebranch。Youcanremedythisbyfetchingandmergingtheremotebranch,orusingpulltoperformbothatonce。
Inothercasesthiserrorisaresultofdestructivechangesmadelocallybyusingcommandslikegitcommitamendorgitrebase。Whileyoucanoverridetheremotebyaddingforcetothepushcommand,youshouldonlydosoifyouareabsolutelycertainthisiswhatyouwanttodo。Forcepushescancauseissuesforotherusersthathavefetchedtheremotebranch,andisconsideredbadpractice。Whenindoubt,don’tforcepush。
以上时较为官方的解释,简单说就是push之前需要先同步远程版本。pull会自动合并,所以要改为fetch手动合并;问题分析
可以这样理解这个问题就是:别人上传到远程仓库后,你没有及时的同步(、拉取)到本地,但是你同时又添加了一些内容(提交),以致于你在提交时,它会检测到你之前从远程仓库拉取的时候的仓库状态和现在的不一样。于是,它为了安全起见拒绝了你的提交(然后就报了这个错误)。
不能快速前进的原因是因为路不一样了,变得不好走了;体现在git里面就是提交历史出现分叉,主线不再是一条直线,而是在前端出现了分叉,git不知道该如何前进,所以报错了,让你来觉得走哪条路!说的简单点,就是远程仓库和本地仓库不同步了解决问题
1。先合并之前的历史,再进行提交提倡使用
先把git的东西fetch到你本地然后merge后再push,(如果有冲突就要解决冲突后再合并,冲突问题比较复杂,这里就不详细说了),这样就可以使远程仓库和你本地仓库一致了,然后就可以提交修改了。gitfetchoriginmastergitmergeoriginFETCHHEAD提示:这2句命令等价于,但是使用gitfetchgitmerge更加安全。gitpulloriginmaster然后执行,重新定基,可以使得历史更加统一,即提交历史趋向于一条直线。gitpullrebaseoriginmaster
2。丢弃之前的历史,强推(谨慎使用)
利用强覆盖方式用你本地的代码替代git仓库内的内容,远程仓库的东西会被本地仓库覆盖!!!gitpushf或者gitpushforce
官方文档提示:Thisflagdisablesthesechecks,andcancausetheremoterepositorytolosecommits;useitwithcare。(即:此标志禁用这些检查,并可能导致远程存储库丢失提交;小心使用。)
不仅在此处,在平时使用时,也要非常注意,除非你真的是想覆盖远程仓库,不然最好不要强制执行。13。彻底清理历史版本
先创建一个分支,添加所有文件,删除其他所有分支。14。回退远程仓库的版本
先把远程仓库指定分支拉下来,手动回退,然后再强制推送上去(拉回来的远程版本库同时带了这个分支的所有历史版本);Gitee和Github1。查看fork的子仓github点击Insightsforkgitee点击fork边上的数字2。保护分支github默认只有分支创建者和仓库管理员有push的权限,其他人可以提交PRgitee需要自己设置分支为保护分支,并在保护分支的设置内设置相应的保护级别和权限。github可以邀请别人成为协作者,个人仓库的协作者可以拉取(读取)仓库的内容并向仓库推送(写入)更改。