Cannot push branch because of weird changes in master

git, push

Solution

Part 1: Getting your push done without worrying about `master`

(Note: actually, it's already done. See note towards the bottom of part 1.)

You're running `git push` with no additional arguments.

If you run `git push` with two more arguments, they specify exactly what to push where. The git documents call these the `<repository>` and the `<refspec>`.

In your case, the repository is always `origin` (which is the usual standard one git sets up when you clone something). So the `refspec` is the more interesting part.

Here's the long1 form:

git push origin feature/mybranch:feature/mybranch

This limits git to only attempting to push your branch `feature/mybranch`, telling the remote, `origin`, that it should update the branch `feature/mybranch` on its side too.

If you leave out the `:<same-name>` part, the default is to use the branch name on the left of the colon, so:

git push origin feature/mybranch

does exactly the same thing, with a bit less command-typing.

Now, what happens when you leave out the `<refspec>`? The answer is in the git push and git config documentation, although in my 1.8.4.3 text version it's really hard to read, and the on-line version I linked to above is, if anything, worse: :-)

When the command line does not specify what to push with <refspec>... arguments or --all, --mirror, --tags options, the command finds the default by consulting remote.*.push configuration, and if it is not found, honors push.default configuration to decide what to push (See gitlink:git-config[1] for the meaning of push.default).

To simplify this a lot, I can tell2 that you have not set either `remote.origin.push` or `push.default`, so you're getting the "default default", which is called `matching`, which means your `git push` calls up `origin` on the metaphorical Internet-phone and says

Hey, what branches do ya got?

and it says:

I have `master` and `feature/mybranch`.

So your git then says:

OK, well, here's what I think `master` should be, and here's what I think `feature/mybranch` should be.

To which he says:

Whoa there buddy, that would set `master` back a couple of revs!

... and that's when you got the `! [rejected] master -> master (non-fast-forward)` thing.

So, there's a couple of really simple solutions.

Solution #0: do nothing

If you still have the original `push` output available, you should be able to see something like this:

   a430f6d..676699a  feature/mybranch -> feature/mybranch
 ! [rejected]        master -> master (non-fast-forward)

This means that even though the change for `master -> master` was rejected, the change for `feature/mybranch -> feature/mybranch` was accepted. The branch you wanted to push, you did! You just got this annoying error message to go with the success (and now you're wondering what to do with branch `master`).

Solution #1: be explicit in the `push`

If you run:

git push origin feature/mybranch

your Git and origin's Git will have a shorter conversation. Instead of your Git asking him "hey, whaddaya got there?" and then trying to push all "matching" branches, yours will just say: "I have some updates for `feature/mybranch`". The fact that you're behind on `master` will be irrelevant; neither you, nor your Git, nor the remote Git will look there.

Solution #2: change your `push.default`

This only works if your git is new enough, although by now, most are:

git config --global push.default simple

The Git folks are planning to change changed (as of Git version 2.0) the "default default", because `matching` turns out to be more annoying than helpful, a lot of the time. The new "default default" will be `simple`. (For details on what this means, see the git config documentation.)

(Setting the `--global` version will change the default default for you, but not for other people. If any repositories—your own, or others—have a local `push.default` setting, that will override your personal global setting, but for those that don't, your global setting is the one git will use. You can choose instead to set the local setting in each repo, which will affect you and anyone else who uses your own repos, but then you need to remember to set it in all your repos.)

1Actually this is only the semi-long form: you can add `refs/heads/` in front of each branch name to make it even longer. That's just for showing off though. :-)

2I'm just guessing, really, but it's a pretty safe bet. Someone who configures `remote.origin.push` and `push.default` probably already knows all of this stuff.

Part 2: Why won't `master` update?

I'm much less sure about this, but it looks as though someone had accidentally committed a bunch of (17) `.java` binaries into the `master` branch, probably from not having a correct `.gitignore`.

At some point they noticed, oops, didn't want all these binaries! So they updated `.gitignore` and committed that, but probably didn't actually `git rm --cached` all of them, so some are still being tracked. If a file that is now listed as ignored was previously committed, git "obeys the commit" rather than the ignore directive, and you get a lot of this:

# 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:   bin/b1

Depending on how you `git add` and what's in the `.gitignore` it's possible to add the in-repository tracked files (that are overriding the ignore entry), and make them "staged for commit" and commit them.

In any case, your `master` is two revs behind, and definitely has some binaries in it—and it's possible that your `feature/mybranch` branch has a "bad" `.gitignore` (some variation on it) that also does not ignore the "right set" of binaries.

Git notices that 7 of your binaries (perhaps re-built with your feature branch features) don't match what's checked in on the `master` branch. These would be "unsafely" clobbered (at least, as far as git can tell). If/when you do `git checkout -f master` (or something equivalent), git clobbers them after all, but you are still left with "untracked" files, implying a bad `.gitignore`.

Once you're quite certain that it's safe to clobber anything in your work-tree—that you have all your work saved away—you can do this to resync your `master` to `origin/master`:

git checkout -f master
git fetch   # resync with origin in case they've fixed more stuff
git reset --hard origin/master

Assuming you don't want binaries in the branches, check over the various `.gitignore` files and make sure they're correct—you'll probably need to fix some. Then, use `git ls-files` and/or `git ls-tree` to see what's in the index and repo (`git ls-tree` requires that you specify a particular tree object, e.g., `git ls-tree HEAD:bin` to see what's in the `bin` tree, if it exists).

To remove committed (even though ignored) files, e.g., to remove everything in `bin`:

git rm --cached -r bin

(the `--cached` says only remove things in the index), or you can allow git to remove the binaries. Once you have the right stuff "git rm"-ed and any updated `.gitignore` files added, `git commit` the changes:

$ cat bin/.gitignore
*
!.gitignore
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   bin/.gitignore
#   deleted:    bin/b1
#   deleted:    bin/b2
#
$ git commit -m 'remove binaries, ignore them in the future'
[master ac60888] remove binaries, ignore them in the future
 3 files changed, 1 insertion(+)
 create mode 100644 bin/.gitignore
 delete mode 100644 bin/b1
 delete mode 100644 bin/b2

(Finally, rebuild any removed binaries as needed, run tests, do a push if appropriate, etc.)

(It's possible that you do want the `.java` binaries in the branches, or that you don't and yet no one has fixed up any `.gitignore` entries, etc.; so that's why I'm much less sure about this.)

Problem

I work on branch, let name it `mybranch`. I do not modify `master`. I want to push changes on `origin/feature/mybranch` but I have some problems. What is strange I've done it before a few times and I didn't have any problems. ``` $ git branch develop * feature/mybranch master $ git push To http://...... ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'http://....' hint: Updates were rejected because a pushed branch tip is behind its remote hint: counterpart. If you did not intend to push that branch, you may want to hint: specify branches to push or set the 'push.default' configuration variable hint: to 'simple', 'current' or 'upstream' to push only the current branch. ``` What? Master?! So lets check the `master`. ``` $ git checkout master Switched to branch 'master' Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded. (use "git pull" to update your local branch) $ git pull Updating 45c7319..f6b8e97 error: Your local changes to the following files would be overwritten by merge: platform/....java services/....java ... Please, commit your changes or stash them before you can merge. Aborting ``` This shows 7 modified files. ``` $ git status # On branch master # Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded. # (use "git pull" to update your local branch) # # 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: platform/....java # modified: algorithms/....java # ... # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # algorithms/.../ # and over 1100 files in bin folder. I don't know why gitignore doesn't work now. ``` This shows 17 (not 7 as above) modified files. Weird ... nevermind. These are not my changes, I want to discard them. ``` $ git checkout -f Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded. (use "git pull" to update your local branch) ``` And I still have these strange changes in `master`...

Original source