git 在 eclipse 中的配置

本贴最后更新于 2631 天前,其中的信息可能已经天翻地覆

转自 沉沦中的探索

一_安装 EGIT 插件

EGit Update Site - Use this URL in Eclipse to install EGit and JGit 5.12.0.202106070339-r

或者使用 Eclipse Marketplace,搜索 EGit

二_使用 EGIT 前的配置

配置个人信息,最重要的是 user.name 和 user.email

l Preferences > Team > Git > Configuration

l New Entry

三_新建 GIT 仓库

新建 NC module project

l File > Team > Share Project 选择 GIT

创建仓库后,在 $workspace\demo 目录下的.git 文件夹,就是 git 的仓库地址。和 CVS、SVN 不同,GIT 不会在每一个目录下建立版本控制文件夹,仅在根目录下建立仓库

同时,eclipse 中的 project 也建立 git 版本控制,此时未创建分支,处于 NO-HEAD 状态

文件夹中的符号”?”表示此文件夹处于 untracked 状态,这样就成功创建 GIT 仓库。

四_配置.gitignore

此时我们尝试做一次提交

l Team -> Commit…

如上图所示,Author 和 Committer 会默认为 Git 配置的用户信息。下面的 Files 窗口中可以看到此次提交的文件,其中有非常多带有 NC_HOME 的文件,此时可以猜测出,在我们的 project 中链接的 NC_HOME 也被 GIT 默认到版本控制中了,如下图:

显然 NC_HOME 和 out 是不需要进行版本控制的,我们可以通过配置.gitignore 来排除这两个文件夹

打开 Navigator 窗口,在 project 根目录中添加.gitignore 文件,将需要排除控制的目录写入.gitignore 文件中

再次尝试 commit,需要提交的文件已经被过滤

首次提交后,会自动生成 master 分支

然后在 public 中新建一个文件,可以看到图标依然是问号,处于 untracked 状态,即 git 没有对此文件进行监控

通过 Team -> Add to index 可以将文件加入 git 索引,进行版本监控

可以看到图标显示也有了变化(EGIT 中只要 Commit 就可以默认将 untracked 的文件添加到索引再提交更新,不需要分开操作)

也可以通过 Team -> Untrack 将文件从索引控制中排除。

将此次新增的文件 commit 到仓库中,文件将处于 unmodified 状态,或者说,这就是一种 staged 状态

然后修改文件的内容,文件将处于 modified 状态

五_查看历史记录

Team -> Show in history 可以查看版本历史提交记录

可以选择对比模式

六_远程 GIT 仓库

此小结的前提是已经搭建 GIT 服务器,并通过 SSH 协议连接,可参看文档《RHEL 下搭建 GIT 服务器》《WindowsXP 下搭建 GIT 服务器》 《GIT 服务器使用基础》。本文使用 RHEL5.5 系统下的 GIT-2012-01-11,用户 root/password,GIT 仓库统一存放在 /app/gitspace 目录下。

首先通过 shell 工具连接到服务器,建立空仓库 gitdemo,此时的 ssh 访问地址如下,分别由协议名称、用户名、IP、端口、git 仓库目录组成。

打开 GIT 资源库窗口,选择克隆资源库

现在已经把远程的 GIT 仓库克隆到本地,接下来需要将仓库检出为 NC 模块项目。

最后得到 gitdemo 模块项目,分支是 mirror

七_推送远程仓库

克隆服务器端仓库后,会在本地建立一个一样的仓库,称本地仓库。在本地进行 commit 操作将把更新提交到本地仓库,然后可以将服务器端的更新 pull 到本地仓库进行合并,最后将合并好的本地仓库 push 到服务器端,这样就进行了一次远程提交。

先提交一次到本地仓库

然后 push 到服务器端的 mirror 分支,Team -> remote -> Push

完成推送后,可以在服务器端 mirror 镜像的 log 中查看到此次记录

八_解决推送冲突

多人协作开发的情况下,往服务器推送更新时难免出现冲突,所以推送之前需要解决服务器端的最新版本和本地仓库的冲突。Pull 操作就是把服务器端的更新拉拢到本地仓库进行合并,解决好合并冲突后,就可以顺利 push 到服务器分支了。

假设现在 Mairo 兄弟在用 GIT 协作开发 NewSuperMairoBro 游戏,目前服务器端的 mushroom.java 文件的内容如下:

MairoBro 克隆出代码后,Mairo 哥哥做了如下修改

Mairo 弟弟做了如下修改

然后 Mairo 弟弟先 push 代码,Mairo 哥哥使用 pull 来合并本地仓库和远程仓库,将发行文件出现冲突,此时 GIT 会自动合并冲突的文件,如下图所示:

很明显自动合并的冲突文件不能直接使用,我们可以手动调整,右键发生冲突的文件,选择 Team -> Merge Tool

第一项是将 GIT 自动合并过的文件和服务器端文件进行对比

第二项是用本地最新版本的文件和服务器端文件进行对比,建议用此项

接下来就是熟悉的对比界面

Mairo 哥哥将冲突文件修改如下

然后右键点击此冲突文件,选择 Team -> Add to index 再次将文件加入索引控制,此时文件已经不是冲突状态,并且可以进行提交并 push 到服务器端

解决合并冲突后,Mairo 弟弟只需要将服务器中合并后的版本 pull 到本地,就完成了一次协作开发的代码合并。从历史记录中可以看到,从 mushroom 开始历史进入分支,先是 mushroomA 的记录,然后是 mushroomB 的记录,最后历史分支合并。

九_Rebase 和 Merge 的区别

Rebase 和 Merge 操作最终的结果是一样的,但是实现原理不一样。

从上面的 MairoBro 例子可以知道 pull 大概对历史记录进行了怎样的合并操作,其实默认 pull 的操作就是一个分支的 merge 操作,如下图重现一下:

Mairo 弟弟的提交记录如下:

Mairo 哥哥的提交记录如下:

首先是 Mairo 弟弟把更新 push 到服务器,这样服务器端的记录就和 Mairo 弟弟本地的记录是一样的,接着 Mairo 哥哥执行 pull 操作,现在分析下 pull 是如何操作的。

l pull 默认就是先把服务器端的最新记录更新到本地的 Remote Tracking 中对应的 mirror 分支

l 接着对 Local 的 mirror 分支和 Remote Tracking 的 mirror 分支进行 merge 操作

Merge 操作后的结果就是会新增加一个 merge 记录节点,如下所示:

从上图可以看出,mushroomA 是在 mushroomB 之前的,这个时间关系不取决于谁先执行 push,而取决于本地仓库中谁先执行 commit。所以 merge 会按照时间顺序严格的记录每一次 commit。

接下来看看 rebase,其实 rebase 也是把两个分支进行合并的操作,当 Mairo 弟弟 push 更新后,服务器端的 mirror 分支的历史如下:

Mairo 哥哥本地的历史如下:

现在 Mairo 哥哥不是执行 merge 操作,而是执行 rebase 操作,最后结果如下:

很明显的区别是没有出现分支的记录,而且注意到 mushroomA*,请注意这个记录和 mushroomA 不是同一个记录,我们先分析下 rebase 操作下,Mairo 哥哥的历史记录都做了哪些变化:

l 先将当前分支的更新部分保存到临时区域,而当前分支重置到上一次 pull 的记录

l 然后将服务器端的更新添加到当前分支,此时当前分支和服务器端分支是一样的

l 最后将原分支的更新部分 mushroomA 提交到当前分支的后面,就是要在 mushroomB 的后面添加 mushroomA 的更新,当然此时更新记录已经不是之前的 mushroomA 了,如果出现冲突则使用对比工具解决冲突,最后记录变成 mushroomA*。

如果 Mairo 哥哥提交过 mushroomA1、mushroomA2、mushroomA3,那么执行 rebase 后会对 mushroomA1、 mushroomA2、mushroomA3 分别顺序执行上图所示的合并,最后记录为 mushroomA1*、mushroomA2*、 mushroomA3*。很显然 rebase 操作更复杂,冲突的概率也更高,并且不是按照时间顺序记录。

十_Rebase 和 Merge 如何选择的简单解析

此小结为什么说是简单解析呢,因为 rebase 和 merge 的选择问题讨论比较激烈,笔者也没有一个定论,而且 git 也处于研究发展阶段,很多理论还没有完全的纯熟。

对于一个多人开发团队频繁提交更新的情况,如果使用 merge 会使得历史线图非常复杂,并且 merge 一次就会新增一个记录点,如果使用 rebase 就是完全的线性开发。

上图所示是 Merge 和 Rebase 的两个结果,显然你不想要 merge 的混乱结果吧,你能告诉我 merge 图中那条线是 master 分支吗?

所以给出如下建议,如果同一文件反复修改或提交次数比较多,预期会出现很多的 conflict,那么可以使用 merge 合并,仅需要解决一次冲突即 可(不过,大范围主题式的修改,是不是应该事先就新开一个分支呢?);如果修改范围小,预期 conflict 少,则建议使用 rebase。

EGIT 中默认的 pull 操作是 Fetch+Merge,如果要用 rebase,可以分开操作。先执行 Fetch 更新 remote tracking,再执行 rebase 进行合并(下一小节将介绍 rebase 操作)。或者修改 pull 的默认操作,在.git/config 文件中配置:

上述配置只对 mirror 分支有效,也可做全局配置,在HOME/.gitconfig中配置,windows系统如果没有配置HOME变量的话就默认在documents and settings/ USER 目录下:

十一_Fetch 和 Rebase

MairoBro 来做 fetch 和 rebase 的测试,首先 Mairo 弟弟在 client 中添加文件 OPQ 分别提交,并 push 到服务器,如图:

此时服务器端的历史已经被更新,但是 Mairo 哥哥的 remote tracking 中 mirror 分支并没有更新到最新的记录,如图:

所以需要更新 remote tracking 中的分支,使得它与服务器端的分支同步,右键点击资源库选择 Fetch

这样就更新了本地的 remote tracking 中的分支,使得它和服务器端分支同步。

然后 Mairo 哥哥在本地的 private 中添加文件 ABC,并分别提交到本地仓库中。

然后将本地 mirror 分支和 remote tracking 中的 mirror 分支进行 rebase,先 checkout 本地 mirror 分支 ,然后右键点击选择 Rebase

如上图可以看到历史记录的顺序是 OPQABC,已经 rebase 成功,接着 push 到服务器即可。

十二_重置功能

GIT 中有三种重置功能,分别是 soft、mixed、hard,区别如下:

l **Soft - **当前分支重置到指定 commit 记录位置,索引和工作树不变;

l **Mixed - **当前分支重置到指定 commit 记录位置,索引被更新,工作树不变;

l **Hard - **当前分支重置到指定 commit 记录位置,索引和工作树都更新。

貌似不好理解,首先要理解 GIT 的三个区域(工作树、索引区、仓库),可以参考文档《GIT 简介》。

先做 soft 的测试,新建 Soft.java 文件,可以看到此文件未添加到索引控制

先进行一次提交,提交后在 History 窗口中重置此次提交,如图:

重置后查看工作树,如图

从上图可以看出,soft 文件还存在,说明重置没有改变工作树,而且 soft 文件不是“问号”图标,说明已经添加到索引,说明索引也没有变。唯一重置的是历史记录。

然后新建 Mixed.java 文件,此时 Mixed.java 也没有添加到索引控制,然后提交。

在 History 窗口中重置

重置后查看工作树结果如下:

从上图可以看出,Mixed.java 文件还存在,说明工作树没有改变,但是文件状态是 untracked,说明索引被更新,此时文件没有添加索引控制。

最后来看 hard 重置,新建 Hard.java 文件,此时文件没有添加索引,然后提交。

在 History 界面重置此次提交,如图:

重置后再查看工作树,结果如下:

可以看到 Hard.java 文件已经不存在了,说明索引和工作树都被更新。

  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    209 引用 • 358 回帖
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    75 引用 • 258 回帖 • 617 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...