Git使用
Git 简介
Git 是 Linux 发明者 Linus 开发的一款新时代的版本控制系统 ,版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统,对于软件开发领域来说版本控制是最重要的一环,而 Git 毫无疑问是当下最流行、最好用的版本控制系统。
- 图中左侧为工作区,右侧为版本库。在版本库中标记为
index
的区域是暂存区(stage
,index
),标记为master
的是master
分支所代表的目录树。 - 图中我们可以看出此时
HEAD
指针实际是指向master
分支的一个“游标”。所以图示的命令中出现 HEAD 的地方可以用 master 来替换。 - 图中的
objects
标识的区域为Git
的对象库,实际位于.git/objects
目录下。 - 当对工作区修改(或新增)的文件执行
git add
命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID
被记录在暂存区的文件索引中。 - 当执行提交操作
git commit
时,暂存区的目录树写到版本库(对象库)中,master
分支会做相应的更新。即master
指向的目录树就是提交时暂存区的目录树。 - 当执行
git reset HEAD
命令时,暂存区的目录树会被重写,被master
分支指向的目录树所替换,但是工作区不受影响。 - 当执行
git rm --cached <file>
命令时,会直接从暂存区删除文件,工作区则不做出改变。 - 当执行
git checkout .
或者git checkout -- <file>
命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。 - 当执行
git checkout HEAD .
或者git checkout HEAD <file>
命令时,会用HEAD
指向的master
分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。
安装
- 安装百度解决
环境设置命令
通常情况下,安装完Git后的第一件事就是设置用户名称和邮件地址。每一个Git的提交都会使用这些信息,如果不设置则无法进行提交。
1
2
3
4
5
6
7
8# 用户名和邮箱也可以填写别的(只要是用户名和邮箱格式就OK)。
$ git config --global user.name "xxx"
$ git config --global user.email "xxxxx@xx.com"
git config --global init.defaultBranch master
# 全局过滤列表
git config --global core.excludesfile /e/fulsun/Documents/.gitignore_global
# 回车换行符input:Windows系统上的签出文件中保留CRLF,会在Mac和Linux系统上,包括仓库中保留LF。
git config --global core.autocrlf input1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#.gitignore_global
target/
!.mvn/wrapper/maven-wrapper.jar
## STS ##
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
## IntelliJ IDEA ##
.idea
*.iws
*.iml
*.ipr
## JRebel ##
rebel.xml
.rebel.xml.bak
## MAC ##
.DS_Store
## Other ##
logs/
temp/
——————使用
--global
参数表示设置了全局的环境,如果想对与特定的项目使用不同的用户名和邮件地址,则可已在该项目目录下不使用--global
参数设置不同的用户名和邮件地址。git config --list
命令可以列出当前Git所有的配置信息。
命令列表
命令行(win + R),输入 cmd 后,输入 git可以判断是否成功安装。
网上找了个图,别人整理的一张图,很全很好,借来用下。下面详细解释一些常用命令。
HEAD
在掌握具体命令前,先理解下
HEAD
。HEAD
,它始终指向当前所处分支的最新的提交点。你所处的分支变化了,或者产生了新的提交点,HEAD就会跟着改变。
git init
初始化仓库,目录已经是一个 git 仓库了
git clone
克隆远程仓库到本地
1
2$ git clone git@github.com:goto456/leetcode.git // 通过ssh方式克隆
$ git clone https://github.com/goto456/leetcode.git // 通过https方式克隆以上2种方式有如下区别:
- https方式:不管是谁,只要拿到该项目的 url 可以随便 clone,但是在 push 到远程的时候需要验证用户名和密码;
- ssh方式:需要现将你电脑的SSH key(SSH公钥)添加到GitHub(或者其他代码托管网站)上,这样在 clone 项目和 push 项目到远程时都不需要输入用户名和密码。
git status
git status 这个命令顾名思义就是查看状态,这个命令可以算是使用最频繁的一个命令了,建议大家没事就输入下这个命令,来查看你当前 git 仓库的一些状态。一般会显示当前所处的分支,以及当前工作区是否干净,是否有文件要提交。
当你克隆远程仓库到本地后,通过该命令查看当前状态时,显示信息如下图所示:
当你修改了一个文件后,再用该命令查看当前状态,它会提示你把当前的变更添加到暂存区或者丢弃该变更,显示信息如下图所示:
当你新增一个文件后,用该命令查看当前状态,它会显示新增的文件状态是未跟踪,并且提示用
git add
命令将其添加到暂存区,显示信息如下图所示:
git add
新建立一个文件,输入 git status
后查看 ,Untracked files ,就是说 a.md 这个文件还没有被跟踪输入 git add a.md
,然后再输入 git status
:提示以下文件 Changes to be committed , 意思就是 a.md 文件等待被提交,当然你可以使用 git rm --cached
这个命令去移除这个缓存.
git add . | 添加当前目录的所有文件到暂存区 |
---|---|
git add [dir] | 添加指定目录到暂存区,包括子目录 |
git add [file1] | 添加指定的文件到暂存区 |
git commit
接着我们输入git commit -m 'first commit'
,这个命令什么意思呢? commit 是提交的意思,-m
代表是提交信息,执行了以上命令代表我们已经正式进行了第一次提交。这个时候再输入 git status
,会提示 nothing to commit。
git commit -m [message] | 提交暂存区到本地仓库,message代表说明消息 |
---|---|
git commit [file1] -m [message] | 提交暂存区的指定文件到本地仓库 |
git commit –amend -m [message] | 使用一次新的commit,替代上一次提交 |
git log
这个时候我们输入 git log 命令, git log 命令可以查看所有产生的 commit 记录,所以可以看到已经产生了一条 commit 记录,而提交时候的附带信息叫 ‘first commit’ 。
1 | $ git log //查看历史版本 |
git log
–graph 左边显示出了分支的图形
git diff
diff 显示变更内容, 当你对文件进行了修改,想查看进行了哪些修改时,可以通过该命令查看。
git diff
命令会显示修改的文件中哪些内容进行了修改,包括新增了哪些内容,删除了哪些内容。1
2$ git diff //后面不接参数,表示显示所有修改文件的变更
$ git diff README.md //后面接文件名,表示只显示该文件的变更例如:我对
README.md
文件进行了修改,删除了1行,新增了2行,然后用该命令查看进行了哪些修改,如下图所示: (“+”
表示新增的内容,“-”
表示删除的内容)
git add & git commit
看到这里估计很多人会有疑问,我想要提交直接进行 commit 不就行了么,为什么先要再 add一次呢?首先 git add 是先把改动添加到一个「暂存区」,你可以理解成是一个缓存区域,临时保存你的改动,而 git commit 才是最后真正的提交。这样做的好处就是防止误提交,当然也有办法把这两步合并成一步,不过后面再介绍,建议新手先按部就班的一步步来。
git branch
branch 即分支的意思,分支的概念很重要,尤其是团队协作的时候,假设两个人都在做同一个项目,这个时候分支就是保证两人能协同合作的最大利器了。
举个例子,A, B俩人都在做同一个项目,但是不同的模块,这个时候A新建了一个分支叫a, B新建了一个分支叫b,这样A、B做的所有代码改动都各自在各自的分支,互不影响,等到俩人都把各自的模块都做完了,最后再统一把分支合并起来。
命令 | 说明 |
---|---|
git branch | 列出本地所有分支 |
git branch -r | 列出所有远程分支 |
git branch -a | 列出所有本地分支和远程分支 |
git branch [branch-name] | 新建一个分支,但是停留在当前分支 |
git branch -b [branch-name] | 新建一个分支并切换到该分支 |
git branch –track [branch][remote-branch] | 新建一个分支,与指定的分支建立追踪关系 |
git checkout [branch-name] | 切换到指定的分区,并更新工作区 |
git branch -d [branch-name] | 删除分支 |
git push origin –delete [branch-name] | 删除远程分支,不要加 origin/ |
执行git init
初始化git仓库之后会默认生成一个主分支 master ,也是你所在的默认分支,也基本是实际开发正式环境下的分支,一般情况下 master 分支不会轻易直接在上面操作的,你们可以输入 git branch
查看下当前分支情况:
新建分支
很简单,执行 git branch a
就新建了一个名字叫 a 的分支,这时候分支 a 跟分支 master 是一模一样的内容,我们再输入 git branch
查看的当前分支情况.但是可以看到 master 分支前有个 * 号,即虽然新建了一个 a 的分支,但是当前所在的分支还是在 master 上。
切换分支
执行这个命令 git checkout a
,然后再输入git branch
查看下分支情况:(前面有*) 可以看到当前我们在的分支已经是a了,这个时候 A 同学就可以尽情的在他新建的a分支去进行代码改动了。
那有人就说了,我要先新建再切换,未免有点麻烦,有没有一步到位的,聪明: git checkout -b a
这个命令的意思就是新建一个a分支,并且自动切换到a分支。
git merge
A同学在a分支代码写的不亦乐乎,终于他的功能完工了,并且测试也都ok了,准备要上线了,这个时候就需要把他的代码合并到主分支master上来,然后发布。
git merge
就是合并分支用到的命令. 针对这个情况,需要先做两步,- 第一步是切换到 master 分支,如果你已经在了就不用切换了
- 第二步执行 git merge a ,意思就是把a分支的代码合并过来,不出意外, 这个时候a分支的代码就顺利合并到 master 分支来了。
- 为什么说不出意外呢?因为这个时候可能会有冲突而合并失败。
merge命令把不同的分支合并起来。如图,在实际开放中,我们可能从master分支中切出一个分支,然后进行开发完成需求,中间经过R3,R4,R5的commit记录,最后开发完成需要合入master中,这便用到了merge。
一般在merge之后,会出现conflict,需要针对冲突情况,手动解除冲突。主要是因为两个用户修改了同一文件的同一块区域。如下图所示,需要手动解除。
命令 | 说明 |
---|---|
git fetch [remote] | merge之前先拉一下远程仓库最新代码 |
git merge [branch] | 合并指定分区到当前分区 |
rebase
rebase又称为衍合,是合并的另外一种选择。
在开始阶段,我们处于new分支上,执行 git rebase dev,那么new分支上新的commit都在master分支上重演一遍,最后checkout切换回到new分支。这一点与merge是一样的,合并前后所处的分支并没有改变。
git rebase dev,通俗的解释就是new分支想站在dev的肩膀上继续下去。rebase也需要手动解决冲突。
rebase与merge的区别
现在我们有这样的两个分支,test和master,提交如下:
1
2
3D---E test
/
A---B---C---F master在master执行
git merge test
,然后得到如下结果:1
2
3D--------E
/
A---B---C---F----G test, master在master执行
git rebase test
,然后得到如下结果:1
A---B---D---E---C'---F' test, master
merge操作会生成一个新的节点,之前的提交分开显示。
而rebase操作不会生成新的节点,是将两个分支融合成一个线性的提交。
如果你想要一个干净的,没有merge commit的线性历史树,那么你应该选择git rebase
如果你想保留完整的历史记录,并且想要避免重写commit history的风险,你应该选择使用git merge
git branch -d
有新建分支,那肯定有删除分支,假如这个分支新建错了,或者a分支的代码已经顺利合并到master 分支来了,那么a分支没用了,需要删除,这个时候执行 git branch -d a
就可以把a分支删除了。
git branch -D
有些时候可能会删除失败,比如如果a分支的代码还没有合并到master,你执行 git branch -d a
是删除不了的,它会智能的提示你a分支还有未合并的代码,但是如果你非要删除,那就执行 git branch -D a
就可以强制删除a分支。
git cherry-pick
挑拣节点合并到当前分支上,该命令一般用于从其他分支上挑拣某些节点到当前分支。
命令:
git cherry-pick commit_id
上图中我想把 ruby_client 分支上的 e43a6 这个节点合并到 master 分支上,但不需要 5ddae 这个节点,那么我们就可以使用下面的命令:
1
2$ git checkout master // 先切换到 master 分支
$ git cherry-pick e43a6 //将 e43a6 节点挑拣合并到当前分支完成后如下图所示: 注意:该节点被挑拣合并到 master 上后会产生一个新的节点a0a41
reset
reset命令把当前分支指向另一个位置,并且相应的变动工作区和暂存区。
命令 | 说明 |
---|---|
git reset –soft [commit] | 只改变提交点,暂存区和工作目录的内容都不改变 |
git reset –mixed [commit] | 只改变提交点,同事改变暂存区的内容 |
git reset –hard [commit] | 暂存区和工作区的内容都会被修改到与提交点完全一致的状态 |
git reset –hard HEAD | 让工作区回到上次提交的状态 |
我们可以先用
git log
看一下当前历史版本,如下图所示:如果要回退到前一个版本,则只需要输入:
git reset HEAD~1
,执行完再看一下历史版本:我们已经回退到前一个版本了。如果需要回退到前2个版本,命令是:
git reset HEAD~2
,回退到前n个版本就是:git reset HEAD~n
如果需要回退到任何一个版本,则需要替换成该版本的
commit id
就可以了,例如:git reset a8336834b50daafa0793370
,执行完再看一下历史:
revert
git revert用一个新提交来消除一个历史提交所做的任何修改。
revert与reset的区别
git revert是用一次新的commit来回滚之前的commit
git reset是直接删除指定的commit。
在回滚这一操作上看,效果差不多。但是在日后继续merge以前的老版本时有区别。
- 因为git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch时,导致这部分改变不会再次出现,减少冲突。
- 但是git reset是之间把某些commit在某个branch上删除,因而和老的branch再次merge时,这些被回滚的commit应该还会被引入,产生很多冲突。
git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容。
push
- 上传本地仓库分支到远程仓库分支,实现同步。
命令 | 说明 |
---|---|
git push [remote] [branch] | 上传本地指定分支到远程仓库 |
git push [remote] –force | 强行推送当前分支到远程仓库,即使有冲突 |
git push [remote] -all | 推送所有分支到远程仓库 |
git pull
- 拉取远程分支到本地并合并,一般是本地分支的进度落后于远程分支时,需要使用该命令。
- 命令:
git pull origin master
,origin
表示远程代码库的一个别名(也可以修改为其他名字,可通过git remote
修改),master
表示需要拉取合并的分支名称。 - 常用
git pull --rebase origin master
用 rebase 的方式进行,不会产生 merge 保持分支干净、整洁
git tag
我们在客户端开发的时候经常有版本的概念,比如v1.0、v1.1之类的,不同的版本肯定对应不同的代码,所以我一般要给我们的代码加上标签,这样假设v1.1版本出了一个新bug,但是又不晓得v1.0是不是有这个bug,有了标签就可以顺利切换到v1.0的代码,重新打个包测试了。
所以如果想要新建一个标签很简单,比如
git tag v1.0
就代表我在当前代码状态下新建了一个v1.0的标签,输入git tag
可以查看历史 tag 记录。想要切换到某个tag怎么办?也很简单,执行
git checkout v1.0
,这样就顺利的切换到 v1.0tag的代码状态了。截止到图中的最近一次提交,我们完成了 1.0 版本的开发,则可以通过以下命令为其打上版本的标签。
命令:
1
2git tag v1.0 //为当前提交打上 v1.0 的标签
git tag v1.0 ab1591eb4e06c1e93fdd50126b9fab8a88d89155 //为这个节点打上 v1.0 的标签图中可以看出 v1.0 标签已经打上了。 如果发现标签打错了,想删除某个标签,则可以通过如下命令来执行。 命令:
git tag -d v1.0
删除 v1.0 标签如果想将标题推送到远程库,则可以使用如下命令来完成。 命令:
git push origin --tags
将打的 tag 都推送到远程库
其他命令
命令 | 说明 |
---|---|
git status | 显示有变更的文件 |
git log | 显示当前分支的版本历史 |
git diff | 显示暂存区和工作区的差异 |
git diff HEAD | 显示工作区与当前分支最新commit之间的差异 |
git cherry-pick [commit] | 选择一个commit,合并进当前分支 |
git show
显示信息,可用于显示某次提交或者某个 tag 相关的信息。
命令:
git show commit_id
显示某次提交的详细信息命令:
git show tag_name
显示某个 tag 的详细信息
git blame
查看文件每行的提交历史(追责),可用于查看某个文件中的每一行是那次提交产生的,是谁提交的,什么时候提交的,提交的版本号是多少等等详细信息,在实际工作中方便对出问题的代码进行追责,找到产生 BUG 的责任人。
命令:
git blame file_name
上图中可以看到
README.md
这个文件有 5 行,其中后 4 行都是我在 2018 年提交的,第 1 行是另外一个人在 2017 年提交的。
git stash
没有在git 版本控制中的文件,是不能被git stash 存起来的
常用git stash命令:
命令 说明 git stash save “save message” 执行存储时,添加备注,方便查找,只有git stash 也要可以的,但查找时不方便识别。 git stash list 查看stash了哪些存储 git stash show 显示做了哪些改动,默认show第一个存储,如果要显示其他存贮,后面加 stash@{$num}
,比如第二个git stash show stash@{1}
git stash show -p 显示第一个存储的改动,如果想显示其他存存储,命令:git stash show stash@{$num} -p ,比如第二个:git stash show stash@{1} -p git stash apply 应用某个存储,但不会把存储从存储列表中删除,默认使用第一个存储,即stash@{0},如果要使用其他个,git stash apply stash@{$num} , 比如第二个:git stash apply stash@{1} git stash pop 命令恢复之前缓存的工作目录,将缓存堆栈中的对应stash删除,并将对应修改应用到当前的工作目录下,默认为第一个stash,即stash@{0},如果要应用并删除其他stash,命令:git stash pop stash@{$num} ,比如应用并删除第二个:git stash pop stash@{1} git stash drop stash@{$num} 丢弃stash@{$num}存储,从列表中删除这个存储 git stash clear 删除所有缓存的stash 常规 git stash 的一个限制是它会一下暂存所有的文件。有时,只备份某些文件更为方便,让另外一些与代码库保持一致。一个非常有用的技巧,用来备份部分文件:
- add 那些你不想备份的文件(例如: git add file1.js, file2.js)
- 调用
git stash –keep-index
。只会备份那些没有被add的文件。 - 调用
git reset
取消已经add的文件的备份,继续自己的工作。
向 GitHub 提交代码
SSH
你拥有了一个 GitHub 账号之后,就可以自由的 clone 或者下载其他项目,也可以创建自己的项目,但是你没法提交代码。仔细想想也知道,肯定不可能随意就能提交代码的,如果随意可以提交代码,那么 GitHub 上的项目岂不乱了套了,所以提交代码之前一定是需要某种授权的,而 GitHub 上一般都是基于 SSH 授权的。
那么什么是 SSH 呢? 简单点说,SSH是一种网络协议,用于计算机之间的加密登录。
目前是每一台 Linux 电脑的标准配置。而大多数 Git 服务器都会选择使用 SSH 公钥来进行授权,所以想要在 GitHub 提交代码的第一步就是要先添加 SSH key 配置。
生成SSH key
Linux 与 Mac 都是默认安装了 SSH ,而 Windows 系统安装了 Git Bash 应该也是带了 SSH的。大家可以在终端(win下在 Git Bash 里)输入 ssh 如果出现提示证明你本机已经安装 SSH, 否则请搜索自行安装下。
紧接着输入 ssh-keygen -t rsa
,什么意思呢?就是指定 rsa 算法生成密钥,接着连续三个回车键(不需要输入密码),然后就会生成两个文件 id_rsa 和 id_rsa.pub ,而id_rsa 是密钥
,id_rsa.pub 就是公钥
。
1 | [sun@CMCC#1 ~]$ ssh-keygen -t rsa -b 4096 -C "your_mail@gmail.com" |
这两文件默认分别在如下目录里生成: Linux/Mac 系统 在 ~/.ssh
下,win系统在 /c/Documents and Settings/username/.ssh
下,都是隐藏文件,相信你们有办法查看的。
接下来要做的是把 id_rsa.pub 的内容添加到 GitHub 上,这样你本地的 id_rsa 密钥跟 GitHub上的 id_rsa.pub 公钥进行配对,授权成功才可以提交代码。
添加到 ssh-agent
将新 SSH 密钥添加到 ssh-agent 以管理密钥之前,应检查现有 SSH 密钥并生成新 SSH 密钥。
Start the ssh-agent in the background.
1
2eval "$(ssh-agent -s)"
Agent pid 59566如果您使用的是 macOS Sierra 10.12.2 或更高版本,则需要修改 ~/.ssh/config 文件以自动将密钥加载到 ssh-agent 中并在密钥链中存储密码。
1
2
3
4Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_rsa将 SSH 私钥添加到 ssh-agent 并将密码存储在密钥链中。 如果您创建了不同名称的密钥,或者您要添加不同名称的现有密钥,请将命令中的 id_rsa 替换为您的私钥文件的名称。
1
ssh-add -K ~/.ssh/id_rsa
添加 SSH key
第一步先在 GitHub 上的设置页面,点击最左侧 SSH and GPG keys : 然后点击右上角的 New SSH key 按钮: 需要做的只是在 Key 那栏把id_rsa.pub
公钥文件里的内容复制粘贴进去就可以了,Title 那栏不需要填写,点击 Add SSH key 按钮就ok了。
这里提醒下,怎么查看 id_rsa.pub 文件的内容? Linux/Mac 用户执行以下命令:
1 | cd ~/.ssh |
Windows用户,设置显示隐藏文件,可以使用 EditPlus 或者 Sublime 打开复制就行了。
SSH key 添加成功之后,输入 ssh -T git@github.com
进行测试,如果出现以下提示证明添加成功了。
Push & Pull
向GitHub 提交代码 在提交代码之前我们先要了解两个命令,也是上次的文章没有介绍的,因为这两个命令需要跟远程仓库配合。
Push
:直译过来就是「推」的意思,什么意思呢?如果你本地代码有更新了,那么就需要把本地代码推到远程仓库,这样本地仓库跟远程仓库就可以保持同步了。
代码示例: git push origin master
意思就是把本地代码推到远程 master 分支。
Pull
:直译过来就是「拉」的意思,如果别人提交代码到远程仓库,这个时候你需要把远程仓库的最新代码拉下来,然后保证两端代码的同步。 代码示例: git pull origin master
意思就是把远程最新的代码更新到本地。一般我们在 push 之前都会先 pull
,这样不容易冲突。
提交代码
- 添加 SSH key 成功之后,我们就有权限向 GitHub 上我们自己的项目提交代码了,而提交代码有两种方法:
Clone自己的项目 我们以我在 GitHub 上创建的 test 项目为例,执行如下命令:
1
2
3git clone git@github.com:fulsun/test.git
git clone -b <指定分支名> <远程仓库地址> --depth=1
depth用于指定克隆深度,为1即表示只克隆最近一次commit.- 这样就把 test 项目 clone 到了本地,你可以把 clone 命令理解为高级点的复制
- 这个时候该项目本身就已经是一个git 仓库了,不需要执行 git init 进行初始化,而且甚至都已经关联好了远程仓库,我们只需要在这个 test 目录下任意修改或者添加文件,然后进行 commit
- 之后就可以执行:
git push origin master
进行代码提交,这种是最简单方便的一种方式。
关联本地已有项目 如果我们本地已经有一个完整的 git 仓库,并且已经进行了很多次 commit,这个时候第一种方法就不适合了。
假设我们本地有个 test2 的项目,我们需要的是在 GitHub 上建一个 test 的项目,然后把本地test2 上的所有代码 commit 记录提交到 GitHub 上的 test 项目。
第一步就是在 GitHub 上建一个 test 项目,这个想必大家都会了,就不用多讲了。
第二步把本地 test2 项目与 GitHub 上的 test 项目进行关联,切换到 test2 目录,执行如下命令:
1
2
3
4
5
6
7
8
9# 添加一个远程仓库,他的地址是`git@github.com:fulsun/test.git`
# origin 是给这个项目的远程仓库起的名字,名字你可以随便取
git remote add origin git@github.com:fulsun/test.git
# 查看我们当前项目远程仓库命令:
git remote -v
# 向远程仓库进行代码提交
git push origin master
友情提醒
在提交代码之前先要设置下自己的用户名与邮箱,这些信息会出现在所有的 commit 记录里,执行以下代码就可以设置:
1 | # 用户名和邮箱也可以填写别的(只要是用户名和邮箱格式就OK)。 |
Git工作流程
4个专有名词解释
- Workspace:工作区
- Index / Stage:暂存区
- Repository:仓库区(或本地仓库)
- Remote:远程仓库
工作区
程序员进行开发改动的地方,是你当前看到的,也是最新的。
平常我们开发就是拷贝远程仓库中的一个分支,基于该分支进行开发。在开发过程中就是对工作区的操作。
暂存区
.git目录下的index文件, 暂存区会记录 git add
添加文件的相关信息(文件名、大小、timestamp…),不保存文件实体, 通过id指向每个文件实体。可以使用 git status查看暂存区的状态。暂存区标记了你当前工作区中,哪些内容是被git管理的。
当你完成某个需求或功能后需要提交到远程仓库,那么第一步就是通过 git add
先提交到暂存区,被git管理。
本地仓库
保存了对象被提交 过的各个版本,比起工作区和暂存区的内容,它要更旧一些。
git commit
后同步index的目录树到本地仓库,方便从下一步通过 git push
同步本地仓库与远程仓库的同步。
远程仓库
远程仓库的内容可能被分布在多个地点的处于协作关系的本地仓库修改,因此它可能与本地仓库同步,也可能不同步,但是它的内容是最旧的。
小结
- 任何对象都是在工作区中诞生和被修改;
- 任何修改都是从进入index区才开始被版本控制;
- 只有把修改提交到本地仓库,该修改才能在仓库中留下痕迹;
- 与协作者分享本地的修改,可以把它们push到远程仓库来共享。
下面这幅图更加直接阐述了四个区域之间的关系,可能有些命令不太清楚,没关系,下部分会详细介绍。
团队协作应用
在团队协作过程中一般会有多个分支,比如有默认的 master 分支,有用于开发的 dev 分支,还有用于测试的 test 分支,用于对外发布的 release 分支,以及每个开发人员开发不同功能时用到的 feature_xx 分支等等。
公司中一般是用 GitLab 搭建的代码托管服务,几个人的小团队也可以自己搭建。
每个团队业务不一样,分支数量的设置也会不一样,下面我介绍一下我们团队的分支设置,以及普通开发人员和项目 leader 对不同分支的不同权限以及不同的操作。
分支设置
- 我们常用的分支有3个(master 分支、dev 分支、test 分支)以及若干个 feature_xx 分支。
master
分支:是主分支,是最终上线代码的分支,该分支被设置被保护分支(锁住),普通开发人员没有权限操作,只有团队 leader 有合并的权限;dev
分支:是用于开发的分支,该分支被设置为默认 clone 的分支,也用于合并到 master 之前进行测试的分支,普通开发人员从远程 clone 到本地的默认分支,可以进行合并等操作;test
分支:是用于测试的分支,测试人员可以将自己开发分支中的修改合并到 test 分支在测试环境进行测试,一般该分支不合并到任何分支;feature_xx
分支:是用户开发自己模块功能的特征分支,可以叫 feature_login, feature_ui, feature_payment 等与开发的功能相关的名称,该分支上的功能开发完、测试无误后可合并到 dev 分支上。
普通开发人员的操作
普通开发人员,一般按照如下几个步骤来进行开发、测试工作就可以了:
- 将远程 dev 分支 clone 到本地,例如:
git clone git@github.com:goto456/test.git
; - 从 dev 分支拉出(新建)自己的 feature 分支用于开发,例如:
git checkout -b feature_login
; - 在自己的 feature 分支上进行开发工作;
- 开发完了用 add、commit 等操作提交到当前分支;
- 如果需要在测试环境进行测试,则将远程 test 分支拉到本地,例如:
git branch test origin/test
; - 将自己的 feature 分支合并到 test 分支,并将 test 分支 push 到远程,例如:
git rebase test
,git checkout test
,git merge feature_login
,git push origin test
;(注意:我们推荐用 rebase 来合并,以保证分支的整洁、美观) - 通过公司的发布平台将远程 test 分支发布到测试环境进行测试;
- 如果测试没问题或者开始就不需要测试,这可以直接将当前 feature 分支合并到 dev 分支,并 push 到远程库,例如:
git rebase dev
,git checkout dev
,git merge feature_login
,git push origin dev
;(注意:我们推荐用 rebase 来合并,以保证分支的整洁、美观) - 这时表示该功能已经开发完成了,代码的 review 以及发布,需要团队 leader 在合并到 master 操作时进行;这时可以删除了自己的 feature 分支,例如:
git branch -d feature_login
; - 如果在 push 到远程的时候提示需要先 pull 时,我们推荐使用 rebase 的方式:
git pull --rebase
以保持分支的整洁、美观。
团队 leader 的操作
因为只有 leader 有操作 master 分支的权限,所以需要完成 dev 分支到 master 分支的合并,以及后续打 tag 和正式上线发布的工作:
- 先切换到 dev 分支,并拉取最新的状态,例如:
git checkout dev
,git pull --rebase origin dev
; - 进行代码 review 等过程后,合并到 master 分支,例如:
git rebase master
,git checkout master
,git merge dev
;(注意:我们推荐用 rebase 来合并,以保证分支的整洁、美观) - 为本次完成的版本打上标签,例如:
git tag v1.0 -m "release version 1.0"
; - 将本地合并后的 master 分支以及标签 push 到远程库,例如:
git push orgin master --tags
。
Git 工作流
- GItFlow是在项目开发过程中使用 Git 的方式
分类
- 集中式工作流 :像 SVN 一样,集中式工作流以中央仓库作为项目所有修改的单点实体。所有修改都提交到Master 这个分支上。 这种方式与 SVN的主要区别就是开发人员有本地库。Git 很多特性并没有用到。
- GitFlow工作流:为功能开发、发布准备和维护设立了独立的分支,让发布迭代过程更流畅。严格的分支模型也为大型项目提供了一些非常必要的结构
- Forking 工作流:在 GitFlow 基础上,充分利用了 Git 的 Fork 和 pull request 的功能以达到代码审核的目的。更适合安全可靠地管理大团队的开发者,而且能接受不信任贡献者的提交。
详解
分支种类
- 主干分支 master: 主要负责管理正在运行的生产环境代码。永远保持与正在运行的生产环境完全一致。
- 开发分支 develop: 主要负责管理正在开发过程中的代码。一般情况下应该是最新的代码。
- bug 修理分支 hotfix: 主要负责管理生产环境下出现的紧急修复的代码。 从主干分支分出,修理完毕并测试上线后,并回主干分支。并回后,视情况可以删除该分支。
- 准生产分支(预发布分支) release: 较大的版本上线前,会从开发分支中分出准生产分支,进行最后阶段的集成测试。该版本上线后,会合并到主干分支。生产环境运行一段阶段较稳定后 可以视情况删除。
- 功能分支 feature: 为了不影响较短周期的开发工作,一般把中长期开发模块,会从开发分支 中独立出来。 开发完成后会合并到开发分支。
Github跨团队协作
- 假设zs团队在开发,要请ls团队协作。
- ls登录Github账户,forkzs的项目后
- 修改本地代码后,推送到远程仓库中,访问Github后,点击
Pull Request
,新建一个pull请求。 - 这时候zs登录github后可以在pull request 中看到请求, 可以进行交流和审核提交的代码。
- 确认无误后,合并代码,选择
merge pull request
,填写操作的日志信息后, confirm merge即可。 - zs团队后续继续开发,ls要获取代码,同样取zs项目和自己项目的diff,创建pull request ,然后merge即可。
结束语
以上就是我从自己平时的应用中整理出的一个比较简洁的教程,以及我们团队在实际工作中是如何使用的。希望对大家有所帮助!