For items 1 and 2, simply use git fetch
to pick up the latest origin/master
(this assumes your github repo is under the remote named origin
, and that you have not fiddled with the fetch =
line as well), then use any log viewer (git log
, gitk
, etc) to show you the commits "they have" that "you don't". There are lots of ways to do this. For a complete view I personally prefer gitk --all
here, but git log --graph master origin/master
will also show something illustrative (see below).
For item 3, you can git push --force
or git push origin +master:master
(again this assumes that origin
is the name of the remote that points to github).
For item 4: this is where the commit graph (as seen in item 1) is useful. Let's say that, for whatever reason, the graph you will see in item 1 looks like this (except that I want to draw it horizontally here, rather than the vertical drawings you'll get in gitk
):
--- o - o <-- master
/
... - o - o
\
o <-- origin/master
In this particular drawing, you're "ahead 2" and "behind 1". You have two commits the remote does not, and it has one commit that you don't. Or rather, you do have "their" commit, but not on the history of commits found via your branch name master
.
If you git push --force
, what your git will do is contact their (github's) git and in "their" repo (i.e., your github copy of your repo), ask it to take your new commits—the two that are on your master
that are not on its—and then just make their master
point to the same commit. That is, their master
will now point to the upper-right-most (in this drawing) commit, which is where your master
points. Your git will then update its copy of their git's master
—this is what your git is keeping in origin/master
—so that the graph you have now looks like this:
--- o - o <-- master, origin/master
/
... - o - o
\
o [abandoned]
That "abandoned" commit may be removed from "their" repo (i.e., your github copy of your own repo) almost immediately.
If someone else is also copying "their" repo and using commits from it, they may still have the "abandoned" commit in their own copy. They may start depending on it, and get annoyed if you've told github to forget that commit, because now they'll have to do extra work to re-synchronize and yet also keep the contents of that commit. But if no one else is also using this github copy, or if they have not picked up that particular commit, they will never know that the commit used to be there and is now abandoned-and-maybe-really-gone.
You mention in an edit that you started a git merge
. It's not clear if you ever finished or aborted the merge. If you are "in the middle" of a merge, you haven't actually created a merge commit yet, but you should either finish or abort the merge first. You can use git status
to tell you if you are still in a merge:
$ git status
On branch master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
[snip]
If you already did abort the merge, and then also copied that commit to a new one (different SHA-1 hash, but same effect) ... well, let's re-draw this graph a bit, and give those commit nodes identifying letters:
--- D - C' <-- master
/
... - A - B
\
C <-- origin/master
Here, the "prime" single-quote in C'
indicates that this commit is a copy of commit C
: it has the same message and same effect, and maybe even the same time-stamps; but it's a bit different because, if nothing else, it has a different parent commit ID: it points to commit D
, rather than commit B
.
If you force-push this to the github copy of the repo, commit C
is abandoned as before. That's no loss since everything important about it is already there in C'
. But it can still make work for someone else who has cloned the github repo and has built new commits on top of C
: they'll have to alter their work so that it sits atop C'
now. The actual moving should be very easy (just git rebase
), but it is still work.
You can go ahead and force-push, or, if you're feeling generous towards these other folks, you can attempt to re-arrange your own work so that it's a linear extension, a "fast forward" as git calls it. In this particular case, that would just require copying commit D
to a D'
that sits atop C
, then abandoning your D - C'
sequence in favor of the new sequence:
--- D - C' <-- your old master, to be abandoned
/
... - A - B
\
C <-- origin/master
\
D' <-- this becomes your new master
To do that, you can simply git rebase
your master
onto origin/master
(with or without -i
). Rebase is usually smart enough to notice a copied commit (C'
) and simply drop it; or you can use git rebase -i
and explicitly drop it yourself:
$ git checkout master
Already on branch 'master'
$ git rebase origin/master
(or with -i
, as above). Once all that works, you should be able to git push
without --force
: you're now strictly "ahead of" origin/master
, which is the case git (and people using git) expect.