Created
May 20, 2014 13:51
-
-
Save Altreus/75f3425d61708d1f9322 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Rebase example! | |
=============== | |
I forgot to commit some things remotely before I cloned my repo to work locally. | |
altreus@local:~ $ git clone altre.us:altre.us | |
Cloning into altre.us ... | |
<snip> | |
altreus@local:~/altre.us $ do_stuff | |
altreus@local:~/altre.us $ git commit -a -m"Turn off static cache for now" | |
altreus@local:~/altre.us $ do_stuff | |
altreus@local:~/altre.us $ git commit -a -m"Implement and use text-input and number-input" | |
altreus@local:~/altre.us $ git lg | |
* e817192 (HEAD, master) Implement and use text-input and number-input | |
* 2810396 Turn off static cache for now | |
* 2aa0b7d (origin/master, origin/HEAD) package.json | |
* dc6c29a this should be git | |
Note that origin is the host called "remote". The below is standard SSH hostname:path stuff. | |
altreus@local:~/altre.us $ git remote -v | |
origin altre.us:altre.us (fetch) | |
origin altre.us:altre.us (push) | |
Note also that my commits have moved master but not origin/master. origin/master is immutable because it | |
represents localhost's idea of what the branch is at altre.us; this can't be changed without either asking | |
(fetch) or telling (push) the remote about the branch. | |
origin/master is a "remote branch" and master is a "local branch". Local branches can be moved to your | |
heart's content, but note that any local branch that "tracks" a remote branch comes with social contracts | |
because other repositories may *also* have a local tracking branch. | |
A tracking branch is simply a local branch that is associated with a remote branch. This can be implicit | |
by its name, but git includes a mechanism by which it associates the one with the other, so to be a true | |
tracking branch this mechanism should be used. It's set up automatically most of the time. | |
Anyway I committed these and wondered what happened to my ability-score element: | |
[email protected]:~/altre.us $ git lg | |
* 2aa0b7d (HEAD, master) package.json | |
* dc6c29a this should be git | |
Forgot to commit. | |
Note here that the commits I made on local do not exist. There is no origin/master because we *are* origin. | |
There is no central repository from which the two were cloned; this is the master repo. | |
This is a bad idea but it's easily fixable so I'll leave it for now. | |
[email protected]:~/altre.us $ git commit -a -m"Update and use ability-score doodah" | |
[email protected]:~/altre.us $ git lg | |
* 8ef0a66 (HEAD, master) Update and use ability-score doodah | |
* 2aa0b7d package.json | |
* dc6c29a this should be git | |
master moves because HEAD points to master. It is possible for HEAD and master to coincide but for HEAD | |
not to point to master; this happens if a) HEAD points to a different (usually new) branch; or b) HEAD | |
points to the SHA at master (8ef0a66) instead. | |
This creates a divergence, but local doesn't know about it yet. | |
altreus@local:~/altre.us $ git lg | |
* e817192 (HEAD, master) Implement and use text-input and number-input | |
* 2810396 Turn off static cache for now | |
* 2aa0b7d (origin/master, origin/HEAD) package.json | |
* dc6c29a this should be git | |
altreus@local:~/altre.us $ git fetch | |
remote: Counting objects: 11, done. | |
remote: Compressing objects: 100% (5/5), done. | |
remote: Total 6 (delta 4), reused 0 (delta 0) | |
Unpacking objects: 100% (6/6), done. | |
From altre.us:altre.us | |
2aa0b7d..8ef0a66 master -> origin/master | |
git fetch will retrieve information about origin/master, but will not do anything about it. Note that | |
last line says "The master branch from altre.us:altre.us has become origin/master here. That's an update | |
from 2aa0b7d to 8ef0a66". That's correct: previously to committing remotely, origin/master was on the same | |
commit as master-at-origin, i.e. 2aa0b7d. | |
After committing remotely, master-at-origin moved to 8ef0a66 (which we created), so fetch has retrieved | |
this commit and updated origin/master to match. | |
altreus@local:~/altre.us $ git fetch | |
* e817192 (HEAD, master) Implement and use text-input and number-input | |
* 2810396 Turn off static cache for now | |
| * 8ef0a66 (origin/master, origin/HEAD) Update and use ability-score doodah | |
|/ | |
* 2aa0b7d package.json | |
* dc6c29a this should be git | |
Now we see the divergence on local. We don't see it at origin: | |
[email protected]:~/altre.us $ git lg | |
* 8ef0a66 (HEAD, master) Update and use ability-score doodah | |
* 2aa0b7d package.json | |
* dc6c29a this should be git | |
That's because we haven't sent the data *to* origin. We can't ssh to altre.us and issue a `git fetch` | |
because origin doesn't have a remote; and `git fetch` fetches from a remote. | |
We could add localhost as a remote to origin, but then we'd have to have the local machine on a permanent | |
hostname and open it up to remote SSH (or readonly HTTP, at a pinch). | |
So we have to send from local to origin, with push: | |
altreus@local:~/altre.us $ git push origin master | |
To altre.us:altre.us | |
! [rejected] master -> master (non-fast-forward) | |
error: failed to push some refs to 'altre.us:altre.us' | |
hint: Updates were rejected because the tip of your current branch is behind | |
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull') | |
hint: before pushing again. | |
hint: See the 'Note about fast-forwards' in 'git push --help' for details. | |
It was rejected. The reason for this is that you cannot trace ancestry from 8ef0a66 to e817192. If we | |
moved origin's master branch from 8ef0a66 to e817192, we would lose 8ef0a66 entirely! | |
That's a non-fast-forward, i.e. you can't fast-forward the repository from snapshot 8ef0a66 to snapshot | |
e817192 without losing information. | |
We need to make it so that local master is based on the new remote master, i.e. the change "Turn off | |
static cache for now" (2810396) is based on "Update and use ability-score doodah" (origin/master). | |
Note that master is already based on 2810396, so as long as we re-parent 2810396, master should follow. | |
Re-parent is of course rebase. | |
altreus@local:~/altre.us $ git rebase origin/master | |
First, rewinding head to replay your work on top of it... | |
Applying: Turn off static cache for now | |
Applying: Implement and use text-input and number-input | |
Line by line: HEAD is at master; we want to rebase master onto origin/master. | |
(master and origin/master are just labels. We could easily have used the SHA at origin/master to do | |
this. We don't mention master explicitly because rebase as a default action rebases your current | |
branch). | |
HEAD is rewound (I think this should be capitalised in the output, ideally) to the "merge base" of | |
master and origin/master, i.e. "2aa0b7d package.json". That produces a list of commits that need | |
to be replayed. HEAD is moved to origin/master (being the argument to rebase) and the produced list | |
of commits are re-applied (remember they are snapshots). Git attempts to apply the first snapshot | |
to the state of origin/master. If that can be done, it does so automatically and moves on. It can; | |
it does. | |
The second commit is considerably more likely to apply because it already was based on the previous | |
commit. However, there is still a chance it interposes itself on stuff changed in the destination. | |
At any point, if git cannot consolidate the new snapshot against the old, you are simply invited | |
to amend the snapshot and tell git to continue. | |
In this case, both commits applied. | |
altreus@local:~/altre.us $ git lg | |
* e330387 (HEAD, master) Implement and use text-input and number-input | |
* 8ceabe5 Turn off static cache for now | |
* 8ef0a66 (origin/master, origin/HEAD) Update and use ability-score doodah | |
* 2aa0b7d package.json | |
* dc6c29a this should be git | |
The thing to note here is that the commits have different SHAs, but the same messages. The old | |
commits still exist; they will eventually be garbage collected. | |
altreus@local:~/altre.us $ git log -1 e817192 | |
commit e817192eacea0fbed561dcec61794300f8e23390 | |
Author: Alastair McGowan-Douglas <[email protected]> | |
Date: Tue May 20 13:58:33 2014 +0100 | |
Implement and use text-input and number-input | |
altreus@local:~/altre.us $ git log -1 master | |
commit e33038788457bad4f9888a08207702727ec2d446 | |
Author: Alastair McGowan-Douglas <[email protected]> | |
Date: Tue May 20 13:58:33 2014 +0100 | |
Implement and use text-input and number-input | |
This lets you get them back, by making a branch there temporarily, if needs be. | |
Now we still can't push, but that's because the remote refuses to clobber its working tree: | |
altreus@local:~/altre.us $ git push origin master | |
Counting objects: 11, done. | |
Delta compression using up to 4 threads. | |
Compressing objects: 100% (7/7), done. | |
Writing objects: 100% (7/7), 919 bytes | 0 bytes/s, done. | |
Total 7 (delta 5), reused 0 (delta 0) | |
remote: error: refusing to update checked out branch: refs/heads/master | |
<snip> | |
As noted, there is no reason for HEAD to point to master; HEAD can point to a SHA. | |
[email protected]:~/altre.us $ git co 8ef0a66 | |
Note: checking out '8ef0a66'. | |
<snip> | |
This has no apparent effect: | |
[email protected]:~/altre.us $ git lg | |
* 8ef0a66 (HEAD, master) Update and use ability-score doodah | |
* 2aa0b7d package.json | |
* dc6c29a this should be git | |
However: | |
altreus@local:~/altre.us $ git push origin master | |
Counting objects: 11, done. | |
Delta compression using up to 4 threads. | |
Compressing objects: 100% (7/7), done. | |
Writing objects: 100% (7/7), 919 bytes | 0 bytes/s, done. | |
Total 7 (delta 5), reused 0 (delta 0) | |
To altre.us:altre.us | |
8ef0a66..e330387 master -> master | |
This lets us push to master because moving master on altre.us does not affect HEAD. | |
Previously, moving master would move HEAD and hence force the working tree to update | |
to the new master. | |
[email protected]:~/altre.us $ git lg | |
* e330387 (master) Implement and use text-input and number-input | |
* 8ceabe5 Turn off static cache for now | |
* 8ef0a66 (HEAD) Update and use ability-score doodah | |
* 2aa0b7d package.json | |
* dc6c29a this should be git | |
Note how HEAD did not move. This push also updates our local information about the | |
remote branches: | |
altreus@local:~/altre.us $ git lg | |
* e330387 (HEAD, origin/master, origin/HEAD, master) Implement and use text-input and number-input | |
* 8ceabe5 Turn off static cache for now | |
* 8ef0a66 Update and use ability-score doodah | |
* 2aa0b7d package.json | |
* dc6c29a this should be git | |
The information about origin/HEAD is wrong. This may be a bug. I'm not sure origin/HEAD | |
is even useful information. We should update the remote to the new stuff anyway: | |
[email protected]:~/altre.us $ git co master | |
Previous HEAD position was 8ef0a66... Update and use ability-score doodah | |
Switched to branch 'master' | |
[email protected]:~/altre.us $ git lg | |
* e330387 (HEAD, master) Implement and use text-input and number-input | |
* 8ceabe5 Turn off static cache for now | |
* 8ef0a66 Update and use ability-score doodah | |
* 2aa0b7d package.json | |
* dc6c29a this should be git | |
No merge commit, no cruft, no problem. | |
Rather than checking HEAD out to a SHA we should have pushed-pulled via a central remote: | |
altre.us:altre.us.git (bare) | |
/ \ | |
localhost (files) altre.us:altre.us (files) | |
Bare repositories contain an index of the commits, but no files. That means you can move | |
the branches around, even HEAD, and it will not clobber the working tree. As the first | |
example showed, you can always fetch into a working tree - files only change when you | |
move HEAD, and fetch only moves remote branches. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment