合并git中2个不同分支中具有相同名称的2个文件

2024-05-11

我目前有一个名为test1在一个名为branch1创建自master另一个文件也命名为test1在一个名为branch2也创建自master。 如果我合并 master 中的两个分支,这两个文件中编写的代码会发生什么?


As 阿米尔回答了 https://stackoverflow.com/a/59532577/1256452(正确),你会遇到合并冲突one的两个合并。您将必须采取一些措施来处理合并冲突。做什么取决于你。不过值得指出的是,why你会得到one合并冲突,不是两个,以及为什么会发生合并冲突。

Git 的合并其实并不是branches。是关于commits。 Git 的大部分实际上都是关于提交的,并且git merge这里没有什么不同。

让我们在这里注意一下提交是什么以及它的作用。每个提交都有两部分:data—所有文件的已保存快照及其metadata,或有关提交的信息。

  • 保存的快照非常简单:如果您克隆存储库并使用--no-checkout,你有一个空的工作树(没有可编辑或可用的副本any文件,尚未)。然后你选择一些提交(任何地方的任何提交)并告诉 Git 检查该特定提交(可能是通过其原始哈希 ID)。现在,您拥有了所有文件的副本,无论是谁进行了该提交,它们的外观都是一样的。

    一般来说,这就是git checkout或 Git-2.23 中的新功能git switch命令的用途是:你选择一些提交并说获取该提交中的所有文件。他们进入你的工作树 or 工作树您可以在其中看到它们并对其进行处理。您还可以将其他未 Git 化的文件放入您的工作树中,例如编译文件或输出或其他文件。这些文件仍然存在未追踪的(我不会在这里详细讨论,但它们不在 Git 中,它们只是位于您的工作树中,除非/直到you删除它们)。

  • The metadata提交中记录了诸如是谁制作的信息——他们的姓名和电子邮件地址——以及他们制作的时间。这就是你看到的东西git log output.

    不过,元数据的一部分是专门针对 Git 本身的。每个提交都有一个唯一的哈希 ID,每个 Git 都同意这一点:一个哈希 ID 用于that提交,并且绝不用于任何其他提交。因此,很容易判断您是否有一些提交:您只需将其哈希 ID 提供给 Git,并且您的 Git 要么拥有它,在这种情况下,它就有that提交,或者你的 Git 没有它,在这种情况下你必须找到其他有它的 Git 帽子。

    无论如何,每个提交都会将其前一个或另一个提交的哈希 ID 存储为元数据的一部分。parent犯罪。大多数提交只有一个。合并提交有点特殊,因为它们有two父母(或更多,但大多数只有两个)。

    这些父提交(或合并时的父提交)是 Git 存储历史记录的方式。每一个快照只是一个快照,但每一个快照也都在说:我之前的快照是______(用哈希 ID 填写空白)。对于合并,这是first父母。对于常规提交,它是唯一的父级(因此也是第一个父级)。因此,通过返回每个提交的第一个父级,Git 可以追溯到一段时间内发生的情况。放两个快照:左边是旧快照,右边是新快照,然后比较它们。有什么不同? https://en.wikipedia.org/wiki/Spot_the_difference这种差异告诉你发生了什么:旧的和新的之间发生了什么变化。

一旦您了解了有关提交的信息,我们只需要添加一件事即可使分支正常工作。在 Git 中,一个分店名称记录的哈希IDlatest我们希望将其称为“分支的一部分”。主要就是这样——这就是分支名称对我们和 Git 的作用。它记录了last犯罪。提交本身记录了历史。

因此,给定一系列提交,在一个只有三个提交和一个分支名称的非常​​小的存储库中,我们有,例如:

A <-B <-C   <--master

The last提交是C。我们有名字master来存储它的实际哈希 ID——这实际上是一些大而丑陋的随机字母和数字字符串,我们永远无法猜到。犯罪C本身存储了早期提交的哈希IDB,使得C指着 B;并承诺B存储早期提交的哈希 IDA.

Commit A很特别:它根本不指向回,因为这是第一次提交,并且不能指向更早的提交。这就是 Git 知道的方式stop回去:当它不能时。

给定一个 Git 存储库,我们可以进入并查找所有提交,并查看哪些是最后提交,但拥有一个可以快速找到它们的名称会更快。当我们开始拥有多个分支机构时,这一点也变得很重要。让我们从一个大约有八次提交的小型存储库开始:

...--G--H   <-- master

现在让我们添加一个新分支。我们将从新的开始name also选择提交H。我们需要一种方法来了解我们正在使用哪个分支,所以我们将附加特殊名称HEAD分支名称之一:

...--G--H   <-- master, feature1 (HEAD)

现在我们将添加一个新的提交,它会获取一些新的随机哈希 ID,我们将调用它I:

          I   <-- feature1 (HEAD)
         /
...--G--H   <-- master

当我们添加一个new提交,Git自动更新分支名称指向新的提交。哪个分支名称会更新?唯一的那个HEAD被附加到。其他人都留在原地。

现在所有提交都通过H are on both分支,并提交I是*仅在feature1。让我们再次提交,然后创建一个新分支feature2选择提交H,然后开始使用那个:

          I--J   <-- feature1
         /
...--G--H   <-- master, feature2 (HEAD)

现在让我们添加两个提交feature2:

          I--J   <-- feature1
         /
...--G--H   <-- master
         \
          K--L   <-- feature2 (HEAD)

现在,假设在提交中I or J,我们创建了一个new file test1,尚未提交H。假设在提交中K or L, we also创建了一个名为的新文件test1.

Merging

We're now going to merge the two features into master, one at a time. For no obvious reason,1 we will use the --no-ff option:

git checkout master
git merge --no-ff feature1

为了达成这个。

When we git checkout master,我们将 Git 定向到:

  1. 提取由名称标识的提交master—commit H——到我们的工作树(以及 Git 的index,我们不会在这里讨论);和
  2. 设置我们的工作树来匹配,这意味着removing文件test1,这是在提交中L— 有一个已保存的具有该名称的快照文件 — 但不在提交中H.

所以,现在我们有:

          I--J   <-- feature1
         /
...--G--H   <-- master (HEAD)
         \
          K--L   <-- feature2

我们准备好了git merge --no-ff feature1.

Git 现在发现三个提交,不只是两个。感兴趣的三个提交是:

  • 我们目前的承诺,HEAD。这真的很容易找到,因为HEAD附加到分支名称并且分支名称指向提交,因此Git找到提交H.

  • 我们命名的另一个提交。这也很简单:我们说过要合并feature1。名字feature1识别提交J。 (看图就知道了!)

  • The merge base. The merge base is defined by the commit graph, formed by the inter-connections from one commit to another. While we won't go into all the details, you can think of this as the best shared commit, i.e., the best commit that's on both branches. Starting from J—as found by name feature1—we work backwards; and starting from H, as found by master, we also work backwards. When some commit is on both branches, that's a shared commit. The newest such commit—with newest not being properly defined here, but in most cases it's obvious—is usually the best commit.2

在这种情况下,合并基础显然是提交的H itself.


1The merge I'll do here is the kind you would get on GitHub, using its "merge pull request" button. From the Git command line, you get more options. The --no-ff option forces command-line Git to make a real merge, instead of using its short-cut "fast forward not-really-a-merge" option.

2Technically, what Git is doing is finding the Lowest Common Ancestor (LCA) in a directed graph. In a tree, there is always one well-defined LCA, but Git's commit graph is not necessarily a single tree: it's just a Directed Acyclic Graph or DAG. Two commits may have no LCA, or may have more than one LCA, and merge does different things for these cases.


合并,第 2 部分

找到合并基础后,Git 现在运行two of its 比较两个提交并查看发生了什么变化运营。比较 #1 将合并基础与--ours承诺,即HEAD。所以 Git 会这样做:

git diff --find-renames <hash-of-H> <hash-of-H>   # what we changed on master

显然,承诺H与提交相同H。一切都没有改变!

然后,Git 进行第二次比较,看看“他们”(我们)在另一侧更改了什么:

git diff --find-renames <hash-of-H> <hash-of-J>   # what they changed on feature1

那么 merge 的作用是combine这两组变化。当我们更改了某些文件而他们没有更改时,Git 会接受我们的更改。当他们更改了某些文件而我们没有更改时,Git 会接受他们的更改。这些组合的更改将应用​​于合并基础快照。这样,我们就可以保留我们所有的工作并添加他们的工作,但无论我们和他们做了什么不同的更改某些文件或多个文件,Git 会显示合并冲突.

在这种情况下,--oursdiff 完全是空的:我们没有改变任何东西。所以无论“他们”是什么——实际上,我们feature1—did,Git 接受这些更改。这包括添加新文件test1。这种合并进展顺利,因此 Git 自行进行了新的合并提交。

The 第一个父母新的合并提交是我们当前的提交,H, on master。新合并提交的第二个父级是他们的提交J, on feature1。我们可以画出这一点——这里的图画并没有正确显示第一次提交和第二次提交,但如果需要的话我们可以记住它,或者向 Git 询问父母双方的情况,看看哪一个是第一个,或者其他什么。

结果如下:

          I--J   <-- feature1
         /    \
...--G--H------M   <-- master (HEAD)
         \
          K--L   <-- feature2

注意如何不other分支名称已更改:我们仍在master,并且它已经移动到指向M, and feature1仍然命名提交J and feature2仍然命名提交L.

冲突的合并

如果我们现在运行另一个git merge——这次与feature2—Git 将再次定位三个提交:

  • 我们的和他们的承诺都是承诺M and L, 当然。
  • 合并基础是最好的shared commit.

看图。两者都有哪些提交master and feature2?提交G-H-I-J-M都在masterH in two方式,直接从第一个父母M,并间接地从J to I to H通过第二个父母M-因此G是否有两种方式存在,等等,但我们真正关心的是H and G在那儿。

同时,feature2结束于L,回到K,然后返回到H。所以承诺H and G两者都是共享的。犯罪H is the best不过,有一个。那么,合并基础再次提交H.

Git 将再次运行两个git diffs,都与--find-renames(检查重命名的文件)并且都来自H到两个分支尖端。所以 Git 将比较以下快照H反对其中的一个M,看看我们改变了什么。

What did我们改变,从H to M?嗯,在M,我们添加了通过比较得到的所有变化H vs J。所以我们的任何文件changed in feature1改变于M。但我们还添加了一个新文件,test1,在任一I or J,所以这个变更集说添加全新文件test1.

当我们比较时H vs L,这也说添加一个全新的文件test1. So 两个变更集都说要添加新文件.

Git 将这种冲突称为添加/添加冲突.在工作树中,Git 只是将两个文件的全部内容作为冲突留给您。你必须以某种方式解决这个冲突。你如何去做取决于你。无论您选择放入文件中的内容test1,您现在可以运行:

git add test1

Git 会假设文件中的内容test1 is the correct该冲突的解决方案。

请务必编辑该文件!如果不这样做,它就只有冲突标记,Git 认为这就是正确答案!可能不是。

一旦解决了所有冲突,并确保合并结果正确(例如,您已经完成了需要做的任何测试),您可以通过运行以下任一命令来安全地完成合并:

git merge --continue

or:

git commit

(The git merge --continue只是确保您仍在完成合并,然后运行git commit对于你来说,所以他们最终会做同样的事情——除非你已经完成或终止了合并,也就是说。)

Git 现在将制作another合并提交;我们称之为提交N,并像这样画它:

          I--J   <-- feature1
         /    \
...--G--H------M--N   <-- master (HEAD)
         \       /
          K-----L   <-- feature2

第一个父母是N is M,以及第二个父母N is L。现在有three方式从N to H, and all图中的提交已开启master.

现在可以安全删除这些名字了feature1 and feature2因为 Git 可以找到这些提交——包括J and L——从提交向后退N。你不have删除名称,如果您想保留查找提交的能力J and L直接、快速,但他们不再必要的,就像合并操作之前一样。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

合并git中2个不同分支中具有相同名称的2个文件 的相关文章

  • Git 和重定向

    我注意到 当 git html 项目页面如下所示 https github com fruux sabre dav 被克隆 以这种方式 git clone https github com fruux sabre dav 实际生成的远程 U
  • 为什么 cmake 在 git commit 后编译所有内容

    假设我有时在 Linux 上使用 cmake 2 8 编译一段代码 我更改了一个文件 my changed file 运行 cmake 并且只构建了这个文件 到目前为止 一切都很好 现在我想提交这个 git add my changed f
  • git reword 在变基期间显示合并冲突,但是 pick 工作正常

    我正在尝试用很少提交的另一个分支来重新建立一个分支 虽然提交包括合并提交 但我可以使用以下命令成功地对其进行变基git rebase i r m
  • 无论我做什么,我都无法推送我的代码并不断收到相同的错误

    我正在尝试将代码推送到远程分支 但不断收到此错误 rejected non fast forward error failed to push some refs to email protected cdn cgi l email pro
  • Eclipse git checkout(又名恢复)

    是否可以做相当于git checkout在 Eclipse 中使用 Egit 插件 我有一个已修改的文件 我想放弃更改并将文件恢复到源存储库中的内容 在 Subversion 中 这称为恢复 在 git 中 相当于 checkout 我在团
  • 未找到 Gradle DSL 方法:“versionCode()”

    构建我的 Android 项目时遇到问题 我使用Grgit https github com ajoberstar grgit填写versionCode and versionName在 gradle 中 一切工作正常 直到我将 Andro
  • 是否有 git-merge --dry-run 选项?

    我正在合并一个可能有很多冲突的远程分支 我怎么知道它是否会发生冲突 我没有看到任何类似的东西 dry run on git merge 如前所述 传入 no commit标志 但为了避免快进提交 也传入 no ff 像这样 git merg
  • 获取 git 存储库中每个文件的提交计数

    我正在寻找一种方法来查看有关 git 存储库中每个文件更改频率的统计信息 基本上 文件提交的频率实际上与以前的版本不同 此外 有没有办法获取文件上次更改的日期 我是一个 git 新手 还没有发现任何关于此的信息 任何帮助将不胜感激 这里有两
  • Git 查找第一个非本地提交

    有关的 列出尚未推送到源的 Git 提交 https stackoverflow com questions 3080509 list git commits not pushed to the origin yet git rev par
  • 在 emacs 的文件中不断出现的这些 ^M 是什么?

    我认为这可能与 TextMate 有关 但我们在一个小团队中工作 并且在 git 中几乎相同的文件的全文件冲突方面遇到了一些问题 在一个分支中 文件的每一行都附加了 M 这是什么神秘的事 M角色应该做什么 它从哪里来 我们的开发人员在 Wi
  • 我是否需要在裸仓库上运行 git gc ?

    man git gc http www kernel org pub software scm git docs git gc html其中没有明显的答案 而且我在谷歌上也没有任何运气 尽管我可能只是使用了错误的搜索词 我明白你应该偶尔跑步
  • 通过 cron 进行 git 推送

    我正在尝试运行git push来自 cron 当我在 shell 上以交互方式执行命令时 一切顺利 从我的用户的 crontab 运行命令时 cron 会传递错误消息 Permission denied publickey 我认为这与查找或
  • git 可以忽略特定行吗?

    我在手机的本机浏览器上测试时使用 git 同步到phonegap 因此我有以下行 var isPhoneGap false 显然 我在构建时更改了这一点 但是有什么方法可以设置 git 来忽略这一行 或者我是否必须将其放入自己的文件中并以这
  • 使用 Git 撤消临时更改

    假设我在 master 上并且有一个斑点 DEBUG FALSE CACHE SIZE 100 code code code 现在我开始在新分支中调试 DEBUG TRUE Don t forget to turn off CACHE SI
  • 本地 git 存储库强制从远程 git 存储库更新。 (胖客户端部署)

    Update 我认为这与 Windows git 客户端 msysgit 的问题有关 抱歉打扰你们了 我正在寻找一种方法来使多个客户端框与远程 git 存储库保持同步 强制从远程存储库进行更新并放弃客户端上可能已更改的任何内容 我遇到的问题
  • 如何使用最近的标签来装饰 git 日志?

    git log decorate将相关引用的信息添加到日志输出中 commit 9e895ace5d82df8929b16f58e9f515f6d54ab82d tag v3 10 rc7 Author Linus Torvalds lt
  • Git 将分支从一个远程推送到另一个远程?

    我设置了以下遥控器 git remote korg rorg 以及以下分支 git branch a no branch remotes korg gingerbread remotes korg gingerbread release r
  • 如何将 GitHub PR 的代码与其他分支的 PR 代码分开?

    我正在开发一个项目并解决问题 我正在为每个拉取请求 PR 创建一个不同的分支 上次我用他们的 PR 创建了两个不同的分支并解决了这两个问题 现在的问题是 我的两个拉取请求都与我在不同分支上推送的代码搞乱了 我借助以下命令在 git bash
  • 我如何知道哪些文件已在 git 中标记为“假设未更改”

    这个答案 https stackoverflow com a 936325 554807向您展示如何将 git 管理的文件标记为 我不希望从该文件的存储库进行更改 IE 拥有该文件的您自己的本地未跟踪版本 即使它仍然受到 git 的修订控制
  • 是否有一个 Git 命令可以在推送到 master 之前添加通知/警告

    我有一个用例 其他人依赖我在从 master 下拉时没有启用标志 但我需要在本地处理存储库时启用它 我希望 希望 Git 有一种方法可以添加通知或警告 当请求推送到 master 时会触发 作为某种 提醒 所以也许我的工作流程可能是这样的

随机推荐