git的常用操作(三)
http://blog.51niux.com/?id=148 这里已经搭建好gitlab服务器了,这里就直接操作向这个服务器来提交。
注:这里的二、三部分命令顺序是借鉴着廖雪峰老师的博客:https://www.liaoxuefeng.com/ 的git教程写的,可以直接飞去这里了解,我这里 就是做个操作命令记录,方便日后查阅。
一、git的常用操作
1.1、创建版本库并提交
$ git --version #查看一下git的版本
git version 2.13.1.windows.2
$ git config --global user.name "wangshuai" #告诉git当前的用户名
$ git config --global user.email "wangshuai@51niux.com" #告诉git当前的邮件地址
$ mkdir demo #demo就是创建的git库的根目录,又称工作区。
$ cd demo/
$ git init #初始化版本库,此目录下隐藏的.git目录就是Git版本库(又叫仓库,repository)
$ echo "Hello" >> test.txt #创建一个文件
$ git add test.txt #将这个新文件添加到版本库,但是一般使用git add . 或者git add *,这样多文件多目录就都添加到版本库了。
$ git commit -m "one commit" #将此次添加代码仓库。-m后面是提交说明
$ git log #可以查看提交日志,结果里面commit后面会跟着一个很长的字符串ID版本号,我们就取前7位就可以了,就可以实现版本回滚等操作
$ git log --stat #可以查看每次提交的文件变更统计
$ git reflog #记录所有操作的版本号
1.2 git的状态查看
$ git status #可以查看当前状态
$ git rev-parse --git-dir #显示版本库.git所在的位置
$ git rev-parse --show-toplevel #显示工作区的根目录
$ git rev-parse --show-cdup #显示从当前目录退回到根目录的深度
1.3 git中的版本库,暂存区和工作区
图中左侧为工作区,右侧为版本库。在版本库中标记为index的区域为暂存区,标记为master的是master分支所代表的目录树。
工作区(Working Directory):就是你在电脑里能看到的目录,比如我们上面创建的demo目录。
版本库(Repository):工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
objects 标识的区域为 Git 的对象库,实际位于.git/objects目录下。
暂存区跟踪记录了工作区的文件名和文件状态(修改时间,文件大小等信息)。
图中的HEAD是一个指向最新commit的引用,可以通过版本回退的方式改变HEAD的指向。
执行git add会更新暂存区(stage)的目录树,同时将工作区的文件内容生成一个对象放入objects对象库中,在暂存区记录了该对象的索引index。
执行git commit会更新版本库的目录树,commit成功后版本库指向的目录树就是暂存区的目录树。因为我们创建Git版本库时,Git自动为我们创建了唯一的一个master分支,所以,现在,git commit就是往master分支上提交更改。
简单的说就是add式将修改的东西从工作区放到stoge(暂存区),commit将提交更改,实际上就是把暂存区的所有内容提交到当前分支,所以add之后修改的东西,commit是不会提交的,只是将暂存区的内容提交。
1.4 暂存区和目录树的命令查看或操作
$ git ls-tree -l HEAD #使用了git底层命令ls-tree来查看,-l显示文件的大小。HEAD(版本库中当前提交)指向的目录树。
100644 blob 417cacb35ecdfb24555b61fedd922726568bc305 12 test.txt 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 test2.txt 040000 tree c25f00bc9034941236fdabe8cf411fd0918e437e - testdir
#第一列字段(前两个是文件,第三个是个目录),后面是文件的权限文件权限是644。
#第二列字段前两个说明是blob对象(文件),而tree说明是目录
#第三列字段则是该文件在对象库中对应的ID(40位的SHA1哈希值格式的ID)。
#第四列字段是文件的大小。
#第五列字段是文件名或者目录名。
$ git ls-files -s #显示暂存区的目录树
$ git diff #工作区和暂存区的比较
$ git diff --cached #暂存区和HEAD的比较
$ git diff HEAD #工作区和HEAD的比较
$ git diff HEAD -- test.txt #可以单独查看某个文件的区别
$ git checkout -- test2.txt #这里就是撤销test2.txt文件add之后的所有操作,也就是让这个文件回到最近一次git commit或git add时的状态,如果不加-- 就变成切换到某个分支了。
$ git reset HEAD test2.tx #如果test2.txt只是将修改add到了暂存区,可以通过这个命令将修改从暂存区放回到工作区。
$ git rm 文件名 #多个文件名 空格隔开,这个才是删除git里面文件的正确步骤然后再commit,用rm只是工作区的文件没有了,暂存区里面还是有的。
博文来自:www.51niux.com
1.5 版本回退
$ git log #git log命令显示从最近到最远的提交日志,我们可以看到3次提交,都有Date时间显示的
commit 0835649c3ecdca9741dbbc579544d2f869507593 (HEAD -> master) Author: wangshuai <wangshuai@51niux.com> Date: Sun Jul 23 16:09:06 2017 +0800 commit update three commit 3e0584436c5b518321abde7f8a4f7bc36ad8da9b #这里是commit id号,而我们只需要取前7位 Author: wangshuai <wangshuai@51niux.com> Date: Sun Jul 23 15:34:55 2017 +0800 commit update agin commit 479585abfe042229c996796c74db6568d60a04a0 Author: wangshuai <wangshuai@51niux.com> Date: Sat Jul 22 23:48:19 2017 +0800 one commit
$ git log --pretty=oneline #可以只显示commit id号,输出简化一点,然后从上到下,最上面是最近一次改动,以此类推
$ git reset --hard HEAD^ #HEAD表示当前版本,上一个版本是HEAD^(或者直接指定id号如3e05844 ),上上版本就是HEAD^^,再多就指定commit id号吧。
$ git log --pretty=oneline #再查看一下,最新的版本已经发生了变化
#现在如果又想变回原来的哪个版本,但是你现在用git log已经找不到哪个版本号了,你又没有记录之前的版本号是什么。
$ git reflog #reflog记录git的每一次命令
$ git reset --hard 0835649 #就又倒退回去了,就是让HEAD指针指定版本号,一般都是指定当前的版本号
1.6 和远端的版本库连接
首先登陆我们创建的gitlab:192.168.1.121,创建一个demo版本库:git@192.168.1.121:wanghai/demo.git
然后因为我们已经操作很多了,所以不能用git clone的形式的,正好用另外一种形式
$ git remote add origin git@192.168.1.121:wanghai/demo.git #添加远程仓库,origin就代表了后面的链接
$ git remote -v #可以查看一下,如果没有推送权限,就看不到push的地址。或者通过$ cat .git/config看一下 #git remote rm origin 这是删除远程的git仓库
$ git add .
$ git commit
$ git push -u origin master #把当前的master分支提交给origin,其实就是提交到origin后面所代表的远程url。由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
#从上图中可以看出,已经将本地创建的一些东西推送到远端的仓库里面去了。
#再有修改啥的,因为现在是我们自己一个人玩,设计不到合并什么的东西,直接$ git push origin master就可以了,不用再去合并分支什么的了。
1.7 Git fetch和git pull的区别
Git中从远程的分支获取最新的版本到本地有这样2个命令:
git fetch:
相当于是从远程获取最新版本到本地,不会自动merge
git fetch origin master #首先从远程的origin的master主分支下载最新的版本到origin/master分支上 git log -p master..origin/master #比较本地的master分支和origin/master分支的差别 git merge origin/master #最后进行合并
当然也可以用下面的这种写法:
git fetch origin master:tmp git diff tmp git merge tmp
git pull:
相当于是从远程获取最新版本并merge到本地
git pull origin master #其实相当于git fetch 和 git merge
在实际使用中,git fetch更安全一些,因为在merge前,我们可以查看更新情况,然后再决定是否合并
博文来自:www.51niux.com
二、分支管理
2.1 创建分支与合并
$ git checkout -b dev #创建dev分支,然后切换到dev分支,-b 参数表示创建并切换,相当于下面两条命令:
$ git branch dev $ git checkout dev
#我们在创建dev分支,一个新的指针指向了dev,如果切换到dev分支,HEAD就指向了这个指针。
$ git branch #查看当前的分支
#从图中可以看到列出了所有的分支,当前分支是dev分支,当前分支前面会有一个*
$ vim test2.txt #编辑此文件新加一行“creating a new dev ranch”
$ git add test2.txt
$ git commit -m "dev branch test"
$ git checkout master #切换回master分支
$ cat test2.txt #再查看一下,发现没有新加的那句话
$ git merge dev #git merge命令用于合并指定的分支到当前的分支
#注意标红的地方,这是“快进模式”的合并.也就是直接把master指向dev的当前提交,所以合并速度非常快。
$ git branch -d dev #可以选择删除dev分支,下次再要改东西的时候再创建一个dev分支再去写完测试没问题了再合并到master分支上。
注(如果你dev分支commit了,但是还没有合并,这时候要删除dev分支):
$ git branch -d dev
#如上图所示,是删除不了这个分支的,上图中也有提示
$ git branch -D dev #就强制删除了这个dev分支了。
2.2 解决合并时候的冲突
git的分支很强大,分支开发难免合并的时候遇到冲突的时候,记得13年接触git,那时候不是我管理,是一个开发来管理这套系统就经常解决冲突问题。
下面用一个小例子来演示一下分支冲突:
$ git checkout -b dev #创建并切换到dev
$ vim test #写一句话
$ git add test.txt
$ git commit -m "dev commit"
$ git checkout master
#上图是Git还提示我们当前master分支比远程的master分支要超前1个提交。
$ vim test.txt #在master分支上也有test.txt添加一句话
$ git add test.txt
$ git commit -m "master commit"
现在,master分支和dev分支各自都分别有新的提交,变成了这样:
$ git merge dev #将dev合并到当前的分支master。
#这种情况下,Git无法执行“快速合并”,但这种合并就可能会有冲突只能试图把各自的修改合并起来。上面是告诉我们test.txt有冲突。
$ git status #也可以看到冲突的状态,会有一些详细的提示
$ cat test.txt #查看下文件可以直接看到冲突的地方
#Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们可以根据冲突的内容的上下位置也可以看到,====上面是master的内容,也就是当前分支的内容,下面是dev分支的内容,而且它下面还有>>>>>>>dev标记呢。
$ cat test.txt #那就手工的去修改一下文件的内容,将master添加的内容去掉。
$ git add test.txt
$ git commit -m "commit dev and master" #再提交
$ git merge dev #再合并会提示你已经是最新的了不用合并了
现在,master分支和dev分支变成了下图所示:
$ git log --graph --pretty=oneline --abbrev-commit #可以查看分支的合并情况,git log --graph可以查看分支合并图
注:合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。如:$ git merge --no-ff -m "merge with no-ff" dev #--no-ff参数,表示禁用Fast forward,通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息
当然gitlab上面也可以查看:
#注意上面那条红线的每个红点,鼠标放在上面可以看到每次commit的ID。
2.3 需要解决bug的时候
如果你正改着内容呢,在dev分支上,现在有个master的bug需要你处理,master应该是稳定版的,不应该在master上面进行修改,你应该保证本地工作区是干净的没有任何修改,不然你就算创建了分支,也会把dev分支上面未修改的东西给带过来,就算提交也会把dev上面未写完的东西提交。
解决上面的问题有两种方法:
第一种方法:
$ vim test.txt #比如现在又在test.txt里面写了一句话,但是我们还么写完不想提交呢
$ git status #会提示你工作区并不是clean状态,有文件更改了
$ git stash #将更改未提交的内容放到一个临时区域
$ git checkout master #切换回master分支
$ git checkout -b bug-101 #创建一个bug-101分支并切换到此分支上
$ vim test2.txt #如test2.txt就是要解决Bug的文件,现在改完了
$ git add test2.txt
$ git commit -m "fix bug 101"
$ git checkout master
$ git merge --no-ff -m "merged bug fix 101" bug-101
$ git push -u origin master #bug解决了也提交了
$ git checkout dev #切换回dev分支继续解决自己没解决的问题吧
$ git stash list #可能有多个分支,都存了临时区域,就不止会有一条,看看刚才放到临时区域的修改内容在哪个位置
$ git stash apply stash@{0} #这就是指定来恢复,当然$ git stash apply 是恢复最近保存的临时工作状态,也就是恢复stash@{0}
$ git stash drop stash@{0} #当然你都恢复了,就不想临时工作区再保存着了,就通过这个命令来删除,当然$ git stash drop是删除找到的第一个。
$ git stash pop stash@{0} #是上面两条命令的结合,既恢复了临时保存的修改,又将临时工作区里面的记录删除掉。
第二种方法:
就是把修改的先commit提交一下了。
注:
dev分支一般是开发分支,一般不会像我操作这样老是删除掉的,master分支是最稳定的分支一般不会老是去跟它合并的,都是其他的开发人员自己的分支跟dev分支合并,然后测试没有问题了,再让dev分支去跟master分支合并。
$ git push origin dev #push后面跟着prigin远程库地址,然后最后指定分支,就是将哪个分支也推送到远程主机仓库。
博文来自:www.51niux.com
三、标签管理
打标签发布代码,是代码上线上面一个很长说的一个口头禅。你看github上面也有很多tags告诉你版本号。
3.1 创建标签
$ git checkout master
$ git tag v1.0 #给当前打一个v1.0的标签
$ git log --pretty=oneline --abbrev-commit #如果以前有的commit忘记打标签了,先将历史查出来
$ git tag v0.9 5a1ae90 #指定commit的id号来打标签
$ git tag #查看标签,标签不是按时间顺序列出,而是按字母排序的。
$ git tag -a v0.8 -m "version 0.8 released" a17c2f7 #可以对标签做注释
$ git show v0.8 #可以查看标签的具体信息
3.2 操作标签
$ git tag -d v0.8 #删除标签,如果创建的标签都只存储在本地,没有推送到远程,可以在本地安全删除(一般是新打的标签)。
$ git push origin v1.0 #推送某个标签到远程
$ git push origin --tags #可以把本地的标签一次性的全推送远程。
如果打的标签已经推送到了远程,就要执行下面的操作:
$ git tag -d v0.9 #现在本地删除标签
$ git push origin :refs/tags/v0.9 #从远程删除标签
注(忽略特殊文件):
忽略特殊文件.gitignone
在根目录下创建一个$ vim .gitignore 文件
#在过滤文件生效之前的文件,以后也不会生效,只有当前过滤设置之后的新文件,才有效。