sweet new branch command option, removed one level, new level on remote tracking, etc

This commit is contained in:
Peter Cottle 2013-10-20 20:12:02 -07:00
parent 0aa9992ec6
commit 3da3df9cf3
8 changed files with 193 additions and 84 deletions

View file

@ -240,5 +240,19 @@ describe('Git Remotes', function() {
);
});
it('sets remote tracking', function() {
expectTreeAsync(
'git clone; git branch foo; git branch -u o/master foo',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":"o/master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('sets remote tracking on current branch if not specified', function() {
expectTreeAsync(
'git clone; git checkout -b foo; git branch -u o/master',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":"o/master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"foo","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
});

View file

@ -23,6 +23,32 @@ var validateBranchName = function(engine, name) {
return engine.validateBranchName(name);
};
var assertIsBranch = function(engine, ref) {
assertIsRef(engine, ref);
var obj = engine.refs[ref];
if (obj.get('type') !== 'branch') {
throw new GitError({
msg: intl.todo(
ref + ' is not a branch'
)
});
}
};
var assertIsRemoteBranch = function(engine, ref) {
assertIsRef(engine, ref);
var obj = engine.refs[ref];
if (obj.get('type') !== 'branch' ||
!obj.getIsRemote()) {
throw new GitError({
msg: intl.todo(
ref + ' is not a remote branch'
)
});
}
};
var assertOriginSpecified = function(generalArgs) {
if (generalArgs[0] !== 'origin') {
throw new GitError({
@ -298,6 +324,7 @@ var commandConfig = {
'-f',
'-a',
'-r',
'-u',
'--contains'
],
execute: function(engine, command) {
@ -316,6 +343,23 @@ var commandConfig = {
return;
}
if (commandOptions['-u']) {
command.acceptNoGeneralArgs();
args = commandOptions['-u'];
command.validateArgBounds(args, 1, 2, '-u');
var remoteBranch = crappyUnescape(args[0]);
var branch = args[1] || engine.getOneBeforeCommit('HEAD').get('id');
// some assertions, both of these have to exist first
assertIsRemoteBranch(engine, remoteBranch);
assertIsBranch(engine, branch);
engine.setLocalToTrackRemote(
engine.refs[branch],
engine.refs[remoteBranch]
);
return;
}
if (commandOptions['--contains']) {
args = commandOptions['--contains'];
command.validateArgBounds(args, 1, 1, '--contains');

View file

@ -171,7 +171,6 @@ var GitDemonstrationView = ContainedBase.extend({
_.each(commands, function(command, index) {
chainPromise = chainPromise.then(_.bind(function() {
var myDefer = Q.defer();
console.log('dispatching', command);
this.mainVis.gitEngine.dispatch(command, myDefer);
return myDefer.promise;
}, this));

View file

@ -37,6 +37,7 @@ exports.levelSequences = {
require('./remote/fetchRebase').level
],
remoteAdvanced: [
require('./remote/tracking').level,
require('./remote/pushManyFeatures').level,
require('./remote/mergeManyFeatures').level
]

View file

@ -1,82 +0,0 @@
exports.level = {
"goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3A%22o/master%22%2C%22localBranchesThatTrackThis%22%3Anull%7D%2C%22foo%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22foo%22%2C%22remoteTrackingBranchID%22%3A%22o/foo%22%2C%22localBranchesThatTrackThis%22%3Anull%7D%2C%22o/master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22o/master%22%2C%22remoteTrackingBranchID%22%3Anull%2C%22localBranchesThatTrackThis%22%3A%5B%22master%22%5D%7D%2C%22o/foo%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22o/foo%22%2C%22remoteTrackingBranchID%22%3Anull%2C%22localBranchesThatTrackThis%22%3A%5B%22foo%22%5D%7D%2C%22side%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22side%22%2C%22remoteTrackingBranchID%22%3Anull%2C%22localBranchesThatTrackThis%22%3Anull%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22side%22%2C%22id%22%3A%22HEAD%22%7D%2C%22originTree%22%3A%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3Anull%2C%22localBranchesThatTrackThis%22%3Anull%7D%2C%22foo%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22foo%22%2C%22remoteTrackingBranchID%22%3Anull%2C%22localBranchesThatTrackThis%22%3Anull%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22foo%22%2C%22id%22%3A%22HEAD%22%7D%7D%7D",
"solutionCommand": "git pull origin foo --rebase;git push origin foo",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\",\"remoteTrackingBranchID\":\"o/master\",\"localBranchesThatTrackThis\":null},\"foo\":{\"target\":\"C1\",\"id\":\"foo\",\"remoteTrackingBranchID\":\"o/foo\",\"localBranchesThatTrackThis\":null},\"o/master\":{\"target\":\"C1\",\"id\":\"o/master\",\"remoteTrackingBranchID\":null,\"localBranchesThatTrackThis\":[\"master\"]},\"o/foo\":{\"target\":\"C1\",\"id\":\"o/foo\",\"remoteTrackingBranchID\":null,\"localBranchesThatTrackThis\":[\"foo\"]},\"side\":{\"target\":\"C3\",\"id\":\"side\",\"remoteTrackingBranchID\":null,\"localBranchesThatTrackThis\":null}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"}},\"HEAD\":{\"target\":\"side\",\"id\":\"HEAD\"},\"originTree\":{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\",\"remoteTrackingBranchID\":null,\"localBranchesThatTrackThis\":null},\"foo\":{\"target\":\"C2\",\"id\":\"foo\",\"remoteTrackingBranchID\":null,\"localBranchesThatTrackThis\":null}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"}},\"HEAD\":{\"target\":\"foo\",\"id\":\"HEAD\"}}}",
"name": {
"en_US": "Specifying Remote/Branch"
},
"hint": {
"en_US": "Review the intro dialogs if you get stuck!"
},
"startDialog": {
"en_US": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Specifying `<remote>/<branch>`",
"",
"One thing that might have seemed \"magical\" is that git knew to rebase our `master` branch onto `o/master`. How did it what branch we wanted? What if we wanted to rebase onto another branch or upload our work to a different branch name?",
"",
"Git knows to rebase onto `o/master` because the `master` branch is set up to *track* `o/master`. So yes, this is another branch property you have to understand -- when you clone a repository, git sets up a the remote branches (like `o/master`) and branches that *track* those remote branches (for instance, `master`).",
"",
"This way when you push and pull, you can simply leave off any arguments and git knows where to put your work."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"However, you can actually specify the remote and the branch name on the remote if you wish to. The command takes the format:",
"",
"* `git push <remote> <branch>`",
"* `git pull <remote> <branch>`",
"",
"Let's see a demonstration"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"I can `pull` down changes onto a totally separate branch..."
],
"afterMarkdowns": [
"See! The `side` branch was updated with work from `o/master` while the `master` branch was not updated at all."
],
"command": "git checkout side; git pull origin master",
"beforeCommand": "git clone; git fakeTeamwork; git branch side"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"I can also push to a different branch as well..."
],
"afterMarkdowns": [
"Here we pushed commits *from* the `side` branch onto the `master` branch on the remote. We did this by specifying the destination of our push.",
"",
"Notice how `o/master` is updated but *not* the `master` branch!"
],
"command": "git push origin master",
"beforeCommand": "git clone; git checkout -b side; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Ok, this level is a bit tricky. Let's pull down work from the `foo` branch on remote, rebase our work on top of that, and publish that work back.",
"",
"Let's do all of this while *not* on the `foo` branch though, just because we can!"
]
}
}
]
}
}
};

View file

@ -0,0 +1,129 @@
exports.level = {
"goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3A%22o/master%22%7D%2C%22o/master%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22o/master%22%2C%22remoteTrackingBranchID%22%3Anull%7D%2C%22side%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22side%22%2C%22remoteTrackingBranchID%22%3A%22o/master%22%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22side%22%2C%22id%22%3A%22HEAD%22%7D%2C%22originTree%22%3A%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3Anull%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D%7D",
"solutionCommand": "git checkout -b side o/master;git commit;git pull --rebase;git push",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\",\"remoteTrackingBranchID\":\"o/master\"},\"o/master\":{\"target\":\"C1\",\"id\":\"o/master\",\"remoteTrackingBranchID\":null}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"},\"originTree\":{\"branches\":{\"master\":{\"target\":\"C2\",\"id\":\"master\",\"remoteTrackingBranchID\":null}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}}",
"name": {
"en_US": "Remote Tracking"
},
"hint": {
"en_US": "Remember there are two ways to set remote tracking!"
},
"startDialog": {
"en_US": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Remote-Tracking branches",
"",
"One thing that might have seemed \"magical\" about the last few lessons is that git knew the `master` branch was related to `o/master`. Sure these branches have similar names and it might make logical sense to connect the `master` branch on the remote to the local `master` branch, but this connection is demonstrated clearly in two scenarios:",
"",
"* During a pull operation, commits are downloaded onto `o/master` and then *merged* into the `master` branch. The implied target of the merge is determined from this connection.",
"* During a push operation, work from the `master` branch was pushed onto the remote's `master` branch (which was then represented by `o/master` locally). The *destination* of the push is determined from the connection between `master` and `o/master`.",
""
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Remote tracking",
"",
"Long story short, this connection between `master` and `o/master` is explained simply by the \"remote tracking\" property of branches. The `master` branch is set to track `o/master` -- this means there is an implied merge target and implied push destination for the `master` branch.",
"",
"You may be wondering how this property got set on the `master` branch when you didn't run any commands to specify it. Well, when you clone a repository with git, this property is actually set for you automatically. ",
"",
"During a clone, git creates a remote branch for every branch on the remote (aka branches like `o/master`) and then, for each remote branch, creates a local branch to *track* that remote branch (aka `master`). Thats why you may have seen the following command output:",
"",
" local branch \"master\" set to track remote branch \"o/master\"",
"",
"When running `git clone`."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Can I specify this myself?",
"",
"Yes you can! You can make any arbitrary branch track `o/master`, and if you do so, that branch will have the same implied push destination and merge target as `master`. This means you can run `git push` on a branch named `totallyNotMaster` and have your work pushed to the `master` branch on the remote!",
"",
"There are two ways to set this property. The first is to checkout a new branch by using a remote branch as the specified ref. Running",
"",
"`git checkout -b totallyNotMaster o/master`",
"",
"Creates a new branch named `totallyNotMaster` and sets it to track `o/master`."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Enough talking, let's see a demonstration! We will checkout a new branch named `foo` and set it to track `master` on the remote."
],
"afterMarkdowns": [
"As you can see, we used the implied merge target of `o/master` to update the `foo` branch. Note how master doesn't get updated!!"
],
"command": "git checkout -b foo o/master; git pull",
"beforeCommand": "git clone; git fakeTeamwork"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"This also applies for git push"
],
"afterMarkdowns": [
"Boom. We pushed our work to the `master` on the remote even though our branch was named something totally different"
],
"command": "git checkout -b foo o/master; git commit; git push",
"beforeCommand": "git clone"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Way #2",
"",
"Another way to set remote tracking on a branch is to simply use the `git branch -u` option. Running",
"",
"`git branch -u o/master foo`",
"",
"will set the `foo` branch to track `o/master`. If `foo` is currently checked out you can even leave it off:",
"",
"`git branch -u o/master`",
""
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Let's see this other way of specifying remote tracking real quick..."
],
"afterMarkdowns": [
"Same as before, just a more explicit command. Sweet!"
],
"command": "git branch -u o/master foo; git commit; git push",
"beforeCommand": "git clone; git checkout -b foo"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Ok! For this level let's push work onto the `master` branch on remote while *not* checked out on `master` locally. I'll let you figure out the rest since this is the advanced course :P"
]
}
}
]
}
}
};

View file

@ -38,6 +38,8 @@ div.modalTerminal a {
font-weight: bold;
}
div.modalTerminal li,
div.modalTerminal p {
line-height: 24px;
margin: 1.5em 0;

View file

@ -5,12 +5,13 @@ Big Things
Origin things:
~~~~~~~~~~~~~~~~~~~~~~~~~~
[ ] polish visual layout?? needed?
[ ] work on TABBED levels layout
Medium things:
~~~~~~~~~~~~~~~~~~~~~~~~~~~
[ ] figure out what to do with instant commands (and parse waterfall and the like)
[ ] disable git commands on hg levels (and vice versa)
[ ] make helper bar clickable with goal vis floating
[ ] make show solution easier
Argument things:
@ -39,6 +40,7 @@ Ideas for cleaning
Done things:
(I only started this on Dec 17th 2012 to get a better sense of what was done)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[x] work on TABBED levels layout
[x] EASY -- make colors the same between remote branches and their remote counterparts
[x] fix undo not syncing the remote tracking
[x] get clone as a before command working in demonstration views (related to test infra as well)