当前分支和分支创建之间的git差异

10

想象一下:

git-diff-three-dots

我三天前创建了分支“B”,这是我目前正在工作的分支。现在我想知道自从创建该分支(X)以来发生了什么更改。

下面内容会给我展示 B 和 X 之间的差异(就像图片中的虚线所示):

git diff A...

上面的命令很方便,因为它很短,我不需要记住“X”。

但是,我非常懒惰。我不想记住我的当前分支是从哪个分支创建的。

我该如何避免记忆/输入A

我正在寻找一种无需我输入的方式。它应该列出自从上次创建分支以来所有的更改。


你的意思是这个命令可以工作:git diff X...?你想要比较A还是X? - Igal S.
@IgalS。我正在寻找一种类似于图片中虚线的差异。 - guettli
1
@IgalS。不,A...是指的。请注意三个点。在git diff中,它们表示“共同祖先”,即Xgit diff A..将计算与A的差异。请注意两个点。 - j6t
@guettli:你能详细介绍一下你的工作方式吗?例如:你是否有一个确定的分支集(比如:masterdeveloprelease-{xx}),它们可以作为分支的有效“分叉点”? - LeGEC
@LeGEC 在90%的情况下,我会从主分支创建一个功能分支。在10%的情况下,我会从同事的功能分支创建一个分支。虽然有发布分支,但在这种情况下并不重要。 - guettli
好的,你的需求可以翻译为:找到当前分支历史记录中最近的提交,该提交位于“{master,其他特性分支}”中。 (注意:您可以调整我的答案的第二部分,仅在“--not”部分中列出“{master,其他特性分支}”)。 - LeGEC
6个回答

10

嗯,@{-1} 可能 是 A。但也有可能不是。它只是表示“我之前所在的分支”。同样地,查看 git reflog 可能会告诉您创建当前分支时所在的位置。

但当前分支本身并没有告诉您任何信息。真正的问题在于您对“分支”的理解与 Git 不同。“自从创建分支以来”这个短语可能会误导您。

您似乎认为 B 是“从 X 开始一直到 B 结束的所有内容”。其实不是这样的。B 只是一个提交:即您图表中标记为 B 的提交。倒退回到根提交的所有内容——B 之前的提交、再往前一次提交、X、X 之前的提交以及再往前一次提交——它们都有完全相同的状态。它们都是可以从 B 访问到的提交,那就是它们的全部内容。

所以,在 Git 的思维中,X 没有什么特别之处。认为它很特别,因为它是 A 和 B“相遇”的地方。但要区分这一点,您必须知道 B A 的名称。如果你想让 Git 帮助你,你必须将你看到的拓扑结构传达给它。

如果您愿意讨论A和B,那么可以使用git diff ...Agit diff A...来查找自X以来发生了什么变化。或者您也可以谈论git merge-base A B找到X。但是只有人类能够区分此处的关键是A。


一个分支没有生日(即它开始存在的提交)吗? - guettli
2
@guettli 不是的。"分支"只是一个提交的标签,仅此而已。你可以删除分支B,然后将相同的标签B附加到相同的提交上。那么你现在会认为分支B是何时诞生的呢? - j6t
如果一个分支被删除,然后再次创建,那么我认为这个分支就是重新诞生了。分支的旧生命将会消失,不需要追踪它。但是追踪新的诞生可能是有意义的。 - guettli
2
你是对的,除了“你必须知道B和A的名称。”可以检查“nothing special”提交在提交树中的位置,以找到最近的祖先提交,该提交也是另一个提交的祖先提交。换句话说,您不必知道A的名称,但要知道一种算法来正确反映您所指的A的语义。据我所知,@VonC的答案做到了这一点。 - Inigo
1
@guttli 很好的发现,但很容易纠正:找到最近的祖先提交,它也是另一个分支头或祖先的头。至于你的问题:我的直觉反应(可能是错误的)是这对 Torvalds 来说是显而易见的,他没有做出来有原因。当你变基一个分支时会发生什么?如果你从一个点重新变基分支,该点在你提出的“生日”之前呢?这将使你的分支成为孤立提交序列的分支。你的想法可能很好,但需要更多的分析。向 Git 维护者提出建议。 - Inigo
显示剩余2条评论

5

但是:我非常懒。我不想记得我当前的分支是从哪个分支创建的。

那你需要编写一个脚本,并命名为git-diffca,然后可通过git diffca进行调用(ca代表“共同祖先”)

在该脚本中,您需要决定在所有候选分支中选择哪些标准:

     c--c--c     (C)
    /
a--Y--X--a--a    (A)
       \
        b--b--b  (B, HEAD)
     

您想查看什么:来自CB分支之间共同祖先Y的更改?还是来自AB之间的共同祖先X
我会查看所有分支,计算每个分支的git merge-base <aBranch> B,并选择最近的提交(在此模式下为X
然后该脚本将显示git diff A...(因为git merge-base A B得出了与B的最近共同祖先)。

非常感谢。我不确定这是否是一个答案。现在的问题是:如何实现脚本 git-diffca - guettli
@guettli 正如我所描述的那样:有多个可能的分支:脚本选择最近的基础合并。 - VonC

3
我不想记住当前分支是从哪个分支创建的。如何避免记住或者输入 A
告诉Git来替你追踪这个信息。为了实现这个功能,在你要分支开展当前检出时,添加 t 选项:
git checkout -tb B

你希望切换到一个新的分支 B 并跟踪你现有的分支,如分支 A,对吧?注意,我不需要记住或输入它。 可以使用 git branch -u 选项在事后设置新的上游。

当你告诉 git 你正在跟踪哪个分支时,git diff @{u}... 或者 git diff @{upstream}... 就能做到你想要的事情。 你甚至可以将其作为别名:git config --global alias.du diff @{u}...


请注意,Git 通常会自动从远程设置上游分支的跟踪:如果你输入 git checkout fix32943,并且你没有一个叫做 fix32943 的分支,但是只有一个远程存在 fix32943 分支,Git 将创建一个本地的 fix32943 分支并设置它跟踪该远程分支,就像你手动设置一样。因此,git diff @{U}... 通常已经能够按照你所期望的方式工作了。


我本以为这是完美的解决方案,但它打破了我的常规流程:git co -b foo,编写代码,提交,推送。然后我看到一条消息:fatal: The current branch foo has no upstream branch.... use: git push --set-upstream origin foo。我复制并粘贴了这行代码,然后创建了一个拉取请求。如果我使用 git co -tb foo,那么这个方法就不再起作用了。悲伤,但却是真实的。 - guettli
检查 push.default 配置,你可能会喜欢 currentmatching 的功能。 - jthill

2

我将重复@matt在他的答案中详细阐述的内容: git 跟踪 提交,但不跟踪 分支


然而,有一些东西看起来像是“该分支的生命周期”,它就是该分支的 reflog:

git reflog my/branch

您可以检查历史记录,看看是否有任何信息。
例如:创建分支的提交是:
git reflog my/branch | tail -1
  # and use something like `| awk '{ print $1 }'` for the sha,
  # or parse the 'branch: Created from ...' message (if there is one)
  # to see if there is a branch name

git reflog --format="%H" my/branch | tail -1   # if you want only the sha

但是需要注意的是:如果在该分支的生命周期内运行了git rebase,那么初始提交点可能不再是您正在寻找的分叉点。


另一个代理方法可能是:查看存在于分支B历史记录中,且不存在于其他任何分支历史记录中的提交:

# the following will list all branches except 'my/branch' :
git branch --format="%(refname:short)" | grep -v "my/branch"

# here is a way to list all commits on 'my/branch', excluding commits
# from all other branches.
# Adding `--boundary` will also display the first 'hidden' commit
git log --boundary --oneline --graph my/branch --not $(<the command above>)

# you can also replace 'git log' with 'git rev-list', if you only want the hashes

如果你很幸运,被称为边界点的提交就是你要找的那一个。


需要注意的是:如果在你的分支历史中有一些合并,那么你可能会有几个“边界”点;如果还有另一个分支比你正在寻找的X更近地从分支B派生出来,那么边界将是该分支与masterdevelop的分岔点,而不是与它。


根据您的评论进行更新:

  • 列出本地克隆中的所有特性分支(除了您自己的分支)
  • 从这些分支中查找当前分支的“分叉点”
# get the name of your current active branch :
mybranch=$(git rev-parse --abbrev-ref HEAD)

# make a separate function to list on stdout "all the branches except mine"
list_branches () {
  # list the `master` branch
  echo "master"

  # get all 'origin/somefeature' branches, excluding mybranch

  # suggestion: list remote branches (you will get all features,
  # even if you haven't created a local checkout of a branch)
  git branch -r --format="%(refname:short)" |\
    grep "/feat/" |\    # you can grep for a pattern if you have one
    grep -b "$mybranch" # remove your branch from the lot
}

# get the 'boundary' commits of your branch with respect to
# all the other branches
base=$(
  git rev-list --boundary --graph "$mybranch" --not $(list_branches "$mybranch") |\
    grep -e "^-" |\  # rev-list will prefix boundary commits with a '-'
    tail -1 |\       # if there are several, only take the last one
    tr -d '-'        # delete that leading '-'
)

# with some luck, we computed the correct base commit :
git diff $base...

0

正如之前的每个人所说,git跟踪提交而不是分支。您可以在分支之前标记提交以使其更容易,但这仍然需要您手动进行标记。

步骤:

  • git tag <some descriptive tag>
  • git push origin <tag name> 如果是单个标签
    • git push --tags 如果是多个标签

然后,从这里您可以轻松查看日志并根据需要查看更改。

或者,您可以只命名您的分支为 branchName_branchedFrom 类型的命名约定,然后它将更容易跟踪(其中branchedFrom可以是short-sha1或如果您已经标记了它,则可以是标记名称。


我非常懒,而且我确信这个工作流程对我来说是不可行的。 - guettli

0

事后修改不可能(执行 git diff A... 是最好最短的选择)。但是,如果你事先知道一个分支在另一个分支的上游,那么你可以在创建分支时使用 -t/--track 选项设置“上游配置”:

git checkout --track --branch newbranch upstreambranch

要为现有分支配置上游,请使用带有-u/--set-upstream-to=选项的git branch命令:

git branch --set-upstream-to=upstreambranch existingbranch

(在您的示例中:newbranch/existingbranch == C,upstreambranch = A)

然后,您可以使用{{link1:newbranch@{upstream}}}或newbranch@{u}(简称)访问上游分支的当前分支尖端提交。要获取当前分支(HEAD)的上游分支,只需使用@{u}即可。

您的命令将变为:

git diff newbranch@{u}...newbranch

或者,使用 newbranch 分支检出:

git diff @{u}...

这不是与jthill的答案相同吗(在您回答几个小时之前发布)? - guettli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接