GIT开发中的使用

目录

GIT

什么是Git?

Git是一个版本控制器:可以记录工程的每一次改动和版本迭代的一个管理系统

注意事项:

  • 所有的版本控制系统,其实只能跟踪文本文件的改动(如TXT文件、网页、所有的程序代码等),版本控制系统可以告诉你每次的改动,如第几行增加/删除了某些单词等
  • 而图片、视频等二进制文件,虽然也可以由版本控制系统管理,但是无法跟踪文件的改变,只能知道文件大小的变化(从100K -> 200K等操作)

Git的安装

  • Linux-centos

查看版本:

git --version

安装Git:

sudo yum -y install git

  • Linux-ubantu

查看版本:

git --version

安装Git:

sudo apt-get install git -y

Git 的基本操作

创建本地仓库:

git init

切记: 不要在.git文件中进行操作

配置Git:

配置用户名

git config [--global] user.name "昵称"

配置邮箱

git config [--global] user.email "邮箱格式"

注意: 执行命令必须在仓库中, --global是可选项,作用是把配置应用到当前机器的所有仓库中,而要删除全局配置也需要加上--global选项

查看配置命令:

git config -l

删除对应的配置命令:

git config [--global] --unset user.name

git config [--global] --unset user.email

认识工作区、暂存区、版本库

工作区: 电脑上要存放代码或者文件的目录

暂存区: 英文名(stage/index)一般存放在 .git目录下的index文件中,有时候也把暂存区叫做索引

版本库: 又叫仓库(repository),工作区有一个隐藏目录 .git,它不算工作区,而是Git的版本库,这个版本库里的文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来的某个时刻可以"还原"

  • 工作区和版本库是处在同一个文件目录下的
  • 在创建Git版本库时,Git会为我们自动创建一个唯一的master分支,以及指向master的一个指针HEAD
  • 当对工作区修改的文件执行 git add 命令时,暂存区目录树的文件索引会被更换
  • 当执行 git commit 时,master分支会作相应的更新(暂存区的目录树才会被真正写到版本库中)

添加文件

添加一个或多个文件到暂存区:

git add [文件1] [文件2] ...

添加指定目录到暂存区,包括子目录:

git add [目录]

添加当前目录下所有文件的改动到暂存区:

git add .

提交暂存区全部内容到本地仓库:

git commit -m "message"

提交暂存区的指定文件到仓库区:

git commit [文件1] [文件2] ... -m "message"

注意: git commit 后面的-m 选项,要跟上描述本次提交的message,由用户自己完成,此部分内容不可省,要好好描述,用来记录提交细节,git commit 命令执行成功后会告诉我们改动结果

查看历史提交记录:

git log

该命令从近到远的显示提交日志,并且可以看到我们commit时的日志消息,如果觉得输出的信息太多,可以加上--pretty=oneline参数:

git log --pretty=oneline

查看.git文件

tree .git/

  • index 就是暂存区,add后的内容都是添加到这里的
  • HEAD 是默认指向master分支的指针
  • refs/heads/master 文件里保存了当前master分支的最新commit id
  • objects 是git的对象库,包括了创建的各种版本库对象以及内容

当执行git add 命令时,暂存区的目录树被更新,同时工作区修改的文件内容被写入到对象库中的一个新的对象中,位于".git/objects"目录下,查找object时要将commit id分成2部分,前2位是文件夹名称,后38位是文件名称,找到这个文件之后,一般不能直接看到里面是什么,该文件是经过sha(安全哈希算法)加密过的文件,我们可以通过

git cat-file -p

命令来查看版本库对象的内容。

注意: Git跟踪并管理的是修改(新增、删除等),并不是文件

查看当前仓库的状态:

git status

该命令用于查看上次提交之后是否对文件再次进行修改

显示暂存区和工作区文件的差异:

git diff [文件名]

显示版本库和工作区文件的区别:

git diff HEAD --[文件名]

版本回退

语法:

git reset [--soft | --mixed | --hard] [HEAD]

  • HEAD
    • 可直接写成commit id ,表示指定退回的版本
    • HEAD 表示当前版本
    • HEAD^ 上一个版本
    • HEAD^^ 上上一个版本
    • 以此类推......
  • 可以使用~数字表示:
    • HEAD~0 当前版本
    • HEAD~1 上一个版本
    • HEAD~2 上上一个版本
    • 以此类推......
  • --soft 只回退版本库,工作区和暂存区不回退
  • --mixed 回退版本库和暂存区,不回退工作区
  • --hard 回退工作区、暂存区、版本库到指定版本

打印历史日志(可以补救回退之后找不到回退之前的版本ID):

git reflog

虽然这里面只是版本号的一部分,不过依然可以用来回退到相对应的版本

撤销修改

如果在工作区 写了很长是时间的代码,但是觉得不妥,想恢复到上一个版本(大前提:都未把本地仓库push到远程仓库)

  • 工作区的代码,未进行add

    手动删除:可以直接删除(通过对文件内容的操作)

    使用:

    git checkout -- [文件名]

    让工作区回到最近一次add或者commit时的状态,其中--不可省

  • 已经add,但未commit

    使用git reset [--mixed(默认参数,可以省略)] HEAD [文件名]

  • 已经add,并且也已经commit了

    直接通过git reset --hard HEAD^ 回退版本

删除(版本库中)文件

  • 逐步操作

    rm [文件名] "删除工作区"

    git add

    git commit

  • 工作区和暂存区合并操作

    git rm [文件名] "该命令会直接把工作区和暂存区都删除"

    git commit

分支管理

理解分支

Git会把每次的(提交)操作串联成一条时间线,这条时间线可以理解成为是一个分支,每次提交,master分支都会向前移动一步,随着不断的提交,master分支的线也会越来越长,而HEAD指针只要一直指向master分支即可指向当前分支

创建分支

Git支持创建其他分支,我们创建一个自己的分支dev

分支命令:

git branch #查看当前本地分支

git branch [分支名,这里是dev] #新建分支dev

当我们创建新的分支之后,Git新建了一个指针叫dev,* 表示当前HEAD 指向的分之是master 分支,刚创建好dev分支之后,会发现当前dev和master指向同一个修改

切换分支

切换命令:

git checkout [分支名]

此时,HEAD指向dev,表示我们切换到了dev分支上

合并分支

注意: 合并分支要在主分支(要合并到的分支)上操作,如dev合并到master上,需要在master分支下操作(合并)

命令:

git merge [被合并的分支名,此处是dev]

合并后状态如图,master就可以看到dev分支提交的内容

Fast-forward代表"快进模式",也就是直接把master指向dev的当前提交,所以合并速度很快

删除分支

合并完分支之后dev分支对我们来说就没什么用了,那么dev分支就可以被删除了

注意: 删除分支的时候不能处于要被删除的分支之下操作

删除分支命令:

git branch -d(delete) [分支名]

因为创建、合并和删除分支非常快,所以Git鼓励使用分支完成某个任务,这和直接在master分支上工作效果一样,但是过程很安全。

合并冲突

实际的合并的时候,可能会出现代码冲突问题

情景:在master单分支下创建一个新分支dev1,并切换至dev1,在dev1分支下对ReadMe文件修改(末尾一行改为bbb)并进行提交,切换回master分支,发现ReadMe文件并未修改(末尾一行是文件原本内容aaa),此种情况很正常,之后对ReadMe文件再进行修改(末尾一行的aaa改为ccc)并进行提交,此时在master分支下的master文件末尾内容是ccc,在dev1分支下ReadMe文件末尾是bbb,然后在master分支下合并master分支和dev1分支,会出现合并冲突

此种情况,Git只能试图把各自的修改合并起来,但是这种合并就会有冲突

报错:Automatic merge failed; fix conflicts and then commit the result.

发现ReadMe文件有冲突后,可以直接查看文件内容

Git会用<<<<<<<,=======, >>>>>>> 来标记出不同分⽀的冲突内容

......

<<<<<<< HEAD

write ccc for new branch

=======

write bbb for new branch >>>>>>> dev1

此时我们需要手动调整冲突代码,并提交(再次提交很重要,切勿忘记)

冲突解决完之后状态为:

最后,不要忘记dev1分支使用完毕后可以删除

创建分支并且切换到新创建的分支上:

git checkout -b [新创建的分支名]

通过log命令来查看分支合并情况(图示法)

git log --graph [--pretty=oneline] --abbrev-commit

分支管理策略

对于Git合并分支时会有两种模式

  • 模式一:Fast forword(ff模式)

在此模式下,删除分支后,查看分支历史时,会丢掉分支信息,看不出最新提交 到底是merge进来的还是正常提交的

  • 模式二:非Fast forword(no-ff模式)

此模式下,可以从分支历史中看出分支信息

Git支持我们强制禁止Fast forword 模式,那么我们在merge时生成一个新的commit,这样从分支历史上可以看出分支信息

强制禁止Fast forword 模式(也就是在合并时伴随着再次提交):

git merge [--no-ff] [-m "日志信息"] [要被合并的分支名]

注意: --no-ff参数,表示禁用Fast forword模式,此时会创建一个新的commit,所以加上-m参数,把描述写进去。

此时状态为:

所以合并分支时,加上--no-ff 参数就可以使用普通模式合并,合并后的历史有分支,能看出曾经做过合并,而Fast forword合并则看不出曾经做过合并

分支策略: 实际开发中,应该按照master分支非常稳定 来发布新版分,也就是说,不能再master分支上写新代码,而要在dev分支上开发新功能,到一定程度再把dev分支合并到master分支上

bug分支

如果在dev2分支上开发到了一半,发现master分支上有bug,需要解决。在Git中,每个bug都可以通过一个新的临时分支来修复,修复后,分支合并,然后将临时分支删除,但是此时dev2的代码工作区已经开发了一半,暂时无法提交怎么办?

Git提供了git stash 命令:

git stash #将当前工作区信息进行储藏,被储藏的内容可以在将来的某个时间恢复

储藏dev2工作区之后,由于我们要基于master分支修复bug,所以需要我们切回master分支,新建fix_bug分支进行修复bug操作,当bug修复完成,继续切回dev2分支进行开发,但是此时工作区是干净的,我们需要使用:

git stash pop #来恢复储藏信息到dev2工作区

git stash list #查看储藏信息

#注意:

git stash apply #恢复现场,但是refs下的stash内容并不删除

git stash drop #配合上方命令主动删除stash内容

#可以使用以下命令恢复指定的stash:

git stash list #查看stash目录

git stash apply stash@{0}

注意: 储藏的信息是在refs下保存,当我们使用git stash pop 恢复储藏之后,会自动删除refs下的stash内容

修复完bug之后的合并方式:

修复完bug之后,并未在dev2上显示,也就是说master分支的最新提交是要领先于新建dev2时master的状态,所以我们在dev2下看不到修复的bug的相关代码

  • 直接将开发分支合并到master分支上(会出现代码冲突,解决冲突容易出错)
  • master分支先合并到开发分支上,后再合并到master分支上(将代码冲突的解决放到开发代码分支上处理)

删除临时分支

一般我们在开发代码的时候都是新建一个分支,在新建的分支上操作,但是如果此时在新建分支上开发代码到一般情况下,被项目经理叫停说不开发这个功能了,虽然白干了,但是这个新建的分支(已经add和commit)还得销毁,这时git branch -d 命令(只能删除未进行add和commit操作的分支)删除不了分支

强制删除分支:

git branch -D [分支名]

远程仓库

Git是分布式版本控制系统 ,上面的介绍都是在本地,那么分布式如何理解?

就是找一台24小时运行的电脑,作为一个充当服务器角色,所有人都从这个"服务器"(github或者gitee)仓库克隆(拉取)一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。

克隆远程仓库:

git clone [远程仓库的地址]

克隆地址有两种方式:

  • HTTPS方式(每次推送需要输入口令)
  • SSH方式(每次推送不需要输入口令)

https简单方便,SSH方式需要在远端库中配置公钥(否则会被服务器拒绝clone链接)

SSH方式的公钥和私钥生成方式:

如果在.ssh目录下没有id_rsaid_rsa.pub 这两个文件,就是没有生成公钥和私钥

ssh-keygen -t rsa -C ["自己的邮箱(就是在gittee上面的邮箱)"]

一路回车,然后去.ssh 文件夹里找id_rsaid_rsa.pub(公钥) 这两个文件

Github/Gitee允许添加多个公钥

当从远程仓库克隆后,实际上Git会自动把本地的master分支和远程的master分支对应起来,并且,远程仓库的默认名称是origin 在本地可以使用

git remote #查看远程库的信息

git remote -v #显示更详细的信息

向远程仓库推送

命令:

git push [远程主机名] [本地分支名]:[远程分支名]

git push [远程主机名(origin)] [本地分支名] #当本地分支名和远程分支名一致时可省略远程分支名

注意:

在推送前需要本地设置的name和email和gitee上配置的用户名和邮箱一致,否则会出错

拉取远程仓库

命令:

git pull [远程主机名(origin)] [远程分支名]:[本地分支名]

git pull [远程主机名(origin)] [远程分支名] #当远程分支名和本地分支名一致时,可以省略本地分支名

配置Git

忽略特殊文件

日常开发中,有些文件不想或者不应该提交到远端,比如:保存了数据库密码的配置文件,那么怎么让Git知道呢?

在Git的工作区的根目录下创建一个特殊的.gitignore 文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。

  • .gitignore 文件可以在gitee创建仓库的时候自动生成(勾选操作)

  • 但是如果没有选择,也可以创建一个

如果要忽略以.so.ini 结尾的所有文件:

#省略选择模本的内容

......

#My configurations:

*.so

*.ini

.* #排除所有.开头的隐藏文件

!XXX(文件名).so(文件后缀)

.gitignore 文件中也可以指定某个确定的文件

当某个文件在我们要忽略的配置文件中,但是却要强制添加:

git add [-f] [文件名] #在.gitignore被忽略后,强制添加到git管理中

git check-ignore [-v] [文件名.后缀] #查看某个文件在.ignore文件中的配置

给命令配置别名

使用Git的时候有些命令太长了,我们可以把它简化:

比如将git log --pretty=oneline --abbrev-commit 简化为git lpa

git config --global [alias.lpa(简化后的命令)] ['log --pretty=oneline --abbrev-commit'(简化前的命令)] #--global是对该电脑下的所用仓库适用,如果不加,就只是对当前仓库起作用

注意简化的只是不包含git这个开头关键字之后的命令

标签管理

理解标签

标签tag 可以简单的理解为对某次提交的一个标识,相当于是起了别名,比如针对某个版本的最后一个提交起一个v1.0 这样的标签来标识里程碑的意义

相较于本次提交的commit id,tag很好的代替了它

创建标签

git tag [标签名] #(默认)给最新一次的提交打上标签

git tag #查看所有标签

git tag [标签名] [某次cimmit id] #给某个历史提交的commit id打上标签

git show [标签名] #查看标签信息

git tag -a [标签名] -m "XXX" [commit id] #给某次历史提交的commit id打上标签并且给上说明 -a指定标签名 -m指定说明文字

注意: 标签不是按照时间排序的,而是按照字母进行排序,而且创建完标签,在refs下问有一个tag,tag下存的是标签,但是标签里面存的是commit id

操作标签

删除标签:

git tag -d [标签名] #删除标签

git push [origin(远程分支名)] <标签名> #向远程分支推送标签(单个)

git push [origin(远程分支名)] --tags #向远程分支推送标签(全部)

要是想删除掉远程仓库中的标签,需要先把本地的删除掉,然后再推送到远程仓库:

git tag -d [标签名] #1.先删除本地仓库的标签

git push [origin(远程分支名)] [本地分支(可省略)] :[标签名] #2.删除(推送)至远程仓库

多人协作开发

多人协同开发,需要将用户添加进开发者,用户才有权限进行代码提交

情景一:单分支多人开发

分别有两个用户:用户一(windows系统)和用户二(Linux系统)上针对同一项目进行协作开发

目前远程仓库中,只有一个master分支,为保证主分支的稳定,在开发新功能时,建立dev分支(基于master分支最新状态)来开发

通过git pull 操作来将远程分支拉取到本地

注意: git pull

而且git branch 只能查看本地分支,要查看远程分支需要加上 [ - r ] 选项,前提是 pull 一下,拉取最新的远程仓库,才能看到最新的内容

git branch -r(或者git branch -a) #查看所有分支

gir branch -vv #查看本地分支和远程分支建立的连接关系

在本地仓库创建dev分支,并切换到该分支上,同时将本地dev分支和远程仓库origin分支下的dev相互连接起来:

git checkout -b [dev(本地分支名)] [origin/dev(远程仓库分支名)] #在本地仓库创建并切换到dev分支,同时将本地dev分支和远程仓库origin下的dev分支建立连接

git branch --set-upstream-to=[origin/dev(远程仓库分支名)] [本地仓库分支名] #远程仓库未和本地仓库某个分支建立连接时,可以使用该命令将分支进行连接操作

假如此时用户一(二)开发完毕进行了add、commit、push到了远程仓库,而另一个用户,比他晚一点提交,会出现分支冲突,此时需要拉取(pull)一下远程仓库(更新本地仓库到最新状态)然后再在本地解决冲突后,再去推送(add、commit、push)

记得,开发完毕后,合并分支的时候,先让master分支合并到dev上,出现冲突,在dev分支上解决完毕之后,再次把dev分支合并到master上面

同一分支进行多人协作的工作模式总结:

  • 首先,试图用git push [origin] [branch-name] 推送自己的修改
  • 如果推送失败,则因为远程分支比本地的更新,需要先用git pull试图合并
  • 如果合并有冲突,则解决冲突,并在本地提交
  • 没有冲突或者解决掉冲突后,再用git push [origin] [branch-name] 推送就可以成功
  • 功能开发完毕,将分支merge进master分支,最后删除

情景二:多分支多人开发

一个需求或者一个功能点创建一个feature分支

两人分别开发两个功能:

A用户:

git checkout -b [feature-1] #新增本地分支 feature-1 并切换

vim [function1] #新增需求内容 - 创建function1文件

cat .\ [function1] #查看function1内容

......add、commit

git push origin [feature-1] #将feature-1推送到远端

远程仓库会自动创建新的feature-1分支

B用户与A用户一致

假如

B用户生病,需要A用户帮B用户继续开发剩下的代码,并且把feature-2分支名告诉了A用户,这时需要A用户在自己的机器上切换到featur-2分支继续开发

操作如下:

git pull #先拉取远程仓库内容

git checkout -b [feature-2] [origin/feature-2] #切换到featur-2分支并于远程仓库建立连接

......开发完成后推送至远端

之后B用户想要再自己的机器上看到最新的代码,需要拉取下最新的代码记录

注意:

merge之前最好切换到master分支下pull一下远端仓库,让master分支保持最新状态,然后再切换到feture分支合并master,最后push

远程分支删除后,本地git branch -a 依然能看到的解决方法

当远程仓库删除之后,在本地使用git branch -a 依然可以看到所有本地分支和远程分支时候时候使用:

git remote show origin #查看remote地址,远程分支还有本地分支相对应关系等信息

#根据提示使用:

git remote prune origin #删除本地关联的不存在的远程分支

企业级开发

系统开发环境:

  1. 开发环境:开发环境是程序员们专门用于日常开发的服务器
  2. 测试环境:开发环境到测试环境的过度环境
  3. 预发布环境:为避免因测试环境和线上环境的差异等带来的缺陷漏洞,而设立的,预发布环境服务器不在线上集成服务器范围之内,为单独的一些机器
  4. 生产环境:正式提供对外服务的线上环境

这几个环境也可以说是系统开发的三个重要阶段:开发 -> 测试 -> 上线,如图:

企业中环境不可能这么简单,这只是大致的简化

Git分支设计规范

不同的环境有不同的分支,例如:

分支 名称 适用环境
master 主分支 生成环境
relese 预发布分支 预发布/测试环境
develop 开发分支 开发环境
feature 需求开发分支 本地
hotfix 紧急修复分支 本地

注意: 以上表格中的分支和环境搭配仅是常用的一种,可视情况不同而定

master分支

  • master 是主分支,该分支为只读且唯一分支,用于部署到正式发布环境,一般由合并release 分支得到
  • 主分支作为稳定的唯一代码库,任何情况下不允许直接在master 分支上修改代码
  • 产品的功能全部实现后,最终在master 分支对外发布,另外所有在master 分支的推送应该打上标签(tag)做记录,方便追溯
  • master 分支不可删除

release分支

  • release 为预发布分支,基于本次上线所有的feature 分支合并到develop 分支之后,基于develop 分支创建
  • 命名以release/ 开头,建议命名规则:release/version(版本)_publishtime(发布时间)
  • release 分支主要用于提交给测试人员进行功能测试,发布提测阶段,会以release 分支代码为基准进行提测
  • 如果在release 分支测试出问题,需要回归验证develop 分支是否存在此问题
  • release 分支属于临时分支,产品上线后可选删除

develop分支

  • develop 为开发分支,基于master 分支创建的只读且唯一分支,始终保持最新完成以及bug修复后的代码
  • 根据需求大小程度确定是由feature 分支合并,还是直接在上面开发(非常不建议)

feature分支

  • feature 分支通常为新功能或新特性开发分支,以develop 分支为基础创建的
  • 命名以feature/ 开头,命名建议:feature/user(用户名)_createtime(创建时间)_feature
  • 新特性或新功能开发完成后,开发人员需合并到develop 分支
  • 一旦需求发布上线,便将其删除

hotfix分支

  • hotfix 分支为线上bug修复分支或补丁分支,主要用于对线上的版本进行bug修复,当线上出现紧急问题需要马上修复时,需要基于master 分支创建hotfix 分支
  • 命名以hotfix/ 开头,建议命名规则:hotfix/user(用户名)_createtime(创建时间)_hotfix
  • 当问题修复完成后,需要合并到master 分支和develop 分支并推送远程,一旦修复上线,便将其删除

测试,发布提测阶段,会以release 分支代码为基准进行提测

  • 如果在release 分支测试出问题,需要回归验证develop 分支是否存在此问题
  • release 分支属于临时分支,产品上线后可选删除

develop分支

  • develop 为开发分支,基于master 分支创建的只读且唯一分支,始终保持最新完成以及bug修复后的代码
  • 根据需求大小程度确定是由feature 分支合并,还是直接在上面开发(非常不建议)

feature分支

  • feature 分支通常为新功能或新特性开发分支,以develop 分支为基础创建的
  • 命名以feature/ 开头,命名建议:feature/user(用户名)_createtime(创建时间)_feature
  • 新特性或新功能开发完成后,开发人员需合并到develop 分支
  • 一旦需求发布上线,便将其删除

hotfix分支

  • hotfix 分支为线上bug修复分支或补丁分支,主要用于对线上的版本进行bug修复,当线上出现紧急问题需要马上修复时,需要基于master 分支创建hotfix 分支
  • 命名以hotfix/ 开头,建议命名规则:hotfix/user(用户名)_createtime(创建时间)_hotfix
  • 当问题修复完成后,需要合并到master 分支和develop 分支并推送远程,一旦修复上线,便将其删除
相关推荐
Smile丶凉轩7 小时前
微服务即时通讯系统的实现(服务端)----(1)
c++·git·微服务·github
和你一起去月球16 小时前
TypeScript - 函数(下)
javascript·git·typescript
我不是程序猿儿17 小时前
【GIT】TortoiseGit的变基(Rebase)操作
git
yyycqupt1 天前
git使用(一)
git
Kkooe1 天前
GitLab|数据迁移
运维·服务器·git
Beekeeper&&P...1 天前
git bash是什么,git是什么,git中的暂存区是什么,git中的本地仓库是什么,git中工作目录指的是什么
开发语言·git·bash
Stara05111 天前
Git推送+拉去+uwsgi+Nginx服务器部署项目
git·python·mysql·nginx·gitee·github·uwsgi
lsswear1 天前
GIT 操作
git