Git介绍及常用命令

一、什么是git?

       百度百科对git的定义如下:git是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。
       1.什么是版本控制呢?
       版本控制是指对软件开发过程中各种程序代码、配置文件及说明文档等文件变更的管理,是软件配置管理的核心思想之一。
       举个直观的例子,假如你现在正在用记事本写一篇很长的文章,写到一半你想大幅修改或者删除某一部分,但你又怕将来想恢复。通常我们另存为一个副本,然后继续修改,有需要时再另存为一个副本。过了很久,你想恢复到之前的某一个副本,但已经记不清哪个副本是你想要的了,只能一个一个找。看着这一大堆副本,想删掉又怕以后会用到。还有时候,你需要让其他人帮你写一部分,于是你把文件发给他,然后继续编辑。几天后,他再把他修改后的文件发回给你,你得把他修改的部分和你的改动合并,想想就头痛。
       Git就是这样一个牛逼的软件,它能帮你追踪文件的变更和变更信息(什么人、改了什么文件、怎么改的文件等),还可以实现并行开发(帮助合并文件等)。
       2.集中式vs分布式
       对于CVN及SVN这些集中式版本控制系统来说,版本库是集中存放在中央服务器中的。如果还用写文章来举例的话,使用集中式版本控制系统进行版本控制时,如果你要修改一些内容,需要先从中央服务器中取出最新版本,修改完毕后再推送给中央服务器。也就是说,如果没有网络,集中式版本控制系统是无法工作的。而且一旦中央服务器出现意外,就全体爆炸。
       而以git为代表的分布式版本控制系统没有中央服务器,每个人的电脑上都是一个完整的版本库,工作时不需要联网。通过分布式版本控制系统进行多人协作就更简单了,每个人将自己的修改推送到其他人的电脑就可以互相看到所有修改了。实际使用时,很少两个人直接在电脑之间推送各自的变更,而是借助一台充当“中央服务器”的电脑,这台电脑的作用仅仅是用于和合并和交换修改,没有他依然可以工作。
       举个简单的例子:使用SVN进行版本控制时,如果没有网络是不能commit修改的。而使用git时,因为本地有完整版本库,commit命令是commit到本地仓库,即使没有网络也完全没影响,仅仅是不能push到云端而已。



二、git常用指令

       最近在学习git,整理了一下常用的git指令。先放两个网站:
       Git的中文官方文档:https://git-scm.com/book/zh/v1/
       廖雪峰的git教程:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

       开始正题,常用的git指令。
       1.git init
       把当前目录变成git可以管理的仓库。执行该指令后,目录下会多出一个.git文件,该文件是用于跟踪管理版本库的,没事不要自己修改。如果看不到.git文件也不要认为指令执行出现错误了,因为.git文件默认是隐藏的。
       2.git add <file>
       把file添加到仓库,如果执行成功则没有任何显示信息,如果出错会有错误提示。
       3.git commit [-a ]-m <“description”>
       把add进来的所有文件提交到仓库,-m后面跟的是本次提交的说明;-a的意思是将所有修改或删除的文件都提交到本地仓库。更多参数执行git commit -help查看。
       4.git status & git diff
       git status指令输出仓库当前的状态(哪些文件被修改过但还没有提交),但如果能输出具体修改了哪些内容更好了。git diff指令能以linux的diff格式输出变更(对哪些文件做了哪些修改)。
       5.git log
从最近到最远输出所有历史提交的记录,其中有三行,commit后很长的一段十六进制数是commit_id,还有作者信息和提交日期。其中HEAD表示当前版本。
       6.git reset --hard <commit_id>
       回滚到之前的某个版本,我们可以使用HEAD表示当前版本,HEAD^表示前一个版本,HEAD^^表示前两个版本以此类推,当回滚前太多版本时,可以使用HEAD~i,i表示回滚版本个数,例如回滚123个版本就是HEAD~123。
       如果回退之后,想要恢复怎么办呢,我们就要找到想要恢复的版本的commit_id,然后使用指令git reset --hard<commit_id>来恢复。
       7. git reflog
       显示git操作的历史记录,可以使用该指令来找到之前回滚掉的版本的commit_id用于恢复之前的版本。

       小结:实际上git内部有一个类似栈的数据结构记录版本信息,还有一个HEAD指针指向当前的版本(严格来说HEAD是指向当前分支的,当前分支指向当前版本,但这里可以简化便于理解)。在执行git log时,从HEAD指针开始输出;执行git reset时,只是改变HEAD指向和版本的文件内容。

       8.git checkout -- \<file>
       用版本库或者暂存区的版本替换工作区的版本,常用于撤销修改(包括删除)。如果file自从被修改(包括删除)之后还没有被add到暂存区,则撤销修改(包括删除)会回到当前版本的状态;如果file已经被add到暂存区后又被修改(包括删除),则撤销修改(包括删除)会回到add到暂存区后的状态。总之就是回到最近一次git add或者git commit时的状态。

       小结:① 如果没有将修改(包括删除)add到暂存区的情况下,想要撤销修改,则执行git checkout – 指令,因为没有添加到暂存区所以该指令使file回到最新版本状态,将修改(包括删除)全部撤销;② 如果已经将修改(包括删除)add到暂存区的情况下,想要撤销修改(包括删除),则需要先执行git reset HEAD 把暂存区的修改(包括删除)撤销掉,重新放回工作区,然后执行git checkout – ,因为此时file的修改(包括删除)已经从暂存区撤销,所以该指令将使file回到最新版本状态;③ 如果已经将修改(包括删除)commit到本地仓库的情况下,想要撤销修改(包括删除),则使用git reset --hard <commit_id>撤销修改。

       9.git rm <file>
       从版本库删除file,删除后需要commit。手动删除文件后,git rm 和git add 是等价的。
       10.git remote add origin git@service-name:yourName/repository-name.git
       该指令在本地仓库执行,将本地仓库与github远程仓库相关联,其中service-name替换成使用的服务例如:“github.com"或者"gitee.com”;yourName 替换成你的账户名;repository-name.git替换成远程仓库的名称。
       11.git push origin [-u ]<local-branch >:<remote-branch>
       将local-branch的内容push到remote-branch上,使用-u参数表示将这两个分支关联起来(添加追踪关系),这样一来之后的push或者pull操作可以省略remote-branch这一参数,git将根据追踪关系自动找到对应分支。
       12.git clone git@service-name:yourGitHub/repository-name.git
       参数含义与关联远程仓库时相同,大多数情况下通过ssh支持的原生git协议速度最快。
       13.git branch <branch> & git checkout <branch>
       git branch指令能够创建分支branch,git checkout的作用是将当前分支切换为branch,这两条指令可以合并为一条git checkout -b 。如果只使用git branch指令,不指定分支名则会显示所有分支并指出当前分支(当前分支前面会有*)。
       14.git merge <branch> & git branch -d <branch> & git branch -D <branch>
       git merge 指令将branch分支合并到当前分支(默认情况下合并模式是fast-forward,也就是直接把master指向dev,这样一来合并速度很快,合并后master的内容是dev分支的内容),git branch加-d参数的作用是删除(delete)branch分支,如果被删除的分支还没有被merge是不能用-d删除的,git会提醒你该分支还没有被合并,如果想要强行删除分支就要使用-D参数。通常情况下,为一个任务创建一个分支,完成后将该分支合并到master分支,然后将该分支删除。大部分时候,创建、合并和删除分支很快,所以git鼓励使用分支完成某个任务,合并后再删掉分支,这和直接在master上操作效果是一样的,但更加安全。

       小结:当两个分支对同一个文件进行修改时,合并时八成会出现冲突,这个时候就需要我们手动解决冲突。当出现冲突时,我们打开产生冲突的文件,在发生冲突的地点会有如下格式的内容:
           “<<<<<<< branch1
              Content of branch1
              =======
              Content of branch2
              >>>>>>> branch2”
       这部分的意思是 branch1分支下的内容Content of branch1和branch2分支下的内容Content of branch2冲突了,我们需要将该文件手动修改成我们需要的样子,然后再进行add和commit操作就可以了。
       管理分支有几个基本原则:① master分支应当是稳定的,仅用来发布新版本。② dev分支是不稳定的,是用来修改的,在新版本发布的时候把dev分支合并到master上然后在master上发布新版本。③ 每个人都有自己的分支,每个人将自己的分支合并到dev上。

       15.git stash & git stash list & git stash apply[ stash@{i}] & git stash drop & git stash pop
       当我们在工作时,一项任务还没完成,突然来了一个优先级更高的任务(以一个危险的bug为例),因为此时我们之前的任务还没完成,不能提交。所以git提供了一个牛逼的功能,能将当前现场保护起来(将它保存到一个未完结变更的堆栈中),在需要的时候将现场恢复。这就是git stash,它能将当前的工作现场存下来保护起来。然后我们可以新建一个分支解决bug并合并到master上,解决完成后我们回到原来的dev分支希望能继续工作。这时我们执行git stash list命令,可以查看所有被保护的现场。而要将现场恢复出来,我们可以执行git stash apply[ stash@{i}]指令,这里的i指的是git stash list列出的现场序列的索引(如果只使用git stash list则恢复最近一个)。使用git stash apply恢复后stash的内容并不删除,需要使用git stash drop来删除,而git stash pop在恢复的同时就会删除stash的内容。PS:git stash只能stash被追踪的或者被暂存的文件,也就是说没有add的文件是不能被stash的,所以在stash前需要将正在变更的文件add到暂存区。

       小结:为什么要使用stash,为什么不能切换到另一个分支,修改完再切换回来呢?考虑如下情景:在dev分支创建一个文件test.txt并add,切回master分支会发现master分支里也是有这个文件的,因为test.txt文件这时候还没有完成,所以修改完bug之后也不能提交bug(如果直接commit的话会将未完成的test.txt文件一起提交了)。这时就体现出stash的作用了,切回dev分支执行git stash保存test.txt的现场后再切回master会发现test.txt消失了,就可以正常修改bug了。

       16.git tag <name>[ -m “tagDescription”][ commit_id]
       给某一次commit打标签,如果没有指定commit_id则默认是最近的一次,也就是用name代替commit_id,-m参数是对标签的说明。注意这里打的标签是针对commit的,也就是说如果某一次commit出现在不同的分支,那么在所有包含这次commit的分支都可以看到这个标签。
       17.git config --global alias.<name> <command>
       这条指令的作用是给指令command配置一个别名name以简化记忆。–global参数的作用是指明该条配置是针对当前用户起作用的,如果不加–global参数只针对当前的仓库有效。
       当我们想要删除别名时,如果只是该仓库的别名,只需要找到仓库下的.git/config文件,打开找到[alias],直接删除后面的别名就可以了。如果是用户级别的别名,那么需要找到用户目录下的一个隐藏文件.gitconfig,同样找到[alias]删除后面的别名。

       例如:git config --global alias.sta status、git config --global alias.cho checkout



三、在github提供客户端的情况下有必要学习和使用git命令吗?

       GUI在通常情况下满足平时的操作需求,但是使用git命令能得到一些客户端得不到的好处:
       1、 有些命令GUI很难提供。
       2、 错误提示非常详细,指出错误出现的地点和正确用法,能够帮助熟悉git原理和指令。
       3、 写自动化脚本的时候,只能使用命令行,比如自动测试和部署脚本,无论是shell脚本还是py脚本,GUI都无法使用。
       4、 Linux下没有git客户端。
       当然在绝大部分情况下,github客户端能够满足我们日常一切使用要求,而且学习成本大幅降低,还是不错的。(github destop官网:https://desktop.github.com)

参考文献

Git的中文官方文档:https://git-scm.com/book/zh/v1/
廖雪峰的git教程:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值