When I first started using git, I was told by another team member to always push using
git push -u origin MYBRANCH
because it would prevent me accidentally pushing code to the wrong branch. I didn't fully understand and today tried to understand what happens that means.
I created a local repo and provide my exact commands so you could copy/paste this to reproduce what I've done.
In this test I have a local (on disk) repo and two branches:
git branch
main
* feature/fixthis
I'm on the feature/fixthis
branch and run:
git push -u origin main
# NOTE: the current branch is feature/fixthis
Did I just accidentally push my feature branch onto main?
My Solution (figure it out myself using local test)
To test this out myself, I did the following. The commands are written in such a way that you can copy/past to a UNIX bash shell to reproduce a local git repo and create the exact scenario I'm asking about.
# 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
Did the command git push -u origin main
accidentally update the main branch?
When I look at the logs I can't figure out what happened to the last push, it doesn't appear to have updated the origin/main branch because I don't see the origin/feature/fixit tag (on any commit).
git log
commit 1bba12ad200080cb0a59aa0e2fb518a1e284b135 (HEAD -> feature/fixit)
Author: [email protected]
Date: Thu Apr 7 14:25:19 2022 0000
change on feature/fixit
commit dcf8098bda7c937c80bc60ee974ac6eb9a895ced (origin/main, main)
Author: [email protected]
Date: Thu Apr 7 14:20:06 2022 0000
initial commit
Searching for answers
Search [git] git push -u origin - around 20,000 results... Hum... that's not going to work, let me add another question to the category. :-)
What exactly does the "u" do? "git push -u origin master" vs "git push origin master" - Good answer with lots of good technical stuff. It might answer my question but if it does I didn't see it.
Many others
CodePudding user response:
The command just pushes into the remote origin
your local branch MYBRANCH
(the remote branch has the same name). This is used when you are working on a branch A and you want to push branch B into the remote.
You could even push into branches with a different name, if so you wished:
git push origin a-local-branch-name:a-remote-branch-name
CodePudding user response:
The -u
option merely tells git push
to run git branch --set-upstream-to
after the push finishes, provided that the push itself finishes successfully.
That doesn't quite get you all the way there because git branch --set-upstream-to
needs two parameters: the name of the branch whose upstream is to be set, and the name of the upstream to set. But it does make it clear that, regardless of whether the current branch is br1
, br2
, or main
, git push -u origin main
starts out doing the same thing as git push origin main
:
- translate
origin
to a URL; - call up whatever Git software responds at that URL;
- send them any commits you have, but they lack, that lead up to and include the tip commit you have on your
main
; and - ask them to set their
main
to point to the same commit that yourmain
points to.
In other words, your br1
and br2
names play no role whatsoever in this operation.
Let's assume now you are on your br1
branch, and that this git push
step finishes successfully. Their (origin
's) main
now names the same commit that your main
names, and your origin/main
now names that commit as well. Now the run git branch --set-upstream-to
action from the -u
option kicks in. This will set the upstream of one of your branch names to one of your origin/
names. Which (local) branch name makes sense here? What origin/
name makes sense here?1 The possibilities include:
git branch --set-upstream-to=origin/br2 br2
even though you're on br1
and just pushed br2
. That makes no sense at all though. Another possibility is:
git branch --set-upstream-to=origin/main br1
But that's not very sensible as you didn't push your br1
(even though you're on branch br1
, as git status
would say). You pushed your main
. So the actual command is:
git branch --set-upstream-to=origin/main main
and that is what the -u
does: after successfully sending your branch's tip commit and other commits if and as needed, and using that to set their branch of the same name and then your corresponding origin/
remote-tracking name, the -u
action sets the upstream of that (named) branch to that remote-tracking name.
The most complex case is the one eftshift0 hints at. We could run, e.g.:
git switch main
git push -u origin br2:new-name
This delivers to origin
the commits that lead up to the tip commit of br2
, whatever commits those may be that they don't already have, then asks them—the origin
Git repository—to set their name new-name
to point to the tip-most commit that we sent (or didn't bother sending if they already had it). But then what git branch --set-upstream-to
happens? Well, let's try it out:
$ 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'.
and indeed git branch -vv
now includes:
fix-signal e068bdf [origin/new-br] make signal handler work in py2k and py3k
(note that I'm on
master in this repository). If I now delete 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
I should now run git branch --unset-upstream fix-signal
since I have no origin/new-br
any more. (It's not exactly harmful to have a broken upstream like this, it's just useless. The branch had no upstream earlier, so I did actually do that.)
1Using the "what makes sense here" rule is slightly dangerous since not everything Git does always makes sense, but it's mostly a decent guide.