Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accidentally executed "Git push origin master" while on branch off master

I created a local Git branch off master (lets call it BranchB). I then committed my changes on that branch (to BranchB). But when it came for the time to push to the remote repository, too much coffee got to me, and I wrote git push origin master instead of just git push to push the new branch to the repository.

I then went into GitHub to see the commits on master. The changes that I recently accidentally pushed to master did not appear here?

So what exactly happened when I pushed to master while on Branch B? Does that just push the commits that were done on master since I specified master.

like image 646
pnizzle Avatar asked Jan 31 '19 23:01

pnizzle


People also ask

What is the error if the changes made in the master branch are pushed to the remote repository at the time of changes done by someone else to the same branch?

The error message error: refusing to update checked out branch: refs/heads/master is emitted by the remote repository and it means you're trying to push code to remote non-bare repository that has different code currently checked out in the working directory.

What happens after git push origin master?

Git Push Origin pushes all the branches to the main branch. Git Push Origin Master pushes your master branch to the origin. Behavior could be changed via git config.


2 Answers

The <refspec> you gave here as a parameter for your push is master, where the full canonical form would have been <src>:<dst>, <src> being the source of the push and <dst> the destination ref. When you omit one, git assumes your parameter is <src> and that no <dst> has been given. In that case, and if the branch has a <repository>.push config set (so in most cases), that ref is used as the source for your push.

So yes, it pushed master (with no new commits) to its remote counterpart. Harmless no-op.

(Maybe check your own config with git config -l | grep origin or something along these lines.)

You would have pushed BranchB on master with an explicit :

git push origin BranchB:master

That's what I understand from the doc, namely the <refspec> paragraph in git-push man page. Seems to make sense with your results.

like image 117
Romain Valeri Avatar answered Oct 20 '22 08:10

Romain Valeri


Short answer: you're fine. Git most likely said:

Everything up-to-date

and did nothing at all. If not, you only sent commits that you made on master, to your GitHub Git's master.

The longer answer is still that you're fine, but you may be working under a few misconceptions about Git branches. They won't bite you ... yet. đŸ˜…

Commits form backwards-pointing chains

Every Git commit is uniquely identified by its hash ID. Given a hash ID, Git can find the commit. Inside the commit is another hash ID—the commit's parent commit, the commit that comes before this one. Also inside the commit, of course, is the name and email address of whoever made the commit, and their log message, and (though it's slightly indirect) the full and complete snapshot of all the files that make up that commit.

What this means is that from any given commit, we can work backwards to the previous commit. So if we have a sequence of commits:

... <-F <-G <-H

we just need the hash ID of the last such commit, such as H. Git will then be able to read H and fish out the hash ID of its parent G, and read G and fish out the ID of F, and so on.

A branch name like master therefore just identifies one commit

The way Git finds the hash ID of the last commit of any branch is through the branch name. The name itself, master or BranchB or whatever, just holds the hash ID:

...--F--G--H   <-- master, BranchB

Here both names store the same hash ID. So all the commits that are on master are also on BranchB.

To make a new commit, Git will save a snapshot, save your name and email and so on, and save the hash ID of the current commit H. This becomes a new commit I, which gets assigned its new unique hash ID:

...--F--G--H   <-- master, BranchB
            \
             I

One of these names has to change now!

Your HEAD remembers which branch you're on

In order to know which name to update, Git attaches the special name HEAD to one branch. If HEAD is attached to BranchB, that's the name that Git will update:

...--F--G--H   <-- master
            \
             I   <-- BranchB (HEAD)

It really is that simple.

Fast forward

Well, "that simple" isn't so simple: branch names do move like this, and Git finds commits by starting at the latest and working backwards. You can, at any time, ask Git to move any branch name to any existing commit. Let's say we force Git to move BranchB back to commit H. How do we then find commit I?

If we do do this, it becomes pretty hard to find I. (There are a bunch of mechanisms for that but let's not worry about them yet.) The simple part is that as long as the branch name moves forward—along new commits we make, one at a time, or a bunch of commits we pick up that also move forward, we're good, because from somewhere past I that leads back to I, we can always work back to I.

This is what Git's special term fast forward means. A branch-name update is a fast-forward operation if, from the new "last" commit, we can still get back to the old "last" commit.

Push (finally!)

This is where git push comes in. When you run git push, you have your Git call up some other Git, at some URL. Your Git and their Git have a conversation. Your Git will hand over new commits to their Git, as needed, and then your Git asks their Git to set one of their branch names.

Remember, their Git is a Git repository, just like yours. So their Git has their own branch names. They already have a master:

...--F--G--H   <-- master

Your Git will call up their Git and ask them: Hey, why don't you set your master to point to commit H? They'll say: It already does. Yours will say: Oh, right, okay bye! and your Git will print:

Everything up-to-date

Or, you could send some new commit hash ID. Your Git will offer their Git your new commit(s), as many as it takes to link this new one back to H, or wherever it goes that your Git and their Git share some earlier commit. Then your Git will as their Git: Hey, how about setting your master to this other hash ID? They might say okay, or they might say: No! that's not a fast-forward! And now that you know what fast-forward means, you know that if they reject your request, it's because whatever commit their master names, that's not in the backwards chain that you get when you look at your master and work backwards.

That is, suppose that you're beaten to the punch—someone else, somewhere else, sends them a new commit:

...--F--G--H--L   <-- master

Your Git has made a few new commits (and you're on your master):

             J--K   <-- master (HEAD)
            /
...--F--G--H   <-- origin/master
            \
             I   <-- BranchB

so your Git sends them the J-K chain and asks them to set their master to K, but that would lose their L—which you don't even have. You'll have to get their L and figure out how to keep their L.

As long as they don't have any commits that your git push request would throw away, though, they'll take your request. So if they don't have L, and you run git push origin master, you'll send your J-K and ask them to set their master to K and they will.

This is true even if you've re-attached your HEAD to your BranchB:

             J--K   <-- master
            /
...--F--G--H   <-- origin/master
            \
             I   <-- BranchB (HEAD)

A git push origin master has your Git call up their Git, offer them your commit K, and ask them to move their master there, where your master is.

A git push origin BranchB has your Git call up their Git, offer them your commit I, and ask them to move (or create) their BranchB there.

Note that you can also git push origin master BranchB to offer them both tip commits (K and I in the drawing above), and make both requests. Or, as RomainValeri noted, you can set up a full refspec argument for each word past the word origin, e.g., git push BranchB:master or git push master:BranchB. These have your Git send theirs your commits as before, and then request that they set their destination branch name (the name after the colon) to match your source branch's tip commit (from the name before the colon). Usually, mixing names like this is not a great idea—it's overly confusing, if nothing else. But there are some special cases where it's a useful shortcut.

like image 32
torek Avatar answered Oct 20 '22 09:10

torek