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 分支并推送远程,一旦修复上线,便将其删除
相关推荐
Winston Wood4 分钟前
一文了解git TAG
git·版本控制
喵喵先森37 分钟前
Git 的基本概念和使用方式
git·源代码管理
xianwu5432 小时前
反向代理模块
linux·开发语言·网络·git
binishuaio4 小时前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
会发光的猪。5 小时前
如何在vscode中安装git详细新手教程
前端·ide·git·vscode
stewie67 小时前
在IDEA中使用Git
java·git
晓理紫15 小时前
使用git lfs向huggingface提交较大的数据或者权重
git
我不是程序猿儿17 小时前
【GIT】sourceTree的“当前分支“,“合并分支“与“检出分支的区别
git
_OLi_1 天前
IDEA中新建与切换Git分支
java·spring boot·git
PyAIGCMaster1 天前
ubuntu下安装 git 及部署cosyvoice(1)
git