封面来源:本文封面来源于 Git 官网,如有侵权,请联系删除。

学习链接:Git大全 Git命令学习

1. 版本控制

版本控制含义

版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。

  • 实现跨区域多人协同开发
  • 追踪和记载一个或者多个文件的历史记录
  • 组织和保护你的源代码和文档
  • 统计工作量
  • 并行开发、提高开发效率
  • 跟踪记录整个软件的开发过程
  • 减轻开发人员的负担,节省时间,同时降低人为错误

简单说就是 用于管理多人协同开发项目的技术

没有进行版本控制或者版本控制本身缺乏正确的流程管理,在软件开发过程中将会引入很多问题,如软件代码的一致性、软件内容的冗余、软件过程的事物性、软件开发过程中的并发性、软件源代码的安全性,以及软件的整合等问题。

如果我们没有版本控制,会增加我们的负担和时间开销。方案一次又一次地变,我们一次又一次地改,改到最后还说第一个版本的好?👿

无论是工作还是学习,或者是自己做笔记,都经历过这样一个阶段!我们就迫切需要一个版本控制工具!多人开发更需要版本控制,不然代价会十分大!

版本控制工具

主流的版本控制器有如下这些:

  • Git
  • SVN(Subversion)
  • CVS(Concurrent Versions System)
  • VSS(Micorosoft Visual SourceSafe)
  • TFS(Team Foundation Server)
  • Visual Studio Online

版本控制产品非常多(Perforce、Rational ClearCase、RCS(GNU Revision Control System)、Serena Dimention、SVK、BitKeeper、Monotone、Bazaar、Mercurial、SourceGear Vault),现在影响力最大且使用最广泛的是 GitSVN

版本控制分类

1、本地版本控制系统

记录文件每次的更新,可以对每个版本做一个快照,或是记录补丁文件,适合个人用,如 RCS。它是在一台机器上,记录版本的不同变化,保证内容不会丢失。

但是,如果多人开发,每个人都在不同的系统和电脑上开发,没办法协同工作。

2、集中版本控制系统

所有的版本数据都保存在服务器上,协同开发者从服务器上同步更新或上传自己的修改。

所有的版本数据都存在中央服务器上,中央服务器可以来管理代码的版本和备份,用户的本地只有自己以前所同步的版本,所有的用户电脑都是从中央服务器中获取代码或者是将本地的代码提交到中央服务器。

如果不连网的话,用户就看不到历史版本,也无法切换版本验证,或在不同分支工作。而且,所有数据都保存在单一的服务器上,有很大的风险这个服务器会损坏,这样就会丢失所有的数据(当然可以定期备份)。代表产品:SVN、CVS、VSS。

集中式版本控制

3、分布式版本控制系统

需要一台服务器作为代码仓库,所有版本信息仓库全部同步到本地的每个用户,这样就可以在本地查看所有版本历史。用户可以本地离线提交,只需在联网时 push 到相应的服务器或其他用户那里。每个用户的电脑都是一个服务器(代码仓库),并且和代码仓库是镜像的,用户修改和获取代码都是提交到自己的服务器当中。由于每个用户那里保存的都是所有的版本数据,只要有一个用户的设备没有问题就可以恢复所有的数据,但这增加了本地存储空间的占用。

不会因为服务器损坏或者网络问题,造成不能工作的情况!

但因为每个人都拥有全部的代码,这存在着安全隐患!

Git 与 SVN 的区别

  • SVN 是集中式版本控制系统,版本库是集中放在中央服务器的,而工作的时候,用的都是自己的电脑,所以首先要从中央服务器得到最新的版本,然后工作,完成工作后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,对网络带宽要求较高。

  • Git 是分布式版本控制系统,没有中央服务器,每个人的电脑就是一个完整的版本库,工作的时候不需要联网了,因为版本都在自己电脑上。协同的方法是这样的:比如说自己在电脑上改了文件 A,其他人也在电脑上改了文件 A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。Git 可以直接看到更新了哪些代码和文件!

Git是目前世界上最先进的分布式版本控制系统

2. Git 的历史

同生活中的许多伟大事物一样,Git 诞生于一个极富纷争大举创新的年代。

Linux 内核开源项目有着为数众广的参与者。绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002 年间)。到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统 BitKeeper 来管理和维护代码。

Linux 社区中存在很多的大佬!破解研究 BitKeeper !

到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用 BitKeeper 时的经验教训,开发出自己的版本系统(开发使用了两周时间,这就是真大佬吧😱), 也就是后来的 Git!

Git是目前世界上最先进的分布式版本控制系统。

Git是免费、开源的,最初Git是为辅助 Linux 内核开发的,来替代 BitKeeper!

李纳斯·托沃兹

Linux 和 Git 之父李纳斯·托沃兹(Linus Benedic Torvalds)1969、芬兰

3. Git 环境配置

3.1 安装与卸载 Git

打开 git官网,下载 git 对应操作系统的版本。

所有东西下载慢的话就可以去找镜像!

如果官网下载太慢,我们可以使用淘宝镜像下载:Git镜像下载

Git官网

进入镜像后,拖至最下方,进入稳定版的下载,然后根据自己操作系统的情况下载并进行安装。

Git镜像下载_1 Git镜像下载_2

安装时使用“傻瓜式”安装,无脑下一步即可。PS:注意按自己需求修改安装路径!😏

安装时还可以修改默认编辑器,使用无敌的 Vim 即可。

Git 的卸载

使用 国内各种管家软件或打开控制面板进行卸载即可,最后记得删除与 Git 相关的、在 path 下的环境变量!

启动Git

安装成功后在开始菜单中会有 Git 项,菜单下有 3 个程序:任意文件夹下右键也可以看到对应的程序!

开始菜单Git项

Git Bash: Unix 与 Linux 风格的命令行(使用最多,推荐使用)

Git CMD: Windows 风格的命令行

Git GUI: 图形界面的 Git,不建议初学者使用,尽量先熟悉常用命令

你在使用时,可以在某一目录中点击右键,点击“Git Bash Here”就可以再当前目录下打开 Git Bash。

3.2 Linux 常用命令

Git 内部使用的命令就是 Linux 的命令,常用的有以下命令:

1、cd:改变目录。

2、cd . . :回退到上一个目录,直接 cd 进入默认目录

3、pwd:显示当前所在的目录路径。

4、ls(ll):都是列出当前目录中的所有文件,只不过 ll(两个 ll)列出的内容更为详细。

5、touch:新建一个文件。如 touch index.js 就会在当前目录下新建一个 index.js 文件。

6、rm:删除一个文件。如 rm index.js 就会把 index.js 文件删除。

7、mkdir:新建一个目录,就是新建一个文件夹。

8、rm -r:删除一个文件夹,rm -r src 删除 src 目录。

9、mv:移动文件。

10、reset:重新初始化终端/清屏。

11、clear:清屏。

12、history:查看命令历史。

13、help:帮助。

14、exit:退出。

15、#:表示注释

建议平时学习时多使用以上命令,熟能生巧~ 😜

3.3 Git 配置

首先我们要明白:所有的配置文件,其实 都保存在本地

我们可以使用命令 git config -l 查看全部配置信息:

Git配置信息

我们还可以使用以下命令,查看不同级别的配置信息:

1
2
3
4
5
#查看系统config
git config --system --list
  
#查看当前用户(global)配置
git config --global --list

Git 相关的本地配置文件位置:

  • Git 安装目录 \etc\gitconfig:Git 安装目录下的 gitconfig --system 系统级配置文件

  • C:\Users\你的用户名\ .gitconfig:只适用于当前登录用户的配置 --global 全局配置文件

当前用户配置文件信息

可以直接在这里编辑配置文件,通过命令设置后会响应到这里。

设置用户名与邮箱 这很重要! 这很重要! 这很重要!

当你安装 Git 后首先要做的事情是设置你的用户名和 email 地址。这是 非常重要 的,因为每次 Git 提交都会使用该信息,它被永远的嵌入到了你的提交中。所以!你必须进行设置!! 这很重要 * 3

如果你刚安装 Git,也没有进行设置用户名和邮箱,运行 git config --global --list,会出现下图中第一种情况,我们需要按照第二与第三个类似命令来设置你的用户名🏃和邮箱✉️(我在此处设置的是我自己的用户名 mofan 与我的邮箱,你需要设置属于你自己的用户名和邮箱)。

配置文件编写

只需要做一次这个设置,如果你传递了 --global 选项,因为 Git 将总是会使用该信息来处理你在系统中所做的一切操作。如果你希望在一个特定的项目中使用不同的名称或 email 地址,你可以在该项目中运行该命令而不要 --global 选项。总之 --global 为全局配置,不加为某个项目的特定配置。

设置好用户名和邮箱后,我们再运行 git config --global --list,就会显示你刚设置的用户名和邮箱了。你也可以前往 C:\Users\你的用户名\.gitconfig 文件中进行查看。

4. Git 基本理论

三大区域

Git本地有三个工作区域:工作目录(Working Directory)、暂存区(Stage/Index)、资源库(Repository 或 Git Directory)。如果在加上远程的 git 仓库(Remote Directory)就可以分为四个工作区域。

文件在这四个区域之间的转换关系如下:

Git三大区域

  • Workspace:工作区,就是你平时存放项目代码的地方。
  • Index / Stage:暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息。
  • Repository:仓库区(或本地仓库),就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中 HEAD 指向最新放入仓库的版本。
  • Remote:远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换。

本地的三个区域确切的说应该是 Git 仓库中 HEAD 指向的版本:

图解三大区域
  • Directory:使用 Git 管理的一个目录,也就是一个仓库,包含我们的工作空间和 Git 的管理空间。
  • WorkSpace:需要通过 Git 进行版本控制的目录和文件,这些目录和文件组成了工作空间。
  • .git:存放 Git 管理信息的目录,初始化仓库的时候自动创建。(这是个隐藏文件
  • Index/Stage:暂存区,或者叫待提交更新区,在提交进入 repo 之前,我们可以把所有的更新放在暂存区。
  • Local Repo:本地仓库,一个存放在本地的版本库;HEAD 会只是当前的开发分支(branch)。
  • Stash:隐藏,是一个工作状态保存栈,用于保存/恢复 WorkSpace 中的临时状态。

工作流程

git 的工作流程一般是这样的:

1、在工作目录中添加、修改文件;

2、将需要进行版本管理的文件放入暂存区域;

3、将暂存区域的文件提交到git仓库。

因此,git 管理的文件有三种状态:已修改(modified),已暂存(staged),已提交(committed)。

Git工作流程

图解 Git 教程

图解Git教程

5. Git 项目搭建

创建工作目录与常用指令

工作目录(WorkSpace)一般就是你希望 Git 帮助你管理的文件夹,可以是你项目的目录,也可以是一个空目录。

建议要求不要有中文。

日常使用只要记住下图 6 个命令:

Git常用命令

本地仓库搭建

创建本地仓库的方法有两种:一种是创建全新的仓库,另一种是克隆远程仓库。

1、创建全新的仓库,需要用 Git 管理的项目的根目录执行:

1
2
# 在当前目录新建一个Git代码库
git init

2、执行后可以看到,仅仅在项目目录多出了一个.git目录,关于版本等的所有信息都在这个目录里面。

克隆远程仓库

1、一种方式是克隆远程目录,就是是将远程服务器上的仓库完全镜像一份至本地!

1
2
# 克隆一个项目和它的整个代码历史(版本信息)
git clone [url]

2、去 gitee 或者 github 上克隆一个测试!

图解示例:

复制仓库URL

![Git clone远程仓库](https://mofan-blog-pics.oss-cn-chengdu.aliyuncs.com/ToolsImages/Git clone远程仓库.png)

根据以上操作👆,​即可在你选中的目录下 clone 远程仓库文件!

删除仓库

Gitee 中的操作:

进入 Gitee 中需要删除的仓库,点击“管理” — 仓库设置 — 删除仓库,根据界面提示进行操作即可。

GitHub 中的操作:

进入 Gitee 中需要删除的仓库,点击“Settings”,下拉网页至最后“Danger Zone”,选中并点击“Delete this Repository”,然后根据界面提示进行操作即可。

6. Git 文件操作

文件的四种状态

版本控制就是对文件的版本控制,要对文件进行修改、提交等操作,首先要知道文件当前在什么状态,不然可能会提交了现在还不想提交的文件,或者要提交的文件没提交上。

1、Untracked:未跟踪,此文件在文件夹中,但并没有加入到 git 库,不参与版本控制。可以通过 git add 状态变为 Staged。

2、Unmodify:文件已经入库,且未修改,即版本库中的文件快照内容与文件夹中完全一致。这种类型的文件有两种去处,如果它被修改,而变为 Modified;如果使用 git rm 移出版本库, 则成为 Untracked 文件。

3、Modified:文件已修改, 仅仅是修改,并没有进行其他的操作。这个文件也有两个去处,通过 git add 可进入暂存 Staged 状态;使用 git checkout 则丢弃修改过, 返回到 Unmodify 状态, 这个 git checkout 表示从库中取出文件,覆盖当前修改 !

4、Staged:暂存状态。执行 git commit 则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为 Unmodify 状态。执行 git reset HEAD filename 取消暂存, 文件状态为 Modified。

查看文件状态

👆上面说文件有4种状态,那么我们通过如下命令可以查看到文件的状态:

1
2
3
4
5
6
7
8
9
10
11
# 查看指定文件状态
git status [filename]

# 查看所有文件状态
git status

# 添加所有文件到暂存区
git add .

# 提交暂存区中的内容到本地仓库 -m 提交信息
git commit -m "消息内容"

忽略文件

有些时候不想把某些文件纳入版本控制中,比如数据库文件,临时文件,设计文件等,这时候我们就需要忽略某些文件。可以这么操作:

在主目录下建立“.gitignore”文件,此文件有如下规则:

1、忽略文件中的空行或以井号 # 开始的行将会被忽略。

2、可以使用 Linux 通配符。例如:星号 * 代表任意多个字符,问号 ? 代表一个字符,方括号 [] 代表可选字符范围,大括号 {} 代表可选的字符串等。

3、如果名称的最前面有一个感叹号 !,表示例外规则,将不被忽略。

4、如果名称的最前面是一个路径分隔符 /,表示要忽略的文件在此目录下,而子目录中的文件不忽略。

5、如果名称的最后面是一个路径分隔符 /,表示要忽略的是此目录下该名称的子目录,而非文件(默认文件或目录都忽略)。

1
2
3
4
5
*.txt        # 忽略所有 .txt 结尾的文件,这样的话上传就不会被选中!
!lib.txt # 但 lib.txt 除外
/temp # 仅忽略项目根目录下的 TODO 文件,不包括其它目录 temp
build/ # 忽略 build/ 目录下的所有文件
doc/*.txt # 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

IDEA 常用忽略文件内容:

1
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
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs
hs_err_pid*
.classpath
.project
.settings
target
.idea
*.iml

7. Gitee 的使用

我们可以使用 GitHub 或者 Gitee,但是 GitHub 是有墙的,因此我们经常选择使用 Gitee,而在公司中,公司有时候会搭建自己的 GitLab 服务器。

Gitee

1、首先,我们需要注册码云(注册过的登录就行)并完善个人信息!

2、为了方便使用,我们需要设置本机绑定SSH公钥(gōng yuè),实现免密码登录!(要求

冷知识:公钥、私钥、密钥中,钥都读 yuè。😱

1
2
3
4
5
# 进入 C:\Users(用户)\你的用户名 目录
# 如果你是第一次设置,在这个目录下看不到.ssh目录
# 在上述目录下右键打开“Git Bash Here”,运行以下命令并生成公钥
ssh-keygen -t rsa -C 邮箱或其他描述性文字
# rsa是加密方式
Git秘钥生成

我们来对输入的命令以及执行命令后需要输出的情况进行解析:

参考链接:SSH-keygen用法

1
ssh-keygen -t rsa -C "your_email@example.com"

以上代码省略了 -f 参数,因此,运行上面那条命令后会让你输入一个文件名,用于保存刚才生成的 SSH key 代码,如:

1
2
Generating public/private rsa key pair.
# Enter file in which to save the key (/c/Users/you/.ssh/id_rsa): [Press enter]

你也可以不输入文件名,使用默认文件名(推荐),那么就会生成 id_rsa 和 id_rsa.pub 两个秘钥文件。(我在此使用默认文件名)

接着又会提示你输入两次密码(该密码是你 push 文件的时候要输入的密码,而不是 Gitee 或 GitHub 管理者的密码),你也可以不输入密码,直接按回车。那么 push 的时候就不需要输入密码,直接提交到 Github 上了,如:(我在此直接回车,不输入密码)

1
2
Enter passphrase (empty for no passphrase): 
# Enter same passphrase again:

接下来,就会显示如下代码提示,如:

1
2
3
4
Your identification has been saved in /c/Users/you/.ssh/id_rsa.
# Your public key has been saved in /c/Users/you/.ssh/id_rsa.pub.
# The key fingerprint is:
# 01:0f:f4:3b:ca:85:d6:17:a1:7d:f0:68:9d:f0:a2:db your_email@example.com

当你看到上面这段代码的收,那就说明,你的 SSH key 已经创建成功,你只需要添加到 Gitee 或 GitHub 的 SSH key 上就可以了。


我们继续 SSH 的配置:

3、打开 Gitee 并进行登录,设置 — 安全设置 — SSH 公钥

4、然后打开目录 C:\Users(用户)\你的用户名\.ssh,将 id_rsa.pub 文件内的内容复制到公钥填写处,然后点击“确定”,输入 Gitee 的密码即可添加成功!

公钥复制

PS:id_rsa 存放的是私钥,id_rsa.pub 存放的是公钥,我们在此复制公钥的内容!

5、运行 Git Bash,输入命令 ssh -T git@gitee.com(如果使用 GitHub,输入 ssh -T git@github.com),然后输入 yes。

6、到此,我们的 SSH 免密登录就配置完成了。

7、如果我们需要新建仓库,轻触上方导航栏中的“+”然后点击“新建仓库”即可:

Gitee创建仓库

8、然后我们 clone 创建的仓库到本地即可。

8. IDEA 中集成 Git

IDEA 配置 Git

首先我们需要在我们的 IDEA 中配置 Git,打开 IDEA,settings — Version Control — Git — Path to Git executable,在此处配置你 Git 安装目录下的 exe 文件。例如:D:\environment\Git\cmd\git.exe,其中 D:\environment\Git 是我的安装目录。(最新版不需要进行配置,IDEA 已经帮我们配置好,以防万一我们可以查看一下!😁)

然后我们可以点击“test”,查看我们的配置是否正确。

你还可以选择 settings — Version Control — GitHub,添加你的 GitHub 账号到 IDEA 中。

IDEA 项目绑定 Git

1、新建项目,绑定 Git。


在此给出两种绑定方式(推荐第二种):

  • 在 clone 的远程仓库的文件中使用 IDEA 创建项目。
  • 使用 IDEA 新建一个项目,将 clone 的远程仓库文件的内容全部复制到项目中。(提示同名文件时,替换即可)

为什么这么做?因为 clone 的远程仓库文件中的 .git 文件已经绑定了远程仓库,我们需要我们的项目中也有 .git 文件。

IDEA 绑定 Git 后,我们操作 Git 后可以在 IDEA 观察到文件颜色的变化

  • 巧克力色 —— 文件尚未添加至暂存区
  • 橄榄色 —— 被忽略而不会被提交的文件
  • 绿色 —— 文件已添加至暂存区
  • 黑色 —— 文件已提交至本地库
  • 蓝色 —— 当前文件被修改,但尚未提交至本地库

2、编写代码,修改文件,使用 IDEA 操作 Git。

我们可以使用右上角 IDEA 集成的 Git 按钮进行操作,也可以使用 IDEA 的命令行进行操作。

注意:这里的非 Git 命令使用的是 Windows 的命令,别使用成了 Linux。

  • 添加到暂存区 git add .
  • commit 提交 git commit -m "your message"
  • push 到远程仓库 git push

除了以上命令,我们还可以右键点击某个修改的文件进行提交。(右键点击文件 — Git — 你的操作)

忽略文件创建

我们不希望将 IDEA 的配置文件(.idea)push 到远程仓库,我们在 .gitignore 文件中添加 .idea/ 即可。那如果创建的是非 SpringBoot 项目,项目中没有 .gitignore 文件呢

  • 我们可以自己手动新建 .gitignore 文件。
  • 还可以右键点击项目,Git — add to .gitignore — 选择 Add to .gitignore 或者 .git/info/exclude。如果你使用 Add to .gitignore,后续还需要提交 .gitignore 文件;如果使用 .git/info/exclude,就不用提交 .gitignore 文件,因此推荐使用第二种方式。两种忽略文件的书写方式是一样的。

IDEA Git 切换版本

图形化界面操作:

1、右击项目 — Git — show History(或者直接点击 IDEA 工具栏集成的 Git 操作图标,这个图标像一个钟表)

2、在 IDEA 下方的 Version Control 窗口中选中需要切换的版本,右键点击 — Copy Revision Number (建议将当前版本和想切换的版本的序列号 都进行复制

3、右击项目 — Git — Repository — Reset HAND… ,Reset Type 选择 Hard,To commit 粘贴你想切换的版本序列号,最后点击 Reset即可。如果我们从版本 3 切换到版本 1 后,还想回到版本 1,这个时候就只能用命令行的方式了。这也是为什么建议在复制版本号时复制当前和切换的两个版本号。

命令行操作:

1、前两步不变。

2、打开 IDEA 的 Terminal,输入以下命令:

1
git reset --hard xxxxxxx #最后的xxx是复制的版本号

3、如果需要把修改 push 到远程仓库,那么可以输入以下命令:

1
git push -f -u origin master # origen表示当前账户,mater表示主分支

当然你也可以直接 git push

IDEA Git 克隆远程仓库

1、进入 Gitee 或 GitHub 复制项目地址

2、进入 IDEA,菜单栏中点击 VCS — Git — Clone…

3、输入复制的 URL,Directory 必须选择一个空的文件夹。等待 Clone 完成…

4、Clone 完毕后,IDEA 会提示是否创建一个项目,根据需要选择

5、然后 IDEA 又会提示在当前窗口还是新窗口打开,根据需要选择

6、完成后,我们需要对工程进行设置。菜单栏点击 File — Project Settings,在 Project 中选择 JDK 版本,在 Modules 选择 Clone 的项目。

7、我们在 Clone 的项目中进行编码,然后 push 到远程仓库时我们可能需要设置文件忽略。文件忽略方式点击查看:忽略文件创建

Clone 远程仓库文件建议使用这种方式:项目绑定Git

9. Git 分支

切换分支的本质就是移动 HEAD 指针。

为什么要有分支?在 Git 中一定会有一个 master 主分支,同时我们也可以创建其他名字的分支。我们一般将 master 分支作为产品正式上线的分支,我们还可以创建一个 dev 分支作为开发分支,我们平时编写的代码就提交到 dev 分支中,等产品上线时合并分支就可以了。这样做可以使开发的代码与上线的代码不冲突,如果不使用 dev 分支,平时编写的代码都提交到 master 主分支,万一新编写的代码与旧代码产生了冲突,产品又等着上线,那么上线的时间就只能延期了,而且也不方便进行排查修改。

分支就是科幻电影里面的平行宇宙,如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,我们就需要处理一些问题了!

Git项目分支

分支的运用

多个分支如果并行执行,不会导致我们代码冲突,也就是同时存在多个版本!

如果同一个文件在合并分支时都被修改了则会引起冲突:解决的办法是我们可以修改冲突文件后重新提交!选择要保留他的代码还是你的代码!

master 主分支应该非常稳定,用来发布新版本,一般情况下不允许在上面工作,工作一般情况下在新建的 dev 分支上工作,工作完后,比如上要发布,或者说 dev 分支代码稳定后可以合并到主分支 master 上来。

实际开发时,通常有多个开发者向一个远程仓库提交代码,为了保证 master 分支的稳定性,一般每人都拉取一个个人分支并在个人分支上进行编码,然后将个人分支合并到 dev 分支上(对应 dev 环境,用于自测),构建代码,进行简单的自测。自测没问题后,将个人分支合并到 master 分支上(对应 test 环境,用于测试),构建代码,交由测试人员进行测试。

Git 分支中常用指令

1
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
30
31
32
33
34
35
36
37
38
# 列出所有本地分支。-a 表示列出所有分支,包括远程分支
git branch [-a]

# 列出所有远程分支
git branch -r

# 新建一个分支,但依然停留在当前分支
git branch [branch-name]

# 切换到某个分支
git checkout [branch-name]

# 新建一个分支,并切换到该分支
git checkout -b [branch]

# 合并指定分支到当前分支
git merge [branch]

# 删除本地分支
git branch -d [branch-name]

# 删除远程分支
git push origin --delete [branch-name]

# 删除远程分支(相当于使用一个空分支来覆盖原来的分支)
git push origin :branch-name

# 查看本地分支和追踪情况
git remote show origin

# 删除对分支的远程跟踪,但这个分支仍然在远程
git branch -dr [remote/branch]

# 更新本地 git 分支与远程分支同步(保留本地存在的分支)
git remote update origin --prune

# 删除本地多余分支(即远程已经不存在的分支)
git remote prune origin

IDEA 图形化界面分支操作

创建分支:

右击项目 — Git — Repository — Branches — New Branch

如何判断当前在哪个分支:

右击项目 — Git — Repository — Branches ,Local Branches 下最上方的就是当前分支。

切换分支:

右击项目 — Git — Repository — Branches ,选中需要切换的分支,单击 Checkout。

合并分支:

右击项目 — Git — Repository — Branches — Merge Changes…

push 到远程仓库:

右击项目 — Git — Repository — push

IDEA Git 更新本地库

如果有人在我们 push 代码之前已经将他的代码 push 到远程仓库了,这时候我们再 push 代码到远程仓库时,要保证本地库是最新的。因此,我们就需要更新我们的本地库。

如何更新本地库?我们依然可以直接 push 我们的代码到远程仓库,但这时候 IDEA 会弹出“Push Rejected”的对话框,我们点击“Merge”或“Rebase”就可以更新本地仓库了。

除此之外,我们还可以直接拉取(pull)远程仓库文件:

右击项目 — Git — Repository — pull

pull 命令行:Git命令之Pull从库拉取

10. 团队协作

10.1 团队内协作

Git团队内协作

假设人员 A 与人员 B 处于同一团队中,如果在同一家公司对同一个项目进行开发的两个人员。

首次由人员 A 初始化仓库,并 push 一系列代码,然后由人员 B clone 项目到本地并开发新的特性,开发完毕后提交 push 到远程仓库,这次人员 A 就可以拉取 pull 远程库的代码看到人员 B 的提交内容。

10.2 跨团队协作

Git跨团队协作

假设人员 A 与人员 B 处于同一团队中,而人员 C 并不处于这一团队,就像我们首次为开源项目提交代码一样。

从人员 C 的角度出发:对源远程库进行 fork,拉取 fork 的远程库,在本地进行修改后提交到远程库,然后可以发送 pull request,等待审核成功后即可合并到真正的远程库。

11. 其他常用命令

11.1 其他常用命令一览

命令 作用
git reflog 查看版本信息
git log 查看版本详细信息
git reset --hard 版本号(7 位) 版本穿梭
git reset --hard HEAD~3 回退到前 3 次提交之前,以此类推,回退到前 n 次提交前
git reset --hard HEAD^ 穿梭到上一个版本
git add 文件 将某一文件添加到暂存区
git rm --cached 文件 将某一文件移除暂存区
git tag 列出所有本地标签
git tag -l 通配模式文本(*) 根据符合通配模式文本,列出所有本地标签
git tag 标签名 为最新提交创建轻量标签
git tag 标签名 版本号(7位) 为对应版本号提交创建轻量标签(在后期打标签)
git tag -a 标签名 -m 备注文本 为最新提交创建附注标签
git tag -d 标签名 删除指定标签
git remote add 别名 远程仓库地址 添加远程库
git remote -v 查看添加过的远程库
git push 远程库地址或其别名 分支名 推送到远程库
git push 远程库地址或其别名 --tags 推送所有标签到远程库
git fetch 将远程库的最新内容拉到本地
git pull 远程库地址或其别名 分支名 将远程仓库某一分支最新内容拉取并合并到当前本地分支
git help 某一命令或指南 使用默认浏览器打开某一命令或指南的手册页

11.2 log 与 reflog 区别

git log 可以显示所有提交过的版本信息。可以加上参数 --pretty=oneline,只会显示版本号和提交时的备注信息。

git reflog 可以查看所有分支的所有操作记录(包括已经被删除的 commit 记录和 reset 的操作)。例如,执行 git reset --hard HEAD~1,退回到上一个版本,用 git log 是看不出来被删除的 commitid,用 git reflog 则可以看到被删除的 commitid。我们就可以买后悔药,恢复到被删除的那个版本。

提交记录过多时,按下 q 可结束浏览。

11.3 git stash

git stash 也是工作中常用的命令,在此单独列举出来。

应用场景

1、假设你现在正在 dev 分支上开发新功能,突然项目出现一个紧急 BUG,需要你立即修复,由于新功能尚未开发完成,你并不想提交它,此时就可以使用 git stash 命令将修改的内容保存至堆栈区。保存完毕后,基于 master 分支新建 hot-fix 分支,对 BUG 进行修改。

2、假设你本应该在 dev 分支上开发新功能,在功能开发完毕时正想提交代码,不料却在 master 分支上进行了开发,为防止切换分支时出现代码冲突,可以使用 git stash 命令将修改内容保存至堆栈区后再切换分支。

命令解析

1、git stash:将所有未提交的修改(工作区和暂存区)保存至堆栈中,用于后续恢复当前工作目录。新增但未提交至暂存区的文件直接执行该命令是不会被保存到堆栈中的。如果想让新增的文件也在执行该命令后保存至堆栈区,需要将该文件交由 Git 管理,即使用 git add 文件 将新增的文件添加至暂存区再执行该命令。

2、git stash save "message":与 git stash 命令效果一样,只不过可以添加一些备注方便查阅。

3、git stash list:查看当前堆栈区所有内容。

4、git stash pop:将堆栈中第一个 stash 应用到当前工作目录下,并在堆栈中删除对应的 stash(也就是会应用并删除堆栈中最近保存的内容)。如果要应用并删除其他 stash,可以使用 git stash pop stash@{$num},即 git stash pop stash@{1} 应用并删除第二个 stash。

5、git stash apply:与 git stash pop 命令效果类似,只不过不会删除对应的 stash,进而将同一个 stash 应用到不同的分支上。

6、git stash drop stash@{$num}:删除堆栈上某一个 stash,比如 git stash drop stash@{1} 将会删除堆栈中第二个 satsh。

7、git stash clear:清空堆栈上所有内容。

8、git stash show:查看堆栈中第一个(最新保存的)stash 和当前目录的差异,可以使用 git stash show stash@{$num} 查看指定的 stash 和当前目录差异。还可以添加参数 -p 查看详细的差异,比如 git stash show -p 可以查看堆栈中第一个 stash 和当前目录的详细差异。

如何只保存部分内容到堆栈

git stash 会将所有未提交的修改(工作区和暂存区)保存至堆栈中,那么如果只保存部分内容呢?

1、将不想存储的文件保存至暂存区,比如 git add a.java, b.java

2、使用 git stash –keep-index 保存那些未被提交至暂存区的文件到堆栈;

3、使用 git reset 将暂存处的文件移动到工作区。

11.4 cherry-pick

应用场景

1、假设本应该在 mofan-master 分支上开发代码并提交,结果在 dev 分支上将代码提交了,此时可以使用 git cherry-pick 将 dev 分支上提交的代码同步到 mofan-master 上,以便自测完成后将 mofan-master 分支合并到 master 分支上。

2、使用 git merge 可以将某一分支的所有变动合并到当前分支上,如果只需要合并部分变动,则可以使用 git cherry-pick

命令解析

1、git cherry-pick 版本号:将指定的提交应用到当前分支,并在当前分支产生一个新的提交(与指定的提交不同的 commitHash)。比如我现在处于 dev 分支上,想将 dev 分支上某次提交应用到 mofan-master 分支上,那么需要先切换至 mofan-master 分支,然后使用 git cherry-pick 并使用那次提交的版本号进行应用。

2、git cherry-pick A版本号 B版本号:将 A 和 B 两次提交应用到当前分支上。

3、git cherry-pick A版本号..B版本号:将 A 到 B 之间的所有提交应用到当前分支上(左开右闭,就是说 A 不会被应用),同时提交 A 必须早于提交 B,否则命令将失败,但不会报错。

4、git cherry-pick A版本号^..B版本号:将 A 到 B 之间的所有提交应用到当前分支上,A 也会被应用。

常用参数

参数 含义
-e 打开外部编辑器,编辑提交信息
-n 只更新工作区和暂存区,不产生新的提交
-x 提交信息后追加 cherry picked from commit …
-s 提交信息后追加操作者签名

冲突的解决

在执行该命令时如果产生冲突,cherry pick 会停下来,让用户决定怎么解决冲突。

1、--continue:用户解决冲突并将修改的文件添加至暂存区后,使用 git cherry-pick --continue 命令继续进行 cherry pick。

2、--abort:放弃 cherry pick 并回到操作前的样子。

3、--quit:退出 cherry pick,但不回到操作前的样子(应用了部分提交)。

缺点

1、产生冲突。 假设在 master 分支上在某一文件的某一行新增了内容并进行提交,然后又在 master 分支上对这行内容进行了删除并提交,此时切换为 dev 分支后,先 cherry pick 第二次提交再 cherry pick 第一次提交将会产生冲突,而不是回到最开始未对这行进行修改的样子。

2、诡异的 commit 记录导致上下游分支相同的提交难以追溯。 假设现在有两个分支分别是 master 和 dev,针对文件 A 进行修改,此刻这两个分支中文件 A 的内容完全相同。先在 dev 分支上对 A 的 最后一行 添加内容“abc”,然后把“abc”修改为“abcd”,最后在 第二行 新增“123”。接下来切到 master 分支,先 cherry pick 第三次提交,一切顺利,然后在 cherry pick 第二次提交,此时会产生冲突,解决冲突后 cherry pick 第一次提交。最终两个分支的 A 文件内容相同的,但是 commit 记录呢?

dev 分支:

1
2
3
123
abcd
abc

master 分支:

1
2
abcd
123

真实的 commit 记录应该像 dev 分支的那样,而进行 cherry pick 后的 master 分支的提交记录则大不相同,过程中甚至出现了冲突。(参考链接:rebase与merge的对比及cherry-pick

3、无法 cherry pick 到新增的文件。 同样两个分支,一个文件 A,三个提交。首先在 dev 分支上修改文件 A 并增加文件 B,然后继续修改文件 A 并修改文件 B,最后只修改文件 A。接下来切换到 分支 master,连续三次修改文件 A,并 cherry pick dev 分支上最后一次提交,dev 分支上的变动会出现在 master 上,但新增的文件 B 不会出现。(参考链接:git cherry-pick 的一个陷阱!!!

4、不留下合并记录,导致上下游分支进行一系列开发再次合并时采用错误的版本并且没有冲突提示。 (参考链接:Stop cherry-picking, start merging, Part 2: The merge conflict that never happened (but should have)

基于提交 A 拉取 feature 分支,master 和 feature 分支分别产生 M1 和 F1 提交,这时发现存在重大 BUG 需要临时修复,于是将某一行的配置由 apple 修改为 berry,产生 F2 提交,测试通过后,在 master 分支上 cherry pick F2 提交,这时 master 分支上的 apple 配置也变为 berry。

临时修复并cherry-pick

然后 master 分支上产生新的提交 M3,这时开发人员找到了 BUG 的源头,原因和 apple 配置无关,因此在 feature 分支上又将 berry 改回 apple,产生 F3 提交。

溯源并改回原配置

F3 提交并测试成功后,是时候把修改同步到 master 了,于是将 feature 分支合并到 master 分支上,产生提交 M4。我们的期望是 master 分支上的临时修改能被 feature 分支上的源头修改覆盖,即 master 上的 berry 配置也改回 apple,然后遗憾的是 master 分支上的内容并没有被该改回。

合并同时出错

这还不是最糟糕的,如果又将 master 分支合并到 feature,这下就完了,配置 berry 也会同步到 feature 上。

合并到feature产生更糟糕的错误

产生这样的原因是什么呢?让我们回到第一次合并前:

溯源并改回原配置

现在我们进行合并。在合并时,Git 会寻找最近的公共基点,也就是提交 A。然后 Git 以 A 为基数,M3 作为 HEAD,F3 为入站变更进行三向合并。让我们抹除不相干的提交:

抹除不相干的提交

对比 master 的基点与头部,会发现由 apple 变为了 berry,但 feature 分支没有任何改变。由于在 feature 上没有任何改变,以为着从 feature 合并到 master 也没有任何改变,也就是 master 上的 berry 不会改变。最终导致在 feature 上是 apple,而在 master 上是 berry。

11.5 git diff

使用这个命令可以比较文件或分支之间的不同。

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

1
git diff [file]

显示暂存区和上一次 commit 的差异:

1
2
git diff --cached [file] 
git diff --staged [file] # 显示摘要而非差异的详细信息

显示两个分支至之间的差异:

1
2
3
4
5
6
7
git diff branch1 branch2 --stat # 显示出 branch1 和 branch2 中差异的部分
git diff branch1 branch2 [file] # 显示指定文件的差异
git diff branch1 branch2 # 显示出所有详细差异
git log branch1 ^branch2 # 查看 branch1 有,branch2 没有的 log
git log branch1..branch2 # 查看 branch2 有,branch1 没有的 log
git log branch1...branch2 # 列出两者之间的 log 差异
git log -lefg-right branch1...branch2 # 列出两者之间的 log 差异,并显示属于哪个分支

11.6 重写历史

有时“脑抽”,我们或许需要修改刚提交的提交信息或者刚提交的实际提交内容。

如果只想修改最后一次的提交的提交信息,可以:

1
git commit --amend

这条命令会将最后一次的提交信息载入到编辑器中供你修改。 当保存并关闭编辑器后,编辑器会将更新后的提交信息写入新提交中,成为新的最后一次提交。

如果你想要修改最后一次提交的实际内容,首先修改文件并 暂存 它们,然后用 git commit --amend 以新的改进后的提交来替换掉旧有的最后一次提交。这样的操作会改变提交的 SHA-1 校验和,因此如果已经推送了最后一次提交就不要修正它(类似于一个小的变基)。

在修改提交时,可以同时修改提交信息和提交内容。 如果你修补了提交的内容,那么几乎肯定要更新提交消息以反映修改后的内容。如果只修改最后提交的实际内容,而不想修改提交信息,那么可以:

1
git commit --amend --no-edit

11.7 回滚与撤销

假设现在有两个文件,分别是 test1.txt 和 test2.txt。

test1.txt 的内容如下:

1
2
3
111
222
333

test2.txt 的内容如下:

1
2
3
000
999
888

此时 A 用户修改了 test1.txt 文件,将 333 改成了 444,test1.txt 变成了:

1
2
3
111
222
444

然后 B 用户修改了 test2.txt 文件,将 888 改成了 777,并新增了 666,test.txt 变成了:

1
2
3
4
000
999
777
666

这时环境出问题了,是用户 A 将 333 修改为 444 导致的,这是需要撤销或回滚代码,那究竟是撤销还是回滚呢?

回滚

用户 A 首先执行 git reflog 指令查看将 333 修改为 444 的那次提交的 前一次提交 的 commit id:

1
2
1a832b5 (HEAD -> master, xxx/master) HEAD@{0}: commit: 333 -> 444
35122a7 HEAD@{1}: commit: 文件初始化

前一次提交的 commit id 为 35122a7,使用此 commit id 执行以下命令:

1
git reset --hard 35122a7

然后 强制推送 到远程分支上:

1
git push -f

这时去查看远程仓库和本地代码,会发现代码已经回到了将 333 修改为 444 之前的那次提交,除此之外,B 用户的修改也不见了。

这样的操作存在一个问题,虽然服务器上的代码被还原了,但在实际开发中,往往会有很多人对一个项目进行提交,他们本地的版本依旧是比服务器的版本要高的,如果别人再提交代码,刚刚进行的回退操作又会被覆盖,上面的操作就白操作了。

当然也可以让别人把他们的本地分支删掉,然后从服务器上重新拉取分支,但这可能吗?

撤销

因此可以使用撤销,还是需要 A 用户执行 git reflog 指令查看提交记录, 只不过这次需要找将 333 修改为 444 的那次提交的 commit id, 从前面我们知道,这次提交的 commit id 为 1a832b5,因此它执行以下命令:

1
git revert -n 1a832b5

执行这个命令后,Git 的命令行界面会出现 (master|REVERTING) 的字样,并且这个命令表示撤销了指定 commit id 的提交,但是保留了那之后的提交,因此还需要推送那之后的提交(也就是说会产生一次新的提交),执行以下命令:

1
2
git commit -m "撤销 333 -> 444"
git push

此时 test1.txt 文件的内容如下:

1
2
3
111
222
333

test2.txt 文件的内容如下:

1
2
3
4
000
999
777
666

很好,撤销了错误的提交,并且还保留的之后的提交。

撤销 撤销

撤销完成后,用户 B 又对 test2.txt 进行了修改:

1
2
3
4
5
000
999
777
555
444

然后 A 用户心想,我那次提交确实有问题,应该将 333 改成 456,那应该怎么回到 444 的版本上将 444 改成 456 呢?

使用 git reflog 查看那次撤销操作的 commit id:

1
2
3
4
5
6
19d641d (HEAD -> master, xxx/master) HEAD@{0}: pull: Fast-forward
b69ab99 HEAD@{1}: commit: 撤销 333 -> 444
081f410 HEAD@{2}: pull: Fast-forward
35122a7 HEAD@{3}: reset: moving to 35122a7
1a832b5 HEAD@{4}: commit: 333 -> 444
35122a7 HEAD@{5}: commit: 文件初始化

得知那次撤销操作的 commit id 为 b69ab99,那么使用这个 commit id 撤销撤销操作:

1
2
3
4
git pull # 先同步代码
git revert -n b69ab99
git commit -m "撤销 撤销 333 -> 444"
git push

现在 test1.txt 的文件内容如下:

1
2
3
111
222
444

test2.txt 的文件内容如下:

1
2
3
4
5
000
999
777
555
444

很棒,符合预期,接下来用户 A 把 444 修改为 456 再提交就行了。

简单总结下:

1、reset 是版本回滚,回滚到某次提交时,那之后的提交都将消失;

2、revert 是撤销,撤销某次提交后,那之后的提交将存储到暂存区,可提交至本地库并推送到远程库产生新的提交。

11.8 其他后悔药

在【11.6 重写历史】中介绍了如何修改提交信息,在【11.7 回滚与撤销】中介绍了怎么回滚或撤销远程库的代码,那怎么撤销在工作区的修改、怎么撤销在暂存区的修改、怎么撤销在本地仓库的修改呢?

撤销工作区的修改(未使用 git add

放弃 某个 文件的修改:

1
2
git checkout -- filepathname
# 比如:git checkout -- test.txt

放弃 所有 文件的修改(两种方式,任选一):

1
2
git checkout . # 放弃所有文件的修改
git restore . # 放弃所有文件的修改

使用上述三个命令可以放弃对某个或所有文件的修改,执行命令后,文件回到未被修改前的样子。

谨慎使用,避免白忙活。

撤销暂存区的修改(已使用了 git add

某个 文件从暂存区移到工作区:

1
2
git reset HEAD filepathname
# 比如:git reset HEAD test.txt

所有 文件从暂存区移到工作区(两种方式,任选一):

1
2
git reset HEAD . # 将所有文件从暂存区移到工作区
git reset # 将所有文件从暂存区移到工作区

使用上述命令只是将某个或多个文件从暂存区移到工作区,如果需要放弃对文件的修改,还需要执行【撤销工作区的修改】中的命令。

撤销本地库的修改(已使用了 git commit

1、撤销(回滚)某次提交(不保留代码修改):

1
2
git reset --hard HEAD^ # 回退到上一次提交状态
git reset --hard [commit id] # 回退到某次提交状态

使用这两个命令不会保留代码的修改,但并不是说就没法再复原了,使用 git reflog 找到那次提交的 commit id,然后再使用第二个命令就能复原。

2、将 commit 和 add 的代码都拉回到工作区(两种方式,任选一)(保留代码的修改):

1
2
git reset --mixed HEAD^
git reset HEAD^

3、将 commit 的代码拉回暂存区,已 add 的代码不拉回到工作区(保留代码的修改):

1
git reset --soft HEAD^

4、撤销暂存区、本地库的修改,使其返回到远程库最新的版本(不保留代码的修改):

1
2
3
git fetch --all # 从远端获取最新到本地
# 撤销所有修改
git reset --hard origin/master # git reset --hard origin/远程分支名

谨慎使用,避免白忙活。

11.9 abort 终止

当我们使用 merge 或者 cherry-pick 时可能会出现冲突,而在解决冲突时发现冲突太多,想要取消本次 merge 或者 cherry-pick,并还原到 merge 或 cherry-pick 之前所有未提交的更改。那么可以使用以下命令:

1
2
git merge --abort # Git 版本 >= 1.7.4
git reset --merge # Git 版本 >= 1.6.1

注意: 在 merge 或 cherry-pick 之前要保证没有未提交的文件,如果有未提交的文件,需要使用 commit 进行提交或者使用 stash 进行暂存,否则在某些情况下无法重现这些修改。

上述这两个命令并不是同一事物的新旧语法,使用 git help merge 命令打开手册页并查看 --abort 选项的信息:

git merge --abort is equivalent to git reset --merge when MERGE_HEAD is present unless MERGE_AUTOSTASH is also present in which case git merge --abort applies the stash entry to the worktree whereas git reset --merge will save the stashed changes in the stash list.

简单来说就是当存在 MERGE_HEAD、并且不存在 MERGE_AUTOSTASH 时,两个命令是相等的。

同样,可以使用 git help reset 命令打开手册页查看 --merge 选项的信息:

Resets the index and updates the files in the working tree that are different between <commit> and HEAD, but keeps those which are different between the index and working tree (i.e. which have changes which have not been added). If a file that is different between <commit> and the index has unstaged changes, reset is aborted.
In other words, --merge does something like a git read-tree -u -m <commit>, but carries forward unmerged index entries.

12. 其他操作流程

12.1 推送到远程仓库

有时我们需要将本地未被 Git 管理的代码交由 Git 管理并推送到远程仓库,但在进行这个流程时出现了以下错误导致无法推送到远程仓库:

Updates were rejected because the remote contains work that you do

这是因为我们在新建本地库后,本地库与远程仓库的内容不一致导致的。

先看下错误的操作流程:

1
2
3
4
5
6
7
8
9
10
# 初始化仓库
git init
# 添加所有文件到本地暂存区
git add .
# 提交到本地仓库
git commit -m "commit info"
# 关联远程仓库并取别名
git remote add origin 远程仓库地址
# 推送到远程仓库
git push -u origin master

正确的操作流程需要在推送到远程仓库前同步远程仓库:

1
2
3
4
5
6
7
8
9
10
11
12
# 初始化仓库
git init
# 添加所有文件到本地暂存区
git add .
# 提交到本地仓库
git commit -m "commit info"
# 关联远程仓库并取别名
git remote add origin 远程仓库地址
# 同步远程仓库
git pull origin master --allow-unrelated-histories
# 推送到远程仓库
git push -u origin master

12.2 拉取远程分支到本地

本地无相关仓库代码,直接拉取即可

1
git clone -b 远程分支名 仓库地址

本地已有相关仓库代码

假设需要拉取的远程分支名为 dev

1
2
3
4
5
6
7
8
# 查看远程分支信息
git branch -r
# 创建本地分支并切换到创建的分支上
git checkout -b mydev
# 远程分支关联本地分支
git branch --set-upstream-to origin/dev mydev
# 拉取远程分支(直接使用 git pull 也行)
git pull origin dev

由于本地分支名称与关联的远程分支名称不一样(所以创建的本地分支名称最好与需要关联的远程分支名称相同),因此在 push 时得这样:

1
git push origin HEAD:dev

除此之外,第二三步创建本地分支并切换到创建的分支上,然后使创建的分支关联远程分支可以合为一步,即:

1
git checkout -b mydev origin/dev

也就是说如果我们 在创建本地分支时忘记关联远程分支,就可以使用第三部的方式进行关联。