Git相关知识整理
一.Git初认识
- Git是什么?
Git是自由、开源、分布式的版本控制系统。 - Git和传统的版本控制系统(如SVN)有什么不同?
1>SVN这类传统的源代码管理都是以服务器为中心的,每个开发者都直接连在中间服务器上,本地修改,然后commit到SVN服务器。当然的会有一些缺陷:例如,因为所有的信息都在服务器上,开发者不能本地追踪代码版本且一旦离开服务器将无法正常工作;再者,如果项目比较大,中央服务器压力过大等。模型结构如下图:
2>Git就是为了解决SVN的这些缺陷应运而生的。本地下载git后,每个人的本地就是一个类似SVN的源代码服务器,可以在本地进行所有SVN的操作,但比SVN多了pull和push功能,为了拉取和提交自己的更改,形成最终版本来发布,具体的划分后面详解。模型结构如下图:
二.Git的各区域结构和工作原理(模块图如下) - Git结构概念
1>Workspace(工作区):我们编辑文件或代码的地方就是工作区。
2>Stage area/Staging/Index(暂存区):工作区用来提交更改前可以暂存工作区的变化的地方,常用的git add就是这个过程。
3>Local repository(本地版本库):受git控制的所有文件修订历史的本地共享数据库,常用的git commit等就是把更改提交到本地数据库。
4>Remote repository(远程版本库):受git控制的所有文件修订历史的远程(服务器)共享数据库,常用的git push/pull就是和远程版本库的交互。
5>Branch(分支):从主线上分离出来的副本,默认分支一般叫master;分支的作用主要是根据功能和目的划分的,比如常用的master为发布线上的最终版本分支,DEV分支用作开发测试代码的合并分支,feature等自建分支用来发开相应功能,最终合并到DEV分支来测试。但实际上分支是什么,就是一个代码版本。 - Git基本使用流程
1>从远程版本库git clone工程目录(对应需要的分支);若已clone工程目录,可以git pull从远程版本库拉取最新文件
2>在本地目录里对文件进行编辑或修改
3>把修改的文件git add到暂存区
4>Git commit到本地版本库
5>把本地版本库git push到远程版本库
三.Git常用命令 - 新建代码库
1>新建一个目录并将其初始化为Git代码库
命令git init [project-name] [project-name]为要创建的目录名称
2>从远程版本库下载一个项目和它的整个代码历史
命令git clone [url] [url]为远程版本库对应项目的地址 - 配置(git的配置文件为.gitconfig)
1>显示当前的Git配置
命令git config --list
2>编辑git配置文件
命令git config -e [–global]
3>设置提交代码时的用户信息
命令git config --global user.name “[name]”
命令git config --global user.password “[password]”
命令git config --global user.email “[email address]” - 增加/删除文件
1>添加指定文件到暂存区
命令git add [file1] [file2]…
2>添加指定目录到暂存区,包括子目录
命令git add [dir]
3>添加当前目录下的所有文件到暂存区
命令git add .
4>删除工作区文件,并且将这次删除放入暂存区
命令git rm [file1] [file2]…
5>停止追踪指定文件,但该文件会保留在工作区(提交会忽略该文件)
命令git rm --cached [file]
6>修改文件名,并且将这次改名放入暂存区
命令git mv [file-original] [file-renamed] - 提交代码
1>提交暂存区到本地版本库
命令git commit -m [message] [message]为提交时的备注信息
2>提交暂存区的指定文件到本地版本库
命令git commit [file1] [file2]… -m [message]
3>使用一次新的commit替换上一次的提交,若代码没有任何改动,则替换上次的提交信息
命令git commit --amend -m [message] - 操作分支(分支说到底都是master的副本或者副本的副本,分支上有一系列的commit)
1>列出所有本地分支
命令git branch
2>列出所有远程分支
命令git branch -r
3>列出所有本地和远程分支
命令git branch -a
4>新建一个分支,但仍然停留在当前分支
命令git branch [branch-name] [branch-name]分支名称
5>新建一个分支,并切换到该分支
命令git checkout -b [branch-name] [base-branch] [base-branch]为模板分支,若省略,默认模板为当前分支
6>从指定的commit,新建一个分支
命令git branch [branch-name] [commit]
7>新建一个分支,与指定远程分支建立追踪关系
命令git branch --track [branch-name] [remote-branch]
8>切换到指定分支,并更新工作区
命令git checkout [branch-name]
9>切换到上一个分支
命令git checkout -
10>创建远程分支
命令git push origin [local-branch]:[local-branch] 把当前所处的本地分支push到远端
命令git branch --set-upstream-to=origin/[local-branch] 使当前所处的本地分支和远端分支建立追踪关系
11>在现有分支和远程分支之间,建立追踪关系(所谓追踪关系就是本地分支和远程分支做关联)
命令git branch --set-upstream [branch-name] [remote-branch]
12>合并指定分支到当前分支
命令git merge [–no–ff] [–squash] [branch-name] [–no–ff]可省略,带上目的:保留分支信息,也就是多次提交信息 [–squash]可省略,带上目的:用于合并到master保证提交日志简洁,也就是把分支上的多次commit合并成一个,但不提交,因此这样合并后需要再commit一次
13>选择一个commit,合并进当前分支
命令git cherry-pick [commit]
14>删除本地分支
命令git branch -d [branch-name]
15>删除远程分支
命令git push origin --delete [branch-name] - 标签命令(也就是tag,作用就是给指定的commit打上标签,方便回退和查找)
1>列出所有tag
命令git tag
2>在当前commit,新建一个tag
命令git tag [tag] [tag]为tag名称
3>在指定commit,新建一个tag
命令git tag [tag] [commit]
4>删除本地tag
命令git tag -d [tag]
5>删除远程仓库对应标签
命令git push origin --delete [tag]
6>查看tag信息
命令git show [tag]
7>给远程发送指定tag
命令git push origin [tag]
8>将本地所有标签发布到远程仓库
命令git push origin --tag
9>以某个tag标记的commit为模板,新建一个分支
命令git checkout -b [branch-name] [tag] 该命令和以一个分支为模板新建分支同样格式 - 查看信息(包括log和版本之间的不同)
1>显示有变更的文件
命令git status
2>查看当前分支的版本历史
命令git log 和 git log --stat
3>根据关键字,搜索提交历史
命令git log -S [keyword]
4>显示某个文件的版本历史
命令git log --follow [file]
5>限制指定文件相关的每一次diff
命令git log -p [file]
6>显示暂存区和工作区的差异
命令git diff
7>显示暂存区和上一个commit的差异
命令git diff --cached
8>显示工作区与当前分支最新commit之间的差异
命令git diff HEAD
9>显示两个分支或版本之间的差异
命令git diff [first-branch]…[second-branch]
10>显示某次提交的元数据和内容变化
命令git show [commit]
11>显示当前分支的最近几次提交
命令git reflog - 远程同步(fetch, pull=fetch+merge; pull是拉取远程分支并与本地分支合并;fetch只是拉取远程分支)
1>下载远程仓库的所有变动,但并不合并到本地分支
命令git fetch [remote]
2>显示所有远程仓库
命令git remote -v
3>显示某个远程仓库的信息
命令git remote show [remote]
4>拉取远程仓库的变化并和本地分支合并
命令git pull [remote] [branch]
5>推送当前分支到远程仓库
命令git push --force强行推送不管冲突 --all推送所有分支到远程仓库 - 撤销命令(恢复变化)
1>恢复暂存区的指定文件到工作区(恢复工作区的某个文件,也就是恢复到git add之前)
命令git checkout – [file]
2>恢复暂存区的所有文件到工作区(恢复工作区)
命令git checkout .
3>重置暂存区的指定文件,与上次commit保持一致,且工作区不变(恢复暂存区某个文件,也就是恢复到git commit之前)
命令git reset HEAD [file]
4>重置暂存区和工作区,与上次commit保持一致(恢复暂存区和工作区)
命令git reset --hard
5>重置当前分支的head为指定commit,同时重置暂存区和工作区(回退版本,回退到某一次commit)
命令git reset --hard {[commit]/HEAD^}
回退版本原理如图(回退版本也就是head指针指向不同的commit):
6>重置当前分支的head为指定commit,但保持暂存区和工作区不变
命令git reset --keep [commit]
7>恢复某个commit的指定文件到暂存区和工作区(恢复工作区和暂存区的某个文件)
命令git checkout [commit] [file]
8>重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变
命令git reset [commit]
四.开发使用工作流程 - 通用工作流程(工作流如图)
Git工作流是基于git的分支功能而来,也和开发环境有关。根据上图,有五个代码环境(但根据实际环境会有更多的分支):两个常驻分支(长期存在)dev和master,其他三个分支为feature、release和hotfix。
1>Dev公共测试环境,代表了功能基本确定,由feature合并而来;dev分支是基于master分支而来的。
2>Master生成环境,代表了代码经过测试无bug的情况,发布到生产环境。
3>Feature开发环境,代表了新功能的特性的开发;feature分支基于dev分支而来,开发完成后要合并到dev分支;根据需要可即时删除。
4>Release预发布环境,代表了某个版本功能完全确定,只有一些小bug的情况;release分支基于dev分支而来,测试通过后需要合并到dev和master分支;根据需要可即时删除。
5>Hotfix代表了正式环境的紧急bug,测试通过后,要合并到dev和master分支;根据需要可即时删除。
举个栗子:
需求:开发两个新功能购物车和支付两个模块
1>基于dev分支新建两个feature分支
2>两个功能开发完后,分别add和commit
3>把两个feature分支合并到dev分支,测试完成后,可删除feature分支
4>测试通过,基于dev分支拉取release分支,在release分支测试完成后,合并到master
5>合并后再次提交,然后push后,master分支就可以发布预生产了 - 当前我们公司项目开发流程
我们并非按照环境去划分分支,而是每次/每天/需要修改问题等时,从master分支拉取一个分支(用日期来命名),测试通过后,合并到master分支,因此master分支就是最新最终版本。且这种方式也方便回滚,可以找到对应日期的版本分支。
五.一些使用场景和问题解决方案(后续补充)