合并同一分支上的两个GIT提交

合并同一分支上的两个GIT提交,git,Git,我重新制造了一个我已经遇到过几次的问题。这是基本情况: 创建包含以下内容的文件file1.txt: 你好, 欢迎来到我的档案。 再见 将第二个正文行添加到file1.txt**注意:添加此行时:“意外”删除“欢迎使用我的文件” 你好, 这是第二行。 再见 合并这两个提交的最佳方式是什么?目标是使文件file1.txt包含以下内容: 你好, 欢迎来到我的档案。 这是第二行。 再见 到目前为止,我尝试的是: $ git checkout 6d83.. $ git branch tmp $ git c

我重新制造了一个我已经遇到过几次的问题。这是基本情况:

创建包含以下内容的文件file1.txt:

你好,
欢迎来到我的档案。
再见

将第二个正文行添加到file1.txt**注意:添加此行时:“意外”删除“欢迎使用我的文件”

你好,
这是第二行。
再见

合并这两个提交的最佳方式是什么?目标是使文件file1.txt包含以下内容:

你好,
欢迎来到我的档案。
这是第二行。
再见

到目前为止,我尝试的是:

$ git checkout 6d83..
$ git branch tmp
$ git checkout master
$ git merge tmp

但我得到的信息是“已经是最新的”。git rebase是这里最好的选择吗?为什么创建一个临时分支然后合并不起作用呢?

在git中没有办法完成您想要做的事情。如果有任何问题,它将导致合并冲突。

您不能像上面尝试的那样通过合并自动完成。但是,假设您已经正确配置了您最喜欢的diff编辑器,这将允许您在提交之前手动修复文件并访问以前的内容。在您的主分支上:

git difftool ccd8:file1.txt file1.txt
一旦正确修复并保存,退出编辑器后

git add file1.txt
如果尚未推送,则可以修改以前的提交

git commit --amend
或者用恢复的生产线创建一个全新的生产线

git commit -m "Recovered line"

这里的问题是,就Git而言,删除您删除的行是正确的答案

记住Git的基本存储单元是提交。每次提交都有:

  • 一些数据:所有文件的快照;及
  • 一些元数据:关于提交的信息。这包括谁制作的、何时(日期和时间戳)以及为什么(您或提交人的日志消息)。不过,Git最后也是最重要的元数据是父提交哈希ID
每个提交都有一个唯一的散列ID。此散列ID在您进行提交时被分配给该提交。从那时起,该散列ID将保留给该提交。只有该提交才能具有该ID。1

同时,正如我们刚才提到的,每个提交都可以在其元数据中存储一个哈希ID。从技术上讲,每个提交可以存储Git想要的任意多个哈希ID,但它们必须是已经存在的提交的哈希ID。2大多数提交只存储一个其他提交哈希ID:提交的父级(单数)。(合并提交存储区2,这是它们合并提交的原因,而某人在一个全新的、完全空的存储库中进行的第一次提交不能有父级,因为没有以前的提交可供引用,所以它就没有父级。)

在您的情况下,那么,您可能有一些早期的提交,或者没有。我们将绘制一个图表,假设您:

... <-F <-G <-H
现在,让我们进行新的提交,添加这个新文件,
file1.txt
。提交
H
根本没有
file1.txt
它有一些其他文件,但没有
file1.txt
。我们
git add file1.txt
并运行
git commit
并提供一条日志消息。Git创建了一个新的提交,它将获得一个新的唯一的大而丑陋的散列ID,但我们将其称为
I
。Git将父项设置为
H
,以便
I
指向
H

...--F--G--H   <-- master
            \
             I
(没有理由将绘图
I
放在单独的行中,因此我们不会这样做。)

现在,您可以编辑文件,并按照通常的过程进行新的提交
J
。提交
J
I
作为其父级,Git将
J
的哈希ID写入名称
master

...--F--G--H
            \
             I   <-- master
...--F--G--H--I--J   <-- master
...--G--H   <-- master (HEAD), dev
现在我们将创建一两个新分支。当我们这样做时,我们需要在绘图中再添加一件东西。如果只有一个分支名称,
master
,那可能就是我们正在使用的分支。但是,如果我们添加了
dev
作为第二个名称会怎么样?我们用的是哪个名字

Git对此的回答是使用特殊的名称
HEAD
。此特殊名称通常附加到您的分支机构名称之一。(它只能附加到一个或无:不能超过一个。)我们将添加第二个分支名称,
dev
,但将
HEAD
附加到
master

...--F--G--H
            \
             I   <-- master
...--F--G--H--I--J   <-- master
...--G--H   <-- master (HEAD), dev
请注意,
dev
尚未移动:它仍然指向现有的提交
H
。名称
master
现在指向newcommit
J

现在,让我们在
dev
上创建两个提交。我们首先做
git checkout dev
。这会将我们的头连接到
dev
,并提取commit
H
的内容,以便与/一起工作:

          I--J   <-- master
         /
...--G--H   <-- dev (HEAD)
现在我们可以运行
git merge
。我们选择一个分支使用我们
git checkout master
git checkout dev
,然后运行
git merge
,并给它另一个分支的名称。4让我们
git checkout master
git merge dev
,以便
HEAD
和当前提交,识别
J
而不是
L
:5

我们合并了。合并后的快照是将
H
-vs-
J
H
-vs-
L
的组合更改应用于
H
的结果。合并的父级是前一个提交(与往常一样),另一个是我们在运行
git merge dev
时选择的提交

既然此合并已存在,则无法尝试将
L
甚至
K
合并到
master
中。原因是
L
M
之间的最佳共享提交是提交
L
。。。这已经是
M
历史的一部分。如果我们沿着最下面一行从
M
后退,我们将到达
L
。Git中由提交(包括它们的连接)组成的历史表明,
L
已经在这里合并


3当你问Git时:
头中有什么?你有两种表达方式。你可以问Git:What分支名称          I--J   <-- master (HEAD)
         /
...--G--H   <-- dev
          I--J   <-- master
         /
...--G--H   <-- dev (HEAD)
          I--J   <-- master
         /
...--G--H
         \
          K--L   <-- dev (HEAD)
          I--J   <-- master (HEAD)
         /
...--G--H
         \
          K--L   <-- dev
          I--J
         /    \
...--G--H      M   <-- master (HEAD)
         \    /
          K--L   <-- dev
          o--P--C--o--o   <-- branch1
         /
...--o--o
         \
          o--o--H   <-- branch2 (HEAD)
...--o--o--P--C--o--o--H   <-- branch (HEAD)
          o--P--C--o--o   <-- branch1
         /
...--o--o
         \
          o--o--H--C'  <-- branch2 (HEAD)
...--o--o--P--C--o--o--H--C'  <-- branch (HEAD)