当我在GitHub上打开一个pull请求时,自我上次请求以来的所有提交和所有新提交都会自动添加到此请求中。我似乎无法控制添加哪些提交,哪些不添加。
我做了以下事情:
git checkout patch
git commit -m "Made a commit"
git push origin patch
git checkout bugs
git commit -m "Fixed a Bug"
git push origin bugs
看了拉请求,两个提交都存在..我不想要那个。我究竟做错了什么?我认为这两个提交都在不同的分支上。我很困惑。
答案 0 :(得分:2)
您需要注意分支起点和生成的提交图。
在Git中,提交可以并且经常是一次多个分支。如果您来自其他一些版本控制系统,这可能会非常令人吃惊。例如,在Mercurial中 - 在许多方面与Git非常相似 - 每次提交都在一个分支上。但是,在Git中,每次提交都在零个或多个分支上同时。
这种影响相当远,但对你来说最直接的一点就是当你在GitHub上发出拉动请求时,GitHub的Git操作会做你没想到的事情。 (我最近使用过的GitHub似乎试图隐藏Git的许多复杂功能。这有其优点,因为Git的复杂性可能令人生畏。但它有缺点,比如引导你走下这条特殊的道路。)
我会尽量避免在这里详细说明(对我而言很难:-))。理解所有这一切的关键在于可视化提交图并知道在某种基本层面上拉动请求是。
该图形正式为 D 竖立的 A 循环 G raph或DAG,由您和其他人提交的提交形成。每个提交通常都有一个父提交。这些父母形成了一个向后链。如果我们从一个完全空的存储库开始(根本没有提交)并进行第一次提交,那么该提交有 no parent,因为之前没有提交:
A
(我在这里提交单字母名称,而不是Git的难以理解的哈希ID)。当我们进行第二次提交时,它将第一次提交作为其父提交。我们说新提交B
"指向"现有提交A
:
A <-B
我们继续进行尽可能多的提交:每个新提交指向一些早期的提交。对于简单的线性链,这一切都非常简单,我们在这里要做的就是添加一个事实,即Git需要一个 name 它可以用来找到 last 提交。我们开始使用的名称是master
:
A <-B <-C <-- master
所有Git的箭头总是倒退。来自分支名称的那些移动实际上,master
或我们所处的任何分支,在我们添加每个新提交时自动更新 - 所以我认为它是明智地继续画画;但是告诉我们提交C
指向B
,B
指向A
的箭头将永久修复。没有箭头就可以更容易地绘制它们,这就是我所做的。
现在让我们创建一个 new 分支名称,其中包含大量提交内容:
...--F--G--H <-- master, patch
我们现在拥有的是两个分支名称,两者都指向同一个提交!提交H
在两个分支上。提交G
和F
以及所有早期的提交也是如此。现在知道我们实际上是哪个分支变得很重要,所以让我们将(HEAD)
添加到其中一个分支:
...--F--G--H <-- master, patch (HEAD)
啊哈,我们在分行HEAD
。我们现在添加一个新的提交I
:
...--F--G--H <-- master
\
I <-- patch (HEAD)
Git的作用与以往一样:它使用一个父进行新的提交,以便I
指向H
,然后移动当前分支 -ie,patch
,如HEAD
所示 - 以便它指向新提交。
master
分支根本不会更改:它仍包含提交A
到H
(包括)。 patch
分支现在包含A
到I
的提交。
现在让我们创建另一个新分支,例如bugs
。但名称bugs
在哪里指向?我们有两个不错的选择:我们可以将名称指向提交H
,其中master
现在点,或者我们可以将其指向提交I
,其中patch
点现在
无论我们选择哪一个,我们现在都可以进行新的提交J
。但J
的父级将由我们创建bugs
后的哪个提交bugs
确定!所以我们选择哪一个非常重要。
当你第一次提交时,你选择了I
,并得到了这样的图片:
...--F--G--H <-- master
\
I <-- patch
\
J <-- bugs (HEAD)
但是,如果您选择H
作为起点,那么您将获得另一张照片:
J <-- bugs (HEAD)
/
...--F--G--H <-- master
\
I <-- patch
拉动请求总是必须针对某些现有起点完成。如果你使用old-school,pure-Git命令,git request-pull
,你提供起点。 GitHub用他们的clicky按钮做的是自动为你选择起点。但是有一个问题:起点必须是您和您的上游存储库已经共享的提交。 (在这个特定的上下文中,您的上游是您分叉的存储库。上游这个词在这里有点含糊不清:就像Git的大部分术语一样,这个词已被重载,意味着许多不同的的东西。)
简而言之,上游提交始终是他们的 master
指向现在,或者至少指向早期(他们自己的master
可能有的)因为你分叉了东西而前进了。)这将在上面的图纸中提交H
。
如果您的图形拓扑类似于第一个提交J
指向返回I
的{{1}} - 那么从该点开始的拉取请求将包括两个提交。 H
在您的存储库中的几个分支上并不重要;重要的是commit I
是您和上游存储库都使用的最新版本。 (同样,这些单字母名称中的每一个代表一个实际的原始Git哈希ID,例如H
或其他。
要让您的拉取请求中只有一个commit 1f931caf22b7...
提交,您需要将图形拓扑与第二个类似,其中J
是H
的父级。 GitHub界面至少在我看来,虽然我对它的经验相对较少 - 非常擅长隐藏你的图形拓扑结构,因此很难让你查看实际的拓扑结构,因此看看会发生什么拉请求。
使用命令行Git时,可以使用the help of "A DOG", all decorate oneline graph查看(可视化)拓扑:
J
各种GUI也会为您执行此操作,例如git log --all --decorate --oneline --graph
。这会像我在这些StackOverflow帖子中那样垂直而不是水平绘制图形,但此时的想法应该足够清晰。
答案 1 :(得分:0)
我在您的行动中看到您在git add <files>
和made a file change
之间以及git commit -m "Made a commit"
和made a file change
之间没有git commit -m "Fixed a Bug"
。这可能有一些意义。