git checkout --track origin/branch 和 git checkout -b branch origin/branch 之间的区别是什么?

316

有人知道这两个命令在切换和跟踪远程分支时的区别吗?

git checkout -b branch origin/branch
git checkout --track origin/branch

我认为两者都跟踪远程分支,所以我可以将我的更改推送到原始分支,对吗?

它们之间有任何实际区别吗?

4个回答

420
这两个命令的效果相同(感谢Robert Siemer的回答指出)。
实际上的区别在于使用不同命名的本地分支时:
  • git checkout -b mybranch origin/abranch 将创建mybranch并跟踪origin/abranch
  • git checkout --track origin/abranch 仅会创建'abranch',而不是具有不同名称的分支。
(也就是说,正如 Sebastian Graf {{em:所评论的那样}},如果本地分支不存在。
如果已经存在,则需要git checkout -B abranch origin/abranch)
注意:从Git 2.23(2019年第三季度)开始,将使用新命令git switch(链接)
git switch -c <branch> --track <remote>/<branch>

如果一个分支存在于多个远程仓库中,并且其中一个由checkout.defaultRemote配置变量命名,我们将使用该远程仓库以消除歧义,即使<branch>在所有远程仓库中都不唯一。将其设置为例如checkout.defaultRemote=origin,以便始终从那里检出远程分支,如果<branch>存在于'origin'远程仓库中但不确定。
这里,“-c”是新的“-b”。
首先,一些背景信息:Tracking 意味着本地分支的上游设置为远程分支:
# git config branch.<branch-name>.remote origin
# git config branch.<branch-name>.merge refs/heads/branch

git checkout -b branch origin/branch会:

  • 创建/重置branchorigin/branch引用的位置。
  • 创建分支branch(使用git branch)并跟踪远程跟踪分支origin/branch

当本地分支从远程跟踪分支开始时,Git会设置分支(特别是branch.<name>.remotebranch.<name>.merge配置条目)以便git pull可以适当地从远程跟踪分支合并。
可以通过全局branch.autosetupmerge配置标志更改此行为。该设置可以通过使用--track--no-track选项来覆盖,并稍后使用git branch --set-upstream-to进行更改。


git checkout --track origin/branch会执行与git branch --set-upstream-to相同的操作:

 # or, since 1.7.0
 git branch --set-upstream upstream/branch branch
 # or, since 1.8.0 (October 2012)
 git branch --set-upstream-to upstream/branch branch
 # the short version remains the same:
 git branch -u upstream/branch branch

它还将设置 'branch' 的上游。
(注:git1.8.0 将弃用 git branch --set-upstream 并替换为 git branch -u|--set-upstream-to:请参见 git1.8.0-rc1 announce

将本地分支注册到上游分支将会:

  • 告诉git在 git statusgit branch -v显示两个分支之间的关系
  • 在检出新分支时,git pull 不带参数 将指向上游分支进行拉取

请参阅 "如何使现有的git分支跟踪远程分支?" 了解更多信息。


1
@VonC 我一直在寻找你提到的额外信息中的那个小细节。在我的情况下,我很好奇为什么我的一些分支允许我 git pull,而有些分支则要求从远程分支拉取。原来,如果你第一次检出同事创建的远程分支,git 会添加 branch.<BNAME>.remote=origin 到本地 gitconfig 中。这样就可以使用 git pull 命令了。但是,如果你是创建分支的人 git checkout -b BNAME,那么 git 当然不知道。所以你应该指定它的远程分支。 - batilc
@batilc “原来如果你第一次查看同事创建的远程分支”,是的,阅读https://git-scm.com/docs/git-checkout,我看到:“`如果<分支>未找到,但确实存在一个跟踪分支在恰好一个远程(称其为<remote>)中具有匹配的名称,则视为等效于$ git checkout -b <branch> --track <remote>/<branch>`” - VonC
@batilc 我同意。我倾向于不使用always,因为我更喜欢明确地设置跟踪,但在你的情况下,那应该是正确的设置。 - VonC
@batilc 我还没有尝试过。我想确实显式配置应该优先。 - VonC
1
"git branch --set-upstream-to branch upstream/branch" 不是正确的语法。正确的语法应该是:"git branch --set-upstream-to upstream/branch branch"。 - Alcamtar
显示剩余2条评论

50

完全没有区别!

1)git checkout -b branch origin/branch

如果没有--track--no-track,则默认情况下会假定使用--track。可以通过设置branch.autosetupmerge更改默认值。

实际上,1)的行为就像git checkout -b branch --track origin/branch

2)git checkout --track origin/branch

“为了方便起见”,省略了-b--track被视为带有-b,并猜测-b的参数为“branch”。 猜测由配置变量remote.origin.fetch驱动。

实际上,2)的行为就像git checkout -b branch --track origin/branch

正如您所看到的:没有区别。

但是它甚至变得更好:

3)git checkout branch

如果“branch”不存在但“origin/branch”存在,则也相当于git checkout -b branch --track origin/branch1


这三个命令都将“branch”的“upstream”设置为“origin/branch”(或失败)。

上游用作无参数git statusgit pushgit merge和因此git pull(如果配置如此(这是默认值或几乎是默认值))的参考点。

例如git status会告诉您与上游相比落后或超前了多少。

自Git 2.0以来,默认情况下将git push配置为将当前分支推送到上游2

1 …如果“origin”是唯一拥有“branch”的远程仓库
2 默认(命名为“simple”)同时强制两个分支名称相同。


这是一个很好的答案,因为它解释了许多我们在命令行中常用的git命令中的隐含参数,无论我们是否考虑到git为我们做出的所有隐含假设,都基于“默认”配置。 - Pablo Adames
@Mikef ... 无论是3)还是我提到的任何其他命令行,都无法实现。 - undefined

6

该书似乎表明这些命令产生的效果是相同的:

简单示例就是你刚刚看到的,运行 git checkout -b [branch] [remotename]/[branch]。如果你有 Git 1.6.2 版本或更高版本,则还可以使用 --track 简写:

$ git checkout --track origin/serverfix 
Branch serverfix set up to track remote branch serverfix from origin. 
Switched to a new branch 'serverfix' 

要设置一个与远程分支不同名称的本地分支,您可以轻松地使用第一个版本并指定不同的本地分支名称:
$ git checkout -b sf origin/serverfix

当你的bash或oh-my-zsh git补全能够为你提取origin/serverfix名称时,这将非常方便 - 只需添加--track(或-t),然后就可以开始了。


0

你不能用这个命令创建一个新分支

git checkout --track origin/branch

如果您有未暂存的更改。
以下是示例:
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   src/App.js

no changes added to commit (use "git add" and/or "git commit -a")

// TRY TO CREATE:

$ git checkout --track origin/new-branch
fatal: 'origin/new-branch' is not a commit and a branch 'new-branch' cannot be created from it

不过,你可以轻松地使用git checkout -b命令创建一个带有未暂存更改的新分支:

$ git checkout -b new-branch
Switched to a new branch 'new-branch'
M       src/App.js

请注意,问题中的两个命令都是用于跟踪现有的远程分支(origin/branch)。 - yorch
@Green 你所测试的是 origin/new-branch 而不是 origin/branch,你知道吗? - Robert Siemer

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