如何创建一个 git 分支与主分支的自定义差异?
How to create a git branch with custom diff to master branch?
抱歉问题标题含糊不清,我不知道如何更好地表达它。基本上我有一个 master
分支有两个提交 c1
和 c2
:
+-----> dummy1 +-----> dummy2
| |
| |
| |
| |
c1+ c2+
. .
└── a.txt + ├── a.txt
├── b.txt +
├── not-wanted.txt +
└── c.txt +
c1
已添加 a.txt
文件。如您所见,c2
又添加了三个文件。现在我想要两个虚拟分支,一个来自 c1
,另一个来自 c2
,这样当我执行 git diff dummy1..dummy2
时,我只看到文件 b.txt
和 c.txt
在差异中。因此 dummy1<-dummy2
之间的结果 PR 仅显示 b.txt
和 c.txt
而不是 not-wanted.txt
.
这可能吗?
无需创建单独的分支。您可以区分当前分支中的提交:
git diff c1 c2
然后,如果需要,使用 diff 创建补丁:How to see the changes between two commits without commits in-between?
由于您不希望 not-wanted.txt 出现,看来您需要在删除 not-wanted.txt.
后创建一个新提交
Delete not-wanted.txt
git commit -m "c3"
现在从 c1 和 c3 创建两个分支
git branch dummy-1 c1
git branch dummy-2 c3
如果你还想在某个分支中备份not-wanted.txt文件,你可以在c2创建分支:
git branch backup-branch c2
TL;DR:您需要一些 new 提交。您无法通过现有提交获得想要的内容。
长
Git 与分支或文件无关:Git 与 提交 有关。 Pull requests2 使用分支名称,但只有这样 Git 才能找到 commits.
换句话说,一切都与提交有关。名称——分支名称如 master
或 develop
,或标签名称如 v2.1
,或 remote-tracking 名称如 origin/master
,甚至 Git 上的拉取请求]Hub——实际上只是识别 一个特定的提交 。每个提交 持有 个文件——实际上是 所有 个文件的完整快照——以及元数据,例如创建者(用户名和电子邮件地址),何时(date-and-time-stamp),以及为什么(日志消息)。
分支或拉取请求中 中有多个提交 这一事实的发生是因为每个提交都记录了其 parent 提交,通过哈希 ID。每个提交都有自己唯一的哈希 ID,每个提交1 都表示 ... 如果您想知道我之前发生了什么,请查看提交 XXXXXX,其中 X
s 是先前提交的哈希 ID。
因此,在您的设置中,您对 master 进行了一系列提交,这些提交要么在 c2
结束,要么继续下去:
...--B--c1--c2--D--E--F--G <--master
其他人可能在他们的存储库中有一系列提交,这些提交在 B
处结束。如果是这样,您可以创建一个指向 c1
的名称,从而得到:
...--B--c1 <-- name1
\
c2--D--...--G <-- master
如果您现在使用 name1
向其他人发出拉取请求,您是在要求其他人(其提交链结束于 B
)复制您的提交 c1
到他们的存储库中,并设置一些 他们 的名称指向 c1
.
你也可以让名字指向c2
:
...--B--c1 <-- name1
\
c2 <-- name2
\
D--...--G <-- master
并使用您的 name2
发出拉取请求,要求某人将 c1
和 c2
合并到他们的存储库中,并且将他们的名字之一设置为指向 c2
.
无论你做什么,你总是会要求他们——无论他们是谁——接受他们的 branch-name 指向现有的共享提交 B
,这已经在他们的存储库以及您的存储库,并将新提交添加到他们提交的末尾 B
。您控制的是您要求他们使用哪个特定提交。他们将从他们的末端——他们的 B
副本——到这个新的 tip 提交。所以你可以做一个新的提交,我们称之为 c3
,在 c1
之后,你记得通过分支名称 name3
:
c3 <-- name3
/
...--B--c1--c2--D--E--F--G <--master
本次提交c3
有你喜欢的任何内容。然后,您向他们发送一个拉取请求,要求他们设置 their master
(或任何其他分支名称),这样他们就不会指向共享提交 B
,而是复制将 c1
和 c3
提交到他们的存储库中,然后将他们的名称设置为指向 c3
.
为此:
$ git checkout -b name3 <hash-of-c1>
... make whatever changes you like, e.g., git cherry-pick -n <hash-of-c2>
... fix things up, git add files as needed ...
$ git commit
创建新的提交 c3
,您的分支名称 name3
将指向该提交。然后,您可以使用此 name3
名称和新的 c3
提交发出拉取请求。
1每个 non-empty 存储库中至少有一个提交有 没有 parent:这是第一个提交,它没有以前的提交,因为它不能。一些提交有两个,甚至可能更多,parents:这些是 merge 提交。不过,大多数提交只有一个 parent。 Git 的历史 是 提交,使用 backwards-looking 链从 上一个 提交向后工作形成的链串在一起,通过某个分支名称找到,一次提交一次(或达到合并时两次或多次提交)。
2拉取请求实际上并不是 Git 本身的一部分:它们是 add-ons,由 GitHub 和比特桶。 Git 提供的是提交本身和方法——git fetch
和 git push
——用于在对等存储库之间接收和发送提交。在 GitHub 之前,人们会克隆一个 Linux 存储库,进行新的提交,然后通过电子邮件发送补丁以供审查和修订……事实上,他们仍然这样做。
抱歉问题标题含糊不清,我不知道如何更好地表达它。基本上我有一个 master
分支有两个提交 c1
和 c2
:
+-----> dummy1 +-----> dummy2
| |
| |
| |
| |
c1+ c2+
. .
└── a.txt + ├── a.txt
├── b.txt +
├── not-wanted.txt +
└── c.txt +
c1
已添加 a.txt
文件。如您所见,c2
又添加了三个文件。现在我想要两个虚拟分支,一个来自 c1
,另一个来自 c2
,这样当我执行 git diff dummy1..dummy2
时,我只看到文件 b.txt
和 c.txt
在差异中。因此 dummy1<-dummy2
之间的结果 PR 仅显示 b.txt
和 c.txt
而不是 not-wanted.txt
.
这可能吗?
无需创建单独的分支。您可以区分当前分支中的提交:
git diff c1 c2
然后,如果需要,使用 diff 创建补丁:How to see the changes between two commits without commits in-between?
由于您不希望 not-wanted.txt 出现,看来您需要在删除 not-wanted.txt.
后创建一个新提交Delete not-wanted.txt
git commit -m "c3"
现在从 c1 和 c3 创建两个分支
git branch dummy-1 c1
git branch dummy-2 c3
如果你还想在某个分支中备份not-wanted.txt文件,你可以在c2创建分支:
git branch backup-branch c2
TL;DR:您需要一些 new 提交。您无法通过现有提交获得想要的内容。
长
Git 与分支或文件无关:Git 与 提交 有关。 Pull requests2 使用分支名称,但只有这样 Git 才能找到 commits.
换句话说,一切都与提交有关。名称——分支名称如 master
或 develop
,或标签名称如 v2.1
,或 remote-tracking 名称如 origin/master
,甚至 Git 上的拉取请求]Hub——实际上只是识别 一个特定的提交 。每个提交 持有 个文件——实际上是 所有 个文件的完整快照——以及元数据,例如创建者(用户名和电子邮件地址),何时(date-and-time-stamp),以及为什么(日志消息)。
分支或拉取请求中 中有多个提交 这一事实的发生是因为每个提交都记录了其 parent 提交,通过哈希 ID。每个提交都有自己唯一的哈希 ID,每个提交1 都表示 ... 如果您想知道我之前发生了什么,请查看提交 XXXXXX,其中 X
s 是先前提交的哈希 ID。
因此,在您的设置中,您对 master 进行了一系列提交,这些提交要么在 c2
结束,要么继续下去:
...--B--c1--c2--D--E--F--G <--master
其他人可能在他们的存储库中有一系列提交,这些提交在 B
处结束。如果是这样,您可以创建一个指向 c1
的名称,从而得到:
...--B--c1 <-- name1
\
c2--D--...--G <-- master
如果您现在使用 name1
向其他人发出拉取请求,您是在要求其他人(其提交链结束于 B
)复制您的提交 c1
到他们的存储库中,并设置一些 他们 的名称指向 c1
.
你也可以让名字指向c2
:
...--B--c1 <-- name1
\
c2 <-- name2
\
D--...--G <-- master
并使用您的 name2
发出拉取请求,要求某人将 c1
和 c2
合并到他们的存储库中,并且将他们的名字之一设置为指向 c2
.
无论你做什么,你总是会要求他们——无论他们是谁——接受他们的 branch-name 指向现有的共享提交 B
,这已经在他们的存储库以及您的存储库,并将新提交添加到他们提交的末尾 B
。您控制的是您要求他们使用哪个特定提交。他们将从他们的末端——他们的 B
副本——到这个新的 tip 提交。所以你可以做一个新的提交,我们称之为 c3
,在 c1
之后,你记得通过分支名称 name3
:
c3 <-- name3
/
...--B--c1--c2--D--E--F--G <--master
本次提交c3
有你喜欢的任何内容。然后,您向他们发送一个拉取请求,要求他们设置 their master
(或任何其他分支名称),这样他们就不会指向共享提交 B
,而是复制将 c1
和 c3
提交到他们的存储库中,然后将他们的名称设置为指向 c3
.
为此:
$ git checkout -b name3 <hash-of-c1>
... make whatever changes you like, e.g., git cherry-pick -n <hash-of-c2>
... fix things up, git add files as needed ...
$ git commit
创建新的提交 c3
,您的分支名称 name3
将指向该提交。然后,您可以使用此 name3
名称和新的 c3
提交发出拉取请求。
1每个 non-empty 存储库中至少有一个提交有 没有 parent:这是第一个提交,它没有以前的提交,因为它不能。一些提交有两个,甚至可能更多,parents:这些是 merge 提交。不过,大多数提交只有一个 parent。 Git 的历史 是 提交,使用 backwards-looking 链从 上一个 提交向后工作形成的链串在一起,通过某个分支名称找到,一次提交一次(或达到合并时两次或多次提交)。
2拉取请求实际上并不是 Git 本身的一部分:它们是 add-ons,由 GitHub 和比特桶。 Git 提供的是提交本身和方法——git fetch
和 git push
——用于在对等存储库之间接收和发送提交。在 GitHub 之前,人们会克隆一个 Linux 存储库,进行新的提交,然后通过电子邮件发送补丁以供审查和修订……事实上,他们仍然这样做。