当你不在 BRANCH 上时 git push -u origin BRANCH 做什么?

What does git push -u origin BRANCH do when you are not on BRANCH?

当我第一次开始使用 git 时,另一位团队成员告诉我要始终使用

git push -u origin MYBRANCH

因为它可以防止我不小心将代码推送到错误的分支。我没有完全理解,今天试图理解这意味着什么。

我创建了一个本地存储库并提供了我的确切命令,这样您就可以copy/paste重现我所做的事情。

在此测试中,我有一个本地(磁盘上)回购和两个分支:

git branch
  main
* feature/fixthis

我在 feature/fixthis 分支并且 运行:

git push -u origin main
  # NOTE: the current branch is feature/fixthis

我是不是不小心把我的功能分支推到了主分支上?

我的解决方案(使用本地测试自行解决)

为了亲自测试,我做了以下操作。这些命令的编写方式使您可以 copy/past 到 UNIX bash shell 以重现本地 git 存储库并创建我正在询问的确切场景。

# Step 1:  Create local repo
mkdir so-test; cd so-test; git init --bare local-git-repo.git

# Step 2: git clone local (empty repo).
git clone ./local-git-repo.git test-this

# Step 3: Add a Readme.md file, commit and push the change 
cd test-this; echo hi > README.md; git add README.md; git commit -m "initial commit"; git push -u origin main

# Step 4: Check the branch feature/fixit.
git co -b feature/fixit

# Step 5: Make change and accidentally push it to main.  
echo In feature/fixit >> README.md; git add -u .; git commit -m "change on feature/fixit"; 

# Step 6: Do the push from the feature/fixit branch to main
git push -u origin main

命令git push -u origin main是否不小心更新了主分支?

当我查看日志时,我无法弄清楚上次推送发生了什么,它似乎没有更新 origin/main 分支,因为我没有看到 origin/feature/fixit 标签(在任何提交上)。

git log
commit 1bba12ad200080cb0a59aa0e2fb518a1e284b135 (HEAD -> feature/fixit)
Author: me@example.com
Date:   Thu Apr 7 14:25:19 2022 +0000

    change on feature/fixit

commit dcf8098bda7c937c80bc60ee974ac6eb9a895ced (origin/main, main)
Author: me@example.com
Date:   Thu Apr 7 14:20:06 2022 +0000

    initial commit

正在寻找答案

许多其他人

该命令只是推送到远程 origin 您的本地分支 MYBRANCH (远程分支具有相同的名称)。当你在分支 A 上工作并且你想将分支 B 推送到远程时使用。

如果您愿意,您甚至可以推入具有不同名称的分支:

git push origin a-local-branch-name:a-remote-branch-name

如果推送本身成功完成,-u 选项仅在推送完成后告诉 git push 到 运行 git branch --set-upstream-to

这并不能完全理解,因为 git branch --set-upstream-to 需要两个参数:要设置其上游的分支的名称,以及要设置的上游的名称。但它确实清楚地表明,无论当前分支是 br1br2 还是 maingit push -u origin main 开始做与 [=25= 相同的事情]:

  • origin翻译成URL;
  • 调用任何 Git 软件响应 URL;
  • 向他们发送您拥有但他们缺少的任何提交,这些提交会导致并包括您在 您的 main 上的提示提交;和
  • 请他们将 他们的 main 设置为指向您的 main 指向的同一个提交。

换句话说,您的 br1br2 名称在此操作中没有任何作用。

让我们假设现在您在 br1 分支上,并且此 git push 步骤已成功完成。他们的 (origin's) main 现在命名与您的 main 相同的提交,并且您的 origin/main 现在也命名该提交。现在,-u 选项中的 运行 git branch --set-upstream-to 操作开始执行。这会将您的分支名称之一的上游设置为您的 origin/ 名字。哪个(本地)分支名称在这里有意义?什么 origin/ 名称在这里有意义?1 可能包括:

git branch --set-upstream-to=origin/br2 br2

即使您 br1 并且只是被推 br2。但这根本没有意义。另一种可能性是:

git branch --set-upstream-to=origin/main br1

但这不是很 明智的 因为你没有推动你的 br1 (即使你是 on branch br1,因为 git status会说)。你推了你的 main。所以实际命令是:

git branch --set-upstream-to=origin/main main

这就是 -u 所做的:在成功发送您的分支的提示提交和其他提交(如果需要)之后,并使用它来设置它们的同名分支,然后设置您相应的 origin/ remote-tracking 名称,-u 操作将该(命名)分支的上游设置为该 remote-tracking 名称。

最复杂的案例是。我们可以运行,例如:

git switch main
git push -u origin br2:new-name

这会向 origin 提交导致 br2 的提交,无论这些提交可能是他们还没有的,然后询问他们 - origin Git 存储库——将它们的名称 new-name 设置为指向我们发送的 tip-most 提交(或者如果他们已经有了它就不会发送)。但是 git branch --set-upstream-to 会发生什么?好吧,让我们试试看:

$ git push -u origin fix-signal:new-br
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To [redacted]
 * [new branch]      fix-signal -> new-br
Branch 'fix-signal' set up to track remote branch 'new-br' from 'origin'.

实际上 git branch -vv 现在包括:

  fix-signal e068bdf [origin/new-br] make signal handler work in py2k and py3k

(请注意,我是此存储库中的 on 大师)。如果我现在删除 origin/newbr:

$ git push origin :new-br
...
 - [deleted]         new-br
$ git branch -vv --list fix-signal
  fix-signal e068bdf [origin/new-br: gone] make signal handler work in py2k and py3k

我现在应该 运行 git branch --unset-upstream fix-signal 因为我已经没有 origin/new-br 了。 (这样的上游断了,也不是有害,只是没用,之前分行没有上游,所以我真的这么做了。)


1使用“这里有意义的”规则有点危险,因为并非所有 Git 总是有意义,但 大部分 一个不错的指南。