如何看到哪个提交在一个分支aren't在其他?

我有两个分支develnext。在devel中,我有一个或多或少巨大的提交量。一些提交是在next中挑选的。我还添加了一些提交到next,合并到devel

现在我想看看next中缺少了什么,这样我就可以在将更改带到next之前详细地测试更改。我现在的问题是,我如何才能看到哪些提交是在devel而不是在next?

85362 次浏览

很少使用的命令git cherry (文档)显示了尚未被选中的提交。

简而言之:

git cherry <feature-branch> [base-branch]
# Checkout the base branch
git checkout main


# Diff against the target branch
git cherry -v next


# Diff against the target branch, without switching
git cherry -v next main

示例输出:

+ 492508acab7b454eee8b805f8ba906056eede0ff feat: make bazzable
- 5ceb5a9077ddb9e78b1e8f24bfc70e674c627949 hotfix: off-by-one
+ b4459544c000f4d51d1ec23f279d9cdb19c1d32b feat: add bar
+ b6ce3b78e938644a293b2dd2a15b2fecb1b54cd9 feat: add foo

+表示提交是仅在next,但是而不是main
-表示提交是在这两个分支

如果你希望提交时不带主题行,可以删除-v:

+ 492508acab7b454eee8b805f8ba906056eede0ff
- 5ceb5a9077ddb9e78b1e8f24bfc70e674c627949
+ b4459544c000f4d51d1ec23f279d9cdb19c1d32b
+ b6ce3b78e938644a293b2dd2a15b2fecb1b54cd9

此外,你还可以使用它来获得一个不错的实际不同提交的列表,这些提交没有在分支之间共享:

git log --left-right --graph --cherry-pick --oneline main...next

示例输出:

> 492508ac (HEAD -> next) feat: make bazzable
> 5ceb5a90 hotfix: off-by-one
> b4459544 feat: add bar
> b6ce3b78 (origin/add-foo, add-foo) feat: add foo

关键字是--cherry-pick

--cherry-pick

省略任何与“另一边”的另一个提交引入相同更改的提交;当提交集被对称差分限制时。例如,如果您有两个分支,A和B,通常的方法是用——left-right列出所有的提交,就像上面这个选项描述中的例子一样。然而,它显示了从另一个分支中挑选的提交(例如,"3rd on "有了这个选项,这样的提交对将被排除在输出之外。

正如在评论中提到的,最新版本的git添加了--cherry-mark:

--cherry-mark

比如——cherry-pick(见下文),但是用=标记等价的提交而不是省略它们,用+标记不等价的提交。

你可以尝试做git日志子集:

git log --oneline devel ^next

如何

git log next..devel

结果类似于Byran的答案(不同的提交顺序),但我们的两个答案都会在分支之间产生不同的提交,而不是只显示一个分支中有什么而另一个分支中没有什么。

要获得未集成到发布分支(下一个)的提交列表,您可以使用:

git rev-list --reverse --pretty="TO_TEST %h (<%ae>) %s" --cherry-pick --right-only origin/release_branch...origin/development_branch | grep "^TO_TEST " > NotIntegratedYet.txt

查看git-rev-list获取更多信息。

@Mark Longair在他的回答中指出了这一点,但我想增加一些额外的见解。

相关的,并且回答了如何分解一个大的Pull Request (PR)的问题,特别是当压缩你的提交是不切实际的,因为一个或多个master合并到你的feature_branch

< br > < p >我的情况: 我做了一个30次提交的大feature_branch,并在GitHub上打开了一个Pull Request (PR),将其合并到master中。分支master在我下面改变了很多,并收到了200个我的feature_branch没有的提交。为了解决冲突,我执行git checkout feature_branchgit merge mastermaster的更改合并到我的feature_branch中。我选择在最新的master上merge而不是rebase,这样我就必须只解决一次冲突,而不是潜在的30次冲突(每次提交一次)。我不想先把我的30个提交压缩成1个,然后重新基于最新的master,因为这可能会在PR中抹去GitHub审查评论历史。所以,我将master合并到我的功能分支中,并一次性解决了冲突。一切都很好。然而,我的PR太大了,同事们无法审阅。我需要把它分开。我去压缩我的30个提交,哦不!他们在哪里?它们现在都与master最近的200次提交混合在一起,因为我将master合并到我的feature_branch!我该怎么办?< / p >

如果你想尝试git cherry-pick单独提交,则使用git cherry:

git cherry来拯救(有点)!

要查看所有在feature_branch但不在master中的提交,我可以这样做:

git checkout feature_branch
git cherry master

或者,我可以检查来自任何分支的提交,而不需要首先通过执行git cherry [upstream_branch] [feature_branch]来确保我在feature_branch上,就像这样。同样,这将检查哪些提交在feature_branch中,但不在upstream_branch中(在本例中为master):

git cherry master feature_branch

添加-v还会显示提交消息的主题行:

git cherry -v master

输送到"word count" "-lines" (wc -l)来计算有多少次提交:

git cherry master | wc -l

你可以将这个计数与GithHub PR中显示的提交数进行比较,以更好地了解git cherry是否真的在工作。你也可以逐个比较git哈希值,看看它们在git cherry和GitHub之间是否匹配。注意,git cherry不会计算你将master合并到feature_branch的任何合并提交,但GitHub会。因此,如果你看到计数中有一个小差异,搜索GitHub PR提交页面中的单词“merge”,你可能会看到这是没有出现在git cherry中的罪魁祸首。例如:一个名为“合并分支'master'到feature_branch”的提交将显示在GitHub PR中,但当你运行git cherry master feature_branch时却不会。这很好,也是意料之中的。

所以,现在我有了一种方法来找出我可能想要在一个新的功能分支上选择哪些差异来分割这个差异:我可以在本地使用git cherry master feature_branch,或者查看GitHub PR中的提交。

压扁会有什么帮助——如果我们能压扁:

然而,另一种方法是把我的30个提交压缩成一个,把它补丁到一个新的特性分支上,软重置补丁提交,然后使用git gui逐文件、逐块或逐行添加片段。,一旦我得到一个子特性,我就可以提交我所添加的,然后检出一个新分支,再添加一些,提交,检出一个新分支,等等,直到我把我的大特性分解成几个子特性。问题是,由于我的__ABC1到我的feature_branch,我的30个提交与来自其他人的其他200个提交混合在一起,因此重基是不切实际的,因为我必须筛选230个提交来重新排序并压缩我的30个提交。

如何使用补丁文件作为一个更容易的压缩替换:

一个解决方法是简单地< A href="https://stackoverflow.com/questions/28192623/create-patch-or-diff-file-from-git-repository-and-apply-it-to-another-different/28193089#28193089">获得一个补丁文件,其中包含我所有30次提交的“压缩等效”,将其补丁到master的一个新fork(一个新的子功能分支),并从那里开始工作,如下所示:

git checkout feature_branch
# ensure I have the latest changes from master merged into feature_branch
git merge master
# Obtain a patch file, which is the equivalent of a squash of my 30 commits into 1 commit:
git diff master..feature_branch > ~/mypatch.patch
git checkout master
# Create a new, sub-feature branch
git checkout -b feature_branch2
# Patch the 30 commit patch file onto it:
git apply ~/mypatch.patch

现在,我已经在本地应用了30个提交的补丁,但它们都是未部署和未提交的。

现在使用git gui来添加文件、块和/或行,并分解你的大PR或“diff”:

注意,如果你没有git gui,你可以很容易地用sudo apt install git-gui在Ubuntu中安装它。

我现在可以运行git gui并开始添加文件、块和/或行(通过在git GUI程序中右键单击),并将30个提交功能分支分解为上面所述的子分支,重复添加、提交,然后分叉一个新的功能分支,重复这个循环,直到所有更改都添加到子功能分支,我的30个提交功能成功地分解为3或4个子功能。现在我可以为每个子功能打开单独的PR,这样我的团队就更容易检查它们了。

引用:

  1. 从git存储库创建补丁或diff文件,并将其应用到另一个不同的git存储库