klayhamn wrote:but that's what I still don't understand - what do you mean by "pushed the changes" -
after all, I've pushed SOME changes before -- at SOME point in history (let's assume for the sake of example that the "A" commit was created, committed and pushed by me)
Sorry if this wasn't clear. Let's assume for simplicity there are two repositories
A) Your local repository which is usually "master"
B) The remote repository on github which is called "origin/master"
For the rest of this post A) is "local" and B) is "remote". The remote is always a single place on github, each user can have a local copy. All users push and pull from the same place and the same branch. Local tracks changes to the remote, you push changes from local to remote and other people pull/fetch your changes from the remote to their local copy.
Going back to the previous example
http://pastebin.com/xvfTggff. In your local repository you have commits A, B, C, D and on the server there is A,B,C,D - both local and remote are at the same point. You develop some features and commit locally only to you local repository commits
X, Y and Z. These are the changes I mean. So the remote still only has A, B, C and D but your local repository has A,B,C,D,
X,Y,Z.
Now comes the more complicated part. In the meantime someone has made changes on their local copy and pushed to the remote. The remote now contains commits A,B,C,D,E,F,G. Your local git history doesn't contain E,F and G. Now, if you rebase the changes to your local copy will be rewritten ahead of the new commits you pull in from the remote. The changes that will move in the rebase are
X, Y and Z -- these are the only commits locally that differ from the remote.
klayhamn wrote:As I see it -
X Y and Z can either be already-pushed, or not-yet-pushed
if they are pushed, what distinguishes them from the "A" commit?
X, Y and Z should be not-yet-pushed commits. They differ from commit "A" in that they don't exist as part of the remote repository. Rebasing should only move commits locally that are not on the remote.
klayhamn wrote:Why can I rebase when I haven't pushed
X Y and Z but HAVE pushed A (at some point in the past)?
but on the other hand I can't rebase when I HAVE pushed
X Y and Z?
what makes them different than A - in this example?
You can rebase when "A" is there solely because the commit exists in both the same place on the local and remote repositories. A rebase with two identical copies will not do anything, no history is rewritten because there are no changes. Commits A-D will stay in the same place in the git history if you issue a rebase.
klayhamn wrote:And then, if I push
X Y and Z to my personal fork,
and then rebase and receive E F and G to my local copy,
then the next time I commit ---
my personal fork would become A B C D
X Y Z E F G
even though the main repo is A B C D E F G ?
You have to be very careful here. You *don't* want to push to your fork if you are going to rebase.
I'll try and give an example. "mage" is now the remote for upstream/master and "fork" is the remote for origin/master
mage looks like this:
A - B - C - D - E - F - G
your local copy looks like this
A - B - C - D -
X - Y - Z
now, if you push to your fork, fork looks like:
A - B - C - D -
X - Y - Z
Now you have pushed, the fork must stay in that order:
If then you decide to do a "git pull --rebase upstream/master" (or fetch/rebase)
Your local copy will look like this, which seems fine:
A - B - C - D - E - F - G -
X' - Y' - Z'
But wait - your fork says the git commit history looks like:
A - B - C - D -
X - Y - Z
Commit
X, Y and Z is after commit D, not E, F and G. The git history is stored in the hashes of each commit and you have effectively rewritten part of the history.
If you issue a "git status" you'll get something to the effect of "your local copy is ahead of fork by 3 commits. your fork is behind your local copy by 3 commits" - because you have effectively erased
X, Y and Z and rewritten them at the head of your local copy.
The correct way to rebase like this in this situation would be:
1) Commit
X,Y,Z locally. Your local copy looks like:
A - B - C - D - (
X) - (Y) - (Z) <--- (not pushed)
And the remote looks like:
A - B - C - D
Someone else adds changes, your local copy still looks the same but the remote looks like:
A - B - C - D - E - F - G
2) git pull --rebase origin/master
Now your local copy looks like:
A - B - C - D - E - F - G - (
X') - (Y') - (Z') <--- (not pushed)
3) push - now both local and remote will be in the same state and have the same history.:
A - B - C - D - E - F - G -
X' - Y' - Z'
Hopefully that goes some way to explaining it, and I didn't manage to confuse myself halfway through either
