这篇使用讲解主要针对,本地仓库和远程仓库之间的一些使用。
在讲解开始前,首先你得拥有一个本地仓库,进入你的项目文件夹,而后用git bash或者你的shell执行git init
你便得到了一个本地仓库。
本地仓库的空间
git的本地仓库有三个概念:工作区、暂存区和版本库。
我们知道本地仓库除了我们能看到的文件以外,还有一个.git目录,我们能看到的这些文件就是我们的工作区,而.git就是git的版本管理得以存在的根本,称之为版本库。
版本库中有一个index文件,那就是暂存区。
还有一个objects文件夹,里面存放了不同版本的文件。
git还有一个分支的概念,分支相关文件在.git/refs下,每个分支中可能存在若干个版本,而当前使用的版本则有一个head指针指向,head文件在.git/refs/heads下,虽然叫做指针,但其实就是对应版本的哈希值。
哈希值对应的版本可在.git/objects中找到,哈希值的前两位是文件夹名字,后38位是对象名字。
首先,当前工作区会对应于某一分支,当我们在工作区对文件进行了修改以后,可以通过git add
命令来将修改从工作区提交至暂存区,再通过git commit
命令来提交至对应的分支下,具体来说是提交至obejcts并修改head的方式,至此我们就在该分支下得到了一个新版本。
你肯定很好奇分支中到底有哪些版本,git log
可以满足你,而标有head的版本就是当前版本了。
tips:
分支的查看:1 git status
2 git log
3 .git/HEAD文件
#常用命令的意义
git add <file> //将修改从工作区提交至暂存区
git commit -m "description" //将暂存区文件提交至对应分支并
git checkout <hash> //将head指向对应的hash,并创建一个该hash的临时分支,并把该hash对应的commit拷贝至暂存区
git checkout -- <file> //将已修改未提交至暂存区的文件恢复
git checkout <branch> //切换至对应分支
git fetch //从远程仓库获取远程仓库中每个分支的最新版本的哈希值
git merge branch //将后一个分支和当前分支所有的版本合并到当前分支,并创建一个新版本作为当前分支的head,用以记录合并变化的信息
git pull //相当于远程的merge,不过是每个分支与从远程仓库的分支进行合并
git diff //比较工作区与暂存区
git diff --cached //比较暂存区与最新版本
git diff HEAD //比较工作区与最新版本
git branch //查看本地分支,-a参数可同时查看远程分支
git branch <name> //创建<name>分支
修改的撤销
add了多余的文件
git reset HEAD
会恢复暂存区,且保留工作区的修改
修改后未提交至暂存区
git checkout -- <file>
从暂存区提取文件
修改后已提交至暂存区或对应分区
先使用git log
找到分支前一版本或某一你需要的版本的哈希值
再通过git checkout <hash> <file>
从某一版本中取出对应的文件
或者通过git reset <hash>
直接获取某一版本的所有文件,该操作会消除所有该版本以后提交的版本,慎用
一些猜想:
当checkout未指定hash值或者分支的时候,默认是从暂存区获取文件
分支名字可以代指分支最新版本哈希值
不成熟的小建议
1.多用git status查看当前情况
2.进行文件恢复之前,用diff查看变化情况
3.多用diff,merge以后,checkout之前,总之变更之前,不确定,就用diff和status看一下
4.尽量不要reset,失去部分版本,你永远不知道会发生什么
5.即使只在本地,也建议使用一个本地仓库,另外一个文件夹作为远程仓库
远程仓库(git服务器)的建立
首先,你得有个项目文件夹
其次,你应该把它git init为本地仓库,进入项目文件夹后执行如下指令
git init
接着,你要得到一个裸仓库,这个裸仓库就是你远程仓库的雏形
git clone --bare <git本地仓库文件夹> <xxx.git>
你会得到一个xxx.git的文件夹,称之为裸仓库,然后你就可以把它放置于某个你能访问到的地方,通过ssh或者直接指定目录(本地)
最后,你只需对你的本地仓库依次git add
git commit
git push
就ok了,其中git push
需指明地址,第一次的话还需指明分支,它看起来是这样的:
git push --set-upstream <address> master
文件追踪
git对版本的管理是类似于增量方式的。
文件
git中会对commit的文件进行跟踪,如果该文件被改动了,那么你在commit之间切换之后,对应的文件也会进行变动。
文件跟踪是从commit之后开始的,举个例子,如果你新建了一个文件,但是该文件还尚未commit,那么此时无论你怎么在各个commit之间切换,该文件都不会丢失。(前提是该文件为“新文件”,如果与某个commit中文件重名,自然会被影响)
目录
那么在目录下呢?
如果你在某个commit(记为0号)下新建了一个目录,并在其中创建了一个文件A,然后commit(得到1号commit),之后你再在该目录下新建一个文件B。记住,0号commit里面是没有这个目录的,而1号commit里面有目录,有文件A,无文件B。
如果此时,将head切换到0号commit,你会发现,此时目录依然存在,里面没有A文件,却有B文件,也就是说,当目录下有未被跟踪的文件时,无论如何切换commit,该目录都不会丢失,但是该目录下的被跟踪的文件依然会受影响。
git对于一些冲突的处理方式
首先,假定有一远程仓库,然后两方clone之后,进行下述操作。这里主要是说明修改同一文件的情况,不同文件是没有担心必要的。
情况一:修改同一文件后,一方已经push,另一方未add,直接pull
会提示erro,让你移除相关文件后再merge
情况二:修改同一文件后,一方已经push,另一方已add,未commit,然后pull
同样提示error,会让你commit之后再pull
情况二:修改同一文件后,一方已经push,另一方已commit,然后pull
会将现在的commit和pull下来的commit之后,将两个commit merge为新的commit,并记录相关信息
注意:此处为merge,如果两个commit的历史上没有相同的commit的话(比如本来是个空仓库,两边clone后创建同名文件,然后add commit push),会认为是不相关的commit,因而会被拒绝merge,这种情况只有先删除当前的commit,然后才能pull。
小结
对于修改同一文件的情况,不用担心当前未add或者未commit的内容会被pull的内容覆盖,可以放心大胆的在自己喜欢的时候pull,如果发现不能pull,建议先add commit之后,再进行pull,这样既可以保证冲突的commit不消失,也可以用merge的新commit记录下相关信息。
对于修改不同的文件的情况,更不用担心,同样可在任何自己喜欢的时候pull,但是建议是在add或者commit之前pull,因为这样可以避免merge到新commit的情况,不用担心丢失文件,也不会多产生一个commit。