Git中~你必须掌握的!

前言:

大佬直接进入下面正题,前言能够略过!git

我相信有不少童鞋在刚开始使用git或者使用了许久以后仍是对git不怎么熟悉,尤为是出现了一大堆英文提示的时候手足无措,又或者代码"莫名其妙"的发生改动,致使团队没法继续正常工做的时候真巴不得不继续使用git了.github

不要慌!这篇文章将带你完彻底全掌握平时常见的场景以及出现的问题如何解决的本领!(同时我本身也能够再复习一遍~🤭)shell

那么本文章默认你已经学习过了git,但只是对git有的知识只知其一;不知其二的状况下去阐述!(也许热爱git的你还不熟悉git基础知识建议能够先去其余地方学习git相关的基础知识,遇到不理解的也许这篇文章就会帮你解开谜团!)bash

最小配置

那么咱们会发如今使用git以前须要配置一段这样的命令(若是不配置之后push之类的操做会有一大堆提示信息影响咱们的后续操做):app

$ git config --global user.name 'your_name'
 $ git config --global user.email 'your_email@domain.com'
复制代码

那么这段命令中的--global你们有没有想过是什么意思呢?究竟有什么做用?dom

config三个做用域

来说下刚刚的--global(全局),那么既然有全局就确定有局部做用域:在git中叫作--local,其实还有一个是针对系统的:--system学习

--global是对当前用户(根据系统用户名断定)全部仓库有效测试

--local只对当前工做的这个仓库有效fetch

--system对系统全部登陆的用户有效(不经常使用,对整个系统进行配置统一的配置项)ui

查看config的设置命令:

$ git config --list --local
 $ git config --list --global
 $ git config --list --system
复制代码

创建git仓库

把已有的项目代码归入Git管理(场景一):

$ cd 项目代码所在的文件夹
$ git init
复制代码

新建的项目直接用Git管理(场景二):

$ cd 某个文件夹
$ git init your_project #会在当前路径下建立和项目名称同名的文件夹
$ cd your_project
复制代码

文件重命名(方法一)

假设咱们重命名readme.mdread.md 因此咱们执行如下命令

$ mv readme.md read.md
复制代码

这条命令会被git认为是 readme.md会删除掉了,而后新增了一个read.md文件

咱们如今要作的是把新增的read.md文件添加到git管理里,且删除原来的readme.md文件

$ git add read.md
$ git rm readme.md
复制代码

而后使用git status查看管理状态 结果会发现如今变成了

Changes to be commited:
(use "git reset HEAD <file>..." to unstage)
    renamed: readme.md -> read.md
复制代码

至此,说明git已经知道了咱们在作重命名操做

假设如今咱们发现本身误操做了,不想要刚刚的操做了,怎么办呢?

$ git reset --hard
复制代码

其实这条命令属于git中比较危险的命令,他的意思是把暂存区工做空间里内容都清理掉(还原到刚刚操做重命名以前的状态)

文件重命名(方法二)

细心的童鞋可能发现刚刚重命名的操做过于复杂,那有没有简单的方法重命名呢?答案是:固然有!(有木有很激动)

$ git mv readme.md read.md
复制代码

而后使用git status查看管理状态 结果会发现如今也变成了

Changes to be commited:
(use "git reset HEAD <file>..." to unstage)
    renamed: readme.md -> read.md
复制代码

这样一句命令就完成了方法一完成的事情,是否是很简单呢~ 那么咱们想提交本次操做该怎么作呢? 咱们能够直接使用

$ git commit -m '重命名readme.md为read.md'
复制代码

咱们发现如今已经成功的新生成了一个commit记录

那么咱们忽然发现此次commit没什么做用想撤销本次commit提交该怎么作

$ git log #查看全部commitId
$ git revert <commit> #找到你想撤销的commitId复制并替换掉这里的<commit>
复制代码

commitId是相似这样的:

删除暂存区文件(并不会直接删除工做区的文件)

$ git rm 文件名
复制代码

暂存区相关

$ git rm --cached . #清理暂存区全部文件
复制代码

git log

经过git log查看版本演变历史

其实git log后面还能够携带参数

$ git log --oneline --all #能够查看简洁的全部commit信息
$ git log -n4 #表明查看最近四次的commit信息
$ git log --all --graph #查看基于图形的commit历史记录
$ git log --oneline <branch> #查看某个分支的commit记录
复制代码

分支操做

$ git branch -av #查看本地共有多少分支
$ git checkout -b temp #建立一个新的temp分支
$ git checkout -b temp <commitId> #基于某一个历史版本新建一个分支 
复制代码

删除分支

$ git branch -d 分支名
复制代码

若是git有提示说明是在一些状况下git不容许删除,若是确认的确须要删除,那么能够把小写d改为大写D来强制删除

图形界面(git自带)

gitk
复制代码

打开后也许会是这样

固然我们能够借助第三方的软件,确定比git自带的使用更加方便快捷,由于这篇文章重点偏向命令式操做,因此这里就不过多介绍了

分离头指针(detached HEAD)

有时候咱们会作出以下操做

$ git checkout 415c5c8086e16 #后面的随机字符串指的是某一次的commitId
复制代码

这时git会给咱们出现相似下面的提示

what? 这段话大概是在说:

你正在基于415c5c8086e16这个commit正在作一个checkout的操做。 你如今正在处于分离头指针的状态,你能够作一些变动,产生一些commit,或者你也能够把你本身生成的这个commit丢弃掉,或者你能够继续作开发,并不会影响其余分支! 那么说的明白点就是:

咱们如今正工做在没有分支的状况下,那么就是说如今没有branch跟它挂钩对应,那么若是当咱们在这种状况下作了一些功能的开发后又切换到了其余分支后,最后极可能会被git当作垃圾清理掉,因此这就是分离头指针危险的地方!

但话又说回来,事物都具备两面性,用的很差或者在不知情的状况下使用确定会对咱们产生危害,但假设咱们知道的他会有什么影响后,说不定多想一想,还可能会带给咱们好处呢。

好处场景举例:有时候变动只是尝试性的变动,若是作出来感受很差或者不想要了,那咱们就能够随时把它扔掉(直接checkout到其余分支,不理会他,过段时间就会自动被git清理掉)!那假设咱们坐下来感受还不错,那么咱们就可使用

$ git commit -am '提交信息' #这条命令意思是直接生成commit不用add,但不推荐
复制代码

咱们提交后,准备使用git log看下commit记录,而后就会发现一件奇怪的事情发生:

咱们仔细看下图片,右边只有一个HEAD,正常状况下,HEAD总会跟一个分支挂钩,但如今怎么没有分支啦? 说明如今咱们还处于分离头指针状态!

咱们如今尝试切换一下分支到master分支!

切换后git可能会出来以下提示

它说有一个commit在后面尚未加到master分支里面去,那么这个其实就是分离头指针致使的!

而后下面它还会再次提醒你,若是你想保存此次的commit记录,那么你能够新建一个分支和这个3d4731d这个commit相关联!

若是你看都不看一眼这个提示,继续任性的往下随心操做,那么你刚刚在分离头指针状态下作的操做会通通丢掉!因此git的提示要多看

比较两个commit之间的差别

$ git diff commitId1 commitId2
$ git diff HEAD HEAD~1
$ git diff HEAD HEAD^
复制代码

**HEAD能够指代最新的commit记录

^是指最新的commit的上一个commit

^^就是指上上一个

~1也是指上一个 ~2就是上上一个

因此这三条命令效果是同样的**

commit相关操做

修改最新commit的message

有时候咱们提交的commit了发现描述的信息不全面,想进行修改,那么咱们可使用下面这条命令

$ git commit --amend
复制代码

而后git会弹出一个新界面,让咱们调整以前的message,修改后咱们可使用:wq!来保存这个新修改的message而且退出这个窗口

修改前几回的commit的message

咱们先来看张图

这里咱们用到了 git中的 变基指令 那么本次咱们想对图中标2的commit的message进行变动,那么咱们该怎么作? 这里强调下,参数i是 指交互式变基就是指会弹出窗口让咱们更方便操做的方式进行 变基 还有就是 被变基的commit的commitId会发生改变哦!

重点来喽 这里咱们须要选择一个,咱们此次要变动第二个commit,那么这个基就要选择被变(第二个commit)的这个commit的父级(第三个commit),父级的commitId是(27d2f814开头的那个),本身的commitId是(429243060b开头的那个),因此要基于父级(27d2f814开头的那个commit)去作变基操做!

这块比较绕,你们本身先捋一捋

接下来看命令操做!

$ git rebase -i 27d2f814
复制代码

敲下回车后咱们发现弹出来了一个交互式的窗口 如图:

咱们把4292430开头的那个commitmessage修改为 Add a refering projects

因此咱们把pick指令改为reword指令

因此最终交互式窗口里的内容就会被咱们修改成

$ reword 4292430 Add refering projects #这里咱们只把刚刚的pick修改成了reword
$ pick a7dc188 Move filename readme.md to readme #本句能够无视,本例中只修改了第一句
复制代码

修改完毕后咱们使用:wq!保存并退出交互式控制台 而后接着git又会弹出另外一个新窗口

那么咱们在这里把Add refering projects修改成Add a refering project

修改完毕后咱们使用:wq!保存并退出交互式控制台 而后git会作出以下提示:

说明咱们的变基操做顺利完成了

变基操做实际上是用到了分离头指针去完成的, 其实git先分离头指针,而后在上面作了调整,调整完毕后git还把新的commit产生后用一个指针指向了它!

但这里须要注意:这只是本地的变基行为,若是有多人已经在线上操做正式项目,切不可盲目用该命令随意操做,否则后果很严重!

差别比较

暂存区和HEAD差别比较

说白了就是add后的文件和最新commit作比较

$ git diff --cached
复制代码

工做区和暂存区的差别比较

说白了就是本身最新写的代码和add里的对比

$ git diff -- 文件名
$ git diff #比较全部工做区和暂存区的差别
复制代码

对比不一样分支的相同文件的差别

$ git diff 分支一 分支二 -- 文件名
复制代码

恢复相关

暂存区恢复为和HEAD(最新的commit)的内容同样

有时候咱们add后忽然发现咱们不要暂存区的东西了,因此就要使用到以下命令了

$ git reset HEAD 或 git reset HEAD -- 文件名 #(若是没有写文件名就是所有恢复)
复制代码

暂存区工做区都恢复为和HEAD(最新的commit)的内容同样

$ git reset --hard HEAD 或 git reset --hard HEAD -- 文件名 #(若是没有写文件名就是所有恢复)
复制代码

这里补充说明下 --hard表明的是工做区

工做区的文件恢复为和暂存区的同样

有些时候作了一些变动,咱们已经把这部分的代码放到了暂存区,而后咱们又继续在工做区作了一些变动,作完以后,思前想后,发现工做区的变动还不如暂存区的好,因此咱们就但愿把工做区的内容扔掉,变成和暂存区的如出一辙。

$ git checkout . #丢掉工做区所有的变动
$ git checkout -- 文件名 #丢弃这个文件的变动
复制代码

这条命令也要慎用!一旦误操做,工做区最新的代码也就丢失啦!

stash

有时候咱们正在写代码,忽然加派紧急任务,要修改其余地方的bug,但咱们又不想提交正在修改的,因此咱们就须要是使用一个命令把当前的状态临时保存起来

$ git stash #存储
$ git stash list #查看存储好的stash
复制代码

存储好以后咱们会发现工做区变成了干净的了。 那么假设咱们的bug已经修改好了,咱们想回到刚刚存储前的状态继续作以前咱们作的事情,该怎么办?

$ git stash apply #把stash里面的东西取出来放到工做区,且他不会删除stash里的记录
$ git stash pop #把stash里面的东西取出来放到工做区,但他会删除stash里的记录
复制代码

以上两个命令随便挑选一个使用均可以恢复,看状况而定

.gitignore

咱们只须要在项目中新建一个名字为:.gitignore的文件 咱们能够在.gitignore里配置本身想exclude(排除)的文件或文件夹。

远程相关

这里默认你们都会创建远程仓库,还不会的童鞋能够先去学习学习!

git push origin 分支名把本地的某个分支推送到远程仓库

git push origin -d 分支名 # 用 -d 参数把远程仓库的分支也删了

假如是某个你本身独立开发的branch 出错了,出错的内容已经合并到 master 同事的工做都在 master 上,你永远不知道你的一次强制 push 会不会洗掉同事刚发上去的新提交。因此除非你是人员数量和行为都彻底可控的超小团队,能够和同事作到无死角的完美沟通,否则必定别在 master 上强制 push

在这种时候,你只能退一步,选用另外一种策略:增长一个新的提交,把以前提交的内容抹掉。例如以前你增长了一行代码,你但愿撤销它,那么你就作一个删掉这行代码的提交;若是你删掉了一行代码,你但愿撤销它,那么你就作一个把这行代码还原回来的提交。这种事作起来也不算麻烦,由于 Git 有一个对应的指令:revert

它的用法很简单,你但愿撤销哪一个 commit,就把它填在后面:

$ git revert HEAD^
复制代码

上面这行代码就会增长一条新的 commit,它的内容和倒数第二个 commit 是相反的,从而和倒数第二个 commit 相互抵消,达到撤销的效果。

revert完成以后,把新的 commitpush 上去,这个 commit 的内容就被撤销了。它和前面所介绍的撤销方式相比,最主要的区别是,此次改动只是被「反转」了,并无在历史中消失掉,你的历史中会存在两条 commit :一个原始 commit ,一个对它的反转 commit

2019年10月29日补充:

git在本地建立一个项目的过程

// git init
// git add .
// git commit -m 'first commit'
// git remote add origin git@github.xx/xxx.git
// git push -u origin master
复制代码
#git设置关闭自动换行
git config --global core.autocrlf false git config --global core.safecrlf true
复制代码

#编辑Git配置文件

git config -e [--global]
复制代码

#设置提交代码时的用户信息

git config [--global] user.name "[name]" git config [--global] user.email "[email address]"
复制代码

#从远端获取分支

git fetch origin
复制代码

#更新远程分支列表

git remote update origin --prune
复制代码

#基于远程分支建立本地分支

git checkout -b newBrach origin/master 在origin/master的基础上,建立一个新分支
复制代码

#master

master 为主分支,也是用于部署生产环境的分支,确保master分支稳定性 master 分支通常由develop以及hotfix分支合并,任什么时候间都不能直接修改代码
复制代码

#develop

develop 为开发分支,始终保持最新完成以及bug修复后的代码 通常开发的新功能时,feature分支都是基于develop分支下建立的
复制代码

#feature

开发新功能时,以develop为基础建立feature分支 feature/xx 开头的为特性分支, 命名规则: feature/login_module、 feature/user_module
复制代码

#release

release 为预上线分支,发布提测阶段,会release分支代码为基准提测

// 当有一组feature开发完成,首先会合并到develop分支,进入提测时,会建立release分支。
// 若是测试过程当中若存在bug须要修复,则直接由开发者在release分支修复并提交。
// 当测试完成以后,合并release分支到master和develop分支,此时master为最新代码,用做上线。
复制代码

#hotfix

分支命名: hotfix/ 开头的为修复分支,它的命名规则与 feature 分支相似 线上出现紧急问题时,须要及时修复,以master分支为基线,建立hotfix分支,修复完成后,须要合并到master分支和develop分支
复制代码

#增长新功能

// (dev)$: git checkout -b feature/xxx            # 从dev创建特性分支
// (feature/xxx)$: git add xxx
// (feature/xxx)$: git commit -m 'commit comment'
// (dev)$: git merge feature/xxx --no-ff          # 把特性分支合并到dev
复制代码

#修复紧急bug

// (master)$: git checkout -b hotfix/xxx         # 从master创建hotfix分支
// (hotfix/xxx)$: blabla                         # 开发
// (hotfix/xxx)$: git add xxx
// (hotfix/xxx)$: git commit -m 'commit comment'
// (master)$: git merge hotfix/xxx --no-ff       # hotfix => master,并上线到生产环境
// (dev)$: git merge hotfix/xxx --no-ff          # hotfix => dev,同步代码
复制代码

#测试环境

// (release)$: git merge dev --no-ff   dev => release
复制代码

#生产环境

// (master)$: git merge release --no-ff  release => master
// (master)$: git tag -a v0.1.0 -m '部署包版本名'
复制代码

--no-ff 会让 Git 生成一个新的提交对象。为何要这样?一般咱们把 master 做为主分支,上面存放的都是比较稳定的代码,提交频率也很低,而 feature 是用来开发特性的,上面会存在许多零碎的提交,快进式合并会把 feature 的提交历史混入到 master 中,搅乱 master 的提交历史。

总结

git经常使用的也就这么多,你们只要经常使用,记住它们不是啥大问题,你们加油!

声明:

本文全部文字纯手打,远程相关中的revert命令参考了掘金小册扔物线大佬创做的小册,其他部分都是原创!码字不易,举起小手点个赞,你的赞就是做者最大的写做动力

文中若是出现错误,请你们在评论区指正,我会及时修改!

相关文章
相关标签/搜索