Git学习6:Git冲突模拟与解决

在真实的Git运行环境中,往往涉及多个用户对版本仓库的协作,而每个用户都有一个完整的Git版本仓库副本,所以在把各自的操作结果推送到远程仓库的时候出现冲突的可能性就非常高。

在Git中解决冲突的一个优雅方式是:首先通过命令git fetch获取远程仓库最新的修改,然后执行命令git merge将本地的操作结果(实际上就是一个commit)与远程仓库的修改(远程仓库最新的commit)进行合并,如果在合并的过程没有发生冲突,那么Git会生成一个新的commit,并自动提交。但是,合并并非总是成功的,因为合并的不同提交可能是同时修改了同一个文件相同区域的内容,这样就会导致冲突。冲突发生后合并操作会终止,在本地解决冲突后,除非放弃此次合并,需要更新暂存区,再提交,最终完成合并过程。

合并示意图

git fetchgit merge操作可以使用一个命令git pull独立完成

下面的简图描绘了git pull操作的过程。

在初始状态,本地仓库和远端仓库可能是这样的:

从远端仓库执行git fetch命令后:

执行git merge操作后是这样的:

最后推送到远程仓库是这样的:

模拟冲突操作

为了模拟多用户操作一个共享仓库并产生冲突的情况,需要有一个共享仓库,为了简便,可以直接在本地使用git init命令初始化一个共享仓库。

首先执行如果命令初始化一个共享仓库:

git init --bare /home/rhwayfun/java/notes/repos/share.git

这样就在响应目录下生成了一个裸仓库(没有工作区的仓库称为裸仓库)。然后在目录/home/rhwayfun/java/notes/to下面创建两个文件夹user1user2,模拟两个用户。并在各自的目录下克隆上面创建的share仓库,以上操作命令如下:

mkdir user1
cd /home/rhwayfun/java/notes/to/user1
git clone file:///home/rhwayfun/java/notes/repos/share.git project

cd ..
mkdir user2
cd user2/
git clone file:///home/rhwayfun/java/notes/repos/share.git project

以上命令执行完毕后就分别在user1和user2两个用户目录下有了最新的远端仓库。

在user1目录执行如下操作:

cd user1/project
git config user.name user1
git config user.email user1@163.com
mkdir team
echo "I‘m user1." > team/user1.txt
git add user1.txt
git commit -m "create team/user1.txt"
git push

在user2目录执行如下操作:

cd user2/project
git config user.name user2
git config user.email user2@163.com
mkdir team
echo "I‘m user2." > team/user2.txt
git add user2.txt
git commit -m "create team/user2.txt"
git push

在user2执行git push操作的时候出现了异常信息:

To file:///home/rhwayfun/java/notes/repos2/share.git

! [rejected] master -> master (fetch first)

可知,user2的push操作被拒绝,而被拒绝的原因在于本地的版本库不是最新的,需要首先获取最新的远程库的提交才能继续后面的执行。因为如果没有基于最新的版本库仓库操作可以降低冲突发生的可能性。在更新本地仓库之前,可以先分析一下,user1在team目录增加了user1.txt,而user2在team目录增加了user2.txt,所以从逻辑上两者的操作是没有冲突的。再根据对合并的说明,user2执行git pull应该会自动合并。

执行git pull命令后,继续执行如下的命令,查看提交日志:

git log --oneline --decorate --graph --all

日志如下:

* 0432ca1 (HEAD -> master) Merge branch ‘master’ of file:///home/rhwayfun/java/notes/repos2/share

|\

| * 5f642a9 (origin/master) create team/user2.txt

* 14cc834 create team/user1.txt

可以看到user1和user2的提交合并到一个新的提交0432ca1。所以与之前的分析是吻合的。

但是,可以发现origin/master(这是远端仓库的引用)的提交滞后与user2的提交,因此只需要执行git push就可以将user2的提交更新到共享仓库。

执行后日志输出如下:

* 0432ca1 (HEAD -> master, origin/master) Merge branch ‘master’ of file:///home/rhwayfun/java/notes/repos2/share

|\

| * 5f642a9 create team/user2.txt

* 14cc834 create team/user1.txt

由于user2又进行了一次更新,所以需要切换到user1目录执行如下操作:

cd user1/project
//获取最新的提交
git pull

冲突解决

现在user1和user2的本地仓库都是最新的了,为了制造冲突,可以在user1目录执行如下操作:

cd user1/project
touch README.txt
echo "Hello, user1." > README.txt
git add README.txt
git commit -m "create README.txt"
git push

切换到user2目录,然后执行如下操作:

cd user2/project
touch README.txt
echo "Hello, user2." > README.txt
git add README.txt
git commit -m "create README.txt"
git push

发现在执行git push的时候失败,于是执行git pull获取最新的提交,但是好像仍然失败了,日志如下:

U README.txt

Pull is not possible because you have unmerged files.

Please, fix them up in the work tree, and then use ‘git add/rm ’

as appropriate to mark resolution and make a commit.

git 提示我们README.txt在拉取最新的提交的时候发生了冲突,需要在工作区先解决冲突,然后重新将冲突文件添加到暂存区,再执行提交。

为了查看发生冲突的文件,可以执行如下名命令:

// 查看暂存区中记录的冲突文件
git ls-files -s

日志如下:

100644 ea9df2ef42c073de18bde4ebdf50e0ac6b1cdd2d 2 README.txt

100644 633d2ed9d0ae01d0d07136c5b5bd857e4d945c14 3 README.txt

100644 17874eaa4a398cc94ed294c93fdbf50f7f843d88 0 team/user1.txt

100644 2dcb7b6ac06d93ea8e6af21ded690f5e171a407c 0 team/user2.txt

编号为2表示暂存区用于保存冲突文件在当前分支中修改的副本,查看该文件的内容执行如下命令:

git show :2:README.txt

输出结果为

Hello, user2.

编号为3的为暂存区用于保存当前冲突文件在合并版本中修改的副本

git show :3:README.txt

输出结果为:

Hello, user1.

最后看看工作区的README.txt文件的内容:

cat README.txt

输出结果:

<<<<<<< HEAD
Hello, user2.
=======
Hello, user1.
>>>>>>> 04eed972e27e23a9874f984f08d6567e565d3436

其中特殊标识<<<<<<<和=======之间的内容是当前分支所更新的内容,特殊标识=======和>>>>>>>之间的内容是所合并的版本更改的内容。所以只需要手动解决这个冲突就可以,将README.txt文件修改如下:

Hello, user2 and user1.

在user2目录下执行如下操作就可以解决冲突了。

//加上-u参数表示把工作区被跟踪的文件添加到暂存区
git add -u
git commit -m "Merge README.txt: Hello, user2 and user1."
git push

重新运行命令:

git ls-files -s

输出:

100644 2ba0d56dda48b03ef57e5fbcd793f7de1103aa0e 0 README.txt

100644 17874eaa4a398cc94ed294c93fdbf50f7f843d88 0 team/user1.txt

100644 2dcb7b6ac06d93ea8e6af21ded690f5e171a407c 0 team/user2.txt

可以看到所有的编号都变成了0,这样就说明已经成功解决了冲突。

小结

通过以上实际操作认识了冲产生了原因和具体解决冲突的方法,以及在解决冲突过程中使用到一些有用的命令。需要提的一点是,在工作区修改冲突文件时可以使用图形工作完成,不过楼主觉得Linux下的vim编辑器就挺好用的,所有没有介绍使用图形工作修改冲突文件的内容,但本质都是对冲突文件进行编译从而解决冲突的过程。

时间: 2024-08-27 03:14:48

Git学习6:Git冲突模拟与解决的相关文章

git学习——&lt;五&gt;git分支

git学习——<一>git安装 git学习——<二>git配置文件 git学习——<三>git操作 git学习——<四>git版本管理 一.提出问题 今天开发的过程中遇到一个问题,A组接到开发任务要修改file文件,B组在此之前的15天为了完成自己的开发任务对file文件进行了修改,为了同步代码,B组将自己未完成的模块file文件提交到了cvs上.A对此一无所知,A组在完成开发任务后,把file文件完全上到了现网环境,报错了. 当然,避免上述问题的途径很多,

Git学习 -- 自定义Git

忽略特殊文件 在工作区创建.gitignore文件,编写内容 # Windows: Thumbs.db ehthumbs.db Desktop.ini # Python: 忽略Python编译产生的.pyc..pyo.dist等文件或目录 *.py[cod] *.so *.egg *.egg-info dist build # My configurations: db.ini deploy_key_rsa 然后add和commit该文件 此后当工作区出现.gitignore中类型文件时,git

Git 学习之Git 基础(二)

Git 基础 读完本章你就能上手使用 Git 了.本章将介绍几个最基本的,也是最常用的 Git 命令,以后绝大多数时间里用到的也就是这几个命令.读完本章,你就能初始化一个新的代码仓库,做一些适当配置:开始或停止跟踪某些文件:暂存或提交某些更新.我们还会展示如何让 Git 忽略某些文件,或是名称符合特定模式的文件:如何既快且容易地撤消犯下的小错误:如何浏览项目的更新历史,查看某两次更新之间的差异:以及如何从远程仓库拉数据下来或者推数据上去. 取得项目的 Git 仓库 有两种取得 Git 项目仓库的

Git学习笔记——Git安装

Git是目前世界上最先进的分布式版本控制系统(没有之一). 在Linux上安装Git 首先,你可以试着输入git,看看系统有没有安装Git: $ git The program 'git' is currently not installed. You can install it by typing: sudo apt-get install git 像上面的命令,有很多Linux会友好地告诉你Git没有安装,还会告诉你如何安装Git. 如果你碰巧用Debian或Ubuntu Linux,通过

git(学习之四)git协议服务器搭建

####################################################################################################### qq:1218761836 qq群:150181442 E-mail:[email protected] #############################################################################################

git学习——&lt;三&gt;git操作

一.创建仓库 创建一个目录 mkdir repository cd到该目录下,初始化该版本库 git init 至此,版本库创建成功,可以在该文件夹下看到.git文件夹,ls -ah可以看到该文件夹. 二.版本管理 1.将文件或文件夹添加到版本库中进行版本控制 在工作区创建一个文件 touch readme.txt 将该文件添加到暂存区 git add readme.txt 将文件从暂存区提交到版本库 git commit -m "some comment" *工作区.暂存区.版本库

Git学习系列-Git基本概念

本系列基于Pro Git介绍如何使用Git进行源代码管理,以及后期如何使用Git进行项目管理. 系列初步目录如下: 1. Git基本概念 2. Git分支操作 后续待定. Git的历史就不在这里进行介绍了,网上随处都可以找到,以下是在使用Git的时候的一些基本概念和方法 Git有三种状态,文件可能处于其中之一:已提交(Committed).已修改(modified)和已暂存(staged).已提交表示数据已经安全的保存在本地数据库中.已修改表示已经修改了文件,但还没有保存在数据库中.已暂存表示对

git学习(二)——git的文件状态

git的文件状态 用于查看git的状态 git status 用于git文件的删除操作 git rm 如果只是 git rm --cache 仅删除暂存区里的文件: 如果不加--cache 会删除工作区里的文件 并提交到暂存区 文件检出 git checkout 直接加文件名 从暂存区将文件恢复到工作区,如果工作区已经有该文件,则会选择覆盖; 加了[分支名] +文件名 则表示从分支名为所写的分支名中拉取文件,并覆盖工作区里的文件; 文件状态 新建文件--->Untracked 使用add命令将新

git 学习(git fetch/ git pull/ git rebase/ git cherry-pick的区别)

使用git做开发管理: 1. Git clone  将远程代码克隆到本地: 2. Git branch  查看本地branch (git clone 时会创建 master) 3. git branch -a  查看本地和远程分支:(远程分支包括 remotes/origin/master 远程master分支) 4. Git remote -v 查看远程库对应的简短名称 (origin  ...) 5. Git checkout -b bug origin/master 创建本地开发分支 6.