I am trying to update my Github repo.
OS/config : Using OS X 10.10.5 (Yosemite) on MacBook Air
After doing these commands:
$ git init
$ git add
$ git commit -m "added new stuff"
$ git remote add origin https://github.com/user/repo.git
$ git push -u origin master
I got this error:
To https://github.com/user/repo.git>
! [rejected] master -> master (fetch first)
error: failed to push some refs to
'https://github.com/user/repo.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Then I tried...
$ git pull --commit https://github.com/user/repo.git
And I got...
Merge https://github.com/user/repo
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
Question
What do these errors mean in English? And what should I do next?
Is there a way to just "dump" whatever is in queue (without trying to "pull" it) so I can just get on with the new commits? I am thoroughly confused about what to do next.
First, let me suggest that you read the Pro Git book , because most of the documentation that comes with git is pretty bad, especially for newbies. (It's improved from where it was 5+ years ago, but it still leaves much to be desired.)
That said, let me try a quick introduction to "what you need to know" here.
git push
is not git pull
, it's actually git fetch
. I think the error message you get should not refer directly to git pull
; we'll see more on this in a bit as well. git log
output, for instance. Every commit has some set of "parent" commits, identified by SHA-1 IDs. You could use SHA-1 IDs yourself, but they're extremely human-unfriendly, you'd never remember whether you should start with f13c9ab
or 0e1d227
or whatever (and these are abbreviated IDs!). master
. A branch name is simply a name that you tell git to use to keep track of the newest commit you've made on that branch. Given the last three items, let's draw a commit graph fragment:
... <- 1f3a33c <- 98ab102 <-- branch
Here, the tip of the branch is commit 98ab102
and its parent is 1f3a33c
. We can say that the name branch
"points to" 98ab102
, which points to its parent, and so on.
When you make a new repository ( git init
, assuming this actually makes one 2 ) it's entirely empty of commits, so the first commit has no parent. It's the second and third and so on commits that point back to previous commits.
When you do a "merge", you tell git to take two (or more, 3 but let's just say two, for now) existing commits and make a new commit that has both of those as parents, by combining all the changes from some common point. Merges are not that complicated, but they're something you should generally do after deliberately dividing up work into separate lines of development.
You've created a new repository ( git init
), put in at least one commit ( git commit
), and added a "remote" ( git remote add origin ...
). This last step says "I have a peer git I want to call origin
, so remember the URL under that name."
Then, you asked your git to call up "origin" ( git push ... origin
) and give it your commits as found under your branch-name "master" ( git push ... master
). Here's where it gets a little bit tricky. When your git talks to his git, what name should his git use? The short answer here is that his git will use the name master
too. This is changeable, but changing it is not what you want here.
(You also asked, via the -u
flag, to have your git record this exchange in your git configuration. We'll leave that aside for now.)
When your git called up his git, your git said "here, look at these shiny new commits" (and he did), and then your git said: "Why not add these new commits exactly as they are to your repository, 4 and make your master
point to the tip-most of those commits?" His answer was: "Well, I could do that, but then I'd lose some commits I have that you don't." This is where you see the rejected
message.
Maybe you want them to forget their stuff-so-far. If so, you can ask for a "force push", where you have your git tell them to set their master
even if that "loses" some commits. It's still up to them whether to do this, but often it's not what you want.
Maybe you want to pick up what they have and add it to your collection, or pick up what they have and toss out your own work-so-far. This is where you want git fetch
.
What git fetch
does, de-complicated as much as possible, 5 is call up the peer over the Internet-phone and find out what they have that you don't. It brings over all these commits (remember, the exchanges go by commits) and adds them, Borg-like, to your repository. Then—this is the crucial part—it changes their branch-names so that they won't interfere with your branch-names.
The names that git fetch
uses to synchronize with your peers are called "remote-tracking branches" or sometimes "remote branches". One odd thing about "remote branches" is that they're not actually on the remote! They're kept in your own repository. The reason is simple: they're a snapshot of what was on the remote, the last time your git talked to that remote. After the two gits hang up the Internet-phone, the remote could get changed. (How fast a remote actually changes depends, of course, on how busy that remote git is.)
The renaming-pattern here is simple: take the remote's branch name (like master
) and add the name of the remote ( origin
) in front: your origin/master
"tracks" origin
's master
. (There's a full-name form that you can use if you accidentally name one of your own purely-local, not-remote-tracking, branches origin/oops
for instance, but your best bet is not to do that in the first place.)
git pull
come in? Note that so far, it's been all git push
and git fetch
. But suppose you've done a git fetch
and picked up their work? Now you have a bit of a problem: you have your work, and you have their work, and these two have diverged.
If you both started from a common base, we can draw your commit graph like this:
... base <- yours <-- HEAD -> master
\
theirs <-- origin/master
I put in the HEAD ->
this time to show which branch you're on (run git status
and you should see "on branch master" in its output).
One easy way to tie these two divergent bits of work together is to use git merge
. If you want to do that, you simply run git merge origin/master
(note the slash: you want your git to find your origin/master
, which it picked up during git fetch
, and merge that into your master
, making a new commit on your master
). The result looks like this:
... base <- yours <- merge <-- HEAD -> master
\ /
theirs <-- origin/master
Another way to handle this—usually the better way, in fact—is to use git rebase
, which I won't go into in detail here; there are plenty of over StackOverflow answers about using rebase
. If you do, though, you wind up with:
... base <- theirs <- yours <-- HEAD -> master
\
.......... <-- origin/master
(Note that in all cases, origin/master
still points to the tip-most "theirs" commit.)
The main point to keep in mind right now is that whatever you do, if you want to get their git to accept your commits without having to force-push, you need to make your work be an add-on to theirs, so that your new commits "point back to" theirs. It doesn't matter to the push
process whether your work has theirs as a "second parent" of a merge commit, or simply builds directly on their commit(s); it only needs to point to their commits, by their commit-IDs. (But again, rebase is usually better than merge!)
git pull
(finally!)... What git pull
does, simplified, is just run git fetch
and then git merge
. In short, it's meant as a convenience script: you're always fetching and then merging, so we'll give you a script that fetches, then merges.
Of course, git merge
is usually wrong. It really should use git rebase
by default.
You can make git pull
use git rebase
, 6 but I think it's wiser, at least (or especially?) for newbies, to use the two separate steps—in part because if something goes wrong, the way you recover from this is different for the two different actions. To get out of a failing merge, you use git merge --abort
. To get out of a failing rebase, you use git rebase --abort
. (These used to be even more different, now it's just "abort whatever's failing", which is a big improvement. But you need to know which to do, and that's an awful lot clearer if you started with git merge
or git rebase
.)
In the end, the action you need to take here depends on what you want to have happen, and what the remote will allow you to do. If you want to drop their stuff, use git push -f
(force), being aware that you're causing them (whoever they are) pain this way, and that they might forbid it entirely. If you want to keep their stuff, use git fetch
first, then keep their stuff however you prefer (merge, rebase, rework, whatever).
1 Or with patches, which you can exchange with your peers by email. It's also possible to "bundle" commits and transfer them by other methods. But in this case we're doing commit-based exchanges over the Internet-phone.
2 You can safely run git init
in an existing repository. It has a minor effect but for our purposes here it basically does nothing, hence the need to say "assuming it actually makes one".
3 Git calls this an "octopus" merge, even if there are just 3 or 4 parents instead of 8.
4 Git mostly only ever adds "more stuff". I like to refer to this as the "Git Borg" , where git adds your technological distinctiveness to its existing collection.
5 A common theme in git is "That wasn't quite what you wanted? OK, we'll keep the existing stuff but make it more complicated so you can do what you want too!"
6 See footnote 5.
This SO answer suggests:
git fetch --all
git reset --hard origin/master
But I haven't tried it yet, so I can't say for certain whether it solves the problem. But it is, at least, one direction to try.
GIT is telling you to fetch first. You can see in the log
$ git fetch -all
Probably somebody else has pushed to master already, and your commit is behind. Therefore you have to fetch, merge the change set, and then you'll be able to push again.
If it says there are changes in the remote make a Pull which will update your working directory.
$ git pull
Then you push your changes to the remote
$ git push -u origin master
I hope this will help you push your changes to the master
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.